Skip to content

Commit 009e541

Browse files
committed
LINKER: partially restored
1 parent 8b558bb commit 009e541

File tree

2 files changed

+126
-72
lines changed

2 files changed

+126
-72
lines changed

chc/linker/CLinker.py

Lines changed: 75 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
# The MIT License (MIT)
66
#
77
# Copyright (c) 2017-2020 Kestrel Technology LLC
8+
# Copyright (c) 2020-2023 Henny B. Sipma
9+
# Copyright (c) 2024 Aarno Labs LLC
810
#
911
# Permission is hereby granted, free of charge, to any person obtaining a copy
1012
# of this software and associated documentation files (the "Software"), to deal
@@ -29,16 +31,27 @@
2931

3032
import xml.etree.ElementTree as ET
3133

34+
from typing import Dict, List, Tuple, TYPE_CHECKING
3235

33-
from chc.linker.CompCompatibility import CompCompatibility
34-
from chc.app.CCompInfo import CCompInfo
3536

36-
from chc.util.UnionFind import UnionFind
37+
38+
from chc.app.CCompInfo import CCompInfo
39+
from chc.app.IndexManager import FileKeyReference, FileVarReference
3740
from chc.app.CGlobalDictionary import CGlobalDictionary
3841

42+
from chc.linker.CompCompatibility import CompCompatibility
43+
3944
import chc.util.fileutil as UF
45+
from chc.util.loggingutil import chklogger
46+
from chc.util.UnionFind import UnionFind
4047
import chc.util.xmlutil as UX
4148

49+
if TYPE_CHECKING:
50+
from chc.app.CApplication import CApplication
51+
from chc.app.CFile import CFile
52+
from chc.app.CGlobalDeclarations import CGlobalDeclarations
53+
from chc.app.IndexManager import IndexManager
54+
4255
"""
4356
Starting point: a list of (fileindex,compinfo key) pairs that identify the
4457
locally declared structs
@@ -54,46 +67,78 @@
5467
"""
5568

5669

57-
class CLinker(object):
58-
def __init__(self, capp):
59-
self.capp = capp # CApplication
60-
self.declarations = self.capp.declarations
70+
class CLinker:
71+
def __init__(self, capp: "CApplication") -> None:
72+
self._capp = capp
73+
self._compinfos: List["CCompInfo"] = []
74+
self._compinfoxrefs: Dict[Tuple[int, int], int] = {}
75+
self._varinfoxrefs: Dict[Tuple[int, int], int] = {}
76+
77+
@property
78+
def capp(self) -> "CApplication":
79+
return self._capp
80+
81+
@property
82+
def indexmanager(self) -> "IndexManager":
83+
return self.capp.indexmanager
84+
85+
@property
86+
def declarations(self) -> "CGlobalDeclarations":
87+
return self.capp.declarations
88+
89+
@property
90+
def compinfos(self) -> List["CCompInfo"]:
91+
return self._compinfos
6192

62-
def get_file_compinfo_xrefs(self, fileindex):
63-
result = {}
93+
@property
94+
def compinfoxrefs(self) -> Dict[Tuple[int, int], int]:
95+
return self._compinfoxrefs
96+
97+
@property
98+
def varinfoxrefs(self) -> Dict[Tuple[int, int], int]:
99+
return self._varinfoxrefs
100+
101+
def get_file_compinfo_xrefs(self, fileindex: int) -> Dict[int, int]:
102+
result: Dict[int, int] = {}
64103
for (fidx, ckey) in self.compinfoxrefs:
65104
if fidx == fileindex:
66105
result[ckey] = self.compinfoxrefs[(fidx, ckey)]
67106
return result
68107

69-
def get_file_varinfo_xrefs(self, fileindex):
70-
result = {}
108+
def get_file_varinfo_xrefs(self, fileindex: int) -> Dict[int, int]:
109+
result: Dict[int, int] = {}
71110
for (fidx, vid) in self.varinfoxrefs:
72111
if fidx == fileindex:
73112
result[vid] = self.varinfoxrefs[(fidx, vid)]
74113
return result
75114

115+
"""
76116
def get_global_compinfos(self):
77117
return self.compinfoinstances
78118
79119
def get_shared_instances(self):
80120
return self.sharedinstances
121+
"""
81122

82-
def link_compinfos(self):
83-
def f(cfile):
84-
print("Linking " + cfile.name)
85-
compinfos = cfile.declarations.get_compinfos()
123+
def link_compinfos(self) -> None:
124+
125+
chklogger.logger.info("Link compinfos")
126+
127+
# index and connect the compinfos from the individual files
128+
for cfile in self.capp.cfiles:
129+
compinfos = cfile.get_compinfos()
86130
self.declarations.index_file_compinfos(cfile.index, compinfos)
87131

88-
self.capp.iter_files(f)
132+
# register the relationships found with the index manager
89133
ckey2gckey = self.declarations.ckey2gckey
90134
for fid in ckey2gckey:
91135
for ckey in ckey2gckey[fid]:
92136
gckey = ckey2gckey[fid][ckey]
93-
self.capp.indexmanager.add_ckey2gckey(fid, ckey, gckey)
137+
filekey = FileKeyReference(fid, ckey)
138+
self.capp.indexmanager.add_ckey2gckey(filekey, gckey)
94139

95140
"""
96-
def linkcompinfos(self):
141+
def linkcompinfos(self) -> None:
97142
self._checkcompinfopairs()
98143
99144
print('Found ' + str(len(self.possiblycompatiblestructs)) +
@@ -144,10 +189,11 @@ def linkcompinfos(self):
144189
else:
145190
filename = self.capp.getfilebyindex(id[0]).getfilename()
146191
self.sharedinstances[gckey].append((filename,c))
192+
147193
"""
148194

149-
def link_varinfos(self):
150-
def f(cfile):
195+
def link_varinfos(self) -> None:
196+
def f(cfile: "CFile") -> None:
151197
varinfos = cfile.declarations.get_global_varinfos()
152198
self.declarations.index_file_varinfos(cfile.index, varinfos)
153199

@@ -157,39 +203,22 @@ def f(cfile):
157203
for fid in vid2gvid:
158204
for vid in vid2gvid[fid]:
159205
gvid = vid2gvid[fid][vid]
160-
self.capp.indexmanager.add_vid2gvid(fid, vid, gvid)
161-
162-
"""
163-
def linkvarinfos(self):
164-
globalvarinfos = {}
165-
for vinfo in self.varinfos:
166-
name = vinfo.getname()
167-
if vinfo.getstorage() == 'static':
168-
fileindex = vinfo.getfile().getindex()
169-
name = name + '__file__' + str(fileindex) + '__'
170-
if not name in globalvarinfos: globalvarinfos[name] = []
171-
globalvarinfos[name].append(vinfo)
172-
173-
gvid = 1
174-
for name in sorted(globalvarinfos):
175-
for vinfo in globalvarinfos[name]:
176-
id = vinfo.getid()
177-
self.varinfoxrefs[id] = gvid
178-
self.capp.indexmanager.addvid2gvid(id[0],id[1],gvid)
179-
gvid += 1
180-
"""
206+
filevar = FileVarReference(fid, vid)
207+
self.indexmanager.add_vid2gvid(filevar, gvid)
181208

182-
def save_global_compinfos(self):
183-
path = self.capp.path
209+
def save_global_compinfos(self) -> None:
210+
path = self.capp.targetpath
184211
xroot = UX.get_xml_header("globals", "globals")
185212
xnode = ET.Element("globals")
186213
xroot.append(xnode)
187214
self.declarations.write_xml(xnode)
188-
filename = UF.get_global_definitions_filename(path)
215+
filename = UF.get_global_definitions_filename(path, self.capp.projectname)
216+
chklogger.logger.info("Saving global compinfos to %s", filename)
189217
with open(filename, "w") as fp:
190218
fp.write(UX.doc_to_pretty(ET.ElementTree(xroot)))
191219

192-
def _checkcompinfopairs(self):
220+
"""
221+
def _checkcompinfopairs(self) -> None:
193222
self.possiblycompatiblestructs = []
194223
compinfos = sorted(self.compinfos, key=lambda c: c.getid())
195224
print(
@@ -209,3 +238,4 @@ def _checkcompinfopairs(self):
209238
self.possiblycompatiblestructs.append(pair)
210239
else:
211240
self.notcompatiblestructs.add(pair)
241+
"""

chc/linker/CompCompatibility.py

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
# ------------------------------------------------------------------------------
55
# The MIT License (MIT)
66
#
7-
# Copyright (c) 2017 Kestrel Technology LLC
7+
# Copyright (c) 2017-2019 Kestrel Technology LLC
8+
# Copyright (c) 2020-2024 Henny B. Sipma
9+
# Copyright (c) 2024 Aarno Labs LLC
810
#
911
# Permission is hereby granted, free of charge, to any person obtaining a copy
1012
# of this software and associated documentation files (the "Software"), to deal
@@ -25,53 +27,75 @@
2527
# SOFTWARE.
2628
# ------------------------------------------------------------------------------
2729

30+
from typing import Iterator, List, Set, Tuple, TYPE_CHECKING
2831

