WIP
This commit is contained in:
parent
3b859363cb
commit
a8a776b5b7
79
test.py
79
test.py
@ -3,7 +3,8 @@
|
|||||||
import ast
|
import ast
|
||||||
import contextlib
|
import contextlib
|
||||||
|
|
||||||
from typing import Dict, List
|
from io import StringIO
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
import spack.directives
|
import spack.directives
|
||||||
import spack.repo
|
import spack.repo
|
||||||
@ -23,8 +24,12 @@ def is_directive(node):
|
|||||||
class NameDescriptor(object):
|
class NameDescriptor(object):
|
||||||
"""Name in a scope, with global/nonlocal and const information."""
|
"""Name in a scope, with global/nonlocal and const information."""
|
||||||
|
|
||||||
def __init__(self, name, const, isglobal, isnonlocal):
|
name: str
|
||||||
# type: (str, bool, bool, bool) -> None
|
const: bool
|
||||||
|
isglobal: bool
|
||||||
|
isnonlocal: bool
|
||||||
|
|
||||||
|
def __init__(self, name: str, const: bool, isglobal: bool, isnonlocal: bool):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.const = const
|
self.const = const
|
||||||
self.isglobal = isglobal
|
self.isglobal = isglobal
|
||||||
@ -38,8 +43,10 @@ class ScopeStack(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
scopes: List[Dict[str, NameDescriptor]]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.scopes = [] # type: List[Dict[str, NameDescriptor]]
|
self.scopes = []
|
||||||
|
|
||||||
def push(self, name):
|
def push(self, name):
|
||||||
"""Add a scope with a name for debugging."""
|
"""Add a scope with a name for debugging."""
|
||||||
@ -66,16 +73,15 @@ def top(self):
|
|||||||
_, scope = self.scopes[-1]
|
_, scope = self.scopes[-1]
|
||||||
return scope
|
return scope
|
||||||
|
|
||||||
def define(self, name, const=None, isglobal=None, isnonlocal=None):
|
def define(self, name: str, const=None, isglobal=None, isnonlocal=None):
|
||||||
# type: NameDescriptor -> None
|
# type: NameDescriptor -> None
|
||||||
self.top[name] = NameDescriptor(name, const, isglobal, isnonlocal)
|
self.top[name] = NameDescriptor(name, const, isglobal, isnonlocal)
|
||||||
|
|
||||||
def assign(self, name, const=None, isglobal=None, isnonlocal=None):
|
def assign(self, name: str, const=None, isglobal=None, isnonlocal=None):
|
||||||
|
|
||||||
self.top.add(name)
|
self.top.add(name)
|
||||||
|
|
||||||
def scope_for(self, name):
|
def scope_for(self, name: str) -> Optional[Dict[str, NameDescriptor]]:
|
||||||
# type: str -> Optional[Dict[str, NameDescriptor]]
|
|
||||||
for _, scope in reversed(self.scopes):
|
for _, scope in reversed(self.scopes):
|
||||||
if name in scope:
|
if name in scope:
|
||||||
return scope
|
return scope
|
||||||
@ -95,6 +101,27 @@ def delete(self, name):
|
|||||||
|
|
||||||
del scope[name]
|
del scope[name]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
out = StringIO()
|
||||||
|
|
||||||
|
out.write("-" * 78)
|
||||||
|
out.write("\n")
|
||||||
|
|
||||||
|
for scope_name, scope in self.scopes:
|
||||||
|
out.write(f"[{scope_name}]\n")
|
||||||
|
for name, desc in scope.items():
|
||||||
|
out.write(" ")
|
||||||
|
out.write(f"{name:20}")
|
||||||
|
out.write("C" if desc.const else "-")
|
||||||
|
out.write("G" if desc.isglobal else "-")
|
||||||
|
out.write("N" if desc.isnonlocal else "-")
|
||||||
|
out.write("\n")
|
||||||
|
|
||||||
|
out.write("-" * 78)
|
||||||
|
out.write("\n")
|
||||||
|
|
||||||
|
return out.getvalue()
|
||||||
|
|
||||||
|
|
||||||
def target_names(node, names=None):
|
def target_names(node, names=None):
|
||||||
"""Get names of values targeted by assignment.
|
"""Get names of values targeted by assignment.
|
||||||
@ -107,17 +134,26 @@ def target_names(node, names=None):
|
|||||||
names = set()
|
names = set()
|
||||||
|
|
||||||
if isinstance(node, ast.Name):
|
if isinstance(node, ast.Name):
|
||||||
|
print(" added", node.id)
|
||||||
names.add(node.id)
|
names.add(node.id)
|
||||||
|
|
||||||
elif isinstance(node, (ast.List, ast.Tuple)):
|
elif isinstance(node, (ast.List, ast.Tuple)):
|
||||||
|
print(" adding from", node.elts)
|
||||||
for elt in node.elts:
|
for elt in node.elts:
|
||||||
names += target_names(elt)
|
names += target_names(elt)
|
||||||
|
|
||||||
elif isinstance(node, (ast.Attribute, ast.Subscript, ast.Starred)):
|
elif isinstance(node, (ast.Attribute, ast.Subscript, ast.Starred)):
|
||||||
|
print(" adding from", node.value)
|
||||||
names += target_names(node.value)
|
names += target_names(node.value)
|
||||||
# TODO: handle the attr in an Attribute to figure out if it's a variable in a
|
# TODO: handle the attr in an Attribute to figure out if it's a variable in a
|
||||||
# TODO: scope somewhere
|
# TODO: scope somewhere
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("WHAT IS THIS: ", type(node))
|
||||||
|
|
||||||
|
print(names)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
def constexpr(node):
|
def constexpr(node):
|
||||||
if isinstance(node, ast.Constant):
|
if isinstance(node, ast.Constant):
|
||||||
@ -209,7 +245,7 @@ def visit_GeneratorExp(self, node, leak=False):
|
|||||||
|
|
||||||
# We currently only test if the entire iter expression is const.
|
# We currently only test if the entire iter expression is const.
|
||||||
#
|
#
|
||||||
# TODO: if we need this to handle different targets separately , e.g. x and y in:
|
# TODO: if we need this to handle different targets separately, e.g. x and y in:
|
||||||
#
|
#
|
||||||
# [(x, y) for x, y in [(a, 1), (b, 2), (c, 3)]]
|
# [(x, y) for x, y in [(a, 1), (b, 2), (c, 3)]]
|
||||||
#
|
#
|
||||||
@ -217,30 +253,31 @@ def visit_GeneratorExp(self, node, leak=False):
|
|||||||
# So both x and y would be non-const here.
|
# So both x and y would be non-const here.
|
||||||
const = constexpr(comp.iter)
|
const = constexpr(comp.iter)
|
||||||
|
|
||||||
|
print(self.scopes)
|
||||||
|
|
||||||
|
names = target_names(comp.target)
|
||||||
for name in target_names(comp.target):
|
for name in target_names(comp.target):
|
||||||
self.scopes.
|
# self.scopes.
|
||||||
self.scopes.define(name.id, const=const)
|
# self.scopes.define(name.id, const=const)
|
||||||
|
pass
|
||||||
|
|
||||||
# visit element expressions once the generator clauses are done
|
# visit element expressions once the generator clauses are done
|
||||||
self.generic_visit(node.elt)
|
self.generic_visit(node.elt)
|
||||||
|
|
||||||
if not leak:
|
if not leak:
|
||||||
for comp in node.generators:
|
for comp in reversed(node.generators):
|
||||||
self.scopes.pop("<generatorexp>")
|
self.scopes.pop("<generatorexp>")
|
||||||
|
|
||||||
self.generic_visit(node)
|
self.generic_visit(node)
|
||||||
|
|
||||||
def visit_ListComp(self, node):
|
def visit_ListComp(self, node):
|
||||||
# use leak-True b/c we support Python 2
|
self.visit_GeneratorExp(node)
|
||||||
self.visit_GeneratorExp(node, leak=True)
|
|
||||||
|
|
||||||
def visit_SetComp(self, node):
|
def visit_SetComp(self, node):
|
||||||
# use leak-True b/c we support Python 2
|
self.visit_GeneratorExp(node)
|
||||||
self.visit_GeneratorExp(node, leak=True)
|
|
||||||
|
|
||||||
def visit_DictComp(self, node):
|
def visit_DictComp(self, node):
|
||||||
# use leak-True b/c we support Python 2
|
self.visit_GeneratorExp(node)
|
||||||
self.visit_GeneratorExp(node, leak=True)
|
|
||||||
|
|
||||||
def visit_Lambda(self, node):
|
def visit_Lambda(self, node):
|
||||||
self.generic_visit(node)
|
self.generic_visit(node)
|
||||||
@ -301,6 +338,9 @@ def visit_Expr(self, node):
|
|||||||
# Directives are represented in the AST as named function call expressions (as
|
# Directives are represented in the AST as named function call expressions (as
|
||||||
# opposed to function calls through a variable callback).
|
# opposed to function calls through a variable callback).
|
||||||
if is_directive(node):
|
if is_directive(node):
|
||||||
|
|
||||||
|
print(node.value.args[0].value)
|
||||||
|
|
||||||
for arg in node.value.args:
|
for arg in node.value.args:
|
||||||
if not constexpr(arg):
|
if not constexpr(arg):
|
||||||
# self.issues.append("ARG: %s" % ast.dump(arg))
|
# self.issues.append("ARG: %s" % ast.dump(arg))
|
||||||
@ -323,8 +363,9 @@ def visit_Expr(self, node):
|
|||||||
root = ast.parse(source)
|
root = ast.parse(source)
|
||||||
const = ConstDirectives(pkg_name)
|
const = ConstDirectives(pkg_name)
|
||||||
|
|
||||||
|
print("PACKAGE:", pkg_name)
|
||||||
|
|
||||||
const.visit(root)
|
const.visit(root)
|
||||||
if not const.const:
|
if not const.const:
|
||||||
print("PACKAGE:", pkg_name)
|
|
||||||
for issue in const.issues:
|
for issue in const.issues:
|
||||||
print(" ", issue)
|
print(" ", issue)
|
||||||
|
Loading…
Reference in New Issue
Block a user