Resolve conflic.

This commit is contained in:
Konstantin Molchanov
2017-03-27 21:46:43 +04:00
52 changed files with 666 additions and 234 deletions

View File

@@ -82,7 +82,7 @@ template mdbg*: bool {.dirty.} =
elif compiles(L.fileIdx):
L.fileIdx == gProjectMainIdx
else:
false
error()
# --------------------------- ident tables ----------------------------------
proc idTableGet*(t: TIdTable, key: PIdObj): RootRef

View File

@@ -604,6 +604,7 @@ proc generateHeaders(m: BModule) =
else:
addf(m.s[cfsHeaders], "#include $1$N", [rope(it)])
add(m.s[cfsHeaders], "#undef linux" & tnl)
add(m.s[cfsHeaders], "#undef near" & tnl)
proc initFrame(p: BProc, procname, filename: Rope): Rope =
discard cgsym(p.module, "nimFrame")

View File

@@ -229,6 +229,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
var base = lastSon(methods[0].ast).sym
result = base
var paramLen = sonsLen(base.typ)
var nilchecks = newNodeI(nkStmtList, base.info)
var disp = newNodeI(nkIfStmt, base.info)
var ands = getSysSym("and")
var iss = getSysSym("of")
@@ -239,7 +240,11 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
if contains(relevantCols, col):
var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
addSon(isn, newSymNode(iss))
addSon(isn, newSymNode(base.typ.n.sons[col].sym))
let param = base.typ.n.sons[col].sym
addSon(isn, newSymNode(param))
if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
addSon(nilchecks, newTree(nkCall,
newSymNode(getCompilerProc"chckNilDisp"), newSymNode(param)))
addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]))
if cond != nil:
var a = newNodeIT(nkCall, base.info, getSysType(tyBool))
@@ -270,7 +275,8 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
addSon(disp, a)
else:
disp = ret
result.ast.sons[bodyPos] = disp
nilchecks.add disp
result.ast.sons[bodyPos] = nilchecks
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
result = newNode(nkStmtList)

View File

@@ -785,14 +785,24 @@ proc writeJsonBuildInstructions*(projectfile: string) =
else:
lit "],\L"
proc linkfiles(f: File; buf, objfiles: var string; toLink: seq[string]) =
for i, it in toLink:
let objfile = addFileExt(it, CC[cCompiler].objExt)
str(objfile)
proc linkfiles(f: File; buf, objfiles: var string) =
for i, it in externalToLink:
let
objFile = if noAbsolutePaths(): it.extractFilename else: it
objStr = addFileExt(objFile, CC[cCompiler].objExt)
add(objfiles, ' ')
add(objfiles, quoteShell(objfile))
if i == toLink.high:
add(objfiles, objStr)
str objStr
if toCompile.len == 0 and i == externalToLink.high:
lit "\L"
else:
lit ",\L"
for i, x in toCompile:
let objStr = quoteShell(x.obj)
add(objfiles, ' ')
add(objfiles, objStr)
str objStr
if i == toCompile.high:
lit "\L"
else:
lit ",\L"
@@ -809,7 +819,7 @@ proc writeJsonBuildInstructions*(projectfile: string) =
lit "],\L\"link\":[\L"
var objfiles = ""
# XXX add every file here that is to link
linkfiles(f, buf, objfiles, externalToLink)
linkfiles(f, buf, objfiles)
lit "],\L\"linkcmd\": "
str getLinkCmd(projectfile, objfiles)

View File

@@ -15,17 +15,28 @@ import
proc ensureNoMissingOrUnusedSymbols(scope: PScope)
proc considerQuotedIdent*(n: PNode): PIdent =
proc noidentError(n, origin: PNode) =
var m = ""
if origin != nil:
m.add "in expression '" & origin.renderTree & "': "
m.add "identifier expected, but found '" & n.renderTree & "'"
localError(n.info, m)
proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent =
## Retrieve a PIdent from a PNode, taking into account accent nodes.
## ``origin`` can be nil. If it is not nil, it is used for a better
## error message.
template handleError(n, origin: PNode) =
noidentError(n, origin)
result = getIdent"<Error>"
case n.kind
of nkIdent: result = n.ident
of nkSym: result = n.sym.name
of nkAccQuoted:
case n.len
of 0:
localError(n.info, errIdentifierExpected, renderTree(n))
result = getIdent"<Error>"
of 1: result = considerQuotedIdent(n.sons[0])
of 0: handleError(n, origin)
of 1: result = considerQuotedIdent(n.sons[0], origin)
else:
var id = ""
for i in 0.. <n.len:
@@ -33,14 +44,11 @@ proc considerQuotedIdent*(n: PNode): PIdent =
case x.kind
of nkIdent: id.add(x.ident.s)
of nkSym: id.add(x.sym.name.s)
else:
localError(n.info, errIdentifierExpected, renderTree(n))
return getIdent"<Error>"
else: handleError(n, origin)
result = getIdent(id)
of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym.name
else:
localError(n.info, errIdentifierExpected, renderTree(n))
result = getIdent"<Error>"
handleError(n, origin)
template addSym*(scope: PScope, s: PSym) =
strTableAdd(scope.symbols, s)
@@ -353,7 +361,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if n.sons[1].kind == nkIdent:
ident = n.sons[1].ident
elif n.sons[1].kind == nkAccQuoted:
ident = considerQuotedIdent(n.sons[1])
ident = considerQuotedIdent(n.sons[1], n)
if ident != nil:
if o.m == c.module:
# a module may access its private members:
@@ -363,8 +371,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
else:
result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n)
else:
localError(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]))
noidentError(n.sons[1], n)
result = errorSym(c, n.sons[1])
of nkClosedSymChoice, nkOpenSymChoice:
o.mode = oimSymChoice

View File

@@ -272,7 +272,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
if msgs.gErrorCounter == 0 and
gCmd notin {cmdInterpret, cmdRun, cmdDump}:
when declared(system.getMaxMem):
let usedMem = formatSize(getMaxMem()) & " peekmem"
let usedMem = formatSize(getMaxMem()) & " peakmem"
else:
let usedMem = formatSize(getTotalMem())
rawMessage(hintSuccessX, [$gLinesCompiled,

View File

@@ -355,7 +355,7 @@ proc semOpAux(c: PContext, n: PNode) =
var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = a.sons[0].info
a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0]), info)
a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0], a), info)
a.sons[1] = semExprWithType(c, a.sons[1], flags)
a.typ = a.sons[1].typ
else:
@@ -1076,7 +1076,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
#restoreOldStyleType(n.sons[0])
var i = considerQuotedIdent(n.sons[1])
var i = considerQuotedIdent(n.sons[1], n)
var ty = n.sons[0].typ
var f: PSym = nil
result = nil
@@ -1160,7 +1160,7 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
addSon(result, n.sons[1])
addSon(result, copyTree(n[0]))
else:
var i = considerQuotedIdent(n.sons[1])
var i = considerQuotedIdent(n.sons[1], n)
result = newNodeI(nkDotCall, n.info)
result.flags.incl nfDotField
addSon(result, newIdentNode(i, n[1].info))
@@ -1280,7 +1280,7 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
c.p.bracketExpr = oldBracketExpr
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
var id = considerQuotedIdent(a[1])
var id = considerQuotedIdent(a[1], a)
var setterId = newIdentNode(getIdent(id.s & '='), n.info)
# a[0] is already checked for semantics, that does ``builtinFieldAccess``
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
@@ -1433,7 +1433,6 @@ proc semReturn(c: PContext, n: PNode): PNode =
proc semProcBody(c: PContext, n: PNode): PNode =
openScope(c)
result = semExpr(c, n)
if c.p.resultSym != nil and not isEmptyType(result.typ):
# transform ``expr`` to ``result = expr``, but not if the expr is already
@@ -1530,7 +1529,7 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
checkSonsLen(n, 2)
var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
if m != nil and m.kind == skModule:
let ident = considerQuotedIdent(n[1])
let ident = considerQuotedIdent(n[1], n)
if m == c.module:
result = strTableGet(c.topLevelScope.symbols, ident)
else:
@@ -1549,7 +1548,7 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
checkSonsLen(n, 2)
# we replace this node by a 'true' or 'false' node:
result = newIntNode(nkIntLit, 0)
if not onlyCurrentScope and considerQuotedIdent(n[0]).s == "defined":
if not onlyCurrentScope and considerQuotedIdent(n[0], n).s == "defined":
if n.sons[1].kind != nkIdent:
localError(n.info, "obsolete usage of 'defined', use 'declared' instead")
elif condsyms.isDefined(n.sons[1].ident):
@@ -2084,9 +2083,8 @@ proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
var t = semTypeNode(c, n.sons[0], nil)
result = n
result.typ = t
result.kind = nkObjConstr
result = newNodeIT(nkObjConstr, n.info, t)
result.add n.sons[0]
t = skipTypes(t, {tyGenericInst, tyAlias})
if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst, tyAlias})
if t.kind != tyObject:
@@ -2099,7 +2097,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
if it.kind != nkExprColonExpr:
localError(n.info, errNamedExprExpected)
break
let id = considerQuotedIdent(it.sons[0])
let id = considerQuotedIdent(it.sons[0], it)
if containsOrIncl(ids, id.id):
localError(it.info, errFieldInitTwice, id.s)
@@ -2125,6 +2123,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
localError(it.info, errUndeclaredFieldX, id.s)
it.sons[1] = e
result.add it
# XXX object field name check for 'case objects' if the kind is static?
if tfNeedsInit in objType.flags:
while true:

View File

@@ -51,10 +51,10 @@ template macroToExpand(s): untyped =
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfAllUntyped in s.flags)
template macroToExpandSym(s): untyped =
s.kind in {skMacro, skTemplate} and (s.typ.len == 1)
s.kind in {skMacro, skTemplate} and (s.typ.len == 1) and not fromDotExpr
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
ctx: var GenericCtx): PNode =
ctx: var GenericCtx; fromDotExpr=false): PNode =
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
incl(s.flags, sfUsed)
case s.kind
@@ -145,7 +145,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
elif s.name.id in ctx.toMixin:
result = newDot(result, symChoice(c, n, s, scForceOpen))
else:
let syms = semGenericStmtSymbol(c, n, s, ctx)
let syms = semGenericStmtSymbol(c, n, s, ctx, fromDotExpr=true)
if syms.kind == nkSym:
let choice = symChoice(c, n, s, scForceOpen)
choice.kind = nkClosedSymChoice

View File

@@ -125,6 +125,11 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
if n.sons[bodyPos].kind != nkEmpty:
let procParams = result.typ.n
for i in 1 .. <procParams.len:
addDecl(c, procParams[i].sym)
maybeAddResult(c, result, result.ast)
inc c.inGenericInst
# add it here, so that recursive generic procs are possible:
var b = n.sons[bodyPos]
@@ -147,13 +152,17 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
for i in countup(0, c.generics.len - 1):
if c.generics[i].genericSym.id == s.id:
var oldPrc = c.generics[i].inst.sym
pushProcCon(c, oldPrc)
pushOwner(c, oldPrc)
pushInfoContext(oldPrc.info)
openScope(c)
var n = oldPrc.ast
n.sons[bodyPos] = copyTree(s.getBody)
instantiateBody(c, n, nil, oldPrc, s)
instantiateBody(c, n, oldPrc.typ.n, oldPrc, s)
closeScope(c)
popInfoContext()
popOwner(c)
popProcCon(c)
proc sideEffectsCheck(c: PContext, s: PSym) =
when false:
@@ -173,7 +182,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
result = replaceTypeVarsT(cl, header)
proc instantiateProcType(c: PContext, pt: TIdTable,
prc: PSym, info: TLineInfo) =
prc: PSym, info: TLineInfo) =
# XXX: Instantiates a generic proc signature, while at the same
# time adding the instantiated proc params into the current scope.
# This is necessary, because the instantiation process may refer to
@@ -229,7 +238,6 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
skipIntLiteralParams(result)
prc.typ = result
maybeAddResult(c, prc, prc.ast)
popInfoContext()
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,

View File

@@ -160,10 +160,11 @@ proc discardCheck(c: PContext, result: PNode) =
else:
var n = result
while n.kind in skipForDiscardable: n = n.lastSon
var s = "expression '" & $n & "' is of type '" &
result.typ.typeToString & "' and has to be discarded"
if result.typ.kind == tyProc:
localError(n.info, "value of type '" & result.typ.typeToString & "' has to be discarded; for a function call use ()")
else:
localError(n.info, errDiscardValueX, result.typ.typeToString)
s.add "; for a function call use ()"
localError(n.info, s)
proc semIf(c: PContext, n: PNode): PNode =
result = n

View File

@@ -350,6 +350,14 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
else: result = isIntConv
else: result = isNone
proc genericParamPut(c: var TCandidate; last, fGenericOrigin: PType) =
if fGenericOrigin != nil and last.kind == tyGenericInst and
last.len-1 == fGenericOrigin.len:
for i in countup(1, sonsLen(fGenericOrigin) - 1):
let x = PType(idTableGet(c.bindings, fGenericOrigin.sons[i]))
if x == nil:
put(c, fGenericOrigin.sons[i], last.sons[i])
proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
var t = a
assert t.kind == tyObject
@@ -363,12 +371,7 @@ proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
t = skipTypes(t, skipPtrs)
inc depth
if t != nil:
if fGenericOrigin != nil and last.kind == tyGenericInst and
last.len-1 == fGenericOrigin.len:
for i in countup(1, sonsLen(fGenericOrigin) - 1):
let x = PType(idTableGet(c.bindings, fGenericOrigin.sons[i]))
if x == nil:
put(c, fGenericOrigin.sons[i], last.sons[i])
genericParamPut(c, last, fGenericOrigin)
result = depth
else:
result = -1
@@ -398,7 +401,7 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType =
break
if r.kind == tyObject and ptrs <= 1: result = r
proc isGenericSubtype(a, f: PType, d: var int): bool =
proc isGenericSubtype(c: var TCandidate; a, f: PType, d: var int, fGenericOrigin: PType = nil): bool =
assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody}
var askip = skippedNone
var fskip = skippedNone
@@ -406,14 +409,17 @@ proc isGenericSubtype(a, f: PType, d: var int): bool =
let r = f.skipToObject(fskip)
if r == nil: return false
var depth = 0
var last = a
# XXX sameObjectType can return false here. Need to investigate
# why that is but sameObjectType does way too much work here anyway.
while t != nil and r.sym != t.sym and askip == fskip:
t = t.sons[0]
if t != nil: t = t.skipToObject(askip)
else: break
if t == nil: break
last = t
t = t.skipToObject(askip)
inc depth
if t != nil and askip == fskip:
genericParamPut(c, last, fGenericOrigin)
d = depth
result = true
@@ -999,7 +1005,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
# simply no match for now:
discard
elif x.kind == tyGenericInst and
((f.sons[0] == x.sons[0]) or isGenericSubtype(x, f, depth)) and
((f.sons[0] == x.sons[0]) or isGenericSubType(c, x, f, depth)) and
(sonsLen(x) - 1 == sonsLen(f)):
for i in countup(1, sonsLen(f) - 1):
if x.sons[i].kind == tyGenericParam:
@@ -1039,6 +1045,14 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
else:
put(c, f.sons[i], x)
if result == isNone:
# Here object inheriting from generic/specialized generic object
# crossing path with metatypes/aliases, so we need to separate them
# by checking sym.id
let genericSubtype = isGenericSubType(c, x, f, depth, f)
if not (genericSubtype and aobj.sym.id != fobj.sym.id):
depth = -1
if depth >= 0:
c.inheritancePenalty += depth
# bug #4863: We still need to bind generic alias crap, so

