pyscreeps-arena 0.3.6__py3-none-any.whl → 0.5.7.1__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.
- pyscreeps_arena/__init__.py +59 -2
- pyscreeps_arena/compiler.py +568 -60
- pyscreeps_arena/core/config.py +1 -1
- pyscreeps_arena/core/const.py +6 -5
- pyscreeps_arena/localization.py +10 -0
- pyscreeps_arena/project.7z +0 -0
- pyscreeps_arena/ui/P2PY.py +108 -0
- pyscreeps_arena/ui/__init__.py +12 -0
- pyscreeps_arena/ui/creeplogic_edit.py +14 -0
- pyscreeps_arena/ui/map_render.py +705 -0
- pyscreeps_arena/ui/mapviewer.py +14 -0
- pyscreeps_arena/ui/project_ui.py +215 -0
- pyscreeps_arena/ui/qcreeplogic/__init__.py +3 -0
- pyscreeps_arena/ui/qcreeplogic/model.py +72 -0
- pyscreeps_arena/ui/qcreeplogic/qcreeplogic.py +770 -0
- pyscreeps_arena/ui/qmapv/__init__.py +3 -0
- pyscreeps_arena/ui/qmapv/qcinfo.py +567 -0
- pyscreeps_arena/ui/qmapv/qco.py +441 -0
- pyscreeps_arena/ui/qmapv/qmapv.py +728 -0
- pyscreeps_arena/ui/qmapv/test_array_drag.py +191 -0
- pyscreeps_arena/ui/qmapv/test_drag.py +107 -0
- pyscreeps_arena/ui/qmapv/test_qcinfo.py +169 -0
- pyscreeps_arena/ui/qmapv/test_qco_drag.py +7 -0
- pyscreeps_arena/ui/qmapv/test_qmapv.py +224 -0
- pyscreeps_arena/ui/qmapv/test_simple_array.py +303 -0
- pyscreeps_arena/ui/qrecipe/__init__.py +1 -0
- pyscreeps_arena/ui/qrecipe/model.py +434 -0
- pyscreeps_arena/ui/qrecipe/qrecipe.py +914 -0
- pyscreeps_arena/ui/rs_icon.py +43 -0
- {pyscreeps_arena-0.3.6.dist-info → pyscreeps_arena-0.5.7.1.dist-info}/METADATA +15 -3
- pyscreeps_arena-0.5.7.1.dist-info/RECORD +40 -0
- {pyscreeps_arena-0.3.6.dist-info → pyscreeps_arena-0.5.7.1.dist-info}/WHEEL +1 -1
- pyscreeps_arena-0.5.7.1.dist-info/entry_points.txt +4 -0
- pyscreeps_arena-0.3.6.dist-info/RECORD +0 -17
- pyscreeps_arena-0.3.6.dist-info/entry_points.txt +0 -2
- {pyscreeps_arena-0.3.6.dist-info → pyscreeps_arena-0.5.7.1.dist-info}/top_level.txt +0 -0
pyscreeps_arena/compiler.py
CHANGED
|
@@ -9,6 +9,7 @@ import chardet
|
|
|
9
9
|
import subprocess
|
|
10
10
|
import pyperclip
|
|
11
11
|
from colorama import Fore
|
|
12
|
+
from typing import List, Optional, Tuple, Union
|
|
12
13
|
|
|
13
14
|
WAIT = Fore.YELLOW + ">>>" + Fore.RESET
|
|
14
15
|
GREEN = Fore.GREEN + "{}" + Fore.RESET
|
|
@@ -16,6 +17,27 @@ python_version_info = sys.version_info
|
|
|
16
17
|
python_version_info = f"{python_version_info.major}.{python_version_info.minor}.{python_version_info.micro}"
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
def replace_src_prefix(file_list):
|
|
21
|
+
"""
|
|
22
|
+
将列表中以'./src.'开头的字符串替换为'./'
|
|
23
|
+
|
|
24
|
+
参数:
|
|
25
|
+
file_list: 字符串列表
|
|
26
|
+
|
|
27
|
+
返回:
|
|
28
|
+
替换后的新列表
|
|
29
|
+
"""
|
|
30
|
+
_ = []
|
|
31
|
+
|
|
32
|
+
for item in file_list:
|
|
33
|
+
if isinstance(item, str) and item.startswith('./src.'):
|
|
34
|
+
_new = item.replace('./src.', './', 1)
|
|
35
|
+
if _new in file_list:
|
|
36
|
+
continue
|
|
37
|
+
_.append(item)
|
|
38
|
+
|
|
39
|
+
return _
|
|
40
|
+
|
|
19
41
|
# def InsertPragmaBefore(content:str) -> str:
|
|
20
42
|
# """
|
|
21
43
|
# 在content的开头插入__pragma__('noalias', 'undefined')等内容 |
|
|
@@ -43,7 +65,7 @@ class Compiler_Const:
|
|
|
43
65
|
|
|
44
66
|
TOTAL_INSERT_AT_HEAD = """
|
|
45
67
|
import { createConstructionSite, findClosestByPath, findClosestByRange, findInRange, findPath, getCpuTime, getDirection, getHeapStatistics, getObjectById, getObjects, getObjectsByPrototype, getRange, getTerrainAt, getTicks,} from 'game/utils';
|
|
46
|
-
import { ConstructionSite, Creep, GameObject, OwnedStructure, Resource, Source, Structure, StructureContainer, StructureExtension, StructureRampart, StructureRoad, StructureSpawn, StructureWall, StructureTower} from 'game/prototypes';
|
|
68
|
+
import { ConstructionSite as GameConstructionSite, Creep as GameCreep, GameObject as GameObjectProto, OwnedStructure, Resource as GameResource, Source as GameSource, Structure as GameStructure, StructureContainer as GameStructureContainer, StructureExtension as GameStructureExtension, StructureRampart as GameStructureRampart, StructureRoad as GameStructureRoad, StructureSpawn as GameStructureSpawn, StructureWall as GameStructureWall, StructureTower as GameStructureTower, Flag as GameFlag} from 'game/prototypes';
|
|
47
69
|
import { ATTACK, ATTACK_POWER, BODYPART_COST, BODYPART_HITS, BOTTOM, BOTTOM_LEFT, BOTTOM_RIGHT, BUILD_POWER, CARRY, CARRY_CAPACITY, CONSTRUCTION_COST, CONSTRUCTION_COST_ROAD_SWAMP_RATIO, CONSTRUCTION_COST_ROAD_WALL_RATIO, CONTAINER_CAPACITY, CONTAINER_HITS, CREEP_SPAWN_TIME, DISMANTLE_COST, DISMANTLE_POWER, ERR_BUSY, ERR_FULL, ERR_INVALID_ARGS, ERR_INVALID_TARGET, ERR_NAME_EXISTS, ERR_NOT_ENOUGH_ENERGY, ERR_NOT_ENOUGH_EXTENSIONS, ERR_NOT_ENOUGH_RESOURCES, ERR_NOT_FOUND, ERR_NOT_IN_RANGE, ERR_NOT_OWNER, ERR_NO_BODYPART, ERR_NO_PATH, ERR_TIRED, EXTENSION_ENERGY_CAPACITY, EXTENSION_HITS, HARVEST_POWER, HEAL, HEAL_POWER, LEFT, MAX_CONSTRUCTION_SITES, MAX_CREEP_SIZE, MOVE, OBSTACLE_OBJECT_TYPES, OK, RAMPART_HITS, RAMPART_HITS_MAX, RANGED_ATTACK, RANGED_ATTACK_DISTANCE_RATE, RANGED_ATTACK_POWER, RANGED_HEAL_POWER, REPAIR_COST, REPAIR_POWER, RESOURCES_ALL, RESOURCE_DECAY, RESOURCE_ENERGY, RIGHT, ROAD_HITS, ROAD_WEAROUT, SOURCE_ENERGY_REGEN, SPAWN_ENERGY_CAPACITY, SPAWN_HITS, STRUCTURE_PROTOTYPES, TERRAIN_PLAIN, TERRAIN_SWAMP, TERRAIN_WALL, TOP, TOP_LEFT, TOP_RIGHT, TOUGH, TOWER_CAPACITY, TOWER_COOLDOWN, TOWER_ENERGY_COST, TOWER_FALLOFF, TOWER_FALLOFF_RANGE, TOWER_HITS, TOWER_OPTIMAL_RANGE, TOWER_POWER_ATTACK, TOWER_POWER_HEAL, TOWER_POWER_REPAIR, TOWER_RANGE, WALL_HITS, WALL_HITS_MAX, WORK} from 'game/constants';
|
|
48
70
|
|
|
49
71
|
import {arenaInfo} from "game";
|
|
@@ -56,27 +78,40 @@ import {searchPath, CostMatrix} from "game/path-finder"
|
|
|
56
78
|
|
|
57
79
|
TOTAL_APPEND_ATEND = """
|
|
58
80
|
export var sch = Scheduler();
|
|
59
|
-
var monitor = Monitor(
|
|
81
|
+
var monitor = Monitor(1);
|
|
60
82
|
know.now = 0;
|
|
61
83
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
84
|
+
StageMachineLogicMeta.__types__ = []; // 清空js首次构造时引入的数据
|
|
85
|
+
__init_before_k__();
|
|
86
|
+
let knowCost = 0;
|
|
87
|
+
let monitorCost = 0;
|
|
88
|
+
let stepCost = 0;
|
|
89
|
+
let timeLine = 0;
|
|
65
90
|
export var loop = function () {
|
|
66
|
-
|
|
91
|
+
get.handle();
|
|
92
|
+
know.now = get.now;
|
|
93
|
+
timeLine = get.cpu_us();
|
|
67
94
|
know.handle();
|
|
68
|
-
|
|
95
|
+
knowCost = get.cpu_us() - timeLine;
|
|
96
|
+
|
|
97
|
+
timeLine = get.cpu_us();
|
|
98
|
+
monitor.handle();
|
|
99
|
+
monitorCost = get.cpu_us() - timeLine;
|
|
100
|
+
for (const creep of know.creeps){
|
|
101
|
+
creep.handle();
|
|
102
|
+
}
|
|
103
|
+
if (know.now === 1) {
|
|
69
104
|
std.show_welcome();
|
|
70
105
|
init (know);
|
|
106
|
+
|
|
71
107
|
}
|
|
72
|
-
|
|
73
|
-
monitor.handle();
|
|
74
|
-
for (const creep of know._creeps){
|
|
75
|
-
creep.motion.handle();
|
|
76
|
-
}
|
|
77
108
|
step (know);
|
|
78
|
-
|
|
109
|
+
timeLine = get.cpu_us();
|
|
110
|
+
if (get._SCH_FLAG) sch.handle();
|
|
111
|
+
stepCost = get.cpu_us() - timeLine;
|
|
79
112
|
std.show_usage ();
|
|
113
|
+
print("knowCost:", knowCost, "monitorCost:", monitorCost, "stepCost:", stepCost);
|
|
114
|
+
if (know.draw) know.draw();
|
|
80
115
|
};
|
|
81
116
|
"""
|
|
82
117
|
|
|
@@ -114,42 +149,60 @@ export var loop = function () {
|
|
|
114
149
|
|
|
115
150
|
ARENA_IMPORTS_GETTER = {
|
|
116
151
|
const.ARENA_GREEN: lambda: f"""
|
|
117
|
-
|
|
118
|
-
|
|
152
|
+
const ARENA_COLOR_TYPE = "GREEN";
|
|
153
|
+
class GameAreaEffect{{
|
|
154
|
+
constructor(){{
|
|
119
155
|
}}
|
|
120
156
|
}};
|
|
121
|
-
|
|
157
|
+
class GameConstructionBoost{{
|
|
158
|
+
constructor(){{
|
|
159
|
+
}}
|
|
160
|
+
}};
|
|
161
|
+
import {{ Portal as GamePortal}} from 'arena/season_{config.season}/{const.ARENA_GREEN}/{"advanced" if config.level in ["advance", "advanced"] else "basic"}/prototypes';
|
|
162
|
+
|
|
122
163
|
""",
|
|
123
164
|
const.ARENA_BLUE: lambda: f"""
|
|
124
|
-
const
|
|
125
|
-
|
|
165
|
+
const ARENA_COLOR_TYPE = "BLUE";
|
|
166
|
+
const GameScoreCollector = GameStructureSpawn;
|
|
167
|
+
class GameAreaEffect{{
|
|
168
|
+
constructor(){{
|
|
169
|
+
}}
|
|
170
|
+
}};
|
|
171
|
+
class GamePortal{{
|
|
172
|
+
constructor(){{
|
|
173
|
+
}}
|
|
174
|
+
}};
|
|
175
|
+
class GameConstructionBoost{{
|
|
176
|
+
constructor(){{
|
|
177
|
+
}}
|
|
178
|
+
}};
|
|
126
179
|
""",
|
|
127
180
|
const.ARENA_RED: lambda: f"""
|
|
128
|
-
|
|
129
|
-
|
|
181
|
+
const ARENA_COLOR_TYPE = "RED";
|
|
182
|
+
class GamePortal{{
|
|
183
|
+
constructor(){{
|
|
130
184
|
}}
|
|
131
185
|
}};
|
|
132
|
-
import {{
|
|
186
|
+
import {{ ConstructionBoost as GameConstructionBoost, AreaEffect as GameAreaEffect }} from 'arena/season_{config.season}/{const.ARENA_RED}/{"advanced" if config.level in ["advance", "advanced"] else "basic"}/prototypes';
|
|
187
|
+
import {{ EFFECT_CONSTRUCTION_BOOST, EFFECT_SLOWDOWN }} from 'arena/season_{config.season}/{const.ARENA_RED}/{"advanced" if config.level in ["advance", "advanced"] else "basic"}/constants';
|
|
133
188
|
|
|
134
|
-
import ("arena/season_{config.season}/collect_and_control/basic")
|
|
135
|
-
.then((module) => {{ const RESOURCE_SCORE_X = module.RESOURCE_SCORE_X; const RESOURCE_SCORE_Y = module.RESOURCE_SCORE_Y; const RESOURCE_SCORE_Z = module.RESOURCE_SCORE_Z; }})
|
|
136
|
-
.catch((error) => {{ }});
|
|
137
189
|
""",
|
|
138
190
|
const.ARENA_GRAY: lambda: f"""
|
|
139
|
-
|
|
140
|
-
|
|
191
|
+
const ARENA_COLOR_TYPE = "GRAY";
|
|
192
|
+
class GameAreaEffect{{
|
|
193
|
+
constructor(){{
|
|
194
|
+
}}
|
|
195
|
+
}};
|
|
196
|
+
class GamePortal{{
|
|
197
|
+
constructor(){{
|
|
198
|
+
}}
|
|
199
|
+
}};
|
|
200
|
+
class GameConstructionBoost{{
|
|
201
|
+
constructor(){{
|
|
141
202
|
}}
|
|
142
203
|
}};
|
|
143
|
-
const ScoreCollector = StructureSpawn;
|
|
144
|
-
import("game/prototypes")
|
|
145
|
-
.then((module) => {{ const Flag = module.Flag; }})
|
|
146
|
-
.catch((error) => {{ }});
|
|
147
204
|
""",
|
|
148
205
|
}
|
|
149
|
-
ARENA_IMPORTS_NOT_BLUE = ""
|
|
150
|
-
ARENA_IMPORTS_NOT_BLUE1 = """
|
|
151
|
-
import { StructureTower } from 'game/prototypes'
|
|
152
|
-
"""
|
|
153
206
|
|
|
154
207
|
|
|
155
208
|
class Compiler_Utils(Compiler_Const):
|
|
@@ -165,7 +218,7 @@ class Compiler_Utils(Compiler_Const):
|
|
|
165
218
|
if not Compiler_Utils.last_output:
|
|
166
219
|
Compiler_Utils.last_output = True
|
|
167
220
|
print()
|
|
168
|
-
core.warn('Compiler_Utils.auto_read', core.lformat(LOC_FILE_NOT_EXISTS, [fpath]), end='', head='\n', ln=config.language)
|
|
221
|
+
core.warn('Compiler_Utils.auto_read', core.lformat(LOC_FILE_NOT_EXISTS, ["", fpath]), end='', head='\n', ln=config.language)
|
|
169
222
|
return ""
|
|
170
223
|
|
|
171
224
|
try:
|
|
@@ -177,12 +230,16 @@ class Compiler_Utils(Compiler_Const):
|
|
|
177
230
|
return f.read()
|
|
178
231
|
except UnicodeDecodeError:
|
|
179
232
|
# 如果使用检测到的编码读取失败,尝试使用chardet检测编码
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
233
|
+
try:
|
|
234
|
+
with open(fpath, 'rb') as f: # 以二进制模式打开文件
|
|
235
|
+
raw_data = f.read() # 读取文件的原始数据
|
|
236
|
+
result = chardet.detect(raw_data) # 使用chardet检测编码
|
|
237
|
+
encoding = result['encoding'] # 获取检测到的编码
|
|
238
|
+
with open(fpath, 'r', encoding=encoding) as f: # 使用检测到的编码打开文件
|
|
239
|
+
return f.read()
|
|
240
|
+
except UnicodeDecodeError as e:
|
|
241
|
+
core.error('Compiler_Utils.auto_read', core.lformat(LOC_FILE_READ_FAILED, [fpath, "UnicodeError", e]), end='', head='\n', ln=config.language)
|
|
242
|
+
quit(-1)
|
|
186
243
|
|
|
187
244
|
def copy_to(self) -> list:
|
|
188
245
|
"""
|
|
@@ -283,8 +340,104 @@ class Compiler_Utils(Compiler_Const):
|
|
|
283
340
|
|
|
284
341
|
return '\n'.join(result) # 将处理后的所有代码行连接成一个字符串,并返回最终结果 | join all processed lines into a string and return
|
|
285
342
|
|
|
286
|
-
def
|
|
343
|
+
def expand_folder_imports(self, fpath: str, project_path: str = None):
|
|
344
|
+
"""
|
|
345
|
+
扩展文件夹导入语句:将 `from folder import *` 替换为 `from folder.module import *`
|
|
346
|
+
仅在文件夹没有 __init__.py 时执行此操作
|
|
347
|
+
|
|
348
|
+
:param fpath: 要处理的文件路径
|
|
349
|
+
:param project_path: 项目根路径,用于解析相对导入,默认为 None(使用文件所在目录)
|
|
287
350
|
"""
|
|
351
|
+
if not os.path.exists(fpath):
|
|
352
|
+
return
|
|
353
|
+
|
|
354
|
+
content = self.auto_read(fpath)
|
|
355
|
+
lines = content.split('\n')
|
|
356
|
+
new_lines = []
|
|
357
|
+
changed = False
|
|
358
|
+
|
|
359
|
+
for line in lines:
|
|
360
|
+
m = self.PY_IMPORT_PAT.match(line)
|
|
361
|
+
if not m:
|
|
362
|
+
new_lines.append(line)
|
|
363
|
+
continue
|
|
364
|
+
|
|
365
|
+
original_target = m.group(1)
|
|
366
|
+
target = original_target
|
|
367
|
+
target_path = project_path or os.path.dirname(fpath)
|
|
368
|
+
|
|
369
|
+
# 处理相对路径(向前定位)
|
|
370
|
+
if target.startswith('.'):
|
|
371
|
+
target_path = os.path.dirname(fpath)
|
|
372
|
+
count = 0
|
|
373
|
+
for c in target:
|
|
374
|
+
if c == '.':
|
|
375
|
+
count += 1
|
|
376
|
+
else:
|
|
377
|
+
break
|
|
378
|
+
|
|
379
|
+
# 向上移动目录
|
|
380
|
+
if count > 1:
|
|
381
|
+
for _ in range(count - 1):
|
|
382
|
+
target_path = os.path.dirname(target_path)
|
|
383
|
+
|
|
384
|
+
# 移除开头的点
|
|
385
|
+
target = target[count:]
|
|
386
|
+
|
|
387
|
+
# 如果 target 为空,跳过
|
|
388
|
+
if not target:
|
|
389
|
+
new_lines.append(line)
|
|
390
|
+
continue
|
|
391
|
+
|
|
392
|
+
# 向后定位,构建完整路径
|
|
393
|
+
temp_target = target
|
|
394
|
+
while (_idx := temp_target.find('.')) != -1:
|
|
395
|
+
part = temp_target[:_idx]
|
|
396
|
+
target_path = os.path.join(target_path, part)
|
|
397
|
+
temp_target = temp_target[_idx + 1:]
|
|
398
|
+
|
|
399
|
+
# 最终的文件夹路径
|
|
400
|
+
final_dir_path = os.path.join(target_path, temp_target) if temp_target else target_path
|
|
401
|
+
|
|
402
|
+
# 检查是否是文件夹且没有 __init__.py
|
|
403
|
+
if os.path.isdir(final_dir_path):
|
|
404
|
+
init_path = os.path.join(final_dir_path, '__init__.py')
|
|
405
|
+
if not os.path.exists(init_path):
|
|
406
|
+
# 找到所有 .py 文件(排除 __init__.py)| 如果包含子目录,产生一个警告
|
|
407
|
+
# try:
|
|
408
|
+
# py_files = [f for f in os.listdir(final_dir_path) if f.endswith('.py') and f != '__init__.py']
|
|
409
|
+
# except (FileNotFoundError, PermissionError):
|
|
410
|
+
py_files = []
|
|
411
|
+
for item in os.listdir(final_dir_path):
|
|
412
|
+
_path = os.path.join(final_dir_path, item)
|
|
413
|
+
if os.path.isfile(_path) and item.endswith('.py') and item != '__init__.py':
|
|
414
|
+
py_files.append(item)
|
|
415
|
+
elif os.path.isdir(_path):
|
|
416
|
+
rel = os.path.relpath(final_dir_path, project_path)
|
|
417
|
+
core.warn(f'Compiler.expand_folder_imports', core.lformat(LOC_DIR_UNDER_NONINIT_DIR, [item, rel]), end='', head='\n', ln=config.language )
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
# 为每个 .py 文件生成导入语句
|
|
421
|
+
if py_files:
|
|
422
|
+
for py_file in py_files:
|
|
423
|
+
module_name = py_file[:-3]
|
|
424
|
+
new_import = f"from {original_target}.{module_name} import *"
|
|
425
|
+
new_lines.append(new_import)
|
|
426
|
+
changed = True
|
|
427
|
+
continue
|
|
428
|
+
|
|
429
|
+
# 保留原行
|
|
430
|
+
new_lines.append(line)
|
|
431
|
+
|
|
432
|
+
# 如果文件有修改,写回
|
|
433
|
+
if changed:
|
|
434
|
+
new_content = '\n'.join(new_lines)
|
|
435
|
+
with open(fpath, 'w', encoding='utf-8') as f:
|
|
436
|
+
f.write(new_content)
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def find_chain_import(self, fpath: str, search_dirs: list[str], project_path: str = None, records: dict[str, None] = None) -> list[str]:
|
|
440
|
+
r"""
|
|
288
441
|
查找文件中的所有import语句,并返回所有import的文件路径 | find all import statements in a file and return the paths of all imported files
|
|
289
442
|
PY_IMPORT_PAT: re.compile(r'\s+from\s+(.+)(?=\s+import)\s+import\s+\*')
|
|
290
443
|
:param fpath: str 目标文件路径 | target file path
|
|
@@ -296,7 +449,7 @@ class Compiler_Utils(Compiler_Const):
|
|
|
296
449
|
if records is None:
|
|
297
450
|
records = {}
|
|
298
451
|
if not os.path.exists(fpath):
|
|
299
|
-
core.error('Compiler.find_chain_import', core.lformat(LOC_FILE_NOT_EXISTS, [fpath]), head='\n', ln=config.language)
|
|
452
|
+
core.error('Compiler.find_chain_import', core.lformat(LOC_FILE_NOT_EXISTS, ["py", fpath]), head='\n', ln=config.language)
|
|
300
453
|
imps = []
|
|
301
454
|
content = self.auto_read(fpath)
|
|
302
455
|
project_path = project_path or os.path.dirname(fpath)
|
|
@@ -342,6 +495,81 @@ class Compiler_Utils(Compiler_Const):
|
|
|
342
495
|
|
|
343
496
|
return imps
|
|
344
497
|
|
|
498
|
+
def find_chain_import2(self, fpath: str, search_dirs: list[str], project_path: str = None, records: dict[str, None] = None) -> list[str]:
|
|
499
|
+
r"""
|
|
500
|
+
查找文件中的所有import语句,并返回所有import的文件路径 | find all import statements in a file and return the paths of all imported files
|
|
501
|
+
PY_IMPORT_PAT: re.compile(r'\s+from\s+(.+)(?=\s+import)\s+import\s+\*')
|
|
502
|
+
:param fpath: str 目标文件路径 | target file path
|
|
503
|
+
:param search_dirs: list[str] 搜索目录 | search directories
|
|
504
|
+
:param project_path=None: str python项目中的概念,指根文件所在的目录。如果不指定,默认使用第一次调用时给定的fpath,并且稍后的递归会全部使用此路径 |
|
|
505
|
+
concept in python-project, refers to the directory where the root file is located. If not specified, the fpath given at the first call is used by default, and all subsequent recursions will use this path
|
|
506
|
+
:param records=None: dict[str, None] 记录已经查找过的文件路径,避免重复查找 | record the file paths that have been searched to avoid duplicate searches
|
|
507
|
+
"""
|
|
508
|
+
if records is None:
|
|
509
|
+
records = {}
|
|
510
|
+
if not os.path.exists(fpath):
|
|
511
|
+
core.error('Compiler.find_chain_import', core.lformat(LOC_FILE_NOT_EXISTS, [fpath]), head='\n', ln=config.language)
|
|
512
|
+
imps = []
|
|
513
|
+
content = self.auto_read(fpath)
|
|
514
|
+
project_path = project_path or os.path.dirname(fpath)
|
|
515
|
+
|
|
516
|
+
# 添加根目录和 src 目录到 search_dirs
|
|
517
|
+
root_dir = os.path.dirname(project_path) # 根目录
|
|
518
|
+
src_dir = os.path.join(root_dir, 'src') # src 目录
|
|
519
|
+
if root_dir not in search_dirs:
|
|
520
|
+
search_dirs = [root_dir] + search_dirs
|
|
521
|
+
if src_dir not in search_dirs:
|
|
522
|
+
search_dirs = [src_dir] + search_dirs
|
|
523
|
+
|
|
524
|
+
for no, line in enumerate(content.split('\n')):
|
|
525
|
+
m = self.PY_IMPORT_PAT.match(line)
|
|
526
|
+
if m:
|
|
527
|
+
target = m.group(1)
|
|
528
|
+
target_path = project_path
|
|
529
|
+
|
|
530
|
+
## 向前定位 | locate forward
|
|
531
|
+
if target.startswith('.'):
|
|
532
|
+
target_path = os.path.dirname(fpath) # 因为使用了相对路径,所以需要先定位到当前文件所在的目录 |
|
|
533
|
+
# because relative path is used, need to locate the directory where the current file is located first
|
|
534
|
+
count = 0
|
|
535
|
+
for c in target:
|
|
536
|
+
if c == '.':
|
|
537
|
+
count += 1
|
|
538
|
+
else:
|
|
539
|
+
break
|
|
540
|
+
if count > 1:
|
|
541
|
+
for _ in range(count - 1):
|
|
542
|
+
target_path = os.path.dirname(target_path)
|
|
543
|
+
|
|
544
|
+
## 向后定位 | locate backward
|
|
545
|
+
while (_idx := target.find('.')) != -1:
|
|
546
|
+
first_name = target[:_idx]
|
|
547
|
+
target_path = os.path.join(target_path, first_name)
|
|
548
|
+
target = target[_idx + 1:]
|
|
549
|
+
|
|
550
|
+
## 检查是否存在 | check if exists
|
|
551
|
+
this_path = os.path.join(target_path, target)
|
|
552
|
+
if os.path.isdir(this_path):
|
|
553
|
+
this_path = os.path.join(this_path, '__init__.py')
|
|
554
|
+
else:
|
|
555
|
+
this_path += '.py'
|
|
556
|
+
|
|
557
|
+
if not os.path.exists(this_path):
|
|
558
|
+
# 如果当前路径不存在,尝试在 search_dirs 中查找
|
|
559
|
+
for search_dir in search_dirs:
|
|
560
|
+
search_path = os.path.join(search_dir, target.replace('.', os.sep)) + ('.py' if not os.path.isdir(this_path) else os.sep + '__init__.py')
|
|
561
|
+
if os.path.exists(search_path):
|
|
562
|
+
this_path = search_path
|
|
563
|
+
break
|
|
564
|
+
else:
|
|
565
|
+
core.error('Compiler.find_chain_import', core.lformat(LOC_CHAIN_FILE_NOT_EXISTS, [fpath, no + 1, this_path]), head='\n', ln=config.language)
|
|
566
|
+
if this_path not in records:
|
|
567
|
+
records[this_path] = None
|
|
568
|
+
tmp = self.find_chain_import(this_path, search_dirs, project_path, records) + [this_path]
|
|
569
|
+
imps.extend(tmp)
|
|
570
|
+
|
|
571
|
+
return imps
|
|
572
|
+
|
|
345
573
|
@staticmethod
|
|
346
574
|
def relist_pyimports_to_jsimports(base_dir:str, pyimps:list[str]) -> list[str]:
|
|
347
575
|
"""
|
|
@@ -358,21 +586,277 @@ class Compiler_Utils(Compiler_Const):
|
|
|
358
586
|
return jsimps
|
|
359
587
|
|
|
360
588
|
# ---------- 自定义函数 ---------- #
|
|
589
|
+
|
|
361
590
|
@staticmethod
|
|
362
|
-
def stage_recursive_replace(content:str) -> str:
|
|
591
|
+
def stage_recursive_replace(content: str) -> str:
|
|
363
592
|
"""
|
|
364
|
-
|
|
365
|
-
Replace '@recursive' with '@recursive(<fname>)', where <fname> is the name of the decorated function.
|
|
593
|
+
移除 '@recursive' 装饰器行,并在文末添加对应的 _recursiveLogin 调用。
|
|
366
594
|
|
|
367
|
-
|
|
595
|
+
对于类方法: _recursiveLogin("ClassName", "method_name")
|
|
596
|
+
对于普通函数: _recursiveLogin("", "function_name")
|
|
368
597
|
"""
|
|
369
|
-
|
|
598
|
+
calls_to_add = []
|
|
599
|
+
deletions = []
|
|
370
600
|
|
|
601
|
+
# 1. 收集所有类定义的位置和缩进
|
|
602
|
+
class_pattern = re.compile(r'^(\s*)class\s+(\w+)', re.MULTILINE)
|
|
603
|
+
classes = [(m.start(), len(m.group(1)), m.group(2))
|
|
604
|
+
for m in class_pattern.finditer(content)]
|
|
605
|
+
|
|
606
|
+
# 2. 查找所有 @recursive 装饰器
|
|
607
|
+
decorator_pattern = re.compile(r'^\s*@\s*recursive\s*$\n?', re.MULTILINE)
|
|
608
|
+
|
|
609
|
+
for dec_match in decorator_pattern.finditer(content):
|
|
610
|
+
dec_end = dec_match.end()
|
|
611
|
+
|
|
612
|
+
# 查找接下来的函数定义(跳过可能的空行)
|
|
613
|
+
after_decorator = content[dec_end:]
|
|
614
|
+
func_match = re.search(r'^(\s*)def\s+([^\s\(]+)', after_decorator, re.MULTILINE)
|
|
615
|
+
|
|
616
|
+
if not func_match:
|
|
617
|
+
continue
|
|
618
|
+
|
|
619
|
+
func_indent_len = len(func_match.group(1))
|
|
620
|
+
func_name = func_match.group(2)
|
|
621
|
+
|
|
622
|
+
# 3. 确定类名:查找装饰器前最近的、缩进小于函数缩进的类
|
|
623
|
+
class_name = ""
|
|
624
|
+
for cls_pos, cls_indent_len, cls_name in reversed(classes):
|
|
625
|
+
if cls_pos < dec_match.start() and func_indent_len > cls_indent_len:
|
|
626
|
+
class_name = cls_name
|
|
627
|
+
break
|
|
628
|
+
|
|
629
|
+
# 4. 记录删除位置和调用信息
|
|
630
|
+
deletions.append((dec_match.start(), dec_end))
|
|
631
|
+
calls_to_add.append(f'_recursiveLogin("{class_name}", "{func_name}")')
|
|
632
|
+
|
|
633
|
+
# 5. 应用删除(倒序避免位置偏移)
|
|
634
|
+
if not deletions:
|
|
635
|
+
return content
|
|
636
|
+
|
|
637
|
+
result = content
|
|
638
|
+
for start, end in sorted(deletions, key=lambda x: x[0], reverse=True):
|
|
639
|
+
result = result[:start] + result[end:]
|
|
640
|
+
|
|
641
|
+
# 6. 在文末添加调用
|
|
642
|
+
if calls_to_add:
|
|
643
|
+
result = '\n'.join(calls_to_add) + '\n' + result
|
|
644
|
+
|
|
645
|
+
return result
|
|
646
|
+
|
|
647
|
+
@staticmethod
|
|
648
|
+
def process_mate_code(code):
|
|
649
|
+
# 用于存储匹配到的信息
|
|
650
|
+
mate_assignments = []
|
|
651
|
+
# 匹配变量赋值为Mate()的正则表达式,允许变量定义中包含或不包含类型注解
|
|
652
|
+
assign_pattern = re.compile(r'(\w+)\s*(?:\:\s*\w*)?\s*=\s*Mate\s*\(')
|
|
653
|
+
# 匹配类定义的正则表达式
|
|
654
|
+
class_pattern = re.compile(r'class\s+(\w+)')
|
|
655
|
+
# 用于记录当前所在的类名
|
|
656
|
+
current_class = None
|
|
657
|
+
# 将代码按行分割
|
|
658
|
+
lines = code.split('\n')
|
|
659
|
+
# 遍历每一行
|
|
660
|
+
for i, line in enumerate(lines):
|
|
661
|
+
# 匹配类定义
|
|
662
|
+
class_match = class_pattern.match(line)
|
|
663
|
+
if class_match:
|
|
664
|
+
current_class = class_match.group(1)
|
|
665
|
+
# 匹配变量赋值为Mate()
|
|
666
|
+
assign_match = assign_pattern.search(line)
|
|
667
|
+
if assign_match:
|
|
668
|
+
# 检查group(1)前面同一行内是否有#,如果有则忽略
|
|
669
|
+
comment = re.search(r'#', line[:assign_match.start()])
|
|
670
|
+
if comment:
|
|
671
|
+
continue
|
|
672
|
+
variable_name = assign_match.group(1)
|
|
673
|
+
# 存储匹配到的信息
|
|
674
|
+
mate_assignments += [(variable_name, current_class)]
|
|
675
|
+
|
|
676
|
+
output_strings = []
|
|
677
|
+
for variable_name, class_name in mate_assignments:
|
|
678
|
+
output_string = f"# > insert Object.defineProperty ({class_name}, '{variable_name}', property.call ({class_name}, {class_name}.{variable_name}._MateGet_, {class_name}.{variable_name}._MateSet_));"
|
|
679
|
+
output_strings.append(output_string)
|
|
680
|
+
|
|
681
|
+
return code + '\n'.join(output_strings)
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
@staticmethod
|
|
685
|
+
def remove_long_docstring(content:str) -> str:
|
|
686
|
+
"""
|
|
687
|
+
移除长注释 | remove long docstring
|
|
688
|
+
"""
|
|
689
|
+
code = re.sub(r'"""[^"]*"""', '', content)
|
|
690
|
+
code = re.sub(r"'''[^']*'''", '', code)
|
|
691
|
+
return code
|
|
692
|
+
|
|
693
|
+
@classmethod
|
|
694
|
+
def _collect_logical_line(cls, lines: List[str], start_idx: int) -> Tuple[str, int]:
|
|
695
|
+
"""收集从start_idx开始的逻辑行(处理多行语句,直到遇到:结尾)"""
|
|
696
|
+
if start_idx >= len(lines):
|
|
697
|
+
return "", start_idx
|
|
698
|
+
|
|
699
|
+
parts = [lines[start_idx].rstrip()]
|
|
700
|
+
i = start_idx
|
|
701
|
+
|
|
702
|
+
# 持续收集直到找到以:结尾的行
|
|
703
|
+
while i < len(lines) and not parts[-1].endswith(':'):
|
|
704
|
+
i += 1
|
|
705
|
+
if i < len(lines):
|
|
706
|
+
parts.append(lines[i].rstrip())
|
|
707
|
+
|
|
708
|
+
return " ".join(parts), i
|
|
709
|
+
|
|
710
|
+
@classmethod
|
|
711
|
+
def _convert_block(cls, lines: List[str], match_counter: Optional[List[int]] = None) -> List[str]:
|
|
712
|
+
if match_counter is None:
|
|
713
|
+
match_counter = [0]
|
|
714
|
+
|
|
715
|
+
result = []
|
|
716
|
+
i = 0
|
|
717
|
+
|
|
718
|
+
while i < len(lines):
|
|
719
|
+
line = lines[i].rstrip()
|
|
720
|
+
|
|
721
|
+
# 检测match语句(支持多行)
|
|
722
|
+
if re.match(r'^\s*match\s+', line):
|
|
723
|
+
full_match, end_idx = cls._collect_logical_line(lines, i)
|
|
724
|
+
|
|
725
|
+
match_stmt = re.match(r'^(\s*)match\s+(.+?)\s*:', full_match)
|
|
726
|
+
if not match_stmt:
|
|
727
|
+
result.append(line)
|
|
728
|
+
i += 1
|
|
729
|
+
continue
|
|
730
|
+
|
|
731
|
+
indent = match_stmt.group(1)
|
|
732
|
+
subject = match_stmt.group(2).strip()
|
|
733
|
+
i = end_idx + 1 # 跳过match语句
|
|
734
|
+
|
|
735
|
+
# 生成临时变量
|
|
736
|
+
var_name = f"__MATCH_{match_counter[0]}__"
|
|
737
|
+
match_counter[0] += 1
|
|
738
|
+
result.append(f"{indent}{var_name} = {subject}")
|
|
739
|
+
|
|
740
|
+
# 解析case语句
|
|
741
|
+
cases: List[Tuple[str, List[str]]] = []
|
|
742
|
+
case_indent = None
|
|
743
|
+
|
|
744
|
+
while i < len(lines):
|
|
745
|
+
case_line = lines[i].rstrip()
|
|
746
|
+
|
|
747
|
+
# 缩进检查 - case必须比match缩进更多
|
|
748
|
+
if not case_line.startswith(indent + ' ') and case_line.strip():
|
|
749
|
+
if re.match(r'^\s*case\s+', case_line):
|
|
750
|
+
raise MatchCaseError(f"第 {i + 1} 行: case 缩进必须大于 match")
|
|
751
|
+
break
|
|
752
|
+
|
|
753
|
+
# 检测case语句(不再使用_collect_logical_line,而是单独处理每一行)
|
|
754
|
+
case_match = re.match(r'^(\s+)case\s+(.+?)\s*:', case_line)
|
|
755
|
+
if case_match:
|
|
756
|
+
curr_case_indent = case_match.group(1)
|
|
757
|
+
case_val = case_match.group(2).strip()
|
|
758
|
+
|
|
759
|
+
# 验证缩进 - 允许不同的case缩进(用于嵌套)
|
|
760
|
+
if len(curr_case_indent) <= len(indent):
|
|
761
|
+
raise MatchCaseError(f"第 {i + 1} 行: case 缩进必须大于 match")
|
|
762
|
+
|
|
763
|
+
# 不再强制要求所有case缩进一致,允许嵌套情况下的不同缩进
|
|
764
|
+
if case_indent is None:
|
|
765
|
+
case_indent = curr_case_indent
|
|
766
|
+
|
|
767
|
+
# 提取内联代码(如果有)
|
|
768
|
+
inline_code = ""
|
|
769
|
+
if ':' in case_line:
|
|
770
|
+
after_colon = case_line.split(':', 1)[1].strip()
|
|
771
|
+
if after_colon:
|
|
772
|
+
inline_code = after_colon
|
|
773
|
+
|
|
774
|
+
i += 1
|
|
775
|
+
|
|
776
|
+
# 收集case块
|
|
777
|
+
block_lines = []
|
|
778
|
+
if inline_code:
|
|
779
|
+
block_lines.append(f"{curr_case_indent} {inline_code}")
|
|
780
|
+
|
|
781
|
+
while i < len(lines):
|
|
782
|
+
block_line = lines[i].rstrip()
|
|
783
|
+
if not block_line.strip():
|
|
784
|
+
block_lines.append(block_line)
|
|
785
|
+
i += 1
|
|
786
|
+
continue
|
|
787
|
+
|
|
788
|
+
# 检查是否是下一个case或者缩进回到当前match级别
|
|
789
|
+
if re.match(r'^\s*case\s+', block_line):
|
|
790
|
+
# 检查这个case是否属于当前match还是父级match
|
|
791
|
+
next_case_indent = re.match(r'^\s*', block_line).group(0)
|
|
792
|
+
if len(next_case_indent) <= len(indent):
|
|
793
|
+
# 属于父级match,退出当前match的处理
|
|
794
|
+
break
|
|
795
|
+
# 仍然属于当前match,继续收集
|
|
796
|
+
if block_line.startswith(curr_case_indent + ' '):
|
|
797
|
+
block_lines.append(block_line)
|
|
798
|
+
i += 1
|
|
799
|
+
continue
|
|
800
|
+
else:
|
|
801
|
+
break
|
|
802
|
+
|
|
803
|
+
if block_line.startswith(indent) and not block_line.startswith(curr_case_indent):
|
|
804
|
+
break
|
|
805
|
+
|
|
806
|
+
if block_line.startswith(curr_case_indent + ' '):
|
|
807
|
+
block_lines.append(block_line)
|
|
808
|
+
i += 1
|
|
809
|
+
continue
|
|
810
|
+
|
|
811
|
+
break
|
|
812
|
+
|
|
813
|
+
cases.append((case_val, block_lines))
|
|
814
|
+
else:
|
|
815
|
+
break
|
|
816
|
+
|
|
817
|
+
# 验证case
|
|
818
|
+
seen = set()
|
|
819
|
+
for idx, (val, _) in enumerate(cases):
|
|
820
|
+
if val == '_':
|
|
821
|
+
if idx != len(cases) - 1:
|
|
822
|
+
raise MatchCaseError(f"第 {i + 1} 行附近: case _ 必须在最后")
|
|
823
|
+
else:
|
|
824
|
+
if val in seen:
|
|
825
|
+
raise MatchCaseError(f"第 {i + 1} 行附近: 重复的 case 值 '{val}'")
|
|
826
|
+
seen.add(val)
|
|
827
|
+
|
|
828
|
+
# 生成if/elif/else
|
|
829
|
+
for idx, (case_val, blk_lines) in enumerate(cases):
|
|
830
|
+
keyword = "else" if case_val == '_' else ("if" if idx == 0 else "elif")
|
|
831
|
+
if keyword == "else":
|
|
832
|
+
result.append(f"{indent}else:")
|
|
833
|
+
else:
|
|
834
|
+
result.append(f"{indent}{keyword} {var_name} == {case_val}:")
|
|
835
|
+
|
|
836
|
+
if blk_lines:
|
|
837
|
+
# 递归处理block_lines,以支持嵌套match
|
|
838
|
+
converted_blk_lines = cls._convert_block(blk_lines, match_counter)
|
|
839
|
+
result.extend(converted_blk_lines)
|
|
840
|
+
|
|
841
|
+
continue
|
|
842
|
+
|
|
843
|
+
result.append(line)
|
|
844
|
+
i += 1
|
|
845
|
+
|
|
846
|
+
return result
|
|
847
|
+
|
|
848
|
+
@classmethod
|
|
849
|
+
def convert_match_to_if(cls, code: str) -> str:
|
|
850
|
+
lines = code.split('\n')
|
|
851
|
+
converted_lines = cls._convert_block(lines, [0])
|
|
852
|
+
return '\n'.join(converted_lines)
|
|
371
853
|
|
|
372
854
|
|
|
373
855
|
class CompilerBase(Compiler_Utils):
|
|
374
856
|
|
|
375
|
-
def __init__(self
|
|
857
|
+
def __init__(self):
|
|
858
|
+
src_dir = "src"
|
|
859
|
+
build_dir = "build"
|
|
376
860
|
# check
|
|
377
861
|
if not os.path.exists(src_dir):
|
|
378
862
|
core.error('Compiler.__init__', core.lformat(LOC_FILE_NOT_EXISTS, ['src', src_dir]), head='\n', ln=config.language)
|
|
@@ -435,6 +919,7 @@ class Compiler(CompilerBase):
|
|
|
435
919
|
# 将PYFILE_PRAGMA_INSERTS.replace("\t", "").replace(" ", "")插入到文件开头
|
|
436
920
|
content = self.auto_read(fpath)
|
|
437
921
|
content = self.PYFILE_PRAGMA_INSERTS.replace("\t", "").replace(" ", "") + content
|
|
922
|
+
# content = self.remove_long_docstring(content) # 移除长注释 | remove long docstring
|
|
438
923
|
|
|
439
924
|
with open(fpath, 'w', encoding='utf-8') as f: # 注意,这里修改的是build目录下的文件,不是源文件 | Note that the file under the build directory is modified here, not the source file
|
|
440
925
|
f.write(content)
|
|
@@ -468,6 +953,8 @@ class Compiler(CompilerBase):
|
|
|
468
953
|
if m and (not m.group(2) or m.group(2)[0] != '*'):
|
|
469
954
|
core.error('Compiler.pre_compile', core.lformat(LOC_IMPORT_STAR2_ERROR, [m.group(1), m.group(2), m.group(1)]), head='\n', ln=config.language)
|
|
470
955
|
|
|
956
|
+
self.expand_folder_imports(fpath, self.build_dir)
|
|
957
|
+
|
|
471
958
|
# -------------------------------- EXPAND IMPORT * -------------------------------- #
|
|
472
959
|
_imports = self.find_chain_import(self.target_py, [os.path.dirname(self.src_dir), self.src_dir])
|
|
473
960
|
_js_imports = self.relist_pyimports_to_jsimports(self.build_dir, _imports)
|
|
@@ -506,6 +993,14 @@ class Compiler(CompilerBase):
|
|
|
506
993
|
else:
|
|
507
994
|
_pre_sort_[fname] = 65535
|
|
508
995
|
|
|
996
|
+
# ------------------------------------ 自定义:mate & match ------------------------------------ #
|
|
997
|
+
for fpath in py_fpath:
|
|
998
|
+
content = self.auto_read(fpath)
|
|
999
|
+
content = self.process_mate_code(content) # 调用process_mate_code
|
|
1000
|
+
content = self.convert_match_to_if(content) # 调用convert_match_to_if
|
|
1001
|
+
with open(fpath, 'w', encoding='utf-8') as f:
|
|
1002
|
+
f.write(content)
|
|
1003
|
+
|
|
509
1004
|
# ------------------------------------ DEFINE ------------------------------------ #
|
|
510
1005
|
# 扫描所有# > define的内容,然后在.py中移除这些行,并记录下来
|
|
511
1006
|
# | get all # > define in .py files, and record them
|
|
@@ -579,21 +1074,21 @@ class Compiler(CompilerBase):
|
|
|
579
1074
|
with open(fpath, 'w', encoding='utf-8') as f:
|
|
580
1075
|
f.write(new_content)
|
|
581
1076
|
|
|
582
|
-
# ------------------------------------
|
|
583
|
-
# 调用stage_recursive_replace
|
|
1077
|
+
# ------------------------------------ 自定义:调用stage_recursive_replace ------------------------------------ #
|
|
584
1078
|
for fpath in py_fpath:
|
|
585
1079
|
content = self.auto_read(fpath)
|
|
586
|
-
content = self.stage_recursive_replace(content)
|
|
1080
|
+
content = self.stage_recursive_replace(content) # 调用stage_recursive_replace
|
|
587
1081
|
with open(fpath, 'w', encoding='utf-8') as f:
|
|
588
1082
|
f.write(content)
|
|
589
1083
|
|
|
1084
|
+
|
|
590
1085
|
core.lprint(GREEN.format('[2/6]'), LOC_DONE, " ", LOC_PREPROCESSING_FINISH, sep="", head="\r", ln=config.language)
|
|
591
1086
|
return _imports, _js_imports, _pre_sort_, _pre_define_, _js_replace_
|
|
592
1087
|
|
|
593
1088
|
def transcrypt_cmd(self):
|
|
594
|
-
# 执行cmd命令: transcrypt -b -m -n -s -e 6 target | execute cmd: transcrypt -b -m -n -s -e 6 target
|
|
1089
|
+
# 执行cmd命令: python -m transcrypt -b -m -n -s -e 6 target | execute cmd: python -m transcrypt -b -m -n -s -e 6 target
|
|
595
1090
|
# 并获取cmd得到的输出 | and get the output of the cmd
|
|
596
|
-
cmd = 'transcrypt -b -m -n -s -e 6 %s' % self.target_py
|
|
1091
|
+
cmd = 'python -m transcrypt -b -m -n -s -e 6 %s' % self.target_py
|
|
597
1092
|
core.lprint(WAIT, core.lformat(LOC_TRANSCRYPTING, [cmd]), end="", ln=config.language)
|
|
598
1093
|
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
|
|
599
1094
|
stdout, stderr = p.communicate()
|
|
@@ -721,9 +1216,8 @@ class Compiler(CompilerBase):
|
|
|
721
1216
|
"""
|
|
722
1217
|
arena_name = const.ARENA_NAMES.get(config.arena, const.ARENA_NAMES['green']) # like green -> spawn_and_swamp
|
|
723
1218
|
self.TOTAL_INSERT_AT_HEAD += self.ARENA_IMPORTS_GETTER[arena_name]() # add arena imports
|
|
724
|
-
if config.arena != "blue":
|
|
725
|
-
self.TOTAL_INSERT_AT_HEAD += self.ARENA_IMPORTS_NOT_BLUE
|
|
726
1219
|
total_js = f"const __VERSION__ = '{const.VERSION}';\nconst __PYTHON_VERSION__ = '{python_version_info}';" + self.TOTAL_INSERT_AT_HEAD + f"\nexport var LANGUAGE = '{config.language}';\n"
|
|
1220
|
+
total_js += f"const __AUTHOR__ = '{const.AUTHOR}';\nconst __AUTHOR_CN__ = '{const.BILIBILI_NAME}';"
|
|
727
1221
|
|
|
728
1222
|
core.lprint(WAIT, LOC_GENERATING_TOTAL_MAIN_JS, end="", ln=config.language)
|
|
729
1223
|
|
|
@@ -814,7 +1308,7 @@ class Compiler(CompilerBase):
|
|
|
814
1308
|
self.transcrypt_cmd()
|
|
815
1309
|
imports, modules = self.analyze_rebuild_main_js(defs, jimps)
|
|
816
1310
|
self.find_add_pure_js_files(sorts, modules)
|
|
817
|
-
total_js = imports + "\n" + self.generate_total_js(modules, imps, sorts, self.FILE_STRONG_REPLACE, reps)
|
|
1311
|
+
total_js = imports + "\n" + self.generate_total_js(replace_src_prefix(modules), imps, sorts, self.FILE_STRONG_REPLACE, reps)
|
|
818
1312
|
|
|
819
1313
|
core.lprint(WAIT, LOC_EXPORTING_TOTAL_MAIN_JS, end="", ln=config.language)
|
|
820
1314
|
|
|
@@ -889,6 +1383,20 @@ class Compiler(CompilerBase):
|
|
|
889
1383
|
|
|
890
1384
|
|
|
891
1385
|
if __name__ == '__main__':
|
|
892
|
-
compiler = Compiler('src', 'library', 'build')
|
|
893
|
-
compiler.compile()
|
|
894
|
-
compiler.clean()
|
|
1386
|
+
# compiler = Compiler('src', 'library', 'build')
|
|
1387
|
+
# compiler.compile()
|
|
1388
|
+
# compiler.clean()
|
|
1389
|
+
test = """
|
|
1390
|
+
|
|
1391
|
+
def patrolling(self, c: Creep):
|
|
1392
|
+
e = self.center.nearest(k.civilian.enemies, 5)
|
|
1393
|
+
if e:
|
|
1394
|
+
match c.test(e,
|
|
1395
|
+
int(c.hpPer <= 0.9) * 2,
|
|
1396
|
+
int(c.info.melee) * -3
|
|
1397
|
+
):
|
|
1398
|
+
case True: c.move(e, SWAMP_MOTION)
|
|
1399
|
+
case False: c.move(self.bpos, SWAMP_MOTION)
|
|
1400
|
+
|
|
1401
|
+
"""
|
|
1402
|
+
print(f"res=\n{Compiler.convert_match_to_if(test)}")
|