1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
#
#
# The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# included from sem.nim
proc symChoice(c: PContext, n: PNode, s: PSym): PNode =
var
a: PSym
o: TOverloadIter
var i = 0
a = initOverloadIter(o, c, n)
while a != nil:
a = nextOverloadIter(o, c, n)
inc(i)
if i > 1: break
if i <= 1:
result = newSymNode(s)
result.info = n.info
markUsed(n, s)
else:
# semantic checking requires a type; ``fitNode`` deals with it
# appropriately
result = newNodeIT(nkSymChoice, n.info, newTypeS(tyNone, c))
a = initOverloadIter(o, c, n)
while a != nil:
incl(a.flags, sfUsed)
addSon(result, newSymNode(a))
a = nextOverloadIter(o, c, n)
proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
for i in 0 .. < n.len:
var a = n.sons[i]
# If 'a' is an overloaded symbol, we use the first symbol as a 'witness'
# and use the fact that subsequent lookups will yield the same symbol!
# This is currently the case due to the hash table's implementation...
let s = QualifiedLookUp(c, a)
if s != nil:
toBind.incl(s.id)
else:
illFormedAst(a)
result = newNodeI(nkEmpty, n.info)
proc resolveTemplateParams(c: PContext, n: PNode, owner: PSym,
toBind: var TIntSet): PNode =
var s: PSym
case n.kind
of nkIdent:
result = n
let s = QualifiedLookUp(c, n, {})
if s != nil:
if s.owner == owner and s.kind == skParam:
result = newSymNode(s)
result.info = n.info
elif Contains(toBind, s.id):
result = symChoice(c, n, s)
of nkEmpty, nkSym..nkNilLit: # atom
result = n
of nkBind:
result = resolveTemplateParams(c, n.sons[0], owner, toBind)
of nkBindStmt:
result = semBindStmt(c, n, toBind)
else:
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
# so we use the generic code for nkDotExpr too
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
let s = QualifiedLookUp(c, n, {})
if s != nil and Contains(toBind, s.id):
return symChoice(c, n, s)
result = n
for i in countup(0, sonsLen(n) - 1):
result.sons[i] = resolveTemplateParams(c, n.sons[i], owner, toBind)
proc transformToExpr(n: PNode): PNode =
var realStmt: int
result = n
case n.kind
of nkStmtList:
realStmt = - 1
for i in countup(0, sonsLen(n) - 1):
case n.sons[i].kind
of nkCommentStmt, nkEmpty, nkNilLit:
nil
else:
if realStmt == - 1: realStmt = i
else: realStmt = - 2
if realStmt >= 0: result = transformToExpr(n.sons[realStmt])
else: n.kind = nkStmtListExpr
of nkBlockStmt:
n.kind = nkBlockExpr
#nkIfStmt: n.kind := nkIfExpr; // this is not correct!
else:
nil
proc semTemplateDef(c: PContext, n: PNode): PNode =
var s: PSym
if c.p.owner.kind == skModule:
s = semIdentVis(c, skTemplate, n.sons[0], {sfExported})
incl(s.flags, sfGlobal)
else:
s = semIdentVis(c, skTemplate, n.sons[0], {})
# check parameter list:
pushOwner(s)
openScope(c.tab)
n.sons[namePos] = newSymNode(s)
if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, s, n.sons[pragmasPos], templatePragmas)
# check that no generic parameters exist:
if n.sons[genericParamsPos].kind != nkEmpty:
LocalError(n.info, errNoGenericParamsAllowedForX, "template")
if n.sons[paramsPos].kind == nkEmpty:
# use ``stmt`` as implicit result type
s.typ = newTypeS(tyProc, c)
s.typ.n = newNodeI(nkFormalParams, n.info)
rawAddSon(s.typ, newTypeS(tyStmt, c))
addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0]))
else:
semParamList(c, n.sons[ParamsPos], nil, s)
if n.sons[paramsPos].sons[0].kind == nkEmpty:
# use ``stmt`` as implicit result type
s.typ.sons[0] = newTypeS(tyStmt, c)
s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
var toBind = initIntSet()
n.sons[bodyPos] = resolveTemplateParams(c, n.sons[bodyPos], s, toBind)
if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}:
n.sons[bodyPos] = transformToExpr(n.sons[bodyPos])
# only parameters are resolved, no type checking is performed
closeScope(c.tab)
popOwner()
s.ast = n
result = n
if n.sons[bodyPos].kind == nkEmpty:
LocalError(n.info, errImplOfXexpected, s.name.s)
let curScope = c.tab.tos - 1
var proto = SearchForProc(c, s, curScope)
if proto == nil:
addInterfaceOverloadableSymAt(c, s, curScope)
else:
SymTabReplace(c.tab.stack[curScope], proto, s)
|