A minimal patch enabling the new typedesc and static types syntax

This commit is contained in:
Zahary Karadjov 2018-04-20 11:44:13 +03:00
commit fb27357b62
10 changed files with 228 additions and 110 deletions

View file

@ -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,

View file

@ -44,6 +44,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimcomputedgoto")
defineSymbol("nimunion")
defineSymbol("nimnewshared")
defineSymbol("nimNewTypedesc")
defineSymbol("nimrequiresnimframe")
defineSymbol("nimparsebiggestfloatmagic")
defineSymbol("nimalias")

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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:

View file

@ -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