17
17
# * introduces method dispatchers
18
18
# * performs lambda lifting for closure support
19
19
# * transforms 'defer' into a 'try finally' statement
20
+ # * generates default field values for objects and transforms object contructors
20
21
21
22
import
22
23
options, ast, astalgo, trees, msgs,
44
45
module: PSym
45
46
transCon: PTransCon # top of a TransCon stack
46
47
inlining: int # > 0 if we are in inlining context (copy vars)
47
- nestedProcs: int # > 0 if we are in a nested proc
48
+ genResult: bool # XXX
48
49
contSyms, breakSyms: seq [PSym ] # to transform 'continue' and 'break'
49
50
deferDetected, tooEarly: bool
50
51
graph: ModuleGraph
@@ -383,7 +384,7 @@ proc transformYield(c: PTransf, n: PNode): PNode =
383
384
let rhs = transform (c, e)
384
385
result .add (asgnTo (lhs, rhs))
385
386
386
- inc ( c.transCon.yieldStmts)
387
+ inc c.transCon.yieldStmts
387
388
if c.transCon.yieldStmts <= 1 :
388
389
# common case
389
390
result .add (c.transCon.forLoopBody)
@@ -658,7 +659,7 @@ proc transformFor(c: PTransf, n: PNode): PNode =
658
659
659
660
let body = transformBody (c.graph, iter, true )
660
661
pushInfoContext (c.graph.config, n.info)
661
- inc ( c.inlining)
662
+ inc c.inlining
662
663
stmtList.add (transform (c, body))
663
664
# findWrongOwners(c, stmtList.pnode)
664
665
dec (c.inlining)
@@ -743,13 +744,13 @@ proc transformCall(c: PTransf, n: PNode): PNode =
743
744
var j = 1
744
745
while j < n.len:
745
746
var a = transform (c, n[j])
746
- inc (j)
747
+ inc j
747
748
if isConstExpr (a):
748
749
while (j < n.len):
749
750
let b = transform (c, n[j])
750
751
if not isConstExpr (b): break
751
752
a = evalOp (op.magic, n, a, b, nil , c.graph)
752
- inc (j)
753
+ inc j
753
754
result .add (a)
754
755
if result .len == 2 : result = result [1 ]
755
756
elif magic == mAddr:
@@ -828,13 +829,13 @@ proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
828
829
var j = 0
829
830
while j < args.len:
830
831
var a = args[j]
831
- inc (j)
832
+ inc j
832
833
if isConstExpr (a):
833
834
while j < args.len:
834
835
let b = args[j]
835
836
if not isConstExpr (b): break
836
837
a = evalOp (op.magic, result , a, b, nil , g)
837
- inc (j)
838
+ inc j
838
839
result .add (a)
839
840
if result .len == 2 : result = result [1 ]
840
841
else :
@@ -882,6 +883,47 @@ proc hoistParamsUsedInDefault(c: PTransf, call, letSection, defExpr: PNode): PNo
882
883
let hoisted = hoistParamsUsedInDefault (c, call, letSection, defExpr[i])
883
884
if hoisted != nil : defExpr[i] = hoisted
884
885
886
+ import nimsets
887
+ proc caseBranchMatchesExpr (branch, matched: PNode ): bool =
888
+ for i in 0 ..< branch.len- 1 :
889
+ if branch[i].kind == nkRange:
890
+ if overlap (branch[i], matched): return true
891
+ elif exprStructuralEquivalent (branch[i], matched):
892
+ return true
893
+
894
+ proc pickCaseBranch (caseExpr, matched: PNode ): int =
895
+ let endsWithElse = caseExpr[^ 1 ].kind == nkElse
896
+ for i in 1 ..< caseExpr.len - endsWithElse.int :
897
+ if caseExpr[i].caseBranchMatchesExpr (matched):
898
+ return i
899
+ if endsWithElse:
900
+ return caseExpr.len - 1
901
+
902
+ proc defaultFieldsForTheUninitialized (c: PTransf , recNode: PNode ): seq [PNode ] =
903
+ case recNode.kind
904
+ of nkRecList:
905
+ for field in recNode:
906
+ result .add defaultFieldsForTheUninitialized (c, field)
907
+ of nkRecCase:
908
+ let discriminator = recNode[0 ]
909
+ var selectedBranch: int
910
+ let defaultValue = discriminator.sym.ast
911
+ if defaultValue == nil :
912
+ # None of the branches were explicitly selected by the user and no value
913
+ # was given to the discrimator. We can assume that it will be initialized
914
+ # to zero and this will select a particular branch as a result:
915
+ selectedBranch = recNode.pickCaseBranch newIntNode (nkIntLit#[ c.graph]# , 0 )
916
+ else : # Try to use default value
917
+ selectedBranch = recNode.pickCaseBranch defaultValue
918
+ result .add newTree (nkExprColonExpr, discriminator, defaultValue)
919
+ result .add defaultFieldsForTheUninitialized (c, recNode[selectedBranch][^ 1 ])
920
+ of nkSym:
921
+ let field = recNode.sym
922
+ if field.ast != nil : # Try to use default value
923
+ result .add newTree (nkExprColonExpr, recNode, field.ast)
924
+ else :
925
+ assert false
926
+
885
927
proc transform (c: PTransf , n: PNode ): PNode =
886
928
when false :
887
929
var oldDeferAnchor: PNode
@@ -890,6 +932,18 @@ proc transform(c: PTransf, n: PNode): PNode =
890
932
nkBlockStmt, nkBlockExpr}:
891
933
oldDeferAnchor = c.deferAnchor
892
934
c.deferAnchor = n
935
+ if c.genResult:
936
+ c.genResult = false
937
+ result = newNodeIT (nkStmtList, n.info, nil )
938
+ let toInit = c.getCurrOwner ().ast[resultPos]
939
+ if toInit.typ != nil and toInit.typ.kind == tyObject:
940
+ var asgnExpr = newTree (nkObjConstr, newNodeIT (nkType, toInit.info, toInit.typ))
941
+ asgnExpr.typ = toInit.typ
942
+ # TODO : Once the VM is ready this should be done in injectdestructors so that it can be elided properly
943
+ asgnExpr.sons.add defaultFieldsForTheUninitialized (c, toInit.typ.n)
944
+ result .add transform (c, newTree (nkAsgn, toInit, asgnExpr))
945
+ result .add transform (c, n)
946
+ return result
893
947
case n.kind
894
948
of nkSym:
895
949
result = transformSym (c, n)
@@ -947,17 +1001,26 @@ proc transform(c: PTransf, n: PNode): PNode =
947
1001
result .add (newSymNode (labl))
948
1002
of nkBreakStmt: result = transformBreak (c, n)
949
1003
of nkCallKinds:
950
- result = transformCall (c, n)
951
- var call = result
952
- if nfDefaultRefsParam in call.flags:
953
- # We've found a default value that references another param.
954
- # See the notes in `hoistParamsUsedInDefault` for more details.
955
- var hoistedParams = newNodeI (nkLetSection, call.info, 0 )
956
- for i in 1 ..< call.len:
957
- let hoisted = hoistParamsUsedInDefault (c, call, hoistedParams, call[i])
958
- if hoisted != nil : call[i] = hoisted
959
- result = newTree (nkStmtListExpr, hoistedParams, call)
960
- result .typ = call.typ
1004
+ # if (n[0].kind == nkSym) and (n[0].sym.magic == mReset) and (n[1].typ.kind == tyObject):
1005
+ # result = newNodeIT(nkStmtList, n.info, n.typ)
1006
+ # result.add transformCall(c, n)
1007
+ # result.add initDefaultFields(n[1], n[1].typ.n)
1008
+ # elif (n[0].kind == nkSym) and (n[0].sym.magic in {mNew, mNewFinalize}) and (n[1].typ.kind == tyRef):
1009
+ # result = newNodeIT(nkStmtListExpr, n.info, n.typ)
1010
+ # result.add transformCall(c, n)
1011
+ # result.add initDefaultFields(n[1], n[1].typ[0].n)
1012
+ # else:
1013
+ result = transformCall (c, n)
1014
+ var call = result
1015
+ if nfDefaultRefsParam in call.flags:
1016
+ # We've found a default value that references another param.
1017
+ # See the notes in `hoistParamsUsedInDefault` for more details.
1018
+ var hoistedParams = newNodeI (nkLetSection, call.info, 0 )
1019
+ for i in 1 ..< call.len:
1020
+ let hoisted = hoistParamsUsedInDefault (c, call, hoistedParams, call[i])
1021
+ if hoisted != nil : call[i] = hoisted
1022
+ result = newTree (nkStmtListExpr, hoistedParams, call)
1023
+ result .typ = call.typ
961
1024
of nkAddr, nkHiddenAddr:
962
1025
result = transformAddrDeref (c, n, nkDerefExpr, nkHiddenDeref)
963
1026
of nkDerefExpr, nkHiddenDeref:
@@ -1013,6 +1076,13 @@ proc transform(c: PTransf, n: PNode): PNode =
1013
1076
return n
1014
1077
of nkExceptBranch:
1015
1078
result = transformExceptBranch (c, n)
1079
+ of nkObjConstr:
1080
+ result = n
1081
+ if result .typ.skipTypes (abstractInst).kind == tyObject or
1082
+ result .typ.skipTypes (abstractInst).kind == tyRef and result .typ.skipTypes (abstractInst)[0 ].kind == tyObject:
1083
+ result .sons.add result [0 ].sons
1084
+ result [0 ] = newNodeIT (nkType, result .info, result .typ)
1085
+ result = transformSons (c, result )
1016
1086
else :
1017
1087
result = transformSons (c, n)
1018
1088
when false :
@@ -1034,6 +1104,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
1034
1104
# nodes into an empty node.
1035
1105
if nfTransf in n.flags: return n
1036
1106
pushTransCon (c, newTransCon (owner))
1107
+ c.genResult = c.getCurrOwner ().kind in routineKinds and c.transCon.owner.ast.len > resultPos and c.transCon.owner.ast[resultPos] != nil
1037
1108
result = transform (c, n)
1038
1109
popTransCon (c)
1039
1110
incl (result .flags, nfTransf)
0 commit comments