ScratchAnalyzer 0.1.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.
- ScratchAnalyzer/Cast.py +12 -0
- ScratchAnalyzer/Project.py +277 -0
- ScratchAnalyzer/Project.pyi +235 -0
- ScratchAnalyzer/Scratch.py +416 -0
- ScratchAnalyzer/Scratch.pyi +95 -0
- ScratchAnalyzer/__init__.py +6 -0
- ScratchAnalyzer/__main__.py +5 -0
- ScratchAnalyzer/assets/codeMain.python.tpl +8 -0
- ScratchAnalyzer/assets/progMain.python.tpl +29 -0
- ScratchAnalyzer/assets/translator.python.json +126 -0
- ScratchAnalyzer/errors.py +2 -0
- ScratchAnalyzer/iostream.py +103 -0
- ScratchAnalyzer/iostream.pyi +116 -0
- ScratchAnalyzer/main.py +78 -0
- ScratchAnalyzer/public.py +41 -0
- ScratchAnalyzer/translator.py +20 -0
- scratchanalyzer-0.1.0.dist-info/METADATA +90 -0
- scratchanalyzer-0.1.0.dist-info/RECORD +22 -0
- scratchanalyzer-0.1.0.dist-info/WHEEL +5 -0
- scratchanalyzer-0.1.0.dist-info/entry_points.txt +2 -0
- scratchanalyzer-0.1.0.dist-info/licenses/LICENSE +21 -0
- scratchanalyzer-0.1.0.dist-info/top_level.txt +1 -0
ScratchAnalyzer/Cast.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
def toCode(value):
|
|
2
|
+
if isinstance(value, int) or isinstance(value, float):
|
|
3
|
+
code = str(value)
|
|
4
|
+
else:
|
|
5
|
+
try:
|
|
6
|
+
value = float(value)
|
|
7
|
+
if int(value) == value:
|
|
8
|
+
value = int(value)
|
|
9
|
+
code = str(value) # 判断是否是合法的数字字符串
|
|
10
|
+
except ValueError:
|
|
11
|
+
code = f'"{value}"'
|
|
12
|
+
return code
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from .errors import UnsupportedError
|
|
4
|
+
from .iostream import ColoredTqdm
|
|
5
|
+
from .Cast import toCode
|
|
6
|
+
from .public import substack_opcodes, substack_opcodes_need_flush
|
|
7
|
+
import json
|
|
8
|
+
import warnings
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Input(object):
|
|
12
|
+
def __init__(self, _input, target, name):
|
|
13
|
+
self.data = _input
|
|
14
|
+
self.target = target
|
|
15
|
+
self.name = name
|
|
16
|
+
|
|
17
|
+
def toCode(self, translator, func_name, procedures_prototypes):
|
|
18
|
+
if isinstance(self.data[1], str):
|
|
19
|
+
try:
|
|
20
|
+
fieldBlock = self.target.blocks[self.data[1]]
|
|
21
|
+
field = fieldBlock.fields[self.name]
|
|
22
|
+
code = field.toCode(translator)
|
|
23
|
+
except KeyError:
|
|
24
|
+
try:
|
|
25
|
+
blockId = self.data[1]
|
|
26
|
+
code, _ = self.target.blocks[blockId].toCode(translator, 1, func_name, procedures_prototypes)
|
|
27
|
+
except KeyError:
|
|
28
|
+
code = f'Scratch.getVariable(instance, "{self.data[1]}")'
|
|
29
|
+
elif self.data[1]:
|
|
30
|
+
value = self.data[1][1]
|
|
31
|
+
code = f"!!![SPECIAL_CODE_TO_GLOBAL][{value}]!!!"
|
|
32
|
+
else:
|
|
33
|
+
code = '""'
|
|
34
|
+
return code
|
|
35
|
+
|
|
36
|
+
class Field(object):
|
|
37
|
+
def __init__(self, field, target):
|
|
38
|
+
self.data = field
|
|
39
|
+
self.target = target
|
|
40
|
+
|
|
41
|
+
def toCode(self, translator):
|
|
42
|
+
return toCode(self.data[0])
|
|
43
|
+
|
|
44
|
+
class Block(object):
|
|
45
|
+
def __init__(self, block, target):
|
|
46
|
+
# 获取数据
|
|
47
|
+
try:
|
|
48
|
+
self.opcode = block["opcode"]
|
|
49
|
+
except TypeError:
|
|
50
|
+
raise TypeError(f"非法block,没有opcode!: {block}\n\n{target._blocks}")
|
|
51
|
+
self._next = block["next"]
|
|
52
|
+
self.next = None
|
|
53
|
+
self._parent = block.get("parent")
|
|
54
|
+
self.parent = None
|
|
55
|
+
self._inputs = block["inputs"]
|
|
56
|
+
self.inputs = {}
|
|
57
|
+
self._fields = block["fields"]
|
|
58
|
+
self.fields = {}
|
|
59
|
+
self.shadow = block["shadow"]
|
|
60
|
+
self.topLevel = block["topLevel"]
|
|
61
|
+
self.target = target
|
|
62
|
+
self.computed = False
|
|
63
|
+
self.comment = block.get("comment")
|
|
64
|
+
self.data = block
|
|
65
|
+
|
|
66
|
+
def getComment(self, indent, uniqueEnv=False):
|
|
67
|
+
if self.comment and (self.opcode not in substack_opcodes if not uniqueEnv else True):
|
|
68
|
+
text = self.target.comments[self.comment]["text"]
|
|
69
|
+
return f" # {text}".replace("\n", " " * indent + "# ") # 保证多行注释正常
|
|
70
|
+
return ""
|
|
71
|
+
|
|
72
|
+
def compute_relation(self):
|
|
73
|
+
# 计算关联
|
|
74
|
+
self.target = self.target
|
|
75
|
+
self.next = self.target.blocks[self._next] if self._next else None
|
|
76
|
+
self.parent = self.target.blocks[self._parent] if self._parent else None
|
|
77
|
+
self.inputs = {k: Input(v, self.target, k) for k, v in self._inputs.items()}
|
|
78
|
+
self.fields = {k: Field(v, self.target) for k, v in self._fields.items()}
|
|
79
|
+
self.computed = True
|
|
80
|
+
|
|
81
|
+
def generateArgs(self, arg_ids, args, translator, func_name, procedures_prototypes):
|
|
82
|
+
result = {}
|
|
83
|
+
for arg_id in arg_ids:
|
|
84
|
+
if arg_id not in args: # 没有传入参数则跳过,内部会使用默认值
|
|
85
|
+
continue
|
|
86
|
+
value = args[arg_id].toCode(translator, func_name, procedures_prototypes)
|
|
87
|
+
result[arg_id] = value
|
|
88
|
+
return json.dumps(result, ensure_ascii=False)
|
|
89
|
+
|
|
90
|
+
def toCode(self, translator, indent, func_name, procedures_prototypes):
|
|
91
|
+
if self.opcode not in substack_opcodes: # shadow指的是是否有SUBSTACK(子积木,就比如“如果”里包着的积木)
|
|
92
|
+
try:
|
|
93
|
+
code = getattr(translator, self.opcode)
|
|
94
|
+
except AttributeError:
|
|
95
|
+
warnings.warn("不支持的积木操作代码: %s,若警告不会停止则默认继续转换(无法翻译的代码将以注释替代!)" % self.opcode)
|
|
96
|
+
code = f"raise RuntimeError('未成功翻译的代码,操作代码:{self.opcode},请手动翻译!') # !!!不支持的积木操作代码: {self.opcode},请手动翻译!!!"
|
|
97
|
+
# 自定义函数执行的特殊处理
|
|
98
|
+
if self.opcode == "procedures_call":
|
|
99
|
+
code = (code.replace("%[FUNC_NAME]%", "!!![FUNC_NAME_TO_GLOBAL][{proccode}]!!!".format(proccode=self.data["mutation"]["proccode"]))
|
|
100
|
+
.replace("%[ARGS]%", "!!![ARGS_TO_GLOBAL][{args}]!!!").format(args=self.generateArgs(
|
|
101
|
+
json.loads(self.data["mutation"]["argumentids"]),
|
|
102
|
+
self.inputs,
|
|
103
|
+
translator, func_name, procedures_prototypes
|
|
104
|
+
)))
|
|
105
|
+
for name, inp in self.inputs.items():
|
|
106
|
+
code = code.replace(f'%[{name}]%', inp.toCode(translator, func_name, procedures_prototypes))
|
|
107
|
+
for name, field in self.fields.items():
|
|
108
|
+
code = code.replace(f'%[{name}]%', field.toCode(translator))
|
|
109
|
+
pattern = r'%\[.*?\]%' # 非贪婪匹配
|
|
110
|
+
code = re.sub(pattern, 'None', code)
|
|
111
|
+
if self.opcode == "control_stop" and self.fields["STOP_OPTION"].data[0] != "other scripts in sprite":
|
|
112
|
+
code += "\n" + " " * indent + "return"
|
|
113
|
+
if self.opcode == "control_delete_this_clone":
|
|
114
|
+
code += "\n" + " " * indent + "if instance.isClone:"
|
|
115
|
+
code += "\n" + " " * (indent+1) + "return"
|
|
116
|
+
else:
|
|
117
|
+
try:
|
|
118
|
+
code = getattr(translator, self.opcode) # 获取主体代码
|
|
119
|
+
except AttributeError:
|
|
120
|
+
warnings.warn("不支持的积木操作代码: %s,若警告不会停止则默认继续转换(无法翻译的代码将以注释替代!)" % self.opcode)
|
|
121
|
+
code = f"raise RuntimeError('未成功翻译的代码,操作代码:{self.opcode},请手动翻译!') # !!!不支持的积木操作代码: {self.opcode},请手动翻译!!!"
|
|
122
|
+
# 将参数格式化进去
|
|
123
|
+
for name, inp in self.inputs.items():
|
|
124
|
+
if name in ("SUBSTACK", "SUBSTACK2"):
|
|
125
|
+
continue
|
|
126
|
+
code = code.replace(f'%[{name}]%', inp.toCode(translator, func_name, procedures_prototypes)) + self.getComment(indent + 1, uniqueEnv=True)
|
|
127
|
+
for name, field in self.fields.items():
|
|
128
|
+
code = code.replace(f'%[{name}]%', field.toCode(translator))
|
|
129
|
+
pattern = r'%\[.*?\]%' # 非贪婪匹配
|
|
130
|
+
code = re.sub(pattern, 'None', code)
|
|
131
|
+
indent += 1
|
|
132
|
+
code += "\n"
|
|
133
|
+
if self.inputs["SUBSTACK"].data[1]:
|
|
134
|
+
head = self.target.blocks[self.inputs["SUBSTACK"].data[1]]
|
|
135
|
+
block = head
|
|
136
|
+
while True:
|
|
137
|
+
cd, indent = block.toCode(translator, indent, func_name, procedures_prototypes)
|
|
138
|
+
code += (" " * indent) + cd + block.getComment(indent) + "\n"
|
|
139
|
+
block = block.next
|
|
140
|
+
if not block:
|
|
141
|
+
break
|
|
142
|
+
if substack_opcodes_need_flush[self.opcode]:
|
|
143
|
+
if func_name in procedures_prototypes and procedures_prototypes[func_name]["warp"]:
|
|
144
|
+
suffix = ""
|
|
145
|
+
else:
|
|
146
|
+
suffix = "await instance.wait_next_frame() # 普通情况:每次循环末尾都等待刷新"
|
|
147
|
+
else:
|
|
148
|
+
suffix = ""
|
|
149
|
+
code += (" " * indent) + suffix + "\n"
|
|
150
|
+
else:
|
|
151
|
+
code += (" " * indent) + "...\n"
|
|
152
|
+
if "SUBSTACK2" in self.inputs:
|
|
153
|
+
code += "{indent}{before}\n".format(indent=" " * (indent-1),before=getattr(translator, self.opcode+"_before_2"))
|
|
154
|
+
if self.inputs["SUBSTACK2"].data[1]:
|
|
155
|
+
head = self.target.blocks[self.inputs["SUBSTACK2"].data[1]]
|
|
156
|
+
block = head
|
|
157
|
+
while True:
|
|
158
|
+
cd, indent = block.toCode(translator, indent, func_name, procedures_prototypes)
|
|
159
|
+
code += (" " * indent) + cd + block.getComment(indent) + "\n"
|
|
160
|
+
block = block.next
|
|
161
|
+
if not block:
|
|
162
|
+
break
|
|
163
|
+
if substack_opcodes_need_flush[self.opcode]:
|
|
164
|
+
suffix = "await instance.wait_next_frame() # 普通情况:每次循环末尾都等待刷新"
|
|
165
|
+
else:
|
|
166
|
+
suffix = ""
|
|
167
|
+
code += (" " * indent) + suffix + "\n"
|
|
168
|
+
else:
|
|
169
|
+
code += (" " * indent) + "...\n"
|
|
170
|
+
indent -= 1
|
|
171
|
+
return code, indent
|
|
172
|
+
|
|
173
|
+
class Target(object):
|
|
174
|
+
def __init__(self, target):
|
|
175
|
+
# 获取数据
|
|
176
|
+
self.isStage = target["isStage"]
|
|
177
|
+
self.name = target["name"]
|
|
178
|
+
self.variables = target["variables"]
|
|
179
|
+
self.lists = target["lists"]
|
|
180
|
+
self.broadcasts = target["broadcasts"]
|
|
181
|
+
self._blocks = target["blocks"]
|
|
182
|
+
self.comments = target["comments"]
|
|
183
|
+
self.currentCostume = target["currentCostume"]
|
|
184
|
+
self.costumes = target["costumes"]
|
|
185
|
+
self.sounds = target["sounds"]
|
|
186
|
+
self.volume = target["volume"]
|
|
187
|
+
self.layerOrder = target["layerOrder"]
|
|
188
|
+
self.visible = target.get("visible", True)
|
|
189
|
+
self.x = target.get("x", 0)
|
|
190
|
+
self.y = target.get("y", 0)
|
|
191
|
+
self.size = target.get("size", 100)
|
|
192
|
+
self.direction = target.get("direction", 90)
|
|
193
|
+
self.draggable = target.get("draggable", False)
|
|
194
|
+
self.rotationStyle = target.get("rotationStyle", "all around")
|
|
195
|
+
self.tempo = target.get("tempo")
|
|
196
|
+
# 解析剩余参数
|
|
197
|
+
self.args = {k: v for k, v in target.items() if k not in {
|
|
198
|
+
'isStage',
|
|
199
|
+
'name',
|
|
200
|
+
'variables',
|
|
201
|
+
'lists',
|
|
202
|
+
'broadcasts',
|
|
203
|
+
'blocks',
|
|
204
|
+
'comments',
|
|
205
|
+
'currentCostume',
|
|
206
|
+
'costumes',
|
|
207
|
+
'sounds',
|
|
208
|
+
'volume',
|
|
209
|
+
'layerOrder',
|
|
210
|
+
'visible',
|
|
211
|
+
'x',
|
|
212
|
+
'y',
|
|
213
|
+
'size',
|
|
214
|
+
'direction',
|
|
215
|
+
'draggable',
|
|
216
|
+
'rotationStyle',
|
|
217
|
+
'tempo'
|
|
218
|
+
}}
|
|
219
|
+
if self._blocks:
|
|
220
|
+
# 计算blocks
|
|
221
|
+
self.blocks = {k: Block(v, self) for k, v in ColoredTqdm(self._blocks.items(), desc="创建积木块中", unit="积木块") if isinstance(v, dict)}
|
|
222
|
+
# 计算关联
|
|
223
|
+
for block in ColoredTqdm(self.blocks.values(), desc="计算块关联中", unit="积木块"):
|
|
224
|
+
block.compute_relation()
|
|
225
|
+
else:
|
|
226
|
+
self.blocks = {}
|
|
227
|
+
|
|
228
|
+
class Monitor(object):
|
|
229
|
+
def __init__(self, monitor):
|
|
230
|
+
self.id = monitor["id"]
|
|
231
|
+
self.mode = monitor["mode"]
|
|
232
|
+
self.opcode = monitor["opcode"]
|
|
233
|
+
self.params = monitor["params"]
|
|
234
|
+
self.spriteName = monitor["spriteName"]
|
|
235
|
+
self.value = monitor["value"]
|
|
236
|
+
self.width = monitor["width"]
|
|
237
|
+
self.height = monitor["height"]
|
|
238
|
+
self.x = monitor["x"]
|
|
239
|
+
self.y = monitor["y"]
|
|
240
|
+
self.visible = monitor["visible"]
|
|
241
|
+
self.sliderMin = monitor.get("sliderMin")
|
|
242
|
+
self.sliderMax = monitor.get("sliderMax")
|
|
243
|
+
self.isDiscrete = monitor.get("isDiscrete")
|
|
244
|
+
|
|
245
|
+
class Extension(object):
|
|
246
|
+
def __init__(self, extension):
|
|
247
|
+
if extension not in ("pen", ):
|
|
248
|
+
warnings.warn("暂不支持扩展:%s,若警告不会停止则默认继续转换" % extension)
|
|
249
|
+
|
|
250
|
+
class Meta(object):
|
|
251
|
+
def __init__(self, meta):
|
|
252
|
+
self.semver = meta["semver"]
|
|
253
|
+
self.agent = meta["agent"]
|
|
254
|
+
self.vm = meta["vm"]
|
|
255
|
+
|
|
256
|
+
class Project(object):
|
|
257
|
+
def __init__(self, project):
|
|
258
|
+
self.project = project
|
|
259
|
+
self._parse()
|
|
260
|
+
|
|
261
|
+
def _parse(self):
|
|
262
|
+
if self.project.get("extensionURLs"):
|
|
263
|
+
warnings.warn("项目中包含自定义URL扩展,可能来自TurboWarp,当前版本不支持解析这些扩展,相关积木将无法转换!")
|
|
264
|
+
self.meta = Meta(self.project["meta"])
|
|
265
|
+
self.extensions = {}
|
|
266
|
+
if self.project["extensions"]:
|
|
267
|
+
for name in ColoredTqdm(self.project["extensions"], desc="处理扩展中", unit="个"):
|
|
268
|
+
self.extensions[name] = Extension(name)
|
|
269
|
+
self.monitors = {}
|
|
270
|
+
if self.project["monitors"]:
|
|
271
|
+
for monitor in ColoredTqdm(self.project["monitors"], desc="处理变量监视器中", unit="个"):
|
|
272
|
+
self.monitors[monitor["id"]] = Monitor(monitor)
|
|
273
|
+
self.targets = {}
|
|
274
|
+
if self.project["targets"]:
|
|
275
|
+
for target in ColoredTqdm(self.project["targets"], desc="处理角色中", unit="个"):
|
|
276
|
+
self.targets[target["name"]] = Target(target)
|
|
277
|
+
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
from typing import TypedDict, List, Optional, Dict, Any, Union
|
|
2
|
+
|
|
3
|
+
from .translator import WrappedTranslator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MetaDict(TypedDict):
|
|
7
|
+
semver: str
|
|
8
|
+
vm: str
|
|
9
|
+
agent: str
|
|
10
|
+
|
|
11
|
+
class MonitorParamDict(TypedDict):
|
|
12
|
+
VARIABLE: str
|
|
13
|
+
LIST: str
|
|
14
|
+
|
|
15
|
+
class MonitorDict(TypedDict):
|
|
16
|
+
id: str
|
|
17
|
+
mode: str
|
|
18
|
+
opcode: str
|
|
19
|
+
params: MonitorParamDict
|
|
20
|
+
spriteName: Optional[str]
|
|
21
|
+
value: Any
|
|
22
|
+
width: int
|
|
23
|
+
height: int
|
|
24
|
+
x: float
|
|
25
|
+
y: float
|
|
26
|
+
visible: bool
|
|
27
|
+
sliderMin: Optional[float]
|
|
28
|
+
sliderMax: Optional[float]
|
|
29
|
+
isDiscrete: Optional[bool]
|
|
30
|
+
|
|
31
|
+
ValueInput = List[int, List[int , Any]] # type: ignore
|
|
32
|
+
CodeInput = List[int, str, List[int , Any]] # type: ignore
|
|
33
|
+
FieldInput = List[int, str, ...] # type: ignore
|
|
34
|
+
InputsDict = Dict[str, Union[ValueInput, CodeInput, FieldInput]]
|
|
35
|
+
FieldsDict = Dict[str, List[str, Optional[str]]] # type: ignore
|
|
36
|
+
|
|
37
|
+
class BlockDict(TypedDict):
|
|
38
|
+
opcode: str
|
|
39
|
+
next: Optional[str]
|
|
40
|
+
parent: Optional[str]
|
|
41
|
+
inputs: InputsDict
|
|
42
|
+
fields: FieldsDict
|
|
43
|
+
shadow: bool
|
|
44
|
+
topLevel: bool
|
|
45
|
+
comment: Optional[str]
|
|
46
|
+
mutation: Optional[dict]
|
|
47
|
+
|
|
48
|
+
VariablesDict = Dict[str, List[str, Any]] # type: ignore
|
|
49
|
+
ListsDict = Dict[str, List[str, Any]] # type: ignore
|
|
50
|
+
BroadcastsDict = Dict[str, str]
|
|
51
|
+
BlocksDict = Dict[str, BlockDict]
|
|
52
|
+
|
|
53
|
+
class Comment(TypedDict):
|
|
54
|
+
blockId: Optional[str]
|
|
55
|
+
x: float
|
|
56
|
+
y: float
|
|
57
|
+
width: float
|
|
58
|
+
height: float
|
|
59
|
+
minimized: bool
|
|
60
|
+
text: str
|
|
61
|
+
|
|
62
|
+
CommentsDict = Dict[str, Comment]
|
|
63
|
+
|
|
64
|
+
class CostumeDict(TypedDict):
|
|
65
|
+
name: str
|
|
66
|
+
bitmapResolution: int
|
|
67
|
+
dataFormat: str
|
|
68
|
+
assetId: str
|
|
69
|
+
md5ext: str
|
|
70
|
+
rotationCenterX: float
|
|
71
|
+
rotationCenterY: float
|
|
72
|
+
|
|
73
|
+
class Sound(TypedDict):
|
|
74
|
+
name: str
|
|
75
|
+
assetId: str
|
|
76
|
+
dataFormat: str
|
|
77
|
+
rate: int
|
|
78
|
+
sampleCount: int
|
|
79
|
+
md5ext: str
|
|
80
|
+
|
|
81
|
+
class TargetDict(TypedDict):
|
|
82
|
+
isStage: bool
|
|
83
|
+
name: str
|
|
84
|
+
variables: VariablesDict
|
|
85
|
+
lists: ListsDict
|
|
86
|
+
broadcasts: BroadcastsDict
|
|
87
|
+
blocks: BlocksDict
|
|
88
|
+
comments: CommentsDict
|
|
89
|
+
currentCostume: int
|
|
90
|
+
costumes: List[CostumeDict]
|
|
91
|
+
sounds: List[Sound]
|
|
92
|
+
volume: int
|
|
93
|
+
layerOrder: int
|
|
94
|
+
visible: Optional[bool]
|
|
95
|
+
x: Optional[float]
|
|
96
|
+
y: Optional[float]
|
|
97
|
+
size: Optional[float]
|
|
98
|
+
direction: Optional[float]
|
|
99
|
+
draggable: Optional[bool]
|
|
100
|
+
rotationStyle: Optional[Any]
|
|
101
|
+
tempo: Optional[int]
|
|
102
|
+
...
|
|
103
|
+
|
|
104
|
+
class ProjectDict(TypedDict):
|
|
105
|
+
targets: List[TargetDict]
|
|
106
|
+
monitors: List[MonitorDict]
|
|
107
|
+
extensions: List[str]
|
|
108
|
+
extensionURLs: Optional[Dict[str, str]]
|
|
109
|
+
meta: MetaDict
|
|
110
|
+
|
|
111
|
+
# =========================
|
|
112
|
+
|
|
113
|
+
class Input(object):
|
|
114
|
+
data: list
|
|
115
|
+
target: Target
|
|
116
|
+
name: str
|
|
117
|
+
|
|
118
|
+
def __init__(self, _input: list, target: Target, name: str):
|
|
119
|
+
...
|
|
120
|
+
|
|
121
|
+
def toCode(self, translator: WrappedTranslator, func_name: str, procedures_prototypes: dict[str, dict]) -> str:
|
|
122
|
+
...
|
|
123
|
+
|
|
124
|
+
class Field(object):
|
|
125
|
+
data: list
|
|
126
|
+
target: Target
|
|
127
|
+
|
|
128
|
+
def __init__(self, field: list, target: Target):
|
|
129
|
+
...
|
|
130
|
+
|
|
131
|
+
def toCode(self, translator: WrappedTranslator) -> str:
|
|
132
|
+
...
|
|
133
|
+
|
|
134
|
+
class Block(object):
|
|
135
|
+
opcode: str
|
|
136
|
+
_next: Optional[str]
|
|
137
|
+
next: Optional[Block]
|
|
138
|
+
_parent: Optional[str]
|
|
139
|
+
parent: Optional[Block]
|
|
140
|
+
_inputs: InputsDict
|
|
141
|
+
inputs: Dict[str, Input]
|
|
142
|
+
_fields: FieldsDict
|
|
143
|
+
fields: Dict[str, Field]
|
|
144
|
+
shadow: bool
|
|
145
|
+
topLevel: bool
|
|
146
|
+
target: Target
|
|
147
|
+
computed: bool
|
|
148
|
+
comment: Optional[str]
|
|
149
|
+
data: BlockDict
|
|
150
|
+
|
|
151
|
+
def __init__(self, block: BlockDict, target: Target):
|
|
152
|
+
...
|
|
153
|
+
|
|
154
|
+
def getComment(self, indent: int, uniqueEnv: bool=False) -> str:
|
|
155
|
+
...
|
|
156
|
+
|
|
157
|
+
def compute_relation(self):
|
|
158
|
+
...
|
|
159
|
+
|
|
160
|
+
def generateArgs(self, arg_ids: list[str], args: dict[str, Input], translator: WrappedTranslator, func_name: str, procedures_prototypes: dict[str, dict]) -> str:
|
|
161
|
+
...
|
|
162
|
+
|
|
163
|
+
def toCode(self, translator: WrappedTranslator, indent: int, func_name: str, procedures_prototypes: dict[str, dict]) -> tuple[str, int]:
|
|
164
|
+
...
|
|
165
|
+
|
|
166
|
+
class Target(object):
|
|
167
|
+
isStage: bool
|
|
168
|
+
name: str
|
|
169
|
+
variables: VariablesDict
|
|
170
|
+
lists: ListsDict
|
|
171
|
+
broadcasts: BroadcastsDict
|
|
172
|
+
_blocks: BlocksDict
|
|
173
|
+
blocks: Dict[str, Block]
|
|
174
|
+
comments: CommentsDict
|
|
175
|
+
currentCostume: int
|
|
176
|
+
costumes: List[CostumeDict]
|
|
177
|
+
sounds: List[Sound]
|
|
178
|
+
volume: int
|
|
179
|
+
layerOrder: int
|
|
180
|
+
visible: Optional[bool]
|
|
181
|
+
x: Optional[float]
|
|
182
|
+
y: Optional[float]
|
|
183
|
+
size: Optional[float]
|
|
184
|
+
direction: Optional[float]
|
|
185
|
+
draggable: Optional[bool]
|
|
186
|
+
rotationStyle: Optional[Any]
|
|
187
|
+
tempo: Optional[int]
|
|
188
|
+
args: Dict[str, Any]
|
|
189
|
+
|
|
190
|
+
def __init__(self, target: TargetDict):
|
|
191
|
+
...
|
|
192
|
+
|
|
193
|
+
class Monitor(object):
|
|
194
|
+
id: str
|
|
195
|
+
mode: str
|
|
196
|
+
opcode: str
|
|
197
|
+
params: MonitorParamDict
|
|
198
|
+
spriteName: Optional[str]
|
|
199
|
+
value: Any
|
|
200
|
+
width: int
|
|
201
|
+
height: int
|
|
202
|
+
x: float
|
|
203
|
+
y: float
|
|
204
|
+
visible: bool
|
|
205
|
+
sliderMin: Optional[float]
|
|
206
|
+
sliderMax: Optional[float]
|
|
207
|
+
isDiscrete: Optional[bool]
|
|
208
|
+
|
|
209
|
+
def __init__(self, monitor: MonitorDict):
|
|
210
|
+
...
|
|
211
|
+
|
|
212
|
+
class Extension(object):
|
|
213
|
+
def __init__(self, extension: str):
|
|
214
|
+
...
|
|
215
|
+
|
|
216
|
+
class Meta(object):
|
|
217
|
+
semver: str
|
|
218
|
+
vm: str
|
|
219
|
+
agent: str
|
|
220
|
+
|
|
221
|
+
def __init__(self, meta: MetaDict):
|
|
222
|
+
...
|
|
223
|
+
|
|
224
|
+
class Project(object):
|
|
225
|
+
project: ProjectDict
|
|
226
|
+
targets: Dict[str, Target]
|
|
227
|
+
monitors: Dict[str, Monitor]
|
|
228
|
+
extensions: Dict[str, Extension]
|
|
229
|
+
meta: Meta
|
|
230
|
+
|
|
231
|
+
def __init__(self, project: ProjectDict):
|
|
232
|
+
...
|
|
233
|
+
|
|
234
|
+
def _parse(self) -> None:
|
|
235
|
+
...
|