|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- #!/usr/bin/env python3
- import os
- import sys
- from argparse import ArgumentParser
-
- parser = ArgumentParser(prog='generate v1')
- parser.add_argument('module', type=str,
- help='the name of the module to generate')
- parser.add_argument('-i', '--input', type=str,
- help='The path and name of the input file')
- parser.add_argument('-o', '--output', type=str,
- help='The path of the output files')
-
- args = parser.parse_args()
- DIR = os.path.dirname(os.path.realpath(sys.argv[0]))
- MODULE = args.module
-
- def isNotKeyword(str):
- keywords = [
- "core",
- "ex",
- "recent",
- "service",
- "set",
- "toggle",
- "toggleNil",
- "vm",
- "$vm",
- "world",
- ]
- return str not in keywords
-
- class CoreAction:
- def __init__(self, func, sink):
- self.func = func
- self.sink = sink
-
- def code(self):
- return f"""
- p.ctrl.m
- .compactMap {{ {self.func}($0) }}
- .receive(on: DispatchQueue.main)
- .sink {{ [weak core = p.core] v in {self.sink} }}
- .store(in: &p.core.subscriptions)
- """.replace("\n\n", "\n")
-
- class CorePipe:
- def __init__(self, name, props):
- self.name = name
- self.props = props
- self.resetMethod()
- self.resetDbg()
- self.resetSrc()
- self.resetExName()
- self.resetSteps()
-
- def code(self):
- return f"""
- p.ctrl.{self.method}(
- dbg: "{self.dbg}",
- sub: &p.core.subscriptions,
- {self.src}.eraseToAnyPublisher(),
- {self.steps}
- )
- """.replace("\n\n", "\n")
-
- def resetDbg(self):
- capitals = [l for l in self.name if l.isupper()]
- # Нет заглавных.
- if len(capitals) == 0:
- self.dbg = self.name
- return
- # Есть заглавные.
- firstCap = self.name.find(capitals[0])
- self.dbg = self.name[:firstCap] + "".join(capitals)
-
- def resetExName(self):
- firstLetter = self.name[0].capitalize()
- self.exName = f"""ex{firstLetter}{self.name[1:]}"""
-
- def resetMethod(self):
- if "toggle" in self.props:
- self.method = "pipe"
- else:
- self.method = "pipeValue"
-
- def resetSrc(self):
- if "core" in self.props:
- self.src = "p.core." + self.name
- elif "world" in self.props:
- self.src = "p.world." + self.name
- elif "vm" in self.props:
- self.src = "p.core.vm." + self.name
- elif "$vm" in self.props:
- self.src = "p.core.vm.$" + self.name
- else:
- # Если это что-то неизвестное заранее, то ищем строку,
- # отличную от известных ключевых слов.
- self.src = next(filter(isNotKeyword, self.props))
-
- def resetSteps(self):
- if "recent" and "ex" in self.props:
- self.steps = f"""
- {{
- $0.{self.name}.value = $1
- $0.{self.name}.isRecent = true
- }},
- {{
- $0.{self.name}.isRecent = false
- $0.{self.exName} = $1
- }}
- """
- elif "recent" in self.props:
- self.steps = f"""
- {{
- $0.{self.name}.value = $1
- $0.{self.name}.isRecent = true
- }},
- {{ m, _ in m.{self.name}.isRecent = false }}
- """
- elif "set" in self.props:
- self.steps = f"""
- {{ $0.{self.name} = $1 }}
- """
- elif "toggle" in self.props:
- self.steps = f"""
- {{ $0.{self.name} = true }},
- {{ $0.{self.name} = false }}
- """
- elif "toggleNil" in self.props:
- self.steps = f"""
- {{ $0.{self.name} = $1 }},
- {{ m, _ in m.{self.name} = nil }}
- """
-
- class ServiceAction:
- def __init__(self, func, sink):
- self.func = func
- self.sink = sink
-
- def code(self):
- return f"""
- sp.ctrl.m
- .compactMap {{ {self.func}($0) }}
- .receive(on: DispatchQueue.main)
- .sink {{ v in {self.sink} }}
- .store(in: &sp.service.subscriptions)
- """.replace("\n\n", "\n")
-
- class ServicePipe:
- def __init__(self, name, props):
- self.name = name
- self.props = props
- self.resetMethod()
- self.resetDbg()
- self.resetSrc()
- self.resetExName()
- self.resetSteps()
-
- def code(self):
- return f"""
- sp.ctrl.{self.method}(
- dbg: "{self.dbg}",
- {self.src}.eraseToAnyPublisher(),
- {self.steps}
- )
- """.replace("\n\n", "\n")
-
- def resetDbg(self):
- capitals = [l for l in self.name if l.isupper()]
- # Нет заглавных.
- if len(capitals) == 0:
- self.dbg = self.name
- return
- # Есть заглавные.
- firstCap = self.name.find(capitals[0])
- self.dbg = self.name[:firstCap] + "".join(capitals)
-
- def resetExName(self):
- firstLetter = self.name[0].capitalize()
- self.exName = f"""ex{firstLetter}{self.name[1:]}"""
-
- def resetMethod(self):
- if "toggle" in self.props:
- self.method = "pipe"
- else:
- self.method = "pipeValue"
-
- def resetSrc(self):
- if "service" in self.props:
- self.src = "sp.service." + self.name
- elif "world" in self.props:
- self.src = "sp.world." + self.name
- else:
- # Если это и не сервис, и не мир, то
- # ищем строку, отличную от известных ключевых слов.
- self.src = next(filter(isNotKeyword, self.props))
-
- def resetSteps(self):
- if "recent" and "ex" in self.props:
- self.steps = f"""
- {{
- $0.{self.name}.value = $1
- $0.{self.name}.isRecent = true
- }},
- {{
- $0.{self.name}.isRecent = false
- $0.{self.exName} = $1
- }}
- """
- elif "recent" in self.props:
- self.steps = f"""
- {{
- $0.{self.name}.value = $1
- $0.{self.name}.isRecent = true
- }},
- {{ m, _ in m.{self.name}.isRecent = false }}
- """
- elif "set" in self.props:
- self.steps = f"""
- {{ $0.{self.name} = $1 }}
- """
- elif "toggle" in self.props:
- self.steps = f"""
- {{ $0.{self.name} = true }},
- {{ $0.{self.name} = false }}
- """
- elif "toggleNil" in self.props:
- self.steps = f"""
- {{ $0.{self.name} = $1 }},
- {{ m, _ in m.{self.name} = nil }}
- """
-
- class State:
- isCoreAction = False
- isCoreController = False
- isServiceAction = False
- isServiceController = False
-
- def generatePlatform(coreActions, corePipes, serviceActions, servicePipes):
- corePlatform = ""
- if len(coreActions) > 0 or len(corePipes) > 0:
- corePlatform = f"""
- static func setupPlatform(_ p: CoreParameters) {{
- {coreActions}
- {corePipes}
- }}
- """
-
- return f"""
- // ВНИМАНИЕ: Сгенерировано автоматом, не менять руками!
-
- import Foundation
-
- extension {MODULE} {{
- enum SectionGenerated {{
- {corePlatform}
- static func setupPlatform(_ sp: ServiceParameters) {{
- {serviceActions}
- {servicePipes}
- }}
- }}
- }}
- """
-
- def generateCoreAction(ln):
- parts = ln.split(": ")
- if len(parts) != 2:
- return None
- func = parts[0].lstrip()
- sink = parts[1].rstrip()
- action = CoreAction(func, sink)
- return action.code()
-
- def generateCorePipe(ln):
- parts = ln.split(": [")
- if len(parts) != 2:
- return None
- name = parts[0].lstrip()
- props = parts[1][:-1].split(", ")
- pipe = CorePipe(name, props)
- return pipe.code()
-
- def generateServiceAction(ln):
- parts = ln.split(": ")
- if len(parts) != 2:
- return None
- func = parts[0].lstrip()
- sink = parts[1].rstrip()
- action = ServiceAction(func, sink)
- return action.code()
-
- def generateServicePipe(ln):
- parts = ln.split(": [")
- if len(parts) != 2:
- return None
- name = parts[0].lstrip()
- props = parts[1][:-1].split(", ")
- pipe = ServicePipe(name, props)
- return pipe.code()
-
- def readFile(fileName):
- lines = []
- with open(fileName) as file:
- for line in file:
- lines.append(line.rstrip())
- return lines
-
- def resetState(ln):
- if ln.startswith("ca:"):
- state.isCoreAction = True
- state.isCoreController = False
- state.isServiceAction = False
- state.isServiceController = False
- elif ln.startswith("cp:"):
- state.isCoreAction = False
- state.isCoreController = True
- state.isServiceAction = False
- state.isServiceController = False
- elif ln.startswith("sa:"):
- state.isCoreAction = False
- state.isCoreController = False
- state.isServiceAction = True
- state.isServiceController = False
- elif ln.startswith("sp:"):
- state.isCoreAction = False
- state.isCoreController = False
- state.isServiceAction = False
- state.isServiceController = True
- return state
-
- def saveFile(fileName, data):
- with open(fileName, "w") as file:
- file.write(data)
-
- def validateVersion(ln):
- if ln.startswith("version: 1") == False:
- print("ERROR: Invalid version")
- sys.exit(1)
-
-
- # Main
- state = State()
- print(f"Generating platform for module '{MODULE}'...")
- fileIn = args.input or f"{DIR}/../../../Modules/{MODULE}/{MODULE}.yml"
- fileOut = args.output or f"{DIR}/../../../Modules/{MODULE}/src"
- fileOut = os.path.join(fileOut, f'{MODULE}.SectionGenerated.swift')
- lines = readFile(fileIn)
- validateVersion(lines[0])
- coreActions = ""
- corePipes = ""
- serviceActions = ""
- servicePipes = ""
- for ln in lines:
- st = resetState(ln)
- if st.isCoreAction:
- action = generateCoreAction(ln)
- if action:
- coreActions += action
- if st.isCoreController:
- pipe = generateCorePipe(ln)
- if pipe:
- corePipes += pipe
- if st.isServiceAction:
- action = generateServiceAction(ln)
- if action:
- serviceActions += action
- if st.isServiceController:
- pipe = generateServicePipe(ln)
- if pipe:
- servicePipes += pipe
- result = generatePlatform(coreActions, corePipes, serviceActions, servicePipes)
- saveFile(fileOut, result)
|