374 lines
10 KiB
Python
Executable File
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)
|