diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index e7d01835f..a988bef88 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -2739,10 +2739,11 @@ public class JavaEditor extends Editor { * Replace all numbers with variables and add code to initialize * these variables and handle update messages. */ - //public boolean automateSketch(Sketch sketch, ArrayList handles[]) - protected boolean automateSketch(Sketch sketch, List> handles) { + protected boolean automateSketch(Sketch sketch, SketchParser parser) { SketchCode[] code = sketch.getCode(); + List> handles = parser.allHandles; + if (code.length < 1) { return false; } @@ -2751,8 +2752,8 @@ public class JavaEditor extends Editor { return false; } - int setupStartPos = SketchParser.getSetupStart(baseCode[0]); - if (setupStartPos < 0) { + int setupEndPos = SketchParser.getSetupEnd(baseCode[0]); + if (setupEndPos < 0) { return false; } @@ -2794,7 +2795,7 @@ public class JavaEditor extends Editor { } code[tab].setProgram(c); } - + // add the main header to the code in the first tab String c = code[0].getProgram(); @@ -2849,8 +2850,8 @@ public class JavaEditor extends Editor { " tweakmode_initAllVars();\n"+ " tweakmode_initCommunication();\n\n"; - setupStartPos = SketchParser.getSetupStart(c); - c = replaceString(c, setupStartPos, setupStartPos, addToSetup); + setupEndPos = SketchParser.getSetupEnd(c); + c = replaceString(c, setupEndPos, setupEndPos, addToSetup); code[0].setProgram(header + c); diff --git a/java/src/processing/mode/java/JavaMode.java b/java/src/processing/mode/java/JavaMode.java index 50a6a083e..9933cfcba 100644 --- a/java/src/processing/mode/java/JavaMode.java +++ b/java/src/processing/mode/java/JavaMode.java @@ -167,7 +167,6 @@ public class JavaMode extends Mode { RunnerListener listener, final boolean present) throws SketchException { final JavaEditor editor = (JavaEditor)listener; - boolean launchInteractive = false; if (isSketchModified(sketch)) { editor.deactivateRun(); @@ -193,7 +192,7 @@ public class JavaMode extends Mode { final SketchParser parser = new SketchParser(editor.baseCode, requiresTweak); // add our code to the sketch - launchInteractive = editor.automateSketch(sketch, parser.allHandles); + final boolean launchInteractive = editor.automateSketch(sketch, parser); build = new JavaBuild(sketch); appletClassName = build.build(false); @@ -204,8 +203,10 @@ public class JavaMode extends Mode { public void run() { runtime.launch(present); // this blocks until finished // next lines are executed when the sketch quits - editor.initEditorCode(parser.allHandles, false); - editor.stopInteractiveMode(parser.allHandles); + if (launchInteractive) { + editor.initEditorCode(parser.allHandles, false); + editor.stopInteractiveMode(parser.allHandles); + } } }).start(); diff --git a/java/src/processing/mode/java/tweak/SketchParser.java b/java/src/processing/mode/java/tweak/SketchParser.java index 4f6eca38f..56130b33e 100644 --- a/java/src/processing/mode/java/tweak/SketchParser.java +++ b/java/src/processing/mode/java/tweak/SketchParser.java @@ -38,17 +38,37 @@ public class SketchParser { ArrayList colorModes; List> scientificNotations; - - + + Range setupFunction; + + List> commentBlocks; + List curlyScopes; + public SketchParser(String[] codeTabs, boolean requiresComment) { this.codeTabs = codeTabs; this.requiresComment = requiresComment; intVarCount=0; floatVarCount=0; - + + // get all comment blocks + commentBlocks = new ArrayList<>(); + for (String code : codeTabs) { + commentBlocks.add(getCommentBlocks(code)); + } + + // get setup function range (to ignore all numbers there) + setupFunction = new Range(getSetupStart(codeTabs[0]), getSetupEnd(codeTabs[0])); + + // build curly scope for every character in the code + curlyScopes = new ArrayList<>(); + for (String code : codeTabs) { + curlyScopes.add(getCurlyScopes(code)); + } + + // get all scientific notation (to ignore them) scientificNotations = getAllScientificNotations(); - // find, add, and sort all tweakable numbers in the sketch + // find, add, and sort all tweak-able numbers in the sketch addAllNumbers(); // handle colors @@ -65,11 +85,11 @@ public class SketchParser { public void addAllNumbers() { - //allHandles = new ArrayList[codeTabs.length]; // moved inside addAllDecimalNumbers + allHandles = new ArrayList<>(); + addAllDecimalNumbers(); addAllHexNumbers(); addAllWebColorNumbers(); - //for (int i=0; i handle : allHandles) { //Collections.sort(allHandles[i], new HandleComparator()); Collections.sort(handle, new HandleComparator()); @@ -83,14 +103,11 @@ public class SketchParser { * list of all numbers in the sketch (excluding hexadecimals) */ private void addAllDecimalNumbers() { - allHandles = new ArrayList<>(); - // for every number found: // save its type (int/float), name, value and position in code. Pattern p = Pattern.compile("[\\[\\{<>(),\\t\\s\\+\\-\\/\\*^%!|&=?:~]\\d+\\.?\\d*"); for (int i = 0; i < codeTabs.length; i++) { - //allHandles[i] = new ArrayList(); List handles = new ArrayList(); allHandles.add(handles); @@ -102,10 +119,15 @@ public class SketchParser { int start = m.start()+1; int end = m.end(); - if (isInComment(start, codeTabs[i])) { + if (isInRangeList(start, commentBlocks.get(i))) { // ignore comments continue; } + + if (setupFunction.contains(start)) { + // ignore numbers in setup + continue; + } if (requiresComment) { // only add numbers that have the "// tweak" comment in their line @@ -150,7 +172,7 @@ public class SketchParser { continue; // beware of the global assignment (bug from 26.07.2013) - if (isGlobal(m.start(), c)) + if (isGlobal(m.start(), i)) continue; int line = countLines(c.substring(0, start)) - 1; // zero based @@ -189,10 +211,15 @@ public class SketchParser { int start = m.start()+1; int end = m.end(); - if (isInComment(start, codeTabs[i])) { + if (isInRangeList(start, commentBlocks.get(i))) { // ignore comments continue; } + + if (setupFunction.contains(start)) { + // ignore number in setup + continue; + } if (requiresComment) { // only add numbers that have the "// tweak" comment in their line @@ -207,7 +234,7 @@ public class SketchParser { } // beware of the global assignment (bug from 26.07.2013) - if (isGlobal(m.start(), c)) { + if (isGlobal(m.start(), i)) { continue; } @@ -245,10 +272,15 @@ public class SketchParser { int start = m.start(); int end = m.end(); - if (isInComment(start, codeTabs[i])) { + if (isInRangeList(start, commentBlocks.get(i))) { // ignore comments continue; } + + if (setupFunction.contains(start)) { + // ignore number in setup + continue; + } if (requiresComment) { // only add numbers that have the "// tweak" comment in their line @@ -263,7 +295,7 @@ public class SketchParser { } // beware of the global assignment (bug from 26.07.2013) - if (isGlobal(m.start(), c)) { + if (isGlobal(m.start(), i)) { continue; } @@ -288,13 +320,14 @@ public class SketchParser { private ArrayList findAllColorModes() { ArrayList modes = new ArrayList(); - for (String tab : codeTabs) { + for (int i=0; i -1) { // found colorMode at index - if (isInComment(index, tab)) { + if (isInRangeList(index, commentBlocks.get(i))) { // ignore comments continue; } @@ -326,7 +359,6 @@ public class SketchParser { Pattern p = Pattern.compile("color\\(|color\\s\\(|fill[\\(\\s]|stroke[\\(\\s]|background[\\(\\s]|tint[\\(\\s]"); for (int i = 0; i < codeTabs.length; i++) { - //colorBoxes[i] = new ArrayList(); List colorBox = new ArrayList(); colorBoxes.add(colorBox); @@ -344,10 +376,15 @@ public class SketchParser { continue; } - if (isInComment(m.start(), tab)) { + if (isInRangeList(m.start(), commentBlocks.get(i))) { // ignore colors in a comment continue; } + + if (setupFunction.contains(m.start())) { + // ignore number in setup + continue; + } // look for handles inside the parenthesis for (Handle handle : allHandles.get(i)) { @@ -360,7 +397,7 @@ public class SketchParser { if (colorHandles.size() > 0) { /* make sure there is no other stuff between '()' like variables. - * substract all handle values from string inside parenthesis and + * subtract all handle values from string inside parenthesis and * check there is no garbage left */ String insidePar = tab.substring(openPar+1, closePar); @@ -423,10 +460,15 @@ public class SketchParser { continue; } - if (isInComment(m.start(), tab)) { + if (isInRangeList(m.start(), commentBlocks.get(i))) { // ignore colors in a comment continue; } + + if (setupFunction.contains(m.start())) { + // ignore number in setup + continue; + } // put 'colorParamsEnd' after three parameters inside the parenthesis or at the close int colorParamsEnd = openPar; @@ -450,7 +492,7 @@ public class SketchParser { if (colorHandles.size() > 0) { /* make sure there is no other stuff between '()' like variables. - * substract all handle values from string inside parenthesis and + * subtract all handle values from string inside parenthesis and * check there is no garbage left */ String insidePar = tab.substring(openPar+1, colorParamsEnd); @@ -542,18 +584,13 @@ public class SketchParser { private List> getAllScientificNotations() { - //ArrayList notations[] = new ArrayList[codeTabs.length]; List> notations = new ArrayList<>(); Pattern p = Pattern.compile("[+\\-]?(?:0|[1-9]\\d*)(?:\\.\\d*)?[eE][+\\-]?\\d+"); - //for (int i = 0; i < codeTabs.length; i++) { for (String code : codeTabs) { List notation = new ArrayList(); - //notations[i] = new ArrayList(); - //Matcher m = p.matcher(codeTabs[i]); Matcher m = p.matcher(code); while (m.find()) { - //notations[i].add(new Range(m.start(), m.end())); notation.add(new Range(m.start(), m.end())); } notations.add(notation); @@ -646,92 +683,128 @@ public class SketchParser { return false; } + + /** + * Builds an int array for every tab that represents the scope depth at each character + * + * @return + */ + static private int[] getCurlyScopes(String code) + { + List comments = getCommentBlocks(code); + + int[] scopes = new int[code.length()]; + int curlyScope = 0; + boolean arrayAssignmentMaybeCommingFlag = false; + int arrayAssignmentCurlyScope = 0; + for (int pos=0; pos0) { + // this is an array assignment + arrayAssignmentCurlyScope++; + arrayAssignmentMaybeCommingFlag = false; + } + else { + curlyScope++; + } + } + else if (code.charAt(pos) == '}') { + if (arrayAssignmentCurlyScope>0) { + arrayAssignmentCurlyScope--; + } + else { + curlyScope--; + } + } + else if (code.charAt(pos) == '=') { + arrayAssignmentMaybeCommingFlag = true; + } + else if (!isWhiteSpace(code.charAt(pos))) { + arrayAssignmentMaybeCommingFlag = false; + } + } + + return scopes; + } + + static private boolean isWhiteSpace(char c) { + if (c == ' ' || + c == '\t' || + c == '\n' || + c == '\r') { + return true; + } + + int[][] a = {{1,2},{3,4}}; + + return false; + } /** * Is this a global position? * @param pos position - * @param code code + * @param codeTabIndex index of the code in codeTabs * @return - * true if the position 'pos' is in global scope in the code 'code' + * true if the position 'pos' is in global scope in the code 'codeTabs[codeTabIndex]' + * */ - static private boolean isGlobal(int pos, String code) { - int curlyScope = 0; // count '{-}' - - for (int c=pos; c>=0; c--) - { - if (code.charAt(c) == '{') { - // check if a function or an array assignment - for (int cc=c; cc>=0; cc--) { - if (code.charAt(cc)==')') { - curlyScope++; - break; - } - else if (code.charAt(cc)==']') { - break; - } - else if (code.charAt(cc)==';') { - break; - } - } - } - else if (code.charAt(c) == '}') { - // check if a function or an array assignment - for (int cc=c; cc>=0; cc--) { - if (code.charAt(cc)==')') { - curlyScope--; - break; - } - else if (code.charAt(cc)==']') { - break; - } - else if (code.charAt(cc)==';') { - break; - } - } - } - } - - if (curlyScope == 0) { - // it is a global position - return true; - } - - return false; + private boolean isGlobal(int pos, int codeTabIndex) { + return (curlyScopes.get(codeTabIndex)[pos]==0); }; - static private boolean isInComment(int pos, String code) { - // look for one line comment - int lineStart = getStartOfLine(pos, code); - if (lineStart < 0) { - return false; + public static List getCommentBlocks(String code) { + List commentBlocks = new ArrayList(); + + int lastBlockStart=0; + boolean lookForEnd = false; + for (int pos=0; pos rangeList) { + for (Range r : rangeList) { + if (r.contains(pos)) { + return true; + } } - - // TODO: look for block comments + return false; } - static private int getEndOfLine(int pos, String code) { return code.indexOf("\n", pos); } - - static private int getStartOfLine(int pos, String code) { - while (pos >= 0) { - if (code.charAt(pos) == '\n') { - return pos+1; - } - pos--; - } - - return 0; - } - - - /** returns the object of the function starting at 'pos' + /** returns the object name (what comes before the '.') of the function starting at 'pos' * * @param pos * @param code @@ -762,7 +835,7 @@ public class SketchParser { } - static public int getSetupStart(String code) { + public static int getSetupStart(String code) { Pattern p = Pattern.compile("void[\\s\\t\\r\\n]*setup[\\s\\t]*\\(\\)[\\s\\t\\r\\n]*\\{"); Matcher m = p.matcher(code); @@ -772,11 +845,44 @@ public class SketchParser { return -1; } - - -// private String replaceString(String str, int start, int end, String put) { -// return str.substring(0, start) + put + str.substring(end, str.length()); -// } + + public static int getSetupEnd(String code) { + List comments = getCommentBlocks(code); + + int setupStart = getSetupStart(code); + if (setupStart == -1) { + return -1; + } + + System.out.println("setup start = " + setupStart); + + // count brackets to look for setup end + int bracketCount=1; + int pos = setupStart; + while (bracketCount>0 && pos