Stevertus / mcscript

A programming language for Minecraft Vanilla
https://mcscript.stevertus.com
MIT License
233 stars 16 forks source link

Logical operators and conditional statements (if/else) get compiled wrongly #32

Open cgytrus opened 3 years ago

cgytrus commented 3 years ago

The compiler assumes that an else statement after if(!condition1 && !condition2) is if(condition1 && condition2), when in reality it should be if(condition1 || condition2) (aka if(!(!condition1 && !condition2)) which mcscript doesn't seem to support) Example, should kill a dropped item if it has a block of gold 1 or 2 blocks below it and set the block at it's current position to a red banner otherwise, but it will instead kill it only when both blocks are blocks of gold:

asat(@e[type=minecraft:item]) {
    if(!'block ~ ~-1 ~ minecraft:gold_block' && !'block ~ ~-2 ~ minecraft:gold_block') {
        /setblock ~ ~ ~ minecraft:red_banner
    } else {
        /kill @s
    }
}
cgytrus commented 3 years ago

Update: figured out a bit more about this there are issues with logical operators and conditional statements that are kinda probably related to each other about logical operators: this code:

asat(@e) {
    if('block ~ ~ ~ air' && 'block ~ ~-1~ air' || 'block ^ ^ ^ air' && 'block ^ ^ ^1 air') {
        /say huh??
    }
}

compiles as

execute as @e at @s if block ~ ~ ~ air if block ~ ~-1~ air if block ^ ^ ^1 air run say huh??
execute as @e at @s if block ^ ^ ^ air run say huh??

when it actually should be

execute as @e at @s if block ~ ~ ~ air if block ~ ~-1~ air run say huh??
execute as @e at @s if block ^ ^ ^ air if block ^ ^ ^1 air run say huh??

from this you can see, that it sorts the operators (cond1 && cond2 || cond3 && cond4) by their priority (cond1 && cond2 && cond4 || cond3) when it actually should take the &&(and) conditions in one execute command and ||(or) in multiple without sorting them a possible solution for this would be to not sort the conditions, but apply multiple "passes", so that one pass handles &&s, then the next one ||s etc.

now about conditional operators (if/else): this code:

asat(@e) {
    if('block ~ ~ ~ air' && 'block ~ ~-1 ~ air) {
        /say cond1
    } else {
        /say cond2
    }
}

compiles as

execute as @e at @s if block ~ ~ ~ air if block ~ ~-1 ~ air run say cond1
execute as @e at @s unless block ~ ~ ~ air unless block ~ ~-1 ~ air run say cond2

when it actually should be

execute as @e at @s if block ~ ~ ~ air if block ~ ~-1 ~ air run say cond1
execute as @e at @s unless block ~ ~ ~ air run say cond2
execute as @e at @s unless block ~ ~-1 ~ air run say cond2

from this you can see, that the else statement only inverts the conditions, when it also should revert the logical operators, so cond1 && cond2 becomes !cond1 && !cond2 but it actually should become !cond1 || !cond2

hope this update helps you to fix these!

Stevertus commented 3 years ago

Thanks for posting this. I often noticed that the boolean parsing is not quite right. And actually made a way better implementation of it in objd. But in fact mcscript was never supposed to do this that way. It should give a slight syntax variation of the minecraft commands and in the process it also inherited the problems with if and unless.

I understand that one might expect this behaving differently, but I honestly have not the time and motivation to rewrite anything to fix this big issue.