Repository navigation
Expand file tree
/
Copy pathsource_question_syntax.py
More file actions
117 lines (99 loc) · 3.63 KB
/
Copy pathsource_question_syntax.py
File metadata and controls
117 lines (99 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
"""Source-only field/guard extraction reused from method_interface_view.
Origin SHA256: c3d3096fabb1e769b7ad82baadf7d10aec3a5d81ea60a4ca51992434d8eff4e9
No receiver dispatch,ownership or runtime-value inference.
"""
import ast
from infinicoder.memory.source.source_dependency_view import location
FUNCTIONS = (ast.FunctionDef, ast.AsyncFunctionDef)
def _walk(node):
"""Stay within this function's scope; closures are separate receivers."""
yield node
for child in ast.iter_child_nodes(node):
if isinstance(child, (*FUNCTIONS, ast.ClassDef, ast.Lambda)):
continue
yield from _walk(child)
def _parents(tree):
return {
child: (node, field)
for node in ast.walk(tree)
for field, value in ast.iter_fields(node)
for child in (value if isinstance(value, list) else [value])
if isinstance(child, ast.AST)
}
def _source(file, node):
return "".join(file["source"].splitlines(keepends=True)[node.lineno - 1 : node.end_lineno])
def _conditions(file, node, parents, function):
result = []
while node in parents and node is not function:
parent, branch = parents[node]
if isinstance(
parent,
(
ast.If,
ast.For,
ast.AsyncFor,
ast.While,
ast.With,
ast.AsyncWith,
ast.Try,
ast.ExceptHandler,
ast.Match,
),
):
# The original header plus branch name is retained. In particular,
# an orelse location must not be mistaken for the positive branch.
body = getattr(parent, "body", [])
end = max(parent.lineno, body[0].lineno - 1) if body else parent.lineno
result.append(
location(
file,
parent.lineno,
end,
"guard",
source="".join(
file["source"].splitlines(keepends=True)[parent.lineno - 1 : end]
),
branch=branch,
certainty="enclosing_syntax;execution_and_early_exit_unknown",
)
)
if isinstance(parent, ast.match_case):
result.append(
location(
file,
parent.pattern.lineno,
parent.pattern.end_lineno,
"guard",
source=_source(file, parent.pattern),
branch=branch,
guard=ast.unparse(parent.guard) if parent.guard else None,
certainty="case_syntax;execution_unknown",
)
)
node = parent
return list(reversed(result))
def _receiver(function):
args = [*function.args.posonlyargs, *function.args.args]
return args[0].arg if args else None
def _fields(node, receiver, context=None):
return {
n.attr
for n in _walk(node)
if isinstance(n, ast.Attribute)
and isinstance(n.value, ast.Name)
and n.value.id == receiver
and (context is None or isinstance(n.ctx, context))
}
def _statement(node, parents, function):
while not isinstance(node, ast.stmt) and node in parents:
node = parents[node][0]
return node if isinstance(node, ast.stmt) and node is not function else None
def _piece(file, node, parents, function):
return location(
file,
node.lineno,
node.end_lineno,
"statement",
source=_source(file, node),
conditions=_conditions(file, node, parents, function),
)