Ввести v4 для режима текстового UI

This commit is contained in:
Михаил Капелько
2024-05-03 15:00:39 +03:00
parent 6fcd542daa
commit 2357062e25
20 changed files with 1125 additions and 0 deletions

186
v4/tPythonC++/CPP.py Normal file
View File

@@ -0,0 +1,186 @@
from Function import *
def includes():
return """#include <map>
#include <string>
#include <vector>
#include "memory.h"
#include "memory_Context.h"
"""
def replaceAnd(s):
return s.replace("and", "&&")
def replaceAppend(s):
return s.replace(".append(", ".push_back(")
def replaceComment(s):
return s.replace("#", "//")
def replaceLen(s):
posLen = s.find("len(")
posEnd = s.find(")", posLen)
if (
posLen == -1 or
posEnd == -1
):
return s
before = s[:posLen]
name = s[posLen + len("len("):posEnd]
after = s[posEnd + len(")"):]
return f"{before}{name}.size(){after}"
def replaceTrue(s):
return s.replace("True", "true")
def translateParameter(s):
# name: type -> type name
parts = s.split(": ")
indent = len(s) - len(s.lstrip())
name = parts[0].lstrip()
t = translateType(parts[1])
indentation = "".join(" " * indent)
return f"{indentation}{t} {name}"
def translateStatement(s, state):
indent = len(s) - len(s.lstrip())
indentation = "".join(" " * indent)
ss = s.lstrip()
posColon = ss.find(": ")
posComma = ss.find(", ")
posComment = ss.find("# ")
posCtx = ss.find("c.")
posEqual = ss.find(" = ")
posFor = ss.find("for ")
posIn = ss.find(" in ")
posRange = ss.find("range(")
posRangeEnd = ss.find("):")
posClosingScope = ss.find("#}")
posOpenSquareBracket = ss.find("[")
# # -> //
if posComment != -1:
return replaceComment(s)
# #} -> }
if posClosingScope != -1:
return f"{indentation}}}"
# for name in range(x, y): -> for (auto name = x; name < y; ++name) {
if (
posFor >= 0 and
posIn >= 0 and
posRange >= 0
):
name = ss[posFor + len("for "):posIn]
x = ss[posRange + len("range("):posComma]
y = ss[posComma + len(", "):posRangeEnd]
return f"{indentation}for (auto {name} = {x}; {name} < {y}; ++{name}) {{"
# name: type = value -> type name = value
if (
posColon >= 0 and
posEqual >= 0
):
name = ss[:posColon]
type = ss[posColon + len(": "):posEqual]
t = translateType(type)
value = ss[posEqual + len(" = "):]
return f"{indentation}{t} {name} = {value};"
# name = value -> auto name = value
if (
posCtx == -1 and
posColon == -1 and
posOpenSquareBracket == -1 and
posEqual >= 0
):
name = ss[:posEqual]
# Skip prepending 'auto' each time variable is assigned,
# only do it the first time
if name not in state.varNames:
state.varNames[name] = True
value = ss[posEqual + len(" = "):]
return f"{indentation}auto {name} = {value};"
# Keep "if ("
if ss == "if (":
state.isIf = True
return s
# Keep "if not ("
if ss == "if not (":
state.isIfNot = True
return f"{indentation}if (!("
# ): -> }
if ss == "):":
# if
if state.isIf:
state.isIf = False
return f"{indentation}) {{"
# if not
state.isIfNot = False
return f"{indentation})) {{"
ending = ";"
if state.isIf or state.isIfNot:
ending = ""
# Unknown.
return f"{s}{ending}"
def translateType(s):
# dict[X, Y] -> std::map<X, Y>
if s.startswith("dict["):
kv = s[len("dict["):-len("]")]
parts = kv.split(", ")
return f"std::map<{parts[0]}, {parts[1]}>"
# str -> std::string
if s == "str":
return "std::string"
# Unknown. Return as is.
return s
class CPP:
def __init__(self, fn):
self.fn = fn
self.isIf = False
self.isIfNot = False
self.varNames = {}
def translate(self):
returnType = translateType(self.fn.returnType)
# Parameters.
params = []
for i in range(0, len(self.fn.parameters)):
p = translateParameter(self.fn.parameters[i])
# Make Context passed by reference.
#if "Context" in p:
# p = p.replace("Context", "Context&")
params.append(p)
strparams = "\n".join(params)
if (len(strparams) > 0):
strparams += "\n"
# Statements.
sts = []
for i in range(0, len(self.fn.statements)):
s = translateStatement(self.fn.statements[i], self)
s = replaceAnd(s)
s = replaceAppend(s)
# Replace len twice to account for double invocation.
s = replaceLen(s)
s = replaceLen(s)
s = replaceTrue(s)
sts.append(s)
strstatements = "\n".join(sts)
return f"""{returnType} {self.fn.name}(
{strparams}) {{
{strstatements}
}}
"""

