semtempl.nim 31 KB

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