View File

@@ -407,7 +407,7 @@ or
...
Other useful iterators for collections (like arrays and sequences) are
* ``items`` and ``mitems``, which provides immutable and mutable elements respectively, and
* ``items`` and ``mitems``, which provides immutable and mutable elements respectively, and
* ``pairs`` and ``mpairs`` which provides the element and an index number (immutable and mutable respectively)
.. code-block:: nim
@@ -1394,6 +1394,27 @@ slice's bounds can hold any value supported by
their type, but it is the proc using the slice object which defines what values
are accepted.
To understand some of the different ways of specifying the indices of strings, arrays, sequences, etc.,
it must be remembered that Nim uses zero-based indices.
So the string ``b`` is of length 19, and two different ways of specifying the indices are
.. code-block:: nim
"Slices are useless."
| | |
0 11 17 using indices
^19 ^8 ^2 using ^ syntax
where ``b[0..^1]`` is equivalent to ``b[0..b.len-1]`` and ``b[0..<b.len]``, and it can be seen that the ``^1`` provides a short-hand way of specifying the ``b.len-1``
In the above example, because the string ends in a period, to get the portion of the string that is "useless" and replace it with "useful"
``b[11..^2]`` is the portion "useless", and
``b[11..^2] = "useful"`` replaces the "useless" portion with "useful",
giving the result "Slices are useful."
Note: alternate ways of writing this are ``b[^8..^2] = "useful"`` or as ``b[11..b.len-2] = "useful"`` or as ``b[11..<b.len-1] = "useful"`` or as ....
Tuples
------

View File

@@ -41,30 +41,26 @@ Options:
Possible Commands:
boot [options] bootstraps with given command line options
distrohelper [bindir] helper for distro packagers
geninstall generate ./install.sh; Unix only!
testinstall test tar.xz package; Unix only! Only for devs!
clean cleans Nim project; removes generated files
web [options] generates the website and the full documentation
website [options] generates only the website
csource [options] builds the C sources for installation
pdf builds the PDF documentation
zip builds the installation ZIP package
xz builds the installation XZ package
nsis [options] builds the NSIS Setup installer (for Windows)
tests [options] run the testsuite
temp options creates a temporary compiler for testing
winrelease creates a release (for coredevs only)
nimble builds the Nimble tool
tools builds Nim related tools
pushcsource push generated C sources to its repo! Only for devs!
nimble builds the Nimble tool
Boot options:
-d:release produce a release version of the compiler
-d:tinyc include the Tiny C backend (not supported on Windows)
-d:useLinenoise use the linenoise library for interactive mode
(not needed on Windows)
-d:nativeStacktrace use native stack traces (only for Mac OS X or Linux)
-d:noCaas build Nim without CAAS support
-d:avoidTimeMachine only for Mac OS X, excludes nimcache dir from backups
Commands for core developers:
web [options] generates the website and the full documentation
website [options] generates only the website
csource -d:release builds the C sources for installation
pdf builds the PDF documentation
zip builds the installation zip package
xz builds the installation tar.xz package
testinstall test tar.xz package; Unix only!
tests [options] run the testsuite
temp options creates a temporary compiler for testing
winrelease creates a Windows release
pushcsource push generated C sources to its repo
Web options:
--googleAnalytics:UA-... add the given google analytics code to the docs. To
build the official docs, use UA-48159761-1
@@ -218,11 +214,14 @@ proc bundleNimsuggest(buildExe: bool) =
copyExe("nimsuggest/nimsuggest".exe, "bin/nimsuggest".exe)
removeFile("nimsuggest/nimsuggest".exe)
proc buildVccTool() =
nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe")
proc bundleWinTools() =
nimexec("c tools/finish.nim")
copyExe("tools/finish".exe, "finish".exe)
removeFile("tools/finish".exe)
nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe")
buildVccTool()
nimexec("c -o:bin/nimgrab.exe -d:ssl tools/nimgrab.nim")
when false:
# not yet a tool worth including
@@ -257,6 +256,7 @@ proc buildTools(latest: bool) =
let nimgrepExe = "bin/nimgrep".exe
nimexec "c -o:" & nimgrepExe & " tools/nimgrep.nim"
when defined(windows): buildVccTool()
buildNimble(latest)
proc nsis(args: string) =

View File

