ribrdb / desynced-tools

Tools for working with behaviors and blueprints from Desynced.
MIT License
4 stars 3 forks source link

How to use compileDynamicJump? #48

Closed swazrgb closed 6 months ago

swazrgb commented 6 months ago

I was wondering what the use case for compileDynamicJump is, and what typescript syntax to use to trigger it?

I managed to trigger it with:

    switch((state)) {
        case 0:
            notify("Hi");
            break;
    }

But I assume this isn't the intended syntax?

If #44 goes ahead I would like to rewrite it to support the following syntax:

switch(state) {
  case value("c_battery", 1):
    notify("First case");
    break;
}

and remove the generation of the setNumber instruction

ribrdb commented 6 months ago

Yes, I was intending this to support numeric switch statements. And it uses a random "id" part of the value so that you can have multiple switch statements. If we have value literals it could make sense to support them in a switch statement, but that could be kind of tricky. What if you want to have multiple switch statements with the same value as a case? I guess maybe we couple put them into separate subroutines?

swazrgb commented 6 months ago

What if you want to have multiple switch statements with the same value as a case

Good point. Better for users to use the label & jump instructions explicitly. Perhaps an inlined function (not a subroutine) could be the target of a jump (though this raises the question of how to deal with passing the parameters in typescript. Perhaps the compiler could simply enforce the function signatures match?). I'm looking for a clean syntax to implement a state machine pattern, and the numeric switch is good but I would prefer no additional instructions such as setNumber to be used.

image

swazrgb commented 6 months ago

What do you think about supporting this syntax?

export function main(state: Value) {
    label(value("c_battery", 1), () => {
        notify("Setup phase");
        state = value("c_battery", 2);
    });

    label(value("c_battery", 2), () => {
        notify("Loop phase");
    });

    jump(state);
    state = value("c_battery", 1);
}

This would generate something akin to (already possible, but annoying because editor considers anything after return dead code):

export function main(state: Value) {
    jump(state);
    state = value("c_battery", 1);
    return;

    {
        label(value("c_battery", 1));
        notify("Setup phase");
        state = value("c_battery", 1);

        return;
    }

    {
        label(value("c_battery", 2));
        notify("Loop phase");

        return;
    }
}

I believe this should be safe w.r.t. local variable scoping as long as label is only permitted in the top-most block, though it would complicate any future variable usage optimizations.

ribrdb commented 6 months ago

That seems like a good way to handle labels. I assume you meant to put the jump after setting state?

swazrgb commented 6 months ago

Yes, correct. I'll follow up with a PR later. Thanks!