Skip to content

Commit d51ae03

Browse files
committed
Fixed invalid minus sign interpretation.
Bug examples: array(5)[0] - 3 would become 2, but array(5)[0] -3 would become string '5 -3'. 2 - 3, 2-3 and 2- 3 would become -1, but 2 -3 and 2 -3 would become string '2 -3'. This commit fixes the minus sign interpretation by the lexer, ignoring whitespaces in front of the '-' sign and with an additional case to support array_get's in format "@A[0]-value".
1 parent 550706d commit d51ae03

2 files changed

Lines changed: 72 additions & 16 deletions

File tree

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

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -798,23 +798,32 @@ public static TokenStream lex(String script, File file, boolean inPureMScript, b
798798

799799
// Convert "-" + number to -number if allowed.
800800
it.previous(); // Select 't' <--.
801-
if(it.hasPrevious()) {
801+
if(it.hasPrevious() && t.type == TType.UNKNOWN) {
802802
Token prev1 = it.previous(); // Select 'prev1' <--.
803-
if(it.hasPrevious()) {
804-
Token prev2 = it.previous(); // Select 'prev2' <--.
805-
if(t.type == TType.UNKNOWN && prev1.type.isPlusMinus() // Convert "± UNKNOWN".
806-
&& !prev2.type.isIdentifier() // Don't convert "number/string/var ± ...".
807-
&& prev2.type != TType.FUNC_END // Don't convert "func() ± ...".
808-
&& !IVAR_PATTERN.matcher(t.val()).matches() // Don't convert "± @var".
809-
&& !VAR_PATTERN.matcher(t.val()).matches()) { // Don't convert "± $var".
810-
// It is a negative/positive number: Absorb the sign.
811-
t.value = prev1.value + t.value;
812-
it.next(); // Select 'prev2' -->.
813-
it.next(); // Select 'prev1' -->.
814-
it.remove(); // Remove 'prev1'.
815-
} else {
816-
it.next(); // Select 'prev2' -->.
817-
it.next(); // Select 'prev1' -->.
803+
if(prev1.type.isPlusMinus()) {
804+
805+
// Find the first non-whitespace token before the '-'.
806+
Token prevNonWhitespace = null;
807+
while(it.hasPrevious()) {
808+
if(it.previous().type != TType.WHITESPACE) {
809+
prevNonWhitespace = it.next();
810+
break;
811+
}
812+
}
813+
while(it.next() != prev1) { // Skip until selection is at 'prev1 -->'.
814+
}
815+
816+
if(prevNonWhitespace != null) {
817+
// Convert "±UNKNOWN" if the '±' is used as a sign (and not an add/subtract operation).
818+
if(!prevNonWhitespace.type.isIdentifier() // Don't convert "number/string/var ± ...".
819+
&& prevNonWhitespace.type != TType.FUNC_END // Don't convert "func() ± ...".
820+
&& prevNonWhitespace.type != TType.RSQUARE_BRACKET // Don't convert "] ± ..." (arrays).
821+
&& !IVAR_PATTERN.matcher(t.val()).matches() // Don't convert "± @var".
822+
&& !VAR_PATTERN.matcher(t.val()).matches()) { // Don't convert "± $var".
823+
// It is a negative/positive number: Absorb the sign.
824+
t.value = prev1.value + t.value;
825+
it.remove(); // Remove 'prev1'.
826+
}
818827
}
819828
} else {
820829
it.next(); // Select 'prev1' -->.

src/test/java/com/laytonsmith/core/MethodScriptCompilerTest.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,4 +1118,51 @@ private void ambigousCommandRegistrationHelper(String cmd1, String cmd2, boolean
11181118
}
11191119
}
11201120

1121+
@Test
1122+
public void testMinusSignHandling() throws Exception {
1123+
// This tests a specific lexer part where token TType.MINUS ('-' sign) is merged with the next token
1124+
// based on whether the MINUS is used as a negation sign or a mathematical operator.
1125+
1126+
// "... - 2".
1127+
this.verifyExecute("msg(5 - 2)", "3");
1128+
this.verifyExecute("msg(5- 2)", "3");
1129+
this.verifyExecute("msg(5 -2)", "3");
1130+
this.verifyExecute("msg(5-2)", "3");
1131+
this.verifyExecute("@arr = array(5); msg(@arr[0] - 2)", "3");
1132+
this.verifyExecute("@arr = array(5); msg(@arr[0]- 2)", "3");
1133+
this.verifyExecute("@arr = array(5); msg(@arr[0] -2)", "3");
1134+
this.verifyExecute("@arr = array(5); msg(@arr[0]-2)", "3");
1135+
this.verifyExecute("@a = 5; msg(@a - 2)", "3");
1136+
this.verifyExecute("@a = 5; msg(@a- 2)", "3");
1137+
this.verifyExecute("@a = 5; msg(@a -2)", "3");
1138+
this.verifyExecute("@a = 5; msg(@a-2)", "3");
1139+
this.verifyExecute("msg(abs(5) - 2)", "3");
1140+
this.verifyExecute("msg(abs(5)- 2)", "3");
1141+
this.verifyExecute("msg(abs(5) -2)", "3");
1142+
this.verifyExecute("msg(abs(5)-2)", "3");
1143+
1144+
// "2 - ...".
1145+
this.verifyExecute("@arr = array(5); msg(2 - @arr[0])", "-3");
1146+
this.verifyExecute("@arr = array(5); msg(2- @arr[0])", "-3");
1147+
this.verifyExecute("@arr = array(5); msg(2 -@arr[0])", "-3");
1148+
this.verifyExecute("@arr = array(5); msg(2-@arr[0])", "-3");
1149+
this.verifyExecute("@a = 5; msg(2 - @a)", "-3");
1150+
this.verifyExecute("@a = 5; msg(2- @a)", "-3");
1151+
this.verifyExecute("@a = 5; msg(2 -@a)", "-3");
1152+
this.verifyExecute("@a = 5; msg(2-@a)", "-3");
1153+
this.verifyExecute("msg(2 - abs(5))", "-3");
1154+
this.verifyExecute("msg(2- abs(5))", "-3");
1155+
this.verifyExecute("msg(2 -abs(5))", "-3");
1156+
this.verifyExecute("msg(2-abs(5))", "-3");
1157+
}
1158+
1159+
private void verifyExecute(String script, String expectedResponse) throws ConfigCompileException, ConfigCompileGroupException {
1160+
MCPlayer temp = this.env.getEnv(CommandHelperEnvironment.class).GetPlayer();
1161+
MCPlayer player = StaticTest.GetOnlinePlayer();
1162+
this.env.getEnv(CommandHelperEnvironment.class).SetPlayer(player);
1163+
MethodScriptCompiler.execute(MethodScriptCompiler.compile(
1164+
MethodScriptCompiler.lex(script, null, true)), this.env, null, null);
1165+
verify(player).sendMessage(expectedResponse);
1166+
this.env.getEnv(CommandHelperEnvironment.class).SetPlayer(temp);
1167+
}
11211168
}

0 commit comments

Comments
 (0)