!1011230 // JavaParser import java.util.*; import java.util.zip.*; import java.util.List; import java.util.regex.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.concurrent.locks.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; import javax.swing.table.*; import java.io.*; import java.net.*; import java.lang.reflect.*; import java.lang.ref.*; import java.lang.management.*; import java.security.*; import java.security.spec.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import javax.imageio.*; import java.math.*; // ifdef in cached includes? => i think cached includes still contain the ifdefs, so it's fine. tok_ifdef is not called within localStuff1 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 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 javax.net.ssl.*; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; import java.text.NumberFormat; class main { static boolean autoQuine = true; static int maxQuineLength = 80; static boolean assumeTriple = 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"); 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 fsi(int i) { return formatSnippetID(unq(i)); } String fsi() { return fsi(0); } 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)); } } // Matches /** * A class to compare vectors of objects. The result of comparison * is a list of change objects which form an * edit script. The objects compared are traditionally lines * of text from two files. Comparison options such as "ignore * whitespace" are implemented by modifying the equals * and hashcode methods for the objects compared. *

* The basic algorithm is described in:
* "An O(ND) Difference Algorithm and its Variations", Eugene Myers, * Algorithmica Vol. 1 No. 2, 1986, p 251. *

* This class outputs different results from GNU diff 1.15 on some * inputs. Our results are actually better (smaller change list, smaller * total size of changes), but it would be nice to know why. Perhaps * there is a memory overwrite bug in GNU diff 1.15. * * @author Stuart D. Gathman, translated from GNU diff 1.15 * Copyright (C) 2000 Business Management Systems, Inc. *

* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. *

* This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. *

