summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md6
-rw-r--r--compiler/semstmts.nim6
-rw-r--r--compiler/semtypes.nim4
-rw-r--r--compiler/vm.nim4
-rw-r--r--doc/manual.rst71
-rw-r--r--tests/metatype/ttypeselectors.nim2
6 files changed, 54 insertions, 39 deletions
diff --git a/changelog.md b/changelog.md
index f75958a73..31cb3d167 100644
--- a/changelog.md
+++ b/changelog.md
@@ -52,6 +52,12 @@
 - With the exception of `uint` and `uint64`, conversion to unsigned types
   are now range checked during runtime.
 
+- Macro arguments of type `typedesc` are now passed in to the macro as
+  `NimNode` like every other type. Use either `typed` or
+  `static[typedesc]` for a behavior that is identical in new and old
+  Nim.
+  RFC: `Pass typedesc as NimNode to macros
+  <https://github.com/nim-lang/RFCs/issues/148>`_.
 
 #### Breaking changes in the standard library
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 655b9c5c0..525de63e8 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1554,11 +1554,7 @@ proc activate(c: PContext, n: PNode) =
 
 proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
   if s.kind == skMacro:
-    let resultType =
-      if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyTypeDesc:
-        s.typ.sons[0]
-      else:
-        sysTypeFromName(c.graph, n.info, "NimNode")
+    let resultType = sysTypeFromName(c.graph, n.info, "NimNode")
     addResult(c, resultType, n.info, s.kind)
     addResultNode(c, n)
   elif s.typ.sons[0] != nil and not isInlineIterator(s):
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index dd9aea0f8..484fcfcd6 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -869,8 +869,8 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
       var a = copySym(param)
       a.typ = staticType.base
       addDecl(c, a)
-    elif param.typ != nil and param.typ.kind == tyTypeDesc:
-      addDecl(c, param)
+      #elif param.typ != nil and param.typ.kind == tyTypeDesc:
+      #  addDecl(c, param)
     else:
       # within a macro, every param has the type NimNode!
       let nn = getSysSym(c.graph, param.info, "NimNode")
diff --git a/compiler/vm.nim b/compiler/vm.nim
index f2d989a8d..8b36b461b 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -2028,8 +2028,8 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
   case typ.kind
   of tyStatic:
     putIntoReg(result, x)
-  of tyTypeDesc:
-    putIntoReg(result, x)
+  #of tyTypeDesc:
+  #  putIntoReg(result, x)
   else:
     result.kind = rkNode
     var n = x
diff --git a/doc/manual.rst b/doc/manual.rst
index 92d23f456..0de96077e 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -4828,16 +4828,8 @@ While macros enable advanced compile-time code transformations, they
 cannot change Nim's syntax. However, this is no real restriction because
 Nim's syntax is flexible enough anyway.
 
-To write macros, one needs to know how the Nim concrete syntax is converted
-to an AST.
-
-There are two ways to invoke a macro:
-(1) invoking a macro like a procedure call (`expression macros`)
-(2) invoking a macro with the special ``macrostmt`` syntax (`statement macros`)
-
-
-Expression Macros
------------------
+Debug Example
+-------------
 
 The following example implements a powerful ``debug`` command that accepts a
 variable number of arguments:
@@ -4943,22 +4935,23 @@ However, the symbols ``write``, ``writeLine`` and ``stdout`` are already bound
 and are not looked up again. As the example shows, ``bindSym`` does work with
 overloaded symbols implicitly.
 
+Case-Of Macro
+-------------
 
-Statement Macros
-----------------
-
-Statement macros are defined just as expression macros. However, they are
-invoked by an expression following a colon.
-
-The following example outlines a macro that generates a lexical analyzer from
-regular expressions:
+In Nim it is possible to have a macro with the syntax of a *case-of*
+expression just with the difference that all of branches are passed to
+and processed by the macro implementation. It is then up the macro
+implementation to transform the *of-branches* into a valid Nim
+statement. The following example should show how this feature could be
+used for a lexical analyzer.
 
 .. code-block:: nim
   import macros
 
-  macro case_token(n: untyped): untyped =
+  macro case_token(args: varargs[untyped]): untyped =
+    echo args.treeRepr
     # creates a lexical analyzer from regular expressions
-    # ... (implementation is an exercise for the reader :-)
+    # ... (implementation is an exercise for the reader ;-)
     discard
 
   case_token: # this colon tells the parser it is a macro statement
@@ -5001,8 +4994,8 @@ This is a simple syntactic transformation into:
     proc p() = discard
 
 
-For loop macros
----------------
+For Loop Macro
+--------------
 
 A macro that takes as its only input parameter an expression of the special
 type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop:
@@ -5197,8 +5190,10 @@ Once bound, type params can appear in the rest of the proc signature:
   declareVariableWithType int, 42
 
 
-Overload resolution can be further influenced by constraining the set of
-types that will match the type param:
+Overload resolution can be further influenced by constraining the set
+of types that will match the type param. This works in practice to
+attaching attributes to types via templates. The constraint can be a
+concrete type or a type class.
 
 .. code-block:: nim
     :test: "nim c $1"
@@ -5211,14 +5206,34 @@ types that will match the type param:
   when false:
     var s = string.maxval # error, maxval is not implemented for string
 
-The constraint can be a concrete type or a type class.
+  template isNumber(t: typedesc[object]): string = "Don't think so."
+  template isNumber(t: typedesc[SomeInteger]): string = "Yes!"
+  template isNumber(t: typedesc[SomeFloat]): string = "Maybe, could be NaN."
+
+  echo "is int a number? ", isNumber(int)
+  echo "is float a number? ", isNumber(float)
+  echo "is RootObj a number? ", isNumber(RootObj)
+
+Passing ``typedesc`` almost identical, just with the differences that
+the macro is not instantiated generically. The type expression is
+simply passed as a ``NimNode`` to the macro, like everything else.
+
+.. code-block:: nim
+
+  import macros
+
+  macro forwardType(arg: typedesc): typedesc =
+    # ``arg`` is of type ``NimNode``
+    let tmp: NimNode = arg
+    result = tmp
 
+  var tmp: forwardType(int)
 
 typeof operator
 ---------------
 
-**Note**: ``typeof(x)`` can also be written as ``type(x)`` but ``type(x)``
-is discouraged.
+**Note**: ``typeof(x)`` can for historical reasons also be written as
+``type(x)`` but ``type(x)`` is discouraged.
 
 You can obtain the type of a given expression by constructing a ``typeof``
 value from it (in many other languages this is known as the `typeof`:idx:
@@ -6989,5 +7004,3 @@ Threads and exceptions
 The interaction between threads and exceptions is simple: A *handled* exception
 in one thread cannot affect any other thread. However, an *unhandled* exception
 in one thread terminates the whole *process*!
-
-
diff --git a/tests/metatype/ttypeselectors.nim b/tests/metatype/ttypeselectors.nim
index eb857271d..52e5415be 100644
--- a/tests/metatype/ttypeselectors.nim
+++ b/tests/metatype/ttypeselectors.nim
@@ -14,7 +14,7 @@ template selectType(x: int): type =
 template simpleTypeTempl: type =
   string
 
-macro typeFromMacro: type = string
+macro typeFromMacro: type = bindSym"string"
 
 # The tests below check that the result variable of the
 # selected type matches the literal types in the code: