parent
3ea3aa633d
commit
1efb5174f2
12 changed files with 290 additions and 171 deletions
|
|
@ -459,7 +459,7 @@ type
|
||||||
tfNotNil, # type cannot be 'nil'
|
tfNotNil, # type cannot be 'nil'
|
||||||
|
|
||||||
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
|
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
|
||||||
# other type so that it requires inititalization
|
# other type so that it requires initalization
|
||||||
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
|
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
|
||||||
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
||||||
# or other type classes
|
# or other type classes
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
if cmp < 0: best = z # x is better than the best so far
|
if cmp < 0: best = z # x is better than the best so far
|
||||||
elif cmp == 0: alt = z # x is as good as the best so far
|
elif cmp == 0: alt = z # x is as good as the best so far
|
||||||
else: discard
|
else: discard
|
||||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
#if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516:
|
||||||
# echo "Matches ", n.info, " ", typeToString(sym.typ)
|
# echo "Matches ", n.info, " ", typeToString(sym.typ)
|
||||||
# debug sym
|
# debug sym
|
||||||
# writeMatches(z)
|
# writeMatches(z)
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@
|
||||||
|
|
||||||
var enforceVoidContext = PType(kind: tyStmt)
|
var enforceVoidContext = PType(kind: tyStmt)
|
||||||
|
|
||||||
proc semDiscard(c: PContext, n: PNode): PNode =
|
proc semDiscard(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||||
if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
|
if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
|
||||||
|
|
||||||
proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
|
|
@ -29,7 +29,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
of nkIdent: s = lookUp(c, n.sons[0])
|
of nkIdent: s = lookUp(c, n.sons[0])
|
||||||
of nkSym: s = n.sons[0].sym
|
of nkSym: s = n.sons[0].sym
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
if s.kind == skLabel and s.owner.id == c.p.owner.id:
|
if s.kind == skLabel and s.owner.id == c.p.owner.id:
|
||||||
var x = newSymNode(s)
|
var x = newSymNode(s)
|
||||||
x.info = n.info
|
x.info = n.info
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
|
|
@ -41,16 +41,16 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
localError(n.info, errGenerated, "'continue' cannot have a label")
|
localError(n.info, errGenerated, "'continue' cannot have a label")
|
||||||
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
||||||
localError(n.info, errInvalidControlFlowX,
|
localError(n.info, errInvalidControlFlowX,
|
||||||
renderTree(n, {renderNoComments}))
|
renderTree(n, {renderNoComments}))
|
||||||
|
|
||||||
proc semAsm(con: PContext, n: PNode): PNode =
|
proc semAsm(con: PContext, n: PNode): PNode =
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
var marker = pragmaAsm(con, n.sons[0])
|
var marker = pragmaAsm(con, n.sons[0])
|
||||||
if marker == '\0': marker = '`' # default marker
|
if marker == '\0': marker = '`' # default marker
|
||||||
result = semAsmOrEmit(con, n, marker)
|
result = semAsmOrEmit(con, n, marker)
|
||||||
|
|
||||||
proc semWhile(c: PContext, n: PNode): PNode =
|
proc semWhile(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -62,16 +62,16 @@ proc semWhile(c: PContext, n: PNode): PNode =
|
||||||
if n.sons[1].typ == enforceVoidContext:
|
if n.sons[1].typ == enforceVoidContext:
|
||||||
result.typ = enforceVoidContext
|
result.typ = enforceVoidContext
|
||||||
|
|
||||||
proc toCover(t: PType): BiggestInt =
|
proc toCover(t: PType): BiggestInt =
|
||||||
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
|
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
|
||||||
if t2.kind == tyEnum and enumHasHoles(t2):
|
if t2.kind == tyEnum and enumHasHoles(t2):
|
||||||
result = sonsLen(t2.n)
|
result = sonsLen(t2.n)
|
||||||
else:
|
else:
|
||||||
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
|
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
|
||||||
|
|
||||||
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
|
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
|
||||||
## Checks that the given symbol is a proper procedure variable, meaning
|
## Checks that the given symbol is a proper procedure variable, meaning
|
||||||
## that it
|
## that it
|
||||||
var smoduleId = getModule(s).id
|
var smoduleId = getModule(s).id
|
||||||
if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
|
if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
|
||||||
smoduleId != c.module.id:
|
smoduleId != c.module.id:
|
||||||
|
|
@ -98,11 +98,11 @@ proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
|
||||||
localError(n.info, warnDestructor)
|
localError(n.info, warnDestructor)
|
||||||
# This still breaks too many things:
|
# This still breaks too many things:
|
||||||
when false:
|
when false:
|
||||||
if efDetermineType notin flags and n.typ.kind == tyTypeDesc and
|
if efDetermineType notin flags and n.typ.kind == tyTypeDesc and
|
||||||
c.p.owner.kind notin {skTemplate, skMacro}:
|
c.p.owner.kind notin {skTemplate, skMacro}:
|
||||||
localError(n.info, errGenerated, "value expected, but got a type")
|
localError(n.info, errGenerated, "value expected, but got a type")
|
||||||
|
|
||||||
proc newDeref(n: PNode): PNode {.inline.} =
|
proc newDeref(n: PNode): PNode {.inline.} =
|
||||||
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
|
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
|
||||||
addSon(result, n)
|
addSon(result, n)
|
||||||
|
|
||||||
|
|
@ -127,7 +127,7 @@ const
|
||||||
proc implicitlyDiscardable(n: PNode): bool =
|
proc implicitlyDiscardable(n: PNode): bool =
|
||||||
var n = n
|
var n = n
|
||||||
while n.kind in skipForDiscardable: n = n.lastSon
|
while n.kind in skipForDiscardable: n = n.lastSon
|
||||||
result = isCallExpr(n) and n.sons[0].kind == nkSym and
|
result = isCallExpr(n) and n.sons[0].kind == nkSym and
|
||||||
sfDiscardable in n.sons[0].sym.flags
|
sfDiscardable in n.sons[0].sym.flags
|
||||||
|
|
||||||
proc fixNilType(n: PNode) =
|
proc fixNilType(n: PNode) =
|
||||||
|
|
@ -160,11 +160,11 @@ proc discardCheck(c: PContext, result: PNode) =
|
||||||
while n.kind in skipForDiscardable: n = n.lastSon
|
while n.kind in skipForDiscardable: n = n.lastSon
|
||||||
localError(n.info, errDiscardValueX, result.typ.typeToString)
|
localError(n.info, errDiscardValueX, result.typ.typeToString)
|
||||||
|
|
||||||
proc semIf(c: PContext, n: PNode): PNode =
|
proc semIf(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
var typ = commonTypeBegin
|
var typ = commonTypeBegin
|
||||||
var hasElse = false
|
var hasElse = false
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
if it.len == 2:
|
if it.len == 2:
|
||||||
when newScopeForIf: openScope(c)
|
when newScopeForIf: openScope(c)
|
||||||
|
|
@ -208,10 +208,10 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
localError(n.info, errSelectorMustBeOfCertainTypes)
|
localError(n.info, errSelectorMustBeOfCertainTypes)
|
||||||
return
|
return
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
var x = n.sons[i]
|
var x = n.sons[i]
|
||||||
case x.kind
|
case x.kind
|
||||||
of nkOfBranch:
|
of nkOfBranch:
|
||||||
checkMinSonsLen(x, 2)
|
checkMinSonsLen(x, 2)
|
||||||
semCaseBranch(c, n, x, i, covered)
|
semCaseBranch(c, n, x, i, covered)
|
||||||
var last = sonsLen(x)-1
|
var last = sonsLen(x)-1
|
||||||
|
|
@ -304,9 +304,9 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
|
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
|
||||||
result = fitNode(c, typ, n)
|
result = fitNode(c, typ, n)
|
||||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||||
changeType(result.sons[1], typ, check=true)
|
changeType(result.sons[1], typ, check=true)
|
||||||
result = result.sons[1]
|
result = result.sons[1]
|
||||||
elif not sameType(result.typ, typ):
|
elif not sameType(result.typ, typ):
|
||||||
|
|
@ -325,7 +325,7 @@ proc identWithin(n: PNode, s: PIdent): bool =
|
||||||
result = n.kind == nkSym and n.sym.name.id == s.id
|
result = n.kind == nkSym and n.sym.name.id == s.id
|
||||||
|
|
||||||
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||||
if isTopLevel(c):
|
if isTopLevel(c):
|
||||||
result = semIdentWithPragma(c, kind, n, {sfExported})
|
result = semIdentWithPragma(c, kind, n, {sfExported})
|
||||||
incl(result.flags, sfGlobal)
|
incl(result.flags, sfGlobal)
|
||||||
else:
|
else:
|
||||||
|
|
@ -340,14 +340,14 @@ proc checkNilable(v: PSym) =
|
||||||
elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
|
elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
|
||||||
message(v.info, warnProveInit, v.name.s)
|
message(v.info, warnProveInit, v.name.s)
|
||||||
|
|
||||||
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
var b: PNode
|
var b: PNode
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
var hasCompileTime = false
|
var hasCompileTime = false
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
|
if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
|
||||||
checkMinSonsLen(a, 3)
|
checkMinSonsLen(a, 3)
|
||||||
var length = sonsLen(a)
|
var length = sonsLen(a)
|
||||||
|
|
@ -369,7 +369,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
typ = def.typ
|
typ = def.typ
|
||||||
else:
|
else:
|
||||||
# BUGFIX: ``fitNode`` is needed here!
|
# BUGFIX: ``fitNode`` is needed here!
|
||||||
# check type compatibility between def.typ and typ
|
# check type compatibility between def.typ and typ
|
||||||
def = fitNode(c, typ, def)
|
def = fitNode(c, typ, def)
|
||||||
#changeType(def.skipConv, typ, check=true)
|
#changeType(def.skipConv, typ, check=true)
|
||||||
else:
|
else:
|
||||||
|
|
@ -381,15 +381,15 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
else:
|
else:
|
||||||
def = ast.emptyNode
|
def = ast.emptyNode
|
||||||
if symkind == skLet: localError(a.info, errLetNeedsInit)
|
if symkind == skLet: localError(a.info, errLetNeedsInit)
|
||||||
|
|
||||||
# this can only happen for errornous var statements:
|
# this can only happen for errornous var statements:
|
||||||
if typ == nil: continue
|
if typ == nil: continue
|
||||||
typeAllowedCheck(a.info, typ, symkind)
|
typeAllowedCheck(a.info, typ, symkind)
|
||||||
var tup = skipTypes(typ, {tyGenericInst})
|
var tup = skipTypes(typ, {tyGenericInst})
|
||||||
if a.kind == nkVarTuple:
|
if a.kind == nkVarTuple:
|
||||||
if tup.kind != tyTuple:
|
if tup.kind != tyTuple:
|
||||||
localError(a.info, errXExpected, "tuple")
|
localError(a.info, errXExpected, "tuple")
|
||||||
elif length-2 != sonsLen(tup):
|
elif length-2 != sonsLen(tup):
|
||||||
localError(a.info, errWrongNumberOfVariables)
|
localError(a.info, errWrongNumberOfVariables)
|
||||||
else:
|
else:
|
||||||
b = newNodeI(nkVarTuple, a.info)
|
b = newNodeI(nkVarTuple, a.info)
|
||||||
|
|
@ -397,7 +397,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
|
b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
|
||||||
b.sons[length-1] = def
|
b.sons[length-1] = def
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
elif tup.kind == tyTuple and def.kind == nkPar and
|
elif tup.kind == tyTuple and def.kind == nkPar and
|
||||||
a.kind == nkIdentDefs and a.len > 3:
|
a.kind == nkIdentDefs and a.len > 3:
|
||||||
message(a.info, warnEachIdentIsTuple)
|
message(a.info, warnEachIdentIsTuple)
|
||||||
|
|
||||||
|
|
@ -438,12 +438,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
if sfCompileTime in v.flags: hasCompileTime = true
|
if sfCompileTime in v.flags: hasCompileTime = true
|
||||||
if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
|
if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
|
||||||
|
|
||||||
proc semConst(c: PContext, n: PNode): PNode =
|
proc semConst(c: PContext, n: PNode): PNode =
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if (a.kind != nkConstDef): illFormedAst(a)
|
if (a.kind != nkConstDef): illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
var v = semIdentDef(c, a.sons[0], skConst)
|
var v = semIdentDef(c, a.sons[0], skConst)
|
||||||
|
|
@ -498,7 +498,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
||||||
var iter = skipTypes(iterBase, {tyGenericInst})
|
var iter = skipTypes(iterBase, {tyGenericInst})
|
||||||
# length == 3 means that there is one for loop variable
|
# length == 3 means that there is one for loop variable
|
||||||
# and thus no tuple unpacking:
|
# and thus no tuple unpacking:
|
||||||
if iter.kind != tyTuple or length == 3:
|
if iter.kind != tyTuple or length == 3:
|
||||||
if length == 3:
|
if length == 3:
|
||||||
var v = symForVar(c, n.sons[0])
|
var v = symForVar(c, n.sons[0])
|
||||||
if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
|
if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
|
||||||
|
|
@ -526,13 +526,13 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
||||||
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
|
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
|
||||||
result = newNodeI(nkCall, arg.info)
|
result = newNodeI(nkCall, arg.info)
|
||||||
result.add(newIdentNode(it.getIdent, arg.info))
|
result.add(newIdentNode(it.getIdent, arg.info))
|
||||||
if arg.typ != nil and arg.typ.kind == tyVar:
|
if arg.typ != nil and arg.typ.kind == tyVar:
|
||||||
result.add newDeref(arg)
|
result.add newDeref(arg)
|
||||||
else:
|
else:
|
||||||
result.add arg
|
result.add arg
|
||||||
result = semExprNoDeref(c, result, {efWantIterator})
|
result = semExprNoDeref(c, result, {efWantIterator})
|
||||||
|
|
||||||
proc semFor(c: PContext, n: PNode): PNode =
|
proc semFor(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkMinSonsLen(n, 3)
|
checkMinSonsLen(n, 3)
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
|
|
@ -567,13 +567,13 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||||
result.typ = enforceVoidContext
|
result.typ = enforceVoidContext
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
proc semRaise(c: PContext, n: PNode): PNode =
|
proc semRaise(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||||
var typ = n.sons[0].typ
|
var typ = n.sons[0].typ
|
||||||
if typ.kind != tyRef or typ.sons[0].kind != tyObject:
|
if typ.kind != tyRef or typ.sons[0].kind != tyObject:
|
||||||
localError(n.info, errExprCannotBeRaised)
|
localError(n.info, errExprCannotBeRaised)
|
||||||
|
|
||||||
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||||
|
|
@ -583,13 +583,13 @@ proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||||
if a.kind == nkSym: addDecl(c, a.sym)
|
if a.kind == nkSym: addDecl(c, a.sym)
|
||||||
else: illFormedAst(a)
|
else: illFormedAst(a)
|
||||||
|
|
||||||
proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||||
# process the symbols on the left side for the whole type section, before
|
# process the symbols on the left side for the whole type section, before
|
||||||
# we even look at the type definitions on the right
|
# we even look at the type definitions on the right
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if a.kind != nkTypeDef: illFormedAst(a)
|
if a.kind != nkTypeDef: illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
var s = semIdentDef(c, a.sons[0], skType)
|
var s = semIdentDef(c, a.sons[0], skType)
|
||||||
|
|
@ -602,29 +602,29 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||||
a.sons[0] = newSymNode(s)
|
a.sons[0] = newSymNode(s)
|
||||||
|
|
||||||
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
if (a.sons[0].kind != nkSym): illFormedAst(a)
|
if (a.sons[0].kind != nkSym): illFormedAst(a)
|
||||||
var s = a.sons[0].sym
|
var s = a.sons[0].sym
|
||||||
if s.magic == mNone and a.sons[2].kind == nkEmpty:
|
if s.magic == mNone and a.sons[2].kind == nkEmpty:
|
||||||
localError(a.info, errImplOfXexpected, s.name.s)
|
localError(a.info, errImplOfXexpected, s.name.s)
|
||||||
if s.magic != mNone: processMagicType(c, s)
|
if s.magic != mNone: processMagicType(c, s)
|
||||||
if a.sons[1].kind != nkEmpty:
|
if a.sons[1].kind != nkEmpty:
|
||||||
# We have a generic type declaration here. In generic types,
|
# We have a generic type declaration here. In generic types,
|
||||||
# symbol lookup needs to be done here.
|
# symbol lookup needs to be done here.
|
||||||
openScope(c)
|
openScope(c)
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
if s.magic == mNone: s.typ.kind = tyGenericBody
|
if s.magic == mNone: s.typ.kind = tyGenericBody
|
||||||
# XXX for generic type aliases this is not correct! We need the
|
# XXX for generic type aliases this is not correct! We need the
|
||||||
# underlying Id really:
|
# underlying Id really:
|
||||||
#
|
#
|
||||||
# type
|
# type
|
||||||
# TGObj[T] = object
|
# TGObj[T] = object
|
||||||
# TAlias[T] = TGObj[T]
|
# TAlias[T] = TGObj[T]
|
||||||
#
|
#
|
||||||
s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
|
s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
|
||||||
a.sons[1] = s.typ.n
|
a.sons[1] = s.typ.n
|
||||||
s.typ.size = -1 # could not be computed properly
|
s.typ.size = -1 # could not be computed properly
|
||||||
|
|
@ -642,13 +642,13 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
s.typ.sons[sonsLen(s.typ) - 1] = body
|
s.typ.sons[sonsLen(s.typ) - 1] = body
|
||||||
popOwner()
|
popOwner()
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
elif a.sons[2].kind != nkEmpty:
|
elif a.sons[2].kind != nkEmpty:
|
||||||
# process the type's body:
|
# process the type's body:
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
var t = semTypeNode(c, a.sons[2], s.typ)
|
var t = semTypeNode(c, a.sons[2], s.typ)
|
||||||
if s.typ == nil:
|
if s.typ == nil:
|
||||||
s.typ = t
|
s.typ = t
|
||||||
elif t != s.typ:
|
elif t != s.typ:
|
||||||
# this can happen for e.g. tcan_alias_specialised_generic:
|
# this can happen for e.g. tcan_alias_specialised_generic:
|
||||||
assignType(s.typ, t)
|
assignType(s.typ, t)
|
||||||
#debug s.typ
|
#debug s.typ
|
||||||
|
|
@ -679,19 +679,19 @@ proc checkForMetaFields(n: PNode) =
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
internalAssert false
|
||||||
|
|
||||||
proc typeSectionFinalPass(c: PContext, n: PNode) =
|
proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if a.sons[0].kind != nkSym: illFormedAst(a)
|
if a.sons[0].kind != nkSym: illFormedAst(a)
|
||||||
var s = a.sons[0].sym
|
var s = a.sons[0].sym
|
||||||
# compute the type's size and check for illegal recursions:
|
# compute the type's size and check for illegal recursions:
|
||||||
if a.sons[1].kind == nkEmpty:
|
if a.sons[1].kind == nkEmpty:
|
||||||
if a.sons[2].kind in {nkSym, nkIdent, nkAccQuoted}:
|
if a.sons[2].kind in {nkSym, nkIdent, nkAccQuoted}:
|
||||||
# type aliases are hard:
|
# type aliases are hard:
|
||||||
#MessageOut('for type ' + typeToString(s.typ));
|
#MessageOut('for type ' + typeToString(s.typ));
|
||||||
var t = semTypeNode(c, a.sons[2], nil)
|
var t = semTypeNode(c, a.sons[2], nil)
|
||||||
if t.kind in {tyObject, tyEnum}:
|
if t.kind in {tyObject, tyEnum}:
|
||||||
assignType(s.typ, t)
|
assignType(s.typ, t)
|
||||||
s.typ.id = t.id # same id
|
s.typ.id = t.id # same id
|
||||||
checkConstructedType(s.info, s.typ)
|
checkConstructedType(s.info, s.typ)
|
||||||
|
|
@ -723,21 +723,21 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) =
|
||||||
if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyStmt:
|
if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyStmt:
|
||||||
localError(n.info, errGenerated, "invalid return type: 'stmt'")
|
localError(n.info, errGenerated, "invalid return type: 'stmt'")
|
||||||
|
|
||||||
proc addParams(c: PContext, n: PNode, kind: TSymKind) =
|
proc addParams(c: PContext, n: PNode, kind: TSymKind) =
|
||||||
for i in countup(1, sonsLen(n)-1):
|
for i in countup(1, sonsLen(n)-1):
|
||||||
if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind)
|
if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind)
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
|
|
||||||
proc semBorrow(c: PContext, n: PNode, s: PSym) =
|
proc semBorrow(c: PContext, n: PNode, s: PSym) =
|
||||||
# search for the correct alias:
|
# search for the correct alias:
|
||||||
var b = searchForBorrowProc(c, c.currentScope.parent, s)
|
var b = searchForBorrowProc(c, c.currentScope.parent, s)
|
||||||
if b != nil:
|
if b != nil:
|
||||||
# store the alias:
|
# store the alias:
|
||||||
n.sons[bodyPos] = newSymNode(b)
|
n.sons[bodyPos] = newSymNode(b)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errNoSymbolToBorrowFromFound)
|
localError(n.info, errNoSymbolToBorrowFromFound)
|
||||||
|
|
||||||
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
||||||
if t != nil:
|
if t != nil:
|
||||||
var s = newSym(skResult, getIdent"result", getCurrOwner(), info)
|
var s = newSym(skResult, getIdent"result", getCurrOwner(), info)
|
||||||
s.typ = t
|
s.typ = t
|
||||||
|
|
@ -745,7 +745,7 @@ proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
||||||
addParamOrResult(c, s, owner)
|
addParamOrResult(c, s, owner)
|
||||||
c.p.resultSym = s
|
c.p.resultSym = s
|
||||||
|
|
||||||
proc addResultNode(c: PContext, n: PNode) =
|
proc addResultNode(c: PContext, n: PNode) =
|
||||||
if c.p.resultSym != nil: addSon(n, newSymNode(c.p.resultSym))
|
if c.p.resultSym != nil: addSon(n, newSymNode(c.p.resultSym))
|
||||||
|
|
||||||
proc copyExcept(n: PNode, i: int): PNode =
|
proc copyExcept(n: PNode, i: int): PNode =
|
||||||
|
|
@ -789,7 +789,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
||||||
result = semStmt(c, x)
|
result = semStmt(c, x)
|
||||||
# since a proc annotation can set pragmas, we process these here again.
|
# since a proc annotation can set pragmas, we process these here again.
|
||||||
# This is required for SqueakNim-like export pragmas.
|
# This is required for SqueakNim-like export pragmas.
|
||||||
if result.kind in procDefs and result[namePos].kind == nkSym and
|
if result.kind in procDefs and result[namePos].kind == nkSym and
|
||||||
result[pragmasPos].kind != nkEmpty:
|
result[pragmasPos].kind != nkEmpty:
|
||||||
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
|
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
|
||||||
return
|
return
|
||||||
|
|
@ -811,7 +811,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
var gp: PNode
|
var gp: PNode
|
||||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||||
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
||||||
gp = n.sons[genericParamsPos]
|
gp = n.sons[genericParamsPos]
|
||||||
else:
|
else:
|
||||||
|
|
@ -861,13 +861,13 @@ proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||||
var n = n
|
var n = n
|
||||||
|
|
||||||
n = replaceTypesInBody(c, pt, n)
|
n = replaceTypesInBody(c, pt, n)
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
n.sons[genericParamsPos] = emptyNode
|
n.sons[genericParamsPos] = emptyNode
|
||||||
n.sons[paramsPos] = n.typ.n
|
n.sons[paramsPos] = n.typ.n
|
||||||
|
|
||||||
openScope(c)
|
openScope(c)
|
||||||
var s = n.sons[namePos].sym
|
var s = n.sons[namePos].sym
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
|
|
@ -880,7 +880,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
popOwner()
|
popOwner()
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
s.ast = result
|
s.ast = result
|
||||||
|
|
||||||
# alternative variant (not quite working):
|
# alternative variant (not quite working):
|
||||||
|
|
@ -926,7 +926,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||||
else: break
|
else: break
|
||||||
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
||||||
if t.deepCopy.isNil: t.deepCopy = s
|
if t.deepCopy.isNil: t.deepCopy = s
|
||||||
else:
|
else:
|
||||||
localError(n.info, errGenerated,
|
localError(n.info, errGenerated,
|
||||||
"cannot bind another 'deepCopy' to: " & typeToString(t))
|
"cannot bind another 'deepCopy' to: " & typeToString(t))
|
||||||
else:
|
else:
|
||||||
|
|
@ -993,10 +993,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
var gp: PNode
|
var gp: PNode
|
||||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||||
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
||||||
gp = n.sons[genericParamsPos]
|
gp = n.sons[genericParamsPos]
|
||||||
else:
|
else:
|
||||||
gp = newNodeI(nkGenericParams, n.info)
|
gp = newNodeI(nkGenericParams, n.info)
|
||||||
# process parameters:
|
# process parameters:
|
||||||
if n.sons[paramsPos].kind != nkEmpty:
|
if n.sons[paramsPos].kind != nkEmpty:
|
||||||
|
|
@ -1013,7 +1013,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
|
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
|
||||||
if s.kind in skIterators:
|
if s.kind in skIterators:
|
||||||
s.typ.flags.incl(tfIterator)
|
s.typ.flags.incl(tfIterator)
|
||||||
|
|
||||||
var proto = searchForProc(c, s.scope, s)
|
var proto = searchForProc(c, s.scope, s)
|
||||||
if proto == nil:
|
if proto == nil:
|
||||||
if s.kind == skClosureIterator: s.typ.callConv = ccClosure
|
if s.kind == skClosureIterator: s.typ.callConv = ccClosure
|
||||||
|
|
@ -1031,14 +1031,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
else:
|
else:
|
||||||
implicitPragmas(c, s, n, validPragmas)
|
implicitPragmas(c, s, n, validPragmas)
|
||||||
else:
|
else:
|
||||||
if n.sons[pragmasPos].kind != nkEmpty:
|
if n.sons[pragmasPos].kind != nkEmpty:
|
||||||
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
|
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
|
||||||
if sfForward notin proto.flags:
|
if sfForward notin proto.flags:
|
||||||
wrongRedefinition(n.info, proto.name.s)
|
wrongRedefinition(n.info, proto.name.s)
|
||||||
excl(proto.flags, sfForward)
|
excl(proto.flags, sfForward)
|
||||||
closeScope(c) # close scope with wrong parameter symbols
|
closeScope(c) # close scope with wrong parameter symbols
|
||||||
openScope(c) # open scope for old (correct) parameter symbols
|
openScope(c) # open scope for old (correct) parameter symbols
|
||||||
if proto.ast.sons[genericParamsPos].kind != nkEmpty:
|
if proto.ast.sons[genericParamsPos].kind != nkEmpty:
|
||||||
addGenericParamListToScope(c, proto.ast.sons[genericParamsPos])
|
addGenericParamListToScope(c, proto.ast.sons[genericParamsPos])
|
||||||
addParams(c, proto.typ.n, proto.kind)
|
addParams(c, proto.typ.n, proto.kind)
|
||||||
proto.info = s.info # more accurate line information
|
proto.info = s.info # more accurate line information
|
||||||
|
|
@ -1088,7 +1088,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
n.sons[bodyPos] = ast.emptyNode
|
n.sons[bodyPos] = ast.emptyNode
|
||||||
else:
|
else:
|
||||||
if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
|
if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
|
||||||
if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
|
if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
|
||||||
incl(s.flags, sfForward)
|
incl(s.flags, sfForward)
|
||||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||||
sideEffectsCheck(c, s)
|
sideEffectsCheck(c, s)
|
||||||
|
|
@ -1126,14 +1126,14 @@ proc semIterator(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
s.typ.callConv = ccInline
|
s.typ.callConv = ccInline
|
||||||
when false:
|
when false:
|
||||||
if s.typ.callConv != ccInline:
|
if s.typ.callConv != ccInline:
|
||||||
s.typ.callConv = ccClosure
|
s.typ.callConv = ccClosure
|
||||||
# and they always at least use the 'env' for the state field:
|
# and they always at least use the 'env' for the state field:
|
||||||
incl(s.typ.flags, tfCapturesEnv)
|
incl(s.typ.flags, tfCapturesEnv)
|
||||||
if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
|
if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
|
||||||
localError(n.info, errImplOfXexpected, s.name.s)
|
localError(n.info, errImplOfXexpected, s.name.s)
|
||||||
|
|
||||||
proc semProc(c: PContext, n: PNode): PNode =
|
proc semProc(c: PContext, n: PNode): PNode =
|
||||||
result = semProcAux(c, n, skProc, procPragmas)
|
result = semProcAux(c, n, skProc, procPragmas)
|
||||||
|
|
||||||
proc hasObjParam(s: PSym): bool =
|
proc hasObjParam(s: PSym): bool =
|
||||||
|
|
@ -1146,10 +1146,10 @@ proc finishMethod(c: PContext, s: PSym) =
|
||||||
if hasObjParam(s):
|
if hasObjParam(s):
|
||||||
methodDef(s, false)
|
methodDef(s, false)
|
||||||
|
|
||||||
proc semMethod(c: PContext, n: PNode): PNode =
|
proc semMethod(c: PContext, n: PNode): PNode =
|
||||||
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
|
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
|
||||||
result = semProcAux(c, n, skMethod, methodPragmas)
|
result = semProcAux(c, n, skMethod, methodPragmas)
|
||||||
|
|
||||||
var s = result.sons[namePos].sym
|
var s = result.sons[namePos].sym
|
||||||
if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty:
|
if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty:
|
||||||
if hasObjParam(s):
|
if hasObjParam(s):
|
||||||
|
|
@ -1157,7 +1157,7 @@ proc semMethod(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
localError(n.info, errXNeedsParamObjectType, "method")
|
localError(n.info, errXNeedsParamObjectType, "method")
|
||||||
|
|
||||||
proc semConverterDef(c: PContext, n: PNode): PNode =
|
proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||||
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
|
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
|
||||||
checkSonsLen(n, bodyPos + 1)
|
checkSonsLen(n, bodyPos + 1)
|
||||||
result = semProcAux(c, n, skConverter, converterPragmas)
|
result = semProcAux(c, n, skConverter, converterPragmas)
|
||||||
|
|
@ -1167,7 +1167,7 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||||
if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
|
if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
|
||||||
addConverter(c, s)
|
addConverter(c, s)
|
||||||
|
|
||||||
proc semMacroDef(c: PContext, n: PNode): PNode =
|
proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||||
checkSonsLen(n, bodyPos + 1)
|
checkSonsLen(n, bodyPos + 1)
|
||||||
result = semProcAux(c, n, skMacro, macroPragmas)
|
result = semProcAux(c, n, skMacro, macroPragmas)
|
||||||
var s = result.sons[namePos].sym
|
var s = result.sons[namePos].sym
|
||||||
|
|
@ -1175,23 +1175,23 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||||
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
|
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
|
||||||
if n.sons[bodyPos].kind == nkEmpty:
|
if n.sons[bodyPos].kind == nkEmpty:
|
||||||
localError(n.info, errImplOfXexpected, s.name.s)
|
localError(n.info, errImplOfXexpected, s.name.s)
|
||||||
|
|
||||||
proc evalInclude(c: PContext, n: PNode): PNode =
|
proc evalInclude(c: PContext, n: PNode): PNode =
|
||||||
result = newNodeI(nkStmtList, n.info)
|
result = newNodeI(nkStmtList, n.info)
|
||||||
addSon(result, n)
|
addSon(result, n)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var f = checkModuleName(n.sons[i])
|
var f = checkModuleName(n.sons[i])
|
||||||
if f != InvalidFileIDX:
|
if f != InvalidFileIDX:
|
||||||
if containsOrIncl(c.includedFiles, f):
|
if containsOrIncl(c.includedFiles, f):
|
||||||
localError(n.info, errRecursiveDependencyX, f.toFilename)
|
localError(n.info, errRecursiveDependencyX, f.toFilename)
|
||||||
else:
|
else:
|
||||||
addSon(result, semStmt(c, gIncludeFile(c.module, f)))
|
addSon(result, semStmt(c, gIncludeFile(c.module, f)))
|
||||||
excl(c.includedFiles, f)
|
excl(c.includedFiles, f)
|
||||||
|
|
||||||
proc setLine(n: PNode, info: TLineInfo) =
|
proc setLine(n: PNode, info: TLineInfo) =
|
||||||
for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
|
for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
|
||||||
n.info = info
|
n.info = info
|
||||||
|
|
||||||
proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||||
let pragmaList = n.sons[0]
|
let pragmaList = n.sons[0]
|
||||||
pragma(c, nil, pragmaList, exprPragmas)
|
pragma(c, nil, pragmaList, exprPragmas)
|
||||||
|
|
@ -1200,7 +1200,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||||
for i in 0 .. <pragmaList.len:
|
for i in 0 .. <pragmaList.len:
|
||||||
case whichPragma(pragmaList.sons[i])
|
case whichPragma(pragmaList.sons[i])
|
||||||
of wLine: setLine(result, pragmaList.sons[i].info)
|
of wLine: setLine(result, pragmaList.sons[i].info)
|
||||||
of wLocks:
|
of wLocks:
|
||||||
result = n
|
result = n
|
||||||
result.typ = n.sons[1].typ
|
result.typ = n.sons[1].typ
|
||||||
else: discard
|
else: discard
|
||||||
|
|
@ -1315,8 +1315,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
inner.addSon(semStmtList(c, rest, flags))
|
inner.addSon(semStmtList(c, rest, flags))
|
||||||
n.sons.setLen(i+1)
|
n.sons.setLen(i+1)
|
||||||
return
|
return
|
||||||
of LastBlockStmts:
|
of LastBlockStmts:
|
||||||
for j in countup(i + 1, length - 1):
|
for j in countup(i + 1, length - 1):
|
||||||
case n.sons[j].kind
|
case n.sons[j].kind
|
||||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
|
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
|
||||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||||
|
|
@ -1338,7 +1338,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# "Last expression must be explicitly returned if it " &
|
# "Last expression must be explicitly returned if it " &
|
||||||
# "is discardable or discarded")
|
# "is discardable or discarded")
|
||||||
|
|
||||||
proc semStmt(c: PContext, n: PNode): PNode =
|
proc semStmt(c: PContext, n: PNode): PNode =
|
||||||
# now: simply an alias:
|
# now: simply an alias:
|
||||||
result = semExprNoType(c, n)
|
result = semExprNoType(c, n)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,17 +157,40 @@ proc sumGeneric(t: PType): int =
|
||||||
result = ord(t.kind == tyGenericInvocation)
|
result = ord(t.kind == tyGenericInvocation)
|
||||||
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
||||||
break
|
break
|
||||||
of tyProc:
|
|
||||||
# proc matches proc better than 'stmt' to disambiguate 'spawn'
|
|
||||||
return 1
|
|
||||||
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
|
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
|
||||||
|
of tyBool, tyChar, tyEnum, tyObject, tyProc, tyPointer,
|
||||||
|
tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||||
|
tyUInt..tyUInt64:
|
||||||
|
return 1
|
||||||
else: return 0
|
else: return 0
|
||||||
|
|
||||||
|
#var ggDebug: bool
|
||||||
|
|
||||||
proc complexDisambiguation(a, b: PType): int =
|
proc complexDisambiguation(a, b: PType): int =
|
||||||
var x, y: int
|
# 'a' matches better if *every* argument matches better or equal than 'b'.
|
||||||
for i in 1 .. <a.len: x += a.sons[i].sumGeneric
|
var winner = 0
|
||||||
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
|
for i in 1 .. <min(a.len, b.len):
|
||||||
result = x - y
|
let x = a.sons[i].sumGeneric
|
||||||
|
let y = b.sons[i].sumGeneric
|
||||||
|
#if ggDebug:
|
||||||
|
# echo "came her ", typeToString(a.sons[i]), " ", typeToString(b.sons[i])
|
||||||
|
if x != y:
|
||||||
|
if winner == 0:
|
||||||
|
if x > y: winner = 1
|
||||||
|
else: winner = -1
|
||||||
|
elif x > y:
|
||||||
|
if winner != 1:
|
||||||
|
# contradiction
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
if winner != -1:
|
||||||
|
return 0
|
||||||
|
result = winner
|
||||||
|
when false:
|
||||||
|
var x, y: int
|
||||||
|
for i in 1 .. <a.len: x += a.sons[i].sumGeneric
|
||||||
|
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
|
||||||
|
result = x - y
|
||||||
when false:
|
when false:
|
||||||
proc betterThan(a, b: PType): bool {.inline.} = a.sumGeneric > b.sumGeneric
|
proc betterThan(a, b: PType): bool {.inline.} = a.sumGeneric > b.sumGeneric
|
||||||
|
|
||||||
|
|
@ -338,7 +361,8 @@ proc minRel(a, b: TTypeRelation): TTypeRelation =
|
||||||
|
|
||||||
proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
result = isNone
|
result = isNone
|
||||||
if sameType(f, a): result = isEqual
|
if sameType(f, a):
|
||||||
|
result = isEqual
|
||||||
elif sonsLen(a) == sonsLen(f):
|
elif sonsLen(a) == sonsLen(f):
|
||||||
result = isEqual
|
result = isEqual
|
||||||
let firstField = if f.kind == tyTuple: 0
|
let firstField = if f.kind == tyTuple: 0
|
||||||
|
|
@ -380,17 +404,17 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
# no luck resolving the type, so the inference fails
|
# no luck resolving the type, so the inference fails
|
||||||
return isNone
|
return isNone
|
||||||
let reverseRel = typeRel(c, a, f)
|
let reverseRel = typeRel(c, a, f)
|
||||||
if reverseRel == isGeneric:
|
if reverseRel >= isGeneric:
|
||||||
result = isInferred
|
result = isInferred
|
||||||
inc c.genericMatches
|
#inc c.genericMatches
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f, a)
|
result = typeRel(c, f, a)
|
||||||
|
|
||||||
if result <= isSubtype or inconsistentVarTypes(f, a):
|
if result <= isSubtype or inconsistentVarTypes(f, a):
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
if result == isEqual:
|
#if result == isEqual:
|
||||||
inc c.exactMatches
|
# inc c.exactMatches
|
||||||
|
|
||||||
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
case a.kind
|
case a.kind
|
||||||
|
|
@ -433,6 +457,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
return isNone
|
return isNone
|
||||||
when useEffectSystem:
|
when useEffectSystem:
|
||||||
if not compatibleEffects(f, a): return isNone
|
if not compatibleEffects(f, a): return isNone
|
||||||
|
|
||||||
of tyNil:
|
of tyNil:
|
||||||
result = f.allowsNil
|
result = f.allowsNil
|
||||||
of tyIter:
|
of tyIter:
|
||||||
|
|
@ -590,10 +615,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
return typeRel(c, f, lastSon(a))
|
return typeRel(c, f, lastSon(a))
|
||||||
|
|
||||||
template bindingRet(res) =
|
template bindingRet(res) =
|
||||||
when res == isGeneric:
|
if doBind:
|
||||||
if doBind:
|
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
||||||
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
if doBind: put(c.bindings, f, bound)
|
||||||
if doBind: put(c.bindings, f, bound)
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
template considerPreviousT(body: stmt) {.immediate.} =
|
template considerPreviousT(body: stmt) {.immediate.} =
|
||||||
|
|
@ -605,20 +629,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyOr:
|
of tyOr:
|
||||||
# seq[int|string] vs seq[number]
|
# seq[int|string] vs seq[number]
|
||||||
# both int and string must match against number
|
# both int and string must match against number
|
||||||
|
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
|
||||||
|
result = isGeneric
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
if typeRel(c, f, branch, false) == isNone:
|
let x = typeRel(c, f, branch, false)
|
||||||
return isNone
|
if x == isNone: return isNone
|
||||||
|
if x < result: result = x
|
||||||
return isGeneric
|
|
||||||
|
|
||||||
of tyAnd:
|
of tyAnd:
|
||||||
# seq[Sortable and Iterable] vs seq[Sortable]
|
# seq[Sortable and Iterable] vs seq[Sortable]
|
||||||
# only one match is enough
|
# only one match is enough
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
if typeRel(c, f, branch, false) != isNone:
|
let x = typeRel(c, f, branch, false)
|
||||||
return isGeneric
|
if x != isNone:
|
||||||
|
return if x >= isGeneric: isGeneric else: x
|
||||||
return isNone
|
result = isNone
|
||||||
|
|
||||||
of tyNot:
|
of tyNot:
|
||||||
case f.kind
|
case f.kind
|
||||||
|
|
@ -781,11 +806,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
inc(c.inheritancePenalty, depth)
|
inc(c.inheritancePenalty, depth)
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual
|
if a.kind == tyDistinct and sameDistinctTypes(f, a): result = isEqual
|
||||||
elif c.coerceDistincts: result = typeRel(c, f.base, a)
|
elif c.coerceDistincts: result = typeRel(c, f.base, a)
|
||||||
of tySet:
|
of tySet:
|
||||||
if a.kind == tySet:
|
if a.kind == tySet:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
if f.sons[0].kind != tyGenericParam and a.sons[0].kind == tyEmpty:
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f.sons[0], a.sons[0])
|
result = typeRel(c, f.sons[0], a.sons[0])
|
||||||
|
|
@ -865,7 +890,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = typeRel(c, ff, aa)
|
result = typeRel(c, ff, aa)
|
||||||
if result == isNone: return
|
if result == isNone: return
|
||||||
if ff.kind == tyRange and result != isEqual: return isNone
|
if ff.kind == tyRange and result != isEqual: return isNone
|
||||||
result = isGeneric
|
#result = isGeneric
|
||||||
# XXX See bug #2220. A[int] should match A[int] better than some generic X
|
# XXX See bug #2220. A[int] should match A[int] better than some generic X
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, lastSon(f), a)
|
result = typeRel(c, lastSon(f), a)
|
||||||
|
|
@ -904,18 +929,23 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyAnd:
|
of tyAnd:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
for branch in f.sons:
|
for branch in f.sons:
|
||||||
if typeRel(c, branch, aOrig) < isSubtype:
|
let x = typeRel(c, branch, aOrig)
|
||||||
return isNone
|
if x < isSubtype: return isNone
|
||||||
|
# 'and' implies minimum matching result:
|
||||||
bindingRet isGeneric
|
if x < result: result = x
|
||||||
|
bindingRet result
|
||||||
|
|
||||||
of tyOr:
|
of tyOr:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
|
result = isNone
|
||||||
for branch in f.sons:
|
for branch in f.sons:
|
||||||
if typeRel(c, branch, aOrig) >= isSubtype:
|
let x = typeRel(c, branch, aOrig)
|
||||||
bindingRet isGeneric
|
# 'or' implies maximum matching result:
|
||||||
|
if x > result: result = x
|
||||||
return isNone
|
if result >= isSubtype:
|
||||||
|
bindingRet result
|
||||||
|
else:
|
||||||
|
result = isNone
|
||||||
|
|
||||||
of tyNot:
|
of tyNot:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
|
|
@ -975,6 +1005,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
internalAssert a.sons != nil and a.sons.len > 0
|
internalAssert a.sons != nil and a.sons.len > 0
|
||||||
c.typedescMatched = true
|
c.typedescMatched = true
|
||||||
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
|
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
|
||||||
|
if result > isGeneric: result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
|
|
@ -998,12 +1029,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
return isNone
|
return isNone
|
||||||
if doBind:
|
if doBind:
|
||||||
put(c.bindings, f, concrete)
|
put(c.bindings, f, concrete)
|
||||||
|
elif result > isGeneric:
|
||||||
|
result = isGeneric
|
||||||
elif a.kind == tyEmpty:
|
elif a.kind == tyEmpty:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
elif x.kind == tyGenericParam:
|
elif x.kind == tyGenericParam:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, x, a) # check if it fits
|
result = typeRel(c, x, a) # check if it fits
|
||||||
|
if result > isGeneric: result = isGeneric
|
||||||
|
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
let prev = PType(idTableGet(c.bindings, f))
|
let prev = PType(idTableGet(c.bindings, f))
|
||||||
|
|
@ -1220,8 +1254,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
of isConvertible, isIntConv: inc(m.convMatches)
|
of isConvertible, isIntConv: inc(m.convMatches)
|
||||||
of isSubtype, isSubrange: inc(m.subtypeMatches)
|
of isSubtype, isSubrange: inc(m.subtypeMatches)
|
||||||
of isGeneric, isInferred: inc(m.genericMatches)
|
of isGeneric, isInferred: inc(m.genericMatches)
|
||||||
of isInferredConvertible: inc(m.genericMatches); inc(m.convMatches)
|
|
||||||
of isFromIntLit: inc(m.intConvMatches, 256)
|
of isFromIntLit: inc(m.intConvMatches, 256)
|
||||||
|
of isInferredConvertible:
|
||||||
|
inc(m.convMatches)
|
||||||
of isEqual: inc(m.exactMatches)
|
of isEqual: inc(m.exactMatches)
|
||||||
of isNone: discard
|
of isNone: discard
|
||||||
|
|
||||||
|
|
@ -1255,9 +1290,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||||
of isSubrange:
|
of isSubrange:
|
||||||
inc(m.subtypeMatches)
|
inc(m.subtypeMatches)
|
||||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
if f.kind == tyVar:
|
||||||
|
result = arg
|
||||||
|
else:
|
||||||
|
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||||
of isInferred, isInferredConvertible:
|
of isInferred, isInferredConvertible:
|
||||||
inc(m.genericMatches)
|
|
||||||
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
|
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
|
||||||
result = c.semInferredLambda(c, m.bindings, arg)
|
result = c.semInferredLambda(c, m.bindings, arg)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1266,6 +1303,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
if r == isInferredConvertible:
|
if r == isInferredConvertible:
|
||||||
inc(m.convMatches)
|
inc(m.convMatches)
|
||||||
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
||||||
|
else:
|
||||||
|
inc(m.genericMatches)
|
||||||
of isGeneric:
|
of isGeneric:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
if arg.typ == nil:
|
if arg.typ == nil:
|
||||||
|
|
@ -1331,7 +1370,16 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||||
for i in countup(0, sonsLen(arg) - 1):
|
for i in countup(0, sonsLen(arg) - 1):
|
||||||
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
|
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
|
||||||
copyCandidate(z, m)
|
copyCandidate(z, m)
|
||||||
|
z.callee = arg.sons[i].typ
|
||||||
|
z.calleeSym = arg.sons[i].sym
|
||||||
|
#if arg.sons[i].sym.name.s == "cmp":
|
||||||
|
# ggDebug = true
|
||||||
|
# echo "CALLLEEEEEEEE ", typeToString(z.callee)
|
||||||
var r = typeRel(z, f, arg.sons[i].typ)
|
var r = typeRel(z, f, arg.sons[i].typ)
|
||||||
|
#if arg.sons[i].sym.name.s == "cmp": # and arg.info.line == 606:
|
||||||
|
# echo "M ", r, " ", arg.info, " ", typeToString(arg.sons[i].sym.typ)
|
||||||
|
# debug arg.sons[i].sym
|
||||||
|
# writeMatches(z)
|
||||||
if r != isNone:
|
if r != isNone:
|
||||||
case x.state
|
case x.state
|
||||||
of csEmpty, csNoMatch:
|
of csEmpty, csNoMatch:
|
||||||
|
|
@ -1644,7 +1692,7 @@ tests:
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
var c: TCandidate
|
var c: TCandidate
|
||||||
InitCandidate(nil, c, nil)
|
initCandidate(nil, c, nil)
|
||||||
|
|
||||||
template yes(x, y) =
|
template yes(x, y) =
|
||||||
test astToStr(x) & " is " & astToStr(y):
|
test astToStr(x) & " is " & astToStr(y):
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ when defined(Windows):
|
||||||
while i < password.len:
|
while i < password.len:
|
||||||
x = runeLenAt(password, i)
|
x = runeLenAt(password, i)
|
||||||
inc i, x
|
inc i, x
|
||||||
password.setLen(password.len - x)
|
password.setLen(password.len - x)
|
||||||
else:
|
else:
|
||||||
password.add(toUTF8(c.Rune))
|
password.add(toUTF8(c.Rune))
|
||||||
stdout.write "\n"
|
stdout.write "\n"
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,15 @@
|
||||||
|
|
||||||
type
|
type
|
||||||
SortOrder* = enum ## sort order
|
SortOrder* = enum ## sort order
|
||||||
Descending, Ascending
|
Descending, Ascending
|
||||||
|
|
||||||
{.deprecated: [TSortOrder: SortOrder].}
|
{.deprecated: [TSortOrder: SortOrder].}
|
||||||
|
|
||||||
|
|
||||||
proc `*`*(x: int, order: SortOrder): int {.inline.} =
|
proc `*`*(x: int, order: SortOrder): int {.inline.} =
|
||||||
## flips `x` if ``order == Descending``;
|
## flips `x` if ``order == Descending``;
|
||||||
## if ``order == Ascending`` then `x` is returned.
|
## if ``order == Ascending`` then `x` is returned.
|
||||||
## `x` is supposed to be the result of a comparator, ie ``< 0`` for
|
## `x` is supposed to be the result of a comparator, ie ``< 0`` for
|
||||||
## *less than*, ``== 0`` for *equal*, ``> 0`` for *greater than*.
|
## *less than*, ``== 0`` for *equal*, ``> 0`` for *greater than*.
|
||||||
var y = order.ord - 1
|
var y = order.ord - 1
|
||||||
result = (x xor y) - y
|
result = (x xor y) - y
|
||||||
|
|
@ -73,14 +73,15 @@ const
|
||||||
onlySafeCode = true
|
onlySafeCode = true
|
||||||
|
|
||||||
proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int =
|
proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int =
|
||||||
## same as binarySearch except that if key is not in `a` then this
|
## same as binarySearch except that if key is not in `a` then this
|
||||||
## returns the location where `key` would be if it were. In other
|
## returns the location where `key` would be if it were. In other
|
||||||
## words if you have a sorted sequence and you call insert(thing, elm, lowerBound(thing, elm))
|
## words if you have a sorted sequence and you call
|
||||||
## the sequence will still be sorted
|
## insert(thing, elm, lowerBound(thing, elm))
|
||||||
|
## the sequence will still be sorted.
|
||||||
|
##
|
||||||
|
## `cmp` is the comparator function to use, the expected return values are
|
||||||
|
## the same as that of system.cmp.
|
||||||
##
|
##
|
||||||
## `cmp` is the comparator function to use, the expected return values are the same as
|
|
||||||
## that of system.cmp
|
|
||||||
##
|
|
||||||
## example::
|
## example::
|
||||||
##
|
##
|
||||||
## var arr = @[1,2,3,5,6,7,8,9]
|
## var arr = @[1,2,3,5,6,7,8,9]
|
||||||
|
|
@ -102,9 +103,9 @@ proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.})
|
||||||
count = step
|
count = step
|
||||||
|
|
||||||
proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
|
proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
|
||||||
proc merge[T](a, b: var openArray[T], lo, m, hi: int,
|
proc merge[T](a, b: var openArray[T], lo, m, hi: int,
|
||||||
cmp: proc (x, y: T): int {.closure.}, order: SortOrder) =
|
cmp: proc (x, y: T): int {.closure.}, order: SortOrder) =
|
||||||
template `<-` (a, b: expr) =
|
template `<-` (a, b: expr) =
|
||||||
when false:
|
when false:
|
||||||
a = b
|
a = b
|
||||||
elif onlySafeCode:
|
elif onlySafeCode:
|
||||||
|
|
@ -151,10 +152,10 @@ proc merge[T](a, b: var openArray[T], lo, m, hi: int,
|
||||||
proc sort*[T](a: var openArray[T],
|
proc sort*[T](a: var openArray[T],
|
||||||
cmp: proc (x, y: T): int {.closure.},
|
cmp: proc (x, y: T): int {.closure.},
|
||||||
order = SortOrder.Ascending) =
|
order = SortOrder.Ascending) =
|
||||||
## Default Nim sort. The sorting is guaranteed to be stable and
|
## Default Nim sort. The sorting is guaranteed to be stable and
|
||||||
## the worst case is guaranteed to be O(n log n).
|
## the worst case is guaranteed to be O(n log n).
|
||||||
## The current implementation uses an iterative
|
## The current implementation uses an iterative
|
||||||
## mergesort to achieve this. It uses a temporary sequence of
|
## mergesort to achieve this. It uses a temporary sequence of
|
||||||
## length ``a.len div 2``. Currently Nim does not support a
|
## length ``a.len div 2``. Currently Nim does not support a
|
||||||
## sensible default argument for ``cmp``, so you have to provide one
|
## sensible default argument for ``cmp``, so you have to provide one
|
||||||
## of your own. However, the ``system.cmp`` procs can be used:
|
## of your own. However, the ``system.cmp`` procs can be used:
|
||||||
|
|
@ -187,7 +188,8 @@ proc sort*[T](a: var openArray[T],
|
||||||
dec(m, s*2)
|
dec(m, s*2)
|
||||||
s = s*2
|
s = s*2
|
||||||
|
|
||||||
proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.}, order = SortOrder.Ascending): seq[T] =
|
proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.},
|
||||||
|
order = SortOrder.Ascending): seq[T] =
|
||||||
## returns `a` sorted by `cmp` in the specified `order`.
|
## returns `a` sorted by `cmp` in the specified `order`.
|
||||||
result = newSeq[T](a.len)
|
result = newSeq[T](a.len)
|
||||||
for i in 0 .. a.high:
|
for i in 0 .. a.high:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
# Bug #2022
|
# Bug #2022
|
||||||
|
|
||||||
|
discard """
|
||||||
|
output: '''@[97, 45]
|
||||||
|
@[true, false]
|
||||||
|
@[false, false]'''
|
||||||
|
"""
|
||||||
|
|
||||||
## The goal of this snippet is to provide and test a construct for general-
|
## The goal of this snippet is to provide and test a construct for general-
|
||||||
## purpose, random-access mapping. I use an AST-manipulation-based approach
|
## purpose, random-access mapping. I use an AST-manipulation-based approach
|
||||||
## because it's more efficient than using procedure pointers and less
|
## because it's more efficient than using procedure pointers and less
|
||||||
|
|
@ -31,6 +37,7 @@ type Mapped[Input; predicate: static[string]] = object
|
||||||
input: Input
|
input: Input
|
||||||
|
|
||||||
macro map(input, predicate: expr): expr =
|
macro map(input, predicate: expr): expr =
|
||||||
|
let predicate = callsite()[2]
|
||||||
newNimNode(nnkObjConstr).add(
|
newNimNode(nnkObjConstr).add(
|
||||||
newNimNode(nnkBracketExpr).add(
|
newNimNode(nnkBracketExpr).add(
|
||||||
ident"Mapped",
|
ident"Mapped",
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
|
discard """
|
||||||
|
output: '''another number: 123
|
||||||
|
yay'''
|
||||||
|
"""
|
||||||
|
|
||||||
# Test overloading of procs when used as function pointers
|
# Test overloading of procs when used as function pointers
|
||||||
|
|
||||||
import strutils
|
import strutils
|
||||||
|
|
||||||
proc parseInt(x: float): int {.noSideEffect.} = nil
|
proc parseInt(x: float): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: bool): int {.noSideEffect.} = nil
|
proc parseInt(x: bool): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: float32): int {.noSideEffect.} = nil
|
proc parseInt(x: float32): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: int8): int {.noSideEffect.} = nil
|
proc parseInt(x: int8): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: TFile): int {.noSideEffect.} = nil
|
proc parseInt(x: TFile): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: char): int {.noSideEffect.} = nil
|
proc parseInt(x: char): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: int16): int {.noSideEffect.} = nil
|
proc parseInt(x: int16): int {.noSideEffect.} = discard
|
||||||
|
|
||||||
proc parseInt[T](x: T): int = echo x; 34
|
proc parseInt[T](x: T): int = echo x; 34
|
||||||
|
|
||||||
|
|
@ -19,12 +24,13 @@ var
|
||||||
q = TParseInt(parseInt)
|
q = TParseInt(parseInt)
|
||||||
p: TParseInt = parseInt
|
p: TParseInt = parseInt
|
||||||
|
|
||||||
proc takeParseInt(x: proc (y: string): int {.noSideEffect.}): int =
|
proc takeParseInt(x: proc (y: string): int {.noSideEffect.}): int =
|
||||||
result = x("123")
|
result = x("123")
|
||||||
|
|
||||||
echo "Give a list of numbers (separated by spaces): "
|
if false:
|
||||||
var x = stdin.readline.split.map(parseInt).max
|
echo "Give a list of numbers (separated by spaces): "
|
||||||
echo x, " is the maximum!"
|
var x = stdin.readline.split.map(parseInt).max
|
||||||
|
echo x, " is the maximum!"
|
||||||
echo "another number: ", takeParseInt(parseInt)
|
echo "another number: ", takeParseInt(parseInt)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
22
tests/overload/tprefer_specialized_generic.nim
Normal file
22
tests/overload/tprefer_specialized_generic.nim
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
discard """
|
||||||
|
output: '''ref ref T ptr S'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc foo[T](x: T) =
|
||||||
|
echo "only T"
|
||||||
|
|
||||||
|
proc foo[T](x: ref T) =
|
||||||
|
echo "ref T"
|
||||||
|
|
||||||
|
proc foo[T, S](x: ref ref T; y: ptr S) =
|
||||||
|
echo "ref ref T ptr S"
|
||||||
|
|
||||||
|
proc foo[T, S](x: ref T; y: ptr S) =
|
||||||
|
echo "ref T ptr S"
|
||||||
|
|
||||||
|
proc foo[T](x: ref T; default = 0) =
|
||||||
|
echo "ref T; default"
|
||||||
|
|
||||||
|
var x: ref ref int
|
||||||
|
var y: ptr ptr int
|
||||||
|
foo(x, y)
|
||||||
|
|
@ -1,17 +1,42 @@
|
||||||
discard """
|
discard """
|
||||||
output: "Version 2 was called."
|
output: '''Version 2 was called.
|
||||||
disabled: true
|
This has the highest precedence.
|
||||||
|
This has the second-highest precedence.
|
||||||
|
This has the lowest precedence.'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# bug #2220
|
# bug #2220
|
||||||
|
when true:
|
||||||
|
type A[T] = object
|
||||||
|
type B = A[int]
|
||||||
|
|
||||||
type A[T] = object
|
proc q[X](x: X) =
|
||||||
type B = A[int]
|
echo "Version 1 was called."
|
||||||
|
|
||||||
proc p[X](x: X) =
|
proc q(x: B) =
|
||||||
echo "Version 1 was called."
|
echo "Version 2 was called."
|
||||||
|
|
||||||
proc p(x: B) =
|
q(B()) # This call reported as ambiguous.
|
||||||
echo "Version 2 was called."
|
|
||||||
|
|
||||||
p(B()) # This call reported as ambiguous.
|
# bug #2219
|
||||||
|
template testPred(a: expr) =
|
||||||
|
block:
|
||||||
|
type A = object of RootObj
|
||||||
|
type B = object of A
|
||||||
|
type SomeA = A|A # A hack to make "A" a typeclass.
|
||||||
|
|
||||||
|
when a >= 3:
|
||||||
|
proc p[X](x: X) =
|
||||||
|
echo "This has the highest precedence."
|
||||||
|
when a >= 2:
|
||||||
|
proc p[X: A](x: X) =
|
||||||
|
echo "This has the second-highest precedence."
|
||||||
|
when a >= 1:
|
||||||
|
proc p[X: SomeA](x: X) =
|
||||||
|
echo "This has the lowest precedence."
|
||||||
|
|
||||||
|
p(B())
|
||||||
|
|
||||||
|
testPred(3)
|
||||||
|
testPred(2)
|
||||||
|
testPred(1)
|
||||||
|
|
|
||||||
|
|
@ -7,3 +7,12 @@ import algorithm
|
||||||
# bug #1657
|
# bug #1657
|
||||||
var modules = @["hi", "ho", "ha", "huu"]
|
var modules = @["hi", "ho", "ha", "huu"]
|
||||||
sort(modules, system.cmp)
|
sort(modules, system.cmp)
|
||||||
|
|
||||||
|
type
|
||||||
|
MyType = object
|
||||||
|
x: string
|
||||||
|
|
||||||
|
proc cmp(a, b: MyType): int = cmp(a.x, b.x)
|
||||||
|
|
||||||
|
var modulesB = @[MyType(x: "ho"), MyType(x: "ha")]
|
||||||
|
sort(modulesB, cmp)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
discard """
|
discard """
|
||||||
errormsg: "'"
|
errormsg: "'"
|
||||||
file: "sequtils.nim"
|
file: "sequtils.nim"
|
||||||
line: 416
|
line: 435
|
||||||
"""
|
"""
|
||||||
# unfortunately our tester doesn't support multiple lines of compiler
|
# unfortunately our tester doesn't support multiple lines of compiler
|
||||||
# error messages yet...
|
# error messages yet...
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue