summary refs log tree commit diff stats
path: root/compiler/semmagic.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/semmagic.nim')
-rw-r--r--compiler/semmagic.nim88
1 files changed, 79 insertions, 9 deletions
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index d5d6bbbd3..478e2cf37 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -10,10 +10,24 @@
 # This include file implements the semantic checking for magics.
 # included from sem.nim
 
+proc semAddr(c: PContext; n: PNode): PNode =
+  result = newNodeI(nkAddr, n.info)
+  let x = semExprWithType(c, n)
+  if isAssignable(c, x) notin {arLValue, arLocalLValue}:
+    localError(n.info, errExprHasNoAddress)
+  result.add x
+  result.typ = makePtrType(c, x.typ)
+
+proc semTypeOf(c: PContext; n: PNode): PNode =
+  result = newNodeI(nkTypeOfExpr, n.info)
+  let typExpr = semExprWithType(c, n, {efInTypeof})
+  result.add typExpr
+  result.typ = makeTypeDesc(c, typExpr.typ.skipTypes({tyTypeDesc, tyIter}))
+
 proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var r = isPartOf(n[1], n[2])
   result = newIntNodeT(ord(r), n)
-  
+
 proc expectIntLit(c: PContext, n: PNode): int =
   let x = c.semConstExpr(c, n)
   case x.kind
@@ -31,7 +45,7 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
   line.intVal = toLinenumber(info)
   result.add(filename)
   result.add(line)
- 
+
 proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
   let typ = operand.skipTypes({tyTypeDesc})
   case trait.sym.name.s.normalize
@@ -40,7 +54,7 @@ proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
     result.typ = newType(tyString, context)
     result.info = trait.info
   of "arity":
-    result = newIntNode(nkIntLit, typ.n.len-1)
+    result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
     result.typ = newType(tyInt, context)
     result.info = trait.info
   else:
@@ -66,18 +80,18 @@ proc semOrd(c: PContext, n: PNode): PNode =
 proc semBindSym(c: PContext, n: PNode): PNode =
   result = copyNode(n)
   result.add(n.sons[0])
-  
+
   let sl = semConstExpr(c, n.sons[1])
-  if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}: 
+  if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
     localError(n.sons[1].info, errStringLiteralExpected)
     return errorNode(c, n)
-  
+
   let isMixin = semConstExpr(c, n.sons[2])
   if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
       isMixin.intVal > high(TSymChoiceRule).int:
     localError(n.sons[2].info, errConstExprExpected)
     return errorNode(c, n)
-  
+
   let id = newIdentNode(getIdent(sl.strVal), n.info)
   let s = qualifiedLookUp(c, id)
   if s != nil:
@@ -110,15 +124,33 @@ proc semLocals(c: PContext, n: PNode): PNode =
 
         addSon(tupleType.n, newSymNode(field))
         addSonSkipIntLit(tupleType, field.typ)
-        
+
         var a = newSymNode(it, result.info)
         if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
         result.add(a)
 
 proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
-proc magicsAfterOverloadResolution(c: PContext, n: PNode, 
+
+proc isStrangeArray(t: PType): bool =
+  let t = t.skipTypes(abstractInst)
+  result = t.kind == tyArray and t.firstOrd != 0
+
+proc isNegative(n: PNode): bool =
+  let n = n.skipConv
+  if n.kind in {nkCharLit..nkUInt64Lit}:
+    result = n.intVal < 0
+  elif n.kind in nkCallKinds and n.sons[0].kind == nkSym:
+    result = n.sons[0].sym.magic in {mUnaryMinusI, mUnaryMinusI64}
+
+proc magicsAfterOverloadResolution(c: PContext, n: PNode,
                                    flags: TExprFlags): PNode =
   case n[0].sym.magic
+  of mAddr:
+    checkSonsLen(n, 2)
+    result = semAddr(c, n.sons[1])
+  of mTypeOf:
+    checkSonsLen(n, 2)
+    result = semTypeOf(c, n.sons[1])
   of mIsPartOf: result = semIsPartOf(c, n, flags)
   of mTypeTrait: result = semTypeTraits(c, n)
   of mAstToStr:
@@ -133,4 +165,42 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mProcCall:
     result = n
     result.typ = n[1].typ
+  of mDotDot:
+    result = n
+    # disallow negative indexing for now:
+    if not c.p.bracketExpr.isNil:
+      if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])):
+        localError(n.info, "use '^' instead of '-'; negative indexing is obsolete")
+  of mRoof:
+    # error correction:
+    result = n.sons[1]
+    if c.p.bracketExpr.isNil:
+      localError(n.info, "no surrounding array access context for '^'")
+    elif c.p.bracketExpr.checkForSideEffects != seNoSideEffect:
+      localError(n.info, "invalid context for '^' as '$#' has side effects" %
+        renderTree(c.p.bracketExpr))
+    elif c.p.bracketExpr.typ.isStrangeArray:
+      localError(n.info, "invalid context for '^' as len!=high+1 for '$#'" %
+        renderTree(c.p.bracketExpr))
+    else:
+      # ^x  is rewritten to: len(a)-x
+      let lenExpr = newNodeI(nkCall, n.info)
+      lenExpr.add newIdentNode(getIdent"len", n.info)
+      lenExpr.add c.p.bracketExpr
+      let lenExprB = semExprWithType(c, lenExpr)
+      if lenExprB.typ.isNil or not isOrdinalType(lenExprB.typ):
+        localError(n.info, "'$#' has to be of an ordinal type for '^'" %
+          renderTree(lenExpr))
+      else:
+        result = newNodeIT(nkCall, n.info, getSysType(tyInt))
+        result.add newSymNode(createMagic("-", mSubI), n.info)
+        result.add lenExprB
+        result.add n.sons[1]
+  of mPlugin:
+    let plugin = getPlugin(n[0].sym)
+    if plugin.isNil:
+      localError(n.info, "cannot find plugin " & n[0].sym.name.s)
+      result = n
+    else:
+      result = plugin(c, n)
   else: result = n