* You should have received a copy of the * GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ static class EGDiff { /** * Prepare to find differences between two arrays. Each element of * the arrays is translated to an "equivalence number" based on * the result of equals. The original Object arrays * are no longer needed for computing the differences. They will * be needed again later to print the results of the comparison as * an edit script, if desired. */ public EGDiff(Object[] a, Object[] b) { Hashtable h = new Hashtable(a.length + b.length); filevec[0] = new file_data(a, h); filevec[1] = new file_data(b, h); } /** * 1 more than the maximum equivalence value used for this or its * sibling file. */ private int equiv_max = 1; /** * When set to true, the comparison uses a heuristic to speed it up. * With this heuristic, for files with a constant small density * of changes, the algorithm is linear in the file size. */ public boolean heuristic = false; /** * When set to true, the algorithm returns a guarranteed minimal * set of changes. This makes things slower, sometimes much slower. */ public boolean no_discards = false; private int[] xvec, yvec; /* Vectors being compared. */ private int[] fdiag; /* Vector, indexed by diagonal, containing the X coordinate of the point furthest along the given diagonal in the forward search of the edit matrix. */ private int[] bdiag; /* Vector, indexed by diagonal, containing the X coordinate of the point furthest along the given diagonal in the backward search of the edit matrix. */ private int fdiagoff, bdiagoff; private final file_data[] filevec = new file_data[2]; private int cost; /** * Find the midpoint of the shortest edit script for a specified * portion of the two files. *

* We scan from the beginnings of the files, and simultaneously from the ends, * doing a breadth-first search through the space of edit-sequence. * When the two searches meet, we have found the midpoint of the shortest * edit sequence. *

* The value returned is the number of the diagonal on which the midpoint lies. * The diagonal number equals the number of inserted lines minus the number * of deleted lines (counting only lines before the midpoint). * The edit cost is stored into COST; this is the total number of * lines inserted or deleted (counting only lines before the midpoint). *

* This function assumes that the first lines of the specified portions * of the two files do not match, and likewise that the last lines do not * match. The caller must trim matching lines from the beginning and end * of the portions it is going to specify. *

* Note that if we return the "wrong" diagonal value, or if * the value of bdiag at that diagonal is "wrong", * the worst this can do is cause suboptimal diff output. * It cannot cause incorrect diff output. */ private int diag(int xoff, int xlim, int yoff, int ylim) { final int[] fd = fdiag; // Give the compiler a chance. final int[] bd = bdiag; // Additional help for the compiler. final int[] xv = xvec; // Still more help for the compiler. final int[] yv = yvec; // And more and more . . . final int dmin = xoff - ylim; // Minimum valid diagonal. final int dmax = xlim - yoff; // Maximum valid diagonal. final int fmid = xoff - yoff; // Center diagonal of top-down search. final int bmid = xlim - ylim; // Center diagonal of bottom-up search. int fmin = fmid, fmax = fmid; // Limits of top-down search. int bmin = bmid, bmax = bmid; // Limits of bottom-up search. /* True if southeast corner is on an odd diagonal with respect to the northwest. */ final boolean odd = (fmid - bmid & 1) != 0; fd[fdiagoff + fmid] = xoff; bd[bdiagoff + bmid] = xlim; for (int c = 1; ; ++c) { int d; /* Active diagonal. */ boolean big_snake = false; /* Extend the top-down search by an edit step in each diagonal. */ if (fmin > dmin) fd[fdiagoff + --fmin - 1] = -1; else ++fmin; if (fmax < dmax) fd[fdiagoff + ++fmax + 1] = -1; else --fmax; for (d = fmax; d >= fmin; d -= 2) { int x, y, oldx, tlo = fd[fdiagoff + d - 1], thi = fd[fdiagoff + d + 1]; if (tlo >= thi) x = tlo + 1; else x = thi; oldx = x; y = x - d; while (x < xlim && y < ylim && xv[x] == yv[y]) { ++x; ++y; } if (x - oldx > 20) big_snake = true; fd[fdiagoff + d] = x; if (odd && bmin <= d && d <= bmax && bd[bdiagoff + d] <= fd[fdiagoff + d]) { cost = 2 * c - 1; return d; } } /* Similar extend the bottom-up search. */ if (bmin > dmin) bd[bdiagoff + --bmin - 1] = Integer.MAX_VALUE; else ++bmin; if (bmax < dmax) bd[bdiagoff + ++bmax + 1] = Integer.MAX_VALUE; else --bmax; for (d = bmax; d >= bmin; d -= 2) { int x, y, oldx, tlo = bd[bdiagoff + d - 1], thi = bd[bdiagoff + d + 1]; if (tlo < thi) x = tlo; else x = thi - 1; oldx = x; y = x - d; while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) { --x; --y; } if (oldx - x > 20) big_snake = true; bd[bdiagoff + d] = x; if (!odd && fmin <= d && d <= fmax && bd[bdiagoff + d] <= fd[fdiagoff + d]) { cost = 2 * c; return d; } } /* Heuristic: check occasionally for a diagonal that has made lots of progress compared with the edit distance. If we have any such, find the one that has made the most progress and return it as if it had succeeded. With this heuristic, for files with a constant small density of changes, the algorithm is linear in the file size. */ if (c > 200 && big_snake && heuristic) { int best = 0; int bestpos = -1; for (d = fmax; d >= fmin; d -= 2) { int dd = d - fmid; if ((fd[fdiagoff + d] - xoff) * 2 - dd > 12 * (c + (dd > 0 ? dd : -dd))) { if (fd[fdiagoff + d] * 2 - dd > best && fd[fdiagoff + d] - xoff > 20 && fd[fdiagoff + d] - d - yoff > 20) { int k; int x = fd[fdiagoff + d]; /* We have a good enough best diagonal; now insist that it end with a significant snake. */ for (k = 1; k <= 20; k++) if (xvec[x - k] != yvec[x - d - k]) break; if (k == 21) { best = fd[fdiagoff + d] * 2 - dd; bestpos = d; } } } } if (best > 0) { cost = 2 * c - 1; return bestpos; } best = 0; for (d = bmax; d >= bmin; d -= 2) { int dd = d - bmid; if ((xlim - bd[bdiagoff + d]) * 2 + dd > 12 * (c + (dd > 0 ? dd : -dd))) { if ((xlim - bd[bdiagoff + d]) * 2 + dd > best && xlim - bd[bdiagoff + d] > 20 && ylim - (bd[bdiagoff + d] - d) > 20) { /* We have a good enough best diagonal; now insist that it end with a significant snake. */ int k; int x = bd[bdiagoff + d]; for (k = 0; k < 20; k++) if (xvec[x + k] != yvec[x - d + k]) break; if (k == 20) { best = (xlim - bd[bdiagoff + d]) * 2 + dd; bestpos = d; } } } } if (best > 0) { cost = 2 * c - 1; return bestpos; } } } } /** * Compare in detail contiguous subsequences of the two files * which are known, as a whole, to match each other. *

* The results are recorded in the vectors filevec[N].changed_flag, by * storing a 1 in the element for each line that is an insertion or deletion. *

* The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1. *

* Note that XLIM, YLIM are exclusive bounds. * All line numbers are origin-0 and discarded lines are not counted. */ private void compareseq(int xoff, int xlim, int yoff, int ylim) { /* Slide down the bottom initial diagonal. */ while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff]) { ++xoff; ++yoff; } /* Slide up the top initial diagonal. */ while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1]) { --xlim; --ylim; } /* Handle simple cases. */ if (xoff == xlim) while (yoff < ylim) filevec[1].changed_flag[1 + filevec[1].realindexes[yoff++]] = true; else if (yoff == ylim) while (xoff < xlim) filevec[0].changed_flag[1 + filevec[0].realindexes[xoff++]] = true; else { /* Find a point of correspondence in the middle of the files. */ int d = diag(xoff, xlim, yoff, ylim); int c = cost; int b = bdiag[bdiagoff + d]; if (c == 1) { /* This should be impossible, because it implies that one of the two subsequences is empty, and that case was handled above without calling `diag'. Let's verify that this is true. */ throw new IllegalArgumentException("Empty subsequence"); } else { /* Use that point to split this problem into two subproblems. */ compareseq(xoff, b, yoff, b - d); /* This used to use f instead of b, but that is incorrect! It is not necessarily the case that diagonal d has a snake from b to f. */ compareseq(b, xlim, b - d, ylim); } } } /** * Discard lines from one file that have no matches in the other file. */ private void discard_confusing_lines() { filevec[0].discard_confusing_lines(filevec[1]); filevec[1].discard_confusing_lines(filevec[0]); } private boolean inhibit = false; /** * Adjust inserts/deletes of blank lines to join changes * as much as possible. */ private void shift_boundaries() { if (inhibit) return; filevec[0].shift_boundaries(filevec[1]); filevec[1].shift_boundaries(filevec[0]); } public interface ScriptBuilder { /** * Scan the tables of which lines are inserted and deleted, * producing an edit script. * * @param changed0 true for lines in first file which do not match 2nd * @param len0 number of lines in first file * @param changed1 true for lines in 2nd file which do not match 1st * @param len1 number of lines in 2nd file * @return a linked list of changes - or null */ public change build_script(boolean[] changed0, int len0, boolean[] changed1, int len1); } /** * Scan the tables of which lines are inserted and deleted, * producing an edit script in reverse order. */ static class ReverseScript implements ScriptBuilder { public change build_script(final boolean[] changed0, int len0, final boolean[] changed1, int len1) { change script = null; int i0 = 0, i1 = 0; while (i0 < len0 || i1 < len1) { if (changed0[1 + i0] || changed1[1 + i1]) { int line0 = i0, line1 = i1; /* Find # lines changed here in each file. */ while (changed0[1 + i0]) ++i0; while (changed1[1 + i1]) ++i1; /* Record this change. */ script = new change(line0, line1, i0 - line0, i1 - line1, script); } /* We have reached lines in the two files that match each other. */ i0++; i1++; } return script; } } static class ForwardScript implements ScriptBuilder { /** * Scan the tables of which lines are inserted and deleted, * producing an edit script in forward order. */ public change build_script(final boolean[] changed0, int len0, final boolean[] changed1, int len1) { change script = null; int i0 = len0, i1 = len1; while (i0 >= 0 || i1 >= 0) { if (changed0[i0] || changed1[i1]) { int line0 = i0, line1 = i1; /* Find # lines changed here in each file. */ while (changed0[i0]) --i0; while (changed1[i1]) --i1; /* Record this change. */ script = new change(i0, i1, line0 - i0, line1 - i1, script); } /* We have reached lines in the two files that match each other. */ i0--; i1--; } return script; } } /** * Standard ScriptBuilders. */ public final static ScriptBuilder forwardScript = new ForwardScript(), reverseScript = new ReverseScript(); /* Report the differences of two files. DEPTH is the current directory depth. */ public final change diff_2(final boolean reverse) { return diff(reverse ? reverseScript : forwardScript); } /** * Get the results of comparison as an edit script. The script * is described by a list of changes. The standard ScriptBuilder * implementations provide for forward and reverse edit scripts. * Alternate implementations could, for instance, list common elements * instead of differences. * * @param bld an object to build the script from change flags * @return the head of a list of changes */ public change diff(final ScriptBuilder bld) { /* Some lines are obviously insertions or deletions because they don't match anything. Detect them now, and avoid even thinking about them in the main comparison algorithm. */ discard_confusing_lines(); /* Now do the main comparison algorithm, considering just the undiscarded lines. */ xvec = filevec[0].undiscarded; yvec = filevec[1].undiscarded; int diags = filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3; fdiag = new int[diags]; fdiagoff = filevec[1].nondiscarded_lines + 1; bdiag = new int[diags]; bdiagoff = filevec[1].nondiscarded_lines + 1; compareseq(0, filevec[0].nondiscarded_lines, 0, filevec[1].nondiscarded_lines); fdiag = null; bdiag = null; /* Modify the results slightly to make them prettier in cases where that can validly be done. */ shift_boundaries(); /* Get the results of comparison in the form of a chain of `struct change's -- an edit script. */ return bld.build_script(filevec[0].changed_flag, filevec[0].buffered_lines, filevec[1].changed_flag, filevec[1].buffered_lines); } /** * The result of comparison is an "edit script": a chain of change objects. * Each change represents one place where some lines are deleted * and some are inserted. *

* LINE0 and LINE1 are the first affected lines in the two files (origin 0). * DELETED is the number of lines deleted here from file 0. * INSERTED is the number of lines inserted here in file 1. *

* If DELETED is 0 then LINE0 is the number of the line before * which the insertion was done; vice versa for INSERTED and LINE1. */ public static class change { /** * Previous or next edit command. */ public change link; /** * # lines of file 1 changed here. */ public final int inserted; /** * # lines of file 0 changed here. */ public final int deleted; /** * Line number of 1st deleted line. */ public final int line0; /** * Line number of 1st inserted line. */ public final int line1; /** * Cons an additional entry onto the front of an edit script OLD. * LINE0 and LINE1 are the first affected lines in the two files (origin 0). * DELETED is the number of lines deleted here from file 0. * INSERTED is the number of lines inserted here in file 1. *

* If DELETED is 0 then LINE0 is the number of the line before * which the insertion was done; vice versa for INSERTED and LINE1. */ public change(int line0, int line1, int deleted, int inserted, change old) { this.line0 = line0; this.line1 = line1; this.inserted = inserted; this.deleted = deleted; this.link = old; //System.err.println(line0+","+line1+","+inserted+","+deleted); } } /** * Data on one input file being compared. */ class file_data { /** * Allocate changed array for the results of comparison. */ void clear() { /* Allocate a flag for each line of each file, saying whether that line is an insertion or deletion. Allocate an extra element, always zero, at each end of each vector. */ changed_flag = new boolean[buffered_lines + 2]; } /** * Return equiv_count[I] as the number of lines in this file * that fall in equivalence class I. * * @return the array of equivalence class counts. */ int[] equivCount() { int[] equiv_count = new int[equiv_max]; for (int i = 0; i < buffered_lines; ++i) ++equiv_count[equivs[i]]; return equiv_count; } /** * Discard lines that have no matches in another file. *

* A line which is discarded will not be considered by the actual * comparison algorithm; it will be as if that line were not in the file. * The file's `realindexes' table maps virtual line numbers * (which don't count the discarded lines) into real line numbers; * this is how the actual comparison algorithm produces results * that are comprehensible when the discarded lines are counted. *

* When we discard a line, we also mark it as a deletion or insertion * so that it will be printed in the output. * * @param f the other file */ void discard_confusing_lines(file_data f) { clear(); /* Set up table of which lines are going to be discarded. */ final byte[] discarded = discardable(f.equivCount()); /* Don't really discard the provisional lines except when they occur in a run of discardables, with nonprovisionals at the beginning and end. */ filterDiscards(discarded); /* Actually discard the lines. */ discard(discarded); } /** * Mark to be discarded each line that matches no line of another file. * If a line matches many lines, mark it as provisionally discardable. * * @param counts The count of each equivalence number for the other file. * @return 0=nondiscardable, 1=discardable or 2=provisionally discardable * for each line */ private byte[] discardable(final int[] counts) { final int end = buffered_lines; final byte[] discards = new byte[end]; final int[] equivs = this.equivs; int many = 5; int tem = end / 64; /* Multiply MANY by approximate square root of number of lines. That is the threshold for provisionally discardable lines. */ while ((tem = tem >> 2) > 0) many *= 2; for (int i = 0; i < end; i++) { int nmatch; if (equivs[i] == 0) continue; nmatch = counts[equivs[i]]; if (nmatch == 0) discards[i] = 1; else if (nmatch > many) discards[i] = 2; } return discards; } /** * Don't really discard the provisional lines except when they occur * in a run of discardables, with nonprovisionals at the beginning * and end. */ private void filterDiscards(final byte[] discards) { final int end = buffered_lines; for (int i = 0; i < end; i++) { /* Cancel provisional discards not in middle of run of discards. */ if (discards[i] == 2) discards[i] = 0; else if (discards[i] != 0) { /* We have found a nonprovisional discard. */ int j; int length; int provisional = 0; /* Find end of this run of discardable lines. Count how many are provisionally discardable. */ for (j = i; j < end; j++) { if (discards[j] == 0) break; if (discards[j] == 2) ++provisional; } /* Cancel provisional discards at end, and shrink the run. */ while (j > i && discards[j - 1] == 2) { discards[--j] = 0; --provisional; } /* Now we have the length of a run of discardable lines whose first and last are not provisional. */ length = j - i; /* If 1/4 of the lines in the run are provisional, cancel discarding of all provisional lines in the run. */ if (provisional * 4 > length) { while (j > i) if (discards[--j] == 2) discards[j] = 0; } else { int consec; int minimum = 1; int tem = length / 4; /* MINIMUM is approximate square root of LENGTH/4. A subrun of two or more provisionals can stand when LENGTH is at least 16. A subrun of 4 or more can stand when LENGTH >= 64. */ while ((tem = tem >> 2) > 0) minimum *= 2; minimum++; /* Cancel any subrun of MINIMUM or more provisionals within the larger run. */ for (j = 0, consec = 0; j < length; j++) if (discards[i + j] != 2) consec = 0; else if (minimum == ++consec) /* Back up to start of subrun, to cancel it all. */ j -= consec; else if (minimum < consec) discards[i + j] = 0; /* Scan from beginning of run until we find 3 or more nonprovisionals in a row or until the first nonprovisional at least 8 lines in. Until that point, cancel any provisionals. */ for (j = 0, consec = 0; j < length; j++) { if (j >= 8 && discards[i + j] == 1) break; if (discards[i + j] == 2) { consec = 0; discards[i + j] = 0; } else if (discards[i + j] == 0) consec = 0; else consec++; if (consec == 3) break; } /* I advances to the last line of the run. */ i += length - 1; /* Same thing, from end. */ for (j = 0, consec = 0; j < length; j++) { if (j >= 8 && discards[i - j] == 1) break; if (discards[i - j] == 2) { consec = 0; discards[i - j] = 0; } else if (discards[i - j] == 0) consec = 0; else consec++; if (consec == 3) break; } } } } } /** * Actually discard the lines. * * @param discards flags lines to be discarded */ private void discard(final byte[] discards) { final int end = buffered_lines; int j = 0; for (int i = 0; i < end; ++i) if (no_discards || discards[i] == 0) { undiscarded[j] = equivs[i]; realindexes[j++] = i; } else changed_flag[1 + i] = true; nondiscarded_lines = j; } file_data(Object[] data, Hashtable h) { buffered_lines = data.length; equivs = new int[buffered_lines]; undiscarded = new int[buffered_lines]; realindexes = new int[buffered_lines]; for (int i = 0; i < data.length; ++i) { Integer ir = (Integer) h.get(data[i]); if (ir == null) h.put(data[i], new Integer(equivs[i] = equiv_max++)); else equivs[i] = ir.intValue(); } } /** * Adjust inserts/deletes of blank lines to join changes * as much as possible. *

* We do something when a run of changed lines include a blank * line at one end and have an excluded blank line at the other. * We are free to choose which blank line is included. * `compareseq' always chooses the one at the beginning, * but usually it is cleaner to consider the following blank line * to be the "change". The only exception is if the preceding blank line * would join this change to other changes. * * @param f the file being compared against */ void shift_boundaries(file_data f) { final boolean[] changed = changed_flag; final boolean[] other_changed = f.changed_flag; int i = 0; int j = 0; int i_end = buffered_lines; int preceding = -1; int other_preceding = -1; for (; ;) { int start, end, other_start; /* Scan forwards to find beginning of another run of changes. Also keep track of the corresponding point in the other file. */ while (i < i_end && !changed[1 + i]) { while (other_changed[1 + j++]) /* Non-corresponding lines in the other file will count as the preceding batch of changes. */ other_preceding = j; i++; } if (i == i_end) break; start = i; other_start = j; for (; ;) { /* Now find the end of this run of changes. */ while (i < i_end && changed[1 + i]) i++; end = i; /* If the first changed line matches the following unchanged one, and this run does not follow right after a previous run, and there are no lines deleted from the other file here, then classify the first changed line as unchanged and the following line as changed in its place. */ /* You might ask, how could this run follow right after another? Only because the previous run was shifted here. */ if (end != i_end && equivs[start] == equivs[end] && !other_changed[1 + j] && end != i_end && !((preceding >= 0 && start == preceding) || (other_preceding >= 0 && other_start == other_preceding))) { changed[1 + end] = true; changed[1 + start++] = false; ++i; /* Since one line-that-matches is now before this run instead of after, we must advance in the other file to keep in synch. */ ++j; } else break; } preceding = i; other_preceding = j; } } /** * Number of elements (lines) in this file. */ final int buffered_lines; /** * Vector, indexed by line number, containing an equivalence code for * each line. It is this vector that is actually compared with that * of another file to generate differences. */ private final int[] equivs; /** * Vector, like the previous one except that * the elements for discarded lines have been squeezed out. */ final int[] undiscarded; /** * Vector mapping virtual line numbers (not counting discarded lines) * to real ones (counting those lines). Both are origin-0. */ final int[] realindexes; /** * Total number of nondiscarded lines. */ int nondiscarded_lines; /** * Array, indexed by real origin-1 line number, * containing true for a line that is an insertion or a deletion. * The results of comparison are stored here. */ boolean[] changed_flag; } } // EGDiff static class BlockDiff { public CopyBlock asCopyBlock() { return null; } public NewBlock asNewBlock () { return null; } } static class CopyBlock extends BlockDiff { int firstLine, lines; CopyBlock(int firstLine, int lines) { this.firstLine = firstLine; this.lines = lines; } public CopyBlock asCopyBlock() { return this; } public int getFirstLine() { return firstLine; } public int getLines() { return lines; } } static class NewBlock extends BlockDiff { int originalStart; List contents; NewBlock(int originalStart, List contents) { this.originalStart = originalStart; this.contents = contents; } public NewBlock asNewBlock () { return this; } public int getOriginalStart() { return originalStart; } public List getContents() { return contents; } } static class ExplodedLine { int type; String left, right; int leftIndex, rightIndex; ExplodedLine(int type, String left, String right, int leftIndex, int rightIndex) { this.type = type; this.left = left; this.right = right; this.leftIndex = leftIndex; this.rightIndex = rightIndex; } public int getType() { return type; } public String getLeft() { return left; } public String getRight() { return right; } public int getLeftIndex() { return leftIndex; } public int getRightIndex() { return rightIndex; } } static class BlockDiffer { public static final int IDENTICAL = 0; public static final int DIFFERENT = 1; public static final int LEFT_ONLY = 2; public static final int RIGHT_ONLY = 3; private static void printChange(EGDiff.change change) { if (change != null) { System.out.println("line0="+change.line0+", line1="+change.line1 +", inserted="+change.inserted+", deleted="+change.deleted); printChange(change.link); } } /** Generates the text content of a Unified-format context diff between 2 files * (NB the 'files-changed' header must be added separately). */ public static List generateUniDiff(List fileA, List fileB, int contextSize) { EGDiff diff = new EGDiff(fileA.toArray(), fileB.toArray()); EGDiff.change change = diff.diff_2(false); if (change != null) { int inserted, deleted; List hunkLines = new ArrayList(); int cumulExtraLinesBwrtA = 0; // Each hunk is generated with a header do { int line0 = change.line0, line1 = change.line1; int changeStart = ((line1 < line0) ? line1 : line0); int contextStart = ((changeStart > contextSize) ? changeStart - contextSize : 0); int headerPosn = hunkLines.size(); // Provide the first lines of context for (int i = contextStart; i < changeStart; i++) //System.out.println(" " + fileA.get(i)); hunkLines.add(" " + fileA.get(i)); boolean hunkFinish = false; // Step through each change giving the change lines and following context do { inserted = change.inserted; deleted = change.deleted; line0 = change.line0; line1 = change.line1; if (line1 < line0) // An insert comes earlier while (inserted-- > 0) hunkLines.add("+" + fileB.get(line1++)); while (deleted-- > 0) hunkLines.add("-" + fileA.get(line0++)); while (inserted-- > 0) hunkLines.add("+" + fileB.get(line1++)); // Lines following are trailing context, identical in fileA and fileB // The next change may overlap the context, so check and if so, form one hunk EGDiff.change nextChange = change.link; int nextChangeStart = fileA.size(); if (nextChange != null) nextChangeStart = ((nextChange.line1 < nextChange.line0) ? nextChange.line1 : nextChange.line0); if (nextChangeStart - line0 > contextSize * 2) { // A separate hunk nextChangeStart = line0 + contextSize; hunkFinish = true; } if (nextChangeStart > fileA.size()) nextChangeStart = fileA.size(); // Limit to file size while (line0 < nextChangeStart) { hunkLines.add(" " + fileA.get(line0++)); line1++; // Keep in sync with trailing context } change = change.link; } while (!hunkFinish && change != null); int hunkStartB = contextStart + cumulExtraLinesBwrtA; int hunkTotA = line0 - contextStart; int hunkTotB = line1 - hunkStartB; hunkLines.add(headerPosn, "@@ -" + (contextStart + 1) + ',' + hunkTotA + " +" + (hunkStartB + 1) + ',' + hunkTotB + " @@"); cumulExtraLinesBwrtA += hunkTotB - hunkTotA; } while (change != null); return hunkLines; } return null; } /* For testing: private static void printUniDiff(List fileA, List fileB, int contextSize) { List uniDiff = generateUniDiff(fileA, fileB, contextSize); if (uniDiff != null) for (int j = 0; j < uniDiff.size(); j++) System.out.println(uniDiff.get(j)); } */ public static List diffLines(List lines, List reference) { List diffs = new ArrayList(); EGDiff diff = new EGDiff(reference.toArray(), lines.toArray()); EGDiff.change change = diff.diff_2(false); //printChange(change); //printUniDiff(reference, lines, 3); int l0 = 0, l1 = 0; while (change != null) { if (change.line0 > l0 && change.line1 > l1) diffs.add(new CopyBlock(l0, change.line0-l0)); if (change.inserted != 0) diffs.add(new NewBlock(change.line1, lines.subList(change.line1, change.line1+change.inserted))); l0 = change.line0 + change.deleted; l1 = change.line1 + change.inserted; change = change.link; } if (l0 < reference.size()) diffs.add(new CopyBlock(l0, reference.size()-l0)); return diffs; } /** fills files with empty lines to align matching blocks * * @param file1 first file * @param file2 second file * @return an array with two lists */ public static List explode(List file1, List file2) { List lines = new ArrayList(); List diffs = BlockDiffer.diffLines(file2, file1); int lastLineCopied = 0, rightOnlyStart = -1, rightPosition = 0; for (int i = 0; i < diffs.size(); i++) { BlockDiff diff = diffs.get(i); if (diff instanceof CopyBlock) { CopyBlock copyBlock = (CopyBlock) diff; if (lastLineCopied < copyBlock.getFirstLine()) { if (rightOnlyStart >= 0) { int overlap = Math.min(lines.size()-rightOnlyStart, copyBlock.getFirstLine()-lastLineCopied); //lines.subList(rightOnlyStart, rightOnlyStart+overlap).clear(); convertRightOnlyToDifferent(lines, rightOnlyStart, overlap, file1, lastLineCopied); lastLineCopied += overlap; } addBlock(lines, LEFT_ONLY, file1, lastLineCopied, copyBlock.getFirstLine(), lastLineCopied, -1); } addBlock(lines, IDENTICAL, file1, copyBlock.getFirstLine(), copyBlock.getFirstLine()+copyBlock.getLines(), copyBlock.getFirstLine(), rightPosition); rightPosition += copyBlock.getLines(); lastLineCopied = copyBlock.getFirstLine()+copyBlock.getLines(); rightOnlyStart = -1; } else if (diff instanceof NewBlock) { NewBlock newBlock = (NewBlock) diff; /*if (nextDiff instanceof BlockDiffer.CopyBlock) { BlockDiffer.CopyBlock copyBlock = (BlockDiffer.CopyBlock) nextDiff; copyBlock.getFirstLine()-lastLineCopied*/ rightOnlyStart = lines.size(); addBlock(lines, RIGHT_ONLY, newBlock.getContents(), 0, newBlock.getContents().size(), -1, rightPosition); rightPosition += newBlock.getContents().size(); } } if (rightOnlyStart >= 0) { int overlap = Math.min(lines.size()-rightOnlyStart, file1.size()-lastLineCopied); //lines.subList(rightOnlyStart, rightOnlyStart+overlap).clear(); convertRightOnlyToDifferent(lines, rightOnlyStart, overlap, file1, lastLineCopied); lastLineCopied += overlap; } addBlock(lines, LEFT_ONLY, file1, lastLineCopied, file1.size(), lastLineCopied, -1); return lines; } private static void convertRightOnlyToDifferent(List lines, int start, int numLines, List leftLines, int leftStart) { for (int i = 0; i < numLines; i++) { ExplodedLine line = lines.get(start+i); lines.set(start+i, new ExplodedLine(DIFFERENT, leftLines.get(i+leftStart), line.getRight(), i+leftStart, line.getRightIndex())); } } private static void addBlock(List lines, int type, List srcLines, int start, int end, int leftStart, int rightStart) { for (int i = start; i < end; i++) lines.add(new ExplodedLine(type, type == RIGHT_ONLY ? "" : srcLines.get(i), type == LEFT_ONLY ? "" : srcLines.get(i), type == RIGHT_ONLY ? -1 : i - start + leftStart, type == LEFT_ONLY ? -1 : i - start + rightStart)); } public static List condense(List lines) { List result = new ArrayList(); for (Iterator i = lines.iterator(); i.hasNext();) { ExplodedLine line = i.next(); if (line.getType() == IDENTICAL) { if (result.isEmpty() || result.get(result.size()-1).getType() != IDENTICAL) result.add(new ExplodedLine(IDENTICAL, "[...]", "[...]", -1, -1)); } else result.add(line); } return result; } } // BlockDiffer static abstract class DialogIO { String line; boolean eos, loud, noClose; Lock lock = lock(); abstract String readLineImpl(); abstract boolean isStillConnected(); abstract void sendLine(String line); abstract boolean isLocalConnection(); abstract Socket getSocket(); abstract void close(); int getPort() { Socket s = getSocket(); return s == null ? 0 : s.getPort(); } boolean helloRead; int shortenOutputTo = 500; String readLineNoBlock() { String l = line; line = null; return l; } boolean waitForLine() { try { ping(); if (line != null) return true; //print("Readline"); line = readLineImpl(); //print("Readline done: " + line); if (line == null) eos = true; return line != null; } catch (Exception __e) { throw rethrow(__e); } } String readLine() { waitForLine(); helloRead = true; return readLineNoBlock(); } String ask(String s, Object... args) { if (loud) return askLoudly(s, args); if (!helloRead) readLine(); if (args.length != 0) s = format3(s, args); sendLine(s); return readLine(); } String askLoudly(String s, Object... args) { if (!helloRead) readLine(); if (args.length != 0) s = format3(s, args); print("> " + shorten(s, shortenOutputTo)); sendLine(s); String answer = readLine(); print("< " + shorten(answer, shortenOutputTo)); return answer; } void pushback(String l) { if (line != null) throw fail(); line = l; helloRead = false; } } static abstract class DialogHandler { abstract void run(DialogIO io); } // DialoGIO static final class IndexedList2 extends AbstractList { ArrayList l = new ArrayList(); MultiSet index = new MultiSet(false); // HashMap static boolean debug; static int instances; IndexedList2() { ++instances; } IndexedList2(List x) { this(); l.ensureCapacity(l(x)); addAll(x); } // required immutable list methods @Override public A get(int i) { return l.get(i); } @Override public int size() { return l.size(); } // required mutable list methods @Override public A set(int i, A a) { A prev = l.get(i); if (prev != a) { index.remove(prev); index.add(a); } l.set(i, a); return prev; } @Override public void add(int i, A a) { index.add(a); l.add(i, a); } @Override public A remove(int i) { A a = l.get(i); index.remove(a); l.remove(i); return a; } // speed up methods @Override protected void removeRange(int fromIndex, int toIndex) { for (int i = fromIndex; i < toIndex; i++) unindex(i); l.subList(fromIndex, toIndex).clear(); } @Override public int indexOf(Object a) { if (!contains(a)) return -1; return l.indexOf(a); } @Override public boolean contains(Object a) { boolean b = index.contains((A) a); if (debug) print("IndexedList2.contains " + a + " => " + b); return b; } @Override public void clear() { index.clear(); l.clear(); } @Override public boolean addAll(int i, Collection c) { index.addAll((Collection) c); return l.addAll(i, c); } // indexing methods void unindex(int i) { index.remove(l.get(i)); } void index(int i) { index.add(l.get(i)); } // static methods static IndexedList2 ensureIndexed(List l) { return l instanceof IndexedList2 ? (IndexedList2) l : new IndexedList2(l); } } // IndexedList2 //include #1001296 // MultiMap // uses HashMap by default static class MultiSet { Map map = new HashMap(); MultiSet(boolean useTreeMap) { if (useTreeMap) map = new TreeMap(); } MultiSet() {} MultiSet(Iterable c) { addAll(c); } MultiSet(MultiSet ms) { synchronized(ms) { for (A a : ms.keySet()) add(a, ms.get(a)); }} synchronized void add(A key) { add(key, 1); } synchronized void addAll(Iterable c) { if (c != null) for (A a : c) add(a); } synchronized void addAll(MultiSet ms) { for (A a : ms.keySet()) add(a, ms.get(a)); } synchronized void add(A key, int count) { if (map.containsKey(key)) map.put(key, map.get(key)+count); else map.put(key, count); } synchronized int get(A key) { Integer i = map.get(key); return i != null ? i : 0; //ret key != null && map.containsKey(key) ? map.get(key) : 0; } synchronized boolean contains(A key) { return map.containsKey(key); } synchronized void remove(A key) { Integer i = map.get(key); if (i != null && i > 1) map.put(key, i - 1); else map.remove(key); } synchronized List topTen() { return getTopTen(); } synchronized List getTopTen() { return getTopTen(10); } synchronized List getTopTen(int maxSize) { List list = getSortedListDescending(); return list.size() > maxSize ? list.subList(0, maxSize) : list; } synchronized List highestFirst() { return getSortedListDescending(); } synchronized List lowestFirst() { return reversedList(getSortedListDescending()); } synchronized List getSortedListDescending() { List list = new ArrayList(map.keySet()); Collections.sort(list, new Comparator() { public int compare(A a, A b) { return map.get(b).compareTo(map.get(a)); } }); return list; } synchronized int getNumberOfUniqueElements() { return map.size(); } synchronized int uniqueSize() { return map.size(); } synchronized Set asSet() { return map.keySet(); } synchronized NavigableSet navigableSet() { return navigableKeys((NavigableMap) map); } synchronized Set keySet() { return map.keySet(); } synchronized A getMostPopularEntry() { int max = 0; A a = null; for (Map.Entry entry : map.entrySet()) { if (entry.getValue() > max) { max = entry.getValue(); a = entry.getKey(); } } return a; } synchronized void removeAll(A key) { map.remove(key); } synchronized int size() { int size = 0; for (int i : map.values()) size += i; return size; } synchronized MultiSet mergeWith(MultiSet set) { MultiSet result = new MultiSet(); for (A a : set.asSet()) { result.add(a, set.get(a)); } return result; } synchronized boolean isEmpty() { return map.isEmpty(); } synchronized public String toString() { // hmm. sync this? return str(map); } synchronized void clear() { map.clear(); } synchronized Map asMap() { return cloneMap(map); } } // MultiSet static ThreadLocal DynamicObject_loading = new ThreadLocal(); static class DynamicObject { String className; // just the name, without the "main$" LinkedHashMap fieldValues = new LinkedHashMap(); DynamicObject() {} // className = just the name, without the "main$" DynamicObject(String className) { this.className = className;} } // DynamicObject static class CompilerBot { static boolean verbose; 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); 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" + progID); File jar = getJarFile(md5); if (jar == null || jar.length() <= 22) { // have to compile boolean canRename = useDummyMainClasses() && isSnippetID(progID) && !tok_classHasModifier(findMainClass(javaTok(src)), "public"); if (verbose) print("useRenaming: " + useDummyMainClasses() + ", canRename: " + canRename + ", progID: " + progID); javaCompileToJar_optionalRename(src, dehlibs, jar, canRename ? progID : null); } 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; } static File getJarFile(String md5) { assertTrue(isMD5(md5)); return new File(getCacheProgramDir("#1002203"), md5 + ".jar"); } } // CompilerBot static boolean isTrue(Object o) { if (o instanceof Boolean) return ((Boolean) o).booleanValue(); if (o == null) return false; if (o instanceof ThreadLocal) return isTrue(((ThreadLocal) o).get()); throw fail(getClassName(o)); } // isTrue static String unquote(String s) { if (s == null) return null; if (s.startsWith("[")) { 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.startsWith("\"") || s.startsWith("\'")) && s.length() > 1) { int l = s.endsWith(substring(s, 0, 1)) ? 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 '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; 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 } // unquote static String transpilingSnippetID; static int varCount; static Map snippetCache = new HashMap(); static boolean useIndexedList = true, opt_javaTok = true; static boolean cacheStdFunctions = true, cacheStdClasses = true; static HashMap cachedIncludes = new HashMap(); static ExecutorService executor; static List lclasses; static long startTime, lastPrint; // These variables have to be cleared manually for each transpilation static HashSet included = new HashSet(); static Set definitions = ciSet(); static HashMap rewrites = new HashMap(); static HashSet shouldNotIncludeFunction = new HashSet(), shouldNotIncludeClass = new HashSet(); static HashSet doNotIncludeFunction = new HashSet(); static HashSet addedFunctions = new HashSet(); static HashSet addedClasses = new HashSet(); static HashSet hardFunctionReferences = new HashSet(); static boolean quickmainDone1, quickmainDone2; static TreeSet libs = new TreeSet(); static String mainBaseClass; static boolean localStuffOnly; // for transpiling a fragment static class CachedInclude { String javax; Future java; String realJava; 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 { vmKeepWithProgramMD5_get("cachedIncludes"); } catch (Throwable __e) { printStackTrace2(__e); } executor = Executors.newFixedThreadPool(numberOfCores()); transpilingSnippetID = or(getThreadLocal((ThreadLocal) getOpt(javax(), "transpilingSnippetID")), transpilingSnippetID); print("transpilingSnippetID", transpilingSnippetID); Object oldPrint = interceptPrintInThisThread(new F1() { Boolean get(String s) { long now = sysNow(); long time = now-lastPrint; // -startTime; lastPrint = now; print_raw("[" + formatInt(time/1000, 2) + ":" + formatInt(time % 1000, 3) + "] " + s); return false; } }); try { _main(); } finally { interceptPrintInThisThread(oldPrint); executor.shutdown(); executor = null; localStuffOnly = false; } } static void _main() { try { //reTok_modify_check = true; if (useIndexedList) findCodeTokens_debug = true; javaTok_opt = opt_javaTok; findCodeTokens_indexed = findCodeTokens_unindexed = 0; findCodeTokens_bails = findCodeTokens_nonbails = 0; javaTok_n = javaTok_elements = 0; String in = loadMainJava(); print("759 STARTING " + identityHashCode(main.class)); included.clear(); definitions.clear(); rewrites.clear(); definitions.add("SymbolAsString"); shouldNotIncludeFunction.clear(); shouldNotIncludeClass.clear(); doNotIncludeFunction.clear(); addedFunctions.clear(); addedClasses.clear(); hardFunctionReferences.clear(); libs.clear(); mainBaseClass = null; varCount = 0; quickmainDone1 = quickmainDone2 = false; //L ts = findTranslators(toLines(join(tok))); //print("Translators in source at start: " + structure(ts)); // "duplicate" statement - unused /*L lines = toLines(in); call(getJavaX(), "findTranslators", lines); in = fromLines(lines); new Matches m; if (match("duplicate *", in, m)) { // actual copying - unused // tok = jtok(loadSnippet(m.get(0))); // reference by include() in = "m { p { callMain(include(" + quote(m.get(0)) + ")); } }"; }*/ List tok = jtok(in); tok_definitions(tok); // add m { } if (!localStuffOnly && !hasCodeTokens(tok, "m", "{") && !hasCodeTokens(tok, "main", "{") && !hasCodeTokens(tok, "class", "main")) { //tok = jtok(moveImportsUp("m {\n" + in + "\n}")); replaceTokens_reTok(tok, 1, 2, "m {\n\n" + tok.get(1)); replaceTokens_reTok(tok, l(tok)-2, l(tok)-1, tok.get(l(tok)-2) + "}"); tok_moveImportsUp(tok); } // standard translate //ts = findTranslators(toLines(join(tok))); //print("Translators in source: " + structure(ts)); if (tok_hasTranslators(tok)) tok = jtok(defaultTranslate(join(tok))); //print("end of default translate"); //print(join(tok)); //tok_autoCloseBrackets(tok); tok = tok_processIncludes(tok); // before standard functions if (processConceptsDot(tok)) tok = tok_processIncludes(tok); tok = localStuff1(tok); if (!localStuffOnly) { int safety = 0; boolean same; do { String before = join(tok); tok = localStuff1(tok); // shortened method declarations BEFORE standardFunctions jreplace(tok, "svoid", "static void"); jreplace(tok, "void {", "$1 $2() {"); jreplace(tok, "String {", "$1 $2() {"); jreplace(tok, "Object {", "$1 $2() {"); jreplace(tok, "List {", "$1 $2() {"); // do the non-local stuff (flags and rewrites) tok_definitions(tok); tok_ifndef(tok); tok_ifdef(tok); tok_replaceWith(tok); tok_findRewrites(tok); tok_processRewrites(tok); try { if (safety == 0) tok = quickmain(tok); } catch (Throwable e) { printSources(tok); rethrow(e); } // Hack to allow DynModule to reimplement _registerThread /*if (tok.contains("DynModule") && !addedClasses.contains("DynModule")) addStandardClasses_v2(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 = tok_sameTest(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); print("Post."); if (mainBaseClass != null) { jreplace1(tok, "class main", "class main extends " + mainBaseClass); mainBaseClass = null; } print("moveImportsUp"); tok_moveImportsUp(tok); print("Indexing"); tok = indexedList2(tok); // POST-PROCESSING after stdstuff loop if (transpilingSnippetID != null) jreplace_dyn(tok, "class whatever", new Object() { String get(List tok, int cIndex) { try { try { return "class " + stringToLegalIdentifier(getSnippetTitle(transpilingSnippetID)); } catch (Throwable __e) { printStackTrace2(__e); } return "class Whatever"; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "pcall { ret \"class \" + stringToLegalIdentifier(getSnippetTitle(transpilingSni..."; }}); //print("Type"); // Type to Type print("extendClasses"); tok = extendClasses(tok); print("libs"); libs(tok); print("sourceCodeLine"); sourceCodeLine(tok); // escaping for lambdas jreplace(tok, "-=>", "->"); // Stuff that depends on the list of inner classes (haveClasses) HashSet 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")); } expandTriple(tok); } if (hasDef("SymbolAsString")) jreplace(tok, "Symbol", "String"); print("classReferences"); expandClassReferences_lazy(tok, haveClasses); // Error-checking print("Error-checking"); Set functions = new HashSet(findFunctions(tok)); for (String f : hardFunctionReferences) if (!functions.contains(f)) throw fail("Function " + f + " requested, but not supplied"); print("autoImports"); tok = autoImports(tok); // faster to do it at the end print("definitions=" + sfu(definitions)); if (containsOneOfIC(definitions, "allpublic", "reparse")) { boolean dontPrintSource = false; // Fire up the Java parser & pretty printer! print(containsIC(definitions, "allpublic")? "Making all public." : "Reparsing."); try { String src = join(tok); try { if (containsIC(definitions, "keepComments")) src = javaParser_makeAllPublic_keepComments(src); else if (containsIC(definitions, "allpublic")) src = javaParser_makeAllPublic(src); else src = javaParser_reparse_keepComments(src); } catch (Throwable e) { extractAndPrintJavaParseError(src, e); dontPrintSource = true; throw e; } tok = jtok(src); } catch (Throwable e) { String src = join(tok); if (!dontPrintSource) print(src); print(f2s(saveProgramTextFile("error.java", src))); throw rethrow(e); } } if (nempty(libs)) for (String lib : libs) tok.add(concatMap_strings(new F1() { String get(String s) { try { return "\n!" + s ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "\"\\n!\" + s"; }}, libs)); } // if (!localStuffOnly) /*if (useIndexedList) print("Indexed/unindexed lookups: " + findCodeTokens_indexed + "/" + findCodeTokens_unindexed + ", lists made: " + IndexedList2.instances); print("findCodeToken bails: " + findCodeTokens_bails + "/" + findCodeTokens_nonbails); print("javaToks: " + javaTok_n + "/" + javaTok_elements);*/ print("Saving."); if (tok.contains("package")) splitJavaFiles(tok); else saveMainJava(tok); } catch (Exception __e) { throw rethrow(__e); } } static List localStuff1(List tok) { int safety = 0, i; boolean same; tok = indexedList2(tok); do { String before = join(tok); earlyStuff(tok); conceptDeclarations(tok); tok_recordDecls(tok); tok = multilineStrings(tok); tok_singleQuoteIdentifiersToStringConstants(tok); inStringEvals(tok); tok_listComprehensions(tok); tok_doubleFor_v2(tok); forPing(tok); directSnippetRefs(tok); quicknu(tok); //tok_juxtaposeCalls(tok); expandVarCopies(tok); jreplace(tok, "LS", "L"); jreplace(tok, "do ping {", "do { ping();"); replaceKeywordBlock(tok, "swing", "{ swing(r {", "}); }"); replaceKeywordBlock(tok, "tokcondition", "new TokCondition { bool get(final L tok, final int i) {", "}}"); jreplace(tok, "synced ", "synchronized $2"); 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", "{ JWindow _loading_window = showLoadingAnimation(); try {", "} finally { disposeWindow(_loading_window); }}"); replaceKeywordPlusQuotedBlock(tok, "loading", new Object() { String[] get(List tok, int i) { String text = tok.get(i+2); return new String[] { "{ JWindow _loading_window = showLoadingAnimation(" + text + "); try {", "} finally { disposeWindow(_loading_window); }}" }; }}); jreplace(tok, "visualize {", "JComponent visualize() {", tokCondition_beginningOfMethodDeclaration()); jreplace(tok, "start {", "void start() { super.start();", tokCondition_beginningOfMethodDeclaration()); replaceKeywordBlock(tok, "html", "static O html(S uri, fMap params) ctex " + "{\n", "}"); if (assumeTriple) { jreplace(tok, "Triple", "T3"); expandTriple(tok); } tok_shortFinals(tok); jreplace(tok, "static sync", "static synchronized"); jreplace(tok, "sclass", "static class"); jreplace(tok, "srecord", "static 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, "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, "PairS", "Pair"); jreplace(tok, "class > {", "class $2 extends $4 {"); // "on fail {" => "catch (Throwable _e) { ... rethrow(_e); }" replaceKeywordBlock(tok, "on fail", "catch (Throwable _e) {", "\nthrow rethrow(_e); }"); // "catch {" => "catch (Throwable _e) {" jreplace(tok, "catch {", "catch (Throwable _e) {"); // "catch print e {" => "catch e { _handleException(e); " jreplace(tok, "catch print {", "catch $3 { _handleException($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() { boolean get(final List tok, final int i) { String word = tok.get(i+3); return startsWithLowerCaseOrUnderscore(word); }}); jreplace(tok, "+ +", "+", new TokCondition() { 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; }}); // some crazy fancy syntax jreplace(tok, "set ;", "$2 = true;"); // [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); }"); // [concepts] "concept.field!" for dereferencing references jreplace(tok, "*!", "$1.get()", new TokCondition() { boolean get(final List tok, final int i) { String l = tok.get(i+1); if (!(isIdentifier(l) || eq(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; }}); // [concepts] "field := value" for defining fields e.g. in "uniq" while ((i = jfind(tok, " :=")) >= 0) { tok.set(i, quote(tok.get(i))); tok.set(i+2, ","); tok.set(i+4, ""); reTok(tok, i, i+5); } // "quoted" := value while ((i = jfind(tok, " :=")) >= 0) { tok.set(i, tok.get(i)); tok.set(i+2, ","); tok.set(i+4, ""); reTok(tok, i, i+5); } jreplace(tok, "for ( )", "for ($3 $4 : list($3))"); jreplace(tok, "for (final )", "for (final $4 $5 : list($4))"); // "continue unless" while ((i = jfind(tok, "continue unless")) >= 0) { int j = scanOverExpression(tok, getBracketMap(tok), i+4, ";"); replaceTokens(tok, i, i+4, "{ if (!("); tok.set(j, ")) continue; }"); reTok(tok, i, j+1); } // "continue if" while ((i = jfind(tok, "continue if")) >= 0) { int j = scanOverExpression(tok, getBracketMap(tok), i+4, ";"); replaceTokens(tok, i, i+4, "{ if ("); tok.set(j, ") continue; }"); reTok(tok, i, j+1); } // "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); } // "return with " / "continue with " while ((i = jfind(tok, " with", new TokCondition() { boolean get(final List tok, final int i) { return eqOneOf(tok.get(i+1), "return", "continue"); }})) >= 0) { int j = scanOverExpression(tok, getBracketMap(tok), i+4, ";"); tok.set(j, "; " + tok.get(i) + "; }"); replaceTokens(tok, i, i+3, "{"); 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); } // while not null () while ((i = jfind(tok, "while not null (")) >= 0) { int closingBracket = findEndOfBracketPart(tok, i+6)-1; replaceTokens(tok, i+2, i+6, "("); 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 funcname(...) => map(f funcname, ...) // filter funcname(...) => filter(f funcname, ...) // ... jreplace(tok, " (", "$1(f $2,", new Object() { boolean get(List tok, int i) { try { return contains(tok_mapLikeFunctions(), tok.get(i+1)) ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "contains(tok_mapLikeFunctions(), tok.get(i+1))"; }}); // "ref -> bla" for dereferencing Concept.Ref or ThreadLocal or other //jreplace(tok, " ->", "$1.get()."); jreplace(tok, "->", ".get().", new TokCondition() { boolean get(final List tok, final int i) { return empty(tok.get(i+2)) && !(empty(_get(tok, i)) && eq(_get(tok, i-1), "-")); // i-->0; }}); // shortened subconcept declaration (before star constructors!) shortenedSubconcepts(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 {", "});"); unswing(tok); lockBlocks(tok); tempBlocks(tok); // trim x; jreplace(tok, "trim ;", "$2 = trim($2);"); // crazy stuff jreplace (tok, "for over :", "for (int $2 = 0; $2 < l($4); $2++)"); jreplace (tok, "for , over : {", "for (int $2 = 0; $2 < l($7); $2++) { $4 $5 = $7.get($2);"); 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); if (containsToken(tok, "cast")) { // TODO: use tokens String s = join(tok); s = s.replaceAll("(\\w+<[\\w\\s,\\[\\]]+>|\\w+|\\w+\\[\\]|\\w+\\[\\]\\[\\])\\s+(\\w+)\\s*=\\s*cast(\\W[^;]*);", "$1 $2 = ($1) ($3);"); tok = jtok(s); } replaceKeywordBlock(tok, "r-thread-messagebox", "r-thread { pcall-messagebox {", "}}"); replaceKeywordBlock(tok, "thread-messagebox", "thread { pcall-messagebox {", "}}"); jreplace(tok, "rThread {", "r-thread {"); replaceKeywordBlock(tok, "r-thread", "runnableThread(r {", "})"); rNamedThread(tok); replaceKeywordBlock(tok, "r-messagebox", "r { pcall-messagebox {", "}}"); // 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); //print("r contents: " + structure(contents)); replaceTokens(tok, i, j+1, "new Runnable() { public void run() { try { " + tok_addSemicolon(contents) + "\n} catch (Exception __e) { throw rethrow(__e); } }" + (autoQuine ? " public S toString() { return " + quote(shorten(maxQuineLength, trim(join(contents)))) + "; }" : "") + "}"); 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() { boolean get(final List tok, final int i) { return tok_tokenBeforeLonelyReturnValue(_get(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 jreplace(tok, "ok ", "return \"OK\" with $2"); replaceKeywordBlock(tok, "ok", "{", " return \"OK\"; }"); // "myFunction;" instead of "myFunction();" - quite rough cond = new TokCondition() { boolean get(List tok, int i) { String word = tok.get(i+3); //print("single word: " + word); return !litlist("break", "continue", "return", "else").contains(word); } }; for (String pre : litlist("}", ";")) jreplace(tok, pre + " ;", "$1 $2();", cond); // shorter match syntax for answer methods jreplace(tok, "if || ", "if (matchOneOf(s, m, $2, $5))"); // "...bla..." jreplace(tok, "if ", "if (find3plusRestsX($2, s, m))", new TokCondition() { 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() { boolean get(final List tok, final int i) { return unquote(tok.get(i+3)).endsWith("..."); }}); // "bla * bla | blubb * blubb" jreplace_dyn(tok, "if ", new Object() { Object get(List tok, int 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 (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() { boolean get(final List tok, final int i) { return javaTokC(unquote(tok.get(i+3))).contains("|"); }}); // "bla" jreplace(tok, "if ", "if (match($2, s))", new TokCondition() { 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))"); // extra commas ("litlist(1, 2,)") jreplace(tok, ",)", ")"); // additional translations (if necessary) jreplace(tok, "pcall ping {", "pcall { ping();"); replaceKeywordBlock(tok, "pcall", "try {", "} catch (Throwable __e) { _handleException(__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, "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); } 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" { replaceKeywordPlusQuotedBlock(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() { 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 {", "}}"); namedThreads(tok); threads(tok); // try answer (string, test with nempty) while ((i = findCodeTokens(tok, "try", "answer")) >= 0) { int j = findEndOfStatement(tok, i); String v = makeVar("a"); tok.set(i, "{ S " + v); tok.set(i+2, "="); tok.set(j-1, "; if (!empty(" + v + ")) ret " + v + "; }"); 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("a"); tok.set(i, "{ Bool " + v); tok.set(i+2, "="); tok.set(j-1, "; if (" + v + " != null) ret " + v + "; }"); reTok(tok, i, j); } // return optional (return if not null) while ((i = jfind(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) while ((i = jfind(tok, "try object")) >= 0) { int j = findEndOfStatement(tok, i); String v = makeVar(); clearTokens(tok, i, i+3); tok.set(i, "{ O " + v + "="); 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); quicknew2(tok); tok_unpair(tok); tok_cachedFunctions(tok); throwFailEtc(tok); tok_typeAA(tok); // do this after expanding sclass etc. tok = expandStarConstructors(tok); tok_kiloConstants(tok); // end of localStuff1 same = tok_sameTest(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(tok, i, j, "localStuff1"); } 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); //print('starConstructors); tok = expandStarConstructors(tok); // drop Java 8 annotations since we're compiling for Java 7 jreplace(tok, "@Nullable", ""); // STANDARD CLASSES & INTERFACES print("standard classes"); final Set haveClasses = addStandardClasses_v2(tok); tok_quickInstanceOf(tok, haveClasses); // concept-related stuff // auto-import concepts boolean _a = tok_hasClassRef2(tok, /*"extends",*/ "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)); throw 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(t))); } return tok; } static void 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, inStringEval(t)); change = true; } } if (change) reTok(tok); } static String 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) + "\""); l.add("(" + trim(substring(t, idx+2, j)) + ")"); t = substring(t, j+2); } if (nempty(t)) l.add("\"" + t + "\""); return "(" + join(" + ", l) + ")"; } 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(tok, i, "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) { return "_" + name + "_" + varCount++; } static String makeVar() { return makeVar(""); } /*static L standardFunctions(L tok) { ret rtq(tok, "#1002474"); }*/ 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); } // O = Object, S = String, ret = return for (int i = 1; i < tok.size(); i += 2) { String t = tok.get(i); if (t.equals("O")) t = "Object"; if (t.equals("S")) t = "String"; else if (t.equals("L")) t = "List"; //else if (t.equals("F")) t = "Function"; else if (t.equals("ret") && neqOneOf(get(tok, i+2), "=", ")", ".")) t = "return"; else if (t.equals("bool") && i+2 < tok.size() && neq(tok.get(i+2), "(")) t = "boolean"; // bool -> boolean if it's not a function name tok.set(i, t); } jreplace(tok, "LL< >", "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 String[] standardImports = { "java.util.*", "java.util.zip.*", "java.util.List", "java.util.regex.*", "java.util.concurrent.*", "java.util.concurrent.atomic.*", "java.util.concurrent.locks.*", "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.*", "javax.imageio.*", "java.math.*" }; static List expandStarConstructors(List tok) { mainLoop: for (int i = 3; i+6 < tok.size(); i += 2) { String t = tok.get(i), l = tok.get(i-2); if (!t.equals("*")) continue; if (!tok.get(i+2).equals("(")) continue; if (!eqOneOf(l, "}", "public", "private", "protected", ";", "{", "endif") && neq(get(tok, i-4), "ifclass")) // is this correct...?? 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; } while (j > 0) { t = tok.get(j); if (t.equals("class")) { String 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; int block = j+1; for (int k = i+2; k < block-1; k += 2) if (tok.get(k).equals("*")) { tok.remove(k); tok.remove(k); 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 List tok_processIncludes(List tok) { int safety = 0; while (hasCodeTokens(tok, "!", "include") && ++safety < 100) tok = tok_processIncludesSingle(tok); //tok_autoCloseBrackets(tok); return tok; } static List tok_processIncludesSingle(List tok) { int i; while ((i = jfind(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); } while ((i = jfind(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; } static void ctex(List tok) { replaceKeywordBlock(tok, "ctex", "{ try {", "} catch (Exception __e) { throw rethrow(__e); } }"); replaceKeywordBlock(tok, "null on exception", "{ try {", "} catch (Throwable __e) { return null; } }"); replaceKeywordBlock(tok, "false on exception", "{ try {", "} catch (Throwable __e) { return false; } }"); } static List dialogHandler(List tok) { return replaceKeywordBlock(tok, "dialogHandler", "new DialogHandler() {\n" + "public void run(final DialogIO io) {", "}}"); } static void quicknew2(List tok) { jreplace(tok, "new ;", "$2 $3 = new $2;"); jreplace(tok, "new <> ;", "$2<$4> $6 = new $2;"); jreplace(tok, "new <> , ;", "$2<$4> $6 = new $2, $8 = new $2;"); jreplace(tok, "new <,> ;", "$2<$4,$6> $8 = new $2;"); jreplace(tok, "new <<>> ;", "$2 $3 $4 $5 $6 $7 $8 $9 = new $2;"); jreplace(tok, "new <[]> ;", "$2 $3 $4 $5 $6 $7 $8 = new $2;"); jreplace(tok, "new < <>, > ;", "$2 $3 $4 $5 $6 $7 $8 $9 $10 $11 = new $2;"); jreplace(tok, "new < <,> > ;", "$2 $3 $4 $5 $6 $7 $8 $9 $10 $11 = new $2;"); jreplace(tok, "new < , <> > ;", "$2 $3 $4 $5 $6 $7 $8 $9 $10 $11 = new $2;"); jreplace(tok, "new < <,,> > ;", "$2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 = new $2;"); jreplace(tok, "new < <,>, > ;", "$2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 = new $2;"); // [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); jreplace1(tok, "new ", "new $2()", new TokCondition() { boolean get(final List tok, final int i) { return eqOneOf(_get(tok, i+5), "{", ",", ")", ";", ":"); }}); jreplace1(tok, "new < >", "new $2<$4>()", new TokCondition() { boolean get(final List tok, final int i) { return eqOneOf(_get(tok, i+11), "{", ",", ")", ";", ":"); }}); 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 jreplace(tok, " = new", "$1 $2 = new $1", new TokCondition() { boolean get(final List tok, final int i) { return eqOneOf(_get(tok, i+9), "(", ";", ",", ")"); }}); jreplace(tok, " = new \\*", "$1 $2 = new $1"); jreplace(tok, "\\* = new ", "$5 $2 = new $5"); jreplace(tok, "<> = new", "$1 $2 $3 $4 $5 = new $1", new TokCondition() { boolean get(final List tok, final int i) { return eqOneOf(_get(tok, i+9+3*2), "(", ";", ",", ")"); }}); jreplace(tok, "<,> = new", "$1 $2 $3 $4 $5 $6 $7 = new $1", new TokCondition() { boolean get(final List tok, final int i) { return eqOneOf(_get(tok, i+9+5*2), "(", ";", ",", ")"); }}); } 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 = join(subList(tok, idx+1, j-1)); List c = findInnerClassOfMain(tok, className); print("Extending class " + className); clearTokens(tok.subList(i, j+1)); if (c == null) { print("Warning: Can't extend class " + className + ", not found"); continue; } int startOfClass = indexOfSubList(tok, c); // magicIndexOfSubList is broken 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", "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(join(subList(tok, 0, i)), '\n')+1)); reTok(tok, i, i+5); } } // done before any other processing static void earlyStuff(List tok) { int i; tok_scopes(tok); 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(join(subList(tok, idx+1, j-1))) + ", "); reTok(tok, i, idx+1); } // func keyword for lambdas - now automatically quines toString() if enabled // 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(join(subList(tok, argsTo+6, idx-1))); String toString = autoQuine ? " public S toString() { ret " + quote(shorten(maxQuineLength, trim(join(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) <= 2) type = "F" + l(types) + "<" + joinWithComma(types) + ", " + returnType + ">"; String body = tok_addReturn(contents); replaceTokens_reTok(tok, i, j, "new " + type + "() { " + 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); List args = cloneSubList(tok, argsFrom-1, argsTo); tok_shortFinals(args); tok_toNonPrimitiveTypes(args); List types = tok_typesOfParams(args); Object type = "O"; if (l(types) <= 2) 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(maxQuineLength, trim(join(contents)))) + "; }" : "") + "}"); reTok(tok, i, j); } jreplace(tok, "func {", "func -> O {"); jreplace(tok, "f {", "f -> O {"); for (String keyword : ll("f", "func")) { while ((i = jfind(tok, keyword + " ->")) >= 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(join(subList(tok, i+6, idx-1))); List contents = subList(tok, idx+1, j-1); replaceTokens(tok, i, j, "new F0<" + returnType + ">() { " + returnType + " get() ctex { " + tok_addReturn(contents) + " }\n" + (autoQuine ? " public S toString() { ret " + quote(shorten(maxQuineLength, trim(join(contents)))) + "; }" : "") + "}"); reTok(tok, i, j); } } } 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") && eq(get(tok, i+4), "(") && !eqOneOf(get(tok, i), "throw", "RuntimeException", "return", "f", "function")) { 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 var = "_t_" + i; String pre = "{ Thread " + var + " = new Thread(" + tName + ") {\n" + "public void run() { pcall {\n"; String post = "} }\n};\n" + "startThread(" + var + "); }"; 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) { for (boolean daemon : litlist(false, true)) for (int i = 0; i < 100; i++) { int idx = findCodeTokens(tok, daemon ? "daemon" : "thread", "{"); if (idx < 0) break; int j = findEndOfBracketPart(tok, idx+2); String var = "_t_" + i; String pre = "{ Thread " + var + " = new Thread() {\n" + "public void run() { pcall\n"; String post = "} }\n};\n" + (daemon ? var + ".setDaemon(true);\n" : "") + "startThread(" + var + "); }"; tok.set(idx, pre); tok.set(j-1, post); reTok(tok, idx, j); } } static Map sf; 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]); } } for (int i = 0; ; i++) { 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(tok.subList(j, j+12)); } while ((j = jfind(tok, "do not include function *.")) >= 0) { String fname = tok.get(j+8); doNotIncludeFunction.add(fname); clearAllTokens(tok.subList(j, j+12)); } doNotIncludeFunction.addAll(tok_importedStaticFunctionNames(tok)); // changes tok Set invocations = findFunctionInvocations(tok, sf, hardFunctionReferences, defd); /*if (invocations.contains("str")) print("==STR==" + join(tok) + "==STR==");*/ if (!cic(definitions, "leanMode")) invocations.addAll(functionsToAlwaysInclude); //print("Functions invoked: " + structure(invocations)); List needed = diff(invocations, defd); for (String f : doNotIncludeFunction) needed.remove(f); if (needed.isEmpty()) break; print("Adding functions: " + join(" " , needed)); HashSet neededSet = new HashSet(needed); Collection bad = setIntersection(neededSet, shouldNotIncludeFunction); if (nempty(bad)) { String msg = "INCLUDING BAD FUNCTIONS: " + sfu(bad); print(msg); print(join(tok)); throw fail(msg); } List added = new ArrayList(); List < Future < String > > parts = new ArrayList(); List preload = new ArrayList(); for (String x : needed) if (sf.containsKey(x)) preload.add(sf.get(x)); cachePreload(preload); for (String x : cloneList(needed)) { if (defd.contains(x)) continue; String id = sf.get(x); if (id == null) { print("Standard function " + x + " not found."); needed.remove(x); continue; } //print("Adding function: " + x + " (" + id + ")"); String function = cacheGet(id); //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()); //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() { return join(localStuff1(jtok(_function))); } }); ci.realJava = null; } parts.add(ci.javaFuture()); } else parts.add(nowFuture(function + "\n")); added.add(x); Collection newFunctions = new HashSet(findFunctionDefs(javaTok(function))); defd.addAll(newFunctions); for (String f : newFunctions) if (!addedFunctions.add(f)) { printSources(tok); throw fail("Trying to add function " + f + " again - main class syntax broken!"); } } String text = join(getAllFutures(parts)); if (cacheStdFunctions) tok = includeInMainLoaded_stdReTok(tok, text); else 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)); tok_definitions(tok); tok_ifndef(tok); tok_ifdef(tok); if (i >= 1000) throw fail("Too many iterations"); } return tok; } static List findFunctions(List tok) { //ret findFunctionDefinitions(join(findMainClass(tok))); return findFunctionDefs(findMainClass(tok)); } static String cacheGet(String snippetID) { snippetID = formatSnippetID(snippetID); String text = snippetCache.get(snippetID); if (text == null) { snippetCache.put(snippetID, text = loadSnippet(snippetID)); if (hasUnclosedStringLiterals(text)) throw fail("Unclosed string literals in " + snippetID); } return text; } static void cachePreload(Collection ids) { List needed = new ArrayList(); for (String id : 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) { List l = javaTok(s); return useIndexedList ? new IndexedList2(l) : l; } 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) { have.addAll(tok_importedClassNames(tok)); have.addAll(usualJavaClassNames()); // for S => S.class return have; } // works on Java level (no "sclass" etc) // returns list of classes we have (useful for other processing) static Set addStandardClasses_v2(List tok) { if (lclasses == null) { String sc = cacheGet("#1003674"); lclasses = new ArrayList(); for (String line : tlft_j(sc)) { int idx = line.indexOf('/'); lclasses.addAll(ll(line.substring(0, idx), line.substring(idx+1))); } } List definitions = lclasses; for (int safety = 0; safety < 10; safety++) { HashSet have = haveClasses_actual(tok); have.addAll(tok_importedClassNames(tok)); int j; while ((j = jfind(tok, "should not include class *.")) >= 0) { String cname = tok.get(j+8); shouldNotIncludeClass.add(cname); clearAllTokens(tok.subList(j, j+12)); } Map need = new HashMap(); Set idx = tokenIndexWithoutIfclass_forStdClasses(tok); for (int i = 0; i+1 < l(definitions); i += 2) { String className = definitions.get(i); if (idx.contains(className) && !have.contains(className)) need.put(className, definitions.get(i+1)); } if (hasDef("SymbolAsString")) { print("Have SymbolAsString."); if (need.containsKey("Symbol")) { print("Have Symbol."); need.remove("Symbol"); } } else print("No SymbolAsString."); 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)); StringBuilder buf = new StringBuilder(); print("Adding classes: " + joinWithSpace(keys(need))); for (String className : keys(need)) { if (have.contains(className)) continue; // intermittent add String snippetID = need.get(className); //print("Adding class " + className + " / " + snippetID); snippetID = fsI(snippetID); String text = cacheGet(snippetID); assertTrue(cacheStdClasses); long _id = psI(snippetID); CachedInclude ci = cachedIncludes.get(_id); if (ci == null) cachedIncludes.put(_id, ci = new CachedInclude()); if (neq(ci.javax, text)) { print("Compiling class: " + className); ci.javax = text; ci.java = null; ci.realJava = join(localStuff1(jtok(text))); } buf.append(ci.java()); List ct = javaTok(ci.java()); for (List c : allClasses(ct)) { String name = getClassDeclarationName(c); have.add(name); } if (!have.contains(className)) throw fail("Wrongly defined class: " + className + " / " + snippetID); if (!addedClasses.add(className)) { printSources(tok); throw fail("Trying to add class " + className + " again - main class syntax broken!"); } } // for className tok = includeInMainLoaded_stdReTok(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 boolean expandClassReferences_lazy(List tok, Set classNames) { boolean change = false; 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); if (eqOneOf(s, "instanceof", "new", ".", "<", ">", "/", "nu")) continue; if (isIdentifier(s) || isInteger(s)) continue; if (eq(get(tok, i+4), ",") && isIdentifier(get(tok, i+6)) && eqGet(tok, i+8, ">")) continue; // e.g. T3, S, S> if (eq(s, ",") && isIdentifier(get(tok, i-4)) && eqGet(tok, i-6, "<")) continue; // e.g. T3 if (eq(s, ",") && eqOneOf(_get(tok, i-6), "implements", "throws")) continue; // TODO: longer lists // 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; } } if (eqOneOf(t, ",", ")", ";", ":")) { tok.set(i, tok.get(i) + ".class"); change = true; } } } return change; } static void expandClassReferences(List tok, Set classNames) { if (expandClassReferences_lazy(tok, classNames)) reTok(tok); } // "/" => "((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) + ")"); } // experimental - "(...)" => "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) { jreplace(tok, "(", "new $1(", new TokCondition() { boolean get(final List tok, final int i) { if (!classNames.contains(tok.get(i+1))) return false; boolean ok = neqOneOf(_get(tok, i-1), "new", ";", "}", "{", "public", "protected", "private", "."); //print("newWithoutNew: checking " + struct(subList(tok, i-1, i+2)) + " => " + ok); return ok; }}); } // +var => "var", +var static void expandVarCopies(List tok) { boolean change = false; 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) + ", "); change = true; } if (change) reTok(tok); } 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 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 (!vars.contains("_fieldOrder") && !isSortedList(vars)) { print("Adding field order"); tok.set(idx+2, "static String _fieldOrder = " + quote(join(" ", vars)) + ";\n " + tok.get(idx+2)); // reTok has to be done by caller } } 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))) 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; jreplace_dyn(tok, "f-thread ", new Object() { Object get(List tok, int 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() { boolean get(final List tok, final int i) { return !eq(tok.get(i+3), "instanceof"); }})) >= 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 fname => r { fname() } // rThread fname => rThread { fname() } while ((i = jfindOneOf_cond(tok, new TokCondition() { boolean get(final List tok, final int i) { return !eq(tok.get(i+3), "instanceof"); }}, "r ", "rThread ")) >= 0) { String f = tok.get(i+2); replaceTokens(tok, i, i+3, tok.get(i) + " { " + f + "(); }"); reTok(tok, i, i+3); } } // # 123 => "#123" static void directSnippetRefs(List tok) { int i; while ((i = jfind(tok, "#", new TokCondition() { 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); } } static void quicknu(List tok) { jreplace(tok, "nu (", "nu($2.class, "); jreplace(tok, "nu ", "new $2"); } // fill variable innerClasses_list static void innerClassesVar(List tok, Set have) { if (!tok.contains("myInnerClasses_list")) return; int i = jfind(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) { if (!tok.contains("myTranspilationDate_value")) return; int i = jfind(tok, "long myTranspilationDate_value;"); if (i < 0) return; tok.set(i+4, " = " + now() + "L;"); reTok(tok, i+4, i+5); } // process ifclass x ... endif blocks static void tok_ifclass(List tok, Set have) { if (!tok.contains("ifclass")) return; int i; while ((i = rjfind(tok, "ifclass ")) >= 0) { int j = jfind(tok, i+4, "endif"); if (j < 0) j = l(tok)-1; String name = tok.get(i+2); boolean has = have.contains(name); //print("ifclass " + name + " => " + has); clearTokens(tok, i, i+3); clearTokens(tok, j, j+1); if (!has) clearTokens(tok, i+3, j); reTok(tok, i, j+1); } } // set flag *. static void tok_definitions(List tok) { int i; while ((i = jfind(tok, "set flag .")) >= 0) { String fname = tok.get(i+4); print("Setting flag " + fname); definitions.add(fname); clearAllTokens(tok.subList(i, i+8)); } while ((i = jfind(tok, "unset flag .")) >= 0) { String fname = tok.get(i+4); print("Unsetting flag " + fname); definitions.remove(fname); clearAllTokens(tok.subList(i, i+8)); } } static void tok_findRewrites(List tok) { int i; while ((i = jfind(tok, "rewrite =")) >= 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); rewrites.put(token, replacement); print("Have rewrite: " + token + " => " + replacement); } } 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) { if (!tok.contains("ifndef")) return; int i; while ((i = rjfind(tok, "ifndef ")) >= 0) { int j = jfind(tok, i+4, "endifndef"); if (j < 0) j = l(tok)-1; String fname = tok.get(i+2); boolean has = !definitions.contains(fname); //print("ifndef " + fname + " => " + has); clearTokens(tok, i, i+3); clearTokens(tok, j, j+1); if (!has) clearTokens(tok, i+3, j); reTok(tok, i, j+1); } } // process ifdef x ... endifdef blocks static void tok_ifdef(List tok) { if (!tok.contains("ifdef")) return; int i; while ((i = rjfind(tok, "ifdef ")) >= 0) { int j = jfind(tok, i+4, "endifdef"); if (j < 0) j = l(tok)-1; String fname = tok.get(i+2); boolean has = definitions.contains(fname); //print("ifdef " + fname + " => " + has); clearTokens(tok, i, i+3); clearTokens(tok, j, j+1); if (!has) clearTokens(tok, i+3, j); reTok(tok, i, j+1); } } static void conceptDeclarations(List tok) { for (String kw : ll("concept", "sconcept")) { Object cond = new TokCondition() { boolean get(final List tok, final int i) { addFieldOrder(tok, i+1); return true; }}; boolean re = false; if (jreplace(tok, kw + " {", "static class $2 extends Concept {", cond)) re = true; if (jreplace(tok, kw + " implements", "static class $2 extends Concept implements", cond)) re = true; if (jreplace(tok, kw + " ", "static class $2", cond)) re = true; if (re) reTok(tok); } } static void shortenedSubconcepts(List tok) { jreplace(tok, " > {", "concept $3 extends $1 {", new TokCondition() { 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() { 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; while ((i = jfind(tok, "temp ")) >= 0) { int semicolon = findEndOfStatement(tok, i)-1; int endOfOuterBlock = findEndOfBracketPart(tok, semicolon)-1; List sub = subList(tok, i-1, semicolon); int eq = subList(sub, 0, smartIndexOf(sub, "{")).indexOf("="); String var; if (eq >= 0) var = sub.get(eq-2); else { // no var name, e.g. temp newThoughtSpace(); var = makeVar(); tok.set(i+2, "AutoCloseable " + var + " = " + tok.get(i+2)); } //tok.set(i, "try ("); //tok.set(semicolon, ") {"; //tok.set(endOfOuterBlock, "}}"); tok.set(i, ""); tok.set(semicolon, "; try {"); tok.set(endOfOuterBlock, "} finally { _close(" + var + "); }}"); reTok(tok, i, endOfOuterBlock+1); } } static void cleanMeUp() { for (CachedInclude ci : values(cachedIncludes)) ci.clean(); vmKeepWithProgramMD5_save("cachedIncludes"); } static void printSources(List tok) { print("----"); print(join(tok)); print("----"); } static void tok_typeAA(List tok) { int n = l(tok)-6; boolean change = false; for (int i = 1; i < l(tok); i += 2) { if (!(eq(get(tok, i+2), "<") && contains(pairClasses, tok.get(i)))) 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; } } //if (change) reTok(tok); /* O cond = tokcondition { pairClasses.contains(tok.get(i+1)) }; jreplace(tok, " < >", "$1<$3, $3>", cond); jreplace(tok, " < <> >", "$1<$3<$5>, $3<$5>>", cond); jreplace(tok, " < <,> >", "$1<$3<$5,$7>, $3<$5,$7>>", cond); */ } static void tok_quickInstanceOf(List tok, final Set haveClasses) { // "x << X" or "x >> X" => "x instanceof X" for (String op : ll("<<", ">>")) jreplace(tok, " " + op + " ", "$1 instanceof $4", new TokCondition() { boolean get(final List tok, final int i) { return haveClasses.contains(tok.get(i+7)) && !eqOneOf(tok.get(i-1), "<", "extends", "implements"); }}); } static boolean hasDef(String s) { return definitions.contains(s); } static void expandTriple(List tok) { jreplace(tok, "T3< >", "T3<$3, $3, $3>"); jreplace(tok, "T3< <> >", "T3<$3<$5>, $3<$5>, $3<$5>>"); } 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 List> innerClassesOfMain(List tok) { return innerClasses(findMainClass(tok)); } static List> innerClassesOfMain(String src) { return innerClassesOfMain(javaTok(src)); } static String joinQuoted(String sep, Collection c) { List l = new ArrayList(); for (String s : c) l.add(quote(s)); return join(sep, l); } static void extractAndPrintJavaParseError(String src, Throwable e) { print(); String msg = firstLine(innerMessage(e)); print(msg); int line = parseIntOpt(regexpFirstGroupIC("line (\\d+)", msg)); print(); if (line != 0) { List lines = lines(src); for (int i = max(0, line-5); i <= min(l(lines), line+5); i++) print((i == line ? "* " : " ") + "LINE " + i + ": " + lines.get(i-1)); } print(); } 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 == '\0') out.append("\\0"); else out.append(c); } out.append('"'); } 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 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); } // 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 String getClassDeclarationName(List c) { if (c != null) for (int i = 1; i+2 < c.size(); i += 2) if (allClasses_keywords.contains(c.get(i))) return c.get(i+2); return null; } 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 List diff(Collection a, Collection b) { Set set = asSet(b); List l = new ArrayList(); for (String s : a) if (!set.contains(s)) l.add(s); return l; } static boolean tok_isSingleTypeArg(List tok, int iOpeningBracket) { int iClosingBracket = findEndOfTypeArgs(tok, iOpeningBracket)-1; if (iClosingBracket == iOpeningBracket+4) return true; if (eq(get(tok, iOpeningBracket+4), "<")) { int j = findEndOfTypeArgs(tok, iOpeningBracket+4); return j == iClosingBracket-1; } return false; // hmm } static String str(Object o) { return o == null ? "null" : o.toString(); } static String str(char[] c) { return new String(c); } // It's rough but should work if you don't make anonymous classes inside the statement or something... // 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. while (j < l(tok) && neq(tok.get(j), ";")) if (eq(get(tok, j), "{")) j = findEndOfBlock(tok, j)+1; else j += 2; return j+1; } static boolean contains(Collection c, Object o) { return c != null && c.contains(o); } 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); } // 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 Set tok_mapLikeFunctions_set = asHashSet( splitAtSpace("map mapLL filter concatMap pairMap antiFilter")); static Set tok_mapLikeFunctions() { return tok_mapLikeFunctions_set; } // before you use this, add a RAM disk cleaner static boolean javaCompileToJar_useRAMDisk; static File javaCompileToJar_optionalRename(String src, File destJar, String progID) { return javaCompileToJar_optionalRename(src, "", destJar, progID); } // returns path to jar static synchronized File javaCompileToJar_optionalRename(String src, String dehlibs, File destJar, String progID) { String javaTarget = null; // use default target //print("Compiling " + l(src) + " chars"); String dummyClass = "main"; if (progID != null) { dummyClass = dummyMainClassName(progID); 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 className = "main"; String fileName = dummyClass + ".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 = new ArrayList(); Matcher m = Pattern.compile("\\d+").matcher(dehlibs); while (m.find()) { String libID = m.group(); //print("libID=" + quote(libID)); assertTrue(isSnippetID(libID)); libraries.add(loadLibrary(libID)); } libraries.add(pathToJavaxJar()); String compilerOutput; try { compilerOutput = (String) call(j, "compileJava", srcDir, libraries, classesDir); } catch (Throwable e) { compilerOutput = (String) get(getJavaX(), "javaCompilerOutput"); throw fail("Compile Error. " + compilerOutput + " " + e); } if (nempty(compilerOutput)) { print("Compiler said: " + compilerOutput); //fail("Compile Error. " + compilerOutput); } // sanity test if (!new File(classesDir, className + ".class").exists()) throw fail("No class generated (" + className + ")"); // 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); //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); } } // 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; } // TODO: extended multi-line strings static int javaTok_n, javaTok_elements; static boolean javaTok_opt; static List javaTok(String s) { ++javaTok_n; 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 // 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)) || "'".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)); ++n; 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 tok_kiloConstants(List tok) { if (!tok.contains("K")) return; jreplace(tok, " K", "($1*1024)"); } static String joinWithComma(Collection c) { return join(", ", c); } static String joinWithComma(String... c) { return join(", ", c); } 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 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)); } // 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; } static int jfindOneOf(List tok, String... patterns) { for (String in : patterns) { int i = jfind(tok, in); if (i >= 0) return i; } return -1; } static List reversedList(Collection l) { List x = cloneList(l); Collections.reverse(x); return x; } static List subList(List l, int startIndex) { return subList(l, startIndex, l(l)); } static List subList(List l, int startIndex, int endIndex) { startIndex = Math.max(0, Math.min(l(l), startIndex)); endIndex = Math.max(0, Math.min(l(l), endIndex)); if (startIndex > endIndex) return litlist(); return l.subList(startIndex, endIndex); } static Map cloneMap(Map map) { if (map == null) return litmap(); // assume mutex is equal to collection synchronized(map) { return map instanceof TreeMap ? new TreeMap((TreeMap) map) // copies comparator : map instanceof LinkedHashMap ? new LinkedHashMap(map) : new HashMap(map); } } 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 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 = i & ~1; j = j | 1; List t = javaTok(join(subList(tok, i, j))); replaceListPart(tok, i, j, t); // fallback to safety // reTok(tok); return tok; } 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(Map m) { return m == null ? 0 : m.size(); } static int l(CharSequence s) { return s == null ? 0 : s.length(); } static long l(File f) { return f == null ? 0 : f.length(); } static int l(Object o) { return o == null ? 0 : o instanceof String ? l((String) o) : o instanceof Map ? l((Map) o) : o instanceof Collection ? l((Collection) o) : o instanceof Object[] ? l((Object[]) o) : (Integer) call(o, "size"); } static int l(MultiSet ms) { return ms == null ? 0 : ms.size(); } static String getServerTranspiled2(String id) { String transpiled = loadCachedTranspilation(id); String md5 = null; if (isOfflineMode()) return transpiled; if (transpiled != null) md5 = md5(transpiled); String transpiledSrc = getServerTranspiled(formatSnippetID(id), md5); if (eq(transpiledSrc, "SAME")) { if (!isTrue(loadPage_silent.get())) print("SAME"); return transpiled; } return transpiledSrc; } // 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 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, A... b) { return c != null && c.addAll(Arrays.asList(b)); } // 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 boolean includeInMainLoaded_safe; static List includeInMainLoaded(List tok, String text) { List main = findMainClass(tok); if (main == null) { print(join(tok)); throw fail("no main class"); } int i = main.lastIndexOf("}"); main.set(i, "\n" + text + "\n}"); i += magicIndexOfSubList(tok, main); return includeInMainLoaded_safe ? includeInMainLoaded_reTok(tok, 0, l(tok)) : includeInMainLoaded_reTok(tok, i, i+1); } static void tok_p_old(List tok) { 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); } // 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 format3(String pat, Object... args) { if (args.length == 0) return pat; List tok = javaTokPlusPeriod(pat); int argidx = 0; for (int i = 1; i < tok.size(); i += 2) if (tok.get(i).equals("*")) tok.set(i, format3_formatArg(argidx < args.length ? args[argidx++] : "null")); return join(tok); } static String format3_formatArg(Object arg) { if (arg == null) return "null"; if (arg instanceof String) { String s = (String) arg; return isIdentifier(s) || isNonNegativeInteger(s) ? s : quote(s); } if (arg instanceof Integer || arg instanceof Long) return String.valueOf(arg); return quote(structure(arg)); } static String sfu(Object o) { return structureForUser(o); } 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 HashSet allClasses_keywords = lithashset("class", "interface", "enum", "sclass"); // 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(); for (int i = 1; i < tok.size(); i += 2) { if (eq(tok.get(i), "{")) // skip functions i = findEndOfBlock(tok, i)-1; else if (allClasses_keywords.contains(tok.get(i)) && (i == 1 || !tok.get(i-2).equals("."))) { int j = i; while (j < tok.size() && !tok.get(j).equals("{")) j += 2; j = findEndOfBlock(tok, j)+1; i = leftScanModifiers(tok, i); l.add(tok.subList(i-1, Math.min(tok.size(), j))); i = j-2; } } return l; } static List> allClasses(String text) { return allClasses(javaTok(text)); } static boolean empty(Collection c) { return c == null || c.isEmpty(); } static boolean empty(CharSequence s) { return s == null || s.length() == 0; } static boolean empty(Map map) { return map == null || map.isEmpty(); } static boolean empty(Object[] o) { return o == null || o.length == 0; } static boolean empty(Object o) { if (o instanceof Collection) return empty((Collection) o); if (o instanceof String) return empty((String) o); if (o instanceof Map) return empty((Map) o); if (o instanceof Object[]) return empty((Object[]) o); if (o instanceof byte[]) return empty((byte[]) o); if (o == null) return true; throw fail("unknown type for 'empty': " + getType(o)); } static boolean empty(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(MultiSet ms) { return ms == null || ms.isEmpty(); } static boolean isInteger(String s) { if (s == null) return false; 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 Class javax() { return getJavaX(); } // 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 String formatSnippetID(String id) { return "#" + parseSnippetID(id); } static String formatSnippetID(long id) { return "#" + id; } static boolean containsToken(List tok, String token) { return tok.contains(token); } 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 vmKeepWithProgramMD5_get(String varName) { String struct = (String) ( callOpt(javax(), "vmKeep_get", programID(), md5OfMyJavaSource(), varName)); if (struct != null) setOpt(mc(), varName, unstructure(struct)); } static Set usualJavaClassNames_set = asHashSet(javaTokC("\r\n String Object Map List Integer Long Collection File Component JComponent JButton\r\n JCheckBox Float JTextArea\r\n")); static Set usualJavaClassNames() { return usualJavaClassNames_set; } 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 int last(int[] 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 long psI(String snippetID) { return parseSnippetID(snippetID); } 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 boolean eq(Object a, Object b) { return a == null ? b == null : a == b || a.equals(b); } static void clearTokens(List tok) { clearAllTokens(tok); } static void clearTokens(List tok, int i, int j) { clearAllTokens(tok, i, j); } static void tokSet(List tok, int idx, String token) { tok.set(idx, token); reTok(tok, idx); } static HashSet lithashset(A... items) { HashSet set = new HashSet(); for (A a : items) set.add(a); return set; } static List splitAtJavaToken(String s, String splitToken) { return splitByJavaToken(s, splitToken); } static String defaultTranslate(String text) { Class javax = getJavaX(); File x = makeTempDir(); saveTextFile(new File(x, "main.java"), text); List libraries_out = new ArrayList(); File y = (File) call(javax, "defaultTranslate", x, libraries_out); if (y == null) return null; return loadTextFile(new File(y, "main.java")); } static List tok_typesOfParams(List tok) { try { List types = new ArrayList(); for (int i = 1; i < l(tok); ) { String t = tok.get(i); if (eq(t, "final")) t = get(tok, i += 2); assertTrue(isIdentifier(t)); i += 2; String type = t; while (eq(get(tok, i), ".")) { type += "." + assertIdentifier(get(tok, i+2)); i += 4; } // 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 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 A _get(A[] l, int idx) { return idx >= 0 && idx < l(l) ? l[idx] : null; } static boolean cic(Collection l, String s) { return containsIgnoreCase(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 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 A printStruct(String prefix, A a) { printStructure(prefix, a); return a; } static A printStruct(A a) { printStructure(a); return a; } // optionally convert expression to return statement static String tok_addReturn(List tok) { String lastToken = get(tok, l(tok)-2); //print("addReturn: " + structure(tok) + ", lastToken: " + quote(lastToken)); if (eq(lastToken, "}") || eq(lastToken, ";")) return join(tok); return "ret " + join(tok) + ";"; } static String tok_addReturn(String s) { return tok_addReturn(javaTok(s)); } static void tok_replaceWith(List tok) { int i; while ((i = jfind(tok, "replace with")) >= 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); print("Replacing " + token + " with " + replacement + "."); int end = findEndOfBlock(tok, repEnd)-1; for (int j = repEnd+2; j < end; j += 2) if (eq(tok.get(j), token)) tok.set(j, replacement); reTok(tok, i, end); } } 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); jreplace1(tok, in, out, condition); return join(tok); } // 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); if (reTok) // would this ever be false?? reTok(tok, i, end); i = end; anyChange = true; } return anyChange; } static boolean jreplace1_debug; static boolean eqGet(List l, int i, Object o) { return eq(get(l, i), o); } static NavigableSet navigableKeys(NavigableMap map) { return map == null ? new TreeSet() : map.navigableKeySet(); } static NavigableSet navigableKeys(MultiSet ms) { return ((NavigableMap) ms.map).navigableKeySet(); } static long now_virtualTime; static long now() { return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis(); } static boolean loadSnippets_verbose; 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))), 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 boolean nempty(Collection c) { return !isEmpty(c); } static boolean nempty(CharSequence s) { return !isEmpty(s); } static boolean nempty(Object[] o) { return !isEmpty(o); } static boolean nempty(byte[] o) { return !isEmpty(o); } static boolean nempty(Map m) { return !isEmpty(m); } static boolean nempty(Iterator i) { return i != null && i.hasNext(); } static boolean nempty(Object o) { return !empty(o); } static boolean reTok_modify_check; // 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(join(subList(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; } static volatile boolean readLine_noReadLine; static String readLine_lastInput; static String readLine_prefix = "[] "; static String readLine() { if (readLine_noReadLine) return null; String s = readLineHidden(); if (s != null) { readLine_lastInput = s; print(readLine_prefix + s); } return s; } static Pair pair(A a, B b) { return new Pair(a, b); } static Pair pair(A a) { return new Pair(a, a); } static int parseInt(String s) { return empty(s) ? 0 : Integer.parseInt(s); } static int parseInt(char c) { return Integer.parseInt(str(c)); } static volatile StringBuffer local_log = new StringBuffer(); // not redirected static volatile Appendable print_log = local_log; // might be redirected, e.g. to main bot // in bytes - will cut to half that static volatile int print_log_max = 1024*1024; static volatile int local_log_max = 100*1024; //static int print_maxLineLength = 0; // 0 = unset static boolean print_silent; // 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 void print() { print(""); } static A print(String s, A o) { print((endsWithLetterOrDigit(s) ? s + ": " : s) + o); return o; } // slightly overblown signature to return original object... static A print(A o) { ping(); if (print_silent) return o; String s = String.valueOf(o) + "\n"; print_noNewLine(s); return o; } static void print_noNewLine(String s) { Object f = print_byThread == null ? null : print_byThread.get(); 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; print_raw(s); } static void print_raw(String s) { s = fixNewLines(s); // TODO if (print_maxLineLength != 0) StringBuffer loc = local_log; Appendable buf = print_log; int loc_max = print_log_max; if (buf != loc && buf != null) { print_append(buf, s, print_log_max); loc_max = local_log_max; } if (loc != null) print_append(loc, s, loc_max); System.out.print(s); } // will create the file or update its last modified timestamp static void touchFile(File file) { try { closeRandomAccessFile(newRandomAccessFile(mkdirsForFile(file), "rw")); } catch (Exception __e) { throw rethrow(__e); } } // 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, 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 Object getOpt(Object o, String field) { 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; f.setAccessible(true); return f.get(o); } catch (Exception e) { throw new RuntimeException(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; f.setAccessible(true); return f.get(null); } catch (Exception e) { throw new RuntimeException(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 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 boolean tok_classHasModifier(List classDecl, String modifier) { int i = classDecl.indexOf("class"); return subList(classDecl, 0, i).contains(modifier); } static String javaParser_makeAllPublic_keepComments(String src) { //CompilationUnit cu = javaParseCompilationUnit(src); CompilationUnit cu = JavaParser.parse(src); PrettyPrinterConfiguration ppconf = new PrettyPrinterConfiguration(); ppconf.setIndent(" "); new javaParser_makeAllPublic_Visitor().visit(cu, null); return cu.toString(ppconf); } static boolean tok_sameTest(List tok, String text) { int iTok = 0, iText = 0, nTok = l(tok), nText = l(text); while (iTok < nTok) { String t = tok.get(iTok++); int n = l(t); if (n == 0) continue; if (!t.regionMatches(0, text, iText, n)) return false; iText += n; } return iText == nText; } 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 struct(Object o) { return structure(o); } static String struct(Object o, structure_Data data) { return structure(o, data); } static List getAllFutures(Collection> l) { List out = new ArrayList(l(l)); for (Future f : unnull(l)) out.add(getFuture(f)); return out; } static boolean containsOneOfIC(Collection l, String... x) { Set set = asCISet(x); for (String a : unnull(l)) if (set.contains(a)) return true; return false; } // 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) { TreeMap map = new TreeMap(); List stack = new ArrayList(); for (int i = 1; i < l(tok); i+= 2) { if (opening.contains(tok.get(i))) stack.add(i); else if (closing.contains(tok.get(i))) { if (!empty(stack)) map.put(liftLast(stack), i); } } return map; } static Set getBracketMap_opening = lithashset("{", "("); static Set getBracketMap_closing = lithashset("}", ")"); static String joinWithSpace(Collection c) { return join(" ", c); } static String joinWithSpace(String... c) { return join(" ", c); } 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; } // 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 boolean tok_doubleFor_v2_debug; static void tok_doubleFor_v2(List tok) { for (int i : reversed(indexesOf(tok, "for"))) { if (neq(get(tok, i+2), "(")) continue; int argsFrom = i+4; int iColon = indexOfAny(tok, argsFrom, ":", ")"); if (neq(get(tok, iColon), ":")) continue; if (tok_doubleFor_v2_debug) print("have colon"); tok_typesAndNamesOfParams_keepModifiers.set(true); List> args = tok_typesAndNamesOfParams(subList(tok, argsFrom-1, iColon-1)); 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_v2_debug) print("have 2 args: " + sfu(args)); int iClosing = tok_findEndOfForExpression(tok, iColon+2); if (iClosing < 0) continue; if (tok_doubleFor_v2_debug) print("have closing"); String exp = trimJoinSubList(tok, iColon+2, iClosing-1); if (tok_doubleFor_v2_debug) print("Expression: " + exp); int iCurly = iClosing+2; if (neq(get(tok, iCurly), "{")) throw fail("please use { with double for"); int iCurlyEnd = findEndOfStatement(tok, iCurly)-1; if (iCurlyEnd < 0) continue; if (tok_doubleFor_v2_debug) print("have curly end"); // complicated expression? evaluate to variable first if (!isIdentifier(exp)) { String expVar = makeVar(); String mapType = "Map<" + first(args).a + ", " + second(args).a + ">"; tokPrepend(tok, i, "{ final " + mapType + " " + expVar + " = " + exp + "; "); tokAppend(tok, iCurlyEnd, "}"); replaceTokens(tok, iColon+2, iClosing-1, expVar); exp = expVar; } tokAppend(tok, iColon, " keys("); tokPrepend(tok, iClosing, ")"); replaceTokens(tok, argsFrom, iColon-1, joinPairWithSpace(first(args))); tokAppend(tok, iCurly, " " + joinPairWithSpace(second(args)) + " =" + exp + ".get(" + first(args).b + "); "); reTok(tok, i, iCurlyEnd+1); } } // process scope x. ... end scope blocks static void tok_scopes(List tok) { if (!tok.contains("scope")) return; int i; while ((i = rjfind(tok, "scope .")) >= 0) { int j = jfind(tok, i+6, "end scope"); if (j < 0) j = l(tok)-1; String scopeName = tok.get(i+2); HashSet names = new HashSet(); HashSet functions = new HashSet(); clearTokens(tok, i, i+5); clearTokens(tok, j, j+3); List subTok = subList(tok, i+5, 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 = i+6; k < j-2; k += 2) { String t = get(tok, k+2); if (eqGet(tok, k, "#") && isIdentifier(t)) { names.add(t); if (eqGet(tok, k+4, "(")) functions.add(t); replaceTokens(tok, k, k+3, scopeName + "_" + t); } } // second pass (references to scoped variables) for (int k = i+6; k < j; k += 2) { String t = get(tok, k); if (isIdentifier(t)) { if (names.contains(t)) { if (eqGet(tok, k-2, ".")) {} else if (eqGet(tok, k+2, "(") && !functions.contains(t)) {} // avoid lock ... and map ... else if (eqOneOf(t, "lock", "map") && isIdentifier(get(tok, k+2))) {} else tok.set(k, scopeName + "_" + t); } else if (eq(t, "__scope")) tok.set(k, quote(scopeName)); } } reTok(tok, i, j+1); } } static int shorten_default = 100; static String shorten(String s) { return shorten(s, shorten_default); } static String shorten(String s, int max) { return shorten(s, max, "..."); } static String shorten(String s, int max, String shortener) { if (s == null) return ""; if (max < 0) return s; return s.length() <= max ? s : substring(s, 0, min(s.length(), max-l(shortener))) + shortener; } static String shorten(int max, String s) { return shorten(s, max); } static NowFuture nowFuture(A a) { return new NowFuture(a); } static int identityHashCode(Object o) { return System.identityHashCode(o); } static void lock(Lock lock) { try { ping(); if (lock == null) return; try { lock.lockInterruptibly(); } catch (InterruptedException e) { print("Locking interrupted! I probably deadlocked, oops."); printStackTrace(e); rethrow(e); } ping(); } 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(); } public static String join(String glue, Iterable strings) { if (strings == null) return ""; StringBuilder buf = new StringBuilder(); Iterator i = strings.iterator(); if (i.hasNext()) { buf.append(i.next()); while (i.hasNext()) buf.append(glue).append(i.next()); } return buf.toString(); } public static String join(String glue, String... strings) { return join(glue, Arrays.asList(strings)); } static 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); } static String fsI(String id) { return formatSnippetID(id); } static String fsI(long id) { return formatSnippetID(id); } static String dropPrefix(String prefix, String s) { return s == null ? null : s.startsWith(prefix) ? s.substring(l(prefix)) : s; } static List jfindAll(List tok, String pat) { return jfindAll(tok, jfind_preprocess(javaTok(pat))); } // tokPat must be jfind_preprocess'd static List jfindAll(List tok, List tokPat) { String[] toks = toStringArray(codeTokensOnly(tokPat)); int i = -1; List l = new ArrayList(); while ((i = findCodeTokens(tok, i+1, false, toks)) >= 0) l.add(i); return l; } static boolean useDummyMainClasses() { return true; //ret eq("1", trim(loadTextFile(getProgramFile(#1008755, "use-dummy-main-classes")))); } 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 List tok_importedClassNames(List tok) { List names = new ArrayList(); for (int i = 1; i < l(tok); 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); if (isIdentifier (s)) names.add(s); i = j-1; } return names; } 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, null); } static int jfind(List tok, String in, Object condition) { return jfind(tok, 1, in, condition); } static int jfind(List tok, int startIdx, String in, Object condition) { List tokin = javaTok(in); jfind_preprocess(tokin); return jfind(tok, startIdx, tokin, 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, List tokin, Object condition) { return findCodeTokens(tok, startIdx, false, toStringArray(codeTokensOnly(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; } 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 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(String msg) { throw new RuntimeException(msg == null ? "" : msg); } static RuntimeException fail(String msg, Throwable innerException) { throw new RuntimeException(msg, innerException); } static boolean tok_repeatWithSleep_verbose; 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 void tok_listComprehensions(List tok) { if (!tok.contains("[")) return; for (int i = 1; i < l(tok); i += 2) { { 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 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(tok.subList(iOp+2, j)); j += 2; int k = scanOverExpression(tok, bracketMap, j, "]"); String where = join(tok.subList(j, k)); ++k; String code = "filter(" + exp + ", func(" + type + " " + id + ") -> Bool { " + where + " })"; replaceTokens(tok, i, k, code); reTok(tok, i, k); } } static String fsi(String id) { return formatSnippetID(id); } //sbool ping_actions_shareable = true; static volatile boolean ping_pauseAll; static int ping_sleep = 100; // poll pauseAll flag every 100 static volatile boolean ping_anyActions; static Map ping_actions = newWeakHashMap(); // always returns true static boolean ping() { if (ping_pauseAll || ping_anyActions ) ping_impl(); //ifndef LeanMode ping_impl(); endifndef return true; } // returns true when it slept static boolean ping_impl() { try { if (ping_pauseAll && !isAWTThread()) { do Thread.sleep(ping_sleep); while (ping_pauseAll); return true; } if (ping_anyActions) { // don't allow sharing ping_actions 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 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 boolean allVarNames_debug; 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 (eq(t, "{")) i = findEndOfBlock(tok, i)+1; // skip function/class bodies } return varNames; } static List allVarNames(String text) { return allVarNames(javaTok(text)); } static File getCacheProgramDir() { return getCacheProgramDir(getProgramID()); } static File getCacheProgramDir(String snippetID) { return new File(userHome(), "JavaX-Caches/" + formatSnippetIDOpt(snippetID)); } public static boolean isSnippetID(String s) { try { parseSnippetID(s); return true; } catch (RuntimeException e) { return false; } } 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 Set setIntersection(Set a, Collection b) { Set set = similarEmptySet(a); Set bSet = asSet(b); for (A x : a) if (bSet.contains(x)) set.add(x); return set; } 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 ArrayList litlist(A... a) { ArrayList l = new ArrayList(a.length); for (A x : a) l.add(x); return l; } // 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 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) { f.setAccessible(true); return f.get(o); } if (o instanceof DynamicObject) return ((DynamicObject) o).fieldValues.get(field); } catch (Exception e) { throw asRuntimeException(e); } throw new RuntimeException("Field '" + field + "' not found in " + o.getClass().getName()); } static Object get_raw(Object o, String field) { try { Field f = get_findField(o.getClass(), field); f.setAccessible(true); return f.get(o); } catch (Exception e) { throw new RuntimeException(e); } } static Object get(Class c, String field) { try { Field f = get_findStaticField(c, field); f.setAccessible(true); 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 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 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 boolean change = false; 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); // 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/*_reTok*/(tok, i, j+1, ""); change = true; i -= 2; } if (nempty(buf)) { if (l(tok) == 1) addAll(tok, "", ""); tok.set(1, str(buf)+"\n"+tok.get(1)); change = true; //reTok(tok, 1, 2); } if (change) reTok(tok); return tok; } 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(t, "ifclass", "ifndef")) ++level; else if (eqOneOf(t, "endif", "endifndef")) --level; else if (level <= 0 && startsWithJavaIdentifierStart(t) && neqGet(tok, i-2, ".")) set.add(t); } return set; } static String f2s(File f) { return f == null ? null : f.getAbsolutePath(); } static String f2s(java.nio.file.Path p) { return p == null ? null : f2s(p.toFile()); } 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; } static void change() { //mainConcepts.allChanged(); // safe version for now cause function is sometimes included unnecessarily (e.g. by EGDiff) callOpt(getOptMC("mainConcepts"), "allChanged"); } static boolean isSortedList(List l) { for (int i = 0; i < l(l)-1; i++) if (cmp(l.get(i), l.get(i+1)) > 0) return false; return true; } 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 String javaParser_makeAllPublic(String src) { CompilationUnit cu = javaParseCompilationUnit(src); PrettyPrinterConfiguration ppconf = new PrettyPrinterConfiguration(); ppconf.setIndent(" "); ppconf.setPrintComments(false); new javaParser_makeAllPublic_Visitor().visit(cu, null); return cu.toString(ppconf); } static class javaParser_makeAllPublic_Visitor extends VoidVisitorAdapter { void makePublic(Set modifiers) { modifiers.remove(com.github.javaparser.ast.Modifier.PRIVATE); modifiers.remove(com.github.javaparser.ast.Modifier.PROTECTED); modifiers.add(com.github.javaparser.ast.Modifier.PUBLIC); } public void visit(ClassOrInterfaceDeclaration n, Object arg) { Node parent = n.getParentNode().get(); if (!(parent instanceof LocalClassDeclarationStmt || parent instanceof CompilationUnit && neq(n.getName().asString(), "main"))) 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) { EnumSet m = n.getModifiers(); //print("Method found: " + n.getName() + " with modifiers: " + m + ", position: " + n.getRange()->begin); if (m.contains(com.github.javaparser.ast.Modifier.PRIVATE) && !m.contains(com.github.javaparser.ast.Modifier.STATIC)) m.add(com.github.javaparser.ast.Modifier.FINAL); makePublic(m); super.visit(n, arg); } } 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, String 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; 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); if (reTok) // would this ever be false?? reTok(tok, i, end); anyChange = true; } throw fail("woot? 10000! " + quote(in) + " => " + quote(out)); } static boolean jreplace_debug; static A getFuture(Future f) { try { return f == null ? null : f.get(); } catch (Exception __e) { throw rethrow(__e); } } static long parseLong(String s) { if (s == null) return 0; return Long.parseLong(dropSuffix("L", s)); } static long parseLong(Object s) { return Long.parseLong((String) s); } static String mainJava; static String loadMainJava() throws IOException { if (mainJava != null) return mainJava; return loadTextFile("input/main.java", ""); } static String md5(String text) { try { if (text == null) return "-"; return bytesToHex(md5_impl(text.getBytes("UTF-8"))); // 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(md5_impl(data)); } static MessageDigest md5_md; /*static byte[] md5_impl(byte[] data) ctex { if (md5_md == null) md5_md = MessageDigest.getInstance("MD5"); return ((MessageDigest) md5_md.clone()).digest(data); }*/ static byte[] md5_impl(byte[] data) { try { return MessageDigest.getInstance("MD5").digest(data); } catch (Exception __e) { throw rethrow(__e); } } static String md5(File file) { return md5OfFile(file); } 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, 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); } // 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 List ll(A... a) { ArrayList l = new ArrayList(a.length); for (A x : a) l.add(x); return l; } static void tok_recordDecls(List tok) { int i; while ((i = jfind(tok, "record (")) >= 0) { int argsFrom = i+6, argsTo = findCodeTokens(tok, i, false, ")"); int idx = findCodeTokens(tok, argsTo, false, "{"); int j = findEndOfBracketPart(tok, idx); String name = tok.get(i+2); boolean noEq = eq(get(tok, i-2), "noeq"); if (noEq) tok.set(i-2, ""); StringBuilder buf = new StringBuilder(); List tArgs = subList(tok, argsFrom-1, argsTo); List> args = tok_typesAndNamesOfParams(tArgs); List contents = subList(tok, idx+1, j); for (Pair p : args) buf.append("\n " + p.a + " " + p.b + ";"); buf.append("\n *() {}"); buf.append("\n *(" + joinWithComma(map(args, new F1, String>() { String get(Pair p) { try { return dropPrefix("new ", p.a) + " *" + p.b ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "dropPrefix(\"new \", p.a) + \" *\" + p.b"; }})) + ") {}"); if (!(jfind(contents, "toString {") >= 0 || jfind(contents, "toString()") >= 0)) buf.append("\n toString { ret " + quote(name + "(") + " + " + join(" + \", \" + ", secondOfPairs(args)) + " + \")\"; }"); if (!noEq) { //buf.append("\n [stdEq]"); buf.append(tok_genEqualsAndHashCode(name, args)); } tok.set(idx, "{" + buf); tok.set(i, "class"); clearTokens(tok, argsFrom-2, argsTo+1); reTok(tok, i, idx+1); } } static boolean isIdentifier(String s) { return isJavaIdentifier(s); } static String getSnippetTitle(String id) { try { if (id == null) return null; if (!isSnippetID(id)) return "?"; long parsedID = parseSnippetID(id); String url; if (isImageServerSnippet(parsedID)) url = "http://ai1.space/images/raw/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(); return or2(trim(loadPageSilently(url)), "?"); } catch (Exception __e) { throw rethrow(__e); } } static String getSnippetTitle(long id) { return getSnippetTitle(fsI(id)); } 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); } 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 int countChar(String s, char c) { int n = 0, l = l(s); for (int i = 0; i < l; i++) if (s.charAt(i) == c) ++n; return n; } static boolean tok_tokenBeforeLonelyReturnValue(String t) { return l(t) == 1 && "{};)".contains(t) || eq(t, "else"); } static boolean tok_hasClassRef2(List tok, String className) { int n = l(tok); int level = 0; for (int i = 1; i < n; i += 2) { String t = tok.get(i); if (eqOneOf(t, "ifclass", "ifndef")) ++level; else if (eqOneOf(t, "endif", "endifndef")) --level; else if (level <= 0 && eq(t, className)) return true; } return false; } static boolean neqOneOf(Object o, Object... l) { for (Object x : l) if (eq(o, x)) return false; return true; } static void replaceTokens(List tok, int i, int j, String s) { clearAllTokens(subList(tok, i, j)); tok.set(i, s); } static void replaceTokens(List tok, String s) { clearAllTokens(tok); tok.set(0, s); } static boolean hasUnclosedStringLiterals(String s) { for (String t : javaTokC(s)) if (isUnproperlyQuoted(t)) return true; return false; } static Set findFunctionDefs_keywords = new HashSet(splitAtSpace("static svoid ssvoid ssynchronized sbool sS sO sL")); static List findFunctionDefs(List tok) { int n = l(tok); List functions = new ArrayList(); for (int i = 1; i < n; i += 2) { String t = tok.get(i); if (findFunctionDefs_keywords.contains(t)) { int j = i+2; while (j < n && !eqOneOf(tok.get(j), ";", "=", "(", "{")) j += 2; if (eq(get(tok, j), "(") && isIdentifier(tok.get(j-2))) functions.add(tok.get(j-2)); } } return functions; } 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 List findCodeTokens_specials = litlist("*", "", "", "", "\\*"); static boolean findCodeTokens_debug; static int findCodeTokens_indexed, findCodeTokens_unindexed; static int findCodeTokens_bails, findCodeTokens_nonbails; static int findCodeTokens(List tok, int startIdx, boolean ignoreCase, String[] tokens, Object condition) { if (findCodeTokens_debug) { if (eq(getClassName(tok), "main$IndexedList2")) findCodeTokens_indexed++; else findCodeTokens_unindexed++; } // bail out early if first token not found (works great with IndexedList) if (!findCodeTokens_specials.contains(tokens[0]) && !tok.contains(tokens[0] /*, startIdx << no signature in List for this, unfortunately */)) { ++findCodeTokens_bails; return -1; } ++findCodeTokens_nonbails; outer: for (int i = startIdx | 1; i+tokens.length*2-2 < tok.size(); i += 2) { for (int j = 0; j < tokens.length; j++) { String p = tokens[j], t = tok.get(i+j*2); boolean match; 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 boolean neq(Object a, Object b) { return !eq(a, b); } static int indexOf(List l, A a, int startIndex) { if (l == null) return -1; for (int i = startIndex; i < l(l); 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) { if (x == null) return -1; for (int i = 0; i < l(x); i++) if (eq(x[i], a)) return i; return -1; } static String javaParser_reparse_keepComments(String src) { CompilationUnit cu = JavaParser.parse(src); PrettyPrinterConfiguration ppconf = new PrettyPrinterConfiguration(); ppconf.setIndent(" "); return cu.toString(ppconf); } static boolean eqOneOf(Object o, Object... l) { for (Object x : l) if (eq(o, x)) return true; return false; } static boolean findFunctionInvocations_debug; // these prefix tokens mark a non-invocation (TODO: expand) static Set findFunctionInvocations_pre = new HashSet(litlist(".", "void", "S", "String", "int", "bool", "boolean", "A", "Object", "O")); static Set findFunctionInvocations(List tok, Map sf) { return findFunctionInvocations(tok, sf, null); } // sf = set of functions to search for or null for any function static Set findFunctionInvocations(List tok, Map sf, Collection hardReferences) { return findFunctionInvocations(tok, sf, hardReferences, null); } static Set findFunctionInvocations(List tok, Map sf, Collection hardReferences, Set haveFunctions) { int i; LinkedHashSet l = new LinkedHashSet(); while ((i = jfind(tok, "please include function *.")) >= 0) { String fname = tok.get(i+6); l.add(fname); hardReferences.add(fname); clearAllTokens(tok.subList(i, i+10)); } boolean result = false; for (i = 1; i+2 < tok.size(); i += 2) { String f = tok.get(i); if (!isIdentifier(f)) continue; // main.bla() if (eq(f, "main") && eq(tok.get(i+2), ".") && eqGet(tok, i+4, "<")) { i = findEndOfTypeArgs(tok, i+4)+1; f = tok.get(i); if (!isIdentifier(f)) continue; } if (findFunctionInvocations_debug) print("Testing identifier " + f); if (!eqGet(tok, i+2, "(")) continue; if (i == 1 || !findFunctionInvocations_pre.contains(tok.get(i-2)) || eq(get(tok, i-2), ".") && eq(get(tok, i-4), "main")) { boolean inSF = sf == null || sf.containsKey(f); if (findFunctionInvocations_debug) print("Possible invocation: " + f + ", inSF: " + inSF); if (inSF && !contains(haveFunctions, f) && l.add(f)) print("Found reference to standard function " + f + ": " + lineAroundToken(tok, i)); } } return l; } static List tlft_j(String text) { return toLinesFullTrim_java(text); } 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); } // 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)); tok.set(j-1, end); replaceTokens(tok, i, idx+1, beg); reTok(tok, i, j); if (debug) print(toUpper(keyword) + "\n" + join(subList(tok, i, j)) + "\n"); } return tok; } static void tok_unpair(List tok) { if (!tok.contains("unpair")) return; int i; 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(); tok.set(i+4, ";"); tok.set(idx-2, ";"); tok.set(i+2, "Pair<" + type1 + "," + 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 List tok_importedStaticFunctionNames(List tok) { List names = new ArrayList(); for (int i = 1; i < l(tok); i += 2) if (eq(tok.get(i), "import") && 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(s); i = j-1; } return names; } 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 volatile int numberOfCores_value; static int numberOfCores() { if (numberOfCores_value == 0) numberOfCores_value = Runtime.getRuntime().availableProcessors(); return numberOfCores_value; } static TokCondition tokCondition_beginningOfMethodDeclaration() { return new TokCondition() { boolean get(final List tok, final int i) { return eqOneOf(_get(tok, i-1), "}", ";", "{", null); }}; } static String trimJoin(List s) { return trim(join(s)); } static List concatLists(Collection... lists) { List l = new ArrayList(); for (Collection list : lists) if (list != null) l.addAll(list); return l; } static List concatLists(Collection> lists) { List l = new ArrayList(); for (Collection list : lists) if (list != null) l.addAll(list); return l; } 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"); 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 TreeSet ciSet() { return caseInsensitiveSet(); } static boolean hasCodeTokens(List tok, String... tokens) { return findCodeTokens(tok, tokens) >= 0; } static String getClassName(Object o) { return o == null ? "null" : o instanceof Class ? ((Class) o).getName() : o.getClass().getName(); } 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)); } static boolean startsWithLowerCaseOrUnderscore(String s) { return nempty(s) && (s.startsWith("_") || Character.isLowerCase(s.charAt(0))); } static void replaceTokens_reTok(List tok, int i, int j, String s) { replaceTokens(tok, i, j, s); reTok(tok, i, j); } static Set keys(Map map) { return map == null ? new HashSet() : map.keySet(); } static Set keys(Object map) { return keys((Map) map); } static Set keys(MultiSet ms) { return ms.keySet(); } static Collection values(Map map) { return map == null ? emptyList() : map.values(); } 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 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 String substring(String s, int x) { return substring(s, x, l(s)); } static String substring(String 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.substring(x, y); } // 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 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 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 long sysNow() { return System.nanoTime()/1000000; } static List includeInMainLoaded_stdReTok(List tok, String text) { List main = findMainClass(tok); if (main == null) { print(join(tok)); throw fail("no main class"); } int i = main.lastIndexOf("}"); main.set(i, "\n" + text + "\n}"); i += magicIndexOfSubList(tok, main); return reTok(tok, i, i+1); } static IndexedList2 indexedList2(List l) { return l instanceof IndexedList2 ? ((IndexedList2) l) : new IndexedList2(l); } static boolean preferCached = false; static boolean loadSnippet_debug = false; static ThreadLocal loadSnippet_silent = 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); } public static String loadSnippet(long snippetID) { try { return loadSnippet(snippetID, preferCached); } catch (Exception __e) { throw rethrow(__e); } } public static String loadSnippet(long snippetID, boolean preferCached) throws IOException { String text; // boss bot disabled for now for shorter transpilations /*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); 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 String dropPrefixTrim(String prefix, String s) { return trim(dropPrefix(prefix, s)); } static Object loadVariableDefinition(String varName) { return loadVariableDefinition(getProgramID(), varName); } // currently only works with string lists ("= litlist(...)") // and strings. 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 Set keySet(Map map) { return map == null ? new HashSet() : map.keySet(); } static Set keySet(Object map) { return keys((Map) map); } static Set keySet(MultiSet ms) { return ms.keySet(); } static RuntimeException rethrow(Throwable t) { if (t instanceof Error) _handleError((Error) t); throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static A or(A a, A b) { return a != null ? a : b; } static void tok_cachedFunctions(List tok) { try { if (!tok.contains("cached")) return; int i; while ((i = jfind(tok, "static cached ")) >= 0) { int bracket = indexOf(tok, "(", i); String fName = assertIdentifier(tok.get(bracket-2)); String type = joinSubList(tok, i+4, bracket-3); replaceTokens(tok, i, bracket-1, ("static Cache<" + (type) + "> " + (fName) + "_cache = new Cache(f " + (fName) + "_load);\n") + ("static " + (type) + " " + (fName) + "() { ret " + (fName) + "_cache!; }\n\n") + ("static " + (type) + " " + (fName) + "_load")); reTok(tok, i, bracket-3); } } catch (Throwable __e) { printStackTrace2(__e); }} static void clear(Collection c) { if (c != null) c.clear(); } static String dropSuffix(String suffix, String s) { return s.endsWith(suffix) ? s.substring(0, l(s)-l(suffix)) : s; } // 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(); } static boolean isMD5(String s) { return l(s) == 32 && isLowerHexString(s); } 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) { structure_Data d = new structure_Data(); d.out = out; structure_go(o, d); } // leave to false, unless unstructure() breaks static boolean structure_allowShortening = false; static class structure_Data { PrintWriter out; int stringSizeLimit; int shareStringsLongerThan = 20; boolean noStringSharing; IdentityHashMap seen = new IdentityHashMap(); //new BitSet refd; HashMap strings = new HashMap(); HashSet concepts = new HashSet(); HashMap> fieldsByClass = 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; } } static void structure_1(final Object o, final structure_Data d) { if (o == null) { d.append("null"); return; } Class c = o.getClass(); boolean concept = false; List lFields = d.fieldsByClass.get(c); 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 ", 2); 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; } if (o instanceof File) { d.append("File ").append(quote(((File) o).getPath())); return; } // referencable objects follow Integer ref = d.seen.get(o); if (o instanceof String && ref == null) ref = d.strings.get((String) o); if (ref != null) { /*d.refd.set(ref);*/ d.append("t").app(ref); return; } if (!(o instanceof String)) d.seen.put(o, d.n); // record token number else { 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; } if (o instanceof HashSet) { d.append(o instanceof LinkedHashSet ? "lhs " : "hashset "); structure_1(new ArrayList((Set) o), d); return; } if (o instanceof TreeSet) { d.append("treeset "); structure_1(new ArrayList((Set) o), d); return; } String name = c.getName(); if (o instanceof Collection && !startsWith(name, "main$") /* && neq(name, "main$Concept$RefL") */) { d.append("["); final int l = d.n; final Iterator it = ((Collection) 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.sta..."; }}); return; } if (o instanceof Map && !startsWith(name, "main$")) { if (o instanceof LinkedHashMap) d.append("lhm"); else if (o instanceof HashMap) d.append("hm"); else if (name.equals("java.util.Collections$SynchronizedMap")) d.append("sync"); else if (name.equals("java.util.Collections$SynchronizedSortedMap")) { d.append("sync tm", 2); } d.append("{"); final int l = d.n; final Iterator it = ((Map) o).entrySet().iterator(); d.stack.add(new Runnable() { boolean v; Map.Entry e; public void run() { 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); } } } }); 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; } String atype = "array", sep = ", "; if (o instanceof int[]) { //ret "intarray " + quote(intArrayToHex((int[]) o)); atype = "intarray"; sep = " "; } 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; } // Need more cases? This should cover all library classes... if (name.startsWith("java.") || name.startsWith("javax.")) { d.append("j ").append(quote(str(o))); return; // Hm. this is not unstructure-able } /*if (name.equals("main$Lisp")) { fail("lisp not supported right now"); }*/ String dynName = shortDynamicClassName(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 ((field.getModifiers() & (java.lang.reflect.Modifier.STATIC | java.lang.reflect.Modifier.TRANSIENT)) != 0) continue; String fieldName = field.getName(); fields.add(field); // put special cases here... } cc = cc.getSuperclass(); } lFields = asList(fields); // Render this$1 first because unstructure needs it for constructor call. for (int i = 0; i < l(lFields); i++) { Field f = lFields.get(i); if (f.getName().equals("this$1")) { lFields.remove(i); lFields.add(0, f); break; } } d.fieldsByClass.put(c, lFields); } // << if (lFields == null) else { // ref handling for lFields != null 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 } LinkedHashMap fv = new LinkedHashMap(); for (Field f : lFields) { Object value; try { value = f.get(o); } catch (Exception e) { value = "?"; } if (value != null) fv.put(f.getName(), value); } String name = c.getName(); String shortName = dropPrefix("main$", name); // Now we have fields & values. Process fieldValues if it's a DynamicObject. // omit field "className" if equal to class's name if (concept && eq(fv.get("className"), shortName)) fv.remove("className"); if (o instanceof DynamicObject) { fv.putAll((Map) fv.get("fieldValues")); fv.remove("fieldValues"); shortName = shortDynamicClassName(o); fv.remove("className"); } String singleField = fv.size() == 1 ? first(fv.keySet()) : null; d.append(shortName); final int l = d.n; final Iterator it = fv.entrySet().iterator(); d.stack.add(new Runnable() { public void run() { try { if (!it.hasNext()) { if (d.n != l) d.append(")"); } else { Map.Entry e = (Map.Entry) it.next(); d.append(d.n == l ? "(" : ", "); d.append((String) e.getKey()).append("="); d.stack.add(this); structure_1(e.getValue(), d); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (!it.hasNext()) {\r\n if (d.n != l)\r\n d.append(\")\");\r\n } else..."; }}); } 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 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 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 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 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 void callF(VF1 f, A a) { if (f != null) f.get(a); } static Object callF(Object f, Object... args) { try { if (f instanceof String) return callMC((String) f, 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)); } catch (Exception __e) { throw rethrow(__e); } } // 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")) { m.setAccessible(true); l.add(m); } if (!l.isEmpty()) break; _c = _c.getSuperclass(); } while (_c != null); callF_cache.put(c, l); return l; } static String getNameOfAnyClass(List tok) { return getClassDeclarationName(first(allClasses(tok))); } static Map newWeakHashMap() { return _registerWeakMap(synchroMap(new WeakHashMap())); } static ArrayList asList(A[] a) { return a == null ? new ArrayList() : new ArrayList(Arrays.asList(a)); } static ArrayList asList(int[] a) { ArrayList l = new ArrayList(); for (int i : a) l.add(i); return l; } 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 void replaceListPart(List l, int i, int j, List l2) { l.subList(i, j).clear(); l.addAll(i, l2); } 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 + "'"; } // "$1" is first code token, "$2" second code token etc. static String jreplaceExpandRefs(String s, List tokref) { List tok = javaTok(s); for (int i = 1; i < l(tok); i += 2) { if (tok.get(i).startsWith("$") && isInteger(tok.get(i).substring(1))) { String x = tokref.get(-1+parseInt(tok.get(i).substring(1))*2); tok.set(i, x); } } return join(tok); } // 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 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 String shortDynamicClassName(Object o) { if (o instanceof DynamicObject && ((DynamicObject) o).className != null) return ((DynamicObject) o).className; return shortClassName(o); } static Thread currentThread() { return Thread.currentThread(); } static Throwable printStackTrace(Throwable e) { // we go to system.out now - system.err is nonsense print(getStackTrace(e)); return e; } static void printStackTrace() { printStackTrace(new Throwable()); } static void printStackTrace(String msg) { printStackTrace(new Throwable(msg)); } /*static void printStackTrace(S indent, Throwable e) { if (endsWithLetter(indent)) indent += " "; printIndent(indent, getStackTrace(e)); }*/ static boolean neqGet(List l, int i, Object o) { return neq(get(l, i), o); } static void replaceCollection(Collection dest, Collection src) { dest.clear(); dest.addAll(src); } static String standardCredentials() { String user = standardCredentialsUser(); String pass = standardCredentialsPass(); if (nempty(user) && nempty(pass)) return "&_user=" + urlencode(user) + "&_pass=" + urlencode(pass); return ""; } static AutoInitVar < String > md5OfMyJavaSource_cache = new AutoInitVar(new F0() { String get() { try { return md5(myJavaSource()) ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "md5(myJavaSource())"; }}); static String md5OfMyJavaSource() { return md5OfMyJavaSource_cache.get(); } static String getType(Object o) { return getClassName(o); } static String standardCredentials_noCookies() { return standardCredentials() + "&noCookies=1"; } 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 int deleteDirectory_minPathLength = 10; static void deleteDirectory(File dir) { deleteDirectory(dir, false, false); } static void deleteDirectory(File dir, boolean verbose, boolean testRun) { dir = getCanonicalFile(dir); assertTrue(f2s(dir), l(f2s(dir)) >= deleteDirectory_minPathLength); File[] files = dir.listFiles(); if (files == null) return; for (File f : files) { if (f.isDirectory()) deleteDirectory(f, verbose, testRun); else { if (verbose) print((testRun ? "Would delete " : "Deleting ") + f.getAbsolutePath()); if (!testRun) f.delete(); } } if (verbose) print((testRun ? "Would delete " : "Deleting ") + dir.getAbsolutePath()); if (!testRun) dir.delete(); } 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 String md5OfFile(File f) { try { if (!f.exists()) return "-"; MessageDigest md5 = MessageDigest.getInstance("MD5"); try ( FileInputStream in = new FileInputStream(f)) { 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()); }} catch (Exception __e) { throw rethrow(__e); } } static A liftLast(List l) { if (l.isEmpty()) return null; int i = l(l)-1; A a = l.get(i); l.remove(i); return a; } 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 unnull(String s) { return s == null ? "" : s; } static List unnull(List l) { return l == null ? emptyList() : 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[]) new Object[0] : a; } static BitSet unnull(BitSet b) { return b == null ? new BitSet() : b; } //ifclass Symbol static Object unstructure(String text) { return unstructure(text, false); } static Object unstructure(String text, final boolean allDynamic) { return unstructure(text, allDynamic, null); } 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); } static Object unstructure_tok(final Producer tok, final boolean allDynamic, final Object classFinder) { final boolean debug = unstructure_debug; final class X { int i = -1; HashMap refs = new HashMap(); HashMap tokrefs = new HashMap(); HashSet concepts = new HashSet(); HashMap classesMap = new HashMap(); List stack = new ArrayList(); String curT; char[] unquoteBuf = new char[unstructure_unquoteBufSize]; 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 = 0; if (structure_isMarker(t, 0, l(t))) { refID = parseInt(t.substring(1)); consume(); } final int _refID = refID; // 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, final unstructure_Receiver out) { String t = t(); // if (debug) print("parse_inner: " + quote(t)); Class c = classesMap.get(t); 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("bigint")) { out.set(parseBigInt()); return; } if (t.equals("d")) { out.set(parseDouble()); return; } if (t.equals("fl")) { out.set(parseFloat()); return; } if (t.equals("sh")) { consume(); t = tpp(); if (t.equals("-")) { t = tpp(); out.set((short) (-parseInt(t))); return; } out.set((short) parseInt(t)); 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; if (debug) print("l=" + l + ", isInt: " + isInt); out.set(isInt ? (Object) new Integer((int) l) : (Object) new Long(l)); return; } if (t.equals("false") || t.equals("f")) { consume(); out.set(false); return; } if (t.equals("true") || t.equals("t")) { consume(); out.set(true); 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; if (debug) print("l=" + l + ", isInt: " + isInt); out.set(isInt ? (Object) new Integer((int) l) : (Object) new Long(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) print("Warning: 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) print("Warning: unsatisfied token reference " + ref); 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 (eqOneOf(t, "hashmap", "hm")) { consume(); parseMap(new HashMap(), out); return; } if (t.equals("lhm")) { consume(); parseMap(new LinkedHashMap(), out); return; } if (t.equals("sync")) { consume(); if (t().equals("tm")) { consume(); { parseMap(synchronizedTreeMap(), out); return; } } { parseMap(synchronizedMap(), out); return; } } if (t.equals("{")) { parseMap(out); return; } if (t.equals("[")) { this.parseList(out); return; } if (t.equals("bitset")) { parseBitSet(out); return; } if (t.equals("array") || t.equals("intarray")) { parseArray(out); return; } if (t.equals("ba")) { consume(); String hex = unquote(tpp()); out.set(hexToBytes(hex)); return; } if (t.equals("boolarray")) { consume(); int n = parseInt(tpp()); String hex = unquote(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("c"); t = t(); assertTrue(isJavaIdentifier(t)); concepts.add(t); } } if (eq(t, "j")) { consume("j"); out.set(parseJava()); return; } if (c == null && !isJavaIdentifier(t)) throw new RuntimeException("Unknown token " + (i+1) + ": " + t); // any other class name if (c == null) { // First, find class if (allDynamic) c = null; else c = classFinder != null ? (Class) callF(classFinder, "main$" + t) : findClass(t); if (c != null) classesMap.put(t, c); } // Check if it has an outer reference consume(); boolean hasBracket = eq(t(), "("); if (hasBracket) consume(); boolean hasOuter = hasBracket && eq(t(), "this$1"); DynamicObject dO = null; Object o = null; final String thingName = t; if (c != null) { o = hasOuter ? nuStubInnerObject(c, classFinder) : nuEmptyObject(c); if (o instanceof DynamicObject) dO = (DynamicObject) o; } else { if (concepts.contains(t) && (c = findClass("Concept")) != null) o = dO = (DynamicObject) nuEmptyObject(c); else dO = new DynamicObject(); dO.className = t; if (debug) print("Made dynamic object " + t + " " + shortClassName(dO)); } // 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! final LinkedHashMap fields = new LinkedHashMap(); // preserve order final Object _o = o; final DynamicObject _dO = dO; if (hasBracket) { stack.add(new Runnable() { public void run() { try { if (eq(t(), ")")) { consume(")"); objRead(_o, _dO, fields); out.set(_o != null ? _o : _dO); } else { final String key = unquote(tpp()); if (!eq(tpp(), "=")) 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); if (eq(t(), ",")) consume(); } }); } } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (eq(t(), \")\")) {\r\n consume(\")\");\r\n objRead(_o, _dO, ..."; }}); } else { objRead(o, dO, fields); out.set(o != null ? o : dO); } } void objRead(Object o, DynamicObject dO, Map fields) { if (o != null) if (dO != null) { if (debug) printStructure("setOptAllDyn", fields); setOptAllDyn(dO, fields); } else { setOptAll_pcall(o, fields); } else for (String field : keys(fields)) dO.fieldValues.put(intern(field), fields.get(field)); if (o != null) pcallOpt_noArgs(o, "_doneLoading"); } void parseSet(final Set set, final unstructure_Receiver out) { this.parseList(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 ..."; }}); } void parseList(final unstructure_Receiver out) { consume("["); final ArrayList list = new ArrayList(); 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 out.set(list);\r\n ..."; }}); } void parseArray(final unstructure_Receiver out) { final String type = tpp(); consume("{"); final List list = new ArrayList(); stack.add(new Runnable() { public void run() { try { if (eq(t(), "}")) { consume("}"); out.set(type.equals("intarray") ? toIntArray(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 out.set(type.equals(\"..."; }}); } Object parseClass() { consume("class"); consume("("); String name = unquote(tpp()); consume(")"); name = dropPrefix("main$", name); Class c = allDynamic ? null : classFinder != null ? (Class) callF(classFinder, name) : findClass(name); if (c != null) return c; DynamicObject dO = new DynamicObject(); dO.className = "java.lang.Class"; dO.fieldValues.put("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 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; 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 (debug) print("parseMap: Got value " + getClassName(value) + ", next token: " + quote(t())); 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(); } void parse_x(unstructure_Receiver out) { consume(); // get first token parse(out); while (nempty(stack)) popLast(stack).run(); } } Boolean b = DynamicObject_loading.get(); DynamicObject_loading.set(true); try { final Var v = new Var(); X x = new X(); x.parse_x(new unstructure_Receiver() { void set(Object o) { v.set(o); } }); unstructure_tokrefs = x.tokrefs.size(); return v.get(); } finally { DynamicObject_loading.set(b); } } static boolean unstructure_debug; static boolean isImageServerSnippet(long id) { return id >= 1100000 && id < 1200000; } static void tokPrepend(List tok, int i, String s) { tok.set(i, s + tok.get(i)); } 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 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 File pathToJavaxJar() { 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 = "http://tinybrain.de/x30.jar"; 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 Class __javax; static Class getJavaX() { try { return __javax; } catch (Exception __e) { throw rethrow(__e); } } static boolean dir2zip_recurse_verbose; 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()) { 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 = new FileInputStream(f); copyStream(fin, outZip); fin.close(); ++n; } } return n; } catch (Exception __e) { throw rethrow(__e); } } static void set(Object o, String field, Object value) { if (o instanceof Class) set((Class) o, field, value); else try { Field f = set_findField(o.getClass(), field); f.setAccessible(true); smartSet(f, o, value); } catch (Exception e) { throw new RuntimeException(e); } } static void set(Class c, String field, Object value) { try { Field f = set_findStaticField(c, field); f.setAccessible(true); 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 File tempDirPossiblyInRAMDisk() { File f = linux_fileInRamDisk(aGlobalID()); if (f != null) { f.mkdirs(); return f; } return makeTempDir(); } static TreeSet asCISet(Collection c) { return toCaseInsensitiveSet(c); } static TreeSet asCISet(String... x) { return toCaseInsensitiveSet(x); } static void closeRandomAccessFile(RandomAccessFile f) { if (f != null) try { f.close(); callJavaX("dropIO", f); } catch (Throwable e) { printStackTrace(e); } } 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)); } // TODO: remove 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) { try { if (o == null) return null; if (o instanceof Class) { Method m = call_findStaticMethod((Class) o, method, args, false); m.setAccessible(true); return invokeMethod(m, null, args); /*} else if (o instanceof DynamicMethods) { ret ((DynamicMethods) o)._dynCall(method, args);*/ } else { Method m = call_findMethod(o, method, args, false); m.setAccessible(true); return invokeMethod(m, o, args); } } catch (Exception __e) { throw rethrow(__e); } } static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (!m.getName().equals(method)) { if (debug) System.out.println("Method name mismatch: " + method); continue; } if ((m.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug)) continue; return m; } c = c.getSuperclass(); } throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + _c.getName()); } static Method call_findMethod(Object o, String method, Object[] args, boolean debug) { Class c = o.getClass(); while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (m.getName().equals(method) && call_checkArgs(m, args, debug)) return m; } c = c.getSuperclass(); } throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName()); } 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) f.setAccessible(true); } } return fields; } static boolean vmExiting() { return isTrue(getOpt(javax(), "killing")); } static File getGlobalCache() { File file = new File(javaxCachesDir(), "Binary Snippets"); file.mkdirs(); return file; } 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 toUpper(String s) { return s == null ? null : s.toUpperCase(); } static List toUpper(Collection s) { return allToUpper(s); } static String boolArrayToHex(boolean[] a) { return bytesToHex(boolArrayToBytes(a)); } static void lockOrFail(Lock lock, long timeout) { try { ping(); 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); } ping(); } catch (Exception __e) { throw rethrow(__e); } } static Iterator emptyIterator() { return Collections.emptyIterator(); } static A callMain(A c, String... args) { callOpt(c, "main", new Object[] {args}); return c; } static void callMain() { callMain(mc()); } static String readLineHidden() { try { if (get(javax(), "readLine_reader") == null) set(javax(), "readLine_reader" , new BufferedReader(new InputStreamReader(System.in, "UTF-8"))); try { return ((BufferedReader) get(javax(), "readLine_reader")).readLine(); } finally { consoleClearInput(); } } catch (Exception __e) { throw rethrow(__e); } } 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 getServerTranspiled(String snippetID) { return getServerTranspiled(snippetID, null); } // returns "SAME" if md5 matches static String getServerTranspiled(String snippetID, String expectedMD5) { try { 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 print_append(Appendable _buf, String s, int max) { try { synchronized(_buf) { _buf.append(s); if (!(_buf instanceof StringBuilder)) return; StringBuilder buf = (StringBuilder) ( _buf); max /= 2; if (buf.length() > max) 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); } } } catch (Exception __e) { throw rethrow(__e); } } // 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() static int magicIndexOfSubList(List list, List sublist) { Integer o1 = (Integer) ( getOpt(list, "offset")); int o2 = (Integer) get(sublist, "offset"); return o2-(o1 != null ? o1 : 0); } 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 boolean isNonNegativeInteger(String s) { return s != null && Pattern.matches("\\d+", s); } static String getNameOfPublicClass(List tok) { for (List c : allClasses(tok)) if (hasModifier(c, "public")) return getClassDeclarationName(c); return null; } static TreeSet caseInsensitiveSet() { return new TreeSet(caseInsensitiveComparator()); } static TreeSet caseInsensitiveSet(Collection c) { return toCaseInsensitiveSet(c); } static boolean isFalse(Object o) { return eq(false, o); } 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 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); } /** writes safely (to temp file, then rename) */ static File saveTextFile(String fileName, String contents) throws IOException { CriticalAction action = beginCriticalAction("Saving file " + fileName + " (" + l(contents) + " chars)"); try { 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()); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8"); PrintWriter printWriter = new PrintWriter(outputStreamWriter); printWriter.print(contents); printWriter.close(); } 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); return file; } finally { action.done(); } } static File saveTextFile(File fileName, String contents) { try { saveTextFile(fileName.getPath(), contents); return fileName; } catch (Exception __e) { throw rethrow(__e); } } 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 } // 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(); 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; } // 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; } 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 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 String joinPairWithSpace(Pair p) { return str(p.a) + " " + str(p.b); } static String loadCachedTranspilation(String id) { return loadTextFilePossiblyGZipped(new File(getCodeProgramDir(id), "Transpilation")); } static RandomAccessFile newRandomAccessFile(File path, String mode) throws IOException { RandomAccessFile f = new RandomAccessFile(path, mode); callJavaX("registerIO", f, path, mode.indexOf('w') >= 0); return f; } static List emptyList() { return new ArrayList(); //ret Collections.emptyList(); } static List emptyList(int capacity) { return new ArrayList(capacity); } // Try to match capacity static List emptyList(Iterable l) { return l instanceof Collection ? emptyList(((Collection) l).size()) : emptyList(); } // returns index of trailing N token static int scanToEndOfInitializer(List tok, Map bracketMap, int i) { while (i < l(tok)) { if (litlist(";", ",", ")", "}").contains(tok.get(i))) return i-1; Integer j = bracketMap.get(i); if (j != null) i = j+1; else i++; } return i; } static String lines(Collection lines) { return fromLines(lines); } static List lines(String s) { return toLines(s); } static boolean setAdd(Collection c, A a) { if (c == null || c.contains(a)) return false; c.add(a); return true; } static String programID() { return getProgramID(); } static String programID(Object o) { return getProgramID(o); } 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); } 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 ReentrantLock fairLock() { return new ReentrantLock(true); } static boolean isOfflineMode() { return eq("1", trim(loadProgramTextFile("#1005806", "offline-mode"))); } static boolean isEmpty(Collection c) { return c == null || c.isEmpty(); } 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 ThreadLocal print_byThread() { synchronized(print_byThread_lock) { if (print_byThread == null) print_byThread = new ThreadLocal(); } return print_byThread; } 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(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 boolean containsIgnoreCase(Collection l, String s) { for (String x : l) if (eqic(x, s)) return true; return false; } static boolean containsIgnoreCase(String[] l, String s) { 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 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); } 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 setOpt_raw(o, field, value); return; } Field f = map.get(field); if (f != null) smartSet(f, o, value); // possible improvement: skip setAccessible } 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); 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) { f.setAccessible(true); return f; } _c = _c.getSuperclass(); } while (_c != null); return null; } static String addSlash(String s) { return empty(s) || s.endsWith("/") ? s : s + "/"; } static A popLast(List l) { return liftLast(l); } static File tempDir() { return makeTempDir(); } static int parseIntOpt(String s) { return isInteger(s) ? parseInt(s) : 0; } 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 String javaTok_substringC(String s, int i, int j) { return s.substring(i, j); } static String urlencode(String x) { try { return URLEncoder.encode(unnull(x), "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } static List splitAtSpace(String s) { return asList(s.split("\\s+")); } 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 int leftScanModifiers(List tok, int i) { List mod = getJavaModifiers(); while (i > 1 && mod.contains(tok.get(i-2))) i -= 2; return i; } static List indexesOf(List l, A a) { List x = new ArrayList(); for (int i = 0; i < l(l); i++) if (eq(l.get(i), a)) x.add(i); return x; } // JavaParser static CompilationUnit javaParseCompilationUnit(String java) { JavaParser.getStaticConfiguration().setAttributeComments(false); return JavaParser.parse(java); } static WeakReference weakRef(A a) { return newWeakReference(a); } static String getStackTrace2(Throwable e) { return hideCredentials(getStackTrace(unwrapTrivialExceptionWraps(e)) + replacePrefix("java.lang.RuntimeException: ", "FAIL: ", hideCredentials(str(getInnerException(e)))) + "\n"); } 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; // It's inefficient :D for (int j = 0; j < l(x); j++) l.remove(i); l.addAll(i, y); i += l(y); } return l; } static List replaceSublist(List l, int fromIndex, int toIndex, List y) { // inefficient while (toIndex > fromIndex) l.remove(--toIndex); l.addAll(fromIndex, y); return l; } static List codeTokensOnly(List tok) { List l = new ArrayList(); for (int i = 1; i < tok.size(); i += 2) l.add(tok.get(i)); return l; } static HashMap litmap(Object... x) { HashMap map = new HashMap(); litmap_impl(map, x); return map; } static void litmap_impl(Map map, Object... x) { for (int i = 0; i < x.length-1; i += 2) if (x[i+1] != null) map.put(x[i], x[i+1]); } static ThreadLocal doPost_silently = new ThreadLocal(); static ThreadLocal doPost_timeout = new ThreadLocal(); 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); setHeaders(conn); 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(); loadPage_charset.set("UTF-8"); String contents = loadPage(conn, url, false); writer.close(); return contents; } catch (Exception __e) { throw rethrow(__e); } } static String firstLine(String text) { int i = text.indexOf('\n'); return i >= 0 ? text.substring(0, i) : text; } static boolean odd(int i) { return (i & 1) != 0; } static boolean odd(long i) { return (i & 1) != 0; } 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 String dropTrailingSquareBracketStuff(String s) { return trimSubstring(s, 0, smartLastIndexOf(s, '[')); } 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 Object getOptMC(String field) { return getOpt(mc(), field); } static List cncSubList(List tok, int from, int to) { from &= ~1; to |= 1; return subList(tok, from, to); } 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 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 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(String a, String b) { return a == null ? b == null ? 0 : -1 : a.compareTo(b); } 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 dummyMainClassName(String progID) { return "m" + psI(progID); } static boolean isMultilineQuoted(String s) { if (!startsWith(s, "[")) return false; int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; return i < s.length() && s.charAt(i) == '['; } static String className(Object o) { return getClassName(o); } static int loadPage_defaultTimeout = 60000; static ThreadLocal loadPage_charset = new ThreadLocal(); static boolean loadPage_allowGzip = true, loadPage_debug; static boolean loadPage_anonymous; // 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(); 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 (url.getProtocol().equals("https")) disableCertificateValidation(); 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 (loadPageThroughProxy_enabled) { print("Trying proxy because of: " + e); try { return loadPageThroughProxy(str(url)); } catch (Throwable e2) { print(" " + exceptionToStringShort(e2)); } } else 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) throws IOException { 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 vm_generalSubMap("URLConnection per thread").put(currentThread(), con); loadPage_responseHeaders.set(con.getHeaderFields()); InputStream in = null; try { in = con.getInputStream(); //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 = new InputStreamReader(in, charset); 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 { 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(); } } static String loadPage_guessCharset(String contentType) { Pattern p = Pattern.compile("text/[a-z]+;\\s*charset=([^\\s]+)\\s*"); Matcher m = p.matcher(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 List toLinesFullTrim_java(String text) { return toLinesFullTrim(joinLines(map("javaDropComments", toLinesFullTrim(text)))); } static String _userHome; static String userHome() { if (_userHome == null) { if (isAndroid()) _userHome = "/storage/sdcard0/"; else _userHome = System.getProperty("user.home"); //System.out.println("userHome: " + _userHome); } return _userHome; } static File userHome(String path) { return new File(userDir(), path); } static ThreadLocal tok_typesAndNamesOfParams_keepModifiers = new ThreadLocal(); static List> tok_typesAndNamesOfParams(List tok) { boolean keepModifiers = isTrue(optParam(tok_typesAndNamesOfParams_keepModifiers)); try { List < Pair < String , String > > out = new ArrayList(); for (int i = 1; i < l(tok); ) { String t = tok.get(i); String pre = ""; if (eq(t, "final")) { if (keepModifiers) pre += "final "; 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), ".")) { 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 += "[]"; } name = 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; } } out.add(pair(pre + type, name)); } return out; } catch (Throwable e) { print("Bad parameter declaration: " + sfu(tok)); throw rethrow(e); } } 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); } } static boolean isLongConstant(String s) { if (!s.endsWith("L")) return false; s = s.substring(0, l(s)-1); return isInteger(s); } 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) x.add(callF(f, o)); return x; } static List map(F1 f, Iterable l) { List x = emptyList(l); if (l != null) for (Object o : l) x.add(callF(f, o)); 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); } // 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()) { Map.Entry e = (Map.Entry) _e; x.add(callF(f, e.getKey(), e.getValue())); } return x; } 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 int max(Collection c) { int x = Integer.MIN_VALUE; for (int i : c) x = max(x, i); return 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 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 secondOfPairs(Collection> l) { return map("secondOfPair", l); } static A assertEquals(Object x, A y) { return assertEquals(null, 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 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 boolean isNormalQuoted_dirty(String s) { return startsWith(s, "\"") && endsWith(s, "\"") && l(s) >= 2; } 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 boolean endsWithLetterOrDigit(String s) { return s != null && s.length() > 0 && Character.isLetterOrDigit(s.charAt(s.length()-1)); } static Object first(Object list) { return empty((List) list) ? null : ((List) list).get(0); } 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 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 A first(Pair p) { return p == null ? null : p.a; } static void _handleError(Error e) { call(javax(), "_handleError", e); } static String tok_genEqualsAndHashCode(String className, List> fields) { return "public bool equals(O o) {\r\n if (!o instanceof " + className + ") false;\r\n " + className + " x = cast o;\r\n ret " + join(" && ", map(fields, new F1, Object>() { Object get(Pair p) { try { return // TODO: use == for primitive fields "eq(" + p.b + ", x." + p.b + ")" ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "// TODO: use == for primitive fields\r\n \"eq(\" + p.b + \", x.\" + p.b + \")\""; }})) + ";\r\n }\r\n \r\n public int hashCode() {\r\n int h = " + hashCode(className) + ";\r\n " + concatMap_strings(fields, new F1, Object>() { Object get(Pair p) { try { return "h = h*2+_hashCode(" + p.b + ");\r\n "; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "\"h = h*2+_hashCode(\" + p.b + \");\\r\\n \""; }}) + "ret h;\r\n }\r\n "; } static boolean isGeneralFileServerSnippet(long id) { return id >= 1400000 && id < 1500000; } static Set similarEmptySet(Set m) { if (m instanceof TreeSet) return new TreeSet(((TreeSet) m).comparator()); if (m instanceof LinkedHashSet) return new LinkedHashSet(); return new HashSet(); } static A second(List l) { return get(l, 1); } 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 RuntimeException asRuntimeException(Throwable t) { if (t instanceof Error) _handleError((Error) t); return t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t); } static Class mc() { return main.class; } static void mapPut(Map map, A key, B value) { if (map != null && key != null && value != null) map.put(key, value); } // 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 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 void printStructure(String prefix, Object o) { if (endsWithLetter(prefix)) prefix += ": "; print(prefix + structureForUser(o)); } static void printStructure(Object o) { print(structureForUser(o)); } static File loadLibrary(String snippetID) { return loadBinarySnippet(snippetID); } static void tokAppend(List tok, int i, String s) { tok.set(i, tok.get(i)+s); } 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; 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) { 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 = tok.size()-tokens.length*2; i >= startIdx; i -= 2) { for (int j = 0; j < tokens.length; j++) { String p = tokens[j], t = tok.get(i+j*2); boolean match; 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 String regexpFirstGroupIC(String pat, String s) { Matcher m = regexpIC(pat, s); if (m.find()) return m.group(1); else return null; } static Object collectionMutex(Object o) { String c = className(o); if (eq(c, "java.util.TreeMap$KeySet")) c = className(o = getOpt(o, "m")); else if (eq(c, "java.util.HashMap$KeySet")) c = className(o = get_raw(o, "this$0")); if (eqOneOf(c, "java.util.TreeMap$AscendingSubMap", "java.util.TreeMap$DescendingSubMap")) c = className(o = get_raw(o, "m")); return o; } static boolean isUnproperlyQuoted(String s) { return isNormallyQuoted(s) && !isProperlyQuoted(s); } static boolean containsNewLine(String s) { return contains(s, '\n'); // screw \r, nobody needs it } static Object callOpt(Object o) { if (o == null) return null; return callF(o); } static Object callOpt(Object o, String method, Object... args) { try { if (o == null) return null; if (o instanceof Class) { Method m = callOpt_findStaticMethod((Class) o, method, args, false); if (m == null) return null; m.setAccessible(true); return invokeMethod(m, null, args); /*} else if (o instanceof DynamicMethods) { ret ((DynamicMethods) o)._dynCall(method, args);*/ } else { Method m = callOpt_findMethod(o, method, args, false); if (m == null) return null; m.setAccessible(true); return invokeMethod(m, o, args); } } catch (Exception e) { //fail(e.getMessage() + " | Method: " + method + ", receiver: " + className(o) + ", args: (" + join(", ", map(f className, args) + ")"); throw rethrow(e); } } static Method callOpt_findStaticMethod(Class c, String method, Object[] args, boolean debug) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (!m.getName().equals(method)) { if (debug) System.out.println("Method name mismatch: " + method); continue; } if ((m.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 || !callOpt_checkArgs(m, args, debug)) continue; return m; } c = c.getSuperclass(); } return null; } static Method callOpt_findMethod(Object o, String method, Object[] args, boolean debug) { Class c = o.getClass(); while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (m.getName().equals(method) && callOpt_checkArgs(m, args, debug)) return m; } c = c.getSuperclass(); } return null; } private static boolean callOpt_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 String innerMessage(Throwable e) { return getInnerMessage(e); } static boolean startsWithJavaIdentifierStart(String s) { return nempty(s) && Character.isJavaIdentifierStart(s.charAt(0)); } static Map vm_generalWeakSubMap(Object name) { synchronized(get(javax(), "generalMap")) { Map map = (Map) ( vm_generalMap_get(name)); if (map == null) vm_generalMap_put(name, map = newWeakMap()); return map; } } static String assertIdentifier(String s) { return assertIsIdentifier(s); } 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 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 final Map> getOpt_cache = _registerWeakMap(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 Object getOpt_cached(Object o, String field) { try { if (o == null) return null; Class c = o.getClass(); HashMap map; synchronized(getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } 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 ((DynamicObject) o).fieldValues.get(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(); Class _c = c; do { for (Field f : _c.getDeclaredFields()) { f.setAccessible(true); 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 String structureForUser(Object o) { return beautifyStructure(struct_noStringSharing(o)); } static String formatSnippetIDOpt(String s) { return isSnippetID(s) ? formatSnippetID(s) : s; } 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 Class hotwire(String src) { 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 String loadTextFile(String fileName) { return loadTextFile(fileName, null); } static String loadTextFile(File f, String defaultContents) { try { checkFileNotTooBigToRead(f); if (f == null || !f.exists()) return defaultContents; FileInputStream fileInputStream = new FileInputStream(f); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8"); 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); } // i must point at the (possibly imaginary) opening bracket ("{") // index returned is index of closing bracket + 1 (or l(cnc)) static int findEndOfBlock(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(); } static String tb_mainServer_default = "http://tinybrain.de:8080"; 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 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 File makeTempDir() { return (File) call(getJavaX(), "TempDirMaker_make"); } static A setThreadLocal(ThreadLocal tl, A value) { A old = tl.get(); tl.set(value); return old; } static boolean isInRAMDisk(File f) { return startsWith(f2s(f), "/dev/shm"); } static String muricaCredentialsQuery() { return htmlQuery(muricaCredentials()); } 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 List reversed(Collection l) { return reversedList(l); } static List reversed(A[] l) { return reversedList(asList(l)); } static String reversed(String s) { return reversedString(s); } 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 List> innerClasses(List tok) { if (tok == null) return emptyList(); int i = 1; while (i < tok.size() && !tok.get(i).equals("{")) i += 2; return allClasses(tok.subList(i+1, tok.size())); } static boolean startsWith(String a, String b) { return a != null && a.startsWith(b); } static boolean startsWith(String a, char c) { return nempty(a) && a.charAt(0) == c; } static boolean startsWith(String a, String b, Matches m) { if (!startsWith(a, b)) return false; m.m = new String[] {substring(a, l(b))}; return true; } static boolean startsWith(List a, List b) { if (a == null || l(b) > l(a)) return false; for (int i = 0; i < l(b); i++) if (neq(a.get(i), b.get(i))) return false; return true; } static List beginCriticalAction_inFlight = synchroList(); static class CriticalAction { String description; CriticalAction() {} CriticalAction(String description) { this.description = description;} void done() { beginCriticalAction_inFlight.remove(this); } } static CriticalAction beginCriticalAction(String description) { ping(); CriticalAction c = new CriticalAction(description); beginCriticalAction_inFlight.add(c); return c; } static void cleanMeUp_beginCriticalAction() { int n = 0; while (nempty(beginCriticalAction_inFlight)) { int m = l(beginCriticalAction_inFlight); if (m != n) { n = m; try { print("Waiting for " + n2(n, "critical actions") + ": " + join(", ", collect(beginCriticalAction_inFlight, "description"))); } catch (Throwable __e) { printStackTrace2(__e); } } sleepInCleanUp(10); } } static String[] dropLast(String[] a, int n) { n = Math.min(n, a.length); String[] b = new String[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 void printWithTime(String s) { print(hmsWithColons() + ": " + s); } static String loadPage_utf8(URL url) { return loadPage_utf8(url.toString()); } static String loadPage_utf8(String url) { loadPage_charset.set("UTF-8"); try { return loadPage(url); } finally { loadPage_charset.set(null); } } 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 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 String replacePrefix(String prefix, String replacement, String s) { if (!startsWith(s, prefix)) return s; return replacement + substring(s, l(prefix)); } static boolean isProperlyQuoted(String s) { return s.length() >= 2 && s.startsWith("\"") && s.endsWith("\"") && (!s.endsWith("\\\"") || s.endsWith("\\\\\"")); } 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)); ctr.setAccessible(true); } } 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 : c.getDeclaredConstructors()) if (m.getParameterTypes().length == 0) return m; throw fail("No default constructor declared in " + c.getName()); } 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 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 synchronizedMap() { return synchroMap(); } static String exceptionToStringShort(Throwable e) { 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; } static Throwable getInnerException(Throwable e) { while (e.getCause() != null) e = e.getCause(); return e; } static String javaDropComments(String s) { return javaDropAllComments(s); } static A optParam(ThreadLocal tl, A defaultValue) { return optPar(tl, defaultValue); } static A optParam(ThreadLocal tl) { return optPar(tl); } static A optParam(Object[] opt, String name, A 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 A optParam(Object[] opt, String name) { return optParam(opt, name, null); } static void saveTranspiledCode(String progID, String code) { File dir = getCodeProgramDir(progID); new File(dir, "Transpilation").delete(); saveGZTextFile(new File(dir, "Transpilation.gz"), code); } 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 A getAndClearThreadLocal(ThreadLocal tl) { A a = tl.get(); tl.set(null); return a; } static boolean jsonDecode_useOrderedMaps = true; static Object jsonDecode(final String text) { final List tok = jsonTok(text); class Y { int i = 1; Object parse() { String t = tok.get(i); if (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)) { i += 2; if (eq(get(tok, i), ".")) { String x = t + "." + get(tok, i+2); i += 4; double d = parseDouble(x); if (minus) d = -d; return d; } else { long l = parseLong(t); if (minus) l = -l; return l != (int) l ? new Long(l) : new Integer((int) l); } } throw new RuntimeException("Unknown token " + (i+1) + ": " + t + ": " + text); } Object parseList() { consume("["); List list = new ArrayList(); while (!tok.get(i).equals("]")) { list.add(parse()); if (tok.get(i).equals(",")) i += 2; } consume("]"); return list; } Object parseMap() { consume("{"); Map map = jsonDecode_useOrderedMaps ? new LinkedHashMap() : new TreeMap(); while (!tok.get(i).equals("}")) { String key = unquote(tok.get(i)); i += 2; consume(":"); Object value = parse(); 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; } } return new Y().parse(); } 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 Comparator caseInsensitiveComparator() { return betterCIComparator(); } 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 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 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 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 URLConnection openConnection(URL url) { try { ping(); callOpt(javax(), "recordOpenURLConnection", str(url)); return url.openConnection(); } catch (Exception __e) { throw rethrow(__e); } } static B secondOfPair(Pair p) { return p == null ? null : p.b; } /** writes safely (to temp file, then rename) */ public static void saveBinaryFile(String fileName, byte[] contents) throws IOException { File file = new File(fileName); File parentFile = file.getParentFile(); if (parentFile != null) parentFile.mkdirs(); String tempFileName = fileName + "_temp"; FileOutputStream fileOutputStream = newFileOutputStream(tempFileName); fileOutputStream.write(contents); fileOutputStream.close(); 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); } static void saveBinaryFile(File fileName, byte[] contents) { try { saveBinaryFile(fileName.getPath(), contents); } catch (IOException e) { throw new RuntimeException(e); } } 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 int hashCode(Object a) { return a == null ? 0 : a.hashCode(); } 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(String path, boolean append) throws IOException { mkdirsForFile(path); FileOutputStream f = new // Line break for ancient translator FileOutputStream(path, append); callJavaX("registerIO", f, path, true); return f; } 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 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 GZIPInputStream newGZIPInputStream(File f) { return gzInputStream(f); } static GZIPInputStream newGZIPInputStream(InputStream in) { return gzInputStream(in); } static TreeSet toCaseInsensitiveSet(Collection c) { // TODO: check if it already is a CI set TreeSet set = caseInsensitiveSet(); if (c != null) set.addAll(c); return set; } static TreeSet toCaseInsensitiveSet(String... x) { TreeSet set = caseInsensitiveSet(); addAll(set, x); return set; } static String asString(Object o) { return o == null ? null : o.toString(); } static Object vm_generalMap_put(Object key, Object value) { return mapPutOrRemove(vm_generalMap(), key, value); } static boolean isSubtypeOf(Class a, Class b) { return b.isAssignableFrom(a); // << always hated that method, let's replace it! } // 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 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 Matcher regexpIC(String pat, String s) { return Pattern.compile(pat, Pattern.CASE_INSENSITIVE).matcher(s); } static Pattern regexpIC(String pat) { return Pattern.compile(pat, Pattern.CASE_INSENSITIVE); } static String myJavaSource_code; static String myJavaSource() { return myJavaSource_code; } static boolean _inCore() { return false; } static String assertIsIdentifier(String s) { if (!isIdentifier(s)) throw fail("Not an identifier: " + quote(s)); return s; } static Map newWeakMap() { return newWeakHashMap(); } static boolean endsWithLetter(String s) { return nempty(s) && isLetter(last(s)); } static volatile boolean disableCertificateValidation_attempted; static void disableCertificateValidation() { try { if (disableCertificateValidation_attempted) return; disableCertificateValidation_attempted = true; try { // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkClientTrusted(X509Certificate[] certs, String authType) {} public void checkServerTrusted(X509Certificate[] certs, String authType) {} }}; // Ignore differences between given hostname and certificate hostname HostnameVerifier hv = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; // Install the all-trusting trust manager SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(hv); } catch (Throwable __e) { printStackTrace2(__e); } } catch (Exception __e) { throw rethrow(__e); } } static A vm_generalMap_get(Object key) { return (A) vm_generalMap().get(key); } static List getJavaModifiers_list = litlist("static", "abstract", "public", "private", "protected", "final", "native", "volatile", "synchronized", "transient"); static List getJavaModifiers() { return getJavaModifiers_list; } static int[] toIntArray(List l) { int[] a = new int[l(l)]; for (int i = 0; i < a.length; i++) a[i] = l.get(i); return a; } static String afterLineBreak(String s) { return substring(s, lastIndexOf(s, '\n')+1); } static boolean isNormallyQuoted(String s) { return startsWith(s, "\""); } static Map synchroMap() { return synchroHashMap(); } static Map synchroMap(Map map) { return Collections.synchronizedMap(map); } static double parseDouble(String s) { return Double.parseDouble(s); } static ThreadLocal < VF1 < File > > checkFileNotTooBigToRead_tl = new ThreadLocal(); static void checkFileNotTooBigToRead(File f) { callF(checkFileNotTooBigToRead_tl.get(), f); } static File[] listFiles(File dir) { File[] files = dir.listFiles(); return files == null ? new File[0] : files; } static File[] listFiles(String dir) { return listFiles(new File(dir)); } 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); 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 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) value = ((Long) value).intValue(); if (type == LinkedHashMap.class && value instanceof Map) { f.set(o, asLinkedHashMap((Map) value)); return; } throw e; } } 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); } } static String aGlobalID() { return randomID(globalIDLength()); } 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 matching arguments 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) { m.setAccessible(true); multiMapPut(callMC_cache, m.getName(), m); } c = c.getSuperclass(); } } } 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 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 void setOptAllDyn(DynamicObject o, Map fields) { if (fields == null) return; HashMap fieldMap = instanceFieldsMap(o); for (Map.Entry e : fields.entrySet()) { String field = e.getKey(); Object val = e.getValue(); boolean has = fieldMap.containsKey(field); if (has) setOpt(o, field, val); else { o.fieldValues.put(intern(field), val); } } } static File loadBinarySnippet(String snippetID) { try { long id = parseSnippetID(snippetID); File f = DiskSnippetCache_getLibrary(id); if (fileSize(f) == 0) f = loadDataSnippetToFile(snippetID); return f; } catch (Exception __e) { throw rethrow(__e); } } static Map vm_generalSubMap(Object name) { synchronized(get(javax(), "generalMap")) { Map map = (Map) ( vm_generalMap_get(name)); if (map == null) vm_generalMap_put(name, map = synchroMap()); return map; } } static String hideCredentials(URL url) { return url == null ? null : hideCredentials(str(url)); } static String hideCredentials(String url) { return url.replaceAll("([&?])(_pass|key)=[^&\\s\"]*", "$1$2="); } static String hideCredentials(Object o) { return hideCredentials(str(o)); } 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; return (o instanceof Class ? (Class) o : o.getClass()).getClassLoader().loadClass("main"); } catch (Exception __e) { throw rethrow(__e); } } static String intern(String s) { return fastIntern(s); } static String reversedString(String s) { return reverseString(s); } 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 joinLines(List lines) { return fromLines(lines); } static String joinLines(String glue, String text) { return join(glue, toLines(text)); } static boolean checkCondition(Object condition, Object... args) { return isTrue(callF(condition, args)); } 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)) || "'".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 ++j; String t = quickSubstring(s, i, j); i = j; return t; } }; } static SortedMap synchronizedTreeMap() { return synchroTreeMap(); } static boolean warn_on = true; 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); } 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 String beautifyStructure(String s) { return structure_addTokenMarkers(s); } // usually L static String fromLines(Collection 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 A callJavaX(String method, Object... args) { return (A) callOpt(getJavaX(), method, args); } 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 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 void consoleClearInput() { consoleSetInput(""); } 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 String beforeLineBreak(String s) { int i = smartIndexOf(s, '\n'); if (i > 0 && s.charAt(i-1) == '\r') --i; return substring(s, 0, i); } static A nuStubInnerObject(Class c) { return nuStubInnerObject(c, null); } static A nuStubInnerObject(Class c, Object classFinder) { try { Class outerType = getOuterClass(c, classFinder); Constructor m = c.getDeclaredConstructor(outerType); m.setAccessible(true); return (A) m.newInstance(new Object[] {null}); } catch (Exception __e) { throw rethrow(__e); } } static String struct_noStringSharing(Object o) { structure_Data d = new structure_Data(); d.noStringSharing = true; return structure(o, d); } static File getCanonicalFile(File f) { try { return f == null ? null : f.getCanonicalFile(); } catch (Exception __e) { throw rethrow(__e); } } static String htmlQuery(Map params) { return params.isEmpty() ? "" : "?" + makePostData(params); } static String htmlQuery(Object... data) { return htmlQuery(litmap(data)); } static void put(Map map, A a, B b) { if (map != null) map.put(a, b); } 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 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 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 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) { f.setAccessible(true); 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) { f.setAccessible(true); 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 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 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 int smartLastIndexOf(String s, char c) { if (s == null) return 0; int i = s.lastIndexOf(c); return i >= 0 ? i : l(s); } 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 standardCredentialsUser() { return trim(loadTextFile(new File(userHome(), ".tinybrain/username"))); } 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() { 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; } public static void 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(); } } catch (Exception __e) { throw rethrow(__e); } } static float parseFloat(String s) { return Float.parseFloat(s); } static String getInnerMessage(Throwable e) { if (e == null) return null; return getInnerException(e).getMessage(); } 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 Map emptyMap() { return new HashMap(); } 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) { for (int i = start; i < s.length(); i++) { char c = s.charAt(i); if (c == '\r' || c == '\n') return i; } return -1; } static String internIfLongerThan(String s, int l) { return s == null ? null : l(s) >= l ? intern(s) : s; } static void pcallOpt_noArgs(Object o, String method) { try { callOpt_noArgs(o, method); } catch (Throwable __e) { printStackTrace2(__e); } } static WeakReference newWeakReference(A a) { return a == null ? null : new WeakReference(a); } static File getProgramDir() { return programDir(); } static File getProgramDir(String snippetID) { return programDir(snippetID); } static Object[] muricaCredentials() { String pass = muricaPassword(); return nempty(pass) ? new Object[] {"_pass", pass } : new Object[0]; } // 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 = l(a); for (; i < n; i++) if (eqic(a.get(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 A assertEqualsVerbose(Object x, A y) { assertEqualsVerbose((String) null, x, y); return y; } static A assertEqualsVerbose(String msg, Object x, A y) { if (!eq(x, y)) { throw fail((msg != null ? msg + ": " : "") + /*sfu*/(y) + " != " + /*sfu*/(x)); } else print("OK: " + /*sfu*/(x)); return y; } static final boolean loadPageThroughProxy_enabled = false; static String loadPageThroughProxy(String url) { return null; } static void hotwire_copyOver(Class c) { synchronized(StringBuffer.class) { // 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())); } } 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 ThreadLocal assertVerbose_value = new ThreadLocal(); static void assertVerbose(boolean b) { assertVerbose_value.set(b); } static boolean assertVerbose() { return isTrue(assertVerbose_value.get()); } 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 sortFilesByName(List l) { sort(l, new Comparator() { public int compare(File a, File b) { return stdcompare(a.getName(), b.getName()); } }); } 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); return pair(tokenToCharIndex(tok, /*tossCoin() ?*/ i /*: j*/), "Bad hygiene - brackets don't match (" + quote(a) + " vs " + quote(b) + ") at lines " + lineNr1 + " and " + lineNr2); } } 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 String makePostData(Map map) { List l = new ArrayList(); for (Map.Entry e : map.entrySet()) { String key = (String) ( e.getKey()); Object val = e.getValue(); if (val != null) { String value = str(val); //structureOrText(val); l.add(urlencode(key) + "=" + urlencode(/*escapeMultichars*/(value))); } } return join("&", l); } static String makePostData(Object... params) { return makePostData(litorderedmap(params)); } 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 boolean call_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 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.length == 0) return nuObjectWithoutArguments(c); // cached! Constructor m = nuObject_findConstructor(c, args); m.setAccessible(true); return (A) m.newInstance(args); } catch (Exception __e) { throw rethrow(__e); } } static Constructor nuObject_findConstructor(Class c, Object... args) { for (Constructor m : c.getDeclaredConstructors()) { 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 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 void sleepSeconds(double s) { if (s > 0) sleep(round(s*1000)); } 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 int latestInstalledJavaX() { File[] files = new File(userHome(), ".javax").listFiles(); int v = 0; if (files != null) for (File f : files) { Matcher m = Pattern.compile("x(\\d\\d\\d?)\\.jar").matcher(f.getName()); if (m.matches()) v = Math.max(v, Integer.parseInt(m.group(1))); } return v; } static int lUtf8(String s) { return l(utf8(s)); } static String standardCredentialsPass() { return trim(loadTextFile(new File(userHome(), ".tinybrain/userpass"))); } static char lastChar(String s) { return empty(s) ? '\0' : s.charAt(l(s)-1); } static File userDir() { return new File(userHome()); } static File userDir(String path) { return new File(userHome(), path); } 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 Throwable getExceptionCause(Throwable e) { Throwable c = e.getCause(); return c != null ? c : e; } static String reverseString(String s) { return new StringBuilder(s).reverse().toString(); } 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 String quickSubstring(String s, int i, int j) { if (i == j) return ""; return s.substring(i, j); } static volatile boolean sleep_noSleep; 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 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 String n(MultiSet ms, String name) { return n(l(ms), name); } 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 : c.getDeclaredConstructors()) if (empty(m.getParameterTypes())) { m.setAccessible(true); return m; } throw fail("No default constructor found in " + c.getName()); } static HashMap instanceFieldsMap(Object o) { Class c = o.getClass(); HashMap map; synchronized(getOpt_cache) { map = getOpt_cache.get(c); if (map == null) map = getOpt_makeCache(c); } 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 return null; } return result.toArray(new String[result.size()]); } static String prependIfNempty(String prefix, String s) { return empty(s) ? s : prefix + s; } static void setOptIfNotNull(Object o, String field, Object value) { if (value != null) setOpt(o, field, value); } static void warnIfOddCount(Object... list) { if (odd(l(list))) printStackTrace("Odd list size: " + list); } static Map synchroHashMap() { return Collections.synchronizedMap(new HashMap()); } static List classNames(Collection l) { return getClassNames(l); } static List classNames(Object[] l) { return getClassNames(Arrays.asList(l)); } 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 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 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); if (classFinder != null) return (Class) callF(classFinder, name); return Class.forName(name); } catch (Exception __e) { throw rethrow(__e); } } static int globalIDLength() { return 16; } static void sleepInCleanUp(long ms) { try { if (ms < 0) return; Thread.sleep(ms); } catch (Exception __e) { throw rethrow(__e); } } static boolean even(int i) { return (i & 1) == 0; } static boolean even(long i) { return (i & 1) == 0; } static SortedMap synchroTreeMap() { return Collections.synchronizedSortedMap(new TreeMap()); } static String n2(long l) { return formatWithThousands(l); } static String n2(Collection l) { return n2(l(l)); } static String n2(long l, String singular, String plural) { return n_fancy2(l, singular, plural); } static String n2(long l, String singular) { return n_fancy2(l, singular, singular + "s"); } 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(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(MultiSet ms, String singular, String plural) { return n_fancy2(ms, singular, plural); } 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 void sort(T[] a, Comparator c) { Arrays.sort(a, c); } static void sort(T[] a) { Arrays.sort(a); } static void sort(List a, Comparator c) { Collections.sort(a, c); } static void sort(List a) { Collections.sort(a); } static List collect(Collection c, String field) { return collectField(c, field); } static List collect(String field, Collection c) { return collectField(c, field); } static A println(A a) { return print(a); } 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 String upper(String s) { return s == null ? null : s.toUpperCase(); } 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 String javaDropAllComments(String s) { List tok = javaTok(s); for (int i = 0; i < l(tok); i += 2) tok.set(i, tok_javaDropCommentsFromWhitespace(tok.get(i))); return join(tok); } static A assertNotNull(A a) { assertTrue(a != null); return a; } static A assertNotNull(String msg, A a) { assertTrue(msg, a != null); return a; } static int tokenIndexToUserLandLineNr(List tok, int tokenIndex) { return charIndexToUserLandLineNr(join(tok), tokenIndexToCharIndex(tok, tokenIndex)); } static Object mainBot; static Object getMainBot() { return mainBot; } 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 new GZIPInputStream(new FileInputStream(f), bufferSize); } catch (Exception __e) { throw rethrow(__e); } } static GZIPInputStream gzInputStream(InputStream in) { try { return new GZIPInputStream(in, gzInputStream_defaultBufferSize); } catch (Exception __e) { throw rethrow(__e); } } static String structure_addTokenMarkers(String s) { List tok = javaTok(s); // 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 s; // add markers for (int i : refs) { int idx = i*2+1; String t = ""; if (endsWithLetterOrDigit(tok.get(idx-1))) t = " "; tok.set(idx, t + "m" + i + " " + tok.get(idx)); } return join(tok); } 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(), formatSnippetID(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 IterableIterator linesFromFile(File f) { try { if (!f.exists()) return emptyIterableIterator(); if (ewic(f.getName(), ".gz")) return linesFromReader(utf8bufferedReader(newGZIPInputStream(f))); return linesFromReader(utf8bufferedReader(f)); } catch (Exception __e) { throw rethrow(__e); } } static List jsonTok(String s) { List tok = new ArrayList(); 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 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 void printException(Throwable e) { printStackTrace(e); } static void consoleSetInput(final String text) { if (headless()) return; setTextAndSelectAll(consoleInputField(), text); focusConsole(); } static File loadDataSnippetToFile(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("http://data.tinybrain.de/blobs/" + psI(snippetID))); 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 volatile boolean muricaPassword_pretendNotAuthed; static String muricaPassword() { if (muricaPassword_pretendNotAuthed) return null; return trim(loadTextFile(muricaPasswordFile())); } static List synchroList() { return Collections.synchronizedList(new ArrayList()); } static List synchroList(List l) { return Collections.synchronizedList(l); } 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 boolean isLinux() { return !isWindows() && !isMac() && !isAndroid(); } 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; } // 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); } // 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 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("http://data.tinybrain.de/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 String getComputerID_quick() { return computerID(); } 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 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 int tokenIndexToCharIndex(List tok, int tokenIndex) { return tokenToCharIndex(tok, tokenIndex); } static byte[] utf8(String s) { return toUtf8(s); } static List parseList(String s) { return (List) safeUnstructure(s); } static void saveGZTextFile(File file, String contents) { 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, "UTF-8"); 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 baseClassName(String className) { return substring(className, className.lastIndexOf('.')+1); } static String baseClassName(Object o) { return baseClassName(getClassName(o)); } static List getClasses(Object[] array) { List l = new ArrayList(); for (Object o : array) l.add(_getClass(o)); return l; } static int indexOfIgnoreCase_manual(String a, String b) { int la = l(a), lb = l(b); if (la < lb) return -1; int n = la-lb; loop: for (int i = 0; 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 LinkedHashMap litorderedmap(Object... x) { LinkedHashMap map = new LinkedHashMap(); litmap_impl(map, x); return map; } 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) { m.setAccessible(true); 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 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 betterCIComparator_C betterCIComparator_instance; static betterCIComparator_C betterCIComparator() { if (betterCIComparator_instance == null) betterCIComparator_instance = new betterCIComparator_C(); return betterCIComparator_instance; } 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 long fileSize(String path) { return getFileSize(path); } static long fileSize(File f) { return getFileSize(f); } static String loadGZTextFile(File file) { try { if (!file.isFile()) return null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream fis = new FileInputStream(file); GZIPInputStream gis = newGZIPInputStream(fis); try { byte[] buffer = new byte[1024]; int len; while((len = gis.read(buffer)) != -1){ baos.write(buffer, 0, len); } } finally { fis.close(); } baos.close(); return fromUtf8(baos.toByteArray()); // TODO: use a Reader } catch (Exception __e) { throw rethrow(__e); } } 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 boolean isLetter(char c) { return Character.isLetter(c); } static String hmsWithColons() { return hmsWithColons(now()); } static String hmsWithColons(long time) { return new SimpleDateFormat("HH:mm:ss").format(time); } static Map classForName_cache = synchroHashMap(); static Class classForName(String name) { try { Class c = classForName_cache.get(name); if (c == null) classForName_cache.put(name, c = Class.forName(name)); return c; } catch (Exception __e) { throw rethrow(__e); } } static int randomID_defaultLength = 12; static String randomID(int length) { return makeRandomID(length); } static String randomID() { return randomID(randomID_defaultLength); } static long round(double d) { return Math.round(d); } public static boolean isWindows() { return System.getProperty("os.name").contains("Windows"); } static List getPlural_specials = ll("sheep", "fish"); static String getPlural(String s) { if (containsIgnoreCase(getPlural_specials, s)) return s; if (ewic(s, "y")) return dropSuffixIgnoreCase("y", s) + "ies"; if (ewic(s, "ss")) return s + "es"; if (ewic(s, "s")) return s; return s + "s"; } static JTextField setTextAndSelectAll(final JTextField tf, final String text) { { swing(new Runnable() { public void run() { try { tf.setText(text); tf.selectAll(); } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "tf.setText(text);\r\n tf.selectAll();"; }}); } return tf; } static String formatWithThousands(long l) { return formatWithThousandsSeparator(l); } 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 File muricaPasswordFile() { return new File(javaxSecretDir(), "murica/muricaPasswordFile"); } 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 getClass(realm).getClassLoader().loadClass(classNameToVM(name)); } catch (Exception __e) { throw rethrow(__e); } } 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 String n_fancy2(MultiSet ms, String singular, String plural) { return n_fancy2(l(ms), singular, plural); } static byte[] toUtf8(String s) { try { return s.getBytes("UTF-8"); } catch (Exception __e) { throw rethrow(__e); } } static IterableIterator linesFromReader(Reader r) { final BufferedReader br = bufferedReader(r); return iteratorFromFunction_f0(new F0() { String get() { try { return readLineFromReaderWithClose(br) ; } catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "readLineFromReaderWithClose(br)"; }}); } static String makeRandomID(int length) { Random random = new 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 void focusConsole(String s) { setConsoleInput(s); focusConsole(); } static void focusConsole() { JComponent tf = consoleInputFieldOrComboBox(); if (tf != null) { //print("Focusing console"); tf.requestFocus(); } } static String dataSnippetLink(String snippetID) { long id = parseSnippetID(snippetID); if (id >= 1100000 && id < 1200000) return "http://ai1.space/images/raw/" + id; if (id >= 1400000 && id < 1500000) return "http://butter.botcompany.de:8080/files/" + id + "?_pass=" + muricaPassword(); if (id >= 1200000 && id < 1300000) { // Woody files, actually String pw = muricaPassword(); if (empty(pw)) throw fail("Please set 'murica password by running #1008829"); return "http://butter.botcompany.de:8080/1008823/raw/" + id + "?_pass=" + pw; // XXX, although it typically gets hidden when printing } else return "http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_" + id + "&contentType=application/binary"; } static long getFileSize(String path) { return path == null ? 0 : new File(path).length(); } static long getFileSize(File f) { return f == null ? 0 : f.length(); } // 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)) { m.setAccessible(true); return m; } c = c.getSuperclass(); } return null; } static Object safeUnstructure(String s) { return unstructure(s, true); } static PersistableThrowable persistableThrowable(Throwable e) { return e == null ? null : new PersistableThrowable(e); } 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 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 { 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 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 sub) { return newFile(javaxDataDir(), sub); } 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 int charDiff(char a, char b) { return (int) a-(int) b; } static int charDiff(String a, char b) { return charDiff(stringToChar(a), b); } static boolean equalsIgnoreCase(String a, String b) { return eqic(a, b); } static boolean equalsIgnoreCase(char a, char b) { return eqic(a, b); } static volatile String caseID_caseID; static String caseID() { return caseID_caseID; } static void caseID(String id) { caseID_caseID = id; } static boolean isMac() { return System.getProperty("os.name").toLowerCase().contains("mac"); } static Map singular_specials = litmap( "children", "child", "images", "image", "chess", "chess"); static Set singular_specials2 = litset("time", "machine", "line"); static String singular(String s) { if (s == null) return null; { String _a_1168 = singular_specials.get(s); if (!empty(_a_1168)) return _a_1168; } //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 IterableIterator emptyIterableIterator_instance = new IterableIterator() { public Object next() { throw fail(); } public boolean hasNext() { return false; } }; static IterableIterator emptyIterableIterator() { return emptyIterableIterator_instance; } static A addAndReturn(Collection c, A a) { if (c != null) c.add(a); return a; } static List collectField(Collection c, String field) { List l = new ArrayList(); for (Object a : c) l.add(getOpt(a, field)); return l; } static List collectField(String field, Collection c) { return collectField(c, field); } static String _computerID; static Lock computerID_lock = lock(); public static String computerID() { if (_computerID == null) { Lock _lock_1175 = computerID_lock; lock(_lock_1175); 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); saveTextFile(file, _computerID); } } finally { unlock(_lock_1175); } } return _computerID; } static JTextField consoleInputField() { Object console = get(getJavaX(), "console"); return (JTextField) getOpt(console, "tfInput"); } static boolean headless() { return isHeadless(); } static void upgradeJavaXAndRestart() { run("#1001639"); restart(); sleep(); } 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 List allToString(Collection 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; } static BufferedReader utf8bufferedReader(InputStream in) { try { return new BufferedReader(new InputStreamReader(in, "UTF-8")); } catch (Exception __e) { throw rethrow(__e); } } static BufferedReader utf8bufferedReader(File f) { try { return utf8bufferedReader(newFileInputStream(f)); } catch (Exception __e) { throw rethrow(__e); } } static boolean sameSnippetID(String a, String b) { if (!isSnippetID(a) || !isSnippetID(b)) return false; return parseSnippetID(a) == parseSnippetID(b); } 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 String fromUtf8(byte[] bytes) { try { return new String(bytes, "UTF-8"); } catch (Exception __e) { throw rethrow(__e); } } 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 HashSet litset(A... items) { return lithashset(items); } static String dropSuffixIgnoreCase(String suffix, String s) { return ewic(s, suffix) ? s.substring(0, l(s)-l(suffix)) : s; } static Object swing(Object f) { return swingAndWait(f); } static A swing(F0 f) { return (A) swingAndWait(f); } static String readLineFromReaderWithClose(BufferedReader r) { try { String s = r.readLine(); if (s == null) r.close(); return s; } catch (Exception __e) { throw rethrow(__e); } } static void setConsoleInput(String text) { consoleSetInput(text); } static IterableIterator iteratorFromFunction_f0(final F0 f) { class IFF2 extends IterableIterator { A a; boolean done; 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 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(total, 100000)))); total += n; } } catch (Exception __e) { throw rethrow(__e); } } static BufferedReader bufferedReader(Reader r) { return r instanceof BufferedReader ? (BufferedReader) r : new BufferedReader(r); } 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; m.m = new String[] { substring(a, 0, l(a)-l(b)) }; return true; } static void renameFile_assertTrue(File a, File b) { try { 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)); } catch (Exception __e) { throw rethrow(__e); } } static File computerIDFile() { return javaxDataDir("Basic Info/computer-id.txt"); } static char stringToChar(String s) { if (l(s) != 1) throw fail("bad stringToChar: " + s); return firstChar(s); } public static File mkdirsFor(File file) { return mkdirsForFile(file); } static JComponent consoleInputFieldOrComboBox() { Object console = get(getJavaX(), "console"); JComboBox cb = (JComboBox) ( getOpt(console, "cbInput")); if (cb != null) return cb; return (JTextField) getOpt(console, "tfInput"); } static Class run(String progID, String... args) { Class main = hotwire(progID); callMain(main, args); return main; } static void unlock(Lock lock, String msg) { if (lock == null) return; print("Unlocking: " + msg); lock.unlock(); } static void unlock(Lock lock) { if (lock == null) return; lock.unlock(); } static String classNameToVM(String name) { return name.replace(".", "$"); } static String afterLastSpace(String s) { return s == null ? null : substring(s, s.lastIndexOf(' ')+1); } static FileInputStream newFileInputStream(File path) throws IOException { return newFileInputStream(path.getPath()); } static FileInputStream newFileInputStream(String path) throws IOException { FileInputStream f = new // Line break for ancient translator FileInputStream(path); //callJavaX("registerIO", f, path, true); return f; } static void restart() { Object j = getJavaX(); call(j, "cleanRestart", get(j, "fullArgs")); } static Class getClass(String name) { try { return Class.forName(name); } catch (ClassNotFoundException e) { return null; } } static Class getClass(Object o) { return o instanceof Class ? (Class) o : o.getClass(); } static Class getClass(Object realm, String name) { try { try { return getClass(realm).getClassLoader().loadClass(classNameToVM(name)); } catch (ClassNotFoundException e) { return null; } } catch (Exception __e) { throw rethrow(__e); } } static String formatWithThousandsSeparator(long l) { return NumberFormat.getInstance(new Locale("en_US")).format(l); } static void swingAndWait(Runnable r) { try { if (isAWTThread()) r.run(); else EventQueue.invokeAndWait(addThreadInfoToRunnable(r)); } catch (Exception __e) { throw rethrow(__e); } } static Object swingAndWait(final Object f) { if (isAWTThread()) return callF(f); else { final 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 boolean regionMatchesIC(String a, int offsetA, String b, int offsetB, int len) { return a != null && a.regionMatches(true, offsetA, b, offsetB, len); } static char firstChar(String s) { return s.charAt(0); } static int roundDownTo(int x, int n) { return x/n*n; } static long roundDownTo(long x, long n) { return x/n*n; } 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 Object _threadInfo_f; static Object _threadInfo() { return callF(_threadInfo_f); } static void _inheritThreadInfo(Object info) { _threadInheritInfo(info); } static Runnable asRunnable(Object o) { return toRunnable(o); } static Object _threadInheritInfo_f; static void _threadInheritInfo(Object info) { callF(_threadInheritInfo_f, info); } static Runnable toRunnable(final Object o) { 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 abstract class VF1 { abstract void get(A a); }static interface Producer { public A next(); }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 { A v; // you can access this directly if you use one thread Var() {} Var(A v) { this.v = v;} 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 synchronized void clear() { v = null; } public String toString() { return str(get()); } }static class AutoInitVar extends Var { Object make; boolean has; Lock lock = lock(); AutoInitVar() {} AutoInitVar(Object make) { this.make = make;} public A get() { if (has) return super.get(); Lock _lock_1271 = lock; lock(_lock_1271); try { if (has) return super.get(); set((A) pcallF(make)); make = null; has = true; return super.get(); } finally { unlock(_lock_1271); } } }static class PersistableThrowable { String className; String msg; String stacktrace; PersistableThrowable() {} PersistableThrowable(Throwable 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; } }static abstract class TokCondition { abstract boolean get(List tok, int i); // i = N Index }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(); } }static class Pair implements Comparable> { A a; 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 interface IVar { void set(A a); A get(); boolean has(); void clear(); } static UnsupportedOperationException unsupportedOperation() { throw new UnsupportedOperationException(); } static int hashCodeFor(Object a) { return a == null ? 0 : a.hashCode(); } static Iterator iterator(Iterable c) { return c == null ? emptyIterator() : c.iterator(); } 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) { return null; } } static B pcallF(F1 f, A a) { try { return f == null ? null : f.get(a); } catch (Throwable __e) { return null; } } static Object pcallFunction(Object f, Object... args) { try { return callFunction(f, args); } catch (Throwable __e) { printStackTrace2(__e); } return null; } static Object callFunction(Object f, Object... args) { return callF(f, args); } }