summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2018-04-20 11:44:13 +0300
committerZahary Karadjov <zahary@gmail.com>2018-06-16 16:46:32 +0300
commitfb27357b6217f53dc882e83fc128da578ad51764 (patch)
tree9922a3180ce7ce445500925aedb38ba932cfcc62 /compiler
parent8633b1b3097e1627f16a52fc648f0e14c647a688 (diff)
downloadNim-fb27357b6217f53dc882e83fc128da578ad51764.tar.gz
A minimal patch enabling the new typedesc and static types syntax
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim4
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/parser.nim63
-rw-r--r--compiler/sem.nim3
-rw-r--r--compiler/semexprs.nim39
-rw-r--r--compiler/semtypes.nim38
-rw-r--r--compiler/sigmatch.nim14
7 files changed, 110 insertions, 52 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 40c1b064d..d266e20b0 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -571,8 +571,8 @@ type
   TMagic* = enum # symbols that require compiler magic:
     mNone,
     mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn,
-    mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin,
-    mEcho, mShallowCopy, mSlurp, mStaticExec,
+    mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mType, mTypeOf,
+    mRoof, mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic,
     mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
     mUnaryLt, mInc, mDec, mOrd,
     mNew, mNewFinalize, mNewSeq, mNewSeqOfCap,
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 56587a4fa..8b2d36722 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -44,6 +44,7 @@ proc initDefines*(symbols: StringTableRef) =
   defineSymbol("nimcomputedgoto")
   defineSymbol("nimunion")
   defineSymbol("nimnewshared")
+  defineSymbol("nimNewTypedesc")
   defineSymbol("nimrequiresnimframe")
   defineSymbol("nimparsebiggestfloatmagic")
   defineSymbol("nimalias")
diff --git a/compiler/parser.nim b/compiler/parser.nim
index c0465b05e..33ee8c9e6 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -50,6 +50,9 @@ type
   SymbolMode = enum
     smNormal, smAllowNil, smAfterDot
 
+  TPrimaryMode = enum
+    pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
+
 proc parseAll*(p: var TParser): PNode
 proc closeParser*(p: var TParser)
 proc parseTopLevelStmt*(p: var TParser): PNode
@@ -81,6 +84,9 @@ proc parsePragma(p: var TParser): PNode
 proc postExprBlocks(p: var TParser, x: PNode): PNode
 proc parseExprStmt(p: var TParser): PNode
 proc parseBlock(p: var TParser): PNode
+proc primary(p: var TParser, mode: TPrimaryMode): PNode
+proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
+
 # implementation
 
 proc getTok(p: var TParser) =
@@ -332,6 +338,8 @@ proc colcom(p: var TParser, n: PNode) =
   eat(p, tkColon)
   skipComment(p, n)
 
+const tkBuiltInMagics = {tkType, tkStatic, tkAddr}
+
 proc parseSymbol(p: var TParser, mode = smNormal): PNode =
   #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
   #|        | IDENT | KEYW
@@ -340,7 +348,7 @@ proc parseSymbol(p: var TParser, mode = smNormal): PNode =
     result = newIdentNodeP(p.tok.ident, p)
     getTok(p)
   of tokKeywordLow..tokKeywordHigh:
-    if p.tok.tokType == tkAddr or p.tok.tokType == tkType or mode == smAfterDot:
+    if p.tok.tokType in tkBuiltInMagics or mode == smAfterDot:
       # for backwards compatibility these 2 are always valid:
       result = newIdentNodeP(p.tok.ident, p)
       getTok(p)
@@ -525,9 +533,6 @@ proc parseGStrLit(p: var TParser, a: PNode): PNode =
   else:
     result = a
 
-type
-  TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
-
 proc complexOrSimpleStmt(p: var TParser): PNode
 proc simpleExpr(p: var TParser, mode = pmNormal): PNode
 
@@ -625,7 +630,7 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
   #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
   #| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
   case p.tok.tokType
-  of tkSymbol, tkType, tkAddr:
+  of tkSymbol, tkBuiltInMagics:
     result = newIdentNodeP(p.tok.ident, p)
     getTok(p)
     result = parseGStrLit(p, result)
@@ -741,7 +746,12 @@ proc commandParam(p: var TParser, isFirstParam: var bool): PNode =
     addSon(result, parseExpr(p))
   isFirstParam = false
 
-proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
+const
+  tkTypeClasses = {tkRef, tkPtr, tkVar, tkStatic, tkType,
+                   tkEnum, tkTuple, tkObject, tkProc}
+
+proc primarySuffix(p: var TParser, r: PNode,
+                   baseIndent: int, mode: TPrimaryMode): PNode =
   #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
   #|       | doBlocks
   #|       | '.' optInd symbol generalizedLit?
@@ -758,7 +768,14 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
     case p.tok.tokType
     of tkParLe:
       # progress guaranteed
-      somePar()
+      if p.tok.strongSpaceA > 0:
+        # inside type sections, expressions such as `ref (int, bar)`
+        # are parsed as a nkCommand with a single tuple argument (nkPar)
+        if mode == pmTypeDef:
+          result = newNodeP(nkCommand, p)
+          result.addSon r
+          result.addSon primary(p, pmNormal)
+        break
       result = namedParams(p, result, nkCall, tkParRi)
       if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
         result.kind = nkObjConstr
@@ -774,9 +791,15 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
       # progress guaranteed
       somePar()
       result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
-    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType,
-       tkOpr, tkDotDot:
-      if p.inPragma == 0 and (isUnary(p) or p.tok.tokType notin {tkOpr, tkDotDot}):
+    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast,
+       tkOpr, tkDotDot, tkTypeClasses - {tkRef, tkPtr}:
+        # XXX: In type sections we allow the free application of the
+        # command syntax, with the exception of expressions such as
+        # `foo ref` or `foo ptr`. Unfortunately, these two are also
+        # used as infix operators for the memory regions feature and
+        # the current parsing rules don't play well here.
+      if mode == pmTypeDef or
+        (p.inPragma == 0 and (isUnary(p) or p.tok.tokType notin {tkOpr, tkDotDot})):
         # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
         # solution, but pragmas.nim can't handle that
         let a = result
@@ -800,9 +823,6 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
     else:
       break
 
-proc primary(p: var TParser, mode: TPrimaryMode): PNode
-proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
-
 proc parseOperators(p: var TParser, headNode: PNode,
                     limit: int, mode: TPrimaryMode): PNode =
   result = headNode
@@ -1107,9 +1127,9 @@ proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
 proc isExprStart(p: TParser): bool =
   case p.tok.tokType
   of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
-     tkProc, tkFunc, tkIterator, tkBind, tkAddr,
+     tkProc, tkFunc, tkIterator, tkBind, tkBuiltInMagics,
      tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
-     tkTuple, tkObject, tkType, tkWhen, tkCase, tkOut:
+     tkTuple, tkObject, tkWhen, tkCase, tkOut:
     result = true
   else: result = false
 
@@ -1170,7 +1190,6 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
   #|          | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
   #| primary = typeKeyw typeDescK
   #|         /  prefixOperator* identOrLiteral primarySuffix*
-  #|         / 'static' primary
   #|         / 'bind' primary
   if isOperator(p.tok):
     let isSigil = isSigilLike(p.tok)
@@ -1183,7 +1202,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
       #XXX prefix operators
       let baseInd = p.lex.currLineIndent
       addSon(result, primary(p, pmSkipSuffix))
-      result = primarySuffix(p, result, baseInd)
+      result = primarySuffix(p, result, baseInd, mode)
     else:
       addSon(result, primary(p, pmNormal))
     return
@@ -1213,14 +1232,6 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
       result = parseTypeClass(p)
     else:
       parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
-  of tkStatic:
-    let info = parLineInfo(p)
-    getTokNoInd(p)
-    let next = primary(p, pmNormal)
-    if next.kind == nkBracket and next.sonsLen == 1:
-      result = newNode(nkStaticTy, info, @[next.sons[0]])
-    else:
-      result = newNode(nkStaticExpr, info, @[next])
   of tkBind:
     result = newNodeP(nkBind, p)
     getTok(p)
@@ -1235,7 +1246,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     let baseInd = p.lex.currLineIndent
     result = identOrLiteral(p, mode)
     if mode != pmSkipSuffix:
-      result = primarySuffix(p, result, baseInd)
+      result = primarySuffix(p, result, baseInd, mode)
 
 proc parseTypeDesc(p: var TParser): PNode =
   #| typeDesc = simpleExpr
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 3b16e0938..3c3ffa194 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -48,6 +48,9 @@ proc semQuoteAst(c: PContext, n: PNode): PNode
 proc finishMethod(c: PContext, s: PSym)
 proc evalAtCompileTime(c: PContext, n: PNode): PNode
 proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
