Skip to content

Commit 90cf68b

Browse files
committed
start detecting cycles
1 parent 4ce7d94 commit 90cf68b

File tree

2 files changed

+63
-41
lines changed

2 files changed

+63
-41
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
/win32json
2+
/out-*
3+
.mypy_cache/

go

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,14 @@
1010
import os
1111
import sys
1212
import json
13-
from typing import List, Set, Dict
14-
15-
#def apiRefTypeName(type_obj):
16-
# return ".".join(type_obj["Parents"] + [type_obj["Name"]])
13+
from typing import List, Set, Dict, Optional
1714

1815
def getApiRefTopLevelType(type_obj):
1916
parents = type_obj["Parents"]
2017
if parents:
2118
return parents[0]
2219
return type_obj["Name"]
2320

24-
#def apiRefName(type_obj):
25-
# return type_obj["Api"] + ":" + apiRefTypeName(type_obj)
26-
2721
class DefaultDict(dict):
2822
def __init__(self, factory):
2923
self.factory = factory
@@ -40,10 +34,14 @@ class ApiRef:
4034
return self.combined.__eq__(other.combined)
4135
def __hash__(self):
4236
return self.combined.__hash__()
37+
def __str__(self):
38+
return self.combined
39+
def __repr__(self):
40+
return self.combined
4341
class ApiTypeNameToApiRefMap:
4442
def __init__(self):
45-
self.top_level: dict[str,Set[ApiRef]] = {}
46-
self.nested: dict[str,Set[ApiRef]] = {}
43+
self.top_level: Dict[str,Set[ApiRef]] = {}
44+
self.nested: Dict[str,Set[ApiRef]] = {}
4745

4846
def getJsonApiRefs(api_refs: Set[ApiRef], json_obj):
4947
if isinstance(json_obj, dict):
@@ -85,7 +83,7 @@ def main():
8583
apis = [getApiName(basename) for basename in os.listdir(api_dir)]
8684
apis.sort()
8785

88-
api_direct_type_refs_table: dict[str,ApiTypeNameToApiRefMap] = {}
86+
api_direct_type_refs_table: Dict[str,ApiTypeNameToApiRefMap] = {}
8987
print("loading types...")
9088
for api_name in apis:
9189
#print(api_name)
@@ -174,28 +172,68 @@ def main():
174172
sys.exit("!!!!!!!!!!! {} not in {} (and {} not in {})".format(ref.name, api, nested_name, api))
175173
# TODO: should we save this nested name? not sure that we need to
176174

177-
178175
print("types verified")
179176

180-
print("creating deps.dot...")
181-
with open(os.path.join(script_dir, "deps.dot"), "w") as file:
182-
file.write("digraph deps {\n")
177+
print("calculating recursive type references...")
178+
api_recursive_type_refs_table: Dict[str,dict[str,Set[ApiRef]]] = {}
179+
with open(os.path.join(script_dir, "out-recursive-deps.txt"), "w") as file:
183180
for api in apis:
181+
#print("calculating recursive deps on {}...".format(api))
184182
direct_type_refs_table = api_direct_type_refs_table[api]
183+
recursive_type_refs_table = {}
185184
for type_name,refs in direct_type_refs_table.top_level.items():
186-
for ref in refs:
187-
table = api_direct_type_refs_table[ref.api]
188-
if not isAnonType(ref.name) and ref.name in table.top_level:
189-
file.write("\"{}\" -> \"{}\";\n".format(type_name, ref.name))
190-
file.write("}\n")
185+
recursive_chains: List[List[ApiRef]] = []
186+
getRecursiveChains(api_direct_type_refs_table, set(), refs, recursive_chains, None)
187+
file.write("{}:{} -> {}\n".format(api, type_name, recursive_chains))
188+
recursive_type_refs_table[type_name] = recursive_chains
189+
api_recursive_type_refs_table[api] = recursive_type_refs_table
190+
print("done calculating recursive type references")
191+
192+
print("searching for cycles...")
193+
with open(os.path.join(script_dir, "out-cycles.txt"), "w") as file:
194+
for api in apis:
195+
#print("API: {}".format(api))
196+
table = api_recursive_type_refs_table[api]
197+
cycle_count = 0
198+
for type_name, recursive_chains in table.items():
199+
type_api_ref = ApiRef(api, type_name)
200+
for chain in recursive_chains:
201+
state = 0
202+
for ref in chain:
203+
if ref.api == api:
204+
if state == 1:
205+
state = 2
206+
break
207+
else:
208+
if state == 0:
209+
state = 1
210+
if state == 2:
211+
file.write("{}:{} CHAIN={}\n".format(api, type_name, chain))
212+
cycle_count += 1
213+
else:
214+
pass
215+
#print("NOT CYCLIC: {}:{} CHAIN={}".format(api, type_name, chain))
216+
if cycle_count > 0:
217+
print("{} cycles: {}:{}".format(cycle_count, api, type_name))
191218

192219
print("done")
193-
#for api in apis:
194-
#for api in [apis[0]]:
195-
# print("calculating recursive deps on {}...".format(api))
196-
# TODO: calculate recursive dependencies
197220

198221

222+
def getRecursiveChains(api_direct_type_refs_table: Dict[str,ApiTypeNameToApiRefMap], handled: Set[ApiRef], refs: Set[ApiRef], result: List[List[ApiRef]], current_chain: Optional[List[ApiRef]]) -> None:
223+
for ref in refs:
224+
ref_api_table = api_direct_type_refs_table[ref.api]
225+
if not isAnonType(ref.name) and ref.name in ref_api_table.top_level:
226+
#file.write("\"{}\" -> \"{}\";\n".format(type_name, ref.name))
227+
next_chain = current_chain
228+
if not next_chain:
229+
next_chain = []
230+
result.append(next_chain)
231+
next_chain.append(ref)
232+
233+
ref_refs = ref_api_table.top_level[ref.name]
234+
if not ref in handled:
235+
handled.add(ref)
236+
getRecursiveChains(api_direct_type_refs_table, handled, ref_refs, result, next_chain)
199237

200238
def getNestedName(type_name: str, ref: ApiRef) -> str:
201239
type_names = type_name.split(".")
@@ -207,23 +245,5 @@ def getNestedName(type_name: str, ref: ApiRef) -> str:
207245
i += 1
208246
return ".".join(type_names + ref_names[i:])
209247

210-
# recursive_dep_table: dict[str,Set[str]] = {}
211-
# for api in apis:
212-
# recursive_deps: Set[str] = set()
213-
# getRecursiveDeps(api_direct_deps, api, recursive_deps)
214-
# #print("{}: {}".format(api, recursive_deps))
215-
# recursive_dep_table[api] = recursive_deps
216-
# for api in apis:
217-
# recursive_deps = recursive_dep_table[api]
218-
# print("{}: {}".format(api, recursive_deps))
219-
# if api in recursive_deps:
220-
# print("{} is CYCLIC!!!!".format(api))
221-
#
222-
#def getRecursiveDeps(direct_dep_table: Set[Set[str]], name: str, result: Set[str]) -> None:
223-
# for direct_dep in direct_dep_table[name]:
224-
# if not direct_dep in result:
225-
# result.add(direct_dep)
226-
# getRecursiveDeps(direct_dep_table, direct_dep, result)
227-
#
228248

229249
main()

0 commit comments

Comments
 (0)