Ввести v4 для режима текстового UI
This commit is contained in:
186
v4/tPythonC++/CPP.py
Normal file
186
v4/tPythonC++/CPP.py
Normal 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
76
v4/tPythonC++/Function.py
Normal 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
37
v4/tPythonC++/process.py
Executable 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
25
v4/tPythonC++/translate
Executable 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)
|
||||
Reference in New Issue
Block a user