+proc semStaticExpr(c: PContext, n: PNode): PNode
+proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType
+proc semTypeOf(c: PContext; n: PNode): PNode
 
 proc isArrayConstr(n: PNode): bool {.inline.} =
   result = n.kind == nkBracket and
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 9d7c493a7..4b45ccf87 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -191,7 +191,25 @@ proc semConv(c: PContext, n: PNode): PNode =
     return n
 
   result = newNodeI(nkConv, n.info)
-  var targetType = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
+
+  var targetType = semTypeNode(c, n.sons[0], nil)
+  if targetType.kind == tyTypeDesc:
+    internalAssert targetType.len > 0
+    if targetType.base.kind == tyNone:
+      return semTypeOf(c, n[1])
+    else:
+      targetType = targetType.base
+  elif targetType.kind == tyStatic:
+    var evaluated = semStaticExpr(c, n[1])
+    if evaluated.kind == nkType or evaluated.typ.kind == tyTypeDesc:
+      result = n
+      result.typ = c.makeTypeDesc semStaticType(c, evaluated, nil)
+      return
+    elif targetType.base.kind == tyNone:
+      return evaluated
+    else:
+      targetType = targetType.base
+
   maybeLiftType(targetType, c, n[0].info)
 
   if targetType.kind in {tySink, tyLent}:
@@ -632,7 +650,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     #  echo "SUCCESS evaluated at compile time: ", call.renderTree
 
 proc semStaticExpr(c: PContext, n: PNode): PNode =
-  let a = semExpr(c, n.sons[0])
+  let a = semExpr(c, n)
   if a.findUnresolvedStatic != nil: return a
   result = evalStaticExpr(c.module, c.graph, a, c.p.owner)
   if result.isNil:
@@ -1034,7 +1052,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
   of skType:
     markUsed(c.config, n.info, s, c.graph.usageSym)
     styleCheckUse(n.info, s)
-    if s.typ.kind == tyStatic and s.typ.n != nil:
+    if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
       return s.typ.n
     result = newSymNode(s, n.info)
     result.typ = makeTypeDesc(c, s.typ)
@@ -1261,8 +1279,18 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # make sure we don't evaluate generic macros/templates
   n.sons[0] = semExprWithType(c, n.sons[0],
                               {efNoEvaluateGeneric})
