typescratch 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
typescratch/blocks.py ADDED
@@ -0,0 +1,961 @@
1
+ """Scratch 3.0 block table - mapping from TypeScratch syntax to Scratch opcodes.
2
+
3
+ Each entry is a dict with keys:
4
+ opcode Scratch opcode (e.g. "looks_sayforsecs")
5
+ args list of input specs. Each spec is a tuple:
6
+ (input_name, input_kind, source)
7
+ where input_kind in {"number","string","color","boolean","any",
8
+ "substack","substack2","var","list","menu"}
9
+ and source in {"args","post"} (which paren group the value
10
+ comes from - args = first parens, post = second parens).
11
+ For args, the index is implicit (consumed in order).
12
+ fields list of (field_name, value_or_None). If None, the value
13
+ comes from the next arg.
14
+ category for organization only.
15
+ special optional marker for special-case handling.
16
+
17
+ For reporters (boolean-returning or value-returning blocks used in
18
+ expressions), see REPORTERS below.
19
+ """
20
+
21
+ # ---------------------------------------------------------------------------
22
+ # Stack blocks (statements)
23
+ # ---------------------------------------------------------------------------
24
+
25
+ STACK_BLOCKS = {
26
+ # ---- Motion ----
27
+ "move": {
28
+ "opcode": "motion_movesteps",
29
+ "args": [("STEPS", "number", "args")],
30
+ },
31
+ "turnRight": {
32
+ "opcode": "motion_turnright",
33
+ "args": [("DEGREES", "number", "args")],
34
+ },
35
+ "turnLeft": {
36
+ "opcode": "motion_turnleft",
37
+ "args": [("DEGREES", "number", "args")],
38
+ },
39
+ "goto": {
40
+ "opcode": "motion_gotoxy",
41
+ "args": [("X", "number", "args"), ("Y", "number", "args")],
42
+ },
43
+ "goToXY": {
44
+ "opcode": "motion_gotoxy",
45
+ "args": [("X", "number", "args"), ("Y", "number", "args")],
46
+ },
47
+ "glide": {
48
+ "opcode": "motion_glidesecstoxy",
49
+ "args": [("SECS", "number", "args"), ("X", "number", "args"), ("Y", "number", "args")],
50
+ },
51
+ "glideTo": {
52
+ "opcode": "motion_glideto",
53
+ "args": [("SECS", "number", "args"), ("TO", "menu", "args")],
54
+ },
55
+ "pointInDirection": {
56
+ "opcode": "motion_pointindirection",
57
+ "args": [("DIRECTION", "angle", "args")],
58
+ },
59
+ "pointTowards": {
60
+ "opcode": "motion_pointtowards",
61
+ "args": [("TOWARDS", "menu", "args")],
62
+ },
63
+ "goTo": {
64
+ "opcode": "motion_goto",
65
+ "args": [("TO", "menu", "args")],
66
+ },
67
+ "changeX": {
68
+ "opcode": "motion_changexby",
69
+ "args": [("DX", "number", "args")],
70
+ },
71
+ "changeY": {
72
+ "opcode": "motion_changeyby",
73
+ "args": [("DY", "number", "args")],
74
+ },
75
+ "setX": {
76
+ "opcode": "motion_setx",
77
+ "args": [("X", "number", "args")],
78
+ },
79
+ "setY": {
80
+ "opcode": "motion_sety",
81
+ "args": [("Y", "number", "args")],
82
+ },
83
+ "ifOnEdgeBounce": {
84
+ "opcode": "motion_ifonedgebounce",
85
+ "args": [],
86
+ },
87
+ "setRotationStyle": {
88
+ "opcode": "motion_setrotationstyle",
89
+ "fields": [("STYLE", None)],
90
+ },
91
+
92
+ # ---- Looks ----
93
+ "say": {
94
+ "opcode": "looks_sayforsecs",
95
+ "args": [("MESSAGE", "string", "args"), ("SECS", "number", "post")],
96
+ },
97
+ "say_": { # used when no post parens -> say without secs
98
+ "opcode": "looks_say",
99
+ "args": [("MESSAGE", "string", "args")],
100
+ },
101
+ "think": {
102
+ "opcode": "looks_thinkforsecs",
103
+ "args": [("MESSAGE", "string", "args"), ("SECS", "number", "post")],
104
+ },
105
+ "think_": {
106
+ "opcode": "looks_think",
107
+ "args": [("MESSAGE", "string", "args")],
108
+ },
109
+ "switchCostumeTo": {
110
+ "opcode": "looks_switchcostumeto",
111
+ "fields": [("COSTUME", None)],
112
+ },
113
+ "nextCostume": {
114
+ "opcode": "looks_nextcostume",
115
+ "args": [],
116
+ },
117
+ "switchBackdropTo": {
118
+ "opcode": "looks_switchbackdropto",
119
+ "fields": [("BACKDROP", None)],
120
+ },
121
+ "nextBackdrop": {
122
+ "opcode": "looks_nextbackdrop",
123
+ "args": [],
124
+ },
125
+ "changeSize": {
126
+ "opcode": "looks_changesizeby",
127
+ "args": [("CHANGE", "number", "args")],
128
+ },
129
+ "setSize": {
130
+ "opcode": "looks_setsizeto",
131
+ "args": [("SIZE", "number", "args")],
132
+ },
133
+ "changeEffect": {
134
+ "opcode": "looks_changeeffectby",
135
+ "fields": [("EFFECT", None)],
136
+ "args": [("CHANGE", "number", "args")],
137
+ },
138
+ "setEffect": {
139
+ "opcode": "looks_seteffectto",
140
+ "fields": [("EFFECT", None)],
141
+ "args": [("VALUE", "number", "args")],
142
+ },
143
+ "clearGraphicEffects": {
144
+ "opcode": "looks_cleargraphiceffects",
145
+ "args": [],
146
+ },
147
+ "show": {
148
+ "opcode": "looks_show",
149
+ "args": [],
150
+ },
151
+ "hide": {
152
+ "opcode": "looks_hide",
153
+ "args": [],
154
+ },
155
+ "goToFront": {
156
+ "opcode": "looks_goforwardbackwardlayers",
157
+ "fields": [("FRONTBACK", "front")],
158
+ "args": [("NUM", "number", "args", True)], # optional - default 1
159
+ },
160
+ "goToBack": {
161
+ "opcode": "looks_goforwardbackwardlayers",
162
+ "fields": [("FRONTBACK", "back")],
163
+ "args": [("NUM", "number", "args", True)],
164
+ },
165
+ "goBackLayers": {
166
+ "opcode": "looks_goforwardbackwardlayers",
167
+ "fields": [("FRONTBACK", "back")],
168
+ "args": [("NUM", "number", "args")],
169
+ },
170
+ "goForwardLayers": {
171
+ "opcode": "looks_goforwardbackwardlayers",
172
+ "fields": [("FRONTBACK", "front")],
173
+ "args": [("NUM", "number", "args")],
174
+ },
175
+
176
+ # ---- Sound ----
177
+ "playSound": {
178
+ "opcode": "sound_play",
179
+ "fields": [("SOUND_MENU", None)],
180
+ },
181
+ "playSoundUntilDone": {
182
+ "opcode": "sound_playuntildone",
183
+ "fields": [("SOUND_MENU", None)],
184
+ },
185
+ "stopAllSounds": {
186
+ "opcode": "sound_stopallsounds",
187
+ "args": [],
188
+ },
189
+ "changePitch": {
190
+ "opcode": "sound_changepitchby",
191
+ "args": [("PITCH", "number", "args")],
192
+ },
193
+ "setPitch": {
194
+ "opcode": "sound_setpitchto",
195
+ "args": [("PITCH", "number", "args")],
196
+ },
197
+ "changeVolume": {
198
+ "opcode": "sound_changevolumeby",
199
+ "args": [("VOLUME", "number", "args")],
200
+ },
201
+ "setVolume": {
202
+ "opcode": "sound_setvolumeto",
203
+ "args": [("VOLUME", "number", "args")],
204
+ },
205
+
206
+ # ---- Control ----
207
+ "createCloneOf": {
208
+ "opcode": "control_create_clone_of",
209
+ "fields": [("CLONE_OPTION", None)],
210
+ },
211
+ "deleteThisClone": {
212
+ "opcode": "control_delete_this_clone",
213
+ "args": [],
214
+ },
215
+ "runBroadcast": { # alias for broadcast() - used internally
216
+ "opcode": "event_broadcast",
217
+ "args": [("BROADCAST_INPUT", "broadcast", "args")],
218
+ },
219
+ "runBroadcastAndWait": {
220
+ "opcode": "event_broadcastandwait",
221
+ "args": [("BROADCAST_INPUT", "broadcast", "args")],
222
+ },
223
+
224
+ # ---- Sensing ----
225
+ "askAndWait": {
226
+ "opcode": "sensing_askandwait",
227
+ "args": [("QUESTION", "string", "args")],
228
+ },
229
+ "resetTimer": {
230
+ "opcode": "sensing_resettimer",
231
+ "args": [],
232
+ },
233
+ "setDraggable": {
234
+ "opcode": "sensing_setdragmode",
235
+ "fields": [("DRAG_MODE", None)],
236
+ },
237
+
238
+ # ---- Variables (handled specially in codegen) ----
239
+ # ---- Lists (handled specially in codegen via ListOp) ----
240
+
241
+ # ---- Pen extension ----
242
+ # accessed as pen.X
243
+ "pen.Down": {"opcode": "pen_penDown", "args": []},
244
+ "pen.Up": {"opcode": "pen_penUp", "args": []},
245
+ "pen.SetColor": {
246
+ "opcode": "pen_setPenColorTo",
247
+ "args": [("COLOR", "color", "args")],
248
+ },
249
+ "pen.ChangeColor": {
250
+ "opcode": "pen_changePenColorBy",
251
+ "args": [("COLOR", "number", "args")],
252
+ },
253
+ "pen.SetHue": {
254
+ "opcode": "pen_setPenHueToNumber",
255
+ "args": [("HUE", "number", "args")],
256
+ },
257
+ "pen.ChangeHue": {
258
+ "opcode": "pen_changePenHueBy",
259
+ "args": [("HUE", "number", "args")],
260
+ },
261
+ "pen.SetShade": {
262
+ "opcode": "pen_setPenShadeToNumber",
263
+ "args": [("SHADE", "number", "args")],
264
+ },
265
+ "pen.ChangeShade": {
266
+ "opcode": "pen_changePenShadeBy",
267
+ "args": [("SHADE", "number", "args")],
268
+ },
269
+ "pen.SetSize": {
270
+ "opcode": "pen_setPenSizeTo",
271
+ "args": [("SIZE", "number", "args")],
272
+ },
273
+ "pen.ChangeSize": {
274
+ "opcode": "pen_changePenSizeBy",
275
+ "args": [("SIZE", "number", "args")],
276
+ },
277
+ "pen.SetSaturation": {
278
+ "opcode": "pen_setPenSaturationToNumber",
279
+ "args": [("SATURATION", "number", "args")],
280
+ },
281
+ "pen.ChangeSaturation": {
282
+ "opcode": "pen_changePenSaturationBy",
283
+ "args": [("SATURATION", "number", "args")],
284
+ },
285
+ "pen.SetBrightness": {
286
+ "opcode": "pen_setPenBrightnessToNumber",
287
+ "args": [("BRIGHTNESS", "number", "args")],
288
+ },
289
+ "pen.ChangeBrightness": {
290
+ "opcode": "pen_changePenBrightnessBy",
291
+ "args": [("BRIGHTNESS", "number", "args")],
292
+ },
293
+ "pen.SetTransparency": {
294
+ "opcode": "pen_setPenTransparencyToNumber",
295
+ "args": [("TRANSPARENCY", "number", "args")],
296
+ },
297
+ "pen.ChangeTransparency": {
298
+ "opcode": "pen_changePenTransparencyBy",
299
+ "args": [("TRANSPARENCY", "number", "args")],
300
+ },
301
+ "pen.Stamp": {"opcode": "pen_stamp", "args": []},
302
+ "pen.Clear": {"opcode": "pen_clear", "args": []},
303
+
304
+ # ---- Music extension (extension Music) ----
305
+ "music.PlayDrum": {
306
+ "opcode": "music_playDrumForBeats",
307
+ "fields": [("DRUM", None)],
308
+ "args": [("BEATS", "number", "args")],
309
+ },
310
+ "music.Rest": {
311
+ "opcode": "music_restForBeats",
312
+ "args": [("BEATS", "number", "args")],
313
+ },
314
+ "music.PlayNote": {
315
+ "opcode": "music_playNoteForBeats",
316
+ "args": [("NOTE", "number", "args"), ("BEATS", "number", "args")],
317
+ },
318
+ "music.SetInstrument": {
319
+ "opcode": "music_setInstrument",
320
+ "fields": [("INSTRUMENT", None)],
321
+ },
322
+ "music.SetTempo": {
323
+ "opcode": "music_setTempo",
324
+ "args": [("TEMPO", "number", "args")],
325
+ },
326
+ "music.ChangeTempo": {
327
+ "opcode": "music_changeTempo",
328
+ "args": [("TEMPO", "number", "args")],
329
+ },
330
+
331
+ # ---- Text to Speech extension (extension Text to Speech) ----
332
+ "tts.Speak": {
333
+ "opcode": "text2speech_speakAndWait",
334
+ "args": [("WORDS", "string", "args")],
335
+ },
336
+ "tts.SetVoice": {
337
+ "opcode": "text2speech_setVoice",
338
+ "fields": [("VOICE", None)],
339
+ },
340
+ "tts.SetLanguage": {
341
+ "opcode": "text2speech_setLanguage",
342
+ "fields": [("LANGUAGE", None)],
343
+ },
344
+
345
+ # ---- Speech to Text extension (hidden / experimental in Scratch UI) ----
346
+ # Emits a warning at compile time. Generates the real speech2text
347
+ # blocks; they may or may not work in your Scratch editor.
348
+ "listenAndWait": {
349
+ "opcode": "speech2text_listenAndWait",
350
+ "args": [],
351
+ "_warn": "Speech to Text is hidden in the Scratch UI and may not work.",
352
+ },
353
+ "listen.Wait": {
354
+ "opcode": "speech2text_listenAndWait",
355
+ "args": [],
356
+ "_warn": "Speech to Text is hidden in the Scratch UI and may not work.",
357
+ },
358
+
359
+ # ---- Sound: clear/change/set sound effects ----
360
+ "clearSoundEffects": {
361
+ "opcode": "sound_cleareffects",
362
+ "args": [],
363
+ },
364
+ "changeSoundEffect": {
365
+ "opcode": "sound_changeeffectby",
366
+ "fields": [("EFFECT", None)],
367
+ "args": [("VALUE", "number", "args")],
368
+ },
369
+ "setSoundEffect": {
370
+ "opcode": "sound_seteffectto",
371
+ "fields": [("EFFECT", None)],
372
+ "args": [("VALUE", "number", "args")],
373
+ },
374
+
375
+ # ---- Variables: show/hide variable (the monitor, not the value) ----
376
+ "showVariable": {
377
+ "opcode": "data_showvariable",
378
+ "fields": [("VARIABLE", None)],
379
+ },
380
+ "hideVariable": {
381
+ "opcode": "data_hidevariable",
382
+ "fields": [("VARIABLE", None)],
383
+ },
384
+
385
+ # ---- Hidden Control blocks: counter ----
386
+ "incrementCounter": {
387
+ "opcode": "control_incr_counter",
388
+ "args": [],
389
+ },
390
+ "resetCounter": {
391
+ "opcode": "control_clear_counter",
392
+ "args": [],
393
+ },
394
+
395
+ # ---- Hidden Control block: all-at-once (run without screen refresh) ----
396
+ "allAtOnce": {
397
+ "opcode": "control_all_at_once",
398
+ "substack": "SUBSTACK",
399
+ },
400
+
401
+ # ---- Hidden Looks blocks: stretch (legacy but still functional) ----
402
+ "changeStretch": {
403
+ "opcode": "looks_changestretchby",
404
+ "args": [("CHANGE", "number", "args")],
405
+ },
406
+ "setStretch": {
407
+ "opcode": "looks_setstretchto",
408
+ "args": [("STRETCH", "number", "args")],
409
+ },
410
+
411
+ # ---- Hidden Looks block: hide all sprites ----
412
+ "hideAllSprites": {
413
+ "opcode": "looks_hideallsprites",
414
+ "args": [],
415
+ },
416
+
417
+ # ---- Hidden Looks block: switch backdrop to X and wait ----
418
+ "switchBackdropToAndWait": {
419
+ "opcode": "looks_switchbackdroptoandwait",
420
+ "fields": [("BACKDROP", None)],
421
+ },
422
+
423
+ # ---- Video Sensing extension ----
424
+ "video.Toggle": {
425
+ "opcode": "videoSensing_videoToggle",
426
+ "fields": [("VIDEO_STATE", None)],
427
+ },
428
+ "video.SetTransparency": {
429
+ "opcode": "videoSensing_setVideoTransparency",
430
+ "args": [("TRANSPARENCY", "number", "args")],
431
+ },
432
+
433
+ # ---- Makey Makey extension ----
434
+ # Both blocks are hats - declared in HAT_BLOCKS below.
435
+
436
+ # ---- micro:bit extension ----
437
+ "mb.DisplaySymbol": {
438
+ "opcode": "microbit_displaySymbol",
439
+ "args": [("MATRIX", "string", "args")],
440
+ },
441
+ "mb.DisplayText": {
442
+ "opcode": "microbit_displayText",
443
+ "args": [("TEXT", "string", "args")],
444
+ },
445
+ "mb.DisplayClear": {
446
+ "opcode": "microbit_displayClear",
447
+ "args": [],
448
+ },
449
+
450
+ # ---- LEGO BOOST extension ----
451
+ "boost.MotorOnFor": {
452
+ "opcode": "boost_motorOnFor",
453
+ "fields": [("MOTOR_ID", None)],
454
+ "args": [("DURATION", "number", "args")],
455
+ },
456
+ "boost.MotorOnForRotation": {
457
+ "opcode": "boost_motorOnForRotation",
458
+ "fields": [("MOTOR_ID", None)],
459
+ "args": [("ROTATION", "number", "args")],
460
+ },
461
+ "boost.MotorOn": {
462
+ "opcode": "boost_motorOn",
463
+ "fields": [("MOTOR_ID", None)],
464
+ },
465
+ "boost.MotorOff": {
466
+ "opcode": "boost_motorOff",
467
+ "fields": [("MOTOR_ID", None)],
468
+ },
469
+ "boost.SetMotorPower": {
470
+ "opcode": "boost_setMotorPower",
471
+ "fields": [("MOTOR_ID", None)],
472
+ "args": [("POWER", "number", "args")],
473
+ },
474
+ "boost.SetMotorDirection": {
475
+ "opcode": "boost_setMotorDirection",
476
+ "fields": [("MOTOR_ID", None), ("MOTOR_DIRECTION", None)],
477
+ },
478
+ "boost.SetLightHue": {
479
+ "opcode": "boost_setLightHue",
480
+ "args": [("HUE", "number", "args")],
481
+ },
482
+
483
+ # ---- LEGO EV3 extension ----
484
+ "ev3.MotorTurnClockwise": {
485
+ "opcode": "ev3_motorTurnClockwise",
486
+ "fields": [("PORT", None)],
487
+ "args": [("TIME", "number", "args")],
488
+ },
489
+ "ev3.MotorTurnCounterClockwise": {
490
+ "opcode": "ev3_motorTurnCounterClockwise",
491
+ "fields": [("PORT", None)],
492
+ "args": [("TIME", "number", "args")],
493
+ },
494
+ "ev3.MotorSetPower": {
495
+ "opcode": "ev3_motorSetPower",
496
+ "fields": [("PORT", None)],
497
+ "args": [("POWER", "number", "args")],
498
+ },
499
+ "ev3.Beep": {
500
+ "opcode": "ev3_beep",
501
+ "args": [("NOTE", "number", "args"), ("TIME", "number", "args")],
502
+ },
503
+
504
+ # ---- LEGO WeDo 2.0 extension ----
505
+ "wedo.MotorOnFor": {
506
+ "opcode": "wedo2_motorOnFor",
507
+ "fields": [("MOTOR_ID", None)],
508
+ "args": [("DURATION", "number", "args")],
509
+ },
510
+ "wedo.MotorOn": {
511
+ "opcode": "wedo2_motorOn",
512
+ "fields": [("MOTOR_ID", None)],
513
+ },
514
+ "wedo.MotorOff": {
515
+ "opcode": "wedo2_motorOff",
516
+ "fields": [("MOTOR_ID", None)],
517
+ },
518
+ "wedo.SetMotorPower": {
519
+ "opcode": "wedo2_startMotorPower",
520
+ "fields": [("MOTOR_ID", None)],
521
+ "args": [("POWER", "number", "args")],
522
+ },
523
+ "wedo.SetMotorDirection": {
524
+ "opcode": "wedo2_setMotorDirection",
525
+ "fields": [("MOTOR_ID", None), ("MOTOR_DIRECTION", None)],
526
+ },
527
+ "wedo.SetLightHue": {
528
+ "opcode": "wedo2_setLightHue",
529
+ "args": [("HUE", "number", "args")],
530
+ },
531
+ "wedo.PlayNote": {
532
+ "opcode": "wedo2_playNoteFor",
533
+ "args": [("NOTE", "number", "args"), ("DURATION", "number", "args")],
534
+ },
535
+
536
+ # ---- Go Direct Force & Acceleration extension (gdxfor) ----
537
+ # All hats and reporters - see HAT_BLOCKS and REPORTERS below.
538
+ }
539
+
540
+ # ---------------------------------------------------------------------------
541
+ # Reporter blocks (used in expressions - return a value)
542
+ # ---------------------------------------------------------------------------
543
+
544
+ REPORTERS = {
545
+ # Motion
546
+ "xPosition": {"opcode": "motion_xposition", "returns": "number"},
547
+ "x": {"opcode": "motion_xposition", "returns": "number"},
548
+ "yPosition": {"opcode": "motion_yposition", "returns": "number"},
549
+ "y": {"opcode": "motion_yposition", "returns": "number"},
550
+ "direction": {"opcode": "motion_direction", "returns": "number"},
551
+
552
+ # Looks
553
+ "costumeName": {"opcode": "looks_costumename", "returns": "string"},
554
+ "costumeNumber": {"opcode": "looks_costumenumber", "returns": "number"},
555
+ "backdropName": {"opcode": "looks_backdropname", "returns": "string"},
556
+ "backdropNumber": {"opcode": "looks_backdropnumber", "returns": "number"},
557
+ "size": {"opcode": "looks_size", "returns": "number"},
558
+
559
+ # Sound
560
+ "volume": {"opcode": "sound_volume", "returns": "number"},
561
+ "tempo": {"opcode": "sound_tempo", "returns": "number"},
562
+
563
+ # Sensing
564
+ "answer": {"opcode": "sensing_answer", "returns": "string"},
565
+ "mouseDown": {"opcode": "sensing_mousedown", "returns": "boolean"},
566
+ "mouseX": {"opcode": "sensing_mousex", "returns": "number"},
567
+ "mouseY": {"opcode": "sensing_mousey", "returns": "number"},
568
+ "loudness": {"opcode": "sensing_loudness", "returns": "number"},
569
+ "timer": {"opcode": "sensing_timer", "returns": "number"},
570
+ "daysSince2000": {"opcode": "sensing_dayssince2000", "returns": "number"},
571
+ "username": {"opcode": "sensing_username", "returns": "string"},
572
+ "keyPressed": {
573
+ "opcode": "sensing_keypressed",
574
+ "fields": [("KEY_OPTION", None)],
575
+ "returns": "boolean",
576
+ },
577
+ "touching": {
578
+ "opcode": "sensing_touchingobject",
579
+ "fields": [("TOUCHINGOBJECTMENU", None)],
580
+ "returns": "boolean",
581
+ },
582
+ "touchingColor": {
583
+ "opcode": "sensing_touchingcolor",
584
+ "args": [("COLOR", "color", "args")],
585
+ "returns": "boolean",
586
+ },
587
+ "colorIsTouching": {
588
+ "opcode": "sensing_coloristouching",
589
+ "args": [("COLOR", "color", "args"), ("COLOR2", "color", "args")],
590
+ "returns": "boolean",
591
+ },
592
+ "distanceTo": {
593
+ "opcode": "sensing_distanceto",
594
+ "fields": [("DISTANCETOMENU", None)],
595
+ "returns": "number",
596
+ },
597
+
598
+ # Operators
599
+ "pickRandom": {
600
+ "opcode": "operator_random",
601
+ "args": [("FROM", "number", "args"), ("TO", "number", "args")],
602
+ "returns": "number",
603
+ },
604
+ "join": {
605
+ "opcode": "operator_join",
606
+ "args": [("STRING1", "string", "args"), ("STRING2", "string", "args")],
607
+ "returns": "string",
608
+ },
609
+ "lengthOf": {
610
+ "opcode": "operator_length",
611
+ "args": [("STRING", "string", "args")],
612
+ "returns": "number",
613
+ },
614
+ "contains": {
615
+ "opcode": "operator_contains",
616
+ "args": [("STRING1", "string", "args"), ("STRING2", "string", "args")],
617
+ "returns": "boolean",
618
+ },
619
+ "round": {
620
+ "opcode": "operator_round",
621
+ "args": [("NUM", "number", "args")],
622
+ "returns": "number",
623
+ },
624
+ # math ops - single arg + OPERATOR field
625
+ "abs": {"opcode": "operator_mathop", "fields": [("OPERATOR", "abs")], "args": [("NUM", "number", "args")], "returns": "number"},
626
+ "floor": {"opcode": "operator_mathop", "fields": [("OPERATOR", "floor")], "args": [("NUM", "number", "args")], "returns": "number"},
627
+ "ceiling": {"opcode": "operator_mathop", "fields": [("OPERATOR", "ceiling")], "args": [("NUM", "number", "args")], "returns": "number"},
628
+ "sqrt": {"opcode": "operator_mathop", "fields": [("OPERATOR", "sqrt")], "args": [("NUM", "number", "args")], "returns": "number"},
629
+ "sin": {"opcode": "operator_mathop", "fields": [("OPERATOR", "sin")], "args": [("NUM", "number", "args")], "returns": "number"},
630
+ "cos": {"opcode": "operator_mathop", "fields": [("OPERATOR", "cos")], "args": [("NUM", "number", "args")], "returns": "number"},
631
+ "tan": {"opcode": "operator_mathop", "fields": [("OPERATOR", "tan")], "args": [("NUM", "number", "args")], "returns": "number"},
632
+ "asin": {"opcode": "operator_mathop", "fields": [("OPERATOR", "asin")], "args": [("NUM", "number", "args")], "returns": "number"},
633
+ "acos": {"opcode": "operator_mathop", "fields": [("OPERATOR", "acos")], "args": [("NUM", "number", "args")], "returns": "number"},
634
+ "atan": {"opcode": "operator_mathop", "fields": [("OPERATOR", "atan")], "args": [("NUM", "number", "args")], "returns": "number"},
635
+ "ln": {"opcode": "operator_mathop", "fields": [("OPERATOR", "ln")], "args": [("NUM", "number", "args")], "returns": "number"},
636
+ "log": {"opcode": "operator_mathop", "fields": [("OPERATOR", "log")], "args": [("NUM", "number", "args")], "returns": "number"},
637
+ "e_^": {"opcode": "operator_mathop", "fields": [("OPERATOR", "e ^")], "args": [("NUM", "number", "args")], "returns": "number"},
638
+ "10_^": {"opcode": "operator_mathop", "fields": [("OPERATOR", "10 ^")], "args": [("NUM", "number", "args")], "returns": "number"},
639
+
640
+ # ---- Music extension reporters ----
641
+ "music.Tempo": {"opcode": "music_getTempo", "returns": "number"},
642
+
643
+ # ---- Translate extension reporters ----
644
+ "translate.To": {
645
+ "opcode": "translate_getTranslate",
646
+ "args": [("WORDS", "string", "args"), ("LANGUAGE", "string", "args")],
647
+ "returns": "string",
648
+ },
649
+ "translate.ViewerLanguage": {
650
+ "opcode": "translate_getViewerLanguage",
651
+ "returns": "string",
652
+ },
653
+
654
+ # ---- Speech to Text extension reporter (hidden / experimental) ----
655
+ "speech": {
656
+ "opcode": "speech2text_getSpeech",
657
+ "returns": "string",
658
+ "_warn": "Speech to Text is hidden in the Scratch UI and may not work.",
659
+ },
660
+
661
+ # ---- Hidden Control reporter: counter ----
662
+ "counter": {
663
+ "opcode": "control_get_counter",
664
+ "returns": "number",
665
+ },
666
+
667
+ # ---- TurboWarp extension reporters ----
668
+ # These only return true when the project is running inside TurboWarp
669
+ # (https://turbowarp.org). In vanilla Scratch they return false.
670
+ "isTurboWarp": {
671
+ "opcode": "tw_isTurboWarp",
672
+ "returns": "boolean",
673
+ },
674
+ "isCompiled": {
675
+ "opcode": "tw_isCompiled",
676
+ "returns": "boolean",
677
+ },
678
+ "isForked": {
679
+ "opcode": "tw_isForked",
680
+ "returns": "boolean",
681
+ },
682
+
683
+ # ---- Sensing: [attribute] of [sprite] (sensing_of) ----
684
+ "attribute": {
685
+ "opcode": "sensing_of",
686
+ "fields": [("PROPERTY", None), ("TARGET", None)],
687
+ "returns": "any",
688
+ },
689
+ # alias
690
+ "getAttribute": {
691
+ "opcode": "sensing_of",
692
+ "fields": [("PROPERTY", None), ("TARGET", None)],
693
+ "returns": "any",
694
+ },
695
+
696
+ # ---- Sensing: current [YEAR/MONTH/DATE/DAYOFWEEK/HOUR/MINUTE/SECOND/WEEKOFYEAR] ----
697
+ "current": {
698
+ "opcode": "sensing_current",
699
+ "fields": [("CURRENTMENU", None)],
700
+ "returns": "number",
701
+ },
702
+
703
+ # ---- Operators: letter (n) of (string) ----
704
+ "letterOf": {
705
+ "opcode": "operator_letter_of",
706
+ "args": [("LETTER", "number", "args"), ("STRING", "string", "args")],
707
+ "returns": "string",
708
+ },
709
+
710
+ # ---- Video Sensing extension reporter ----
711
+ "video.Motion": {
712
+ "opcode": "videoSensing_videoOn",
713
+ "fields": [("ATTRIBUTE", None), ("SUBJECT", None)],
714
+ "returns": "number",
715
+ },
716
+
717
+ # ---- micro:bit extension reporters / booleans ----
718
+ "mb.ButtonPressed": {
719
+ "opcode": "microbit_isButtonPressed",
720
+ "fields": [("BTN", None)],
721
+ "returns": "boolean",
722
+ },
723
+ "mb.Tilted": {
724
+ "opcode": "microbit_isTilted",
725
+ "fields": [("DIRECTION", None)],
726
+ "returns": "boolean",
727
+ },
728
+ "mb.TiltAngle": {
729
+ "opcode": "microbit_getTiltAngle",
730
+ "fields": [("DIRECTION", None)],
731
+ "returns": "number",
732
+ },
733
+
734
+ # ---- LEGO BOOST extension reporters / booleans ----
735
+ "boost.MotorPosition": {
736
+ "opcode": "boost_getMotorPosition",
737
+ "fields": [("MOTOR_REPORTER_ID", None)],
738
+ "returns": "number",
739
+ },
740
+ "boost.SeeingColor": {
741
+ "opcode": "boost_seeingColor",
742
+ "fields": [("COLOR", None)],
743
+ "returns": "boolean",
744
+ },
745
+ "boost.TiltAngle": {
746
+ "opcode": "boost_getTiltAngle",
747
+ "fields": [("TILT_DIRECTION", None)],
748
+ "returns": "number",
749
+ },
750
+
751
+ # ---- LEGO EV3 extension reporters / booleans ----
752
+ "ev3.MotorPosition": {
753
+ "opcode": "ev3_getMotorPosition",
754
+ "fields": [("PORT", None)],
755
+ "returns": "number",
756
+ },
757
+ "ev3.ButtonPressed": {
758
+ "opcode": "ev3_buttonPressed",
759
+ "fields": [("PORT", None)],
760
+ "returns": "boolean",
761
+ },
762
+ "ev3.Distance": {"opcode": "ev3_getDistance", "returns": "number"},
763
+ "ev3.Brightness": {"opcode": "ev3_getBrightness", "returns": "number"},
764
+
765
+ # ---- LEGO WeDo 2.0 extension reporters / booleans ----
766
+ "wedo.Distance": {"opcode": "wedo2_getDistance", "returns": "number"},
767
+ "wedo.Tilted": {
768
+ "opcode": "wedo2_isTilted",
769
+ "fields": [("TILT_DIRECTION_ANY", None)],
770
+ "returns": "boolean",
771
+ },
772
+ "wedo.TiltAngle": {
773
+ "opcode": "wedo2_getTiltAngle",
774
+ "fields": [("TILT_DIRECTION", None)],
775
+ "returns": "number",
776
+ },
777
+
778
+ # ---- Go Direct Force & Acceleration (gdxfor) reporters / booleans ----
779
+ "gdx.Force": {"opcode": "gdxfor_getForce", "returns": "number"},
780
+ "gdx.FreeFalling": {"opcode": "gdxfor_isFreeFalling", "returns": "boolean"},
781
+ "gdx.Tilted": {
782
+ "opcode": "gdxfor_isTilted",
783
+ "fields": [("TILT", None)],
784
+ "returns": "boolean",
785
+ },
786
+ "gdx.Tilt": {
787
+ "opcode": "gdxfor_getTilt",
788
+ "fields": [("TILT", None)],
789
+ "returns": "number",
790
+ },
791
+ "gdx.SpinSpeed": {
792
+ "opcode": "gdxfor_getSpinSpeed",
793
+ "fields": [("DIRECTION", None)],
794
+ "returns": "number",
795
+ },
796
+ "gdx.Acceleration": {
797
+ "opcode": "gdxfor_getAcceleration",
798
+ "fields": [("DIRECTION", None)],
799
+ "returns": "number",
800
+ },
801
+ }
802
+
803
+ # ---------------------------------------------------------------------------
804
+ # Auto-generate "?" variants for boolean reporters.
805
+ # In Scratch, boolean reporters often have "?" in their display names
806
+ # (e.g. "touching?", "key pressed?"). In TypeScratch we name them
807
+ # without the "?" (e.g. "isTurboWarp"), but users may instinctively add
808
+ # the "?". This loop creates aliases so both forms work.
809
+ # ---------------------------------------------------------------------------
810
+ for _key in list(REPORTERS.keys()):
811
+ _spec = REPORTERS[_key]
812
+ if _spec.get("returns") == "boolean" and not _key.endswith("?"):
813
+ REPORTERS[_key + "?"] = _spec
814
+
815
+ # ---------------------------------------------------------------------------
816
+ # Built-in reporters reachable by bare name (e.g. `days since 2000`)
817
+ # Maps lowercased bare name -> (canonical_name, reporter_key)
818
+ # ---------------------------------------------------------------------------
819
+
820
+ BUILTIN_ALIASES = {
821
+ # motion
822
+ "x position": "xPosition",
823
+ "y position": "yPosition",
824
+ # looks
825
+ "costume name": "costumeName",
826
+ "costume number": "costumeNumber",
827
+ "backdrop name": "backdropName",
828
+ "backdrop number": "backdropNumber",
829
+ # sensing
830
+ "answer": "answer",
831
+ "mouse down": "mouseDown",
832
+ "mouse x": "mouseX",
833
+ "mouse y": "mouseY",
834
+ "loudness": "loudness",
835
+ "timer": "timer",
836
+ "days since 2000": "daysSince2000",
837
+ "username": "username",
838
+ "key space pressed": "keyPressed",
839
+ # sound
840
+ "volume": "volume",
841
+ "tempo": "tempo",
842
+ "size": "size",
843
+ "direction": "direction",
844
+ }
845
+
846
+ # ---------------------------------------------------------------------------
847
+ # Hat blocks (event_whenX)
848
+ # ---------------------------------------------------------------------------
849
+
850
+ HAT_BLOCKS = {
851
+ "gf": {"opcode": "event_whenflagclicked"},
852
+ "spr": {"opcode": "event_whenthisspriteclicked"},
853
+ "stage_clicked": {"opcode": "event_whenstageclicked"},
854
+ "cloned": {"opcode": "control_start_as_clone"},
855
+ "key": {"opcode": "event_whenkeypressed",
856
+ "fields": [("KEY_OPTION", 0)]},
857
+ "backdrop": {"opcode": "event_whenbackdropswitchesto",
858
+ "fields": [("BACKDROP", 0)]},
859
+ "receive": {"opcode": "event_whenbroadcastreceived",
860
+ "fields": [("BROADCAST_OPTION", 0)]},
861
+ "greater_than": {"opcode": "event_whengreaterthan",
862
+ "fields": [("WHENGREATERTHANMENU", 0)],
863
+ "args": [("VALUE", "number", "args")]},
864
+
865
+ # ---- Video Sensing extension hat ----
866
+ "video_motion": {"opcode": "videoSensing_whenMotionGreaterThan",
867
+ "args": [("REFERENCE", "number", "args")]},
868
+
869
+ # ---- Speech to Text extension hat (hidden / experimental) ----
870
+ "i_hear": {"opcode": "speech2text_whenIHearHat",
871
+ "fields": [("PHRASE", 0)],
872
+ "_warn": "Speech to Text is hidden in the Scratch UI and may not work."},
873
+
874
+ # ---- Hidden Event hat: when touching [object] ----
875
+ "touching": {"opcode": "event_whentouchingobject",
876
+ "fields": [("TOUCHINGOBJECTMENU", 0)]},
877
+
878
+ # ---- Makey Makey extension hats ----
879
+ "makey_key": {"opcode": "makeymakey_whenMakeyKeyPressed",
880
+ "fields": [("KEY", 0)]},
881
+ "makey_code": {"opcode": "makeymakey_whenCodePressed",
882
+ "fields": [("SEQUENCE", 0)]},
883
+
884
+ # ---- micro:bit extension hats ----
885
+ "mb_button": {"opcode": "microbit_whenButtonPressed",
886
+ "fields": [("BTN", 0)]},
887
+ "mb_gesture": {"opcode": "microbit_whenGesture",
888
+ "fields": [("GESTURE", 0)]},
889
+ "mb_tilted": {"opcode": "microbit_whenTilted",
890
+ "fields": [("DIRECTION", 0)]},
891
+ "mb_pin": {"opcode": "microbit_whenPinConnected",
892
+ "fields": [("PIN", 0)]},
893
+
894
+ # ---- LEGO BOOST extension hats ----
895
+ "boost_color": {"opcode": "boost_whenColor",
896
+ "fields": [("COLOR", 0)]},
897
+ "boost_tilted": {"opcode": "boost_whenTilted",
898
+ "fields": [("TILT_DIRECTION_ANY", 0)]},
899
+
900
+ # ---- LEGO EV3 extension hats ----
901
+ "ev3_button": {"opcode": "ev3_whenButtonPressed",
902
+ "fields": [("PORT", 0)]},
903
+ "ev3_distance": {"opcode": "ev3_whenDistanceLessThan",
904
+ "args": [("DISTANCE", "number", "args")]},
905
+ "ev3_brightness": {"opcode": "ev3_whenBrightnessLessThan",
906
+ "args": [("DISTANCE", "number", "args")]},
907
+
908
+ # ---- LEGO WeDo 2.0 extension hats ----
909
+ "wedo_distance": {"opcode": "wedo2_whenDistance",
910
+ "fields": [("OP", 0)],
911
+ "args": [("REFERENCE", "number", "args")]},
912
+ "wedo_tilted": {"opcode": "wedo2_whenTilted",
913
+ "fields": [("TILT_DIRECTION_ANY", 0)]},
914
+
915
+ # ---- Go Direct Force & Acceleration (gdxfor) hats ----
916
+ "gdx_gesture": {"opcode": "gdxfor_whenGesture",
917
+ "fields": [("GESTURE", 0)]},
918
+ "gdx_force": {"opcode": "gdxfor_whenForcePushedOrPulled",
919
+ "fields": [("PUSH_PULL", 0)]},
920
+ "gdx_tilted": {"opcode": "gdxfor_whenTilted",
921
+ "fields": [("TILT", 0)]},
922
+ }
923
+
924
+ # ---------------------------------------------------------------------------
925
+ # Stop options
926
+ # ---------------------------------------------------------------------------
927
+ STOP_OPTIONS = {
928
+ "all": "all",
929
+ "this script": "this script",
930
+ "thisscript": "this script",
931
+ "other scripts in sprite": "other scripts in sprite",
932
+ "other scripts in stage": "other scripts in stage",
933
+ }
934
+
935
+ # ---------------------------------------------------------------------------
936
+ # Effect names
937
+ # ---------------------------------------------------------------------------
938
+ EFFECT_NAMES = {"color", "fisheye", "whirl", "pixelate", "mosaic", "brightness", "ghost"}
939
+
940
+ # ---------------------------------------------------------------------------
941
+ # Rotation styles
942
+ # ---------------------------------------------------------------------------
943
+ ROTATION_STYLES = {
944
+ "all around": "all around",
945
+ "all-around": "all around",
946
+ "left-right": "left-right",
947
+ "left right": "left-right",
948
+ "don't rotate": "don't rotate",
949
+ "dont rotate": "don't rotate",
950
+ "don't-rotate": "don't rotate",
951
+ }
952
+
953
+ # ---------------------------------------------------------------------------
954
+ # Sprite menu targets (for pointTowards, goTo, distanceTo, etc.)
955
+ # ---------------------------------------------------------------------------
956
+ SPRITE_MENUS = {
957
+ "mouse": "_mouse_",
958
+ "random": "_random_",
959
+ "_mouse_": "_mouse_",
960
+ "_random_": "_random_",
961
+ }