tweakmode: handle comment blocks, ignore global assignments

This commit is contained in:
Gal Sasson
2015-04-28 09:42:52 -04:00
parent eb351f4c4e
commit 7d9bfc2496
3 changed files with 155 additions and 94 deletions

View File

@@ -2739,9 +2739,11 @@ public class JavaEditor extends Editor {
* Replace all numbers with variables and add code to initialize
* these variables and handle update messages.
*/
protected boolean automateSketch(Sketch sketch, List<List<Handle>> handles) {
protected boolean automateSketch(Sketch sketch, SketchParser parser) {
SketchCode[] code = sketch.getCode();
List<List<Handle>> handles = parser.allHandles;
if (code.length < 1) {
return false;
}
@@ -2793,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();

View File

@@ -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();

View File

@@ -41,15 +41,30 @@ public class SketchParser {
Range setupFunction;
List<List<Range>> commentBlocks;
List<int[]> 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();
@@ -104,7 +119,7 @@ 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;
}
@@ -157,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
@@ -196,7 +211,7 @@ 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;
}
@@ -219,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;
}
@@ -257,7 +272,7 @@ 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;
}
@@ -280,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;
}
@@ -305,13 +320,14 @@ public class SketchParser {
private ArrayList<ColorMode> findAllColorModes() {
ArrayList<ColorMode> modes = new ArrayList<ColorMode>();
for (String tab : codeTabs) {
for (int i=0; i<codeTabs.length; i++) {
String tab = codeTabs[i];
int index = -1;
// search for a call to colorMode function
while ((index = tab.indexOf("colorMode", index+1)) > -1) {
// found colorMode at index
if (isInComment(index, tab)) {
if (isInRangeList(index, commentBlocks.get(i))) {
// ignore comments
continue;
}
@@ -360,7 +376,7 @@ public class SketchParser {
continue;
}
if (isInComment(m.start(), tab)) {
if (isInRangeList(m.start(), commentBlocks.get(i))) {
// ignore colors in a comment
continue;
}
@@ -444,7 +460,7 @@ public class SketchParser {
continue;
}
if (isInComment(m.start(), tab)) {
if (isInRangeList(m.start(), commentBlocks.get(i))) {
// ignore colors in a comment
continue;
}
@@ -568,7 +584,6 @@ public class SketchParser {
private List<List<Range>> getAllScientificNotations() {
//ArrayList<Range> notations[] = new ArrayList[codeTabs.length];
List<List<Range>> notations = new ArrayList<>();
Pattern p = Pattern.compile("[+\\-]?(?:0|[1-9]\\d*)(?:\\.\\d*)?[eE][+\\-]?\\d+");
@@ -668,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<Range> comments = getCommentBlocks(code);
int[] scopes = new int[code.length()];
int curlyScope = 0;
boolean arrayAssignmentMaybeCommingFlag = false;
int arrayAssignmentCurlyScope = 0;
for (int pos=0; pos<code.length(); pos++) {
scopes[pos] = curlyScope;
if (isInRangeList(pos, comments)) {
// we are inside a comment, ignore and move on
continue;
}
if (code.charAt(pos) == '{') {
if (arrayAssignmentMaybeCommingFlag ||
arrayAssignmentCurlyScope>0) {
// 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<Range> getCommentBlocks(String code) {
List<Range> commentBlocks = new ArrayList<Range>();
int lastBlockStart=0;
boolean lookForEnd = false;
for (int pos=0; pos<code.length()-1; pos++) {
if (lookForEnd) {
// we have a start, look for the end
if (code.charAt(pos) == '*' && code.charAt(pos+1) == '/') {
commentBlocks.add(new Range(lastBlockStart, pos+1));
lookForEnd = false;
}
}
else {
if (code.charAt(pos) == '/' && code.charAt(pos+1) == '*') {
// we found a block start
lastBlockStart = pos;
lookForEnd = true;
}
else if (code.charAt(pos) == '/' && code.charAt(pos+1) == '/') {
// we found a line comment
commentBlocks.add(new Range(pos, getEndOfLine(pos, code)));
}
}
}
if (code.substring(lineStart, pos).indexOf("//") != -1) {
return true;
return commentBlocks;
}
private static boolean isInRangeList(int pos, List<Range> 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
@@ -784,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);
@@ -795,25 +846,32 @@ public class SketchParser {
return -1;
}
static public int getSetupEnd(String code) {
public static int getSetupEnd(String code) {
List<Range> 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<code.length()) {
if (isInRangeList(pos, comments)) {
// in a comment, ignore and move on
pos++;
continue;
}
if (code.charAt(pos) == '{') {
if (!isInComment(pos, code)) {
bracketCount++;
}
bracketCount++;
}
else if (code.charAt(pos) == '}') {
if (!isInComment(pos, code)) {
bracketCount--;
}
bracketCount--;
}
pos++;