Files
check-ios-bus/Utilities/platform/1/generate
Михаил Капелько d893364ff4 d
2023-12-28 13:33:48 +03:00

374 lines
10 KiB
Python
Executable File

#!/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)