SkyTemple / ExplorerScript

ExplorerScript and SSBScript: Script languages for decompiled SSB (Pokémon Mystery Dungeon Explorers of Sky)
MIT License
17 stars 6 forks source link

Multiple statements in with blocks #4

Closed theCapypara closed 1 month ago

theCapypara commented 3 years ago

Summary

Allow multiple simple statements in with blocks. Currently only one is supported. Multiple statements in one with-block would be compiled as if multiple consecutive with-blocks with a single statement were written.

Motivation

This change makes using multiple consecutive operations for one actor/object/performer much simpler to write or read, as such operations can now be grouped into a single block.

Examples

with (actor ACTOR_ATTENDANT1) {
        SetEffect(EFFECT_JOYOUS, 3);
        MovePositionOffset(1, 48, 0);
}

This would be an example of this new syntax.

with (actor ACTOR_ATTENDANT1) {
        SetEffect(EFFECT_JOYOUS, 3);
}
with (actor ACTOR_ATTENDANT1) {
        MovePositionOffset(1, 48, 0);
}

It is equivalent to the above, which is currently already possible without this change.

lives(ACTOR_ATTENDANT1);
SetEffect(EFFECT_JOYOUS, 3);
lives(ACTOR_ATTENDANT1);
MovePositionOffset(1, 48, 0);

It produces this equivalent SsbScript.

Language Changes

Parser and Lexer Changes

The parser needs to accept one or multiple simple_stmt in ctx_block, where it currently only accepts one.

Behaviour

This does not cause any further behavioral changes.

Compiler Implementation

Compiler Interface Changes

The compiler interface is not changed.

Decompiler Changes

The decompiler could be extended to decompile multiple consecutive blocks of lives,object,performer and operations into a single with block (given that the ID of the entity match).

How to teach

The section on with blocks in the documentation is extended to explain that with blocks can contain multiple statements.

Alternatives

  1. 49 : Substitute with-blocks with inline context syntax. This could be an alternative to this change, but it could also be a supplement, as both ideas have different situational advantages.

  2. Add additional syntax to allow calling global code from the global context "breaking out" of with-blocks (<WaitExecuteLives(ACTOR_ATTENDANT1);)
  3. Add a self keyword that gets replaced with the ID of the entity during compilation. (WaitExecuteLives(self);)
  4. A concern raised was expectation of concurrency when using with-blocks. This can already be confusing the the existing with-blocks, but having the ability to add multiple statements to a with-block can make this even more confusing, with some operations waiting for the previous to finish, while others don't, which can also depend on whether the previous operation was for the same entity or not,

No. 2. and 3. have been discussed on Discord. We have concluded that it is probably better not to include them, as combined with 1. there isn't much need and the syntax can be confusing. 3. especially requires 2. to be useful. No. 4. was deemed to be probably not a huge issue, as the potentially surprising behavior is quickly observed when testing scripts and this is already an issue anyway.

Backwards compatibility

This is fully backwards compatible.