Skip to content

Commit d413b08

Browse files
committed
Prepare for SSTub computation
1 parent ee48e14 commit d413b08

3 files changed

Lines changed: 117 additions & 6 deletions

File tree

code_diff/__init__.py

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
1-
from .ast import parse_ast
1+
from code_tokenize.config import load_from_lang_config
2+
from code_tokenize.tokens import match_type
3+
4+
from .ast import parse_ast
5+
from .utils import cached_property
6+
from .sstubs import SStubPattern, classify_sstub
27

38

49
# Main method --------------------------------------------------------
510

611
def difference(source, target, lang = "guess", **kwargs):
712

13+
config = load_from_lang_config(lang, **kwargs)
814
source_ast = parse_ast(source, lang = lang, **kwargs)
915
target_ast = parse_ast(target, lang = lang, **kwargs)
1016

1117
# Concretize Diff
1218
source_ast, target_ast = diff_search(source_ast, target_ast)
1319

14-
return ASTDiff(source_ast, target_ast)
20+
return ASTDiff(config, source_ast, target_ast)
1521

1622

1723
# Diff Search --------------------------------------------------------
@@ -40,12 +46,92 @@ def diff_search(source_ast, target_ast):
4046
return (source_node, target_node)
4147

4248

43-
44-
4549
# AST Difference --------------------------------------------------------
4650

4751
class ASTDiff:
4852

49-
def __init__(self, source_ast, target_ast):
53+
def __init__(self, config, source_ast, target_ast):
54+
self.config = config
5055
self.source_ast = source_ast
51-
self.target_ast = target_ast
56+
self.target_ast = target_ast
57+
58+
@cached_property
59+
def is_single_statement(self):
60+
return (is_single_statement(self.config.statement_types, self.source_ast)
61+
and is_single_statement(self.config.statement_types, self.target_ast))
62+
63+
@cached_property
64+
def source_text(self):
65+
return tokenize_tree(self.source_ast)
66+
67+
@cached_property
68+
def target_text(self):
69+
return tokenize_tree(self.target_ast)
70+
71+
def statement_diff(self):
72+
source_stmt = parent_statement(self.config.statement_types, self.source_ast)
73+
target_stmt = parent_statement(self.config.statement_types, self.target_ast)
74+
75+
if source_stmt is None or target_stmt is None:
76+
raise ValueError("AST diff is not enclosed in a statement")
77+
78+
return ASTDiff(self.config, source_stmt, target_stmt)
79+
80+
def sstub_pattern(self):
81+
if not self.is_single_statement:
82+
return SStubPattern.MULTI_STMT
83+
84+
return classify_sstub(*diff_search(self.source_ast, self.target_ast))
85+
86+
def edit_script(self):
87+
pass
88+
89+
def __repr__(self):
90+
return "%s -> %s" % (self.source_text, self.target_text)
91+
92+
93+
94+
95+
# AST Utils -----------------------------------------------------------
96+
97+
def is_single_statement(statement_types, ast):
98+
99+
if parent_statement(statement_types, ast) is None: return False
100+
101+
def is_statement_type(node_type):
102+
return any(match_type(r, node_type) for r in statement_types)
103+
104+
# Test if any other statement as child
105+
queue = list(ast.children)
106+
while len(queue) > 0:
107+
node = queue.pop(0)
108+
if is_statement_type(node.type): return False
109+
110+
queue.extend(node.children)
111+
112+
return True
113+
114+
115+
def parent_statement(statement_types, ast):
116+
117+
def is_statement_type(node_type):
118+
return any(match_type(r, node_type) for r in statement_types)
119+
120+
# Test if node in statement
121+
parent_node = ast
122+
while parent_node is not None and not is_statement_type(parent_node.type):
123+
parent_node = parent_node.parent
124+
125+
return parent_node
126+
127+
128+
def tokenize_tree(ast):
129+
tokens = []
130+
131+
# Test if any other statement as child
132+
if ast.text: tokens.append(ast.text)
133+
134+
for child in ast.children:
135+
tokens.append(tokenize_tree(child))
136+
137+
return " ".join(tokens)

code_diff/sstubs.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from enum import Enum
2+
3+
class SStubPattern(Enum):
4+
5+
MULTI_STMT = 0
6+
SINGLE_STMT = 1
7+
8+
9+
# SStub classification -------------------------------
10+
11+
def classify_sstub(source_ast, target_ast):
12+
pass

code_diff/utils.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
def cached_property(fnc):
3+
name = fnc.__name__
4+
5+
def load_from_cache(self):
6+
if not hasattr(self, "_cache"): self._cache = {}
7+
8+
if name not in self._cache:
9+
self._cache[name] = fnc(self)
10+
11+
return self._cache[name]
12+
13+
return property(load_from_cache)

0 commit comments

Comments
 (0)