semtempl.nim 26 KB

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