mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-30 01:44:37 +00:00
With this commit, we no longer see an error if we pass `--styleCheck:error` when compiling a file that contains `import sugar` or `import std/with`. The problem was that those modules (and only those modules) import `std/private/underscored_calls`, which contained a styleCheck issue: its spelling of `nnkArgList` didn't match the `nnkArglist` spelling in `macros.nim`. This commit fixes the issue by renaming `nnkArgList` to `nnkArglist` repo-wide. The other way around would be a breaking change for code that used `nnkArglist` and `--styleCheck:error`. Fixes: #16174
1088 lines
22 KiB
Nim
1088 lines
22 KiB
Nim
discard """
|
|
action: compile
|
|
"""
|
|
|
|
# this test should ensure that the AST doesn't change slightly without it getting noticed.
|
|
|
|
import ../ast_pattern_matching
|
|
|
|
template expectNimNode(arg: untyped): NimNode = arg
|
|
## This template here is just to be injected by `myquote`, so that
|
|
## a nice error message appears when the captured symbols are not of
|
|
## type `NimNode`.
|
|
|
|
proc substitudeComments(symbols, values, n: NimNode): NimNode =
|
|
## substitutes all nodes of kind nnkCommentStmt to parameter
|
|
## symbols. Consumes the argument `n`.
|
|
if n.kind == nnkCommentStmt:
|
|
values.add newCall(bindSym"newCommentStmtNode", newLit(n.strVal))
|
|
# Gensym doesn't work for parameters. These identifiers won't
|
|
# clash unless an argument is constructed to clash here.
|
|
symbols.add ident("comment" & $values.len & "_XObBdOnh6meCuJK2smZV")
|
|
return symbols[^1]
|
|
for i in 0 ..< n.len:
|
|
n[i] = substitudeComments(symbols, values, n[i])
|
|
return n
|
|
|
|
macro myquote*(args: varargs[untyped]): untyped =
|
|
expectMinLen(args, 1)
|
|
|
|
# This is a workaround for #10430 where comments are removed in
|
|
# template expansions. This workaround lifts all comments
|
|
# statements to be arguments of the temporary template.
|
|
|
|
let extraCommentSymbols = newNimNode(nnkBracket)
|
|
let extraCommentGenExpr = newNimNode(nnkBracket)
|
|
let body = substitudeComments(
|
|
extraCommentSymbols, extraCommentGenExpr, args[^1]
|
|
)
|
|
|
|
let formalParams = nnkFormalParams.newTree(ident"untyped")
|
|
for i in 0 ..< args.len-1:
|
|
formalParams.add nnkIdentDefs.newTree(
|
|
args[i], ident"untyped", newEmptyNode()
|
|
)
|
|
for sym in extraCommentSymbols:
|
|
formalParams.add nnkIdentDefs.newTree(
|
|
sym, ident"untyped", newEmptyNode()
|
|
)
|
|
|
|
let templateSym = genSym(nskTemplate)
|
|
let templateDef = nnkTemplateDef.newTree(
|
|
templateSym,
|
|
newEmptyNode(),
|
|
newEmptyNode(),
|
|
formalParams,
|
|
nnkPragma.newTree(ident"dirty"),
|
|
newEmptyNode(),
|
|
args[^1]
|
|
)
|
|
|
|
let templateCall = newCall(templateSym)
|
|
for i in 0 ..< args.len-1:
|
|
let symName = args[i]
|
|
# identifiers and quoted identifiers are allowed.
|
|
if symName.kind == nnkAccQuoted:
|
|
symName.expectLen 1
|
|
symName[0].expectKind nnkIdent
|
|
else:
|
|
symName.expectKind nnkIdent
|
|
templateCall.add newCall(bindSym"expectNimNode", symName)
|
|
for expr in extraCommentGenExpr:
|
|
templateCall.add expr
|
|
let getAstCall = newCall(bindSym"getAst", templateCall)
|
|
result = newStmtList(templateDef, getAstCall)
|
|
|
|
|
|
macro testAddrAst(arg: typed): bool =
|
|
arg.expectKind nnkStmtListExpr
|
|
arg[0].expectKind(nnkVarSection)
|
|
arg[1].expectKind({nnkAddr, nnkCall})
|
|
result = newLit(arg[1].kind == nnkCall)
|
|
|
|
const newAddrAst: bool = testAddrAst((var x: int; addr(x)))
|
|
|
|
static:
|
|
echo "new addr ast: ", newAddrAst
|
|
|
|
# TODO test on matching failures
|
|
|
|
proc peelOff*(arg: NimNode, kinds: set[NimNodeKind]): NimNode {.compileTime.} =
|
|
## Peel off nodes of a specific kinds.
|
|
if arg.len == 1 and arg.kind in kinds:
|
|
arg[0].peelOff(kinds)
|
|
else:
|
|
arg
|
|
|
|
proc peelOff*(arg: NimNode, kind: NimNodeKind): NimNode {.compileTime.} =
|
|
## Peel off nodes of a specific kind.
|
|
if arg.len == 1 and arg.kind == kind:
|
|
arg[0].peelOff(kind)
|
|
else:
|
|
arg
|
|
|
|
static:
|
|
template testPattern(pattern, astArg: untyped): untyped =
|
|
let ast = quote do: `astArg`
|
|
ast.matchAst:
|
|
of `pattern`:
|
|
echo "ok"
|
|
|
|
template testPatternFail(pattern, astArg: untyped): untyped =
|
|
let ast = quote do: `astArg`
|
|
ast.matchAst:
|
|
of `pattern`:
|
|
error("this should not match", ast)
|
|
else:
|
|
echo "OK"
|
|
|
|
|
|
testPattern nnkIntLit(intVal = 42), 42
|
|
testPattern nnkInt8Lit(intVal = 42), 42'i8
|
|
testPattern nnkInt16Lit(intVal = 42), 42'i16
|
|
testPattern nnkInt32Lit(intVal = 42), 42'i32
|
|
testPattern nnkInt64Lit(intVal = 42), 42'i64
|
|
testPattern nnkUInt8Lit(intVal = 42), 42'u8
|
|
testPattern nnkUInt16Lit(intVal = 42), 42'u16
|
|
testPattern nnkUInt32Lit(intVal = 42), 42'u32
|
|
testPattern nnkUInt64Lit(intVal = 42), 42'u64
|
|
#testPattern nnkFloat64Lit(floatVal = 42.0), 42.0
|
|
testPattern nnkFloat32Lit(floatVal = 42.0), 42.0'f32
|
|
#testPattern nnkFloat64Lit(floatVal = 42.0), 42.0'f64
|
|
testPattern nnkStrLit(strVal = "abc"), "abc"
|
|
testPattern nnkRStrLit(strVal = "abc"), r"abc"
|
|
testPattern nnkTripleStrLit(strVal = "abc"), """abc"""
|
|
testPattern nnkCharLit(intVal = 32), ' '
|
|
testPattern nnkNilLit(), nil
|
|
testPattern nnkIdent(strVal = "myIdentifier"), myIdentifier
|
|
|
|
testPatternFail nnkInt8Lit(intVal = 42), 42'i16
|
|
testPatternFail nnkInt16Lit(intVal = 42), 42'i8
|
|
|
|
|
|
|
|
# this should be just `block` but it doesn't work that way anymore because of VM.
|
|
macro scope(arg: untyped): untyped =
|
|
let procSym = genSym(nskProc)
|
|
result = quote do:
|
|
proc `procSym`() {.compileTime.} =
|
|
`arg`
|
|
|
|
`procSym`()
|
|
|
|
static:
|
|
## Command call
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
echo "abc", "xyz"
|
|
|
|
ast.matchAst:
|
|
of nnkCommand(ident"echo", "abc", "xyz"):
|
|
echo "ok"
|
|
|
|
## Call with ``()``
|
|
|
|
scope:
|
|
let ast = myquote:
|
|
echo("abc", "xyz")
|
|
|
|
ast.matchAst:
|
|
of nnkCall(ident"echo", "abc", "xyz"):
|
|
echo "ok"
|
|
|
|
## Infix operator call
|
|
|
|
macro testInfixOperatorCall(ast: untyped): untyped =
|
|
ast.matchAst(errorSym):
|
|
of nnkInfix(
|
|
ident"&",
|
|
nnkStrLit(strVal = "abc"),
|
|
nnkStrLit(strVal = "xyz")
|
|
):
|
|
echo "ok1"
|
|
of nnkInfix(
|
|
ident"+",
|
|
nnkIntLit(intVal = 5),
|
|
nnkInfix(
|
|
ident"*",
|
|
nnkIntLit(intVal = 3),
|
|
nnkIntLit(intVal = 4)
|
|
)
|
|
):
|
|
echo "ok2"
|
|
of nnkCall(
|
|
nnkAccQuoted(
|
|
ident"+"
|
|
),
|
|
nnkIntLit(intVal = 3),
|
|
nnkIntLit(intVal = 4)
|
|
):
|
|
echo "ok3"
|
|
|
|
testInfixOperatorCall("abc" & "xyz")
|
|
testInfixOperatorCall(5 + 3 * 4)
|
|
testInfixOperatorCall(`+`(3, 4))
|
|
|
|
|
|
## Prefix operator call
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
? "xyz"
|
|
|
|
ast.matchAst(err):
|
|
of nnkPrefix(
|
|
ident"?",
|
|
nnkStrLit(strVal = "xyz")
|
|
):
|
|
echo "ok"
|
|
|
|
|
|
## Postfix operator call
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
proc identifier*
|
|
|
|
ast[0].matchAst(err):
|
|
of nnkPostfix(
|
|
ident"*",
|
|
ident"identifier"
|
|
):
|
|
echo "ok"
|
|
|
|
|
|
## Call with named arguments
|
|
|
|
macro testCallWithNamedArguments(ast: untyped): untyped =
|
|
ast.peelOff(nnkStmtList).matchAst:
|
|
of nnkCall(
|
|
ident"writeLine",
|
|
nnkExprEqExpr(
|
|
ident"file",
|
|
ident"stdout"
|
|
),
|
|
nnkStrLit(strVal = "hallo")
|
|
):
|
|
echo "ok"
|
|
|
|
testCallWithNamedArguments:
|
|
writeLine(file=stdout, "hallo")
|
|
|
|
## Call with raw string literal
|
|
scope:
|
|
let ast = myquote:
|
|
echo"abc"
|
|
|
|
|
|
ast.matchAst(err):
|
|
of nnkCallStrLit(
|
|
ident"echo",
|
|
nnkRStrLit(strVal = "abc")
|
|
):
|
|
echo "ok"
|
|
|
|
## Dereference operator ``[]``
|
|
|
|
scope:
|
|
# The dereferece operator exists only on a typed ast.
|
|
macro testDereferenceOperator(ast: typed): untyped =
|
|
ast.matchAst(err):
|
|
of nnkDerefExpr(_):
|
|
echo "ok"
|
|
|
|
var x: ptr int
|
|
testDereferenceOperator(x[])
|
|
|
|
|
|
|
|
## Addr operator
|
|
|
|
scope:
|
|
# The addr operator exists only on a typed ast.
|
|
macro testAddrOperator(ast: untyped): untyped =
|
|
echo ast.treeRepr
|
|
ast.matchAst(err):
|
|
of nnkAddr(ident"x"):
|
|
echo "old nim"
|
|
of nnkCall(ident"addr", ident"x"):
|
|
echo "ok"
|
|
|
|
var x: int
|
|
testAddrOperator(addr(x))
|
|
|
|
|
|
## Cast operator
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
cast[T](x)
|
|
|
|
ast.matchAst:
|
|
of nnkCast(ident"T", ident"x"):
|
|
echo "ok"
|
|
|
|
|
|
## Object access operator ``.``
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
x.y
|
|
|
|
ast.matchAst:
|
|
of nnkDotExpr(ident"x", ident"y"):
|
|
echo "ok"
|
|
|
|
## Array access operator ``[]``
|
|
|
|
macro testArrayAccessOperator(ast: untyped): untyped =
|
|
ast.matchAst:
|
|
of nnkBracketExpr(ident"x", ident"y"):
|
|
echo "ok"
|
|
|
|
testArrayAccessOperator(x[y])
|
|
|
|
|
|
|
|
## Parentheses
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
(1, 2, (3))
|
|
|
|
ast.matchAst:
|
|
of nnkPar(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkPar(nnkIntLit(intVal = 3))):
|
|
echo "ok"
|
|
|
|
|
|
## Curly braces
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
{1, 2, 3}
|
|
|
|
ast.matchAst:
|
|
of nnkCurly(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)):
|
|
echo "ok"
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
{a: 3, b: 5}
|
|
|
|
ast.matchAst:
|
|
of nnkTableConstr(
|
|
nnkExprColonExpr(ident"a", nnkIntLit(intVal = 3)),
|
|
nnkExprColonExpr(ident"b", nnkIntLit(intVal = 5))
|
|
):
|
|
echo "ok"
|
|
|
|
|
|
## Brackets
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
[1, 2, 3]
|
|
|
|
ast.matchAst:
|
|
of nnkBracket(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)):
|
|
echo "ok"
|
|
|
|
|
|
## Ranges
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
1..3
|
|
|
|
ast.matchAst:
|
|
of nnkInfix(
|
|
ident"..",
|
|
nnkIntLit(intVal = 1),
|
|
nnkIntLit(intVal = 3)
|
|
):
|
|
echo "ok"
|
|
|
|
|
|
## If expression
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
if cond1: expr1 elif cond2: expr2 else: expr3
|
|
|
|
ast.matchAst:
|
|
of {nnkIfExpr, nnkIfStmt}(
|
|
{nnkElifExpr, nnkElifBranch}(`cond1`, `expr1`),
|
|
{nnkElifExpr, nnkElifBranch}(`cond2`, `expr2`),
|
|
{nnkElseExpr, nnkElse}(`expr3`)
|
|
):
|
|
echo "ok"
|
|
|
|
## Documentation Comments
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
## This is a comment
|
|
## This is part of the first comment
|
|
stmt1
|
|
## Yet another
|
|
|
|
ast.matchAst:
|
|
of nnkStmtList(
|
|
nnkCommentStmt(),
|
|
`stmt1`,
|
|
nnkCommentStmt()
|
|
):
|
|
echo "ok"
|
|
else:
|
|
echo "warning!"
|
|
echo ast.treeRepr
|
|
echo "TEST causes no fail, because of a regression in Nim."
|
|
|
|
scope:
|
|
let ast = myquote:
|
|
{.emit: "#include <stdio.h>".}
|
|
|
|
ast.matchAst:
|
|
of nnkPragma(
|
|
nnkExprColonExpr(
|
|
ident"emit",
|
|
nnkStrLit(strVal = "#include <stdio.h>") # the "argument"
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
scope:
|
|
let ast = myquote:
|
|
{.pragma: cdeclRename, cdecl.}
|
|
|
|
ast.matchAst:
|
|
of nnkPragma(
|
|
nnkExprColonExpr(
|
|
ident"pragma", # this is always first when declaring a new pragma
|
|
ident"cdeclRename" # the name of the pragma
|
|
),
|
|
ident"cdecl"
|
|
):
|
|
echo "ok"
|
|
|
|
|
|
|
|
scope:
|
|
let ast = myquote:
|
|
if cond1:
|
|
stmt1
|
|
elif cond2:
|
|
stmt2
|
|
elif cond3:
|
|
stmt3
|
|
else:
|
|
stmt4
|
|
|
|
ast.matchAst:
|
|
of nnkIfStmt(
|
|
nnkElifBranch(`cond1`, `stmt1`),
|
|
nnkElifBranch(`cond2`, `stmt2`),
|
|
nnkElifBranch(`cond3`, `stmt3`),
|
|
nnkElse(`stmt4`)
|
|
):
|
|
echo "ok"
|
|
|
|
|
|
|
|
scope:
|
|
let ast = myquote:
|
|
x = 42
|
|
|
|
ast.matchAst:
|
|
of nnkAsgn(ident"x", nnkIntLit(intVal = 42)):
|
|
echo "ok"
|
|
|
|
|
|
|
|
scope:
|
|
let ast = myquote:
|
|
stmt1
|
|
stmt2
|
|
stmt3
|
|
|
|
ast.matchAst:
|
|
of nnkStmtList(`stmt1`, `stmt2`, `stmt3`):
|
|
assert stmt1.strVal == "stmt1"
|
|
assert stmt2.strVal == "stmt2"
|
|
assert stmt3.strVal == "stmt3"
|
|
echo "ok"
|
|
|
|
## Case statement
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
case expr1
|
|
of expr2, expr3..expr4:
|
|
stmt1
|
|
of expr5:
|
|
stmt2
|
|
elif cond1:
|
|
stmt3
|
|
else:
|
|
stmt4
|
|
|
|
ast.matchAst:
|
|
of nnkCaseStmt(
|
|
`expr1`,
|
|
nnkOfBranch(`expr2`, {nnkRange, nnkInfix}(_, `expr3`, `expr4`), `stmt1`),
|
|
nnkOfBranch(`expr5`, `stmt2`),
|
|
nnkElifBranch(`cond1`, `stmt3`),
|
|
nnkElse(`stmt4`)
|
|
):
|
|
echo "ok"
|
|
|
|
## While statement
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
while expr1:
|
|
stmt1
|
|
|
|
ast.matchAst:
|
|
of nnkWhileStmt(`expr1`, `stmt1`):
|
|
echo "ok"
|
|
|
|
|
|
## For statement
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
for ident1, ident2 in expr1:
|
|
stmt1
|
|
|
|
ast.matchAst:
|
|
of nnkForStmt(`ident1`, `ident2`, `expr1`, `stmt1`):
|
|
echo "ok"
|
|
|
|
|
|
## Try statement
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
try:
|
|
stmt1
|
|
except e1, e2:
|
|
stmt2
|
|
except e3:
|
|
stmt3
|
|
except:
|
|
stmt4
|
|
finally:
|
|
stmt5
|
|
|
|
ast.matchAst:
|
|
of nnkTryStmt(
|
|
`stmt1`,
|
|
nnkExceptBranch(`e1`, `e2`, `stmt2`),
|
|
nnkExceptBranch(`e3`, `stmt3`),
|
|
nnkExceptBranch(`stmt4`),
|
|
nnkFinally(`stmt5`)
|
|
):
|
|
echo "ok"
|
|
|
|
|
|
## Return statement
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
return expr1
|
|
|
|
ast.matchAst:
|
|
of nnkReturnStmt(`expr1`):
|
|
echo "ok"
|
|
|
|
|
|
## Continue statement
|
|
|
|
scope:
|
|
let ast = myquote:
|
|
continue
|
|
|
|
ast.matchAst:
|
|
of nnkContinueStmt:
|
|
echo "ok"
|
|
|
|
## Break statement
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
break otherLocation
|
|
|
|
ast.matchAst:
|
|
of nnkBreakStmt(ident"otherLocation"):
|
|
echo "ok"
|
|
|
|
## Block statement
|
|
|
|
scope:
|
|
|
|
template blockStatement {.dirty.} =
|
|
block name:
|
|
discard
|
|
|
|
let ast = getAst(blockStatement())
|
|
|
|
ast.matchAst:
|
|
of nnkBlockStmt(ident"name", nnkStmtList):
|
|
echo "ok"
|
|
|
|
## Asm statement
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
asm """some asm"""
|
|
|
|
ast.matchAst:
|
|
of nnkAsmStmt(
|
|
nnkEmpty(), # for pragmas
|
|
nnkTripleStrLit(strVal = "some asm"),
|
|
):
|
|
echo "ok"
|
|
|
|
## Import section
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
import math
|
|
|
|
ast.matchAst:
|
|
of nnkImportStmt(ident"math"):
|
|
echo "ok"
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
import math except pow
|
|
|
|
ast.matchAst:
|
|
of nnkImportExceptStmt(ident"math",ident"pow"):
|
|
echo "ok"
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
import strutils as su
|
|
|
|
ast.matchAst:
|
|
of nnkImportStmt(
|
|
nnkInfix(
|
|
ident"as",
|
|
ident"strutils",
|
|
ident"su"
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
## From statement
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
from math import pow
|
|
|
|
ast.matchAst:
|
|
of nnkFromStmt(ident"math", ident"pow"):
|
|
echo "ok"
|
|
|
|
## Export statement
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
export unsigned
|
|
|
|
ast.matchAst:
|
|
of nnkExportStmt(ident"unsigned"):
|
|
echo "ok"
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
export math except pow # we're going to implement our own exponentiation
|
|
|
|
ast.matchAst:
|
|
of nnkExportExceptStmt(ident"math",ident"pow"):
|
|
echo "ok"
|
|
|
|
## Include statement
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
include blocks
|
|
|
|
ast.matchAst:
|
|
of nnkIncludeStmt(ident"blocks"):
|
|
echo "ok"
|
|
|
|
## Var section
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
var a = 3
|
|
|
|
ast.matchAst:
|
|
of nnkVarSection(
|
|
nnkIdentDefs(
|
|
ident"a",
|
|
nnkEmpty(), # or nnkIdent(...) if the variable declares the type
|
|
nnkIntLit(intVal = 3),
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
## Let section
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
let a = 3
|
|
|
|
ast.matchAst:
|
|
of nnkLetSection(
|
|
nnkIdentDefs(
|
|
ident"a",
|
|
nnkEmpty(), # or nnkIdent(...) for the type
|
|
nnkIntLit(intVal = 3),
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
## Const section
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
const a = 3
|
|
|
|
ast.matchAst:
|
|
of nnkConstSection(
|
|
nnkConstDef( # not nnkConstDefs!
|
|
ident"a",
|
|
nnkEmpty(), # or nnkIdent(...) if the variable declares the type
|
|
nnkIntLit(intVal = 3), # required in a const declaration!
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
## Type section
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
type A = int
|
|
|
|
ast.matchAst:
|
|
of nnkTypeSection(
|
|
nnkTypeDef(
|
|
ident"A",
|
|
nnkEmpty(),
|
|
ident"int"
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
type MyInt = distinct int
|
|
|
|
ast.peelOff({nnkTypeSection}).matchAst:
|
|
of# ...
|
|
nnkTypeDef(
|
|
ident"MyInt",
|
|
nnkEmpty(),
|
|
nnkDistinctTy(
|
|
ident"int"
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
type A[T] = expr1
|
|
|
|
ast.matchAst:
|
|
of nnkTypeSection(
|
|
nnkTypeDef(
|
|
ident"A",
|
|
nnkGenericParams(
|
|
nnkIdentDefs(
|
|
ident"T",
|
|
nnkEmpty(), # if the type is declared with options, like
|
|
# ``[T: SomeInteger]``, they are given here
|
|
nnkEmpty()
|
|
)
|
|
),
|
|
`expr1`
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
type IO = object of RootObj
|
|
|
|
ast.peelOff(nnkTypeSection).matchAst:
|
|
of nnkTypeDef(
|
|
ident"IO",
|
|
nnkEmpty(),
|
|
nnkObjectTy(
|
|
nnkEmpty(), # no pragmas here
|
|
nnkOfInherit(
|
|
ident"RootObj" # inherits from RootObj
|
|
),
|
|
nnkEmpty()
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
scope:
|
|
macro testRecCase(ast: untyped): untyped =
|
|
ast.peelOff({nnkStmtList, nnkTypeSection})[2].matchAst:
|
|
of nnkObjectTy(
|
|
nnkPragma(
|
|
ident"inheritable"
|
|
),
|
|
nnkEmpty(),
|
|
nnkRecList( # list of object parameters
|
|
nnkIdentDefs(
|
|
ident"name",
|
|
ident"string",
|
|
nnkEmpty()
|
|
),
|
|
nnkRecCase( # case statement within object (not nnkCaseStmt)
|
|
nnkIdentDefs(
|
|
ident"isFat",
|
|
ident"bool",
|
|
nnkEmpty()
|
|
),
|
|
nnkOfBranch(
|
|
ident"true",
|
|
nnkRecList( # again, a list of object parameters
|
|
nnkIdentDefs(
|
|
ident"m",
|
|
nnkBracketExpr(
|
|
ident"array",
|
|
nnkIntLit(intVal = 100000),
|
|
ident"T"
|
|
),
|
|
nnkEmpty()
|
|
)
|
|
)
|
|
),
|
|
nnkOfBranch(
|
|
ident"false",
|
|
nnkRecList(
|
|
nnkIdentDefs(
|
|
ident"m",
|
|
nnkBracketExpr(
|
|
ident"array",
|
|
nnkIntLit(intVal = 10),
|
|
ident"T"
|
|
),
|
|
nnkEmpty()
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
|
|
|
|
testRecCase:
|
|
type Obj[T] = object {.inheritable.}
|
|
name: string
|
|
case isFat: bool
|
|
of true:
|
|
m: array[100_000, T]
|
|
of false:
|
|
m: array[10, T]
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
type X = enum
|
|
First
|
|
|
|
ast.peelOff({nnkStmtList, nnkTypeSection})[2].matchAst:
|
|
of nnkEnumTy(
|
|
nnkEmpty(),
|
|
ident"First" # you need at least one nnkIdent or the compiler complains
|
|
):
|
|
echo "ok"
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
type Con = concept x,y,z
|
|
(x & y & z) is string
|
|
|
|
ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst:
|
|
of nnkTypeDef(_, _, nnkTypeClassTy(nnkArglist, _, _, nnkStmtList)):
|
|
# note this isn't nnkConceptTy!
|
|
echo "ok"
|
|
|
|
|
|
scope:
|
|
|
|
let astX = myquote:
|
|
type
|
|
A[T: static[int]] = object
|
|
|
|
let ast = astX.peelOff({nnkStmtList, nnkTypeSection})
|
|
|
|
ast.matchAst(err): # this is a sub ast for this a findAst or something like that is useful
|
|
of nnkTypeDef(_, nnkGenericParams( nnkIdentDefs( ident"T", nnkCall( ident"[]", ident"static", _ ), _ )), _):
|
|
echo "ok"
|
|
else:
|
|
echo "foobar"
|
|
echo ast.treeRepr
|
|
|
|
|
|
scope:
|
|
let ast = myquote:
|
|
type MyProc[T] = proc(x: T)
|
|
|
|
ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst(err):
|
|
of nnkTypeDef(
|
|
ident"MyProc",
|
|
nnkGenericParams, # here, not with the proc
|
|
nnkProcTy( # behaves like a procedure declaration from here on
|
|
nnkFormalParams, _
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
## Mixin statement
|
|
|
|
macro testMixinStatement(ast: untyped): untyped =
|
|
ast.peelOff(nnkStmtList).matchAst:
|
|
of nnkMixinStmt(ident"x"):
|
|
echo "ok"
|
|
|
|
testMixinStatement:
|
|
mixin x
|
|
|
|
## Bind statement
|
|
|
|
|
|
macro testBindStmt(ast: untyped): untyped =
|
|
ast[0].matchAst:
|
|
of `node` @ nnkBindStmt(ident"x"):
|
|
echo "ok"
|
|
|
|
testBindStmt:
|
|
bind x
|
|
|
|
## Procedure declaration
|
|
|
|
macro testProcedureDeclaration(ast: untyped): untyped =
|
|
# NOTE this is wrong in astdef
|
|
|
|
ast.peelOff(nnkStmtList).matchAst:
|
|
of nnkProcDef(
|
|
nnkPostfix(ident"*", ident"hello"), # the exported proc name
|
|
nnkEmpty, # patterns for term rewriting in templates and macros (not procs)
|
|
nnkGenericParams( # generic type parameters, like with type declaration
|
|
nnkIdentDefs(
|
|
ident"T",
|
|
ident"SomeInteger", _
|
|
)
|
|
),
|
|
nnkFormalParams(
|
|
ident"int", # the first FormalParam is the return type. nnkEmpty if there is none
|
|
nnkIdentDefs(
|
|
ident"x",
|
|
ident"int", # type type (required for procs, not for templates)
|
|
nnkIntLit(intVal = 3) # a default value
|
|
),
|
|
nnkIdentDefs(
|
|
ident"y",
|
|
ident"float32",
|
|
nnkEmpty
|
|
)
|
|
),
|
|
nnkPragma(ident"inline"),
|
|
nnkEmpty, # reserved slot for future use
|
|
`meat` @ nnkStmtList # the meat of the proc
|
|
):
|
|
echo "ok got meat: ", meat.lispRepr
|
|
|
|
testProcedureDeclaration:
|
|
proc hello*[T: SomeInteger](x: int = 3, y: float32): int {.inline.} = discard
|
|
|
|
scope:
|
|
var ast = myquote:
|
|
proc foobar(a, b: int): void
|
|
|
|
ast = ast[3]
|
|
|
|
ast.matchAst: # sub expression
|
|
of nnkFormalParams(
|
|
_, # return would be here
|
|
nnkIdentDefs(
|
|
ident"a", # the first parameter
|
|
ident"b", # directly to the second parameter
|
|
ident"int", # their shared type identifier
|
|
nnkEmpty, # default value would go here
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
proc hello(): var int
|
|
|
|
ast[3].matchAst: # subAst
|
|
of nnkFormalParams(
|
|
nnkVarTy(
|
|
ident"int"
|
|
)
|
|
):
|
|
echo "ok"
|
|
|
|
## Iterator declaration
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
iterator nonsense[T](x: seq[T]): float {.closure.} =
|
|
discard
|
|
|
|
ast.matchAst:
|
|
of nnkIteratorDef(ident"nonsense", nnkEmpty, _, _, _, _, _):
|
|
echo "ok"
|
|
|
|
## Converter declaration
|
|
|
|
scope:
|
|
|
|
let ast = myquote:
|
|
converter toBool(x: float): bool
|
|
|
|
ast.matchAst:
|
|
of nnkConverterDef(ident"toBool",_,_,_,_,_,_):
|
|
echo "ok"
|
|
|
|
## Template declaration
|
|
|
|
scope:
|
|
let ast = myquote:
|
|
template optOpt{expr1}(a: int): int
|
|
|
|
ast.matchAst:
|
|
of nnkTemplateDef(ident"optOpt", nnkStmtList(`expr1`), _, _, _, _, _):
|
|
echo "ok"
|