From 0c828ad43335e9ded9a494d54dcdba487183952c Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 18 Jul 2017 20:28:20 +0100 Subject: [PATCH] Fix #5165. Wrong tab for missing brace --- java/src/processing/mode/java/JavaBuild.java | 42 ++++++----- .../mode/java/pdex/SourceUtils.java | 74 +++++++++++-------- 2 files changed, 67 insertions(+), 49 deletions(-) diff --git a/java/src/processing/mode/java/JavaBuild.java b/java/src/processing/mode/java/JavaBuild.java index 88f6fc3be..5b12e894c 100644 --- a/java/src/processing/mode/java/JavaBuild.java +++ b/java/src/processing/mode/java/JavaBuild.java @@ -52,6 +52,7 @@ import processing.core.PApplet; import processing.core.PConstants; import processing.data.StringList; import processing.data.XML; +import processing.mode.java.pdex.SourceUtils; import processing.mode.java.preproc.PdePreprocessor; import processing.mode.java.preproc.PreprocessorResult; import processing.mode.java.preproc.SurfaceInfo; @@ -280,27 +281,30 @@ public class JavaBuild { //System.out.println(java.getAbsolutePath()); // System.out.println(bigCode); - if (msg.contains("expecting RCURLY")) { - //if (msg.equals("expecting RCURLY, found 'null'")) { - // This can be a problem since the error is sometimes listed as a line - // that's actually past the number of lines. For instance, it might - // report "line 15" of a 14 line program. Added code to highlightLine() - // inside Editor to deal with this situation (since that code is also - // useful for other similar situations). - throw new SketchException("Found one too many { characters " + - "without a } to match it.", - errorFile, errorLine, re.getColumn(), false); - } + if (msg.contains("expecting RCURLY") || msg.contains("expecting LCURLY")) { + for (int i = 0; i < sketch.getCodeCount(); i++) { + SketchCode sc = sketch.getCode(i); + if (sc.isExtension("pde")) { + String s = sc.getProgram(); + int[] braceTest = SourceUtils.checkForMissingBraces( + SourceUtils.scrubCommentsAndStrings(s) + "\n", 0, s.length()+1); + if (braceTest[0] == 0) continue; - if (msg.contains("expecting LCURLY")) { - System.err.println(msg); - String suffix = "."; - String[] m = PApplet.match(msg, "found ('.*')"); - if (m != null) { - suffix = ", not " + m[1] + "."; + // Completely ignoring the errorFile/errorLine given since it's + // likely to be the wrong tab. For the same reason, I'm not showing + // the result of PApplet.match(msg, "found ('.*')") on missing + // LCURLY. + throw new SketchException(braceTest[0] > 0 + ? "Found one too many { characters without a } to match it." + : "Found one too many } characters without a { to match it.", + i, braceTest[1], braceTest[2], false); + } } - throw new SketchException("Was expecting a { character" + suffix, - errorFile, errorLine, re.getColumn(), false); + // If we're still here, there's the right brackets, just not in the + // right place. Passing on the original error. + throw new SketchException( + msg.replace("LCURLY", "{").replace("RCURLY", "}"), + errorFile, errorLine, re.getColumn(), false); } if (msg.indexOf("expecting RBRACK") != -1) { diff --git a/java/src/processing/mode/java/pdex/SourceUtils.java b/java/src/processing/mode/java/pdex/SourceUtils.java index fecde5c94..1c7ae1d29 100644 --- a/java/src/processing/mode/java/pdex/SourceUtils.java +++ b/java/src/processing/mode/java/pdex/SourceUtils.java @@ -333,43 +333,57 @@ public class SourceUtils { static public List checkForMissingBraces(StringBuilder p, int[] tabStartOffsets) { List problems = new ArrayList<>(0); - tabLoop: for (int tabIndex = 0; tabIndex < tabStartOffsets.length; tabIndex++) { + for (int tabIndex = 0; tabIndex < tabStartOffsets.length; tabIndex++) { int tabStartOffset = tabStartOffsets[tabIndex]; int tabEndOffset = (tabIndex < tabStartOffsets.length - 1) ? tabStartOffsets[tabIndex + 1] : p.length(); - int depth = 0; - int lineNumber = 0; - for (int i = tabStartOffset; i < tabEndOffset; i++) { - char ch = p.charAt(i); - switch (ch) { - case '{': - depth++; - break; - case '}': - depth--; - break; - case '\n': - lineNumber++; - break; - } - if (depth < 0) { - JavaProblem problem = - new JavaProblem("Found one too many } characters without { to match it.", - JavaProblem.ERROR, tabIndex, lineNumber); - problem.setPDEOffsets(i - tabStartOffset, i - tabStartOffset + 1); - problems.add(problem); - continue tabLoop; - } - } - if (depth > 0) { + int[] braceResult = checkForMissingBraces(p, tabStartOffset, tabEndOffset); + if (braceResult[0] != 0) { JavaProblem problem = - new JavaProblem("Found one too many { characters without } to match it.", - JavaProblem.ERROR, tabIndex, lineNumber - 1); - problem.setPDEOffsets(tabEndOffset - tabStartOffset - 2, tabEndOffset - tabStartOffset - 1); - problems.add(problem); + new JavaProblem(braceResult[0] < 0 + ? "Found one too many } characters without { to match it." + : "Found one too many { characters without } to match it.", + JavaProblem.ERROR, tabIndex, braceResult[1]); + problem.setPDEOffsets(braceResult[3], braceResult[3] + 1); + problems.add(problem); } } return problems; } + + /** + * Checks a single code fragment (such as a tab) for non-matching braces. + * Broken out to allow easy use in JavaBuild. + * @param c Program code scrubbed of comments and string literals. + * @param start Start index, inclusive. + * @param end End index, exclusive. + * @return {@code int[4]} Depth at which the loop stopped, followed by the + * line number, column, and string index (within the range) at which + * an error was found, if any. + */ + static public int[] checkForMissingBraces(CharSequence c, int start, int end) { + int depth = 0; + int lineNumber = 0; + int lineStart = start; + for (int i = start; i < end; i++) { + char ch = c.charAt(i); + switch (ch) { + case '{': + depth++; + break; + case '}': + depth--; + break; + case '\n': + lineNumber++; + lineStart = i; + break; + } + if (depth < 0) { + return new int[] {depth, lineNumber, i - lineStart, i - start}; + } + } + return new int[] {depth, lineNumber - 1, end - lineStart - 2, end - start - 2}; + } }