Merge remote-tracking branch 'upstream/devel' into devel
This commit is contained in:
commit
50ed39fd66
129 changed files with 3195 additions and 2204 deletions
|
|
@ -196,6 +196,7 @@ type
|
|||
nkTypeOfExpr, # type(1+2)
|
||||
nkObjectTy, # object body
|
||||
nkTupleTy, # tuple body
|
||||
nkTupleClassTy, # tuple type class
|
||||
nkTypeClassTy, # user-defined type class
|
||||
nkStaticTy, # ``static[T]``
|
||||
nkRecList, # list of object parts
|
||||
|
|
@ -458,7 +459,7 @@ type
|
|||
tfNotNil, # type cannot be 'nil'
|
||||
|
||||
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
|
||||
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
||||
# or other type classes
|
||||
|
|
@ -946,10 +947,7 @@ template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
|||
n.sons[i -| n] = s
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = -1 # 884953 # 612794
|
||||
#612840 # 612905 # 614635 # 614637 # 614641
|
||||
# 423408
|
||||
#429107 # 430443 # 441048 # 441090 # 441153
|
||||
const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
|
||||
var gNodeId: int
|
||||
|
||||
proc newNode*(kind: TNodeKind): PNode =
|
||||
|
|
@ -1320,7 +1318,7 @@ proc isGCedMem*(t: PType): bool {.inline.} =
|
|||
t.kind == tyProc and t.callConv == ccClosure
|
||||
|
||||
proc propagateToOwner*(owner, elem: PType) =
|
||||
const HaveTheirOwnEmpty = {tySequence, tySet}
|
||||
const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc}
|
||||
owner.flags = owner.flags + (elem.flags * {tfHasMeta})
|
||||
if tfNotNil in elem.flags:
|
||||
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
|
||||
|
|
|
|||
|
|
@ -203,9 +203,9 @@ proc mustRehash(length, counter: int): bool =
|
|||
assert(length > counter)
|
||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||
|
||||
proc spaces(x: int): PRope =
|
||||
proc rspaces(x: int): PRope =
|
||||
# returns x spaces
|
||||
result = toRope(repeatChar(x))
|
||||
result = toRope(spaces(x))
|
||||
|
||||
proc toYamlChar(c: char): string =
|
||||
case c
|
||||
|
|
@ -253,7 +253,7 @@ proc typeToYamlAux(n: PType, marker: var IntSet,
|
|||
indent, maxRecDepth: int): PRope
|
||||
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
var istr = spaces(indent + 2)
|
||||
var istr = rspaces(indent + 2)
|
||||
result = toRope("[")
|
||||
var mycount = 0
|
||||
for i in countup(0, high(n.data)):
|
||||
|
|
@ -262,20 +262,20 @@ proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
|||
appf(result, "$N$1$2",
|
||||
[istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
|
||||
inc(mycount)
|
||||
if mycount > 0: appf(result, "$N$1", [spaces(indent)])
|
||||
if mycount > 0: appf(result, "$N$1", [rspaces(indent)])
|
||||
app(result, "]")
|
||||
assert(mycount == n.counter)
|
||||
|
||||
proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
|
||||
# array of (name, value) pairs
|
||||
var istr = spaces(indent + 2)
|
||||
var istr = rspaces(indent + 2)
|
||||
result = toRope("{")
|
||||
var i = 0
|
||||
while i <= high(c):
|
||||
if i > 0: app(result, ",")
|
||||
appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
|
||||
inc(i, 2)
|
||||
appf(result, "$N$1}", [spaces(indent)])
|
||||
appf(result, "$N$1}", [rspaces(indent)])
|
||||
|
||||
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
|
||||
maxRecDepth: int): PRope =
|
||||
|
|
@ -310,9 +310,9 @@ proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
|
|||
result = toRope("[")
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if i > 0: app(result, ",")
|
||||
appf(result, "$N$1$2", [spaces(indent + 4), typeToYamlAux(n.sons[i],
|
||||
appf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i],
|
||||
marker, indent + 4, maxRecDepth - 1)])
|
||||
appf(result, "$N$1]", [spaces(indent + 2)])
|
||||
appf(result, "$N$1]", [rspaces(indent + 2)])
|
||||
else:
|
||||
result = toRope("null")
|
||||
result = ropeConstr(indent, [toRope("kind"),
|
||||
|
|
@ -331,7 +331,7 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
|
|||
if n == nil:
|
||||
result = toRope("null")
|
||||
else:
|
||||
var istr = spaces(indent + 2)
|
||||
var istr = rspaces(indent + 2)
|
||||
result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
|
||||
if maxRecDepth != 0:
|
||||
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
||||
|
|
@ -359,12 +359,12 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
|
|||
appf(result, ",$N$1\"sons\": [", [istr])
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if i > 0: app(result, ",")
|
||||
appf(result, "$N$1$2", [spaces(indent + 4), treeToYamlAux(n.sons[i],
|
||||
appf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i],
|
||||
marker, indent + 4, maxRecDepth - 1)])
|
||||
appf(result, "$N$1]", [istr])
|
||||
appf(result, ",$N$1\"typ\": $2",
|
||||
[istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
|
||||
appf(result, "$N$1}", [spaces(indent)])
|
||||
appf(result, "$N$1}", [rspaces(indent)])
|
||||
|
||||
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||
var marker = initIntSet()
|
||||
|
|
@ -408,7 +408,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
|||
if n == nil:
|
||||
result = toRope("null")
|
||||
else:
|
||||
var istr = spaces(indent + 2)
|
||||
var istr = rspaces(indent + 2)
|
||||
result = ropef("{$N$1\"kind\": $2",
|
||||
[istr, makeYamlString($n.kind)])
|
||||
if maxRecDepth != 0:
|
||||
|
|
@ -440,11 +440,11 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
|||
appf(result, ",$N$1\"sons\": [", [istr])
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if i > 0: app(result, ",")
|
||||
appf(result, "$N$1$2", [spaces(indent + 4), debugTree(n.sons[i],
|
||||
appf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i],
|
||||
indent + 4, maxRecDepth - 1, renderType)])
|
||||
appf(result, "$N$1]", [istr])
|
||||
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
||||
appf(result, "$N$1}", [spaces(indent)])
|
||||
appf(result, "$N$1}", [rspaces(indent)])
|
||||
|
||||
proc debug(n: PSym) =
|
||||
if n == nil:
|
||||
|
|
@ -681,9 +681,8 @@ proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
|
|||
else: result = nextIdentIter(ti, tab)
|
||||
|
||||
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
||||
var h, start: THash
|
||||
h = ti.h and high(tab.data)
|
||||
start = h
|
||||
var h = ti.h and high(tab.data)
|
||||
var start = h
|
||||
result = tab.data[h]
|
||||
while result != nil:
|
||||
if result.name.id == ti.name.id: break
|
||||
|
|
|
|||
|
|
@ -339,7 +339,8 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
|||
let typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||
if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
|
||||
result.app(~"(")
|
||||
result.app genOtherArg(p, ri, 1, typ)
|
||||
if 1 < ri.len:
|
||||
result.app genOtherArg(p, ri, 1, typ)
|
||||
for k in j+1 .. < ri.len:
|
||||
result.app(~", ")
|
||||
result.app genOtherArg(p, ri, k, typ)
|
||||
|
|
|
|||
|
|
@ -56,11 +56,6 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
|
|||
case skipTypes(ty, abstractVarRange).kind
|
||||
of tyChar, tyNil:
|
||||
result = intLiteral(n.intVal)
|
||||
of tyInt:
|
||||
if n.intVal >= low(int32) and n.intVal <= high(int32):
|
||||
result = int32Literal(int32(n.intVal))
|
||||
else:
|
||||
result = intLiteral(n.intVal)
|
||||
of tyBool:
|
||||
if n.intVal != 0: result = ~"NIM_TRUE"
|
||||
else: result = ~"NIM_FALSE"
|
||||
|
|
@ -954,7 +949,7 @@ proc genEcho(p: BProc, n: PNode) =
|
|||
initLocExpr(p, n.sons[i], a)
|
||||
appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
|
||||
linefmt(p, cpsStmts, "printf($1$2);$n",
|
||||
makeCString(repeatStr(n.len, "%s") & tnl), args)
|
||||
makeCString(repeat("%s", n.len) & tnl), args)
|
||||
|
||||
proc gcUsage(n: PNode) =
|
||||
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ proc getUniqueType*(key: PType): PType =
|
|||
gCanonicalTypes[k] = key
|
||||
result = key
|
||||
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
|
||||
internalError("GetUniqueType")
|
||||
internalError("getUniqueType")
|
||||
of tyDistinct:
|
||||
if key.deepCopy != nil: result = key
|
||||
else: result = getUniqueType(lastSon(key))
|
||||
|
|
@ -135,7 +135,7 @@ proc getUniqueType*(key: PType): PType =
|
|||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
for h in countup(0, high(gTypeTable[k].data)):
|
||||
var t = PType(gTypeTable[k].data[h].key)
|
||||
if t != nil and sameType(t, key):
|
||||
if t != nil and sameBackendType(t, key):
|
||||
return t
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
|
|||
let field = getField(typ.n, i)
|
||||
pack(it, field.typ, res +! field.offset)
|
||||
else:
|
||||
# XXX: todo
|
||||
globalError(x.info, "cannot pack unnamed tuple")
|
||||
|
||||
const maxPackDepth = 20
|
||||
|
|
|
|||
|
|
@ -572,6 +572,9 @@ proc footprint(filename: string): TCrc32 =
|
|||
getCompileCFileCmd(filename, true)
|
||||
|
||||
proc externalFileChanged(filename: string): bool =
|
||||
if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
|
||||
return false
|
||||
|
||||
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
||||
var currentCrc = int(footprint(filename))
|
||||
var f: File
|
||||
|
|
|
|||
|
|
@ -37,11 +37,11 @@ const
|
|||
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
|
||||
|
||||
proc newLine(p: var TTmplParser) =
|
||||
llStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
|
||||
llStreamWrite(p.outp, repeat(')', p.emitPar))
|
||||
p.emitPar = 0
|
||||
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
|
||||
if p.pendingExprLine:
|
||||
llStreamWrite(p.outp, repeatChar(2))
|
||||
llStreamWrite(p.outp, spaces(2))
|
||||
p.pendingExprLine = false
|
||||
|
||||
proc scanPar(p: var TTmplParser, d: int) =
|
||||
|
|
@ -88,24 +88,24 @@ proc parseLine(p: var TTmplParser) =
|
|||
else:
|
||||
p.info.col = int16(j)
|
||||
localError(p.info, errXNotAllowedHere, "end")
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, "#end")
|
||||
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
|
||||
wConverter, wMacro, wTemplate, wMethod:
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
inc(p.indent, 2)
|
||||
of wElif, wOf, wElse, wExcept, wFinally:
|
||||
llStreamWrite(p.outp, repeatChar(p.indent - 2))
|
||||
llStreamWrite(p.outp, spaces(p.indent - 2))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
of wLet, wVar, wConst, wType:
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
if not p.x.contains({':', '='}):
|
||||
# no inline element --> treat as block:
|
||||
inc(p.indent, 2)
|
||||
else:
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, substr(p.x, d))
|
||||
p.state = psDirective
|
||||
else:
|
||||
|
|
@ -120,11 +120,11 @@ proc parseLine(p: var TTmplParser) =
|
|||
# next line of string literal:
|
||||
llStreamWrite(p.outp, p.conc)
|
||||
llStreamWrite(p.outp, "\n")
|
||||
llStreamWrite(p.outp, repeatChar(p.indent + 2))
|
||||
llStreamWrite(p.outp, spaces(p.indent + 2))
|
||||
llStreamWrite(p.outp, "\"")
|
||||
of psDirective:
|
||||
newLine(p)
|
||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
||||
llStreamWrite(p.outp, spaces(p.indent))
|
||||
llStreamWrite(p.outp, p.emit)
|
||||
llStreamWrite(p.outp, "(\"")
|
||||
inc(p.emitPar)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ proc getModuleName*(n: PNode): string =
|
|||
result = n.ident.s
|
||||
of nkSym:
|
||||
result = n.sym.name.s
|
||||
of nkInfix:
|
||||
of nkInfix, nkPrefix:
|
||||
if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
|
||||
# XXX hack ahead:
|
||||
n.kind = nkImportAs
|
||||
|
|
|
|||
|
|
@ -780,7 +780,7 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
|||
moveInto(p, stmt, r)
|
||||
appf(p.body, "}$n" | "end$n")
|
||||
if p.target == targetJS:
|
||||
app(p.body, repeatChar(toClose, '}') & tnl)
|
||||
app(p.body, repeat('}', toClose) & tnl)
|
||||
else:
|
||||
for i in 1..toClose: appf(p.body, "end$n")
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ proc llStreamOpen*(data: string): PLLStream =
|
|||
result.s = data
|
||||
result.kind = llsString
|
||||
|
||||
proc llStreamOpen*(f: var File): PLLStream =
|
||||
proc llStreamOpen*(f: File): PLLStream =
|
||||
new(result)
|
||||
result.f = f
|
||||
result.kind = llsFile
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
|||
if sfExported in sym.flags:
|
||||
# add to interface:
|
||||
if c.module != nil: strTableAdd(c.module.tab, sym)
|
||||
else: internalError(sym.info, "AddInterfaceDeclAux")
|
||||
else: internalError(sym.info, "addInterfaceDeclAux")
|
||||
|
||||
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||
addDeclAt(scope, sym)
|
||||
|
|
|
|||
|
|
@ -117,7 +117,8 @@ type
|
|||
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
||||
warnEachIdentIsTuple, warnShadowIdent,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnUser,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||
warnUser,
|
||||
hintSuccess, hintSuccessX,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
|
|
@ -391,6 +392,7 @@ const
|
|||
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
|
||||
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
|
||||
warnLockLevel: "$1 [LockLevel]",
|
||||
warnResultShadowed: "Special variable 'result' is shadowed. [ResultShadowed]",
|
||||
warnUser: "$1 [User]",
|
||||
hintSuccess: "operation successful [Success]",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
|
||||
|
|
@ -411,7 +413,7 @@ const
|
|||
hintUser: "$1 [User]"]
|
||||
|
||||
const
|
||||
WarningsToStr*: array[0..29, string] = ["CannotOpenFile", "OctalEscape",
|
||||
WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape",
|
||||
"XIsNeverRead", "XmightNotBeenInit",
|
||||
"Deprecated", "ConfigDeprecated",
|
||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||
|
|
@ -421,7 +423,7 @@ const
|
|||
"TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
|
||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "User"]
|
||||
"GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
|
||||
|
||||
HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
|
|
@ -784,7 +786,7 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
|
|||
proc writeSurroundingSrc(info: TLineInfo) =
|
||||
const indent = " "
|
||||
msgWriteln(indent & info.sourceLine.ropeToStr)
|
||||
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
|
||||
msgWriteln(indent & spaces(info.col) & '^')
|
||||
|
||||
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||
let frmt = case msg
|
||||
|
|
|
|||
|
|
@ -18,3 +18,4 @@ define:useStdoutAsStdmsg
|
|||
cs:partial
|
||||
#define:useNodeIds
|
||||
symbol:nimfix
|
||||
#gc:markAndSweep
|
||||
|
|
|
|||
|
|
@ -166,4 +166,4 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
|
|||
inc(i)
|
||||
result.add("\n")
|
||||
if marker:
|
||||
result.add(repeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")
|
||||
result.add(spaces(getColNumber(L, L.bufpos)) & '^' & "\n")
|
||||
|
|
|
|||
|
|
@ -865,6 +865,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
|||
#| [' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
||||
#| extTupleDecl = 'tuple'
|
||||
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
||||
#| tupleClass = 'tuple'
|
||||
result = newNodeP(nkTupleTy, p)
|
||||
getTok(p)
|
||||
if p.tok.tokType == tkBracketLe:
|
||||
|
|
@ -894,6 +895,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
|||
parMessage(p, errIdentifierExpected, p.tok)
|
||||
break
|
||||
if not sameInd(p): break
|
||||
else:
|
||||
result = newNodeP(nkTupleClassTy, p)
|
||||
|
||||
proc parseParamList(p: var TParser, retColon = true): PNode =
|
||||
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
|||
let filename = fileIdx.toFullPathConsiderDirty
|
||||
if module.name.s == "-":
|
||||
module.name.s = "stdinfile"
|
||||
s = llStreamOpenStdIn()
|
||||
s = llStreamOpen(stdin)
|
||||
else:
|
||||
s = llStreamOpen(filename, fmRead)
|
||||
if s == nil:
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
|
|||
|
||||
proc addPendingNL(g: var TSrcGen) =
|
||||
if g.pendingNL >= 0:
|
||||
addTok(g, tkSpaces, "\n" & repeatChar(g.pendingNL))
|
||||
addTok(g, tkSpaces, "\n" & spaces(g.pendingNL))
|
||||
g.lineLen = g.pendingNL
|
||||
g.pendingNL = - 1
|
||||
|
||||
|
|
@ -190,7 +190,7 @@ proc putComment(g: var TSrcGen, s: string) =
|
|||
if not isCode and (g.lineLen + (j - i) > MaxLineLen):
|
||||
put(g, tkComment, com)
|
||||
optNL(g, ind)
|
||||
com = '#' & repeatChar(comIndent)
|
||||
com = '#' & spaces(comIndent)
|
||||
while s[i] > ' ':
|
||||
add(com, s[i])
|
||||
inc(i)
|
||||
|
|
@ -280,7 +280,7 @@ proc gcom(g: var TSrcGen, n: PNode) =
|
|||
(g.lineLen < LineCommentColumn):
|
||||
var ml = maxLineLength(n.comment)
|
||||
if ml + LineCommentColumn <= MaxLineLen:
|
||||
put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen))
|
||||
put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen))
|
||||
putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
|
||||
|
||||
proc gcoms(g: var TSrcGen) =
|
||||
|
|
@ -395,6 +395,7 @@ proc lsub(n: PNode): int =
|
|||
of nkClosedSymChoice, nkOpenSymChoice:
|
||||
result = lsons(n) + len("()") + sonsLen(n) - 1
|
||||
of nkTupleTy: result = lcomma(n) + len("tuple[]")
|
||||
of nkTupleClassTy: result = len("tuple")
|
||||
of nkDotExpr: result = lsons(n) + 1
|
||||
of nkBind: result = lsons(n) + len("bind_")
|
||||
of nkBindStmt: result = lcomma(n) + len("bind_")
|
||||
|
|
@ -1292,10 +1293,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
|||
gsub(g, n.sons[0])
|
||||
of nkTupleTy:
|
||||
put(g, tkTuple, "tuple")
|
||||
if sonsLen(n) > 0:
|
||||
put(g, tkBracketLe, "[")
|
||||
gcomma(g, n)
|
||||
put(g, tkBracketRi, "]")
|
||||
put(g, tkBracketLe, "[")
|
||||
gcomma(g, n)
|
||||
put(g, tkBracketRi, "]")
|
||||
of nkTupleClassTy:
|
||||
put(g, tkTuple, "tuple")
|
||||
of nkMetaNode_Obsolete:
|
||||
put(g, tkParLe, "(META|")
|
||||
gsub(g, n.sons[0])
|
||||
|
|
|
|||
|
|
@ -41,48 +41,55 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
|||
best, alt: var TCandidate,
|
||||
errors: var CandidateErrors) =
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, headSymbol)
|
||||
var symScope = o.lastOverloadScope
|
||||
# thanks to the lazy semchecking for operands, we need to iterate over the
|
||||
# symbol table *before* any call to 'initCandidate' which might invoke
|
||||
# semExpr which might modify the symbol table in cases like
|
||||
# 'init(a, 1, (var b = new(Type2); b))'.
|
||||
var symx = initOverloadIter(o, c, headSymbol)
|
||||
let symScope = o.lastOverloadScope
|
||||
|
||||
var syms: seq[tuple[a: PSym, b: int]] = @[]
|
||||
while symx != nil:
|
||||
if symx.kind in filter: syms.add((symx, o.lastOverloadScope))
|
||||
symx = nextOverloadIter(o, c, headSymbol)
|
||||
if syms.len == 0: return
|
||||
|
||||
var z: TCandidate
|
||||
|
||||
if sym == nil: return
|
||||
initCandidate(c, best, sym, initialBinding, symScope)
|
||||
initCandidate(c, alt, sym, initialBinding, symScope)
|
||||
initCandidate(c, best, syms[0][0], initialBinding, symScope)
|
||||
initCandidate(c, alt, syms[0][0], initialBinding, symScope)
|
||||
best.state = csNoMatch
|
||||
|
||||
while sym != nil:
|
||||
if sym.kind in filter:
|
||||
determineType(c, sym)
|
||||
initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
|
||||
z.calleeSym = sym
|
||||
for i in 0 .. <syms.len:
|
||||
let sym = syms[i][0]
|
||||
determineType(c, sym)
|
||||
initCandidate(c, z, sym, initialBinding, syms[i][1])
|
||||
z.calleeSym = sym
|
||||
|
||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
||||
# gDebug = true
|
||||
matches(c, n, orig, z)
|
||||
if errors != nil:
|
||||
errors.safeAdd(sym)
|
||||
if z.errors != nil:
|
||||
for err in z.errors:
|
||||
errors.add(err)
|
||||
if z.state == csMatch:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
||||
case best.state
|
||||
of csEmpty, csNoMatch: best = z
|
||||
of csMatch:
|
||||
var cmp = cmpCandidates(best, z)
|
||||
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
|
||||
else: discard
|
||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
||||
# echo "Matches ", n.info, " ", typeToString(sym.typ)
|
||||
# debug sym
|
||||
# writeMatches(z)
|
||||
# for i in 1 .. <len(z.call):
|
||||
# z.call[i].typ.debug
|
||||
# quit 1
|
||||
sym = nextOverloadIter(o, c, headSymbol)
|
||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
||||
# gDebug = true
|
||||
matches(c, n, orig, z)
|
||||
if errors != nil:
|
||||
errors.safeAdd(sym)
|
||||
if z.errors != nil:
|
||||
for err in z.errors:
|
||||
errors.add(err)
|
||||
if z.state == csMatch:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
||||
case best.state
|
||||
of csEmpty, csNoMatch: best = z
|
||||
of csMatch:
|
||||
var cmp = cmpCandidates(best, z)
|
||||
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
|
||||
else: discard
|
||||
#if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516:
|
||||
# echo "Matches ", n.info, " ", typeToString(sym.typ)
|
||||
# debug sym
|
||||
# writeMatches(z)
|
||||
# for i in 1 .. <len(z.call):
|
||||
# z.call[i].typ.debug
|
||||
# quit 1
|
||||
|
||||
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||
|
|
|
|||
|
|
@ -1866,6 +1866,14 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
addSonSkipIntLit(typ, n.sons[i].typ)
|
||||
result.typ = typ
|
||||
|
||||
proc isTupleType(n: PNode): bool =
|
||||
if n.len == 0:
|
||||
return false # don't interpret () as type
|
||||
for i in countup(0, n.len - 1):
|
||||
if n[i].typ == nil or n[i].typ.kind != tyTypeDesc:
|
||||
return false
|
||||
return true
|
||||
|
||||
proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
|
||||
case n.kind
|
||||
of nkRecList:
|
||||
|
|
@ -2055,7 +2063,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
of nkBind:
|
||||
message(n.info, warnDeprecated, "bind")
|
||||
result = semExpr(c, n.sons[0], flags)
|
||||
of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy, nkStaticTy:
|
||||
of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy:
|
||||
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
#result = symNodeFromType(c, typ, n.info)
|
||||
|
|
@ -2129,7 +2137,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
of nkPar:
|
||||
case checkPar(n)
|
||||
of paNone: result = errorNode(c, n)
|
||||
of paTuplePositions: result = semTuplePositionsConstr(c, n, flags)
|
||||
of paTuplePositions:
|
||||
var tupexp = semTuplePositionsConstr(c, n, flags)
|
||||
if isTupleType(tupexp):
|
||||
# reinterpret as type
|
||||
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
|
||||
result.typ = makeTypeDesc(c, typ)
|
||||
else:
|
||||
result = tupexp
|
||||
of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
|
||||
of paSingle: result = semExpr(c, n.sons[0], flags)
|
||||
of nkCurly: result = semSetConstr(c, n)
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
|||
of nkIdent: a = n.sons[i]
|
||||
else: illFormedAst(n)
|
||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
||||
of nkObjectTy, nkTupleTy:
|
||||
of nkObjectTy, nkTupleTy, nkTupleClassTy:
|
||||
discard
|
||||
of nkFormalParams:
|
||||
checkMinSonsLen(n, 1)
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
|
|||
if g.kind == skUnknown:
|
||||
var field: PSym = nil
|
||||
var ty = n.sons[0].typ.skipTypes(abstractPtrs)
|
||||
if ty.kind == tyTuple:
|
||||
if ty.kind == tyTuple and not ty.n.isNil:
|
||||
field = lookupInRecord(ty.n, g.name)
|
||||
else:
|
||||
while ty != nil and ty.kind == tyObject:
|
||||
|
|
|
|||
|
|
@ -400,6 +400,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
elif tup.kind == tyTuple and def.kind == nkPar and
|
||||
a.kind == nkIdentDefs and a.len > 3:
|
||||
message(a.info, warnEachIdentIsTuple)
|
||||
|
||||
for j in countup(0, length-3):
|
||||
var v = semIdentDef(c, a.sons[j], symkind)
|
||||
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
||||
|
|
@ -409,6 +410,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
|||
let shadowed = findShadowedVar(c, v)
|
||||
if shadowed != nil:
|
||||
shadowed.flags.incl(sfShadowed)
|
||||
if shadowed.kind == skResult:
|
||||
message(a.info, warnResultShadowed)
|
||||
# a shadowed variable is an error unless it appears on the right
|
||||
# side of the '=':
|
||||
if warnShadowIdent in gNotes and not identWithin(def, v.name):
|
||||
|
|
@ -692,7 +695,7 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
|
|||
assignType(s.typ, t)
|
||||
s.typ.id = t.id # same id
|
||||
checkConstructedType(s.info, s.typ)
|
||||
if s.typ.kind in {tyObject, tyTuple}:
|
||||
if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
|
||||
checkForMetaFields(s.typ.n)
|
||||
let aa = a.sons[2]
|
||||
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
|
||||
|
|
@ -786,7 +789,8 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
|||
result = semStmt(c, x)
|
||||
# since a proc annotation can set pragmas, we process these here again.
|
||||
# This is required for SqueakNim-like export pragmas.
|
||||
if result[namePos].kind == nkSym and result[pragmasPos].kind != nkEmpty:
|
||||
if result.kind in procDefs and result[namePos].kind == nkSym and
|
||||
result[pragmasPos].kind != nkEmpty:
|
||||
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -345,8 +345,14 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
|||
localError(n.info, errIdentifierExpected)
|
||||
result = errorSym(c, n)
|
||||
|
||||
proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
if sonsLen(n) == 0:
|
||||
localError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyTuple, prev, c)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
addSonSkipIntLit(result, semTypeNode(c, n.sons[i], nil))
|
||||
|
||||
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
if n.sonsLen == 0: return newConstraint(c, tyTuple)
|
||||
var typ: PType
|
||||
result = newOrPrevType(tyTuple, prev, c)
|
||||
result.n = newNodeI(nkRecList, n.info)
|
||||
|
|
@ -1117,9 +1123,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
of nkPar:
|
||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||
else:
|
||||
# XXX support anon tuple here
|
||||
localError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
result = semAnonTuple(c, n, prev)
|
||||
of nkCallKinds:
|
||||
if isRange(n):
|
||||
result = semRangeAux(c, n, prev)
|
||||
|
|
@ -1227,6 +1231,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
|||
result = newOrPrevType(tyError, prev, c)
|
||||
of nkObjectTy: result = semObjectNode(c, n, prev)
|
||||
of nkTupleTy: result = semTuple(c, n, prev)
|
||||
of nkTupleClassTy: result = newConstraint(c, tyTuple)
|
||||
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
||||
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
||||
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
||||
|
|
|
|||
|
|
@ -341,6 +341,8 @@ proc skipIntLiteralParams*(t: PType) =
|
|||
proc propagateFieldFlags(t: PType, n: PNode) =
|
||||
# This is meant for objects and tuples
|
||||
# The type must be fully instantiated!
|
||||
if n.isNil:
|
||||
return
|
||||
internalAssert n.kind != nkRecWhen
|
||||
case n.kind
|
||||
of nkSym:
|
||||
|
|
|
|||
|
|
@ -157,17 +157,40 @@ proc sumGeneric(t: PType): int =
|
|||
result = ord(t.kind == tyGenericInvocation)
|
||||
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
||||
break
|
||||
of tyProc:
|
||||
# proc matches proc better than 'stmt' to disambiguate 'spawn'
|
||||
return 1
|
||||
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
|
||||
|
||||
#var ggDebug: bool
|
||||
|
||||
proc complexDisambiguation(a, b: PType): int =
|
||||
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
|
||||
# 'a' matches better if *every* argument matches better or equal than 'b'.
|
||||
var winner = 0
|
||||
for i in 1 .. <min(a.len, b.len):
|
||||
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:
|
||||
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 =
|
||||
result = isNone
|
||||
if sameType(f, a): result = isEqual
|
||||
if sameType(f, a):
|
||||
result = isEqual
|
||||
elif sonsLen(a) == sonsLen(f):
|
||||
result = isEqual
|
||||
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
|
||||
return isNone
|
||||
let reverseRel = typeRel(c, a, f)
|
||||
if reverseRel == isGeneric:
|
||||
if reverseRel >= isGeneric:
|
||||
result = isInferred
|
||||
inc c.genericMatches
|
||||
#inc c.genericMatches
|
||||
else:
|
||||
result = typeRel(c, f, a)
|
||||
|
||||
if result <= isSubtype or inconsistentVarTypes(f, a):
|
||||
result = isNone
|
||||
|
||||
if result == isEqual:
|
||||
inc c.exactMatches
|
||||
#if result == isEqual:
|
||||
# inc c.exactMatches
|
||||
|
||||
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
case a.kind
|
||||
|
|
@ -433,6 +457,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
|||
return isNone
|
||||
when useEffectSystem:
|
||||
if not compatibleEffects(f, a): return isNone
|
||||
|
||||
of tyNil:
|
||||
result = f.allowsNil
|
||||
of tyIter:
|
||||
|
|
@ -590,10 +615,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
return typeRel(c, f, lastSon(a))
|
||||
|
||||
template bindingRet(res) =
|
||||
when res == isGeneric:
|
||||
if doBind:
|
||||
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
||||
if doBind: put(c.bindings, f, bound)
|
||||
if doBind:
|
||||
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
||||
if doBind: put(c.bindings, f, bound)
|
||||
return res
|
||||
|
||||
template considerPreviousT(body: stmt) {.immediate.} =
|
||||
|
|
@ -605,20 +629,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
of tyOr:
|
||||
# seq[int|string] vs seq[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:
|
||||
if typeRel(c, f, branch, false) == isNone:
|
||||
return isNone
|
||||
|
||||
return isGeneric
|
||||
let x = typeRel(c, f, branch, false)
|
||||
if x == isNone: return isNone
|
||||
if x < result: result = x
|
||||
|
||||
of tyAnd:
|
||||
# seq[Sortable and Iterable] vs seq[Sortable]
|
||||
# only one match is enough
|
||||
for branch in a.sons:
|
||||
if typeRel(c, f, branch, false) != isNone:
|
||||
return isGeneric
|
||||
|
||||
return isNone
|
||||
let x = typeRel(c, f, branch, false)
|
||||
if x != isNone:
|
||||
return if x >= isGeneric: isGeneric else: x
|
||||
result = isNone
|
||||
|
||||
of tyNot:
|
||||
case f.kind
|
||||
|
|
@ -781,11 +806,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
inc(c.inheritancePenalty, depth)
|
||||
result = isSubtype
|
||||
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)
|
||||
of 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
|
||||
else:
|
||||
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)
|
||||
if result == isNone: return
|
||||
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
|
||||
else:
|
||||
result = typeRel(c, lastSon(f), a)
|
||||
|
|
@ -904,18 +929,23 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
of tyAnd:
|
||||
considerPreviousT:
|
||||
for branch in f.sons:
|
||||
if typeRel(c, branch, aOrig) < isSubtype:
|
||||
return isNone
|
||||
|
||||
bindingRet isGeneric
|
||||
let x = typeRel(c, branch, aOrig)
|
||||
if x < isSubtype: return isNone
|
||||
# 'and' implies minimum matching result:
|
||||
if x < result: result = x
|
||||
bindingRet result
|
||||
|
||||
of tyOr:
|
||||
considerPreviousT:
|
||||
result = isNone
|
||||
for branch in f.sons:
|
||||
if typeRel(c, branch, aOrig) >= isSubtype:
|
||||
bindingRet isGeneric
|
||||
|
||||
return isNone
|
||||
let x = typeRel(c, branch, aOrig)
|
||||
# 'or' implies maximum matching result:
|
||||
if x > result: result = x
|
||||
if result >= isSubtype:
|
||||
bindingRet result
|
||||
else:
|
||||
result = isNone
|
||||
|
||||
of tyNot:
|
||||
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
|
||||
c.typedescMatched = true
|
||||
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
|
||||
if result > isGeneric: result = isGeneric
|
||||
else:
|
||||
result = isNone
|
||||
else:
|
||||
|
|
@ -998,12 +1029,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
|||
return isNone
|
||||
if doBind:
|
||||
put(c.bindings, f, concrete)
|
||||
elif result > isGeneric:
|
||||
result = isGeneric
|
||||
elif a.kind == tyEmpty:
|
||||
result = isGeneric
|
||||
elif x.kind == tyGenericParam:
|
||||
result = isGeneric
|
||||
else:
|
||||
result = typeRel(c, x, a) # check if it fits
|
||||
if result > isGeneric: result = isGeneric
|
||||
|
||||
of tyStatic:
|
||||
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 isSubtype, isSubrange: inc(m.subtypeMatches)
|
||||
of isGeneric, isInferred: inc(m.genericMatches)
|
||||
of isInferredConvertible: inc(m.genericMatches); inc(m.convMatches)
|
||||
of isFromIntLit: inc(m.intConvMatches, 256)
|
||||
of isInferredConvertible:
|
||||
inc(m.convMatches)
|
||||
of isEqual: inc(m.exactMatches)
|
||||
of isNone: discard
|
||||
|
||||
|
|
@ -1232,7 +1267,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
elif f.kind == tyStatic:
|
||||
return arg.typ.n
|
||||
else:
|
||||
return argOrig
|
||||
return argSemantized # argOrig
|
||||
|
||||
if r != isNone and f.isInlineIterator:
|
||||
var inlined = newTypeS(tyStatic, c)
|
||||
|
|
@ -1244,21 +1279,22 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
case r
|
||||
of isConvertible:
|
||||
inc(m.convMatches)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isIntConv:
|
||||
# I'm too lazy to introduce another ``*matches`` field, so we conflate
|
||||
# ``isIntConv`` and ``isIntLit`` here:
|
||||
inc(m.intConvMatches)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isSubtype:
|
||||
inc(m.subtypeMatches)
|
||||
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
||||
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||
of isSubrange:
|
||||
inc(m.subtypeMatches)
|
||||
#result = copyTree(arg)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
if f.kind == tyVar:
|
||||
result = arg
|
||||
else:
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isInferred, isInferredConvertible:
|
||||
inc(m.genericMatches)
|
||||
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
|
||||
result = c.semInferredLambda(c, m.bindings, arg)
|
||||
else:
|
||||
|
|
@ -1267,41 +1303,35 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
|||
if r == isInferredConvertible:
|
||||
inc(m.convMatches)
|
||||
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
||||
else:
|
||||
inc(m.genericMatches)
|
||||
of isGeneric:
|
||||
inc(m.genericMatches)
|
||||
when true:
|
||||
if skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
elif arg.typ != nil and arg.typ.isEmptyContainer:
|
||||
result = arg.copyTree
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
else:
|
||||
result = arg
|
||||
else:
|
||||
# XXX Why is this ever necessary? arg's type should not be retrofitted
|
||||
# to match formal's type in this way!
|
||||
result = copyTree(arg)
|
||||
if arg.typ == nil:
|
||||
result = arg
|
||||
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
elif arg.typ.isEmptyContainer:
|
||||
result = arg.copyTree
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
# BUG: f may not be the right key!
|
||||
if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
# BUGFIX: use ``result.typ`` and not `f` here
|
||||
else:
|
||||
result = arg
|
||||
of isFromIntLit:
|
||||
# too lazy to introduce another ``*matches`` field, so we conflate
|
||||
# ``isIntConv`` and ``isIntLit`` here:
|
||||
inc(m.intConvMatches, 256)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isEqual:
|
||||
inc(m.exactMatches)
|
||||
result = copyTree(arg)
|
||||
result = arg
|
||||
if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
of isNone:
|
||||
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
||||
if a.kind in {tyProxy, tyUnknown}:
|
||||
inc(m.genericMatches)
|
||||
m.fauxMatch = a.kind
|
||||
return copyTree(arg)
|
||||
return arg
|
||||
result = userConvMatch(c, m, f, a, arg)
|
||||
# check for a base type match, which supports varargs[T] without []
|
||||
# constructor in a call:
|
||||
|
|
@ -1340,7 +1370,16 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
|||
for i in countup(0, sonsLen(arg) - 1):
|
||||
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
|
||||
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)
|
||||
#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:
|
||||
case x.state
|
||||
of csEmpty, csNoMatch:
|
||||
|
|
@ -1653,7 +1692,7 @@ tests:
|
|||
|
||||
setup:
|
||||
var c: TCandidate
|
||||
InitCandidate(nil, c, nil)
|
||||
initCandidate(nil, c, nil)
|
||||
|
||||
template yes(x, y) =
|
||||
test astToStr(x) & " is " & astToStr(y):
|
||||
|
|
|
|||
|
|
@ -507,18 +507,22 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
|||
if prefer == preferModuleInfo: preferModuleInfo else: preferName)
|
||||
of tyTuple:
|
||||
# we iterate over t.sons here, because t.n may be nil
|
||||
result = "tuple["
|
||||
if t.n != nil:
|
||||
result = "tuple["
|
||||
assert(sonsLen(t.n) == sonsLen(t))
|
||||
for i in countup(0, sonsLen(t.n) - 1):
|
||||
assert(t.n.sons[i].kind == nkSym)
|
||||
add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
|
||||
if i < sonsLen(t.n) - 1: add(result, ", ")
|
||||
add(result, ']')
|
||||
elif sonsLen(t) == 0:
|
||||
result = "tuple[]"
|
||||
else:
|
||||
result = "("
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
add(result, typeToString(t.sons[i]))
|
||||
if i < sonsLen(t) - 1: add(result, ", ")
|
||||
add(result, ']')
|
||||
add(result, ')')
|
||||
of tyPtr, tyRef, tyVar, tyMutable, tyConst:
|
||||
result = typeToStr[t.kind]
|
||||
if t.len >= 2:
|
||||
|
|
@ -654,7 +658,7 @@ type
|
|||
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
||||
|
||||
TTypeCmpFlag* = enum
|
||||
IgnoreTupleFields
|
||||
IgnoreTupleFields ## NOTE: Only set this flag for backends!
|
||||
IgnoreCC
|
||||
ExactTypeDescValues
|
||||
ExactGenericParams
|
||||
|
|
@ -774,8 +778,8 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
|
|||
var x = a.sons[i]
|
||||
var y = b.sons[i]
|
||||
if IgnoreTupleFields in c.flags:
|
||||
x = skipTypes(x, {tyRange})
|
||||
y = skipTypes(y, {tyRange})
|
||||
x = skipTypes(x, {tyRange, tyGenericInst})
|
||||
y = skipTypes(y, {tyRange, tyGenericInst})
|
||||
|
||||
result = sameTypeAux(x, y, c)
|
||||
if not result: return
|
||||
|
|
@ -823,8 +827,13 @@ proc sameEnumTypes*(a, b: PType): bool {.inline.} =
|
|||
proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool =
|
||||
if a == b:
|
||||
result = true
|
||||
elif (a != nil) and (b != nil) and (a.kind == b.kind):
|
||||
if sameTypeOrNilAux(a.typ, b.typ, c):
|
||||
elif a != nil and b != nil and a.kind == b.kind:
|
||||
var x = a.typ
|
||||
var y = b.typ
|
||||
if IgnoreTupleFields in c.flags:
|
||||
if x != nil: x = skipTypes(x, {tyRange, tyGenericInst})
|
||||
if y != nil: y = skipTypes(y, {tyRange, tyGenericInst})
|
||||
if sameTypeOrNilAux(x, y, c):
|
||||
case a.kind
|
||||
of nkSym:
|
||||
# same symbol as string is enough:
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ proc renderType(n: PNode): string =
|
|||
assert n[i].kind == nkIdent
|
||||
result.add(',' & typeStr)
|
||||
of nkTupleTy:
|
||||
assert len(n) > 0
|
||||
result = "tuple["
|
||||
for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
|
||||
result[<len(result)] = ']'
|
||||
|
|
|
|||
|
|
@ -1435,6 +1435,7 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
|
|||
newSeq(tos.slots, c.prc.maxSlots)
|
||||
#for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||
result = rawExecute(c, start, tos).regToNode
|
||||
if result.info.line < 0: result.info = n.info
|
||||
|
||||
proc evalConstExpr*(module: PSym, e: PNode): PNode =
|
||||
result = evalConstExprAux(module, nil, e, emConst)
|
||||
|
|
@ -1496,6 +1497,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
|||
# temporary storage:
|
||||
#for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||
result = rawExecute(c, start, tos).regToNode
|
||||
if result.info.line < 0: result.info = n.info
|
||||
if cyclicTree(result): globalError(n.info, errCyclicTree)
|
||||
dec(evalMacroCounter)
|
||||
c.callsite = nil
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ clang.options.size = "-Os"
|
|||
vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
|
||||
vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
|
||||
vcc.options.always = "/nologo"
|
||||
vcc.options.speed = "/Ox /arch:SSE2"
|
||||
vcc.options.speed = "/O2 /arch:SSE2"
|
||||
vcc.options.size = "/O1"
|
||||
|
||||
# Configuration for the Digital Mars C/C++ compiler:
|
||||
|
|
|
|||
|
|
@ -175,6 +175,9 @@ Generic Operating System Services
|
|||
This module implements the ability to monitor a directory/file for changes
|
||||
using Posix's inotify API.
|
||||
|
||||
* `asyncfile <asyncfile.html>`_
|
||||
This module implements asynchronous file reading and writing using
|
||||
``asyncdispatch``.
|
||||
|
||||
Math libraries
|
||||
--------------
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ dispatch.
|
|||
|
||||
.. code-block:: nim
|
||||
type
|
||||
Expression = object ## abstract base class for an expression
|
||||
Expression = object of RootObj ## abstract base class for an expression
|
||||
Literal = object of Expression
|
||||
x: int
|
||||
PlusExpr = object of Expression
|
||||
|
|
@ -387,7 +387,7 @@ dispatching:
|
|||
|
||||
.. code-block:: nim
|
||||
type
|
||||
Thing = object
|
||||
Thing = object of RootObj
|
||||
Unit = object of Thing
|
||||
x: int
|
||||
|
||||
|
|
|
|||
2
koch.nim
2
koch.nim
|
|
@ -347,7 +347,7 @@ proc temp(args: string) =
|
|||
if args.len > 0: exec(finalDest & " " & args)
|
||||
|
||||
proc showHelp() =
|
||||
quit(HelpText % [VersionAsString & repeatChar(44-len(VersionAsString)),
|
||||
quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
|
||||
CompileDate, CompileTime], QuitSuccess)
|
||||
|
||||
var op = initOptParser()
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ type
|
|||
nnkStmtListType, nnkBlockType,
|
||||
nnkWith, nnkWithout,
|
||||
nnkTypeOfExpr, nnkObjectTy,
|
||||
nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
|
||||
nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
|
||||
nnkRecList, nnkRecCase, nnkRecWhen,
|
||||
nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||
nnkConstTy, nnkMutableTy,
|
||||
|
|
@ -343,7 +343,7 @@ proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
|
|||
## checks that `n` is of kind `k`. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check the AST that is passed to them.
|
||||
if n.kind != k: error("macro expects a node of kind: " & $k)
|
||||
if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind)
|
||||
|
||||
proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} =
|
||||
## checks that `n` has at least `min` children. If this is not the case,
|
||||
|
|
@ -581,10 +581,8 @@ const
|
|||
CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
|
||||
nnkCallStrLit, nnkHiddenCallConv}
|
||||
|
||||
from strutils import cmpIgnoreStyle, format
|
||||
|
||||
proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
|
||||
assert n.kind in k, "Expected one of $1, got $2".format(k, n.kind)
|
||||
assert n.kind in k, "Expected one of " & $k & ", got " & $n.kind
|
||||
|
||||
proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()];
|
||||
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
|
||||
|
|
@ -654,7 +652,7 @@ proc `pragma=`*(someProc: PNimrodNode; val: PNimrodNode){.compileTime.}=
|
|||
|
||||
|
||||
template badNodeKind(k; f): stmt{.immediate.} =
|
||||
assert false, "Invalid node kind $# for macros.`$2`".format(k, f)
|
||||
assert false, "Invalid node kind " & $k & " for macros.`" & $f & "`"
|
||||
|
||||
proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||
case someProc.kind:
|
||||
|
|
@ -776,6 +774,22 @@ proc copy*(node: PNimrodNode): PNimrodNode {.compileTime.} =
|
|||
## An alias for copyNimTree().
|
||||
return node.copyNimTree()
|
||||
|
||||
proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
|
||||
proc toLower(c: char): char {.inline.} =
|
||||
if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A')))
|
||||
else: result = c
|
||||
var i = 0
|
||||
var j = 0
|
||||
while true:
|
||||
while a[i] == '_': inc(i)
|
||||
while b[j] == '_': inc(j) # BUGFIX: typo
|
||||
var aa = toLower(a[i])
|
||||
var bb = toLower(b[j])
|
||||
result = ord(aa) - ord(bb)
|
||||
if result != 0 or aa == '\0': break
|
||||
inc(i)
|
||||
inc(j)
|
||||
|
||||
proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0
|
||||
## Check if two idents are identical.
|
||||
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ type
|
|||
ppointer = ptr pointer
|
||||
pbyteArray = ptr array[0.. 0xffff, int8]
|
||||
|
||||
TGenSeq = object
|
||||
TGenericSeq {.importc.} = object
|
||||
len, space: int
|
||||
PGenSeq = ptr TGenSeq
|
||||
PGenSeq = ptr TGenericSeq
|
||||
|
||||
const
|
||||
GenericSeqSize = (2 * sizeof(int))
|
||||
|
|
|
|||
|
|
@ -33,27 +33,71 @@ when defined(Windows):
|
|||
stdout.write(prompt)
|
||||
result = readLine(stdin, line)
|
||||
|
||||
import winlean
|
||||
|
||||
const
|
||||
VK_SHIFT* = 16
|
||||
VK_CONTROL* = 17
|
||||
VK_MENU* = 18
|
||||
KEY_EVENT* = 1
|
||||
|
||||
type
|
||||
KEY_EVENT_RECORD = object
|
||||
bKeyDown: WinBool
|
||||
wRepeatCount: uint16
|
||||
wVirtualKeyCode: uint16
|
||||
wVirtualScanCode: uint16
|
||||
unicodeChar: uint16
|
||||
dwControlKeyState: uint32
|
||||
INPUT_RECORD = object
|
||||
eventType*: int16
|
||||
reserved*: int16
|
||||
event*: KEY_EVENT_RECORD
|
||||
safetyBuffer: array[0..5, DWORD]
|
||||
|
||||
proc readConsoleInputW*(hConsoleInput: THANDLE, lpBuffer: var INPUTRECORD,
|
||||
nLength: uint32,
|
||||
lpNumberOfEventsRead: var uint32): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".}
|
||||
|
||||
proc getch(): uint16 =
|
||||
let hStdin = getStdHandle(STD_INPUT_HANDLE)
|
||||
var
|
||||
irInputRecord: INPUT_RECORD
|
||||
dwEventsRead: uint32
|
||||
|
||||
while readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead) != 0:
|
||||
if irInputRecord.eventType == KEY_EVENT and
|
||||
irInputRecord.event.wVirtualKeyCode notin {VK_SHIFT, VK_MENU, VK_CONTROL}:
|
||||
result = irInputRecord.event.unicodeChar
|
||||
discard readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead)
|
||||
return result
|
||||
|
||||
from unicode import toUTF8, Rune, runeLenAt
|
||||
|
||||
proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
|
||||
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
||||
## Reads a `password` from stdin without printing it. `password` must not
|
||||
## be ``nil``! Returns ``false`` if the end of the file has been reached,
|
||||
## ``true`` otherwise.
|
||||
proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
|
||||
|
||||
password.setLen(0)
|
||||
var c: char
|
||||
stdout.write(prompt)
|
||||
while true:
|
||||
c = getch().char
|
||||
case c
|
||||
let c = getch()
|
||||
case c.char
|
||||
of '\r', chr(0xA):
|
||||
break
|
||||
of '\b':
|
||||
password.setLen(password.len - 1)
|
||||
# ensure we delete the whole UTF-8 character:
|
||||
var i = 0
|
||||
var x = 1
|
||||
while i < password.len:
|
||||
x = runeLenAt(password, i)
|
||||
inc i, x
|
||||
password.setLen(password.len - x)
|
||||
else:
|
||||
password.add(c)
|
||||
password.add(toUTF8(c.Rune))
|
||||
stdout.write "\n"
|
||||
# TODO: How to detect EOF on Windows?
|
||||
|
||||
else:
|
||||
import readline, history, termios, unsigned
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ proc rawCompile(pattern: string, flags: cint): PPcre =
|
|||
offset: cint
|
||||
result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil)
|
||||
if result == nil:
|
||||
raiseInvalidRegex($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n")
|
||||
raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
|
||||
|
||||
proc finalizeRegEx(x: Regex) =
|
||||
# XXX This is a hack, but PCRE does not export its "free" function properly.
|
||||
|
|
@ -291,7 +291,7 @@ proc replace*(s: string, sub: Regex, by = ""): string =
|
|||
## accessed in `by`. Examples:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## "var1=key; var2=key2".replace(re"(\w+)'='(\w+)")
|
||||
## "var1=key; var2=key2".replace(re"(\w+)=(\w+)")
|
||||
##
|
||||
## Results in:
|
||||
##
|
||||
|
|
@ -313,7 +313,7 @@ proc replacef*(s: string, sub: Regex, by: string): string =
|
|||
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## "var1=key; var2=key2".replacef(re"(\w+)'='(\w+)", "$1<-$2$2")
|
||||
## "var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2")
|
||||
##
|
||||
## Results in:
|
||||
##
|
||||
|
|
|
|||
|
|
@ -103,7 +103,11 @@ __clang__
|
|||
# define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
|
||||
# define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
|
||||
|
||||
# define N_LIB_EXPORT extern __declspec(dllexport)
|
||||
# ifdef __cplusplus
|
||||
# define N_LIB_EXPORT extern "C" __declspec(dllexport)
|
||||
# else
|
||||
# define N_LIB_EXPORT extern __declspec(dllexport)
|
||||
# endif
|
||||
# define N_LIB_IMPORT extern __declspec(dllimport)
|
||||
#else
|
||||
# define N_CDECL(rettype, name) rettype name
|
||||
|
|
@ -118,7 +122,11 @@ __clang__
|
|||
# define N_FASTCALL_PTR(rettype, name) rettype (*name)
|
||||
# define N_SAFECALL_PTR(rettype, name) rettype (*name)
|
||||
|
||||
# define N_LIB_EXPORT extern
|
||||
# ifdef __cplusplus
|
||||
# define N_LIB_EXPORT extern "C"
|
||||
# else
|
||||
# define N_LIB_EXPORT extern
|
||||
# endif
|
||||
# define N_LIB_IMPORT extern
|
||||
#endif
|
||||
|
||||
|
|
@ -398,4 +406,6 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(
|
|||
# include <sys/types.h>
|
||||
# include <types/vxWind.h>
|
||||
# include <tool/gnu/toolMacros.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ proc getIndent(L: var TLexer, tok: var TToken) =
|
|||
tok.line = L.line
|
||||
L.col = tok.ival
|
||||
tok.ival = max(tok.ival - L.baseIndent, 0)
|
||||
tok.symbol = "\n" & repeatChar(tok.ival)
|
||||
tok.symbol = "\n" & spaces(tok.ival)
|
||||
|
||||
proc rawGetTok(L: var TLexer, tok: var TToken) =
|
||||
tok.symbol = ""
|
||||
|
|
@ -963,7 +963,7 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
|
|||
break
|
||||
else:
|
||||
add(n.text, "\n")
|
||||
add(n.text, repeatChar(p.tok[p.idx].ival - indent))
|
||||
add(n.text, spaces(p.tok[p.idx].ival - indent))
|
||||
inc(p.idx)
|
||||
else:
|
||||
add(n.text, p.tok[p.idx].symbol)
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
|||
const
|
||||
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
|
||||
if n == nil: return
|
||||
var ind = repeatChar(d.indent)
|
||||
var ind = spaces(d.indent)
|
||||
case n.kind
|
||||
of rnInner:
|
||||
renderRstSons(d, n, result)
|
||||
|
|
@ -124,7 +124,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
|||
|
||||
result.add("\n")
|
||||
result.add(ind)
|
||||
result.add repeatChar(headlineLen, lvlToChar[n.level])
|
||||
result.add repeat(lvlToChar[n.level], headlineLen)
|
||||
of rnOverline:
|
||||
result.add("\n")
|
||||
result.add(ind)
|
||||
|
|
@ -132,7 +132,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
|||
var headline = ""
|
||||
renderRstSons(d, n, headline)
|
||||
|
||||
let lvl = repeatChar(headline.len - d.indent, lvlToChar[n.level])
|
||||
let lvl = repeat(lvlToChar[n.level], headline.len - d.indent)
|
||||
result.add(lvl)
|
||||
result.add("\n")
|
||||
result.add(headline)
|
||||
|
|
@ -143,7 +143,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
|||
of rnTransition:
|
||||
result.add("\n\n")
|
||||
result.add(ind)
|
||||
result.add repeatChar(78-d.indent, '-')
|
||||
result.add repeat('-', 78-d.indent)
|
||||
result.add("\n\n")
|
||||
of rnParagraph:
|
||||
result.add("\n\n")
|
||||
|
|
@ -196,7 +196,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
|||
result.add ':'
|
||||
result.add tmp
|
||||
result.add ':'
|
||||
result.add repeatChar(L - tmp.len - 2)
|
||||
result.add spaces(L - tmp.len - 2)
|
||||
renderRstToRst(d, n.sons[1], result)
|
||||
|
||||
dec(d.indent, L)
|
||||
|
|
|
|||
|
|
@ -461,9 +461,9 @@ proc indentToLevel(level: var int, newLevel: int): string =
|
|||
if level == newLevel:
|
||||
return
|
||||
if newLevel > level:
|
||||
result = repeatStr(newLevel - level, "<ul>")
|
||||
result = repeat("<ul>", newLevel - level)
|
||||
else:
|
||||
result = repeatStr(level - newLevel, "</ul>")
|
||||
result = repeat("</ul>", level - newLevel)
|
||||
level = newLevel
|
||||
|
||||
proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
|
||||
|
|
@ -701,7 +701,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
|||
# Generate index entry using spaces to indicate TOC level for the output HTML.
|
||||
assert n.level >= 0
|
||||
setIndexTerm(d, refname, tmp.stripTOCHTML,
|
||||
repeatChar(max(0, n.level), ' ') & tmp)
|
||||
spaces(max(0, n.level)) & tmp)
|
||||
|
||||
proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||
if d.meta[metaTitle].len == 0:
|
||||
|
|
|
|||
|
|
@ -75,11 +75,12 @@ const
|
|||
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
|
||||
## 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))
|
||||
## the sequence will still be sorted
|
||||
## words if you have a sorted sequence and you call
|
||||
## 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::
|
||||
##
|
||||
|
|
@ -187,6 +188,35 @@ proc sort*[T](a: var openArray[T],
|
|||
dec(m, s*2)
|
||||
s = s*2
|
||||
|
||||
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`.
|
||||
result = newSeq[T](a.len)
|
||||
for i in 0 .. a.high:
|
||||
result[i] = a[i]
|
||||
sort(result, cmp, order)
|
||||
|
||||
template sortByIt*(seq1, op: expr): expr =
|
||||
## Convenience template around the ``sorted`` proc to reduce typing.
|
||||
##
|
||||
## The template injects the ``it`` variable which you can use directly in an
|
||||
## expression. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## var users: seq[tuple[id: int, name: string]] =
|
||||
## @[(0, "Smith"), (1, "Pratt"), (2, "Sparrow")]
|
||||
##
|
||||
## echo users.sortByIt(it.name)
|
||||
##
|
||||
var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int =
|
||||
var it {.inject.} = x
|
||||
let a = op
|
||||
it = y
|
||||
let b = op
|
||||
result = cmp(a, b))
|
||||
result
|
||||
|
||||
proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
|
||||
## produces the Cartesian product of the array. Warning: complexity
|
||||
## may explode.
|
||||
|
|
|
|||
|
|
@ -1222,7 +1222,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
|
|||
of nnkTryStmt:
|
||||
# try: await x; except: ...
|
||||
result = newNimNode(nnkStmtList, node)
|
||||
template wrapInTry(n, tryBody: PNimrodNode) =
|
||||
template wrapInTry(n, tryBody: expr) =
|
||||
var temp = n
|
||||
n[0] = tryBody
|
||||
tryBody = temp
|
||||
|
|
@ -1323,14 +1323,25 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
|||
newLit(prc[0].getName)))) # Get type from return type of this proc
|
||||
|
||||
# -> iterator nameIter(): FutureBase {.closure.} =
|
||||
# -> {.push warning[resultshadowed]: off.}
|
||||
# -> var result: T
|
||||
# -> {.pop.}
|
||||
# -> <proc_body>
|
||||
# -> complete(retFuture, result)
|
||||
var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
|
||||
var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
|
||||
if not subtypeIsVoid:
|
||||
procBody.insert(0, newNimNode(nnkVarSection, prc[6]).add(
|
||||
procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
|
||||
newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
|
||||
newIdentNode("warning"), newIdentNode("resultshadowed")),
|
||||
newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
|
||||
|
||||
procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
|
||||
newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
|
||||
|
||||
procBody.insert(2, newNimNode(nnkPragma).add(
|
||||
newIdentNode("pop"))) # -> {.pop.})
|
||||
|
||||
procBody.add(
|
||||
newCall(newIdentNode("complete"),
|
||||
retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements asynchronous file handling.
|
||||
## This module implements asynchronous file reading and writing.
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
## import asyncfile, asyncdispatch, os
|
||||
|
|
@ -24,17 +24,17 @@
|
|||
|
||||
import asyncdispatch, os
|
||||
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
import winlean
|
||||
else:
|
||||
import posix
|
||||
|
||||
type
|
||||
AsyncFile = ref object
|
||||
AsyncFile* = ref object
|
||||
fd: TAsyncFd
|
||||
offset: int64
|
||||
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
proc getDesiredAccess(mode: FileMode): int32 =
|
||||
case mode
|
||||
of fmRead:
|
||||
|
|
@ -70,7 +70,7 @@ else:
|
|||
|
||||
proc getFileSize(f: AsyncFile): int64 =
|
||||
## Retrieves the specified file's size.
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
var high: DWord
|
||||
let low = getFileSize(f.fd.THandle, addr high)
|
||||
if low == INVALID_FILE_SIZE:
|
||||
|
|
@ -81,7 +81,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
|
|||
## Opens a file specified by the path in ``filename`` using
|
||||
## the specified ``mode`` asynchronously.
|
||||
new result
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
|
||||
let desiredAccess = getDesiredAccess(mode)
|
||||
let creationDisposition = getCreationDisposition(mode, filename)
|
||||
|
|
@ -120,7 +120,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
|
|||
## returned.
|
||||
var retFuture = newFuture[string]("asyncfile.read")
|
||||
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
var buffer = alloc0(size)
|
||||
|
||||
var ol = PCustomOverlapped()
|
||||
|
|
@ -224,7 +224,7 @@ proc setFilePos*(f: AsyncFile, pos: int64) =
|
|||
## Sets the position of the file pointer that is used for read/write
|
||||
## operations. The file's first byte has the index zero.
|
||||
f.offset = pos
|
||||
when not defined(windows):
|
||||
when not defined(windows) and not defined(nimdoc):
|
||||
let ret = lseek(f.fd.cint, pos, SEEK_SET)
|
||||
if ret == -1:
|
||||
raiseOSError(osLastError())
|
||||
|
|
@ -245,7 +245,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
|
|||
## specified file.
|
||||
var retFuture = newFuture[void]("asyncfile.write")
|
||||
var copy = data
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
var buffer = alloc0(data.len)
|
||||
copyMem(buffer, addr copy[0], data.len)
|
||||
|
||||
|
|
@ -316,7 +316,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
|
|||
|
||||
proc close*(f: AsyncFile) =
|
||||
## Closes the file specified.
|
||||
when defined(windows):
|
||||
when defined(windows) or defined(nimdoc):
|
||||
if not closeHandle(f.fd.THandle).bool:
|
||||
raiseOSError(osLastError())
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -47,6 +47,24 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
|||
result[i] = itm
|
||||
inc(i)
|
||||
|
||||
proc repeat*[T](s: seq[T], n: Natural): seq[T] =
|
||||
## Returns a new sequence with the items of `s` repeated `n` times.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:
|
||||
##
|
||||
## let
|
||||
## s = @[1, 2, 3]
|
||||
## total = s.repeat(3)
|
||||
## assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||
result = newSeq[T](n * s.len)
|
||||
var o = 0
|
||||
for x in 1..n:
|
||||
for e in s:
|
||||
result[o] = e
|
||||
inc o
|
||||
|
||||
proc deduplicate*[T](seq1: seq[T]): seq[T] =
|
||||
## Returns a new sequence without duplicates.
|
||||
##
|
||||
|
|
@ -86,7 +104,7 @@ proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
|
|||
newSeq(result, m)
|
||||
for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
|
||||
|
||||
proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
|
||||
proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
|
||||
## Splits and distributes a sequence `s` into `num` sub sequences.
|
||||
##
|
||||
## Returns a sequence of `num` sequences. For some input values this is the
|
||||
|
|
@ -113,11 +131,12 @@ proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
|
|||
## assert numbers.distribute(6)[0] == @[1, 2]
|
||||
## assert numbers.distribute(6)[5] == @[7]
|
||||
assert(not s.isNil, "`s` can't be nil")
|
||||
assert(num > 0, "`num` has to be greater than zero")
|
||||
if num < 2:
|
||||
result = @[s]
|
||||
return
|
||||
|
||||
let num = int(num) # XXX probably only needed because of .. bug
|
||||
|
||||
# Create the result and calculate the stride size and the remainder if any.
|
||||
result = newSeq[seq[T]](num)
|
||||
var
|
||||
|
|
@ -587,4 +606,14 @@ when isMainModule:
|
|||
seq2D[0][1] = true
|
||||
doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
|
||||
|
||||
block: # repeat tests
|
||||
let
|
||||
a = @[1, 2, 3]
|
||||
b: seq[int] = @[]
|
||||
|
||||
doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||
doAssert a.repeat(0) == @[]
|
||||
#doAssert a.repeat(-1) == @[] # will not compile!
|
||||
doAssert b.repeat(3) == @[]
|
||||
|
||||
echo "Finished doc tests"
|
||||
|
|
|
|||
|
|
@ -196,7 +196,11 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B =
|
|||
var hc: THash
|
||||
var index = rawGet(t, key, hc)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: raise newException(KeyError, "key not found: " & $key)
|
||||
else:
|
||||
when compiles($key):
|
||||
raise newException(KeyError, "key not found: " & $key)
|
||||
else:
|
||||
raise newException(KeyError, "key not found")
|
||||
|
||||
iterator allValues*[A, B](t: Table[A, B]; key: A): B =
|
||||
## iterates over any value in the table `t` that belongs to the given `key`.
|
||||
|
|
|
|||
|
|
@ -365,9 +365,9 @@ proc polar*(z: Complex): tuple[r, phi: float] =
|
|||
result.phi = phase(z)
|
||||
|
||||
proc rect*(r: float, phi: float): Complex =
|
||||
## Returns the complex number with poolar coordinates `r` and `phi`.
|
||||
## Returns the complex number with polar coordinates `r` and `phi`.
|
||||
result.re = r * cos(phi)
|
||||
result.im = sin(phi)
|
||||
result.im = r * sin(phi)
|
||||
|
||||
|
||||
proc `$`*(z: Complex): string =
|
||||
|
|
@ -438,5 +438,6 @@ when isMainModule:
|
|||
assert( arccoth(a) =~ arctanh(1/a) )
|
||||
|
||||
assert( phase(a) == 1.1071487177940904 )
|
||||
assert( polar(a) =~ (2.23606797749979, 1.1071487177940904) )
|
||||
var t = polar(a)
|
||||
assert( rect(t.r, t.phi) =~ a )
|
||||
assert( rect(1.0, 2.0) =~ (-0.4161468365471424, 0.9092974268256817) )
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@
|
|||
## proc hash(x: Something): THash =
|
||||
## ## Computes a THash from `x`.
|
||||
## var h: THash = 0
|
||||
## h = h &! hash(x.foo)
|
||||
## h = h &! hash(x.bar)
|
||||
## h = h !& hash(x.foo)
|
||||
## h = h !& hash(x.bar)
|
||||
## result = !$h
|
||||
|
||||
import
|
||||
|
|
|
|||
|
|
@ -390,8 +390,11 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
|
|||
## server takes longer than specified an ETimeout exception will be raised.
|
||||
var r = if proxy == nil: parseUri(url) else: proxy.url
|
||||
var headers = substr(httpMethod, len("http"))
|
||||
# TODO: Use generateHeaders further down once it supports proxies.
|
||||
if proxy == nil:
|
||||
headers.add(" " & r.path)
|
||||
headers.add ' '
|
||||
if r.path[0] != '/': headers.add '/'
|
||||
headers.add(r.path)
|
||||
if r.query.len > 0:
|
||||
headers.add("?" & r.query)
|
||||
else:
|
||||
|
|
@ -567,9 +570,12 @@ proc downloadFile*(url: string, outputFilename: string,
|
|||
|
||||
proc generateHeaders(r: Uri, httpMethod: string,
|
||||
headers: StringTableRef): string =
|
||||
# TODO: Use this in the blocking HttpClient once it supports proxies.
|
||||
result = substr(httpMethod, len("http"))
|
||||
# TODO: Proxies
|
||||
result.add(" " & r.path)
|
||||
result.add ' '
|
||||
if r.path[0] != '/': result.add '/'
|
||||
result.add(r.path)
|
||||
if r.query.len > 0:
|
||||
result.add("?" & r.query)
|
||||
result.add(" HTTP/1.1\c\L")
|
||||
|
|
|
|||
|
|
@ -816,7 +816,7 @@ proc copy*(p: JsonNode): JsonNode =
|
|||
# ------------- pretty printing ----------------------------------------------
|
||||
|
||||
proc indent(s: var string, i: int) =
|
||||
s.add(repeatChar(i))
|
||||
s.add(spaces(i))
|
||||
|
||||
proc newIndent(curr, indent: int, ml: bool): int =
|
||||
if ml: return curr + indent
|
||||
|
|
|
|||
|
|
@ -165,5 +165,5 @@ proc getCurrentLine(L: BaseLexer, marker: bool = true): string =
|
|||
inc(i)
|
||||
add(result, "\n")
|
||||
if marker:
|
||||
add(result, repeatChar(getColNumber(L, L.bufpos)) & "^\n")
|
||||
add(result, spaces(getColNumber(L, L.bufpos)) & "^\n")
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,23 @@ type
|
|||
TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket,
|
||||
TSocketImpl: SocketImpl].}
|
||||
|
||||
type
|
||||
IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
|
||||
IPv6, ## IPv6 address
|
||||
IPv4 ## IPv4 address
|
||||
|
||||
TIpAddress* = object ## stores an arbitrary IP address
|
||||
case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
|
||||
of IpAddressFamily.IPv6:
|
||||
address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
|
||||
## case of IPv6
|
||||
of IpAddressFamily.IPv4:
|
||||
address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
|
||||
## case of IPv4
|
||||
|
||||
proc isIpAddress*(address_str: string): bool {.tags: [].}
|
||||
proc parseIpAddress*(address_str: string): TIpAddress
|
||||
|
||||
proc isDisconnectionError*(flags: set[SocketFlag],
|
||||
lastError: OSErrorCode): bool =
|
||||
## Determines whether ``lastError`` is a disconnection error. Only does this
|
||||
|
|
@ -511,6 +528,12 @@ proc connect*(socket: Socket, address: string, port = Port(0),
|
|||
|
||||
when defined(ssl):
|
||||
if socket.isSSL:
|
||||
# RFC3546 for SNI specifies that IP addresses are not allowed.
|
||||
if not isIpAddress(address):
|
||||
# Discard result in case OpenSSL version doesn't support SNI, or we're
|
||||
# not using TLSv1+
|
||||
discard SSL_set_tlsext_host_name(socket.sslHandle, address)
|
||||
|
||||
let ret = SSLConnect(socket.sslHandle)
|
||||
socketError(socket, ret)
|
||||
|
||||
|
|
@ -969,20 +992,6 @@ proc isSsl*(socket: Socket): bool =
|
|||
proc getFd*(socket: Socket): SocketHandle = return socket.fd
|
||||
## Returns the socket's file descriptor
|
||||
|
||||
type
|
||||
IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
|
||||
IPv6, ## IPv6 address
|
||||
IPv4 ## IPv4 address
|
||||
|
||||
TIpAddress* = object ## stores an arbitrary IP address
|
||||
case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
|
||||
of IpAddressFamily.IPv6:
|
||||
address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
|
||||
## case of IPv6
|
||||
of IpAddressFamily.IPv4:
|
||||
address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
|
||||
## case of IPv4
|
||||
|
||||
proc IPv4_any*(): TIpAddress =
|
||||
## Returns the IPv4 any address, which can be used to listen on all available
|
||||
## network adapters
|
||||
|
|
@ -1241,7 +1250,7 @@ proc parseIPv6Address(address_str: string): TIpAddress =
|
|||
raise newException(ValueError,
|
||||
"Invalid IP Address. The address consists of too many groups")
|
||||
|
||||
proc parseIpAddress*(address_str: string): TIpAddress =
|
||||
proc parseIpAddress(address_str: string): TIpAddress =
|
||||
## Parses an IP address
|
||||
## Raises EInvalidValue on error
|
||||
if address_str == nil:
|
||||
|
|
@ -1250,3 +1259,13 @@ proc parseIpAddress*(address_str: string): TIpAddress =
|
|||
return parseIPv6Address(address_str)
|
||||
else:
|
||||
return parseIPv4Address(address_str)
|
||||
|
||||
|
||||
proc isIpAddress(address_str: string): bool =
|
||||
## Checks if a string is an IP address
|
||||
## Returns true if it is, false otherwise
|
||||
try:
|
||||
discard parseIpAddress(address_str)
|
||||
except ValueError:
|
||||
return false
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -11,9 +11,12 @@
|
|||
## It supports one convenience iterator over all command line options and some
|
||||
## lower-level features.
|
||||
##
|
||||
## **Deprecated since version 0.9.3:** Use the `parseopt2 <parseopt2.html>`_
|
||||
## module instead as this version has issues with spaces in arguments.
|
||||
{.deprecated.}
|
||||
## Supported syntax:
|
||||
##
|
||||
## 1. short options - ``-abcd``, where a, b, c, d are names
|
||||
## 2. long option - ``--foo:bar``, ``--foo=bar`` or ``--foo``
|
||||
## 3. argument - everything else
|
||||
|
||||
{.push debugger: off.}
|
||||
|
||||
include "system/inclrtl"
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
|
|||
my.kind = xmlError
|
||||
my.a = ""
|
||||
my.b = ""
|
||||
my.c = nil
|
||||
my.options = options
|
||||
|
||||
proc close*(my: var XmlParser) {.inline.} =
|
||||
|
|
@ -138,43 +139,43 @@ proc kind*(my: XmlParser): XmlEventKind {.inline.} =
|
|||
## returns the current event type for the XML parser
|
||||
return my.kind
|
||||
|
||||
proc charData*(my: XmlParser): string {.inline.} =
|
||||
template charData*(my: XmlParser): string =
|
||||
## returns the character data for the events: ``xmlCharData``,
|
||||
## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial``
|
||||
assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData,
|
||||
xmlSpecial})
|
||||
return my.a
|
||||
my.a
|
||||
|
||||
proc elementName*(my: XmlParser): string {.inline.} =
|
||||
template elementName*(my: XmlParser): string =
|
||||
## returns the element name for the events: ``xmlElementStart``,
|
||||
## ``xmlElementEnd``, ``xmlElementOpen``
|
||||
assert(my.kind in {xmlElementStart, xmlElementEnd, xmlElementOpen})
|
||||
return my.a
|
||||
my.a
|
||||
|
||||
proc entityName*(my: XmlParser): string {.inline.} =
|
||||
template entityName*(my: XmlParser): string =
|
||||
## returns the entity name for the event: ``xmlEntity``
|
||||
assert(my.kind == xmlEntity)
|
||||
return my.a
|
||||
my.a
|
||||
|
||||
proc attrKey*(my: XmlParser): string {.inline.} =
|
||||
template attrKey*(my: XmlParser): string =
|
||||
## returns the attribute key for the event ``xmlAttribute``
|
||||
assert(my.kind == xmlAttribute)
|
||||
return my.a
|
||||
my.a
|
||||
|
||||
proc attrValue*(my: XmlParser): string {.inline.} =
|
||||
template attrValue*(my: XmlParser): string =
|
||||
## returns the attribute value for the event ``xmlAttribute``
|
||||
assert(my.kind == xmlAttribute)
|
||||
return my.b
|
||||
my.b
|
||||
|
||||
proc piName*(my: XmlParser): string {.inline.} =
|
||||
template piName*(my: XmlParser): string =
|
||||
## returns the processing instruction name for the event ``xmlPI``
|
||||
assert(my.kind == xmlPI)
|
||||
return my.a
|
||||
my.a
|
||||
|
||||
proc piRest*(my: XmlParser): string {.inline.} =
|
||||
template piRest*(my: XmlParser): string =
|
||||
## returns the rest of the processing instruction for the event ``xmlPI``
|
||||
assert(my.kind == xmlPI)
|
||||
return my.b
|
||||
my.b
|
||||
|
||||
proc rawData*(my: XmlParser): string {.inline.} =
|
||||
## returns the underlying 'data' string by reference.
|
||||
|
|
@ -621,7 +622,7 @@ proc next*(my: var XmlParser) =
|
|||
of stateEmptyElementTag:
|
||||
my.state = stateNormal
|
||||
my.kind = xmlElementEnd
|
||||
if not isNil(my.c):
|
||||
if not my.c.isNil:
|
||||
my.a = my.c
|
||||
of stateError:
|
||||
my.kind = xmlError
|
||||
|
|
|
|||
|
|
@ -902,7 +902,7 @@ proc replacef*(s: string, sub: Peg, by: string): string {.
|
|||
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2")
|
||||
## "var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2")
|
||||
##
|
||||
## Results in:
|
||||
##
|
||||
|
|
|
|||
|
|
@ -798,6 +798,22 @@ proc zunionstore*(r: Redis, destination: string, numkeys: string,
|
|||
|
||||
return r.readInteger()
|
||||
|
||||
# HyperLogLog
|
||||
|
||||
proc pfadd*(r: Redis, key: string, elements: varargs[string]): RedisInteger =
|
||||
## Add variable number of elements into special 'HyperLogLog' set type
|
||||
r.sendCommand("PFADD", key, elements)
|
||||
return r.readInteger()
|
||||
|
||||
proc pfcount*(r: Redis, key: string): RedisInteger =
|
||||
## Count approximate number of elements in 'HyperLogLog'
|
||||
r.sendCommand("PFCOUNT", key)
|
||||
return r.readInteger()
|
||||
|
||||
proc pfmerge*(r: Redis, destination: string, sources: varargs[string]) =
|
||||
## Merge several source HyperLogLog's into one specified by destKey
|
||||
r.sendCommand("PFMERGE", destination, sources)
|
||||
raiseNoOK(r.readStatus(), r.pipeline.enabled)
|
||||
|
||||
# Pub/Sub
|
||||
|
||||
|
|
|
|||
|
|
@ -224,10 +224,12 @@ proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
|||
|
||||
proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
||||
var s = StringStream(s)
|
||||
if bufLen > 0:
|
||||
setLen(s.data, s.data.len + bufLen)
|
||||
copyMem(addr(s.data[s.pos]), buffer, bufLen)
|
||||
inc(s.pos, bufLen)
|
||||
if bufLen <= 0:
|
||||
return
|
||||
if s.pos + bufLen > s.data.len:
|
||||
setLen(s.data, s.pos + bufLen)
|
||||
copyMem(addr(s.data[s.pos]), buffer, bufLen)
|
||||
inc(s.pos, bufLen)
|
||||
|
||||
proc ssClose(s: Stream) =
|
||||
var s = StringStream(s)
|
||||
|
|
|
|||
|
|
@ -499,26 +499,47 @@ proc parseEnum*[T: enum](s: string, default: T): T =
|
|||
return e
|
||||
result = default
|
||||
|
||||
proc repeatChar*(count: int, c: char = ' '): string {.noSideEffect,
|
||||
proc repeat*(c: char, count: int): string {.noSideEffect,
|
||||
rtl, extern: "nsuRepeatChar".} =
|
||||
## Returns a string of length `count` consisting only of
|
||||
## the character `c`. You can use this proc to left align strings. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## proc tabexpand(indent: int, text: string, tabsize: int = 4) =
|
||||
## echo '\t'.repeat(indent div tabsize), ' '.repeat(indent mod tabsize), text
|
||||
##
|
||||
## tabexpand(4, "At four")
|
||||
## tabexpand(5, "At five")
|
||||
## tabexpand(6, "At six")
|
||||
result = newString(count)
|
||||
for i in 0..count-1: result[i] = c
|
||||
|
||||
proc repeat*(s: string, n: int): string {.noSideEffect,
|
||||
rtl, extern: "nsuRepeatStr".} =
|
||||
## Returns String `s` concatenated `n` times. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## echo "+++ STOP ".repeat(4), "+++"
|
||||
result = newStringOfCap(n * s.len)
|
||||
for i in 1..n: result.add(s)
|
||||
|
||||
template spaces*(n: int): string = repeat(' ',n)
|
||||
## Returns a String with `n` space characters. You can use this proc
|
||||
## to left align strings. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## let
|
||||
## width = 15
|
||||
## text1 = "Hello user!"
|
||||
## text2 = "This is a very long string"
|
||||
## echo text1 & repeatChar(max(0, width - text1.len)) & "|"
|
||||
## echo text2 & repeatChar(max(0, width - text2.len)) & "|"
|
||||
result = newString(count)
|
||||
for i in 0..count-1: result[i] = c
|
||||
## echo text1 & spaces(max(0, width - text1.len)) & "|"
|
||||
## echo text2 & spaces(max(0, width - text2.len)) & "|"
|
||||
|
||||
proc repeatStr*(count: int, s: string): string {.noSideEffect,
|
||||
rtl, extern: "nsuRepeatStr".} =
|
||||
## Returns `s` concatenated `count` times.
|
||||
result = newStringOfCap(count*s.len)
|
||||
for i in 0..count-1: result.add(s)
|
||||
proc repeatChar*(count: int, c: char = ' '): string {.deprecated.} = repeat(c, count)
|
||||
## deprecated: use repeat() or spaces()
|
||||
|
||||
proc repeatStr*(count: int, s: string): string {.deprecated.} = repeat(s, count)
|
||||
## deprecated: use repeat(string, count) or string.repeat(count)
|
||||
|
||||
proc align*(s: string, count: int, padding = ' '): string {.
|
||||
noSideEffect, rtl, extern: "nsuAlignString".} =
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ when defined(windows):
|
|||
var
|
||||
oldAttr = getAttributes()
|
||||
|
||||
proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".}
|
||||
else:
|
||||
import termios, unsigned
|
||||
|
||||
|
|
@ -364,12 +363,11 @@ macro styledEcho*(m: varargs[expr]): stmt =
|
|||
result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
|
||||
result.add(newCall(bindSym"resetAttributes"))
|
||||
|
||||
proc getch*(): char =
|
||||
## Read a single character from the terminal, blocking until it is entered.
|
||||
## The character is not printed to the terminal.
|
||||
when defined(windows):
|
||||
result = winGetch().char
|
||||
else:
|
||||
when not defined(windows):
|
||||
proc getch*(): char =
|
||||
## Read a single character from the terminal, blocking until it is entered.
|
||||
## The character is not printed to the terminal. This is not available for
|
||||
## Windows.
|
||||
let fd = getFileHandle(stdin)
|
||||
var oldMode: Termios
|
||||
discard fd.tcgetattr(addr oldMode)
|
||||
|
|
|
|||
|
|
@ -628,25 +628,25 @@ proc formatToken(info: TimeInfo, token: string, buf: var string) =
|
|||
var fr = ($info.year).len()-2
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 2: fyear = repeatChar(2-fyear.len(), '0') & fyear
|
||||
if fyear.len != 2: fyear = repeat('0', 2-fyear.len()) & fyear
|
||||
buf.add(fyear)
|
||||
of "yyy":
|
||||
var fr = ($info.year).len()-3
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 3: fyear = repeatChar(3-fyear.len(), '0') & fyear
|
||||
if fyear.len != 3: fyear = repeat('0', 3-fyear.len()) & fyear
|
||||
buf.add(fyear)
|
||||
of "yyyy":
|
||||
var fr = ($info.year).len()-4
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 4: fyear = repeatChar(4-fyear.len(), '0') & fyear
|
||||
if fyear.len != 4: fyear = repeat('0', 4-fyear.len()) & fyear
|
||||
buf.add(fyear)
|
||||
of "yyyyy":
|
||||
var fr = ($info.year).len()-5
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 5: fyear = repeatChar(5-fyear.len(), '0') & fyear
|
||||
if fyear.len != 5: fyear = repeat('0', 5-fyear.len()) & fyear
|
||||
buf.add(fyear)
|
||||
of "z":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
|
|
|
|||
|
|
@ -118,21 +118,35 @@ proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
|
|||
elif i <=% 0x07FF:
|
||||
result = newString(2)
|
||||
result[0] = chr((i shr 6) or 0b110_00000)
|
||||
result[1] = chr((i and ones(6)) or 0b10_000000)
|
||||
result[1] = chr((i and ones(6)) or 0b10_0000_00)
|
||||
elif i <=% 0xFFFF:
|
||||
result = newString(3)
|
||||
result[0] = chr(i shr 12 or 0b1110_0000)
|
||||
result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(i and ones(6) or 0b10_0000_00)
|
||||
elif i <=% 0x0010FFFF:
|
||||
elif i <=% 0x001FFFFF:
|
||||
result = newString(4)
|
||||
result[0] = chr(i shr 18 or 0b1111_0000)
|
||||
result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[3] = chr(i and ones(6) or 0b10_0000_00)
|
||||
elif i <=% 0x03FFFFFF:
|
||||
result = newString(5)
|
||||
result[0] = chr(i shr 24 or 0b111110_00)
|
||||
result[1] = chr(i shr 18 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(i shr 12 and ones(6) or 0b10_0000_00)
|
||||
result[3] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[4] = chr(i and ones(6) or 0b10_0000_00)
|
||||
elif i <=% 0x7FFFFFFF:
|
||||
result = newString(6)
|
||||
result[0] = chr(i shr 30 or 0b1111110_0)
|
||||
result[1] = chr(i shr 24 and ones(6) or 0b10_0000_00)
|
||||
result[2] = chr(i shr 18 and ones(6) or 0b10_0000_00)
|
||||
result[3] = chr(i shr 12 and ones(6) or 0b10_0000_00)
|
||||
result[4] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||
result[5] = chr(i and ones(6) or 0b10_0000_00)
|
||||
else:
|
||||
result = newString(1)
|
||||
result[0] = chr(i)
|
||||
discard # error, exception?
|
||||
|
||||
proc `$`*(rune: Rune): string =
|
||||
## converts a rune to a string
|
||||
|
|
|
|||
|
|
@ -285,6 +285,16 @@ proc `$`*(u: Uri): string =
|
|||
result.add(u.anchor)
|
||||
|
||||
when isMainModule:
|
||||
block:
|
||||
let str = "http://localhost"
|
||||
let test = parseUri(str)
|
||||
doAssert test.path == ""
|
||||
|
||||
block:
|
||||
let str = "http://localhost/"
|
||||
let test = parseUri(str)
|
||||
doAssert test.path == "/"
|
||||
|
||||
block:
|
||||
let str = "http://localhost:8080/test"
|
||||
let test = parseUri(str)
|
||||
|
|
|
|||
|
|
@ -1083,7 +1083,7 @@ proc addEscaped(s: string): string =
|
|||
else: result.add(c)
|
||||
|
||||
proc nodeToXml(n: PNode, indent: int = 0): string =
|
||||
result = repeatChar(indent, ' ') & "<" & n.nodeName
|
||||
result = spaces(indent) & "<" & n.nodeName
|
||||
if not isNil(n.attributes):
|
||||
for i in items(n.attributes):
|
||||
result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
|
||||
|
|
@ -1098,23 +1098,23 @@ proc nodeToXml(n: PNode, indent: int = 0): string =
|
|||
of ElementNode:
|
||||
result.add(nodeToXml(i, indent + 2))
|
||||
of TextNode:
|
||||
result.add(repeatChar(indent * 2, ' '))
|
||||
result.add(spaces(indent * 2))
|
||||
result.add(addEscaped(i.nodeValue))
|
||||
of CDataSectionNode:
|
||||
result.add(repeatChar(indent * 2, ' '))
|
||||
result.add(spaces(indent * 2))
|
||||
result.add("<![CDATA[" & i.nodeValue & "]]>")
|
||||
of ProcessingInstructionNode:
|
||||
result.add(repeatChar(indent * 2, ' '))
|
||||
result.add(spaces(indent * 2))
|
||||
result.add("<?" & PProcessingInstruction(i).target & " " &
|
||||
PProcessingInstruction(i).data & " ?>")
|
||||
of CommentNode:
|
||||
result.add(repeatChar(indent * 2, ' '))
|
||||
result.add(spaces(indent * 2))
|
||||
result.add("<!-- " & i.nodeValue & " -->")
|
||||
else:
|
||||
continue
|
||||
result.add("\n")
|
||||
# Add the ending tag - </tag>
|
||||
result.add(repeatChar(indent, ' ') & "</" & n.nodeName & ">")
|
||||
result.add(spaces(indent) & "</" & n.nodeName & ">")
|
||||
|
||||
proc `$`*(doc: PDocument): string =
|
||||
## Converts a PDocument object into a string representation of it's XML
|
||||
|
|
|
|||
|
|
@ -2021,7 +2021,7 @@ proc `$`*[T: tuple|object](x: T): string =
|
|||
result = "("
|
||||
var firstElement = true
|
||||
for name, value in fieldPairs(x):
|
||||
if not(firstElement): result.add(", ")
|
||||
if not firstElement: result.add(", ")
|
||||
result.add(name)
|
||||
result.add(": ")
|
||||
result.add($value)
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.benign.} =
|
|||
|
||||
proc copyDeepString(src: NimString): NimString {.inline.} =
|
||||
if src != nil:
|
||||
result = rawNewString(src.space)
|
||||
result = rawNewStringNoInit(src.len)
|
||||
result.len = src.len
|
||||
c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
|
||||
c_memcpy(result.data, src.data, src.len + 1)
|
||||
|
||||
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
|
||||
var
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -117,7 +117,7 @@ proc usrToCell(usr: pointer): PCell {.inline.} =
|
|||
# convert pointer to userdata to object (=pointer to refcount)
|
||||
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
|
||||
|
||||
proc canbeCycleRoot(c: PCell): bool {.inline.} =
|
||||
proc canBeCycleRoot(c: PCell): bool {.inline.} =
|
||||
result = ntfAcyclic notin c.typ.flags
|
||||
|
||||
proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
|
||||
|
|
@ -461,6 +461,9 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
|
|||
|
||||
{.pop.}
|
||||
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
zeroMem(result, size)
|
||||
|
|
@ -1050,7 +1053,11 @@ when useMarkForDebug or useBackupGc:
|
|||
markGlobals(gch)
|
||||
|
||||
proc collectCT(gch: var TGcHeap) =
|
||||
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
||||
# stackMarkCosts prevents some pathological behaviour: Stack marking
|
||||
# becomes more expensive with large stacks and large stacks mean that
|
||||
# cells with RC=0 are more likely to be kept alive by the stack.
|
||||
let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
|
||||
if (gch.zct.len >= stackMarkCosts or (cycleGC and
|
||||
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
||||
gch.recGcLock == 0:
|
||||
when useMarkForDebug:
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
|||
return
|
||||
add(gch.zct, res)
|
||||
|
||||
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1: bool): pointer =
|
||||
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer =
|
||||
# generates a new object and sets its reference counter to 0
|
||||
acquire(gch)
|
||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||
|
|
|
|||
|
|
@ -261,6 +261,10 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
|||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
# `newObj` already uses locks, so no need for them here.
|
||||
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ when declared(NimString):
|
|||
# we are in system module:
|
||||
{.pragma: codegenType, compilerproc.}
|
||||
else:
|
||||
{.pragma: codegenType.}
|
||||
{.pragma: codegenType, importc.}
|
||||
|
||||
type
|
||||
# This should be he same as ast.TTypeKind
|
||||
|
|
@ -65,7 +65,7 @@ type
|
|||
tyBigNum,
|
||||
|
||||
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
||||
TNimNode {.codegenType, final.} = object
|
||||
TNimNode {.codegenType.} = object
|
||||
kind: TNimNodeKind
|
||||
offset: int
|
||||
typ: ptr TNimType
|
||||
|
|
@ -78,7 +78,7 @@ type
|
|||
ntfAcyclic = 1, # type cannot form a cycle
|
||||
ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow
|
||||
# version
|
||||
TNimType {.codegenType, final.} = object
|
||||
TNimType {.codegenType.} = object
|
||||
size: int
|
||||
kind: TNimKind
|
||||
flags: set[TNimTypeFlag]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
#
|
||||
# Nim's Runtime Library
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
|
@ -240,6 +240,8 @@ elif defined(nogc) and defined(useMalloc):
|
|||
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||
result = alloc(size)
|
||||
|
||||
proc growObj(old: pointer, newsize: int): pointer =
|
||||
result = realloc(old, newsize)
|
||||
|
|
@ -289,6 +291,10 @@ elif defined(nogc):
|
|||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||
result = alloc0(size)
|
||||
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||
result = alloc(size)
|
||||
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
||||
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||
cast[PGenericSeq](result).len = len
|
||||
|
|
|
|||
|
|
@ -145,8 +145,8 @@ proc readAllFile(file: File): string =
|
|||
proc readAll(file: File): TaintedString =
|
||||
# Separate handling needed because we need to buffer when we
|
||||
# don't know the overall length of the File.
|
||||
var len = rawFileSize(file)
|
||||
if len >= 0:
|
||||
let len = if file != stdin: rawFileSize(file) else: -1
|
||||
if len > 0:
|
||||
result = readAllFile(file, len).TaintedString
|
||||
else:
|
||||
result = readAllBuffer(file).TaintedString
|
||||
|
|
|
|||
|
|
@ -30,18 +30,30 @@ proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
|
|||
if a == b: return true
|
||||
if a == nil or b == nil: return false
|
||||
return a.len == b.len and
|
||||
c_memcmp(a.data, b.data, a.len * sizeof(char)) == 0'i32
|
||||
c_memcmp(a.data, b.data, a.len) == 0'i32
|
||||
|
||||
when declared(allocAtomic):
|
||||
template allocStr(size: expr): expr =
|
||||
cast[NimString](allocAtomic(size))
|
||||
|
||||
template allocStrNoInit(size: expr): expr =
|
||||
cast[NimString](boehmAllocAtomic(size))
|
||||
else:
|
||||
template allocStr(size: expr): expr =
|
||||
cast[NimString](newObj(addr(strDesc), size))
|
||||
|
||||
template allocStrNoInit(size: expr): expr =
|
||||
cast[NimString](newObjNoInit(addr(strDesc), size))
|
||||
|
||||
proc rawNewStringNoInit(space: int): NimString {.compilerProc.} =
|
||||
var s = space
|
||||
if s < 7: s = 7
|
||||
result = allocStrNoInit(sizeof(TGenericSeq) + s + 1)
|
||||
result.reserved = s
|
||||
|
||||
proc rawNewString(space: int): NimString {.compilerProc.} =
|
||||
var s = space
|
||||
if s < 8: s = 7
|
||||
if s < 7: s = 7
|
||||
result = allocStr(sizeof(TGenericSeq) + s + 1)
|
||||
result.reserved = s
|
||||
|
||||
|
|
@ -53,10 +65,10 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
|
|||
var start = max(start, 0)
|
||||
var len = min(last, s.len-1) - start + 1
|
||||
if len > 0:
|
||||
result = rawNewString(len)
|
||||
result = rawNewStringNoInit(len)
|
||||
result.len = len
|
||||
c_memcpy(result.data, addr(s.data[start]), len * sizeof(char))
|
||||
#result.data[len] = '\0'
|
||||
c_memcpy(result.data, addr(s.data[start]), len)
|
||||
result.data[len] = '\0'
|
||||
else:
|
||||
result = rawNewString(len)
|
||||
|
||||
|
|
@ -64,10 +76,9 @@ proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
|
|||
result = copyStrLast(s, start, s.len-1)
|
||||
|
||||
proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
|
||||
result = rawNewString(len)
|
||||
result = rawNewStringNoInit(len)
|
||||
result.len = len
|
||||
c_memcpy(result.data, str, (len+1) * sizeof(char))
|
||||
#result.data[len] = '\0' # readline relies on this!
|
||||
c_memcpy(result.data, str, len + 1)
|
||||
|
||||
proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
|
||||
result = toNimStr(str, c_strlen(str))
|
||||
|
|
@ -77,23 +88,24 @@ proc copyString(src: NimString): NimString {.compilerRtl.} =
|
|||
if (src.reserved and seqShallowFlag) != 0:
|
||||
result = src
|
||||
else:
|
||||
result = rawNewString(src.space)
|
||||
result = rawNewStringNoInit(src.len)
|
||||
result.len = src.len
|
||||
c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
|
||||
c_memcpy(result.data, src.data, src.len + 1)
|
||||
|
||||
proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
|
||||
if src != nil:
|
||||
var s = src.space
|
||||
if s < 8: s = 7
|
||||
when declared(newObjRC1):
|
||||
var s = src.len
|
||||
if s < 7: s = 7
|
||||
result = cast[NimString](newObjRC1(addr(strDesc), sizeof(TGenericSeq) +
|
||||
s+1))
|
||||
result.reserved = s
|
||||
else:
|
||||
result = allocStr(sizeof(TGenericSeq) + s + 1)
|
||||
result.reserved = s
|
||||
result = rawNewStringNoInit(src.len)
|
||||
result.len = src.len
|
||||
c_memcpy(result.data, src.data, src.len + 1)
|
||||
|
||||
|
||||
proc hashString(s: string): int {.compilerproc.} =
|
||||
# the compiler needs exactly the same hash function!
|
||||
# this used to be used for efficient generation of string case statements
|
||||
|
|
@ -113,7 +125,7 @@ proc addChar(s: NimString, c: char): NimString =
|
|||
if result.len >= result.space:
|
||||
result.reserved = resize(result.space)
|
||||
result = cast[NimString](growObj(result,
|
||||
sizeof(TGenericSeq) + (result.reserved+1) * sizeof(char)))
|
||||
sizeof(TGenericSeq) + result.reserved + 1))
|
||||
result.data[result.len] = c
|
||||
result.data[result.len+1] = '\0'
|
||||
inc(result.len)
|
||||
|
|
@ -157,7 +169,7 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
|
|||
result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
|
||||
result.reserved = sp
|
||||
#result = rawNewString(sp)
|
||||
#copyMem(result, dest, dest.len * sizeof(char) + sizeof(TGenericSeq))
|
||||
#copyMem(result, dest, dest.len + sizeof(TGenericSeq))
|
||||
# DO NOT UPDATE LEN YET: dest.len = newLen
|
||||
|
||||
proc appendString(dest, src: NimString) {.compilerproc, inline.} =
|
||||
|
|
@ -264,7 +276,17 @@ proc nimFloatToStr(f: float): string {.compilerproc.} =
|
|||
buf[n] = '.'
|
||||
buf[n+1] = '0'
|
||||
buf[n+2] = '\0'
|
||||
result = $buf
|
||||
# On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' are produced.
|
||||
# We want to get rid of these here:
|
||||
if buf[n-1] == 'N':
|
||||
result = "nan"
|
||||
elif buf[n-1] == 'F':
|
||||
if buf[0] == '-':
|
||||
result = "-inf"
|
||||
else:
|
||||
result = "inf"
|
||||
else:
|
||||
result = $buf
|
||||
|
||||
proc strtod(buf: cstring, endptr: ptr cstring): float64 {.importc,
|
||||
header: "<stdlib.h>", noSideEffect.}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ when useWinVersion:
|
|||
from winlean import SocketHandle
|
||||
else:
|
||||
const
|
||||
versions = "(.10|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
|
||||
versions = "(.10|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
|
||||
when defined(macosx):
|
||||
const
|
||||
DLLSSLName = "libssl" & versions & ".dylib"
|
||||
|
|
@ -141,6 +141,14 @@ const
|
|||
SSL_CTRL_GET_MAX_CERT_LIST* = 50
|
||||
SSL_CTRL_SET_MAX_CERT_LIST* = 51 #* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
|
||||
# * when just a single record has been written): *
|
||||
SSL_CTRL_SET_TLSEXT_SERVERNAME_CB = 53
|
||||
SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG = 54
|
||||
SSL_CTRL_SET_TLSEXT_HOSTNAME = 55
|
||||
TLSEXT_NAMETYPE_host_name* = 0
|
||||
SSL_TLSEXT_ERR_OK* = 0
|
||||
SSL_TLSEXT_ERR_ALERT_WARNING* = 1
|
||||
SSL_TLSEXT_ERR_ALERT_FATAL* = 2
|
||||
SSL_TLSEXT_ERR_NOACK* = 3
|
||||
SSL_MODE_ENABLE_PARTIAL_WRITE* = 1 #* Make it possible to retry SSL_write() with changed buffer location
|
||||
# * (buffer contents must stay the same!); this is not the default to avoid
|
||||
# * the misconception that non-blocking SSL_write() behaves like
|
||||
|
|
@ -296,9 +304,41 @@ proc CRYPTO_malloc_init*() =
|
|||
proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cInt, larg: int, parg: pointer): int{.
|
||||
cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
proc SSL_CTX_callback_ctrl(ctx: SslCtx, typ: cInt, fp: PFunction): int{.
|
||||
cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
proc SSLCTXSetMode*(ctx: SslCtx, mode: int): int =
|
||||
result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil)
|
||||
|
||||
proc SSL_ctrl*(ssl: SslPtr, cmd: cInt, larg: int, parg: pointer): int{.
|
||||
cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
proc SSL_set_tlsext_host_name*(ssl: SslPtr, name: cstring): int =
|
||||
result = SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name)
|
||||
## Set the SNI server name extension to be used in a client hello.
|
||||
## Returns 1 if SNI was set, 0 if current SSL configuration doesn't support SNI.
|
||||
|
||||
|
||||
proc SSL_get_servername*(ssl: SslPtr, typ: cInt = TLSEXT_NAMETYPE_host_name): cstring {.cdecl, dynlib: DLLSSLName, importc.}
|
||||
## Retrieve the server name requested in the client hello. This can be used
|
||||
## in the callback set in `SSL_CTX_set_tlsext_servername_callback` to
|
||||
## implement virtual hosting. May return `nil`.
|
||||
|
||||
proc SSL_CTX_set_tlsext_servername_callback*(ctx: SslCtx, cb: proc(ssl: SslPtr, cb_id: int, arg: pointer): int {.cdecl.}): int =
|
||||
## Set the callback to be used on listening SSL connections when the client hello is received.
|
||||
##
|
||||
## The callback should return one of:
|
||||
## * SSL_TLSEXT_ERR_OK
|
||||
## * SSL_TLSEXT_ERR_ALERT_WARNING
|
||||
## * SSL_TLSEXT_ERR_ALERT_FATAL
|
||||
## * SSL_TLSEXT_ERR_NOACK
|
||||
result = SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cast[PFunction](cb))
|
||||
|
||||
proc SSL_CTX_set_tlsext_servername_arg*(ctx: SslCtx, arg: pointer): int =
|
||||
## Set the pointer to be used in the callback registered to ``SSL_CTX_set_tlsext_servername_callback``.
|
||||
result = SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, arg)
|
||||
|
||||
|
||||
proc bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".}
|
||||
proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".}
|
||||
proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".}
|
||||
|
|
@ -341,8 +381,6 @@ else:
|
|||
dynlib: DLLSSLName, importc.}
|
||||
|
||||
proc SslSetFd*(s: PSSL, fd: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
||||
proc SslCtrl*(ssl: PSSL, cmd: cInt, larg: int, parg: Pointer): int{.cdecl,
|
||||
dynlib: DLLSSLName, importc.}
|
||||
proc SslCTXCtrl*(ctx: PSSL_CTX, cmd: cInt, larg: int, parg: Pointer): int{.
|
||||
cdecl, dynlib: DLLSSLName, importc.}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,6 @@ the Nim compiler itself is written in the Nim programming language
|
|||
the C source of an older version of the compiler are needed to bootstrap the
|
||||
latest version. The C sources are available in a separate repo [here](http://github.com/nim-lang/csources).
|
||||
|
||||
Pre-compiled snapshots of the compiler are also available on
|
||||
[Nimbuild](http://build.nim-lang.org/). Your platform however may not
|
||||
currently be built for.
|
||||
|
||||
The compiler currently supports the following platform and architecture
|
||||
combinations:
|
||||
|
||||
|
|
@ -39,8 +35,7 @@ $ bin/nim c koch
|
|||
$ ./koch boot -d:release
|
||||
```
|
||||
|
||||
``koch install [dir]`` may then be used to install Nim, or you can simply
|
||||
add it to your PATH. More ``koch`` related options are documented in
|
||||
``koch install [dir]`` may then be used to install Nim, but lots of things don't work then so don't do that. Add it to your PATH instead. More ``koch`` related options are documented in
|
||||
[doc/koch.txt](doc/koch.txt).
|
||||
|
||||
The above steps can be performed on Windows in a similar fashion, the
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
discard """
|
||||
line: 21
|
||||
errormsg: "invalid type: 'Table[string, proc (string){.gcsafe.}]'"
|
||||
output: "action 3 arg"
|
||||
"""
|
||||
|
||||
import tables
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ discard """
|
|||
WARNING: false first assertion from bar
|
||||
ERROR: false second assertion from bar
|
||||
-1
|
||||
tests/assert/tfailedassert.nim:27 false assertion from foo
|
||||
tfailedassert.nim:27 false assertion from foo
|
||||
'''
|
||||
"""
|
||||
|
||||
type
|
||||
TLineInfo = tuple[filename: string, line: int]
|
||||
|
||||
TMyError = object of E_Base
|
||||
TMyError = object of Exception
|
||||
lineinfo: TLineInfo
|
||||
|
||||
EMyError = ref TMyError
|
||||
|
|
|
|||
30
tests/ccgbugs/tmissingderef.nim
Normal file
30
tests/ccgbugs/tmissingderef.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
discard """
|
||||
output: '''255
|
||||
1 1
|
||||
0.5'''
|
||||
"""
|
||||
|
||||
# bug #1181
|
||||
|
||||
type
|
||||
TFoo = object
|
||||
x: int32
|
||||
|
||||
proc mainowar =
|
||||
var foo: TFoo
|
||||
foo.x = 0xff
|
||||
var arr1 = cast[ptr array[4, uint8]](addr foo)[] # Fails.
|
||||
echo arr1[when cpuEndian == littleEndian: 0 else: 3]
|
||||
|
||||
var i = 1i32
|
||||
let x = addr i
|
||||
var arr2 = cast[ptr array[4, uint8]](x)[] # Fails.
|
||||
echo arr2[when cpuEndian == littleEndian: 0 else: 3], " ", i
|
||||
|
||||
# bug #1715
|
||||
var a: array[2, float32] = [0.5'f32, 0.7]
|
||||
let p = addr a
|
||||
var b = p[]
|
||||
echo b[0]
|
||||
|
||||
mainowar()
|
||||
15
tests/ccgbugs/tstringslice.nim
Normal file
15
tests/ccgbugs/tstringslice.nim
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
discard """
|
||||
disabled: "true"
|
||||
"""
|
||||
|
||||
# Now the compiler fails with OOM. yay.
|
||||
|
||||
# bug #794
|
||||
type TRange = range[0..3]
|
||||
|
||||
const str = "123456789"
|
||||
|
||||
for i in TRange.low .. TRange.high:
|
||||
echo str[i] #This works fine
|
||||
echo str[int(i) .. int(TRange.high)] #So does this
|
||||
echo str[i .. TRange.high] #The compiler complains about this
|
||||
80
tests/ccgbugs/tuple_canon.nim
Normal file
80
tests/ccgbugs/tuple_canon.nim
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# bug #2250
|
||||
|
||||
import
|
||||
math, strutils
|
||||
|
||||
type
|
||||
Meters = float
|
||||
Point2[T] = tuple[x, y: T]
|
||||
|
||||
HexState* = enum
|
||||
hsOn, hsOff
|
||||
|
||||
Index = uint16
|
||||
|
||||
HexGrid* = object
|
||||
w, h: int ## Width and height of the hex grid.
|
||||
radius: Meters ## Radius of circle that circumscribes a hexagon.
|
||||
grid: seq[HexState] ## Information on what hexes are drawn.
|
||||
|
||||
HexVtxIndex = enum
|
||||
hiA, hiB, hiC, hiD, hiE, hiF
|
||||
|
||||
HexCoord* = Point2[int]
|
||||
|
||||
const
|
||||
HexDY = sqrt(1.0 - (0.5 * 0.5)) # dy from center to midpoint of 1-2
|
||||
HexDX = sqrt(1.0 - (HexDY * HexDY)) # dx from center to midpoint of 1-5 (0.5)
|
||||
|
||||
|
||||
let
|
||||
hexOffsets : array[HexVtxIndex, Point2[float]] = [
|
||||
(-1.0, 0.0),
|
||||
(-HexDX, -HexDY),
|
||||
(HexDX, -HexDY),
|
||||
(1.0, 0.0),
|
||||
(HexDX, HexDY),
|
||||
(-HexDX, HexDY)]
|
||||
|
||||
evenSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
|
||||
((0,0), hiA),
|
||||
((0,0), hiB),
|
||||
((1,-1), hiA),
|
||||
((1,0), hiB),
|
||||
((1,0), hiA),
|
||||
((0,1), hiB)]
|
||||
|
||||
oddSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
|
||||
((0,0), hiA),
|
||||
((0,0), hiB),
|
||||
((1,0), hiA),
|
||||
((1,1), hiB),
|
||||
((1,1), hiA),
|
||||
((0,1), hiB)]
|
||||
|
||||
template odd*(i: int) : expr =
|
||||
(i and 1) != 0
|
||||
|
||||
proc vidx(hg: HexGrid; col, row: int; i: HexVtxIndex) : Index =
|
||||
#NOTE: this variation compiles
|
||||
#var offset : type(evenSharingOffsets[i])
|
||||
#
|
||||
#if odd(col):
|
||||
# offset = oddSharingOffsets[i]
|
||||
#else:
|
||||
# offset = evenSharingOffsets[i]
|
||||
|
||||
let
|
||||
#NOTE: this line generates the bad code
|
||||
offset = (if odd(col): oddSharingOffsets[i] else: evenSharingOffsets[i])
|
||||
x = col + 1 + offset.hc.x
|
||||
y = row + 1 + offset.hc.y
|
||||
|
||||
result = Index(x*2 + y * (hg.w + 2)*2 + int(offset.idx))
|
||||
|
||||
proc go() =
|
||||
var hg : HexGrid
|
||||
|
||||
echo "vidx ", $vidx(hg, 1, 2, hiC)
|
||||
|
||||
go()
|
||||
8
tests/clearmsg/tconsttypemismatch.nim
Normal file
8
tests/clearmsg/tconsttypemismatch.nim
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
discard """
|
||||
file: "tconsttypemismatch.nim"
|
||||
line: 7
|
||||
errormsg: "type mismatch"
|
||||
"""
|
||||
# bug #2252
|
||||
const foo: int = 1000 / 30
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
discard """
|
||||
cmd: "nim cpp $target"
|
||||
cmd: "nim cpp $file"
|
||||
"""
|
||||
|
||||
import rawsockets
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
discard """
|
||||
cmd: "nim cpp $target"
|
||||
cmd: "nim cpp $file"
|
||||
"""
|
||||
|
||||
import typeinfo
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
discard """
|
||||
line: 9
|
||||
errormsg: "'a' is deprecated [Deprecated]"
|
||||
nimout: "a is deprecated [Deprecated]"
|
||||
"""
|
||||
|
||||
var
|
||||
|
|
@ -8,4 +7,3 @@ var
|
|||
|
||||
a[8] = 1
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
discard """
|
||||
line: 20
|
||||
errormsg: " usage of a type with a destructor in a non destructible context"
|
||||
line: 23
|
||||
nimout: " usage of a type with a destructor in a non destructible context"
|
||||
"""
|
||||
|
||||
{.experimental.}
|
||||
|
|
@ -19,5 +19,9 @@ proc open: TMyObj =
|
|||
|
||||
proc `$`(x: TMyObj): string = $x.y
|
||||
|
||||
echo open()
|
||||
proc foo =
|
||||
discard open()
|
||||
|
||||
# XXX doesn't trigger this yet:
|
||||
#echo open()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
discard """
|
||||
line: 7
|
||||
errormsg: "expression 'items' cannot be called"
|
||||
errormsg: "undeclared identifier: 'items'"
|
||||
"""
|
||||
|
||||
type a = enum b,c,d
|
||||
|
|
|
|||
18
tests/exception/tdefer1.nim
Normal file
18
tests/exception/tdefer1.nim
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
discard """
|
||||
output: '''hi
|
||||
hi'''
|
||||
"""
|
||||
|
||||
# bug #1742
|
||||
|
||||
template test(): expr =
|
||||
let a = 0
|
||||
defer: echo "hi"
|
||||
a
|
||||
|
||||
let i = test()
|
||||
|
||||
import strutils
|
||||
let x = try: parseInt("133a")
|
||||
except: -1
|
||||
finally: echo "hi"
|
||||
6
tests/exprs/tresultwarning.nim
Normal file
6
tests/exprs/tresultwarning.nim
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
discard """
|
||||
nimout: "Special variable 'result' is shadowed. [ResultShadowed]"
|
||||
"""
|
||||
|
||||
proc test(): string =
|
||||
var result = "foo"
|
||||
|
|
@ -188,7 +188,7 @@ proc traceTree[T,D](root: PNode[T,D]) =
|
|||
write stdout, space
|
||||
|
||||
proc doTrace(n: PNode[T,D], level: int) =
|
||||
var space = repeatChar(2 * level)
|
||||
var space = spaces(2 * level)
|
||||
traceln(space)
|
||||
write stdout, "node: "
|
||||
if n == nil:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
# Bug #2022
|
||||
|
||||
discard """
|
||||
output: '''@[97, 45]
|
||||
@[true, false]
|
||||
@[false, false]'''
|
||||
"""
|
||||
|
||||
## 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
|
||||
## because it's more efficient than using procedure pointers and less
|
||||
|
|
@ -31,6 +37,7 @@ type Mapped[Input; predicate: static[string]] = object
|
|||
input: Input
|
||||
|
||||
macro map(input, predicate: expr): expr =
|
||||
let predicate = callsite()[2]
|
||||
newNimNode(nnkObjConstr).add(
|
||||
newNimNode(nnkBracketExpr).add(
|
||||
ident"Mapped",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
discard """
|
||||
file: "toop1.nim"
|
||||
output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
|
||||
disabled: "true"
|
||||
"""
|
||||
|
||||
import globalaux, globalaux2
|
||||
|
|
|
|||
54
tests/init/tuninit2.nim
Normal file
54
tests/init/tuninit2.nim
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# bug #2316
|
||||
|
||||
type
|
||||
EventType = enum
|
||||
QuitEvent = 5
|
||||
AppMain* = ref object of RootObj
|
||||
width: int
|
||||
height: int
|
||||
title: string
|
||||
running: bool
|
||||
event_type: EventType
|
||||
App* = ref object of AppMain
|
||||
draw_proc: proc(app: AppMain): void {.closure.}
|
||||
events_proc: proc(app: AppMain): void {.closure.}
|
||||
update_proc: proc(app: AppMain, dt: float): void {.closure.}
|
||||
load_proc: proc(app: AppMain): void {.closure.}
|
||||
|
||||
|
||||
proc initApp*(t: string, w, h: int): App =
|
||||
App(width: w, height: h, title: t, event_type: EventType.QuitEvent)
|
||||
|
||||
|
||||
method getTitle*(self: AppMain): string = self.title
|
||||
method getWidth*(self: AppMain): int = self.width
|
||||
method getHeight*(self: AppMain): int = self.height
|
||||
|
||||
|
||||
method draw*(self: App, draw: proc(app: AppMain)): void =
|
||||
self.draw_proc = draw
|
||||
|
||||
method load*(self: App, load: proc(a: AppMain)): void =
|
||||
self.load_proc = load
|
||||
|
||||
method events*(self: App, events: proc(app: AppMain)): void =
|
||||
self.events_proc = events
|
||||
|
||||
method update*(self: App, update: proc(app: AppMain, delta: float)): void =
|
||||
self.update_proc = update
|
||||
|
||||
method run*(self: App): void = discard
|
||||
|
||||
var mygame = initApp("Example", 800, 600)
|
||||
|
||||
mygame.load(proc(app: AppMain): void =
|
||||
echo app.getTitle()
|
||||
echo app.getWidth()
|
||||
echo app.getHeight()
|
||||
)
|
||||
|
||||
mygame.events(proc(app: AppMain): void =
|
||||
discard
|
||||
)
|
||||
|
||||
mygame.run()
|
||||
|
|
@ -471,7 +471,7 @@ proc build_help*(expected: seq[Tparameter_specification] = @[],
|
|||
let width = prefixes.map(proc (x: string): int = 3 + len(x)).max
|
||||
|
||||
for line in zip(prefixes, helps):
|
||||
result.add(line.a & repeatChar(width - line.a.len) & line.b)
|
||||
result.add(line.a & spaces(width - line.a.len) & line.b)
|
||||
|
||||
|
||||
proc echo_help*(expected: seq[Tparameter_specification] = @[],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import streams
|
||||
from strutils import repeatChar
|
||||
from strutils import repeat
|
||||
|
||||
proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString =
|
||||
var lastChr = length
|
||||
|
|
@ -10,7 +10,7 @@ proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString =
|
|||
proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') =
|
||||
if str.len < length:
|
||||
s.write(str)
|
||||
s.write(repeatChar(length - str.len, padChar))
|
||||
s.write(repeat(padChar, length - str.len))
|
||||
elif str.len > length:
|
||||
s.write(str.substr(0, length - 1))
|
||||
else:
|
||||
|
|
@ -37,7 +37,7 @@ when isMainModule:
|
|||
testStream.setPosition 0
|
||||
testStream.writePaddedStr("Sup", 10)
|
||||
echo(repr(testStream), testStream.data.len)
|
||||
doAssert testStream.data == "Sup"&repeatChar(7, '\0')
|
||||
doAssert testStream.data == "Sup"&repeat('\0', 7)
|
||||
|
||||
testStream.setPosition 0
|
||||
res = testStream.readPaddedStr(10)
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ when isMainModule:
|
|||
discard """block:
|
||||
var
|
||||
TestFile: FileChallengePair
|
||||
contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
|
||||
contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
|
||||
testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
|
||||
testFile.file = checksumStr(contents)
|
||||
myAssets.add testFile"""
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ when defined(recordMode):
|
|||
isRecording = false
|
||||
proc zeroPad*(s: string; minLen: int): string =
|
||||
if s.len < minLen:
|
||||
result = repeatChar(minLen - s.len, '0')
|
||||
result = repeat(0, minLen - s.len)
|
||||
result.add s
|
||||
else:
|
||||
result = s
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ when isMainModule:
|
|||
var res = t.map(proc(z: int): int = result = z * 10)
|
||||
dumpSeq res
|
||||
|
||||
from strutils import toHex, repeatStr
|
||||
from strutils import toHex
|
||||
var foocakes = t.map(proc(z: int): string =
|
||||
result = toHex((z * 23).biggestInt, 4))
|
||||
result = toHex((z * 23).BiggestInt, 4))
|
||||
dumpSeq foocakes
|
||||
|
||||
t.mapInPlace(proc(z: int): int = result = z * 30)
|
||||
|
|
|
|||
|
|
@ -24,17 +24,17 @@ when isMainModule:
|
|||
import strutils
|
||||
var r = compress("Hello")
|
||||
echo repr(r)
|
||||
var l = "Hello".len
|
||||
var rr = uncompress(r, l)
|
||||
var ln = "Hello".len
|
||||
var rr = uncompress(r, ln)
|
||||
echo repr(rr)
|
||||
assert rr == "Hello"
|
||||
|
||||
proc `*`(a: string; b: int): string {.inline.} = result = repeatStr(b, a)
|
||||
proc `*`(a: string; b: int): string {.inline.} = result = repeat(a, b)
|
||||
var s = "yo dude sup bruh homie" * 50
|
||||
r = compress(s)
|
||||
echo s.len, " -> ", r.len
|
||||
|
||||
l = s.len
|
||||
rr = uncompress(r, l)
|
||||
ln = s.len
|
||||
rr = uncompress(r, ln)
|
||||
echo r.len, " -> ", rr.len
|
||||
assert rr == s
|
||||
|
|
@ -174,7 +174,7 @@ when isMainModule:
|
|||
block:
|
||||
var
|
||||
TestFile: FileChallengePair
|
||||
contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
|
||||
contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
|
||||
testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
|
||||
testFile.file = checksumStr(contents)
|
||||
myAssets.add testFile
|
||||
|
|
|
|||
105
tests/misc/parsecomb.nim
Normal file
105
tests/misc/parsecomb.nim
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
type Input[T] = object
|
||||
toks: seq[T]
|
||||
index: int
|
||||
|
||||
type
|
||||
ResultKind* = enum rkSuccess, rkFailure
|
||||
Result*[T, O] = object
|
||||
case kind*: ResultKind
|
||||
of rkSuccess:
|
||||
output*: O
|
||||
input: Input[T]
|
||||
of rkFailure:
|
||||
nil
|
||||
|
||||
type
|
||||
Parser*[T, O] = distinct proc (input: Input[T]): Result[T, O]
|
||||
|
||||
proc unit*[T, O](v: O): Parser[T, O] =
|
||||
Parser(proc (inp: Input[T]): Result[T, O] =
|
||||
Result[T, O](kind: rkSuccess, output: v, input: inp))
|
||||
|
||||
proc fail*[T, O](): Parser[T, O] =
|
||||
Parser(proc (inp: Input[T]): Result[T, O] =
|
||||
Result(kind: rkFailure))
|
||||
|
||||
method runInput[T, O](self: Parser[T, O], inp: Input[T]): Result[T, O] =
|
||||
# hmmm ..
|
||||
type tmp = proc (input: Input[T]): Result[T, O]
|
||||
# XXX: above needed for now, as without the `tmp` bit below, it compiles to invalid C.
|
||||
tmp(self)(inp)
|
||||
|
||||
method run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] =
|
||||
self.runInput(Input[T](toks: toks, index: 0))
|
||||
|
||||
method chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] =
|
||||
Parser(proc (inp: Input[T]): Result[T, O2] =
|
||||
let r = self.runInput(inp)
|
||||
case r.kind:
|
||||
of rkSuccess:
|
||||
nextp(r.output).runInput(r.input)
|
||||
of rkFailure:
|
||||
Result[T, O2](kind: rkFailure))
|
||||
|
||||
method skip[T](self: Input[T], n: int): Input[T] =
|
||||
Input[T](toks: self.toks, index: self.index + n)
|
||||
|
||||
proc pskip*[T](n: int): Parser[T, tuple[]] =
|
||||
Parser(proc (inp: Input[T]): Result[T, tuple[]] =
|
||||
if inp.index + n <= inp.toks.len:
|
||||
Result[T, tuple[]](kind: rkSuccess, output: (), input: inp.skip(n))
|
||||
else:
|
||||
Result[T, tuple[]](kind: rkFailure))
|
||||
|
||||
proc tok*[T](t: T): Parser[T, T] =
|
||||
Parser(proc (inp: Input[T]): Result[T, T] =
|
||||
if inp.index < inp.toks.len and inp.toks[inp.index] == t:
|
||||
pskip[T](1).then(unit[T, T](t)).runInput(inp)
|
||||
else:
|
||||
Result[T, T](kind: rkFailure))
|
||||
|
||||
proc `+`*[T, O](first: Parser[T, O], second: Parser[T, O]): Parser[T, O] =
|
||||
Parser(proc (inp: Input[T]): Result[T, O] =
|
||||
let r = first.runInput(inp)
|
||||
case r.kind
|
||||
of rkSuccess:
|
||||
r
|
||||
else:
|
||||
second.runInput(inp))
|
||||
|
||||
# end of primitives (definitions involving Parser(..))
|
||||
|
||||
method map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] =
|
||||
self.chain(proc (v: O1): Parser[T, O2] =
|
||||
unit[T, O2](p(v)))
|
||||
|
||||
method then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] =
|
||||
self.chain(proc (v: O1): Parser[T, O2] =
|
||||
next)
|
||||
|
||||
proc `*`*[T, O1, O2](first: Parser[T, O1], second: Parser[T, O2]): Parser[T, (O1, O2)] =
|
||||
first.chain(proc (v1: O1): Parser[T, (O1, O2)] =
|
||||
second.map(proc (v2: O2): (O1, O2) =
|
||||
(v1, v2)))
|
||||
|
||||
proc repeat0*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
|
||||
var nothing = unit[T, seq[O]](@[])
|
||||
inner.chain(proc(v: O): Parser[T, seq[O]] =
|
||||
repeat0(inner).map(proc(vs: seq[O]): seq[O] =
|
||||
@[v] & vs)) + nothing
|
||||
|
||||
proc repeat1*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
|
||||
inner.chain(proc(v: O): Parser[T, seq[O]] =
|
||||
repeat0(inner).map(proc(vs: seq[O]): seq[O] =
|
||||
@[v] & vs))
|
||||
|
||||
proc leftRec*[T, O, A](inner: Parser[T, O], after: Parser[T, A], fold: proc(i: O, a: A): O): Parser[T, O] =
|
||||
(inner*repeat0(after)).map(proc(ias: (O, seq[A])): O =
|
||||
var (i, asx) = ias
|
||||
for a in asx:
|
||||
i = fold(i, a)
|
||||
i)
|
||||
|
||||
proc lazy*[T, O](inner: proc(): Parser[T, O]): Parser[T, O] =
|
||||
unit[T, tuple[]](()).chain(proc(v: tuple[]): Parser[T, O] =
|
||||
inner())
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
discard """
|
||||
file: "tissue710.nim"
|
||||
line: 8
|
||||
errorMsg: "expression '||' cannot be called"
|
||||
errorMsg: "undeclared identifier: '||'"
|
||||
"""
|
||||
var sum = 0
|
||||
for x in 3..1000:
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue