summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2012-04-06 05:02:48 +0300
committerZahary Karadjov <zahary@gmail.com>2012-04-06 13:46:31 +0300
commitefb53233cb3434b94b28060f0a642c51049cb09d (patch)
tree00f51557f8d12355402ede92e27c497d9dc13c53
parent98b7bdaa5050a9b3709e8a27fd44477a2a28e4f7 (diff)
downloadNim-efb53233cb3434b94b28060f0a642c51049cb09d.tar.gz
the foundations of a type traits module; better error messages for expr, typedesc and typeclasses params
-rwxr-xr-xcompiler/ast.nim8
-rwxr-xr-xcompiler/evals.nim20
-rwxr-xr-xcompiler/msgs.nim3
-rwxr-xr-xcompiler/semexprs.nim10
-rwxr-xr-xcompiler/semfold.nim2
-rw-r--r--compiler/semmagic.nim11
-rwxr-xr-xcompiler/semtypes.nim6
-rwxr-xr-xcompiler/types.nim17
8 files changed, 65 insertions, 12 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 972ba7924..c6a2b32e7 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -243,8 +243,13 @@ const
   sfFakeConst* = sfDeadCodeElim  # const cannot be put into a data section
   sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
   sfNoInit* = sfMainModule       # don't generate code to init the variable
+
   sfImmediate* = sfDeadCodeElim  # macro or template is immediately expanded
                                  # without considering any possible overloads
+  
+  sfAnon* = sfCompilerProc  # symbol name that was generated by the compiler
+                            # the compiler will avoid printing such names 
+                            # in user messages.
 
 const
   # getting ready for the future expr/stmt merge
@@ -358,7 +363,8 @@ const
 
 type
   TMagic* = enum # symbols that require compiler magic:
-    mNone, mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mIs, mOf,
+    mNone,
+    mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
     mEcho, mShallowCopy, mSlurp,
     mParseExprToAst, mParseStmtToAst, mExpandToAst,
     mUnaryLt, mSucc, 
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 84d3023a5..92726ae31 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -490,7 +490,7 @@ proc evalSwap(c: PEvalContext, n: PNode): PNode =
 proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = 
   var s = n.sym
   case s.kind
-  of skProc, skConverter, skMacro: 
+  of skProc, skConverter, skMacro, skType:
     result = n
     #result = s.getBody
   of skVar, skLet, skForVar, skTemp, skResult:
@@ -891,7 +891,24 @@ proc evalTemplate*(n: PNode, sym: PSym): PNode =
   result = evalTemplateAux(sym.getBody, args, sym)
   
   dec(evalTemplateCounter)
+ 
+proc evalTypeTrait*(n: PNode, context: PSym): PNode =
+  ## XXX: This should be pretty much guaranteed to be true
+  # by the type traits procs' signitures, but until the
+  # code is more mature it doesn't hurt to be extra safe
+  internalAssert n.sons.len >= 2 and
+                 n.sons[1].sym.typ.kind == tyTypeDesc
   
+  let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
+  case n.sons[0].sym.name.s
+  of "name":
+    result = newStrNode(nkStrLit, typ.typeToString)
+    result.typ = newType(tyString, context)
+    result.info = n.info
+
+  else:
+    internalAssert false
+
 proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
   var
     n = original.copyTree
@@ -941,6 +958,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
   of mParseExprToAst: result = evalParseExpr(c, n)
   of mParseStmtToAst: result = evalParseStmt(c, n)
   of mExpandToAst: result = evalExpandToAst(c, n)
+  of mTypeTrait: result = evalTypeTrait(n, c.module)
   of mNLen:
     result = evalAux(c, n.sons[1], {efLValue})
     if isSpecial(result): return 
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index df9064ab2..87f5e5650 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -667,3 +667,6 @@ template AssertNotNil*(e: expr): expr =
   if(e == nil): InternalError($InstantiationInfo())
   e
 
+template InternalAssert*(e: bool): stmt =
+  if not e: InternalError($InstantiationInfo())
+
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 8ab4c5f63..bca27a43d 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1314,11 +1314,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     Message(n.info, warnDeprecated, "bind")
     result = semExpr(c, n.sons[0], flags)
   of nkTypeOfExpr:
-    var typ = semTypeNode(c, n, nil)
-    if typ.sym == nil:
-      typ = copyType(typ, typ.owner, true)
-      typ.linkTo(newSym(skType, getIdent"typedesc", typ.owner))
-    result = newSymNode(typ.sym, n.info)
+    var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc})
+    typ = makeTypedesc(c, typ)
+    var sym = newSym(skType, getIdent"TypeOfExpr", typ.owner).linkTo(typ)
+    sym.flags.incl(sfAnon)
+    result = newSymNode(sym, n.info)
   of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: 
     # check if it is an expression macro:
     checkMinSonsLen(n, 1)
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 956667091..82ee7de13 100755
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -206,7 +206,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mNewString, mNewStringOfCap, 
      mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, 
      mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, 
-     mParseExprToAst, mParseStmtToAst, mExpandToAst,
+     mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
      mNLen..mNError, mEqRef: 
     nil
   of mRand:
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 4f120e2ab..e6861f2e4 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -8,6 +8,7 @@
 #
 
 # This include file implements the semantic checking for magics.
+# included from sem.nim
 
 proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var r = isPartOf(n[1], n[2])
@@ -43,11 +44,21 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
   result.add(filename)
   result.add(line)
 
+proc semTypeTraits(c: PContext, n: PNode): PNode =
+  checkMinSonsLen(n, 2)
+  internalAssert n.sons[1].kind == nkSym
+  if n.sons[1].sym.kind == skType:
+    result = evalTypeTrait(n, GetCurrOwner())
+  else:
+    # pass unmodified to evals
+    result = n
+
 proc magicsAfterOverloadResolution(c: PContext, n: PNode, 
                                    flags: TExprFlags): PNode =
   case n[0].sym.magic
   of mSlurp: result = semSlurp(c, n, flags)
   of mIsPartOf: result = semIsPartOf(c, n, flags)
+  of mTypeTrait: result = semTypeTraits(c, n)
   of mAstToStr:
     result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
     result.typ = getSysType(tyString)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 38cf19406..8479810d2 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -583,8 +583,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
                 break addImplicitGeneric
 
             var s = newSym(skType, paramTypId, getCurrOwner())
-            s.typ = typeClass
-            s.typ.sym = s
+            s.flags.incl(sfAnon)
+            s.linkTo(typeClass)
             s.position = genericParams.len
             genericParams.addSon(newSymNode(s))
             endingType = typeClass
@@ -693,7 +693,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkTypeOfExpr:
     # for ``type(countup(1,3))``, see ``tests/ttoseq``.
     checkSonsLen(n, 1)
-    result = semExprWithType(c, n.sons[0], {efInTypeof}).typ
+    result = semExprWithType(c, n.sons[0], {efInTypeof, efAllowType}).typ
   of nkPar: 
     if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
     else: GlobalError(n.info, errTypeExpected)
diff --git a/compiler/types.nim b/compiler/types.nim
index 3f7c2c820..15390bed7 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -372,6 +372,13 @@ proc rangeToStr(n: PNode): string =
   assert(n.kind == nkRange)
   result = ValueToString(n.sons[0]) & ".." & ValueToString(n.sons[1])
 
+proc constraintsToStr(t: PType): string =
+  let sep = if tfAny in t.flags: " or " else: " and "
+  result = ""
+  for i in countup(0, t.sons.len - 1):
+    if i > 0: result.add(sep)
+    result.add(t.sons[i].typeToString)
+
 proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string = 
   const 
     typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty", 
@@ -387,7 +394,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   var t = typ
   result = ""
   if t == nil: return 
-  if prefer == preferName and t.sym != nil:
+  if prefer == preferName and t.sym != nil and sfAnon notin t.sym.flags:
     return t.sym.Name.s
   case t.Kind
   of tyGenericBody, tyGenericInst, tyGenericInvokation:
@@ -396,6 +403,14 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       if i > 1: add(result, ", ")
       add(result, typeToString(t.sons[i]))
     add(result, ']')
+  of tyTypeDesc:
+    if t.sons.len == 0: result = "typedesc"
+    else: result = "typedesc{" & constraintsToStr(t) & "}"
+  of tyTypeClass:
+    result = constraintsToStr(t)
+  of tyExpr:
+    if t.sons.len == 0: result = "expr"
+    else: result = "expr{" & constraintsToStr(t) & "}"
   of tyArray: 
     if t.sons[0].kind == tyRange: 
       result = "array[" & rangeToStr(t.sons[0].n) & ", " &