diff options
Diffstat (limited to 'lib/core/macros.nim')
-rw-r--r-- | lib/core/macros.nim | 90 |
1 files changed, 57 insertions, 33 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim index b26264405..7646b165c 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -23,6 +23,8 @@ when defined(nimPreviewSlimSystem): ## .. include:: ../../doc/astspec.txt +## .. importdoc:: system.nim + # If you look for the implementation of the magic symbol # ``{.magic: "Foo".}``, search for `mFoo` and `opcFoo`. @@ -91,6 +93,8 @@ type nnkFuncDef, nnkTupleConstr, nnkError, ## erroneous AST node + nnkModuleRef, nnkReplayAction, nnkNilRodNode ## internal IC nodes + nnkOpenSym NimNodeKinds* = set[NimNodeKind] NimTypeKind* = enum # some types are no longer used, see ast.nim @@ -143,8 +147,9 @@ type const nnkLiterals* = {nnkCharLit..nnkNilLit} + # see matching set CallNodes below nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, - nnkCallStrLit} + nnkCallStrLit, nnkHiddenCallConv} nnkPragmaCallKinds = {nnkExprColonExpr, nnkCall, nnkCallStrLit} {.push warnings: off.} @@ -205,7 +210,7 @@ template `or`*(x, y: NimNode): NimNode = ## Evaluate `x` and when it is not an empty node, return ## it. Otherwise evaluate to `y`. Can be used to chain several ## expressions to get the first expression that is not empty. - ## ``` + ## ```nim ## let node = mightBeEmpty() or mightAlsoBeEmpty() or fallbackNode ## ``` @@ -274,7 +279,7 @@ when (NimMajor, NimMinor, NimPatch) >= (1, 3, 5) or defined(nimSymImplTransform) ## note that code transformations are implementation dependent and subject to change. ## See an example in `tests/macros/tmacros_various.nim`. -proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.} +proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect, deprecated.} ## Accepts a node of kind `nnkSym` and returns its owner's symbol. ## The meaning of 'owner' depends on `sym`'s `NimSymKind` and declaration ## context. For top level declarations this is an `nskModule` symbol, @@ -344,8 +349,7 @@ proc getTypeImpl*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} = newLit(x.getTypeImpl.repr) let t = """ object - arr: array[0 .. 3, float32] -""" + arr: array[0 .. 3, float32]""" doAssert(dumpTypeImpl(a) == t) doAssert(dumpTypeImpl(b) == t) doAssert(dumpTypeImpl(c) == t) @@ -424,7 +428,12 @@ proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.} = let x = 12 echo x -proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.} +when defined(nimHasNoReturnError): + {.pragma: errorNoReturn, noreturn.} +else: + {.pragma: errorNoReturn.} + +proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign, errorNoReturn.} ## Writes an error message at compile time. The optional `n: NimNode` ## parameter is used as the source for file and line number information in ## the compilation error message. @@ -533,6 +542,22 @@ proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.} proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.} ## Copy lineinfo from `info`. +proc setLine(arg: NimNode, line: uint16) {.magic: "NLineInfo", noSideEffect.} +proc setColumn(arg: NimNode, column: int16) {.magic: "NLineInfo", noSideEffect.} +proc setFile(arg: NimNode, file: string) {.magic: "NLineInfo", noSideEffect.} + +proc setLineInfo*(arg: NimNode, file: string, line: int, column: int) = + ## Sets the line info on the NimNode. The file needs to exists, but can be a + ## relative path. If you want to attach line info to a block using `quote` + ## you'll need to add the line information after the quote block. + arg.setFile(file) + arg.setLine(line.uint16) + arg.setColumn(column.int16) + +proc setLineInfo*(arg: NimNode, lineInfo: LineInfo) = + ## See `setLineInfo proc<#setLineInfo,NimNode,string,int,int>`_ + setLineInfo(arg, lineInfo.filename, lineInfo.line, lineInfo.column) + proc lineInfoObj*(n: NimNode): LineInfo = ## Returns `LineInfo` of `n`, using absolute path for `filename`. result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn) @@ -571,7 +596,7 @@ proc getAst*(macroOrTemplate: untyped): NimNode {.magic: "ExpandToAst", noSideEf ## Obtains the AST nodes returned from a macro or template invocation. ## See also `genasts.genAst`. ## Example: - ## ``` + ## ```nim ## macro FooMacro() = ## var ast = getAst(BarTemplate()) ## ``` @@ -929,6 +954,8 @@ proc treeTraverse(n: NimNode; res: var string; level = 0; isLisp = false, indent discard # same as nil node in this representation of nnkCharLit .. nnkInt64Lit: res.add(" " & $n.intVal) + of nnkUIntLit .. nnkUInt64Lit: + res.add(" " & $cast[uint64](n.intVal)) of nnkFloatLit .. nnkFloat64Lit: res.add(" " & $n.floatVal) of nnkStrLit .. nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym: @@ -1028,7 +1055,7 @@ macro dumpTree*(s: untyped): untyped = echo s.treeRepr ## a certain expression/statement. ## ## For example: - ## ``` + ## ```nim ## dumpTree: ## echo "Hello, World!" ## ``` @@ -1052,7 +1079,7 @@ macro dumpLisp*(s: untyped): untyped = echo s.lispRepr(indented = true) ## a certain expression/statement. ## ## For example: - ## ``` + ## ```nim ## dumpLisp: ## echo "Hello, World!" ## ``` @@ -1075,7 +1102,7 @@ macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr ## outputs and then copying the snippets into the macro for modification. ## ## For example: - ## ``` + ## ```nim ## dumpAstGen: ## echo "Hello, World!" ## ``` @@ -1158,7 +1185,7 @@ proc newIdentDefs*(name, kind: NimNode; ## `let` or `var` blocks may have an empty `kind` node if the ## identifier is being assigned a value. Example: ## - ## ``` + ## ```nim ## var varSection = newNimNode(nnkVarSection).add( ## newIdentDefs(ident("a"), ident("string")), ## newIdentDefs(ident("b"), newEmptyNode(), newLit(3))) @@ -1169,7 +1196,7 @@ proc newIdentDefs*(name, kind: NimNode; ## ## If you need to create multiple identifiers you need to use the lower level ## `newNimNode`: - ## ``` + ## ```nim ## result = newNimNode(nnkIdentDefs).add( ## ident("a"), ident("b"), ident("c"), ident("string"), ## newStrLitNode("Hello")) @@ -1188,8 +1215,8 @@ const RoutineNodes* = {nnkProcDef, nnkFuncDef, nnkMethodDef, nnkDo, nnkLambda, nnkIteratorDef, nnkTemplateDef, nnkConverterDef, nnkMacroDef} AtomicNodes* = {nnkNone..nnkNilLit} - CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, - nnkCallStrLit, nnkHiddenCallConv} + # see matching set nnkCallKinds above + CallNodes* = nnkCallKinds proc expectKind*(n: NimNode; k: set[NimNodeKind]) = ## Checks that `n` is of kind `k`. If this is not the case, @@ -1220,7 +1247,7 @@ proc newProc*(name = newEmptyNode(); proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]): NimNode = ## Constructor for `if` statements. - ## ``` + ## ```nim ## newIfStmt( ## (Ident, StmtList), ## ... @@ -1237,7 +1264,7 @@ proc newEnum*(name: NimNode, fields: openArray[NimNode], ## Creates a new enum. `name` must be an ident. Fields are allowed to be ## either idents or EnumFieldDef: - ## ``` + ## ```nim ## newEnum( ## name = ident("Colors"), ## fields = [ident("Blue"), ident("Red")], @@ -1382,7 +1409,7 @@ proc `$`*(node: NimNode): string = result = node.basename.strVal & "*" of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkSym, nnkIdent: result = node.strVal - of nnkOpenSymChoice, nnkClosedSymChoice: + of nnkOpenSymChoice, nnkClosedSymChoice, nnkOpenSym: result = $node[0] of nnkAccQuoted: result = "" @@ -1408,7 +1435,7 @@ iterator children*(n: NimNode): NimNode {.inline.} = template findChild*(n: NimNode; cond: untyped): NimNode {.dirty.} = ## Find the first child node matching condition (or nil). - ## ``` + ## ```nim ## var res = findChild(n, it.kind == nnkPostfix and ## it.basename.ident == ident"foo") ## ``` @@ -1503,11 +1530,10 @@ proc boolVal*(n: NimNode): bool {.noSideEffect.} = if n.kind == nnkIntLit: n.intVal != 0 else: n == bindSym"true" # hacky solution for now -when defined(nimMacrosGetNodeId): - proc nodeID*(n: NimNode): int {.magic: "NodeId".} - ## Returns the id of `n`, when the compiler has been compiled - ## with the flag `-d:useNodeids`, otherwise returns `-1`. This - ## proc is for the purpose to debug the compiler only. +proc nodeID*(n: NimNode): int {.magic: "NodeId".} + ## Returns the id of `n`, when the compiler has been compiled + ## with the flag `-d:useNodeids`, otherwise returns `-1`. This + ## proc is for the purpose to debug the compiler only. macro expandMacros*(body: typed): untyped = ## Expands one level of macro - useful for debugging. @@ -1516,7 +1542,7 @@ macro expandMacros*(body: typed): untyped = ## ## For instance, ## - ## ``` + ## ```nim ## import std/[sugar, macros] ## ## let @@ -1574,7 +1600,7 @@ proc customPragmaNode(n: NimNode): NimNode = elif impl.kind in {nnkIdentDefs, nnkConstDef} and impl[0].kind == nnkPragmaExpr: return impl[0][1] else: - let timpl = typ.getImpl() + let timpl = getImpl(if typ.kind == nnkBracketExpr: typ[0] else: typ) if timpl.len>0 and timpl[0].len>1: return timpl[0][1] else: @@ -1582,11 +1608,9 @@ proc customPragmaNode(n: NimNode): NimNode = if n.kind in {nnkDotExpr, nnkCheckedFieldExpr}: let name = $(if n.kind == nnkCheckedFieldExpr: n[0][1] else: n[1]) - let typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0]) - var typDef = getImpl( - if typInst.kind in {nnkVarTy, nnkBracketExpr}: typInst[0] - else: typInst - ) + var typInst = getTypeInst(if n.kind == nnkCheckedFieldExpr or n[0].kind == nnkHiddenDeref: n[0][0] else: n[0]) + while typInst.kind in {nnkVarTy, nnkBracketExpr}: typInst = typInst[0] + var typDef = getImpl(typInst) while typDef != nil: typDef.expectKind(nnkTypeDef) let typ = typDef[2].extractTypeImpl() @@ -1634,7 +1658,7 @@ macro hasCustomPragma*(n: typed, cp: typed{nkSym}): untyped = ## ## See also `getCustomPragmaVal`_. ## - ## ``` + ## ```nim ## template myAttr() {.pragma.} ## type ## MyObj = object @@ -1659,7 +1683,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped = ## ## See also `hasCustomPragma`_. ## - ## ``` + ## ```nim ## template serializationKey(key: string) {.pragma.} ## type ## MyObj {.serializationKey: "mo".} = object @@ -1755,7 +1779,7 @@ proc extractDocCommentsAndRunnables*(n: NimNode): NimNode = ## runnableExamples in `a`, stopping at the first child that is neither. ## Example: ## - ## ``` + ## ```nim ## import std/macros ## macro transf(a): untyped = ## result = quote do: |