@@ -173,17 +173,33 @@ iterator fastRows*(db: DbConn, query: SqlQuery,
rawExec(db, query, args)
var sqlres = mysql.useResult(db)
if sqlres != nil:
var L = int(mysql.numFields(sqlres))
var result = newRow(L)
var row: cstringArray
var
L = int(mysql.numFields(sqlres))
row: cstringArray
result: Row
backup: Row
newSeq(result, L)
while true:
row = mysql.fetchRow(sqlres)
if row == nil: break
for i in 0..L-1:
setLen(result[i], 0)
if row[i] == nil:
if backup == nil:
newSeq(backup, L)
if backup[i] == nil and result[i] != nil:
shallowCopy(backup[i], result[i])
result[i] = nil
else:
if result[i] == nil:
if backup != nil:
if backup[i] == nil:
backup[i] = ""
shallowCopy(result[i], backup[i])
setLen(result[i], 0)
else:
result[i] = ""
else:
setLen(result[i], 0)
add(result[i], row[i])
yield result
properFreeResult(sqlres, row)

View File

@@ -406,6 +406,8 @@ proc setInterval*(w: Window, function: proc (), pause: int): ref TInterval
proc setTimeout*(w: Window, code: cstring, pause: int): ref TTimeOut
proc setTimeout*(w: Window, function: proc (), pause: int): ref TInterval
proc stop*(w: Window)
proc requestAnimationFrame*(w: Window, function: proc (time: float)): int
proc cancelAnimationFrame*(w: Window, id: int)
# Node "methods"
proc appendChild*(n, child: Node)

View File

@@ -489,3 +489,13 @@ proc writeFromStream*(f: AsyncFile, fs: FutureStream[string]) {.async.} =
await f.write(value)
else:
break
proc readToStream*(f: AsyncFile, fs: FutureStream[string]) {.async.} =
## Writes data to the specified future stream as the file is read.
while true:
let data = await read(f, 4000)
if data.len == 0:
break
await fs.write(data)
fs.complete()

View File

@@ -80,7 +80,7 @@ proc `[]`*[T](deq: Deque[T], i: Natural) : T {.inline.} =
## Access the i-th element of `deq` by order from first to last.
## deq[0] is the first, deq[^1] is the last.
xBoundsCheck(deq, i)
return deq.data[(deq.first + i) and deq.mask]
return deq.data[(deq.head + i) and deq.mask]
proc `[]`*[T](deq: var Deque[T], i: Natural): var T {.inline.} =
## Access the i-th element of `deq` and returns a mutable
@@ -266,4 +266,4 @@ when isMainModule:
foo(1,1)
foo(2,1)
foo(1,5)
foo(3,2)
foo(3,2)

View File

@@ -617,20 +617,6 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
flushFile(d)
close(d)
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
tags: [ReadIOEffect, WriteIOEffect].} =
## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
when defined(Windows):
when useWinUnicode:
let s = newWideCString(source)
let d = newWideCString(dest)
if moveFileW(s, d) == 0'i32: raiseOSError(osLastError())
else:
if moveFileA(source, dest) == 0'i32: raiseOSError(osLastError())
else:
if c_rename(source, dest) != 0'i32:
raiseOSError(osLastError(), $strerror(errno))
when not declared(ENOENT) and not defined(Windows):
when NoFakeVars:
const ENOENT = cint(2) # 2 on most systems including Solaris
@@ -647,25 +633,63 @@ when defined(Windows):
template setFileAttributes(file, attrs: untyped): untyped =
setFileAttributesA(file, attrs)
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
## Removes the `file`. If this fails, `OSError` is raised. This does not fail
proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
## Removes the `file`. If this fails, returns `false`. This does not fail
## if the file never existed in the first place.
## On Windows, ignores the read-only attribute.
result = true
when defined(Windows):
when useWinUnicode:
let f = newWideCString(file)
else:
let f = file
if deleteFile(f) == 0:
if getLastError() == ERROR_ACCESS_DENIED:
if setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) == 0:
raiseOSError(osLastError())
if deleteFile(f) == 0:
raiseOSError(osLastError())
result = false
let err = getLastError()
if err == ERROR_FILE_NOT_FOUND or err == ERROR_PATH_NOT_FOUND:
result = true
elif err == ERROR_ACCESS_DENIED and
setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) != 0 and
deleteFile(f) != 0:
result = true
else:
if c_remove(file) != 0'i32 and errno != ENOENT:
result = false
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
## Removes the `file`. If this fails, `OSError` is raised. This does not fail
## if the file never existed in the first place.
## On Windows, ignores the read-only attribute.
if not tryRemoveFile(file):
when defined(Windows):
raiseOSError(osLastError())
else:
raiseOSError(osLastError(), $strerror(errno))
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
tags: [ReadIOEffect, WriteIOEffect].} =
## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
when defined(Windows):
when useWinUnicode:
let s = newWideCString(source)
let d = newWideCString(dest)
if moveFileW(s, d) == 0'i32: raiseOSError(osLastError())
else:
if moveFileA(source, dest) == 0'i32: raiseOSError(osLastError())
else:
if c_rename(source, dest) != 0'i32:
let err = osLastError()
if err == EXDEV.OSErrorCode:
# Fallback to copy & del
copyFile(source, dest)
try:
removeFile(source)
except:
discard tryRemoveFile(dest)
raise
else:
raiseOSError(err, $strerror(errno))
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
tags: [ExecIOEffect].} =
## Executes a `shell command`:idx:.
@@ -1616,7 +1640,8 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} =
proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
tags: [ReadIOEffect].} =
## returns the file size of `file`. Can raise ``OSError``.
## returns the file size of `file` (in bytes). An ``OSError`` exception is
## raised in case of an error.
when defined(windows):
var a: WIN32_FIND_DATA
var resA = findFirstFile(file, a)

View File

@@ -13,10 +13,6 @@
##
## Tested on these OSes: Linux, Windows, OSX
type
NilAccessError* = object of SystemError ## \
## Raised on dereferences of ``nil`` pointers.
# do allocate memory upfront:
var se: ref NilAccessError
new(se)

View File

@@ -597,9 +597,12 @@ elif defined(JS):
result.month = Month(t.getMonth())
result.year = t.getFullYear()
result.weekday = weekDays[t.getDay()]
result.yearday = 0
result.timezone = getTimezone()
result.yearday = result.monthday - 1
for month in mJan..<result.month:
result.yearday += getDaysInMonth(month, result.year)
proc getGMTime(t: Time): TimeInfo =
result.second = t.getUTCSeconds()
result.minute = t.getUTCMinutes()
@@ -608,7 +611,10 @@ elif defined(JS):
result.month = Month(t.getUTCMonth())
result.year = t.getUTCFullYear()
result.weekday = weekDays[t.getUTCDay()]
result.yearday = 0
result.yearday = result.monthday - 1
for month in mJan..<result.month:
result.yearday += getDaysInMonth(month, result.year)
proc timeInfoToTime(timeInfo: TimeInfo): Time = toTime(timeInfo)

View File

@@ -375,7 +375,6 @@ template test*(name, body) {.dirty.} =
ensureFormattersInitialized()
if shouldRun(name):
var stackTrace {.inject.}: string
checkpoints = @[]
var testStatusIMPL {.inject.} = OK
@@ -391,7 +390,7 @@ template test*(name, body) {.dirty.} =
except:
when not defined(js):
checkpoint("Unhandled exception: " & getCurrentExceptionMsg())
stackTrace = getCurrentException().getStackTrace()
var stackTrace {.inject.} = getCurrentException().getStackTrace()
fail()
finally:

View File

