@@ -13,9 +13,11 @@ local util = require 'utility'
1313--- @field assignMap table<parser.object , true>
1414--- @field careMap table<parser.object , true>
1515--- @field mark table<parser.object , true>
16+ --- @field casts parser.object[]
1617--- @field nodes table<parser.object , vm.node | false>
1718--- @field main parser.object
1819--- @field uri uri
20+ --- @field castIndex integer ?
1921local mt = {}
2022mt .__index = mt
2123
@@ -79,25 +81,27 @@ function mt:collectLocal()
7981 self .assigns [# self .assigns + 1 ] = obj
8082 self .assignMap [obj ] = true
8183 self :collectCare (obj )
84+ if obj .finish > finishPos then
85+ finishPos = obj .finish
86+ end
8287 end
8388 if obj .type == ' getlocal' then
8489 self :collectCare (obj )
90+ if obj .finish > finishPos then
91+ finishPos = obj .finish
92+ end
8593 end
8694 end
8795
8896 local casts = self :getCasts ()
8997 for _ , cast in ipairs (casts ) do
9098 if cast .loc [1 ] == self .source [1 ]
91- and cast .start > startPos
99+ and cast .start > startPos
92100 and cast .finish < finishPos
93101 and guide .getLocal (self .source , self .source [1 ], cast .start ) == self .source then
94- self .assigns [# self .assigns + 1 ] = cast
102+ self .casts [# self .casts + 1 ] = cast
95103 end
96104 end
97-
98- table.sort (self .assigns , function (a , b )
99- return a .start < b .start
100- end )
101105end
102106
103107--- @param start integer
@@ -109,7 +113,7 @@ function mt:getLastAssign(start, finish)
109113 if obj .start < start then
110114 goto CONTINUE
111115 end
112- if obj .start >= finish then
116+ if ( obj .range or obj . start ) >= finish then
113117 break
114118 end
115119 local objBlock = guide .getParentBlock (obj )
@@ -125,6 +129,58 @@ function mt:getLastAssign(start, finish)
125129 return assign
126130end
127131
132+ --- @param pos integer
133+ function mt :resetCastsIndex (pos )
134+ for i = 1 , # self .casts do
135+ local cast = self .casts [i ]
136+ if cast .start > pos then
137+ self .castIndex = i
138+ return
139+ end
140+ end
141+ self .castIndex = nil
142+ end
143+
144+ --- @param pos integer
145+ --- @param node vm.node
146+ --- @return vm.node
147+ function mt :fastWardCasts (pos , node )
148+ if not self .castIndex then
149+ return node
150+ end
151+ for i = self .castIndex , # self .casts do
152+ local action = self .casts [i ]
153+ if action .start > pos then
154+ return node
155+ end
156+ node = node :copy ()
157+ for _ , cast in ipairs (action .casts ) do
158+ if cast .mode == ' +' then
159+ if cast .optional then
160+ node :addOptional ()
161+ end
162+ if cast .extends then
163+ node :merge (vm .compileNode (cast .extends ))
164+ end
165+ elseif cast .mode == ' -' then
166+ if cast .optional then
167+ node :removeOptional ()
168+ end
169+ if cast .extends then
170+ node :removeNode (vm .compileNode (cast .extends ))
171+ end
172+ else
173+ if cast .extends then
174+ node :clear ()
175+ node :merge (vm .compileNode (cast .extends ))
176+ end
177+ end
178+ end
179+ end
180+ self .castIndex = self .castIndex + 1
181+ return node
182+ end
183+
128184--- @param action parser.object
129185--- @param topNode vm.node
130186--- @param outNode ? vm.node
@@ -136,6 +192,7 @@ function mt:lookIntoChild(action, topNode, outNode)
136192 return topNode , outNode or topNode
137193 end
138194 self .mark [action ] = true
195+ topNode = self :fastWardCasts (action .start , topNode )
139196 if action .type == ' getlocal' then
140197 if action .node == self .source then
141198 self .nodes [action ] = topNode
@@ -306,13 +363,18 @@ function mt:lookIntoChild(action, topNode, outNode)
306363 or subBlock .hasBreak
307364 or subBlock .hasError
308365 if not neverReturn then
366+ local ok
309367 local lastAssign = self :getLastAssign (subBlock .start , subBlock .finish )
310368 if lastAssign then
311369 local node = self :getNode (lastAssign )
312370 if node then
313371 blockNodes [# blockNodes + 1 ] = node
372+ ok = true
314373 end
315374 end
375+ if not ok then
376+ blockNodes [# blockNodes + 1 ] = blockNode
377+ end
316378 end
317379 end
318380 if not hasElse and not topNode :hasKnownType () then
367429--- @param start integer
368430--- @param node vm.node
369431function mt :lookIntoBlock (block , start , node )
432+ self :resetCastsIndex (start )
370433 for _ , action in ipairs (block ) do
371434 if action .start < start then
372435 goto CONTINUE
@@ -436,6 +499,7 @@ local function createTracer(source)
436499 assignMap = {},
437500 careMap = {},
438501 mark = {},
502+ casts = {},
439503 nodes = {},
440504 main = main ,
441505 uri = guide .getUri (source ),
0 commit comments