Open towerofnix opened 1 year ago
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 https://github.com/leopard-js/sb-edit/issues/45#issuecomment-1464771339 — I do believe these should be implemented in a (mostly) language-agnostic way. More on that in the future!
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.
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).
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 asoperator_equals
have a direct JavaScript analogue===
but due to specifics in Scratch implementation, must use a customcompare()
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 inblockToJS
.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
anddata_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 scopeIn 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 anIndex
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.