std/macros
Исходный кодИзменитьЭтот модуль содержит интерфейс к абстрактного синтаксического дерева (АСД) компилятора. Макросы работают с этим деревом.
См. также:
АСД в Nim
Этот раздел описывает, как АСД моделируется с помощью системы типов Nim. АСД состоит из узлов (NimNode) с переменным количеством дочерних узлов. Каждый узел имеет поле, названное kind, которое описывает содержимое узла:
type
NimNodeKind = enum ## kind of a node; only explanatory
nnkNone, ## invalid node kind
nnkEmpty, ## empty node
nnkIdent, ## node contains an identifier
nnkIntLit, ## node contains an int literal (example: 10)
nnkStrLit, ## node contains a string literal (example: "abc")
nnkNilLit, ## node contains a nil literal (example: nil)
nnkCaseStmt, ## node represents a case statement
... ## many more
NimNode = ref NimNodeObj
NimNodeObj = object
case kind: NimNodeKind ## the node's kind
of nnkNone, nnkEmpty, nnkNilLit:
discard ## node contains no additional fields
of nnkCharLit..nnkUInt64Lit:
intVal: BiggestInt ## the int literal
of nnkFloatLit..nnkFloat64Lit:
floatVal: BiggestFloat ## the float literal
of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym:
strVal: string ## the string literal
else:
sons: seq[NimNode] ## the node's sons (or children) Для типа NimNode оператор [] был перегружен: n[i] является n-ым дочерним узлом i.
Для задания АСД для различных конструкций Nim используется обозначение nodekind(son1, son2, ...) или nodekind(value) или nodekind(field=value).
Некоторые дочерние узлы могут отсутствовать. Отсутствующий дочерний узел имеет тип nnkEmpty; дочерний узел никогда не может быть пустым.
Листовые узлы/Атомы
Лист АСД часто соответствует терминальному символу в конкретном синтаксисе. Обратите внимание, что по умолчанию float в Nim отображается как float64, так что по умолчанию АСД для числа с плавающей точкой является nnkFloat64Lit, как показано ниже.
| Выражение Nim | Соответствующее АСД |
|---|---|
42 |
nnkIntLit(intVal = 42) |
42'i8 |
nnkInt8Lit(intVal = 42) |
42'i16 |
nnkInt16Lit(intVal = 42) |
42'i32 |
nnkInt32Lit(intVal = 42) |
42'i64 |
nnkInt64Lit(intVal = 42) |
42'u8 |
nnkUInt8Lit(intVal = 42) |
42'u16 |
nnkUInt16Lit(intVal = 42) |
42'u32 |
nnkUInt32Lit(intVal = 42) |
42'u64 |
nnkUInt64Lit(intVal = 42) |
42.0 |
nnkFloat64Lit(floatVal = 42.0) |
42.0'f32 |
nnkFloat32Lit(floatVal = 42.0) |
42.0'f64 |
nnkFloat64Lit(floatVal = 42.0) |
"abc" |
nnkStrLit(strVal = "abc") |
r"abc" |
nnkRStrLit(strVal = "abc") |
"""abc""" |
nnkTripleStrLit(strVal = "abc") |
' ' |
nnkCharLit(intVal = 32) |
nil |
nnkNilLit() |
myIdentifier |
nnkIdent(strVal = "myIdentifier") |
myIdentifier |
после прохода поиска: nnkSym(strVal = "myIdentifier", ...)
|
Идентификаторы являются узлами nnkIdent. После прохода поиска имён эти узлы преобразуются в узлы nnkSym.
Вызовы/выражения
Вызов команды
Конкретный синтаксис:
echo "abc", "xyz"
АСД:
nnkCommand(
nnkIdent("echo"),
nnkStrLit("abc"),
nnkStrLit("xyz")
) Вызов с ()
Конкретный синтаксис:
echo("abc", "xyz") АСД:
nnkCall(
nnkIdent("echo"),
nnkStrLit("abc"),
nnkStrLit("xyz")
) Вызов инфиксного оператора
Конкретный синтаксис:
"abc" & "xyz"
АСД:
nnkInfix(
nnkIdent("&"),
nnkStrLit("abc"),
nnkStrLit("xyz")
) Обратите внимание, что при нескольких инфиксных операторах команда разбирается по приоритету операторов.
Конкретный синтаксис:
5 + 3 * 4
АСД:
nnkInfix(
nnkIdent("+"),
nnkIntLit(5),
nnkInfix(
nnkIdent("*"),
nnkIntLit(3),
nnkIntLit(4)
)
) Отметим, что если вы выберите использовать инфиксные операторы в префиксной форме, АСД ведет себя как вызов родительской функции с nnkAccQuoted, как показано ниже:
Конкретный синтаксис:
`+`(3, 4)
АСД:
nnkCall(
nnkAccQuoted(
nnkIdent("+")
),
nnkIntLit(3),
nnkIntLit(4)
) Вызов префиксного оператора
Конкретный синтаксис:
? "xyz"
АСД:
nnkPrefix(
nnkIdent("?"),
nnkStrLit("abc")
) Вызов постфиксного оператора
Примечание: В Nim нет постфиксных операторов. Однако узел nnkPostfix используется для маркера экспорта звёздочкой *:
Конкретный синтаксис:
identifier*
АСД:
nnkPostfix(
nnkIdent("*"),
nnkIdent("identifier")
) Вызов с именованными аргументами
Конкретный синтаксис:
writeLine(file=stdout, "hallo")
АСД:
nnkCall(
nnkIdent("writeLine"),
nnkExprEqExpr(
nnkIdent("file"),
nnkIdent("stdout")
),
nnkStrLit("hallo")
) Вызов с сырой строковой литеральной
Это используется, например, в примерах bindSym здесь и с re"some regexp" в модуле регулярных выражений.
Конкретный синтаксис:
echo"abc"
АСД:
nnkCallStrLit(
nnkIdent("echo"),
nnkRStrLit("hello")
) Оператор разыменования []
Конкретный синтаксис:
x[]
АСД:
nnkDerefExpr(nnkIdent("x")) Оператор addr
Конкретный синтаксис:
addr(x)
АСД:
nnkAddr(nnkIdent("x")) Оператор приведения типов
Конкретный синтаксис:
cast[T](x)
АСД:
nnkCast(nnkIdent("T"), nnkIdent("x")) Оператор доступа к объекту .
Конкретный синтаксис:
x.y
АСД:
nnkDotExpr(nnkIdent("x"), nnkIdent("y")) Если вы используете гибкий синтаксис вызова Nim (как в x.len()), результат будет таким же, как выше, но обернут в nnkCall.
Оператор доступа к массиву []
Конкретный синтаксис:
x[y]
АСД:
nnkBracketExpr(nnkIdent("x"), nnkIdent("y")) Скобки
Скобки для влияния на приоритет операторов используют узел nnkPar.
Конкретный синтаксис:
(a + b) * c
АСД:
nnkInfix(nnkIdent("*"),
nnkPar(
nnkInfix(nnkIdent("+"), nnkIdent("a"), nnkIdent("b"))),
nnkIdent("c")) Конструкторы кортежей
Узлы для построения кортежей создаются с помощью узла nnkTupleConstr.
Конкретный синтаксис:
(1, 2, 3) (a: 1, b: 2, c: 3) ()
АСД:
nnkTupleConstr(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
nnkTupleConstr(
nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1)),
nnkExprColonExpr(nnkIdent("b"), nnkIntLit(2)),
nnkExprColonExpr(nnkIdent("c"), nnkIntLit(3)))
nnkTupleConstr() Поскольку один кортеж был бы синтаксически идентичен скобкам с выражением внутри, анализатор ожидает заключительной запятой для них. Для конструкторов кортежей с именами полей это необязательно.
(1,) (a: 1)
АСД:
nnkTupleConstr(nnkIntLit(1))
nnkTupleConstr(
nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1))) Фигурные скобки
Фигурные скобки используются в качестве конструктора множеств.
Конкретный синтаксис:
{1, 2, 3} АСД:
nnkCurly(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
При использовании в качестве конструктора таблицы синтаксис отличается.
Конкретный синтаксис:
{a: 3, b: 5} АСД:
nnkTableConstr(
nnkExprColonExpr(nnkIdent("a"), nnkIntLit(3)),
nnkExprColonExpr(nnkIdent("b"), nnkIntLit(5))
) Квадратные скобки
Квадратные скобки используются в качестве конструктора массивов.
Конкретный синтаксис:
[1, 2, 3]
АСД:
nnkBracket(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
Диапазоны
Диапазоны встречаются в конструкторах множеств, ветвях оператора case или срезах массивов. Внутри используется тип узла nnkRange, но при построении АСД следует использовать построение с .. в качестве инфиксного оператора.
Конкретный синтаксис:
1..3
АСД:
nnkInfix(
nnkIdent(".."),
nnkIntLit(1),
nnkIntLit(3)
) Пример кода:
macro genRepeatEcho() =
result = newNimNode(nnkStmtList)
var forStmt = newNimNode(nnkForStmt) # generate a for statement
forStmt.add(ident("i")) # use the variable `i` for iteration
var rangeDef = newNimNode(nnkInfix).add(
ident("..")).add(
newIntLitNode(3),newIntLitNode(5)) # iterate over the range 3..5
forStmt.add(rangeDef)
forStmt.add(newCall(ident("echo"), newIntLitNode(3))) # meat of the loop
result.add(forStmt)
genRepeatEcho() # gives:
# 3
# 3
# 3 Выражение if
Представление выражения if тонкое, но легко просматриваемое.
Конкретный синтаксис:
if cond1: expr1 elif cond2: expr2 else: expr3
АСД:
nnkIfExpr( nnkElifExpr(cond1, expr1), nnkElifExpr(cond2, expr2), nnkElseExpr(expr3) )
Комментарии документации
Комментарии с двойным решёткой (##) в коде фактически имеют свой собственный формат, используя strVal для получения и установки текста комментария. Комментарии с одинарной решёткой (#) игнорируются.
Конкретный синтаксис:
## This is a comment ## This is part of the first comment stmt1 ## Yet another
АСД:
nnkCommentStmt() # only appears once for the first two lines!
stmt1
nnkCommentStmt() # another nnkCommentStmt because there is another comment
# (separate from the first) Директивы
Одной из интересных особенностей Nim являются директивы, которые позволяют тонко настраивать различные аспекты языка. Они бывают всех типов, например, для украшения процедур и объектов, но отдельная директива emit показывает основы с АСД.
Конкретный синтаксис:
{.emit: "#include <stdio.h>".} АСД:
nnkPragma(
nnkExprColonExpr(
nnkIdent("emit"),
nnkStrLit("#include <stdio.h>") # the "argument"
)
) Поскольку nnkIdent появляются так же часто, как и директивы между {..}. Обратите внимание, что объявление новых директив по сути такое же:
Конкретный синтаксис:
{.pragma: cdeclRename, cdecl.} АСД:
nnkPragma(
nnkExprColonExpr(
nnkIdent("pragma"), # this is always first when declaring a new pragma
nnkIdent("cdeclRename") # the name of the pragma
),
nnkIdent("cdecl")
) Операторы
Оператор if
Представление оператора if тонкое, но легко просматриваемое. Если нет else ветви, то нет nnkElse дочернего узла.
Конкретный синтаксис:
if cond1: stmt1 elif cond2: stmt2 elif cond3: stmt3 else: stmt4
АСД:
nnkIfStmt( nnkElifBranch(cond1, stmt1), nnkElifBranch(cond2, stmt2), nnkElifBranch(cond3, stmt3), nnkElse(stmt4) )
Оператор when
Подобно оператору if, но корень имеет тип nnkWhenStmt.
Присваивание
Конкретный синтаксис:
x = 42
АСД:
nnkAsgn(nnkIdent("x"), nnkIntLit(42)) Это не синтаксис присваивания, когда он сочетается с var, let или const.
Список операторов
Конкретный синтаксис:
stmt1 stmt2 stmt3
АСД:
nnkStmtList(stmt1, stmt2, stmt3)
Оператор case
Конкретный синтаксис:
case expr1 of expr2, expr3..expr4: stmt1 of expr5: stmt2 elif cond1: stmt3 else: stmt4
АСД:
nnkCaseStmt( expr1, nnkOfBranch(expr2, nnkRange(expr3, expr4), stmt1), nnkOfBranch(expr5, stmt2), nnkElifBranch(cond1, stmt3), nnkElse(stmt4) )
Части nnkElifBranch и nnkElse могут отсутствовать.
Оператор while
Конкретный синтаксис:
while expr1: stmt1
АСД:
nnkWhileStmt(expr1, stmt1)
Оператор for
Конкретный синтаксис:
for ident1, ident2 in expr1: stmt1
АСД:
nnkForStmt(ident1, ident2, expr1, stmt1)
Оператор try
Конкретный синтаксис:
try: stmt1 except e1, e2: stmt2 except e3: stmt3 except: stmt4 finally: stmt5
АСД:
nnkTryStmt( stmt1, nnkExceptBranch(e1, e2, stmt2), nnkExceptBranch(e3, stmt3), nnkExceptBranch(stmt4), nnkFinally(stmt5) )
Оператор return
Конкретный синтаксис:
return expr1
АСД:
nnkReturnStmt(expr1)
Оператор yield
Подобно return, но с типом узла nnkYieldStmt.
nnkYieldStmt(expr1)
Оператор discard
Подобно return, но с типом узла nnkDiscardStmt.
nnkDiscardStmt(expr1)
Оператор continue
Конкретный синтаксис:
continue
АСД:
nnkContinueStmt()
Оператор break
Конкретный синтаксис:
break otherLocation
AST:
nnkBreakStmt(nnkIdent("otherLocation")) Если break используется без указания места перехода, то nnkEmpty заменяет nnkIdent.
Блок оператор
Конкретная синтаксическая запись:
block name:
AST:
nnkBlockStmt(nnkIdent("name"), nnkStmtList(...)) У block не нужно имя, в этом случае используется nnkEmpty.
Оператор asm
Конкретная синтаксическая запись:
asm """ some asm """
AST:
nnkAsmStmt(
nnkEmpty(), # for pragmas
nnkTripleStrLit("some asm"),
) Раздел импорта
Оператор импорта в Nim import может иметь различные варианты в зависимости от присутствующих ключевых слов. Начнём с самого простого случая.
Конкретная синтаксическая запись:
import std/math
AST:
nnkImportStmt(nnkIdent("math")) С except мы получаем nnkImportExceptStmt.
Конкретная синтаксическая запись:
import std/math except pow
AST:
nnkImportExceptStmt(nnkIdent("math"),nnkIdent("pow")) Обратите внимание, что import std/math as m не использует другой узел; вместо этого мы используем nnkImportStmt с as в качестве инфиксного оператора.
Конкретная синтаксическая запись:
import std/strutils as su
AST:
nnkImportStmt(
nnkInfix(
nnkIdent("as"),
nnkIdent("strutils"),
nnkIdent("su")
)
) Оператор from
Если мы используем from ... import, результат также будет отличаться.
Конкретная синтаксическая запись:
from std/math import pow
AST:
nnkFromStmt(nnkIdent("math"), nnkIdent("pow")) Использование from std/math as m import pow эквивалентно модификатору as с оператором import, но обернутому в nnkFromStmt.
Оператор export
Когда вы делаете импортированный модуль доступным для модулей, которые импортируют ваш, синтаксис export достаточно прост.
Конкретная синтаксическая запись:
export unsigned
AST:
nnkExportStmt(nnkIdent("unsigned")) Аналогично оператору import, AST отличается для export ... except.
Конкретная синтаксическая запись:
export math except pow # we're going to implement our own exponentiation
AST:
nnkExportExceptStmt(nnkIdent("math"),nnkIdent("pow")) Оператор include
Как и обычный оператор import, но с nnkIncludeStmt.
Конкретная синтаксическая запись:
include blocks
AST:
nnkIncludeStmt(nnkIdent("blocks")) Раздел var
Конкретная синтаксическая запись:
var a = 3
AST:
nnkVarSection(
nnkIdentDefs(
nnkIdent("a"),
nnkEmpty(), # or nnkIdent(...) if the variable declares the type
nnkIntLit(3),
)
) Обратите внимание, что второй или третий (или оба) параметра выше должны существовать, так как компилятор должен каким-то образом узнать тип (который может быть выведен из заданного присваивания).
Это не тот же AST для всех случаев использования var. Подробности см. в Разделе описания процедуры.
Раздел let
Это эквивалентно var, но с nnkLetSection вместо nnkVarSection.
Конкретная синтаксическая запись:
let a = 3
AST:
nnkLetSection(
nnkIdentDefs(
nnkIdent("a"),
nnkEmpty(), # or nnkIdent(...) for the type
nnkIntLit(3),
)
) Раздел const
Конкретная синтаксическая запись:
const a = 3
AST:
nnkConstSection(
nnkConstDef( # not nnkConstDefs!
nnkIdent("a"),
nnkEmpty(), # or nnkIdent(...) if the variable declares the type
nnkIntLit(3), # required in a const declaration!
)
) Раздел type
Начиная с самого простого случая, раздел type выглядит примерно так же, как var и const.
Конкретная синтаксическая запись:
type A = int
AST:
nnkTypeSection(
nnkTypeDef(
nnkIdent("A"),
nnkEmpty(),
nnkIdent("int")
)
) Объявление distinct типов аналогично, с последним nnkIdent, обернутым в nnkDistinctTy.
Конкретная синтаксическая запись:
type MyInt = distinct int
AST:
# ...
nnkTypeDef(
nnkIdent("MyInt"),
nnkEmpty(),
nnkDistinctTy(
nnkIdent("int")
)
) Если раздел type использует параметры дженериков, они обрабатываются здесь:
Конкретная синтаксическая запись:
type A[T] = expr1
AST:
nnkTypeSection(
nnkTypeDef(
nnkIdent("A"),
nnkGenericParams(
nnkIdentDefs(
nnkIdent("T"),
nnkEmpty(), # if the type is declared with options, like
# ``[T: SomeInteger]``, they are given here
nnkEmpty(),
)
)
expr1,
)
) Обратите внимание, что не все nnkTypeDef используют nnkIdent в качестве параметра. Одним из самых распространённых случаев использования объявлений типов является работа с объектами.
Конкретная синтаксическая запись:
type IO = object of RootObj
AST:
# ...
nnkTypeDef(
nnkIdent("IO"),
nnkEmpty(),
nnkObjectTy(
nnkEmpty(), # no pragmas here
nnkOfInherit(
nnkIdent("RootObj") # inherits from RootObj
),
nnkEmpty()
)
) Синтаксис объектов Nim богат. Давайте рассмотрим подробный пример целиком, чтобы увидеть некоторые из сложностей.
Конкретная синтаксическая запись:
type Obj[T] {.inheritable.} = object
name: string
case isFat: bool
of true:
m: array[100_000, T]
of false:
m: array[10, T] AST:
# ...
nnkPragmaExpr(
nnkIdent("Obj"),
nnkPragma(nnkIdent("inheritable"))
),
nnkGenericParams(
nnkIdentDefs(
nnkIdent("T"),
nnkEmpty(),
nnkEmpty())
),
nnkObjectTy(
nnkEmpty(),
nnkEmpty(),
nnkRecList( # list of object parameters
nnkIdentDefs(
nnkIdent("name"),
nnkIdent("string"),
nnkEmpty()
),
nnkRecCase( # case statement within object (not nnkCaseStmt)
nnkIdentDefs(
nnkIdent("isFat"),
nnkIdent("bool"),
nnkEmpty()
),
nnkOfBranch(
nnkIdent("true"),
nnkRecList( # again, a list of object parameters
nnkIdentDefs(
nnkIdent("m"),
nnkBracketExpr(
nnkIdent("array"),
nnkIntLit(100000),
nnkIdent("T")
),
nnkEmpty()
)
),
nnkOfBranch(
nnkIdent("false"),
nnkRecList(
nnkIdentDefs(
nnkIdent("m"),
nnkBracketExpr(
nnkIdent("array"),
nnkIntLit(10),
nnkIdent("T")
),
nnkEmpty()
)
)
)
)
)
) Использование enum аналогично использованию object.
Конкретная синтаксическая запись:
type X = enum First
AST:
# ...
nnkEnumTy(
nnkEmpty(),
nnkIdent("First") # you need at least one nnkIdent or the compiler complains
) Использование concept (экспериментальный) аналогично использованию объектов.
Конкретная синтаксическая запись:
type Con = concept x,y,z (x & y & z) is string
AST:
# ...
nnkTypeClassTy( # note this isn't nnkConceptTy!
nnkArgList(
# ... idents for x, y, z
)
# ...
) Статические типы, такие как static[int], используют nnkIdent, обернутое в nnkStaticTy.
Конкретная синтаксическая запись:
type A[T: static[int]] = object
AST:
# ... within nnkGenericParams
nnkIdentDefs(
nnkIdent("T"),
nnkStaticTy(
nnkIdent("int")
),
nnkEmpty()
)
# ... В общем, объявление типов отражает этот синтаксис (т.е., nnkStaticTy для static и т.д.). Следуют примеры (исключения отмечены *):
| Тип Nim | Соответствующий AST |
|---|---|
static |
nnkStaticTy |
tuple |
nnkTupleTy |
var |
nnkVarTy |
ptr |
nnkPtrTy |
ref |
nnkRefTy |
distinct |
nnkDistinctTy |
enum |
nnkEnumTy |
concept |
nnkTypeClassTy* |
array |
nnkBracketExpr(nnkIdent("array"),...* |
proc |
nnkProcTy |
iterator |
nnkIteratorTy |
object |
nnkObjectTy |
Обращайте особое внимание при объявлении типов как proc. Поведение аналогично Procedure declaration ниже, но не обрабатывает nnkGenericParams. Параметры дженериков обрабатываются в типе, а не в самом proc.
Конкретная синтаксическая запись:
type MyProc[T] = proc(x: T) {.nimcall.} AST:
# ...
nnkTypeDef(
nnkIdent("MyProc"),
nnkGenericParams( # here, not with the proc
# ...
)
nnkProcTy( # behaves like a procedure declaration from here on
nnkFormalParams(
# ...
),
nnkPragma(nnkIdent("nimcall"))
)
) Тот же синтаксис применяется к iterator (с nnkIteratorTy), но не применяется к converter или template.
Версии type class этих узлов обычно имеют тот же вид узла, но без дочерних узлов. Type class tuple представлен nnkTupleClassTy, а type class proc или iterator с директивами имеет узел nnkEmpty вместо узла nnkFormalParams узла конкретного типа proc или iterator.
type TypeClass = proc {.nimcall.} | ref | tuple AST:
nnkTypeDef(
nnkIdent("TypeClass"),
nnkEmpty(),
nnkInfix(
nnkIdent("|"),
nnkProcTy(
nnkEmpty(),
nnkPragma(nnkIdent("nimcall"))
),
nnkInfix(
nnkIdent("|"),
nnkRefTy(),
nnkTupleClassTy()
)
)
) Оператор mixin
Конкретная синтаксическая запись:
mixin x
AST:
nnkMixinStmt(nnkIdent("x")) Оператор bind
Конкретная синтаксическая запись:
bind x
AST:
nnkBindStmt(nnkIdent("x")) Объявление процедуры
Давайте рассмотрим процедуру с множеством интересных аспектов, чтобы понять, как разлагаются вызовы процедур.
Конкретная синтаксическая запись:
proc hello*[T: SomeInteger](x: int = 3, y: float32): int {.inline.} = discard AST:
nnkProcDef(
nnkPostfix(nnkIdent("*"), nnkIdent("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(
nnkIdent("T"),
nnkIdent("SomeInteger"),
nnkEmpty()
)
),
nnkFormalParams(
nnkIdent("int"), # the first FormalParam is the return type. nnkEmpty() if there is none
nnkIdentDefs(
nnkIdent("x"),
nnkIdent("int"), # type type (required for procs, not for templates)
nnkIntLit(3) # a default value
),
nnkIdentDefs(
nnkIdent("y"),
nnkIdent("float32"),
nnkEmpty()
)
),
nnkPragma(nnkIdent("inline")),
nnkEmpty(), # reserved slot for future use
nnkStmtList(nnkDiscardStmt(nnkEmpty())) # the meat of the proc
) Есть ещё одно соображение. Nim имеет гибкую идентификацию типов для своих процедур. Хотя proc(a: int, b: int) и proc(a, b: int) эквивалентны в коде, AST немного отличается для последнего.
Конкретная синтаксическая запись:
proc(a, b: int)
AST:
# ...AST as above...
nnkFormalParams(
nnkEmpty(), # no return here
nnkIdentDefs(
nnkIdent("a"), # the first parameter
nnkIdent("b"), # directly to the second parameter
nnkIdent("int"), # their shared type identifier
nnkEmpty(), # default value would go here
)
),
# ... Когда процедура использует специальную переменную возврата типа var, результат отличается от результата раздела var.
Конкретная синтаксическая запись:
proc hello(): var int
AST:
# ...
nnkFormalParams(
nnkVarTy(
nnkIdent("int")
)
) Объявление итератора
Синтаксис итераторов похож на процедуры, но nnkIteratorDef заменяет nnkProcDef.
Конкретная синтаксическая запись:
iterator nonsense[T](x: seq[T]): float {.closure.} = ... AST:
nnkIteratorDef(
nnkIdent("nonsense"),
nnkEmpty(),
...
) Объявление преобразователя
Преобразователь похож на процедуру.
Конкретная синтаксическая запись:
converter toBool(x: float): bool
AST:
nnkConverterDef(
nnkIdent("toBool"),
# ...
) Объявление шаблона
Шаблоны (а также макросы, как мы увидим) имеют немного расширенный AST по сравнению с процедурами и итераторами. Причина в этом – макросы переписывания терминов. Заметили nnkEmpty() в качестве второго аргумента к nnkProcDef и nnkIteratorDef выше? Именно туда попадают макросы переписывания терминов.
Конкретная синтаксическая запись:
template optOpt{expr1}(a: int): int AST:
nnkTemplateDef(
nnkIdent("optOpt"),
nnkStmtList( # instead of nnkEmpty()
expr1
),
# follows like a proc or iterator
) Если шаблон не имеет типов для своих параметров, идентификаторы типов внутри nnkFormalParams просто становятся nnkEmpty.
Объявление макроса
Макросы ведут себя как шаблоны, но nnkTemplateDef заменяется на nnkMacroDef.
Скрытое стандартное преобразование
var f: float = 1
Тип "f" – это float, но тип "1" на самом деле int. Вставка int в float – ошибка типа. Nim вставляет узел nnkHiddenStdConv вокруг узла nnkIntLit, чтобы новый узел имел правильный тип float. Это работает для всех автоматически преобразуемых узлов и делает преобразование явным.
Особые виды узлов
Существует несколько видов узлов, используемых для семантического проверки или генерации кода. Они доступны в этом модуле, но не должны использоваться. Другие виды узлов специально разработаны для упрощения манипуляций с AST. Они объясняются здесь.
Подлежит написанию.
Импорты
- since
Типы
BindSymRule = enum brClosed, ## only the symbols in current scope are bound brOpen, ## open for overloaded symbols, but may be a single ## symbol if not ambiguous (the rules match that of ## binding in generics) brForceOpen ## same as brOpen, but it will always be open even ## if not ambiguous (this cannot be achieved with ## any other means in the language currently)- Определяет, как ведёт себя
bindSym. Разница между открытыми и закрытыми символами описана в manual.html#symbol-lookup-in-generics-open-and-closed-symbols Источник Изменить NimIdent {....deprecated.} = object of RootObj- Представляет идентификатор Nim в AST. Примечание: Это редко используется, для построения идентификатора из строки используйте
ident"abc". Источник Изменить NimNodeKind = enum nnkNone, nnkEmpty, nnkIdent, nnkSym, nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit, nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit, nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit, nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit, nnkTripleStrLit, nnkNilLit, nnkComesFrom, nnkDotCall, nnkCommand, nnkCall, nnkCallStrLit, nnkInfix, nnkPrefix, nnkPostfix, nnkHiddenCallConv, nnkExprEqExpr, nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkPar, nnkObjConstr, nnkCurly, nnkCurlyExpr, nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange, nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr, nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted, nnkTableConstr, nnkBind, nnkClosedSymChoice, nnkOpenSymChoice, nnkHiddenStdConv, nnkHiddenSubConv, nnkConv, nnkCast, nnkStaticExpr, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString, nnkAsgn, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkImportAs, nnkProcDef, nnkMethodDef, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt, nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt, nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection, nnkConstDef, nnkTypeDef, nnkYieldStmt, nnkDefer, nnkTryStmt, nnkFinally, nnkRaiseStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkImportExceptStmt, nnkExportStmt, nnkExportExceptStmt, nnkFromStmt, nnkIncludeStmt, nnkBindStmt, nnkMixinStmt, nnkUsingStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkWith, nnkWithout, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkRefTy, nnkPtrTy, nnkVarTy, nnkConstTy, nnkOutTy, nnkDistinctTy, nnkProcTy, nnkIteratorTy, nnkSinkAsgn, nnkEnumTy, nnkEnumFieldDef, nnkArgList, nnkPattern, nnkHiddenTryStmt, nnkClosure, nnkGotoState, nnkState, nnkBreakState, nnkFuncDef, nnkTupleConstr, nnkError, ## erroneous AST node nnkModuleRef, nnkReplayAction, nnkNilRodNode, ## internal IC nodes nnkOpenSym
- Источник Изменить
NimSym {....deprecated.} = ref NimSymObj- Представляет символ Nim в компиляторе; символ - это найденный идентификатор. Источник Изменить
NimSymKind = enum nskUnknown, nskConditional, nskDynLib, nskParam, nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet, nskConst, nskResult, nskProc, nskFunc, nskMethod, nskIterator, nskConverter, nskMacro, nskTemplate, nskField, nskEnumField, nskForVar, nskLabel, nskStub
- Источник Изменить
NimTypeKind = enum ntyNone, ntyBool, ntyChar, ntyEmpty, ntyAlias, ntyNil, ntyExpr, ntyStmt, ntyTypeDesc, ntyGenericInvocation, ntyGenericBody, ntyGenericInst, ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal, ntyArray, ntyObject, ntyTuple, ntySet, ntyRange, ntyPtr, ntyRef, ntyVar, ntySequence, ntyProc, ntyPointer, ntyOpenArray, ntyString, ntyCString, ntyForward, ntyInt, ntyInt8, ntyInt16, ntyInt32, ntyInt64, ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128, ntyUInt, ntyUInt8, ntyUInt16, ntyUInt32, ntyUInt64, ntyUnused0, ntyUnused1, ntyUnused2, ntyVarargs, ntyUncheckedArray, ntyError, ntyBuiltinTypeClass, ntyUserTypeClass, ntyUserTypeClassInst, ntyCompositeTypeClass, ntyInferred, ntyAnd, ntyOr, ntyNot, ntyAnything, ntyStatic, ntyFromExpr, ntyOptDeprecated, ntyVoid
- Источник Изменить
Константы
CallNodes = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, nnkCallStrLit, nnkHiddenCallConv}- Источник Изменить
Процедуры
proc `$`(arg: LineInfo): string {....raises: [], tags: [], forbids: [].}- Возвращает строковое представление в формате
filepath(line, column). Исходный код Изменить proc `$`(i: NimIdent): string {.magic: "NStrVal", noSideEffect, ...deprecated: "Deprecated since version 0.18.1; Use \'strVal\' instead.", raises: [], tags: [], forbids: [].}- Преобразует идентификатор Nim в строку. Исходный код Изменить
proc `$`(node: NimNode): string {....raises: [], tags: [], forbids: [].}- Получить строку узла идентификатора. Исходный код Изменить
proc `$`(s: NimSym): string {.magic: "NStrVal", noSideEffect, ...deprecated: "Deprecated since version 0.18.1; Use \'strVal\' instead.", raises: [], tags: [], forbids: [].}- Преобразует символ Nim в строку. Исходный код Изменить
proc `==`(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect, ...deprecated: "Deprecated since version 0.18.1; Use \'==\' on \'NimNode\' instead.", raises: [], tags: [], forbids: [].}- Сравнивает два идентификатора Nim. Исходный код Изменить
proc `==`(a, b: NimNode): bool {.magic: "EqNimrodNode", noSideEffect, ...raises: [], tags: [], forbids: [].}- Сравнивает два узла Nim. Возвращает true, если узлы структурно эквивалентны. Это означает, что два независимо созданных узла могут быть равны. Исходный код Изменить
proc `==`(a, b: NimSym): bool {.magic: "EqNimrodNode", noSideEffect, ...deprecated: "Deprecated since version 0.18.1; Use \'==(NimNode, NimNode)\' instead.", raises: [], tags: [], forbids: [].}- Сравнивает два символа Nim. Исходный код Изменить
proc `[]`(n: NimNode; i: BackwardsIndex): NimNode {....raises: [], tags: [], forbids: [].}- Получить
n'si-ый дочерний узел. Исходный код Изменить proc `[]`(n: NimNode; i: int): NimNode {.magic: "NChild", noSideEffect, ...raises: [], tags: [], forbids: [].}- Получить
n'si-ый дочерний узел. Исходный код Изменить proc `[]`[T, U: Ordinal](n: NimNode; x: HSlice[T, U]): seq[NimNode]
- Операция среза для NimNode. Возвращает последовательность дочерних узлов
nв диапазоне[n[x.a], n[x.b]]. Исходный код Изменить proc `[]=`(n: NimNode; i: BackwardsIndex; child: NimNode) {....raises: [], tags: [], forbids: [].}- Установить
n'si-ый дочерний узел вchild. Исходный код Изменить proc `[]=`(n: NimNode; i: int; child: NimNode) {.magic: "NSetChild", noSideEffect, ...raises: [], tags: [], forbids: [].}- Установить
n'si-ый дочерний узел вchild. Исходный код Изменить proc add(father, child: NimNode): NimNode {.magic: "NAdd", discardable, noSideEffect, ...raises: [], tags: [], forbids: [].}- Добавляет
childк узлуfather. Возвращает родительский узел для вложенных вызовов. Исходный код Изменить proc add(father: NimNode; children: varargs[NimNode]): NimNode {. magic: "NAddMultiple", discardable, noSideEffect, ...raises: [], tags: [], forbids: [].}- Добавляет каждый дочерний узел из
childrenк узлуfather. Возвращает узелfatherдля вложенных вызовов. Исходный код Изменить proc addIdentIfAbsent(dest: NimNode; ident: string) {....raises: [], tags: [], forbids: [].}- Добавить
identкdest, если он отсутствует. Предназначено для использования с директивами. Исходный код Изменить proc addPragma(someProc, pragma: NimNode) {....raises: [], tags: [], forbids: [].}- Добавляет директиву к определению процедуры. Исходный код Изменить
proc astGenRepr(n: NimNode): string {....gcsafe, raises: [], tags: [], forbids: [].}-
Преобразует AST
nв код, необходимый для генерации этого AST.См. также system: repr, treeRepr и lispRepr.
Исходный код Изменить proc basename(a: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Извлечь идентификатор из префиксных/постфиксных выражений. Исходный код Изменить
proc basename=(a: NimNode; val: string) {....raises: [], tags: [], forbids: [].}- Исходный код Изменить
proc bindSym(ident: string | NimNode; rule: BindSymRule = brClosed): NimNode {. magic: "NBindSym", noSideEffect, ...raises: [], tags: [], forbids: [].}-
Создает узел, который связывает
identс узлом символа. Связанный символ может быть перегруженным символом. Еслиidentэто NimNode, у него должен быть типnnkIdent. Еслиrule == brClosedлибо возвращается деревоnnkClosedSymChoice, либоnnkSym, если символ не неоднозначен. Еслиrule == brOpenлибо возвращается деревоnnkOpenSymChoice, либоnnkSym, если символ не неоднозначен. Еслиrule == brForceOpen, то всегда возвращается деревоnnkOpenSymChoice, даже если символ не неоднозначен.См. справочник для получения дополнительной информации.
Исходный код Изменить proc body(someProc: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Исходный код Изменить
proc body=(someProc: NimNode; val: NimNode) {....raises: [], tags: [], forbids: [].}- Исходный код Изменить
proc boolVal(n: NimNode): bool {.noSideEffect, ...raises: [], tags: [], forbids: [].}- Исходный код Изменить
proc callsite(): NimNode {.magic: "NCallSite", ...gcsafe, deprecated: "Deprecated since v0.18.1; use `varargs[untyped]` in the macro prototype instead", raises: [], tags: [], forbids: [].}- Возвращает AST вызова выражения, вызвавшего этот макрос. Исходный код Изменить
proc copy(node: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Псевдоним для copyNimTree. Исходный код Изменить
proc copyChildrenTo(src, dest: NimNode) {....raises: [], tags: [], forbids: [].}- Скопировать все дочерние узлы из
srcвdest. Исходный код Изменить
proc copyLineInfo(arg: NimNode; info: NimNode) {.magic: "NLineInfo", noSideEffect, ...raises: [], tags: [], forbids: [].}- Копирует информацию о строке из
info. Исходный код Изменить proc copyNimNode(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect, ...raises: [], tags: [], forbids: [].}- Создаёт новый узел AST, копируя узел
n. В отличие отcopyNimTree, дочерние узлыnне копируются.Пример:
macro foo(x: typed) = var s = copyNimNode(x) doAssert s.len == 0 doAssert s.kind == nnkStmtList foo: let x = 12 echo x
Исходный код Изменить proc copyNimTree(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect, ...raises: [], tags: [], forbids: [].}- Создаёт новый узел AST, рекурсивно копируя узел
n. В отличие отcopyNimNode, это копируетn, дочерние узлыnи т.д.Пример:
macro foo(x: typed) = var s = copyNimTree(x) doAssert s.len == 2 doAssert s.kind == nnkStmtList foo: let x = 12 echo x
Исходный код Изменить proc del(father: NimNode; idx = 0; n = 1) {.magic: "NDel", noSideEffect, ...raises: [], tags: [], forbids: [].}- Удаляет
nдочерних узловfather, начиная с индексаidx. Исходный код Изменить proc eqIdent(a: NimNode; b: NimNode): bool {.magic: "EqIdent", noSideEffect, ...raises: [], tags: [], forbids: [].}- Сравнение без учёта регистра.
aиbмогут быть идентификатором или символом. Оба могут быть обернуты в маркер экспорта (nnkPostfix) или заключены в обратные кавычки (nnkAccQuoted), эти узлы будут распакованы. Исходный код Изменить proc eqIdent(a: NimNode; b: string): bool {.magic: "EqIdent", noSideEffect, ...raises: [], tags: [], forbids: [].}- Сравнение без учёта регистра.
aможет быть идентификатором или символом.aможет быть обернут в маркер экспорта (nnkPostfix) или заключён в обратные кавычки (nnkAccQuoted), эти узлы будут распакованы. Исходный код Изменить proc eqIdent(a: string; b: NimNode): bool {.magic: "EqIdent", noSideEffect, ...raises: [], tags: [], forbids: [].}- Сравнение без учёта регистра.
bможет быть идентификатором или символом.bможет быть обернут в маркер экспорта (nnkPostfix) или заключён в обратные кавычки (nnkAccQuoted), эти узлы будут распакованы. Исходный код Изменить proc eqIdent(a: string; b: string): bool {.magic: "EqIdent", noSideEffect, ...raises: [], tags: [], forbids: [].}- Сравнение без учёта регистра. Исходный код Изменить
proc error(msg: string; n: NimNode = nil) {.magic: "NError", ...gcsafe, noreturn, ...raises: [], tags: [], forbids: [].}- Выводит сообщение об ошибке во время компиляции. Необязательный параметр
n: NimNodeиспользуется в качестве источника информации о файле и строке в сообщении об ошибке компиляции. Исходный код Изменить proc expectIdent(n: NimNode; name: string) {....raises: [], tags: [], forbids: [].}- Проверяет, что
eqIdent(n,name)истинно. Если это не так, компиляция прерывается с сообщением об ошибке. Это полезно для написания макросов, которые проверяют AST, передаваемый им. Исходный код Изменить proc expectKind(n: NimNode; k: NimNodeKind) {....raises: [], tags: [], forbids: [].}- Проверяет, что
nимеет типk. Если это не так, компиляция прерывается с сообщением об ошибке. Это полезно для написания макросов, которые проверяют AST, передаваемый им. Исходный код Изменить proc expectKind(n: NimNode; k: set[NimNodeKind]) {....raises: [], tags: [], forbids: [].}- Проверяет, что
nимеет типk. Если это не так, компиляция прерывается с сообщением об ошибке. Это полезно для написания макросов, которые проверяют AST, передаваемый им. Исходный код Изменить proc expectLen(n: NimNode; len: int) {....raises: [], tags: [], forbids: [].}- Проверяет, что у
nровноlenдочерних узлов. Если это не так, компиляция прерывается с сообщением об ошибке. Это полезно для написания макросов, которые проверяют количество аргументов. Исходный код Изменить proc expectLen(n: NimNode; min, max: int) {....raises: [], tags: [], forbids: [].}- Проверяет, что у
nколичество дочерних узлов находится в диапазонеmin..max. Если это не так, компиляция прерывается с сообщением об ошибке. Это полезно для написания макросов, которые проверяют количество аргументов. Исходный код Изменить proc expectMinLen(n: NimNode; min: int) {....raises: [], tags: [], forbids: [].}- Проверяет, что у
nне менееminдочерних узлов. Если это не так, компиляция прерывается с сообщением об ошибке. Это полезно для написания макросов, которые проверяют количество аргументов. Исходный код Изменить proc extractDocCommentsAndRunnables(n: NimNode): NimNode {....raises: [], tags: [], forbids: [].}-
Возвращает
nnkStmtList, содержащий верхнеуровневые комментарии к документации и runnableExamples вa, останавливаясь на первом дочернем узле, который не является ни тем, ни другим. Пример:import std/macros macro transf(a): untyped = result = quote do: proc fun2*() = discard let header = extractDocCommentsAndRunnables(a.body) # correct usage: rest is appended result.body = header result.body.add quote do: discard # just an example # incorrect usage: nesting inside a nnkStmtList: # result.body = quote do: (`header`; discard) proc fun*() {.transf.} = ## first comment runnableExamples: discard runnableExamples: discard ## last comment discard # first statement after doc comments + runnableExamples ## not docgen'dИсходный код Изменить proc floatVal(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает значение float из любого числового литерала с плавающей точкой. Исходный код Изменить
proc floatVal=(n: NimNode; val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect, ...raises: [], tags: [], forbids: [].}- Исходный код Изменить
proc genSym(kind: NimSymKind = nskLet; ident = ""): NimNode {.magic: "NGenSym", noSideEffect, ...raises: [], tags: [], forbids: [].}- Генерирует новый уникальный символ. Символ должен быть в контексте объявления. Исходный код Изменить
proc getAlign(arg: NimNode): int {.magic: "NSizeOf", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает тот же результат, что и
system.alignof, если выравнивание известно компилятору Nim. Работает сNimNodeдля использования в контексте макросов. Возвращает отрицательное значение, если компилятор Nim не знает выравнивание. Исходный код Изменить proc getAst(macroOrTemplate: untyped): NimNode {.magic: "ExpandToAst", noSideEffect, ...raises: [], tags: [], forbids: [].}-
Получает узлы AST, возвращаемые вызовом макроса или шаблона. Смотрите также
genasts.genAst. Пример:macro FooMacro() = var ast = getAst(BarTemplate())
Исходный код Изменить proc getImpl(s: NimSym): NimNode {.magic: "GetImpl", noSideEffect, ...deprecated: "use `getImpl: NimNode -> NimNode` instead", raises: [], tags: [], forbids: [].}- Исходный код Изменить
proc getImpl(symbol: NimNode): NimNode {.magic: "GetImpl", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает копию объявления символа или
nil. Исходный код Изменить
proc getImplTransformed(symbol: NimNode): NimNode {.magic: "GetImplTransf", noSideEffect, ...raises: [], tags: [], forbids: [].}- Для типизированной процедуры возвращает АСТ после этапа преобразования; это полезно для отладки того, как компилятор преобразует код (например:
defer,for), но обратите внимание, что преобразования кода зависят от реализации и могут изменяться. См. пример вtests/macros/tmacros_various.nim. Исходный код Редактировать proc getOffset(arg: NimNode): int {.magic: "NSizeOf", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает тот же результат, что и
system.offsetof, если смещение известно Nim-компилятору. Ожидает узел разрешенного символа из поля типа. Поэтому требует только один аргумент вместо двух. Возвращает отрицательное значение, если Nim-компилятор не знает смещение. Исходный код Редактировать proc getProjectPath(): string {....raises: [], tags: [], forbids: [].}-
Возвращает путь к текущему компилируемому проекту.
Не следует путать с system.currentSourcePath, который возвращает путь к исходному файлу, содержащему вызов этого шаблона.
Например, предположим, что
dir1/foo.nimимпортируетdir2/bar.nim, и пустьbar.nimвыведет обаgetProjectPathиcurrentSourcePathрезультата.Теперь, когда
foo.nimкомпилируется,getProjectPathизbar.nimвернёт путь кdir1/, аcurrentSourcePathвернет путь к файлу исходного кодаbar.nim.Теперь, когда
bar.nimкомпилируется напрямую,getProjectPathвернёт путь кdir2/, аcurrentSourcePathпо-прежнему вернёт тот же путь, путь к исходному файлуbar.nim.Возвращаемый путь устанавливается на этапе компиляции.
См. также:
Исходный код Редактировать proc getSize(arg: NimNode): int {.magic: "NSizeOf", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает тот же результат, что и
system.sizeof, если размер известен Nim-компилятору. Возвращает отрицательное значение, если Nim-компилятор не знает размер. Исходный код Редактировать proc getType(n: NimNode): NimNode {.magic: "NGetType", noSideEffect, ...raises: [], tags: [], forbids: [].}- С помощью 'getType' вы можете получить доступ к типу узла. Тип Nim сопоставляется с АСТ Nim, поэтому это немного запутанно, но это означает, что для обхода типов можно использовать тот же API. Рекурсивные типы сплющиваются для вас, поэтому нет опасности бесконечной рекурсии во время обхода. Чтобы разрешить рекурсивные типы, нужно вызвать 'getType' снова. Чтобы увидеть, какой тип это, вызовите
typeKindна результате getType. Исходный код Редактировать proc getType(n: typedesc): NimNode {.magic: "NGetType", noSideEffect, ...raises: [], tags: [], forbids: [].}- Версия
getType, которая принимаетtypedesc. Исходный код Редактировать proc getTypeImpl(n: NimNode): NimNode {.magic: "NGetType", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает тип узла в форме, соответствующей реализации типа. Любые промежуточные алиасы расширяются, чтобы получить окончательную реализацию типа. Вы можете вместо этого использовать
getImplдля символа, если хотите найти промежуточные алиасы.Пример:
type Vec[N: static[int], T] = object arr: array[N, T] Vec4[T] = Vec[4, T] Vec4f = Vec4[float32] var a: Vec4f var b: Vec4[float32] var c: Vec[4, float32] macro dumpTypeImpl(x: typed): untyped = newLit(x.getTypeImpl.repr) let t = """ object arr: array[0 .. 3, float32]""" doAssert(dumpTypeImpl(a) == t) doAssert(dumpTypeImpl(b) == t) doAssert(dumpTypeImpl(c) == t)Исходный код Редактировать proc getTypeImpl(n: typedesc): NimNode {.magic: "NGetType", noSideEffect, ...raises: [], tags: [], forbids: [].}- Версия
getTypeImpl, которая принимаетtypedesc. Исходный код Редактировать proc getTypeInst(n: NimNode): NimNode {.magic: "NGetType", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает тип узла в форме, соответствующей способу объявления экземпляра типа в коде.
Пример:
type Vec[N: static[int], T] = object arr: array[N, T] Vec4[T] = Vec[4, T] Vec4f = Vec4[float32] var a: Vec4f var b: Vec4[float32] var c: Vec[4, float32] macro dumpTypeInst(x: typed): untyped = newLit(x.getTypeInst.repr) doAssert(dumpTypeInst(a) == "Vec4f") doAssert(dumpTypeInst(b) == "Vec4[float32]") doAssert(dumpTypeInst(c) == "Vec[4, float32]")Исходный код Редактировать proc getTypeInst(n: typedesc): NimNode {.magic: "NGetType", noSideEffect, ...raises: [], tags: [], forbids: [].}- Версия
getTypeInst, которая принимаетtypedesc. Исходный код Редактировать proc hasArgOfName(params: NimNode; name: string): bool {....raises: [], tags: [], forbids: [].}- Поиск
nnkFormalParamsпо аргументу. Исходный код Редактировать proc hint(msg: string; n: NimNode = nil) {.magic: "NHint", ...gcsafe, raises: [], tags: [], forbids: [].}- Выводит сообщение-подсказку во время компиляции. Исходный код Редактировать
proc ident(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect, ...deprecated: "Deprecated since version 0.18.1; All functionality is defined on \'NimNode\'.", raises: [], tags: [], forbids: [].}- Исходный код Редактировать
proc ident(name: string): NimNode {.magic: "StrToIdent", noSideEffect, ...raises: [], tags: [], forbids: [].}- Создаёт новый узел ident из строки. Исходный код Редактировать
proc ident=(n: NimNode; val: NimIdent) {.magic: "NSetIdent", noSideEffect, ...deprecated: "Deprecated since version 0.18.1; Generate a new \'NimNode\' with \'ident(string)\' instead.", raises: [], tags: [], forbids: [].}- Исходный код Редактировать
proc infix(a: NimNode; op: string; b: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Исходный код Редактировать
proc insert(a: NimNode; pos: int; b: NimNode) {....raises: [], tags: [], forbids: [].}- Вставить узел
bв узелaна позициюpos. Исходный код Редактировать proc internalErrorFlag(): string {.magic: "NError", noSideEffect, ...raises: [], tags: [], forbids: [].}- Некоторые встроенные функции устанавливают флаг ошибки. Затем он преобразуется в правильное исключение. Примечание: обычный код приложения не должен вызывать эту функцию. Исходный код Редактировать
proc intVal(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает целое значение из любого целочисленного литерала или символа поля перечисления. Исходный код Редактировать
proc intVal=(n: NimNode; val: BiggestInt) {.magic: "NSetIntVal", noSideEffect, ...raises: [], tags: [], forbids: [].}- Исходный код Редактировать
proc isExported(n: NimNode): bool {.noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает, экспортирован ли символ. Исходный код Редактировать
proc isInstantiationOf(instanceProcSym, genProcSym: NimNode): bool {. magic: "SymIsInstantiationOf", noSideEffect, ...raises: [], tags: [], forbids: [].}- Проверяет, является ли символ процедуры экземпляром обобщенного символа процедуры. Полезно для проверки символов процедур на соответствие обобщенным символам, возвращаемым
bindSym. Исходный код Редактировать proc kind(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает
kindузлаn. Исходный код Редактировать
proc last(node: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Возвращает последний элемент в узлах-потомках. То же, что и
node[^1]. Исходный код Изменить proc len(n: NimNode): int {.magic: "NLen", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает количество дочерних элементов
n. Исходный код Изменить proc lineInfo(arg: NimNode): string {....raises: [], tags: [], forbids: [].}- Возвращает информацию о строке в формате
filepath(line, column). Исходный код Изменить proc lineInfoObj(n: NimNode): LineInfo {....raises: [], tags: [], forbids: [].}- Возвращает
LineInfoузлаn, используя абсолютный путь дляfilename. Исходный код Изменить proc lispRepr(n: NimNode; indented = false): string {....gcsafe, raises: [], tags: [], forbids: [].}-
Преобразует AST-дерево
nв удобочитаемую строку, похожую на Lisp.См. также
Исходный код Изменитьrepr, treeRepr и astGenRepr. proc name(someProc: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Исходный код Изменить
proc name=(someProc: NimNode; val: NimNode) {....raises: [], tags: [], forbids: [].}- Исходный код Изменить
proc nestList(op: NimNode; pack: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Вложенный список
packв дерево выражений вызовов:[a, b, c]преобразуется вop(a, op(c, d)). Это также известно как выражение свертки. Исходный код Изменить proc nestList(op: NimNode; pack: NimNode; init: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Вложенный список
packв дерево выражений вызовов:[a, b, c]преобразуется вop(a, op(c, d)). Это также известно как выражение свертки. Исходный код Изменить proc newAssignment(lhs, rhs: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Исходный код Изменить
proc newBlockStmt(body: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Создать новый блок: stmt. Исходный код Изменить
proc newBlockStmt(label, body: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Создать новое оператор блока с меткой. Исходный код Изменить
proc newCall(theProc: NimIdent; args: varargs[NimNode]): NimNode {....deprecated: "Deprecated since v0.18.1; use \'newCall(string, ...)\' or \'newCall(NimNode, ...)\' instead", raises: [], tags: [], forbids: [].}- Создает новый узел вызова.
theProc— это процедура, которая вызывается с аргументамиargs[0..]. Исходный код Изменить proc newCall(theProc: NimNode; args: varargs[NimNode]): NimNode {....raises: [], tags: [], forbids: [].}- Создает новый узел вызова.
theProc— это процедура, которая вызывается с аргументамиargs[0..]. Исходный код Изменить proc newCall(theProc: string; args: varargs[NimNode]): NimNode {....raises: [], tags: [], forbids: [].}- Создает новый узел вызова.
theProc— это процедура, которая вызывается с аргументамиargs[0..]. Исходный код Изменить proc newColonExpr(a, b: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Создать новое выражение двоеточия. newColonExpr(a, b) ->
a: bИсходный код Изменить proc newCommentStmtNode(s: string): NimNode {.noSideEffect, ...raises: [], tags: [], forbids: [].}- Создает узел оператора комментария. Исходный код Изменить
proc newConstStmt(name, value: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Создать новый оператор const. Исходный код Изменить
proc newDotExpr(a, b: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Создать новое выражение точки. a.dot(b) ->
a.bИсходный код Изменить proc newEmptyNode(): NimNode {.noSideEffect, ...raises: [], tags: [], forbids: [].}- Создать новый пустой узел. Исходный код Изменить
proc newEnum(name: NimNode; fields: openArray[NimNode]; public, pure: bool): NimNode {. ...raises: [], tags: [], forbids: [].}-
Создает новый перечисление.
nameдолжен быть идентификатором. Поля могут быть либо идентификаторами, либо EnumFieldDef:newEnum( name = ident("Colors"), fields = [ident("Blue"), ident("Red")], public = true, pure = false) # type Colors* = Blue RedИсходный код Изменить proc newFloatLitNode(f: BiggestFloat): NimNode {....raises: [], tags: [], forbids: [].}- Создает узел с плавающей запятой из
f. Исходный код Изменить proc newIdentDefs(name, kind: NimNode; default = newEmptyNode()): NimNode {. ...raises: [], tags: [], forbids: [].}-
Создает новый узел
nnkIdentDefsопределенного типа и значения.Узлы
nnkIdentDefsдолжны иметь как минимум три дочерних узла, но могут иметь больше: сначала идёт список идентификаторов, затем тип и значение. Эта процедура создаёт поддерево из трёх узлов, первым из которых является имя одного идентификатора. Узлыkindиdefault(значение) могут быть пустыми в зависимости от того, где появляетсяnnkIdentDefs: определения кортежей или объектов будут иметь пустой узелdefault, блокиletилиvarмогут иметь пустой узелkind, если идентификатору присваивается значение. Пример:var varSection = newNimNode(nnkVarSection).add( newIdentDefs(ident("a"), ident("string")), newIdentDefs(ident("b"), newEmptyNode(), newLit(3))) # --> var # a: string # b = 3Если вам нужно создать несколько идентификаторов, вам нужно использовать более низкоуровневую процедуру
newNimNode:result = newNimNode(nnkIdentDefs).add( ident("a"), ident("b"), ident("c"), ident("string"), newStrLitNode("Hello"))Исходный код Изменить proc newIdentNode(i: NimIdent): NimNode {....deprecated: "use ident(string)", raises: [], tags: [], forbids: [].}- Создаёт узел идентификатора из
i. Исходный код Изменить proc newIdentNode(i: string): NimNode {.magic: "StrToIdent", noSideEffect, ...raises: [], tags: [], forbids: [].}- Создаёт узел идентификатора из
i. Это просто псевдоним дляident(string). Используйте его, он короче. Исходный код Изменить
proc newIfStmt(branches: varargs[tuple[cond, body: NimNode]]): NimNode {. ...raises: [], tags: [], forbids: [].}-
Конструктор для операторов
if.newIfStmt( (Ident, StmtList), ... )
Исходный код Редактировать proc newIntLitNode(i: BiggestInt): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт узел целочисленной литеральной константы из
i. Исходный код Редактировать proc newLetStmt(name, value: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый оператор let. Исходный код Редактировать
proc newLit(arg: enum): NimNode
- Исходный код Редактировать
proc newLit(arg: object): NimNode
- Исходный код Редактировать
proc newLit(arg: ref object): NimNode
- генерирует новый узел литерала типа ref. Исходный код Редактировать
proc newLit(b: bool): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел булевого литерала. Исходный код Редактировать
proc newLit(c: char): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел символьного литерала. Исходный код Редактировать
proc newLit(f: float32): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел литерала с плавающей точкой. Исходный код Редактировать
proc newLit(f: float64): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел литерала с плавающей точкой. Исходный код Редактировать
proc newLit(i: int): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел целочисленного литерала. Исходный код Редактировать
proc newLit(i: int8): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел целочисленного литерала. Исходный код Редактировать
proc newLit(i: int16): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел целочисленного литерала. Исходный код Редактировать
proc newLit(i: int32): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел целочисленного литерала. Исходный код Редактировать
proc newLit(i: int64): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел целочисленного литерала. Исходный код Редактировать
proc newLit(i: uint): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел беззнакового целочисленного литерала. Исходный код Редактировать
proc newLit(i: uint8): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел беззнакового целочисленного литерала. Исходный код Редактировать
proc newLit(i: uint16): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел беззнакового целочисленного литерала. Исходный код Редактировать
proc newLit(i: uint32): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел беззнакового целочисленного литерала. Исходный код Редактировать
proc newLit(i: uint64): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел беззнакового целочисленного литерала. Исходный код Редактировать
proc newLit(s: string): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый узел строкового литерала. Исходный код Редактировать
proc newLit[N, T](arg: array[N, T]): NimNode
- Исходный код Редактировать
proc newLit[T: tuple](arg: T): NimNode
- Исходный код Редактировать
proc newLit[T](arg: seq[T]): NimNode
- Исходный код Редактировать
proc newLit[T](s: set[T]): NimNode
- Исходный код Редактировать
proc newNilLit(): NimNode {....raises: [], tags: [], forbids: [].}- Сокращение для создания узла nil. Исходный код Редактировать
proc newNimNode(kind: NimNodeKind; lineInfoFrom: NimNode = nil): NimNode {. magic: "NNewNimNode", noSideEffect, ...raises: [], tags: [], forbids: [].}-
Создаёт новый узел AST указанного типа.
Параметр
Исходный код РедактироватьlineInfoFromиспользуется для хранения информации о строке при возникновении ошибок в сгенерированном коде. Вы должны убедиться, что он установлен в узел, который вы преобразуете. proc newPar(exprs: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новое выражение в скобках. Исходный код Редактировать
proc newPar(exprs: varargs[NimNode]): NimNode {....deprecated: "don\'t use newPar/nnkPar to construct tuple expressions; use nnkTupleConstr instead", raises: [], tags: [], forbids: [].}- Создаёт новое выражение в скобках. Исходный код Редактировать
proc newProc(name = newEmptyNode(); params: openArray[NimNode] = [newEmptyNode()]; body: NimNode = newStmtList(); procType = nnkProcDef; pragmas: NimNode = newEmptyNode()): NimNode {....raises: [], tags: [], forbids: [].}-
Сокращение для создания новой функции.
Массив
Исходный код Редактироватьparamsдолжен начинаться с возвращаемого типа функции, за которым следует список IdentDefs, определяющих параметры. proc newStmtList(stmts: varargs[NimNode]): NimNode {....raises: [], tags: [], forbids: [].}- Создаёт новый список операторов. Исходный код Редактировать
proc newStrLitNode(s: string): NimNode {.noSideEffect, ...raises: [], tags: [], forbids: [].}- Создаёт узел строкового литерала из
s. Исходный код Редактировать proc newTree(kind: NimNodeKind; children: varargs[NimNode]): NimNode {. ...raises: [], tags: [], forbids: [].}- Создаёт новый узел с дочерними узлами. Исходный код Редактировать
proc owner(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect, ...deprecated, raises: [], tags: [], forbids: [].}-
Принимает узел типа
nnkSymи возвращает символ его владельца. Значение «владелец» зависит отsym'sNimSymKindи контекста объявления. Для объявлений верхнего уровня это символnskModule, для локальных переменных процедуры — символnskProc, для полей перечисления/объекта — символnskTypeи т. д. Для символов без владельца возвращаетсяnil.См. также:
- процедура symKind для получения типа символа
- процедура getImpl для получения объявления символа
proc parseExpr(s: string; filename: string = ""): NimNode {.noSideEffect, ...raises: [ValueError], tags: [], forbids: [].}- Компилирует переданную строку в её представление AST. Ожидает единственное выражение. Вызывает исключение
ValueErrorпри ошибках синтаксического анализа. Для более информативных сообщений об ошибках можно указать имя файла. Источник Изменить proc parseStmt(s: string; filename: string = ""): NimNode {.noSideEffect, ...raises: [ValueError], tags: [], forbids: [].}- Компилирует переданную строку в её представление AST. Ожидает одно или несколько инструкций. Вызывает исключение
ValueErrorпри ошибках синтаксического анализа. Для более информативных сообщений об ошибках можно указать имя файла. Источник Изменить proc quote(bl: typed; op = "``"): NimNode {.magic: "QuoteAst", noSideEffect, ...raises: [], tags: [], forbids: [].}-
Оператор квази-цитирования. Принимает выражение или блок и возвращает представляющее его AST. Внутри цитируемого AST можно интерполировать выражения NimNode из окружающего контекста. Если оператор не указан, цитирование выполняется с помощью обратных кавычек. В противном случае необходимо использовать данный оператор в качестве префиксного оператора для любого интерполированного выражения. Первоначальное значение оператора интерполяции можно получить, экранировав его (добавив его в качестве префикса) при использовании в качестве унарного оператора: например,
@экранируется как@@,&%экранируется как&%&%и так далее; см. примеры.Интерполяция пользовательского оператора требует акцентного цитирования (``), когда она разрешается в символ.
См. также genasts, который позволяет избежать некоторых проблем с
quote.Пример:
macro check(ex: untyped) = # this is a simplified version of the check macro from the # unittest module. # If there is a failed check, we want to make it easy for # the user to jump to the faulty line in the code, so we # get the line info here: var info = ex.lineinfo # We will also display the code string of the failed check: var expString = ex.toStrLit # Finally we compose the code to implement the check: result = quote do: if not `ex`: echo `info` & ": Check failed: " & `expString` check 1 + 1 == 2Пример:
# example showing how to define a symbol that requires backtick without # quoting it. var destroyCalled = false macro bar() = let s = newTree(nnkAccQuoted, ident"=destroy") # let s = ident"`=destroy`" # this would not work result = quote do: type Foo = object # proc `=destroy`(a: var Foo) = destroyCalled = true # this would not work proc `s`(a: var Foo) = destroyCalled = true block: let a = Foo() bar() doAssert destroyCalledПример:
# custom `op` var destroyCalled = false macro bar(ident) = var x = 1.5 result = quote("@") do: type Foo = object let `@ident` = 0 # custom op interpolated symbols need quoted (``) proc `=destroy`(a: var Foo) = doAssert @x == 1.5 doAssert compiles(@x == 1.5) let b1 = @[1,2] let b2 = @@[1,2] doAssert $b1 == "[1, 2]" doAssert $b2 == "@[1, 2]" destroyCalled = true block: let a = Foo() bar(someident) doAssert destroyCalled proc `&%`(x: int): int = 1 proc `&%`(x, y: int): int = 2 macro bar2() = var x = 3 result = quote("&%") do: var y = &%x # quoting operator doAssert &%&%y == 1 # unary operator => need to escape doAssert y &% y == 2 # binary operator => no need to escape doAssert y == 3 bar2()Источник Изменить proc setLineInfo(arg: NimNode; file: string; line: int; column: int) {. ...raises: [], tags: [], forbids: [].}- Устанавливает информацию о строке в NimNode. Файл должен существовать, но может быть относительным путем. Если вы хотите добавить информацию о строке в блок, используя
quote, вам нужно добавить информацию о строке после блока цитирования. Источник Изменить proc setLineInfo(arg: NimNode; lineInfo: LineInfo) {....raises: [], tags: [], forbids: [].}- См. процедуру setLineInfo Источник Изменить
proc signatureHash(n: NimNode): string {.magic: "NSigHash", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает стабильный идентификатор, полученный из сигнатуры символа. Сигнатура сочетает в себе множество факторов, таких как тип символа, модуль владения символа и другие. Тот же идентификатор используется в back-end для создания искаженного имени символа. Источник Изменить
proc strVal(n: NimNode): string {.magic: "NStrVal", noSideEffect, ...raises: [], tags: [], forbids: [].}-
Возвращает строковое значение идентификатора, символа, комментария или строковой константы.
См. также:
- процедура strVal= для установки строкового значения.
proc strVal=(n: NimNode; val: string) {.magic: "NSetStrVal", noSideEffect, ...raises: [], tags: [], forbids: [].}-
Устанавливает строковое значение строковой константы или комментария. Установка
strValзапрещена для узловnnkIdentиnnkSym; вместо этого необходимо создать новый узел с помощьюidentилиbindSym.См. также:
- процедура strVal для получения строкового значения.
- процедура ident для создания идентификатора.
- процедура bindSym для привязки символа.
proc symBodyHash(s: NimNode): string {.noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает стабильный дайджест для символов, полученных не только из сигнатуры типа и модуля владения, но и из тела реализации. Все процедуры/переменные, используемые в реализации этого символа, также хэшируются рекурсивно, включая магические константы из системного модуля. Источник Изменить
proc toNimIdent(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, ...deprecated: "Deprecated since version 0.18.0: Use \'ident\' or \'newIdentNode\' instead.", raises: [], tags: [], forbids: [].}- Создаёт идентификатор из строки
s. Исходный код Редактировать proc toStrLit(n: NimNode): NimNode {....raises: [], tags: [], forbids: [].}- Преобразует АСТ
nв конкретный код Nim и оборачивает его в узел строковой литералы. Исходный код Редактировать proc treeRepr(n: NimNode): string {....gcsafe, raises: [], tags: [], forbids: [].}-
Преобразует АСТ
nв удобочитаемую строку в виде дерева.См. также
Исходный код Редактироватьrepr, lispRepr и astGenRepr. proc typeKind(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect, ...raises: [], tags: [], forbids: [].}- Возвращает тип узла 'n', который должен представлять тип, то есть узел должен быть получен с помощью
getType. Исходный код Редактировать proc unpackInfix(node: NimNode): tuple[left: NimNode, op: string, right: NimNode] {. ...raises: [], tags: [], forbids: [].}- Исходный код Редактировать
proc unpackPostfix(node: NimNode): tuple[node: NimNode, op: string] {. ...raises: [], tags: [], forbids: [].}- Исходный код Редактировать
proc unpackPrefix(node: NimNode): tuple[node: NimNode, op: string] {....raises: [], tags: [], forbids: [].}- Исходный код Редактировать
proc warning(msg: string; n: NimNode = nil) {.magic: "NWarning", ...gcsafe, raises: [], tags: [], forbids: [].}- Выводит сообщение об ошибке во время компиляции. Исходный код Редактировать
Итераторы
iterator children(n: NimNode): NimNode {.inline, ...raises: [], tags: [], forbids: [].}- Итерируется по дочерним узлам NimNode
n. Исходный код Редактировать iterator items(n: NimNode): NimNode {.inline, ...raises: [], tags: [], forbids: [].}- Итерируется по дочерним узлам NimNode
n. Исходный код Редактировать iterator pairs(n: NimNode): (int, NimNode) {.inline, ...raises: [], tags: [], forbids: [].}- Итерируется по дочерним узлам NimNode
nи их индексам. Исходный код Редактировать
Макросы
macro dumpAstGen(s: untyped): untyped
-
Принимает блок кода Nim и выводит полученное абстрактное синтаксическое дерево с помощью процедуры
astGenRepr. Вывод осуществляется во время компиляции.Это можно использовать как инструмент для более быстрого написания макросов, записывая примеры вывода, а затем копируя фрагменты в макрос для изменения.
Например:
dumpAstGen: echo "Hello, World!"
Вывод:
nnkStmtList.newTree( nnkCommand.newTree( newIdentNode("echo"), newLit("Hello, World!") ) )Также см.
Исходный код РедактироватьdumpTreeиdumpLisp. macro dumpLisp(s: untyped): untyped
-
Принимает блок кода Nim и выводит полученное абстрактное синтаксическое дерево с помощью процедуры
lispRepr. Вывод осуществляется во время компиляции.Это можно использовать как инструмент для изучения абстрактного синтаксического дерева Nim и для выявления типов узлов, необходимых для представления определённого выражения/оператора.
Например:
dumpLisp: echo "Hello, World!"
Вывод:
(StmtList (Command (Ident "echo") (StrLit "Hello, World!")))
Также см.
Исходный код РедактироватьdumpAstGenиdumpTree. macro dumpTree(s: untyped): untyped
-
Принимает блок кода Nim и выводит полученное абстрактное синтаксическое дерево с помощью процедуры
treeRepr. Вывод осуществляется во время компиляции.Это можно использовать как инструмент для изучения абстрактного синтаксического дерева Nim и для выявления типов узлов, необходимых для представления определённого выражения/оператора.
Например:
dumpTree: echo "Hello, World!"
Вывод:
StmtList Command Ident "echo" StrLit "Hello, World!"Также см.
Исходный код РедактироватьdumpAstGenиdumpLisp. macro expandMacros(body: typed): untyped
-
Разворачивает один уровень макроса — полезно для отладки. Можно использовать для проверки того, что происходит при развёртывании вызова макроса, не изменяя его результат.
Например,
import std/[sugar, macros] let x = 10 y = 20 expandMacros: dump(x + y)
фактически выведет
Исходный код Редактироватьx + y, но в то же время выведет во время компиляции развёртывание макросаdump, которое в данном случае равноdebugEcho ["x + y", " = ", x + y]. macro getCustomPragmaVal(n: typed; cp: typed{nkSym}): untyped-
Расширяется до значения пользовательского псевдонима
cpвыраженияn, которое ожидаетсяnnkDotExpr, процедура или тип.См. также hasCustomPragma.
template serializationKey(key: string) {.pragma.} type MyObj {.serializationKey: "mo".} = object myField {.serializationKey: "mf".}: int var o: MyObj assert(o.myField.getCustomPragmaVal(serializationKey) == "mf") assert(o.getCustomPragmaVal(serializationKey) == "mo") assert(MyObj.getCustomPragmaVal(serializationKey) == "mo")Исходный код Редактировать macro hasCustomPragma(n: typed; cp: typed{nkSym}): untyped-
Расширяется до
true, если выражениеn, которое ожидается,nnkDotExpr(если проверяется поле), процедура или тип имеет пользовательский псевдонимcp.См. также getCustomPragmaVal.
template myAttr() {.pragma.} type MyObj = object myField {.myAttr.}: int proc myProc() {.myAttr.} = discard var o: MyObj assert(o.myField.hasCustomPragma(myAttr)) assert(myProc.hasCustomPragma(myAttr))Исходный код Редактировать macro unpackVarargs(callee: untyped; args: varargs[untyped]): untyped
- Вызывает
calleeсargs, распакованными как отдельные аргументы. Это полезно в 2 случаях:- при передаче
varargs[T]для какого-то типизированногоT - при передаче
varargs[untyped], когдаargsможет быть пустым из-за ограничения компилятора
Пример:
template call1(fun: typed; args: varargs[untyped]): untyped = unpackVarargs(fun, args) # when varargsLen(args) > 0: fun(args) else: fun() # this would also work template call2(fun: typed; args: varargs[typed]): untyped = unpackVarargs(fun, args) proc fn1(a = 0, b = 1) = discard (a, b) call1(fn1, 10, 11) call1(fn1) # `args` is empty in this case if false: call2(echo, 10, 11) # would print 1011
Исходный код Редактировать - при передаче
Шаблоны
template findChild(n: NimNode; cond: untyped): NimNode {.dirty.}-
Находит первый узел-потомок, удовлетворяющий условию (или nil).
var res = findChild(n, it.kind == nnkPostfix and it.basename.ident == ident"foo")Исходный код Редактировать template `or`(x, y: NimNode): NimNode
-
Вычисляет
xи, если это не пустой узел, возвращает его. В противном случае вычисляетy. Может быть использован для объединения нескольких выражений для получения первого непустого выражения.let node = mightBeEmpty() or mightAlsoBeEmpty() or fallbackNode
Исходный код Редактировать
© 2006–2024 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/macros.html