semtempl.nim 28 KB

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