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)
|
nkTypeOfExpr, # type(1+2)
|
||||||
nkObjectTy, # object body
|
nkObjectTy, # object body
|
||||||
nkTupleTy, # tuple body
|
nkTupleTy, # tuple body
|
||||||
|
nkTupleClassTy, # tuple type class
|
||||||
nkTypeClassTy, # user-defined type class
|
nkTypeClassTy, # user-defined type class
|
||||||
nkStaticTy, # ``static[T]``
|
nkStaticTy, # ``static[T]``
|
||||||
nkRecList, # list of object parts
|
nkRecList, # list of object parts
|
||||||
|
|
@ -458,7 +459,7 @@ type
|
||||||
tfNotNil, # type cannot be 'nil'
|
tfNotNil, # type cannot be 'nil'
|
||||||
|
|
||||||
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
|
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
|
||||||
# other type so that it requires inititalization
|
# other type so that it requires initalization
|
||||||
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
|
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
|
||||||
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
||||||
# or other type classes
|
# or other type classes
|
||||||
|
|
@ -946,10 +947,7 @@ template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
||||||
n.sons[i -| n] = s
|
n.sons[i -| n] = s
|
||||||
|
|
||||||
when defined(useNodeIds):
|
when defined(useNodeIds):
|
||||||
const nodeIdToDebug* = -1 # 884953 # 612794
|
const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
|
||||||
#612840 # 612905 # 614635 # 614637 # 614641
|
|
||||||
# 423408
|
|
||||||
#429107 # 430443 # 441048 # 441090 # 441153
|
|
||||||
var gNodeId: int
|
var gNodeId: int
|
||||||
|
|
||||||
proc newNode*(kind: TNodeKind): PNode =
|
proc newNode*(kind: TNodeKind): PNode =
|
||||||
|
|
@ -1320,7 +1318,7 @@ proc isGCedMem*(t: PType): bool {.inline.} =
|
||||||
t.kind == tyProc and t.callConv == ccClosure
|
t.kind == tyProc and t.callConv == ccClosure
|
||||||
|
|
||||||
proc propagateToOwner*(owner, elem: PType) =
|
proc propagateToOwner*(owner, elem: PType) =
|
||||||
const HaveTheirOwnEmpty = {tySequence, tySet}
|
const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc}
|
||||||
owner.flags = owner.flags + (elem.flags * {tfHasMeta})
|
owner.flags = owner.flags + (elem.flags * {tfHasMeta})
|
||||||
if tfNotNil in elem.flags:
|
if tfNotNil in elem.flags:
|
||||||
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
|
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
|
||||||
|
|
|
||||||
|
|
@ -203,9 +203,9 @@ proc mustRehash(length, counter: int): bool =
|
||||||
assert(length > counter)
|
assert(length > counter)
|
||||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||||
|
|
||||||
proc spaces(x: int): PRope =
|
proc rspaces(x: int): PRope =
|
||||||
# returns x spaces
|
# returns x spaces
|
||||||
result = toRope(repeatChar(x))
|
result = toRope(spaces(x))
|
||||||
|
|
||||||
proc toYamlChar(c: char): string =
|
proc toYamlChar(c: char): string =
|
||||||
case c
|
case c
|
||||||
|
|
@ -253,7 +253,7 @@ proc typeToYamlAux(n: PType, marker: var IntSet,
|
||||||
indent, maxRecDepth: int): PRope
|
indent, maxRecDepth: int): PRope
|
||||||
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
||||||
maxRecDepth: int): PRope =
|
maxRecDepth: int): PRope =
|
||||||
var istr = spaces(indent + 2)
|
var istr = rspaces(indent + 2)
|
||||||
result = toRope("[")
|
result = toRope("[")
|
||||||
var mycount = 0
|
var mycount = 0
|
||||||
for i in countup(0, high(n.data)):
|
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",
|
appf(result, "$N$1$2",
|
||||||
[istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
|
[istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
|
||||||
inc(mycount)
|
inc(mycount)
|
||||||
if mycount > 0: appf(result, "$N$1", [spaces(indent)])
|
if mycount > 0: appf(result, "$N$1", [rspaces(indent)])
|
||||||
app(result, "]")
|
app(result, "]")
|
||||||
assert(mycount == n.counter)
|
assert(mycount == n.counter)
|
||||||
|
|
||||||
proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
|
proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
|
||||||
# array of (name, value) pairs
|
# array of (name, value) pairs
|
||||||
var istr = spaces(indent + 2)
|
var istr = rspaces(indent + 2)
|
||||||
result = toRope("{")
|
result = toRope("{")
|
||||||
var i = 0
|
var i = 0
|
||||||
while i <= high(c):
|
while i <= high(c):
|
||||||
if i > 0: app(result, ",")
|
if i > 0: app(result, ",")
|
||||||
appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
|
appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
|
||||||
inc(i, 2)
|
inc(i, 2)
|
||||||
appf(result, "$N$1}", [spaces(indent)])
|
appf(result, "$N$1}", [rspaces(indent)])
|
||||||
|
|
||||||
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
|
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
|
||||||
maxRecDepth: int): PRope =
|
maxRecDepth: int): PRope =
|
||||||
|
|
@ -310,9 +310,9 @@ proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
|
||||||
result = toRope("[")
|
result = toRope("[")
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: app(result, ",")
|
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)])
|
marker, indent + 4, maxRecDepth - 1)])
|
||||||
appf(result, "$N$1]", [spaces(indent + 2)])
|
appf(result, "$N$1]", [rspaces(indent + 2)])
|
||||||
else:
|
else:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
result = ropeConstr(indent, [toRope("kind"),
|
result = ropeConstr(indent, [toRope("kind"),
|
||||||
|
|
@ -331,7 +331,7 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
|
||||||
if n == nil:
|
if n == nil:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
else:
|
else:
|
||||||
var istr = spaces(indent + 2)
|
var istr = rspaces(indent + 2)
|
||||||
result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
|
result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
|
||||||
if maxRecDepth != 0:
|
if maxRecDepth != 0:
|
||||||
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
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])
|
appf(result, ",$N$1\"sons\": [", [istr])
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: app(result, ",")
|
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)])
|
marker, indent + 4, maxRecDepth - 1)])
|
||||||
appf(result, "$N$1]", [istr])
|
appf(result, "$N$1]", [istr])
|
||||||
appf(result, ",$N$1\"typ\": $2",
|
appf(result, ",$N$1\"typ\": $2",
|
||||||
[istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
|
[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 =
|
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||||
var marker = initIntSet()
|
var marker = initIntSet()
|
||||||
|
|
@ -408,7 +408,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
||||||
if n == nil:
|
if n == nil:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
else:
|
else:
|
||||||
var istr = spaces(indent + 2)
|
var istr = rspaces(indent + 2)
|
||||||
result = ropef("{$N$1\"kind\": $2",
|
result = ropef("{$N$1\"kind\": $2",
|
||||||
[istr, makeYamlString($n.kind)])
|
[istr, makeYamlString($n.kind)])
|
||||||
if maxRecDepth != 0:
|
if maxRecDepth != 0:
|
||||||
|
|
@ -440,11 +440,11 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
||||||
appf(result, ",$N$1\"sons\": [", [istr])
|
appf(result, ",$N$1\"sons\": [", [istr])
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: app(result, ",")
|
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)])
|
indent + 4, maxRecDepth - 1, renderType)])
|
||||||
appf(result, "$N$1]", [istr])
|
appf(result, "$N$1]", [istr])
|
||||||
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
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) =
|
proc debug(n: PSym) =
|
||||||
if n == nil:
|
if n == nil:
|
||||||
|
|
@ -681,9 +681,8 @@ proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
|
||||||
else: result = nextIdentIter(ti, tab)
|
else: result = nextIdentIter(ti, tab)
|
||||||
|
|
||||||
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
||||||
var h, start: THash
|
var h = ti.h and high(tab.data)
|
||||||
h = ti.h and high(tab.data)
|
var start = h
|
||||||
start = h
|
|
||||||
result = tab.data[h]
|
result = tab.data[h]
|
||||||
while result != nil:
|
while result != nil:
|
||||||
if result.name.id == ti.name.id: break
|
if result.name.id == ti.name.id: break
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
||||||
let typ = skipTypes(ri.sons[0].typ, abstractInst)
|
let typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||||
if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
|
if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
|
||||||
result.app(~"(")
|
result.app(~"(")
|
||||||
|
if 1 < ri.len:
|
||||||
result.app genOtherArg(p, ri, 1, typ)
|
result.app genOtherArg(p, ri, 1, typ)
|
||||||
for k in j+1 .. < ri.len:
|
for k in j+1 .. < ri.len:
|
||||||
result.app(~", ")
|
result.app(~", ")
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,6 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
|
||||||
case skipTypes(ty, abstractVarRange).kind
|
case skipTypes(ty, abstractVarRange).kind
|
||||||
of tyChar, tyNil:
|
of tyChar, tyNil:
|
||||||
result = intLiteral(n.intVal)
|
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:
|
of tyBool:
|
||||||
if n.intVal != 0: result = ~"NIM_TRUE"
|
if n.intVal != 0: result = ~"NIM_TRUE"
|
||||||
else: result = ~"NIM_FALSE"
|
else: result = ~"NIM_FALSE"
|
||||||
|
|
@ -954,7 +949,7 @@ proc genEcho(p: BProc, n: PNode) =
|
||||||
initLocExpr(p, n.sons[i], a)
|
initLocExpr(p, n.sons[i], a)
|
||||||
appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
|
appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
|
||||||
linefmt(p, cpsStmts, "printf($1$2);$n",
|
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) =
|
proc gcUsage(n: PNode) =
|
||||||
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
|
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ proc getUniqueType*(key: PType): PType =
|
||||||
gCanonicalTypes[k] = key
|
gCanonicalTypes[k] = key
|
||||||
result = key
|
result = key
|
||||||
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
|
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
|
||||||
internalError("GetUniqueType")
|
internalError("getUniqueType")
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
if key.deepCopy != nil: result = key
|
if key.deepCopy != nil: result = key
|
||||||
else: result = getUniqueType(lastSon(key))
|
else: result = getUniqueType(lastSon(key))
|
||||||
|
|
@ -135,7 +135,7 @@ proc getUniqueType*(key: PType): PType =
|
||||||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||||
for h in countup(0, high(gTypeTable[k].data)):
|
for h in countup(0, high(gTypeTable[k].data)):
|
||||||
var t = PType(gTypeTable[k].data[h].key)
|
var t = PType(gTypeTable[k].data[h].key)
|
||||||
if t != nil and sameType(t, key):
|
if t != nil and sameBackendType(t, key):
|
||||||
return t
|
return t
|
||||||
idTablePut(gTypeTable[k], key, key)
|
idTablePut(gTypeTable[k], key, key)
|
||||||
result = key
|
result = key
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
|
||||||
let field = getField(typ.n, i)
|
let field = getField(typ.n, i)
|
||||||
pack(it, field.typ, res +! field.offset)
|
pack(it, field.typ, res +! field.offset)
|
||||||
else:
|
else:
|
||||||
|
# XXX: todo
|
||||||
globalError(x.info, "cannot pack unnamed tuple")
|
globalError(x.info, "cannot pack unnamed tuple")
|
||||||
|
|
||||||
const maxPackDepth = 20
|
const maxPackDepth = 20
|
||||||
|
|
|
||||||
|
|
@ -572,6 +572,9 @@ proc footprint(filename: string): TCrc32 =
|
||||||
getCompileCFileCmd(filename, true)
|
getCompileCFileCmd(filename, true)
|
||||||
|
|
||||||
proc externalFileChanged(filename: string): bool =
|
proc externalFileChanged(filename: string): bool =
|
||||||
|
if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
|
||||||
|
return false
|
||||||
|
|
||||||
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
||||||
var currentCrc = int(footprint(filename))
|
var currentCrc = int(footprint(filename))
|
||||||
var f: File
|
var f: File
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,11 @@ const
|
||||||
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
|
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
|
||||||
|
|
||||||
proc newLine(p: var TTmplParser) =
|
proc newLine(p: var TTmplParser) =
|
||||||
llStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
|
llStreamWrite(p.outp, repeat(')', p.emitPar))
|
||||||
p.emitPar = 0
|
p.emitPar = 0
|
||||||
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
|
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
|
||||||
if p.pendingExprLine:
|
if p.pendingExprLine:
|
||||||
llStreamWrite(p.outp, repeatChar(2))
|
llStreamWrite(p.outp, spaces(2))
|
||||||
p.pendingExprLine = false
|
p.pendingExprLine = false
|
||||||
|
|
||||||
proc scanPar(p: var TTmplParser, d: int) =
|
proc scanPar(p: var TTmplParser, d: int) =
|
||||||
|
|
@ -88,24 +88,24 @@ proc parseLine(p: var TTmplParser) =
|
||||||
else:
|
else:
|
||||||
p.info.col = int16(j)
|
p.info.col = int16(j)
|
||||||
localError(p.info, errXNotAllowedHere, "end")
|
localError(p.info, errXNotAllowedHere, "end")
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
llStreamWrite(p.outp, spaces(p.indent))
|
||||||
llStreamWrite(p.outp, "#end")
|
llStreamWrite(p.outp, "#end")
|
||||||
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
|
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
|
||||||
wConverter, wMacro, wTemplate, wMethod:
|
wConverter, wMacro, wTemplate, wMethod:
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
llStreamWrite(p.outp, spaces(p.indent))
|
||||||
llStreamWrite(p.outp, substr(p.x, d))
|
llStreamWrite(p.outp, substr(p.x, d))
|
||||||
inc(p.indent, 2)
|
inc(p.indent, 2)
|
||||||
of wElif, wOf, wElse, wExcept, wFinally:
|
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))
|
llStreamWrite(p.outp, substr(p.x, d))
|
||||||
of wLet, wVar, wConst, wType:
|
of wLet, wVar, wConst, wType:
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
llStreamWrite(p.outp, spaces(p.indent))
|
||||||
llStreamWrite(p.outp, substr(p.x, d))
|
llStreamWrite(p.outp, substr(p.x, d))
|
||||||
if not p.x.contains({':', '='}):
|
if not p.x.contains({':', '='}):
|
||||||
# no inline element --> treat as block:
|
# no inline element --> treat as block:
|
||||||
inc(p.indent, 2)
|
inc(p.indent, 2)
|
||||||
else:
|
else:
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
llStreamWrite(p.outp, spaces(p.indent))
|
||||||
llStreamWrite(p.outp, substr(p.x, d))
|
llStreamWrite(p.outp, substr(p.x, d))
|
||||||
p.state = psDirective
|
p.state = psDirective
|
||||||
else:
|
else:
|
||||||
|
|
@ -120,11 +120,11 @@ proc parseLine(p: var TTmplParser) =
|
||||||
# next line of string literal:
|
# next line of string literal:
|
||||||
llStreamWrite(p.outp, p.conc)
|
llStreamWrite(p.outp, p.conc)
|
||||||
llStreamWrite(p.outp, "\n")
|
llStreamWrite(p.outp, "\n")
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent + 2))
|
llStreamWrite(p.outp, spaces(p.indent + 2))
|
||||||
llStreamWrite(p.outp, "\"")
|
llStreamWrite(p.outp, "\"")
|
||||||
of psDirective:
|
of psDirective:
|
||||||
newLine(p)
|
newLine(p)
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
llStreamWrite(p.outp, spaces(p.indent))
|
||||||
llStreamWrite(p.outp, p.emit)
|
llStreamWrite(p.outp, p.emit)
|
||||||
llStreamWrite(p.outp, "(\"")
|
llStreamWrite(p.outp, "(\"")
|
||||||
inc(p.emitPar)
|
inc(p.emitPar)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ proc getModuleName*(n: PNode): string =
|
||||||
result = n.ident.s
|
result = n.ident.s
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = n.sym.name.s
|
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:
|
if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
|
||||||
# XXX hack ahead:
|
# XXX hack ahead:
|
||||||
n.kind = nkImportAs
|
n.kind = nkImportAs
|
||||||
|
|
|
||||||
|
|
@ -780,7 +780,7 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
moveInto(p, stmt, r)
|
moveInto(p, stmt, r)
|
||||||
appf(p.body, "}$n" | "end$n")
|
appf(p.body, "}$n" | "end$n")
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
app(p.body, repeatChar(toClose, '}') & tnl)
|
app(p.body, repeat('}', toClose) & tnl)
|
||||||
else:
|
else:
|
||||||
for i in 1..toClose: appf(p.body, "end$n")
|
for i in 1..toClose: appf(p.body, "end$n")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ proc llStreamOpen*(data: string): PLLStream =
|
||||||
result.s = data
|
result.s = data
|
||||||
result.kind = llsString
|
result.kind = llsString
|
||||||
|
|
||||||
proc llStreamOpen*(f: var File): PLLStream =
|
proc llStreamOpen*(f: File): PLLStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.f = f
|
result.f = f
|
||||||
result.kind = llsFile
|
result.kind = llsFile
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||||
if sfExported in sym.flags:
|
if sfExported in sym.flags:
|
||||||
# add to interface:
|
# add to interface:
|
||||||
if c.module != nil: strTableAdd(c.module.tab, sym)
|
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) =
|
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||||
addDeclAt(scope, sym)
|
addDeclAt(scope, sym)
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,8 @@ type
|
||||||
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
||||||
warnEachIdentIsTuple, warnShadowIdent,
|
warnEachIdentIsTuple, warnShadowIdent,
|
||||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnUser,
|
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||||
|
warnUser,
|
||||||
hintSuccess, hintSuccessX,
|
hintSuccess, hintSuccessX,
|
||||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||||
|
|
@ -391,6 +392,7 @@ const
|
||||||
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
|
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]",
|
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]",
|
warnLockLevel: "$1 [LockLevel]",
|
||||||
|
warnResultShadowed: "Special variable 'result' is shadowed. [ResultShadowed]",
|
||||||
warnUser: "$1 [User]",
|
warnUser: "$1 [User]",
|
||||||
hintSuccess: "operation successful [Success]",
|
hintSuccess: "operation successful [Success]",
|
||||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
|
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
|
||||||
|
|
@ -411,7 +413,7 @@ const
|
||||||
hintUser: "$1 [User]"]
|
hintUser: "$1 [User]"]
|
||||||
|
|
||||||
const
|
const
|
||||||
WarningsToStr*: array[0..29, string] = ["CannotOpenFile", "OctalEscape",
|
WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape",
|
||||||
"XIsNeverRead", "XmightNotBeenInit",
|
"XIsNeverRead", "XmightNotBeenInit",
|
||||||
"Deprecated", "ConfigDeprecated",
|
"Deprecated", "ConfigDeprecated",
|
||||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||||
|
|
@ -421,7 +423,7 @@ const
|
||||||
"TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
|
"TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
|
||||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||||
"GcMem", "Destructor", "LockLevel", "User"]
|
"GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
|
||||||
|
|
||||||
HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
|
HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
|
||||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||||
|
|
@ -784,7 +786,7 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||||
proc writeSurroundingSrc(info: TLineInfo) =
|
proc writeSurroundingSrc(info: TLineInfo) =
|
||||||
const indent = " "
|
const indent = " "
|
||||||
msgWriteln(indent & info.sourceLine.ropeToStr)
|
msgWriteln(indent & info.sourceLine.ropeToStr)
|
||||||
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
|
msgWriteln(indent & spaces(info.col) & '^')
|
||||||
|
|
||||||
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||||
let frmt = case msg
|
let frmt = case msg
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,4 @@ define:useStdoutAsStdmsg
|
||||||
cs:partial
|
cs:partial
|
||||||
#define:useNodeIds
|
#define:useNodeIds
|
||||||
symbol:nimfix
|
symbol:nimfix
|
||||||
|
#gc:markAndSweep
|
||||||
|
|
|
||||||
|
|
@ -166,4 +166,4 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
|
||||||
inc(i)
|
inc(i)
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
if marker:
|
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 ']'
|
#| [' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
||||||
#| extTupleDecl = 'tuple'
|
#| extTupleDecl = 'tuple'
|
||||||
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
||||||
|
#| tupleClass = 'tuple'
|
||||||
result = newNodeP(nkTupleTy, p)
|
result = newNodeP(nkTupleTy, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
if p.tok.tokType == tkBracketLe:
|
if p.tok.tokType == tkBracketLe:
|
||||||
|
|
@ -894,6 +895,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
||||||
parMessage(p, errIdentifierExpected, p.tok)
|
parMessage(p, errIdentifierExpected, p.tok)
|
||||||
break
|
break
|
||||||
if not sameInd(p): break
|
if not sameInd(p): break
|
||||||
|
else:
|
||||||
|
result = newNodeP(nkTupleClassTy, p)
|
||||||
|
|
||||||
proc parseParamList(p: var TParser, retColon = true): PNode =
|
proc parseParamList(p: var TParser, retColon = true): PNode =
|
||||||
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
||||||
let filename = fileIdx.toFullPathConsiderDirty
|
let filename = fileIdx.toFullPathConsiderDirty
|
||||||
if module.name.s == "-":
|
if module.name.s == "-":
|
||||||
module.name.s = "stdinfile"
|
module.name.s = "stdinfile"
|
||||||
s = llStreamOpenStdIn()
|
s = llStreamOpen(stdin)
|
||||||
else:
|
else:
|
||||||
s = llStreamOpen(filename, fmRead)
|
s = llStreamOpen(filename, fmRead)
|
||||||
if s == nil:
|
if s == nil:
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
|
||||||
|
|
||||||
proc addPendingNL(g: var TSrcGen) =
|
proc addPendingNL(g: var TSrcGen) =
|
||||||
if g.pendingNL >= 0:
|
if g.pendingNL >= 0:
|
||||||
addTok(g, tkSpaces, "\n" & repeatChar(g.pendingNL))
|
addTok(g, tkSpaces, "\n" & spaces(g.pendingNL))
|
||||||
g.lineLen = g.pendingNL
|
g.lineLen = g.pendingNL
|
||||||
g.pendingNL = - 1
|
g.pendingNL = - 1
|
||||||
|
|
||||||
|
|
@ -190,7 +190,7 @@ proc putComment(g: var TSrcGen, s: string) =
|
||||||
if not isCode and (g.lineLen + (j - i) > MaxLineLen):
|
if not isCode and (g.lineLen + (j - i) > MaxLineLen):
|
||||||
put(g, tkComment, com)
|
put(g, tkComment, com)
|
||||||
optNL(g, ind)
|
optNL(g, ind)
|
||||||
com = '#' & repeatChar(comIndent)
|
com = '#' & spaces(comIndent)
|
||||||
while s[i] > ' ':
|
while s[i] > ' ':
|
||||||
add(com, s[i])
|
add(com, s[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
@ -280,7 +280,7 @@ proc gcom(g: var TSrcGen, n: PNode) =
|
||||||
(g.lineLen < LineCommentColumn):
|
(g.lineLen < LineCommentColumn):
|
||||||
var ml = maxLineLength(n.comment)
|
var ml = maxLineLength(n.comment)
|
||||||
if ml + LineCommentColumn <= MaxLineLen:
|
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);
|
putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
|
||||||
|
|
||||||
proc gcoms(g: var TSrcGen) =
|
proc gcoms(g: var TSrcGen) =
|
||||||
|
|
@ -395,6 +395,7 @@ proc lsub(n: PNode): int =
|
||||||
of nkClosedSymChoice, nkOpenSymChoice:
|
of nkClosedSymChoice, nkOpenSymChoice:
|
||||||
result = lsons(n) + len("()") + sonsLen(n) - 1
|
result = lsons(n) + len("()") + sonsLen(n) - 1
|
||||||
of nkTupleTy: result = lcomma(n) + len("tuple[]")
|
of nkTupleTy: result = lcomma(n) + len("tuple[]")
|
||||||
|
of nkTupleClassTy: result = len("tuple")
|
||||||
of nkDotExpr: result = lsons(n) + 1
|
of nkDotExpr: result = lsons(n) + 1
|
||||||
of nkBind: result = lsons(n) + len("bind_")
|
of nkBind: result = lsons(n) + len("bind_")
|
||||||
of nkBindStmt: result = lcomma(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])
|
gsub(g, n.sons[0])
|
||||||
of nkTupleTy:
|
of nkTupleTy:
|
||||||
put(g, tkTuple, "tuple")
|
put(g, tkTuple, "tuple")
|
||||||
if sonsLen(n) > 0:
|
|
||||||
put(g, tkBracketLe, "[")
|
put(g, tkBracketLe, "[")
|
||||||
gcomma(g, n)
|
gcomma(g, n)
|
||||||
put(g, tkBracketRi, "]")
|
put(g, tkBracketRi, "]")
|
||||||
|
of nkTupleClassTy:
|
||||||
|
put(g, tkTuple, "tuple")
|
||||||
of nkMetaNode_Obsolete:
|
of nkMetaNode_Obsolete:
|
||||||
put(g, tkParLe, "(META|")
|
put(g, tkParLe, "(META|")
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
|
|
|
||||||
|
|
@ -41,20 +41,28 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
best, alt: var TCandidate,
|
best, alt: var TCandidate,
|
||||||
errors: var CandidateErrors) =
|
errors: var CandidateErrors) =
|
||||||
var o: TOverloadIter
|
var o: TOverloadIter
|
||||||
var sym = initOverloadIter(o, c, headSymbol)
|
# thanks to the lazy semchecking for operands, we need to iterate over the
|
||||||
var symScope = o.lastOverloadScope
|
# 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
|
var z: TCandidate
|
||||||
|
initCandidate(c, best, syms[0][0], initialBinding, symScope)
|
||||||
if sym == nil: return
|
initCandidate(c, alt, syms[0][0], initialBinding, symScope)
|
||||||
initCandidate(c, best, sym, initialBinding, symScope)
|
|
||||||
initCandidate(c, alt, sym, initialBinding, symScope)
|
|
||||||
best.state = csNoMatch
|
best.state = csNoMatch
|
||||||
|
|
||||||
while sym != nil:
|
for i in 0 .. <syms.len:
|
||||||
if sym.kind in filter:
|
let sym = syms[i][0]
|
||||||
determineType(c, sym)
|
determineType(c, sym)
|
||||||
initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
|
initCandidate(c, z, sym, initialBinding, syms[i][1])
|
||||||
z.calleeSym = sym
|
z.calleeSym = sym
|
||||||
|
|
||||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
||||||
|
|
@ -75,14 +83,13 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
if cmp < 0: best = z # x is better than the best so far
|
if cmp < 0: best = z # x is better than the best so far
|
||||||
elif cmp == 0: alt = z # x is as good as the best so far
|
elif cmp == 0: alt = z # x is as good as the best so far
|
||||||
else: discard
|
else: discard
|
||||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
#if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516:
|
||||||
# echo "Matches ", n.info, " ", typeToString(sym.typ)
|
# echo "Matches ", n.info, " ", typeToString(sym.typ)
|
||||||
# debug sym
|
# debug sym
|
||||||
# writeMatches(z)
|
# writeMatches(z)
|
||||||
# for i in 1 .. <len(z.call):
|
# for i in 1 .. <len(z.call):
|
||||||
# z.call[i].typ.debug
|
# z.call[i].typ.debug
|
||||||
# quit 1
|
# quit 1
|
||||||
sym = nextOverloadIter(o, c, headSymbol)
|
|
||||||
|
|
||||||
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
# 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)
|
addSonSkipIntLit(typ, n.sons[i].typ)
|
||||||
result.typ = 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) =
|
proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkRecList:
|
of nkRecList:
|
||||||
|
|
@ -2055,7 +2063,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkBind:
|
of nkBind:
|
||||||
message(n.info, warnDeprecated, "bind")
|
message(n.info, warnDeprecated, "bind")
|
||||||
result = semExpr(c, n.sons[0], flags)
|
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})
|
var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
|
||||||
result.typ = makeTypeDesc(c, typ)
|
result.typ = makeTypeDesc(c, typ)
|
||||||
#result = symNodeFromType(c, typ, n.info)
|
#result = symNodeFromType(c, typ, n.info)
|
||||||
|
|
@ -2129,7 +2137,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkPar:
|
of nkPar:
|
||||||
case checkPar(n)
|
case checkPar(n)
|
||||||
of paNone: result = errorNode(c, 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 paTupleFields: result = semTupleFieldsConstr(c, n, flags)
|
||||||
of paSingle: result = semExpr(c, n.sons[0], flags)
|
of paSingle: result = semExpr(c, n.sons[0], flags)
|
||||||
of nkCurly: result = semSetConstr(c, n)
|
of nkCurly: result = semSetConstr(c, n)
|
||||||
|
|
|
||||||
|
|
@ -356,7 +356,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
of nkIdent: a = n.sons[i]
|
of nkIdent: a = n.sons[i]
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
||||||
of nkObjectTy, nkTupleTy:
|
of nkObjectTy, nkTupleTy, nkTupleClassTy:
|
||||||
discard
|
discard
|
||||||
of nkFormalParams:
|
of nkFormalParams:
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
|
||||||
if g.kind == skUnknown:
|
if g.kind == skUnknown:
|
||||||
var field: PSym = nil
|
var field: PSym = nil
|
||||||
var ty = n.sons[0].typ.skipTypes(abstractPtrs)
|
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)
|
field = lookupInRecord(ty.n, g.name)
|
||||||
else:
|
else:
|
||||||
while ty != nil and ty.kind == tyObject:
|
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
|
elif tup.kind == tyTuple and def.kind == nkPar and
|
||||||
a.kind == nkIdentDefs and a.len > 3:
|
a.kind == nkIdentDefs and a.len > 3:
|
||||||
message(a.info, warnEachIdentIsTuple)
|
message(a.info, warnEachIdentIsTuple)
|
||||||
|
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var v = semIdentDef(c, a.sons[j], symkind)
|
var v = semIdentDef(c, a.sons[j], symkind)
|
||||||
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
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)
|
let shadowed = findShadowedVar(c, v)
|
||||||
if shadowed != nil:
|
if shadowed != nil:
|
||||||
shadowed.flags.incl(sfShadowed)
|
shadowed.flags.incl(sfShadowed)
|
||||||
|
if shadowed.kind == skResult:
|
||||||
|
message(a.info, warnResultShadowed)
|
||||||
# a shadowed variable is an error unless it appears on the right
|
# a shadowed variable is an error unless it appears on the right
|
||||||
# side of the '=':
|
# side of the '=':
|
||||||
if warnShadowIdent in gNotes and not identWithin(def, v.name):
|
if warnShadowIdent in gNotes and not identWithin(def, v.name):
|
||||||
|
|
@ -692,7 +695,7 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||||
assignType(s.typ, t)
|
assignType(s.typ, t)
|
||||||
s.typ.id = t.id # same id
|
s.typ.id = t.id # same id
|
||||||
checkConstructedType(s.info, s.typ)
|
checkConstructedType(s.info, s.typ)
|
||||||
if s.typ.kind in {tyObject, tyTuple}:
|
if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
|
||||||
checkForMetaFields(s.typ.n)
|
checkForMetaFields(s.typ.n)
|
||||||
let aa = a.sons[2]
|
let aa = a.sons[2]
|
||||||
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
|
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)
|
result = semStmt(c, x)
|
||||||
# since a proc annotation can set pragmas, we process these here again.
|
# since a proc annotation can set pragmas, we process these here again.
|
||||||
# This is required for SqueakNim-like export pragmas.
|
# This is required for SqueakNim-like export pragmas.
|
||||||
if result[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)
|
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -345,8 +345,14 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
localError(n.info, errIdentifierExpected)
|
localError(n.info, errIdentifierExpected)
|
||||||
result = errorSym(c, n)
|
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 =
|
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if n.sonsLen == 0: return newConstraint(c, tyTuple)
|
|
||||||
var typ: PType
|
var typ: PType
|
||||||
result = newOrPrevType(tyTuple, prev, c)
|
result = newOrPrevType(tyTuple, prev, c)
|
||||||
result.n = newNodeI(nkRecList, n.info)
|
result.n = newNodeI(nkRecList, n.info)
|
||||||
|
|
@ -1117,9 +1123,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||||
else:
|
else:
|
||||||
# XXX support anon tuple here
|
result = semAnonTuple(c, n, prev)
|
||||||
localError(n.info, errTypeExpected)
|
|
||||||
result = newOrPrevType(tyError, prev, c)
|
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
if isRange(n):
|
if isRange(n):
|
||||||
result = semRangeAux(c, n, prev)
|
result = semRangeAux(c, n, prev)
|
||||||
|
|
@ -1227,6 +1231,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
of nkObjectTy: result = semObjectNode(c, n, prev)
|
of nkObjectTy: result = semObjectNode(c, n, prev)
|
||||||
of nkTupleTy: result = semTuple(c, n, prev)
|
of nkTupleTy: result = semTuple(c, n, prev)
|
||||||
|
of nkTupleClassTy: result = newConstraint(c, tyTuple)
|
||||||
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
||||||
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
||||||
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
||||||
|
|
|
||||||
|
|
@ -341,6 +341,8 @@ proc skipIntLiteralParams*(t: PType) =
|
||||||
proc propagateFieldFlags(t: PType, n: PNode) =
|
proc propagateFieldFlags(t: PType, n: PNode) =
|
||||||
# This is meant for objects and tuples
|
# This is meant for objects and tuples
|
||||||
# The type must be fully instantiated!
|
# The type must be fully instantiated!
|
||||||
|
if n.isNil:
|
||||||
|
return
|
||||||
internalAssert n.kind != nkRecWhen
|
internalAssert n.kind != nkRecWhen
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
|
|
|
||||||
|
|
@ -157,13 +157,36 @@ proc sumGeneric(t: PType): int =
|
||||||
result = ord(t.kind == tyGenericInvocation)
|
result = ord(t.kind == tyGenericInvocation)
|
||||||
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
||||||
break
|
break
|
||||||
of tyProc:
|
|
||||||
# proc matches proc better than 'stmt' to disambiguate 'spawn'
|
|
||||||
return 1
|
|
||||||
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
|
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
|
||||||
|
of tyBool, tyChar, tyEnum, tyObject, tyProc, tyPointer,
|
||||||
|
tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||||
|
tyUInt..tyUInt64:
|
||||||
|
return 1
|
||||||
else: return 0
|
else: return 0
|
||||||
|
|
||||||
|
#var ggDebug: bool
|
||||||
|
|
||||||
proc complexDisambiguation(a, b: PType): int =
|
proc complexDisambiguation(a, b: PType): int =
|
||||||
|
# '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
|
var x, y: int
|
||||||
for i in 1 .. <a.len: x += a.sons[i].sumGeneric
|
for i in 1 .. <a.len: x += a.sons[i].sumGeneric
|
||||||
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
|
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
|
||||||
|
|
@ -338,7 +361,8 @@ proc minRel(a, b: TTypeRelation): TTypeRelation =
|
||||||
|
|
||||||
proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
result = isNone
|
result = isNone
|
||||||
if sameType(f, a): result = isEqual
|
if sameType(f, a):
|
||||||
|
result = isEqual
|
||||||
elif sonsLen(a) == sonsLen(f):
|
elif sonsLen(a) == sonsLen(f):
|
||||||
result = isEqual
|
result = isEqual
|
||||||
let firstField = if f.kind == tyTuple: 0
|
let firstField = if f.kind == tyTuple: 0
|
||||||
|
|
@ -380,17 +404,17 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
# no luck resolving the type, so the inference fails
|
# no luck resolving the type, so the inference fails
|
||||||
return isNone
|
return isNone
|
||||||
let reverseRel = typeRel(c, a, f)
|
let reverseRel = typeRel(c, a, f)
|
||||||
if reverseRel == isGeneric:
|
if reverseRel >= isGeneric:
|
||||||
result = isInferred
|
result = isInferred
|
||||||
inc c.genericMatches
|
#inc c.genericMatches
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f, a)
|
result = typeRel(c, f, a)
|
||||||
|
|
||||||
if result <= isSubtype or inconsistentVarTypes(f, a):
|
if result <= isSubtype or inconsistentVarTypes(f, a):
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
if result == isEqual:
|
#if result == isEqual:
|
||||||
inc c.exactMatches
|
# inc c.exactMatches
|
||||||
|
|
||||||
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
case a.kind
|
case a.kind
|
||||||
|
|
@ -433,6 +457,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
return isNone
|
return isNone
|
||||||
when useEffectSystem:
|
when useEffectSystem:
|
||||||
if not compatibleEffects(f, a): return isNone
|
if not compatibleEffects(f, a): return isNone
|
||||||
|
|
||||||
of tyNil:
|
of tyNil:
|
||||||
result = f.allowsNil
|
result = f.allowsNil
|
||||||
of tyIter:
|
of tyIter:
|
||||||
|
|
@ -590,7 +615,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
return typeRel(c, f, lastSon(a))
|
return typeRel(c, f, lastSon(a))
|
||||||
|
|
||||||
template bindingRet(res) =
|
template bindingRet(res) =
|
||||||
when res == isGeneric:
|
|
||||||
if doBind:
|
if doBind:
|
||||||
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
||||||
if doBind: put(c.bindings, f, bound)
|
if doBind: put(c.bindings, f, bound)
|
||||||
|
|
@ -605,20 +629,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyOr:
|
of tyOr:
|
||||||
# seq[int|string] vs seq[number]
|
# seq[int|string] vs seq[number]
|
||||||
# both int and string must match against number
|
# both int and string must match against number
|
||||||
|
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
|
||||||
|
result = isGeneric
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
if typeRel(c, f, branch, false) == isNone:
|
let x = typeRel(c, f, branch, false)
|
||||||
return isNone
|
if x == isNone: return isNone
|
||||||
|
if x < result: result = x
|
||||||
return isGeneric
|
|
||||||
|
|
||||||
of tyAnd:
|
of tyAnd:
|
||||||
# seq[Sortable and Iterable] vs seq[Sortable]
|
# seq[Sortable and Iterable] vs seq[Sortable]
|
||||||
# only one match is enough
|
# only one match is enough
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
if typeRel(c, f, branch, false) != isNone:
|
let x = typeRel(c, f, branch, false)
|
||||||
return isGeneric
|
if x != isNone:
|
||||||
|
return if x >= isGeneric: isGeneric else: x
|
||||||
return isNone
|
result = isNone
|
||||||
|
|
||||||
of tyNot:
|
of tyNot:
|
||||||
case f.kind
|
case f.kind
|
||||||
|
|
@ -781,11 +806,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
inc(c.inheritancePenalty, depth)
|
inc(c.inheritancePenalty, depth)
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual
|
if a.kind == tyDistinct and sameDistinctTypes(f, a): result = isEqual
|
||||||
elif c.coerceDistincts: result = typeRel(c, f.base, a)
|
elif c.coerceDistincts: result = typeRel(c, f.base, a)
|
||||||
of tySet:
|
of tySet:
|
||||||
if a.kind == tySet:
|
if a.kind == tySet:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
if f.sons[0].kind != tyGenericParam and a.sons[0].kind == tyEmpty:
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f.sons[0], a.sons[0])
|
result = typeRel(c, f.sons[0], a.sons[0])
|
||||||
|
|
@ -865,7 +890,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = typeRel(c, ff, aa)
|
result = typeRel(c, ff, aa)
|
||||||
if result == isNone: return
|
if result == isNone: return
|
||||||
if ff.kind == tyRange and result != isEqual: return isNone
|
if ff.kind == tyRange and result != isEqual: return isNone
|
||||||
result = isGeneric
|
#result = isGeneric
|
||||||
# XXX See bug #2220. A[int] should match A[int] better than some generic X
|
# XXX See bug #2220. A[int] should match A[int] better than some generic X
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, lastSon(f), a)
|
result = typeRel(c, lastSon(f), a)
|
||||||
|
|
@ -904,18 +929,23 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyAnd:
|
of tyAnd:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
for branch in f.sons:
|
for branch in f.sons:
|
||||||
if typeRel(c, branch, aOrig) < isSubtype:
|
let x = typeRel(c, branch, aOrig)
|
||||||
return isNone
|
if x < isSubtype: return isNone
|
||||||
|
# 'and' implies minimum matching result:
|
||||||
bindingRet isGeneric
|
if x < result: result = x
|
||||||
|
bindingRet result
|
||||||
|
|
||||||
of tyOr:
|
of tyOr:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
|
result = isNone
|
||||||
for branch in f.sons:
|
for branch in f.sons:
|
||||||
if typeRel(c, branch, aOrig) >= isSubtype:
|
let x = typeRel(c, branch, aOrig)
|
||||||
bindingRet isGeneric
|
# 'or' implies maximum matching result:
|
||||||
|
if x > result: result = x
|
||||||
return isNone
|
if result >= isSubtype:
|
||||||
|
bindingRet result
|
||||||
|
else:
|
||||||
|
result = isNone
|
||||||
|
|
||||||
of tyNot:
|
of tyNot:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
|
|
@ -975,6 +1005,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
internalAssert a.sons != nil and a.sons.len > 0
|
internalAssert a.sons != nil and a.sons.len > 0
|
||||||
c.typedescMatched = true
|
c.typedescMatched = true
|
||||||
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
|
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
|
||||||
|
if result > isGeneric: result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
|
|
@ -998,12 +1029,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
return isNone
|
return isNone
|
||||||
if doBind:
|
if doBind:
|
||||||
put(c.bindings, f, concrete)
|
put(c.bindings, f, concrete)
|
||||||
|
elif result > isGeneric:
|
||||||
|
result = isGeneric
|
||||||
elif a.kind == tyEmpty:
|
elif a.kind == tyEmpty:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
elif x.kind == tyGenericParam:
|
elif x.kind == tyGenericParam:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, x, a) # check if it fits
|
result = typeRel(c, x, a) # check if it fits
|
||||||
|
if result > isGeneric: result = isGeneric
|
||||||
|
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
let prev = PType(idTableGet(c.bindings, f))
|
let prev = PType(idTableGet(c.bindings, f))
|
||||||
|
|
@ -1220,8 +1254,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
of isConvertible, isIntConv: inc(m.convMatches)
|
of isConvertible, isIntConv: inc(m.convMatches)
|
||||||
of isSubtype, isSubrange: inc(m.subtypeMatches)
|
of isSubtype, isSubrange: inc(m.subtypeMatches)
|
||||||
of isGeneric, isInferred: inc(m.genericMatches)
|
of isGeneric, isInferred: inc(m.genericMatches)
|
||||||
of isInferredConvertible: inc(m.genericMatches); inc(m.convMatches)
|
|
||||||
of isFromIntLit: inc(m.intConvMatches, 256)
|
of isFromIntLit: inc(m.intConvMatches, 256)
|
||||||
|
of isInferredConvertible:
|
||||||
|
inc(m.convMatches)
|
||||||
of isEqual: inc(m.exactMatches)
|
of isEqual: inc(m.exactMatches)
|
||||||
of isNone: discard
|
of isNone: discard
|
||||||
|
|
||||||
|
|
@ -1232,7 +1267,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
elif f.kind == tyStatic:
|
elif f.kind == tyStatic:
|
||||||
return arg.typ.n
|
return arg.typ.n
|
||||||
else:
|
else:
|
||||||
return argOrig
|
return argSemantized # argOrig
|
||||||
|
|
||||||
if r != isNone and f.isInlineIterator:
|
if r != isNone and f.isInlineIterator:
|
||||||
var inlined = newTypeS(tyStatic, c)
|
var inlined = newTypeS(tyStatic, c)
|
||||||
|
|
@ -1244,21 +1279,22 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
case r
|
case r
|
||||||
of isConvertible:
|
of isConvertible:
|
||||||
inc(m.convMatches)
|
inc(m.convMatches)
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||||
of isIntConv:
|
of isIntConv:
|
||||||
# I'm too lazy to introduce another ``*matches`` field, so we conflate
|
# I'm too lazy to introduce another ``*matches`` field, so we conflate
|
||||||
# ``isIntConv`` and ``isIntLit`` here:
|
# ``isIntConv`` and ``isIntLit`` here:
|
||||||
inc(m.intConvMatches)
|
inc(m.intConvMatches)
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||||
of isSubtype:
|
of isSubtype:
|
||||||
inc(m.subtypeMatches)
|
inc(m.subtypeMatches)
|
||||||
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||||
of isSubrange:
|
of isSubrange:
|
||||||
inc(m.subtypeMatches)
|
inc(m.subtypeMatches)
|
||||||
#result = copyTree(arg)
|
if f.kind == tyVar:
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = arg
|
||||||
|
else:
|
||||||
|
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||||
of isInferred, isInferredConvertible:
|
of isInferred, isInferredConvertible:
|
||||||
inc(m.genericMatches)
|
|
||||||
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
|
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
|
||||||
result = c.semInferredLambda(c, m.bindings, arg)
|
result = c.semInferredLambda(c, m.bindings, arg)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1267,41 +1303,35 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
if r == isInferredConvertible:
|
if r == isInferredConvertible:
|
||||||
inc(m.convMatches)
|
inc(m.convMatches)
|
||||||
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
||||||
|
else:
|
||||||
|
inc(m.genericMatches)
|
||||||
of isGeneric:
|
of isGeneric:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
when true:
|
if arg.typ == nil:
|
||||||
if skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
result = arg
|
||||||
|
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||||
elif arg.typ != nil and arg.typ.isEmptyContainer:
|
elif arg.typ.isEmptyContainer:
|
||||||
result = arg.copyTree
|
result = arg.copyTree
|
||||||
result.typ = getInstantiatedType(c, arg, m, f)
|
result.typ = getInstantiatedType(c, arg, m, f)
|
||||||
else:
|
else:
|
||||||
result = arg
|
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)
|
|
||||||
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
|
|
||||||
of isFromIntLit:
|
of isFromIntLit:
|
||||||
# too lazy to introduce another ``*matches`` field, so we conflate
|
# too lazy to introduce another ``*matches`` field, so we conflate
|
||||||
# ``isIntConv`` and ``isIntLit`` here:
|
# ``isIntConv`` and ``isIntLit`` here:
|
||||||
inc(m.intConvMatches, 256)
|
inc(m.intConvMatches, 256)
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||||
of isEqual:
|
of isEqual:
|
||||||
inc(m.exactMatches)
|
inc(m.exactMatches)
|
||||||
result = copyTree(arg)
|
result = arg
|
||||||
if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
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:
|
of isNone:
|
||||||
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
||||||
if a.kind in {tyProxy, tyUnknown}:
|
if a.kind in {tyProxy, tyUnknown}:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
m.fauxMatch = a.kind
|
m.fauxMatch = a.kind
|
||||||
return copyTree(arg)
|
return arg
|
||||||
result = userConvMatch(c, m, f, a, arg)
|
result = userConvMatch(c, m, f, a, arg)
|
||||||
# check for a base type match, which supports varargs[T] without []
|
# check for a base type match, which supports varargs[T] without []
|
||||||
# constructor in a call:
|
# constructor in a call:
|
||||||
|
|
@ -1340,7 +1370,16 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||||
for i in countup(0, sonsLen(arg) - 1):
|
for i in countup(0, sonsLen(arg) - 1):
|
||||||
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
|
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
|
||||||
copyCandidate(z, m)
|
copyCandidate(z, m)
|
||||||
|
z.callee = arg.sons[i].typ
|
||||||
|
z.calleeSym = arg.sons[i].sym
|
||||||
|
#if arg.sons[i].sym.name.s == "cmp":
|
||||||
|
# ggDebug = true
|
||||||
|
# echo "CALLLEEEEEEEE ", typeToString(z.callee)
|
||||||
var r = typeRel(z, f, arg.sons[i].typ)
|
var r = typeRel(z, f, arg.sons[i].typ)
|
||||||
|
#if arg.sons[i].sym.name.s == "cmp": # and arg.info.line == 606:
|
||||||
|
# echo "M ", r, " ", arg.info, " ", typeToString(arg.sons[i].sym.typ)
|
||||||
|
# debug arg.sons[i].sym
|
||||||
|
# writeMatches(z)
|
||||||
if r != isNone:
|
if r != isNone:
|
||||||
case x.state
|
case x.state
|
||||||
of csEmpty, csNoMatch:
|
of csEmpty, csNoMatch:
|
||||||
|
|
@ -1653,7 +1692,7 @@ tests:
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
var c: TCandidate
|
var c: TCandidate
|
||||||
InitCandidate(nil, c, nil)
|
initCandidate(nil, c, nil)
|
||||||
|
|
||||||
template yes(x, y) =
|
template yes(x, y) =
|
||||||
test astToStr(x) & " is " & astToStr(y):
|
test astToStr(x) & " is " & astToStr(y):
|
||||||
|
|
|
||||||
|
|
@ -507,18 +507,22 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
if prefer == preferModuleInfo: preferModuleInfo else: preferName)
|
if prefer == preferModuleInfo: preferModuleInfo else: preferName)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
# we iterate over t.sons here, because t.n may be nil
|
# we iterate over t.sons here, because t.n may be nil
|
||||||
result = "tuple["
|
|
||||||
if t.n != nil:
|
if t.n != nil:
|
||||||
|
result = "tuple["
|
||||||
assert(sonsLen(t.n) == sonsLen(t))
|
assert(sonsLen(t.n) == sonsLen(t))
|
||||||
for i in countup(0, sonsLen(t.n) - 1):
|
for i in countup(0, sonsLen(t.n) - 1):
|
||||||
assert(t.n.sons[i].kind == nkSym)
|
assert(t.n.sons[i].kind == nkSym)
|
||||||
add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
|
add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
|
||||||
if i < sonsLen(t.n) - 1: add(result, ", ")
|
if i < sonsLen(t.n) - 1: add(result, ", ")
|
||||||
|
add(result, ']')
|
||||||
|
elif sonsLen(t) == 0:
|
||||||
|
result = "tuple[]"
|
||||||
else:
|
else:
|
||||||
|
result = "("
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
add(result, typeToString(t.sons[i]))
|
add(result, typeToString(t.sons[i]))
|
||||||
if i < sonsLen(t) - 1: add(result, ", ")
|
if i < sonsLen(t) - 1: add(result, ", ")
|
||||||
add(result, ']')
|
add(result, ')')
|
||||||
of tyPtr, tyRef, tyVar, tyMutable, tyConst:
|
of tyPtr, tyRef, tyVar, tyMutable, tyConst:
|
||||||
result = typeToStr[t.kind]
|
result = typeToStr[t.kind]
|
||||||
if t.len >= 2:
|
if t.len >= 2:
|
||||||
|
|
@ -654,7 +658,7 @@ type
|
||||||
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
||||||
|
|
||||||
TTypeCmpFlag* = enum
|
TTypeCmpFlag* = enum
|
||||||
IgnoreTupleFields
|
IgnoreTupleFields ## NOTE: Only set this flag for backends!
|
||||||
IgnoreCC
|
IgnoreCC
|
||||||
ExactTypeDescValues
|
ExactTypeDescValues
|
||||||
ExactGenericParams
|
ExactGenericParams
|
||||||
|
|
@ -774,8 +778,8 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
|
||||||
var x = a.sons[i]
|
var x = a.sons[i]
|
||||||
var y = b.sons[i]
|
var y = b.sons[i]
|
||||||
if IgnoreTupleFields in c.flags:
|
if IgnoreTupleFields in c.flags:
|
||||||
x = skipTypes(x, {tyRange})
|
x = skipTypes(x, {tyRange, tyGenericInst})
|
||||||
y = skipTypes(y, {tyRange})
|
y = skipTypes(y, {tyRange, tyGenericInst})
|
||||||
|
|
||||||
result = sameTypeAux(x, y, c)
|
result = sameTypeAux(x, y, c)
|
||||||
if not result: return
|
if not result: return
|
||||||
|
|
@ -823,8 +827,13 @@ proc sameEnumTypes*(a, b: PType): bool {.inline.} =
|
||||||
proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool =
|
proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool =
|
||||||
if a == b:
|
if a == b:
|
||||||
result = true
|
result = true
|
||||||
elif (a != nil) and (b != nil) and (a.kind == b.kind):
|
elif a != nil and b != nil and a.kind == b.kind:
|
||||||
if sameTypeOrNilAux(a.typ, b.typ, c):
|
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
|
case a.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
# same symbol as string is enough:
|
# same symbol as string is enough:
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ proc renderType(n: PNode): string =
|
||||||
assert n[i].kind == nkIdent
|
assert n[i].kind == nkIdent
|
||||||
result.add(',' & typeStr)
|
result.add(',' & typeStr)
|
||||||
of nkTupleTy:
|
of nkTupleTy:
|
||||||
assert len(n) > 0
|
|
||||||
result = "tuple["
|
result = "tuple["
|
||||||
for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
|
for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
|
||||||
result[<len(result)] = ']'
|
result[<len(result)] = ']'
|
||||||
|
|
|
||||||
|
|
@ -1435,6 +1435,7 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
|
||||||
newSeq(tos.slots, c.prc.maxSlots)
|
newSeq(tos.slots, c.prc.maxSlots)
|
||||||
#for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
#for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||||
result = rawExecute(c, start, tos).regToNode
|
result = rawExecute(c, start, tos).regToNode
|
||||||
|
if result.info.line < 0: result.info = n.info
|
||||||
|
|
||||||
proc evalConstExpr*(module: PSym, e: PNode): PNode =
|
proc evalConstExpr*(module: PSym, e: PNode): PNode =
|
||||||
result = evalConstExprAux(module, nil, e, emConst)
|
result = evalConstExprAux(module, nil, e, emConst)
|
||||||
|
|
@ -1496,6 +1497,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
||||||
# temporary storage:
|
# temporary storage:
|
||||||
#for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
|
#for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||||
result = rawExecute(c, start, tos).regToNode
|
result = rawExecute(c, start, tos).regToNode
|
||||||
|
if result.info.line < 0: result.info = n.info
|
||||||
if cyclicTree(result): globalError(n.info, errCyclicTree)
|
if cyclicTree(result): globalError(n.info, errCyclicTree)
|
||||||
dec(evalMacroCounter)
|
dec(evalMacroCounter)
|
||||||
c.callsite = nil
|
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.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
|
||||||
vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
|
vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
|
||||||
vcc.options.always = "/nologo"
|
vcc.options.always = "/nologo"
|
||||||
vcc.options.speed = "/Ox /arch:SSE2"
|
vcc.options.speed = "/O2 /arch:SSE2"
|
||||||
vcc.options.size = "/O1"
|
vcc.options.size = "/O1"
|
||||||
|
|
||||||
# Configuration for the Digital Mars C/C++ compiler:
|
# 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
|
This module implements the ability to monitor a directory/file for changes
|
||||||
using Posix's inotify API.
|
using Posix's inotify API.
|
||||||
|
|
||||||
|
* `asyncfile <asyncfile.html>`_
|
||||||
|
This module implements asynchronous file reading and writing using
|
||||||
|
``asyncdispatch``.
|
||||||
|
|
||||||
Math libraries
|
Math libraries
|
||||||
--------------
|
--------------
|
||||||
|
|
|
||||||
|
|
@ -351,7 +351,7 @@ dispatch.
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
type
|
type
|
||||||
Expression = object ## abstract base class for an expression
|
Expression = object of RootObj ## abstract base class for an expression
|
||||||
Literal = object of Expression
|
Literal = object of Expression
|
||||||
x: int
|
x: int
|
||||||
PlusExpr = object of Expression
|
PlusExpr = object of Expression
|
||||||
|
|
@ -387,7 +387,7 @@ dispatching:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
type
|
type
|
||||||
Thing = object
|
Thing = object of RootObj
|
||||||
Unit = object of Thing
|
Unit = object of Thing
|
||||||
x: int
|
x: int
|
||||||
|
|
||||||
|
|
|
||||||
2
koch.nim
2
koch.nim
|
|
@ -347,7 +347,7 @@ proc temp(args: string) =
|
||||||
if args.len > 0: exec(finalDest & " " & args)
|
if args.len > 0: exec(finalDest & " " & args)
|
||||||
|
|
||||||
proc showHelp() =
|
proc showHelp() =
|
||||||
quit(HelpText % [VersionAsString & repeatChar(44-len(VersionAsString)),
|
quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
|
||||||
CompileDate, CompileTime], QuitSuccess)
|
CompileDate, CompileTime], QuitSuccess)
|
||||||
|
|
||||||
var op = initOptParser()
|
var op = initOptParser()
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ type
|
||||||
nnkStmtListType, nnkBlockType,
|
nnkStmtListType, nnkBlockType,
|
||||||
nnkWith, nnkWithout,
|
nnkWith, nnkWithout,
|
||||||
nnkTypeOfExpr, nnkObjectTy,
|
nnkTypeOfExpr, nnkObjectTy,
|
||||||
nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
|
nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
|
||||||
nnkRecList, nnkRecCase, nnkRecWhen,
|
nnkRecList, nnkRecCase, nnkRecWhen,
|
||||||
nnkRefTy, nnkPtrTy, nnkVarTy,
|
nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||||
nnkConstTy, nnkMutableTy,
|
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,
|
## checks that `n` is of kind `k`. If this is not the case,
|
||||||
## compilation aborts with an error message. This is useful for writing
|
## compilation aborts with an error message. This is useful for writing
|
||||||
## macros that check the AST that is passed to them.
|
## 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.} =
|
proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} =
|
||||||
## checks that `n` has at least `min` children. If this is not the case,
|
## 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,
|
CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
|
||||||
nnkCallStrLit, nnkHiddenCallConv}
|
nnkCallStrLit, nnkHiddenCallConv}
|
||||||
|
|
||||||
from strutils import cmpIgnoreStyle, format
|
|
||||||
|
|
||||||
proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
|
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()];
|
proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()];
|
||||||
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
|
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
|
||||||
|
|
@ -654,7 +652,7 @@ proc `pragma=`*(someProc: PNimrodNode; val: PNimrodNode){.compileTime.}=
|
||||||
|
|
||||||
|
|
||||||
template badNodeKind(k; f): stmt{.immediate.} =
|
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.} =
|
proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||||
case someProc.kind:
|
case someProc.kind:
|
||||||
|
|
@ -776,6 +774,22 @@ proc copy*(node: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||||
## An alias for copyNimTree().
|
## An alias for copyNimTree().
|
||||||
return node.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
|
proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0
|
||||||
## Check if two idents are identical.
|
## Check if two idents are identical.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,9 @@ type
|
||||||
ppointer = ptr pointer
|
ppointer = ptr pointer
|
||||||
pbyteArray = ptr array[0.. 0xffff, int8]
|
pbyteArray = ptr array[0.. 0xffff, int8]
|
||||||
|
|
||||||
TGenSeq = object
|
TGenericSeq {.importc.} = object
|
||||||
len, space: int
|
len, space: int
|
||||||
PGenSeq = ptr TGenSeq
|
PGenSeq = ptr TGenericSeq
|
||||||
|
|
||||||
const
|
const
|
||||||
GenericSeqSize = (2 * sizeof(int))
|
GenericSeqSize = (2 * sizeof(int))
|
||||||
|
|
|
||||||
|
|
@ -33,27 +33,71 @@ when defined(Windows):
|
||||||
stdout.write(prompt)
|
stdout.write(prompt)
|
||||||
result = readLine(stdin, line)
|
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):
|
proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
|
||||||
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
||||||
## Reads a `password` from stdin without printing it. `password` must not
|
## Reads a `password` from stdin without printing it. `password` must not
|
||||||
## be ``nil``! Returns ``false`` if the end of the file has been reached,
|
## be ``nil``! Returns ``false`` if the end of the file has been reached,
|
||||||
## ``true`` otherwise.
|
## ``true`` otherwise.
|
||||||
proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
|
|
||||||
|
|
||||||
password.setLen(0)
|
password.setLen(0)
|
||||||
var c: char
|
|
||||||
stdout.write(prompt)
|
stdout.write(prompt)
|
||||||
while true:
|
while true:
|
||||||
c = getch().char
|
let c = getch()
|
||||||
case c
|
case c.char
|
||||||
of '\r', chr(0xA):
|
of '\r', chr(0xA):
|
||||||
break
|
break
|
||||||
of '\b':
|
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:
|
else:
|
||||||
password.add(c)
|
password.add(toUTF8(c.Rune))
|
||||||
stdout.write "\n"
|
stdout.write "\n"
|
||||||
# TODO: How to detect EOF on Windows?
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
import readline, history, termios, unsigned
|
import readline, history, termios, unsigned
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ proc rawCompile(pattern: string, flags: cint): PPcre =
|
||||||
offset: cint
|
offset: cint
|
||||||
result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil)
|
result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
raiseInvalidRegex($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n")
|
raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
|
||||||
|
|
||||||
proc finalizeRegEx(x: Regex) =
|
proc finalizeRegEx(x: Regex) =
|
||||||
# XXX This is a hack, but PCRE does not export its "free" function properly.
|
# 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:
|
## accessed in `by`. Examples:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## "var1=key; var2=key2".replace(re"(\w+)'='(\w+)")
|
## "var1=key; var2=key2".replace(re"(\w+)=(\w+)")
|
||||||
##
|
##
|
||||||
## Results in:
|
## Results in:
|
||||||
##
|
##
|
||||||
|
|
@ -313,7 +313,7 @@ proc replacef*(s: string, sub: Regex, by: string): string =
|
||||||
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. 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:
|
## Results in:
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,11 @@ __clang__
|
||||||
# define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
|
# define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
|
||||||
# define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
|
# define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
# define N_LIB_EXPORT extern "C" __declspec(dllexport)
|
||||||
|
# else
|
||||||
# define N_LIB_EXPORT extern __declspec(dllexport)
|
# define N_LIB_EXPORT extern __declspec(dllexport)
|
||||||
|
# endif
|
||||||
# define N_LIB_IMPORT extern __declspec(dllimport)
|
# define N_LIB_IMPORT extern __declspec(dllimport)
|
||||||
#else
|
#else
|
||||||
# define N_CDECL(rettype, name) rettype name
|
# define N_CDECL(rettype, name) rettype name
|
||||||
|
|
@ -118,7 +122,11 @@ __clang__
|
||||||
# define N_FASTCALL_PTR(rettype, name) rettype (*name)
|
# define N_FASTCALL_PTR(rettype, name) rettype (*name)
|
||||||
# define N_SAFECALL_PTR(rettype, name) rettype (*name)
|
# define N_SAFECALL_PTR(rettype, name) rettype (*name)
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
# define N_LIB_EXPORT extern "C"
|
||||||
|
# else
|
||||||
# define N_LIB_EXPORT extern
|
# define N_LIB_EXPORT extern
|
||||||
|
# endif
|
||||||
# define N_LIB_IMPORT extern
|
# define N_LIB_IMPORT extern
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -398,4 +406,6 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <types/vxWind.h>
|
# include <types/vxWind.h>
|
||||||
# include <tool/gnu/toolMacros.h>
|
# include <tool/gnu/toolMacros.h>
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
# include <sys/types.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ proc getIndent(L: var TLexer, tok: var TToken) =
|
||||||
tok.line = L.line
|
tok.line = L.line
|
||||||
L.col = tok.ival
|
L.col = tok.ival
|
||||||
tok.ival = max(tok.ival - L.baseIndent, 0)
|
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) =
|
proc rawGetTok(L: var TLexer, tok: var TToken) =
|
||||||
tok.symbol = ""
|
tok.symbol = ""
|
||||||
|
|
@ -963,7 +963,7 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
add(n.text, "\n")
|
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)
|
inc(p.idx)
|
||||||
else:
|
else:
|
||||||
add(n.text, p.tok[p.idx].symbol)
|
add(n.text, p.tok[p.idx].symbol)
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||||
const
|
const
|
||||||
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
|
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
var ind = repeatChar(d.indent)
|
var ind = spaces(d.indent)
|
||||||
case n.kind
|
case n.kind
|
||||||
of rnInner:
|
of rnInner:
|
||||||
renderRstSons(d, n, result)
|
renderRstSons(d, n, result)
|
||||||
|
|
@ -124,7 +124,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||||
|
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
result.add(ind)
|
result.add(ind)
|
||||||
result.add repeatChar(headlineLen, lvlToChar[n.level])
|
result.add repeat(lvlToChar[n.level], headlineLen)
|
||||||
of rnOverline:
|
of rnOverline:
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
result.add(ind)
|
result.add(ind)
|
||||||
|
|
@ -132,7 +132,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||||
var headline = ""
|
var headline = ""
|
||||||
renderRstSons(d, n, 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(lvl)
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
result.add(headline)
|
result.add(headline)
|
||||||
|
|
@ -143,7 +143,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||||
of rnTransition:
|
of rnTransition:
|
||||||
result.add("\n\n")
|
result.add("\n\n")
|
||||||
result.add(ind)
|
result.add(ind)
|
||||||
result.add repeatChar(78-d.indent, '-')
|
result.add repeat('-', 78-d.indent)
|
||||||
result.add("\n\n")
|
result.add("\n\n")
|
||||||
of rnParagraph:
|
of rnParagraph:
|
||||||
result.add("\n\n")
|
result.add("\n\n")
|
||||||
|
|
@ -196,7 +196,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||||
result.add ':'
|
result.add ':'
|
||||||
result.add tmp
|
result.add tmp
|
||||||
result.add ':'
|
result.add ':'
|
||||||
result.add repeatChar(L - tmp.len - 2)
|
result.add spaces(L - tmp.len - 2)
|
||||||
renderRstToRst(d, n.sons[1], result)
|
renderRstToRst(d, n.sons[1], result)
|
||||||
|
|
||||||
dec(d.indent, L)
|
dec(d.indent, L)
|
||||||
|
|
|
||||||
|
|
@ -461,9 +461,9 @@ proc indentToLevel(level: var int, newLevel: int): string =
|
||||||
if level == newLevel:
|
if level == newLevel:
|
||||||
return
|
return
|
||||||
if newLevel > level:
|
if newLevel > level:
|
||||||
result = repeatStr(newLevel - level, "<ul>")
|
result = repeat("<ul>", newLevel - level)
|
||||||
else:
|
else:
|
||||||
result = repeatStr(level - newLevel, "</ul>")
|
result = repeat("</ul>", level - newLevel)
|
||||||
level = newLevel
|
level = newLevel
|
||||||
|
|
||||||
proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
|
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.
|
# Generate index entry using spaces to indicate TOC level for the output HTML.
|
||||||
assert n.level >= 0
|
assert n.level >= 0
|
||||||
setIndexTerm(d, refname, tmp.stripTOCHTML,
|
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) =
|
proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||||
if d.meta[metaTitle].len == 0:
|
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 =
|
proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int =
|
||||||
## same as binarySearch except that if key is not in `a` then this
|
## same as binarySearch except that if key is not in `a` then this
|
||||||
## returns the location where `key` would be if it were. In other
|
## returns the location where `key` would be if it were. In other
|
||||||
## words if you have a sorted sequence and you call insert(thing, elm, lowerBound(thing, elm))
|
## words if you have a sorted sequence and you call
|
||||||
## the sequence will still be sorted
|
## insert(thing, elm, lowerBound(thing, elm))
|
||||||
|
## the sequence will still be sorted.
|
||||||
##
|
##
|
||||||
## `cmp` is the comparator function to use, the expected return values are the same as
|
## `cmp` is the comparator function to use, the expected return values are
|
||||||
## that of system.cmp
|
## the same as that of system.cmp.
|
||||||
##
|
##
|
||||||
## example::
|
## example::
|
||||||
##
|
##
|
||||||
|
|
@ -187,6 +188,35 @@ proc sort*[T](a: var openArray[T],
|
||||||
dec(m, s*2)
|
dec(m, s*2)
|
||||||
s = s*2
|
s = s*2
|
||||||
|
|
||||||
|
proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.},
|
||||||
|
order = SortOrder.Ascending): seq[T] =
|
||||||
|
## 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]] =
|
proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
|
||||||
## produces the Cartesian product of the array. Warning: complexity
|
## produces the Cartesian product of the array. Warning: complexity
|
||||||
## may explode.
|
## may explode.
|
||||||
|
|
|
||||||
|
|
@ -1222,7 +1222,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
|
||||||
of nnkTryStmt:
|
of nnkTryStmt:
|
||||||
# try: await x; except: ...
|
# try: await x; except: ...
|
||||||
result = newNimNode(nnkStmtList, node)
|
result = newNimNode(nnkStmtList, node)
|
||||||
template wrapInTry(n, tryBody: PNimrodNode) =
|
template wrapInTry(n, tryBody: expr) =
|
||||||
var temp = n
|
var temp = n
|
||||||
n[0] = tryBody
|
n[0] = tryBody
|
||||||
tryBody = temp
|
tryBody = temp
|
||||||
|
|
@ -1323,14 +1323,25 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||||
newLit(prc[0].getName)))) # Get type from return type of this proc
|
newLit(prc[0].getName)))) # Get type from return type of this proc
|
||||||
|
|
||||||
# -> iterator nameIter(): FutureBase {.closure.} =
|
# -> iterator nameIter(): FutureBase {.closure.} =
|
||||||
|
# -> {.push warning[resultshadowed]: off.}
|
||||||
# -> var result: T
|
# -> var result: T
|
||||||
|
# -> {.pop.}
|
||||||
# -> <proc_body>
|
# -> <proc_body>
|
||||||
# -> complete(retFuture, result)
|
# -> complete(retFuture, result)
|
||||||
var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
|
var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
|
||||||
var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
|
var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
|
||||||
if not subtypeIsVoid:
|
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
|
newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
|
||||||
|
|
||||||
|
procBody.insert(2, newNimNode(nnkPragma).add(
|
||||||
|
newIdentNode("pop"))) # -> {.pop.})
|
||||||
|
|
||||||
procBody.add(
|
procBody.add(
|
||||||
newCall(newIdentNode("complete"),
|
newCall(newIdentNode("complete"),
|
||||||
retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
|
retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements asynchronous file handling.
|
## This module implements asynchronous file reading and writing.
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## import asyncfile, asyncdispatch, os
|
## import asyncfile, asyncdispatch, os
|
||||||
|
|
@ -24,17 +24,17 @@
|
||||||
|
|
||||||
import asyncdispatch, os
|
import asyncdispatch, os
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
import winlean
|
import winlean
|
||||||
else:
|
else:
|
||||||
import posix
|
import posix
|
||||||
|
|
||||||
type
|
type
|
||||||
AsyncFile = ref object
|
AsyncFile* = ref object
|
||||||
fd: TAsyncFd
|
fd: TAsyncFd
|
||||||
offset: int64
|
offset: int64
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
proc getDesiredAccess(mode: FileMode): int32 =
|
proc getDesiredAccess(mode: FileMode): int32 =
|
||||||
case mode
|
case mode
|
||||||
of fmRead:
|
of fmRead:
|
||||||
|
|
@ -70,7 +70,7 @@ else:
|
||||||
|
|
||||||
proc getFileSize(f: AsyncFile): int64 =
|
proc getFileSize(f: AsyncFile): int64 =
|
||||||
## Retrieves the specified file's size.
|
## Retrieves the specified file's size.
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
var high: DWord
|
var high: DWord
|
||||||
let low = getFileSize(f.fd.THandle, addr high)
|
let low = getFileSize(f.fd.THandle, addr high)
|
||||||
if low == INVALID_FILE_SIZE:
|
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
|
## Opens a file specified by the path in ``filename`` using
|
||||||
## the specified ``mode`` asynchronously.
|
## the specified ``mode`` asynchronously.
|
||||||
new result
|
new result
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
|
let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
|
||||||
let desiredAccess = getDesiredAccess(mode)
|
let desiredAccess = getDesiredAccess(mode)
|
||||||
let creationDisposition = getCreationDisposition(mode, filename)
|
let creationDisposition = getCreationDisposition(mode, filename)
|
||||||
|
|
@ -120,7 +120,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
|
||||||
## returned.
|
## returned.
|
||||||
var retFuture = newFuture[string]("asyncfile.read")
|
var retFuture = newFuture[string]("asyncfile.read")
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
var buffer = alloc0(size)
|
var buffer = alloc0(size)
|
||||||
|
|
||||||
var ol = PCustomOverlapped()
|
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
|
## Sets the position of the file pointer that is used for read/write
|
||||||
## operations. The file's first byte has the index zero.
|
## operations. The file's first byte has the index zero.
|
||||||
f.offset = pos
|
f.offset = pos
|
||||||
when not defined(windows):
|
when not defined(windows) and not defined(nimdoc):
|
||||||
let ret = lseek(f.fd.cint, pos, SEEK_SET)
|
let ret = lseek(f.fd.cint, pos, SEEK_SET)
|
||||||
if ret == -1:
|
if ret == -1:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
@ -245,7 +245,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
|
||||||
## specified file.
|
## specified file.
|
||||||
var retFuture = newFuture[void]("asyncfile.write")
|
var retFuture = newFuture[void]("asyncfile.write")
|
||||||
var copy = data
|
var copy = data
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
var buffer = alloc0(data.len)
|
var buffer = alloc0(data.len)
|
||||||
copyMem(buffer, addr copy[0], 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) =
|
proc close*(f: AsyncFile) =
|
||||||
## Closes the file specified.
|
## Closes the file specified.
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
if not closeHandle(f.fd.THandle).bool:
|
if not closeHandle(f.fd.THandle).bool:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,24 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
||||||
result[i] = itm
|
result[i] = itm
|
||||||
inc(i)
|
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] =
|
proc deduplicate*[T](seq1: seq[T]): seq[T] =
|
||||||
## Returns a new sequence without duplicates.
|
## 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)
|
newSeq(result, m)
|
||||||
for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
|
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.
|
## Splits and distributes a sequence `s` into `num` sub sequences.
|
||||||
##
|
##
|
||||||
## Returns a sequence of `num` sequences. For some input values this is the
|
## 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)[0] == @[1, 2]
|
||||||
## assert numbers.distribute(6)[5] == @[7]
|
## assert numbers.distribute(6)[5] == @[7]
|
||||||
assert(not s.isNil, "`s` can't be nil")
|
assert(not s.isNil, "`s` can't be nil")
|
||||||
assert(num > 0, "`num` has to be greater than zero")
|
|
||||||
if num < 2:
|
if num < 2:
|
||||||
result = @[s]
|
result = @[s]
|
||||||
return
|
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.
|
# Create the result and calculate the stride size and the remainder if any.
|
||||||
result = newSeq[seq[T]](num)
|
result = newSeq[seq[T]](num)
|
||||||
var
|
var
|
||||||
|
|
@ -587,4 +606,14 @@ when isMainModule:
|
||||||
seq2D[0][1] = true
|
seq2D[0][1] = true
|
||||||
doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
|
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"
|
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 hc: THash
|
||||||
var index = rawGet(t, key, hc)
|
var index = rawGet(t, key, hc)
|
||||||
if index >= 0: result = t.data[index].val
|
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 =
|
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`.
|
## 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)
|
result.phi = phase(z)
|
||||||
|
|
||||||
proc rect*(r: float, phi: float): Complex =
|
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.re = r * cos(phi)
|
||||||
result.im = sin(phi)
|
result.im = r * sin(phi)
|
||||||
|
|
||||||
|
|
||||||
proc `$`*(z: Complex): string =
|
proc `$`*(z: Complex): string =
|
||||||
|
|
@ -438,5 +438,6 @@ when isMainModule:
|
||||||
assert( arccoth(a) =~ arctanh(1/a) )
|
assert( arccoth(a) =~ arctanh(1/a) )
|
||||||
|
|
||||||
assert( phase(a) == 1.1071487177940904 )
|
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) )
|
assert( rect(1.0, 2.0) =~ (-0.4161468365471424, 0.9092974268256817) )
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@
|
||||||
## proc hash(x: Something): THash =
|
## proc hash(x: Something): THash =
|
||||||
## ## Computes a THash from `x`.
|
## ## Computes a THash from `x`.
|
||||||
## var h: THash = 0
|
## var h: THash = 0
|
||||||
## h = h &! hash(x.foo)
|
## h = h !& hash(x.foo)
|
||||||
## h = h &! hash(x.bar)
|
## h = h !& hash(x.bar)
|
||||||
## result = !$h
|
## result = !$h
|
||||||
|
|
||||||
import
|
import
|
||||||
|
|
|
||||||
|
|
@ -390,8 +390,11 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
|
||||||
## server takes longer than specified an ETimeout exception will be raised.
|
## server takes longer than specified an ETimeout exception will be raised.
|
||||||
var r = if proxy == nil: parseUri(url) else: proxy.url
|
var r = if proxy == nil: parseUri(url) else: proxy.url
|
||||||
var headers = substr(httpMethod, len("http"))
|
var headers = substr(httpMethod, len("http"))
|
||||||
|
# TODO: Use generateHeaders further down once it supports proxies.
|
||||||
if proxy == nil:
|
if proxy == nil:
|
||||||
headers.add(" " & r.path)
|
headers.add ' '
|
||||||
|
if r.path[0] != '/': headers.add '/'
|
||||||
|
headers.add(r.path)
|
||||||
if r.query.len > 0:
|
if r.query.len > 0:
|
||||||
headers.add("?" & r.query)
|
headers.add("?" & r.query)
|
||||||
else:
|
else:
|
||||||
|
|
@ -567,9 +570,12 @@ proc downloadFile*(url: string, outputFilename: string,
|
||||||
|
|
||||||
proc generateHeaders(r: Uri, httpMethod: string,
|
proc generateHeaders(r: Uri, httpMethod: string,
|
||||||
headers: StringTableRef): string =
|
headers: StringTableRef): string =
|
||||||
|
# TODO: Use this in the blocking HttpClient once it supports proxies.
|
||||||
result = substr(httpMethod, len("http"))
|
result = substr(httpMethod, len("http"))
|
||||||
# TODO: Proxies
|
# TODO: Proxies
|
||||||
result.add(" " & r.path)
|
result.add ' '
|
||||||
|
if r.path[0] != '/': result.add '/'
|
||||||
|
result.add(r.path)
|
||||||
if r.query.len > 0:
|
if r.query.len > 0:
|
||||||
result.add("?" & r.query)
|
result.add("?" & r.query)
|
||||||
result.add(" HTTP/1.1\c\L")
|
result.add(" HTTP/1.1\c\L")
|
||||||
|
|
|
||||||
|
|
@ -816,7 +816,7 @@ proc copy*(p: JsonNode): JsonNode =
|
||||||
# ------------- pretty printing ----------------------------------------------
|
# ------------- pretty printing ----------------------------------------------
|
||||||
|
|
||||||
proc indent(s: var string, i: int) =
|
proc indent(s: var string, i: int) =
|
||||||
s.add(repeatChar(i))
|
s.add(spaces(i))
|
||||||
|
|
||||||
proc newIndent(curr, indent: int, ml: bool): int =
|
proc newIndent(curr, indent: int, ml: bool): int =
|
||||||
if ml: return curr + indent
|
if ml: return curr + indent
|
||||||
|
|
|
||||||
|
|
@ -165,5 +165,5 @@ proc getCurrentLine(L: BaseLexer, marker: bool = true): string =
|
||||||
inc(i)
|
inc(i)
|
||||||
add(result, "\n")
|
add(result, "\n")
|
||||||
if marker:
|
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,
|
TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket,
|
||||||
TSocketImpl: SocketImpl].}
|
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],
|
proc isDisconnectionError*(flags: set[SocketFlag],
|
||||||
lastError: OSErrorCode): bool =
|
lastError: OSErrorCode): bool =
|
||||||
## Determines whether ``lastError`` is a disconnection error. Only does this
|
## 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):
|
when defined(ssl):
|
||||||
if socket.isSSL:
|
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)
|
let ret = SSLConnect(socket.sslHandle)
|
||||||
socketError(socket, ret)
|
socketError(socket, ret)
|
||||||
|
|
||||||
|
|
@ -969,20 +992,6 @@ proc isSsl*(socket: Socket): bool =
|
||||||
proc getFd*(socket: Socket): SocketHandle = return socket.fd
|
proc getFd*(socket: Socket): SocketHandle = return socket.fd
|
||||||
## Returns the socket's file descriptor
|
## 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 =
|
proc IPv4_any*(): TIpAddress =
|
||||||
## Returns the IPv4 any address, which can be used to listen on all available
|
## Returns the IPv4 any address, which can be used to listen on all available
|
||||||
## network adapters
|
## network adapters
|
||||||
|
|
@ -1241,7 +1250,7 @@ proc parseIPv6Address(address_str: string): TIpAddress =
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too many groups")
|
"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
|
## Parses an IP address
|
||||||
## Raises EInvalidValue on error
|
## Raises EInvalidValue on error
|
||||||
if address_str == nil:
|
if address_str == nil:
|
||||||
|
|
@ -1250,3 +1259,13 @@ proc parseIpAddress*(address_str: string): TIpAddress =
|
||||||
return parseIPv6Address(address_str)
|
return parseIPv6Address(address_str)
|
||||||
else:
|
else:
|
||||||
return parseIPv4Address(address_str)
|
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
|
## It supports one convenience iterator over all command line options and some
|
||||||
## lower-level features.
|
## lower-level features.
|
||||||
##
|
##
|
||||||
## **Deprecated since version 0.9.3:** Use the `parseopt2 <parseopt2.html>`_
|
## Supported syntax:
|
||||||
## module instead as this version has issues with spaces in arguments.
|
##
|
||||||
{.deprecated.}
|
## 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.}
|
{.push debugger: off.}
|
||||||
|
|
||||||
include "system/inclrtl"
|
include "system/inclrtl"
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
|
||||||
my.kind = xmlError
|
my.kind = xmlError
|
||||||
my.a = ""
|
my.a = ""
|
||||||
my.b = ""
|
my.b = ""
|
||||||
|
my.c = nil
|
||||||
my.options = options
|
my.options = options
|
||||||
|
|
||||||
proc close*(my: var XmlParser) {.inline.} =
|
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
|
## returns the current event type for the XML parser
|
||||||
return my.kind
|
return my.kind
|
||||||
|
|
||||||
proc charData*(my: XmlParser): string {.inline.} =
|
template charData*(my: XmlParser): string =
|
||||||
## returns the character data for the events: ``xmlCharData``,
|
## returns the character data for the events: ``xmlCharData``,
|
||||||
## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial``
|
## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial``
|
||||||
assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData,
|
assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData,
|
||||||
xmlSpecial})
|
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``,
|
## returns the element name for the events: ``xmlElementStart``,
|
||||||
## ``xmlElementEnd``, ``xmlElementOpen``
|
## ``xmlElementEnd``, ``xmlElementOpen``
|
||||||
assert(my.kind in {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``
|
## returns the entity name for the event: ``xmlEntity``
|
||||||
assert(my.kind == 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``
|
## returns the attribute key for the event ``xmlAttribute``
|
||||||
assert(my.kind == 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``
|
## returns the attribute value for the event ``xmlAttribute``
|
||||||
assert(my.kind == 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``
|
## returns the processing instruction name for the event ``xmlPI``
|
||||||
assert(my.kind == 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``
|
## returns the rest of the processing instruction for the event ``xmlPI``
|
||||||
assert(my.kind == xmlPI)
|
assert(my.kind == xmlPI)
|
||||||
return my.b
|
my.b
|
||||||
|
|
||||||
proc rawData*(my: XmlParser): string {.inline.} =
|
proc rawData*(my: XmlParser): string {.inline.} =
|
||||||
## returns the underlying 'data' string by reference.
|
## returns the underlying 'data' string by reference.
|
||||||
|
|
@ -621,7 +622,7 @@ proc next*(my: var XmlParser) =
|
||||||
of stateEmptyElementTag:
|
of stateEmptyElementTag:
|
||||||
my.state = stateNormal
|
my.state = stateNormal
|
||||||
my.kind = xmlElementEnd
|
my.kind = xmlElementEnd
|
||||||
if not isNil(my.c):
|
if not my.c.isNil:
|
||||||
my.a = my.c
|
my.a = my.c
|
||||||
of stateError:
|
of stateError:
|
||||||
my.kind = xmlError
|
my.kind = xmlError
|
||||||
|
|
|
||||||
|
|
@ -902,7 +902,7 @@ proc replacef*(s: string, sub: Peg, by: string): string {.
|
||||||
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. 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:
|
## Results in:
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -798,6 +798,22 @@ proc zunionstore*(r: Redis, destination: string, numkeys: string,
|
||||||
|
|
||||||
return r.readInteger()
|
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
|
# Pub/Sub
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -224,8 +224,10 @@ proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
||||||
|
|
||||||
proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
if bufLen > 0:
|
if bufLen <= 0:
|
||||||
setLen(s.data, s.data.len + bufLen)
|
return
|
||||||
|
if s.pos + bufLen > s.data.len:
|
||||||
|
setLen(s.data, s.pos + bufLen)
|
||||||
copyMem(addr(s.data[s.pos]), buffer, bufLen)
|
copyMem(addr(s.data[s.pos]), buffer, bufLen)
|
||||||
inc(s.pos, bufLen)
|
inc(s.pos, bufLen)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -499,26 +499,47 @@ proc parseEnum*[T: enum](s: string, default: T): T =
|
||||||
return e
|
return e
|
||||||
result = default
|
result = default
|
||||||
|
|
||||||
proc repeatChar*(count: int, c: char = ' '): string {.noSideEffect,
|
proc repeat*(c: char, count: int): string {.noSideEffect,
|
||||||
rtl, extern: "nsuRepeatChar".} =
|
rtl, extern: "nsuRepeatChar".} =
|
||||||
## Returns a string of length `count` consisting only of
|
## Returns a string of length `count` consisting only of
|
||||||
## the character `c`. You can use this proc to left align strings. Example:
|
## the character `c`. You can use this proc to left align strings. Example:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. 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
|
## let
|
||||||
## width = 15
|
## width = 15
|
||||||
## text1 = "Hello user!"
|
## text1 = "Hello user!"
|
||||||
## text2 = "This is a very long string"
|
## text2 = "This is a very long string"
|
||||||
## echo text1 & repeatChar(max(0, width - text1.len)) & "|"
|
## echo text1 & spaces(max(0, width - text1.len)) & "|"
|
||||||
## echo text2 & repeatChar(max(0, width - text2.len)) & "|"
|
## echo text2 & spaces(max(0, width - text2.len)) & "|"
|
||||||
result = newString(count)
|
|
||||||
for i in 0..count-1: result[i] = c
|
|
||||||
|
|
||||||
proc repeatStr*(count: int, s: string): string {.noSideEffect,
|
proc repeatChar*(count: int, c: char = ' '): string {.deprecated.} = repeat(c, count)
|
||||||
rtl, extern: "nsuRepeatStr".} =
|
## deprecated: use repeat() or spaces()
|
||||||
## Returns `s` concatenated `count` times.
|
|
||||||
result = newStringOfCap(count*s.len)
|
proc repeatStr*(count: int, s: string): string {.deprecated.} = repeat(s, count)
|
||||||
for i in 0..count-1: result.add(s)
|
## deprecated: use repeat(string, count) or string.repeat(count)
|
||||||
|
|
||||||
proc align*(s: string, count: int, padding = ' '): string {.
|
proc align*(s: string, count: int, padding = ' '): string {.
|
||||||
noSideEffect, rtl, extern: "nsuAlignString".} =
|
noSideEffect, rtl, extern: "nsuAlignString".} =
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ when defined(windows):
|
||||||
var
|
var
|
||||||
oldAttr = getAttributes()
|
oldAttr = getAttributes()
|
||||||
|
|
||||||
proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".}
|
|
||||||
else:
|
else:
|
||||||
import termios, unsigned
|
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"write", bindSym"stdout", newStrLitNode("\n")))
|
||||||
result.add(newCall(bindSym"resetAttributes"))
|
result.add(newCall(bindSym"resetAttributes"))
|
||||||
|
|
||||||
proc getch*(): char =
|
when not defined(windows):
|
||||||
|
proc getch*(): char =
|
||||||
## Read a single character from the terminal, blocking until it is entered.
|
## Read a single character from the terminal, blocking until it is entered.
|
||||||
## The character is not printed to the terminal.
|
## The character is not printed to the terminal. This is not available for
|
||||||
when defined(windows):
|
## Windows.
|
||||||
result = winGetch().char
|
|
||||||
else:
|
|
||||||
let fd = getFileHandle(stdin)
|
let fd = getFileHandle(stdin)
|
||||||
var oldMode: Termios
|
var oldMode: Termios
|
||||||
discard fd.tcgetattr(addr oldMode)
|
discard fd.tcgetattr(addr oldMode)
|
||||||
|
|
|
||||||
|
|
@ -628,25 +628,25 @@ proc formatToken(info: TimeInfo, token: string, buf: var string) =
|
||||||
var fr = ($info.year).len()-2
|
var fr = ($info.year).len()-2
|
||||||
if fr < 0: fr = 0
|
if fr < 0: fr = 0
|
||||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
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)
|
buf.add(fyear)
|
||||||
of "yyy":
|
of "yyy":
|
||||||
var fr = ($info.year).len()-3
|
var fr = ($info.year).len()-3
|
||||||
if fr < 0: fr = 0
|
if fr < 0: fr = 0
|
||||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
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)
|
buf.add(fyear)
|
||||||
of "yyyy":
|
of "yyyy":
|
||||||
var fr = ($info.year).len()-4
|
var fr = ($info.year).len()-4
|
||||||
if fr < 0: fr = 0
|
if fr < 0: fr = 0
|
||||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
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)
|
buf.add(fyear)
|
||||||
of "yyyyy":
|
of "yyyyy":
|
||||||
var fr = ($info.year).len()-5
|
var fr = ($info.year).len()-5
|
||||||
if fr < 0: fr = 0
|
if fr < 0: fr = 0
|
||||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
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)
|
buf.add(fyear)
|
||||||
of "z":
|
of "z":
|
||||||
let hrs = (info.timezone div 60) div 60
|
let hrs = (info.timezone div 60) div 60
|
||||||
|
|
|
||||||
|
|
@ -118,21 +118,35 @@ proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
|
||||||
elif i <=% 0x07FF:
|
elif i <=% 0x07FF:
|
||||||
result = newString(2)
|
result = newString(2)
|
||||||
result[0] = chr((i shr 6) or 0b110_00000)
|
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:
|
elif i <=% 0xFFFF:
|
||||||
result = newString(3)
|
result = newString(3)
|
||||||
result[0] = chr(i shr 12 or 0b1110_0000)
|
result[0] = chr(i shr 12 or 0b1110_0000)
|
||||||
result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||||
result[2] = chr(i 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 = newString(4)
|
||||||
result[0] = chr(i shr 18 or 0b1111_0000)
|
result[0] = chr(i shr 18 or 0b1111_0000)
|
||||||
result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
|
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[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||||
result[3] = chr(i 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:
|
else:
|
||||||
result = newString(1)
|
discard # error, exception?
|
||||||
result[0] = chr(i)
|
|
||||||
|
|
||||||
proc `$`*(rune: Rune): string =
|
proc `$`*(rune: Rune): string =
|
||||||
## converts a rune to a string
|
## converts a rune to a string
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,16 @@ proc `$`*(u: Uri): string =
|
||||||
result.add(u.anchor)
|
result.add(u.anchor)
|
||||||
|
|
||||||
when isMainModule:
|
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:
|
block:
|
||||||
let str = "http://localhost:8080/test"
|
let str = "http://localhost:8080/test"
|
||||||
let test = parseUri(str)
|
let test = parseUri(str)
|
||||||
|
|
|
||||||
|
|
@ -1083,7 +1083,7 @@ proc addEscaped(s: string): string =
|
||||||
else: result.add(c)
|
else: result.add(c)
|
||||||
|
|
||||||
proc nodeToXml(n: PNode, indent: int = 0): string =
|
proc nodeToXml(n: PNode, indent: int = 0): string =
|
||||||
result = repeatChar(indent, ' ') & "<" & n.nodeName
|
result = spaces(indent) & "<" & n.nodeName
|
||||||
if not isNil(n.attributes):
|
if not isNil(n.attributes):
|
||||||
for i in items(n.attributes):
|
for i in items(n.attributes):
|
||||||
result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
|
result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
|
||||||
|
|
@ -1098,23 +1098,23 @@ proc nodeToXml(n: PNode, indent: int = 0): string =
|
||||||
of ElementNode:
|
of ElementNode:
|
||||||
result.add(nodeToXml(i, indent + 2))
|
result.add(nodeToXml(i, indent + 2))
|
||||||
of TextNode:
|
of TextNode:
|
||||||
result.add(repeatChar(indent * 2, ' '))
|
result.add(spaces(indent * 2))
|
||||||
result.add(addEscaped(i.nodeValue))
|
result.add(addEscaped(i.nodeValue))
|
||||||
of CDataSectionNode:
|
of CDataSectionNode:
|
||||||
result.add(repeatChar(indent * 2, ' '))
|
result.add(spaces(indent * 2))
|
||||||
result.add("<![CDATA[" & i.nodeValue & "]]>")
|
result.add("<![CDATA[" & i.nodeValue & "]]>")
|
||||||
of ProcessingInstructionNode:
|
of ProcessingInstructionNode:
|
||||||
result.add(repeatChar(indent * 2, ' '))
|
result.add(spaces(indent * 2))
|
||||||
result.add("<?" & PProcessingInstruction(i).target & " " &
|
result.add("<?" & PProcessingInstruction(i).target & " " &
|
||||||
PProcessingInstruction(i).data & " ?>")
|
PProcessingInstruction(i).data & " ?>")
|
||||||
of CommentNode:
|
of CommentNode:
|
||||||
result.add(repeatChar(indent * 2, ' '))
|
result.add(spaces(indent * 2))
|
||||||
result.add("<!-- " & i.nodeValue & " -->")
|
result.add("<!-- " & i.nodeValue & " -->")
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
# Add the ending tag - </tag>
|
# Add the ending tag - </tag>
|
||||||
result.add(repeatChar(indent, ' ') & "</" & n.nodeName & ">")
|
result.add(spaces(indent) & "</" & n.nodeName & ">")
|
||||||
|
|
||||||
proc `$`*(doc: PDocument): string =
|
proc `$`*(doc: PDocument): string =
|
||||||
## Converts a PDocument object into a string representation of it's XML
|
## Converts a PDocument object into a string representation of it's XML
|
||||||
|
|
|
||||||
|
|
@ -2021,7 +2021,7 @@ proc `$`*[T: tuple|object](x: T): string =
|
||||||
result = "("
|
result = "("
|
||||||
var firstElement = true
|
var firstElement = true
|
||||||
for name, value in fieldPairs(x):
|
for name, value in fieldPairs(x):
|
||||||
if not(firstElement): result.add(", ")
|
if not firstElement: result.add(", ")
|
||||||
result.add(name)
|
result.add(name)
|
||||||
result.add(": ")
|
result.add(": ")
|
||||||
result.add($value)
|
result.add($value)
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,9 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.benign.} =
|
||||||
|
|
||||||
proc copyDeepString(src: NimString): NimString {.inline.} =
|
proc copyDeepString(src: NimString): NimString {.inline.} =
|
||||||
if src != nil:
|
if src != nil:
|
||||||
result = rawNewString(src.space)
|
result = rawNewStringNoInit(src.len)
|
||||||
result.len = 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) =
|
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
|
||||||
var
|
var
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nim's Runtime Library
|
# Nim's Runtime Library
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2015 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# 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)
|
# convert pointer to userdata to object (=pointer to refcount)
|
||||||
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
|
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
|
result = ntfAcyclic notin c.typ.flags
|
||||||
|
|
||||||
proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
|
proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
|
||||||
|
|
@ -461,6 +461,9 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
|
result = rawNewObj(typ, size, gch)
|
||||||
|
|
||||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
result = rawNewObj(typ, size, gch)
|
result = rawNewObj(typ, size, gch)
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
|
|
@ -1050,7 +1053,11 @@ when useMarkForDebug or useBackupGc:
|
||||||
markGlobals(gch)
|
markGlobals(gch)
|
||||||
|
|
||||||
proc collectCT(gch: var TGcHeap) =
|
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
|
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
||||||
gch.recGcLock == 0:
|
gch.recGcLock == 0:
|
||||||
when useMarkForDebug:
|
when useMarkForDebug:
|
||||||
|
|
|
||||||
|
|
@ -593,7 +593,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
||||||
return
|
return
|
||||||
add(gch.zct, res)
|
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
|
# generates a new object and sets its reference counter to 0
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,10 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
when defined(memProfiler): nimProfile(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.} =
|
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
# `newObj` already uses locks, so no need for them here.
|
# `newObj` already uses locks, so no need for them here.
|
||||||
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ when declared(NimString):
|
||||||
# we are in system module:
|
# we are in system module:
|
||||||
{.pragma: codegenType, compilerproc.}
|
{.pragma: codegenType, compilerproc.}
|
||||||
else:
|
else:
|
||||||
{.pragma: codegenType.}
|
{.pragma: codegenType, importc.}
|
||||||
|
|
||||||
type
|
type
|
||||||
# This should be he same as ast.TTypeKind
|
# This should be he same as ast.TTypeKind
|
||||||
|
|
@ -65,7 +65,7 @@ type
|
||||||
tyBigNum,
|
tyBigNum,
|
||||||
|
|
||||||
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
||||||
TNimNode {.codegenType, final.} = object
|
TNimNode {.codegenType.} = object
|
||||||
kind: TNimNodeKind
|
kind: TNimNodeKind
|
||||||
offset: int
|
offset: int
|
||||||
typ: ptr TNimType
|
typ: ptr TNimType
|
||||||
|
|
@ -78,7 +78,7 @@ type
|
||||||
ntfAcyclic = 1, # type cannot form a cycle
|
ntfAcyclic = 1, # type cannot form a cycle
|
||||||
ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow
|
ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow
|
||||||
# version
|
# version
|
||||||
TNimType {.codegenType, final.} = object
|
TNimType {.codegenType.} = object
|
||||||
size: int
|
size: int
|
||||||
kind: TNimKind
|
kind: TNimKind
|
||||||
flags: set[TNimTypeFlag]
|
flags: set[TNimTypeFlag]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nim's Runtime Library
|
# Nim's Runtime Library
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2015 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# 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))
|
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||||
cast[PGenericSeq](result).len = len
|
cast[PGenericSeq](result).len = len
|
||||||
cast[PGenericSeq](result).reserved = len
|
cast[PGenericSeq](result).reserved = len
|
||||||
|
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||||
|
result = alloc(size)
|
||||||
|
|
||||||
proc growObj(old: pointer, newsize: int): pointer =
|
proc growObj(old: pointer, newsize: int): pointer =
|
||||||
result = realloc(old, newsize)
|
result = realloc(old, newsize)
|
||||||
|
|
@ -289,6 +291,10 @@ elif defined(nogc):
|
||||||
|
|
||||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||||
result = alloc0(size)
|
result = alloc0(size)
|
||||||
|
|
||||||
|
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||||
|
result = alloc(size)
|
||||||
|
|
||||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
||||||
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||||
cast[PGenericSeq](result).len = len
|
cast[PGenericSeq](result).len = len
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,8 @@ proc readAllFile(file: File): string =
|
||||||
proc readAll(file: File): TaintedString =
|
proc readAll(file: File): TaintedString =
|
||||||
# Separate handling needed because we need to buffer when we
|
# Separate handling needed because we need to buffer when we
|
||||||
# don't know the overall length of the File.
|
# don't know the overall length of the File.
|
||||||
var len = rawFileSize(file)
|
let len = if file != stdin: rawFileSize(file) else: -1
|
||||||
if len >= 0:
|
if len > 0:
|
||||||
result = readAllFile(file, len).TaintedString
|
result = readAllFile(file, len).TaintedString
|
||||||
else:
|
else:
|
||||||
result = readAllBuffer(file).TaintedString
|
result = readAllBuffer(file).TaintedString
|
||||||
|
|
|
||||||
|
|
@ -30,18 +30,30 @@ proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
|
||||||
if a == b: return true
|
if a == b: return true
|
||||||
if a == nil or b == nil: return false
|
if a == nil or b == nil: return false
|
||||||
return a.len == b.len and
|
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):
|
when declared(allocAtomic):
|
||||||
template allocStr(size: expr): expr =
|
template allocStr(size: expr): expr =
|
||||||
cast[NimString](allocAtomic(size))
|
cast[NimString](allocAtomic(size))
|
||||||
|
|
||||||
|
template allocStrNoInit(size: expr): expr =
|
||||||
|
cast[NimString](boehmAllocAtomic(size))
|
||||||
else:
|
else:
|
||||||
template allocStr(size: expr): expr =
|
template allocStr(size: expr): expr =
|
||||||
cast[NimString](newObj(addr(strDesc), size))
|
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.} =
|
proc rawNewString(space: int): NimString {.compilerProc.} =
|
||||||
var s = space
|
var s = space
|
||||||
if s < 8: s = 7
|
if s < 7: s = 7
|
||||||
result = allocStr(sizeof(TGenericSeq) + s + 1)
|
result = allocStr(sizeof(TGenericSeq) + s + 1)
|
||||||
result.reserved = s
|
result.reserved = s
|
||||||
|
|
||||||
|
|
@ -53,10 +65,10 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
|
||||||
var start = max(start, 0)
|
var start = max(start, 0)
|
||||||
var len = min(last, s.len-1) - start + 1
|
var len = min(last, s.len-1) - start + 1
|
||||||
if len > 0:
|
if len > 0:
|
||||||
result = rawNewString(len)
|
result = rawNewStringNoInit(len)
|
||||||
result.len = len
|
result.len = len
|
||||||
c_memcpy(result.data, addr(s.data[start]), len * sizeof(char))
|
c_memcpy(result.data, addr(s.data[start]), len)
|
||||||
#result.data[len] = '\0'
|
result.data[len] = '\0'
|
||||||
else:
|
else:
|
||||||
result = rawNewString(len)
|
result = rawNewString(len)
|
||||||
|
|
||||||
|
|
@ -64,10 +76,9 @@ proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
|
||||||
result = copyStrLast(s, start, s.len-1)
|
result = copyStrLast(s, start, s.len-1)
|
||||||
|
|
||||||
proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
|
proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
|
||||||
result = rawNewString(len)
|
result = rawNewStringNoInit(len)
|
||||||
result.len = len
|
result.len = len
|
||||||
c_memcpy(result.data, str, (len+1) * sizeof(char))
|
c_memcpy(result.data, str, len + 1)
|
||||||
#result.data[len] = '\0' # readline relies on this!
|
|
||||||
|
|
||||||
proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
|
proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
|
||||||
result = toNimStr(str, c_strlen(str))
|
result = toNimStr(str, c_strlen(str))
|
||||||
|
|
@ -77,23 +88,24 @@ proc copyString(src: NimString): NimString {.compilerRtl.} =
|
||||||
if (src.reserved and seqShallowFlag) != 0:
|
if (src.reserved and seqShallowFlag) != 0:
|
||||||
result = src
|
result = src
|
||||||
else:
|
else:
|
||||||
result = rawNewString(src.space)
|
result = rawNewStringNoInit(src.len)
|
||||||
result.len = 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.} =
|
proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
|
||||||
if src != nil:
|
if src != nil:
|
||||||
var s = src.space
|
|
||||||
if s < 8: s = 7
|
|
||||||
when declared(newObjRC1):
|
when declared(newObjRC1):
|
||||||
|
var s = src.len
|
||||||
|
if s < 7: s = 7
|
||||||
result = cast[NimString](newObjRC1(addr(strDesc), sizeof(TGenericSeq) +
|
result = cast[NimString](newObjRC1(addr(strDesc), sizeof(TGenericSeq) +
|
||||||
s+1))
|
s+1))
|
||||||
else:
|
|
||||||
result = allocStr(sizeof(TGenericSeq) + s + 1)
|
|
||||||
result.reserved = s
|
result.reserved = s
|
||||||
|
else:
|
||||||
|
result = rawNewStringNoInit(src.len)
|
||||||
result.len = src.len
|
result.len = src.len
|
||||||
c_memcpy(result.data, src.data, src.len + 1)
|
c_memcpy(result.data, src.data, src.len + 1)
|
||||||
|
|
||||||
|
|
||||||
proc hashString(s: string): int {.compilerproc.} =
|
proc hashString(s: string): int {.compilerproc.} =
|
||||||
# the compiler needs exactly the same hash function!
|
# the compiler needs exactly the same hash function!
|
||||||
# this used to be used for efficient generation of string case statements
|
# 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:
|
if result.len >= result.space:
|
||||||
result.reserved = resize(result.space)
|
result.reserved = resize(result.space)
|
||||||
result = cast[NimString](growObj(result,
|
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] = c
|
||||||
result.data[result.len+1] = '\0'
|
result.data[result.len+1] = '\0'
|
||||||
inc(result.len)
|
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 = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
|
||||||
result.reserved = sp
|
result.reserved = sp
|
||||||
#result = rawNewString(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
|
# DO NOT UPDATE LEN YET: dest.len = newLen
|
||||||
|
|
||||||
proc appendString(dest, src: NimString) {.compilerproc, inline.} =
|
proc appendString(dest, src: NimString) {.compilerproc, inline.} =
|
||||||
|
|
@ -264,6 +276,16 @@ proc nimFloatToStr(f: float): string {.compilerproc.} =
|
||||||
buf[n] = '.'
|
buf[n] = '.'
|
||||||
buf[n+1] = '0'
|
buf[n+1] = '0'
|
||||||
buf[n+2] = '\0'
|
buf[n+2] = '\0'
|
||||||
|
# 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
|
result = $buf
|
||||||
|
|
||||||
proc strtod(buf: cstring, endptr: ptr cstring): float64 {.importc,
|
proc strtod(buf: cstring, endptr: ptr cstring): float64 {.importc,
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ when useWinVersion:
|
||||||
from winlean import SocketHandle
|
from winlean import SocketHandle
|
||||||
else:
|
else:
|
||||||
const
|
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):
|
when defined(macosx):
|
||||||
const
|
const
|
||||||
DLLSSLName = "libssl" & versions & ".dylib"
|
DLLSSLName = "libssl" & versions & ".dylib"
|
||||||
|
|
@ -141,6 +141,14 @@ const
|
||||||
SSL_CTRL_GET_MAX_CERT_LIST* = 50
|
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
|
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): *
|
# * 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
|
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
|
# * (buffer contents must stay the same!); this is not the default to avoid
|
||||||
# * the misconception that non-blocking SSL_write() behaves like
|
# * 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{.
|
proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cInt, larg: int, parg: pointer): int{.
|
||||||
cdecl, dynlib: DLLSSLName, importc.}
|
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 =
|
proc SSLCTXSetMode*(ctx: SslCtx, mode: int): int =
|
||||||
result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil)
|
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 bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".}
|
||||||
proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".}
|
proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".}
|
||||||
proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".}
|
proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".}
|
||||||
|
|
@ -341,8 +381,6 @@ else:
|
||||||
dynlib: DLLSSLName, importc.}
|
dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
proc SslSetFd*(s: PSSL, fd: cInt): cInt{.cdecl, 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{.
|
proc SslCTXCtrl*(ctx: PSSL_CTX, cmd: cInt, larg: int, parg: Pointer): int{.
|
||||||
cdecl, dynlib: DLLSSLName, importc.}
|
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
|
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).
|
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
|
The compiler currently supports the following platform and architecture
|
||||||
combinations:
|
combinations:
|
||||||
|
|
||||||
|
|
@ -39,8 +35,7 @@ $ bin/nim c koch
|
||||||
$ ./koch boot -d:release
|
$ ./koch boot -d:release
|
||||||
```
|
```
|
||||||
|
|
||||||
``koch install [dir]`` may then be used to install Nim, or you can simply
|
``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
|
||||||
add it to your PATH. More ``koch`` related options are documented in
|
|
||||||
[doc/koch.txt](doc/koch.txt).
|
[doc/koch.txt](doc/koch.txt).
|
||||||
|
|
||||||
The above steps can be performed on Windows in a similar fashion, the
|
The above steps can be performed on Windows in a similar fashion, the
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
line: 21
|
output: "action 3 arg"
|
||||||
errormsg: "invalid type: 'Table[string, proc (string){.gcsafe.}]'"
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import tables
|
import tables
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ discard """
|
||||||
WARNING: false first assertion from bar
|
WARNING: false first assertion from bar
|
||||||
ERROR: false second assertion from bar
|
ERROR: false second assertion from bar
|
||||||
-1
|
-1
|
||||||
tests/assert/tfailedassert.nim:27 false assertion from foo
|
tfailedassert.nim:27 false assertion from foo
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type
|
type
|
||||||
TLineInfo = tuple[filename: string, line: int]
|
TLineInfo = tuple[filename: string, line: int]
|
||||||
|
|
||||||
TMyError = object of E_Base
|
TMyError = object of Exception
|
||||||
lineinfo: TLineInfo
|
lineinfo: TLineInfo
|
||||||
|
|
||||||
EMyError = ref TMyError
|
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 """
|
discard """
|
||||||
cmd: "nim cpp $target"
|
cmd: "nim cpp $file"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import rawsockets
|
import rawsockets
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: "nim cpp $target"
|
cmd: "nim cpp $file"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import typeinfo
|
import typeinfo
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
line: 9
|
nimout: "a is deprecated [Deprecated]"
|
||||||
errormsg: "'a' is deprecated [Deprecated]"
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -8,4 +7,3 @@ var
|
||||||
|
|
||||||
a[8] = 1
|
a[8] = 1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
line: 20
|
line: 23
|
||||||
errormsg: " usage of a type with a destructor in a non destructible context"
|
nimout: " usage of a type with a destructor in a non destructible context"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
{.experimental.}
|
{.experimental.}
|
||||||
|
|
@ -19,5 +19,9 @@ proc open: TMyObj =
|
||||||
|
|
||||||
proc `$`(x: TMyObj): string = $x.y
|
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 """
|
discard """
|
||||||
line: 7
|
line: 7
|
||||||
errormsg: "expression 'items' cannot be called"
|
errormsg: "undeclared identifier: 'items'"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type a = enum b,c,d
|
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
|
write stdout, space
|
||||||
|
|
||||||
proc doTrace(n: PNode[T,D], level: int) =
|
proc doTrace(n: PNode[T,D], level: int) =
|
||||||
var space = repeatChar(2 * level)
|
var space = spaces(2 * level)
|
||||||
traceln(space)
|
traceln(space)
|
||||||
write stdout, "node: "
|
write stdout, "node: "
|
||||||
if n == nil:
|
if n == nil:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
# Bug #2022
|
# Bug #2022
|
||||||
|
|
||||||
|
discard """
|
||||||
|
output: '''@[97, 45]
|
||||||
|
@[true, false]
|
||||||
|
@[false, false]'''
|
||||||
|
"""
|
||||||
|
|
||||||
## The goal of this snippet is to provide and test a construct for general-
|
## The goal of this snippet is to provide and test a construct for general-
|
||||||
## purpose, random-access mapping. I use an AST-manipulation-based approach
|
## purpose, random-access mapping. I use an AST-manipulation-based approach
|
||||||
## because it's more efficient than using procedure pointers and less
|
## because it's more efficient than using procedure pointers and less
|
||||||
|
|
@ -31,6 +37,7 @@ type Mapped[Input; predicate: static[string]] = object
|
||||||
input: Input
|
input: Input
|
||||||
|
|
||||||
macro map(input, predicate: expr): expr =
|
macro map(input, predicate: expr): expr =
|
||||||
|
let predicate = callsite()[2]
|
||||||
newNimNode(nnkObjConstr).add(
|
newNimNode(nnkObjConstr).add(
|
||||||
newNimNode(nnkBracketExpr).add(
|
newNimNode(nnkBracketExpr).add(
|
||||||
ident"Mapped",
|
ident"Mapped",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
file: "toop1.nim"
|
|
||||||
output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
|
output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
|
||||||
|
disabled: "true"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import globalaux, globalaux2
|
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
|
let width = prefixes.map(proc (x: string): int = 3 + len(x)).max
|
||||||
|
|
||||||
for line in zip(prefixes, helps):
|
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] = @[],
|
proc echo_help*(expected: seq[Tparameter_specification] = @[],
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import streams
|
import streams
|
||||||
from strutils import repeatChar
|
from strutils import repeat
|
||||||
|
|
||||||
proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString =
|
proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString =
|
||||||
var lastChr = length
|
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') =
|
proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') =
|
||||||
if str.len < length:
|
if str.len < length:
|
||||||
s.write(str)
|
s.write(str)
|
||||||
s.write(repeatChar(length - str.len, padChar))
|
s.write(repeat(padChar, length - str.len))
|
||||||
elif str.len > length:
|
elif str.len > length:
|
||||||
s.write(str.substr(0, length - 1))
|
s.write(str.substr(0, length - 1))
|
||||||
else:
|
else:
|
||||||
|
|
@ -37,7 +37,7 @@ when isMainModule:
|
||||||
testStream.setPosition 0
|
testStream.setPosition 0
|
||||||
testStream.writePaddedStr("Sup", 10)
|
testStream.writePaddedStr("Sup", 10)
|
||||||
echo(repr(testStream), testStream.data.len)
|
echo(repr(testStream), testStream.data.len)
|
||||||
doAssert testStream.data == "Sup"&repeatChar(7, '\0')
|
doAssert testStream.data == "Sup"&repeat('\0', 7)
|
||||||
|
|
||||||
testStream.setPosition 0
|
testStream.setPosition 0
|
||||||
res = testStream.readPaddedStr(10)
|
res = testStream.readPaddedStr(10)
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ when isMainModule:
|
||||||
discard """block:
|
discard """block:
|
||||||
var
|
var
|
||||||
TestFile: FileChallengePair
|
TestFile: FileChallengePair
|
||||||
contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
|
contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
|
||||||
testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
|
testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
|
||||||
testFile.file = checksumStr(contents)
|
testFile.file = checksumStr(contents)
|
||||||
myAssets.add testFile"""
|
myAssets.add testFile"""
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ when defined(recordMode):
|
||||||
isRecording = false
|
isRecording = false
|
||||||
proc zeroPad*(s: string; minLen: int): string =
|
proc zeroPad*(s: string; minLen: int): string =
|
||||||
if s.len < minLen:
|
if s.len < minLen:
|
||||||
result = repeatChar(minLen - s.len, '0')
|
result = repeat(0, minLen - s.len)
|
||||||
result.add s
|
result.add s
|
||||||
else:
|
else:
|
||||||
result = s
|
result = s
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,9 @@ when isMainModule:
|
||||||
var res = t.map(proc(z: int): int = result = z * 10)
|
var res = t.map(proc(z: int): int = result = z * 10)
|
||||||
dumpSeq res
|
dumpSeq res
|
||||||
|
|
||||||
from strutils import toHex, repeatStr
|
from strutils import toHex
|
||||||
var foocakes = t.map(proc(z: int): string =
|
var foocakes = t.map(proc(z: int): string =
|
||||||
result = toHex((z * 23).biggestInt, 4))
|
result = toHex((z * 23).BiggestInt, 4))
|
||||||
dumpSeq foocakes
|
dumpSeq foocakes
|
||||||
|
|
||||||
t.mapInPlace(proc(z: int): int = result = z * 30)
|
t.mapInPlace(proc(z: int): int = result = z * 30)
|
||||||
|
|
|
||||||
|
|
@ -24,17 +24,17 @@ when isMainModule:
|
||||||
import strutils
|
import strutils
|
||||||
var r = compress("Hello")
|
var r = compress("Hello")
|
||||||
echo repr(r)
|
echo repr(r)
|
||||||
var l = "Hello".len
|
var ln = "Hello".len
|
||||||
var rr = uncompress(r, l)
|
var rr = uncompress(r, ln)
|
||||||
echo repr(rr)
|
echo repr(rr)
|
||||||
assert rr == "Hello"
|
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
|
var s = "yo dude sup bruh homie" * 50
|
||||||
r = compress(s)
|
r = compress(s)
|
||||||
echo s.len, " -> ", r.len
|
echo s.len, " -> ", r.len
|
||||||
|
|
||||||
l = s.len
|
ln = s.len
|
||||||
rr = uncompress(r, l)
|
rr = uncompress(r, ln)
|
||||||
echo r.len, " -> ", rr.len
|
echo r.len, " -> ", rr.len
|
||||||
assert rr == s
|
assert rr == s
|
||||||
|
|
@ -174,7 +174,7 @@ when isMainModule:
|
||||||
block:
|
block:
|
||||||
var
|
var
|
||||||
TestFile: FileChallengePair
|
TestFile: FileChallengePair
|
||||||
contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
|
contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
|
||||||
testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
|
testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
|
||||||
testFile.file = checksumStr(contents)
|
testFile.file = checksumStr(contents)
|
||||||
myAssets.add testFile
|
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 """
|
discard """
|
||||||
file: "tissue710.nim"
|
file: "tissue710.nim"
|
||||||
line: 8
|
line: 8
|
||||||
errorMsg: "expression '||' cannot be called"
|
errorMsg: "undeclared identifier: '||'"
|
||||||
"""
|
"""
|
||||||
var sum = 0
|
var sum = 0
|
||||||
for x in 3..1000:
|
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