Skip to content

Commit

Permalink
cpp: defend against recursion in computing decltypes
Browse files Browse the repository at this point in the history
  • Loading branch information
adsharma committed Jun 26, 2021
1 parent c46f5c4 commit 967d9fe
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 14 deletions.
42 changes: 32 additions & 10 deletions py2many/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,28 +91,47 @@ def value_type(node):


class ValueExpressionVisitor(ast.NodeVisitor):
def __init__(self):
super().__init__()
self._stack = []

def visit_Constant(self, node):
return str(node.n)

def visit_Str(self, node):
return node.s

def visit_Name(self, node):
var = node.scopes.find(get_id(node))
name = get_id(node)
if name in self._stack:
# Avoid infinite recursion in cases like foo = bar(foo)
return name
self._stack.append(name)
try:
return self._visit_Name(node)
finally:
self._stack.pop()

def _visit_Name(self, node):
name = get_id(node)
var = node.scopes.find(name)

if not var: # TODO why no scopes found for node id?
return get_id(node)
return name

# TODO: code looks C++ specific. Move out
if isinstance(var.assigned_from, ast.For):
it = var.assigned_from.iter
return "std::declval<typename decltype({0})::value_type>()".format(
self.visit(it)
)
elif isinstance(var.assigned_from, ast.FunctionDef):
return get_id(var)
if hasattr(var, "assigned_from"):
if isinstance(var.assigned_from, ast.For):
it = var.assigned_from.iter
return "std::declval<typename decltype({0})::value_type>()".format(
self.visit(it)
)
elif isinstance(var.assigned_from, ast.FunctionDef):
return get_id(var)
else:
return self.visit(var.assigned_from.value)
else:
return self.visit(var.assigned_from.value)
return name

def visit_Call(self, node):
arg_strings = [self.visit(arg) for arg in node.args]
Expand All @@ -132,6 +151,9 @@ def visit_BinOp(self, node):


class ValueTypeVisitor(ast.NodeVisitor):
def generic_visit(self, node):
return "auto"

def visit_Constant(self, node):
return value_expr(node)

Expand Down
2 changes: 1 addition & 1 deletion pycpp/transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ def visit_List(self, node):
if element_type == self._default_type:
typename = decltype(node)
# Workaround for cases where we couldn't figure out type
if "(None)" in typename:
if "auto" in typename:
return f"{{{elements_str}}}"
return f"{typename}{{{elements_str}}}"
return f"std::vector<{element_type}>{{{elements_str}}}"
Expand Down
6 changes: 3 additions & 3 deletions tests/test_transpile_self.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,14 @@ def test_cpp_recursive(self):
assert len(successful) == 10
assert set(failures) == {
transpiler_module / "plugins.py",
transpiler_module / "transpiler.py",
transpiler_module / "__init__.py",
}

successful, format_errors, failures = _process_dir(
settings, PY2MANY_MODULE, OUT_DIR, _suppress_exceptions=suppress_exceptions
)
assert len(successful) == 13
assert len(failures) == 3
assert len(successful) == 16
assert len(failures) == 1

def test_julia_recursive(self):
settings = self.SETTINGS["julia"]
Expand Down

0 comments on commit 967d9fe

Please sign in to comment.