-
Notifications
You must be signed in to change notification settings - Fork 15
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
toLeopard: Store # of times to repeat statically when it's a block #122
Conversation
Nice! I kinda forgot that you can declare whatever you want within the for loop. Just to make sure: we should never run into a case where the code within the loop is expecting to access a |
Yep, absolutely. There are no expressions which aren't prefixed by some constant identifier (usually It might be interesting to explore "transforming" variables that are only accessed within the scope of a single script/custom block (or whose value can be proven to be exactly known within that script and never accessed outside that script) into actual local JavaScript variables, but that's definitely something to look at later! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! 😄
I just realized that custom blocks are converted to methods with inputs as parameters, which have no prefix. Could we end up with a situation like this? *myCustomBlock(times) { // Suppose times = 5 and this.vars.count = 10
for (let i = 0, times = this.vars.count; i < times; i++) {
this.say(times); // Should say "5" but instead says "10"
}
} |
That is terrifying :) Excellent catch. I'm going to investigate this but I think you're right. On an interim solution, I'm probably just going to iterate over I don't think it would make sense to roll a more complex system of getting available local variable names into this PR, but I'd be happy to do a follow-up (as a PR or issue) exploring that. It would be a useful capability to have for performing more complex block-to-JS operations in general! |
I felt that and agree. 😅 But I think your proposed solution makes sense. |
45be08a
to
1e17b65
Compare
I just made a test project to confirm each of the things that should be working: https://scratch.mit.edu/projects/941395074/ (The last two still aren't, of course!) |
1e17b65
to
f52cd4b
Compare
Hoo-ray! We fixed the problems with overshadowing a custom block input named "times" - as well as sequentially higher names - and did the same thing for "i", since that's also a name we use, and might accidentally overshadow. Plus, we added a totally new snapshot test, to actually make sure this is working. Highly recommend looking at the 4 latest commits ("add test ... don't overshadow i, either") in order, to understand our process:
We went back and edited commits 1 and 2 as we realized they needed additions or changes. We also tested manually by using the test project we made in December: https://scratch.mit.edu/projects/941395074/ Note that in one case we expect this code: *avoidAbscuring(times, i) {
for (let i2 = 0; i2 < 1; i2++) {
for (
let i2 = 0, times2 = this.x + 6 * this.toNumber(i);
i2 < times2;
i2++
) {
this.x += this.toNumber(times);
yield;
}
yield;
}
} This is OK JS, but it's yucky (we define |
Yes, that worked! It was pretty much as simple as associating the unique-local-var-name function with the script, so it could be reused in We're pretty sure this is basically the perfect solution to #122 (comment) LOL. If it keeps working as it appears to~ |
One more addendum: Currently, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. Thank you for adding an additional (very comprehensive) test.
In the future, I would consider using i, j, k, etc. as opposed to i, i2, i3, etc. but this PR is perfect for now. |
Snapshot includes current output as of this commit...
Manually entered. As of this commit, the test fails. Note that we're fully expecting i2 to be used twice in the nested repeat example - although awkward, this is perfectly OK from a JavaScript perspective.
Resolves #119. See the issue for some related (philosophical) discussion.
For
control_repeat
blocks whose number of times to repeat is a reporter, this stores that expression in atimes
variable to be evaluated only once, alongsidei = 0
; like in Scratch, that value remains static over the course of the for loop's evaluation. This improves compatibility with a relatively minimal impact on (output) code legibility.Tested manually. I'd have liked to update the snapshot test, but couldn't figure out how to open and edit it in Scratch without inadvertently causing a number of unrelated changes to the sb3.
Requesting a review from either or both - this is a change to Leopard project generation that will affect quite a number of projects, though it's always an improvement for compatibility with Scratch. IMO it lays bare how both the repeat block and
for
loops work - but declaring two variables in the beginning of afor
loop is admittedly not very common.At the moment, it's impossible to move the
times
declaration out of thefor
loop because we don't have trck which JavaScript variables in-scope - you'd have to ensurelet times1
,let times2
, etc get declared, not just reusing the one name. That said, this is only an issue for loops on the same level, not loops nested in each other:If we wanted to go with a separate
times
declaration from the loop, I think that would be doable - but I don't feel the code would be much nicer.So my preference is to leave it as this PR has it (and not just because that's less work for me! LOL). But interested to hear what others think.