76
v4/tPythonC++/Function.py Normal file
View File

@@ -0,0 +1,76 @@
class Function:
def __init__(self):
self.isBody = False
self.isComplete = False
self.isSignature = False
self.name = None
self.parameters = []
self.returnType = None
self.statements = []
def parseLine(self, ln):
parts = ln.split(" ")
count = len(parts)
lastPart = parts[count - 1]
# Complete.
if (
self.isBody and
ln.startswith("#}")
):
self.isComplete = True
# Statements.
if (
self.isBody and
not ln.startswith("#}")
):
self.statements.append(ln)
# Parameters.
if (
self.isSignature and
not ln.endswith(":")
):
p = ln
# Remove comma if present.
if p.endswith(","):
p = p[:-1]
self.parameters.append(p)
# Beginning of signature.
if (
self.returnType is None and
self.name is None
and lastPart.endswith("(")
):
self.isSignature = True
# Return type.
if (
self.isSignature and
ln.startswith(") -> ") and
ln.endswith(":")
):
self.returnType = ln[len(") -> "):-len(":")]
# End of parameters/signature.
if (
self.isSignature and
ln.startswith(") -> ") and
ln.endswith(":")
):
self.isSignature = False
self.isBody = True
# Name.
if (
self.isSignature and
lastPart.endswith("(")
):
self.name = lastPart[:-1]
def __repr__(self):
return self.__str__()
def __str__(self):
return f"Function(name/returnT/parameters/statements: '{self.name}'/'{self.returnType}'/'{self.parameters}'/'{self.statements}')"

37
v4/tPythonC++/process.py Executable file
View File

@@ -0,0 +1,37 @@
from CPP import *
from Function import *
def process(FILE_IN):
# Read file.
lines_in = []
with open(FILE_IN) as file:
for line in file:
lines_in.append(line.rstrip())
f = Function()
out = includes()
# Parse.
for ln in lines_in:
ln = ln.rstrip()
# Empty line.
if ln == "":
out += "\n"
# Comment.
elif (
ln.startswith("#") and
not f.isBody
):
out += replaceComment(ln) + "\n"
# Function.
else:
f.parseLine(ln)
if f.isComplete:
cpp = CPP(f)
out += cpp.translate()
# Create new function instance.
f = Function()
return out

25
v4/tPythonC++/translate Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env python3
import os
import sys
from process import *
DIR = os.path.dirname(os.path.realpath(sys.argv[0]))
if len(sys.argv) < 2:
print("Usage: /path/to/translate [OPTIONS] PYTHON_FILE")
sys.exit(1)
FILE_IN = sys.argv[-1]
# Parse options
# TODO Use options
OPT_HEADER = "--header" in sys.argv
OPT_INCLUDES = None
OPT_PREFIX_INCLUDES = "--includes="
for arg in sys.argv:
if arg.startswith(OPT_PREFIX_INCLUDES):
OPT_INCLUDES = arg[len(OPT_PREFIX_INCLUDES):]
# Translate file.
out = process(FILE_IN, OPT_HEADER, OPT_INCLUDES)
print(out)