summary refs log tree commit diff stats
path: root/lib/core/macros.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/core/macros.nim')
-rw-r--r--lib/core/macros.nim72
1 files changed, 54 insertions, 18 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 4522e0fc6..4296cb0ae 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -12,7 +12,7 @@ include "system/inclrtl"
 ## This module contains the interface to the compiler's abstract syntax
 ## tree (`AST`:idx:). Macros operate on this tree.
 
-## .. include:: ../doc/astspec.txt
+## .. include:: ../../doc/astspec.txt
 
 type
   NimNodeKind* = enum
@@ -197,6 +197,18 @@ proc typeKind*(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect.}
   ## Returns the type kind of the node 'n' that should represent a type, that
   ## means the node should have been obtained via `getType`.
 
+proc getTypeInst*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
+  ## Like getType except it includes generic parameters for a specific instance
+
+proc getTypeInst*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
+  ## Like getType except it includes generic parameters for a specific instance
+
+proc getTypeImpl*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
+  ## Like getType except it includes generic parameters for the implementation
+
+proc getTypeImpl*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
+  ## Like getType except it includes generic parameters for the implementation
+
 proc strVal*(n: NimNode): string  {.magic: "NStrVal", noSideEffect.}
 
 proc `intVal=`*(n: NimNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.}
@@ -496,7 +508,7 @@ proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
 
   add(result, ")")
 
-macro dumpTree*(s: stmt): stmt {.immediate.} = echo s.treeRepr
+macro dumpTree*(s: untyped): untyped = echo s.treeRepr
   ## Accepts a block of nim code and prints the parsed abstract syntax
   ## tree using the `toTree` function. Printing is done *at compile time*.
   ##
@@ -504,17 +516,17 @@ macro dumpTree*(s: stmt): stmt {.immediate.} = echo s.treeRepr
   ## tree and to discover what kind of nodes must be created to represent
   ## a certain expression/statement.
 
-macro dumpLisp*(s: stmt): stmt {.immediate.} = echo s.lispRepr
+macro dumpLisp*(s: untyped): untyped = echo s.lispRepr
   ## Accepts a block of nim code and prints the parsed abstract syntax
   ## tree using the `toLisp` function. Printing is done *at compile time*.
   ##
   ## See `dumpTree`.
 
-macro dumpTreeImm*(s: stmt): stmt {.immediate, deprecated.} = echo s.treeRepr
-  ## The ``immediate`` version of `dumpTree`.
+macro dumpTreeImm*(s: untyped): untyped {.deprecated.} = echo s.treeRepr
+  ## Deprecated.
 
-macro dumpLispImm*(s: stmt): stmt {.immediate, deprecated.} = echo s.lispRepr
-  ## The ``immediate`` version of `dumpLisp`.
+macro dumpLispImm*(s: untyped): untyped {.deprecated.} = echo s.lispRepr
+  ## Deprecated.
 
 
 proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} =
@@ -680,8 +692,16 @@ proc `pragma=`*(someProc: NimNode; val: NimNode){.compileTime.}=
   assert val.kind in {nnkEmpty, nnkPragma}
   someProc[4] = val
 
+proc addPragma*(someProc, pragma: NimNode) {.compileTime.} =
+  ## Adds pragma to routine definition
+  someProc.expectRoutine
+  var pragmaNode = someProc.pragma
+  if pragmaNode.isNil or pragmaNode.kind == nnkEmpty:
+    pragmaNode = newNimNode(nnkPragma)
+    someProc.pragma = pragmaNode
+  pragmaNode.add(pragma)
 
-template badNodeKind(k; f): stmt{.immediate.} =
+template badNodeKind(k, f) =
   assert false, "Invalid node kind " & $k & " for macros.`" & $f & "`"
 
 proc body*(someProc: NimNode): NimNode {.compileTime.} =
@@ -738,20 +758,19 @@ iterator children*(n: NimNode): NimNode {.inline.} =
   for i in 0 ..< n.len:
     yield n[i]
 
-template findChild*(n: NimNode; cond: expr): NimNode {.
-  immediate, dirty.} =
+template findChild*(n: NimNode; cond: untyped): NimNode {.dirty.} =
   ## Find the first child node matching condition (or nil).
   ##
   ## .. code-block:: nim
   ##   var res = findChild(n, it.kind == nnkPostfix and
   ##                          it.basename.ident == !"foo")
   block:
-    var result: NimNode
+    var res: NimNode
     for it in n.children:
       if cond:
-        result = it
+        res = it
         break
-    result
+    res
 
 proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} =
   ## Insert node B into A at pos
@@ -796,17 +815,17 @@ proc infix*(a: NimNode; op: string;
 proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] {.
   compileTime.} =
   node.expectKind nnkPostfix
-  result = (node[0], $node[1])
+  result = (node[1], $node[0])
 
 proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] {.
   compileTime.} =
   node.expectKind nnkPrefix
-  result = (node[0], $node[1])
+  result = (node[1], $node[0])
 
 proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string;
                                         right: NimNode] {.compileTime.} =
   assert node.kind == nnkInfix
-  result = (node[0], $node[1], node[2])
+  result = (node[1], $node[0], node[2])
 
 proc copy*(node: NimNode): NimNode {.compileTime.} =
   ## An alias for copyNimTree().
@@ -818,6 +837,8 @@ proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
     else: result = c
   var i = 0
   var j = 0
+  # first char is case sensitive
+  if a[0] != b[0]: return 1
   while true:
     while a[i] == '_': inc(i)
     while b[j] == '_': inc(j) # BUGFIX: typo
@@ -828,9 +849,23 @@ proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
     inc(i)
     inc(j)
 
-proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0
+proc eqIdent*(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
   ## Check if two idents are identical.
 
+proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
+  ## Check if node is some identifier node (``nnkIdent``, ``nnkSym``, etc.)
+  ## is the same as ``s``. Note that this is the preferred way to check! Most
+  ## other ways like ``node.ident`` are much more error-prone, unfortunately.
+  case node.kind
+  of nnkIdent:
+    result = node.ident == !s
+  of nnkSym:
+    result = eqIdent($node.symbol, s)
+  of nnkOpenSymChoice, nnkClosedSymChoice:
+    result = eqIdent($node[0], s)
+  else:
+    result = false
+
 proc hasArgOfName* (params: NimNode; name: string): bool {.compiletime.}=
   ## Search nnkFormalParams for an argument.
   assert params.kind == nnkFormalParams
@@ -856,7 +891,7 @@ proc boolVal*(n: NimNode): bool {.compileTime, noSideEffect.} =
   else: n == bindSym"true" # hacky solution for now
 
 when not defined(booting):
-  template emit*(e: static[string]): stmt =
+  template emit*(e: static[string]): stmt {.deprecated.} =
     ## accepts a single string argument and treats it as nim code
     ## that should be inserted verbatim in the program
     ## Example:
@@ -864,6 +899,7 @@ when not defined(booting):
     ## .. code-block:: nim
     ##   emit("echo " & '"' & "hello world".toUpper & '"')
     ##
+    ## Deprecated since version 0.15 since it's so rarely useful.
     macro payload: stmt {.gensym.} =
       result = parseStmt(e)
     payload()