29-
class CompCompatibility(object):
32+
if TYPE_CHECKING:
33+
from chc.app.CCompInfo import CCompInfo
34+
from chc.app.CFieldInfo import CFieldInfo
35+
36+
37+
class CompCompatibility:
3038
"""Determines compatibility between two structs."""
3139

32-
def __init__(self, comp1, comp2):
33-
self.comp1 = comp1 # CCompInfo
34-
self.comp2 = comp2 # CCompInfo
40+
def __init__(self, comp1: "CCompInfo", comp2: "CCompInfo") -> None:
41+
self._comp1 = comp1
42+
self._comp2 = comp2
43+
44+
@property
45+
def comp1(self) -> "CCompInfo":
46+
return self._comp1
47+
48+
@property
49+
def comp2(self) -> "CCompInfo":
50+
return self._comp2
3551

36-
"""Return true if they have the same fields (but not necessarily compatible field types)"""
52+
def are_structurally_compatible(self) -> bool:
53+
"""Returns true if comp1 and comp2 have the same fields.
3754
38-
def are_structurally_compatible(self):
39-
if self.comp1.getfieldcount() == self.comp2.getfieldcount():
40-
return set(self.comp1.getfieldnames()) == set(self.comp2.getfieldnames())
55+
Note: The field types are not necessarily compatible.
56+
"""
57+
if self.comp1.fieldcount == self.comp2.fieldcount:
58+
return set(self.comp1.fieldnames) == set(self.comp2.fieldnames)
4159
return False
4260

43-
"""Return true if they are structurally compatible and if the types of their fields
44-
are structurally compatible, taking into account a list of pairs of struct tags
45-
that are explicitly declared incompatible."""
61+
def are_shallow_compatible(
62+
self, incompatibles: Set[Tuple[str, str]] = set([])) -> bool:
63+
"""Returns true if comp1 and comp2 are structurally compatible.
4664
47-
def are_shallow_compatible(self, incompatibles=set([])):
65+
Note: This means the the types of comp1 and comp2 are structurally
66+
compatible taking into account a list of pairs of struct tags that
67+
are explicitly declared incompatible.
68+
"""
4869
if self.are_structurally_compatible():
4970
return self._forall_shallowcompatiblefieldtype(incompatibles)
5071
return False
5172

52-
def __str__(self):
53-
if self.comp1.getid() == self.comp2.getid():
73+
def __str__(self) -> str:
74+
if self.comp1.index == self.comp2.index:
5475
return "identical"
5576
if self.are_shallow_compatible():
5677
return "shallow compatible (without incompatibles declared)"
5778
if self.are_structurally_compatible():
5879
return self._find_incompatiblefieldtype()
5980
return "not structurally compatible"
6081

61-
def _find_incompatiblefieldtype(self):
62-
fieldpairs = zip(sorted(self.comp1.getfields()), sorted(self.comp2.getfields()))
63-
for ((_, finfo1), (_, finfo2)) in fieldpairs:
64-
t1 = finfo1.gettype()
65-
t2 = finfo2.gettype()
66-
if not t1.shallowcompatible(t2):
82+
def _find_incompatiblefieldtype(self) -> str:
83+
fieldpairs: Iterator[Tuple["CFieldInfo", "CFieldInfo"]] = zip(
84+
self.comp1.fields, self.comp2.fields)
85+
for (finfo1, finfo2) in fieldpairs:
86+
t1 = finfo1.ftype
87+
t2 = finfo2.ftype
88+
if not t1.equal(t2):
6789
return "t1: " + str(t1) + "\nt2: " + str(t2)
6890
return "no incompatible fields found"
6991

70-
def _forall_shallowcompatiblefieldtype(self, incompatibles=set([])):
71-
fieldpairs = zip(sorted(self.comp1.getfields()), sorted(self.comp2.getfields()))
72-
for ((_, finfo1), (_, finfo2)) in fieldpairs:
73-
t1 = finfo1.gettype().expand()
74-
t2 = finfo2.gettype().expand()
75-
if not t1.shallowcompatible(t2, incompatibles):
92+
def _forall_shallowcompatiblefieldtype(
93+
self, incompatibles: Set[Tuple[str, str]] = set([])) -> bool:
94+
fieldpairs: Iterator[Tuple["CFieldInfo", "CFieldInfo"]] = zip(
95+
self.comp1.fields, self.comp2.fields)
96+
for (finfo1, finfo2) in fieldpairs:
97+
t1 = finfo1.ftype.expand()
98+
t2 = finfo2.ftype.expand()
99+
if not t1.equal(t2):
76100
return False
77101
return True

0 commit comments

Comments
 (0)