mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-05 11:24:08 +00:00
Merge branch 'zahary' into araq2
This commit is contained in:
@@ -452,10 +452,12 @@ type
|
||||
nfExprCall # this is an attempt to call a regular expression
|
||||
nfIsRef # this node is a 'ref' node; used for the VM
|
||||
nfPreventCg # this node should be ignored by the codegen
|
||||
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 30)
|
||||
tfVarargs, # procedure has C styled varargs
|
||||
# tyArray type represeting a varargs list
|
||||
tfNoSideEffect, # procedure type does not allow side effects
|
||||
tfFinal, # is the object final?
|
||||
tfInheritable, # is the object inheritable?
|
||||
@@ -1346,6 +1348,9 @@ proc initIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc newIdTable*: TIdTable =
|
||||
initIdTable(result)
|
||||
|
||||
proc resetIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
# clear and set to old initial size:
|
||||
|
||||
@@ -70,6 +70,8 @@ proc debug*(n: PNode) {.deprecated.}
|
||||
template mdbg*: bool {.dirty.} =
|
||||
when compiles(c.module):
|
||||
c.module.fileIdx == gProjectMainIdx
|
||||
elif compiles(c.c.module):
|
||||
c.c.module.fileIdx == gProjectMainIdx
|
||||
elif compiles(m.c.module):
|
||||
m.c.module.fileIdx == gProjectMainIdx
|
||||
elif compiles(cl.c.module):
|
||||
@@ -79,6 +81,8 @@ template mdbg*: bool {.dirty.} =
|
||||
p.lex.fileIdx == gProjectMainIdx
|
||||
else:
|
||||
p.module.module.fileIdx == gProjectMainIdx
|
||||
elif compiles(m.module.fileIdx):
|
||||
m.module.fileIdx == gProjectMainIdx
|
||||
elif compiles(L.fileIdx):
|
||||
L.fileIdx == gProjectMainIdx
|
||||
else:
|
||||
|
||||
@@ -267,7 +267,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
# little HACK to support the new 'var T' as return type:
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||
return
|
||||
let ty = skipTypes(dest.t, abstractRange)
|
||||
let ty = skipTypes(dest.t, abstractRange + tyUserTypeClasses)
|
||||
case ty.kind
|
||||
of tyRef:
|
||||
genRefAssign(p, dest, src, flags)
|
||||
@@ -756,7 +756,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||
genRecordFieldAux(p, e, d, a)
|
||||
var r = rdLoc(a)
|
||||
var f = e.sons[1].sym
|
||||
let ty = skipTypes(a.t, abstractInst)
|
||||
let ty = skipTypes(a.t, abstractInst + tyUserTypeClasses)
|
||||
if ty.kind == tyTuple:
|
||||
# we found a unique tuple type which lacks field information
|
||||
# so we use Field$i
|
||||
|
||||
@@ -164,7 +164,7 @@ proc mapType(typ: PType): TCTypeKind =
|
||||
of tySet: result = mapSetType(typ)
|
||||
of tyOpenArray, tyArray, tyVarargs: result = ctArray
|
||||
of tyObject, tyTuple: result = ctStruct
|
||||
of tyUserTypeClass, tyUserTypeClassInst:
|
||||
of tyUserTypeClasses:
|
||||
internalAssert typ.isResolvedUserTypeClass
|
||||
return mapType(typ.lastSon)
|
||||
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
|
||||
@@ -1094,7 +1094,7 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
|
||||
|
||||
proc genTypeInfo(m: BModule, t: PType): Rope =
|
||||
let origType = t
|
||||
var t = skipTypes(origType, irrelevantForBackend)
|
||||
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
|
||||
|
||||
let sig = hashType(origType)
|
||||
result = m.typeInfoMarker.getOrDefault(sig)
|
||||
@@ -1131,6 +1131,9 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
|
||||
of tyStatic:
|
||||
if t.n != nil: result = genTypeInfo(m, lastSon t)
|
||||
else: internalError("genTypeInfo(" & $t.kind & ')')
|
||||
of tyUserTypeClasses:
|
||||
internalAssert t.isResolvedUserTypeClass
|
||||
return genTypeInfo(m, t.lastSon)
|
||||
of tyProc:
|
||||
if t.callConv != ccClosure:
|
||||
genTypeInfoAuxBase(m, t, t, result, rope"0")
|
||||
|
||||
@@ -90,7 +90,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
|
||||
|
||||
result = newNodeI(nkArgList, n.info)
|
||||
for i in 1 .. givenRegularParams:
|
||||
result.addSon n.sons[i]
|
||||
result.addSon n[i]
|
||||
|
||||
# handle parameters with default values, which were
|
||||
# not supplied by the user
|
||||
|
||||
@@ -67,6 +67,8 @@ proc parseTry(p: var TParser; isExpr: bool): PNode
|
||||
proc parseCase(p: var TParser): PNode
|
||||
proc parseStmtPragma(p: var TParser): PNode
|
||||
proc parsePragma(p: var TParser): PNode
|
||||
proc postExprBlocks(p: var TParser, x: PNode): PNode
|
||||
proc parseExprStmt(p: var TParser): PNode
|
||||
# implementation
|
||||
|
||||
proc getTok(p: var TParser) =
|
||||
@@ -194,7 +196,6 @@ proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
|
||||
proc parseExpr(p: var TParser): PNode
|
||||
proc parseStmt(p: var TParser): PNode
|
||||
proc parseTypeDesc(p: var TParser): PNode
|
||||
proc parseDoBlocks(p: var TParser, call: PNode)
|
||||
proc parseParamList(p: var TParser, retColon = true): PNode
|
||||
|
||||
proc isSigilLike(tok: TToken): bool {.inline.} =
|
||||
@@ -365,7 +366,10 @@ proc colonOrEquals(p: var TParser, a: PNode): PNode =
|
||||
proc exprColonEqExpr(p: var TParser): PNode =
|
||||
#| exprColonEqExpr = expr (':'|'=' expr)?
|
||||
var a = parseExpr(p)
|
||||
result = colonOrEquals(p, a)
|
||||
if p.tok.tokType == tkDo:
|
||||
result = postExprBlocks(p, a)
|
||||
else:
|
||||
result = colonOrEquals(p, a)
|
||||
|
||||
proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
|
||||
#| exprList = expr ^+ comma
|
||||
@@ -520,7 +524,9 @@ proc parsePar(p: var TParser): PNode =
|
||||
result.add(parseStmtPragma(p))
|
||||
elif p.tok.tokType != tkParRi:
|
||||
var a = simpleExpr(p)
|
||||
if p.tok.tokType == tkEquals:
|
||||
if p.tok.tokType == tkDo:
|
||||
result = postExprBlocks(p, a)
|
||||
elif p.tok.tokType == tkEquals:
|
||||
# special case: allow assignments
|
||||
let asgn = newNodeP(nkAsgn, p)
|
||||
getTok(p)
|
||||
@@ -669,7 +675,6 @@ proc namedParams(p: var TParser, callee: PNode,
|
||||
# progress guaranteed
|
||||
exprColonEqExprListAux(p, endTok, result)
|
||||
|
||||
proc parseMacroColon(p: var TParser, x: PNode): PNode
|
||||
proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||
#| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
|
||||
#| | doBlocks
|
||||
@@ -696,14 +701,6 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||
result = namedParams(p, result, nkCall, tkParRi)
|
||||
if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
|
||||
result.kind = nkObjConstr
|
||||
elif p.tok.tokType == tkDo:
|
||||
parseDoBlocks(p, result)
|
||||
of tkDo:
|
||||
# progress guaranteed
|
||||
var a = result
|
||||
result = newNodeP(nkCall, p)
|
||||
addSon(result, a)
|
||||
parseDoBlocks(p, result)
|
||||
of tkDot:
|
||||
# progress guaranteed
|
||||
result = dotExpr(p, result)
|
||||
@@ -735,10 +732,7 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
|
||||
if p.tok.tokType != tkComma: break
|
||||
getTok(p)
|
||||
optInd(p, x)
|
||||
if p.tok.tokType == tkDo:
|
||||
parseDoBlocks(p, result)
|
||||
else:
|
||||
result = parseMacroColon(p, result)
|
||||
result = postExprBlocks(p, result)
|
||||
break
|
||||
else:
|
||||
break
|
||||
@@ -977,16 +971,9 @@ proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
|
||||
let params = parseParamList(p, retColon=false)
|
||||
let pragmas = optPragmas(p)
|
||||
colcom(p, result)
|
||||
result = newProcNode(nkDo, info, parseStmt(p),
|
||||
params = params,
|
||||
pragmas = pragmas)
|
||||
|
||||
proc parseDoBlocks(p: var TParser, call: PNode) =
|
||||
#| doBlocks = doBlock ^* IND{=}
|
||||
while sameOrNoInd(p) and p.tok.tokType == tkDo:
|
||||
let info = parLineInfo(p)
|
||||
getTok(p)
|
||||
addSon(call, parseDoBlock(p, info))
|
||||
result = parseStmt(p)
|
||||
if params.kind != nkEmpty:
|
||||
result = newProcNode(nkDo, info, result, params = params, pragmas = pragmas)
|
||||
|
||||
proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
|
||||
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
|
||||
@@ -1162,49 +1149,75 @@ proc makeCall(n: PNode): PNode =
|
||||
result = newNodeI(nkCall, n.info)
|
||||
result.add n
|
||||
|
||||
proc parseMacroColon(p: var TParser, x: PNode): PNode =
|
||||
#| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
|
||||
#| | IND{=} 'elif' expr ':' stmt
|
||||
#| | IND{=} 'except' exprList ':' stmt
|
||||
#| | IND{=} 'else' ':' stmt )*
|
||||
proc postExprBlocks(p: var TParser, x: PNode): PNode =
|
||||
#| postExprBlocks = ':' stmt? ( IND{=} doBlock
|
||||
#| | IND{=} 'of' exprList ':' stmt
|
||||
#| | IND{=} 'elif' expr ':' stmt
|
||||
#| | IND{=} 'except' exprList ':' stmt
|
||||
#| | IND{=} 'else' ':' stmt )*
|
||||
result = x
|
||||
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
||||
if p.tok.indent >= 0: return
|
||||
|
||||
var
|
||||
openingParams = emptyNode
|
||||
openingPragmas = emptyNode
|
||||
|
||||
if p.tok.tokType == tkDo:
|
||||
getTok(p)
|
||||
openingParams = parseParamList(p, retColon=false)
|
||||
openingPragmas = optPragmas(p)
|
||||
|
||||
if p.tok.tokType == tkColon:
|
||||
result = makeCall(result)
|
||||
getTok(p)
|
||||
skipComment(p, result)
|
||||
let stmtList = newNodeP(nkStmtList, p)
|
||||
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||
let body = parseStmt(p)
|
||||
stmtList.add body
|
||||
#addSon(result, makeStmtList(body))
|
||||
# progress guaranteed
|
||||
while sameInd(p):
|
||||
var b: PNode
|
||||
case p.tok.tokType
|
||||
of tkOf:
|
||||
b = newNodeP(nkOfBranch, p)
|
||||
exprList(p, tkColon, b)
|
||||
of tkElif:
|
||||
b = newNodeP(nkElifBranch, p)
|
||||
getTok(p)
|
||||
optInd(p, b)
|
||||
addSon(b, parseExpr(p))
|
||||
of tkExcept:
|
||||
b = newNodeP(nkExceptBranch, p)
|
||||
exprList(p, tkColon, b)
|
||||
of tkElse:
|
||||
b = newNodeP(nkElse, p)
|
||||
getTok(p)
|
||||
else: break
|
||||
eat(p, tkColon)
|
||||
addSon(b, parseStmt(p))
|
||||
addSon(stmtList, b)
|
||||
if b.kind == nkElse: break
|
||||
if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
|
||||
var stmtList = newNodeP(nkStmtList, p)
|
||||
stmtList.add parseStmt(p)
|
||||
# to keep backwards compatibility (see tests/vm/tstringnil)
|
||||
result.add stmtList[0]
|
||||
else:
|
||||
result.add stmtList
|
||||
if stmtList[0].kind == nkStmtList: stmtList = stmtList[0]
|
||||
|
||||
stmtList.flags.incl nfBlockArg
|
||||
if openingParams.kind != nkEmpty:
|
||||
result.add newProcNode(nkDo, stmtList.info, stmtList,
|
||||
params = openingParams, pragmas = openingPragmas)
|
||||
else:
|
||||
result.add stmtList
|
||||
|
||||
while sameInd(p):
|
||||
var nextBlock: PNode
|
||||
let nextToken = p.tok.tokType
|
||||
if nextToken == tkDo:
|
||||
let info = parLineInfo(p)
|
||||
getTok(p)
|
||||
nextBlock = parseDoBlock(p, info)
|
||||
else:
|
||||
case nextToken:
|
||||
of tkOf:
|
||||
nextBlock = newNodeP(nkOfBranch, p)
|
||||
exprList(p, tkColon, nextBlock)
|
||||
of tkElif:
|
||||
nextBlock = newNodeP(nkElifBranch, p)
|
||||
getTok(p)
|
||||
optInd(p, nextBlock)
|
||||
nextBlock.addSon parseExpr(p)
|
||||
of tkExcept:
|
||||
nextBlock = newNodeP(nkExceptBranch, p)
|
||||
exprList(p, tkColon, nextBlock)
|
||||
of tkElse:
|
||||
nextBlock = newNodeP(nkElse, p)
|
||||
getTok(p)
|
||||
else: break
|
||||
eat(p, tkColon)
|
||||
nextBlock.addSon parseStmt(p)
|
||||
|
||||
nextBlock.flags.incl nfBlockArg
|
||||
result.add nextBlock
|
||||
|
||||
if nextBlock.kind == nkElse: break
|
||||
else:
|
||||
if openingParams.kind != nkEmpty:
|
||||
parMessage(p, errTokenExpected, ":")
|
||||
|
||||
proc parseExprStmt(p: var TParser): PNode =
|
||||
#| exprStmt = simpleExpr
|
||||
@@ -1219,12 +1232,7 @@ proc parseExprStmt(p: var TParser): PNode =
|
||||
getTok(p)
|
||||
optInd(p, result)
|
||||
var b = parseExpr(p)
|
||||
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
||||
if b.kind != nkEmpty:
|
||||
let call = makeCall(b)
|
||||
call.add parseDoBlock(p, parLineInfo(p))
|
||||
parseDoBlocks(p, call)
|
||||
b = call
|
||||
b = postExprBlocks(p, b)
|
||||
addSon(result, a)
|
||||
addSon(result, b)
|
||||
else:
|
||||
@@ -1247,11 +1255,7 @@ proc parseExprStmt(p: var TParser): PNode =
|
||||
optInd(p, result)
|
||||
else:
|
||||
result = a
|
||||
if p.tok.tokType == tkDo and p.tok.indent < 0:
|
||||
result = makeCall(result)
|
||||
parseDoBlocks(p, result)
|
||||
return result
|
||||
result = parseMacroColon(p, result)
|
||||
result = postExprBlocks(p, result)
|
||||
|
||||
proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
|
||||
result = parseExpr(p)
|
||||
@@ -1341,7 +1345,9 @@ proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
|
||||
# NL terminates:
|
||||
addSon(result, ast.emptyNode)
|
||||
else:
|
||||
addSon(result, parseExpr(p))
|
||||
var e = parseExpr(p)
|
||||
e = postExprBlocks(p, e)
|
||||
addSon(result, e)
|
||||
|
||||
proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
|
||||
#| condStmt = expr colcom stmt COMMENT?
|
||||
@@ -1893,14 +1899,7 @@ proc parseVariable(p: var TParser): PNode =
|
||||
#| variable = (varTuple / identColonEquals) colonBody? indAndComment
|
||||
if p.tok.tokType == tkParLe: result = parseVarTuple(p)
|
||||
else: result = parseIdentColonEquals(p, {withPragma})
|
||||
if p.tok.tokType == tkColon and p.tok.indent < 0:
|
||||
let last = result.len-1
|
||||
let ex = result.sons[last]
|
||||
if ex.kind != nkEmpty:
|
||||
let call = makeCall(ex)
|
||||
call.add parseDoBlock(p, parLineInfo(p))
|
||||
parseDoBlocks(p, call)
|
||||
result.sons[last] = call
|
||||
result{-1} = postExprBlocks(p, result{-1})
|
||||
indAndComment(p, result)
|
||||
|
||||
proc parseBind(p: var TParser, k: TNodeKind): PNode =
|
||||
|
||||
@@ -351,8 +351,8 @@ when false:
|
||||
for i in 0 ..< n.safeLen:
|
||||
resetSemFlag(n[i])
|
||||
|
||||
proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
flags: TExprFlags): PNode =
|
||||
proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
s: PSym, flags: TExprFlags): PNode =
|
||||
## Semantically check the output of a macro.
|
||||
## This involves processes such as re-checking the macro output for type
|
||||
## coherence, making sure that variables declared with 'let' aren't
|
||||
@@ -363,8 +363,8 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
globalError(s.info, errTemplateInstantiationTooNested)
|
||||
c.friendModules.add(s.owner.getModule)
|
||||
|
||||
result = n
|
||||
excl(n.flags, nfSem)
|
||||
result = macroResult
|
||||
excl(result.flags, nfSem)
|
||||
#resetSemFlag n
|
||||
if s.typ.sons[0] == nil:
|
||||
result = semStmt(c, result)
|
||||
@@ -378,13 +378,26 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||
of tyStmt:
|
||||
result = semStmt(c, result)
|
||||
of tyTypeDesc:
|
||||
if n.kind == nkStmtList: result.kind = nkStmtListType
|
||||
if result.kind == nkStmtList: result.kind = nkStmtListType
|
||||
var typ = semTypeNode(c, result, nil)
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
#result = symNodeFromType(c, typ, n.info)
|
||||
else:
|
||||
var retType = s.typ.sons[0]
|
||||
if s.ast[genericParamsPos] != nil and retType.isMetaType:
|
||||
# The return type may depend on the Macro arguments
|
||||
# e.g. template foo(T: typedesc): seq[T]
|
||||
# We will instantiate the return type here, because
|
||||
# we now know the supplied arguments
|
||||
var paramTypes = newIdTable()
|
||||
for param, value in genericParamsInMacroCall(s, call):
|
||||
idTablePut(paramTypes, param.typ, value.typ)
|
||||
|
||||
retType = generateTypeInstance(c, paramTypes,
|
||||
macroResult.info, retType)
|
||||
|
||||
result = semExpr(c, result, flags)
|
||||
result = fitNode(c, s.typ.sons[0], result, result.info)
|
||||
result = fitNode(c, retType, result, result.info)
|
||||
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
|
||||
dec(evalTemplateCounter)
|
||||
discard c.friendModules.pop()
|
||||
@@ -409,7 +422,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
# c.evalContext = c.createEvalContext(emStatic)
|
||||
result = evalMacroCall(c.module, c.cache, n, nOrig, sym)
|
||||
if efNoSemCheck notin flags:
|
||||
result = semAfterMacroCall(c, result, sym, flags)
|
||||
result = semAfterMacroCall(c, n, result, sym, flags)
|
||||
result = wrapInComesFrom(nOrig.info, result)
|
||||
popInfoContext()
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||
styleCheckUse(n.info, s)
|
||||
pushInfoContext(n.info)
|
||||
result = evalTemplate(n, s, getCurrOwner(c), efFromHlo in flags)
|
||||
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
|
||||
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
|
||||
popInfoContext()
|
||||
|
||||
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||
@@ -47,10 +47,11 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
#raiseRecoverableError("")
|
||||
result = errorNode(c, n)
|
||||
if result.typ == nil or result.typ == enforceVoidContext:
|
||||
# we cannot check for 'void' in macros ...
|
||||
localError(n.info, errExprXHasNoType,
|
||||
renderTree(result, {renderNoComments}))
|
||||
result.typ = errorType(c)
|
||||
if n.kind != nkStmtList:
|
||||
# we cannot check for 'void' in macros ...
|
||||
localError(n.info, errExprXHasNoType,
|
||||
renderTree(result, {renderNoComments}))
|
||||
result.typ = errorType(c)
|
||||
else:
|
||||
if efNoProcvarCheck notin flags: semProcvarCheck(c, result)
|
||||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
@@ -1155,6 +1156,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
ty = n.sons[0].typ
|
||||
return nil
|
||||
ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef, tyAlias})
|
||||
if ty.kind in tyUserTypeClasses and ty.isResolvedUserTypeClass:
|
||||
ty = ty.lastSon
|
||||
while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
|
||||
var check: PNode = nil
|
||||
if ty.kind == tyObject:
|
||||
@@ -1713,7 +1716,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
# We transform the do block into a template with a param for
|
||||
# each interpolation. We'll pass this template to getAst.
|
||||
var
|
||||
doBlk = n{-1}
|
||||
quotedBlock = n{-1}
|
||||
op = if n.len == 3: expectString(c, n[1]) else: "``"
|
||||
quotes = newSeq[PNode](1)
|
||||
# the quotes will be added to a nkCall statement
|
||||
@@ -1721,20 +1724,23 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
ids = newSeq[PNode]()
|
||||
# this will store the generated param names
|
||||
|
||||
if doBlk.kind != nkDo:
|
||||
if quotedBlock.kind != nkStmtList:
|
||||
localError(n.info, errXExpected, "block")
|
||||
|
||||
processQuotations(doBlk.sons[bodyPos], op, quotes, ids)
|
||||
processQuotations(quotedBlock, op, quotes, ids)
|
||||
|
||||
var dummyTemplate = newProcNode(
|
||||
nkTemplateDef, quotedBlock.info, quotedBlock,
|
||||
name = newAnonSym(c, skTemplate, n.info).newSymNode)
|
||||
|
||||
doBlk.sons[namePos] = newAnonSym(c, skTemplate, n.info).newSymNode
|
||||
if ids.len > 0:
|
||||
doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
|
||||
doBlk[paramsPos].add getSysSym("typed").newSymNode # return type
|
||||
dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
|
||||
dummyTemplate[paramsPos].add getSysSym("typed").newSymNode # return type
|
||||
ids.add getSysSym("untyped").newSymNode # params type
|
||||
ids.add emptyNode # no default value
|
||||
doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids)
|
||||
dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids)
|
||||
|
||||
var tmpl = semTemplateDef(c, doBlk)
|
||||
var tmpl = semTemplateDef(c, dummyTemplate)
|
||||
quotes[0] = tmpl[namePos]
|
||||
result = newNode(nkCall, n.info, @[
|
||||
getMagicSym(mExpandToAst).newSymNode,
|
||||
@@ -2325,8 +2331,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkCurly: result = semSetConstr(c, n)
|
||||
of nkBracket: result = semArrayConstr(c, n, flags)
|
||||
of nkObjConstr: result = semObjConstr(c, n, flags)
|
||||
of nkLambda: result = semLambda(c, n, flags)
|
||||
of nkDo: result = semDo(c, n, flags)
|
||||
of nkLambdaKinds: result = semLambda(c, n, flags)
|
||||
of nkDerefExpr: result = semDeref(c, n)
|
||||
of nkAddr:
|
||||
result = n
|
||||
|
||||
@@ -121,12 +121,13 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
localError(n.info, errWrongNumberOfVariables)
|
||||
return result
|
||||
|
||||
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
|
||||
const skippedTypesForFields = abstractVar - {tyTypeDesc} + tyUserTypeClasses
|
||||
var tupleTypeA = skipTypes(call.sons[1].typ, skippedTypesForFields)
|
||||
if tupleTypeA.kind notin {tyTuple, tyObject}:
|
||||
localError(n.info, errGenerated, "no object or tuple type")
|
||||
return result
|
||||
for i in 1..call.len-1:
|
||||
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
|
||||
var tupleTypeB = skipTypes(call.sons[i].typ, skippedTypesForFields)
|
||||
if not sameType(tupleTypeA, tupleTypeB):
|
||||
typeMismatch(call.sons[i].info, tupleTypeA, tupleTypeB)
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ proc rawPushProcCon(c: PContext, owner: PSym) =
|
||||
c.p = x
|
||||
|
||||
proc rawHandleSelf(c: PContext; owner: PSym) =
|
||||
if c.selfName != nil and owner.kind in {skProc, skMethod, skConverter, skIterator, skMacro} and owner.typ != nil:
|
||||
const callableSymbols = {skProc, skMethod, skConverter, skIterator, skMacro}
|
||||
if c.selfName != nil and owner.kind in callableSymbols and owner.typ != nil:
|
||||
let params = owner.typ.n
|
||||
if params.len > 1:
|
||||
let arg = params[1].sym
|
||||
|
||||
@@ -851,9 +851,12 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||
# type aliases are hard:
|
||||
var t = semTypeNode(c, x, nil)
|
||||
assert t != nil
|
||||
if t.kind in {tyObject, tyEnum, tyDistinct}:
|
||||
assert s.typ != nil
|
||||
if s.typ.kind != tyAlias:
|
||||
if s.typ != nil and s.typ.kind != tyAlias:
|
||||
if t.kind in {tyProc, tyGenericInst} and not t.isMetaType:
|
||||
assignType(s.typ, t)
|
||||
s.typ.id = t.id
|
||||
elif t.kind in {tyObject, tyEnum, tyDistinct}:
|
||||
assert s.typ != nil
|
||||
assignType(s.typ, t)
|
||||
s.typ.id = t.id # same id
|
||||
checkConstructedType(s.info, s.typ)
|
||||
@@ -1063,13 +1066,6 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
popOwner(c)
|
||||
result.typ = s.typ
|
||||
|
||||
proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# 'do' without params produces a stmt:
|
||||
if n[genericParamsPos].kind == nkEmpty and n[paramsPos].kind == nkEmpty:
|
||||
result = semStmt(c, n[bodyPos])
|
||||
else:
|
||||
result = semLambda(c, n, flags)
|
||||
|
||||
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||
var n = n
|
||||
|
||||
@@ -1174,7 +1170,8 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
var objB = t.sons[2]
|
||||
while true:
|
||||
if objB.kind == tyGenericBody: objB = objB.lastSon
|
||||
elif objB.kind == tyGenericInvocation: objB = objB.sons[0]
|
||||
elif objB.kind in {tyGenericInvocation, tyGenericInst}:
|
||||
objB = objB.sons[0]
|
||||
else: break
|
||||
if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
|
||||
if obj.assignment.isNil:
|
||||
@@ -1655,7 +1652,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
else: discard
|
||||
|
||||
if result.len == 1 and
|
||||
c.inTypeClass == 0 and # concept bodies should be preserved as a stmt list
|
||||
# concept bodies should be preserved as a stmt list:
|
||||
c.inTypeClass == 0 and
|
||||
# also, don't make life complicated for macros.
|
||||
# they will always expect a proper stmtlist:
|
||||
nfBlockArg notin n.flags and
|
||||
result.sons[0].kind != nkDefer:
|
||||
result = result.sons[0]
|
||||
|
||||
|
||||
@@ -135,7 +135,9 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||
let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
|
||||
let n = if n[0].kind == nkBracket: n[0] else: n
|
||||
checkMinSonsLen(n, 1)
|
||||
var base = semTypeNode(c, n.lastSon, nil).skipTypes({tyTypeDesc})
|
||||
var t = semTypeNode(c, n.lastSon, nil)
|
||||
if t.kind == tyTypeDesc and tfUnresolved notin t.flags:
|
||||
t = t.base
|
||||
result = newOrPrevType(kind, prev, c)
|
||||
var isNilable = false
|
||||
# check every except the last is an object:
|
||||
@@ -149,7 +151,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||
tyError, tyObject}:
|
||||
message n[i].info, errGenerated, "region needs to be an object type"
|
||||
addSonSkipIntLit(result, region)
|
||||
addSonSkipIntLit(result, base)
|
||||
addSonSkipIntLit(result, t)
|
||||
#if not isNilable: result.flags.incl tfNotNil
|
||||
|
||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||
@@ -891,13 +893,20 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
let lifted = liftingWalk(paramType.sons[i])
|
||||
if lifted != nil: paramType.sons[i] = lifted
|
||||
|
||||
if paramType.base.lastSon.kind == tyUserTypeClass:
|
||||
let body = paramType.base
|
||||
if body.kind == tyForward:
|
||||
# this may happen for proc type appearing in a type section
|
||||
# before one of its param types
|
||||
return
|
||||
|
||||
if body.lastSon.kind == tyUserTypeClass:
|
||||
let expanded = instGenericContainer(c, info, paramType,
|
||||
allowMetaTypes = true)
|
||||
result = liftingWalk(expanded, true)
|
||||
|
||||
of tyUserTypeClasses, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), true))
|
||||
of tyUserTypeClasses, tyBuiltInTypeClass, tyCompositeTypeClass,
|
||||
tyAnd, tyOr, tyNot:
|
||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), false))
|
||||
|
||||
of tyGenericParam:
|
||||
markUsed(info, paramType.sym, c.graph.usageSym)
|
||||
@@ -1065,6 +1074,7 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
||||
|
||||
proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
|
||||
result = semTypeNode(c, n, nil)
|
||||
n.typ = makeTypeDesc(c, result)
|
||||
|
||||
proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
|
||||
var
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
# This module does the instantiation of generic types.
|
||||
|
||||
import ast, astalgo, msgs, types, magicsys, semdata, renderer
|
||||
import ast, astalgo, msgs, types, magicsys, semdata, renderer, options
|
||||
|
||||
const
|
||||
tfInstClearedFlags = {tfHasMeta}
|
||||
tfInstClearedFlags = {tfHasMeta, tfUnresolved}
|
||||
|
||||
proc checkPartialConstructedType(info: TLineInfo, t: PType) =
|
||||
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
|
||||
@@ -50,6 +50,9 @@ proc searchInstTypes*(key: PType): PType =
|
||||
# types such as Channel[empty]. Why?
|
||||
# See the notes for PActor in handleGenericInvocation
|
||||
return
|
||||
if not sameFlags(inst, key):
|
||||
continue
|
||||
|
||||
block matchType:
|
||||
for j in 1 .. high(key.sons):
|
||||
# XXX sameType is not really correct for nested generics?
|
||||
@@ -231,6 +234,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||
proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
|
||||
# XXX: relying on allowMetaTypes is a kludge
|
||||
result = copyType(t, t.owner, cl.allowMetaTypes)
|
||||
if cl.allowMetaTypes: return
|
||||
result.flags.incl tfFromGeneric
|
||||
if not (t.kind in tyMetaTypes or
|
||||
(t.kind == tyStatic and t.n == nil)):
|
||||
@@ -247,10 +251,11 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
result = PType(idTableGet(cl.localCache, t))
|
||||
else:
|
||||
result = searchInstTypes(t)
|
||||
|
||||
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
var x = t.sons[i]
|
||||
if x.kind == tyGenericParam:
|
||||
if x.kind in {tyGenericParam}:
|
||||
x = lookupTypeVar(cl, x)
|
||||
if x != nil:
|
||||
if header == t: header = instCopyType(cl, t)
|
||||
@@ -307,31 +312,32 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
rawAddSon(result, newbody)
|
||||
checkPartialConstructedType(cl.info, newbody)
|
||||
let dc = newbody.deepCopy
|
||||
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||
# 'deepCopy' needs to be instantiated for
|
||||
# generics *when the type is constructed*:
|
||||
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
|
||||
attachedDeepCopy, 1)
|
||||
if bodyIsNew and newbody.typeInst == nil:
|
||||
#doassert newbody.typeInst == nil
|
||||
newbody.typeInst = result
|
||||
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
|
||||
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
|
||||
# need to look into this issue later
|
||||
assert newbody.kind in {tyRef, tyPtr}
|
||||
assert newbody.lastSon.typeInst == nil
|
||||
newbody.lastSon.typeInst = result
|
||||
let asgn = newbody.assignment
|
||||
if asgn != nil and sfFromGeneric notin asgn.flags:
|
||||
# '=' needs to be instantiated for generics when the type is constructed:
|
||||
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
|
||||
attachedAsgn, 1)
|
||||
let methods = skipTypes(bbody, abstractPtrs).methods
|
||||
for col, meth in items(methods):
|
||||
# we instantiate the known methods belonging to that type, this causes
|
||||
# them to be registered and that's enough, so we 'discard' the result.
|
||||
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
|
||||
attachedAsgn, col)
|
||||
if cl.allowMetaTypes == false:
|
||||
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||
# 'deepCopy' needs to be instantiated for
|
||||
# generics *when the type is constructed*:
|
||||
newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
|
||||
attachedDeepCopy, 1)
|
||||
if bodyIsNew and newbody.typeInst == nil:
|
||||
#doassert newbody.typeInst == nil
|
||||
newbody.typeInst = result
|
||||
if tfRefsAnonObj in newbody.flags and newbody.kind != tyGenericInst:
|
||||
# can come here for tyGenericInst too, see tests/metatype/ttypeor.nim
|
||||
# need to look into this issue later
|
||||
assert newbody.kind in {tyRef, tyPtr}
|
||||
assert newbody.lastSon.typeInst == nil
|
||||
newbody.lastSon.typeInst = result
|
||||
let asgn = newbody.assignment
|
||||
if asgn != nil and sfFromGeneric notin asgn.flags:
|
||||
# '=' needs to be instantiated for generics when the type is constructed:
|
||||
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
|
||||
attachedAsgn, 1)
|
||||
let methods = skipTypes(bbody, abstractPtrs).methods
|
||||
for col, meth in items(methods):
|
||||
# we instantiate the known methods belonging to that type, this causes
|
||||
# them to be registered and that's enough, so we 'discard' the result.
|
||||
discard cl.c.instTypeBoundOp(cl.c, meth, result, cl.info,
|
||||
attachedAsgn, col)
|
||||
|
||||
proc eraseVoidParams*(t: PType) =
|
||||
# transform '(): void' into '()' because old parts of the compiler really
|
||||
@@ -526,6 +532,14 @@ proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||
result = replaceTypeVarsT(cl, t)
|
||||
popInfoContext()
|
||||
|
||||
proc prepareMetatypeForSigmatch*(p: PContext, pt: TIdTable, info: TLineInfo,
|
||||
t: PType): PType =
|
||||
var cl = initTypeVars(p, pt, info, nil)
|
||||
cl.allowMetaTypes = true
|
||||
pushInfoContext(info)
|
||||
result = replaceTypeVarsT(cl, t)
|
||||
popInfoContext()
|
||||
|
||||
template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
|
||||
t: PType): untyped =
|
||||
generateTypeInstance(p, pt, arg.info, t)
|
||||
|
||||
@@ -154,7 +154,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
else:
|
||||
c.hashSym(t.sym)
|
||||
return
|
||||
of tyAlias, tyGenericInst:
|
||||
of tyAlias, tyGenericInst, tyUserTypeClasses:
|
||||
c.hashType t.lastSon, flags
|
||||
return
|
||||
else:
|
||||
@@ -201,16 +201,6 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
of tyRef, tyPtr, tyGenericBody, tyVar:
|
||||
c.hashType t.lastSon, flags
|
||||
if tfVarIsPtr in t.flags: c &= ".varisptr"
|
||||
of tyUserTypeClass:
|
||||
if t.sym != nil and t.sym.owner != nil:
|
||||
c &= t.sym.owner.name.s
|
||||
else:
|
||||
c &= "unknown typeclass"
|
||||
of tyUserTypeClassInst:
|
||||
let body = t.sons[0]
|
||||
c.hashSym body.sym
|
||||
for i in countup(1, sonsLen(t) - 2):
|
||||
c.hashType t.sons[i], flags
|
||||
of tyFromExpr, tyFieldAccessor:
|
||||
c.hashTree(t.n)
|
||||
of tyTuple:
|
||||
|
||||
@@ -26,7 +26,7 @@ type
|
||||
sym*: PSym
|
||||
unmatchedVarParam*: int
|
||||
diagnostics*: seq[string]
|
||||
|
||||
|
||||
CandidateErrors* = seq[CandidateError]
|
||||
|
||||
TCandidate* = object
|
||||
@@ -68,7 +68,7 @@ type
|
||||
# future.
|
||||
mutabilityProblem*: uint8 # tyVar mismatch
|
||||
inheritancePenalty: int # to prefer closest father object type
|
||||
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
isNone, isConvertible,
|
||||
isIntConv,
|
||||
@@ -177,6 +177,13 @@ proc sumGeneric(t: PType): int =
|
||||
tyOpenArray, tyVarargs, tySet, tyRange, tySequence, tyGenericBody:
|
||||
t = t.lastSon
|
||||
inc result
|
||||
of tyOr:
|
||||
var maxBranch = 0
|
||||
for branch in t.sons:
|
||||
let branchSum = branch.sumGeneric
|
||||
if branchSum > maxBranch: maxBranch = branchSum
|
||||
inc result, maxBranch + 1
|
||||
break
|
||||
of tyVar:
|
||||
t = t.sons[0]
|
||||
inc result
|
||||
@@ -185,8 +192,8 @@ proc sumGeneric(t: PType): int =
|
||||
t = t.lastSon
|
||||
if t.kind == tyEmpty: break
|
||||
inc result
|
||||
of tyGenericInvocation, tyTuple, tyProc:
|
||||
result += ord(t.kind == tyGenericInvocation)
|
||||
of tyGenericInvocation, tyTuple, tyProc, tyAnd:
|
||||
result += ord(t.kind in {tyGenericInvocation, tyAnd})
|
||||
for i in 0 .. <t.len:
|
||||
if t.sons[i] != nil:
|
||||
result += t.sons[i].sumGeneric
|
||||
@@ -228,6 +235,15 @@ proc complexDisambiguation(a, b: PType): int =
|
||||
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
|
||||
result = x - y
|
||||
|
||||
proc writeMatches*(c: TCandidate) =
|
||||
echo "Candidate '", c.calleeSym.name.s, "' at ", c.calleeSym.info
|
||||
echo " exact matches: ", c.exactMatches
|
||||
echo " generic matches: ", c.genericMatches
|
||||
echo " subtype matches: ", c.subtypeMatches
|
||||
echo " intconv matches: ", c.intConvMatches
|
||||
echo " conv matches: ", c.convMatches
|
||||
echo " inheritance: ", c.inheritancePenalty
|
||||
|
||||
proc cmpCandidates*(a, b: TCandidate): int =
|
||||
result = a.exactMatches - b.exactMatches
|
||||
if result != 0: return
|
||||
@@ -248,14 +264,6 @@ proc cmpCandidates*(a, b: TCandidate): int =
|
||||
if result != 0: return
|
||||
result = a.calleeScope - b.calleeScope
|
||||
|
||||
proc writeMatches*(c: TCandidate) =
|
||||
writeLine(stdout, "exact matches: " & $c.exactMatches)
|
||||
writeLine(stdout, "generic matches: " & $c.genericMatches)
|
||||
writeLine(stdout, "subtype matches: " & $c.subtypeMatches)
|
||||
writeLine(stdout, "intconv matches: " & $c.intConvMatches)
|
||||
writeLine(stdout, "conv matches: " & $c.convMatches)
|
||||
writeLine(stdout, "inheritance: " & $c.inheritancePenalty)
|
||||
|
||||
proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
|
||||
if arg.kind in nkSymChoices:
|
||||
result = typeToString(arg[0].typ, prefer)
|
||||
@@ -639,7 +647,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
makeTypeDesc(c, typ)
|
||||
|
||||
typeParams.safeAdd((param, typ))
|
||||
|
||||
|
||||
addDecl(c, param)
|
||||
|
||||
for param in typeClass.n[0]:
|
||||
@@ -676,7 +684,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
flags: TExprFlags = {}
|
||||
collectDiagnostics = m.diagnostics != nil or
|
||||
sfExplain in typeClass.sym.flags
|
||||
|
||||
|
||||
if collectDiagnostics:
|
||||
oldWriteHook = writelnHook
|
||||
# XXX: we can't write to m.diagnostics directly, because
|
||||
@@ -688,13 +696,13 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
let msg = s.replace("Error:", errorPrefix)
|
||||
if oldWriteHook != nil: oldWriteHook msg
|
||||
diagnostics.add msg
|
||||
|
||||
|
||||
var checkedBody = c.semTryExpr(c, body.copyTree, flags)
|
||||
|
||||
if collectDiagnostics:
|
||||
writelnHook = oldWriteHook
|
||||
for msg in diagnostics: m.diagnostics.safeAdd msg
|
||||
|
||||
|
||||
if checkedBody == nil: return nil
|
||||
|
||||
# The inferrable type params have been identified during the semTryExpr above.
|
||||
@@ -739,14 +747,14 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
|
||||
allowMetaTypes = allowUnresolved)
|
||||
result = c.c.semExpr(c.c, instantiated)
|
||||
|
||||
proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
|
||||
proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
|
||||
# This is a simple integer arithimetic equation solver,
|
||||
# capable of deriving the value of a static parameter in
|
||||
# expressions such as (N + 5) / 2 = rhs
|
||||
#
|
||||
# Preconditions:
|
||||
#
|
||||
# * The input of this proc must be semantized
|
||||
# * The input of this proc must be semantized
|
||||
# - all templates should be expanded
|
||||
# - aby constant folding possible should already be performed
|
||||
#
|
||||
@@ -754,64 +762,69 @@ proc inferStaticParam*(lhs: PNode, rhs: BiggestInt): PType =
|
||||
#
|
||||
# Result:
|
||||
#
|
||||
# The proc will return the inferred static type with the `n` field
|
||||
# populated with the inferred value.
|
||||
#
|
||||
# `nil` will be returned if the inference was not possible
|
||||
# The proc will return true if the static types was successfully
|
||||
# inferred. The result will be bound to the original static type
|
||||
# in the TCandidate.
|
||||
#
|
||||
if lhs.kind in nkCallKinds and lhs[0].kind == nkSym:
|
||||
case lhs[0].sym.magic
|
||||
of mUnaryLt:
|
||||
return inferStaticParam(lhs[1], rhs + 1)
|
||||
return inferStaticParam(c, lhs[1], rhs + 1)
|
||||
|
||||
of mAddI, mAddU, mInc, mSucc:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[2], rhs - lhs[1].intVal)
|
||||
return inferStaticParam(c, lhs[2], rhs - lhs[1].intVal)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs - lhs[2].intVal)
|
||||
|
||||
return inferStaticParam(c, lhs[1], rhs - lhs[2].intVal)
|
||||
|
||||
of mDec, mSubI, mSubU, mPred:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[2], lhs[1].intVal - rhs)
|
||||
return inferStaticParam(c, lhs[2], lhs[1].intVal - rhs)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs + lhs[2].intVal)
|
||||
|
||||
return inferStaticParam(c, lhs[1], rhs + lhs[2].intVal)
|
||||
|
||||
of mMulI, mMulU:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
if rhs mod lhs[1].intVal == 0:
|
||||
return inferStaticParam(lhs[2], rhs div lhs[1].intVal)
|
||||
return inferStaticParam(c, lhs[2], rhs div lhs[1].intVal)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
if rhs mod lhs[2].intVal == 0:
|
||||
return inferStaticParam(lhs[1], rhs div lhs[2].intVal)
|
||||
|
||||
return inferStaticParam(c, lhs[1], rhs div lhs[2].intVal)
|
||||
|
||||
of mDivI, mDivU:
|
||||
if lhs[1].kind == nkIntLit:
|
||||
if lhs[1].intVal mod rhs == 0:
|
||||
return inferStaticParam(lhs[2], lhs[1].intVal div rhs)
|
||||
return inferStaticParam(c, lhs[2], lhs[1].intVal div rhs)
|
||||
elif lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], lhs[2].intVal * rhs)
|
||||
|
||||
return inferStaticParam(c, lhs[1], lhs[2].intVal * rhs)
|
||||
|
||||
of mShlI:
|
||||
if lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs shr lhs[2].intVal)
|
||||
|
||||
return inferStaticParam(c, lhs[1], rhs shr lhs[2].intVal)
|
||||
|
||||
of mShrI:
|
||||
if lhs[2].kind == nkIntLit:
|
||||
return inferStaticParam(lhs[1], rhs shl lhs[2].intVal)
|
||||
|
||||
return inferStaticParam(c, lhs[1], rhs shl lhs[2].intVal)
|
||||
|
||||
of mUnaryMinusI:
|
||||
return inferStaticParam(lhs[1], -rhs)
|
||||
|
||||
return inferStaticParam(c, lhs[1], -rhs)
|
||||
|
||||
of mUnaryPlusI, mToInt, mToBiggestInt:
|
||||
return inferStaticParam(lhs[1], rhs)
|
||||
|
||||
return inferStaticParam(c, lhs[1], rhs)
|
||||
|
||||
else: discard
|
||||
|
||||
|
||||
elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil:
|
||||
lhs.typ.n = newIntNode(nkIntLit, rhs)
|
||||
return lhs.typ
|
||||
|
||||
return nil
|
||||
var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ.sons)
|
||||
inferred.n = newIntNode(nkIntLit, rhs)
|
||||
put(c, lhs.typ, inferred)
|
||||
if c.c.inTypeClass > 0:
|
||||
# inside concepts, binding is currently done with
|
||||
# direct mutation of the involved types:
|
||||
lhs.typ.n = inferred.n
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
proc failureToInferStaticParam(n: PNode) =
|
||||
let staticParam = n.findUnresolvedStatic
|
||||
@@ -825,13 +838,10 @@ proc inferStaticsInRange(c: var TCandidate,
|
||||
allowUnresolved = true)
|
||||
let upperBound = tryResolvingStaticExpr(c, inferred.n[1],
|
||||
allowUnresolved = true)
|
||||
|
||||
template doInferStatic(c: var TCandidate, e: PNode, r: BiggestInt) =
|
||||
template doInferStatic(e: PNode, r: BiggestInt) =
|
||||
var exp = e
|
||||
var rhs = r
|
||||
var inferred = inferStaticParam(exp, rhs)
|
||||
if inferred != nil:
|
||||
put(c, inferred, inferred)
|
||||
if inferStaticParam(c, exp, rhs):
|
||||
return isGeneric
|
||||
else:
|
||||
failureToInferStaticParam exp
|
||||
@@ -842,9 +852,9 @@ proc inferStaticsInRange(c: var TCandidate,
|
||||
return isGeneric
|
||||
else:
|
||||
return isNone
|
||||
doInferStatic(c, upperBound, lengthOrd(concrete) + lowerBound.intVal - 1)
|
||||
doInferStatic(upperBound, lengthOrd(concrete) + lowerBound.intVal - 1)
|
||||
elif upperBound.kind == nkIntLit:
|
||||
doInferStatic(c, lowerBound, upperBound.intVal + 1 - lengthOrd(concrete))
|
||||
doInferStatic(lowerBound, upperBound.intVal + 1 - lengthOrd(concrete))
|
||||
|
||||
template subtypeCheck() =
|
||||
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
||||
@@ -1049,18 +1059,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
result = typeRel(c, f.sons[1].skipTypes({tyTypeDesc}),
|
||||
a.sons[1].skipTypes({tyTypeDesc}))
|
||||
if result < isGeneric: return isNone
|
||||
|
||||
|
||||
if fRange.rangeHasUnresolvedStatic:
|
||||
return inferStaticsInRange(c, fRange, a)
|
||||
elif c.c.inTypeClass > 0 and aRange.rangeHasUnresolvedStatic:
|
||||
return inferStaticsInRange(c, aRange, f)
|
||||
elif lengthOrd(fRange) != lengthOrd(a):
|
||||
result = isNone
|
||||
else:
|
||||
if lengthOrd(fRange) != lengthOrd(aRange):
|
||||
result = isNone
|
||||
else: discard
|
||||
of tyOpenArray, tyVarargs:
|
||||
# varargs[expr] is special too but handled earlier. So we only need to
|
||||
# handle varargs[stmt] which is the same as varargs[typed]:
|
||||
if f.kind == tyVarargs:
|
||||
if tfVarargs in a.flags:
|
||||
return typeRel(c, f.base, a.lastSon)
|
||||
if tfOldSchoolExprStmt in f.sons[0].flags:
|
||||
if f.sons[0].kind == tyExpr: return
|
||||
elif f.sons[0].kind == tyStmt: return
|
||||
@@ -1204,9 +1217,51 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
of tyEmpty, tyVoid:
|
||||
if a.kind == f.kind: result = isEqual
|
||||
|
||||
of tyGenericInst, tyAlias:
|
||||
of tyAlias:
|
||||
result = typeRel(c, lastSon(f), a)
|
||||
|
||||
of tyGenericInst:
|
||||
var prev = PType(idTableGet(c.bindings, f))
|
||||
var f = if prev == nil: f else: prev
|
||||
|
||||
let roota = a.skipGenericAlias
|
||||
let rootf = f.skipGenericAlias
|
||||
|
||||
var m = c
|
||||
if a.kind == tyGenericInst:
|
||||
if roota.base == rootf.base:
|
||||
for i in 1 .. rootf.sonsLen-2:
|
||||
let ff = rootf.sons[i]
|
||||
let aa = roota.sons[i]
|
||||
result = typeRel(c, ff, aa)
|
||||
if result notin {isEqual, isGeneric}: return isNone
|
||||
# if ff.kind == tyRange and result != isEqual: return isNone
|
||||
|
||||
if prev == nil: put(c, f, a)
|
||||
result = isGeneric
|
||||
else:
|
||||
let fKind = rootf.lastSon.kind
|
||||
if fKind in {tyAnd, tyOr}:
|
||||
result = typeRel(c, lastSon(f), a)
|
||||
if result != isNone: put(c, f, a)
|
||||
return
|
||||
|
||||
var aAsObject = roota.lastSon
|
||||
|
||||
if fKind in {tyRef, tyPtr} and aAsObject.kind == fKind:
|
||||
aAsObject = aAsObject.base
|
||||
|
||||
if aAsObject.kind == tyObject:
|
||||
let baseType = aAsObject.base
|
||||
if baseType != nil:
|
||||
c.inheritancePenalty += 1
|
||||
return typeRel(c, f, baseType)
|
||||
|
||||
result = isNone
|
||||
else:
|
||||
result = typeRel(c, lastSon(f), a)
|
||||
if result != isNone: put(c, f, a)
|
||||
|
||||
of tyGenericBody:
|
||||
considerPreviousT:
|
||||
if a.kind == tyGenericInst and a.sons[0] == f:
|
||||
@@ -1217,6 +1272,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
|
||||
of tyGenericInvocation:
|
||||
var x = a.skipGenericAlias
|
||||
# XXX: This is very hacky. It should be moved back into liftTypeParam
|
||||
if x.kind in {tyGenericInst, tyArray} and
|
||||
c.calleeSym != nil and
|
||||
c.calleeSym.kind == skProc:
|
||||
let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
|
||||
return typeRel(c, inst, a)
|
||||
|
||||
var depth = 0
|
||||
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
|
||||
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
||||
@@ -1333,13 +1395,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if f.isResolvedUserTypeClass:
|
||||
result = typeRel(c, f.lastSon, a)
|
||||
else:
|
||||
var matched = matchUserTypeClass(c.c, c, f, aOrig)
|
||||
if matched != nil:
|
||||
bindConcreteTypeToUserTypeClass(matched, a)
|
||||
put(c, f, matched)
|
||||
result = isGeneric
|
||||
else:
|
||||
result = isNone
|
||||
considerPreviousT:
|
||||
var matched = matchUserTypeClass(c.c, c, f, aOrig)
|
||||
if matched != nil:
|
||||
bindConcreteTypeToUserTypeClass(matched, a)
|
||||
if doBind: put(c, f, matched)
|
||||
result = isGeneric
|
||||
else:
|
||||
result = isNone
|
||||
|
||||
of tyCompositeTypeClass:
|
||||
considerPreviousT:
|
||||
@@ -1357,6 +1420,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if result != isNone:
|
||||
put(c, f, a)
|
||||
result = isGeneric
|
||||
|
||||
of tyGenericParam:
|
||||
var x = PType(idTableGet(c.bindings, f))
|
||||
if x == nil:
|
||||
@@ -1376,16 +1440,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
internalAssert a.sons != nil and a.sons.len > 0
|
||||
c.typedescMatched = true
|
||||
var aa = a
|
||||
while aa.kind in {tyTypeDesc, tyGenericParam} and
|
||||
aa.len > 0:
|
||||
while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
|
||||
aa = lastSon(aa)
|
||||
if aa.kind == tyGenericParam:
|
||||
return isGeneric
|
||||
result = typeRel(c, f.base, aa)
|
||||
if result > isGeneric: result = isGeneric
|
||||
else:
|
||||
result = isNone
|
||||
else:
|
||||
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
|
||||
result = typeRel(c, f.lastSon, a)
|
||||
result = typeRel(c, f.lastSon, a, false)
|
||||
if doBind and result notin {isNone, isGeneric}:
|
||||
let concrete = concreteType(c, a)
|
||||
if concrete == nil: return isNone
|
||||
@@ -1590,6 +1655,10 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
|
||||
of isEqual: inc(m.exactMatches)
|
||||
of isNone: discard
|
||||
|
||||
template matchesVoidProc(t: PType): bool =
|
||||
(t.kind == tyProc and t.len == 1 and t.sons[0] == nil) or
|
||||
(t.kind == tyBuiltInTypeClass and t.sons[0].kind == tyProc)
|
||||
|
||||
proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||
argSemantized, argOrig: PNode): PNode =
|
||||
var
|
||||
@@ -1726,6 +1795,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||
inc(m.genericMatches)
|
||||
m.fauxMatch = a.kind
|
||||
return arg
|
||||
elif a.kind == tyVoid and f.matchesVoidProc and argOrig.kind == nkStmtList:
|
||||
# lift do blocks without params to lambdas
|
||||
let lifted = c.semExpr(c, newProcNode(nkDo, argOrig.info, argOrig), {})
|
||||
if f.kind == tyBuiltInTypeClass:
|
||||
inc m.genericMatches
|
||||
put(m, f, lifted.typ)
|
||||
inc m.convMatches
|
||||
return implicitConv(nkHiddenStdConv, f, lifted, m, c)
|
||||
result = userConvMatch(c, m, f, a, arg)
|
||||
# check for a base type match, which supports varargs[T] without []
|
||||
# constructor in a call:
|
||||
@@ -2008,6 +2085,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
#assert(container == nil)
|
||||
if container.isNil:
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||
container.typ.flags.incl tfVarargs
|
||||
else:
|
||||
incrIndexType(container.typ)
|
||||
addSon(container, arg)
|
||||
@@ -2086,6 +2164,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
|
||||
return nil
|
||||
var f = dc.typ.sons[col]
|
||||
|
||||
if op == attachedDeepCopy:
|
||||
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||
else:
|
||||
|
||||
@@ -886,6 +886,9 @@ proc isGenericAlias*(t: PType): bool =
|
||||
proc skipGenericAlias*(t: PType): PType =
|
||||
return if t.isGenericAlias: t.lastSon else: t
|
||||
|
||||
proc sameFlags*(a, b: PType): bool {.inline.} =
|
||||
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
|
||||
|
||||
proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
template cycleCheck() =
|
||||
# believe it or not, the direct check for ``containsOrIncl(c, a, b)``
|
||||
@@ -898,9 +901,6 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
else:
|
||||
if containsOrIncl(c, a, b): return true
|
||||
|
||||
proc sameFlags(a, b: PType): bool {.inline.} =
|
||||
result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
|
||||
|
||||
if x == y: return true
|
||||
var a = skipTypes(x, {tyGenericInst, tyAlias})
|
||||
var b = skipTypes(y, {tyGenericInst, tyAlias})
|
||||
|
||||
@@ -1606,6 +1606,12 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
||||
n.typ = x.typ
|
||||
result.node = n
|
||||
|
||||
iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
|
||||
let gp = macroSym.ast[genericParamsPos]
|
||||
for i in 0 .. <gp.len:
|
||||
let idx = macroSym.typ.len + i
|
||||
yield (gp[i].sym, call.sons[idx])
|
||||
|
||||
var evalMacroCounter: int
|
||||
|
||||
proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
|
||||
|
||||
@@ -78,6 +78,10 @@ type
|
||||
## Statically typed wrapper around a JavaScript object.
|
||||
NotString = concept c
|
||||
c isnot string
|
||||
js* = JsObject
|
||||
|
||||
var jsarguments* {.importc: "arguments", nodecl}: JsObject
|
||||
## JavaScript's arguments pseudo-variable
|
||||
|
||||
# New
|
||||
proc newJsObject*: JsObject {. importcpp: "{@}" .}
|
||||
@@ -93,18 +97,64 @@ proc hasOwnProperty*(x: JsObject, prop: cstring): bool
|
||||
proc jsTypeOf*(x: JsObject): cstring {. importcpp: "typeof(#)" .}
|
||||
## Returns the name of the JsObject's JavaScript type as a cstring.
|
||||
|
||||
proc jsnew*(x: auto): JsObject {.importcpp: "(new #)".}
|
||||
## Turns a regular function call into an invocation of the
|
||||
## JavaScript's `new` operator
|
||||
|
||||
proc jsdelete*(x: auto): JsObject {.importcpp: "(delete #)".}
|
||||
## JavaScript's `delete` operator
|
||||
|
||||
# Conversion to and from JsObject
|
||||
proc to*(x: JsObject, T: typedesc): T {. importcpp: "(#)" .}
|
||||
## Converts a JsObject `x` to type `T`.
|
||||
|
||||
proc toJs*[T](val: T): JsObject {. importcpp: "(#)" .}
|
||||
## Converts a value of any type to type JsObject
|
||||
|
||||
template toJs*(s: string): JsObject = cstring(s).toJs
|
||||
|
||||
macro jsFromAst*(n: untyped): untyped =
|
||||
result = n
|
||||
if n.kind == nnkStmtList:
|
||||
result = newProc(procType = nnkDo, body = result)
|
||||
return quote: toJs(`result`)
|
||||
|
||||
proc `&`*(a, b: cstring): cstring {.importcpp: "(# + #)".}
|
||||
## Concatenation operator for JavaScript strings
|
||||
|
||||
proc `+` *(x, y: JsObject): JsObject {. importcpp: "(# + #)" .}
|
||||
proc `-` *(x, y: JsObject): JsObject {. importcpp: "(# - #)" .}
|
||||
proc `*` *(x, y: JsObject): JsObject {. importcpp: "(# * #)" .}
|
||||
proc `/` *(x, y: JsObject): JsObject {. importcpp: "(# / #)" .}
|
||||
proc `%` *(x, y: JsObject): JsObject {. importcpp: "(# % #)" .}
|
||||
proc `+=` *(x, y: JsObject): JsObject {. importcpp: "(# += #)", discardable .}
|
||||
proc `-=` *(x, y: JsObject): JsObject {. importcpp: "(# -= #)", discardable .}
|
||||
proc `*=` *(x, y: JsObject): JsObject {. importcpp: "(# *= #)", discardable .}
|
||||
proc `/=` *(x, y: JsObject): JsObject {. importcpp: "(# /= #)", discardable .}
|
||||
proc `%=` *(x, y: JsObject): JsObject {. importcpp: "(# %= #)", discardable .}
|
||||
proc `++` *(x: JsObject): JsObject {. importcpp: "(++#)" .}
|
||||
proc `--` *(x: JsObject): JsObject {. importcpp: "(--#)" .}
|
||||
proc `>` *(x, y: JsObject): JsObject {. importcpp: "(# > #)" .}
|
||||
proc `<` *(x, y: JsObject): JsObject {. importcpp: "(# < #)" .}
|
||||
proc `>=` *(x, y: JsObject): JsObject {. importcpp: "(# >= #)" .}
|
||||
proc `<=` *(x, y: JsObject): JsObject {. importcpp: "(# <= #)" .}
|
||||
proc `and`*(x, y: JsObject): JsObject {. importcpp: "(# && #)" .}
|
||||
proc `or` *(x, y: JsObject): JsObject {. importcpp: "(# || #)" .}
|
||||
proc `not`*(x: JsObject): JsObject {. importcpp: "(!#)" .}
|
||||
proc `in` *(x, y: JsObject): JsObject {. importcpp: "(# in #)" .}
|
||||
|
||||
proc `[]`*(obj: JsObject, field: cstring): JsObject {. importcpp: getImpl .}
|
||||
## Return the value of a property of name `field` from a JsObject `obj`.
|
||||
|
||||
proc `[]`*(obj: JsObject, field: int): JsObject {. importcpp: getImpl .}
|
||||
## Return the value of a property of name `field` from a JsObject `obj`.
|
||||
|
||||
proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {. importcpp: setImpl .}
|
||||
## Set the value of a property of name `field` in a JsObject `obj` to `v`.
|
||||
|
||||
proc `[]=`*[T](obj: JsObject, field: int, val: T) {. importcpp: setImpl .}
|
||||
## Set the value of a property of name `field` in a JsObject `obj` to `v`.
|
||||
|
||||
proc `[]`*[K: NotString, V](obj: JsAssoc[K, V], field: K): V
|
||||
{. importcpp: getImpl .}
|
||||
## Return the value of a property of name `field` from a JsAssoc `obj`.
|
||||
@@ -171,8 +221,9 @@ macro `.=`*(obj: JsObject, field: static[cstring], value: untyped): untyped =
|
||||
{. importcpp: `importString`, gensym .}
|
||||
helper(`obj`, `value`)
|
||||
|
||||
macro `.()`*(obj: JsObject, field: static[cstring],
|
||||
args: varargs[JsObject, toJs]): JsObject =
|
||||
macro `.()`*(obj: JsObject,
|
||||
field: static[cstring],
|
||||
args: varargs[JsObject, jsFromAst]): JsObject =
|
||||
## Experimental "method call" operator for type JsObject.
|
||||
## Takes the name of a method of the JavaScript object (`field`) and calls
|
||||
## it with `args` as arguments, returning a JsObject (which may be discarded,
|
||||
@@ -196,9 +247,9 @@ macro `.()`*(obj: JsObject, field: static[cstring],
|
||||
if not mangledNames.hasKey($field):
|
||||
mangledNames[$field] = $mangleJsName(field)
|
||||
importString = "#." & mangledNames[$field] & "(@)"
|
||||
result = quote do:
|
||||
result = quote:
|
||||
proc helper(o: JsObject): JsObject
|
||||
{. importcpp: `importString`, gensym .}
|
||||
{. importcpp: `importString`, gensym, discardable .}
|
||||
helper(`obj`)
|
||||
for idx in 0 ..< args.len:
|
||||
let paramName = newIdentNode(!("param" & $idx))
|
||||
@@ -206,7 +257,7 @@ macro `.()`*(obj: JsObject, field: static[cstring],
|
||||
result[1].add args[idx].copyNimTree
|
||||
|
||||
macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||
field: static[cstring]): V =
|
||||
field: static[cstring]): V =
|
||||
## Experimental dot accessor (get) for type JsAssoc.
|
||||
## Returns the value of a property of name `field` from a JsObject `x`.
|
||||
var importString: string
|
||||
@@ -222,7 +273,8 @@ macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||
helper(`obj`)
|
||||
|
||||
macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||
field: static[cstring], value: V): untyped =
|
||||
field: static[cstring],
|
||||
value: V): untyped =
|
||||
## Experimental dot accessor (set) for type JsAssoc.
|
||||
## Sets the value of a property of name `field` in a JsObject `x` to `value`.
|
||||
var importString: string
|
||||
@@ -238,7 +290,8 @@ macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||
helper(`obj`, `value`)
|
||||
|
||||
macro `.()`*[K: string | cstring, V: proc](obj: JsAssoc[K, V],
|
||||
field: static[cstring], args: varargs[untyped]): auto =
|
||||
field: static[cstring],
|
||||
args: varargs[untyped]): auto =
|
||||
## Experimental "method call" operator for type JsAssoc.
|
||||
## Takes the name of a method of the JavaScript object (`field`) and calls
|
||||
## it with `args` as arguments. Here, everything is typechecked, so you do not
|
||||
|
||||
@@ -7,7 +7,7 @@ discard """
|
||||
import macros
|
||||
|
||||
macro mixer(n: typed): untyped =
|
||||
expectKind(n, nnkCharLit)
|
||||
|
||||
expectKind(n[0], nnkCharLit)
|
||||
|
||||
mixer:
|
||||
echo "owh"
|
||||
echo "owh"
|
||||
|
||||
45
tests/closure/tdonotation.nim
Normal file
45
tests/closure/tdonotation.nim
Normal file
@@ -0,0 +1,45 @@
|
||||
discard """
|
||||
output: '''
|
||||
click at 10,20
|
||||
lost focus 1
|
||||
lost focus 2
|
||||
registered handler for UserEvent 1
|
||||
registered handler for UserEvent 2
|
||||
registered handler for UserEvent 3'''
|
||||
"""
|
||||
|
||||
import future
|
||||
|
||||
type
|
||||
Button = object
|
||||
Event = object
|
||||
x, y: int
|
||||
|
||||
proc onClick(x: Button, handler: proc(x: Event)) =
|
||||
handler(Event(x: 10, y: 20))
|
||||
|
||||
proc onFocusLost(x: Button, handler: proc()) =
|
||||
handler()
|
||||
|
||||
proc onUserEvent(x: Button, eventName: string, handler: proc) =
|
||||
echo "registered handler for ", eventName
|
||||
|
||||
var b = Button()
|
||||
|
||||
b.onClick do (e: Event):
|
||||
echo "click at ", e.x, ",", e.y
|
||||
|
||||
b.onFocusLost:
|
||||
echo "lost focus 1"
|
||||
|
||||
b.onFocusLost do:
|
||||
echo "lost focus 2"
|
||||
|
||||
b.onUserEvent "UserEvent 1" do:
|
||||
discard
|
||||
|
||||
b.onUserEvent "UserEvent 2":
|
||||
discard
|
||||
|
||||
b.onUserEvent("UserEvent 3", () => echo "event 3")
|
||||
|
||||
25
tests/concepts/t5642.nim
Normal file
25
tests/concepts/t5642.nim
Normal file
@@ -0,0 +1,25 @@
|
||||
discard """
|
||||
output: 9
|
||||
"""
|
||||
|
||||
type DataTable = concept x
|
||||
x is object
|
||||
for f in fields(x):
|
||||
f is seq
|
||||
|
||||
type Students = object
|
||||
id : seq[int]
|
||||
name : seq[string]
|
||||
age: seq[int]
|
||||
|
||||
proc nrow*(dt: DataTable) : Natural =
|
||||
var totalLen = 0
|
||||
for f in fields(dt):
|
||||
totalLen += f.len
|
||||
return totalLen
|
||||
|
||||
let
|
||||
stud = Students (id : @[1,2,3], name : @["Vas", "Pas", "NafNaf"], age : @[10,16,32])
|
||||
|
||||
echo nrow(stud)
|
||||
|
||||
53
tests/concepts/tconceptinclosure.nim
Normal file
53
tests/concepts/tconceptinclosure.nim
Normal file
@@ -0,0 +1,53 @@
|
||||
discard """
|
||||
output: '''
|
||||
10
|
||||
20
|
||||
int
|
||||
20
|
||||
3
|
||||
'''
|
||||
"""
|
||||
|
||||
import typetraits
|
||||
|
||||
type
|
||||
FonConcept = concept x
|
||||
x.x is int
|
||||
|
||||
GenericConcept[T] = concept x
|
||||
x.x is T
|
||||
const L = T.name.len
|
||||
|
||||
Implementation = object
|
||||
x: int
|
||||
|
||||
Closure = object
|
||||
f: proc()
|
||||
|
||||
proc f1(x: FonConcept): Closure =
|
||||
result.f = proc () =
|
||||
echo x.x
|
||||
|
||||
proc f2(x: GenericConcept): Closure =
|
||||
result.f = proc () =
|
||||
echo x.x
|
||||
echo GenericConcept.T.name
|
||||
|
||||
proc f3[T](x: GenericConcept[T]): Closure =
|
||||
result.f = proc () =
|
||||
echo x.x
|
||||
echo x.L
|
||||
|
||||
let x = Implementation(x: 10)
|
||||
let y = Implementation(x: 20)
|
||||
|
||||
let a = x.f1
|
||||
let b = x.f2
|
||||
let c = x.f1
|
||||
let d = y.f2
|
||||
let e = y.f3
|
||||
|
||||
a.f()
|
||||
d.f()
|
||||
e.f()
|
||||
|
||||
@@ -42,7 +42,7 @@ echo p2 is AbstractPointOfFloat # true
|
||||
echo p2.x is float and p2.y is float # true
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/2018
|
||||
type ProtocolFollower = generic
|
||||
type ProtocolFollower = concept
|
||||
true # not a particularly involved protocol
|
||||
|
||||
type ImplementorA = object
|
||||
|
||||
42
tests/concepts/trandom_vars.nim
Normal file
42
tests/concepts/trandom_vars.nim
Normal file
@@ -0,0 +1,42 @@
|
||||
discard """
|
||||
output: "11.0"
|
||||
"""
|
||||
|
||||
type
|
||||
# A random number generator
|
||||
Random = object
|
||||
random: proc(): float
|
||||
# A generic typeclass for a random var
|
||||
RandomVar[A] = concept x
|
||||
var rng: Random
|
||||
rng.sample(x) is A
|
||||
# A few concrete instances
|
||||
Uniform = object
|
||||
a, b: float
|
||||
ClosureVar[A] = object
|
||||
f: proc(rng: var Random): A
|
||||
|
||||
# How to sample from various concrete instances
|
||||
proc sample(rng: var Random, u: Uniform): float = u.a + (u.b - u.a) * rng.random()
|
||||
|
||||
proc sample[A](rng: var Random, c: ClosureVar[A]): A = c.f(rng)
|
||||
|
||||
proc uniform(a, b: float): Uniform = Uniform(a: a, b: b)
|
||||
|
||||
# How to lift a function on values to a function on random variables
|
||||
proc map[A, B](x: RandomVar[A], f: proc(a: A): B): ClosureVar[B] =
|
||||
proc inner(rng: var Random): B =
|
||||
f(rng.sample(x))
|
||||
|
||||
result.f = inner
|
||||
|
||||
import future
|
||||
|
||||
proc fakeRandom(): Random =
|
||||
result.random = () => 0.5
|
||||
|
||||
let x = uniform(1, 10).map((x: float) => 2 * x)
|
||||
|
||||
var rng = fakeRandom()
|
||||
|
||||
echo rng.sample(x)
|
||||
27
tests/generics/t5570.nim
Normal file
27
tests/generics/t5570.nim
Normal file
@@ -0,0 +1,27 @@
|
||||
discard """
|
||||
nimout: "type uint32\ntype uint32"
|
||||
output: "(weight: 17.0, color: 100)"
|
||||
"""
|
||||
|
||||
import macros
|
||||
|
||||
type
|
||||
BaseFruit[T] = object of RootObj
|
||||
color: T
|
||||
|
||||
Banana[T] = object of BaseFruit[uint32]
|
||||
weight: T
|
||||
|
||||
macro printTypeName(typ: typed): untyped =
|
||||
echo "type ", getType(typ).repr
|
||||
|
||||
proc setColor[K](self: var BaseFruit[K], c: int) =
|
||||
printTypeName(self.color)
|
||||
self.color = uint32(c)
|
||||
|
||||
var x: Banana[float64]
|
||||
x.weight = 17
|
||||
printTypeName(x.color)
|
||||
x.setColor(100)
|
||||
echo x
|
||||
|
||||
18
tests/generics/t5602_inheritence.nim
Normal file
18
tests/generics/t5602_inheritence.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
discard """
|
||||
output: "seq[float]\n0"
|
||||
"""
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/5602
|
||||
|
||||
import typetraits
|
||||
|
||||
type
|
||||
Foo[T] = object of RootObj
|
||||
Bar[T] = object of Foo[seq[T]]
|
||||
|
||||
proc p[T](f: Foo[T]): T =
|
||||
echo T.name
|
||||
|
||||
var s: Bar[float]
|
||||
echo p(s).len # the bug was: p(s) should return seq[float], but returns float instead
|
||||
|
||||
30
tests/generics/t5643.nim
Normal file
30
tests/generics/t5643.nim
Normal file
@@ -0,0 +1,30 @@
|
||||
type
|
||||
Matrix*[M, N: static[int], T: SomeReal] = object
|
||||
data: ref array[N * M, T]
|
||||
|
||||
Matrix64*[M, N: static[int]] = Matrix[M, N, float64]
|
||||
|
||||
proc zeros64(M,N: static[int]): Matrix64[M,N] =
|
||||
new result.data
|
||||
for i in 0 .. < (M * N):
|
||||
result.data[i] = 0'f64
|
||||
|
||||
proc bar*[M,N: static[int], T](a: Matrix[M,N,T], b: Matrix[M,N,T]) =
|
||||
discard
|
||||
|
||||
let a = zeros64(2,2)
|
||||
bar(a,a)
|
||||
# https://github.com/nim-lang/Nim/issues/5643
|
||||
#
|
||||
# The test case was failing here, because the compiler failed to
|
||||
# detect the two matrix instantiations as the same type.
|
||||
#
|
||||
# The root cause was that the `T` type variable is a different
|
||||
# type after the first Matrix type has been matched.
|
||||
#
|
||||
# Sigmatch was failing to match the second version of `T`, but
|
||||
# due to some complex interplay between tyOr, tyTypeDesc and
|
||||
# tyGenericParam this was allowed to went through. The generic
|
||||
# instantiation of the second matrix was incomplete and the
|
||||
# generic cache lookup failed, producing two separate types.
|
||||
|
||||
31
tests/generics/t5683.nim
Normal file
31
tests/generics/t5683.nim
Normal file
@@ -0,0 +1,31 @@
|
||||
discard """
|
||||
output: "perm: 22 det: 22"
|
||||
"""
|
||||
|
||||
type Matrix[M,N: static[int]] = array[M, array[N, float]]
|
||||
|
||||
proc det[M,N](a: Matrix[M,N]): int = N*10 + M
|
||||
proc perm[M,N](a: Matrix[M,N]): int = M*10 + N
|
||||
|
||||
const
|
||||
a = [ [1.0, 2.0]
|
||||
, [3.0, 4.0]
|
||||
]
|
||||
|
||||
echo "perm: ", a.perm, " det: ", a.det
|
||||
|
||||
# This tests multiple instantiations of a generic
|
||||
# proc involving static params:
|
||||
type
|
||||
Vector64*[N: static[int]] = ref array[N, float64]
|
||||
Array64[N: static[int]] = array[N, float64]
|
||||
|
||||
proc vector*[N: static[int]](xs: Array64[N]): Vector64[N] =
|
||||
new result
|
||||
for i in 0 .. < N:
|
||||
result[i] = xs[i]
|
||||
|
||||
let v1 = vector([1.0, 2.0, 3.0, 4.0, 5.0])
|
||||
let v2 = vector([1.0, 2.0, 3.0, 4.0, 5.0])
|
||||
let v3 = vector([1.0, 2.0, 3.0, 4.0])
|
||||
|
||||
68
tests/generics/tbindoncevsbindmany.nim
Normal file
68
tests/generics/tbindoncevsbindmany.nim
Normal file
@@ -0,0 +1,68 @@
|
||||
template accept(x) =
|
||||
static: assert(compiles(x))
|
||||
|
||||
template reject(x) =
|
||||
static: assert(not compiles(x))
|
||||
|
||||
type
|
||||
ObjectWithNumber = concept obj
|
||||
obj.number is int
|
||||
|
||||
Foo[T] = object
|
||||
x: T
|
||||
|
||||
type A = object
|
||||
anumber: int
|
||||
|
||||
type B = object
|
||||
bnumber: int
|
||||
|
||||
proc number(a: A): int = a.anumber
|
||||
proc number(b: B): int = b.bnumber
|
||||
|
||||
proc notDistincConcept1(a: ObjectWithNumber, b: ObjectWithNumber) = discard
|
||||
proc notDistincConcept2(a, b: ObjectWithNumber) = discard
|
||||
proc distinctConcept1(a, b: distinct ObjectWithNumber) = discard
|
||||
proc distinctConcept2(a: ObjectWithNumber, b: distinct ObjectWithNumber) = discard
|
||||
proc distinctConcept3(a: distinct ObjectWithNumber, b: ObjectWithNumber) = discard
|
||||
proc distinctConcept4(a: distinct ObjectWithNumber, b: distinct ObjectWithNumber) = discard
|
||||
|
||||
var a = A(anumber: 5)
|
||||
var b = B(bnumber: 6)
|
||||
|
||||
accept notDistincConcept1(a, a)
|
||||
accept notDistincConcept1(b, b)
|
||||
reject notDistincConcept2(a, b)
|
||||
|
||||
accept notDistincConcept2(a, a)
|
||||
accept notDistincConcept2(b, b)
|
||||
reject notDistincConcept2(a, b)
|
||||
|
||||
accept distinctConcept1(a, b)
|
||||
accept distinctConcept2(a, b)
|
||||
accept distinctConcept3(a, b)
|
||||
accept distinctConcept4(a, b)
|
||||
|
||||
proc nonDistincGeneric1(a: Foo, b: Foo) = discard
|
||||
proc nonDistincGeneric2(a, b: Foo) = discard
|
||||
proc distinctGeneric1(a, b: distinct Foo) = discard
|
||||
proc distinctGeneric2(a: distinct Foo, b: Foo) = discard
|
||||
proc distinctGeneric3(a: Foo, b: distinct Foo) = discard
|
||||
proc distinctGeneric4(a: distinct Foo, b: distinct Foo) = discard
|
||||
|
||||
var f1 = Foo[int](x: 10)
|
||||
var f2 = Foo[string](x: "x")
|
||||
|
||||
accept nonDistincGeneric1(f1, f1)
|
||||
accept nonDistincGeneric1(f2, f2)
|
||||
reject nonDistincGeneric1(f1, f2)
|
||||
|
||||
accept nonDistincGeneric2(f1, f1)
|
||||
accept nonDistincGeneric2(f2, f2)
|
||||
reject nonDistincGeneric2(f1, f2)
|
||||
|
||||
accept distinctGeneric1(f1, f1)
|
||||
accept distinctGeneric2(f1, f1)
|
||||
accept distinctGeneric3(f1, f1)
|
||||
accept distinctGeneric4(f1, f1)
|
||||
|
||||
28
tests/generics/tmapping_generic_alias.nim
Normal file
28
tests/generics/tmapping_generic_alias.nim
Normal file
@@ -0,0 +1,28 @@
|
||||
discard """
|
||||
output: '''type(c) = GenAlias[system.int]
|
||||
T = int
|
||||
seq[int]
|
||||
'''
|
||||
"""
|
||||
|
||||
import typetraits
|
||||
|
||||
type
|
||||
Gen[T] = object
|
||||
x: T
|
||||
|
||||
GenAlias[T] = Gen[seq[T]]
|
||||
|
||||
proc f1[T](x: Gen[T]) =
|
||||
echo T.name
|
||||
|
||||
proc f2[T](x: GenAlias[T]) =
|
||||
echo "type(c) = ", type(x).name
|
||||
echo "T = ", T.name
|
||||
f1 x
|
||||
|
||||
let
|
||||
y = Gen[seq[int]](x: @[10])
|
||||
|
||||
f2 y
|
||||
|
||||
28
tests/generics/tparam_binding.nim
Normal file
28
tests/generics/tparam_binding.nim
Normal file
@@ -0,0 +1,28 @@
|
||||
discard """
|
||||
errormsg: "got (ref Matrix[2, 2, system.float], ref Matrix[2, 1, system.float])"
|
||||
line: 27
|
||||
"""
|
||||
|
||||
type
|
||||
Matrix[M,N: static[int]; T: SomeReal] = distinct array[0..(M*N - 1), T]
|
||||
|
||||
let a = new Matrix[2,2,float]
|
||||
let b = new Matrix[2,1,float]
|
||||
|
||||
proc foo[M,N: static[int],T](a: ref Matrix[M, N, T], b: ref Matrix[M, N, T])=
|
||||
discard
|
||||
|
||||
foo(a, a)
|
||||
|
||||
proc bar[M,N: static[int],T](a: ref Matrix[M, M, T], b: ref Matrix[M, N, T])=
|
||||
discard
|
||||
|
||||
bar(a, b)
|
||||
bar(a, a)
|
||||
|
||||
proc baz[M,N: static[int],T](a: ref Matrix[N, N, T], b: ref Matrix[M, N, T])=
|
||||
discard
|
||||
|
||||
baz(a, a)
|
||||
baz(a, b)
|
||||
|
||||
20
tests/generics/tptrinheritance.nim
Normal file
20
tests/generics/tptrinheritance.nim
Normal file
@@ -0,0 +1,20 @@
|
||||
type NSPasteboardItem* = ptr object
|
||||
type NSPasteboard* = ptr object
|
||||
type NSArrayAbstract = ptr object {.inheritable.}
|
||||
type NSMutableArrayAbstract = ptr object of NSArrayAbstract
|
||||
type NSArray*[T] = ptr object of NSArrayAbstract
|
||||
type NSMutableArray*[T] = ptr object of NSArray[T]
|
||||
|
||||
proc newMutableArrayAbstract*(): NSMutableArrayAbstract = discard
|
||||
|
||||
template newMutableArray*(T: typedesc): NSMutableArray[T] =
|
||||
cast[NSMutableArray[T]](newMutableArrayAbstract())
|
||||
|
||||
proc writeObjects*(p: NSPasteboard, o: ptr NSArray[NSPasteboardItem]) = discard
|
||||
|
||||
let a = newMutableArray NSPasteboardItem
|
||||
var x: NSMutableArray[NSPasteboardItem]
|
||||
var y: NSArray[NSPasteboardItem] = x
|
||||
|
||||
writeObjects(nil, a)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
output: '''true
|
||||
output: '''
|
||||
true
|
||||
true
|
||||
true
|
||||
@@ -14,10 +14,18 @@ true
|
||||
true
|
||||
true
|
||||
true
|
||||
true'''
|
||||
true
|
||||
true
|
||||
3
|
||||
2
|
||||
12
|
||||
Event { name: 'click: test' }
|
||||
Event { name: 'reloaded: test' }
|
||||
Event { name: 'updates: test' }
|
||||
'''
|
||||
"""
|
||||
|
||||
import macros, jsffi
|
||||
import macros, jsffi, jsconsole
|
||||
|
||||
# Tests for JsObject
|
||||
# Test JsObject []= and []
|
||||
@@ -55,8 +63,8 @@ block:
|
||||
block:
|
||||
proc test(): bool =
|
||||
let obj = newJsObject()
|
||||
obj.`?!$` = proc(x, y, z: int, t: string): string = t & $(x + y + z)
|
||||
obj.`?!$`(1, 2, 3, "Result is: ").to(string) == "Result is: 6"
|
||||
obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z)
|
||||
obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == "Result is: 6"
|
||||
echo test()
|
||||
|
||||
# Test JsObject []()
|
||||
@@ -265,3 +273,47 @@ block:
|
||||
let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever))
|
||||
obj.onWhatever(1) == 10
|
||||
echo test()
|
||||
|
||||
block:
|
||||
{.emit: "function jsProc(n) { return n; }" .}
|
||||
proc jsProc(x: int32): JsObject {.importc: "jsProc".}
|
||||
|
||||
proc test() =
|
||||
var x = jsProc(1)
|
||||
var y = jsProc(2)
|
||||
console.log x + y
|
||||
console.log ++x
|
||||
|
||||
x += jsProc(10)
|
||||
console.log x
|
||||
|
||||
test()
|
||||
|
||||
import macros
|
||||
|
||||
block:
|
||||
{.emit:
|
||||
"""
|
||||
function Event(name) { this.name = name; }
|
||||
function on(eventName, eventHandler) { eventHandler(new Event(eventName + ": test")); }
|
||||
var jslib = { "on": on, "subscribe": on };
|
||||
"""
|
||||
.}
|
||||
|
||||
type Event = object
|
||||
name: cstring
|
||||
|
||||
proc on(event: cstring, handler: proc) {.importc: "on".}
|
||||
var jslib {.importc: "jslib", nodecl.}: JsObject
|
||||
|
||||
on("click") do (e: Event):
|
||||
console.log e
|
||||
|
||||
jslib.on "reloaded" do:
|
||||
console.log jsarguments[0]
|
||||
|
||||
# this test case is different from the above, because
|
||||
# `subscribe` is not overloaded in the current scope
|
||||
jslib.subscribe "updates":
|
||||
console.log jsarguments[0]
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
|
||||
import macros
|
||||
|
||||
macro match*(s: cstring|string; pos: int; sections: untyped): untyped =
|
||||
for sec in sections.children:
|
||||
macro match*(s: cstring|string; pos: int; sections: varargs[untyped]): untyped =
|
||||
for sec in sections:
|
||||
expectKind sec, nnkOfBranch
|
||||
expectLen sec, 2
|
||||
result = newStmtList()
|
||||
|
||||
513
tests/parser/tpostexprblocks.nim
Normal file
513
tests/parser/tpostexprblocks.nim
Normal file
@@ -0,0 +1,513 @@
|
||||
discard """
|
||||
nimout: '''
|
||||
StmtList
|
||||
Ident !"foo"
|
||||
Call
|
||||
Ident !"foo"
|
||||
Call
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
Command
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
Call
|
||||
Ident !"foo"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
StrLit test
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
StrLit test
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Command
|
||||
Ident !"foo"
|
||||
StrLit test
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Command
|
||||
Ident !"foo"
|
||||
StrLit test
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Command
|
||||
Ident !"foo"
|
||||
IntLit 1
|
||||
Par
|
||||
Infix
|
||||
Ident !"+"
|
||||
IntLit 2
|
||||
IntLit 3
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Command
|
||||
Ident !"foo"
|
||||
IntLit 1
|
||||
Par
|
||||
Infix
|
||||
Ident !"+"
|
||||
IntLit 2
|
||||
IntLit 3
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
Do
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
FormalParams
|
||||
Empty
|
||||
IdentDefs
|
||||
Ident !"x"
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
Do
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
FormalParams
|
||||
Empty
|
||||
IdentDefs
|
||||
Ident !"x"
|
||||
Ident !"int"
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
Do
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
FormalParams
|
||||
Ident !"int"
|
||||
IdentDefs
|
||||
Ident !"x"
|
||||
Ident !"int"
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Command
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
Do
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
FormalParams
|
||||
Empty
|
||||
IdentDefs
|
||||
Ident !"y"
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Else
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Else
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Command
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
Do
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
FormalParams
|
||||
Empty
|
||||
IdentDefs
|
||||
Ident !"y"
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Do
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
FormalParams
|
||||
Ident !"int"
|
||||
IdentDefs
|
||||
Ident !"z"
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Do
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
FormalParams
|
||||
Ident !"int"
|
||||
IdentDefs
|
||||
Ident !"w"
|
||||
Ident !"int"
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Else
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
Call
|
||||
Ident !"bar"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Else
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
VarSection
|
||||
IdentDefs
|
||||
Ident !"a"
|
||||
Empty
|
||||
Ident !"foo"
|
||||
VarSection
|
||||
IdentDefs
|
||||
Ident !"a"
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
VarSection
|
||||
IdentDefs
|
||||
Ident !"a"
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
VarSection
|
||||
IdentDefs
|
||||
Ident !"a"
|
||||
Empty
|
||||
Command
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
VarSection
|
||||
IdentDefs
|
||||
Ident !"a"
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
VarSection
|
||||
IdentDefs
|
||||
Ident !"a"
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
VarSection
|
||||
IdentDefs
|
||||
Ident !"a"
|
||||
Empty
|
||||
Call
|
||||
Ident !"foo"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Else
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
VarSection
|
||||
IdentDefs
|
||||
Ident !"a"
|
||||
Empty
|
||||
Command
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
Do
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
FormalParams
|
||||
Empty
|
||||
IdentDefs
|
||||
Ident !"y"
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Else
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Asgn
|
||||
Ident !"a"
|
||||
Ident !"foo"
|
||||
Asgn
|
||||
Ident !"a"
|
||||
Call
|
||||
Ident !"foo"
|
||||
Asgn
|
||||
Ident !"a"
|
||||
Call
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
Asgn
|
||||
Ident !"a"
|
||||
Command
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
Asgn
|
||||
Ident !"a"
|
||||
Call
|
||||
Ident !"foo"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Asgn
|
||||
Ident !"a"
|
||||
Call
|
||||
Ident !"foo"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Asgn
|
||||
Ident !"a"
|
||||
Call
|
||||
Ident !"foo"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Else
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Asgn
|
||||
Ident !"a"
|
||||
Command
|
||||
Ident !"foo"
|
||||
Ident !"x"
|
||||
Do
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
FormalParams
|
||||
Empty
|
||||
IdentDefs
|
||||
Ident !"y"
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
Empty
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Else
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
Call
|
||||
DotExpr
|
||||
Ident !"result"
|
||||
Ident !"add"
|
||||
BracketExpr
|
||||
Call
|
||||
Ident !"quote"
|
||||
StmtList
|
||||
DiscardStmt
|
||||
Empty
|
||||
IntLit 0
|
||||
'''
|
||||
"""
|
||||
|
||||
import macros
|
||||
|
||||
dumpTree:
|
||||
# simple calls
|
||||
foo
|
||||
foo()
|
||||
foo(x)
|
||||
foo x
|
||||
|
||||
foo:
|
||||
discard
|
||||
|
||||
foo do:
|
||||
discard
|
||||
|
||||
foo("test"):
|
||||
discard
|
||||
|
||||
foo("test") do:
|
||||
discard
|
||||
|
||||
foo "test":
|
||||
discard
|
||||
|
||||
foo "test" do:
|
||||
discard
|
||||
|
||||
# more complicated calls
|
||||
foo 1, (2+3):
|
||||
discard
|
||||
|
||||
foo 1, (2+3) do:
|
||||
discard
|
||||
|
||||
foo do (x):
|
||||
discard
|
||||
|
||||
foo do (x: int):
|
||||
discard
|
||||
|
||||
foo do (x: int) -> int:
|
||||
discard
|
||||
|
||||
foo x do (y):
|
||||
discard
|
||||
|
||||
# extra blocks
|
||||
foo:
|
||||
discard
|
||||
else:
|
||||
discard
|
||||
|
||||
foo do:
|
||||
discard
|
||||
do:
|
||||
discard
|
||||
else:
|
||||
discard
|
||||
|
||||
foo x do (y):
|
||||
discard
|
||||
do (z) -> int:
|
||||
discard
|
||||
do (w: int) -> int:
|
||||
discard
|
||||
do:
|
||||
discard
|
||||
else:
|
||||
discard
|
||||
|
||||
# call with blocks as a param
|
||||
foo(x, bar do:
|
||||
discard
|
||||
else:
|
||||
discard
|
||||
)
|
||||
|
||||
# introduce a variable
|
||||
var a = foo
|
||||
var a = foo()
|
||||
var a = foo(x)
|
||||
var a = foo x
|
||||
|
||||
var a = foo:
|
||||
discard
|
||||
|
||||
var a = foo do:
|
||||
discard
|
||||
|
||||
var a = foo do:
|
||||
discard
|
||||
else:
|
||||
discard
|
||||
|
||||
var a = foo x do (y):
|
||||
discard
|
||||
else:
|
||||
discard
|
||||
|
||||
# assignments
|
||||
a = foo
|
||||
a = foo()
|
||||
a = foo(x)
|
||||
a = foo x
|
||||
|
||||
a = foo:
|
||||
discard
|
||||
|
||||
a = foo do:
|
||||
discard
|
||||
|
||||
a = foo do:
|
||||
discard
|
||||
else:
|
||||
discard
|
||||
|
||||
a = foo x do (y):
|
||||
discard
|
||||
else:
|
||||
discard
|
||||
|
||||
# some edge cases
|
||||
result.add((quote do:
|
||||
discard
|
||||
)[0])
|
||||
|
||||
@@ -59,14 +59,13 @@ template wrap(body: typed): untyped =
|
||||
|
||||
macro makeProc(): typed =
|
||||
# Make a template tree
|
||||
result = (quote do:
|
||||
result = quote do:
|
||||
proc someProc* =
|
||||
wrap do:
|
||||
let x = 123
|
||||
# Implicit conversion here
|
||||
let s: string = x
|
||||
echo s
|
||||
)
|
||||
|
||||
makeProc()
|
||||
|
||||
|
||||
6
tests/types/t5640.nim
Normal file
6
tests/types/t5640.nim
Normal file
@@ -0,0 +1,6 @@
|
||||
type
|
||||
vecBase[I: static[int]] = distinct array[I, float32]
|
||||
vec2* = vecBase[2]
|
||||
|
||||
var v = vec2([0.0'f32, 0.0'f32])
|
||||
|
||||
21
tests/types/t5648.nim
Normal file
21
tests/types/t5648.nim
Normal file
@@ -0,0 +1,21 @@
|
||||
discard """
|
||||
output: "ptr Foo"
|
||||
"""
|
||||
|
||||
import typetraits
|
||||
|
||||
type Foo = object
|
||||
bar*: int
|
||||
|
||||
proc main() =
|
||||
var f = create(Foo)
|
||||
f.bar = 3
|
||||
echo f.type.name
|
||||
|
||||
discard realloc(f, 0)
|
||||
|
||||
var g = Foo()
|
||||
g.bar = 3
|
||||
|
||||
main()
|
||||
|
||||
22
tests/types/thard_tyforward.nim
Executable file
22
tests/types/thard_tyforward.nim
Executable file
@@ -0,0 +1,22 @@
|
||||
type
|
||||
Bar[T] = Foo[T, T]
|
||||
Baz[T] = proc (x: Foo[T, T])
|
||||
|
||||
GenericAlias[T] = Foo[T]
|
||||
GenericAlias2[T] = Foo[Baz[T]]
|
||||
|
||||
Concrete1 = Foo[int, float]
|
||||
Concrete2 = proc(x: proc(a: Foo[int, float]))
|
||||
|
||||
Foo[T, U] = object
|
||||
x: T
|
||||
y: U
|
||||
|
||||
var
|
||||
x1: Bar[float]
|
||||
x2: Baz[int]
|
||||
x3: Concrete1
|
||||
x4: Concrete2
|
||||
x5: GenericAlias[int]
|
||||
x6: GenericAlias2[string]
|
||||
|
||||
Reference in New Issue
Block a user