semtempl.nim 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  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 0..<n.len:
  29. var it = n[i]
  30. var key = if it.kind == nkExprColonExpr: it[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;
  40. isField = false): PNode =
  41. var
  42. a: PSym
  43. o: TOverloadIter = default(TOverloadIter)
  44. var i = 0
  45. a = initOverloadIter(o, c, n)
  46. while a != nil:
  47. if a.kind != skModule:
  48. inc(i)
  49. if i > 1: break
  50. a = nextOverloadIter(o, c, n)
  51. let info = getCallLineInfo(n)
  52. if i <= 1 and r != scForceOpen:
  53. # XXX this makes more sense but breaks bootstrapping for now:
  54. # (s.kind notin routineKinds or s.magic != mNone):
  55. # for instance 'nextTry' is both in tables.nim and astalgo.nim ...
  56. if not isField or sfGenSym notin s.flags:
  57. result = newSymNode(s, info)
  58. if isField:
  59. # possibly not final field sym
  60. incl(s.flags, sfUsed)
  61. markOwnerModuleAsUsed(c, s)
  62. else:
  63. markUsed(c, info, s)
  64. onUse(info, s)
  65. else:
  66. result = n
  67. elif i == 0:
  68. # forced open but symbol not in scope, retain information
  69. result = n
  70. else:
  71. # semantic checking requires a type; ``fitNode`` deals with it
  72. # appropriately
  73. let kind = if r == scClosed or n.kind == nkDotExpr: nkClosedSymChoice
  74. else: nkOpenSymChoice
  75. result = newNodeIT(kind, info, newTypeS(tyNone, c))
  76. a = initOverloadIter(o, c, n)
  77. while a != nil:
  78. if a.kind != skModule and (not isField or sfGenSym notin a.flags):
  79. incl(a.flags, sfUsed)
  80. markOwnerModuleAsUsed(c, a)
  81. result.add newSymNode(a, info)
  82. onUse(info, a)
  83. a = nextOverloadIter(o, c, n)
  84. proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
  85. result = copyNode(n)
  86. for i in 0..<n.len:
  87. var a = n[i]
  88. # If 'a' is an overloaded symbol, we used to use the first symbol
  89. # as a 'witness' and use the fact that subsequent lookups will yield
  90. # the same symbol!
  91. # This is however not true anymore for hygienic templates as semantic
  92. # processing for them changes the symbol table...
  93. let s = qualifiedLookUp(c, a, {checkUndeclared})
  94. if s != nil:
  95. # we need to mark all symbols:
  96. let sc = symChoice(c, n, s, scClosed)
  97. if sc.kind == nkSym:
  98. toBind.incl(sc.sym.id)
  99. result.add sc
  100. else:
  101. for x in items(sc):
  102. toBind.incl(x.sym.id)
  103. result.add x
  104. else:
  105. illFormedAst(a, c.config)
  106. proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
  107. result = copyNode(n)
  108. for i in 0..<n.len:
  109. toMixin.incl(considerQuotedIdent(c, n[i]).id)
  110. let x = symChoice(c, n[i], nil, scForceOpen)
  111. result.add x
  112. proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
  113. case n.kind
  114. of nkPostfix: replaceIdentBySym(c, n[1], s)
  115. of nkPragmaExpr: replaceIdentBySym(c, n[0], s)
  116. of nkIdent, nkAccQuoted, nkSym: n = s
  117. else: illFormedAst(n, c.config)
  118. type
  119. TemplCtx = object
  120. c: PContext
  121. toBind, toMixin, toInject: IntSet
  122. owner: PSym
  123. cursorInBody: bool # only for nimsuggest
  124. scopeN: int
  125. noGenSym: int
  126. inTemplateHeader: int
  127. proc isTemplParam(c: TemplCtx, s: PSym): bool {.inline.} =
  128. result = s.kind == skParam and
  129. s.owner == c.owner and sfTemplateParam in s.flags
  130. proc getIdentReplaceParams(c: var TemplCtx, n: var PNode): tuple[node: PNode, hasParam: bool] =
  131. case n.kind
  132. of nkPostfix: result = getIdentReplaceParams(c, n[1])
  133. of nkPragmaExpr: result = getIdentReplaceParams(c, n[0])
  134. of nkIdent:
  135. result = (n, false)
  136. let s = qualifiedLookUp(c.c, n, {})
  137. if s != nil and isTemplParam(c, s):
  138. n = newSymNode(s, n.info)
  139. result = (n, true)
  140. of nkSym:
  141. result = (n, isTemplParam(c, n.sym))
  142. of nkAccQuoted:
  143. result = (n, false)
  144. for i in 0..<n.safeLen:
  145. let (ident, hasParam) = getIdentReplaceParams(c, n[i])
  146. if hasParam:
  147. result.node[i] = ident
  148. result.hasParam = true
  149. else:
  150. illFormedAst(n, c.c.config)
  151. result = (n, false)
  152. proc semTemplBody(c: var TemplCtx, n: PNode): PNode
  153. proc openScope(c: var TemplCtx) =
  154. openScope(c.c)
  155. proc closeScope(c: var TemplCtx) =
  156. closeScope(c.c)
  157. proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
  158. openScope(c)
  159. result = semTemplBody(c, n)
  160. closeScope(c)
  161. proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
  162. result = newSym(kind, considerQuotedIdent(c.c, n), c.c.idgen, c.owner, n.info)
  163. incl(result.flags, sfGenSym)
  164. incl(result.flags, sfShadowed)
  165. proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
  166. # locals default to 'gensym', fields default to 'inject':
  167. if (n.kind == nkPragmaExpr and symBinding(n[1]) == spInject) or
  168. k == skField:
  169. # even if injected, don't produce a sym choice here:
  170. #n = semTemplBody(c, n)
  171. let (ident, hasParam) = getIdentReplaceParams(c, n)
  172. if not hasParam:
  173. if k != skField:
  174. c.toInject.incl(considerQuotedIdent(c.c, ident).id)
  175. else:
  176. if (n.kind == nkPragmaExpr and n.len >= 2 and n[1].kind == nkPragma):
  177. let pragmaNode = n[1]
  178. for i in 0..<pragmaNode.len:
  179. let ni = pragmaNode[i]
  180. # see D20210801T100514
  181. var found = false
  182. if ni.kind == nkIdent:
  183. for a in templatePragmas:
  184. if ni.ident.id == ord(a):
  185. found = true
  186. break
  187. if not found:
  188. openScope(c)
  189. pragmaNode[i] = semTemplBody(c, pragmaNode[i])
  190. closeScope(c)
  191. let (ident, hasParam) = getIdentReplaceParams(c, n)
  192. if not hasParam:
  193. if n.kind != nkSym and not (n.kind == nkIdent and n.ident.id == ord(wUnderscore)):
  194. let local = newGenSym(k, ident, c)
  195. addPrelimDecl(c.c, local)
  196. styleCheckDef(c.c, n.info, local)
  197. onDef(n.info, local)
  198. replaceIdentBySym(c.c, n, newSymNode(local, n.info))
  199. if k == skParam and c.inTemplateHeader > 0:
  200. local.flags.incl sfTemplateParam
  201. proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField: bool): PNode =
  202. incl(s.flags, sfUsed)
  203. # bug #12885; ideally sem'checking is performed again afterwards marking
  204. # the symbol as used properly, but the nfSem mechanism currently prevents
  205. # that from happening, so we mark the module as used here already:
  206. markOwnerModuleAsUsed(c.c, s)
  207. # we do not call onUse here, as the identifier is not really
  208. # resolved here. We will fixup the used identifiers later.
  209. case s.kind
  210. of skUnknown:
  211. # Introduced in this pass! Leave it as an identifier.
  212. result = n
  213. of OverloadableSyms:
  214. result = symChoice(c.c, n, s, scOpen, isField)
  215. if not isField and result.kind in {nkSym, nkOpenSymChoice}:
  216. if openSym in c.c.features:
  217. if result.kind == nkSym:
  218. result = newOpenSym(result)
  219. else:
  220. result.typ = nil
  221. else:
  222. result.flags.incl nfDisabledOpenSym
  223. result.typ = nil
  224. of skGenericParam:
  225. if isField and sfGenSym in s.flags: result = n
  226. else:
  227. result = newSymNodeTypeDesc(s, c.c.idgen, n.info)
  228. if not isField and s.owner != c.owner:
  229. if openSym in c.c.features:
  230. result = newOpenSym(result)
  231. else:
  232. result.flags.incl nfDisabledOpenSym
  233. result.typ = nil
  234. of skParam:
  235. result = n
  236. of skType:
  237. if isField and sfGenSym in s.flags: result = n
  238. else: result = newSymNodeTypeDesc(s, c.c.idgen, n.info)
  239. else:
  240. if isField and sfGenSym in s.flags: result = n
  241. else:
  242. result = newSymNode(s, n.info)
  243. if not isField:
  244. if openSym in c.c.features:
  245. result = newOpenSym(result)
  246. else:
  247. result.flags.incl nfDisabledOpenSym
  248. result.typ = nil
  249. # Issue #12832
  250. when defined(nimsuggest):
  251. suggestSym(c.c.graph, n.info, s, c.c.graph.usageSym, false)
  252. # field access (dot expr) will be handled by builtinFieldAccess
  253. if not isField:
  254. styleCheckUse(c.c, n.info, s)
  255. proc semRoutineInTemplName(c: var TemplCtx, n: PNode, explicitInject: bool): PNode =
  256. result = n
  257. if n.kind == nkIdent:
  258. let s = qualifiedLookUp(c.c, n, {})
  259. if s != nil:
  260. if s.owner == c.owner and (s.kind == skParam or
  261. (sfGenSym in s.flags and not explicitInject)):
  262. incl(s.flags, sfUsed)
  263. result = newSymNode(s, n.info)
  264. onUse(n.info, s)
  265. else:
  266. for i in 0..<n.safeLen:
  267. result[i] = semRoutineInTemplName(c, n[i], explicitInject)
  268. proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
  269. result = n
  270. checkSonsLen(n, bodyPos + 1, c.c.config)
  271. if n.kind notin nkLambdaKinds:
  272. # routines default to 'inject':
  273. let binding = symBinding(n[pragmasPos])
  274. if binding == spGenSym:
  275. let (ident, hasParam) = getIdentReplaceParams(c, n[namePos])
  276. if not hasParam:
  277. var s = newGenSym(k, ident, c)
  278. s.ast = n
  279. addPrelimDecl(c.c, s)
  280. styleCheckDef(c.c, n.info, s)
  281. onDef(n.info, s)
  282. n[namePos] = newSymNode(s, n[namePos].info)
  283. else:
  284. n[namePos] = ident
  285. else:
  286. n[namePos] = semRoutineInTemplName(c, n[namePos], binding == spInject)
  287. # open scope for parameters
  288. openScope(c)
  289. for i in patternPos..paramsPos-1:
  290. n[i] = semTemplBody(c, n[i])
  291. if k == skTemplate: inc(c.inTemplateHeader)
  292. n[paramsPos] = semTemplBody(c, n[paramsPos])
  293. if k == skTemplate: dec(c.inTemplateHeader)
  294. for i in paramsPos+1..miscPos:
  295. n[i] = semTemplBody(c, n[i])
  296. # open scope for locals
  297. inc c.scopeN
  298. openScope(c)
  299. n[bodyPos] = semTemplBody(c, n[bodyPos])
  300. # close scope for locals
  301. closeScope(c)
  302. dec c.scopeN
  303. # close scope for parameters
  304. closeScope(c)
  305. proc semTemplIdentDef(c: var TemplCtx, a: PNode, symKind: TSymKind) =
  306. checkMinSonsLen(a, 3, c.c.config)
  307. when defined(nimsuggest):
  308. inc c.c.inTypeContext
  309. a[^2] = semTemplBody(c, a[^2])
  310. when defined(nimsuggest):
  311. dec c.c.inTypeContext
  312. a[^1] = semTemplBody(c, a[^1])
  313. for j in 0..<a.len-2:
  314. addLocalDecl(c, a[j], symKind)
  315. proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start = 0) =
  316. for i in start..<n.len:
  317. var a = n[i]
  318. case a.kind:
  319. of nkCommentStmt: continue
  320. of nkIdentDefs, nkVarTuple, nkConstDef:
  321. semTemplIdentDef(c, a, symKind)
  322. else:
  323. illFormedAst(a, c.c.config)
  324. proc semPattern(c: PContext, n: PNode; s: PSym): PNode
  325. proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode =
  326. result = n
  327. for i in 0..<n.len:
  328. result[i] = semTemplBody(c, n[i])
  329. proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
  330. result = n
  331. semIdeForTemplateOrGenericCheck(c.c.config, n, c.cursorInBody)
  332. case n.kind
  333. of nkIdent:
  334. if n.ident.id in c.toInject: return n
  335. let s = qualifiedLookUp(c.c, n, {})
  336. if s != nil:
  337. if s.owner == c.owner and s.kind == skParam and sfTemplateParam in s.flags:
  338. incl(s.flags, sfUsed)
  339. result = newSymNode(s, n.info)
  340. onUse(n.info, s)
  341. elif contains(c.toBind, s.id):
  342. result = symChoice(c.c, n, s, scClosed, c.noGenSym > 0)
  343. elif contains(c.toMixin, s.name.id):
  344. result = symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
  345. elif s.owner == c.owner and sfGenSym in s.flags and c.noGenSym == 0:
  346. # template tmp[T](x: var seq[T]) =
  347. # var yz: T
  348. incl(s.flags, sfUsed)
  349. result = newSymNode(s, n.info)
  350. onUse(n.info, s)
  351. else:
  352. if s.kind in {skType, skVar, skLet, skConst}:
  353. discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
  354. result = semTemplSymbol(c, n, s, c.noGenSym > 0)
  355. of nkBind:
  356. result = semTemplBody(c, n[0])
  357. of nkBindStmt:
  358. result = semBindStmt(c.c, n, c.toBind)
  359. of nkMixinStmt:
  360. if c.scopeN > 0: result = semTemplBodySons(c, n)
  361. else: result = semMixinStmt(c.c, n, c.toMixin)
  362. of nkEmpty, nkSym..nkNilLit, nkComesFrom:
  363. discard
  364. of nkIfStmt:
  365. for i in 0..<n.len:
  366. var it = n[i]
  367. if it.len == 2:
  368. openScope(c)
  369. it[0] = semTemplBody(c, it[0])
  370. it[1] = semTemplBody(c, it[1])
  371. closeScope(c)
  372. else:
  373. n[i] = semTemplBodyScope(c, it)
  374. of nkWhileStmt:
  375. openScope(c)
  376. for i in 0..<n.len:
  377. n[i] = semTemplBody(c, n[i])
  378. closeScope(c)
  379. of nkCaseStmt:
  380. openScope(c)
  381. n[0] = semTemplBody(c, n[0])
  382. for i in 1..<n.len:
  383. var a = n[i]
  384. checkMinSonsLen(a, 1, c.c.config)
  385. for j in 0..<a.len-1:
  386. a[j] = semTemplBody(c, a[j])
  387. a[^1] = semTemplBodyScope(c, a[^1])
  388. closeScope(c)
  389. of nkForStmt, nkParForStmt:
  390. openScope(c)
  391. n[^2] = semTemplBody(c, n[^2])
  392. for i in 0..<n.len - 2:
  393. if n[i].kind == nkVarTuple:
  394. for j in 0..<n[i].len-1:
  395. addLocalDecl(c, n[i][j], skForVar)
  396. else:
  397. addLocalDecl(c, n[i], skForVar)
  398. openScope(c)
  399. n[^1] = semTemplBody(c, n[^1])
  400. closeScope(c)
  401. closeScope(c)
  402. of nkBlockStmt, nkBlockExpr, nkBlockType:
  403. checkSonsLen(n, 2, c.c.config)
  404. openScope(c)
  405. if n[0].kind != nkEmpty:
  406. addLocalDecl(c, n[0], skLabel)
  407. when false:
  408. # labels are always 'gensym'ed:
  409. let s = newGenSym(skLabel, n[0], c)
  410. addPrelimDecl(c.c, s)
  411. styleCheckDef(c.c, s)
  412. onDef(n[0].info, s)
  413. n[0] = newSymNode(s, n[0].info)
  414. n[1] = semTemplBody(c, n[1])
  415. closeScope(c)
  416. of nkTryStmt, nkHiddenTryStmt:
  417. checkMinSonsLen(n, 2, c.c.config)
  418. n[0] = semTemplBodyScope(c, n[0])
  419. for i in 1..<n.len:
  420. var a = n[i]
  421. checkMinSonsLen(a, 1, c.c.config)
  422. openScope(c)
  423. for j in 0..<a.len-1:
  424. if a[j].isInfixAs():
  425. addLocalDecl(c, a[j][2], skLet)
  426. a[j][1] = semTemplBody(c, a[j][1])
  427. else:
  428. a[j] = semTemplBody(c, a[j])
  429. a[^1] = semTemplBodyScope(c, a[^1])
  430. closeScope(c)
  431. of nkVarSection: semTemplSomeDecl(c, n, skVar)
  432. of nkLetSection: semTemplSomeDecl(c, n, skLet)
  433. of nkFormalParams:
  434. checkMinSonsLen(n, 1, c.c.config)
  435. semTemplSomeDecl(c, n, skParam, 1)
  436. n[0] = semTemplBody(c, n[0])
  437. of nkConstSection: semTemplSomeDecl(c, n, skConst)
  438. of nkTypeSection:
  439. for i in 0..<n.len:
  440. var a = n[i]
  441. if a.kind == nkCommentStmt: continue
  442. if (a.kind != nkTypeDef): illFormedAst(a, c.c.config)
  443. checkSonsLen(a, 3, c.c.config)
  444. addLocalDecl(c, a[0], skType)
  445. for i in 0..<n.len:
  446. var a = n[i]
  447. if a.kind == nkCommentStmt: continue
  448. if (a.kind != nkTypeDef): illFormedAst(a, c.c.config)
  449. checkSonsLen(a, 3, c.c.config)
  450. if a[1].kind != nkEmpty:
  451. openScope(c)
  452. a[1] = semTemplBody(c, a[1])
  453. a[2] = semTemplBody(c, a[2])
  454. closeScope(c)
  455. else:
  456. a[2] = semTemplBody(c, a[2])
  457. of nkObjectTy:
  458. openScope(c)
  459. result = semTemplBodySons(c, n)
  460. closeScope(c)
  461. of nkRecList:
  462. for i in 0..<n.len:
  463. var a = n[i]
  464. case a.kind:
  465. of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue
  466. of nkIdentDefs:
  467. semTemplIdentDef(c, a, skField)
  468. of nkRecCase, nkRecWhen:
  469. n[i] = semTemplBody(c, a)
  470. else:
  471. illFormedAst(a, c.c.config)
  472. of nkRecCase:
  473. semTemplIdentDef(c, n[0], skField)
  474. for i in 1..<n.len:
  475. n[i] = semTemplBody(c, n[i])
  476. of nkProcDef, nkLambdaKinds:
  477. result = semRoutineInTemplBody(c, n, skProc)
  478. of nkFuncDef:
  479. result = semRoutineInTemplBody(c, n, skFunc)
  480. of nkMethodDef:
  481. result = semRoutineInTemplBody(c, n, skMethod)
  482. of nkIteratorDef:
  483. result = semRoutineInTemplBody(c, n, skIterator)
  484. of nkTemplateDef:
  485. result = semRoutineInTemplBody(c, n, skTemplate)
  486. of nkMacroDef:
  487. result = semRoutineInTemplBody(c, n, skMacro)
  488. of nkConverterDef:
  489. result = semRoutineInTemplBody(c, n, skConverter)
  490. of nkPragmaExpr:
  491. result[0] = semTemplBody(c, n[0])
  492. of nkPostfix:
  493. result[1] = semTemplBody(c, n[1])
  494. of nkPragma:
  495. for x in n:
  496. if x.kind == nkExprColonExpr:
  497. x[1] = semTemplBody(c, x[1])
  498. of nkBracketExpr:
  499. if n.typ == nil:
  500. # if a[b] is nested inside a typed expression, don't convert it
  501. # back to `[]`(a, b), prepareOperand will not typecheck it again
  502. # and so `[]` will not be resolved
  503. # checking if a[b] is typed should be enough to cover this case
  504. result = newNodeI(nkCall, n.info)
  505. result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
  506. for i in 0..<n.len: result.add(n[i])
  507. result = semTemplBodySons(c, result)
  508. of nkCurlyExpr:
  509. if n.typ == nil:
  510. # see nkBracketExpr case for explanation
  511. result = newNodeI(nkCall, n.info)
  512. result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
  513. for i in 0..<n.len: result.add(n[i])
  514. result = semTemplBodySons(c, result)
  515. of nkAsgn, nkFastAsgn, nkSinkAsgn:
  516. checkSonsLen(n, 2, c.c.config)
  517. let a = n[0]
  518. let b = n[1]
  519. let k = a.kind
  520. case k
  521. of nkBracketExpr:
  522. if a.typ == nil:
  523. # see nkBracketExpr case above for explanation
  524. result = newNodeI(nkCall, n.info)
  525. result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
  526. for i in 0..<a.len: result.add(a[i])
  527. result.add(b)
  528. let a0 = semTemplBody(c, a[0])
  529. result = semTemplBodySons(c, result)
  530. of nkCurlyExpr:
  531. if a.typ == nil:
  532. # see nkBracketExpr case above for explanation
  533. result = newNodeI(nkCall, n.info)
  534. result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
  535. for i in 0..<a.len: result.add(a[i])
  536. result.add(b)
  537. result = semTemplBodySons(c, result)
  538. else:
  539. result = semTemplBodySons(c, n)
  540. of nkCallKinds-{nkPostfix}:
  541. # do not transform runnableExamples (bug #9143)
  542. if not isRunnableExamples(n[0]):
  543. result = semTemplBodySons(c, n)
  544. of nkDotExpr, nkAccQuoted:
  545. # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
  546. # so we use the generic code for nkDotExpr too
  547. let s = qualifiedLookUp(c.c, n, {})
  548. if s != nil:
  549. # mirror the nkIdent case
  550. # do not symchoice a quoted template parameter (bug #2390):
  551. if s.owner == c.owner and s.kind == skParam and
  552. n.kind == nkAccQuoted and n.len == 1:
  553. incl(s.flags, sfUsed)
  554. onUse(n.info, s)
  555. return newSymNode(s, n.info)
  556. elif contains(c.toBind, s.id):
  557. return symChoice(c.c, n, s, scClosed, c.noGenSym > 0)
  558. elif contains(c.toMixin, s.name.id):
  559. return symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
  560. else:
  561. if s.kind in {skType, skVar, skLet, skConst}:
  562. discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
  563. return semTemplSymbol(c, n, s, c.noGenSym > 0)
  564. if n.kind == nkDotExpr:
  565. result = n
  566. result[0] = semTemplBody(c, n[0])
  567. inc c.noGenSym
  568. result[1] = semTemplBody(c, n[1])
  569. dec c.noGenSym
  570. if result[1].kind == nkSym and result[1].sym.kind in routineKinds:
  571. # prevent `dotTransformation` from rewriting this node to `nkIdent`
  572. # by making it a symchoice
  573. # in generics this becomes `nkClosedSymChoice` but this breaks code
  574. # as the old behavior here was that this became `nkIdent`
  575. var choice = newNodeIT(nkOpenSymChoice, n[1].info, newTypeS(tyNone, c.c))
  576. choice.add result[1]
  577. result[1] = choice
  578. else:
  579. result = semTemplBodySons(c, n)
  580. of nkExprColonExpr, nkExprEqExpr:
  581. if n.len == 2:
  582. inc c.noGenSym
  583. result[0] = semTemplBody(c, n[0])
  584. dec c.noGenSym
  585. result[1] = semTemplBody(c, n[1])
  586. else:
  587. result = semTemplBodySons(c, n)
  588. of nkTableConstr:
  589. # also transform the keys (bug #12595)
  590. for i in 0..<n.len:
  591. result[i] = semTemplBodySons(c, n[i])
  592. else:
  593. result = semTemplBodySons(c, n)
  594. proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
  595. result = n
  596. semIdeForTemplateOrGenericCheck(c.c.config, n, c.cursorInBody)
  597. case n.kind
  598. of nkIdent:
  599. let s = qualifiedLookUp(c.c, n, {})
  600. if s != nil:
  601. if s.owner == c.owner and s.kind == skParam:
  602. result = newSymNode(s, n.info)
  603. elif contains(c.toBind, s.id):
  604. result = symChoice(c.c, n, s, scClosed)
  605. of nkBind:
  606. result = semTemplBodyDirty(c, n[0])
  607. of nkBindStmt:
  608. result = semBindStmt(c.c, n, c.toBind)
  609. of nkEmpty, nkSym..nkNilLit, nkComesFrom:
  610. discard
  611. else:
  612. # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
  613. # so we use the generic code for nkDotExpr too
  614. if n.kind == nkDotExpr or n.kind == nkAccQuoted:
  615. let s = qualifiedLookUp(c.c, n, {})
  616. if s != nil and contains(c.toBind, s.id):
  617. return symChoice(c.c, n, s, scClosed)
  618. result = n
  619. for i in 0..<n.len:
  620. result[i] = semTemplBodyDirty(c, n[i])
  621. # in semstmts.nim:
  622. proc semProcAnnotation(c: PContext, prc: PNode; validPragmas: TSpecialWords): PNode
  623. proc semTemplateDef(c: PContext, n: PNode): PNode =
  624. result = semProcAnnotation(c, n, templatePragmas)
  625. if result != nil: return result
  626. result = n
  627. var s: PSym
  628. if isTopLevel(c):
  629. s = semIdentVis(c, skTemplate, n[namePos], {sfExported})
  630. incl(s.flags, sfGlobal)
  631. else:
  632. s = semIdentVis(c, skTemplate, n[namePos], {})
  633. assert s.kind == skTemplate
  634. styleCheckDef(c, s)
  635. onDef(n[namePos].info, s)
  636. # check parameter list:
  637. #s.scope = c.currentScope
  638. # push noalias flag at first to prevent unwanted recursive calls:
  639. incl(s.flags, sfNoalias)
  640. pushOwner(c, s)
  641. openScope(c)
  642. n[namePos] = newSymNode(s)
  643. pragmaCallable(c, s, n, templatePragmas)
  644. implicitPragmas(c, s, n.info, templatePragmas)
  645. setGenericParamsMisc(c, n)
  646. # process parameters:
  647. var allUntyped = true
  648. var nullary = true
  649. if n[paramsPos].kind != nkEmpty:
  650. semParamList(c, n[paramsPos], n[genericParamsPos], s)
  651. # a template's parameters are not gensym'ed even if that was originally the
  652. # case as we determine whether it's a template parameter in the template
  653. # body by the absence of the sfGenSym flag:
  654. let retType = s.typ[0]
  655. if retType != nil and retType.kind != tyUntyped:
  656. allUntyped = false
  657. for i in 1..<s.typ.n.len:
  658. let param = s.typ.n[i].sym
  659. if param.name.id != ord(wUnderscore):
  660. param.flags.incl sfTemplateParam
  661. param.flags.excl sfGenSym
  662. if param.typ.kind != tyUntyped: allUntyped = false
  663. # no default value, parameters required in call
  664. if param.ast == nil: nullary = false
  665. else:
  666. s.typ = newTypeS(tyProc, c)
  667. # XXX why do we need tyTyped as a return type again?
  668. s.typ.n = newNodeI(nkFormalParams, n.info)
  669. rawAddSon(s.typ, newTypeS(tyTyped, c))
  670. s.typ.n.add newNodeIT(nkType, n.info, s.typ[0])
  671. if n[genericParamsPos].safeLen == 0:
  672. # restore original generic type params as no explicit or implicit were found
  673. n[genericParamsPos] = n[miscPos][1]
  674. n[miscPos] = c.graph.emptyNode
  675. if allUntyped: incl(s.flags, sfAllUntyped)
  676. if nullary and
  677. n[genericParamsPos].kind == nkEmpty and
  678. n[bodyPos].kind != nkEmpty:
  679. # template can be called with alias syntax, remove pushed noalias flag
  680. excl(s.flags, sfNoalias)
  681. if n[patternPos].kind != nkEmpty:
  682. n[patternPos] = semPattern(c, n[patternPos], s)
  683. var ctx: TemplCtx
  684. ctx.toBind = initIntSet()
  685. ctx.toMixin = initIntSet()
  686. ctx.toInject = initIntSet()
  687. ctx.c = c
  688. ctx.owner = s
  689. if sfDirty in s.flags:
  690. n[bodyPos] = semTemplBodyDirty(ctx, n[bodyPos])
  691. else:
  692. n[bodyPos] = semTemplBody(ctx, n[bodyPos])
  693. # only parameters are resolved, no type checking is performed
  694. semIdeForTemplateOrGeneric(c, n[bodyPos], ctx.cursorInBody)
  695. closeScope(c)
  696. popOwner(c)
  697. # set the symbol AST after pragmas, at least. This stops pragma that have
  698. # been pushed (implicit) to be explicitly added to the template definition
  699. # and misapplied to the body. see #18113
  700. s.ast = n
  701. if sfCustomPragma in s.flags:
  702. if n[bodyPos].kind != nkEmpty:
  703. localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)
  704. elif n[bodyPos].kind == nkEmpty:
  705. localError(c.config, n.info, "implementation of '$1' expected" % s.name.s)
  706. var (proto, comesFromShadowscope) = searchForProc(c, c.currentScope, s)
  707. if proto == nil:
  708. addInterfaceOverloadableSymAt(c, c.currentScope, s)
  709. elif not comesFromShadowscope:
  710. if {sfTemplateRedefinition, sfGenSym} * s.flags == {}:
  711. #wrongRedefinition(c, n.info, proto.name.s, proto.info)
  712. message(c.config, n.info, warnImplicitTemplateRedefinition, s.name.s)
  713. symTabReplace(c.currentScope.symbols, proto, s)
  714. if n[patternPos].kind != nkEmpty:
  715. c.patterns.add(s)
  716. proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
  717. template templToExpand(s: untyped): untyped =
  718. s.kind == skTemplate and (s.typ.len == 1 or sfAllUntyped in s.flags)
  719. proc newParam(c: var TemplCtx, n: PNode, s: PSym): PNode =
  720. # the param added in the current scope is actually wrong here for
  721. # macros because they have a shadowed param of type 'PNimNode' (see
  722. # semtypes.addParamOrResult). Within the pattern we have to ensure
  723. # to use the param with the proper type though:
  724. incl(s.flags, sfUsed)
  725. onUse(n.info, s)
  726. let x = c.owner.typ.n[s.position+1].sym
  727. assert x.name == s.name
  728. result = newSymNode(x, n.info)
  729. proc handleSym(c: var TemplCtx, n: PNode, s: PSym): PNode =
  730. result = n
  731. if s != nil:
  732. if s.owner == c.owner and s.kind == skParam:
  733. result = newParam(c, n, s)
  734. elif contains(c.toBind, s.id):
  735. result = symChoice(c.c, n, s, scClosed)
  736. elif templToExpand(s):
  737. result = semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
  738. else:
  739. discard
  740. # we keep the ident unbound for matching instantiated symbols and
  741. # more flexibility
  742. proc expectParam(c: var TemplCtx, n: PNode): PNode =
  743. let s = qualifiedLookUp(c.c, n, {})
  744. if s != nil and s.owner == c.owner and s.kind == skParam:
  745. result = newParam(c, n, s)
  746. else:
  747. localError(c.c.config, n.info, "invalid expression")
  748. result = n
  749. result = n
  750. case n.kind
  751. of nkIdent:
  752. let s = qualifiedLookUp(c.c, n, {})
  753. result = handleSym(c, n, s)
  754. of nkBindStmt:
  755. result = semBindStmt(c.c, n, c.toBind)
  756. of nkEmpty, nkSym..nkNilLit: discard
  757. of nkCurlyExpr:
  758. # we support '(pattern){x}' to bind a subpattern to a parameter 'x';
  759. # '(pattern){|x}' does the same but the matches will be gathered in 'x'
  760. if n.len != 2:
  761. localError(c.c.config, n.info, "invalid expression")
  762. elif n[1].kind == nkIdent:
  763. n[0] = semPatternBody(c, n[0])
  764. n[1] = expectParam(c, n[1])
  765. elif n[1].kind == nkPrefix and n[1][0].kind == nkIdent:
  766. let opr = n[1][0]
  767. if opr.ident.s == "|":
  768. n[0] = semPatternBody(c, n[0])
  769. n[1][1] = expectParam(c, n[1][1])
  770. else:
  771. localError(c.c.config, n.info, "invalid expression")
  772. else:
  773. localError(c.c.config, n.info, "invalid expression")
  774. of nkStmtList, nkStmtListExpr:
  775. if stupidStmtListExpr(n):
  776. result = semPatternBody(c, n.lastSon)
  777. else:
  778. for i in 0..<n.len:
  779. result[i] = semPatternBody(c, n[i])
  780. of nkCallKinds:
  781. let s = qualifiedLookUp(c.c, n[0], {})
  782. if s != nil:
  783. if s.owner == c.owner and s.kind == skParam: discard
  784. elif contains(c.toBind, s.id): discard
  785. elif templToExpand(s):
  786. return semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
  787. if n.kind == nkInfix and (let id = considerQuotedIdent(c.c, n[0]); id != nil):
  788. # we interpret `*` and `|` only as pattern operators if they occur in
  789. # infix notation, so that '`*`(a, b)' can be used for verbatim matching:
  790. if id.s == "*" or id.s == "**":
  791. result = newNodeI(nkPattern, n.info, n.len)
  792. result[0] = newIdentNode(id, n.info)
  793. result[1] = semPatternBody(c, n[1])
  794. result[2] = expectParam(c, n[2])
  795. return
  796. elif id.s == "|":
  797. result = newNodeI(nkPattern, n.info, n.len)
  798. result[0] = newIdentNode(id, n.info)
  799. result[1] = semPatternBody(c, n[1])
  800. result[2] = semPatternBody(c, n[2])
  801. return
  802. if n.kind == nkPrefix and (let id = considerQuotedIdent(c.c, n[0]); id != nil):
  803. if id.s == "~":
  804. result = newNodeI(nkPattern, n.info, n.len)
  805. result[0] = newIdentNode(id, n.info)
  806. result[1] = semPatternBody(c, n[1])
  807. return
  808. for i in 0..<n.len:
  809. result[i] = semPatternBody(c, n[i])
  810. else:
  811. # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
  812. # so we use the generic code for nkDotExpr too
  813. case n.kind
  814. of nkDotExpr, nkAccQuoted:
  815. let s = qualifiedLookUp(c.c, n, {})
  816. if s != nil:
  817. if contains(c.toBind, s.id):
  818. return symChoice(c.c, n, s, scClosed)
  819. else:
  820. return newIdentNode(s.name, n.info)
  821. of nkPar:
  822. if n.len == 1: return semPatternBody(c, n[0])
  823. else: discard
  824. for i in 0..<n.len:
  825. result[i] = semPatternBody(c, n[i])
  826. proc semPattern(c: PContext, n: PNode; s: PSym): PNode =
  827. openScope(c)
  828. var ctx: TemplCtx
  829. ctx.toBind = initIntSet()
  830. ctx.toMixin = initIntSet()
  831. ctx.toInject = initIntSet()
  832. ctx.c = c
  833. ctx.owner = getCurrOwner(c)
  834. result = flattenStmts(semPatternBody(ctx, n))
  835. if result.kind in {nkStmtList, nkStmtListExpr}:
  836. if result.len == 1:
  837. result = result[0]
  838. elif result.len == 0:
  839. localError(c.config, n.info, "a pattern cannot be empty")
  840. closeScope(c)
  841. addPattern(c, LazySym(sym: s))