CommandHelper

CommandHelper

46.5k Downloads

Compiler failure on @var = @bool1 || !@bool2 (ignores the second command)

LadyCailinBot opened this issue ยท 5 comments

commented

CMDHELPER-3174 - Reported by Pieter12345

Running the optimizer on:
@var = @bool1 || !@bool2
Results in:
sconcat(assign(@var,or(@bool1)),@bool2)
Which is equivalent to:
@var = or(@bool1); @bool2;
Workaround:
@var = @bool1 || not(@bool2)

CommandHelper version: 3.3.2-SNAPSHOT build 3381

commented

Comment by PseudoKnight

Confirmed for build #3320, so it wasn't recently introduced.

commented

Comment by PseudoKnight

Hah. Wow. I ran into three more bugs within seconds of each other when looking into this.

@var = @a || ++@b;
// or more sensibly, something like...
@var = @a || ++@b == 3;

Error: 'Expecting an integer, but received "||" instead'.

If I post increment instead, some fun things happen.

@var = @a || @b++ == 3;

Error: 'Unexpected symbol (==). Did you forget to quote your symbols?'

If I throw this in a closure, something I do to see the compiled output, we get a stacktrace.

closure(@var = @a || @b++);

Exception in thread "main" java.lang.IndexOutOfBoundException: Index: 3, Size: 3
  at java.util.ArrayList.rangeCheck(Unknown Source)
  at java.util.ArrayList.get(Unknown Source)
  at com.laytonsmith.core.functions.Compiler$__autoconcat__.optimizeSpecial(Compiler.java:234)
  at com.laytonsmith.core.functions.Compiler$__autoconcat__.optimizeDynamic(Compiler.java:144)
  at com.laytonsmith.core.MethodScriptCompiler.optimizeAutoconcats(MethodScriptCompiler.java:1764
  ...
commented

Comment by PseudoKnight

Problem is here:

https://github.com/EngineHub/CommandHelper/blob/master/src/main/java/com/laytonsmith/core/functions/Compiler.java#L230

It looks like this is for multi-assignment chaining, but it's eating the "||" and "!" as the next two children, leaving @b because it's not a symbol. I'm not sure why it's going by twos here, exactly. If it's for chaining, it should maybe be checking if it's actually chaining an ivar and an equals symbol.

commented

Comment by LadyCailin

Order of operations is screwed up in edge cases like this. While it's fine to patch this, the real solution is to finish writing the object oriented, more formalized version here. https://github.com/EngineHub/CommandHelper/blob/master/src/main/java/com/laytonsmith/core/compiler/LexerObject.java and here: https://github.com/EngineHub/CommandHelper/blob/master/src/main/java/com/laytonsmith/core/compiler/CompilerObject.java and particularly here: https://github.com/EngineHub/CommandHelper/blob/master/src/main/java/com/laytonsmith/core/compiler/NewMethodScriptCompiler.java

While I don't think this is useable as is, (it's probably easier to start over) it should be rewritten using this as the inspiration. Particularly using the LexerObject would be a huge improvement, as it formalizes and cleans up the tokenization, and then formalize the order of operations (I don't think I ever actually wrote that particular code).

commented

Comment by Pieter12345

Update:
Since somewhere between build 3511 and 3589, this bug results in an uncaught exception during compile time. In build 3590, this was changed to a compile exception (even though the code is syntactically valid). This update is positive in the sense that code now breaks at compile time instead of having wrong runtime behavior,

Another workaround is to use braces: @var = @bool1 || (!@bool2) instead of @var = @bool1 || !@bool2.