Skip to content

Commit

Permalink
Merge pull request #480 from Pieter12345/lexer_minus_fix
Browse files Browse the repository at this point in the history
Fixed invalid minus sign interpretation.
  • Loading branch information
LadyCailin committed Apr 15, 2018
2 parents 35527f9 + b3f6bec commit d2490df
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 16 deletions.
41 changes: 25 additions & 16 deletions src/main/java/com/laytonsmith/core/MethodScriptCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -798,23 +798,32 @@ public static TokenStream lex(String script, File file, boolean inPureMScript, b

// Convert "-" + number to -number if allowed.
it.previous(); // Select 't' <--.
if(it.hasPrevious()) {
if(it.hasPrevious() && t.type == TType.UNKNOWN) {
Token prev1 = it.previous(); // Select 'prev1' <--.
if(it.hasPrevious()) {
Token prev2 = it.previous(); // Select 'prev2' <--.
if(t.type == TType.UNKNOWN && prev1.type.isPlusMinus() // Convert "± UNKNOWN".
&& !prev2.type.isIdentifier() // Don't convert "number/string/var ± ...".
&& prev2.type != TType.FUNC_END // Don't convert "func() ± ...".
&& !IVAR_PATTERN.matcher(t.val()).matches() // Don't convert "± @var".
&& !VAR_PATTERN.matcher(t.val()).matches()) { // Don't convert "± $var".
// It is a negative/positive number: Absorb the sign.
t.value = prev1.value + t.value;
it.next(); // Select 'prev2' -->.
it.next(); // Select 'prev1' -->.
it.remove(); // Remove 'prev1'.
} else {
it.next(); // Select 'prev2' -->.
it.next(); // Select 'prev1' -->.
if(prev1.type.isPlusMinus()) {

// Find the first non-whitespace token before the '-'.
Token prevNonWhitespace = null;
while(it.hasPrevious()) {
if(it.previous().type != TType.WHITESPACE) {
prevNonWhitespace = it.next();
break;
}
}
while(it.next() != prev1) { // Skip until selection is at 'prev1 -->'.
}

if(prevNonWhitespace != null) {
// Convert "±UNKNOWN" if the '±' is used as a sign (and not an add/subtract operation).
if(!prevNonWhitespace.type.isIdentifier() // Don't convert "number/string/var ± ...".
&& prevNonWhitespace.type != TType.FUNC_END // Don't convert "func() ± ...".
&& prevNonWhitespace.type != TType.RSQUARE_BRACKET // Don't convert "] ± ..." (arrays).
&& !IVAR_PATTERN.matcher(t.val()).matches() // Don't convert "± @var".
&& !VAR_PATTERN.matcher(t.val()).matches()) { // Don't convert "± $var".
// It is a negative/positive number: Absorb the sign.
t.value = prev1.value + t.value;
it.remove(); // Remove 'prev1'.
}
}
} else {
it.next(); // Select 'prev1' -->.
Expand Down
121 changes: 121 additions & 0 deletions src/test/java/com/laytonsmith/core/MethodScriptCompilerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1118,4 +1118,125 @@ private void ambigousCommandRegistrationHelper(String cmd1, String cmd2, boolean
}
}

@Test
public void testMinusSignHandling() throws Exception {
// This tests a specific lexer part where token TType.MINUS ('-' sign) is merged with the next token
// based on whether the MINUS is used as a negation sign or a mathematical operator.

// "... - 2".
this.verifyExecute("msg(5 - 2)", "3");
this.verifyExecute("msg(5- 2)", "3");
this.verifyExecute("msg(5 -2)", "3");
this.verifyExecute("msg(5-2)", "3");
this.verifyExecute("msg(0x05 - 2)", "3");
this.verifyExecute("msg(0x05- 2)", "3");
this.verifyExecute("msg(0x05 -2)", "3");
this.verifyExecute("msg(0x05-2)", "3");
this.verifyExecute("@arr = array(5); msg(@arr[0] - 2)", "3");
this.verifyExecute("@arr = array(5); msg(@arr[0]- 2)", "3");
this.verifyExecute("@arr = array(5); msg(@arr[0] -2)", "3");
this.verifyExecute("@arr = array(5); msg(@arr[0]-2)", "3");
this.verifyExecute("@a = 5; msg(@a - 2)", "3");
this.verifyExecute("@a = 5; msg(@a- 2)", "3");
this.verifyExecute("@a = 5; msg(@a -2)", "3");
this.verifyExecute("@a = 5; msg(@a-2)", "3");
this.verifyExecute("msg(abs(5) - 2)", "3");
this.verifyExecute("msg(abs(5)- 2)", "3");
this.verifyExecute("msg(abs(5) -2)", "3");
this.verifyExecute("msg(abs(5)-2)", "3");

// "2 - ...".
this.verifyExecute("msg(2 - 0x05)", "-3");
this.verifyExecute("msg(2- 0x05)", "-3");
this.verifyExecute("msg(2 -0x05)", "-3");
this.verifyExecute("msg(2-0x05)", "-3");
this.verifyExecute("@arr = array(5); msg(2 - @arr[0])", "-3");
this.verifyExecute("@arr = array(5); msg(2- @arr[0])", "-3");
this.verifyExecute("@arr = array(5); msg(2 -@arr[0])", "-3");
this.verifyExecute("@arr = array(5); msg(2-@arr[0])", "-3");
this.verifyExecute("@a = 5; msg(2 - @a)", "-3");
this.verifyExecute("@a = 5; msg(2- @a)", "-3");
this.verifyExecute("@a = 5; msg(2 -@a)", "-3");
this.verifyExecute("@a = 5; msg(2-@a)", "-3");
this.verifyExecute("msg(2 - abs(5))", "-3");
this.verifyExecute("msg(2- abs(5))", "-3");
this.verifyExecute("msg(2 -abs(5))", "-3");
this.verifyExecute("msg(2-abs(5))", "-3");

// "- something".
this.verifyExecute("msg(-5)", "-5");
this.verifyExecute("msg(typeof(-5))", "int");
this.verifyExecute("msg(- 5)", "-5");
this.verifyExecute("msg(typeof(- 5))", "int");
this.verifyExecute("@a = 5; msg(-@a)", "-5");
this.verifyExecute("@a = 5; msg(typeof(-@a))", "int");
this.verifyExecute("@a = 5; msg(- @a)", "-5");
this.verifyExecute("@a = 5; msg(typeof(- @a))", "int");
}

@Test
public void testPlusSignHandling() throws Exception {
// This tests a specific lexer part where token TType.PLUS ('+' sign) is merged with the next token
// based on whether the PLUS is used as a positive sign or a mathematical operator.

// "... + 2".
this.verifyExecute("msg(5 + 2)", "7");
this.verifyExecute("msg(5+ 2)", "7");
this.verifyExecute("msg(5 +2)", "7");
this.verifyExecute("msg(5+2)", "7");
this.verifyExecute("msg(0x05 + 2)", "7");
this.verifyExecute("msg(0x05+ 2)", "7");
this.verifyExecute("msg(0x05 +2)", "7");
this.verifyExecute("msg(0x05+2)", "7");
this.verifyExecute("@arr = array(5); msg(@arr[0] + 2)", "7");
this.verifyExecute("@arr = array(5); msg(@arr[0]+ 2)", "7");
this.verifyExecute("@arr = array(5); msg(@arr[0] +2)", "7");
this.verifyExecute("@arr = array(5); msg(@arr[0]+2)", "7");
this.verifyExecute("@a = 5; msg(@a + 2)", "7");
this.verifyExecute("@a = 5; msg(@a+ 2)", "7");
this.verifyExecute("@a = 5; msg(@a +2)", "7");
this.verifyExecute("@a = 5; msg(@a+2)", "7");
this.verifyExecute("msg(abs(5) + 2)", "7");
this.verifyExecute("msg(abs(5)+ 2)", "7");
this.verifyExecute("msg(abs(5) +2)", "7");
this.verifyExecute("msg(abs(5)+2)", "7");

// "2 + ...".
this.verifyExecute("msg(2 + 0x05)", "7");
this.verifyExecute("msg(2+ 0x05)", "7");
this.verifyExecute("msg(2 +0x05)", "7");
this.verifyExecute("msg(2+0x05)", "7");
this.verifyExecute("@arr = array(5); msg(2 + @arr[0])", "7");
this.verifyExecute("@arr = array(5); msg(2+ @arr[0])", "7");
this.verifyExecute("@arr = array(5); msg(2 +@arr[0])", "7");
this.verifyExecute("@arr = array(5); msg(2+@arr[0])", "7");
this.verifyExecute("@a = 5; msg(2 + @a)", "7");
this.verifyExecute("@a = 5; msg(2+ @a)", "7");
this.verifyExecute("@a = 5; msg(2 +@a)", "7");
this.verifyExecute("@a = 5; msg(2+@a)", "7");
this.verifyExecute("msg(2 + abs(5))", "7");
this.verifyExecute("msg(2+ abs(5))", "7");
this.verifyExecute("msg(2 +abs(5))", "7");
this.verifyExecute("msg(2+abs(5))", "7");

// "+ something".
this.verifyExecute("msg(+5)", "5");
this.verifyExecute("msg(typeof(+5))", "int");
this.verifyExecute("msg(+ 5)", "5");
this.verifyExecute("msg(typeof(+ 5))", "int");
this.verifyExecute("@a = 5; msg(+@a)", "5");
this.verifyExecute("@a = 5; msg(typeof(+@a))", "int");
this.verifyExecute("@a = 5; msg(+ @a)", "5");
this.verifyExecute("@a = 5; msg(typeof(+ @a))", "int");
}

private void verifyExecute(String script, String expectedResponse) throws ConfigCompileException, ConfigCompileGroupException {
MCPlayer temp = this.env.getEnv(CommandHelperEnvironment.class).GetPlayer();
MCPlayer player = StaticTest.GetOnlinePlayer();
this.env.getEnv(CommandHelperEnvironment.class).SetPlayer(player);
MethodScriptCompiler.execute(MethodScriptCompiler.compile(
MethodScriptCompiler.lex(script, null, true)), this.env, null, null);
verify(player).sendMessage(expectedResponse);
this.env.getEnv(CommandHelperEnvironment.class).SetPlayer(temp);
}
}

0 comments on commit d2490df

Please sign in to comment.