Skip to content

Commit 9fdb6fe

Browse files
authored
Merge pull request #493 from Pieter12345/mismatched-paren-feedback
Improve code target for mismatched parens
2 parents 3361663 + b2f8bab commit 9fdb6fe

File tree

1 file changed

+71
-7
lines changed

1 file changed

+71
-7
lines changed

src/main/java/com/laytonsmith/core/MethodScriptCompiler.java

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,7 @@ public static ParseTree compile(TokenStream stream) throws ConfigCompileExceptio
11601160
int parens = 0;
11611161
Token t = null;
11621162

1163-
int bracketCount = 0;
1163+
int braceCount = 0;
11641164

11651165
// Create a Token array to iterate over, rather than using the LinkedList's O(n) get() method.
11661166
Token[] tokenArray = stream.toArray(new Token[stream.size()]);
@@ -1177,13 +1177,13 @@ public static ParseTree compile(TokenStream stream) throws ConfigCompileExceptio
11771177
tree.addChild(b);
11781178
tree = b;
11791179
parents.push(b);
1180-
bracketCount++;
1180+
braceCount++;
11811181
constructCount.push(new AtomicInteger(0));
11821182
continue;
11831183
}
11841184

11851185
if(t.type == TType.RCURLY_BRACKET) {
1186-
bracketCount--;
1186+
braceCount--;
11871187
if(constructCount.peek().get() > 1) {
11881188
//We need to autoconcat some stuff
11891189
int stacks = constructCount.peek().get();
@@ -1575,14 +1575,50 @@ public static ParseTree compile(TokenStream stream) throws ConfigCompileExceptio
15751575

15761576
assert t != null;
15771577

1578+
// Handle mismatching square brackets "[]".
1579+
assert arrayStack.size() != 0 : "The last element of arrayStack should be present, but it was popped.";
15781580
if(arrayStack.size() != 1) {
1579-
throw new ConfigCompileException("Mismatched square brackets", t.target);
1581+
1582+
// Some starting square bracket '[' was not closed at the end of the script.
1583+
// Find the last '[' that was not closed and use that as target instead of the last line of the script.
1584+
Target target = traceMismatchedOpenToken(stream, TType.LSQUARE_BRACKET, TType.RSQUARE_BRACKET);
1585+
assert target != null : "Mismatched bracket was detected, but target-finding code could not find it.";
1586+
if(target == null) {
1587+
target = t.target;
1588+
}
1589+
1590+
// Throw a CRE.
1591+
throw new ConfigCompileException("Mismatched square brackets", target);
15801592
}
1593+
1594+
// Handle mismatching parentheses "()".
15811595
if(parens != 0) {
1582-
throw new ConfigCompileException("Mismatched parenthesis", t.target);
1596+
1597+
// Some starting parentheses '(' was not closed at the end of the script.
1598+
// Find the last '(' that was not closed and use that as target instead of the last line of the script.
1599+
Target target = traceMismatchedOpenToken(stream, TType.FUNC_START, TType.FUNC_END);
1600+
assert target != null : "Mismatched parentheses was detected, but target-finding code could not find it.";
1601+
if(target == null) {
1602+
target = t.target;
1603+
}
1604+
1605+
// Throw a CRE.
1606+
throw new ConfigCompileException("Mismatched parentheses", target);
15831607
}
1584-
if(bracketCount != 0) {
1585-
throw new ConfigCompileException("Mismatched curly braces", t.target);
1608+
1609+
// Handle mismatching curly braces "{}".
1610+
if(braceCount != 0) {
1611+
1612+
// Some starting curly brace '{' was not closed at the end of the script.
1613+
// Find the last '{' that was not closed and use that as target instead of the last line of the script.
1614+
Target target = traceMismatchedOpenToken(stream, TType.LCURLY_BRACKET, TType.RCURLY_BRACKET);
1615+
assert target != null : "Mismatched curly brace was detected, but target-finding code could not find it.";
1616+
if(target == null) {
1617+
target = t.target;
1618+
}
1619+
1620+
// Throw a CRE.
1621+
throw new ConfigCompileException("Mismatched curly braces", target);
15861622
}
15871623

15881624
Stack<List<Procedure>> procs = new Stack<>();
@@ -1608,6 +1644,34 @@ public static ParseTree compile(TokenStream stream) throws ConfigCompileExceptio
16081644
return tree;
16091645
}
16101646

1647+
/**
1648+
* Trace target of mismatching open tokens such as '(' in '()' or '{' in '{}'. This should be used when it is
1649+
* known that there are more start than close tokens, but no target is known for the extra start token.
1650+
* @param stream - The token stream to scan.
1651+
* @param openType - The open type, which would be {@link TType#FUNC_START (} for a parentheses check.
1652+
* @param closeType - The close type, which would be {@link TType#FUNC_END )} for a parentheses check.
1653+
* @return The target of the last occurrence of the opening type that did not have a matching closing type.
1654+
* Returns null of no target was found.
1655+
*/
1656+
private static Target traceMismatchedOpenToken(TokenStream stream, TType openType, TType closeType) {
1657+
// Some starting parentheses '(' was not closed at the end of the script.
1658+
// Find the last '(' that was not closed and use that as target instead of the last line of the script.
1659+
Iterator<Token> iterator = stream.descendingIterator();
1660+
int closingCount = 0;
1661+
while(iterator.hasNext()) {
1662+
Token token = iterator.next();
1663+
if(token.type == closeType) {
1664+
closingCount++;
1665+
} else if(token.type == openType) {
1666+
if(closingCount <= 0) {
1667+
return token.target;
1668+
}
1669+
closingCount--;
1670+
}
1671+
}
1672+
return null;
1673+
}
1674+
16111675
/**
16121676
* Recurses down the tree and ensures that breaks don't bubble up past procedures or the root code tree.
16131677
*

0 commit comments

Comments
 (0)