@@ -58,26 +58,61 @@ proc sem(graph: ModuleGraph; path: AbsoluteFile): PNode =
5858
5959const SysTypeKinds = {tyBool, tyChar, tyString, tyInt .. tyUInt64}
6060
61+ type
62+ # Nim's AST has cycles that causes infinite recursive loop in eql procs.
63+ # this is used to prevent that happen.
64+ EqlContext = object
65+ nodeStack: seq [PNode ]
66+ # symStack: seq[PSym]
67+ typStack: seq [PType ]
68+
6169# Compare PType, PSym and PNode but ignores fields nifencoder and nifdecoder doesn't support
6270# Assumes `x` is generated by sem.nim and `y` is decoded by icnif/nifdecoder.
6371# So `eql(x, y) == eql(y, x)` is not always true.
64- proc eql (x, y: PType ): bool =
72+ proc eql (x, y: PNode ; c: var EqlContext ): bool
73+
74+ proc eql (x, y: PType ; c: var EqlContext ): bool =
6575 if x == nil and y == nil :
6676 result = true
6777 elif x == nil or y == nil :
78+ echo " type is missing"
6879 result = false
69- elif x.kind == y.kind:
70- result = true
71- else :
80+ elif x.kind != y.kind:
7281 echo " type kind mismatch: " , x.kind, " /" , y.kind
7382 result = false
83+ elif x.flags != y.flags:
84+ echo " flag mismatch: " , x.flags, " /" , y.flags
85+ result = false
86+ else :
87+ if c.typStack.len != 0 :
88+ for i in countDown (c.typStack.len - 1 , 0 ):
89+ if x == c.typStack[i]:
90+ # echo "cycle is detected in PType"
91+ return true
92+ c.typStack.add x
93+ if not eql (x.n, y.n, c):
94+ echo " type.n mismatch"
95+ result = false
96+ elif x.kidsLen != y.kidsLen:
97+ echo " type kidsLen mismatch"
98+ result = false
99+ else :
100+ result = true
101+ for i in 0 ..< x.kidsLen:
102+ if not eql (x[i], y[i], c):
103+ echo " type kids mismatch: "
104+ debug (x[i])
105+ debug (y[i])
106+ result = false
107+ break
108+ discard c.typStack.pop
74109
75- proc eql (x, y: PSym ): bool =
110+ proc eql (x, y: PSym ; c: var EqlContext ): bool =
76111 if x == nil and y == nil :
77112 result = true
78113 elif x == nil or y == nil :
79114 result = false
80- elif x.kind == y.kind and eql (x.typ, y.typ) and x.name.s == y.name.s:
115+ elif x.kind == y.kind and eql (x.typ, y.typ, c ) and x.name.s == y.name.s:
81116 if (x.itemId.item == y.itemId.item and x.disamb == y.disamb and x.flags == y.flags) or (x.kind == skType and x.typ.kind in SysTypeKinds ):
82117 if x.owner == nil and y.owner == nil :
83118 result = true
@@ -100,15 +135,21 @@ proc eql(x, y: PSym): bool =
100135 else :
101136 result = false
102137
103- proc eql (x, y: PNode ): bool =
138+ proc eql (x, y: PNode ; c: var EqlContext ): bool =
104139 if x == nil and y == nil :
105140 result = true
106141 elif x == nil or y == nil :
107142 result = false
108143 elif x.kind == y.kind and x.safeLen == y.safeLen and x.flags == y.flags:
144+ if c.nodeStack.len != 0 :
145+ for i in countDown (c.nodeStack.len - 1 , 0 ):
146+ if x == c.nodeStack[i]:
147+ # echo "cycle is detected in PNode"
148+ return true
149+ c.nodeStack.add x
109150 case x.kind:
110151 of nkSym:
111- result = eql (x.sym, y.sym)
152+ result = eql (x.sym, y.sym, c )
112153 if not result :
113154 echo " Symbol mismatch:"
114155 debug (x.sym)
@@ -119,22 +160,23 @@ proc eql(x, y: PNode): bool =
119160 result = sameValue (x, y)
120161 of nkIdentDefs:
121162 assert x.len == 3 and y.len == 3
122- if eql (x[0 ], y[0 ]) and eql (x[2 ], y[2 ]):
163+ if eql (x[0 ], y[0 ], c ) and eql (x[2 ], y[2 ], c ):
123164 result = y[1 ].kind == nkEmpty and y[0 ].sym.typ != nil
124165 else :
125166 result = false
126167 of nkTypeDef:
127168 assert x.len == 3 and y.len == 3
128- if eql (x[0 ], y[0 ]) and eql (x[1 ], y[1 ]):
169+ if eql (x[0 ], y[0 ], c ) and eql (x[1 ], y[1 ], c ):
129170 result = y[2 ].kind == nkEmpty and y[0 ].sym.typ != nil
130171 else :
131172 result = false
132173 else :
133174 result = true
134175 for i in 0 ..< x.safeLen:
135- if not eql (x[i], y[i]):
176+ if not eql (x[i], y[i], c ):
136177 result = false
137178 break
179+ discard c.nodeStack.pop
138180 else :
139181 result = false
140182
@@ -143,13 +185,15 @@ proc testNifEncDec(graph: ModuleGraph; src: string) =
143185 let n = sem (graph, fullPath)
144186 let nif = saveNifToBuffer (n, graph.config)
145187 # debug(n)
188+ # debug(n[0][0][0].typ)
146189 # echo nif
147190
148191 # Don't reuse the ModuleGraph used for semcheck when load NIF.
149192 var graphForLoad = newModuleGraph (newIdentCache (), newConfigRefForTest ())
150193 let n2 = loadNifFromBuffer (nif, fullPath, graphForLoad)
151194 # debug(n2)
152- assert eql (n, n2)
195+ var c = EqlContext ()
196+ assert eql (n, n2, c)
153197
154198var conf = newConfigRefForTest ()
155199var cache = newIdentCache ()
0 commit comments