tastspec.nim 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
  1. discard """
  2. action: compile
  3. """
  4. # this test should ensure that the AST doesn't change slightly without it getting noticed.
  5. import ../ast_pattern_matching
  6. template expectNimNode(arg: untyped): NimNode = arg
  7. ## This template here is just to be injected by `myquote`, so that
  8. ## a nice error message appears when the captured symbols are not of
  9. ## type `NimNode`.
  10. proc substitudeComments(symbols, values, n: NimNode): NimNode =
  11. ## substitutes all nodes of kind nnkCommentStmt to parameter
  12. ## symbols. Consumes the argument `n`.
  13. if n.kind == nnkCommentStmt:
  14. values.add newCall(bindSym"newCommentStmtNode", newLit(n.strVal))
  15. # Gensym doesn't work for parameters. These identifiers won't
  16. # clash unless an argument is constructed to clash here.
  17. symbols.add ident("comment" & $values.len & "_XObBdOnh6meCuJK2smZV")
  18. return symbols[^1]
  19. for i in 0 ..< n.len:
  20. n[i] = substitudeComments(symbols, values, n[i])
  21. return n
  22. macro myquote*(args: varargs[untyped]): untyped =
  23. expectMinLen(args, 1)
  24. # This is a workaround for #10430 where comments are removed in
  25. # template expansions. This workaround lifts all comments
  26. # statements to be arguments of the temporary template.
  27. let extraCommentSymbols = newNimNode(nnkBracket)
  28. let extraCommentGenExpr = newNimNode(nnkBracket)
  29. let body = substitudeComments(
  30. extraCommentSymbols, extraCommentGenExpr, args[^1]
  31. )
  32. let formalParams = nnkFormalParams.newTree(ident"untyped")
  33. for i in 0 ..< args.len-1:
  34. formalParams.add nnkIdentDefs.newTree(
  35. args[i], ident"untyped", newEmptyNode()
  36. )
  37. for sym in extraCommentSymbols:
  38. formalParams.add nnkIdentDefs.newTree(
  39. sym, ident"untyped", newEmptyNode()
  40. )
  41. let templateSym = genSym(nskTemplate)
  42. let templateDef = nnkTemplateDef.newTree(
  43. templateSym,
  44. newEmptyNode(),
  45. newEmptyNode(),
  46. formalParams,
  47. nnkPragma.newTree(ident"dirty"),
  48. newEmptyNode(),
  49. args[^1]
  50. )
  51. let templateCall = newCall(templateSym)
  52. for i in 0 ..< args.len-1:
  53. let symName = args[i]
  54. # identifiers and quoted identifiers are allowed.
  55. if symName.kind == nnkAccQuoted:
  56. symName.expectLen 1
  57. symName[0].expectKind nnkIdent
  58. else:
  59. symName.expectKind nnkIdent
  60. templateCall.add newCall(bindSym"expectNimNode", symName)
  61. for expr in extraCommentGenExpr:
  62. templateCall.add expr
  63. let getAstCall = newCall(bindSym"getAst", templateCall)
  64. result = newStmtList(templateDef, getAstCall)
  65. macro testAddrAst(arg: typed): bool =
  66. arg.expectKind nnkStmtListExpr
  67. arg[0].expectKind(nnkVarSection)
  68. arg[1].expectKind({nnkAddr, nnkCall})
  69. result = newLit(arg[1].kind == nnkCall)
  70. const newAddrAst: bool = testAddrAst((var x: int; addr(x)))
  71. static:
  72. echo "new addr ast: ", newAddrAst
  73. # TODO test on matching failures
  74. proc peelOff*(arg: NimNode, kinds: set[NimNodeKind]): NimNode {.compileTime.} =
  75. ## Peel off nodes of a specific kinds.
  76. if arg.len == 1 and arg.kind in kinds:
  77. arg[0].peelOff(kinds)
  78. else:
  79. arg
  80. proc peelOff*(arg: NimNode, kind: NimNodeKind): NimNode {.compileTime.} =
  81. ## Peel off nodes of a specific kind.
  82. if arg.len == 1 and arg.kind == kind:
  83. arg[0].peelOff(kind)
  84. else:
  85. arg
  86. static:
  87. template testPattern(pattern, astArg: untyped): untyped =
  88. let ast = quote do: `astArg`
  89. ast.matchAst:
  90. of `pattern`:
  91. echo "ok"
  92. template testPatternFail(pattern, astArg: untyped): untyped =
  93. let ast = quote do: `astArg`
  94. ast.matchAst:
  95. of `pattern`:
  96. error("this should not match", ast)
  97. else:
  98. echo "OK"
  99. testPattern nnkIntLit(intVal = 42), 42
  100. testPattern nnkInt8Lit(intVal = 42), 42'i8
  101. testPattern nnkInt16Lit(intVal = 42), 42'i16
  102. testPattern nnkInt32Lit(intVal = 42), 42'i32
  103. testPattern nnkInt64Lit(intVal = 42), 42'i64
  104. testPattern nnkUInt8Lit(intVal = 42), 42'u8
  105. testPattern nnkUInt16Lit(intVal = 42), 42'u16
  106. testPattern nnkUInt32Lit(intVal = 42), 42'u32
  107. testPattern nnkUInt64Lit(intVal = 42), 42'u64
  108. #testPattern nnkFloat64Lit(floatVal = 42.0), 42.0
  109. testPattern nnkFloat32Lit(floatVal = 42.0), 42.0'f32
  110. #testPattern nnkFloat64Lit(floatVal = 42.0), 42.0'f64
  111. testPattern nnkStrLit(strVal = "abc"), "abc"
  112. testPattern nnkRStrLit(strVal = "abc"), r"abc"
  113. testPattern nnkTripleStrLit(strVal = "abc"), """abc"""
  114. testPattern nnkCharLit(intVal = 32), ' '
  115. testPattern nnkNilLit(), nil
  116. testPattern nnkIdent(strVal = "myIdentifier"), myIdentifier
  117. testPatternFail nnkInt8Lit(intVal = 42), 42'i16
  118. testPatternFail nnkInt16Lit(intVal = 42), 42'i8
  119. # this should be just `block` but it doesn't work that way anymore because of VM.
  120. macro scope(arg: untyped): untyped =
  121. let procSym = genSym(nskProc)
  122. result = quote do:
  123. proc `procSym`() {.compileTime.} =
  124. `arg`
  125. `procSym`()
  126. static:
  127. ## Command call
  128. scope:
  129. let ast = myquote:
  130. echo "abc", "xyz"
  131. ast.matchAst:
  132. of nnkCommand(ident"echo", "abc", "xyz"):
  133. echo "ok"
  134. ## Call with ``()``
  135. scope:
  136. let ast = myquote:
  137. echo("abc", "xyz")
  138. ast.matchAst:
  139. of nnkCall(ident"echo", "abc", "xyz"):
  140. echo "ok"
  141. ## Infix operator call
  142. macro testInfixOperatorCall(ast: untyped): untyped =
  143. ast.matchAst(errorSym):
  144. of nnkInfix(
  145. ident"&",
  146. nnkStrLit(strVal = "abc"),
  147. nnkStrLit(strVal = "xyz")
  148. ):
  149. echo "ok1"
  150. of nnkInfix(
  151. ident"+",
  152. nnkIntLit(intVal = 5),
  153. nnkInfix(
  154. ident"*",
  155. nnkIntLit(intVal = 3),
  156. nnkIntLit(intVal = 4)
  157. )
  158. ):
  159. echo "ok2"
  160. of nnkCall(
  161. nnkAccQuoted(
  162. ident"+"
  163. ),
  164. nnkIntLit(intVal = 3),
  165. nnkIntLit(intVal = 4)
  166. ):
  167. echo "ok3"
  168. testInfixOperatorCall("abc" & "xyz")
  169. testInfixOperatorCall(5 + 3 * 4)
  170. testInfixOperatorCall(`+`(3, 4))
  171. ## Prefix operator call
  172. scope:
  173. let ast = myquote:
  174. ? "xyz"
  175. ast.matchAst(err):
  176. of nnkPrefix(
  177. ident"?",
  178. nnkStrLit(strVal = "xyz")
  179. ):
  180. echo "ok"
  181. ## Postfix operator call
  182. scope:
  183. let ast = myquote:
  184. proc identifier*
  185. ast[0].matchAst(err):
  186. of nnkPostfix(
  187. ident"*",
  188. ident"identifier"
  189. ):
  190. echo "ok"
  191. ## Call with named arguments
  192. macro testCallWithNamedArguments(ast: untyped): untyped =
  193. ast.peelOff(nnkStmtList).matchAst:
  194. of nnkCall(
  195. ident"writeLine",
  196. nnkExprEqExpr(
  197. ident"file",
  198. ident"stdout"
  199. ),
  200. nnkStrLit(strVal = "hallo")
  201. ):
  202. echo "ok"
  203. testCallWithNamedArguments:
  204. writeLine(file=stdout, "hallo")
  205. ## Call with raw string literal
  206. scope:
  207. let ast = myquote:
  208. echo"abc"
  209. ast.matchAst(err):
  210. of nnkCallStrLit(
  211. ident"echo",
  212. nnkRStrLit(strVal = "abc")
  213. ):
  214. echo "ok"
  215. ## Dereference operator ``[]``
  216. scope:
  217. # The dereferece operator exists only on a typed ast.
  218. macro testDereferenceOperator(ast: typed): untyped =
  219. ast.matchAst(err):
  220. of nnkDerefExpr(_):
  221. echo "ok"
  222. var x: ptr int
  223. testDereferenceOperator(x[])
  224. ## Addr operator
  225. scope:
  226. # The addr operator exists only on a typed ast.
  227. macro testAddrOperator(ast: untyped): untyped =
  228. echo ast.treeRepr
  229. ast.matchAst(err):
  230. of nnkAddr(ident"x"):
  231. echo "old nim"
  232. of nnkCall(ident"addr", ident"x"):
  233. echo "ok"
  234. var x: int
  235. testAddrOperator(addr(x))
  236. ## Cast operator
  237. scope:
  238. let ast = myquote:
  239. cast[T](x)
  240. ast.matchAst:
  241. of nnkCast(ident"T", ident"x"):
  242. echo "ok"
  243. ## Object access operator ``.``
  244. scope:
  245. let ast = myquote:
  246. x.y
  247. ast.matchAst:
  248. of nnkDotExpr(ident"x", ident"y"):
  249. echo "ok"
  250. ## Array access operator ``[]``
  251. macro testArrayAccessOperator(ast: untyped): untyped =
  252. ast.matchAst:
  253. of nnkBracketExpr(ident"x", ident"y"):
  254. echo "ok"
  255. testArrayAccessOperator(x[y])
  256. ## Parentheses
  257. scope:
  258. let ast = myquote:
  259. (a + b) * c
  260. ast.matchAst:
  261. of nnkInfix(ident"*", nnkPar(nnkInfix(ident"+", ident"a", ident"b")), ident"c"):
  262. echo "parentheses ok"
  263. ## Tuple Constructors
  264. scope:
  265. let ast = myquote:
  266. (1, 2, 3)
  267. (a: 1, b: 2, c: 3)
  268. (1,)
  269. (a: 1)
  270. ()
  271. for it in ast:
  272. echo it.lispRepr
  273. it.matchAst:
  274. of nnkTupleConstr(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)):
  275. echo "simple tuple ok"
  276. of nnkTupleConstr(
  277. nnkExprColonExpr(ident"a", nnkIntLit(intVal = 1)),
  278. nnkExprColonExpr(ident"b", nnkIntLit(intVal = 2)),
  279. nnkExprColonExpr(ident"c", nnkIntLit(intVal = 3))
  280. ):
  281. echo "named tuple ok"
  282. of nnkTupleConstr(nnkIntLit(intVal = 1)):
  283. echo "one tuple ok"
  284. of nnkTupleConstr(nnkExprColonExpr(ident"a", nnkIntLit(intVal = 1))):
  285. echo "named one tuple ok"
  286. of nnkTupleConstr():
  287. echo "empty tuple ok"
  288. ## Curly braces
  289. scope:
  290. let ast = myquote:
  291. {1, 2, 3}
  292. ast.matchAst:
  293. of nnkCurly(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)):
  294. echo "ok"
  295. scope:
  296. let ast = myquote:
  297. {a: 3, b: 5}
  298. ast.matchAst:
  299. of nnkTableConstr(
  300. nnkExprColonExpr(ident"a", nnkIntLit(intVal = 3)),
  301. nnkExprColonExpr(ident"b", nnkIntLit(intVal = 5))
  302. ):
  303. echo "ok"
  304. ## Brackets
  305. scope:
  306. let ast = myquote:
  307. [1, 2, 3]
  308. ast.matchAst:
  309. of nnkBracket(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)):
  310. echo "ok"
  311. ## Ranges
  312. scope:
  313. let ast = myquote:
  314. 1..3
  315. ast.matchAst:
  316. of nnkInfix(
  317. ident"..",
  318. nnkIntLit(intVal = 1),
  319. nnkIntLit(intVal = 3)
  320. ):
  321. echo "ok"
  322. ## If expression
  323. scope:
  324. let ast = myquote:
  325. if cond1: expr1 elif cond2: expr2 else: expr3
  326. ast.matchAst:
  327. of {nnkIfExpr, nnkIfStmt}(
  328. {nnkElifExpr, nnkElifBranch}(`cond1`, `expr1`),
  329. {nnkElifExpr, nnkElifBranch}(`cond2`, `expr2`),
  330. {nnkElseExpr, nnkElse}(`expr3`)
  331. ):
  332. echo "ok"
  333. ## Documentation Comments
  334. scope:
  335. let ast = myquote:
  336. ## This is a comment
  337. ## This is part of the first comment
  338. stmt1
  339. ## Yet another
  340. ast.matchAst:
  341. of nnkStmtList(
  342. nnkCommentStmt(),
  343. `stmt1`,
  344. nnkCommentStmt()
  345. ):
  346. echo "ok"
  347. else:
  348. echo "warning!"
  349. echo ast.treeRepr
  350. echo "TEST causes no fail, because of a regression in Nim."
  351. scope:
  352. let ast = myquote:
  353. {.emit: "#include <stdio.h>".}
  354. ast.matchAst:
  355. of nnkPragma(
  356. nnkExprColonExpr(
  357. ident"emit",
  358. nnkStrLit(strVal = "#include <stdio.h>") # the "argument"
  359. )
  360. ):
  361. echo "ok"
  362. scope:
  363. let ast = myquote:
  364. {.pragma: cdeclRename, cdecl.}
  365. ast.matchAst:
  366. of nnkPragma(
  367. nnkExprColonExpr(
  368. ident"pragma", # this is always first when declaring a new pragma
  369. ident"cdeclRename" # the name of the pragma
  370. ),
  371. ident"cdecl"
  372. ):
  373. echo "ok"
  374. scope:
  375. let ast = myquote:
  376. if cond1:
  377. stmt1
  378. elif cond2:
  379. stmt2
  380. elif cond3:
  381. stmt3
  382. else:
  383. stmt4
  384. ast.matchAst:
  385. of nnkIfStmt(
  386. nnkElifBranch(`cond1`, `stmt1`),
  387. nnkElifBranch(`cond2`, `stmt2`),
  388. nnkElifBranch(`cond3`, `stmt3`),
  389. nnkElse(`stmt4`)
  390. ):
  391. echo "ok"
  392. scope:
  393. let ast = myquote:
  394. x = 42
  395. ast.matchAst:
  396. of nnkAsgn(ident"x", nnkIntLit(intVal = 42)):
  397. echo "ok"
  398. scope:
  399. let ast = myquote:
  400. stmt1
  401. stmt2
  402. stmt3
  403. ast.matchAst:
  404. of nnkStmtList(`stmt1`, `stmt2`, `stmt3`):
  405. assert stmt1.strVal == "stmt1"
  406. assert stmt2.strVal == "stmt2"
  407. assert stmt3.strVal == "stmt3"
  408. echo "ok"
  409. ## Case statement
  410. scope:
  411. let ast = myquote:
  412. case expr1
  413. of expr2, expr3..expr4:
  414. stmt1
  415. of expr5:
  416. stmt2
  417. elif cond1:
  418. stmt3
  419. else:
  420. stmt4
  421. ast.matchAst:
  422. of nnkCaseStmt(
  423. `expr1`,
  424. nnkOfBranch(`expr2`, {nnkRange, nnkInfix}(_, `expr3`, `expr4`), `stmt1`),
  425. nnkOfBranch(`expr5`, `stmt2`),
  426. nnkElifBranch(`cond1`, `stmt3`),
  427. nnkElse(`stmt4`)
  428. ):
  429. echo "ok"
  430. ## While statement
  431. scope:
  432. let ast = myquote:
  433. while expr1:
  434. stmt1
  435. ast.matchAst:
  436. of nnkWhileStmt(`expr1`, `stmt1`):
  437. echo "ok"
  438. ## For statement
  439. scope:
  440. let ast = myquote:
  441. for ident1, ident2 in expr1:
  442. stmt1
  443. ast.matchAst:
  444. of nnkForStmt(`ident1`, `ident2`, `expr1`, `stmt1`):
  445. echo "ok"
  446. ## Try statement
  447. scope:
  448. let ast = myquote:
  449. try:
  450. stmt1
  451. except e1, e2:
  452. stmt2
  453. except e3:
  454. stmt3
  455. except:
  456. stmt4
  457. finally:
  458. stmt5
  459. ast.matchAst:
  460. of nnkTryStmt(
  461. `stmt1`,
  462. nnkExceptBranch(`e1`, `e2`, `stmt2`),
  463. nnkExceptBranch(`e3`, `stmt3`),
  464. nnkExceptBranch(`stmt4`),
  465. nnkFinally(`stmt5`)
  466. ):
  467. echo "ok"
  468. ## Return statement
  469. scope:
  470. let ast = myquote:
  471. return expr1
  472. ast.matchAst:
  473. of nnkReturnStmt(`expr1`):
  474. echo "ok"
  475. ## Continue statement
  476. scope:
  477. let ast = myquote:
  478. continue
  479. ast.matchAst:
  480. of nnkContinueStmt:
  481. echo "ok"
  482. ## Break statement
  483. scope:
  484. let ast = myquote:
  485. break otherLocation
  486. ast.matchAst:
  487. of nnkBreakStmt(ident"otherLocation"):
  488. echo "ok"
  489. ## Block statement
  490. scope:
  491. template blockStatement {.dirty.} =
  492. block name:
  493. discard
  494. let ast = getAst(blockStatement())
  495. ast.matchAst:
  496. of nnkBlockStmt(ident"name", nnkStmtList):
  497. echo "ok"
  498. ## Asm statement
  499. scope:
  500. let ast = myquote:
  501. asm """some asm"""
  502. ast.matchAst:
  503. of nnkAsmStmt(
  504. nnkEmpty(), # for pragmas
  505. nnkTripleStrLit(strVal = "some asm"),
  506. ):
  507. echo "ok"
  508. ## Import section
  509. scope:
  510. let ast = myquote:
  511. import math
  512. ast.matchAst:
  513. of nnkImportStmt(ident"math"):
  514. echo "ok"
  515. scope:
  516. let ast = myquote:
  517. import math except pow
  518. ast.matchAst:
  519. of nnkImportExceptStmt(ident"math",ident"pow"):
  520. echo "ok"
  521. scope:
  522. let ast = myquote:
  523. import strutils as su
  524. ast.matchAst:
  525. of nnkImportStmt(
  526. nnkInfix(
  527. ident"as",
  528. ident"strutils",
  529. ident"su"
  530. )
  531. ):
  532. echo "ok"
  533. ## From statement
  534. scope:
  535. let ast = myquote:
  536. from math import pow
  537. ast.matchAst:
  538. of nnkFromStmt(ident"math", ident"pow"):
  539. echo "ok"
  540. ## Export statement
  541. scope:
  542. let ast = myquote:
  543. export unsigned
  544. ast.matchAst:
  545. of nnkExportStmt(ident"unsigned"):
  546. echo "ok"
  547. scope:
  548. let ast = myquote:
  549. export math except pow # we're going to implement our own exponentiation
  550. ast.matchAst:
  551. of nnkExportExceptStmt(ident"math",ident"pow"):
  552. echo "ok"
  553. ## Include statement
  554. scope:
  555. let ast = myquote:
  556. include blocks
  557. ast.matchAst:
  558. of nnkIncludeStmt(ident"blocks"):
  559. echo "ok"
  560. ## Var section
  561. scope:
  562. let ast = myquote:
  563. var a = 3
  564. ast.matchAst:
  565. of nnkVarSection(
  566. nnkIdentDefs(
  567. ident"a",
  568. nnkEmpty(), # or nnkIdent(...) if the variable declares the type
  569. nnkIntLit(intVal = 3),
  570. )
  571. ):
  572. echo "ok"
  573. ## Let section
  574. scope:
  575. let ast = myquote:
  576. let a = 3
  577. ast.matchAst:
  578. of nnkLetSection(
  579. nnkIdentDefs(
  580. ident"a",
  581. nnkEmpty(), # or nnkIdent(...) for the type
  582. nnkIntLit(intVal = 3),
  583. )
  584. ):
  585. echo "ok"
  586. ## Const section
  587. scope:
  588. let ast = myquote:
  589. const a = 3
  590. ast.matchAst:
  591. of nnkConstSection(
  592. nnkConstDef( # not nnkConstDefs!
  593. ident"a",
  594. nnkEmpty(), # or nnkIdent(...) if the variable declares the type
  595. nnkIntLit(intVal = 3), # required in a const declaration!
  596. )
  597. ):
  598. echo "ok"
  599. ## Type section
  600. scope:
  601. let ast = myquote:
  602. type A = int
  603. ast.matchAst:
  604. of nnkTypeSection(
  605. nnkTypeDef(
  606. ident"A",
  607. nnkEmpty(),
  608. ident"int"
  609. )
  610. ):
  611. echo "ok"
  612. scope:
  613. let ast = myquote:
  614. type MyInt = distinct int
  615. ast.peelOff({nnkTypeSection}).matchAst:
  616. of# ...
  617. nnkTypeDef(
  618. ident"MyInt",
  619. nnkEmpty(),
  620. nnkDistinctTy(
  621. ident"int"
  622. )
  623. ):
  624. echo "ok"
  625. scope:
  626. let ast = myquote:
  627. type A[T] = expr1
  628. ast.matchAst:
  629. of nnkTypeSection(
  630. nnkTypeDef(
  631. ident"A",
  632. nnkGenericParams(
  633. nnkIdentDefs(
  634. ident"T",
  635. nnkEmpty(), # if the type is declared with options, like
  636. # ``[T: SomeInteger]``, they are given here
  637. nnkEmpty()
  638. )
  639. ),
  640. `expr1`
  641. )
  642. ):
  643. echo "ok"
  644. scope:
  645. let ast = myquote:
  646. type IO = object of RootObj
  647. ast.peelOff(nnkTypeSection).matchAst:
  648. of nnkTypeDef(
  649. ident"IO",
  650. nnkEmpty(),
  651. nnkObjectTy(
  652. nnkEmpty(), # no pragmas here
  653. nnkOfInherit(
  654. ident"RootObj" # inherits from RootObj
  655. ),
  656. nnkEmpty()
  657. )
  658. ):
  659. echo "ok"
  660. scope:
  661. macro testRecCase(ast: untyped): untyped =
  662. ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst:
  663. of nnkTypeDef(
  664. nnkPragmaExpr(
  665. ident"Obj",
  666. nnkPragma(ident"inheritable")
  667. ),
  668. nnkGenericParams(
  669. nnkIdentDefs(
  670. ident"T",
  671. nnkEmpty(),
  672. nnkEmpty())
  673. ),
  674. nnkObjectTy(
  675. nnkEmpty(),
  676. nnkEmpty(),
  677. nnkRecList( # list of object parameters
  678. nnkIdentDefs(
  679. ident"name",
  680. ident"string",
  681. nnkEmpty()
  682. ),
  683. nnkRecCase( # case statement within object (not nnkCaseStmt)
  684. nnkIdentDefs(
  685. ident"isFat",
  686. ident"bool",
  687. nnkEmpty()
  688. ),
  689. nnkOfBranch(
  690. ident"true",
  691. nnkRecList( # again, a list of object parameters
  692. nnkIdentDefs(
  693. ident"m",
  694. nnkBracketExpr(
  695. ident"array",
  696. nnkIntLit(intVal = 100000),
  697. ident"T"
  698. ),
  699. nnkEmpty()
  700. )
  701. )
  702. ),
  703. nnkOfBranch(
  704. ident"false",
  705. nnkRecList(
  706. nnkIdentDefs(
  707. ident"m",
  708. nnkBracketExpr(
  709. ident"array",
  710. nnkIntLit(intVal = 10),
  711. ident"T"
  712. ),
  713. nnkEmpty()
  714. )
  715. )
  716. )
  717. )
  718. )
  719. )
  720. ):
  721. echo "ok"
  722. testRecCase:
  723. type Obj[T] {.inheritable.} = object
  724. name: string
  725. case isFat: bool
  726. of true:
  727. m: array[100_000, T]
  728. of false:
  729. m: array[10, T]
  730. scope:
  731. let ast = myquote:
  732. type X = enum
  733. First
  734. ast.peelOff({nnkStmtList, nnkTypeSection})[2].matchAst:
  735. of nnkEnumTy(
  736. nnkEmpty(),
  737. ident"First" # you need at least one nnkIdent or the compiler complains
  738. ):
  739. echo "ok"
  740. scope:
  741. let ast = myquote:
  742. type Con = concept x,y,z
  743. (x & y & z) is string
  744. ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst:
  745. of nnkTypeDef(_, _, nnkTypeClassTy(nnkArgList, _, _, nnkStmtList)):
  746. # note this isn't nnkConceptTy!
  747. echo "ok"
  748. scope:
  749. let astX = myquote:
  750. type
  751. A[T: static[int]] = object
  752. let ast = astX.peelOff({nnkStmtList, nnkTypeSection})
  753. ast.matchAst(err): # this is a sub ast for this a findAst or something like that is useful
  754. of nnkTypeDef(_, nnkGenericParams( nnkIdentDefs( ident"T", nnkCall( ident"[]", ident"static", _ ), _ )), _):
  755. echo "ok"
  756. else:
  757. echo "foobar"
  758. echo ast.treeRepr
  759. scope:
  760. let ast = myquote:
  761. type MyProc[T] = proc(x: T)
  762. ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst(err):
  763. of nnkTypeDef(
  764. ident"MyProc",
  765. nnkGenericParams, # here, not with the proc
  766. nnkProcTy( # behaves like a procedure declaration from here on
  767. nnkFormalParams, _
  768. )
  769. ):
  770. echo "ok"
  771. ## Mixin statement
  772. macro testMixinStatement(ast: untyped): untyped =
  773. ast.peelOff(nnkStmtList).matchAst:
  774. of nnkMixinStmt(ident"x"):
  775. echo "ok"
  776. testMixinStatement:
  777. mixin x
  778. ## Bind statement
  779. macro testBindStmt(ast: untyped): untyped =
  780. ast[0].matchAst:
  781. of `node` @ nnkBindStmt(ident"x"):
  782. echo "ok"
  783. testBindStmt:
  784. bind x
  785. ## Procedure declaration
  786. macro testProcedureDeclaration(ast: untyped): untyped =
  787. # NOTE this is wrong in astdef
  788. ast.peelOff(nnkStmtList).matchAst:
  789. of nnkProcDef(
  790. nnkPostfix(ident"*", ident"hello"), # the exported proc name
  791. nnkEmpty, # patterns for term rewriting in templates and macros (not procs)
  792. nnkGenericParams( # generic type parameters, like with type declaration
  793. nnkIdentDefs(
  794. ident"T",
  795. ident"SomeInteger", _
  796. )
  797. ),
  798. nnkFormalParams(
  799. ident"int", # the first FormalParam is the return type. nnkEmpty if there is none
  800. nnkIdentDefs(
  801. ident"x",
  802. ident"int", # type type (required for procs, not for templates)
  803. nnkIntLit(intVal = 3) # a default value
  804. ),
  805. nnkIdentDefs(
  806. ident"y",
  807. ident"float32",
  808. nnkEmpty
  809. )
  810. ),
  811. nnkPragma(ident"inline"),
  812. nnkEmpty, # reserved slot for future use
  813. `meat` @ nnkStmtList # the meat of the proc
  814. ):
  815. echo "ok got meat: ", meat.lispRepr
  816. testProcedureDeclaration:
  817. proc hello*[T: SomeInteger](x: int = 3, y: float32): int {.inline.} = discard
  818. scope:
  819. var ast = myquote:
  820. proc foobar(a, b: int): void
  821. ast = ast[3]
  822. ast.matchAst: # sub expression
  823. of nnkFormalParams(
  824. _, # return would be here
  825. nnkIdentDefs(
  826. ident"a", # the first parameter
  827. ident"b", # directly to the second parameter
  828. ident"int", # their shared type identifier
  829. nnkEmpty, # default value would go here
  830. )
  831. ):
  832. echo "ok"
  833. scope:
  834. let ast = myquote:
  835. proc hello(): var int
  836. ast[3].matchAst: # subAst
  837. of nnkFormalParams(
  838. nnkVarTy(
  839. ident"int"
  840. )
  841. ):
  842. echo "ok"
  843. ## Iterator declaration
  844. scope:
  845. let ast = myquote:
  846. iterator nonsense[T](x: seq[T]): float {.closure.} =
  847. discard
  848. ast.matchAst:
  849. of nnkIteratorDef(ident"nonsense", nnkEmpty, _, _, _, _, _):
  850. echo "ok"
  851. ## Converter declaration
  852. scope:
  853. let ast = myquote:
  854. converter toBool(x: float): bool
  855. ast.matchAst:
  856. of nnkConverterDef(ident"toBool",_,_,_,_,_,_):
  857. echo "ok"
  858. ## Template declaration
  859. scope:
  860. let ast = myquote:
  861. template optOpt{expr1}(a: int): int
  862. ast.matchAst:
  863. of nnkTemplateDef(ident"optOpt", nnkStmtList(`expr1`), _, _, _, _, _):
  864. echo "ok"