semtempl.nim 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # included from sem.nim
  10. discard """
  11. hygienic templates:
  12. template `||` (a, b: untyped): untyped =
  13. let aa = a
  14. if aa: aa else: b
  15. var
  16. a, b: T
  17. echo a || b || a
  18. Each evaluation context has to be different and we need to perform
  19. some form of preliminary symbol lookup in template definitions. Hygiene is
  20. a way to achieve lexical scoping at compile time.
  21. """
  22. type
  23. TSymBinding = enum
  24. spNone, spGenSym, spInject
  25. proc symBinding(n: PNode): TSymBinding =
  26. for i in countup(0, sonsLen(n) - 1):
  27. var it = n.sons[i]
  28. var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
  29. if key.kind == nkIdent:
  30. case whichKeyword(key.ident)
  31. of wGensym: return spGenSym
  32. of wInject: return spInject
  33. else: discard
  34. type
  35. TSymChoiceRule = enum
  36. scClosed, scOpen, scForceOpen
  37. proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
  38. var
  39. a: PSym
  40. o: TOverloadIter
  41. var i = 0
  42. a = initOverloadIter(o, c, n)
  43. while a != nil:
  44. if a.kind != skModule:
  45. inc(i)
  46. if i > 1: break
  47. a = nextOverloadIter(o, c, n)
  48. if i <= 1 and r != scForceOpen:
  49. # XXX this makes more sense but breaks bootstrapping for now:
  50. # (s.kind notin routineKinds or s.magic != mNone):
  51. # for instance 'nextTry' is both in tables.nim and astalgo.nim ...
  52. result = newSymNode(s, n.info)
  53. markUsed(n.info, s, c.graph.usageSym)
  54. else:
  55. # semantic checking requires a type; ``fitNode`` deals with it
  56. # appropriately
  57. let kind = if r == scClosed or n.kind == nkDotExpr: nkClosedSymChoice
  58. else: nkOpenSymChoice
  59. result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
  60. a = initOverloadIter(o, c, n)
  61. while a != nil:
  62. if a.kind != skModule:
  63. incl(a.flags, sfUsed)
  64. addSon(result, newSymNode(a, n.info))
  65. a = nextOverloadIter(o, c, n)
  66. proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
  67. for i in 0 .. < n.len:
  68. var a = n.sons[i]
  69. # If 'a' is an overloaded symbol, we used to use the first symbol
  70. # as a 'witness' and use the fact that subsequent lookups will yield
  71. # the same symbol!
  72. # This is however not true anymore for hygienic templates as semantic
  73. # processing for them changes the symbol table...
  74. let s = qualifiedLookUp(c, a, {checkUndeclared})
  75. if s != nil:
  76. # we need to mark all symbols:
  77. let sc = symChoice(c, n, s, scClosed)
  78. if sc.kind == nkSym:
  79. toBind.incl(sc.sym.id)
  80. else:
  81. for x in items(sc): toBind.incl(x.sym.id)
  82. else:
  83. illFormedAst(a)
  84. result = newNodeI(nkEmpty, n.info)
  85. proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
  86. for i in 0 .. < n.len:
  87. toMixin.incl(considerQuotedIdent(n.sons[i]).id)
  88. result = newNodeI(nkEmpty, n.info)
  89. proc replaceIdentBySym(n: var PNode, s: PNode) =
  90. case n.kind
  91. of nkPostfix: replaceIdentBySym(n.sons[1], s)
  92. of nkPragmaExpr: replaceIdentBySym(n.sons[0], s)
  93. of nkIdent, nkAccQuoted, nkSym: n = s
  94. else: illFormedAst(n)
  95. type
  96. TemplCtx = object
  97. c: PContext
  98. toBind, toMixin, toInject: IntSet
  99. owner: PSym
  100. cursorInBody: bool # only for nimsuggest
  101. scopeN: int
  102. bracketExpr: PNode
  103. template withBracketExpr(ctx, x, body: untyped) =
  104. let old = ctx.bracketExpr
  105. ctx.bracketExpr = x
  106. body
  107. ctx.bracketExpr = old
  108. proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
  109. case n.kind
  110. of nkPostfix: result = getIdentNode(c, n.sons[1])
  111. of nkPragmaExpr: result = getIdentNode(c, n.sons[0])
  112. of nkIdent:
  113. result = n
  114. let s = qualifiedLookUp(c.c, n, {})
  115. if s != nil:
  116. if s.owner == c.owner and s.kind == skParam:
  117. result = newSymNode(s, n.info)
  118. of nkAccQuoted, nkSym: result = n
  119. else:
  120. illFormedAst(n)
  121. result = n
  122. proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
  123. result = n.kind == nkSym and n.sym.kind == skParam and
  124. n.sym.owner == c.owner and sfGenSym notin n.sym.flags
  125. proc semTemplBody(c: var TemplCtx, n: PNode): PNode
  126. proc openScope(c: var TemplCtx) =
  127. openScope(c.c)
  128. proc closeScope(c: var TemplCtx) =
  129. closeScope(c.c)
  130. proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
  131. openScope(c)
  132. result = semTemplBody(c, n)
  133. closeScope(c)
  134. proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
  135. result = n
  136. if n.kind == nkIdent:
  137. let s = qualifiedLookUp(c.c, n, {})
  138. if s != nil:
  139. if s.owner == c.owner and s.kind == skParam:
  140. incl(s.flags, sfUsed)
  141. result = newSymNode(s, n.info)
  142. styleCheckUse(n.info, s)
  143. else:
  144. for i in 0 .. <n.safeLen:
  145. result.sons[i] = onlyReplaceParams(c, n.sons[i])
  146. proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
  147. result = newSym(kind, considerQuotedIdent(n), c.owner, n.info)
  148. incl(result.flags, sfGenSym)
  149. incl(result.flags, sfShadowed)
  150. proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
  151. # locals default to 'gensym':
  152. if n.kind == nkPragmaExpr and symBinding(n.sons[1]) == spInject:
  153. # even if injected, don't produce a sym choice here:
  154. #n = semTemplBody(c, n)
  155. var x = n[0]
  156. while true:
  157. case x.kind
  158. of nkPostfix: x = x[1]
  159. of nkPragmaExpr: x = x[0]
  160. of nkIdent: break
  161. of nkAccQuoted:
  162. # consider: type `T TemplParam` {.inject.}
  163. # it suffices to return to treat it like 'inject':
  164. n = onlyReplaceParams(c, n)
  165. return
  166. else:
  167. illFormedAst(x)
  168. let ident = getIdentNode(c, x)
  169. if not isTemplParam(c, ident):
  170. c.toInject.incl(x.ident.id)
  171. else:
  172. replaceIdentBySym(n, ident)
  173. else:
  174. let ident = getIdentNode(c, n)
  175. if not isTemplParam(c, ident):
  176. # fix #2670, consider:
  177. #
  178. # when b:
  179. # var a = "hi"
  180. # else:
  181. # var a = 5
  182. # echo a
  183. #
  184. # We need to ensure that both 'a' produce the same gensym'ed symbol.
  185. # So we need only check the *current* scope.
  186. let s = localSearchInScope(c.c, considerQuotedIdent ident)
  187. if s != nil and s.owner == c.owner and sfGenSym in s.flags:
  188. styleCheckUse(n.info, s)
  189. replaceIdentBySym(n, newSymNode(s, n.info))
  190. else:
  191. let local = newGenSym(k, ident, c)
  192. addPrelimDecl(c.c, local)
  193. styleCheckDef(n.info, local)
  194. replaceIdentBySym(n, newSymNode(local, n.info))
  195. else:
  196. replaceIdentBySym(n, ident)
  197. proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
  198. incl(s.flags, sfUsed)
  199. # we do not call styleCheckUse here, as the identifier is not really
  200. # resolved here. We will fixup the used identifiers later.
  201. case s.kind
  202. of skUnknown:
  203. # Introduced in this pass! Leave it as an identifier.
  204. result = n
  205. of OverloadableSyms:
  206. result = symChoice(c, n, s, scOpen)
  207. of skGenericParam:
  208. result = newSymNodeTypeDesc(s, n.info)
  209. of skParam:
  210. result = n
  211. of skType:
  212. result = newSymNodeTypeDesc(s, n.info)
  213. else:
  214. result = newSymNode(s, n.info)
  215. proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
  216. result = n
  217. if n.kind == nkIdent:
  218. let s = qualifiedLookUp(c.c, n, {})
  219. if s != nil:
  220. if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
  221. incl(s.flags, sfUsed)
  222. result = newSymNode(s, n.info)
  223. styleCheckUse(n.info, s)
  224. else:
  225. for i in countup(0, safeLen(n) - 1):
  226. result.sons[i] = semRoutineInTemplName(c, n.sons[i])
  227. proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
  228. result = n
  229. checkSonsLen(n, bodyPos + 1)
  230. # routines default to 'inject':
  231. if n.kind notin nkLambdaKinds and symBinding(n.sons[pragmasPos]) == spGenSym:
  232. let ident = getIdentNode(c, n.sons[namePos])
  233. if not isTemplParam(c, ident):
  234. var s = newGenSym(k, ident, c)
  235. s.ast = n
  236. addPrelimDecl(c.c, s)
  237. styleCheckDef(n.info, s)
  238. n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
  239. else:
  240. n.sons[namePos] = ident
  241. else:
  242. n.sons[namePos] = semRoutineInTemplName(c, n.sons[namePos])
  243. # open scope for parameters
  244. openScope(c)
  245. for i in patternPos..miscPos:
  246. n.sons[i] = semTemplBody(c, n.sons[i])
  247. # open scope for locals
  248. inc c.scopeN
  249. openScope(c)
  250. n.sons[bodyPos] = semTemplBody(c, n.sons[bodyPos])
  251. # close scope for locals
  252. closeScope(c)
  253. dec c.scopeN
  254. # close scope for parameters
  255. closeScope(c)
  256. proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) =
  257. for i in countup(start, sonsLen(n) - 1):
  258. var a = n.sons[i]
  259. if a.kind == nkCommentStmt: continue
  260. if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
  261. checkMinSonsLen(a, 3)
  262. var L = sonsLen(a)
  263. when defined(nimsuggest):
  264. inc c.c.inTypeContext
  265. a.sons[L-2] = semTemplBody(c, a.sons[L-2])
  266. when defined(nimsuggest):
  267. dec c.c.inTypeContext
  268. a.sons[L-1] = semTemplBody(c, a.sons[L-1])
  269. for j in countup(0, L-3):
  270. addLocalDecl(c, a.sons[j], symKind)
  271. proc semPattern(c: PContext, n: PNode): PNode
  272. proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode =
  273. result = n
  274. for i in 0.. < n.len:
  275. result.sons[i] = semTemplBody(c, n.sons[i])
  276. proc oprIsRoof(n: PNode): bool =
  277. const roof = "^"
  278. case n.kind
  279. of nkIdent: result = n.ident.s == roof
  280. of nkSym: result = n.sym.name.s == roof
  281. of nkAccQuoted:
  282. if n.len == 1:
  283. result = oprIsRoof(n.sons[0])
  284. of nkOpenSymChoice, nkClosedSymChoice:
  285. result = oprIsRoof(n.sons[0])
  286. else: discard
  287. proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
  288. result = n
  289. semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
  290. case n.kind
  291. of nkIdent:
  292. if n.ident.id in c.toInject: return n
  293. let s = qualifiedLookUp(c.c, n, {})
  294. if s != nil:
  295. if s.owner == c.owner and s.kind == skParam:
  296. incl(s.flags, sfUsed)
  297. result = newSymNode(s, n.info)
  298. styleCheckUse(n.info, s)
  299. elif contains(c.toBind, s.id):
  300. result = symChoice(c.c, n, s, scClosed)
  301. elif contains(c.toMixin, s.name.id):
  302. result = symChoice(c.c, n, s, scForceOpen)
  303. elif s.owner == c.owner and sfGenSym in s.flags:
  304. # template tmp[T](x: var seq[T]) =
  305. # var yz: T
  306. incl(s.flags, sfUsed)
  307. result = newSymNode(s, n.info)
  308. styleCheckUse(n.info, s)
  309. else:
  310. result = semTemplSymbol(c.c, n, s)
  311. of nkBind:
  312. result = semTemplBody(c, n.sons[0])
  313. of nkBindStmt:
  314. result = semBindStmt(c.c, n, c.toBind)
  315. of nkMixinStmt:
  316. if c.scopeN > 0: result = semTemplBodySons(c, n)
  317. else: result = semMixinStmt(c.c, n, c.toMixin)
  318. of nkEmpty, nkSym..nkNilLit:
  319. discard
  320. of nkIfStmt:
  321. for i in countup(0, sonsLen(n)-1):
  322. var it = n.sons[i]
  323. if it.len == 2:
  324. when newScopeForIf: openScope(c)
  325. it.sons[0] = semTemplBody(c, it.sons[0])
  326. when not newScopeForIf: openScope(c)
  327. it.sons[1] = semTemplBody(c, it.sons[1])
  328. closeScope(c)
  329. else:
  330. n.sons[i] = semTemplBodyScope(c, it)
  331. of nkWhileStmt:
  332. openScope(c)
  333. for i in countup(0, sonsLen(n)-1):
  334. n.sons[i] = semTemplBody(c, n.sons[i])
  335. closeScope(c)
  336. of nkCaseStmt:
  337. openScope(c)
  338. n.sons[0] = semTemplBody(c, n.sons[0])
  339. for i in countup(1, sonsLen(n)-1):
  340. var a = n.sons[i]
  341. checkMinSonsLen(a, 1)
  342. var L = sonsLen(a)
  343. for j in countup(0, L-2):
  344. a.sons[j] = semTemplBody(c, a.sons[j])
  345. a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1])
  346. closeScope(c)
  347. of nkForStmt, nkParForStmt:
  348. var L = sonsLen(n)
  349. openScope(c)
  350. n.sons[L-2] = semTemplBody(c, n.sons[L-2])
  351. for i in countup(0, L - 3):
  352. addLocalDecl(c, n.sons[i], skForVar)
  353. n.sons[L-1] = semTemplBody(c, n.sons[L-1])
  354. closeScope(c)
  355. of nkBlockStmt, nkBlockExpr, nkBlockType:
  356. checkSonsLen(n, 2)
  357. openScope(c)
  358. if n.sons[0].kind != nkEmpty:
  359. addLocalDecl(c, n.sons[0], skLabel)
  360. when false:
  361. # labels are always 'gensym'ed:
  362. let s = newGenSym(skLabel, n.sons[0], c)
  363. addPrelimDecl(c.c, s)
  364. styleCheckDef(s)
  365. n.sons[0] = newSymNode(s, n.sons[0].info)
  366. n.sons[1] = semTemplBody(c, n.sons[1])
  367. closeScope(c)
  368. of nkTryStmt:
  369. checkMinSonsLen(n, 2)
  370. n.sons[0] = semTemplBodyScope(c, n.sons[0])
  371. for i in countup(1, sonsLen(n)-1):
  372. var a = n.sons[i]
  373. checkMinSonsLen(a, 1)
  374. var L = sonsLen(a)
  375. openScope(c)
  376. for j in countup(0, L-2):
  377. if a.sons[j].isInfixAs():
  378. addLocalDecl(c, a.sons[j].sons[2], skLet)
  379. a.sons[j].sons[1] = semTemplBody(c, a.sons[j][1])
  380. else:
  381. a.sons[j] = semTemplBody(c, a.sons[j])
  382. a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1])
  383. closeScope(c)
  384. of nkVarSection: semTemplSomeDecl(c, n, skVar)
  385. of nkLetSection: semTemplSomeDecl(c, n, skLet)
  386. of nkFormalParams:
  387. checkMinSonsLen(n, 1)
  388. n.sons[0] = semTemplBody(c, n.sons[0])
  389. semTemplSomeDecl(c, n, skParam, 1)
  390. of nkConstSection:
  391. for i in countup(0, sonsLen(n) - 1):
  392. var a = n.sons[i]
  393. if a.kind == nkCommentStmt: continue
  394. if (a.kind != nkConstDef): illFormedAst(a)
  395. checkSonsLen(a, 3)
  396. addLocalDecl(c, a.sons[0], skConst)
  397. a.sons[1] = semTemplBody(c, a.sons[1])
  398. a.sons[2] = semTemplBody(c, a.sons[2])
  399. of nkTypeSection:
  400. for i in countup(0, sonsLen(n) - 1):
  401. var a = n.sons[i]
  402. if a.kind == nkCommentStmt: continue
  403. if (a.kind != nkTypeDef): illFormedAst(a)
  404. checkSonsLen(a, 3)
  405. addLocalDecl(c, a.sons[0], skType)
  406. for i in countup(0, sonsLen(n) - 1):
  407. var a = n.sons[i]
  408. if a.kind == nkCommentStmt: continue
  409. if (a.kind != nkTypeDef): illFormedAst(a)
  410. checkSonsLen(a, 3)
  411. if a.sons[1].kind != nkEmpty:
  412. openScope(c)
  413. a.sons[1] = semTemplBody(c, a.sons[1])
  414. a.sons[2] = semTemplBody(c, a.sons[2])
  415. closeScope(c)
  416. else:
  417. a.sons[2] = semTemplBody(c, a.sons[2])
  418. of nkProcDef, nkLambdaKinds:
  419. result = semRoutineInTemplBody(c, n, skProc)
  420. of nkFuncDef:
  421. result = semRoutineInTemplBody(c, n, skFunc)
  422. of nkMethodDef:
  423. result = semRoutineInTemplBody(c, n, skMethod)
  424. of nkIteratorDef:
  425. result = semRoutineInTemplBody(c, n, skIterator)
  426. of nkTemplateDef:
  427. result = semRoutineInTemplBody(c, n, skTemplate)
  428. of nkMacroDef:
  429. result = semRoutineInTemplBody(c, n, skMacro)
  430. of nkConverterDef:
  431. result = semRoutineInTemplBody(c, n, skConverter)
  432. of nkPragmaExpr:
  433. result.sons[0] = semTemplBody(c, n.sons[0])
  434. of nkPostfix:
  435. result.sons[1] = semTemplBody(c, n.sons[1])
  436. of nkPragma:
  437. for x in n:
  438. if x.kind == nkExprColonExpr:
  439. x.sons[1] = semTemplBody(c, x.sons[1])
  440. of nkBracketExpr:
  441. result = newNodeI(nkCall, n.info)
  442. result.add newIdentNode(getIdent("[]"), n.info)
  443. for i in 0 ..< n.len: result.add(n[i])
  444. let n0 = semTemplBody(c, n.sons[0])
  445. withBracketExpr c, n0:
  446. result = semTemplBodySons(c, result)
  447. of nkCurlyExpr:
  448. result = newNodeI(nkCall, n.info)
  449. result.add newIdentNode(getIdent("{}"), n.info)
  450. for i in 0 ..< n.len: result.add(n[i])
  451. result = semTemplBodySons(c, result)
  452. of nkAsgn, nkFastAsgn:
  453. checkSonsLen(n, 2)
  454. let a = n.sons[0]
  455. let b = n.sons[1]
  456. let k = a.kind
  457. case k
  458. of nkBracketExpr:
  459. result = newNodeI(nkCall, n.info)
  460. result.add newIdentNode(getIdent("[]="), n.info)
  461. for i in 0 ..< a.len: result.add(a[i])
  462. result.add(b)
  463. let a0 = semTemplBody(c, a.sons[0])
  464. withBracketExpr c, a0:
  465. result = semTemplBodySons(c, result)
  466. of nkCurlyExpr:
  467. result = newNodeI(nkCall, n.info)
  468. result.add newIdentNode(getIdent("{}="), n.info)
  469. for i in 0 ..< a.len: result.add(a[i])
  470. result.add(b)
  471. result = semTemplBodySons(c, result)
  472. else:
  473. result = semTemplBodySons(c, n)
  474. of nkCallKinds-{nkPostfix}:
  475. result = semTemplBodySons(c, n)
  476. if c.bracketExpr != nil and n.len == 2 and oprIsRoof(n.sons[0]):
  477. result.add c.bracketExpr
  478. of nkDotExpr, nkAccQuoted:
  479. # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
  480. # so we use the generic code for nkDotExpr too
  481. let s = qualifiedLookUp(c.c, n, {})
  482. if s != nil:
  483. # do not symchoice a quoted template parameter (bug #2390):
  484. if s.owner == c.owner and s.kind == skParam and
  485. n.kind == nkAccQuoted and n.len == 1:
  486. incl(s.flags, sfUsed)
  487. styleCheckUse(n.info, s)
  488. return newSymNode(s, n.info)
  489. elif contains(c.toBind, s.id):
  490. return symChoice(c.c, n, s, scClosed)
  491. elif contains(c.toMixin, s.name.id):
  492. return symChoice(c.c, n, s, scForceOpen)
  493. else:
  494. return symChoice(c.c, n, s, scOpen)
  495. result = semTemplBodySons(c, n)
  496. else:
  497. result = semTemplBodySons(c, n)
  498. proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
  499. result = n
  500. semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
  501. case n.kind
  502. of nkIdent:
  503. let s = qualifiedLookUp(c.c, n, {})
  504. if s != nil:
  505. if s.owner == c.owner and s.kind == skParam:
  506. result = newSymNode(s, n.info)
  507. elif contains(c.toBind, s.id):
  508. result = symChoice(c.c, n, s, scClosed)
  509. of nkBind:
  510. result = semTemplBodyDirty(c, n.sons[0])
  511. of nkBindStmt:
  512. result = semBindStmt(c.c, n, c.toBind)
  513. of nkEmpty, nkSym..nkNilLit:
  514. discard
  515. else:
  516. # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
  517. # so we use the generic code for nkDotExpr too
  518. if n.kind == nkDotExpr or n.kind == nkAccQuoted:
  519. let s = qualifiedLookUp(c.c, n, {})
  520. if s != nil and contains(c.toBind, s.id):
  521. return symChoice(c.c, n, s, scClosed)
  522. result = n
  523. for i in countup(0, sonsLen(n) - 1):
  524. result.sons[i] = semTemplBodyDirty(c, n.sons[i])
  525. proc semTemplateDef(c: PContext, n: PNode): PNode =
  526. var s: PSym
  527. if isTopLevel(c):
  528. s = semIdentVis(c, skTemplate, n.sons[0], {sfExported})
  529. incl(s.flags, sfGlobal)
  530. else:
  531. s = semIdentVis(c, skTemplate, n.sons[0], {})
  532. styleCheckDef(s)
  533. # check parameter list:
  534. #s.scope = c.currentScope
  535. pushOwner(c, s)
  536. openScope(c)
  537. n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
  538. if n.sons[pragmasPos].kind != nkEmpty:
  539. pragma(c, s, n.sons[pragmasPos], templatePragmas)
  540. var gp: PNode
  541. if n.sons[genericParamsPos].kind != nkEmpty:
  542. n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
  543. gp = n.sons[genericParamsPos]
  544. else:
  545. gp = newNodeI(nkGenericParams, n.info)
  546. # process parameters:
  547. var allUntyped = true
  548. if n.sons[paramsPos].kind != nkEmpty:
  549. semParamList(c, n.sons[paramsPos], gp, s)
  550. # a template's parameters are not gensym'ed even if that was originally the
  551. # case as we determine whether it's a template parameter in the template
  552. # body by the absence of the sfGenSym flag:
  553. for i in 1 .. s.typ.n.len-1:
  554. let param = s.typ.n.sons[i].sym
  555. param.flags.excl sfGenSym
  556. if param.typ.kind != tyExpr: allUntyped = false
  557. if sonsLen(gp) > 0:
  558. if n.sons[genericParamsPos].kind == nkEmpty:
  559. # we have a list of implicit type parameters:
  560. n.sons[genericParamsPos] = gp
  561. # no explicit return type? -> use tyStmt
  562. if n.sons[paramsPos].sons[0].kind == nkEmpty:
  563. # use ``stmt`` as implicit result type
  564. s.typ.sons[0] = newTypeS(tyStmt, c)
  565. s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
  566. else:
  567. s.typ = newTypeS(tyProc, c)
  568. # XXX why do we need tyStmt as a return type again?
  569. s.typ.n = newNodeI(nkFormalParams, n.info)
  570. rawAddSon(s.typ, newTypeS(tyStmt, c))
  571. addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0]))
  572. if allUntyped: incl(s.flags, sfAllUntyped)
  573. if n.sons[patternPos].kind != nkEmpty:
  574. n.sons[patternPos] = semPattern(c, n.sons[patternPos])
  575. var ctx: TemplCtx
  576. ctx.toBind = initIntSet()
  577. ctx.toMixin = initIntSet()
  578. ctx.toInject = initIntSet()
  579. ctx.c = c
  580. ctx.owner = s
  581. if sfDirty in s.flags:
  582. n.sons[bodyPos] = semTemplBodyDirty(ctx, n.sons[bodyPos])
  583. else:
  584. n.sons[bodyPos] = semTemplBody(ctx, n.sons[bodyPos])
  585. # only parameters are resolved, no type checking is performed
  586. semIdeForTemplateOrGeneric(c, n.sons[bodyPos], ctx.cursorInBody)
  587. closeScope(c)
  588. popOwner(c)
  589. s.ast = n
  590. result = n
  591. if n.sons[bodyPos].kind == nkEmpty:
  592. localError(n.info, errImplOfXexpected, s.name.s)
  593. var proto = searchForProc(c, c.currentScope, s)
  594. if proto == nil:
  595. addInterfaceOverloadableSymAt(c, c.currentScope, s)
  596. else:
  597. symTabReplace(c.currentScope.symbols, proto, s)
  598. if n.sons[patternPos].kind != nkEmpty:
  599. c.patterns.add(s)
  600. proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
  601. template templToExpand(s: untyped): untyped =
  602. s.kind == skTemplate and (s.typ.len == 1 or sfAllUntyped in s.flags)
  603. proc newParam(c: var TemplCtx, n: PNode, s: PSym): PNode =
  604. # the param added in the current scope is actually wrong here for
  605. # macros because they have a shadowed param of type 'PNimNode' (see
  606. # semtypes.addParamOrResult). Within the pattern we have to ensure
  607. # to use the param with the proper type though:
  608. incl(s.flags, sfUsed)
  609. styleCheckUse(n.info, s)
  610. let x = c.owner.typ.n.sons[s.position+1].sym
  611. assert x.name == s.name
  612. result = newSymNode(x, n.info)
  613. proc handleSym(c: var TemplCtx, n: PNode, s: PSym): PNode =
  614. result = n
  615. if s != nil:
  616. if s.owner == c.owner and s.kind == skParam:
  617. result = newParam(c, n, s)
  618. elif contains(c.toBind, s.id):
  619. result = symChoice(c.c, n, s, scClosed)
  620. elif templToExpand(s):
  621. result = semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
  622. else:
  623. discard
  624. # we keep the ident unbound for matching instantiated symbols and
  625. # more flexibility
  626. proc expectParam(c: var TemplCtx, n: PNode): PNode =
  627. let s = qualifiedLookUp(c.c, n, {})
  628. if s != nil and s.owner == c.owner and s.kind == skParam:
  629. result = newParam(c, n, s)
  630. else:
  631. localError(n.info, errInvalidExpression)
  632. result = n
  633. proc stupidStmtListExpr(n: PNode): bool =
  634. for i in 0 .. n.len-2:
  635. if n[i].kind notin {nkEmpty, nkCommentStmt}: return false
  636. result = true
  637. result = n
  638. case n.kind
  639. of nkIdent:
  640. let s = qualifiedLookUp(c.c, n, {})
  641. result = handleSym(c, n, s)
  642. of nkBindStmt:
  643. result = semBindStmt(c.c, n, c.toBind)
  644. of nkEmpty, nkSym..nkNilLit: discard
  645. of nkCurlyExpr:
  646. # we support '(pattern){x}' to bind a subpattern to a parameter 'x';
  647. # '(pattern){|x}' does the same but the matches will be gathered in 'x'
  648. if n.len != 2:
  649. localError(n.info, errInvalidExpression)
  650. elif n.sons[1].kind == nkIdent:
  651. n.sons[0] = semPatternBody(c, n.sons[0])
  652. n.sons[1] = expectParam(c, n.sons[1])
  653. elif n.sons[1].kind == nkPrefix and n.sons[1].sons[0].kind == nkIdent:
  654. let opr = n.sons[1].sons[0]
  655. if opr.ident.s == "|":
  656. n.sons[0] = semPatternBody(c, n.sons[0])
  657. n.sons[1].sons[1] = expectParam(c, n.sons[1].sons[1])
  658. else:
  659. localError(n.info, errInvalidExpression)
  660. else:
  661. localError(n.info, errInvalidExpression)
  662. of nkStmtList, nkStmtListExpr:
  663. if stupidStmtListExpr(n):
  664. result = semPatternBody(c, n.lastSon)
  665. else:
  666. for i in countup(0, sonsLen(n) - 1):
  667. result.sons[i] = semPatternBody(c, n.sons[i])
  668. of nkCallKinds:
  669. let s = qualifiedLookUp(c.c, n.sons[0], {})
  670. if s != nil:
  671. if s.owner == c.owner and s.kind == skParam: discard
  672. elif contains(c.toBind, s.id): discard
  673. elif templToExpand(s):
  674. return semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
  675. if n.kind == nkInfix and n.sons[0].kind == nkIdent:
  676. # we interpret `*` and `|` only as pattern operators if they occur in
  677. # infix notation, so that '`*`(a, b)' can be used for verbatim matching:
  678. let opr = n.sons[0]
  679. if opr.ident.s == "*" or opr.ident.s == "**":
  680. result = newNodeI(nkPattern, n.info, n.len)
  681. result.sons[0] = opr
  682. result.sons[1] = semPatternBody(c, n.sons[1])
  683. result.sons[2] = expectParam(c, n.sons[2])
  684. return
  685. elif opr.ident.s == "|":
  686. result = newNodeI(nkPattern, n.info, n.len)
  687. result.sons[0] = opr
  688. result.sons[1] = semPatternBody(c, n.sons[1])
  689. result.sons[2] = semPatternBody(c, n.sons[2])
  690. return
  691. if n.kind == nkPrefix and n.sons[0].kind == nkIdent:
  692. let opr = n.sons[0]
  693. if opr.ident.s == "~":
  694. result = newNodeI(nkPattern, n.info, n.len)
  695. result.sons[0] = opr
  696. result.sons[1] = semPatternBody(c, n.sons[1])
  697. return
  698. for i in countup(0, sonsLen(n) - 1):
  699. result.sons[i] = semPatternBody(c, n.sons[i])
  700. else:
  701. # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
  702. # so we use the generic code for nkDotExpr too
  703. case n.kind
  704. of nkDotExpr, nkAccQuoted:
  705. let s = qualifiedLookUp(c.c, n, {})
  706. if s != nil:
  707. if contains(c.toBind, s.id):
  708. return symChoice(c.c, n, s, scClosed)
  709. else:
  710. return newIdentNode(s.name, n.info)
  711. of nkPar:
  712. if n.len == 1: return semPatternBody(c, n.sons[0])
  713. else: discard
  714. for i in countup(0, sonsLen(n) - 1):
  715. result.sons[i] = semPatternBody(c, n.sons[i])
  716. proc semPattern(c: PContext, n: PNode): PNode =
  717. openScope(c)
  718. var ctx: TemplCtx
  719. ctx.toBind = initIntSet()
  720. ctx.toMixin = initIntSet()
  721. ctx.toInject = initIntSet()
  722. ctx.c = c
  723. ctx.owner = getCurrOwner(c)
  724. result = flattenStmts(semPatternBody(ctx, n))
  725. if result.kind in {nkStmtList, nkStmtListExpr}:
  726. if result.len == 1:
  727. result = result.sons[0]
  728. elif result.len == 0:
  729. localError(n.info, errInvalidExpression)
  730. closeScope(c)