如何在 Nim 中检查未命名的元组?

How to check for unnamed tuple in Nim?

如果就地定义了元组,则下面的宏有效,但如果它是通过类型名称定义的,则无效。

playground

import macros

macro is_unnamed_tuple[T](TT: type[T]): bool =
  # nnkTupleTy - named
  let r = new_lit(TT.getTypeInst[1].kind == nnkTupleConstr)
  quote do:
    `r`

type NamedT = tuple[a: string]
type UnnamedT = (string,)

echo is_unnamed_tuple tuple[a: string] # => false
echo is_unnamed_tuple NamedT           # => false
echo is_unnamed_tuple (string,)        # => true
echo is_unnamed_tuple UnnamedT         # => false <- Error

P.S.

也许有更简单的方法来检查它,比如 T is named tuple 或类似的东西?

此外,是否可以进行类似的检查对象是否为 variant

Here都是宏。

import std/macros

macro is_unnamed_tuple(T: typedesc): bool =
  # nnkTupleTy - named
  if T.kind != nnkTupleConstr:
    if T.kind == nnkSym:
      result = newLit( T.getImpl[^1].kind == nnkTupleConstr)
    else:
      result = newLit(false)
  else:
    result = newLit(true)

macro isVariant(T: typedesc): bool =
  result = newLit(false)
  let impl = T.getImpl
  if impl.kind != nnkNilLit:
    let objImpl =
      if impl[^1].kind == nnkRefTy:
        impl[^1][0]
      else:
        impl[^1]
    if objImpl.kind == nnkObjectTy:
      for x in objImpl[^1]:
        if x.kind == nnkRecCase:
          result = newLit(true)
          break
type 
  NamedT = tuple[a: string]
  UnnamedT = (string,)
  VarObj = object
    a: int
    case t: bool
    of true: discard
    of false: discard

assert is_unnamed_tuple(tuple[a: string]) == false
assert is_unnamed_tuple(NamedT) == false
assert is_unnamed_tuple((string,)) == true
assert is_unnamed_tuple(UnnamedT) == true
assert string.isVariant == false
assert VarObj.isVariant == true
assert int.isVariant == false