semtempl.nim 29 KB

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