semtempl.nim 26 KB

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