Skip to content

Commit

Permalink
Allow transpilers it declare main signature
Browse files Browse the repository at this point in the history
Also integrates c++ main handling with PythonMainRewriter.
  • Loading branch information
jayvdb committed Jun 27, 2021
1 parent ef48ac2 commit eae0901
Show file tree
Hide file tree
Showing 11 changed files with 28 additions and 26 deletions.
2 changes: 1 addition & 1 deletion py2many/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def _transpile(
language = transpiler.NAME
generic_rewriters = [
ComplexDestructuringRewriter(language),
PythonMainRewriter(language),
PythonMainRewriter(settings.transpiler._main_signature_arg_names),
FStringJoinRewriter(language),
DocStringToCommentRewriter(language),
WithToBlockTransformer(language),
Expand Down
1 change: 1 addition & 0 deletions py2many/clike.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ def __init__(self):
self._container_type_map = {}
self._default_type = _AUTO
self._statement_separator = ";"
self._main_signature_arg_names = []
self._extension = False
self._ignored_module_set = IGNORED_MODULE_SET.copy()
self._module = None
Expand Down
14 changes: 11 additions & 3 deletions py2many/rewriters.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ def rename(scope, old_name, new_name):


class PythonMainRewriter(ast.NodeTransformer):
def __init__(self, language):
def __init__(self, main_signature_arg_names):
self.main_signature_arg_names = set(main_signature_arg_names)
super().__init__()

def visit_If(self, node):
Expand All @@ -145,10 +146,17 @@ def visit_If(self, node):
if hasattr(node, "scopes") and len(node.scopes) > 1:
rename(node.scopes[-2], "main", "main_func")
# ast.parse produces a Module object that needs to be destructured
ret = ast.parse("def main(argc: int, argv: List[str]): True").body[0]
if self.main_signature_arg_names == {"argc", "argv"}:
ret = ast.parse(
"def main(argc: int, argv: List[str]) -> int: True"
).body[0]
elif self.main_signature_arg_names == {"argv"}:
ret = ast.parse("def main(argv: List[str]): True").body[0]
else:
ret = ast.parse("def main(): True").body[0]
ret.lineno = node.lineno
ret.body = node.body
# So backends know to insert argc, argv etc
# So backends know to handle argc, argv etc
ret.python_main = True
return ret
return node
Expand Down
4 changes: 3 additions & 1 deletion pycpp/tests/test_transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ def test_print_program_args():
'if __name__ == "__main__":', " for arg in sys.argv:", " print(arg)"
)
cpp = transpile(source)
# Note the args and return type are missing here as this `transpile` wrapper
# is not the main py2many wrapper, and notably doesnt use PythonMainRewriter.
assert cpp == parse(
"int main(int argc, char ** argv) {",
"void main() {",
"pycpp::sys::argv = std::vector<std::string>(argv, argv + argc);",
"for(auto arg : pycpp::sys::argv) {",
"std::cout << arg;",
Expand Down
21 changes: 10 additions & 11 deletions pycpp/transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ def __init__(self, extension: bool = False, no_prologue: bool = False):
self._small_usings_map = SMALL_USINGS_MAP
self._func_dispatch_table = FUNC_DISPATCH_TABLE
self._attr_dispatch_table = ATTR_DISPATCH_TABLE
self._main_signature_arg_names = ["argc", "argv"]

def usings(self):
usings = sorted(list(set(self._usings)))
Expand Down Expand Up @@ -170,6 +171,7 @@ def visit_FunctionDef(self, node):
):
return generate_catch_test_case(node, body)

is_python_main = getattr(node, "python_main", False)
typenames, args = self.visit(node.args)

args_list = []
Expand All @@ -187,17 +189,21 @@ def visit_FunctionDef(self, node):
typename = "T{0}".format(index)
typedecls.append(typename)
index += 1
if is_python_main and arg in ["argv"]:
typename = "char **"
args_list.append(f"{typename} {arg}")

template = "inline "
if len(typedecls) > 0:
typedecls_str = ", ".join([f"typename {t}" for t in typedecls])
template = f"template <{typedecls_str}>"

return_type = "auto"
if node.name == "main":
if is_python_main:
body = (
"pycpp::sys::argv = std::vector<std::string>(argv, argv + argc);\n"
+ body
)
template = ""
return_type = "int"

if not is_void_function(node):
if node.returns:
Expand All @@ -210,14 +216,7 @@ def visit_FunctionDef(self, node):

args = ", ".join(args_list)
funcdef = f"{template}{return_type} {node.name}({args}) {{"
if getattr(node, "python_main", False):
funcdef = "\n".join(
[
"int main(int argc, char ** argv) {",
"pycpp::sys::argv = "
"std::vector<std::string>(argv, argv + argc);",
]
)

return funcdef + "\n" + body + "}\n"

def visit_Attribute(self, node):
Expand Down
1 change: 1 addition & 0 deletions pydart/transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def __init__(self):
self._small_usings_map = SMALL_USINGS_MAP
self._func_dispatch_table = FUNC_DISPATCH_TABLE
self._attr_dispatch_table = ATTR_DISPATCH_TABLE
self._main_signature_arg_names = ["argv"]

def _get_temp(self):
self._temp += 1
Expand Down
4 changes: 0 additions & 4 deletions pygo/transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,12 @@ def visit_FunctionDef(self, node):
if len(typenames) and typenames[0] == None and hasattr(node, "self_type"):
typenames[0] = node.self_type

is_python_main = getattr(node, "python_main", False)

args_list = []
typedecls = []
index = 0
for i in range(len(args)):
typename = typenames[i]
arg = args[i]
if is_python_main and arg in ["argc", "argv"]:
continue

if typename == "T":
typename = "T{0} any".format(index)
Expand Down
2 changes: 0 additions & 2 deletions pyjl/transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ def visit_FunctionDef(self, node):
for i in range(len(args)):
typename = typenames[i]
arg = args[i]
if is_python_main and arg in ["argc", "argv"]:
continue
if typename == "T":
typename = "T{0}".format(index)
typedecls.append(typename)
Expand Down
1 change: 1 addition & 0 deletions pykt/transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def __init__(self):
super().__init__()
self._default_type = ""
self._container_type_map = self.CONTAINER_TYPE_MAP
self._main_signature_arg_names = ["argv"]

def usings(self):
usings = sorted(list(set(self._usings)))
Expand Down
2 changes: 0 additions & 2 deletions pynim/transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ def visit_FunctionDef(self, node):
for i in range(len(args)):
typename = typenames[i]
arg = args[i]
if is_python_main and arg in ["argc", "argv"]:
continue

args_list.append(f"{arg}: {typename}".format(arg, typename))

Expand Down
2 changes: 0 additions & 2 deletions pyrs/transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,6 @@ def visit_FunctionDef(self, node, async_prefix=""):
for i in range(len(args)):
typename = typenames[i]
arg = args[i]
if is_python_main and arg in ["argc", "argv"]:
continue

if typename == "T":
typename = "T{0}".format(index)
Expand Down

0 comments on commit eae0901

Please sign in to comment.