Merge branch 'devel' into newasync
This commit is contained in:
commit
b3a0906619
15 changed files with 190 additions and 97 deletions
|
|
@ -1376,7 +1376,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
getTemp(p, getSysType(tyInt), i) # our counter
|
getTemp(p, getSysType(tyInt), i) # our counter
|
||||||
initLocExpr(p, e.sons[1], a)
|
initLocExpr(p, e.sons[1], a)
|
||||||
initLocExpr(p, e.sons[2], b)
|
initLocExpr(p, e.sons[2], b)
|
||||||
if d.k == locNone: getTemp(p, a.t, d)
|
if d.k == locNone: getTemp(p, getSysType(tyBool), d)
|
||||||
lineF(p, cpsStmts, lookupOpr[op],
|
lineF(p, cpsStmts, lookupOpr[op],
|
||||||
[rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
|
[rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
|
||||||
of mEqSet:
|
of mEqSet:
|
||||||
|
|
|
||||||
|
|
@ -332,6 +332,7 @@ proc myOpen(module: PSym): PPassContext =
|
||||||
c.semOperand = semOperand
|
c.semOperand = semOperand
|
||||||
c.semConstBoolExpr = semConstBoolExpr
|
c.semConstBoolExpr = semConstBoolExpr
|
||||||
c.semOverloadedCall = semOverloadedCall
|
c.semOverloadedCall = semOverloadedCall
|
||||||
|
c.semGenerateInstance = generateInstance
|
||||||
c.semTypeNode = semTypeNode
|
c.semTypeNode = semTypeNode
|
||||||
pushProcCon(c, module)
|
pushProcCon(c, module)
|
||||||
pushOwner(c.module)
|
pushOwner(c.module)
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,8 @@ type
|
||||||
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
|
||||||
filter: TSymKinds): PNode {.nimcall.}
|
filter: TSymKinds): PNode {.nimcall.}
|
||||||
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
|
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
|
||||||
|
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
|
||||||
|
info: TLineInfo): PSym
|
||||||
includedFiles*: TIntSet # used to detect recursive include files
|
includedFiles*: TIntSet # used to detect recursive include files
|
||||||
userPragmas*: TStrTable
|
userPragmas*: TStrTable
|
||||||
evalContext*: PEvalContext
|
evalContext*: PEvalContext
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,14 @@ proc semConv(c: PContext, n: PNode): PNode =
|
||||||
if not isSymChoice(op):
|
if not isSymChoice(op):
|
||||||
let status = checkConvertible(c, result.typ, op.typ)
|
let status = checkConvertible(c, result.typ, op.typ)
|
||||||
case status
|
case status
|
||||||
of convOK: discard
|
of convOK:
|
||||||
|
# handle SomeProcType(SomeGenericProc)
|
||||||
|
# XXX: This needs fixing. checkConvertible uses typeRel internally, but
|
||||||
|
# doesn't bother to perform the work done in paramTypeMatchAux/fitNode
|
||||||
|
# so we are redoing the typeRel work here. Why does semConv exist as a
|
||||||
|
# separate proc from fitNode?
|
||||||
|
if op.kind == nkSym and op.sym.isGenericRoutine:
|
||||||
|
result.sons[1] = fitNode(c, result.typ, result.sons[1])
|
||||||
of convNotNeedeed:
|
of convNotNeedeed:
|
||||||
message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
|
message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
|
||||||
of convNotLegal:
|
of convNotLegal:
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ type
|
||||||
isSubtype,
|
isSubtype,
|
||||||
isSubrange, # subrange of the wanted type; no type conversion
|
isSubrange, # subrange of the wanted type; no type conversion
|
||||||
# but apart from that counts as ``isSubtype``
|
# but apart from that counts as ``isSubtype``
|
||||||
|
isInferred, # generic proc was matched against a concrete type
|
||||||
|
isInferredConvertible, # same as above, but requiring proc CC conversion
|
||||||
isGeneric,
|
isGeneric,
|
||||||
isFromIntLit, # conversion *from* int literal; proven safe
|
isFromIntLit, # conversion *from* int literal; proven safe
|
||||||
isEqual
|
isEqual
|
||||||
|
|
@ -338,10 +340,40 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
proc allowsNil(f: PType): TTypeRelation {.inline.} =
|
proc allowsNil(f: PType): TTypeRelation {.inline.} =
|
||||||
result = if tfNotNil notin f.flags: isSubtype else: isNone
|
result = if tfNotNil notin f.flags: isSubtype else: isNone
|
||||||
|
|
||||||
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
|
||||||
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
||||||
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
|
||||||
|
|
||||||
|
proc procParamTypeRel(c: var TCandidate, f, a: PType,
|
||||||
|
result: var TTypeRelation) =
|
||||||
|
var
|
||||||
|
m: TTypeRelation
|
||||||
|
f = f
|
||||||
|
|
||||||
|
if a.isMetaType:
|
||||||
|
if f.isMetaType:
|
||||||
|
# we are matching a generic proc (as proc param)
|
||||||
|
# to another generic type appearing in the proc
|
||||||
|
# sigunature. there is a change that the target
|
||||||
|
# type is already fully-determined, so we are
|
||||||
|
# going to try resolve it
|
||||||
|
f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
|
||||||
|
if f == nil or f.isMetaType:
|
||||||
|
# no luck resolving the type, so the inference fails
|
||||||
|
result = isNone
|
||||||
|
return
|
||||||
|
let reverseRel = typeRel(c, a, f)
|
||||||
|
if reverseRel == isGeneric:
|
||||||
|
m = isInferred
|
||||||
|
else:
|
||||||
|
m = typeRel(c, f, a)
|
||||||
|
|
||||||
|
if m <= isSubtype or inconsistentVarTypes(f, a):
|
||||||
|
result = isNone
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
result = minRel(m, result)
|
||||||
|
|
||||||
|
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyProc:
|
of tyProc:
|
||||||
if sonsLen(f) != sonsLen(a): return
|
if sonsLen(f) != sonsLen(a): return
|
||||||
|
|
@ -350,18 +382,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
result = isEqual # start with maximum; also correct for no
|
result = isEqual # start with maximum; also correct for no
|
||||||
# params at all
|
# params at all
|
||||||
for i in countup(1, sonsLen(f)-1):
|
for i in countup(1, sonsLen(f)-1):
|
||||||
var m = typeRel(c, f.sons[i], a.sons[i])
|
procParamTypeRel(c, f.sons[i], a.sons[i], result)
|
||||||
if m <= isSubtype or inconsistentVarTypes(f.sons[i], a.sons[i]):
|
|
||||||
return isNone
|
|
||||||
else: result = minRel(m, result)
|
|
||||||
if f.sons[0] != nil:
|
if f.sons[0] != nil:
|
||||||
if a.sons[0] != nil:
|
if a.sons[0] != nil:
|
||||||
var m = typeRel(c, f.sons[0], a.sons[0])
|
procParamTypeRel(c, f.sons[0], a.sons[0], result)
|
||||||
# Subtype is sufficient for return types!
|
|
||||||
if m < isSubtype or inconsistentVarTypes(f.sons[0], a.sons[0]):
|
|
||||||
return isNone
|
|
||||||
elif m == isSubtype: result = isConvertible
|
|
||||||
else: result = minRel(m, result)
|
|
||||||
else:
|
else:
|
||||||
return isNone
|
return isNone
|
||||||
elif a.sons[0] != nil:
|
elif a.sons[0] != nil:
|
||||||
|
|
@ -376,7 +400,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
elif f.callConv != a.callConv:
|
elif f.callConv != a.callConv:
|
||||||
# valid to pass a 'nimcall' thingie to 'closure':
|
# valid to pass a 'nimcall' thingie to 'closure':
|
||||||
if f.callConv == ccClosure and a.callConv == ccDefault:
|
if f.callConv == ccClosure and a.callConv == ccDefault:
|
||||||
result = isConvertible
|
result = if result != isInferred: isConvertible
|
||||||
|
else: isInferredConvertible
|
||||||
else:
|
else:
|
||||||
return isNone
|
return isNone
|
||||||
when useEffectSystem:
|
when useEffectSystem:
|
||||||
|
|
@ -402,18 +427,8 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
|
||||||
|
|
||||||
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
ff, a: PType): TTypeRelation =
|
ff, a: PType): TTypeRelation =
|
||||||
#if f.n == nil:
|
|
||||||
# let r = typeRel(m, f, a)
|
|
||||||
# return if r == isGeneric: arg else: nil
|
|
||||||
|
|
||||||
var body = ff.skipTypes({tyUserTypeClassInst})
|
var body = ff.skipTypes({tyUserTypeClassInst})
|
||||||
|
|
||||||
# var prev = PType(idTableGet(m.bindings, f))
|
|
||||||
# if prev != nil:
|
|
||||||
# if sameType(prev, a): return arg
|
|
||||||
# else: return nil
|
|
||||||
|
|
||||||
# pushInfoContext(arg.info)
|
|
||||||
openScope(c)
|
openScope(c)
|
||||||
inc c.inTypeClass
|
inc c.inTypeClass
|
||||||
|
|
||||||
|
|
@ -462,7 +477,6 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
return isGeneric
|
return isGeneric
|
||||||
# put(m.bindings, f, a)
|
|
||||||
|
|
||||||
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# typeRel can be used to establish various relationships between types:
|
# typeRel can be used to establish various relationships between types:
|
||||||
|
|
@ -1022,6 +1036,13 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
inc(m.subtypeMatches)
|
inc(m.subtypeMatches)
|
||||||
#result = copyTree(arg)
|
#result = copyTree(arg)
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||||
|
of isInferred, isInferredConvertible:
|
||||||
|
var prc = if arg.kind in nkLambdaKinds: arg[0].sym
|
||||||
|
else: arg.sym
|
||||||
|
let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
|
||||||
|
result = newSymNode(inferred, arg.info)
|
||||||
|
if r == isInferredConvertible:
|
||||||
|
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
||||||
of isGeneric:
|
of isGeneric:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
|
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
|
||||||
|
|
|
||||||
|
|
@ -441,7 +441,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
|
||||||
decodeBImm(nkIntLit)
|
decodeBImm(nkIntLit)
|
||||||
#assert regs[rb].kind == nkBracket
|
#assert regs[rb].kind == nkBracket
|
||||||
# also used by mNLen:
|
# also used by mNLen:
|
||||||
regs[ra].intVal = regs[rb].skipMeta.len - imm
|
regs[ra].intVal = regs[rb].skipMeta.safeLen - imm
|
||||||
of opcLenStr:
|
of opcLenStr:
|
||||||
decodeBImm(nkIntLit)
|
decodeBImm(nkIntLit)
|
||||||
if regs[rb].kind == nkNilLit:
|
if regs[rb].kind == nkNilLit:
|
||||||
|
|
|
||||||
|
|
@ -216,10 +216,12 @@ proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
|
||||||
internalAssert tmp >= 0
|
internalAssert tmp >= 0
|
||||||
result = TRegister(tmp)
|
result = TRegister(tmp)
|
||||||
|
|
||||||
proc clearDest(n: PNode; dest: var TDest) {.inline.} =
|
proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
|
||||||
# stmt is different from 'void' in meta programming contexts.
|
# stmt is different from 'void' in meta programming contexts.
|
||||||
# So we only set dest to -1 if 'void':
|
# So we only set dest to -1 if 'void':
|
||||||
if n.typ.isNil or n.typ.kind == tyEmpty: dest = -1
|
if dest >= 0 and (n.typ.isNil or n.typ.kind == tyEmpty):
|
||||||
|
c.freeTemp(dest)
|
||||||
|
dest = -1
|
||||||
|
|
||||||
proc isNotOpr(n: PNode): bool =
|
proc isNotOpr(n: PNode): bool =
|
||||||
n.kind in nkCallKinds and n.sons[0].kind == nkSym and
|
n.kind in nkCallKinds and n.sons[0].kind == nkSym and
|
||||||
|
|
@ -259,7 +261,7 @@ proc genWhile(c: PCtx; n: PNode) =
|
||||||
proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
|
proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
withBlock(n.sons[0].sym):
|
withBlock(n.sons[0].sym):
|
||||||
c.gen(n.sons[1], dest)
|
c.gen(n.sons[1], dest)
|
||||||
clearDest(n, dest)
|
c.clearDest(n, dest)
|
||||||
|
|
||||||
proc genBreak(c: PCtx; n: PNode) =
|
proc genBreak(c: PCtx; n: PNode) =
|
||||||
let L1 = c.xjmp(n, opcJmp)
|
let L1 = c.xjmp(n, opcJmp)
|
||||||
|
|
@ -297,14 +299,16 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
|
||||||
else:
|
else:
|
||||||
c.gen(it.sons[0], tmp)
|
c.gen(it.sons[0], tmp)
|
||||||
elsePos = c.xjmp(it.sons[0], opcFJmp, tmp) # if false
|
elsePos = c.xjmp(it.sons[0], opcFJmp, tmp) # if false
|
||||||
|
c.clearDest(n, dest)
|
||||||
c.gen(it.sons[1], dest) # then part
|
c.gen(it.sons[1], dest) # then part
|
||||||
if i < sonsLen(n)-1:
|
if i < sonsLen(n)-1:
|
||||||
endings.add(c.xjmp(it.sons[1], opcJmp, 0))
|
endings.add(c.xjmp(it.sons[1], opcJmp, 0))
|
||||||
c.patch(elsePos)
|
c.patch(elsePos)
|
||||||
else:
|
else:
|
||||||
|
c.clearDest(n, dest)
|
||||||
c.gen(it.sons[0], dest)
|
c.gen(it.sons[0], dest)
|
||||||
for endPos in endings: c.patch(endPos)
|
for endPos in endings: c.patch(endPos)
|
||||||
clearDest(n, dest)
|
c.clearDest(n, dest)
|
||||||
|
|
||||||
proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
|
proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
|
||||||
# asgn dest, a
|
# asgn dest, a
|
||||||
|
|
@ -385,8 +389,8 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
if i < sonsLen(n)-1:
|
if i < sonsLen(n)-1:
|
||||||
endings.add(c.xjmp(it.lastSon, opcJmp, 0))
|
endings.add(c.xjmp(it.lastSon, opcJmp, 0))
|
||||||
c.patch(elsePos)
|
c.patch(elsePos)
|
||||||
|
c.clearDest(n, dest)
|
||||||
for endPos in endings: c.patch(endPos)
|
for endPos in endings: c.patch(endPos)
|
||||||
clearDest(n, dest)
|
|
||||||
|
|
||||||
proc genType(c: PCtx; typ: PType): int =
|
proc genType(c: PCtx; typ: PType): int =
|
||||||
for i, t in c.types:
|
for i, t in c.types:
|
||||||
|
|
@ -400,6 +404,7 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
var endings: seq[TPosition] = @[]
|
var endings: seq[TPosition] = @[]
|
||||||
let elsePos = c.xjmp(n, opcTry, 0)
|
let elsePos = c.xjmp(n, opcTry, 0)
|
||||||
c.gen(n.sons[0], dest)
|
c.gen(n.sons[0], dest)
|
||||||
|
c.clearDest(n, dest)
|
||||||
c.patch(elsePos)
|
c.patch(elsePos)
|
||||||
for i in 1 .. <n.len:
|
for i in 1 .. <n.len:
|
||||||
let it = n.sons[i]
|
let it = n.sons[i]
|
||||||
|
|
@ -415,6 +420,7 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
# general except section:
|
# general except section:
|
||||||
c.gABx(it, opcExcept, 0, 0)
|
c.gABx(it, opcExcept, 0, 0)
|
||||||
c.gen(it.lastSon, dest)
|
c.gen(it.lastSon, dest)
|
||||||
|
c.clearDest(n, dest)
|
||||||
if i < sonsLen(n)-1:
|
if i < sonsLen(n)-1:
|
||||||
endings.add(c.xjmp(it, opcJmp, 0))
|
endings.add(c.xjmp(it, opcJmp, 0))
|
||||||
c.patch(endExcept)
|
c.patch(endExcept)
|
||||||
|
|
@ -425,8 +431,8 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
c.gABx(fin, opcFinally, 0, 0)
|
c.gABx(fin, opcFinally, 0, 0)
|
||||||
if fin.kind == nkFinally:
|
if fin.kind == nkFinally:
|
||||||
c.gen(fin.sons[0], dest)
|
c.gen(fin.sons[0], dest)
|
||||||
|
c.clearDest(n, dest)
|
||||||
c.gABx(fin, opcFinallyEnd, 0, 0)
|
c.gABx(fin, opcFinallyEnd, 0, 0)
|
||||||
clearDest(n, dest)
|
|
||||||
|
|
||||||
proc genRaise(c: PCtx; n: PNode) =
|
proc genRaise(c: PCtx; n: PNode) =
|
||||||
let dest = genx(c, n.sons[0])
|
let dest = genx(c, n.sons[0])
|
||||||
|
|
@ -860,7 +866,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
|
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
|
||||||
of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI, mAbsI64:
|
of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI, mAbsI64:
|
||||||
c.genCall(n, dest)
|
c.genCall(n, dest)
|
||||||
clearDest(n, dest)
|
|
||||||
of mExpandToAst:
|
of mExpandToAst:
|
||||||
if n.len != 2:
|
if n.len != 2:
|
||||||
globalError(n.info, errGenerated, "expandToAst requires 1 argument")
|
globalError(n.info, errGenerated, "expandToAst requires 1 argument")
|
||||||
|
|
@ -1281,7 +1286,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||||
genMagic(c, n, dest)
|
genMagic(c, n, dest)
|
||||||
else:
|
else:
|
||||||
genCall(c, n, dest)
|
genCall(c, n, dest)
|
||||||
clearDest(n, dest)
|
clearDest(c, n, dest)
|
||||||
of nkCharLit..nkInt64Lit:
|
of nkCharLit..nkInt64Lit:
|
||||||
if isInt16Lit(n):
|
if isInt16Lit(n):
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
|
|
||||||
|
|
@ -1701,11 +1701,11 @@ algorithm returns true:
|
||||||
result = isOrdinal(t) or t.kind in {float, float32, float64}
|
result = isOrdinal(t) or t.kind in {float, float32, float64}
|
||||||
|
|
||||||
proc isExplicitlyConvertible(a, b: PType): bool =
|
proc isExplicitlyConvertible(a, b: PType): bool =
|
||||||
|
result = false
|
||||||
if isImplicitlyConvertible(a, b): return true
|
if isImplicitlyConvertible(a, b): return true
|
||||||
if typeEqualsOrDistinct(a, b): return true
|
if typeEqualsOrDistinct(a, b): return true
|
||||||
if isIntegralType(a) and isIntegralType(b): return true
|
if isIntegralType(a) and isIntegralType(b): return true
|
||||||
if isSubtype(a, b) or isSubtype(b, a): return true
|
if isSubtype(a, b) or isSubtype(b, a): return true
|
||||||
return false
|
|
||||||
|
|
||||||
The convertible relation can be relaxed by a user-defined type
|
The convertible relation can be relaxed by a user-defined type
|
||||||
`converter`:idx:.
|
`converter`:idx:.
|
||||||
|
|
@ -1774,7 +1774,7 @@ Example:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc p(x, y: int): int =
|
proc p(x, y: int): int =
|
||||||
return x + y
|
result = x + y
|
||||||
|
|
||||||
discard p(3, 4) # discard the return value of `p`
|
discard p(3, 4) # discard the return value of `p`
|
||||||
|
|
||||||
|
|
@ -1789,7 +1789,7 @@ been declared with the `discardable`:idx: pragma:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc p(x, y: int): int {.discardable.} =
|
proc p(x, y: int): int {.discardable.} =
|
||||||
return x + y
|
result = x + y
|
||||||
|
|
||||||
p(3, 4) # now valid
|
p(3, 4) # now valid
|
||||||
|
|
||||||
|
|
@ -2440,7 +2440,7 @@ A procedure cannot modify its parameters (unless the parameters have the type
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc `$` (x: int): string =
|
proc `$` (x: int): string =
|
||||||
# converts an integer to a string; this is a prefix operator.
|
# converts an integer to a string; this is a prefix operator.
|
||||||
return intToStr(x)
|
result = intToStr(x)
|
||||||
|
|
||||||
Operators with one parameter are prefix operators, operators with two
|
Operators with one parameter are prefix operators, operators with two
|
||||||
parameters are infix operators. (However, the parser distinguishes these from
|
parameters are infix operators. (However, the parser distinguishes these from
|
||||||
|
|
@ -2454,7 +2454,7 @@ notation. (Thus an operator can have more than two parameters):
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc `*+` (a, b, c: int): int =
|
proc `*+` (a, b, c: int): int =
|
||||||
# Multiply and add
|
# Multiply and add
|
||||||
return a * b + c
|
result = a * b + c
|
||||||
|
|
||||||
assert `*+`(3, 4, 6) == `*`(a, `+`(b, c))
|
assert `*+`(3, 4, 6) == `*`(a, `+`(b, c))
|
||||||
|
|
||||||
|
|
@ -2500,7 +2500,7 @@ different; for this a special setter syntax is needed:
|
||||||
|
|
||||||
proc host*(s: TSocket): int {.inline.} =
|
proc host*(s: TSocket): int {.inline.} =
|
||||||
## getter of hostAddr
|
## getter of hostAddr
|
||||||
return s.FHost
|
s.FHost
|
||||||
|
|
||||||
var
|
var
|
||||||
s: TSocket
|
s: TSocket
|
||||||
|
|
@ -2650,11 +2650,12 @@ return values. This can be done in a cleaner way by returning a tuple:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc divmod(a, b: int): tuple[res, remainder: int] =
|
proc divmod(a, b: int): tuple[res, remainder: int] =
|
||||||
return (a div b, a mod b)
|
(a div b, a mod b)
|
||||||
|
|
||||||
var t = divmod(8, 5)
|
var t = divmod(8, 5)
|
||||||
|
|
||||||
assert t.res == 1
|
assert t.res == 1
|
||||||
assert t.remainder = 3
|
assert t.remainder == 3
|
||||||
|
|
||||||
One can use `tuple unpacking`:idx: to access the tuple's fields:
|
One can use `tuple unpacking`:idx: to access the tuple's fields:
|
||||||
|
|
||||||
|
|
@ -2726,7 +2727,7 @@ dispatch.
|
||||||
|
|
||||||
method eval(e: ref TPlusExpr): int =
|
method eval(e: ref TPlusExpr): int =
|
||||||
# watch out: relies on dynamic binding
|
# watch out: relies on dynamic binding
|
||||||
return eval(e.a) + eval(e.b)
|
result = eval(e.a) + eval(e.b)
|
||||||
|
|
||||||
proc newLit(x: int): ref TLiteral =
|
proc newLit(x: int): ref TLiteral =
|
||||||
new(result)
|
new(result)
|
||||||
|
|
@ -2925,7 +2926,7 @@ parameters of an outer factory proc:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc mycount(a, b: int): iterator (): int =
|
proc mycount(a, b: int): iterator (): int =
|
||||||
return iterator (): int =
|
result = iterator (): int =
|
||||||
var x = a
|
var x = a
|
||||||
while x <= b:
|
while x <= b:
|
||||||
yield x
|
yield x
|
||||||
|
|
@ -3375,9 +3376,9 @@ module to illustrate this:
|
||||||
## requires `x` and `y` to be of the same tuple type
|
## requires `x` and `y` to be of the same tuple type
|
||||||
## generic ``==`` operator for tuples that is lifted from the components
|
## generic ``==`` operator for tuples that is lifted from the components
|
||||||
## of `x` and `y`.
|
## of `x` and `y`.
|
||||||
|
result = true
|
||||||
for a, b in fields(x, y):
|
for a, b in fields(x, y):
|
||||||
if a != b: return false
|
if a != b: result = false
|
||||||
return true
|
|
||||||
|
|
||||||
Alternatively, the ``distinct`` type modifier can be applied to the type class
|
Alternatively, the ``distinct`` type modifier can be applied to the type class
|
||||||
to allow each param matching the type class to bind to a different type.
|
to allow each param matching the type class to bind to a different type.
|
||||||
|
|
@ -3999,9 +4000,9 @@ predicate:
|
||||||
|
|
||||||
proc re(pattern: semistatic[string]): TRegEx =
|
proc re(pattern: semistatic[string]): TRegEx =
|
||||||
when isStatic(pattern):
|
when isStatic(pattern):
|
||||||
return precompiledRegex(pattern)
|
result = precompiledRegex(pattern)
|
||||||
else:
|
else:
|
||||||
return compile(pattern)
|
result = compile(pattern)
|
||||||
|
|
||||||
Static params can also appear in the signatures of generic types:
|
Static params can also appear in the signatures of generic types:
|
||||||
|
|
||||||
|
|
@ -4508,7 +4509,7 @@ This is best illustrated by an example:
|
||||||
proc p*(x: A.T1): A.T1 =
|
proc p*(x: A.T1): A.T1 =
|
||||||
# this works because the compiler has already
|
# this works because the compiler has already
|
||||||
# added T1 to A's interface symbol table
|
# added T1 to A's interface symbol table
|
||||||
return x + 1
|
result = x + 1
|
||||||
|
|
||||||
|
|
||||||
Import statement
|
Import statement
|
||||||
|
|
@ -5136,6 +5137,8 @@ Example:
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
{.deadCodeElim: on.}
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
|
|
||||||
|
..
|
||||||
NoForward pragma
|
NoForward pragma
|
||||||
----------------
|
----------------
|
||||||
The `noforward`:idx: pragma can be used to turn on and off a special compilation
|
The `noforward`:idx: pragma can be used to turn on and off a special compilation
|
||||||
|
|
@ -5182,6 +5185,7 @@ Example:
|
||||||
|
|
||||||
foo(10)
|
foo(10)
|
||||||
|
|
||||||
|
|
||||||
Pragma pragma
|
Pragma pragma
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
@ -5199,7 +5203,7 @@ Example:
|
||||||
{.pragma: rtl, importc, dynlib: "client.dll", cdecl.}
|
{.pragma: rtl, importc, dynlib: "client.dll", cdecl.}
|
||||||
|
|
||||||
proc p*(a, b: int): int {.rtl.} =
|
proc p*(a, b: int): int {.rtl.} =
|
||||||
return a+b
|
result = a+b
|
||||||
|
|
||||||
In the example a new pragma named ``rtl`` is introduced that either imports
|
In the example a new pragma named ``rtl`` is introduced that either imports
|
||||||
a symbol from a dynamic library or exports the symbol for dynamic library
|
a symbol from a dynamic library or exports the symbol for dynamic library
|
||||||
|
|
|
||||||
10
doc/tut1.txt
10
doc/tut1.txt
|
|
@ -690,8 +690,8 @@ Nimrod provides the ability to overload procedures similar to C++:
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc toString(x: int): string = ...
|
proc toString(x: int): string = ...
|
||||||
proc toString(x: bool): string =
|
proc toString(x: bool): string =
|
||||||
if x: return "true"
|
if x: result = "true"
|
||||||
else: return "false"
|
else: result = "false"
|
||||||
|
|
||||||
echo(toString(13)) # calls the toString(x: int) proc
|
echo(toString(13)) # calls the toString(x: int) proc
|
||||||
echo(toString(true)) # calls the toString(x: bool) proc
|
echo(toString(true)) # calls the toString(x: bool) proc
|
||||||
|
|
@ -1569,7 +1569,7 @@ This is best illustrated by an example:
|
||||||
proc p*(x: A.T1): A.T1 =
|
proc p*(x: A.T1): A.T1 =
|
||||||
# this works because the compiler has already
|
# this works because the compiler has already
|
||||||
# added T1 to A's interface symbol table
|
# added T1 to A's interface symbol table
|
||||||
return x + 1
|
result = x + 1
|
||||||
|
|
||||||
|
|
||||||
A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. If
|
A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. If
|
||||||
|
|
@ -1600,11 +1600,11 @@ rules apply:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
# Module A
|
# Module A
|
||||||
proc x*(a: int): string = return $a
|
proc x*(a: int): string = result = $a
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
# Module B
|
# Module B
|
||||||
proc x*(a: string): string = return $a
|
proc x*(a: string): string = result = $a
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
# Module C
|
# Module C
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ The syntax for type conversions is ``destination_type(expression_to_convert)``
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
proc getID(x: TPerson): int =
|
proc getID(x: TPerson): int =
|
||||||
return TStudent(x).id
|
TStudent(x).id
|
||||||
|
|
||||||
The ``EInvalidObjectConversion`` exception is raised if ``x`` is not a
|
The ``EInvalidObjectConversion`` exception is raised if ``x`` is not a
|
||||||
``TStudent``.
|
``TStudent``.
|
||||||
|
|
@ -238,7 +238,7 @@ is needed:
|
||||||
|
|
||||||
proc host*(s: TSocket): int {.inline.} =
|
proc host*(s: TSocket): int {.inline.} =
|
||||||
## getter of hostAddr
|
## getter of hostAddr
|
||||||
return s.FHost
|
s.FHost
|
||||||
|
|
||||||
var
|
var
|
||||||
s: TSocket
|
s: TSocket
|
||||||
|
|
|
||||||
|
|
@ -241,3 +241,7 @@ proc `<=`*[A](s, t: TSet[A]): bool =
|
||||||
|
|
||||||
proc `==`*[A](s, t: TSet[A]): bool =
|
proc `==`*[A](s, t: TSet[A]): bool =
|
||||||
s.counter == t.counter and s <= t
|
s.counter == t.counter and s <= t
|
||||||
|
|
||||||
|
proc map*[A, B](data: TSet[A], op: proc (x: A): B {.closure.}): TSet[B] =
|
||||||
|
result = initSet[B]()
|
||||||
|
for item in data: result.incl(op(item))
|
||||||
|
|
|
||||||
20
tests/generics/tinferredgenericprocs.nim
Normal file
20
tests/generics/tinferredgenericprocs.nim
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
discard """
|
||||||
|
output: '''123
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# https://github.com/Araq/Nimrod/issues/797
|
||||||
|
proc foo[T](s:T):string = $s
|
||||||
|
|
||||||
|
type IntStringProc = proc(x: int): string
|
||||||
|
|
||||||
|
var f1 = IntStringProc(foo)
|
||||||
|
var f2: proc(x: int): string = foo
|
||||||
|
var f3: IntStringProc = foo
|
||||||
|
|
||||||
|
echo f1(1), f2(2), f3(3)
|
||||||
|
|
||||||
|
for x in map([1,2,3], foo): echo x
|
||||||
|
|
||||||
12
tests/sets/tsets_lt.nim
Normal file
12
tests/sets/tsets_lt.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
discard """
|
||||||
|
output: '''true
|
||||||
|
true
|
||||||
|
true'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
var s, s1: set[char]
|
||||||
|
s = {'a'..'d'}
|
||||||
|
s1 = {'a'..'c'}
|
||||||
|
echo s1 < s
|
||||||
|
echo s1 * s == {'a'..'c'}
|
||||||
|
echo s1 <= s
|
||||||
17
tests/stdlib/tsets.nim
Normal file
17
tests/stdlib/tsets.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
output: '''true
|
||||||
|
true'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sets
|
||||||
|
var
|
||||||
|
a = initSet[int]()
|
||||||
|
b = initSet[int]()
|
||||||
|
c = initSet[string]()
|
||||||
|
|
||||||
|
for i in 0..5: a.incl(i)
|
||||||
|
for i in 1..6: b.incl(i)
|
||||||
|
for i in 0..5: c.incl($i)
|
||||||
|
|
||||||
|
echo map(a, proc(x: int): int = x + 1) == b
|
||||||
|
echo map(a, proc(x: int): string = $x) == c
|
||||||
Loading…
Add table
Add a link
Reference in a new issue