32
32
indegree, touched: int
33
33
indegreeFacts: Facts
34
34
Context = object
35
- cf, dest: TokenBuf
35
+ cf, dest, toplevelStmts: TokenBuf
36
+ routines: seq [Cursor ]
36
37
typeCache: TypeCache
37
38
facts: Facts
38
39
writesTo: seq [SymId ]
@@ -123,9 +124,11 @@ proc compileCmp(c: var Context; paramMap: Table[SymId, int]; req, call: Cursor):
123
124
b = mapSymbol (c, paramMap, call, r.symId)
124
125
inc r
125
126
elif r.kind == IntLit :
127
+ b = VarId (0 )
126
128
cnst = createXint (pool.integers[r.intId])
127
129
inc r
128
130
elif r.kind == UIntLit :
131
+ b = VarId (0 )
129
132
cnst = createXint (pool.uintegers[r.uintId])
130
133
inc r
131
134
elif (let op = r.exprKind; op in {AddX , SubX }):
@@ -300,10 +303,12 @@ proc rightHandSide(c: var Context; pc: var Cursor; fact: var LeXplusC): bool =
300
303
result = true
301
304
inc pc
302
305
elif pc.kind == IntLit :
306
+ fact.b = VarId (0 )
303
307
fact.c = fact.c + createXint (pool.integers[pc.intId])
304
308
result = true
305
309
inc pc
306
310
elif pc.kind == UIntLit :
311
+ fact.b = VarId (0 )
307
312
fact.c = fact.c + createXint (pool.uintegers[pc.uintId])
308
313
result = true
309
314
inc pc
@@ -537,7 +542,7 @@ proc decAndTest(x: var int): bool {.inline.} =
537
542
result = x == 0
538
543
539
544
proc takeFacts (c: var Context ; bb: var BasicBlock ; conditionalFacts: int ; negate: bool ) =
540
- let start = bb.indegreeFacts.len
545
+ # let start = bb.indegreeFacts.len
541
546
if bb.touched == 0 :
542
547
for i in 1 ..< c.facts.len - conditionalFacts:
543
548
bb.indegreeFacts.add c.facts[i]
@@ -557,10 +562,20 @@ proc pushFacts(c: var Context; bb: var BasicBlock) =
557
562
for i in 0 ..< bb.indegreeFacts.len:
558
563
c.facts.add bb.indegreeFacts[i]
559
564
560
- proc checkContracts (c: var Context ) =
561
- var bbs = computeBasicBlocks (c.cf)
565
+ proc checkContracts (c: var Context ; n: Cursor ) =
566
+ c.cf = toControlflow (n)
567
+ c.facts = createFacts ()
568
+ freeze c.cf
569
+ # echo "CF IS ", codeListing(c.cf)
570
+
562
571
c.startInstr = readonlyCursorAt (c.cf, 0 )
563
- var current = BasicBlockIdx (0 )
572
+ var body = c.startInstr
573
+ if body.stmtKind in {ProcS , FuncS , IteratorS , ConverterS , MethodS , MacroS }:
574
+ inc body
575
+ for i in 0 ..< BodyPos : skip body
576
+
577
+ var current = BasicBlockIdx (cursorToPosition (c.cf, body))
578
+ var bbs = computeBasicBlocks (c.cf, current.int )
564
579
var nextIter = true
565
580
var candidates = newSeq [BasicBlockIdx ]()
566
581
while nextIter or candidates.len > 0 :
@@ -588,17 +603,68 @@ proc checkContracts(c: var Context) =
588
603
else :
589
604
candidates.add cont.elsePart
590
605
606
+ proc traverseProc (c: var Context ; n: var Cursor ) =
607
+ let orig = n
608
+ let r = takeRoutine (n, SkipExclBody )
609
+ skip n # effects
610
+ if not isGeneric (r):
611
+ c.routines.add orig
612
+ var nested = 0
613
+ while true :
614
+ # don't forget about inner procs:
615
+ let sk = n.stmtKind
616
+ if sk in {ProcS , FuncS , IteratorS , ConverterS , MethodS }:
617
+ traverseProc (c, n)
618
+ elif sk in {MacroS , TemplateS , TypeS , CommentS , PragmasS }:
619
+ skip n
620
+ elif n.kind == ParLe :
621
+ inc nested
622
+ inc n
623
+ elif n.kind == ParRi :
624
+ dec nested
625
+ inc n
626
+ if nested == 0 : break
627
+ else :
628
+ inc n
629
+ skipParRi n
630
+ else :
631
+ skip n # body
632
+ skipParRi n
633
+
634
+ proc traverseToplevel (c: var Context ; n: var Cursor ) =
635
+ case n.stmtKind
636
+ of StmtsS :
637
+ c.toplevelStmts.add n
638
+ inc n
639
+ while n.kind != ParRi :
640
+ traverseToplevel (c, n)
641
+ c.toplevelStmts.add n
642
+ skipParRi n
643
+ of ProcS , FuncS , IteratorS , ConverterS , MethodS :
644
+ traverseProc (c, n)
645
+ of MacroS , TemplateS , TypeS , CommentS , PragmasS ,
646
+ ImportasS , ExportexceptS , BindS , MixinS , UsingS ,
647
+ ExportS ,
648
+ IncludeS , ImportS , FromimportS , ImportExceptS :
649
+ skip n
650
+ of IfS , WhenS , WhileS , ForS , CaseS , TryS , YldS , RaiseS ,
651
+ UnpackDeclS , StaticstmtS , AsmS , DeferS ,
652
+ CallS , CmdS , GvarS , TvarS , VarS , ConstS , ResultS ,
653
+ GletS , TletS , LetS , CursorS , BlockS , EmitS , AsgnS , ScopeS ,
654
+ BreakS , ContinueS , RetS , InclS , ExclS , DiscardS , AssumeS , AssertS , NoStmt :
655
+ c.toplevelStmts.takeTree n
656
+
591
657
proc analyzeContracts * (input: var TokenBuf ): TokenBuf =
592
658
let oldInfos = prepare (input)
593
659
var c = Context (typeCache: createTypeCache (),
594
- dest: createTokenBuf (500 ),
595
- cf: toControlflow (beginRead input),
596
- facts: createFacts ())
597
- freeze c.cf
598
- # echo "CF IS ", codeListing(c.cf)
660
+ dest: createTokenBuf (500 ))
599
661
c.typeCache.openScope ()
600
-
601
- checkContracts (c)
662
+ var n = beginRead (input)
663
+ traverseToplevel c, n
664
+ for r in c.routines:
665
+ checkContracts (c, r)
666
+ var nt = beginRead c.toplevelStmts
667
+ checkContracts (c, nt)
602
668
603
669
endRead input
604
670
restore (input, oldInfos)
0 commit comments