Проверка шаблона шины для iOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

generate 10KB

10 maanden geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. #!/usr/bin/env python3
  2. import os
  3. import sys
  4. from argparse import ArgumentParser
  5. parser = ArgumentParser(prog='generate v1')
  6. parser.add_argument('module', type=str,
  7. help='the name of the module to generate')
  8. parser.add_argument('-i', '--input', type=str,
  9. help='The path and name of the input file')
  10. parser.add_argument('-o', '--output', type=str,
  11. help='The path of the output files')
  12. args = parser.parse_args()
  13. DIR = os.path.dirname(os.path.realpath(sys.argv[0]))
  14. MODULE = args.module
  15. def isNotKeyword(str):
  16. keywords = [
  17. "core",
  18. "ex",
  19. "recent",
  20. "service",
  21. "set",
  22. "toggle",
  23. "toggleNil",
  24. "vm",
  25. "$vm",
  26. "world",
  27. ]
  28. return str not in keywords
  29. class CoreAction:
  30. def __init__(self, func, sink):
  31. self.func = func
  32. self.sink = sink
  33. def code(self):
  34. return f"""
  35. p.ctrl.m
  36. .compactMap {{ {self.func}($0) }}
  37. .receive(on: DispatchQueue.main)
  38. .sink {{ [weak core = p.core] v in {self.sink} }}
  39. .store(in: &p.core.subscriptions)
  40. """.replace("\n\n", "\n")
  41. class CorePipe:
  42. def __init__(self, name, props):
  43. self.name = name
  44. self.props = props
  45. self.resetMethod()
  46. self.resetDbg()
  47. self.resetSrc()
  48. self.resetExName()
  49. self.resetSteps()
  50. def code(self):
  51. return f"""
  52. p.ctrl.{self.method}(
  53. dbg: "{self.dbg}",
  54. sub: &p.core.subscriptions,
  55. {self.src}.eraseToAnyPublisher(),
  56. {self.steps}
  57. )
  58. """.replace("\n\n", "\n")
  59. def resetDbg(self):
  60. capitals = [l for l in self.name if l.isupper()]
  61. # Нет заглавных.
  62. if len(capitals) == 0:
  63. self.dbg = self.name
  64. return
  65. # Есть заглавные.
  66. firstCap = self.name.find(capitals[0])
  67. self.dbg = self.name[:firstCap] + "".join(capitals)
  68. def resetExName(self):
  69. firstLetter = self.name[0].capitalize()
  70. self.exName = f"""ex{firstLetter}{self.name[1:]}"""
  71. def resetMethod(self):
  72. if "toggle" in self.props:
  73. self.method = "pipe"
  74. else:
  75. self.method = "pipeValue"
  76. def resetSrc(self):
  77. if "core" in self.props:
  78. self.src = "p.core." + self.name
  79. elif "world" in self.props:
  80. self.src = "p.world." + self.name
  81. elif "vm" in self.props:
  82. self.src = "p.core.vm." + self.name
  83. elif "$vm" in self.props:
  84. self.src = "p.core.vm.$" + self.name
  85. else:
  86. # Если это что-то неизвестное заранее, то ищем строку,
  87. # отличную от известных ключевых слов.
  88. self.src = next(filter(isNotKeyword, self.props))
  89. def resetSteps(self):
  90. if "recent" and "ex" in self.props:
  91. self.steps = f"""
  92. {{
  93. $0.{self.name}.value = $1
  94. $0.{self.name}.isRecent = true
  95. }},
  96. {{
  97. $0.{self.name}.isRecent = false
  98. $0.{self.exName} = $1
  99. }}
  100. """
  101. elif "recent" in self.props:
  102. self.steps = f"""
  103. {{
  104. $0.{self.name}.value = $1
  105. $0.{self.name}.isRecent = true
  106. }},
  107. {{ m, _ in m.{self.name}.isRecent = false }}
  108. """
  109. elif "set" in self.props:
  110. self.steps = f"""
  111. {{ $0.{self.name} = $1 }}
  112. """
  113. elif "toggle" in self.props:
  114. self.steps = f"""
  115. {{ $0.{self.name} = true }},
  116. {{ $0.{self.name} = false }}
  117. """
  118. elif "toggleNil" in self.props:
  119. self.steps = f"""
  120. {{ $0.{self.name} = $1 }},
  121. {{ m, _ in m.{self.name} = nil }}
  122. """
  123. class ServiceAction:
  124. def __init__(self, func, sink):
  125. self.func = func
  126. self.sink = sink
  127. def code(self):
  128. return f"""
  129. sp.ctrl.m
  130. .compactMap {{ {self.func}($0) }}
  131. .receive(on: DispatchQueue.main)
  132. .sink {{ v in {self.sink} }}
  133. .store(in: &sp.service.subscriptions)
  134. """.replace("\n\n", "\n")
  135. class ServicePipe:
  136. def __init__(self, name, props):
  137. self.name = name
  138. self.props = props
  139. self.resetMethod()
  140. self.resetDbg()
  141. self.resetSrc()
  142. self.resetExName()
  143. self.resetSteps()
  144. def code(self):
  145. return f"""
  146. sp.ctrl.{self.method}(
  147. dbg: "{self.dbg}",
  148. {self.src}.eraseToAnyPublisher(),
  149. {self.steps}
  150. )
  151. """.replace("\n\n", "\n")
  152. def resetDbg(self):
  153. capitals = [l for l in self.name if l.isupper()]
  154. # Нет заглавных.
  155. if len(capitals) == 0:
  156. self.dbg = self.name
  157. return
  158. # Есть заглавные.
  159. firstCap = self.name.find(capitals[0])
  160. self.dbg = self.name[:firstCap] + "".join(capitals)
  161. def resetExName(self):
  162. firstLetter = self.name[0].capitalize()
  163. self.exName = f"""ex{firstLetter}{self.name[1:]}"""
  164. def resetMethod(self):
  165. if "toggle" in self.props:
  166. self.method = "pipe"
  167. else:
  168. self.method = "pipeValue"
  169. def resetSrc(self):
  170. if "service" in self.props:
  171. self.src = "sp.service." + self.name
  172. elif "world" in self.props:
  173. self.src = "sp.world." + self.name
  174. else:
  175. # Если это и не сервис, и не мир, то
  176. # ищем строку, отличную от известных ключевых слов.
  177. self.src = next(filter(isNotKeyword, self.props))
  178. def resetSteps(self):
  179. if "recent" and "ex" in self.props:
  180. self.steps = f"""
  181. {{
  182. $0.{self.name}.value = $1
  183. $0.{self.name}.isRecent = true
  184. }},
  185. {{
  186. $0.{self.name}.isRecent = false
  187. $0.{self.exName} = $1
  188. }}
  189. """
  190. elif "recent" in self.props:
  191. self.steps = f"""
  192. {{
  193. $0.{self.name}.value = $1
  194. $0.{self.name}.isRecent = true
  195. }},
  196. {{ m, _ in m.{self.name}.isRecent = false }}
  197. """
  198. elif "set" in self.props:
  199. self.steps = f"""
  200. {{ $0.{self.name} = $1 }}
  201. """
  202. elif "toggle" in self.props:
  203. self.steps = f"""
  204. {{ $0.{self.name} = true }},
  205. {{ $0.{self.name} = false }}
  206. """
  207. elif "toggleNil" in self.props:
  208. self.steps = f"""
  209. {{ $0.{self.name} = $1 }},
  210. {{ m, _ in m.{self.name} = nil }}
  211. """
  212. class State:
  213. isCoreAction = False
  214. isCoreController = False
  215. isServiceAction = False
  216. isServiceController = False
  217. def generatePlatform(coreActions, corePipes, serviceActions, servicePipes):
  218. corePlatform = ""
  219. if len(coreActions) > 0 or len(corePipes) > 0:
  220. corePlatform = f"""
  221. static func setupPlatform(_ p: CoreParameters) {{
  222. {coreActions}
  223. {corePipes}
  224. }}
  225. """
  226. return f"""
  227. // ВНИМАНИЕ: Сгенерировано автоматом, не менять руками!
  228. import Foundation
  229. extension {MODULE} {{
  230. enum SectionGenerated {{
  231. {corePlatform}
  232. static func setupPlatform(_ sp: ServiceParameters) {{
  233. {serviceActions}
  234. {servicePipes}
  235. }}
  236. }}
  237. }}
  238. """
  239. def generateCoreAction(ln):
  240. parts = ln.split(": ")
  241. if len(parts) != 2:
  242. return None
  243. func = parts[0].lstrip()
  244. sink = parts[1].rstrip()
  245. action = CoreAction(func, sink)
  246. return action.code()
  247. def generateCorePipe(ln):
  248. parts = ln.split(": [")
  249. if len(parts) != 2:
  250. return None
  251. name = parts[0].lstrip()
  252. props = parts[1][:-1].split(", ")
  253. pipe = CorePipe(name, props)
  254. return pipe.code()
  255. def generateServiceAction(ln):
  256. parts = ln.split(": ")
  257. if len(parts) != 2:
  258. return None
  259. func = parts[0].lstrip()
  260. sink = parts[1].rstrip()
  261. action = ServiceAction(func, sink)
  262. return action.code()
  263. def generateServicePipe(ln):
  264. parts = ln.split(": [")
  265. if len(parts) != 2:
  266. return None
  267. name = parts[0].lstrip()
  268. props = parts[1][:-1].split(", ")
  269. pipe = ServicePipe(name, props)
  270. return pipe.code()
  271. def readFile(fileName):
  272. lines = []
  273. with open(fileName) as file:
  274. for line in file:
  275. lines.append(line.rstrip())
  276. return lines
  277. def resetState(ln):
  278. if ln.startswith("ca:"):
  279. state.isCoreAction = True
  280. state.isCoreController = False
  281. state.isServiceAction = False
  282. state.isServiceController = False
  283. elif ln.startswith("cp:"):
  284. state.isCoreAction = False
  285. state.isCoreController = True
  286. state.isServiceAction = False
  287. state.isServiceController = False
  288. elif ln.startswith("sa:"):
  289. state.isCoreAction = False
  290. state.isCoreController = False
  291. state.isServiceAction = True
  292. state.isServiceController = False
  293. elif ln.startswith("sp:"):
  294. state.isCoreAction = False
  295. state.isCoreController = False
  296. state.isServiceAction = False
  297. state.isServiceController = True
  298. return state
  299. def saveFile(fileName, data):
  300. with open(fileName, "w") as file:
  301. file.write(data)
  302. def validateVersion(ln):
  303. if ln.startswith("version: 1") == False:
  304. print("ERROR: Invalid version")
  305. sys.exit(1)
  306. # Main
  307. state = State()
  308. print(f"Generating platform for module '{MODULE}'...")
  309. fileIn = args.input or f"{DIR}/../../../Modules/{MODULE}/{MODULE}.yml"
  310. fileOut = args.output or f"{DIR}/../../../Modules/{MODULE}/src"
  311. fileOut = os.path.join(fileOut, f'{MODULE}.SectionGenerated.swift')
  312. lines = readFile(fileIn)
  313. validateVersion(lines[0])
  314. coreActions = ""
  315. corePipes = ""
  316. serviceActions = ""
  317. servicePipes = ""
  318. for ln in lines:
  319. st = resetState(ln)
  320. if st.isCoreAction:
  321. action = generateCoreAction(ln)
  322. if action:
  323. coreActions += action
  324. if st.isCoreController:
  325. pipe = generateCorePipe(ln)
  326. if pipe:
  327. corePipes += pipe
  328. if st.isServiceAction:
  329. action = generateServiceAction(ln)
  330. if action:
  331. serviceActions += action
  332. if st.isServiceController:
  333. pipe = generateServicePipe(ln)
  334. if pipe:
  335. servicePipes += pipe
  336. result = generatePlatform(coreActions, corePipes, serviceActions, servicePipes)
  337. saveFile(fileOut, result)