semtempl.nim 26 KB

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