@@ -154,9 +154,13 @@ proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} =
discard
proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} =
## Builtin 'addr' operator for taking the address of a memory location.
## This works even for ``let`` variables or parameters for better interop
## with C and so it is considered even more unsafe than the ordinary ``addr``.
## Builtin 'addr' operator for taking the address of a memory
## location. This works even for ``let`` variables or parameters
## for better interop with C and so it is considered even more
## unsafe than the ordinary ``addr``. When you use it to write a
## wrapper for a C library, you should always check that the
## original library does never write to data behind the pointer that
## is returned from this procedure.
## Cannot be overloaded.
discard
@@ -554,6 +558,10 @@ type
## Raised if it is attempted to send a message to a dead thread.
##
## See the full `exception hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
NilAccessError* = object of SystemError ## \
## Raised on dereferences of ``nil`` pointers.
##
## This is only raised if the ``segfaults.nim`` module was imported!
{.deprecated: [TObject: RootObj, PObject: RootRef, TEffect: RootEffect,
FTime: TimeEffect, FIO: IOEffect, FReadIO: ReadIOEffect,
@@ -2463,8 +2471,8 @@ template accumulateResult*(iter: untyped) =
const NimStackTrace = compileOption("stacktrace")
template coroutinesSupportedPlatform(): bool =
when defined(sparc) or defined(ELATE) or compileOption("gc", "v2") or
defined(boehmgc) or defined(gogc) or defined(nogc) or defined(gcStack) or
when defined(sparc) or defined(ELATE) or compileOption("gc", "v2") or
defined(boehmgc) or defined(gogc) or defined(nogc) or defined(gcStack) or
defined(gcMarkAndSweep):
false
else:

View File

@@ -763,6 +763,8 @@ proc getOccupiedMem(a: MemRegion): int {.inline.} =
# ---------------------- thread memory region -------------------------------
template instantiateForRegion(allocator: untyped) =
{.push stackTrace: off.}
when defined(fulldebug):
proc interiorAllocatedPtr*(p: pointer): pointer =
result = interiorAllocatedPtr(allocator, p)
@@ -850,5 +852,6 @@ template instantiateForRegion(allocator: untyped) =
proc getOccupiedSharedMem(): int =
sharedMemStatsShared(sharedHeap.currMem - sharedHeap.freeMem)
{.pop.}
{.pop.}

View File

@@ -50,7 +50,11 @@ proc chckRangeF(x, a, b: float): float =
proc chckNil(p: pointer) =
if p == nil:
sysFatal(ValueError, "attempt to write to a nil address")
sysFatal(NilAccessError, "attempt to write to a nil address")
proc chckNilDisp(p: pointer) {.compilerproc.} =
if p == nil:
sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")
proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
# checks if obj is of type subclass:

View File

@@ -642,6 +642,10 @@ proc toU32*(a: int64): int32 {.asmNoStackFrame, compilerproc.} =
proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b
proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b
proc chckNilDisp(p: pointer) {.compilerproc.} =
if p == nil:
sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")
type NimString = string # hack for hti.nim
include "system/hti"

View File

@@ -242,7 +242,6 @@ type
PGcThread = ptr GcThread
GcThread {.pure, inheritable.} = object
sys: SysThread
when emulatedThreadVars and not useStackMaskHack:
tls: ThreadLocalStorage
else:
@@ -345,18 +344,16 @@ when not defined(useNimRtl):
# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway.
type
Thread* {.pure, final.}[TArg] =
object of GcThread ## Nim thread. A thread is a heavy object (~14K)
## that **must not** be part of a message! Use
## a ``ThreadId`` for that.
Thread* {.pure, final.}[TArg] = object
core: PGcThread
sys: SysThread
when TArg is void:
dataFn: proc () {.nimcall, gcsafe.}
else:
dataFn: proc (m: TArg) {.nimcall, gcsafe.}
data: TArg
ThreadId*[TArg] = ptr Thread[TArg] ## the current implementation uses
## a pointer as a thread ID.
{.deprecated: [TThread: Thread, TThreadId: ThreadId].}
{.deprecated: [TThread: Thread].}
var
threadDestructionHandlers {.rtlThreadVar.}: seq[proc () {.closure, gcsafe.}]
@@ -423,19 +420,20 @@ proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
when declared(threadType):
threadType = ThreadType.NimThread
when declared(registerThread):
thrd.stackBottom = addr(thrd)
registerThread(thrd)
thrd.core.stackBottom = addr(thrd)
registerThread(thrd.core)
p(thrd)
when declared(registerThread): unregisterThread(thrd)
when declared(registerThread): unregisterThread(thrd.core)
when declared(deallocOsPages): deallocOsPages()
else:
threadProcWrapDispatch(thrd)
template threadProcWrapperBody(closure: expr) {.immediate.} =
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
var thrd = cast[ptr Thread[TArg]](closure)
var core = thrd.core
when declared(globalsSlot): threadVarSetValue(globalsSlot, thrd.core)
when declared(initAllocator):
initAllocator()
var thrd = cast[ptr Thread[TArg]](closure)
threadProcWrapStackFrame(thrd)
# Since an unhandled exception terminates the whole process (!), there is
# no need for a ``try finally`` here, nor would it be correct: The current
@@ -444,7 +442,9 @@ template threadProcWrapperBody(closure: expr) {.immediate.} =
# page!
# mark as not running anymore:
thrd.core = nil
thrd.dataFn = nil
deallocShared(cast[pointer](core))
{.push stack_trace:off.}
when defined(windows):
@@ -502,6 +502,10 @@ when false:
discard pthread_cancel(t.sys)
when declared(registerThread): unregisterThread(addr(t))
t.dataFn = nil
## if thread `t` already exited, `t.core` will be `null`.
if not isNil(t.core):
deallocShared(t.core)
t.core = nil
when hostOS == "windows":
proc createThread*[TArg](t: var Thread[TArg],
@@ -510,9 +514,11 @@ when hostOS == "windows":
## creates a new thread `t` and starts its execution. Entry point is the
## proc `tp`. `param` is passed to `tp`. `TArg` can be ``void`` if you
## don't need to pass any data to the thread.
t.core = cast[PGcThread](allocShared0(sizeof(GcThread)))
when TArg isnot void: t.data = param
t.dataFn = tp
when hasSharedHeap: t.stackSize = ThreadStackSize
when hasSharedHeap: t.core.stackSize = ThreadStackSize
var dummyThreadId: int32
t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg],
addr(t), 0'i32, dummyThreadId)
@@ -532,9 +538,11 @@ else:
## creates a new thread `t` and starts its execution. Entry point is the
## proc `tp`. `param` is passed to `tp`. `TArg` can be ``void`` if you
## don't need to pass any data to the thread.
t.core = cast[PGcThread](allocShared0(sizeof(GcThread)))
when TArg isnot void: t.data = param
t.dataFn = tp
when hasSharedHeap: t.stackSize = ThreadStackSize
when hasSharedHeap: t.core.stackSize = ThreadStackSize
var a {.noinit.}: PthreadAttr
pthread_attr_init(a)
pthread_attr_setstacksize(a, ThreadStackSize)
@@ -554,10 +562,6 @@ else:
proc createThread*(t: var Thread[void], tp: proc () {.thread, nimcall.}) =
createThread[void](t, tp)
proc threadId*[TArg](t: var Thread[TArg]): ThreadId[TArg] {.inline.} =
## returns the thread ID of `t`.
result = addr(t)
when false:
proc mainThreadId*[TArg](): ThreadId[TArg] =
## returns the thread ID of the main thread.

View File

@@ -667,6 +667,8 @@ const
# Error Constants
const
ERROR_FILE_NOT_FOUND* = 2
ERROR_PATH_NOT_FOUND* = 3
ERROR_ACCESS_DENIED* = 5
ERROR_HANDLE_EOF* = 38
ERROR_BAD_ARGUMENTS* = 165

View File

@@ -1,7 +1,5 @@
/* linenoise.c -- VERSION 1.0
*
* Guerrilla line editing library against the idea that a line editing lib
* needs to be 20,000 lines of C code.
/* linenoise.c -- guerrilla line editing library against the idea that a
* line editing lib needs to be 20,000 lines of C code.
*
* You can find the latest source code at:
*
@@ -12,7 +10,7 @@
*
* ------------------------------------------------------------------------
*
* Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
@@ -113,17 +111,18 @@
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#ifndef __LINENOISE_H
# include "clinenoise.h"
#endif
#include "linenoise.h"
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
#define LINENOISE_MAX_LINE 4096
static char *unsupported_term[] = {"dumb","cons25","emacs",NULL};
static linenoiseCompletionCallback *completionCallback = NULL;
static linenoiseHintsCallback *hintsCallback = NULL;
static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
static struct termios orig_termios; /* In order to restore at exit.*/
static int rawmode = 0; /* For atexit() function to check if restore is needed*/
@@ -141,7 +140,7 @@ struct linenoiseState {
int ofd; /* Terminal stdout file descriptor. */
char *buf; /* Edited line buffer. */
size_t buflen; /* Edited line buffer size. */
char *prompt; /* Prompt to display. */
const char *prompt; /* Prompt to display. */
size_t plen; /* Prompt length. */
size_t pos; /* Current cursor position. */
size_t oldpos; /* Previous refresh cursor position. */
@@ -174,7 +173,7 @@ enum KEY_ACTION{
};
static void linenoiseAtExit(void);
int linenoiseHistoryAdd(char *line);
int linenoiseHistoryAdd(const char *line);
static void refreshLine(struct linenoiseState *l);
/* Debugging macro. */
@@ -411,18 +410,30 @@ void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
completionCallback = fn;
}
/* Register a hits function to be called to show hits to the user at the
* right of the prompt. */
void linenoiseSetHintsCallback(linenoiseHintsCallback *fn) {
hintsCallback = fn;
}
/* Register a function to free the hints returned by the hints callback
* registered with linenoiseSetHintsCallback(). */
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
freeHintsCallback = fn;
}
/* This function is used by the callback function registered by the user
* in order to add completion options given the input string when the
* user typed <tab>. See the example.c source code for a very easy to
* understand example. */
void linenoiseAddCompletion(linenoiseCompletions *lc, char *str) {
void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
size_t len = strlen(str);
char *copy, **cvec;
copy = (char*)malloc(len+1);
copy = malloc(len+1);
if (copy == NULL) return;
memcpy(copy,str,len+1);
cvec = (char**)realloc(lc->cvec,sizeof(char*)*(lc->len+1));
cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
if (cvec == NULL) {
free(copy);
return;
@@ -447,12 +458,12 @@ static void abInit(struct abuf *ab) {
ab->len = 0;
}
static void abAppend(struct abuf *ab, char *s, int len) {
char *neww = (char*)realloc(ab->b,ab->len+len);
static void abAppend(struct abuf *ab, const char *s, int len) {
char *new = realloc(ab->b,ab->len+len);
if (neww == NULL) return;
memcpy(neww+ab->len,s,len);
ab->b = neww;
if (new == NULL) return;
memcpy(new+ab->len,s,len);
ab->b = new;
ab->len += len;
}
@@ -460,6 +471,30 @@ static void abFree(struct abuf *ab) {
free(ab->b);
}
/* Helper of refreshSingleLine() and refreshMultiLine() to show hints
* to the right of the prompt. */
void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) {
char seq[64];
if (hintsCallback && plen+l->len < l->cols) {
int color = -1, bold = 0;
char *hint = hintsCallback(l->buf,&color,&bold);
if (hint) {
int hintlen = strlen(hint);
int hintmaxlen = l->cols-(plen+l->len);
if (hintlen > hintmaxlen) hintlen = hintmaxlen;
if (bold == 1 && color == -1) color = 37;
if (color != -1 || bold != 0)
snprintf(seq,64,"\033[%d;%d;49m",bold,color);
abAppend(ab,seq,strlen(seq));
abAppend(ab,hint,hintlen);
if (color != -1 || bold != 0)
abAppend(ab,"\033[0m",4);
/* Call the function to free the hint returned. */
if (freeHintsCallback) freeHintsCallback(hint);
}
}
}
/* Single line low level line refresh.
*
* Rewrite the currently edited line accordingly to the buffer content,
@@ -489,6 +524,8 @@ static void refreshSingleLine(struct linenoiseState *l) {
/* Write the prompt and the current buffer content */
abAppend(&ab,l->prompt,strlen(l->prompt));
abAppend(&ab,buf,len);
/* Show hits if any. */
refreshShowHints(&ab,l,plen);
/* Erase to right */
snprintf(seq,64,"\x1b[0K");
abAppend(&ab,seq,strlen(seq));
@@ -542,6 +579,9 @@ static void refreshMultiLine(struct linenoiseState *l) {
abAppend(&ab,l->prompt,strlen(l->prompt));
abAppend(&ab,l->buf,l->len);
/* Show hits if any. */
refreshShowHints(&ab,l,plen);
/* If we are at the very end of the screen with our prompt, we need to
* emit a newline and move the prompt to the first column. */
if (l->pos &&
@@ -602,7 +642,7 @@ int linenoiseEditInsert(struct linenoiseState *l, char c) {
l->pos++;
l->len++;
l->buf[l->len] = '\0';
if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) {
if ((!mlmode && l->plen+l->len < l->cols && !hintsCallback)) {
/* Avoid a full update of the line in the
* trivial case. */
if (write(l->ofd,&c,1) == -1) return -1;
@@ -725,7 +765,7 @@ void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
* when ctrl+d is typed.
*
* The function returns the length of the current buffer. */
static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, char *prompt)
static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
{
struct linenoiseState l;
@@ -776,6 +816,14 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
history_len--;
free(history[history_len]);
if (mlmode) linenoiseEditMoveEnd(&l);
if (hintsCallback) {
/* Force a refresh without hints to leave the previous
* line as the user typed it after a newline. */
linenoiseHintsCallback *hc = hintsCallback;
hintsCallback = NULL;
refreshLine(&l);
hintsCallback = hc;
}
return (int)l.len;
case CTRL_C: /* ctrl-c */
errno = EAGAIN;
@@ -931,41 +979,71 @@ void linenoisePrintKeyCodes(void) {
/* This function calls the line editing function linenoiseEdit() using
* the STDIN file descriptor set in raw mode. */
static int linenoiseRaw(char *buf, size_t buflen, char *prompt) {
static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
int count;
if (buflen == 0) {
errno = EINVAL;
return -1;
}
if (!isatty(STDIN_FILENO)) {
/* Not a tty: read from file / pipe. */
if (fgets(buf, buflen, stdin) == NULL) return -1;
count = strlen(buf);
if (count && buf[count-1] == '\n') {
count--;
buf[count] = '\0';
}
} else {
/* Interactive editing. */
if (enableRawMode(STDIN_FILENO) == -1) return -1;
count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
disableRawMode(STDIN_FILENO);
printf("\n");
}
if (enableRawMode(STDIN_FILENO) == -1) return -1;
count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
disableRawMode(STDIN_FILENO);
printf("\n");
return count;
}
/* This function is called when linenoise() is called with the standard
* input file descriptor not attached to a TTY. So for example when the
* program using linenoise is called in pipe or with a file redirected
* to its standard input. In this case, we want to be able to return the
* line regardless of its length (by default we are limited to 4k). */
static char *linenoiseNoTTY(void) {
char *line = NULL;
size_t len = 0, maxlen = 0;
while(1) {
if (len == maxlen) {
if (maxlen == 0) maxlen = 16;
maxlen *= 2;
char *oldval = line;
line = realloc(line,maxlen);
if (line == NULL) {
if (oldval) free(oldval);
return NULL;
}
}
int c = fgetc(stdin);
if (c == EOF || c == '\n') {
if (c == EOF && len == 0) {
free(line);
return NULL;
} else {
line[len] = '\0';
return line;
}
} else {
line[len] = c;
len++;
}
}
}
/* The high level function that is the main API of the linenoise library.
* This function checks if the terminal has basic capabilities, just checking
* for a blacklist of stupid terminals, and later either calls the line
* editing function or uses dummy fgets() so that you will be able to type
* something even in the most desperate of the conditions. */
char *linenoise(char *prompt) {
char *linenoise(const char *prompt) {
char buf[LINENOISE_MAX_LINE];
int count;
if (isUnsupportedTerm()) {
if (!isatty(STDIN_FILENO)) {
/* Not a tty: read from file / pipe. In this mode we don't want any
* limit to the line size, so we call a function to handle that. */
return linenoiseNoTTY();
} else if (isUnsupportedTerm()) {
size_t len;
printf("%s",prompt);
@@ -984,6 +1062,14 @@ char *linenoise(char *prompt) {
}
}
/* This is just a wrapper the user may want to call in order to make sure
* the linenoise returned buffer is freed with the same allocator it was
* created with. Useful when the main program is using an alternative
* allocator. */
void linenoiseFree(void *ptr) {
free(ptr);
}
/* ================================ History ================================= */
/* Free the history, but does not reset it. Only used when we have to
@@ -1011,14 +1097,14 @@ static void linenoiseAtExit(void) {
* histories, but will work well for a few hundred of entries.
*
* Using a circular buffer is smarter, but a bit more complex to handle. */
int linenoiseHistoryAdd(char *line) {
int linenoiseHistoryAdd(const char *line) {
char *linecopy;
if (history_max_len == 0) return 0;
/* Initialization on first call. */
if (history == NULL) {
history = (char**)malloc(sizeof(char*)*history_max_len);
history = malloc(sizeof(char*)*history_max_len);
if (history == NULL) return 0;
memset(history,0,(sizeof(char*)*history_max_len));
}
@@ -1045,14 +1131,14 @@ int linenoiseHistoryAdd(char *line) {
* just the latest 'len' elements if the new history length value is smaller
* than the amount of items already inside the history. */
int linenoiseHistorySetMaxLen(int len) {
char **neww;
char **new;
if (len < 1) return 0;
if (history) {
int tocopy = history_len;
neww = (char**)malloc(sizeof(char*)*len);
if (neww == NULL) return 0;
new = malloc(sizeof(char*)*len);
if (new == NULL) return 0;
/* If we can't copy everything, free the elements we'll not use. */
if (len < tocopy) {
@@ -1061,10 +1147,10 @@ int linenoiseHistorySetMaxLen(int len) {
for (j = 0; j < tocopy-len; j++) free(history[j]);
tocopy = len;
}
memset(neww,0,sizeof(char*)*len);
memcpy(neww,history+(history_len-tocopy), sizeof(char*)*tocopy);
memset(new,0,sizeof(char*)*len);
memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy);
free(history);
history = neww;
history = new;
}
history_max_len = len;
if (history_len > history_max_len)
@@ -1074,11 +1160,15 @@ int linenoiseHistorySetMaxLen(int len) {
/* Save the history in the specified file. On success 0 is returned
* otherwise -1 is returned. */
int linenoiseHistorySave(char *filename) {
FILE *fp = fopen(filename,"w");
int linenoiseHistorySave(const char *filename) {
mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
FILE *fp;
int j;
fp = fopen(filename,"w");
umask(old_umask);
if (fp == NULL) return -1;
chmod(filename,S_IRUSR|S_IWUSR);
for (j = 0; j < history_len; j++)
fprintf(fp,"%s\n",history[j]);
fclose(fp);
@@ -1090,7 +1180,7 @@ int linenoiseHistorySave(char *filename) {
*
* If the file exists and the operation succeeded 0 is returned, otherwise
* on error -1 is returned. */
int linenoiseHistoryLoad(char *filename) {
int linenoiseHistoryLoad(const char *filename) {
FILE *fp = fopen(filename,"r");
char buf[LINENOISE_MAX_LINE];

View File

@@ -39,22 +39,35 @@
#ifndef __LINENOISE_H
#define __LINENOISE_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct linenoiseCompletions {
size_t len;
char **cvec;
} linenoiseCompletions;
typedef void(linenoiseCompletionCallback)(char *, linenoiseCompletions *);
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
typedef void(linenoiseFreeHintsCallback)(void *);
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
void linenoiseAddCompletion(linenoiseCompletions *, char *);
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
char *linenoise(char *prompt);
int linenoiseHistoryAdd(char *line);
char *linenoise(const char *prompt);
void linenoiseFree(void *ptr);
int linenoiseHistoryAdd(const char *line);
int linenoiseHistorySetMaxLen(int len);
int linenoiseHistorySave(char *filename);
int linenoiseHistoryLoad(char *filename);
int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename);
void linenoiseClearScreen(void);
void linenoiseSetMultiLine(int ml);
void linenoisePrintKeyCodes(void);
#ifdef __cplusplus
}
#endif
#endif /* __LINENOISE_H */

View File

@@ -14,8 +14,7 @@ type
CompletionCallback* = proc (a2: cstring; a3: ptr Completions) {.cdecl.}
{.emit: staticRead"clinenoise.h".}
{.emit: staticRead"clinenoise.c".}
{.compile: "linenoise.c".}
proc setCompletionCallback*(a2: ptr CompletionCallback) {.
importc: "linenoiseSetCompletionCallback".}

View File

@@ -485,6 +485,10 @@ proc mainCommand(graph: ModuleGraph; cache: IdentCache) =
incl gGlobalOptions, optCaasEnabled
isServing = true
wantMainModule()
if not fileExists(gProjectFull):
quit "cannot find file: " & gProjectFull
add(searchPaths, options.libpath)
# do not stop after the first error:

View File

@@ -0,0 +1,17 @@
discard """
output: '''true'''
"""
import deques
proc index(self: Deque[int], idx: Natural): int =
self[idx]
proc main =
var testDeque = initDeque[int]()
testDeque.addFirst(1)
assert testDeque.index(0) == 1
main()
echo "true"

View File

@@ -1,10 +1,10 @@
discard """
line: 10
errormsg: "value of type 'bool' has to be discarded"
errormsg: '''expression 'open(f, "arg.txt", fmRead, -1)' is of type 'bool' and has to be discarded'''
"""
proc p =
var f: TFile
var f: File
echo "hi"
open(f, "arg.txt")

View File

@@ -1,5 +1,5 @@
discard """
errormsg: "value of type 'string' has to be discarded"
errormsg: '''expression '"invalid"' is of type 'string' and has to be discarded'''
line: 12
"""

View File

@@ -1,5 +1,5 @@
discard """
errormsg: "value of type 'bool' has to be discarded"
errormsg: "expression 'true' is of type 'bool' and has to be discarded"
line: 13
file: "tdont_show_system.nim"
"""

View File

@@ -1,6 +1,6 @@
discard """
line: 10
errormsg: "value of type 'string' has to be discarded"
errormsg: "expression 'result[1 .. -(len(result), 1)]' is of type 'string' and has to be discarded"
"""
# bug #578

View File

@@ -1,7 +1,7 @@
discard """
file: "tstmtexp.nim"
line: 8
errormsg: "value of type 'int literal(5)' has to be discarded"
errormsg: "expression '5' is of type 'int literal(5)' and has to be discarded"
"""
# Test 3

View File

@@ -14,3 +14,16 @@ proc arrayItem(a: ArrayType): auto =
var arr: ArrayType[int]
echo arrayItem(arr)
# bug #5597
template fail() = "what"
proc g[T](x: var T) =
x.fail = 3
type
Obj = object
fail: int
var y: Obj
g y

View File

@@ -1,5 +1,6 @@
discard """
output: '''b()
720 120.0
720 120.0'''
"""
@@ -16,13 +17,12 @@ proc fac[T](x: T): T =
echo fac(6), " ", fac(5.0)
when false:
# This still doesn't work...
# test recursive generic with forwarding:
proc fac2[T](x: T): T
# test recursive generic with forwarding:
proc fac2[T](x: T): T
echo fac2(6), " ", fac2(5.0)
echo fac2(6), " ", fac2(5.0)
proc fac2[T](x: T): T =
if x == 0: return 1
else: return fac2(x-1)*x
proc fac2[T](x: T): T =
if x == 0: return 1
else: return fac2(x-1)*x

View File

@@ -1,7 +1,6 @@
discard """
output: "1.1000000000000001e+00 11"
output: "1.1 11\n42\n0"
ccodecheck: "!@'ClEnv'"
disabled: "true"
"""
proc p[T](a, b: T): T
@@ -12,3 +11,18 @@ proc p[T](a, b: T): T =
let c = b
result = a + b + c
# https://github.com/nim-lang/Nim/issues/4908
proc foo(t: typedesc[int]): int
proc bar(): int = foo(int)
proc foo(t: typedesc[int]): int =
return 0
# https://github.com/nim-lang/Nim/issues/4104
proc print[T](t: T) # Error: implementation of 'print.print(t: int)' expected
print 42 # moving this line after the implementation fixes the error,
# but such behaviour makes forward declaration pointless
proc print[T](t: T) =
echo t
echo bar()

View File

@@ -0,0 +1,65 @@
discard """
output: '''(peel: 0, color: 15)
(color: 15)
17
(width: 0.0, taste: nil, color: 13)
(width: 0.0, taste: nil, color: 15)
cool'''
"""
# bug #5241
type
BaseFruit[T] = object of RootObj
color: T
MidLevel[T] = object of BaseFruit[T]
Mango = object of MidLevel[int]
peel: int
Peach[X, T, Y] = object of T
width: X
taste: Y
proc setColor[T](self: var BaseFruit[T]) =
self.color = 15
proc setColor[T](self: var BaseFruit[T], c: int) =
self.color = c
var c: Mango
setColor(c)
echo c
var d: MidLevel[int]
setColor(d)
echo d
type
FooBase[T] = ref object of RootRef
v: T
BarClient = ref object of FooBase[int]
proc getColor[T](f: FooBase[T]): T = 17
var b: BarClient
echo getColor(b)
var z: Peach[float64, BaseFruit[int], string]
z.setColor(13)
echo z
z.setColor()
echo z
# bug #5411
type
Foo[T] = ref object of RootRef
v: T
Bar = ref object of Foo[int]
method m(o: RootRef) {.base.} = assert(false, "Abstract method called")
method m[T](o: Foo[T]) = echo "cool"
var v: Bar
v.new()
v.m() # Abstract method not called anymore

13
tests/js/ttimes.nim Normal file
View File

@@ -0,0 +1,13 @@
# test times module with js
discard """
action: run
"""
import times
# $ date --date='@2147483647'
# Tue 19 Jan 03:14:07 GMT 2038
block yeardayTest:
# check if yearday attribute is properly set on TimeInfo creation
doAssert fromSeconds(2147483647).getGMTime().yearday == 18

View File

@@ -35,5 +35,6 @@ except:
echo "Second readLine raised an exception"
echo line
f.close()
removeFile(fn)

View File

@@ -96,5 +96,12 @@ suite "bug #4494":
check:
allIt(0..3, tags[it] != tags[it + 1])
suite "bug #5571":
test "can define gcsafe procs within tests":
proc doTest {.gcsafe.} =
let line = "a"
check: line == "a"
doTest()
static:
echo "compile end"

View File

@@ -186,25 +186,11 @@ proc longGCTests(r: var TResults, cat: Category, options: string) =
proc threadTests(r: var TResults, cat: Category, options: string) =
template test(filename: untyped) =
testSpec r, makeTest("tests/threads" / filename, options, cat, actionRun)
testSpec r, makeTest("tests/threads" / filename, options &
" -d:release", cat, actionRun)
testSpec r, makeTest("tests/threads" / filename, options &
" --tlsEmulation:on", cat, actionRun)
test "tactors"
test "tactors2"
test "threadex"
# deactivated because output capturing still causes problems sometimes:
#test "trecursive_actor"
#test "threadring"
#test "tthreadanalysis"
#test "tthreadsort"
test "tthreadanalysis2"
#test "tthreadanalysis3"
test "tthreadheapviolation1"
test "tonthreadcreation"
test "tracy_allocator"
testSpec r, makeTest(filename, options, cat, actionRun)
testSpec r, makeTest(filename, options & " -d:release", cat, actionRun)
testSpec r, makeTest(filename, options & " --tlsEmulation:on", cat, actionRun)
for t in os.walkFiles("tests/threads/t*.nim"):
test(t)
# ------------------------- IO tests ------------------------------------------

View File

@@ -0,0 +1,30 @@
discard """
outputsub: "129"
"""
import os, locks
type
MarkerObj = object
lock: Lock
counter: int
Marker = ptr MarkerObj
const
ThreadsCount = 129
SleepTime = 1000
proc worker(p: Marker) {.thread.} =
acquire(p.lock)
inc(p.counter)
release(p.lock)
sleep(SleepTime)
var p = cast[Marker](allocShared0(sizeof(MarkerObj)))
initLock(p.lock)
var ts = newSeq[Thread[Marker]](ThreadsCount)
for i in 0..<ts.len:
createThread(ts[i], worker, p)
joinThreads(ts)
echo p.counter

View File

@@ -1,4 +1,5 @@
discard """
disabled: yes
outputsub: "0"
"""

View File

@@ -0,0 +1,28 @@
discard """
outputsub: "129"
"""
import os, locks
type
MarkerObj = object
lock: Lock
counter: int
Marker = ptr MarkerObj
const
ThreadsCount = 129
proc worker(p: Marker) {.thread.} =
acquire(p.lock)
inc(p.counter)
release(p.lock)
var p = cast[Marker](allocShared0(sizeof(MarkerObj)))
initLock(p.lock)
for i in 0..(ThreadsCount - 1):
var thread: Thread[Marker]
createThread(thread, worker, p)
joinThread(thread)
echo p.counter

View File

@@ -1,4 +1,5 @@
discard """
disabled: yes
outputsub: "101"
errormsg: "'threadFunc' is not GC-safe"
line: 39

View File

@@ -1,4 +1,5 @@
discard """
disabled: yes
outputsub: "channel is empty"
"""

View File

@@ -52,13 +52,13 @@ test(OrderR, OrderG)
test(OrderR, OrderAlias)
test(OrderG, OrderAlias)
typeRep(OrderAlias, Order) # true
typeRep(OrderR, Order) # true
typeRep(OrderG, Order) # true
typeRep(OrderAlias.R, Order.R) # true
typeRep(OrderR.R, Order.R) # true
typeRep(OrderG.R, Order.R) # true
typeRep(OrderR, OrderAlias) # true
typeRep(OrderG, OrderAlias) # true
typeRep(OrderR, OrderG) # true
typeRep(OrderR.R, OrderAlias.R) # true
typeRep(OrderG.R, OrderAlias.R) # true
typeRep(OrderR.R, OrderG.R) # true
echo OrderR.R # R
echo OrderG.R # R

View File

@@ -42,6 +42,9 @@ Changes affecting backwards compatibility
AST that is the same as what is used to define an enum. Previously the AST
returned had a repeated ``EnumTy`` node and was missing the initial pragma
node (which is currently empty for an enum).
- If the dispatcher parameter's value used in multi method is ``nil``,
a ``NilError`` exception is raised. The old behavior was that the method
would be a ``nop`` then.
Library Additions