semtempl.nim 26 KB

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