Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Investigate inspecting return types of input blocks for general-use static interpretation #98

Open
towerofnix opened this issue Feb 28, 2023 · 3 comments
Labels
API / interface Relevant to object structures and interfaces beyond serialization blocked This is blocked on other changes or resolutions discussion Looking for feedback and input

Comments

@towerofnix
Copy link
Member

For Leopard serialization — it may be useful to have access to the satisfied input shape of a block, in cases when the desired shape is Any. Comparison blocks such as operator_equals have a direct JavaScript analogue === but due to specifics in Scratch implementation, must use a custom compare() function when neither side of the block has a determined type.

Currently, we only determine the type of primitive (static) inputs, e.g. "10" (number, index, string, any) or "hello world" (string, any). However, there's nothing theoretically barring us from inspecting the kind of value which would be returned by a block as well, particularly since we already have a mapping of that information: satisfiesInputShape as determined in blockToJS.

  • Most blocks have an unchanging return shape, e.g. motion_xposition (number), operators_contains (boolean), sensing_mousedown (boolean).

  • Some blocks have a return shape which is never determined(*), such as data_variable and data_itemoflist.

  • Some blocks have a return shape determined by an input on the block, such as sensing_of.
    (*) without further static analysis (e.g. what kinds of values a variable is ever set to) - which builds on ideas in this issue but is out of its scope

In order to support dynamic return shapes, we probably need to evaluate the exact return shape of a block at serialization time for any given input.

It is possible to create a mapping of blocks to their possible return shapes (as an array). I would probably treat this as metadata about block serialization and have it include forms it's also capable of "absorbing" into its input shape (e.g. how data_itemnumoflist can absorb the following - 1 to satisfy an Index input).

A pertinent question is, how much of this should be brought out as an interface for all output formats to (be able to) make use of? I've been using toLeopard.ts as a convenient place to isolate and experiment with changes, but many of these ideas have relevance for serialization to other languages too. Accessing the return shape of a block may also be useful for language-agnostic static interpretation: changes which operate on and return sb-edit blocks and inputs themselves, rather than at time of serialization.

Many of the block-specific operations we do for Leopard would also be useful in serialization to other languages. Pulling them and relevant support out of Leopard would help make sb-edit as a whole more robust, and tighten the scope of toLeopard.ts in particular.

@towerofnix towerofnix added the discussion Looking for feedback and input label Mar 10, 2023
@towerofnix
Copy link
Member Author

towerofnix commented Mar 11, 2023

I'm labelling this as a follow-up issue to #100 (for the general necessary rework) and #93 (for specific API implementation). Cases I discuss in this issue would be examples of the "mutations" I mentioned in #45 (comment) — I do believe these should be implemented in a (mostly) language-agnostic way. More on that in the future!

@towerofnix towerofnix added blocked This is blocked on other changes or resolutions API / interface Relevant to object structures and interfaces beyond serialization labels Mar 11, 2023
@towerofnix
Copy link
Member Author

See #119 for a brief discussion of static analysis in general. This issue discusses type analysis; there we touch on an example where state analysis, instead, would be needed. For example, we can only skip the times variable if we determine (via state analysis) that the value which i is compared against would remain constant over the course of the loop. Likewise, we can only "roll" this.index (or any variable) into the loop if we determine that it won't be otherwise altered, i.e. it will continue in a straight increment up to the (also constant) number of times to loop.

@towerofnix
Copy link
Member Author

See #9 for a case where relatively aggressive number-casting is required for handling hexadecimally represented "numbers", instead of just storing the value as a number in the first place (this.vars.myVariable = 0x7f7f7f), because Scratch doesn't store hex-represented values as numbers - it stores them as strings. This is important for blocks like "length of (string)" and "letter (pos) of (string)".

With static type analysis, we could identify that a variable has no string-based uses (in other words any block that is sensitive to the variable's value as-is, distinct from as casted to a number); if so, we could represent its value as a number from the start, and not worry about casting the variable to a number later (also provided it's never set to a non-numeric string, of course).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API / interface Relevant to object structures and interfaces beyond serialization blocked This is blocked on other changes or resolutions discussion Looking for feedback and input
Projects
None yet
Development

No branches or pull requests

1 participant