-  let arr = skipTypes(n.sons[0].typ, {tyGenericInst,
+  var arr = skipTypes(n.sons[0].typ, {tyGenericInst,
                                       tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink})
+  if arr.kind == tyStatic:
+    if arr.base.kind == tyNone:
+      result = n
+      result.typ = semStaticType(c, n[1], nil)
+      return
+    elif arr.n != nil:
+      return semSubscript(c, arr.n, flags)
+    else:
+      arr = arr.base
+
   case arr.kind
   of tyArray, tyOpenArray, tyVarargs, tySequence, tyString,
      tyCString:
@@ -2426,8 +2454,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     # handling of sym choices is context dependent
     # the node is left intact for now
     discard
-  of nkStaticExpr:
-    result = semStaticExpr(c, n)
+  of nkStaticExpr: result = semStaticExpr(c, n[0])
   of nkAsgn: result = semAsgn(c, n)
   of nkBlockStmt, nkBlockExpr: result = semBlock(c, n)
   of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 3e62652a7..597522f6f 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -37,6 +37,12 @@ const
   errNoGenericParamsAllowedForX = "no generic parameters allowed for $1"
   errInOutFlagNotExtern = "the '$1' modifier can be used only with imported types"
 
+const
+  mStaticTy = {mStatic}
+  mTypeTy = {mType, mTypeOf}
+  # XXX: This should be needed only temporarily until the C
+  # sources are rebuilt
+
 proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
   if prev == nil:
     result = newTypeS(kind, c)
@@ -363,6 +369,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
     if result != nil:
       markUsed(c.config, n.info, result, c.graph.usageSym)
       styleCheckUse(n.info, result)
+
       if result.kind == skParam and result.typ.kind == tyTypeDesc:
         # This is a typedesc param. is it already bound?
         # it's not bound when it's used multiple times in the
@@ -388,8 +395,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
         else:
           localError(c.config, n.info, errTypeExpected)
           return errorSym(c, n)
-
-      if result.kind != skType:
+      if result.kind != skType and result.magic notin (mStaticTy + mTypeTy):
         # this implements the wanted ``var v: V, x: V`` feature ...
         var ov: TOverloadIter
         var amb = initOverloadIter(ov, c, n)
@@ -856,9 +862,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     result = addImplicitGenericImpl(c, newTypeS(tyGenericParam, c), nil)
 
   of tyStatic:
-    # proc(a: expr{string}, b: expr{nkLambda})
-    # overload on compile time values and AST trees
-    if paramType.n != nil: return # this is a concrete type
+    if paramType.base.kind != tyNone and paramType.n != nil:
+      # this is a concrete type
+      return
     if tfUnresolved in paramType.flags: return # already lifted
     let base = paramType.base.maybeLift
     if base.isMetaType and procKind == skMacro:
@@ -879,7 +885,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
   of tyDistinct:
     if paramType.sonsLen == 1:
       # disable the bindOnce behavior for the type class
-      result = liftingWalk(paramType.sons[0], true)
+      result = liftingWalk(paramType.base, true)
 
   of tySequence, tySet, tyArray, tyOpenArray,
      tyVar, tyLent, tyPtr, tyRef, tyProc:
@@ -1349,6 +1355,12 @@ proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
     localError(c.config, n.info, errTypeExpected)
     result = errorSym(c, n)
 
+proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =
+  result = newOrPrevType(tyStatic, prev, c)
+  var base = semTypeNode(c, childNode, nil).skipTypes({tyTypeDesc, tyAlias})
+  result.rawAddSon(base)
+  result.flags.incl tfHasStatic
+
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   result = nil
   inc c.inTypeContext
@@ -1456,7 +1468,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     of mSeq: result = semContainer(c, n, tySequence, "seq", prev)
     of mOpt: result = semContainer(c, n, tyOpt, "opt", prev)
     of mVarargs: result = semVarargs(c, n, prev)
-    of mTypeDesc: result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
+    of mTypeDesc, mTypeTy: result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
+    of mStaticTy: result = semStaticType(c, n[1], prev)
     of mExpr:
       result = semTypeNode(c, n.sons[0], nil)
       if result != nil:
@@ -1545,11 +1558,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
   of nkVarTy: result = semVarType(c, n, prev)
   of nkDistinctTy: result = semDistinct(c, n, prev)
-  of nkStaticTy:
-    result = newOrPrevType(tyStatic, prev, c)
-    var base = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
-    result.rawAddSon(base)
-    result.flags.incl tfHasStatic
+  of nkStaticTy: result = semStaticType(c, n[0], prev)
   of nkIteratorTy:
     if n.sonsLen == 0:
       result = newTypeS(tyBuiltInTypeClass, c)
@@ -1645,9 +1654,12 @@ proc processMagicType(c: PContext, m: PSym) =
   of mStmt:
     setMagicType(c.config, m, tyStmt, 0)
     if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt
-  of mTypeDesc:
+  of mTypeDesc, mType:
     setMagicType(c.config, m, tyTypeDesc, 0)
     rawAddSon(m.typ, newTypeS(tyNone, c))
+  of mStatic:
+    setMagicType(m, tyStatic, 0)
+    rawAddSon(m.typ, newTypeS(tyNone, c))
   of mVoidType:
     setMagicType(c.config, m, tyVoid, 0)
   of mArray:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 9a3c75261..5a556732b 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1666,13 +1666,17 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
     let prev = PType(idTableGet(c.bindings, f))
     if prev == nil:
       if aOrig.kind == tyStatic:
-        result = typeRel(c, f.lastSon, a)
-        if result != isNone and f.n != nil:
-          if not exprStructuralEquivalent(f.n, aOrig.n):
-            result = isNone
+        if f.base.kind != tyNone:
+          result = typeRel(c, f.base, a)
+          if result != isNone and f.n != nil:
+            if not exprStructuralEquivalent(f.n, aOrig.n):
+              result = isNone
+        else:
+          result = isGeneric
         if result != isNone: put(c, f, aOrig)
       elif aOrig.n != nil and aOrig.n.typ != nil:
-        result = typeRel(c, f.lastSon, aOrig.n.typ)
+        result = if f.base.kind != tyNone: typeRel(c, f.lastSon, aOrig.n.typ)
+                 else: isGeneric
         if result != isNone:
           var boundType = newTypeWithSons(c.c, tyStatic, @[aOrig.n.typ])
           boundType.n = aOrig.n