Merge branch 'devel' into feature/3691
This commit is contained in:
commit
d5bb5e832b
84 changed files with 1381 additions and 492 deletions
25
appveyor.yml
25
appveyor.yml
|
|
@ -34,21 +34,20 @@ environment:
|
||||||
# platform: x86
|
# platform: x86
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- MKDIR %CD%\PCRE
|
- MKDIR %CD%\DIST
|
||||||
- nuget install pcre -Verbosity quiet -Version 8.33.0.1 -OutputDirectory %CD%\pcre
|
- MKDIR %CD%\DIST\PCRE
|
||||||
|
- nuget install pcre -Verbosity quiet -Version 8.33.0.1 -OutputDirectory %CD%\DIST\PCRE
|
||||||
- IF not exist "%SQLITE_ARCHIVE%" appveyor DownloadFile "%SQLITE_URL%" -FileName "%SQLITE_ARCHIVE%"
|
- IF not exist "%SQLITE_ARCHIVE%" appveyor DownloadFile "%SQLITE_URL%" -FileName "%SQLITE_ARCHIVE%"
|
||||||
- 7z x -y "%SQLITE_ARCHIVE%" > nul
|
- 7z x -y "%SQLITE_ARCHIVE%" -o"%CD%\DIST"> nul
|
||||||
- IF not exist "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%"
|
- IF not exist "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%"
|
||||||
- 7z x -y "%MINGW_ARCHIVE%" > nul
|
- 7z x -y "%MINGW_ARCHIVE%" -o"%CD%\DIST"> nul
|
||||||
- IF not exist "%FASM_ARCHIVE%" appveyor DownloadFile "%FASM_URL%" -FileName "%FASM_ARCHIVE%"
|
- IF not exist "%FASM_ARCHIVE%" appveyor DownloadFile "%FASM_URL%" -FileName "%FASM_ARCHIVE%"
|
||||||
- 7z x -y "%FASM_ARCHIVE%" -o"%CD%\%FASM_DIR%" > nul
|
- 7z x -y "%FASM_ARCHIVE%" -o"%CD%\DIST\%FASM_DIR%" > nul
|
||||||
- SET PATH=%CD%\%MINGW_DIR%\bin;%CD%\Nim\bin;%CD%\%FASM_DIR%;%PATH%
|
- SET PATH=%CD%\DIST\%MINGW_DIR%\BIN;%CD%\BIN;%CD%\DIST\%FASM_DIR%;%PATH%
|
||||||
- git clone https://github.com/nim-lang/Nim.git %CD%\Nim
|
- IF "%PLATFORM%" == "x64" ( copy C:\OpenSSL-Win64\libeay32.dll %CD%\BIN\libeay64.dll & copy C:\OpenSSL-Win64\libeay32.dll %CD%\BIN\libeay32.dll & copy C:\OpenSSL-Win64\libssl32.dll %CD%\BIN\libssl64.dll & copy C:\OpenSSL-Win64\libssl32.dll %CD%\BIN\libssl32.dll )
|
||||||
- IF "%PLATFORM%" == "x64" ( copy C:\OpenSSL-Win64\libeay32.dll %CD%\Nim\bin\libeay64.dll & copy C:\OpenSSL-Win64\libeay32.dll %CD%\Nim\bin\libeay32.dll & copy C:\OpenSSL-Win64\libssl32.dll %CD%\Nim\bin\libssl64.dll & copy C:\OpenSSL-Win64\libssl32.dll %CD%\Nim\bin\libssl32.dll )
|
ELSE ( copy C:\OpenSSL-Win32\libeay32.dll %CD%\BIN\libeay32.dll & copy C:\OpenSSL-Win32\libssl32.dll %CD%\BIN\libssl32.dll )
|
||||||
ELSE ( copy C:\OpenSSL-Win32\libeay32.dll %CD%\Nim\bin\libeay32.dll & copy C:\OpenSSL-Win32\libssl32.dll %CD%\Nim\bin\libssl32.dll )
|
- IF "%PLATFORM%" == "x64" ( copy %CD%\DIST\sqlite3.dll %CD%\BIN\sqlite3_64.dll ) ELSE ( copy %CD%\DIST\sqlite3.dll %CD%\BIN\sqlite3_32.dll )
|
||||||
- IF "%PLATFORM%" == "x64" ( copy %CD%\sqlite3.dll %CD%\Nim\bin\sqlite3_64.dll ) ELSE ( copy %CD%\sqlite3.dll %CD%\Nim\bin\sqlite3_32.dll )
|
- IF "%PLATFORM%" == "x64" ( copy %CD%\DIST\PCRE\pcre.redist.8.33.0.1\build\native\bin\v100\x64\Release\dynamic\utf8\pcre8.dll %CD%\bin\pcre64.dll ) ELSE ( copy %CD%\DIST\PCRE\pcre.redist.8.33.0.1\build\native\bin\v100\Win32\Release\dynamic\utf8\pcre8.dll %CD%\bin\pcre32.dll )
|
||||||
- IF "%PLATFORM%" == "x64" ( copy %CD%\pcre\pcre.redist.8.33.0.1\build\native\bin\v100\x64\Release\dynamic\utf8\pcre8.dll %CD%\Nim\bin\pcre64.dll ) ELSE ( copy %CD%\pcre\pcre.redist.8.33.0.1\build\native\bin\v100\Win32\Release\dynamic\utf8\pcre8.dll %CD%\Nim\bin\pcre32.dll )
|
|
||||||
- cd %CD%\Nim
|
|
||||||
- git clone --depth 1 https://github.com/nim-lang/csources
|
- git clone --depth 1 https://github.com/nim-lang/csources
|
||||||
- cd csources
|
- cd csources
|
||||||
- IF "%PLATFORM%" == "x64" ( build64.bat ) else ( build.bat )
|
- IF "%PLATFORM%" == "x64" ( build64.bat ) else ( build.bat )
|
||||||
|
|
@ -70,6 +69,6 @@ build_script:
|
||||||
test_script:
|
test_script:
|
||||||
- tests\testament\tester --pedantic all
|
- tests\testament\tester --pedantic all
|
||||||
- koch csource
|
- koch csource
|
||||||
- koch xz
|
- koch zip
|
||||||
|
|
||||||
deploy: off
|
deploy: off
|
||||||
|
|
|
||||||
|
|
@ -1541,7 +1541,8 @@ proc skipGenericOwner*(s: PSym): PSym =
|
||||||
## Generic instantiations are owned by their originating generic
|
## Generic instantiations are owned by their originating generic
|
||||||
## symbol. This proc skips such owners and goes straight to the owner
|
## symbol. This proc skips such owners and goes straight to the owner
|
||||||
## of the generic itself (the module or the enclosing proc).
|
## of the generic itself (the module or the enclosing proc).
|
||||||
result = if s.kind in skProcKinds and sfFromGeneric in s.flags:
|
result = if s.kind in skProcKinds and {sfGenSym, sfFromGeneric} * s.flags ==
|
||||||
|
{sfFromGeneric}:
|
||||||
s.owner.owner
|
s.owner.owner
|
||||||
else:
|
else:
|
||||||
s.owner
|
s.owner
|
||||||
|
|
|
||||||
|
|
@ -1210,7 +1210,7 @@ proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
|
||||||
|
|
||||||
proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
|
proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
|
||||||
var elem, a, arr: TLoc
|
var elem, a, arr: TLoc
|
||||||
if t.kind == nkBracket:
|
if t.sons[1].kind == nkBracket:
|
||||||
t.sons[1].typ = t.typ
|
t.sons[1].typ = t.typ
|
||||||
genSeqConstr(p, t.sons[1], d)
|
genSeqConstr(p, t.sons[1], d)
|
||||||
return
|
return
|
||||||
|
|
@ -1383,7 +1383,9 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
assert(d.k == locNone)
|
assert(d.k == locNone)
|
||||||
initLocExpr(p, e.sons[1], a)
|
var x = e.sons[1]
|
||||||
|
if x.kind in {nkAddr, nkHiddenAddr}: x = x[0]
|
||||||
|
initLocExpr(p, x, a)
|
||||||
initLocExpr(p, e.sons[2], b)
|
initLocExpr(p, e.sons[2], b)
|
||||||
let t = skipTypes(e.sons[1].typ, {tyVar})
|
let t = skipTypes(e.sons[1].typ, {tyVar})
|
||||||
let setLenPattern = if not p.module.compileToCpp:
|
let setLenPattern = if not p.module.compileToCpp:
|
||||||
|
|
@ -2001,7 +2003,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
if sfThread in sym.flags:
|
if sfThread in sym.flags:
|
||||||
accessThreadLocalVar(p, sym)
|
accessThreadLocalVar(p, sym)
|
||||||
if emulatedThreadVars():
|
if emulatedThreadVars():
|
||||||
putIntoDest(p, d, sym.loc.t, "NimTV->" & sym.loc.r)
|
putIntoDest(p, d, sym.loc.t, "NimTV_->" & sym.loc.r)
|
||||||
else:
|
else:
|
||||||
putLocIntoDest(p, d, sym.loc)
|
putLocIntoDest(p, d, sym.loc)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||||
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
|
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
|
||||||
else:
|
else:
|
||||||
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
|
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
|
||||||
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]
|
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym, t)]
|
||||||
putLocIntoDest(p, v.loc, field)
|
putLocIntoDest(p, v.loc, field)
|
||||||
|
|
||||||
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
|
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
|
||||||
|
|
@ -102,7 +102,7 @@ proc assignLabel(b: var TBlock): Rope {.inline.} =
|
||||||
proc blockBody(b: var TBlock): Rope =
|
proc blockBody(b: var TBlock): Rope =
|
||||||
result = b.sections[cpsLocals]
|
result = b.sections[cpsLocals]
|
||||||
if b.frameLen > 0:
|
if b.frameLen > 0:
|
||||||
result.addf("FR.len+=$1;$n", [b.frameLen.rope])
|
result.addf("FR_.len+=$1;$n", [b.frameLen.rope])
|
||||||
result.add(b.sections[cpsInit])
|
result.add(b.sections[cpsInit])
|
||||||
result.add(b.sections[cpsStmts])
|
result.add(b.sections[cpsStmts])
|
||||||
|
|
||||||
|
|
@ -123,7 +123,7 @@ proc endBlock(p: BProc) =
|
||||||
~"}$n"
|
~"}$n"
|
||||||
let frameLen = p.blocks[topBlock].frameLen
|
let frameLen = p.blocks[topBlock].frameLen
|
||||||
if frameLen > 0:
|
if frameLen > 0:
|
||||||
blockEnd.addf("FR.len-=$1;$n", [frameLen.rope])
|
blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope])
|
||||||
endBlock(p, blockEnd)
|
endBlock(p, blockEnd)
|
||||||
|
|
||||||
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
|
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
|
||||||
|
|
@ -156,7 +156,7 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||||
initLocExpr(p, n.sons[0], a)
|
initLocExpr(p, n.sons[0], a)
|
||||||
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
|
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
|
||||||
p.beforeRetNeeded = true
|
p.beforeRetNeeded = true
|
||||||
lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", [])
|
lineF(p, cpsStmts, "case -1: goto BeforeRet_;$n", [])
|
||||||
for i in 0 .. lastOrd(n.sons[0].typ):
|
for i in 0 .. lastOrd(n.sons[0].typ):
|
||||||
lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [rope(i)])
|
lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [rope(i)])
|
||||||
lineF(p, cpsStmts, "}$n", [])
|
lineF(p, cpsStmts, "}$n", [])
|
||||||
|
|
@ -373,7 +373,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
|
||||||
# consume it before we return.
|
# consume it before we return.
|
||||||
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
|
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
|
||||||
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
|
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
|
||||||
lineF(p, cpsStmts, "goto BeforeRet;$n", [])
|
lineF(p, cpsStmts, "goto BeforeRet_;$n", [])
|
||||||
|
|
||||||
proc genGotoForCase(p: BProc; caseStmt: PNode) =
|
proc genGotoForCase(p: BProc; caseStmt: PNode) =
|
||||||
for i in 1 .. <caseStmt.len:
|
for i in 1 .. <caseStmt.len:
|
||||||
|
|
@ -411,11 +411,11 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||||
localError(n.info, "no case statement found for computed goto"); return
|
localError(n.info, "no case statement found for computed goto"); return
|
||||||
var id = p.labels+1
|
var id = p.labels+1
|
||||||
inc p.labels, arraySize+1
|
inc p.labels, arraySize+1
|
||||||
let tmp = "TMP$1" % [id.rope]
|
let tmp = "TMP$1_" % [id.rope]
|
||||||
var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope]
|
var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope]
|
||||||
for i in 1..arraySize-1:
|
for i in 1..arraySize-1:
|
||||||
gotoArray.addf("&&TMP$#, ", [(id+i).rope])
|
gotoArray.addf("&&TMP$#_, ", [(id+i).rope])
|
||||||
gotoArray.addf("&&TMP$#};$n", [(id+arraySize).rope])
|
gotoArray.addf("&&TMP$#_};$n", [(id+arraySize).rope])
|
||||||
line(p, cpsLocals, gotoArray)
|
line(p, cpsLocals, gotoArray)
|
||||||
|
|
||||||
let topBlock = p.blocks.len-1
|
let topBlock = p.blocks.len-1
|
||||||
|
|
@ -445,7 +445,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||||
localError(it.info, "range notation not available for computed goto")
|
localError(it.info, "range notation not available for computed goto")
|
||||||
return
|
return
|
||||||
let val = getOrdValue(it.sons[j])
|
let val = getOrdValue(it.sons[j])
|
||||||
lineF(p, cpsStmts, "TMP$#:$n", [intLiteral(val+id+1)])
|
lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)])
|
||||||
genStmts(p, it.lastSon)
|
genStmts(p, it.lastSon)
|
||||||
#for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB
|
#for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB
|
||||||
#for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA
|
#for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA
|
||||||
|
|
@ -600,7 +600,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||||
for i in 1..until:
|
for i in 1..until:
|
||||||
# bug #4230: avoid false sharing between branches:
|
# bug #4230: avoid false sharing between branches:
|
||||||
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
||||||
lineF(p, cpsStmts, "LA$1: ;$n", [rope(labId + i)])
|
lineF(p, cpsStmts, "LA$1_: ;$n", [rope(labId + i)])
|
||||||
if t.sons[i].kind == nkOfBranch:
|
if t.sons[i].kind == nkOfBranch:
|
||||||
var length = sonsLen(t.sons[i])
|
var length = sonsLen(t.sons[i])
|
||||||
exprBlock(p, t.sons[i].sons[length - 1], d)
|
exprBlock(p, t.sons[i].sons[length - 1], d)
|
||||||
|
|
@ -618,15 +618,15 @@ proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
if t.sons[i].kind == nkOfBranch: # else statement
|
if t.sons[i].kind == nkOfBranch: # else statement
|
||||||
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
|
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
|
||||||
"LA" & rope(p.labels))
|
"LA" & rope(p.labels) & "_")
|
||||||
else:
|
else:
|
||||||
lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
|
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
|
||||||
if until < t.len-1:
|
if until < t.len-1:
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
var gotoTarget = p.labels
|
var gotoTarget = p.labels
|
||||||
lineF(p, cpsStmts, "goto LA$1;$n", [rope(gotoTarget)])
|
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(gotoTarget)])
|
||||||
result = genCaseSecondPass(p, t, d, labId, until)
|
result = genCaseSecondPass(p, t, d, labId, until)
|
||||||
lineF(p, cpsStmts, "LA$1: ;$n", [rope(gotoTarget)])
|
lineF(p, cpsStmts, "LA$1_: ;$n", [rope(gotoTarget)])
|
||||||
else:
|
else:
|
||||||
result = genCaseSecondPass(p, t, d, labId, until)
|
result = genCaseSecondPass(p, t, d, labId, until)
|
||||||
|
|
||||||
|
|
@ -664,7 +664,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
if t.sons[i].kind == nkOfBranch:
|
if t.sons[i].kind == nkOfBranch:
|
||||||
genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels),
|
genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels) & "_",
|
||||||
branches)
|
branches)
|
||||||
else:
|
else:
|
||||||
# else statement: nothing to do yet
|
# else statement: nothing to do yet
|
||||||
|
|
@ -678,7 +678,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
||||||
[intLiteral(j), branches[j]])
|
[intLiteral(j), branches[j]])
|
||||||
lineF(p, cpsStmts, "}$n", []) # else statement:
|
lineF(p, cpsStmts, "}$n", []) # else statement:
|
||||||
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
|
if t.sons[sonsLen(t)-1].kind != nkOfBranch:
|
||||||
lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
|
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
|
||||||
# third pass: generate statements
|
# third pass: generate statements
|
||||||
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
|
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
|
||||||
fixLabel(p, lend)
|
fixLabel(p, lend)
|
||||||
|
|
@ -802,7 +802,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
let length = sonsLen(t)
|
let length = sonsLen(t)
|
||||||
endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
|
endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
|
||||||
if optStackTrace in p.options:
|
if optStackTrace in p.options:
|
||||||
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n")
|
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
|
||||||
inc p.inExceptBlock
|
inc p.inExceptBlock
|
||||||
var i = 1
|
var i = 1
|
||||||
var catchAllPresent = false
|
var catchAllPresent = false
|
||||||
|
|
@ -910,7 +910,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||||
startBlock(p, "else {$n")
|
startBlock(p, "else {$n")
|
||||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||||
if optStackTrace in p.options:
|
if optStackTrace in p.options:
|
||||||
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n")
|
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
|
||||||
inc p.inExceptBlock
|
inc p.inExceptBlock
|
||||||
var i = 1
|
var i = 1
|
||||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
|
||||||
if emulatedThreadVars() and not p.threadVarAccessed:
|
if emulatedThreadVars() and not p.threadVarAccessed:
|
||||||
p.threadVarAccessed = true
|
p.threadVarAccessed = true
|
||||||
incl p.module.flags, usesThreadVars
|
incl p.module.flags, usesThreadVars
|
||||||
addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
|
addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV_;$n", [])
|
||||||
add(p.procSec(cpsInit),
|
add(p.procSec(cpsInit),
|
||||||
ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
|
ropecg(p.module, "\tNimTV_ = (NimThreadVars*) #GetThreadLocalVars();$n"))
|
||||||
|
|
||||||
var
|
var
|
||||||
nimtv: Rope # Nim thread vars; the struct body
|
nimtv: Rope # Nim thread vars; the struct body
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
|
||||||
|
|
||||||
if sfThread in s.flags and emulatedThreadVars():
|
if sfThread in s.flags and emulatedThreadVars():
|
||||||
accessThreadLocalVar(p, s)
|
accessThreadLocalVar(p, s)
|
||||||
sLoc = "NimTV->" & sLoc
|
sLoc = "NimTV_->" & sLoc
|
||||||
|
|
||||||
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
|
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
|
||||||
c.p = p
|
c.p = p
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,10 @@ proc isKeyword(w: PIdent): bool =
|
||||||
ord(wInline): return true
|
ord(wInline): return true
|
||||||
else: return false
|
else: return false
|
||||||
|
|
||||||
proc mangleField(name: PIdent): string =
|
proc mangleField(m: BModule; name: PIdent): string =
|
||||||
result = mangle(name.s)
|
result = mangle(name.s)
|
||||||
if isKeyword(name):
|
if isKeyword(name) or m.g.config.cppDefines.contains(result):
|
||||||
result[0] = result[0].toUpperAscii
|
result.add "_0"
|
||||||
# Mangling makes everything lowercase,
|
|
||||||
# but some identifiers are C keywords
|
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
proc hashOwner(s: PSym): SigHash =
|
proc hashOwner(s: PSym): SigHash =
|
||||||
|
|
@ -67,55 +65,50 @@ proc idOrSig(m: BModule; s: PSym): Rope =
|
||||||
proc mangleName(m: BModule; s: PSym): Rope =
|
proc mangleName(m: BModule; s: PSym): Rope =
|
||||||
result = s.loc.r
|
result = s.loc.r
|
||||||
if result == nil:
|
if result == nil:
|
||||||
let keepOrigName = s.kind in skLocalVars - {skForVar} and
|
|
||||||
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
|
|
||||||
not isKeyword(s.name)
|
|
||||||
# Even with all these inefficient checks, the bootstrap
|
|
||||||
# time is actually improved. This is probably because so many
|
|
||||||
# rope concatenations are now eliminated.
|
|
||||||
#
|
|
||||||
# sfFromGeneric is needed in order to avoid multiple
|
|
||||||
# definitions of certain variables generated in transf with
|
|
||||||
# names such as:
|
|
||||||
# `r`, `res`
|
|
||||||
# I need to study where these come from.
|
|
||||||
#
|
|
||||||
# about sfShadowed:
|
|
||||||
# consider the following Nim code:
|
|
||||||
# var x = 10
|
|
||||||
# block:
|
|
||||||
# var x = something(x)
|
|
||||||
# The generated C code will be:
|
|
||||||
# NI x;
|
|
||||||
# x = 10;
|
|
||||||
# {
|
|
||||||
# NI x;
|
|
||||||
# x = something(x); // Oops, x is already shadowed here
|
|
||||||
# }
|
|
||||||
# Right now, we work-around by not keeping the original name
|
|
||||||
# of the shadowed variable, but we can do better - we can
|
|
||||||
# create an alternative reference to it in the outer scope and
|
|
||||||
# use that in the inner scope.
|
|
||||||
#
|
|
||||||
# about isCKeyword:
|
|
||||||
# Nim variable names can be C keywords.
|
|
||||||
# We need to avoid such names in the generated code.
|
|
||||||
#
|
|
||||||
# about sfGlobal:
|
|
||||||
# This seems to be harder - a top level extern variable from
|
|
||||||
# another modules can have the same name as a local one.
|
|
||||||
# Maybe we should just implement sfShadowed for them too.
|
|
||||||
#
|
|
||||||
# about skForVar:
|
|
||||||
# These are not properly scoped now - we need to add blocks
|
|
||||||
# around for loops in transf
|
|
||||||
result = s.name.s.mangle.rope
|
result = s.name.s.mangle.rope
|
||||||
if keepOrigName:
|
add(result, m.idOrSig(s))
|
||||||
result.add "0"
|
|
||||||
else:
|
|
||||||
add(result, m.idOrSig(s))
|
|
||||||
s.loc.r = result
|
s.loc.r = result
|
||||||
|
writeMangledName(m.ndi, s)
|
||||||
|
|
||||||
|
proc mangleParamName(m: BModule; s: PSym): Rope =
|
||||||
|
## we cannot use 'sigConflicts' here since we have a BModule, not a BProc.
|
||||||
|
## Fortunately C's scoping rules are sane enough so that that doesn't
|
||||||
|
## cause any trouble.
|
||||||
|
result = s.loc.r
|
||||||
|
if result == nil:
|
||||||
|
var res = s.name.s.mangle
|
||||||
|
if isKeyword(s.name) or m.g.config.cppDefines.contains(res):
|
||||||
|
res.add "_0"
|
||||||
|
result = res.rope
|
||||||
|
s.loc.r = result
|
||||||
|
writeMangledName(m.ndi, s)
|
||||||
|
|
||||||
|
proc mangleLocalName(p: BProc; s: PSym): Rope =
|
||||||
|
assert s.kind in skLocalVars+{skTemp}
|
||||||
|
assert sfGlobal notin s.flags
|
||||||
|
result = s.loc.r
|
||||||
|
if result == nil:
|
||||||
|
var key = s.name.s.mangle
|
||||||
|
shallow(key)
|
||||||
|
let counter = p.sigConflicts.getOrDefault(key)
|
||||||
|
result = key.rope
|
||||||
|
if s.kind == skTemp:
|
||||||
|
# speed up conflict search for temps (these are quite common):
|
||||||
|
if counter != 0: result.add "_" & rope(counter+1)
|
||||||
|
elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key):
|
||||||
|
result.add "_" & rope(counter+1)
|
||||||
|
p.sigConflicts.inc(key)
|
||||||
|
s.loc.r = result
|
||||||
|
if s.kind != skTemp: writeMangledName(p.module.ndi, s)
|
||||||
|
|
||||||
|
proc scopeMangledParam(p: BProc; param: PSym) =
|
||||||
|
## parameter generation only takes BModule, not a BProc, so we have to
|
||||||
|
## remember these parameter names are already in scope to be able to
|
||||||
|
## generate unique identifiers reliably (consider that ``var a = a`` is
|
||||||
|
## even an idiom in Nim).
|
||||||
|
var key = param.name.s.mangle
|
||||||
|
shallow(key)
|
||||||
|
p.sigConflicts.inc(key)
|
||||||
|
|
||||||
const
|
const
|
||||||
irrelevantForBackend = {tyGenericBody, tyGenericInst, tyGenericInvocation,
|
irrelevantForBackend = {tyGenericBody, tyGenericInst, tyGenericInvocation,
|
||||||
|
|
@ -393,7 +386,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||||
var param = t.n.sons[i].sym
|
var param = t.n.sons[i].sym
|
||||||
if isCompileTimeOnly(param.typ): continue
|
if isCompileTimeOnly(param.typ): continue
|
||||||
if params != nil: add(params, ~", ")
|
if params != nil: add(params, ~", ")
|
||||||
fillLoc(param.loc, locParam, param.typ, mangleName(m, param),
|
fillLoc(param.loc, locParam, param.typ, mangleParamName(m, param),
|
||||||
param.paramStorageLoc)
|
param.paramStorageLoc)
|
||||||
if ccgIntroducedPtr(param):
|
if ccgIntroducedPtr(param):
|
||||||
add(params, getTypeDescWeak(m, param.typ, check))
|
add(params, getTypeDescWeak(m, param.typ, check))
|
||||||
|
|
@ -436,12 +429,12 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||||
else: add(params, ")")
|
else: add(params, ")")
|
||||||
params = "(" & params
|
params = "(" & params
|
||||||
|
|
||||||
proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
|
proc mangleRecFieldName(m: BModule; field: PSym, rectype: PType): Rope =
|
||||||
if (rectype.sym != nil) and
|
if (rectype.sym != nil) and
|
||||||
({sfImportc, sfExportc} * rectype.sym.flags != {}):
|
({sfImportc, sfExportc} * rectype.sym.flags != {}):
|
||||||
result = field.loc.r
|
result = field.loc.r
|
||||||
else:
|
else:
|
||||||
result = rope(mangleField(field.name))
|
result = rope(mangleField(m, field.name))
|
||||||
if result == nil: internalError(field.info, "mangleRecFieldName")
|
if result == nil: internalError(field.info, "mangleRecFieldName")
|
||||||
|
|
||||||
proc genRecordFieldsAux(m: BModule, n: PNode,
|
proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
|
|
@ -480,7 +473,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
let field = n.sym
|
let field = n.sym
|
||||||
if field.typ.kind == tyVoid: return
|
if field.typ.kind == tyVoid: return
|
||||||
#assert(field.ast == nil)
|
#assert(field.ast == nil)
|
||||||
let sname = mangleRecFieldName(field, rectype)
|
let sname = mangleRecFieldName(m, field, rectype)
|
||||||
let ae = if accessExpr != nil: "$1.$2" % [accessExpr, sname]
|
let ae = if accessExpr != nil: "$1.$2" % [accessExpr, sname]
|
||||||
else: sname
|
else: sname
|
||||||
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
|
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
|
||||||
|
|
@ -1103,13 +1096,11 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
|
||||||
discard cgsym(m, "TNimType")
|
discard cgsym(m, "TNimType")
|
||||||
discard cgsym(m, "TNimNode")
|
discard cgsym(m, "TNimNode")
|
||||||
addf(m.s[cfsVars], "extern TNimType $1;$n", [result])
|
addf(m.s[cfsVars], "extern TNimType $1;$n", [result])
|
||||||
#return "(&".rope & result & ")".rope
|
|
||||||
#result = "NTI$1" % [rope($sig)]
|
|
||||||
# also store in local type section:
|
# also store in local type section:
|
||||||
m.typeInfoMarker[sig] = result
|
m.typeInfoMarker[sig] = result
|
||||||
return "(&".rope & result & ")".rope
|
return "(&".rope & result & ")".rope
|
||||||
|
|
||||||
result = "NTI$1" % [rope($sig)]
|
result = "NTI$1_" % [rope($sig)]
|
||||||
m.typeInfoMarker[sig] = result
|
m.typeInfoMarker[sig] = result
|
||||||
|
|
||||||
let owner = t.skipTypes(typedescPtrs).owner.getModule
|
let owner = t.skipTypes(typedescPtrs).owner.getModule
|
||||||
|
|
|
||||||
|
|
@ -164,28 +164,50 @@ proc makeSingleLineCString*(s: string): string =
|
||||||
result.add('\"')
|
result.add('\"')
|
||||||
|
|
||||||
proc mangle*(name: string): string =
|
proc mangle*(name: string): string =
|
||||||
## Lowercases the given name and manges any non-alphanumeric characters
|
|
||||||
## so they are represented as `HEX____`. If the name starts with a number,
|
|
||||||
## `N` is prepended
|
|
||||||
result = newStringOfCap(name.len)
|
result = newStringOfCap(name.len)
|
||||||
case name[0]
|
var start = 0
|
||||||
of Letters:
|
if name[0] in Digits:
|
||||||
result.add(name[0])
|
result.add("X" & name[0])
|
||||||
of Digits:
|
start = 1
|
||||||
result.add("N" & name[0])
|
var requiresUnderscore = false
|
||||||
else:
|
template special(x) =
|
||||||
result = "HEX" & toHex(ord(name[0]), 2)
|
result.add x
|
||||||
for i in 1..(name.len-1):
|
requiresUnderscore = true
|
||||||
|
for i in start..(name.len-1):
|
||||||
let c = name[i]
|
let c = name[i]
|
||||||
case c
|
case c
|
||||||
of 'A'..'Z':
|
of 'a'..'z', '0'..'9', 'A'..'Z':
|
||||||
add(result, c.toLowerAscii)
|
|
||||||
of '_':
|
|
||||||
discard
|
|
||||||
of 'a'..'z', '0'..'9':
|
|
||||||
add(result, c)
|
add(result, c)
|
||||||
|
of '_':
|
||||||
|
# we generate names like 'foo_9' for scope disambiguations and so
|
||||||
|
# disallow this here:
|
||||||
|
if i < name.len-1 and name[i] in Digits:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
add(result, c)
|
||||||
|
of '$': special "dollar"
|
||||||
|
of '%': special "percent"
|
||||||
|
of '&': special "amp"
|
||||||
|
of '^': special "roof"
|
||||||
|
of '!': special "emark"
|
||||||
|
of '?': special "qmark"
|
||||||
|
of '*': special "star"
|
||||||
|
of '+': special "plus"
|
||||||
|
of '-': special "minus"
|
||||||
|
of '/': special "slash"
|
||||||
|
of '=': special "eq"
|
||||||
|
of '<': special "lt"
|
||||||
|
of '>': special "gt"
|
||||||
|
of '~': special "tilde"
|
||||||
|
of ':': special "colon"
|
||||||
|
of '.': special "dot"
|
||||||
|
of '@': special "at"
|
||||||
|
of '|': special "bar"
|
||||||
else:
|
else:
|
||||||
add(result, "HEX" & toHex(ord(c), 2))
|
add(result, "X" & toHex(ord(c), 2))
|
||||||
|
requiresUnderscore = true
|
||||||
|
if requiresUnderscore:
|
||||||
|
result.add "_"
|
||||||
|
|
||||||
proc makeLLVMString*(s: string): Rope =
|
proc makeLLVMString*(s: string): Rope =
|
||||||
const MaxLineLength = 64
|
const MaxLineLength = 64
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import
|
||||||
nversion, nimsets, msgs, securehash, bitsets, idents, lists, types,
|
nversion, nimsets, msgs, securehash, bitsets, idents, lists, types,
|
||||||
ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
||||||
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
|
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
|
||||||
lowerings, semparallel, tables
|
lowerings, semparallel, tables, sets, ndi
|
||||||
|
|
||||||
import strutils except `%` # collides with ropes.`%`
|
import strutils except `%` # collides with ropes.`%`
|
||||||
|
|
||||||
|
|
@ -216,7 +216,7 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||||
{optLineTrace, optStackTrace}) and
|
{optLineTrace, optStackTrace}) and
|
||||||
(p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex >= 0:
|
(p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex >= 0:
|
||||||
if freshLineInfo(p, tt.info):
|
if freshLineInfo(p, tt.info):
|
||||||
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
|
||||||
line.rope, tt.info.quotedFilename)
|
line.rope, tt.info.quotedFilename)
|
||||||
|
|
||||||
proc postStmtActions(p: BProc) {.inline.} =
|
proc postStmtActions(p: BProc) {.inline.} =
|
||||||
|
|
@ -338,7 +338,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||||
|
|
||||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
result.r = "LOC" & rope(p.labels)
|
result.r = "T" & rope(p.labels) & "_"
|
||||||
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
||||||
result.k = locTemp
|
result.k = locTemp
|
||||||
result.t = t
|
result.t = t
|
||||||
|
|
@ -347,12 +347,12 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||||
constructLoc(p, result, not needsInit)
|
constructLoc(p, result, not needsInit)
|
||||||
|
|
||||||
proc initGCFrame(p: BProc): Rope =
|
proc initGCFrame(p: BProc): Rope =
|
||||||
if p.gcFrameId > 0: result = "struct {$1} GCFRAME;$n" % [p.gcFrameType]
|
if p.gcFrameId > 0: result = "struct {$1} GCFRAME_;$n" % [p.gcFrameType]
|
||||||
|
|
||||||
proc deinitGCFrame(p: BProc): Rope =
|
proc deinitGCFrame(p: BProc): Rope =
|
||||||
if p.gcFrameId > 0:
|
if p.gcFrameId > 0:
|
||||||
result = ropecg(p.module,
|
result = ropecg(p.module,
|
||||||
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
|
"if (((NU)&GCFRAME_) < 4096) #nimGCFrame(&GCFRAME_);$n")
|
||||||
|
|
||||||
proc localDebugInfo(p: BProc, s: PSym) =
|
proc localDebugInfo(p: BProc, s: PSym) =
|
||||||
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
|
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
|
||||||
|
|
@ -361,7 +361,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
|
||||||
var a = "&" & s.loc.r
|
var a = "&" & s.loc.r
|
||||||
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
|
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
|
||||||
lineF(p, cpsInit,
|
lineF(p, cpsInit,
|
||||||
"FR.s[$1].address = (void*)$3; FR.s[$1].typ = $4; FR.s[$1].name = $2;$n",
|
"FR_.s[$1].address = (void*)$3; FR_.s[$1].typ = $4; FR_.s[$1].name = $2;$n",
|
||||||
[p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
|
[p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
|
||||||
genTypeInfo(p.module, s.loc.t)])
|
genTypeInfo(p.module, s.loc.t)])
|
||||||
inc(p.maxFrameLen)
|
inc(p.maxFrameLen)
|
||||||
|
|
@ -369,7 +369,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
|
||||||
|
|
||||||
proc localVarDecl(p: BProc; s: PSym): Rope =
|
proc localVarDecl(p: BProc; s: PSym): Rope =
|
||||||
if s.loc.k == locNone:
|
if s.loc.k == locNone:
|
||||||
fillLoc(s.loc, locLocalVar, s.typ, mangleName(p.module, s), OnStack)
|
fillLoc(s.loc, locLocalVar, s.typ, mangleLocalName(p, s), OnStack)
|
||||||
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
||||||
result = getTypeDesc(p.module, s.typ)
|
result = getTypeDesc(p.module, s.typ)
|
||||||
if s.constraint.isNil:
|
if s.constraint.isNil:
|
||||||
|
|
@ -434,6 +434,7 @@ proc assignGlobalVar(p: BProc, s: PSym) =
|
||||||
|
|
||||||
proc assignParam(p: BProc, s: PSym) =
|
proc assignParam(p: BProc, s: PSym) =
|
||||||
assert(s.loc.r != nil)
|
assert(s.loc.r != nil)
|
||||||
|
scopeMangledParam(p, s)
|
||||||
localDebugInfo(p, s)
|
localDebugInfo(p, s)
|
||||||
|
|
||||||
proc fillProcLoc(m: BModule; sym: PSym) =
|
proc fillProcLoc(m: BModule; sym: PSym) =
|
||||||
|
|
@ -442,7 +443,7 @@ proc fillProcLoc(m: BModule; sym: PSym) =
|
||||||
|
|
||||||
proc getLabel(p: BProc): TLabel =
|
proc getLabel(p: BProc): TLabel =
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
result = "LA" & rope(p.labels)
|
result = "LA" & rope(p.labels) & "_"
|
||||||
|
|
||||||
proc fixLabel(p: BProc, labl: TLabel) =
|
proc fixLabel(p: BProc, labl: TLabel) =
|
||||||
lineF(p, cpsStmts, "$1: ;$n", [labl])
|
lineF(p, cpsStmts, "$1: ;$n", [labl])
|
||||||
|
|
@ -520,7 +521,7 @@ proc mangleDynLibProc(sym: PSym): Rope =
|
||||||
# NOTE: sym.loc.r is the external name!
|
# NOTE: sym.loc.r is the external name!
|
||||||
result = rope(sym.name.s)
|
result = rope(sym.name.s)
|
||||||
else:
|
else:
|
||||||
result = "Dl_$1" % [rope(sym.id)]
|
result = "Dl_$1_" % [rope(sym.id)]
|
||||||
|
|
||||||
proc symInDynamicLib(m: BModule, sym: PSym) =
|
proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||||
var lib = sym.annex
|
var lib = sym.annex
|
||||||
|
|
@ -608,11 +609,11 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope =
|
||||||
discard cgsym(p.module, "nimFrame")
|
discard cgsym(p.module, "nimFrame")
|
||||||
if p.maxFrameLen > 0:
|
if p.maxFrameLen > 0:
|
||||||
discard cgsym(p.module, "VarSlot")
|
discard cgsym(p.module, "VarSlot")
|
||||||
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
|
result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4)$N",
|
||||||
procname, filename, p.maxFrameLen.rope,
|
procname, filename, p.maxFrameLen.rope,
|
||||||
p.blocks[0].frameLen.rope)
|
p.blocks[0].frameLen.rope)
|
||||||
else:
|
else:
|
||||||
result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
|
result = rfmt(nil, "\tnimfr_($1, $2)$N", procname, filename)
|
||||||
|
|
||||||
proc deinitFrame(p: BProc): Rope =
|
proc deinitFrame(p: BProc): Rope =
|
||||||
result = rfmt(p.module, "\t#popFrame();$n")
|
result = rfmt(p.module, "\t#popFrame();$n")
|
||||||
|
|
@ -707,7 +708,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||||
if p.beforeRetNeeded: add(generatedProc, "{")
|
if p.beforeRetNeeded: add(generatedProc, "{")
|
||||||
add(generatedProc, p.s(cpsInit))
|
add(generatedProc, p.s(cpsInit))
|
||||||
add(generatedProc, p.s(cpsStmts))
|
add(generatedProc, p.s(cpsStmts))
|
||||||
if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet: ;$n")
|
if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet_: ;$n")
|
||||||
add(generatedProc, deinitGCFrame(p))
|
add(generatedProc, deinitGCFrame(p))
|
||||||
if optStackTrace in prc.options: add(generatedProc, deinitFrame(p))
|
if optStackTrace in prc.options: add(generatedProc, deinitFrame(p))
|
||||||
add(generatedProc, returnStmt)
|
add(generatedProc, returnStmt)
|
||||||
|
|
@ -846,7 +847,8 @@ proc genVarPrototype(m: BModule, sym: PSym) =
|
||||||
genVarPrototypeAux(m, sym)
|
genVarPrototypeAux(m, sym)
|
||||||
|
|
||||||
proc addIntTypes(result: var Rope) {.inline.} =
|
proc addIntTypes(result: var Rope) {.inline.} =
|
||||||
addf(result, "#define NIM_INTBITS $1" & tnl, [
|
addf(result, "#define NIM_NEW_MANGLING_RULES" & tnl &
|
||||||
|
"#define NIM_INTBITS $1" & tnl, [
|
||||||
platform.CPU[targetCPU].intSize.rope])
|
platform.CPU[targetCPU].intSize.rope])
|
||||||
|
|
||||||
proc getCopyright(cfile: Cfile): Rope =
|
proc getCopyright(cfile: Cfile): Rope =
|
||||||
|
|
@ -1058,7 +1060,7 @@ proc genInitCode(m: BModule) =
|
||||||
var procname = makeCString(m.module.name.s)
|
var procname = makeCString(m.module.name.s)
|
||||||
add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
|
add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
|
||||||
else:
|
else:
|
||||||
add(prc, ~"\tTFrame FR; FR.len = 0;$N")
|
add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
|
||||||
|
|
||||||
add(prc, genSectionStart(cpsInit))
|
add(prc, genSectionStart(cpsInit))
|
||||||
add(prc, m.preInitProc.s(cpsInit))
|
add(prc, m.preInitProc.s(cpsInit))
|
||||||
|
|
@ -1123,7 +1125,7 @@ proc initProcOptions(m: BModule): TOptions =
|
||||||
|
|
||||||
proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
|
proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
|
||||||
new(result)
|
new(result)
|
||||||
result.tmpBase = rope("T" & $hashOwner(module) & "_")
|
result.tmpBase = rope("TM" & $hashOwner(module) & "_")
|
||||||
initLinkedList(result.headerFiles)
|
initLinkedList(result.headerFiles)
|
||||||
result.declaredThings = initIntSet()
|
result.declaredThings = initIntSet()
|
||||||
result.declaredProtos = initIntSet()
|
result.declaredProtos = initIntSet()
|
||||||
|
|
@ -1150,6 +1152,9 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
|
||||||
incl result.flags, preventStackTrace
|
incl result.flags, preventStackTrace
|
||||||
excl(result.preInitProc.options, optStackTrace)
|
excl(result.preInitProc.options, optStackTrace)
|
||||||
excl(result.postInitProc.options, optStackTrace)
|
excl(result.postInitProc.options, optStackTrace)
|
||||||
|
let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(filename), "ndi")
|
||||||
|
else: ""
|
||||||
|
open(result.ndi, ndiName)
|
||||||
|
|
||||||
proc nullify[T](arr: var T) =
|
proc nullify[T](arr: var T) =
|
||||||
for i in low(arr)..high(arr):
|
for i in low(arr)..high(arr):
|
||||||
|
|
@ -1212,16 +1217,16 @@ proc newModule(g: BModuleList; module: PSym): BModule =
|
||||||
if (sfDeadCodeElim in module.flags):
|
if (sfDeadCodeElim in module.flags):
|
||||||
internalError("added pending module twice: " & module.filename)
|
internalError("added pending module twice: " & module.filename)
|
||||||
|
|
||||||
template injectG() {.dirty.} =
|
template injectG(config) {.dirty.} =
|
||||||
if graph.backend == nil:
|
if graph.backend == nil:
|
||||||
graph.backend = newModuleList()
|
graph.backend = newModuleList(config)
|
||||||
let g = BModuleList(graph.backend)
|
let g = BModuleList(graph.backend)
|
||||||
|
|
||||||
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
|
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
|
||||||
injectG()
|
injectG(graph.config)
|
||||||
result = newModule(g, module)
|
result = newModule(g, module)
|
||||||
if optGenIndex in gGlobalOptions and g.generatedHeader == nil:
|
if optGenIndex in gGlobalOptions and g.generatedHeader == nil:
|
||||||
let f = if headerFile.len > 0: headerFile else: gProjectFull
|
let f = if graph.config.headerFile.len > 0: graph.config.headerFile else: gProjectFull
|
||||||
g.generatedHeader = rawNewModule(g, module,
|
g.generatedHeader = rawNewModule(g, module,
|
||||||
changeFileExt(completeCFilePath(f), hExt))
|
changeFileExt(completeCFilePath(f), hExt))
|
||||||
incl g.generatedHeader.flags, isHeaderFile
|
incl g.generatedHeader.flags, isHeaderFile
|
||||||
|
|
@ -1258,7 +1263,7 @@ proc getCFile(m: BModule): string =
|
||||||
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
|
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
|
||||||
|
|
||||||
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
|
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
|
||||||
injectG()
|
injectG(graph.config)
|
||||||
assert optSymbolFiles in gGlobalOptions
|
assert optSymbolFiles in gGlobalOptions
|
||||||
var m = newModule(g, module)
|
var m = newModule(g, module)
|
||||||
readMergeInfo(getCFile(m), m)
|
readMergeInfo(getCFile(m), m)
|
||||||
|
|
@ -1341,6 +1346,7 @@ proc writeModule(m: BModule, pending: bool) =
|
||||||
var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
|
var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
|
||||||
if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached}
|
if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached}
|
||||||
addFileToCompile(cf)
|
addFileToCompile(cf)
|
||||||
|
close(m.ndi)
|
||||||
|
|
||||||
proc updateCachedModule(m: BModule) =
|
proc updateCachedModule(m: BModule) =
|
||||||
let cfile = getCFile(m)
|
let cfile = getCFile(m)
|
||||||
|
|
@ -1373,11 +1379,12 @@ proc myClose(b: PPassContext, n: PNode): PNode =
|
||||||
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
|
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
|
||||||
genMainProc(m)
|
genMainProc(m)
|
||||||
|
|
||||||
proc cgenWriteModules*(backend: RootRef) =
|
proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
|
||||||
let g = BModuleList(backend)
|
let g = BModuleList(backend)
|
||||||
# we need to process the transitive closure because recursive module
|
# we need to process the transitive closure because recursive module
|
||||||
# deps are allowed (and the system module is processed in the wrong
|
# deps are allowed (and the system module is processed in the wrong
|
||||||
# order anyway)
|
# order anyway)
|
||||||
|
g.config = config
|
||||||
if g.generatedHeader != nil: finishModule(g.generatedHeader)
|
if g.generatedHeader != nil: finishModule(g.generatedHeader)
|
||||||
while g.forwardedProcsCounter > 0:
|
while g.forwardedProcsCounter > 0:
|
||||||
for m in cgenModules(g):
|
for m in cgenModules(g):
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, ropes, passes, options, intsets, lists, platform, sighashes,
|
ast, astalgo, ropes, passes, options, intsets, lists, platform, sighashes,
|
||||||
tables
|
tables, ndi
|
||||||
|
|
||||||
from msgs import TLineInfo
|
from msgs import TLineInfo
|
||||||
|
|
||||||
|
|
@ -56,7 +56,7 @@ type
|
||||||
BProc* = ref TCProc
|
BProc* = ref TCProc
|
||||||
TBlock*{.final.} = object
|
TBlock*{.final.} = object
|
||||||
id*: int # the ID of the label; positive means that it
|
id*: int # the ID of the label; positive means that it
|
||||||
label*: Rope # generated text for the label
|
label*: Rope # generated text for the label
|
||||||
# nil if label is not used
|
# nil if label is not used
|
||||||
sections*: TCProcSections # the code beloging
|
sections*: TCProcSections # the code beloging
|
||||||
isLoop*: bool # whether block is a loop
|
isLoop*: bool # whether block is a loop
|
||||||
|
|
@ -76,7 +76,7 @@ type
|
||||||
# leaving such scopes by raise or by return must
|
# leaving such scopes by raise or by return must
|
||||||
# execute any applicable finally blocks
|
# execute any applicable finally blocks
|
||||||
finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
|
finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
|
||||||
# using return in finally statements
|
# using return in finally statements
|
||||||
labels*: Natural # for generating unique labels in the C proc
|
labels*: Natural # for generating unique labels in the C proc
|
||||||
blocks*: seq[TBlock] # nested blocks
|
blocks*: seq[TBlock] # nested blocks
|
||||||
breakIdx*: int # the block that will be exited
|
breakIdx*: int # the block that will be exited
|
||||||
|
|
@ -92,6 +92,7 @@ type
|
||||||
# (yes, C++ is weird like that)
|
# (yes, C++ is weird like that)
|
||||||
gcFrameId*: Natural # for the GC stack marking
|
gcFrameId*: Natural # for the GC stack marking
|
||||||
gcFrameType*: Rope # the struct {} we put the GC markers into
|
gcFrameType*: Rope # the struct {} we put the GC markers into
|
||||||
|
sigConflicts*: CountTable[string]
|
||||||
|
|
||||||
TTypeSeq* = seq[PType]
|
TTypeSeq* = seq[PType]
|
||||||
TypeCache* = Table[SigHash, Rope]
|
TypeCache* = Table[SigHash, Rope]
|
||||||
|
|
@ -115,6 +116,7 @@ type
|
||||||
breakPointId*: int
|
breakPointId*: int
|
||||||
breakpoints*: Rope # later the breakpoints are inserted into the main proc
|
breakpoints*: Rope # later the breakpoints are inserted into the main proc
|
||||||
typeInfoMarker*: TypeCache
|
typeInfoMarker*: TypeCache
|
||||||
|
config*: ConfigRef
|
||||||
|
|
||||||
TCGen = object of TPassContext # represents a C source file
|
TCGen = object of TPassContext # represents a C source file
|
||||||
s*: TCFileSections # sections of the C file
|
s*: TCFileSections # sections of the C file
|
||||||
|
|
@ -144,6 +146,7 @@ type
|
||||||
injectStmt*: Rope
|
injectStmt*: Rope
|
||||||
sigConflicts*: CountTable[SigHash]
|
sigConflicts*: CountTable[SigHash]
|
||||||
g*: BModuleList
|
g*: BModuleList
|
||||||
|
ndi*: NdiFile
|
||||||
|
|
||||||
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
|
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
|
||||||
# section in the current block
|
# section in the current block
|
||||||
|
|
@ -162,9 +165,10 @@ proc newProc*(prc: PSym, module: BModule): BProc =
|
||||||
newSeq(result.blocks, 1)
|
newSeq(result.blocks, 1)
|
||||||
result.nestedTryStmts = @[]
|
result.nestedTryStmts = @[]
|
||||||
result.finallySafePoints = @[]
|
result.finallySafePoints = @[]
|
||||||
|
result.sigConflicts = initCountTable[string]()
|
||||||
|
|
||||||
proc newModuleList*(): BModuleList =
|
proc newModuleList*(config: ConfigRef): BModuleList =
|
||||||
BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope]())
|
BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: config)
|
||||||
|
|
||||||
iterator cgenModules*(g: BModuleList): BModule =
|
iterator cgenModules*(g: BModuleList): BModule =
|
||||||
for i in 0..high(g.modules):
|
for i in 0..high(g.modules):
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,8 @@ type
|
||||||
passPP # preprocessor called processCommand()
|
passPP # preprocessor called processCommand()
|
||||||
|
|
||||||
proc processCommand*(switch: string, pass: TCmdLinePass)
|
proc processCommand*(switch: string, pass: TCmdLinePass)
|
||||||
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
|
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
|
config: ConfigRef = nil)
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
|
|
@ -312,7 +313,8 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
options.inclDynlibOverride(arg)
|
options.inclDynlibOverride(arg)
|
||||||
|
|
||||||
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
|
config: ConfigRef = nil) =
|
||||||
var
|
var
|
||||||
theOS: TSystemOS
|
theOS: TSystemOS
|
||||||
cpu: TSystemCPU
|
cpu: TSystemCPU
|
||||||
|
|
@ -509,10 +511,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
|
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
|
||||||
of "passc", "t":
|
of "passc", "t":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
|
if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(arg)
|
||||||
of "passl", "l":
|
of "passl", "l":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
|
if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(arg)
|
||||||
of "cincludes":
|
of "cincludes":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info)
|
if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info)
|
||||||
|
|
@ -523,7 +525,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info)
|
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info)
|
||||||
of "header":
|
of "header":
|
||||||
headerFile = arg
|
if config != nil: config.headerFile = arg
|
||||||
incl(gGlobalOptions, optGenIndex)
|
incl(gGlobalOptions, optGenIndex)
|
||||||
of "index":
|
of "index":
|
||||||
processOnOffSwitchG({optGenIndex}, arg, pass, info)
|
processOnOffSwitchG({optGenIndex}, arg, pass, info)
|
||||||
|
|
@ -646,6 +648,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(switch, arg, pass, info)
|
||||||
incl(gGlobalOptions, optNoCppExceptions)
|
incl(gGlobalOptions, optNoCppExceptions)
|
||||||
defineSymbol("noCppExceptions")
|
defineSymbol("noCppExceptions")
|
||||||
|
of "cppdefine":
|
||||||
|
expectArg(switch, arg, pass, info)
|
||||||
|
if config != nil:
|
||||||
|
config.cppDefine(arg)
|
||||||
else:
|
else:
|
||||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
||||||
else: invalidCmdLineOption(pass, switch, info)
|
else: invalidCmdLineOption(pass, switch, info)
|
||||||
|
|
|
||||||
|
|
@ -101,3 +101,4 @@ proc initDefines*() =
|
||||||
defineSymbol("nimImmediateDeprecated")
|
defineSymbol("nimImmediateDeprecated")
|
||||||
defineSymbol("nimNewShiftOps")
|
defineSymbol("nimNewShiftOps")
|
||||||
defineSymbol("nimDistros")
|
defineSymbol("nimDistros")
|
||||||
|
defineSymbol("nimHasCppDefine")
|
||||||
|
|
|
||||||
|
|
@ -209,26 +209,26 @@ proc getPlainDocstring(n: PNode): string =
|
||||||
result = getPlainDocstring(n.sons[i])
|
result = getPlainDocstring(n.sons[i])
|
||||||
if result.len > 0: return
|
if result.len > 0: return
|
||||||
|
|
||||||
|
when false:
|
||||||
|
proc findDocComment(n: PNode): PNode =
|
||||||
|
if n == nil: return nil
|
||||||
|
if not isNil(n.comment) and startsWith(n.comment, "##"): return n
|
||||||
|
for i in countup(0, safeLen(n)-1):
|
||||||
|
result = findDocComment(n.sons[i])
|
||||||
|
if result != nil: return
|
||||||
|
|
||||||
proc findDocComment(n: PNode): PNode =
|
proc extractDocComment*(s: PSym, d: PDoc = nil): string =
|
||||||
if n == nil: return nil
|
let n = findDocComment(s.ast)
|
||||||
if not isNil(n.comment) and startsWith(n.comment, "##"): return n
|
result = ""
|
||||||
for i in countup(0, safeLen(n)-1):
|
if not n.isNil:
|
||||||
result = findDocComment(n.sons[i])
|
if not d.isNil:
|
||||||
if result != nil: return
|
var dummyHasToc: bool
|
||||||
|
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
|
||||||
proc extractDocComment*(s: PSym, d: PDoc = nil): string =
|
toLinenumber(n.info), toColumn(n.info),
|
||||||
let n = findDocComment(s.ast)
|
dummyHasToc, d.options + {roSkipPounds}),
|
||||||
result = ""
|
result)
|
||||||
if not n.isNil:
|
else:
|
||||||
if not d.isNil:
|
result = n.comment.substr(2).replace("\n##", "\n").strip
|
||||||
var dummyHasToc: bool
|
|
||||||
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
|
|
||||||
toLinenumber(n.info), toColumn(n.info),
|
|
||||||
dummyHasToc, d.options + {roSkipPounds}),
|
|
||||||
result)
|
|
||||||
else:
|
|
||||||
result = n.comment.substr(2).replace("\n##", "\n").strip
|
|
||||||
|
|
||||||
proc isVisible(n: PNode): bool =
|
proc isVisible(n: PNode): bool =
|
||||||
result = false
|
result = false
|
||||||
|
|
|
||||||
|
|
@ -392,6 +392,8 @@ type
|
||||||
var
|
var
|
||||||
externalToLink: TLinkedList # files to link in addition to the file
|
externalToLink: TLinkedList # files to link in addition to the file
|
||||||
# we compiled
|
# we compiled
|
||||||
|
linkOptionsCmd: string = ""
|
||||||
|
compileOptionsCmd: seq[string] = @[]
|
||||||
linkOptions: string = ""
|
linkOptions: string = ""
|
||||||
compileOptions: string = ""
|
compileOptions: string = ""
|
||||||
ccompilerpath: string = ""
|
ccompilerpath: string = ""
|
||||||
|
|
@ -450,6 +452,12 @@ proc addCompileOption*(option: string) =
|
||||||
if strutils.find(compileOptions, option, 0) < 0:
|
if strutils.find(compileOptions, option, 0) < 0:
|
||||||
addOpt(compileOptions, option)
|
addOpt(compileOptions, option)
|
||||||
|
|
||||||
|
proc addLinkOptionCmd*(option: string) =
|
||||||
|
addOpt(linkOptionsCmd, option)
|
||||||
|
|
||||||
|
proc addCompileOptionCmd*(option: string) =
|
||||||
|
compileOptionsCmd.add(option)
|
||||||
|
|
||||||
proc initVars*() =
|
proc initVars*() =
|
||||||
# we need to define the symbol here, because ``CC`` may have never been set!
|
# we need to define the symbol here, because ``CC`` may have never been set!
|
||||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||||
|
|
@ -524,6 +532,10 @@ proc add(s: var string, many: openArray[string]) =
|
||||||
|
|
||||||
proc cFileSpecificOptions(cfilename: string): string =
|
proc cFileSpecificOptions(cfilename: string): string =
|
||||||
result = compileOptions
|
result = compileOptions
|
||||||
|
for option in compileOptionsCmd:
|
||||||
|
if strutils.find(result, option, 0) < 0:
|
||||||
|
addOpt(result, option)
|
||||||
|
|
||||||
var trunk = splitFile(cfilename).name
|
var trunk = splitFile(cfilename).name
|
||||||
if optCDebug in gGlobalOptions:
|
if optCDebug in gGlobalOptions:
|
||||||
var key = trunk & ".debug"
|
var key = trunk & ".debug"
|
||||||
|
|
@ -544,7 +556,7 @@ proc getCompileOptions: string =
|
||||||
result = cFileSpecificOptions("__dummy__")
|
result = cFileSpecificOptions("__dummy__")
|
||||||
|
|
||||||
proc getLinkOptions: string =
|
proc getLinkOptions: string =
|
||||||
result = linkOptions
|
result = linkOptions & " " & linkOptionsCmd & " "
|
||||||
for linkedLib in items(cLinkedLibs):
|
for linkedLib in items(cLinkedLibs):
|
||||||
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
|
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
|
||||||
for libDir in items(cLibs):
|
for libDir in items(cLibs):
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ Start: "doc/html/overview.html"
|
||||||
|
|
||||||
|
|
||||||
[Other]
|
[Other]
|
||||||
Files: "readme.txt;install.txt;contributors.txt;copying.txt"
|
Files: "readme.txt;copying.txt"
|
||||||
Files: "makefile"
|
Files: "makefile"
|
||||||
Files: "koch.nim"
|
Files: "koch.nim"
|
||||||
Files: "install_nimble.nims"
|
Files: "install_nimble.nims"
|
||||||
|
|
@ -94,15 +94,17 @@ Files: "bin/vccexe.exe"
|
||||||
|
|
||||||
Files: "koch.exe"
|
Files: "koch.exe"
|
||||||
Files: "finish.exe"
|
Files: "finish.exe"
|
||||||
|
Files: "downloader.exe"
|
||||||
|
|
||||||
; Files: "dist/mingw"
|
; Files: "dist/mingw"
|
||||||
Files: r"tools\start.bat"
|
Files: r"tools\start.bat"
|
||||||
BinPath: r"bin;dist\mingw\bin;dist"
|
BinPath: r"bin;dist\mingw\bin;dist"
|
||||||
|
|
||||||
; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry
|
; Section | dir | zipFile | size hint (in KB) | url | exe start menu entry
|
||||||
Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html"
|
Download: r"Documentation|doc|docs.zip|13824|https://nim-lang.org/download/docs-${version}.zip|overview.html"
|
||||||
Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip"
|
Download: r"C Compiler (MingW)|dist|mingw.zip|82944|https://nim-lang.org/download/${mingw}.zip"
|
||||||
Download: r"Support DLLs|bin|nim_dlls.zip|479|http://nim-lang.org/download/dlls.zip"
|
Download: r"Support DLLs|bin|nim_dlls.zip|479|https://nim-lang.org/download/dlls.zip"
|
||||||
Download: r"Aporia Text Editor|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.4.0.zip|aporia-0.4.0\bin\aporia.exe"
|
Download: r"Aporia Text Editor|dist|aporia.zip|97997|https://nim-lang.org/download/aporia-0.4.0.zip|aporia-0.4.0\bin\aporia.exe"
|
||||||
; for now only NSIS supports optional downloads
|
; for now only NSIS supports optional downloads
|
||||||
|
|
||||||
[WinBin]
|
[WinBin]
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
|
||||||
#registerPass(cleanupPass())
|
#registerPass(cleanupPass())
|
||||||
|
|
||||||
compileProject(graph, cache)
|
compileProject(graph, cache)
|
||||||
cgenWriteModules(graph.backend)
|
cgenWriteModules(graph.backend, graph.config)
|
||||||
if gCmd != cmdRun:
|
if gCmd != cmdRun:
|
||||||
let proj = changeFileExt(gProjectFull, "")
|
let proj = changeFileExt(gProjectFull, "")
|
||||||
extccomp.callCCompiler(proj)
|
extccomp.callCCompiler(proj)
|
||||||
|
|
@ -294,4 +294,4 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
|
||||||
|
|
||||||
resetAttributes()
|
resetAttributes()
|
||||||
|
|
||||||
proc mainCommand*() = mainCommand(newModuleGraph(), newIdentCache())
|
proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache())
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
## - Its dependent module stays the same.
|
## - Its dependent module stays the same.
|
||||||
##
|
##
|
||||||
|
|
||||||
import ast, intsets, tables
|
import ast, intsets, tables, options
|
||||||
|
|
||||||
type
|
type
|
||||||
ModuleGraph* = ref object
|
ModuleGraph* = ref object
|
||||||
|
|
@ -39,16 +39,21 @@ type
|
||||||
importStack*: seq[int32] # The current import stack. Used for detecting recursive
|
importStack*: seq[int32] # The current import stack. Used for detecting recursive
|
||||||
# module dependencies.
|
# module dependencies.
|
||||||
backend*: RootRef # minor hack so that a backend can extend this easily
|
backend*: RootRef # minor hack so that a backend can extend this easily
|
||||||
|
config*: ConfigRef
|
||||||
|
|
||||||
{.this: g.}
|
{.this: g.}
|
||||||
|
|
||||||
proc newModuleGraph*(): ModuleGraph =
|
proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
|
||||||
result = ModuleGraph()
|
result = ModuleGraph()
|
||||||
initStrTable(result.packageSyms)
|
initStrTable(result.packageSyms)
|
||||||
result.deps = initIntSet()
|
result.deps = initIntSet()
|
||||||
result.modules = @[]
|
result.modules = @[]
|
||||||
result.importStack = @[]
|
result.importStack = @[]
|
||||||
result.inclToMod = initTable[int32, int32]()
|
result.inclToMod = initTable[int32, int32]()
|
||||||
|
if config.isNil:
|
||||||
|
result.config = newConfigRef()
|
||||||
|
else:
|
||||||
|
result.config = config
|
||||||
|
|
||||||
proc resetAllModules*(g: ModuleGraph) =
|
proc resetAllModules*(g: ModuleGraph) =
|
||||||
initStrTable(packageSyms)
|
initStrTable(packageSyms)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import
|
||||||
|
|
||||||
type
|
type
|
||||||
TMsgKind* = enum
|
TMsgKind* = enum
|
||||||
errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated,
|
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated,
|
||||||
errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
|
errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
|
||||||
errIntLiteralExpected, errInvalidCharacterConstant,
|
errIntLiteralExpected, errInvalidCharacterConstant,
|
||||||
errClosingTripleQuoteExpected, errClosingQuoteExpected,
|
errClosingTripleQuoteExpected, errClosingQuoteExpected,
|
||||||
|
|
@ -135,8 +135,8 @@ type
|
||||||
const
|
const
|
||||||
MsgKindToStr*: array[TMsgKind, string] = [
|
MsgKindToStr*: array[TMsgKind, string] = [
|
||||||
errUnknown: "unknown error",
|
errUnknown: "unknown error",
|
||||||
errIllFormedAstX: "illformed AST: $1",
|
|
||||||
errInternal: "internal error: $1",
|
errInternal: "internal error: $1",
|
||||||
|
errIllFormedAstX: "illformed AST: $1",
|
||||||
errCannotOpenFile: "cannot open \'$1\'",
|
errCannotOpenFile: "cannot open \'$1\'",
|
||||||
errGenerated: "$1",
|
errGenerated: "$1",
|
||||||
errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++",
|
errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++",
|
||||||
|
|
|
||||||
40
compiler/ndi.nim
Normal file
40
compiler/ndi.nim
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2017 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## This module implements the generation of ``.ndi`` files for better debugging
|
||||||
|
## support of Nim code. "ndi" stands for "Nim debug info".
|
||||||
|
|
||||||
|
import ast, msgs, ropes
|
||||||
|
|
||||||
|
type
|
||||||
|
NdiFile* = object
|
||||||
|
enabled: bool
|
||||||
|
f: File
|
||||||
|
buf: string
|
||||||
|
|
||||||
|
proc doWrite(f: var NdiFile; s: PSym) =
|
||||||
|
f.buf.setLen 0
|
||||||
|
f.buf.add s.info.line.int
|
||||||
|
f.buf.add "\t"
|
||||||
|
f.buf.add s.info.col.int
|
||||||
|
f.f.write(s.name.s, "\t")
|
||||||
|
f.f.writeRope(s.loc.r)
|
||||||
|
f.f.writeLine("\t", s.info.toFullPath, "\t", f.buf)
|
||||||
|
|
||||||
|
template writeMangledName*(f: NdiFile; s: PSym) =
|
||||||
|
if f.enabled: doWrite(f, s)
|
||||||
|
|
||||||
|
proc open*(f: var NdiFile; filename: string) =
|
||||||
|
f.enabled = filename.len > 0
|
||||||
|
if f.enabled:
|
||||||
|
f.f = open(filename, fmWrite, 8000)
|
||||||
|
f.buf = newStringOfCap(20)
|
||||||
|
|
||||||
|
proc close*(f: var NdiFile) =
|
||||||
|
if f.enabled: close(f.f)
|
||||||
|
|
@ -37,7 +37,7 @@ proc prependCurDir(f: string): string =
|
||||||
else:
|
else:
|
||||||
result = f
|
result = f
|
||||||
|
|
||||||
proc handleCmdLine(cache: IdentCache) =
|
proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
|
||||||
if paramCount() == 0:
|
if paramCount() == 0:
|
||||||
writeCommandLineUsage()
|
writeCommandLineUsage()
|
||||||
else:
|
else:
|
||||||
|
|
@ -59,22 +59,22 @@ proc handleCmdLine(cache: IdentCache) =
|
||||||
gProjectName = p.name
|
gProjectName = p.name
|
||||||
else:
|
else:
|
||||||
gProjectPath = canonicalizePath getCurrentDir()
|
gProjectPath = canonicalizePath getCurrentDir()
|
||||||
loadConfigs(DefaultConfig) # load all config files
|
loadConfigs(DefaultConfig, config) # load all config files
|
||||||
let scriptFile = gProjectFull.changeFileExt("nims")
|
let scriptFile = gProjectFull.changeFileExt("nims")
|
||||||
if fileExists(scriptFile):
|
if fileExists(scriptFile):
|
||||||
runNimScript(cache, scriptFile, freshDefines=false)
|
runNimScript(cache, scriptFile, freshDefines=false, config)
|
||||||
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
|
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
|
||||||
if scriptFile == gProjectFull: return
|
if scriptFile == gProjectFull: return
|
||||||
elif fileExists(gProjectPath / "config.nims"):
|
elif fileExists(gProjectPath / "config.nims"):
|
||||||
# directory wide NimScript file
|
# directory wide NimScript file
|
||||||
runNimScript(cache, gProjectPath / "config.nims", freshDefines=false)
|
runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config)
|
||||||
# now process command line arguments again, because some options in the
|
# now process command line arguments again, because some options in the
|
||||||
# command line can overwite the config file's settings
|
# command line can overwite the config file's settings
|
||||||
extccomp.initVars()
|
extccomp.initVars()
|
||||||
processCmdLine(passCmd2, "")
|
processCmdLine(passCmd2, "")
|
||||||
if options.command == "":
|
if options.command == "":
|
||||||
rawMessage(errNoCommand, command)
|
rawMessage(errNoCommand, command)
|
||||||
mainCommand(newModuleGraph(), cache)
|
mainCommand(newModuleGraph(config), cache)
|
||||||
if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
|
if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
|
||||||
#echo(GC_getStatistics())
|
#echo(GC_getStatistics())
|
||||||
if msgs.gErrorCounter == 0:
|
if msgs.gErrorCounter == 0:
|
||||||
|
|
@ -118,5 +118,5 @@ when compileOption("gc", "v2") or compileOption("gc", "refc"):
|
||||||
condsyms.initDefines()
|
condsyms.initDefines()
|
||||||
|
|
||||||
when not defined(selftest):
|
when not defined(selftest):
|
||||||
handleCmdLine(newIdentCache())
|
handleCmdLine(newIdentCache(), newConfigRef())
|
||||||
msgQuit(int8(msgs.gErrorCounter > 0))
|
msgQuit(int8(msgs.gErrorCounter > 0))
|
||||||
|
|
|
||||||
|
|
@ -21,37 +21,37 @@ proc ppGetTok(L: var TLexer, tok: var TToken) =
|
||||||
rawGetTok(L, tok)
|
rawGetTok(L, tok)
|
||||||
while tok.tokType in {tkComment}: rawGetTok(L, tok)
|
while tok.tokType in {tkComment}: rawGetTok(L, tok)
|
||||||
|
|
||||||
proc parseExpr(L: var TLexer, tok: var TToken): bool
|
proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool
|
||||||
proc parseAtom(L: var TLexer, tok: var TToken): bool =
|
proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
|
||||||
if tok.tokType == tkParLe:
|
if tok.tokType == tkParLe:
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
result = parseExpr(L, tok)
|
result = parseExpr(L, tok, config)
|
||||||
if tok.tokType == tkParRi: ppGetTok(L, tok)
|
if tok.tokType == tkParRi: ppGetTok(L, tok)
|
||||||
else: lexMessage(L, errTokenExpected, "\')\'")
|
else: lexMessage(L, errTokenExpected, "\')\'")
|
||||||
elif tok.ident.id == ord(wNot):
|
elif tok.ident.id == ord(wNot):
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
result = not parseAtom(L, tok)
|
result = not parseAtom(L, tok, config)
|
||||||
else:
|
else:
|
||||||
result = isDefined(tok.ident)
|
result = isDefined(tok.ident)
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
|
|
||||||
proc parseAndExpr(L: var TLexer, tok: var TToken): bool =
|
proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
|
||||||
result = parseAtom(L, tok)
|
result = parseAtom(L, tok, config)
|
||||||
while tok.ident.id == ord(wAnd):
|
while tok.ident.id == ord(wAnd):
|
||||||
ppGetTok(L, tok) # skip "and"
|
ppGetTok(L, tok) # skip "and"
|
||||||
var b = parseAtom(L, tok)
|
var b = parseAtom(L, tok, config)
|
||||||
result = result and b
|
result = result and b
|
||||||
|
|
||||||
proc parseExpr(L: var TLexer, tok: var TToken): bool =
|
proc parseExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
|
||||||
result = parseAndExpr(L, tok)
|
result = parseAndExpr(L, tok, config)
|
||||||
while tok.ident.id == ord(wOr):
|
while tok.ident.id == ord(wOr):
|
||||||
ppGetTok(L, tok) # skip "or"
|
ppGetTok(L, tok) # skip "or"
|
||||||
var b = parseAndExpr(L, tok)
|
var b = parseAndExpr(L, tok, config)
|
||||||
result = result or b
|
result = result or b
|
||||||
|
|
||||||
proc evalppIf(L: var TLexer, tok: var TToken): bool =
|
proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
|
||||||
ppGetTok(L, tok) # skip 'if' or 'elif'
|
ppGetTok(L, tok) # skip 'if' or 'elif'
|
||||||
result = parseExpr(L, tok)
|
result = parseExpr(L, tok, config)
|
||||||
if tok.tokType == tkColon: ppGetTok(L, tok)
|
if tok.tokType == tkColon: ppGetTok(L, tok)
|
||||||
else: lexMessage(L, errTokenExpected, "\':\'")
|
else: lexMessage(L, errTokenExpected, "\':\'")
|
||||||
|
|
||||||
|
|
@ -66,20 +66,20 @@ type
|
||||||
TJumpDest = enum
|
TJumpDest = enum
|
||||||
jdEndif, jdElseEndif
|
jdEndif, jdElseEndif
|
||||||
|
|
||||||
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest)
|
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef)
|
||||||
proc doElse(L: var TLexer, tok: var TToken) =
|
proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
if tok.tokType == tkColon: ppGetTok(L, tok)
|
if tok.tokType == tkColon: ppGetTok(L, tok)
|
||||||
if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif)
|
if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config)
|
||||||
|
|
||||||
proc doElif(L: var TLexer, tok: var TToken) =
|
proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||||
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
|
||||||
var res = evalppIf(L, tok)
|
var res = evalppIf(L, tok, config)
|
||||||
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif)
|
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config)
|
||||||
else: condStack[high(condStack)] = true
|
else: condStack[high(condStack)] = true
|
||||||
|
|
||||||
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
|
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef) =
|
||||||
var nestedIfs = 0
|
var nestedIfs = 0
|
||||||
while true:
|
while true:
|
||||||
if tok.ident != nil and tok.ident.s == "@":
|
if tok.ident != nil and tok.ident.s == "@":
|
||||||
|
|
@ -89,11 +89,11 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
|
||||||
inc(nestedIfs)
|
inc(nestedIfs)
|
||||||
of wElse:
|
of wElse:
|
||||||
if dest == jdElseEndif and nestedIfs == 0:
|
if dest == jdElseEndif and nestedIfs == 0:
|
||||||
doElse(L, tok)
|
doElse(L, tok, config)
|
||||||
break
|
break
|
||||||
of wElif:
|
of wElif:
|
||||||
if dest == jdElseEndif and nestedIfs == 0:
|
if dest == jdElseEndif and nestedIfs == 0:
|
||||||
doElif(L, tok)
|
doElif(L, tok, config)
|
||||||
break
|
break
|
||||||
of wEnd:
|
of wEnd:
|
||||||
if nestedIfs == 0:
|
if nestedIfs == 0:
|
||||||
|
|
@ -108,16 +108,16 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
|
||||||
else:
|
else:
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
|
|
||||||
proc parseDirective(L: var TLexer, tok: var TToken) =
|
proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||||
ppGetTok(L, tok) # skip @
|
ppGetTok(L, tok) # skip @
|
||||||
case whichKeyword(tok.ident)
|
case whichKeyword(tok.ident)
|
||||||
of wIf:
|
of wIf:
|
||||||
setLen(condStack, len(condStack) + 1)
|
setLen(condStack, len(condStack) + 1)
|
||||||
let res = evalppIf(L, tok)
|
let res = evalppIf(L, tok, config)
|
||||||
condStack[high(condStack)] = res
|
condStack[high(condStack)] = res
|
||||||
if not res: jumpToDirective(L, tok, jdElseEndif)
|
if not res: jumpToDirective(L, tok, jdElseEndif, config)
|
||||||
of wElif: doElif(L, tok)
|
of wElif: doElif(L, tok, config)
|
||||||
of wElse: doElse(L, tok)
|
of wElse: doElse(L, tok, config)
|
||||||
of wEnd: doEnd(L, tok)
|
of wEnd: doEnd(L, tok)
|
||||||
of wWrite:
|
of wWrite:
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
|
|
@ -146,58 +146,58 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
|
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
|
||||||
|
|
||||||
proc confTok(L: var TLexer, tok: var TToken) =
|
proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||||
ppGetTok(L, tok)
|
ppGetTok(L, tok)
|
||||||
while tok.ident != nil and tok.ident.s == "@":
|
while tok.ident != nil and tok.ident.s == "@":
|
||||||
parseDirective(L, tok) # else: give the token to the parser
|
parseDirective(L, tok, config) # else: give the token to the parser
|
||||||
|
|
||||||
proc checkSymbol(L: TLexer, tok: TToken) =
|
proc checkSymbol(L: TLexer, tok: TToken) =
|
||||||
if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}:
|
if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}:
|
||||||
lexMessage(L, errIdentifierExpected, tokToStr(tok))
|
lexMessage(L, errIdentifierExpected, tokToStr(tok))
|
||||||
|
|
||||||
proc parseAssignment(L: var TLexer, tok: var TToken) =
|
proc parseAssignment(L: var TLexer, tok: var TToken; config: ConfigRef) =
|
||||||
if tok.ident.s == "-" or tok.ident.s == "--":
|
if tok.ident.s == "-" or tok.ident.s == "--":
|
||||||
confTok(L, tok) # skip unnecessary prefix
|
confTok(L, tok, config) # skip unnecessary prefix
|
||||||
var info = getLineInfo(L, tok) # save for later in case of an error
|
var info = getLineInfo(L, tok) # save for later in case of an error
|
||||||
checkSymbol(L, tok)
|
checkSymbol(L, tok)
|
||||||
var s = tokToStr(tok)
|
var s = tokToStr(tok)
|
||||||
confTok(L, tok) # skip symbol
|
confTok(L, tok, config) # skip symbol
|
||||||
var val = ""
|
var val = ""
|
||||||
while tok.tokType == tkDot:
|
while tok.tokType == tkDot:
|
||||||
add(s, '.')
|
add(s, '.')
|
||||||
confTok(L, tok)
|
confTok(L, tok, config)
|
||||||
checkSymbol(L, tok)
|
checkSymbol(L, tok)
|
||||||
add(s, tokToStr(tok))
|
add(s, tokToStr(tok))
|
||||||
confTok(L, tok)
|
confTok(L, tok, config)
|
||||||
if tok.tokType == tkBracketLe:
|
if tok.tokType == tkBracketLe:
|
||||||
# BUGFIX: val, not s!
|
# BUGFIX: val, not s!
|
||||||
# BUGFIX: do not copy '['!
|
# BUGFIX: do not copy '['!
|
||||||
confTok(L, tok)
|
confTok(L, tok, config)
|
||||||
checkSymbol(L, tok)
|
checkSymbol(L, tok)
|
||||||
add(val, tokToStr(tok))
|
add(val, tokToStr(tok))
|
||||||
confTok(L, tok)
|
confTok(L, tok, config)
|
||||||
if tok.tokType == tkBracketRi: confTok(L, tok)
|
if tok.tokType == tkBracketRi: confTok(L, tok, config)
|
||||||
else: lexMessage(L, errTokenExpected, "']'")
|
else: lexMessage(L, errTokenExpected, "']'")
|
||||||
add(val, ']')
|
add(val, ']')
|
||||||
let percent = tok.ident != nil and tok.ident.s == "%="
|
let percent = tok.ident != nil and tok.ident.s == "%="
|
||||||
if tok.tokType in {tkColon, tkEquals} or percent:
|
if tok.tokType in {tkColon, tkEquals} or percent:
|
||||||
if len(val) > 0: add(val, ':')
|
if len(val) > 0: add(val, ':')
|
||||||
confTok(L, tok) # skip ':' or '=' or '%'
|
confTok(L, tok, config) # skip ':' or '=' or '%'
|
||||||
checkSymbol(L, tok)
|
checkSymbol(L, tok)
|
||||||
add(val, tokToStr(tok))
|
add(val, tokToStr(tok))
|
||||||
confTok(L, tok) # skip symbol
|
confTok(L, tok, config) # skip symbol
|
||||||
while tok.ident != nil and tok.ident.s == "&":
|
while tok.ident != nil and tok.ident.s == "&":
|
||||||
confTok(L, tok)
|
confTok(L, tok, config)
|
||||||
checkSymbol(L, tok)
|
checkSymbol(L, tok)
|
||||||
add(val, tokToStr(tok))
|
add(val, tokToStr(tok))
|
||||||
confTok(L, tok)
|
confTok(L, tok, config)
|
||||||
if percent:
|
if percent:
|
||||||
processSwitch(s, strtabs.`%`(val, options.gConfigVars,
|
processSwitch(s, strtabs.`%`(val, options.gConfigVars,
|
||||||
{useEnvironment, useEmpty}), passPP, info)
|
{useEnvironment, useEmpty}), passPP, info, config)
|
||||||
else:
|
else:
|
||||||
processSwitch(s, val, passPP, info)
|
processSwitch(s, val, passPP, info, config)
|
||||||
|
|
||||||
proc readConfigFile(filename: string; cache: IdentCache) =
|
proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) =
|
||||||
var
|
var
|
||||||
L: TLexer
|
L: TLexer
|
||||||
tok: TToken
|
tok: TToken
|
||||||
|
|
@ -207,8 +207,8 @@ proc readConfigFile(filename: string; cache: IdentCache) =
|
||||||
initToken(tok)
|
initToken(tok)
|
||||||
openLexer(L, filename, stream, cache)
|
openLexer(L, filename, stream, cache)
|
||||||
tok.tokType = tkEof # to avoid a pointless warning
|
tok.tokType = tkEof # to avoid a pointless warning
|
||||||
confTok(L, tok) # read in the first token
|
confTok(L, tok, config) # read in the first token
|
||||||
while tok.tokType != tkEof: parseAssignment(L, tok)
|
while tok.tokType != tkEof: parseAssignment(L, tok, config)
|
||||||
if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
|
if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
|
||||||
closeLexer(L)
|
closeLexer(L)
|
||||||
rawMessage(hintConf, filename)
|
rawMessage(hintConf, filename)
|
||||||
|
|
@ -225,22 +225,22 @@ proc getSystemConfigPath(filename: string): string =
|
||||||
if not existsFile(result): result = joinPath([p, "etc", filename])
|
if not existsFile(result): result = joinPath([p, "etc", filename])
|
||||||
if not existsFile(result): result = "/etc/" & filename
|
if not existsFile(result): result = "/etc/" & filename
|
||||||
|
|
||||||
proc loadConfigs*(cfg: string; cache: IdentCache) =
|
proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) =
|
||||||
setDefaultLibpath()
|
setDefaultLibpath()
|
||||||
|
|
||||||
if optSkipConfigFile notin gGlobalOptions:
|
if optSkipConfigFile notin gGlobalOptions:
|
||||||
readConfigFile(getSystemConfigPath(cfg), cache)
|
readConfigFile(getSystemConfigPath(cfg), cache, config)
|
||||||
|
|
||||||
if optSkipUserConfigFile notin gGlobalOptions:
|
if optSkipUserConfigFile notin gGlobalOptions:
|
||||||
readConfigFile(getUserConfigPath(cfg), cache)
|
readConfigFile(getUserConfigPath(cfg), cache, config)
|
||||||
|
|
||||||
var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir()
|
var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir()
|
||||||
if optSkipParentConfigFiles notin gGlobalOptions:
|
if optSkipParentConfigFiles notin gGlobalOptions:
|
||||||
for dir in parentDirs(pd, fromRoot=true, inclusive=false):
|
for dir in parentDirs(pd, fromRoot=true, inclusive=false):
|
||||||
readConfigFile(dir / cfg, cache)
|
readConfigFile(dir / cfg, cache, config)
|
||||||
|
|
||||||
if optSkipProjConfigFile notin gGlobalOptions:
|
if optSkipProjConfigFile notin gGlobalOptions:
|
||||||
readConfigFile(pd / cfg, cache)
|
readConfigFile(pd / cfg, cache, config)
|
||||||
|
|
||||||
if gProjectName.len != 0:
|
if gProjectName.len != 0:
|
||||||
# new project wide config file:
|
# new project wide config file:
|
||||||
|
|
@ -251,8 +251,8 @@ proc loadConfigs*(cfg: string; cache: IdentCache) =
|
||||||
projectConfig = changeFileExt(gProjectFull, "nimrod.cfg")
|
projectConfig = changeFileExt(gProjectFull, "nimrod.cfg")
|
||||||
if fileExists(projectConfig):
|
if fileExists(projectConfig):
|
||||||
rawMessage(warnDeprecated, projectConfig)
|
rawMessage(warnDeprecated, projectConfig)
|
||||||
readConfigFile(projectConfig, cache)
|
readConfigFile(projectConfig, cache, config)
|
||||||
|
|
||||||
proc loadConfigs*(cfg: string) =
|
proc loadConfigs*(cfg: string; config: ConfigRef = nil) =
|
||||||
# for backwards compatibility only.
|
# for backwards compatibility only.
|
||||||
loadConfigs(cfg, newIdentCache())
|
loadConfigs(cfg, newIdentCache(), config)
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,17 @@ type
|
||||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
|
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
|
||||||
ideHighlight, ideOutline
|
ideHighlight, ideOutline
|
||||||
|
|
||||||
|
ConfigRef* = ref object ## eventually all global configuration should be moved here
|
||||||
|
cppDefines*: HashSet[string]
|
||||||
|
headerFile*: string
|
||||||
|
|
||||||
|
proc newConfigRef*(): ConfigRef =
|
||||||
|
result = ConfigRef(cppDefines: initSet[string](),
|
||||||
|
headerFile: "")
|
||||||
|
|
||||||
|
proc cppDefine*(c: ConfigRef; define: string) =
|
||||||
|
c.cppDefines.incl define
|
||||||
|
|
||||||
var
|
var
|
||||||
gIdeCmd*: IdeCmd
|
gIdeCmd*: IdeCmd
|
||||||
|
|
||||||
|
|
@ -122,7 +133,7 @@ var
|
||||||
outFile*: string = ""
|
outFile*: string = ""
|
||||||
docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \
|
docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \
|
||||||
# The string uses the formatting variables `path` and `line`.
|
# The string uses the formatting variables `path` and `line`.
|
||||||
headerFile*: string = ""
|
#headerFile*: string = ""
|
||||||
gVerbosity* = 1 # how verbose the compiler is
|
gVerbosity* = 1 # how verbose the compiler is
|
||||||
gNumberOfProcessors*: int # number of processors
|
gNumberOfProcessors*: int # number of processors
|
||||||
gWholeProject*: bool # for 'doc2': output any dependency
|
gWholeProject*: bool # for 'doc2': output any dependency
|
||||||
|
|
|
||||||
|
|
@ -665,9 +665,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
of wExportc:
|
of wExportc:
|
||||||
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
|
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||||
incl(sym.flags, sfUsed) # avoid wrong hints
|
incl(sym.flags, sfUsed) # avoid wrong hints
|
||||||
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"), it.info)
|
of wImportc:
|
||||||
|
let name = getOptionalStr(c, it, "$1")
|
||||||
|
cppDefine(c.graph.config, name)
|
||||||
|
makeExternImport(sym, name, it.info)
|
||||||
of wImportCompilerProc:
|
of wImportCompilerProc:
|
||||||
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info)
|
let name = getOptionalStr(c, it, "$1")
|
||||||
|
cppDefine(c.graph.config, name)
|
||||||
|
processImportCompilerProc(sym, name, it.info)
|
||||||
of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
|
of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
|
||||||
of wImmediate:
|
of wImmediate:
|
||||||
if sym.kind in {skTemplate, skMacro}:
|
if sym.kind in {skTemplate, skMacro}:
|
||||||
|
|
@ -758,6 +763,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
processDynLib(c, it, sym)
|
processDynLib(c, it, sym)
|
||||||
of wCompilerproc:
|
of wCompilerproc:
|
||||||
noVal(it) # compilerproc may not get a string!
|
noVal(it) # compilerproc may not get a string!
|
||||||
|
cppDefine(c.graph.config, sym.name.s)
|
||||||
if sfFromGeneric notin sym.flags: markCompilerProc(sym)
|
if sfFromGeneric notin sym.flags: markCompilerProc(sym)
|
||||||
of wProcVar:
|
of wProcVar:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) =
|
||||||
if kind in filter: result.add path
|
if kind in filter: result.add path
|
||||||
setResult(a, result)
|
setResult(a, result)
|
||||||
|
|
||||||
proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext =
|
proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
||||||
|
config: ConfigRef = nil): PEvalContext =
|
||||||
# For Nimble we need to export 'setupVM'.
|
# For Nimble we need to export 'setupVM'.
|
||||||
result = newCtx(module, cache)
|
result = newCtx(module, cache)
|
||||||
result.mode = emRepl
|
result.mode = emRepl
|
||||||
|
|
@ -109,10 +110,13 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext
|
||||||
let arg = a.getString 1
|
let arg = a.getString 1
|
||||||
if arg.len > 0:
|
if arg.len > 0:
|
||||||
gProjectName = arg
|
gProjectName = arg
|
||||||
|
let path =
|
||||||
|
if gProjectName.isAbsolute: gProjectName
|
||||||
|
else: gProjectPath / gProjectName
|
||||||
try:
|
try:
|
||||||
gProjectFull = canonicalizePath(gProjectPath / gProjectName)
|
gProjectFull = canonicalizePath(path)
|
||||||
except OSError:
|
except OSError:
|
||||||
gProjectFull = gProjectName
|
gProjectFull = path
|
||||||
cbconf getCommand:
|
cbconf getCommand:
|
||||||
setResult(a, options.command)
|
setResult(a, options.command)
|
||||||
cbconf switch:
|
cbconf switch:
|
||||||
|
|
@ -133,12 +137,15 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext
|
||||||
gModuleOverrides[key] = val
|
gModuleOverrides[key] = val
|
||||||
cbconf selfExe:
|
cbconf selfExe:
|
||||||
setResult(a, os.getAppFilename())
|
setResult(a, os.getAppFilename())
|
||||||
|
cbconf cppDefine:
|
||||||
|
if config != nil:
|
||||||
|
options.cppDefine(config, a.getString(0))
|
||||||
|
|
||||||
proc runNimScript*(cache: IdentCache; scriptName: string;
|
proc runNimScript*(cache: IdentCache; scriptName: string;
|
||||||
freshDefines=true) =
|
freshDefines=true; config: ConfigRef=nil) =
|
||||||
passes.gIncludeFile = includeModule
|
passes.gIncludeFile = includeModule
|
||||||
passes.gImportModule = importModule
|
passes.gImportModule = importModule
|
||||||
let graph = newModuleGraph()
|
let graph = newModuleGraph(config)
|
||||||
if freshDefines: initDefines()
|
if freshDefines: initDefines()
|
||||||
|
|
||||||
defineSymbol("nimscript")
|
defineSymbol("nimscript")
|
||||||
|
|
@ -150,7 +157,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string;
|
||||||
|
|
||||||
var m = graph.makeModule(scriptName)
|
var m = graph.makeModule(scriptName)
|
||||||
incl(m.flags, sfMainModule)
|
incl(m.flags, sfMainModule)
|
||||||
vm.globalCtx = setupVM(m, cache, scriptName)
|
vm.globalCtx = setupVM(m, cache, scriptName, config)
|
||||||
|
|
||||||
graph.compileSystemModule(cache)
|
graph.compileSystemModule(cache)
|
||||||
discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)
|
discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)
|
||||||
|
|
|
||||||
|
|
@ -1052,6 +1052,8 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# work without now. template/tsymchoicefield doesn't like an early exit
|
# work without now. template/tsymchoicefield doesn't like an early exit
|
||||||
# here at all!
|
# here at all!
|
||||||
#if isSymChoice(n.sons[1]): return
|
#if isSymChoice(n.sons[1]): return
|
||||||
|
when defined(nimsuggest):
|
||||||
|
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||||
|
|
||||||
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule})
|
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared, checkModule})
|
||||||
if s != nil:
|
if s != nil:
|
||||||
|
|
|
||||||
|
|
@ -97,10 +97,17 @@ proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
|
||||||
if inst.compilesId == id and sameInstantiation(entry, inst[]):
|
if inst.compilesId == id and sameInstantiation(entry, inst[]):
|
||||||
return inst.sym
|
return inst.sym
|
||||||
|
|
||||||
|
when false:
|
||||||
|
proc `$`(x: PSym): string =
|
||||||
|
result = x.name.s & " " & " id " & $x.id
|
||||||
|
|
||||||
proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
|
proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
|
||||||
# we need to create a fresh set of gensym'ed symbols:
|
# we need to create a fresh set of gensym'ed symbols:
|
||||||
if n.kind == nkSym and sfGenSym in n.sym.flags and
|
#if n.kind == nkSym and sfGenSym in n.sym.flags:
|
||||||
(n.sym.owner == orig or n.sym.owner.kind == skPackage):
|
# if n.sym.owner != orig:
|
||||||
|
# echo "symbol ", n.sym.name.s, " orig ", orig, " owner ", n.sym.owner
|
||||||
|
if n.kind == nkSym and {sfGenSym, sfFromGeneric} * n.sym.flags == {sfGenSym}: # and
|
||||||
|
# (n.sym.owner == orig or n.sym.owner.kind in {skPackage}):
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
var x = PSym(idTableGet(symMap, s))
|
var x = PSym(idTableGet(symMap, s))
|
||||||
if x == nil:
|
if x == nil:
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,7 @@ type
|
||||||
toBind, toMixin, toInject: IntSet
|
toBind, toMixin, toInject: IntSet
|
||||||
owner: PSym
|
owner: PSym
|
||||||
cursorInBody: bool # only for nimsuggest
|
cursorInBody: bool # only for nimsuggest
|
||||||
|
scopeN: int
|
||||||
bracketExpr: PNode
|
bracketExpr: PNode
|
||||||
|
|
||||||
template withBracketExpr(ctx, x, body: untyped) =
|
template withBracketExpr(ctx, x, body: untyped) =
|
||||||
|
|
@ -141,8 +142,13 @@ proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
|
||||||
|
|
||||||
proc semTemplBody(c: var TemplCtx, n: PNode): PNode
|
proc semTemplBody(c: var TemplCtx, n: PNode): PNode
|
||||||
|
|
||||||
proc openScope(c: var TemplCtx) = openScope(c.c)
|
proc openScope(c: var TemplCtx) =
|
||||||
proc closeScope(c: var TemplCtx) = closeScope(c.c)
|
openScope(c.c)
|
||||||
|
inc c.scopeN
|
||||||
|
|
||||||
|
proc closeScope(c: var TemplCtx) =
|
||||||
|
dec c.scopeN
|
||||||
|
closeScope(c.c)
|
||||||
|
|
||||||
proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
|
proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -166,6 +172,7 @@ proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
|
||||||
result = newSym(kind, considerQuotedIdent(n), c.owner, n.info)
|
result = newSym(kind, considerQuotedIdent(n), c.owner, n.info)
|
||||||
incl(result.flags, sfGenSym)
|
incl(result.flags, sfGenSym)
|
||||||
incl(result.flags, sfShadowed)
|
incl(result.flags, sfShadowed)
|
||||||
|
if c.scopeN == 0: incl(result.flags, sfFromGeneric)
|
||||||
|
|
||||||
proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
||||||
# locals default to 'gensym':
|
# locals default to 'gensym':
|
||||||
|
|
|
||||||
|
|
@ -659,7 +659,8 @@ proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||||
addInheritedFieldsAux(c, check, pos, obj.n)
|
addInheritedFieldsAux(c, check, pos, obj.n)
|
||||||
|
|
||||||
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if n.sonsLen == 0: return newConstraint(c, tyObject)
|
if n.sonsLen == 0:
|
||||||
|
return newConstraint(c, tyObject)
|
||||||
var check = initIntSet()
|
var check = initIntSet()
|
||||||
var pos = 0
|
var pos = 0
|
||||||
var base, realBase: PType = nil
|
var base, realBase: PType = nil
|
||||||
|
|
@ -1159,8 +1160,16 @@ proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
|
||||||
result.sym = prev.sym
|
result.sym = prev.sym
|
||||||
assignType(prev, result)
|
assignType(prev, result)
|
||||||
|
|
||||||
|
proc fixupTypeOf(c: PContext, prev: PType, typExpr: PNode) =
|
||||||
|
if prev != nil:
|
||||||
|
let result = newTypeS(tyAlias, c)
|
||||||
|
result.rawAddSon typExpr.typ
|
||||||
|
result.sym = prev.sym
|
||||||
|
assignType(prev, result)
|
||||||
|
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkEmpty: discard
|
of nkEmpty: discard
|
||||||
|
|
@ -1168,6 +1177,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
|
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
|
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
|
||||||
|
fixupTypeOf(c, prev, typExpr)
|
||||||
result = typExpr.typ
|
result = typExpr.typ
|
||||||
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)
|
||||||
|
|
@ -1234,6 +1244,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
elif op.id == ord(wType):
|
elif op.id == ord(wType):
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
|
let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
|
||||||
|
fixupTypeOf(c, prev, typExpr)
|
||||||
result = typExpr.typ
|
result = typExpr.typ
|
||||||
else:
|
else:
|
||||||
result = semTypeExpr(c, n, prev)
|
result = semTypeExpr(c, n, prev)
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,20 @@ var
|
||||||
|
|
||||||
template origModuleName(m: PSym): string = m.name.s
|
template origModuleName(m: PSym): string = m.name.s
|
||||||
|
|
||||||
|
proc findDocComment(n: PNode): PNode =
|
||||||
|
if n == nil: return nil
|
||||||
|
if not isNil(n.comment): return n
|
||||||
|
for i in countup(0, safeLen(n)-1):
|
||||||
|
result = findDocComment(n.sons[i])
|
||||||
|
if result != nil: return
|
||||||
|
|
||||||
|
proc extractDocComment(s: PSym): string =
|
||||||
|
let n = findDocComment(s.ast)
|
||||||
|
if not n.isNil:
|
||||||
|
result = n.comment.replace("\n##", "\n").strip
|
||||||
|
else:
|
||||||
|
result = ""
|
||||||
|
|
||||||
proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo;
|
proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo;
|
||||||
quality: range[0..100]): Suggest =
|
quality: range[0..100]): Suggest =
|
||||||
result.section = parseIdeCmd(section)
|
result.section = parseIdeCmd(section)
|
||||||
|
|
|
||||||
|
|
@ -559,7 +559,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
if regs[rb].node.kind == nkRefTy:
|
if regs[rb].node.kind == nkRefTy:
|
||||||
regs[ra].node = regs[rb].node.sons[0]
|
regs[ra].node = regs[rb].node.sons[0]
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errGenerated, "limited VM support for pointers")
|
ensureKind(rkNode)
|
||||||
|
regs[ra].node = regs[rb].node
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errNilAccess)
|
stackTrace(c, tos, pc, errNilAccess)
|
||||||
of opcWrDeref:
|
of opcWrDeref:
|
||||||
|
|
@ -932,7 +933,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
c.module
|
c.module
|
||||||
var macroCall = newNodeI(nkCall, c.debug[pc])
|
var macroCall = newNodeI(nkCall, c.debug[pc])
|
||||||
macroCall.add(newSymNode(prc))
|
macroCall.add(newSymNode(prc))
|
||||||
for i in 1 .. rc-1: macroCall.add(regs[rb+i].regToNode)
|
for i in 1 .. rc-1:
|
||||||
|
let node = regs[rb+i].regToNode
|
||||||
|
node.info = c.debug[pc]
|
||||||
|
macroCall.add(node)
|
||||||
let a = evalTemplate(macroCall, prc, genSymOwner)
|
let a = evalTemplate(macroCall, prc, genSymOwner)
|
||||||
a.recSetFlagIsRef
|
a.recSetFlagIsRef
|
||||||
ensureKind(rkNode)
|
ensureKind(rkNode)
|
||||||
|
|
|
||||||
|
|
@ -1259,6 +1259,13 @@ proc isTemp(c: PCtx; dest: TDest): bool =
|
||||||
template needsAdditionalCopy(n): untyped =
|
template needsAdditionalCopy(n): untyped =
|
||||||
not c.isTemp(dest) and not fitsRegister(n.typ)
|
not c.isTemp(dest) and not fitsRegister(n.typ)
|
||||||
|
|
||||||
|
proc genAdditionalCopy(c: PCtx; n: PNode; opc: TOpcode;
|
||||||
|
dest, idx, value: TRegister) =
|
||||||
|
var cc = c.getTemp(n.typ)
|
||||||
|
c.gABC(n, whichAsgnOpc(n), cc, value, 0)
|
||||||
|
c.gABC(n, opc, dest, idx, cc)
|
||||||
|
c.freeTemp(cc)
|
||||||
|
|
||||||
proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
|
proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
|
||||||
dest, idx, value: TRegister) =
|
dest, idx, value: TRegister) =
|
||||||
# opcLdObj et al really means "load address". We sometimes have to create a
|
# opcLdObj et al really means "load address". We sometimes have to create a
|
||||||
|
|
@ -1266,10 +1273,7 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
|
||||||
# mylocal = a.b # needs a copy of the data!
|
# mylocal = a.b # needs a copy of the data!
|
||||||
assert n.typ != nil
|
assert n.typ != nil
|
||||||
if needsAdditionalCopy(n):
|
if needsAdditionalCopy(n):
|
||||||
var cc = c.getTemp(n.typ)
|
genAdditionalCopy(c, n, opc, dest, idx, value)
|
||||||
c.gABC(n, whichAsgnOpc(n), cc, value, 0)
|
|
||||||
c.gABC(n, opc, dest, idx, cc)
|
|
||||||
c.freeTemp(cc)
|
|
||||||
else:
|
else:
|
||||||
c.gABC(n, opc, dest, idx, value)
|
c.gABC(n, opc, dest, idx, value)
|
||||||
|
|
||||||
|
|
@ -1352,7 +1356,7 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
|
||||||
c.gABx(n, opcLdGlobal, dest, s.position)
|
c.gABx(n, opcLdGlobal, dest, s.position)
|
||||||
if s.ast != nil:
|
if s.ast != nil:
|
||||||
let tmp = c.genx(s.ast)
|
let tmp = c.genx(s.ast)
|
||||||
c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp)
|
c.genAdditionalCopy(n, opcWrDeref, dest, 0, tmp)
|
||||||
c.freeTemp(dest)
|
c.freeTemp(dest)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
|
|
@ -1506,7 +1510,7 @@ proc genVarSection(c: PCtx; n: PNode) =
|
||||||
#assert(a.sons[0].kind == nkSym) can happen for transformed vars
|
#assert(a.sons[0].kind == nkSym) can happen for transformed vars
|
||||||
if a.kind == nkVarTuple:
|
if a.kind == nkVarTuple:
|
||||||
for i in 0 .. a.len-3:
|
for i in 0 .. a.len-3:
|
||||||
setSlot(c, a[i].sym)
|
if not a[i].sym.isGlobal: setSlot(c, a[i].sym)
|
||||||
checkCanEval(c, a[i])
|
checkCanEval(c, a[i])
|
||||||
c.gen(lowerTupleUnpacking(a, c.getOwner))
|
c.gen(lowerTupleUnpacking(a, c.getOwner))
|
||||||
elif a.sons[0].kind == nkSym:
|
elif a.sons[0].kind == nkSym:
|
||||||
|
|
@ -1525,7 +1529,7 @@ proc genVarSection(c: PCtx; n: PNode) =
|
||||||
if a.sons[2].kind != nkEmpty:
|
if a.sons[2].kind != nkEmpty:
|
||||||
let tmp = c.genx(a.sons[0], {gfAddrOf})
|
let tmp = c.genx(a.sons[0], {gfAddrOf})
|
||||||
let val = c.genx(a.sons[2])
|
let val = c.genx(a.sons[2])
|
||||||
c.preventFalseAlias(a.sons[2], opcWrDeref, tmp, 0, val)
|
c.genAdditionalCopy(a.sons[2], opcWrDeref, tmp, 0, val)
|
||||||
c.freeTemp(val)
|
c.freeTemp(val)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Configuration file for the Nim Compiler.
|
# Configuration file for the Nim Compiler.
|
||||||
# (c) 2015 Andreas Rumpf
|
# (c) 2017 Andreas Rumpf
|
||||||
|
|
||||||
# Feel free to edit the default values as you need.
|
# Feel free to edit the default values as you need.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
=====================================================
|
=====================================================
|
||||||
Nim -- a Compiler for Nim. http://nim-lang.org/
|
Nim -- a Compiler for Nim. https://nim-lang.org/
|
||||||
|
|
||||||
Copyright (C) 2006-2015 Andreas Rumpf. All rights reserved.
|
Copyright (C) 2006-2017 Andreas Rumpf. All rights reserved.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ etc. Note that currently the ``deprecated`` statement does not work well with
|
||||||
overloading so for routines the latter variant is better.
|
overloading so for routines the latter variant is better.
|
||||||
|
|
||||||
|
|
||||||
`Deprecated <http://nim-lang.org/docs/manual.html#pragmas-deprecated-pragma>`_
|
`Deprecated <https://nim-lang.org/docs/manual.html#pragmas-deprecated-pragma>`_
|
||||||
pragma in the manual.
|
pragma in the manual.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ web command
|
||||||
The `web`:idx: command converts the documentation in the ``doc`` directory
|
The `web`:idx: command converts the documentation in the ``doc`` directory
|
||||||
from rst to HTML. It also repeats the same operation but places the result in
|
from rst to HTML. It also repeats the same operation but places the result in
|
||||||
the ``web/upload`` which can be used to update the website at
|
the ``web/upload`` which can be used to update the website at
|
||||||
http://nim-lang.org.
|
https://nim-lang.org.
|
||||||
|
|
||||||
By default the documentation will be built in parallel using the number of
|
By default the documentation will be built in parallel using the number of
|
||||||
available CPU cores. If any documentation build sub commands fail, they will
|
available CPU cores. If any documentation build sub commands fail, they will
|
||||||
|
|
|
||||||
|
|
@ -586,4 +586,4 @@ Nim programming language.
|
||||||
nimblepkglist.js or have javascript disabled in your browser.</b></div>
|
nimblepkglist.js or have javascript disabled in your browser.</b></div>
|
||||||
|
|
||||||
<script type="text/javascript" src="nimblepkglist.js"></script>
|
<script type="text/javascript" src="nimblepkglist.js"></script>
|
||||||
<script type="text/javascript" src="http://irclogs.nim-lang.org/packages?callback=gotPackageList" async></script>
|
<script type="text/javascript" src="https://irclogs.nim-lang.org/packages?callback=gotPackageList" async></script>
|
||||||
|
|
|
||||||
69
koch.nim
69
koch.nim
|
|
@ -70,6 +70,8 @@ Web options:
|
||||||
build the official docs, use UA-48159761-1
|
build the official docs, use UA-48159761-1
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
const gaCode = " --googleAnalytics:UA-48159761-1"
|
||||||
|
|
||||||
proc exe(f: string): string =
|
proc exe(f: string): string =
|
||||||
result = addFileExt(f, ExeExt)
|
result = addFileExt(f, ExeExt)
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -221,6 +223,8 @@ proc bundleWinTools() =
|
||||||
copyExe("tools/finish".exe, "finish".exe)
|
copyExe("tools/finish".exe, "finish".exe)
|
||||||
removeFile("tools/finish".exe)
|
removeFile("tools/finish".exe)
|
||||||
nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe")
|
nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe")
|
||||||
|
nimexec(r"c --cc:vcc --app:gui -o:bin\downloader.exe -d:ssl --noNimblePath " &
|
||||||
|
r"--path:..\ui tools\downloader.nim")
|
||||||
|
|
||||||
proc zip(args: string) =
|
proc zip(args: string) =
|
||||||
bundleNimbleSrc()
|
bundleNimbleSrc()
|
||||||
|
|
@ -319,7 +323,8 @@ proc boot(args: string) =
|
||||||
var finalDest = "bin" / "nim".exe
|
var finalDest = "bin" / "nim".exe
|
||||||
# default to use the 'c' command:
|
# default to use the 'c' command:
|
||||||
let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: ""
|
let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: ""
|
||||||
let smartNimcache = if "release" in args: "nimcache/release" else: "nimcache/debug"
|
let smartNimcache = (if "release" in args: "nimcache/r_" else: "nimcache/d_") &
|
||||||
|
hostOs & "_" & hostCpu
|
||||||
|
|
||||||
copyExe(findStartNim(), 0.thVersion)
|
copyExe(findStartNim(), 0.thVersion)
|
||||||
for i in 0..2:
|
for i in 0..2:
|
||||||
|
|
@ -380,8 +385,64 @@ proc clean(args: string) =
|
||||||
|
|
||||||
# -------------- builds a release ---------------------------------------------
|
# -------------- builds a release ---------------------------------------------
|
||||||
|
|
||||||
|
proc patchConfig(lookFor, replaceBy: string) =
|
||||||
|
const
|
||||||
|
cfgFile = "config/nim.cfg"
|
||||||
|
try:
|
||||||
|
let cfg = readFile(cfgFile)
|
||||||
|
let newCfg = cfg.replace(lookFor, replaceBy)
|
||||||
|
if newCfg == cfg:
|
||||||
|
echo "Could not patch 'config/nim.cfg' [Error]"
|
||||||
|
echo "Reason: patch substring not found:"
|
||||||
|
echo lookFor
|
||||||
|
else:
|
||||||
|
writeFile(cfgFile, newCfg)
|
||||||
|
except IOError:
|
||||||
|
quit "Could not access 'config/nim.cfg' [Error]"
|
||||||
|
|
||||||
|
proc winReleaseArch(arch: string) =
|
||||||
|
doAssert arch in ["32", "64"]
|
||||||
|
let cpu = if arch == "32": "i386" else: "amd64"
|
||||||
|
|
||||||
|
template withMingw(path, body) =
|
||||||
|
const orig = """#gcc.path = r"$nim\dist\mingw\bin""""
|
||||||
|
let replacePattern = """gcc.path = r"..\mingw$1\bin" # winrelease""" % arch
|
||||||
|
patchConfig(orig, replacePattern)
|
||||||
|
try:
|
||||||
|
body
|
||||||
|
finally:
|
||||||
|
patchConfig(replacePattern, orig)
|
||||||
|
|
||||||
|
withMingw r"..\mingw" & arch & r"\bin":
|
||||||
|
# Rebuilding koch is necessary because it uses its pointer size to
|
||||||
|
# determine which mingw link to put in the NSIS installer.
|
||||||
|
nimexec "c --out:koch_temp --cpu:$# koch" % cpu
|
||||||
|
exec "koch_temp boot -d:release --cpu:$#" % cpu
|
||||||
|
exec "koch_temp nsis -d:release"
|
||||||
|
exec "koch_temp zip -d:release"
|
||||||
|
|
||||||
|
when false:
|
||||||
|
# we now disable the NSIS installer as it cannot download from https
|
||||||
|
# and is broken in so many different ways it's not funny anymore:
|
||||||
|
moveFile r"build\nim_$#.exe" % VersionAsString,
|
||||||
|
r"web\upload\download\nim-$#_x$#.exe" % [VersionAsString, arch]
|
||||||
|
moveFile r"build\nim-$#.zip" % VersionAsString,
|
||||||
|
r"web\upload\download\nim-$#_x$#.zip" % [VersionAsString, arch]
|
||||||
|
|
||||||
proc winRelease() =
|
proc winRelease() =
|
||||||
exec(r"call ci\nsis_build.bat " & VersionAsString)
|
# Build -docs file:
|
||||||
|
when true:
|
||||||
|
web(gaCode)
|
||||||
|
withDir "web/upload/" & VersionAsString:
|
||||||
|
exec "7z a -tzip docs-$#.zip *.html" % VersionAsString
|
||||||
|
moveFile "web/upload/$1/docs-$1.zip" % VersionAsString,
|
||||||
|
"web/upload/download/docs-$1.zip" % VersionAsString
|
||||||
|
when true:
|
||||||
|
csource("-d:release")
|
||||||
|
when true:
|
||||||
|
winReleaseArch "32"
|
||||||
|
when true:
|
||||||
|
winReleaseArch "64"
|
||||||
|
|
||||||
# -------------- tests --------------------------------------------------------
|
# -------------- tests --------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -463,10 +524,10 @@ of cmdArgument:
|
||||||
of "web": web(op.cmdLineRest)
|
of "web": web(op.cmdLineRest)
|
||||||
of "doc", "docs": web("--onlyDocs " & op.cmdLineRest)
|
of "doc", "docs": web("--onlyDocs " & op.cmdLineRest)
|
||||||
of "json2": web("--json2 " & op.cmdLineRest)
|
of "json2": web("--json2 " & op.cmdLineRest)
|
||||||
of "website": website(op.cmdLineRest & " --googleAnalytics:UA-48159761-1")
|
of "website": website(op.cmdLineRest & gaCode)
|
||||||
of "web0":
|
of "web0":
|
||||||
# undocumented command for Araq-the-merciful:
|
# undocumented command for Araq-the-merciful:
|
||||||
web(op.cmdLineRest & " --googleAnalytics:UA-48159761-1")
|
web(op.cmdLineRest & gaCode)
|
||||||
of "pdf": pdf()
|
of "pdf": pdf()
|
||||||
of "csource", "csources": csource(op.cmdLineRest)
|
of "csource", "csources": csource(op.cmdLineRest)
|
||||||
of "zip": zip(op.cmdLineRest)
|
of "zip": zip(op.cmdLineRest)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,15 @@ export options
|
||||||
##
|
##
|
||||||
## A regular expression library for Nim using PCRE to do the hard work.
|
## A regular expression library for Nim using PCRE to do the hard work.
|
||||||
##
|
##
|
||||||
|
## **Note**: If you love ``sequtils.toSeq`` we have bad news for you. This
|
||||||
|
## library doesn't work with it due to documented compiler limitations. As
|
||||||
|
## a workaround, use this:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
##
|
||||||
|
## import nre except toSeq
|
||||||
|
##
|
||||||
|
##
|
||||||
## Licencing
|
## Licencing
|
||||||
## ---------
|
## ---------
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -402,16 +402,29 @@ struct TFrame {
|
||||||
NI16 calldepth;
|
NI16 calldepth;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define nimfr(proc, file) \
|
#ifdef NIM_NEW_MANGLING_RULES
|
||||||
TFrame FR; \
|
#define nimfr_(proc, file) \
|
||||||
FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = 0; nimFrame(&FR);
|
TFrame FR_; \
|
||||||
|
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; nimFrame(&FR_);
|
||||||
|
|
||||||
#define nimfrs(proc, file, slots, length) \
|
#define nimfrs_(proc, file, slots, length) \
|
||||||
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR; \
|
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR_; \
|
||||||
FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = length; nimFrame((TFrame*)&FR);
|
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; nimFrame((TFrame*)&FR_);
|
||||||
|
|
||||||
#define nimln(n, file) \
|
#define nimln_(n, file) \
|
||||||
FR.line = n; FR.filename = file;
|
FR_.line = n; FR_.filename = file;
|
||||||
|
#else
|
||||||
|
#define nimfr(proc, file) \
|
||||||
|
TFrame FR; \
|
||||||
|
FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = 0; nimFrame(&FR);
|
||||||
|
|
||||||
|
#define nimfrs(proc, file, slots, length) \
|
||||||
|
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; VarSlot s[slots];} FR; \
|
||||||
|
FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = length; nimFrame((TFrame*)&FR);
|
||||||
|
|
||||||
|
#define nimln(n, file) \
|
||||||
|
FR.line = n; FR.filename = file;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define NIM_POSIX_INIT __attribute__((constructor))
|
#define NIM_POSIX_INIT __attribute__((constructor))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -753,26 +753,6 @@ when defined(windows) or defined(nimdoc):
|
||||||
let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
||||||
let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
||||||
|
|
||||||
template completeAccept() {.dirty.} =
|
|
||||||
var listenSock = socket
|
|
||||||
let setoptRet = setsockopt(clientSock, SOL_SOCKET,
|
|
||||||
SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
|
|
||||||
sizeof(listenSock).SockLen)
|
|
||||||
if setoptRet != 0: raiseOSError(osLastError())
|
|
||||||
|
|
||||||
var localSockaddr, remoteSockaddr: ptr SockAddr
|
|
||||||
var localLen, remoteLen: int32
|
|
||||||
getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
|
|
||||||
dwLocalAddressLength, dwRemoteAddressLength,
|
|
||||||
addr localSockaddr, addr localLen,
|
|
||||||
addr remoteSockaddr, addr remoteLen)
|
|
||||||
register(clientSock.AsyncFD)
|
|
||||||
# TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
|
|
||||||
retFuture.complete(
|
|
||||||
(address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
|
|
||||||
client: clientSock.AsyncFD)
|
|
||||||
)
|
|
||||||
|
|
||||||
template failAccept(errcode) =
|
template failAccept(errcode) =
|
||||||
if flags.isDisconnectionError(errcode):
|
if flags.isDisconnectionError(errcode):
|
||||||
var newAcceptFut = acceptAddr(socket, flags)
|
var newAcceptFut = acceptAddr(socket, flags)
|
||||||
|
|
@ -785,6 +765,29 @@ when defined(windows) or defined(nimdoc):
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
||||||
|
|
||||||
|
template completeAccept() {.dirty.} =
|
||||||
|
var listenSock = socket
|
||||||
|
let setoptRet = setsockopt(clientSock, SOL_SOCKET,
|
||||||
|
SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
|
||||||
|
sizeof(listenSock).SockLen)
|
||||||
|
if setoptRet != 0:
|
||||||
|
let errcode = osLastError()
|
||||||
|
discard clientSock.closeSocket()
|
||||||
|
failAccept(errcode)
|
||||||
|
else:
|
||||||
|
var localSockaddr, remoteSockaddr: ptr SockAddr
|
||||||
|
var localLen, remoteLen: int32
|
||||||
|
getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
|
||||||
|
dwLocalAddressLength, dwRemoteAddressLength,
|
||||||
|
addr localSockaddr, addr localLen,
|
||||||
|
addr remoteSockaddr, addr remoteLen)
|
||||||
|
register(clientSock.AsyncFD)
|
||||||
|
# TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
|
||||||
|
retFuture.complete(
|
||||||
|
(address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
|
||||||
|
client: clientSock.AsyncFD)
|
||||||
|
)
|
||||||
|
|
||||||
var ol = PCustomOverlapped()
|
var ol = PCustomOverlapped()
|
||||||
GC_ref(ol)
|
GC_ref(ol)
|
||||||
ol.data = CompletionData(fd: socket, cb:
|
ol.data = CompletionData(fd: socket, cb:
|
||||||
|
|
|
||||||
|
|
@ -284,9 +284,9 @@ proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} =
|
||||||
proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||||
## This macro transforms a single procedure into a closure iterator.
|
## This macro transforms a single procedure into a closure iterator.
|
||||||
## The ``async`` macro supports a stmtList holding multiple async procedures.
|
## The ``async`` macro supports a stmtList holding multiple async procedures.
|
||||||
if prc.kind notin {nnkProcDef, nnkLambda}:
|
if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef}:
|
||||||
error("Cannot transform this node kind into an async proc." &
|
error("Cannot transform this node kind into an async proc." &
|
||||||
" Proc definition or lambda node expected.")
|
" proc/method definition or lambda node expected.")
|
||||||
|
|
||||||
hint("Processing " & prc[0].getName & " as an async proc.")
|
hint("Processing " & prc[0].getName & " as an async proc.")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -814,11 +814,14 @@ proc len*[A](t: CountTable[A]): int =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
proc clear*[A](t: var CountTable[A] | CountTableRef[A]) =
|
proc clear*[A](t: CountTableRef[A]) =
|
||||||
## Resets the table so that it is empty.
|
## Resets the table so that it is empty.
|
||||||
clearImpl()
|
clearImpl()
|
||||||
t.counter = 0
|
|
||||||
|
|
||||||
|
proc clear*[A](t: var CountTable[A]) =
|
||||||
|
## Resets the table so that it is empty.
|
||||||
|
clearImpl()
|
||||||
|
|
||||||
iterator pairs*[A](t: CountTable[A]): (A, int) =
|
iterator pairs*[A](t: CountTable[A]): (A, int) =
|
||||||
## iterates over any (key, value) pair in the table `t`.
|
## iterates over any (key, value) pair in the table `t`.
|
||||||
for h in 0..high(t.data):
|
for h in 0..high(t.data):
|
||||||
|
|
|
||||||
|
|
@ -312,3 +312,10 @@ when isMainModule:
|
||||||
test.add("Connection", "Test")
|
test.add("Connection", "Test")
|
||||||
doAssert test["Connection", 2] == "Test"
|
doAssert test["Connection", 2] == "Test"
|
||||||
doAssert "upgrade" in test["Connection"]
|
doAssert "upgrade" in test["Connection"]
|
||||||
|
|
||||||
|
# Bug #5344.
|
||||||
|
doAssert parseHeader("foobar: ") == ("foobar", @[""])
|
||||||
|
let (key, value) = parseHeader("foobar: ")
|
||||||
|
test = newHttpHeaders()
|
||||||
|
test[key] = value
|
||||||
|
doAssert test["foobar"] == ""
|
||||||
|
|
@ -165,7 +165,7 @@ proc close*(ev: SelectEvent) =
|
||||||
|
|
||||||
template checkFd(s, f) =
|
template checkFd(s, f) =
|
||||||
if f >= s.maxFD:
|
if f >= s.maxFD:
|
||||||
raiseIOSelectorsError("Maximum file descriptors exceeded")
|
raiseIOSelectorsError("Maximum number of descriptors is exhausted!")
|
||||||
|
|
||||||
proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
||||||
events: set[Event], data: T) =
|
events: set[Event], data: T) =
|
||||||
|
|
@ -188,7 +188,8 @@ proc updateHandle*[T](s: Selector[T], fd: SocketHandle, events: set[Event]) =
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
var pkey = addr(s.fds[fdi])
|
var pkey = addr(s.fds[fdi])
|
||||||
doAssert(pkey.ident != 0)
|
doAssert(pkey.ident != 0,
|
||||||
|
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||||
doAssert(pkey.events * maskEvents == {})
|
doAssert(pkey.events * maskEvents == {})
|
||||||
if pkey.events != events:
|
if pkey.events != events:
|
||||||
var epv = epoll_event(events: EPOLLRDHUP)
|
var epv = epoll_event(events: EPOLLRDHUP)
|
||||||
|
|
@ -215,8 +216,8 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
var pkey = addr(s.fds[fdi])
|
var pkey = addr(s.fds[fdi])
|
||||||
doAssert(pkey.ident != 0)
|
doAssert(pkey.ident != 0,
|
||||||
|
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||||
if pkey.events != {}:
|
if pkey.events != {}:
|
||||||
when not defined(android):
|
when not defined(android):
|
||||||
if pkey.events * {Event.Read, Event.Write} != {}:
|
if pkey.events * {Event.Read, Event.Write} != {}:
|
||||||
|
|
@ -277,7 +278,7 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) =
|
||||||
let fdi = int(ev.efd)
|
let fdi = int(ev.efd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
var pkey = addr(s.fds[fdi])
|
var pkey = addr(s.fds[fdi])
|
||||||
doAssert(pkey.ident != 0)
|
doAssert(pkey.ident != 0, "Event is not registered in the queue!")
|
||||||
doAssert(Event.User in pkey.events)
|
doAssert(Event.User in pkey.events)
|
||||||
var epv = epoll_event()
|
var epv = epoll_event()
|
||||||
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
|
if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fdi.cint, addr epv) != 0:
|
||||||
|
|
@ -380,7 +381,7 @@ when not defined(android):
|
||||||
|
|
||||||
proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
||||||
let fdi = int(ev.efd)
|
let fdi = int(ev.efd)
|
||||||
doAssert(s.fds[fdi].ident == 0)
|
doAssert(s.fds[fdi].ident == 0, "Event is already registered in the queue!")
|
||||||
s.setKey(fdi, {Event.User}, 0, data)
|
s.setKey(fdi, {Event.User}, 0, data)
|
||||||
var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP)
|
var epv = epoll_event(events: EPOLLIN or EPOLLRDHUP)
|
||||||
epv.data.u64 = ev.efd.uint
|
epv.data.u64 = ev.efd.uint
|
||||||
|
|
|
||||||
|
|
@ -119,12 +119,13 @@ proc newSelector*[T](): Selector[T] =
|
||||||
result.maxFD = maxFD.int
|
result.maxFD = maxFD.int
|
||||||
|
|
||||||
proc close*[T](s: Selector[T]) =
|
proc close*[T](s: Selector[T]) =
|
||||||
let res = posix.close(s.kqFD)
|
let res1 = posix.close(s.kqFD)
|
||||||
|
let res2 = posix.close(s.sock)
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
deinitLock(s.changesLock)
|
deinitLock(s.changesLock)
|
||||||
deallocSharedArray(s.fds)
|
deallocSharedArray(s.fds)
|
||||||
deallocShared(cast[pointer](s))
|
deallocShared(cast[pointer](s))
|
||||||
if res != 0:
|
if res1 != 0 or res2 != 0:
|
||||||
raiseIOSelectorsError(osLastError())
|
raiseIOSelectorsError(osLastError())
|
||||||
|
|
||||||
template clearKey[T](key: ptr SelectorKey[T]) =
|
template clearKey[T](key: ptr SelectorKey[T]) =
|
||||||
|
|
@ -157,7 +158,7 @@ proc close*(ev: SelectEvent) =
|
||||||
|
|
||||||
template checkFd(s, f) =
|
template checkFd(s, f) =
|
||||||
if f >= s.maxFD:
|
if f >= s.maxFD:
|
||||||
raiseIOSelectorsError("Maximum file descriptors exceeded!")
|
raiseIOSelectorsError("Maximum number of descriptors is exhausted!")
|
||||||
|
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
template withChangeLock[T](s: Selector[T], body: untyped) =
|
template withChangeLock[T](s: Selector[T], body: untyped) =
|
||||||
|
|
@ -241,7 +242,8 @@ proc updateHandle*[T](s: Selector[T], fd: SocketHandle,
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
var pkey = addr(s.fds[fdi])
|
var pkey = addr(s.fds[fdi])
|
||||||
doAssert(pkey.ident != 0)
|
doAssert(pkey.ident != 0,
|
||||||
|
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||||
doAssert(pkey.events * maskEvents == {})
|
doAssert(pkey.events * maskEvents == {})
|
||||||
|
|
||||||
if pkey.events != events:
|
if pkey.events != events:
|
||||||
|
|
@ -329,7 +331,7 @@ proc registerProcess*[T](s: Selector[T], pid: int,
|
||||||
|
|
||||||
proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
||||||
let fdi = ev.rfd.int
|
let fdi = ev.rfd.int
|
||||||
doAssert(s.fds[fdi].ident == 0)
|
doAssert(s.fds[fdi].ident == 0, "Event is already registered in the queue!")
|
||||||
setKey(s, fdi, {Event.User}, 0, data)
|
setKey(s, fdi, {Event.User}, 0, data)
|
||||||
|
|
||||||
modifyKQueue(s, fdi.uint, EVFILT_READ, EV_ADD, 0, 0, nil)
|
modifyKQueue(s, fdi.uint, EVFILT_READ, EV_ADD, 0, 0, nil)
|
||||||
|
|
@ -372,7 +374,8 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
var pkey = addr(s.fds[fdi])
|
var pkey = addr(s.fds[fdi])
|
||||||
doAssert(pkey.ident != 0)
|
doAssert(pkey.ident != 0,
|
||||||
|
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||||
|
|
||||||
if pkey.events != {}:
|
if pkey.events != {}:
|
||||||
if pkey.events * {Event.Read, Event.Write} != {}:
|
if pkey.events * {Event.Read, Event.Write} != {}:
|
||||||
|
|
@ -431,9 +434,8 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) =
|
||||||
let fdi = int(ev.rfd)
|
let fdi = int(ev.rfd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
var pkey = addr(s.fds[fdi])
|
var pkey = addr(s.fds[fdi])
|
||||||
doAssert(pkey.ident != 0)
|
doAssert(pkey.ident != 0, "Event is not registered in the queue!")
|
||||||
doAssert(Event.User in pkey.events)
|
doAssert(Event.User in pkey.events)
|
||||||
|
|
||||||
modifyKQueue(s, uint(fdi), EVFILT_READ, EV_DELETE, 0, 0, nil)
|
modifyKQueue(s, uint(fdi), EVFILT_READ, EV_DELETE, 0, 0, nil)
|
||||||
when not declared(CACHE_EVENTS):
|
when not declared(CACHE_EVENTS):
|
||||||
flushKQueue(s)
|
flushKQueue(s)
|
||||||
|
|
@ -564,8 +566,7 @@ proc selectInto*[T](s: Selector[T], timeout: int,
|
||||||
pkey.events.incl(Event.Finished)
|
pkey.events.incl(Event.Finished)
|
||||||
rkey.events.incl(Event.Process)
|
rkey.events.incl(Event.Process)
|
||||||
else:
|
else:
|
||||||
pkey = addr(s.fds[cast[int](kevent.udata)])
|
doAssert(true, "Unsupported kqueue filter in the queue!")
|
||||||
raiseIOSelectorsError("Unsupported kqueue filter in queue!")
|
|
||||||
|
|
||||||
if (kevent.flags and EV_EOF) != 0:
|
if (kevent.flags and EV_EOF) != 0:
|
||||||
rkey.events.incl(Event.Error)
|
rkey.events.incl(Event.Error)
|
||||||
|
|
|
||||||
|
|
@ -115,9 +115,8 @@ template pollUpdate[T](s: Selector[T], sock: cint, events: set[Event]) =
|
||||||
s.pollfds[i].events = pollev
|
s.pollfds[i].events = pollev
|
||||||
break
|
break
|
||||||
inc(i)
|
inc(i)
|
||||||
|
doAssert(i < s.pollcnt,
|
||||||
if i == s.pollcnt:
|
"Descriptor [" & $sock & "] is not registered in the queue!")
|
||||||
raiseIOSelectorsError("Descriptor is not registered in queue")
|
|
||||||
|
|
||||||
template pollRemove[T](s: Selector[T], sock: cint) =
|
template pollRemove[T](s: Selector[T], sock: cint) =
|
||||||
withPollLock(s):
|
withPollLock(s):
|
||||||
|
|
@ -140,7 +139,7 @@ template pollRemove[T](s: Selector[T], sock: cint) =
|
||||||
|
|
||||||
template checkFd(s, f) =
|
template checkFd(s, f) =
|
||||||
if f >= s.maxFD:
|
if f >= s.maxFD:
|
||||||
raiseIOSelectorsError("Descriptor is not registered in queue")
|
raiseIOSelectorsError("Maximum number of descriptors is exhausted!")
|
||||||
|
|
||||||
proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
||||||
events: set[Event], data: T) =
|
events: set[Event], data: T) =
|
||||||
|
|
@ -157,7 +156,8 @@ proc updateHandle*[T](s: Selector[T], fd: SocketHandle,
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
var pkey = addr(s.fds[fdi])
|
var pkey = addr(s.fds[fdi])
|
||||||
doAssert(pkey.ident != 0)
|
doAssert(pkey.ident != 0,
|
||||||
|
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||||
doAssert(pkey.events * maskEvents == {})
|
doAssert(pkey.events * maskEvents == {})
|
||||||
|
|
||||||
if pkey.events != events:
|
if pkey.events != events:
|
||||||
|
|
@ -172,7 +172,7 @@ proc updateHandle*[T](s: Selector[T], fd: SocketHandle,
|
||||||
|
|
||||||
proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
proc registerEvent*[T](s: Selector[T], ev: SelectEvent, data: T) =
|
||||||
var fdi = int(ev.rfd)
|
var fdi = int(ev.rfd)
|
||||||
doAssert(s.fds[fdi].ident == 0)
|
doAssert(s.fds[fdi].ident == 0, "Event is already registered in the queue!")
|
||||||
var events = {Event.User}
|
var events = {Event.User}
|
||||||
setKey(s, fdi, events, 0, data)
|
setKey(s, fdi, events, 0, data)
|
||||||
events.incl(Event.Read)
|
events.incl(Event.Read)
|
||||||
|
|
@ -182,7 +182,8 @@ proc unregister*[T](s: Selector[T], fd: int|SocketHandle) =
|
||||||
let fdi = int(fd)
|
let fdi = int(fd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
var pkey = addr(s.fds[fdi])
|
var pkey = addr(s.fds[fdi])
|
||||||
doAssert(pkey.ident != 0)
|
doAssert(pkey.ident != 0,
|
||||||
|
"Descriptor [" & $fdi & "] is not registered in the queue!")
|
||||||
pkey.ident = 0
|
pkey.ident = 0
|
||||||
pkey.events = {}
|
pkey.events = {}
|
||||||
s.pollRemove(fdi.cint)
|
s.pollRemove(fdi.cint)
|
||||||
|
|
@ -191,7 +192,7 @@ proc unregister*[T](s: Selector[T], ev: SelectEvent) =
|
||||||
let fdi = int(ev.rfd)
|
let fdi = int(ev.rfd)
|
||||||
s.checkFd(fdi)
|
s.checkFd(fdi)
|
||||||
var pkey = addr(s.fds[fdi])
|
var pkey = addr(s.fds[fdi])
|
||||||
doAssert(pkey.ident != 0)
|
doAssert(pkey.ident != 0, "Event is not registered in the queue!")
|
||||||
doAssert(Event.User in pkey.events)
|
doAssert(Event.User in pkey.events)
|
||||||
pkey.ident = 0
|
pkey.ident = 0
|
||||||
pkey.events = {}
|
pkey.events = {}
|
||||||
|
|
|
||||||
|
|
@ -202,8 +202,8 @@ proc setSelectKey[T](s: Selector[T], fd: SocketHandle, events: set[Event],
|
||||||
pkey.data = data
|
pkey.data = data
|
||||||
break
|
break
|
||||||
inc(i)
|
inc(i)
|
||||||
if i == FD_SETSIZE:
|
if i >= FD_SETSIZE:
|
||||||
raiseIOSelectorsError("Maximum numbers of fds exceeded")
|
raiseIOSelectorsError("Maximum number of descriptors is exhausted!")
|
||||||
|
|
||||||
proc getKey[T](s: Selector[T], fd: SocketHandle): ptr SelectorKey[T] =
|
proc getKey[T](s: Selector[T], fd: SocketHandle): ptr SelectorKey[T] =
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -213,8 +213,8 @@ proc getKey[T](s: Selector[T], fd: SocketHandle): ptr SelectorKey[T] =
|
||||||
result = addr(s.fds[i])
|
result = addr(s.fds[i])
|
||||||
break
|
break
|
||||||
inc(i)
|
inc(i)
|
||||||
if i == FD_SETSIZE:
|
doAssert(i < FD_SETSIZE,
|
||||||
raiseIOSelectorsError("Descriptor not registered in queue")
|
"Descriptor [" & $int(fd) & "] is not registered in the queue!")
|
||||||
|
|
||||||
proc delKey[T](s: Selector[T], fd: SocketHandle) =
|
proc delKey[T](s: Selector[T], fd: SocketHandle) =
|
||||||
var empty: T
|
var empty: T
|
||||||
|
|
@ -226,8 +226,8 @@ proc delKey[T](s: Selector[T], fd: SocketHandle) =
|
||||||
s.fds[i].data = empty
|
s.fds[i].data = empty
|
||||||
break
|
break
|
||||||
inc(i)
|
inc(i)
|
||||||
if i == FD_SETSIZE:
|
doAssert(i < FD_SETSIZE,
|
||||||
raiseIOSelectorsError("Descriptor not registered in queue")
|
"Descriptor [" & $int(fd) & "] is not registered in the queue!")
|
||||||
|
|
||||||
proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
proc registerHandle*[T](s: Selector[T], fd: SocketHandle,
|
||||||
events: set[Event], data: T) =
|
events: set[Event], data: T) =
|
||||||
|
|
@ -294,6 +294,7 @@ proc unregister*[T](s: Selector[T], fd: SocketHandle) =
|
||||||
proc unregister*[T](s: Selector[T], ev: SelectEvent) =
|
proc unregister*[T](s: Selector[T], ev: SelectEvent) =
|
||||||
let fd = ev.rsock
|
let fd = ev.rsock
|
||||||
s.withSelectLock():
|
s.withSelectLock():
|
||||||
|
var pkey = s.getKey(fd)
|
||||||
IOFD_CLR(fd, addr s.rSet)
|
IOFD_CLR(fd, addr s.rSet)
|
||||||
dec(s.count)
|
dec(s.count)
|
||||||
s.delKey(fd)
|
s.delKey(fd)
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,12 @@ const useWinVersion = defined(Windows) or defined(nimdoc)
|
||||||
when useWinVersion:
|
when useWinVersion:
|
||||||
import winlean
|
import winlean
|
||||||
export WSAEWOULDBLOCK, WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
|
export WSAEWOULDBLOCK, WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
|
||||||
|
WSANOTINITIALISED, WSAENOTSOCK, WSAEINPROGRESS, WSAEINTR,
|
||||||
WSAEDISCON, ERROR_NETNAME_DELETED
|
WSAEDISCON, ERROR_NETNAME_DELETED
|
||||||
else:
|
else:
|
||||||
import posix
|
import posix
|
||||||
export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL,
|
export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL,
|
||||||
EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET
|
EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET, EBADF
|
||||||
export Sockaddr_storage, Sockaddr_un, Sockaddr_un_path_length
|
export Sockaddr_storage, Sockaddr_un, Sockaddr_un_path_length
|
||||||
|
|
||||||
export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen,
|
export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen,
|
||||||
|
|
|
||||||
|
|
@ -630,7 +630,7 @@ proc getch*(): char =
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
let fd = getStdHandle(STD_INPUT_HANDLE)
|
let fd = getStdHandle(STD_INPUT_HANDLE)
|
||||||
var keyEvent = KEY_EVENT_RECORD()
|
var keyEvent = KEY_EVENT_RECORD()
|
||||||
var numRead: cint
|
var numRead: cint
|
||||||
while true:
|
while true:
|
||||||
# Block until character is entered
|
# Block until character is entered
|
||||||
doAssert(waitForSingleObject(fd, INFINITE) == WAIT_OBJECT_0)
|
doAssert(waitForSingleObject(fd, INFINITE) == WAIT_OBJECT_0)
|
||||||
|
|
|
||||||
|
|
@ -3252,19 +3252,18 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} =
|
||||||
|
|
||||||
template spliceImpl(s, a, L, b: untyped): untyped =
|
template spliceImpl(s, a, L, b: untyped): untyped =
|
||||||
# make room for additional elements or cut:
|
# make room for additional elements or cut:
|
||||||
var slen = s.len
|
var shift = b.len - max(0,L) # ignore negative slice size
|
||||||
var shift = b.len - L
|
var newLen = s.len + shift
|
||||||
var newLen = slen + shift
|
|
||||||
if shift > 0:
|
if shift > 0:
|
||||||
# enlarge:
|
# enlarge:
|
||||||
setLen(s, newLen)
|
setLen(s, newLen)
|
||||||
for i in countdown(newLen-1, a+shift+1): shallowCopy(s[i], s[i-shift])
|
for i in countdown(newLen-1, a+b.len): shallowCopy(s[i], s[i-shift])
|
||||||
else:
|
else:
|
||||||
for i in countup(a+b.len, s.len-1+shift): shallowCopy(s[i], s[i-shift])
|
for i in countup(a+b.len, newLen-1): shallowCopy(s[i], s[i-shift])
|
||||||
# cut down:
|
# cut down:
|
||||||
setLen(s, newLen)
|
setLen(s, newLen)
|
||||||
# fill the hole:
|
# fill the hole:
|
||||||
for i in 0 .. <b.len: s[i+a] = b[i]
|
for i in 0 .. <b.len: s[a+i] = b[i]
|
||||||
|
|
||||||
when hasAlloc or defined(nimscript):
|
when hasAlloc or defined(nimscript):
|
||||||
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
|
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
|
||||||
|
|
|
||||||
|
|
@ -295,10 +295,11 @@ proc writeFreeList(a: MemRegion) =
|
||||||
proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
|
proc requestOsChunks(a: var MemRegion, size: int): PBigChunk =
|
||||||
when not defined(emscripten):
|
when not defined(emscripten):
|
||||||
if not a.blockChunkSizeIncrease:
|
if not a.blockChunkSizeIncrease:
|
||||||
if a.currMem < 64 * 1024:
|
let usedMem = a.currMem # - a.freeMem
|
||||||
|
if usedMem < 64 * 1024:
|
||||||
a.nextChunkSize = PageSize*4
|
a.nextChunkSize = PageSize*4
|
||||||
else:
|
else:
|
||||||
a.nextChunkSize = min(roundup(a.currMem shr 2, PageSize), a.nextChunkSize * 2)
|
a.nextChunkSize = min(roundup(usedMem shr 2, PageSize), a.nextChunkSize * 2)
|
||||||
var size = size
|
var size = size
|
||||||
|
|
||||||
if size > a.nextChunkSize:
|
if size > a.nextChunkSize:
|
||||||
|
|
@ -708,7 +709,7 @@ proc realloc(allocator: var MemRegion, p: pointer, newsize: Natural): pointer =
|
||||||
if newsize > 0:
|
if newsize > 0:
|
||||||
result = alloc0(allocator, newsize)
|
result = alloc0(allocator, newsize)
|
||||||
if p != nil:
|
if p != nil:
|
||||||
copyMem(result, p, ptrSize(p))
|
copyMem(result, p, min(ptrSize(p), newsize))
|
||||||
dealloc(allocator, p)
|
dealloc(allocator, p)
|
||||||
elif p != nil:
|
elif p != nil:
|
||||||
dealloc(allocator, p)
|
dealloc(allocator, p)
|
||||||
|
|
|
||||||
|
|
@ -293,6 +293,11 @@ template task*(name: untyped; description: string; body: untyped): untyped =
|
||||||
setCommand "nop"
|
setCommand "nop"
|
||||||
`name Task`()
|
`name Task`()
|
||||||
|
|
||||||
|
proc cppDefine*(define: string) =
|
||||||
|
## tell Nim that ``define`` is a C preprocessor ``#define`` and so always
|
||||||
|
## needs to be mangled.
|
||||||
|
builtin
|
||||||
|
|
||||||
when not defined(nimble):
|
when not defined(nimble):
|
||||||
# nimble has its own implementation for these things.
|
# nimble has its own implementation for these things.
|
||||||
var
|
var
|
||||||
|
|
|
||||||
|
|
@ -195,15 +195,15 @@ else:
|
||||||
importc: "pthread_setaffinity_np", header: pthreadh.}
|
importc: "pthread_setaffinity_np", header: pthreadh.}
|
||||||
|
|
||||||
when defined(linux):
|
when defined(linux):
|
||||||
proc syscall(arg: int): int {.varargs, importc: "syscall", header: "<unistd.h>".}
|
proc syscall(arg: clong): clong {.varargs, importc: "syscall", header: "<unistd.h>".}
|
||||||
var SYS_gettid {.importc, header: "<sys/syscall.h>".}: int
|
var NR_gettid {.importc: "__NR_gettid", header: "<sys/syscall.h>".}: int
|
||||||
|
|
||||||
#type Pid {.importc: "pid_t", header: "<sys/types.h>".} = distinct int
|
#type Pid {.importc: "pid_t", header: "<sys/types.h>".} = distinct int
|
||||||
#proc gettid(): Pid {.importc, header: "<sys/types.h>".}
|
#proc gettid(): Pid {.importc, header: "<sys/types.h>".}
|
||||||
|
|
||||||
proc getThreadId*(): int =
|
proc getThreadId*(): int =
|
||||||
## get the ID of the currently running thread.
|
## get the ID of the currently running thread.
|
||||||
result = int(syscall(SYS_gettid))
|
result = int(syscall(NR_gettid))
|
||||||
elif defined(macosx) or defined(bsd):
|
elif defined(macosx) or defined(bsd):
|
||||||
proc pthread_threadid_np(y: pointer; x: var uint64): cint {.importc, header: "pthread.h".}
|
proc pthread_threadid_np(y: pointer; x: var uint64): cint {.importc, header: "pthread.h".}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -738,26 +738,6 @@ when defined(windows) or defined(nimdoc):
|
||||||
let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
let dwLocalAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
||||||
let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
|
||||||
|
|
||||||
template completeAccept() {.dirty.} =
|
|
||||||
var listenSock = socket
|
|
||||||
let setoptRet = setsockopt(clientSock, SOL_SOCKET,
|
|
||||||
SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
|
|
||||||
sizeof(listenSock).SockLen)
|
|
||||||
if setoptRet != 0: raiseOSError(osLastError())
|
|
||||||
|
|
||||||
var localSockaddr, remoteSockaddr: ptr SockAddr
|
|
||||||
var localLen, remoteLen: int32
|
|
||||||
getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
|
|
||||||
dwLocalAddressLength, dwRemoteAddressLength,
|
|
||||||
addr localSockaddr, addr localLen,
|
|
||||||
addr remoteSockaddr, addr remoteLen)
|
|
||||||
register(clientSock.AsyncFD)
|
|
||||||
# TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
|
|
||||||
retFuture.complete(
|
|
||||||
(address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
|
|
||||||
client: clientSock.AsyncFD)
|
|
||||||
)
|
|
||||||
|
|
||||||
template failAccept(errcode) =
|
template failAccept(errcode) =
|
||||||
if flags.isDisconnectionError(errcode):
|
if flags.isDisconnectionError(errcode):
|
||||||
var newAcceptFut = acceptAddr(socket, flags)
|
var newAcceptFut = acceptAddr(socket, flags)
|
||||||
|
|
@ -770,6 +750,29 @@ when defined(windows) or defined(nimdoc):
|
||||||
else:
|
else:
|
||||||
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
||||||
|
|
||||||
|
template completeAccept() {.dirty.} =
|
||||||
|
var listenSock = socket
|
||||||
|
let setoptRet = setsockopt(clientSock, SOL_SOCKET,
|
||||||
|
SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
|
||||||
|
sizeof(listenSock).SockLen)
|
||||||
|
if setoptRet != 0:
|
||||||
|
let errcode = osLastError()
|
||||||
|
discard clientSock.closeSocket()
|
||||||
|
failAccept(errcode)
|
||||||
|
else:
|
||||||
|
var localSockaddr, remoteSockaddr: ptr SockAddr
|
||||||
|
var localLen, remoteLen: int32
|
||||||
|
getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
|
||||||
|
dwLocalAddressLength, dwRemoteAddressLength,
|
||||||
|
addr localSockaddr, addr localLen,
|
||||||
|
addr remoteSockaddr, addr remoteLen)
|
||||||
|
register(clientSock.AsyncFD)
|
||||||
|
# TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
|
||||||
|
retFuture.complete(
|
||||||
|
(address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
|
||||||
|
client: clientSock.AsyncFD)
|
||||||
|
)
|
||||||
|
|
||||||
var ol = PCustomOverlapped()
|
var ol = PCustomOverlapped()
|
||||||
GC_ref(ol)
|
GC_ref(ol)
|
||||||
ol.data = CompletionData(fd: socket, cb:
|
ol.data = CompletionData(fd: socket, cb:
|
||||||
|
|
@ -1056,16 +1059,14 @@ when defined(windows) or defined(nimdoc):
|
||||||
|
|
||||||
proc unregister*(ev: AsyncEvent) =
|
proc unregister*(ev: AsyncEvent) =
|
||||||
## Unregisters event ``ev``.
|
## Unregisters event ``ev``.
|
||||||
if ev.hWaiter != 0:
|
doAssert(ev.hWaiter != 0, "Event is not registered in the queue!")
|
||||||
let p = getGlobalDispatcher()
|
let p = getGlobalDispatcher()
|
||||||
p.handles.excl(AsyncFD(ev.hEvent))
|
p.handles.excl(AsyncFD(ev.hEvent))
|
||||||
if unregisterWait(ev.hWaiter) == 0:
|
if unregisterWait(ev.hWaiter) == 0:
|
||||||
let err = osLastError()
|
let err = osLastError()
|
||||||
if err.int32 != ERROR_IO_PENDING:
|
if err.int32 != ERROR_IO_PENDING:
|
||||||
raiseOSError(err)
|
raiseOSError(err)
|
||||||
ev.hWaiter = 0
|
ev.hWaiter = 0
|
||||||
else:
|
|
||||||
raise newException(ValueError, "Event is not registered!")
|
|
||||||
|
|
||||||
proc close*(ev: AsyncEvent) =
|
proc close*(ev: AsyncEvent) =
|
||||||
## Closes event ``ev``.
|
## Closes event ``ev``.
|
||||||
|
|
@ -1076,8 +1077,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
|
|
||||||
proc addEvent*(ev: AsyncEvent, cb: Callback) =
|
proc addEvent*(ev: AsyncEvent, cb: Callback) =
|
||||||
## Registers callback ``cb`` to be called when ``ev`` will be signaled
|
## Registers callback ``cb`` to be called when ``ev`` will be signaled
|
||||||
if ev.hWaiter != 0:
|
doAssert(ev.hWaiter == 0, "Event is already registered in the queue!")
|
||||||
raise newException(ValueError, "Event is already registered!")
|
|
||||||
|
|
||||||
let p = getGlobalDispatcher()
|
let p = getGlobalDispatcher()
|
||||||
let hEvent = ev.hEvent
|
let hEvent = ev.hEvent
|
||||||
|
|
@ -1086,17 +1086,22 @@ when defined(windows) or defined(nimdoc):
|
||||||
var flags = WT_EXECUTEINWAITTHREAD.Dword
|
var flags = WT_EXECUTEINWAITTHREAD.Dword
|
||||||
|
|
||||||
proc eventcb(fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
|
proc eventcb(fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
|
||||||
if cb(fd):
|
if ev.hWaiter != 0:
|
||||||
# we need this check to avoid exception, if `unregister(event)` was
|
if cb(fd):
|
||||||
# called in callback.
|
# we need this check to avoid exception, if `unregister(event)` was
|
||||||
deallocShared(cast[pointer](pcd))
|
# called in callback.
|
||||||
if ev.hWaiter != 0: unregister(ev)
|
deallocShared(cast[pointer](pcd))
|
||||||
|
if ev.hWaiter != 0:
|
||||||
|
unregister(ev)
|
||||||
|
else:
|
||||||
|
# if callback returned `false`, then it wants to be called again, so
|
||||||
|
# we need to ref and protect `pcd.ovl` again, because it will be
|
||||||
|
# unrefed and disposed in `poll()`.
|
||||||
|
GC_ref(pcd.ovl)
|
||||||
|
pcd.ovl.data.cell = system.protect(rawEnv(pcd.ovl.data.cb))
|
||||||
else:
|
else:
|
||||||
# if callback returned `false`, then it wants to be called again, so
|
# if ev.hWaiter == 0, then event was unregistered before `poll()` call.
|
||||||
# we need to ref and protect `pcd.ovl` again, because it will be
|
deallocShared(cast[pointer](pcd))
|
||||||
# unrefed and disposed in `poll()`.
|
|
||||||
GC_ref(pcd.ovl)
|
|
||||||
pcd.ovl.data.cell = system.protect(rawEnv(pcd.ovl.data.cb))
|
|
||||||
|
|
||||||
registerWaitableHandle(p, hEvent, flags, pcd, INFINITE, eventcb)
|
registerWaitableHandle(p, hEvent, flags, pcd, INFINITE, eventcb)
|
||||||
ev.hWaiter = pcd.waitFd
|
ev.hWaiter = pcd.waitFd
|
||||||
|
|
@ -1205,7 +1210,7 @@ else:
|
||||||
not p.selector.isEmpty() or p.timers.len != 0 or p.callbacks.len != 0
|
not p.selector.isEmpty() or p.timers.len != 0 or p.callbacks.len != 0
|
||||||
|
|
||||||
template processBasicCallbacks(ident, rwlist: untyped) =
|
template processBasicCallbacks(ident, rwlist: untyped) =
|
||||||
# Process pending descriptor's callbacks.
|
# Process pending descriptor's and AsyncEvent callbacks.
|
||||||
# Invoke every callback stored in `rwlist`, until first one
|
# Invoke every callback stored in `rwlist`, until first one
|
||||||
# returned `false`, which means callback wants to stay
|
# returned `false`, which means callback wants to stay
|
||||||
# alive. In such case all remaining callbacks will be added
|
# alive. In such case all remaining callbacks will be added
|
||||||
|
|
@ -1231,7 +1236,14 @@ else:
|
||||||
newList.add(cb)
|
newList.add(cb)
|
||||||
|
|
||||||
withData(p.selector, ident, adata) do:
|
withData(p.selector, ident, adata) do:
|
||||||
|
# descriptor still present in queue.
|
||||||
adata.rwlist = newList & adata.rwlist
|
adata.rwlist = newList & adata.rwlist
|
||||||
|
rLength = len(adata.readList)
|
||||||
|
wLength = len(adata.writeList)
|
||||||
|
do:
|
||||||
|
# descriptor was unregistered in callback via `unregister()`.
|
||||||
|
rLength = -1
|
||||||
|
wLength = -1
|
||||||
|
|
||||||
template processCustomCallbacks(ident: untyped) =
|
template processCustomCallbacks(ident: untyped) =
|
||||||
# Process pending custom event callbacks. Custom events are
|
# Process pending custom event callbacks. Custom events are
|
||||||
|
|
@ -1250,11 +1262,16 @@ else:
|
||||||
var cb = curList[0]
|
var cb = curList[0]
|
||||||
if not cb(fd.AsyncFD):
|
if not cb(fd.AsyncFD):
|
||||||
newList.add(cb)
|
newList.add(cb)
|
||||||
else:
|
|
||||||
p.selector.unregister(fd)
|
|
||||||
|
|
||||||
withData(p.selector, ident, adata) do:
|
withData(p.selector, ident, adata) do:
|
||||||
|
# descriptor still present in queue.
|
||||||
adata.readList = newList & adata.readList
|
adata.readList = newList & adata.readList
|
||||||
|
if len(adata.readList) == 0:
|
||||||
|
# if no callbacks registered with descriptor, unregister it.
|
||||||
|
p.selector.unregister(fd)
|
||||||
|
do:
|
||||||
|
# descriptor was unregistered in callback via `unregister()`.
|
||||||
|
discard
|
||||||
|
|
||||||
proc poll*(timeout = 500) =
|
proc poll*(timeout = 500) =
|
||||||
var keys: array[64, ReadyKey]
|
var keys: array[64, ReadyKey]
|
||||||
|
|
@ -1275,6 +1292,8 @@ else:
|
||||||
var custom = false
|
var custom = false
|
||||||
let fd = keys[i].fd
|
let fd = keys[i].fd
|
||||||
let events = keys[i].events
|
let events = keys[i].events
|
||||||
|
var rLength = 0 # len(data.readList) after callback
|
||||||
|
var wLength = 0 # len(data.writeList) after callback
|
||||||
|
|
||||||
if Event.Read in events or events == {Event.Error}:
|
if Event.Read in events or events == {Event.Error}:
|
||||||
processBasicCallbacks(fd, readList)
|
processBasicCallbacks(fd, readList)
|
||||||
|
|
@ -1283,8 +1302,10 @@ else:
|
||||||
processBasicCallbacks(fd, writeList)
|
processBasicCallbacks(fd, writeList)
|
||||||
|
|
||||||
if Event.User in events or events == {Event.Error}:
|
if Event.User in events or events == {Event.Error}:
|
||||||
custom = true
|
|
||||||
processBasicCallbacks(fd, readList)
|
processBasicCallbacks(fd, readList)
|
||||||
|
custom = true
|
||||||
|
if rLength == 0:
|
||||||
|
p.selector.unregister(fd)
|
||||||
|
|
||||||
when ioselSupportedPlatform:
|
when ioselSupportedPlatform:
|
||||||
if (customSet * events) != {}:
|
if (customSet * events) != {}:
|
||||||
|
|
@ -1294,13 +1315,10 @@ else:
|
||||||
# because state `data` can be modified in callback we need to update
|
# because state `data` can be modified in callback we need to update
|
||||||
# descriptor events with currently registered callbacks.
|
# descriptor events with currently registered callbacks.
|
||||||
if not custom:
|
if not custom:
|
||||||
var update = false
|
|
||||||
var newEvents: set[Event] = {}
|
var newEvents: set[Event] = {}
|
||||||
p.selector.withData(fd, adata) do:
|
if rLength != -1 and wLength != -1:
|
||||||
if len(adata.readList) > 0: incl(newEvents, Event.Read)
|
if rLength > 0: incl(newEvents, Event.Read)
|
||||||
if len(adata.writeList) > 0: incl(newEvents, Event.Write)
|
if wLength > 0: incl(newEvents, Event.Write)
|
||||||
update = true
|
|
||||||
if update:
|
|
||||||
p.selector.updateHandle(SocketHandle(fd), newEvents)
|
p.selector.updateHandle(SocketHandle(fd), newEvents)
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -419,9 +419,6 @@ const
|
||||||
|
|
||||||
ws2dll = "Ws2_32.dll"
|
ws2dll = "Ws2_32.dll"
|
||||||
|
|
||||||
WSAEWOULDBLOCK* = 10035
|
|
||||||
WSAEINPROGRESS* = 10036
|
|
||||||
|
|
||||||
proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
|
proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -760,6 +757,11 @@ const
|
||||||
WSAEDISCON* = 10101
|
WSAEDISCON* = 10101
|
||||||
WSAENETRESET* = 10052
|
WSAENETRESET* = 10052
|
||||||
WSAETIMEDOUT* = 10060
|
WSAETIMEDOUT* = 10060
|
||||||
|
WSANOTINITIALISED* = 10093
|
||||||
|
WSAENOTSOCK* = 10038
|
||||||
|
WSAEINPROGRESS* = 10036
|
||||||
|
WSAEINTR* = 10004
|
||||||
|
WSAEWOULDBLOCK* = 10035
|
||||||
ERROR_NETNAME_DELETED* = 64
|
ERROR_NETNAME_DELETED* = 64
|
||||||
STATUS_PENDING* = 0x103
|
STATUS_PENDING* = 0x103
|
||||||
|
|
||||||
|
|
|
||||||
36
tests/async/tacceptcloserace.nim
Normal file
36
tests/async/tacceptcloserace.nim
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
discard """
|
||||||
|
exitcode: 0
|
||||||
|
output: ""
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncdispatch, net, os, nativesockets
|
||||||
|
|
||||||
|
# bug: https://github.com/nim-lang/Nim/issues/5279
|
||||||
|
|
||||||
|
proc setupServerSocket(hostname: string, port: Port): AsyncFD =
|
||||||
|
let fd = newNativeSocket()
|
||||||
|
if fd == osInvalidSocket:
|
||||||
|
raiseOSError(osLastError())
|
||||||
|
setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
|
||||||
|
var aiList = getAddrInfo(hostname, port)
|
||||||
|
if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
|
||||||
|
freeAddrInfo(aiList)
|
||||||
|
raiseOSError(osLastError())
|
||||||
|
freeAddrInfo(aiList)
|
||||||
|
if listen(fd) != 0:
|
||||||
|
raiseOSError(osLastError())
|
||||||
|
setBlocking(fd, false)
|
||||||
|
result = fd.AsyncFD
|
||||||
|
register(result)
|
||||||
|
|
||||||
|
const port = Port(5614)
|
||||||
|
for i in 0..100:
|
||||||
|
let serverFd = setupServerSocket("localhost", port)
|
||||||
|
serverFd.accept().callback = proc(fut: Future[AsyncFD]) =
|
||||||
|
if not fut.failed:
|
||||||
|
fut.read().closeSocket()
|
||||||
|
|
||||||
|
var fd = newAsyncNativeSocket()
|
||||||
|
waitFor fd.connect("localhost", port)
|
||||||
|
serverFd.closeSocket()
|
||||||
|
fd.closeSocket()
|
||||||
17
tests/async/tasync_in_seq_constr.nim
Normal file
17
tests/async/tasync_in_seq_constr.nim
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
discard """
|
||||||
|
output: '''@[1, 2, 3, 4]'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #5314
|
||||||
|
|
||||||
|
import asyncdispatch
|
||||||
|
|
||||||
|
proc bar(): Future[int] {.async.} =
|
||||||
|
await sleepAsync(500)
|
||||||
|
result = 3
|
||||||
|
|
||||||
|
proc foo(): Future[seq[int]] {.async.} =
|
||||||
|
await sleepAsync(500)
|
||||||
|
result = @[1, 2, await bar(), 4] # <--- The bug is here
|
||||||
|
|
||||||
|
echo waitFor foo()
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''
|
output: '''
|
||||||
OK
|
OK
|
||||||
OK
|
|
||||||
OK
|
|
||||||
OK
|
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -31,11 +28,50 @@ when defined(upcoming):
|
||||||
var fut = waitEvent(event)
|
var fut = waitEvent(event)
|
||||||
asyncCheck(delayedSet(event, 500))
|
asyncCheck(delayedSet(event, 500))
|
||||||
waitFor(fut or sleepAsync(1000))
|
waitFor(fut or sleepAsync(1000))
|
||||||
if fut.finished:
|
if not fut.finished:
|
||||||
echo "OK"
|
|
||||||
else:
|
|
||||||
echo "eventTest: Timeout expired before event received!"
|
echo "eventTest: Timeout expired before event received!"
|
||||||
|
|
||||||
|
proc eventTest5304() =
|
||||||
|
# Event should not be signaled if it was uregistered,
|
||||||
|
# even in case, when poll() was not called yet.
|
||||||
|
# Issue #5304.
|
||||||
|
var unregistered = false
|
||||||
|
let e = newAsyncEvent()
|
||||||
|
addEvent(e) do (fd: AsyncFD) -> bool:
|
||||||
|
assert(not unregistered)
|
||||||
|
e.setEvent()
|
||||||
|
e.unregister()
|
||||||
|
unregistered = true
|
||||||
|
poll()
|
||||||
|
|
||||||
|
proc eventTest5298() =
|
||||||
|
# Event must raise `AssertionError` if event was unregistered twice.
|
||||||
|
# Issue #5298.
|
||||||
|
let e = newAsyncEvent()
|
||||||
|
var eventReceived = false
|
||||||
|
addEvent(e) do (fd: AsyncFD) -> bool:
|
||||||
|
eventReceived = true
|
||||||
|
return true
|
||||||
|
e.setEvent()
|
||||||
|
while not eventReceived:
|
||||||
|
poll()
|
||||||
|
try:
|
||||||
|
e.unregister()
|
||||||
|
except AssertionError:
|
||||||
|
discard
|
||||||
|
e.close()
|
||||||
|
|
||||||
|
proc eventTest5331() =
|
||||||
|
# Event must not raise any exceptions while was unregistered inside of
|
||||||
|
# own callback.
|
||||||
|
# Issue #5331.
|
||||||
|
let e = newAsyncEvent()
|
||||||
|
addEvent(e) do (fd: AsyncFD) -> bool:
|
||||||
|
e.unregister()
|
||||||
|
e.close()
|
||||||
|
e.setEvent()
|
||||||
|
poll()
|
||||||
|
|
||||||
when ioselSupportedPlatform or defined(windows):
|
when ioselSupportedPlatform or defined(windows):
|
||||||
|
|
||||||
import osproc
|
import osproc
|
||||||
|
|
@ -56,7 +92,6 @@ when defined(upcoming):
|
||||||
|
|
||||||
proc timerTest() =
|
proc timerTest() =
|
||||||
waitFor(waitTimer(200))
|
waitFor(waitTimer(200))
|
||||||
echo "OK"
|
|
||||||
|
|
||||||
proc processTest() =
|
proc processTest() =
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -70,7 +105,7 @@ when defined(upcoming):
|
||||||
var fut = waitProcess(process)
|
var fut = waitProcess(process)
|
||||||
waitFor(fut or waitTimer(2000))
|
waitFor(fut or waitTimer(2000))
|
||||||
if fut.finished and process.peekExitCode() == 0:
|
if fut.finished and process.peekExitCode() == 0:
|
||||||
echo "OK"
|
discard
|
||||||
else:
|
else:
|
||||||
echo "processTest: Timeout expired before process exited!"
|
echo "processTest: Timeout expired before process exited!"
|
||||||
|
|
||||||
|
|
@ -92,23 +127,31 @@ when defined(upcoming):
|
||||||
var fut = waitSignal(posix.SIGINT)
|
var fut = waitSignal(posix.SIGINT)
|
||||||
asyncCheck(delayedSignal(posix.SIGINT, 500))
|
asyncCheck(delayedSignal(posix.SIGINT, 500))
|
||||||
waitFor(fut or waitTimer(1000))
|
waitFor(fut or waitTimer(1000))
|
||||||
if fut.finished:
|
if not fut.finished:
|
||||||
echo "OK"
|
|
||||||
else:
|
|
||||||
echo "signalTest: Timeout expired before signal received!"
|
echo "signalTest: Timeout expired before signal received!"
|
||||||
|
|
||||||
when ioselSupportedPlatform:
|
when ioselSupportedPlatform:
|
||||||
timerTest()
|
timerTest()
|
||||||
eventTest()
|
eventTest()
|
||||||
|
eventTest5304()
|
||||||
|
eventTest5298()
|
||||||
|
eventTest5331()
|
||||||
processTest()
|
processTest()
|
||||||
signalTest()
|
signalTest()
|
||||||
|
echo "OK"
|
||||||
elif defined(windows):
|
elif defined(windows):
|
||||||
timerTest()
|
timerTest()
|
||||||
eventTest()
|
eventTest()
|
||||||
|
eventTest5304()
|
||||||
|
eventTest5298()
|
||||||
|
eventTest5331()
|
||||||
processTest()
|
processTest()
|
||||||
echo "OK"
|
echo "OK"
|
||||||
else:
|
else:
|
||||||
eventTest()
|
eventTest()
|
||||||
echo "OK\nOK\nOK"
|
eventTest5304()
|
||||||
|
eventTest5298()
|
||||||
|
eventTest5331()
|
||||||
|
echo "OK"
|
||||||
else:
|
else:
|
||||||
echo "OK\nOK\nOK\nOK"
|
echo "OK"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
discard """
|
discard """
|
||||||
output: "1"
|
output: "1"
|
||||||
cmd: r"nim c --hints:on $options -d:release $file"
|
cmd: r"nim c --hints:on $options -d:release $file"
|
||||||
ccodecheck: "'NI volatile state0;'"
|
ccodecheck: "'NI volatile state;'"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# bug #1539
|
# bug #1539
|
||||||
|
|
|
||||||
|
|
@ -190,28 +190,26 @@ block zeroHashKeysTest:
|
||||||
doZeroHashValueTest(toOrderedTable[string,string]({"egg": "sausage"}),
|
doZeroHashValueTest(toOrderedTable[string,string]({"egg": "sausage"}),
|
||||||
"", "spam")
|
"", "spam")
|
||||||
|
|
||||||
# Until #4448 is fixed, these tests will fail
|
block clearTableTest:
|
||||||
when false:
|
var t = data.toTable
|
||||||
block clearTableTest:
|
assert t.len() != 0
|
||||||
var t = data.toTable
|
t.clear()
|
||||||
assert t.len() != 0
|
assert t.len() == 0
|
||||||
t.clear()
|
|
||||||
assert t.len() == 0
|
|
||||||
|
|
||||||
block clearOrderedTableTest:
|
block clearOrderedTableTest:
|
||||||
var t = data.toOrderedTable
|
var t = data.toOrderedTable
|
||||||
assert t.len() != 0
|
assert t.len() != 0
|
||||||
t.clear()
|
t.clear()
|
||||||
assert t.len() == 0
|
assert t.len() == 0
|
||||||
|
|
||||||
block clearCountTableTest:
|
block clearCountTableTest:
|
||||||
var t = initCountTable[string]()
|
var t = initCountTable[string]()
|
||||||
t.inc("90", 3)
|
t.inc("90", 3)
|
||||||
t.inc("12", 2)
|
t.inc("12", 2)
|
||||||
t.inc("34", 1)
|
t.inc("34", 1)
|
||||||
assert t.len() != 0
|
assert t.len() != 0
|
||||||
t.clear()
|
t.clear()
|
||||||
assert t.len() == 0
|
assert t.len() == 0
|
||||||
|
|
||||||
proc orderedTableSortTest() =
|
proc orderedTableSortTest() =
|
||||||
var t = initOrderedTable[string, int](2)
|
var t = initOrderedTable[string, int](2)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
discard """
|
||||||
# fsmonitor test
|
disabled: windows
|
||||||
#
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import fsmonitor
|
import fsmonitor
|
||||||
|
|
@ -9,4 +9,3 @@ suite "fsmonitor":
|
||||||
test "should not raise OSError, bug# 3611":
|
test "should not raise OSError, bug# 3611":
|
||||||
let m = newMonitor()
|
let m = newMonitor()
|
||||||
m.add("foo", {MonitorCloseWrite, MonitorCloseNoWrite})
|
m.add("foo", {MonitorCloseWrite, MonitorCloseNoWrite})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ Filter Iterator: 7
|
||||||
Filter: [3, 5, 7]
|
Filter: [3, 5, 7]
|
||||||
FilterIt: [1, 3, 7]
|
FilterIt: [1, 3, 7]
|
||||||
Concat: [1, 3, 5, 7, 2, 4, 6]
|
Concat: [1, 3, 5, 7, 2, 4, 6]
|
||||||
Deduplicate: [1, 2, 3, 4, 5, 7]'''
|
Deduplicate: [1, 2, 3, 4, 5, 7]
|
||||||
|
@[()]'''
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -52,4 +53,12 @@ echo "Concat: ", $$(concatseq)
|
||||||
var seq3 = @[1,2,3,4,5,5,5,7]
|
var seq3 = @[1,2,3,4,5,5,5,7]
|
||||||
var dedupseq = deduplicate(seq3)
|
var dedupseq = deduplicate(seq3)
|
||||||
echo "Deduplicate: ", $$(dedupseq)
|
echo "Deduplicate: ", $$(dedupseq)
|
||||||
|
# bug #4973
|
||||||
|
type
|
||||||
|
SomeObj = object
|
||||||
|
OtherObj = object
|
||||||
|
field: SomeObj
|
||||||
|
|
||||||
|
let aSeq = @[OtherObj(field: SomeObj())]
|
||||||
|
let someObjSeq = aSeq.mapIt(it.field)
|
||||||
|
echo someObjSeq
|
||||||
|
|
|
||||||
55
tests/stdlib/tstring.nim
Normal file
55
tests/stdlib/tstring.nim
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
discard """
|
||||||
|
file: "tstring.nim"
|
||||||
|
output: "OK"
|
||||||
|
"""
|
||||||
|
const characters = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
const numbers = "1234567890"
|
||||||
|
|
||||||
|
var s: string
|
||||||
|
|
||||||
|
proc test_string_slice() =
|
||||||
|
# test "slice of length == len(characters)":
|
||||||
|
# replace characters completely by numbers
|
||||||
|
s = characters
|
||||||
|
s[0..^1] = numbers
|
||||||
|
doAssert s == numbers
|
||||||
|
|
||||||
|
# test "slice of length > len(numbers)":
|
||||||
|
# replace characters by slice of same length
|
||||||
|
s = characters
|
||||||
|
s[1..16] = numbers
|
||||||
|
doAssert s == "a1234567890rstuvwxyz"
|
||||||
|
|
||||||
|
# test "slice of length == len(numbers)":
|
||||||
|
# replace characters by slice of same length
|
||||||
|
s = characters
|
||||||
|
s[1..10] = numbers
|
||||||
|
doAssert s == "a1234567890lmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
# test "slice of length < len(numbers)":
|
||||||
|
# replace slice of length. and insert remaining chars
|
||||||
|
s = characters
|
||||||
|
s[1..4] = numbers
|
||||||
|
doAssert s == "a1234567890fghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
# test "slice of length == 1":
|
||||||
|
# replace first character. and insert remaining 9 chars
|
||||||
|
s = characters
|
||||||
|
s[1..1] = numbers
|
||||||
|
doAssert s == "a1234567890cdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
# test "slice of length == 0":
|
||||||
|
# insert chars at slice start index
|
||||||
|
s = characters
|
||||||
|
s[2..1] = numbers
|
||||||
|
doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
# test "slice of negative length":
|
||||||
|
# same as slice of zero length
|
||||||
|
s = characters
|
||||||
|
s[2..0] = numbers
|
||||||
|
doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
echo("OK")
|
||||||
|
|
||||||
|
test_string_slice()
|
||||||
21
tests/template/tgensymregression.nim
Normal file
21
tests/template/tgensymregression.nim
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
template mathPerComponent(op: untyped): untyped =
|
||||||
|
proc op*[N,T](v,u: array[N,T]): array[N,T] {.inline.} =
|
||||||
|
for i in 0 ..< len(result):
|
||||||
|
result[i] = `*`(v[i], u[i])
|
||||||
|
|
||||||
|
mathPerComponent(`***`)
|
||||||
|
# bug #5285
|
||||||
|
when true:
|
||||||
|
if isMainModule:
|
||||||
|
var v1: array[3, float64]
|
||||||
|
var v2: array[3, float64]
|
||||||
|
echo repr(v1 *** v2)
|
||||||
|
|
||||||
|
|
||||||
|
proc foo(): void =
|
||||||
|
var v1: array[4, float64]
|
||||||
|
var v2: array[4, float64]
|
||||||
|
echo repr(v1 *** v2)
|
||||||
|
|
||||||
|
foo()
|
||||||
|
|
@ -6,7 +6,7 @@ discard """
|
||||||
|
|
||||||
var i {.compileTime.} = 2
|
var i {.compileTime.} = 2
|
||||||
|
|
||||||
template defineId*(t: typedesc): stmt =
|
template defineId*(t: typedesc) =
|
||||||
const id {.genSym.} = i
|
const id {.genSym.} = i
|
||||||
static: inc(i)
|
static: inc(i)
|
||||||
proc idFor*(T: typedesc[t]): int {.inline, raises: [].} = id
|
proc idFor*(T: typedesc[t]): int {.inline, raises: [].} = id
|
||||||
|
|
|
||||||
|
|
@ -284,9 +284,9 @@ proc compileExample(r: var TResults, pattern, options: string, cat: Category) =
|
||||||
testNoSpec r, makeTest(test, options, cat)
|
testNoSpec r, makeTest(test, options, cat)
|
||||||
|
|
||||||
proc testStdlib(r: var TResults, pattern, options: string, cat: Category) =
|
proc testStdlib(r: var TResults, pattern, options: string, cat: Category) =
|
||||||
var disabledSet = disabledFiles.toSet()
|
|
||||||
for test in os.walkFiles(pattern):
|
for test in os.walkFiles(pattern):
|
||||||
if test notin disabledSet:
|
let name = extractFilename(test)
|
||||||
|
if name notin disabledFiles:
|
||||||
let contents = readFile(test).string
|
let contents = readFile(test).string
|
||||||
if contents.contains("when isMainModule"):
|
if contents.contains("when isMainModule"):
|
||||||
testSpec r, makeTest(test, options, cat, actionRunNoSpec)
|
testSpec r, makeTest(test, options, cat, actionRunNoSpec)
|
||||||
|
|
|
||||||
|
|
@ -108,12 +108,6 @@ proc callCompiler(cmdTemplate, filename, options: string,
|
||||||
elif suc =~ pegSuccess:
|
elif suc =~ pegSuccess:
|
||||||
result.err = reSuccess
|
result.err = reSuccess
|
||||||
|
|
||||||
if result.err == reNimcCrash and
|
|
||||||
("Your platform is not supported" in result.msg or
|
|
||||||
"cannot open 'sdl'" in result.msg or
|
|
||||||
"cannot open 'opengl'" in result.msg):
|
|
||||||
result.err = reIgnored
|
|
||||||
|
|
||||||
proc callCCompiler(cmdTemplate, filename, options: string,
|
proc callCCompiler(cmdTemplate, filename, options: string,
|
||||||
target: TTarget): TSpec =
|
target: TTarget): TSpec =
|
||||||
let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
|
let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
|
||||||
|
|
@ -393,9 +387,14 @@ proc makeTest(test, options: string, cat: Category, action = actionCompile,
|
||||||
result = TTest(cat: cat, name: test, options: options,
|
result = TTest(cat: cat, name: test, options: options,
|
||||||
target: target, action: action, startTime: epochTime())
|
target: target, action: action, startTime: epochTime())
|
||||||
|
|
||||||
const
|
when defined(windows):
|
||||||
# array of modules disabled from compilation test of stdlib.
|
const
|
||||||
disabledFiles = ["-"]
|
# array of modules disabled from compilation test of stdlib.
|
||||||
|
disabledFiles = ["coro.nim", "fsmonitor.nim"]
|
||||||
|
else:
|
||||||
|
const
|
||||||
|
# array of modules disabled from compilation test of stdlib.
|
||||||
|
disabledFiles = ["-"]
|
||||||
|
|
||||||
include categories
|
include categories
|
||||||
|
|
||||||
|
|
@ -460,7 +459,9 @@ proc main() =
|
||||||
backend.close()
|
backend.close()
|
||||||
if optPedantic:
|
if optPedantic:
|
||||||
var failed = r.total - r.passed - r.skipped
|
var failed = r.total - r.passed - r.skipped
|
||||||
if failed > 0 : quit(QuitFailure)
|
if failed > 0:
|
||||||
|
echo "FAILURE! total: ", r.total, " passed: ", r.passed, " skipped: ", r.skipped
|
||||||
|
quit(QuitFailure)
|
||||||
|
|
||||||
if paramCount() == 0:
|
if paramCount() == 0:
|
||||||
quit Usage
|
quit Usage
|
||||||
|
|
|
||||||
38
tests/vm/tableinstatic.nim
Normal file
38
tests/vm/tableinstatic.nim
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
discard """
|
||||||
|
nimout: '''0
|
||||||
|
0
|
||||||
|
0
|
||||||
|
{hallo: 123, welt: 456}'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tables
|
||||||
|
|
||||||
|
# bug #5327
|
||||||
|
|
||||||
|
type
|
||||||
|
MyType* = object
|
||||||
|
counter: int
|
||||||
|
|
||||||
|
proc foo(t: var MyType) =
|
||||||
|
echo t.counter
|
||||||
|
|
||||||
|
proc bar(t: MyType) =
|
||||||
|
echo t.counter
|
||||||
|
|
||||||
|
static:
|
||||||
|
var myValue: MyType
|
||||||
|
myValue.foo # works nicely
|
||||||
|
|
||||||
|
var refValue: ref MyType
|
||||||
|
refValue.new
|
||||||
|
|
||||||
|
refValue[].foo # fails to compile
|
||||||
|
refValue[].bar # works again nicely
|
||||||
|
|
||||||
|
static:
|
||||||
|
var otherTable = newTable[string, string]()
|
||||||
|
|
||||||
|
otherTable["hallo"] = "123"
|
||||||
|
otherTable["welt"] = "456"
|
||||||
|
|
||||||
|
echo otherTable
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
msg: '''2
|
nimout: '''2
|
||||||
3
|
3
|
||||||
4:2
|
4:2
|
||||||
Got Hi
|
Got Hi
|
||||||
|
|
@ -13,7 +13,7 @@ import macros, tables, strtabs
|
||||||
var ZOOT{.compileTime.} = initTable[int, int](2)
|
var ZOOT{.compileTime.} = initTable[int, int](2)
|
||||||
var iii {.compiletime.} = 1
|
var iii {.compiletime.} = 1
|
||||||
|
|
||||||
macro zoo:stmt=
|
macro zoo: untyped =
|
||||||
ZOOT[iii] = iii*2
|
ZOOT[iii] = iii*2
|
||||||
inc iii
|
inc iii
|
||||||
echo iii
|
echo iii
|
||||||
|
|
@ -22,7 +22,7 @@ zoo
|
||||||
zoo
|
zoo
|
||||||
|
|
||||||
|
|
||||||
macro tupleUnpack: stmt =
|
macro tupleUnpack: untyped =
|
||||||
var (y,z) = (4, 2)
|
var (y,z) = (4, 2)
|
||||||
echo y, ":", z
|
echo y, ":", z
|
||||||
|
|
||||||
|
|
@ -32,14 +32,14 @@ tupleUnpack
|
||||||
|
|
||||||
var x {.compileTime.}: StringTableRef
|
var x {.compileTime.}: StringTableRef
|
||||||
|
|
||||||
macro addStuff(stuff, body: expr): stmt {.immediate.} =
|
macro addStuff(stuff, body: untyped): untyped =
|
||||||
result = newNimNode(nnkStmtList)
|
result = newNimNode(nnkStmtList)
|
||||||
|
|
||||||
if x.isNil:
|
if x.isNil:
|
||||||
x = newStringTable(modeStyleInsensitive)
|
x = newStringTable(modeStyleInsensitive)
|
||||||
x[$stuff] = ""
|
x[$stuff] = ""
|
||||||
|
|
||||||
macro dump(): stmt =
|
macro dump(): untyped =
|
||||||
result = newNimNode(nnkStmtList)
|
result = newNimNode(nnkStmtList)
|
||||||
for y in x.keys: echo "Got ", y
|
for y in x.keys: echo "Got ", y
|
||||||
|
|
||||||
|
|
|
||||||
30
tests/vm/tcopy_global_var.nim
Normal file
30
tests/vm/tcopy_global_var.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
discard """
|
||||||
|
nimout: "static done"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #5269
|
||||||
|
|
||||||
|
proc assertEq[T](arg0, arg1: T): void =
|
||||||
|
assert arg0 == arg1, $arg0 & " == " & $arg1
|
||||||
|
|
||||||
|
type
|
||||||
|
MyType = object
|
||||||
|
str: string
|
||||||
|
a: int
|
||||||
|
|
||||||
|
block:
|
||||||
|
var localValue = MyType(str: "Original strning, (OK)", a: 0)
|
||||||
|
var valueCopy = localValue
|
||||||
|
valueCopy.a = 123
|
||||||
|
valueCopy.str = "Modified strning, (not OK when in localValue)"
|
||||||
|
assertEq(localValue.str, "Original strning, (OK)")
|
||||||
|
assertEq(localValue.a, 0)
|
||||||
|
|
||||||
|
static:
|
||||||
|
var localValue = MyType(str: "Original strning, (OK)", a: 0)
|
||||||
|
var valueCopy = localValue
|
||||||
|
valueCopy.a = 123
|
||||||
|
valueCopy.str = "Modified strning, (not OK when in localValue)"
|
||||||
|
assertEq(localValue.str, "Original strning, (OK)")
|
||||||
|
assertEq(localValue.a, 0)
|
||||||
|
echo "static done"
|
||||||
|
|
@ -22,7 +22,7 @@ proc download(pkg: string; c: Controls) {.async.} =
|
||||||
|
|
||||||
client.onProgressChanged = onProgressChanged
|
client.onProgressChanged = onProgressChanged
|
||||||
# XXX give a destination filename instead
|
# XXX give a destination filename instead
|
||||||
let contents = await client.getContent("http://nim-lang.org/download/" & pkg & ".zip")
|
let contents = await client.getContent("https://nim-lang.org/download/" & pkg & ".zip")
|
||||||
let z = "dist" / pkg & ".zip"
|
let z = "dist" / pkg & ".zip"
|
||||||
# XXX make this async somehow:
|
# XXX make this async somehow:
|
||||||
writeFile(z, contents)
|
writeFile(z, contents)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
|
|
||||||
# -------------- post unzip steps ---------------------------------------------
|
# -------------- post unzip steps ---------------------------------------------
|
||||||
|
|
||||||
import strutils, os, osproc, browsers
|
import strutils, os, osproc, streams, browsers
|
||||||
|
|
||||||
const arch = $(sizeof(int)*8)
|
const arch = $(sizeof(int)*8)
|
||||||
|
|
||||||
proc downloadMingw() =
|
proc downloadMingw() =
|
||||||
openDefaultBrowser("http://nim-lang.org/download/mingw$1.zip" % arch)
|
openDefaultBrowser("https://nim-lang.org/download/mingw$1.zip" % arch)
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
import registry
|
import registry
|
||||||
|
|
@ -86,18 +86,21 @@ when defined(windows):
|
||||||
proc checkGccArch(mingw: string): bool =
|
proc checkGccArch(mingw: string): bool =
|
||||||
let gccExe = mingw / r"gcc.exe"
|
let gccExe = mingw / r"gcc.exe"
|
||||||
if fileExists(gccExe):
|
if fileExists(gccExe):
|
||||||
|
const nimCompat = "nim_compat.c"
|
||||||
|
writeFile(nimCompat, """typedef int
|
||||||
|
Nim_and_C_compiler_disagree_on_target_architecture[
|
||||||
|
$# == sizeof(void*) ? 1 : -1];
|
||||||
|
""" % $sizeof(int))
|
||||||
try:
|
try:
|
||||||
let arch = execProcess(gccExe, ["-dumpmachine"], nil, {poStdErrToStdOut,
|
let p = startProcess(gccExe, "", ["-c", nimCompat], nil,
|
||||||
poUsePath}).strip
|
{poStdErrToStdOut, poUsePath})
|
||||||
when hostCPU == "i386":
|
#echo p.outputStream.readAll()
|
||||||
result = (arch.contains("i686-") and not arch.contains("w64")) or
|
result = p.waitForExit() == 0
|
||||||
arch == "mingw32"
|
|
||||||
elif hostCPU == "amd64":
|
|
||||||
result = arch.contains("x86_64-") or arch.contains("i686-w64-mingw32")
|
|
||||||
else:
|
|
||||||
{.error: "Unknown CPU for Windows.".}
|
|
||||||
except OSError, IOError:
|
except OSError, IOError:
|
||||||
result = false
|
result = false
|
||||||
|
finally:
|
||||||
|
removeFile(nimCompat)
|
||||||
|
removeFile(nimCompat.changeFileExt("o"))
|
||||||
|
|
||||||
proc defaultMingwLocations(): seq[string] =
|
proc defaultMingwLocations(): seq[string] =
|
||||||
proc probeDir(dir: string; result: var seq[string]) =
|
proc probeDir(dir: string; result: var seq[string]) =
|
||||||
|
|
|
||||||
|
|
@ -507,7 +507,7 @@ proc srcdist(c: var ConfigData) =
|
||||||
if not existsDir(getOutputDir(c) / "c_code"):
|
if not existsDir(getOutputDir(c) / "c_code"):
|
||||||
createDir(getOutputDir(c) / "c_code")
|
createDir(getOutputDir(c) / "c_code")
|
||||||
for x in walkFiles(c.libpath / "lib/*.h"):
|
for x in walkFiles(c.libpath / "lib/*.h"):
|
||||||
echo(getOutputDir(c) / "c_code" / extractFilename(x))
|
when false: echo(getOutputDir(c) / "c_code" / extractFilename(x))
|
||||||
copyFile(dest=getOutputDir(c) / "c_code" / extractFilename(x), source=x)
|
copyFile(dest=getOutputDir(c) / "c_code" / extractFilename(x), source=x)
|
||||||
var winIndex = -1
|
var winIndex = -1
|
||||||
var intel32Index = -1
|
var intel32Index = -1
|
||||||
|
|
@ -624,7 +624,7 @@ proc xzDist(c: var ConfigData; windowsZip=false) =
|
||||||
|
|
||||||
proc processFile(destFile, src: string) =
|
proc processFile(destFile, src: string) =
|
||||||
let dest = tmpDir / destFile
|
let dest = tmpDir / destFile
|
||||||
echo "Copying ", src, " to ", dest
|
when false: echo "Copying ", src, " to ", dest
|
||||||
if not existsFile(src):
|
if not existsFile(src):
|
||||||
echo "[Warning] Source file doesn't exist: ", src
|
echo "[Warning] Source file doesn't exist: ", src
|
||||||
let destDir = dest.splitFile.dir
|
let destDir = dest.splitFile.dir
|
||||||
|
|
|
||||||
52
tools/nimsuggest/crashtester.nim
Normal file
52
tools/nimsuggest/crashtester.nim
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
|
||||||
|
import strutils, os, osproc, streams
|
||||||
|
|
||||||
|
const
|
||||||
|
DummyEof = "!EOF!"
|
||||||
|
|
||||||
|
proc getPosition(s: string): (int, int) =
|
||||||
|
result = (1, 1)
|
||||||
|
var col = 0
|
||||||
|
for i in 0..<s.len:
|
||||||
|
if s[i] == '\L':
|
||||||
|
inc result[0]
|
||||||
|
col = 0
|
||||||
|
else:
|
||||||
|
inc col
|
||||||
|
result[1] = col+1
|
||||||
|
|
||||||
|
proc callNimsuggest() =
|
||||||
|
let cl = parseCmdLine("nimsuggest --tester temp000.nim")
|
||||||
|
var p = startProcess(command=cl[0], args=cl[1 .. ^1],
|
||||||
|
options={poStdErrToStdOut, poUsePath,
|
||||||
|
poInteractive, poDemon})
|
||||||
|
let outp = p.outputStream
|
||||||
|
let inp = p.inputStream
|
||||||
|
var report = ""
|
||||||
|
var a = newStringOfCap(120)
|
||||||
|
let contents = readFile("tools/nimsuggest/crashtester.nim")
|
||||||
|
try:
|
||||||
|
# read and ignore anything nimsuggest says at startup:
|
||||||
|
while outp.readLine(a):
|
||||||
|
if a == DummyEof: break
|
||||||
|
|
||||||
|
var line = 0
|
||||||
|
for i in 0..< contents.len:
|
||||||
|
let slic = contents[0..i]
|
||||||
|
writeFile("temp000.nim", slic)
|
||||||
|
let (line, col) = getPosition(slic)
|
||||||
|
inp.writeLine("sug temp000.nim:$#:$#" % [$line, $col])
|
||||||
|
inp.flush()
|
||||||
|
var answer = ""
|
||||||
|
while outp.readLine(a):
|
||||||
|
if a == DummyEof: break
|
||||||
|
answer.add a
|
||||||
|
answer.add '\L'
|
||||||
|
echo answer
|
||||||
|
finally:
|
||||||
|
inp.writeLine("quit")
|
||||||
|
inp.flush()
|
||||||
|
close(p)
|
||||||
|
|
||||||
|
callNimsuggest()
|
||||||
|
|
@ -418,7 +418,7 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||||
options.gProjectName = unixToNativePath(p.key)
|
options.gProjectName = unixToNativePath(p.key)
|
||||||
# if processArgument(pass, p, argsCount): break
|
# if processArgument(pass, p, argsCount): break
|
||||||
|
|
||||||
proc handleCmdLine(cache: IdentCache) =
|
proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
|
||||||
if paramCount() == 0:
|
if paramCount() == 0:
|
||||||
stdout.writeline(Usage)
|
stdout.writeline(Usage)
|
||||||
else:
|
else:
|
||||||
|
|
@ -444,23 +444,23 @@ proc handleCmdLine(cache: IdentCache) =
|
||||||
gPrefixDir = binaryPath.splitPath().head.parentDir()
|
gPrefixDir = binaryPath.splitPath().head.parentDir()
|
||||||
#msgs.writelnHook = proc (line: string) = logStr(line)
|
#msgs.writelnHook = proc (line: string) = logStr(line)
|
||||||
|
|
||||||
loadConfigs(DefaultConfig, cache) # load all config files
|
loadConfigs(DefaultConfig, cache, config) # load all config files
|
||||||
# now process command line arguments again, because some options in the
|
# now process command line arguments again, because some options in the
|
||||||
# command line can overwite the config file's settings
|
# command line can overwite the config file's settings
|
||||||
options.command = "nimsuggest"
|
options.command = "nimsuggest"
|
||||||
let scriptFile = gProjectFull.changeFileExt("nims")
|
let scriptFile = gProjectFull.changeFileExt("nims")
|
||||||
if fileExists(scriptFile):
|
if fileExists(scriptFile):
|
||||||
runNimScript(cache, scriptFile, freshDefines=false)
|
runNimScript(cache, scriptFile, freshDefines=false, config)
|
||||||
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
|
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
|
||||||
if scriptFile == gProjectFull: return
|
if scriptFile == gProjectFull: return
|
||||||
elif fileExists(gProjectPath / "config.nims"):
|
elif fileExists(gProjectPath / "config.nims"):
|
||||||
# directory wide NimScript file
|
# directory wide NimScript file
|
||||||
runNimScript(cache, gProjectPath / "config.nims", freshDefines=false)
|
runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config)
|
||||||
|
|
||||||
extccomp.initVars()
|
extccomp.initVars()
|
||||||
processCmdLine(passCmd2, "")
|
processCmdLine(passCmd2, "")
|
||||||
|
|
||||||
let graph = newModuleGraph()
|
let graph = newModuleGraph(config)
|
||||||
graph.suggestMode = true
|
graph.suggestMode = true
|
||||||
mainCommand(graph, cache)
|
mainCommand(graph, cache)
|
||||||
|
|
||||||
|
|
@ -472,4 +472,4 @@ when false:
|
||||||
|
|
||||||
condsyms.initDefines()
|
condsyms.initDefines()
|
||||||
defineSymbol "nimsuggest"
|
defineSymbol "nimsuggest"
|
||||||
handleCmdline(newIdentCache())
|
handleCmdline(newIdentCache(), newConfigRef())
|
||||||
|
|
|
||||||
|
|
@ -161,8 +161,16 @@ proc runTest(filename: string): int =
|
||||||
answer.add '\L'
|
answer.add '\L'
|
||||||
if resp != answer and not smartCompare(resp, answer):
|
if resp != answer and not smartCompare(resp, answer):
|
||||||
report.add "\nTest failed: " & filename
|
report.add "\nTest failed: " & filename
|
||||||
report.add "\n Expected: " & resp
|
var hasDiff = false
|
||||||
report.add "\n But got: " & answer
|
for i in 0..min(resp.len-1, answer.len-1):
|
||||||
|
if resp[i] != answer[i]:
|
||||||
|
report.add "\n Expected: " & resp.substr(i)
|
||||||
|
report.add "\n But got: " & answer.substr(i)
|
||||||
|
hasDiff = true
|
||||||
|
break
|
||||||
|
if not hasDiff:
|
||||||
|
report.add "\n Expected: " & resp
|
||||||
|
report.add "\n But got: " & answer
|
||||||
finally:
|
finally:
|
||||||
inp.writeLine("quit")
|
inp.writeLine("quit")
|
||||||
inp.flush()
|
inp.flush()
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
discard """
|
discard """
|
||||||
$nimsuggest --tester $file
|
$nimsuggest --tester $file
|
||||||
>def $1
|
>def $1
|
||||||
def;;skProc;;tdef1.hello;;proc ();;$file;;9;;5;;"";;100
|
def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"Return hello";;100
|
||||||
>def $1
|
>def $1
|
||||||
def;;skProc;;tdef1.hello;;proc ();;$file;;9;;5;;"";;100
|
def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"Return hello";;100
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc hello() string =
|
proc hello(): string =
|
||||||
## Return hello
|
## Return hello
|
||||||
"Hello"
|
"Hello"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
discard """
|
discard """
|
||||||
$nimsuggest --tester lib/pure/strutils.nim
|
$nimsuggest --tester lib/pure/strutils.nim
|
||||||
>def lib/pure/strutils.nim:2300:6
|
>def lib/pure/strutils.nim:2300:6
|
||||||
def;;skTemplate;;system.doAssert;;proc (cond: bool, msg: string): typed;;*/lib/system.nim;;*;;9;;"";;100
|
def;;skTemplate;;system.doAssert;;proc (cond: bool, msg: string): typed;;*/lib/system.nim;;*;;9;;"same as `assert` but is always turned on and not affected by the\x0A``--assertions`` command line switch.";;100
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Line 2300 in strutils.nim is doAssert and this is unlikely to change
|
# Line 2300 in strutils.nim is doAssert and this is unlikely to change
|
||||||
|
|
|
||||||
213
tools/nimsuggest/tests/twithin_macro.nim
Normal file
213
tools/nimsuggest/tests/twithin_macro.nim
Normal file
|
|
@ -0,0 +1,213 @@
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
macro class*(head, body: untyped): untyped =
|
||||||
|
# The macro is immediate, since all its parameters are untyped.
|
||||||
|
# This means, it doesn't resolve identifiers passed to it.
|
||||||
|
|
||||||
|
var typeName, baseName: NimNode
|
||||||
|
|
||||||
|
# flag if object should be exported
|
||||||
|
var exported: bool
|
||||||
|
|
||||||
|
if head.kind == nnkInfix and head[0].ident == !"of":
|
||||||
|
# `head` is expression `typeName of baseClass`
|
||||||
|
# echo head.treeRepr
|
||||||
|
# --------------------
|
||||||
|
# Infix
|
||||||
|
# Ident !"of"
|
||||||
|
# Ident !"Animal"
|
||||||
|
# Ident !"RootObj"
|
||||||
|
typeName = head[1]
|
||||||
|
baseName = head[2]
|
||||||
|
|
||||||
|
elif head.kind == nnkInfix and head[0].ident == !"*" and
|
||||||
|
head[2].kind == nnkPrefix and head[2][0].ident == !"of":
|
||||||
|
# `head` is expression `typeName* of baseClass`
|
||||||
|
# echo head.treeRepr
|
||||||
|
# --------------------
|
||||||
|
# Infix
|
||||||
|
# Ident !"*"
|
||||||
|
# Ident !"Animal"
|
||||||
|
# Prefix
|
||||||
|
# Ident !"of"
|
||||||
|
# Ident !"RootObj"
|
||||||
|
typeName = head[1]
|
||||||
|
baseName = head[2][1]
|
||||||
|
exported = true
|
||||||
|
|
||||||
|
else:
|
||||||
|
quit "Invalid node: " & head.lispRepr
|
||||||
|
|
||||||
|
# The following prints out the AST structure:
|
||||||
|
#
|
||||||
|
# import macros
|
||||||
|
# dumptree:
|
||||||
|
# type X = ref object of Y
|
||||||
|
# z: int
|
||||||
|
# --------------------
|
||||||
|
# StmtList
|
||||||
|
# TypeSection
|
||||||
|
# TypeDef
|
||||||
|
# Ident !"X"
|
||||||
|
# Empty
|
||||||
|
# RefTy
|
||||||
|
# ObjectTy
|
||||||
|
# Empty
|
||||||
|
# OfInherit
|
||||||
|
# Ident !"Y"
|
||||||
|
# RecList
|
||||||
|
# IdentDefs
|
||||||
|
# Ident !"z"
|
||||||
|
# Ident !"int"
|
||||||
|
# Empty
|
||||||
|
|
||||||
|
# create a type section in the result
|
||||||
|
result =
|
||||||
|
if exported:
|
||||||
|
# mark `typeName` with an asterisk
|
||||||
|
quote do:
|
||||||
|
type `typeName`* = ref object of `baseName`
|
||||||
|
else:
|
||||||
|
quote do:
|
||||||
|
type `typeName` = ref object of `baseName`
|
||||||
|
|
||||||
|
# echo treeRepr(body)
|
||||||
|
# --------------------
|
||||||
|
# StmtList
|
||||||
|
# VarSection
|
||||||
|
# IdentDefs
|
||||||
|
# Ident !"name"
|
||||||
|
# Ident !"string"
|
||||||
|
# Empty
|
||||||
|
# IdentDefs
|
||||||
|
# Ident !"age"
|
||||||
|
# Ident !"int"
|
||||||
|
# Empty
|
||||||
|
# MethodDef
|
||||||
|
# Ident !"vocalize"
|
||||||
|
# Empty
|
||||||
|
# Empty
|
||||||
|
# FormalParams
|
||||||
|
# Ident !"string"
|
||||||
|
# Empty
|
||||||
|
# Empty
|
||||||
|
# StmtList
|
||||||
|
# StrLit ...
|
||||||
|
# MethodDef
|
||||||
|
# Ident !"age_human_yrs"
|
||||||
|
# Empty
|
||||||
|
# Empty
|
||||||
|
# FormalParams
|
||||||
|
# Ident !"int"
|
||||||
|
# Empty
|
||||||
|
# Empty
|
||||||
|
# StmtList
|
||||||
|
# DotExpr
|
||||||
|
# Ident !"this"
|
||||||
|
# Ident !"age"
|
||||||
|
|
||||||
|
# var declarations will be turned into object fields
|
||||||
|
var recList = newNimNode(nnkRecList)
|
||||||
|
|
||||||
|
# expected name of constructor
|
||||||
|
let ctorName = newIdentNode("new" & $typeName)
|
||||||
|
|
||||||
|
# Iterate over the statements, adding `this: T`
|
||||||
|
# to the parameters of functions, unless the
|
||||||
|
# function is a constructor
|
||||||
|
for node in body.children:
|
||||||
|
case node.kind:
|
||||||
|
|
||||||
|
of nnkMethodDef, nnkProcDef:
|
||||||
|
# check if it is the ctor proc
|
||||||
|
if node.name.kind != nnkAccQuoted and node.name.basename == ctorName:
|
||||||
|
# specify the return type of the ctor proc
|
||||||
|
node.params[0] = typeName
|
||||||
|
else:
|
||||||
|
# inject `self: T` into the arguments
|
||||||
|
node.params.insert(1, newIdentDefs(ident("self"), typeName))
|
||||||
|
result.add(node)
|
||||||
|
|
||||||
|
of nnkVarSection:
|
||||||
|
# variables get turned into fields of the type.
|
||||||
|
for n in node.children:
|
||||||
|
recList.add(n)
|
||||||
|
|
||||||
|
else:
|
||||||
|
result.add(node)
|
||||||
|
|
||||||
|
# Inspect the tree structure:
|
||||||
|
#
|
||||||
|
# echo result.treeRepr
|
||||||
|
# --------------------
|
||||||
|
# StmtList
|
||||||
|
# TypeSection
|
||||||
|
# TypeDef
|
||||||
|
# Ident !"Animal"
|
||||||
|
# Empty
|
||||||
|
# RefTy
|
||||||
|
# ObjectTy
|
||||||
|
# Empty
|
||||||
|
# OfInherit
|
||||||
|
# Ident !"RootObj"
|
||||||
|
# Empty <= We want to replace this
|
||||||
|
# MethodDef
|
||||||
|
# ...
|
||||||
|
|
||||||
|
result[0][0][2][0][2] = recList
|
||||||
|
|
||||||
|
# Lets inspect the human-readable version of the output
|
||||||
|
#echo repr(result)
|
||||||
|
|
||||||
|
# ---
|
||||||
|
|
||||||
|
class Animal of RootObj:
|
||||||
|
var name: string
|
||||||
|
var age: int
|
||||||
|
method vocalize: string {.base.} = "..." # use `base` pragma to annonate base methods
|
||||||
|
method age_human_yrs: int {.base.} = self.age # `this` is injected
|
||||||
|
proc `$`: string = "animal:" & self.name & ":" & $self.age
|
||||||
|
|
||||||
|
class Dog of Animal:
|
||||||
|
method vocalize: string = "woof"
|
||||||
|
method age_human_yrs: int = self.age * 7
|
||||||
|
proc `$`: string = "dog:" & self.name & ":" & $self.age
|
||||||
|
|
||||||
|
class Cat of Animal:
|
||||||
|
method vocalize: string = "meow"
|
||||||
|
proc `$`: string = "cat:" & self.name & ":" & $self.age
|
||||||
|
|
||||||
|
class Rabbit of Animal:
|
||||||
|
proc newRabbit(name: string, age: int) = # the constructor doesn't need a return type
|
||||||
|
result = Rabbit(name: name, age: age)
|
||||||
|
method vocalize: string = "meep"
|
||||||
|
proc `$`: string =
|
||||||
|
self.#[!]#
|
||||||
|
result = "rabbit:" & self.name & ":" & $self.age
|
||||||
|
|
||||||
|
# ---
|
||||||
|
|
||||||
|
var animals: seq[Animal] = @[]
|
||||||
|
animals.add(Dog(name: "Sparky", age: 10))
|
||||||
|
animals.add(Cat(name: "Mitten", age: 10))
|
||||||
|
|
||||||
|
for a in animals:
|
||||||
|
echo a.vocalize()
|
||||||
|
echo a.age_human_yrs()
|
||||||
|
|
||||||
|
let r = newRabbit("Fluffy", 3)
|
||||||
|
echo r.vocalize()
|
||||||
|
echo r.age_human_yrs()
|
||||||
|
echo r
|
||||||
|
|
||||||
|
discard """
|
||||||
|
$nimsuggest --tester $file
|
||||||
|
>sug $1
|
||||||
|
sug;;skField;;name;;string;;$file;;166;;6;;"";;100
|
||||||
|
sug;;skField;;age;;int;;$file;;167;;6;;"";;100
|
||||||
|
sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int{.noSideEffect, gcsafe, locks: 0.};;$file;;169;;9;;"";;100
|
||||||
|
sug;;skMacro;;twithin_macro.class;;proc (head: untyped, body: untyped): untyped{.gcsafe, locks: <unknown>.};;$file;;4;;6;;"Iterates over the children of the NimNode ``n``.";;100
|
||||||
|
sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string{.noSideEffect, gcsafe, locks: 0.};;$file;;168;;9;;"";;100
|
||||||
|
sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string{.noSideEffect, gcsafe, locks: 0.};;$file;;184;;9;;"";;100*
|
||||||
|
"""
|
||||||
|
|
@ -263,8 +263,8 @@ proc findNim(): string =
|
||||||
|
|
||||||
proc exec(cmd: string) =
|
proc exec(cmd: string) =
|
||||||
echo(cmd)
|
echo(cmd)
|
||||||
let (_, exitCode) = osproc.execCmdEx(cmd)
|
let (outp, exitCode) = osproc.execCmdEx(cmd)
|
||||||
if exitCode != 0: quit("external program failed")
|
if exitCode != 0: quit outp
|
||||||
|
|
||||||
proc sexec(cmds: openarray[string]) =
|
proc sexec(cmds: openarray[string]) =
|
||||||
## Serial queue wrapper around exec.
|
## Serial queue wrapper around exec.
|
||||||
|
|
@ -272,10 +272,13 @@ proc sexec(cmds: openarray[string]) =
|
||||||
|
|
||||||
proc mexec(cmds: openarray[string], processors: int) =
|
proc mexec(cmds: openarray[string], processors: int) =
|
||||||
## Multiprocessor version of exec
|
## Multiprocessor version of exec
|
||||||
if processors < 2:
|
doAssert processors > 0, "nimweb needs at least one processor"
|
||||||
|
if processors == 1:
|
||||||
sexec(cmds)
|
sexec(cmds)
|
||||||
return
|
return
|
||||||
if execProcesses(cmds, {poStdErrToStdOut, poParentStreams, poEchoCmd}) != 0:
|
let r = execProcesses(cmds, {poStdErrToStdOut, poParentStreams, poEchoCmd},
|
||||||
|
n = processors)
|
||||||
|
if r != 0:
|
||||||
echo "external program failed, retrying serial work queue for logs!"
|
echo "external program failed, retrying serial work queue for logs!"
|
||||||
sexec(cmds)
|
sexec(cmds)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,15 +187,15 @@ runForever()
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4>Community</h4>
|
<h4>Community</h4>
|
||||||
<a href="http://forum.nim-lang.org">User Forum</a>
|
<a href="https://forum.nim-lang.org">User Forum</a>
|
||||||
<a href="http://webchat.freenode.net/?channels=nim">Online IRC</a>
|
<a href="http://webchat.freenode.net/?channels=nim">Online IRC</a>
|
||||||
<a href="http://irclogs.nim-lang.org/">IRC Logs</a>
|
<a href="https://irclogs.nim-lang.org/">IRC Logs</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="foot-legal">
|
<div id="foot-legal">
|
||||||
<h4>Written in Nim - Powered by <a href="https://github.com/dom96/jester">Jester</a></h4>
|
<h4>Written in Nim - Powered by <a href="https://github.com/dom96/jester">Jester</a></h4>
|
||||||
Web Design by <a href="http://reign-studios.net/philipwitte/">Philip Witte</a> & <a href="http://picheta.me/">Dominik Picheta</a><br>
|
Web Design by <a href="http://reign-studios.net/philipwitte/">Philip Witte</a> & <a href="http://picheta.me/">Dominik Picheta</a><br>
|
||||||
Copyright © 2015 - <a href="http://nim-lang.org/blog/">Andreas Rumpf</a> & <a href="https://github.com/nim-lang/nim/graphs/contributors">Contributors</a>
|
Copyright © 2017 - <a href="https://nim-lang.org/blog/">Andreas Rumpf</a> & <a href="https://github.com/nim-lang/nim/graphs/contributors">Contributors</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Nim's Community
|
||||||
Forum
|
Forum
|
||||||
-----
|
-----
|
||||||
|
|
||||||
The `Nim forum <http://forum.nim-lang.org/>`_ is the place where most
|
The `Nim forum <https://forum.nim-lang.org/>`_ is the place where most
|
||||||
discussions related to the language happen. It not only includes discussions
|
discussions related to the language happen. It not only includes discussions
|
||||||
relating to the design of Nim but also allows for beginners to ask questions
|
relating to the design of Nim but also allows for beginners to ask questions
|
||||||
relating to Nim.
|
relating to Nim.
|
||||||
|
|
@ -35,7 +35,7 @@ Nim's Community
|
||||||
welcome any questions that you may have!
|
welcome any questions that you may have!
|
||||||
|
|
||||||
You may also be interested in reading the
|
You may also be interested in reading the
|
||||||
`IRC logs <http://irclogs.nim-lang.org/>`_ which are an archive of all
|
`IRC logs <https://irclogs.nim-lang.org/>`_ which are an archive of all
|
||||||
of the previous discussions that took place in the IRC channel.
|
of the previous discussions that took place in the IRC channel.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,14 @@ We now encourage you to install via the provided zipfiles:
|
||||||
* | 64 bit: `nim-0.16.0_x64.zip <download/nim-0.16.0_x64.zip>`_
|
* | 64 bit: `nim-0.16.0_x64.zip <download/nim-0.16.0_x64.zip>`_
|
||||||
| SHA-256 e667cdad1ae8e9429147aea5031fa8a80c4ccef6d274cec0e9480252d9c3168c
|
| SHA-256 e667cdad1ae8e9429147aea5031fa8a80c4ccef6d274cec0e9480252d9c3168c
|
||||||
|
|
||||||
Unzip these where you want and optionally run ``finish.exe`` to
|
Unzip these where you want and **optionally** run ``finish.exe`` to
|
||||||
detect your MingW environment.
|
detect your MingW environment. (Though that's not reliable yet.)
|
||||||
|
|
||||||
|
You can find the required DLLs here, if you lack them for some reason:
|
||||||
|
|
||||||
|
* | 32 and 64 bit: `DLLs.zip <download/dlls.zip>`_
|
||||||
|
| SHA-256 198112d3d6dc74d7964ba452158d44bfa57adef4dc47be8c39903f2a24e4a555
|
||||||
|
|
||||||
|
|
||||||
Exes
|
Exes
|
||||||
%%%%
|
%%%%
|
||||||
|
|
|
||||||
|
|
@ -41,3 +41,69 @@ these procedures.
|
||||||
|
|
||||||
In the near future we will be converting all exception types to refs to
|
In the near future we will be converting all exception types to refs to
|
||||||
remove the need for the ``newException`` template.
|
remove the need for the ``newException`` template.
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
The list below has been generated based on the commits in Nim's git
|
||||||
|
repository. As such it lists only the issues which have been closed
|
||||||
|
via a commit, for a full list see
|
||||||
|
`this link on Github <https://github.com/nim-lang/Nim/issues?utf8=%E2%9C%93&q=is%3Aissue+closed%3A%222017-01-07+..+2017-02-06%22+>`_.
|
||||||
|
|
||||||
|
- Fixed "Weird compilation bug"
|
||||||
|
(`#4884 <https://github.com/nim-lang/Nim/issues/4884>`_)
|
||||||
|
- Fixed "Return by arg optimization does not set result to default value"
|
||||||
|
(`#5098 <https://github.com/nim-lang/Nim/issues/5098>`_)
|
||||||
|
- Fixed "upcoming asyncdispatch doesn't remove recv callback if remote side closed socket"
|
||||||
|
(`#5128 <https://github.com/nim-lang/Nim/issues/5128>`_)
|
||||||
|
- Fixed "compiler bug, executable writes into wrong memory"
|
||||||
|
(`#5218 <https://github.com/nim-lang/Nim/issues/5218>`_)
|
||||||
|
- Fixed "Module aliasing fails when multiple modules have the same original name"
|
||||||
|
(`#5112 <https://github.com/nim-lang/Nim/issues/5112>`_)
|
||||||
|
- Fixed "JS: var argument + case expr with arg = bad codegen"
|
||||||
|
(`#5244 <https://github.com/nim-lang/Nim/issues/5244>`_)
|
||||||
|
- Fixed "compiler reject proc's param shadowing inside template"
|
||||||
|
(`#5225 <https://github.com/nim-lang/Nim/issues/5225>`_)
|
||||||
|
- Fixed "const value not accessible in proc"
|
||||||
|
(`#3434 <https://github.com/nim-lang/Nim/issues/3434>`_)
|
||||||
|
- Fixed "Compilation regression 0.13.0 vs 0.16.0 in compile-time evaluation"
|
||||||
|
(`#5237 <https://github.com/nim-lang/Nim/issues/5237>`_)
|
||||||
|
- Fixed "Regression: JS: wrong field-access codegen"
|
||||||
|
(`#5234 <https://github.com/nim-lang/Nim/issues/5234>`_)
|
||||||
|
- Fixed "fixes #5234"
|
||||||
|
(`#5240 <https://github.com/nim-lang/Nim/issues/5240>`_)
|
||||||
|
- Fixed "JS Codegen: duplicated fields in object constructor"
|
||||||
|
(`#5271 <https://github.com/nim-lang/Nim/issues/5271>`_)
|
||||||
|
- Fixed "RFC: improving JavaScript FFI"
|
||||||
|
(`#4873 <https://github.com/nim-lang/Nim/issues/4873>`_)
|
||||||
|
- Fixed "Wrong result type when using bitwise and"
|
||||||
|
(`#5216 <https://github.com/nim-lang/Nim/issues/5216>`_)
|
||||||
|
- Fixed "upcoming.asyncdispatch is prone to memory leaks"
|
||||||
|
(`#5290 <https://github.com/nim-lang/Nim/issues/5290>`_)
|
||||||
|
- Fixed "Using threadvars leads to crash on Windows when threads are created/destroyed"
|
||||||
|
(`#5301 <https://github.com/nim-lang/Nim/issues/5301>`_)
|
||||||
|
- Fixed "Type inferring templates do not work with non-ref types."
|
||||||
|
(`#4973 <https://github.com/nim-lang/Nim/issues/4973>`_)
|
||||||
|
- Fixed "Nimble package list no longer works on lib.html"
|
||||||
|
(`#5318 <https://github.com/nim-lang/Nim/issues/5318>`_)
|
||||||
|
- Fixed "Missing file name and line number in error message"
|
||||||
|
(`#4992 <https://github.com/nim-lang/Nim/issues/4992>`_)
|
||||||
|
- Fixed "ref type can't be converted to var parameter in VM"
|
||||||
|
(`#5327 <https://github.com/nim-lang/Nim/issues/5327>`_)
|
||||||
|
- Fixed "nimweb ignores the value of --parallelBuild"
|
||||||
|
(`#5328 <https://github.com/nim-lang/Nim/issues/5328>`_)
|
||||||
|
- Fixed "Cannot unregister/close AsyncEvent from within its handler"
|
||||||
|
(`#5331 <https://github.com/nim-lang/Nim/issues/5331>`_)
|
||||||
|
- Fixed "name collision with template instanciated generic inline function with inlined iterator specialization used from different modules"
|
||||||
|
(`#5285 <https://github.com/nim-lang/Nim/issues/5285>`_)
|
||||||
|
- Fixed "object in VM does not have value semantic"
|
||||||
|
(`#5269 <https://github.com/nim-lang/Nim/issues/5269>`_)
|
||||||
|
- Fixed "Unstable tuple destructuring behavior in Nim VM"
|
||||||
|
(`#5221 <https://github.com/nim-lang/Nim/issues/5221>`_)
|
||||||
|
- Fixed "nre module breaks os templates"
|
||||||
|
(`#4996 <https://github.com/nim-lang/Nim/issues/4996>`_)
|
||||||
|
- Fixed "Cannot implement distinct seq with setLen"
|
||||||
|
(`#5090 <https://github.com/nim-lang/Nim/issues/5090>`_)
|
||||||
|
- Fixed "await inside array/dict literal produces invalid code"
|
||||||
|
(`#5314 <https://github.com/nim-lang/Nim/issues/5314>`_)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue