commit
17d3c6f3f3
81 changed files with 1074 additions and 1398 deletions
|
|
@ -11,6 +11,10 @@
|
||||||
to deal with!
|
to deal with!
|
||||||
- Indexing into a ``cstring`` for the JS target is now mapped
|
- Indexing into a ``cstring`` for the JS target is now mapped
|
||||||
to ``charCodeAt``.
|
to ``charCodeAt``.
|
||||||
|
- Assignments that would "slice" an object into its supertype are not prevented
|
||||||
|
at runtime. Use ``ref object`` with inheritance rather than ``object`` with
|
||||||
|
inheritance to prevent this issue.
|
||||||
|
|
||||||
|
|
||||||
#### Breaking changes in the standard library
|
#### Breaking changes in the standard library
|
||||||
|
|
||||||
|
|
@ -27,6 +31,7 @@
|
||||||
- ``proc `-`*(a, b: Time): int64`` in the ``times`` module has changed return type
|
- ``proc `-`*(a, b: Time): int64`` in the ``times`` module has changed return type
|
||||||
to ``times.Duration`` in order to support higher time resolutions.
|
to ``times.Duration`` in order to support higher time resolutions.
|
||||||
The proc is no longer deprecated.
|
The proc is no longer deprecated.
|
||||||
|
- ``posix.Timeval.tv_sec`` has changed type to ``posix.Time``.
|
||||||
|
|
||||||
#### Breaking changes in the compiler
|
#### Breaking changes in the compiler
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1042,9 +1042,9 @@ proc newNode*(kind: TNodeKind): PNode =
|
||||||
new(result)
|
new(result)
|
||||||
result.kind = kind
|
result.kind = kind
|
||||||
#result.info = UnknownLineInfo() inlined:
|
#result.info = UnknownLineInfo() inlined:
|
||||||
result.info.fileIndex = int32(-1)
|
result.info.fileIndex = InvalidFileIdx
|
||||||
result.info.col = int16(-1)
|
result.info.col = int16(-1)
|
||||||
result.info.line = int16(-1)
|
result.info.line = uint16(0)
|
||||||
when defined(useNodeIds):
|
when defined(useNodeIds):
|
||||||
result.id = gNodeId
|
result.id = gNodeId
|
||||||
if result.id == nodeIdToDebug:
|
if result.id == nodeIdToDebug:
|
||||||
|
|
@ -1116,13 +1116,13 @@ proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
|
||||||
s.typ = t
|
s.typ = t
|
||||||
result = s
|
result = s
|
||||||
|
|
||||||
template fileIdx*(c: PSym): int32 =
|
template fileIdx*(c: PSym): FileIndex =
|
||||||
# XXX: this should be used only on module symbols
|
# XXX: this should be used only on module symbols
|
||||||
c.position.int32
|
c.position.FileIndex
|
||||||
|
|
||||||
template filename*(c: PSym): string =
|
template filename*(c: PSym): string =
|
||||||
# XXX: this should be used only on module symbols
|
# XXX: this should be used only on module symbols
|
||||||
c.position.int32.toFilename
|
c.position.FileIndex.toFilename
|
||||||
|
|
||||||
proc appendToModule*(m: PSym, n: PNode) =
|
proc appendToModule*(m: PSym, n: PNode) =
|
||||||
## The compiler will use this internally to add nodes that will be
|
## The compiler will use this internally to add nodes that will be
|
||||||
|
|
|
||||||
|
|
@ -72,24 +72,25 @@ proc bitSetContains(x, y: TBitSet): bool =
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
# Number of set bits for all values of int8
|
# Number of set bits for all values of int8
|
||||||
const populationCount: array[low(int8)..high(int8), int8] = [
|
const populationCount: array[low(int8)..high(int8), int8] = block:
|
||||||
1.int8, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
var arr: array[low(int8)..high(int8), int8]
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
proc countSetBits(x: int8): int8 =
|
||||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
return
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
( x and 0b00000001'i8) +
|
||||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
((x and 0b00000010'i8) shr 1) +
|
||||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
((x and 0b00000100'i8) shr 2) +
|
||||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
|
((x and 0b00001000'i8) shr 3) +
|
||||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
((x and 0b00010000'i8) shr 4) +
|
||||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
((x and 0b00100000'i8) shr 5) +
|
||||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
((x and 0b01000000'i8) shr 6) +
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
((x and 0b10000000'i8) shr 7)
|
||||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
||||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
for it in low(int8)..high(int8):
|
||||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7
|
arr[it] = countSetBits(it)
|
||||||
]
|
|
||||||
|
arr
|
||||||
|
|
||||||
proc bitSetCard(x: TBitSet): BiggestInt =
|
proc bitSetCard(x: TBitSet): BiggestInt =
|
||||||
for it in x:
|
for it in x:
|
||||||
|
|
|
||||||
|
|
@ -2023,7 +2023,7 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} =
|
||||||
let theMacro = it[0].sym
|
let theMacro = it[0].sym
|
||||||
add p.s(cpsStmts), initFrameNoDebug(p, frameName,
|
add p.s(cpsStmts), initFrameNoDebug(p, frameName,
|
||||||
makeCString theMacro.name.s,
|
makeCString theMacro.name.s,
|
||||||
theMacro.info.quotedFilename, it.info.line)
|
theMacro.info.quotedFilename, it.info.line.int)
|
||||||
else:
|
else:
|
||||||
genStmts(p, it)
|
genStmts(p, it)
|
||||||
if n.len > 0: exprOrStmt
|
if n.len > 0: exprOrStmt
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||||
line.rope, makeCString(toFilename(tt.info)))
|
line.rope, makeCString(toFilename(tt.info)))
|
||||||
elif ({optLineTrace, optStackTrace} * p.options ==
|
elif ({optLineTrace, optStackTrace} * p.options ==
|
||||||
{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 != InvalidFileIDX:
|
||||||
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)
|
||||||
|
|
@ -1301,7 +1301,7 @@ proc resetCgenModules*(g: BModuleList) =
|
||||||
for m in cgenModules(g): resetModule(m)
|
for m in cgenModules(g): resetModule(m)
|
||||||
|
|
||||||
proc rawNewModule(g: BModuleList; module: PSym): BModule =
|
proc rawNewModule(g: BModuleList; module: PSym): BModule =
|
||||||
result = rawNewModule(g, module, module.position.int32.toFullPath)
|
result = rawNewModule(g, module, module.position.FileIndex.toFullPath)
|
||||||
|
|
||||||
proc newModule(g: BModuleList; module: PSym): BModule =
|
proc newModule(g: BModuleList; module: PSym): BModule =
|
||||||
# we should create only one cgen module for each module sym
|
# we should create only one cgen module for each module sym
|
||||||
|
|
@ -1311,7 +1311,7 @@ proc newModule(g: BModuleList; module: PSym): BModule =
|
||||||
|
|
||||||
if (optDeadCodeElim in gGlobalOptions):
|
if (optDeadCodeElim in gGlobalOptions):
|
||||||
if (sfDeadCodeElim in module.flags):
|
if (sfDeadCodeElim in module.flags):
|
||||||
internalError("added pending module twice: " & module.filename)
|
internalError("added pending module twice: " & toFilename(FileIndex module.position))
|
||||||
|
|
||||||
template injectG(config) {.dirty.} =
|
template injectG(config) {.dirty.} =
|
||||||
if graph.backend == nil:
|
if graph.backend == nil:
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,14 @@ proc writeAdvancedUsage(pass: TCmdLinePass) =
|
||||||
{msgStdout})
|
{msgStdout})
|
||||||
msgQuit(0)
|
msgQuit(0)
|
||||||
|
|
||||||
|
proc writeFullhelp(pass: TCmdLinePass) =
|
||||||
|
if pass == passCmd1:
|
||||||
|
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||||
|
platform.OS[platform.hostOS].name,
|
||||||
|
CPU[platform.hostCPU].name]) & Usage & AdvancedUsage,
|
||||||
|
{msgStdout})
|
||||||
|
msgQuit(0)
|
||||||
|
|
||||||
proc writeVersionInfo(pass: TCmdLinePass) =
|
proc writeVersionInfo(pass: TCmdLinePass) =
|
||||||
if pass == passCmd1:
|
if pass == passCmd1:
|
||||||
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
msgWriteln(`%`(HelpMessage, [VersionAsString,
|
||||||
|
|
@ -311,7 +319,7 @@ proc trackDirty(arg: string, info: TLineInfo) =
|
||||||
localError(info, errInvalidNumber, a[2])
|
localError(info, errInvalidNumber, a[2])
|
||||||
|
|
||||||
let dirtyOriginalIdx = a[1].fileInfoIdx
|
let dirtyOriginalIdx = a[1].fileInfoIdx
|
||||||
if dirtyOriginalIdx >= 0:
|
if dirtyOriginalIdx.int32 >= 0:
|
||||||
msgs.setDirtyFile(dirtyOriginalIdx, a[0])
|
msgs.setDirtyFile(dirtyOriginalIdx, a[0])
|
||||||
|
|
||||||
gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
|
gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
|
||||||
|
|
@ -611,6 +619,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
of "advanced":
|
of "advanced":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(switch, arg, pass, info)
|
||||||
writeAdvancedUsage(pass)
|
writeAdvancedUsage(pass)
|
||||||
|
of "fullhelp":
|
||||||
|
expectNoArg(switch, arg, pass, info)
|
||||||
|
writeFullhelp(pass)
|
||||||
of "help", "h":
|
of "help", "h":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(switch, arg, pass, info)
|
||||||
helpOnError(pass)
|
helpOnError(pass)
|
||||||
|
|
@ -702,7 +713,6 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(switch, arg, pass, info)
|
||||||
useNimNamespace = true
|
useNimNamespace = true
|
||||||
defineSymbol("cppCompileToNamespace")
|
defineSymbol("cppCompileToNamespace")
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -544,7 +544,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||||
|
|
||||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||||
|
|
||||||
result = %{ "name": %name, "type": %($k), "line": %n.info.line,
|
result = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
|
||||||
"col": %n.info.col}
|
"col": %n.info.col}
|
||||||
if comm != nil and comm != "":
|
if comm != nil and comm != "":
|
||||||
result["description"] = %comm
|
result["description"] = %comm
|
||||||
|
|
@ -618,7 +618,7 @@ proc generateJson*(d: PDoc, n: PNode) =
|
||||||
of nkCommentStmt:
|
of nkCommentStmt:
|
||||||
if n.comment != nil and startsWith(n.comment, "##"):
|
if n.comment != nil and startsWith(n.comment, "##"):
|
||||||
let stripped = n.comment.substr(2).strip
|
let stripped = n.comment.substr(2).strip
|
||||||
d.add %{ "comment": %stripped, "line": %n.info.line,
|
d.add %{ "comment": %stripped, "line": %n.info.line.int,
|
||||||
"col": %n.info.col }
|
"col": %n.info.col }
|
||||||
of nkProcDef:
|
of nkProcDef:
|
||||||
when useEffectSystem: documentRaises(n)
|
when useEffectSystem: documentRaises(n)
|
||||||
|
|
@ -790,7 +790,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string,
|
||||||
discard "fixme: error report"
|
discard "fixme: error report"
|
||||||
|
|
||||||
proc commandDoc*() =
|
proc commandDoc*() =
|
||||||
var ast = parseFile(gProjectMainIdx, newIdentCache())
|
var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
|
||||||
if ast == nil: return
|
if ast == nil: return
|
||||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||||
d.hasToc = true
|
d.hasToc = true
|
||||||
|
|
@ -840,7 +840,7 @@ proc commandRst2TeX*() =
|
||||||
commandRstAux(gProjectFull, TexExt)
|
commandRstAux(gProjectFull, TexExt)
|
||||||
|
|
||||||
proc commandJson*() =
|
proc commandJson*() =
|
||||||
var ast = parseFile(gProjectMainIdx, newIdentCache())
|
var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
|
||||||
if ast == nil: return
|
if ast == nil: return
|
||||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||||
d.hasToc = true
|
d.hasToc = true
|
||||||
|
|
@ -855,7 +855,7 @@ proc commandJson*() =
|
||||||
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
|
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
|
||||||
|
|
||||||
proc commandTags*() =
|
proc commandTags*() =
|
||||||
var ast = parseFile(gProjectMainIdx, newIdentCache())
|
var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache())
|
||||||
if ast == nil: return
|
if ast == nil: return
|
||||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||||
d.hasToc = true
|
d.hasToc = true
|
||||||
|
|
|
||||||
|
|
@ -106,8 +106,9 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
|
||||||
for i in 1 .. genericParams:
|
for i in 1 .. genericParams:
|
||||||
result.addSon n.sons[givenRegularParams + i]
|
result.addSon n.sons[givenRegularParams + i]
|
||||||
|
|
||||||
|
# to prevent endless recursion in template instantiation
|
||||||
|
const evalTemplateLimit* = 1000
|
||||||
var evalTemplateCounter* = 0
|
var evalTemplateCounter* = 0
|
||||||
# to prevent endless recursion in templates instantiation
|
|
||||||
|
|
||||||
proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
|
proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
|
||||||
when true:
|
when true:
|
||||||
|
|
@ -133,7 +134,7 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
|
||||||
|
|
||||||
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
|
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
|
||||||
inc(evalTemplateCounter)
|
inc(evalTemplateCounter)
|
||||||
if evalTemplateCounter > 100:
|
if evalTemplateCounter > evalTemplateLimit:
|
||||||
globalError(n.info, errTemplateInstantiationTooNested)
|
globalError(n.info, errTemplateInstantiationTooNested)
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ const
|
||||||
proc newLine(p: var TTmplParser) =
|
proc newLine(p: var TTmplParser) =
|
||||||
llStreamWrite(p.outp, repeat(')', p.emitPar))
|
llStreamWrite(p.outp, repeat(')', p.emitPar))
|
||||||
p.emitPar = 0
|
p.emitPar = 0
|
||||||
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
|
if p.info.line > uint16(1): llStreamWrite(p.outp, "\n")
|
||||||
if p.pendingExprLine:
|
if p.pendingExprLine:
|
||||||
llStreamWrite(p.outp, spaces(2))
|
llStreamWrite(p.outp, spaces(2))
|
||||||
p.pendingExprLine = false
|
p.pendingExprLine = false
|
||||||
|
|
@ -212,9 +212,9 @@ proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
|
||||||
p.x = newStringOfCap(120)
|
p.x = newStringOfCap(120)
|
||||||
# do not process the first line which contains the directive:
|
# do not process the first line which contains the directive:
|
||||||
if llStreamReadLine(p.inp, p.x):
|
if llStreamReadLine(p.inp, p.x):
|
||||||
p.info.line = p.info.line + int16(1)
|
p.info.line = p.info.line + 1'u16
|
||||||
while llStreamReadLine(p.inp, p.x):
|
while llStreamReadLine(p.inp, p.x):
|
||||||
p.info.line = p.info.line + int16(1)
|
p.info.line = p.info.line + 1'u16
|
||||||
parseLine(p)
|
parseLine(p)
|
||||||
newLine(p)
|
newLine(p)
|
||||||
result = p.outp
|
result = p.outp
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
|
||||||
assert x.kind in {nkStmtList, nkCall}
|
assert x.kind in {nkStmtList, nkCall}
|
||||||
# better be safe than sorry, so check evalTemplateCounter too:
|
# better be safe than sorry, so check evalTemplateCounter too:
|
||||||
inc(evalTemplateCounter)
|
inc(evalTemplateCounter)
|
||||||
if evalTemplateCounter > 100:
|
if evalTemplateCounter > evalTemplateLimit:
|
||||||
globalError(n.info, errTemplateInstantiationTooNested)
|
globalError(n.info, errTemplateInstantiationTooNested)
|
||||||
# deactivate this pattern:
|
# deactivate this pattern:
|
||||||
c.patterns[i] = nil
|
c.patterns[i] = nil
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# This is the JavaScript code generator.
|
# This is the JavaScript code generator.
|
||||||
# Also a PHP code generator. ;-)
|
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
The JS code generator contains only 2 tricks:
|
The JS code generator contains only 2 tricks:
|
||||||
|
|
@ -38,11 +37,8 @@ import
|
||||||
from modulegraphs import ModuleGraph
|
from modulegraphs import ModuleGraph
|
||||||
|
|
||||||
type
|
type
|
||||||
TTarget = enum
|
|
||||||
targetJS, targetPHP
|
|
||||||
TJSGen = object of TPassContext
|
TJSGen = object of TPassContext
|
||||||
module: PSym
|
module: PSym
|
||||||
target: TTarget
|
|
||||||
sigConflicts: CountTable[SigHash]
|
sigConflicts: CountTable[SigHash]
|
||||||
|
|
||||||
BModule = ref TJSGen
|
BModule = ref TJSGen
|
||||||
|
|
@ -92,16 +88,12 @@ type
|
||||||
module: BModule
|
module: BModule
|
||||||
g: PGlobals
|
g: PGlobals
|
||||||
beforeRetNeeded: bool
|
beforeRetNeeded: bool
|
||||||
target: TTarget # duplicated here for faster dispatching
|
|
||||||
unique: int # for temp identifier generation
|
unique: int # for temp identifier generation
|
||||||
blocks: seq[TBlock]
|
blocks: seq[TBlock]
|
||||||
extraIndent: int
|
extraIndent: int
|
||||||
up: PProc # up the call chain; required for closure support
|
up: PProc # up the call chain; required for closure support
|
||||||
declaredGlobals: IntSet
|
declaredGlobals: IntSet
|
||||||
|
|
||||||
template `|`(a, b: untyped): untyped {.dirty.} =
|
|
||||||
(if p.target == targetJS: a else: b)
|
|
||||||
|
|
||||||
var indent = "\t".rope
|
var indent = "\t".rope
|
||||||
|
|
||||||
proc indentLine(p: PProc, r: Rope): Rope =
|
proc indentLine(p: PProc, r: Rope): Rope =
|
||||||
|
|
@ -157,11 +149,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
||||||
module: module,
|
module: module,
|
||||||
procDef: procDef,
|
procDef: procDef,
|
||||||
g: globals,
|
g: globals,
|
||||||
target: module.target,
|
|
||||||
extraIndent: int(procDef != nil))
|
extraIndent: int(procDef != nil))
|
||||||
if procDef != nil: result.prc = procDef.sons[namePos].sym
|
if procDef != nil: result.prc = procDef.sons[namePos].sym
|
||||||
if result.target == targetPHP:
|
|
||||||
result.declaredGlobals = initIntSet()
|
|
||||||
|
|
||||||
proc declareGlobal(p: PProc; id: int; r: Rope) =
|
proc declareGlobal(p: PProc; id: int; r: Rope) =
|
||||||
if p.prc != nil and not p.declaredGlobals.containsOrIncl(id):
|
if p.prc != nil and not p.declaredGlobals.containsOrIncl(id):
|
||||||
|
|
@ -208,8 +197,7 @@ proc mapType(typ: PType): TJSTypeKind =
|
||||||
of tyUnused, tyOptAsRef: internalError("mapType")
|
of tyUnused, tyOptAsRef: internalError("mapType")
|
||||||
|
|
||||||
proc mapType(p: PProc; typ: PType): TJSTypeKind =
|
proc mapType(p: PProc; typ: PType): TJSTypeKind =
|
||||||
if p.target == targetPHP: result = etyObject
|
result = mapType(typ)
|
||||||
else: result = mapType(typ)
|
|
||||||
|
|
||||||
proc mangleName(m: BModule, s: PSym): Rope =
|
proc mangleName(m: BModule, s: PSym): Rope =
|
||||||
proc validJsName(name: string): bool =
|
proc validJsName(name: string): bool =
|
||||||
|
|
@ -236,7 +224,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
|
||||||
if result == nil:
|
if result == nil:
|
||||||
if s.kind == skField and s.name.s.validJsName:
|
if s.kind == skField and s.name.s.validJsName:
|
||||||
result = rope(s.name.s)
|
result = rope(s.name.s)
|
||||||
elif m.target == targetJS or s.kind == skTemp:
|
elif s.kind == skTemp:
|
||||||
result = rope(mangle(s.name.s))
|
result = rope(mangle(s.name.s))
|
||||||
else:
|
else:
|
||||||
var x = newStringOfCap(s.name.s.len)
|
var x = newStringOfCap(s.name.s.len)
|
||||||
|
|
@ -314,7 +302,7 @@ proc useMagic(p: PProc, name: string) =
|
||||||
proc isSimpleExpr(p: PProc; n: PNode): bool =
|
proc isSimpleExpr(p: PProc; n: PNode): bool =
|
||||||
# calls all the way down --> can stay expression based
|
# calls all the way down --> can stay expression based
|
||||||
if n.kind in nkCallKinds+{nkBracketExpr, nkDotExpr, nkPar, nkTupleConstr} or
|
if n.kind in nkCallKinds+{nkBracketExpr, nkDotExpr, nkPar, nkTupleConstr} or
|
||||||
(p.target == targetJS and n.kind in {nkObjConstr, nkBracket, nkCurly}):
|
(n.kind in {nkObjConstr, nkBracket, nkCurly}):
|
||||||
for c in n:
|
for c in n:
|
||||||
if not p.isSimpleExpr(c): return false
|
if not p.isSimpleExpr(c): return false
|
||||||
result = true
|
result = true
|
||||||
|
|
@ -323,12 +311,9 @@ proc isSimpleExpr(p: PProc; n: PNode): bool =
|
||||||
|
|
||||||
proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
|
proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
|
||||||
inc(p.unique)
|
inc(p.unique)
|
||||||
if p.target == targetJS:
|
|
||||||
result = "Tmp$1" % [rope(p.unique)]
|
result = "Tmp$1" % [rope(p.unique)]
|
||||||
if defineInLocals:
|
if defineInLocals:
|
||||||
add(p.locals, p.indentLine("var $1;$n" % [result]))
|
add(p.locals, p.indentLine("var $1;$n" % [result]))
|
||||||
else:
|
|
||||||
result = "$$Tmp$1" % [rope(p.unique)]
|
|
||||||
|
|
||||||
proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
|
proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||||
assert r.kind == resNone
|
assert r.kind == resNone
|
||||||
|
|
@ -477,15 +462,9 @@ proc unsignedTrimmerJS(size: BiggestInt): Rope =
|
||||||
of 4: rope">>> 0"
|
of 4: rope">>> 0"
|
||||||
else: rope""
|
else: rope""
|
||||||
|
|
||||||
proc unsignedTrimmerPHP(size: BiggestInt): Rope =
|
|
||||||
case size
|
|
||||||
of 1: rope"& 0xff"
|
|
||||||
of 2: rope"& 0xffff"
|
|
||||||
of 4: rope"& 0xffffffff"
|
|
||||||
else: rope""
|
|
||||||
|
|
||||||
template unsignedTrimmer(size: BiggestInt): Rope =
|
template unsignedTrimmer(size: BiggestInt): Rope =
|
||||||
size.unsignedTrimmerJS | size.unsignedTrimmerPHP
|
size.unsignedTrimmerJS
|
||||||
|
|
||||||
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
|
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
|
||||||
reassign = false) =
|
reassign = false) =
|
||||||
|
|
@ -533,45 +512,17 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
of mMulU: binaryUintExpr(p, n, r, "*")
|
of mMulU: binaryUintExpr(p, n, r, "*")
|
||||||
of mDivU: binaryUintExpr(p, n, r, "/")
|
of mDivU: binaryUintExpr(p, n, r, "/")
|
||||||
of mDivI:
|
of mDivI:
|
||||||
if p.target == targetPHP:
|
|
||||||
var x, y: TCompRes
|
|
||||||
gen(p, n.sons[1], x)
|
|
||||||
gen(p, n.sons[2], y)
|
|
||||||
r.res = "intval($1 / $2)" % [x.rdLoc, y.rdLoc]
|
|
||||||
else:
|
|
||||||
arithAux(p, n, r, op)
|
arithAux(p, n, r, op)
|
||||||
of mModI:
|
of mModI:
|
||||||
if p.target == targetPHP:
|
|
||||||
var x, y: TCompRes
|
|
||||||
gen(p, n.sons[1], x)
|
|
||||||
gen(p, n.sons[2], y)
|
|
||||||
r.res = "($1 % $2)" % [x.rdLoc, y.rdLoc]
|
|
||||||
else:
|
|
||||||
arithAux(p, n, r, op)
|
arithAux(p, n, r, op)
|
||||||
of mShrI:
|
of mShrI:
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
|
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
|
||||||
if p.target == targetPHP:
|
|
||||||
# XXX prevent multi evaluations
|
|
||||||
r.res = "(($1 $2) >= 0) ? (($1 $2) >> $3) : ((($1 $2) & 0x7fffffff) >> $3) | (0x40000000 >> ($3 - 1))" % [x.rdLoc, trimmer, y.rdLoc]
|
|
||||||
else:
|
|
||||||
r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc]
|
r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc]
|
||||||
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr,
|
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr,
|
||||||
mCStrToStr, mStrToStr, mEnumToStr:
|
mCStrToStr, mStrToStr, mEnumToStr:
|
||||||
if p.target == targetPHP:
|
|
||||||
if op == mEnumToStr:
|
|
||||||
var x: TCompRes
|
|
||||||
gen(p, n.sons[1], x)
|
|
||||||
r.res = "$#[$#]" % [genEnumInfoPHP(p, n.sons[1].typ), x.rdLoc]
|
|
||||||
elif op == mCharToStr:
|
|
||||||
var x: TCompRes
|
|
||||||
gen(p, n.sons[1], x)
|
|
||||||
r.res = "chr($#)" % [x.rdLoc]
|
|
||||||
else:
|
|
||||||
gen(p, n.sons[1], r)
|
|
||||||
else:
|
|
||||||
arithAux(p, n, r, op)
|
arithAux(p, n, r, op)
|
||||||
else:
|
else:
|
||||||
arithAux(p, n, r, op)
|
arithAux(p, n, r, op)
|
||||||
|
|
@ -591,7 +542,7 @@ proc genLineDir(p: PProc, n: PNode) =
|
||||||
useMagic(p, "endb")
|
useMagic(p, "endb")
|
||||||
lineF(p, "endb($1);$n", [rope(line)])
|
lineF(p, "endb($1);$n", [rope(line)])
|
||||||
elif hasFrameInfo(p):
|
elif hasFrameInfo(p):
|
||||||
lineF(p, "F.line = $1;$n" | "$$F['line'] = $1;$n", [rope(line)])
|
lineF(p, "F.line = $1;$n", [rope(line)])
|
||||||
|
|
||||||
proc genWhileStmt(p: PProc, n: PNode) =
|
proc genWhileStmt(p: PProc, n: PNode) =
|
||||||
var
|
var
|
||||||
|
|
@ -604,12 +555,12 @@ proc genWhileStmt(p: PProc, n: PNode) =
|
||||||
p.blocks[length].id = -p.unique
|
p.blocks[length].id = -p.unique
|
||||||
p.blocks[length].isLoop = true
|
p.blocks[length].isLoop = true
|
||||||
let labl = p.unique.rope
|
let labl = p.unique.rope
|
||||||
lineF(p, "L$1: while (true) {$n" | "while (true) {$n", [labl])
|
lineF(p, "L$1: while (true) {$n", [labl])
|
||||||
p.nested: gen(p, n.sons[0], cond)
|
p.nested: gen(p, n.sons[0], cond)
|
||||||
lineF(p, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
|
lineF(p, "if (!$1) break L$2;$n",
|
||||||
[cond.res, labl])
|
[cond.res, labl])
|
||||||
p.nested: genStmt(p, n.sons[1])
|
p.nested: genStmt(p, n.sons[1])
|
||||||
lineF(p, "}$n" | "}L$#:;$n", [labl])
|
lineF(p, "}$n", [labl])
|
||||||
setLen(p.blocks, length)
|
setLen(p.blocks, length)
|
||||||
|
|
||||||
proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
|
proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
|
||||||
|
|
@ -653,26 +604,22 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var i = 1
|
var i = 1
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch
|
var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch
|
||||||
if catchBranchesExist and p.target == targetJS:
|
if catchBranchesExist:
|
||||||
add(p.body, "++excHandler;" & tnl)
|
add(p.body, "++excHandler;" & tnl)
|
||||||
var tmpFramePtr = rope"F"
|
var tmpFramePtr = rope"F"
|
||||||
if optStackTrace notin p.options:
|
if optStackTrace notin p.options:
|
||||||
tmpFramePtr = p.getTemp(true)
|
tmpFramePtr = p.getTemp(true)
|
||||||
line(p, tmpFramePtr & " = framePtr;" & tnl)
|
line(p, tmpFramePtr & " = framePtr;" & tnl)
|
||||||
lineF(p, "try {$n", [])
|
lineF(p, "try {$n", [])
|
||||||
if p.target == targetPHP and p.globals == nil:
|
|
||||||
p.globals = "global $lastJSError; global $prevJSError;".rope
|
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
gen(p, n.sons[0], a)
|
gen(p, n.sons[0], a)
|
||||||
moveInto(p, a, r)
|
moveInto(p, a, r)
|
||||||
var generalCatchBranchExists = false
|
var generalCatchBranchExists = false
|
||||||
let dollar = rope(if p.target == targetJS: "" else: "$")
|
let dollar = rope("")
|
||||||
if p.target == targetJS and catchBranchesExist:
|
if catchBranchesExist:
|
||||||
addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
||||||
" lastJSError = EXC;$n --excHandler;$n", [])
|
" lastJSError = EXC;$n --excHandler;$n", [])
|
||||||
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||||
elif p.target == targetPHP:
|
|
||||||
lineF(p, "} catch (Exception $$EXC) {$n $$prevJSError = $$lastJSError;$n $$lastJSError = $$EXC;$n", [])
|
|
||||||
while i < length and n.sons[i].kind == nkExceptBranch:
|
while i < length and n.sons[i].kind == nkExceptBranch:
|
||||||
let blen = sonsLen(n.sons[i])
|
let blen = sonsLen(n.sons[i])
|
||||||
if blen == 1:
|
if blen == 1:
|
||||||
|
|
@ -704,18 +651,10 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
line(p, indent & "reraiseException();" & tnl)
|
line(p, indent & "reraiseException();" & tnl)
|
||||||
line(p, "}" & tnl)
|
line(p, "}" & tnl)
|
||||||
addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
|
addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
|
||||||
if p.target == targetJS:
|
|
||||||
line(p, "} finally {" & tnl)
|
line(p, "} finally {" & tnl)
|
||||||
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||||
if p.target == targetPHP:
|
|
||||||
# XXX ugly hack for PHP codegen
|
|
||||||
line(p, "}" & tnl)
|
|
||||||
if i < length and n.sons[i].kind == nkFinally:
|
if i < length and n.sons[i].kind == nkFinally:
|
||||||
genStmt(p, n.sons[i].sons[0])
|
genStmt(p, n.sons[i].sons[0])
|
||||||
if p.target == targetPHP:
|
|
||||||
# XXX ugly hack for PHP codegen
|
|
||||||
line(p, "if($lastJSError) throw($lastJSError);" & tnl)
|
|
||||||
if p.target == targetJS:
|
|
||||||
line(p, "}" & tnl)
|
line(p, "}" & tnl)
|
||||||
|
|
||||||
proc genRaiseStmt(p: PProc, n: PNode) =
|
proc genRaiseStmt(p: PProc, n: PNode) =
|
||||||
|
|
@ -737,7 +676,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
gen(p, n.sons[0], cond)
|
gen(p, n.sons[0], cond)
|
||||||
let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
|
let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
|
||||||
if stringSwitch and p.target == targetJS:
|
if stringSwitch:
|
||||||
useMagic(p, "toJSStr")
|
useMagic(p, "toJSStr")
|
||||||
lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc])
|
lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc])
|
||||||
else:
|
else:
|
||||||
|
|
@ -789,12 +728,12 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
sym.loc.k = locOther
|
sym.loc.k = locOther
|
||||||
sym.position = idx+1
|
sym.position = idx+1
|
||||||
let labl = p.unique
|
let labl = p.unique
|
||||||
lineF(p, "L$1: do {$n" | "", [labl.rope])
|
lineF(p, "L$1: do {$n", [labl.rope])
|
||||||
setLen(p.blocks, idx + 1)
|
setLen(p.blocks, idx + 1)
|
||||||
p.blocks[idx].id = - p.unique # negative because it isn't used yet
|
p.blocks[idx].id = - p.unique # negative because it isn't used yet
|
||||||
gen(p, n.sons[1], r)
|
gen(p, n.sons[1], r)
|
||||||
setLen(p.blocks, idx)
|
setLen(p.blocks, idx)
|
||||||
lineF(p, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
|
lineF(p, "} while(false);$n", [labl.rope])
|
||||||
|
|
||||||
proc genBreakStmt(p: PProc, n: PNode) =
|
proc genBreakStmt(p: PProc, n: PNode) =
|
||||||
var idx: int
|
var idx: int
|
||||||
|
|
@ -812,7 +751,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
|
||||||
if idx < 0 or not p.blocks[idx].isLoop:
|
if idx < 0 or not p.blocks[idx].isLoop:
|
||||||
internalError(n.info, "no loop to break")
|
internalError(n.info, "no loop to break")
|
||||||
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
||||||
lineF(p, "break L$1;$n" | "goto L$1;$n", [rope(p.blocks[idx].id)])
|
lineF(p, "break L$1;$n", [rope(p.blocks[idx].id)])
|
||||||
|
|
||||||
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
|
|
@ -826,7 +765,6 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||||
let v = it.sym
|
let v = it.sym
|
||||||
# for backwards compatibility we don't deref syms here :-(
|
# for backwards compatibility we don't deref syms here :-(
|
||||||
if v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
if v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
||||||
if p.target == targetPHP: p.body.add "$"
|
|
||||||
p.body.add mangleName(p.module, v)
|
p.body.add mangleName(p.module, v)
|
||||||
else:
|
else:
|
||||||
var r: TCompRes
|
var r: TCompRes
|
||||||
|
|
@ -869,24 +807,11 @@ proc generateHeader(p: PProc, typ: PType): Rope =
|
||||||
if isCompileTimeOnly(param.typ): continue
|
if isCompileTimeOnly(param.typ): continue
|
||||||
if result != nil: add(result, ", ")
|
if result != nil: add(result, ", ")
|
||||||
var name = mangleName(p.module, param)
|
var name = mangleName(p.module, param)
|
||||||
if p.target == targetJS:
|
|
||||||
add(result, name)
|
add(result, name)
|
||||||
if mapType(param.typ) == etyBaseIndex:
|
if mapType(param.typ) == etyBaseIndex:
|
||||||
add(result, ", ")
|
add(result, ", ")
|
||||||
add(result, name)
|
add(result, name)
|
||||||
add(result, "_Idx")
|
add(result, "_Idx")
|
||||||
elif not (i == 1 and param.name.s == "this"):
|
|
||||||
let k = param.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind
|
|
||||||
if k in {tyVar, tyRef, tyPtr, tyLent, tyPointer}:
|
|
||||||
add(result, "&")
|
|
||||||
add(result, "$")
|
|
||||||
add(result, name)
|
|
||||||
# XXX I think something like this is needed for PHP to really support
|
|
||||||
# ptr "inside" strings and seq
|
|
||||||
#if mapType(param.typ) == etyBaseIndex:
|
|
||||||
# add(result, ", $")
|
|
||||||
# add(result, name)
|
|
||||||
# add(result, "_Idx")
|
|
||||||
|
|
||||||
proc countJsParams(typ: PType): int =
|
proc countJsParams(typ: PType): int =
|
||||||
for i in countup(1, sonsLen(typ.n) - 1):
|
for i in countup(1, sonsLen(typ.n) - 1):
|
||||||
|
|
@ -906,21 +831,10 @@ const
|
||||||
|
|
||||||
proc needsNoCopy(p: PProc; y: PNode): bool =
|
proc needsNoCopy(p: PProc; y: PNode): bool =
|
||||||
result = (y.kind in nodeKindsNeedNoCopy) or
|
result = (y.kind in nodeKindsNeedNoCopy) or
|
||||||
(skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyLent, tyVar}) or
|
(skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyLent, tyVar})
|
||||||
p.target == targetPHP
|
|
||||||
|
|
||||||
proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||||
var a, b: TCompRes
|
var a, b: TCompRes
|
||||||
|
|
||||||
if p.target == targetPHP and x.kind == nkBracketExpr and
|
|
||||||
x[0].typ.skipTypes(abstractVar).kind in {tyString, tyCString}:
|
|
||||||
var c: TCompRes
|
|
||||||
gen(p, x[0], a)
|
|
||||||
gen(p, x[1], b)
|
|
||||||
gen(p, y, c)
|
|
||||||
lineF(p, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
|
|
||||||
return
|
|
||||||
|
|
||||||
var xtyp = mapType(p, x.typ)
|
var xtyp = mapType(p, x.typ)
|
||||||
|
|
||||||
if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
|
if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
|
||||||
|
|
@ -968,7 +882,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||||
|
|
||||||
proc genAsgn(p: PProc, n: PNode) =
|
proc genAsgn(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=p.target == targetPHP)
|
genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
|
||||||
|
|
||||||
proc genFastAsgn(p: PProc, n: PNode) =
|
proc genFastAsgn(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
|
|
@ -991,12 +905,10 @@ proc genSwap(p: PProc, n: PNode) =
|
||||||
let tmp2 = p.getTemp(false)
|
let tmp2 = p.getTemp(false)
|
||||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||||
internalError(n.info, "genSwap")
|
internalError(n.info, "genSwap")
|
||||||
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n" |
|
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n",
|
||||||
"$1 = $2; $2 = $3; $3 = $1;$n",
|
|
||||||
[tmp, a.address, b.address])
|
[tmp, a.address, b.address])
|
||||||
tmp = tmp2
|
tmp = tmp2
|
||||||
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;" |
|
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;",
|
||||||
"$1 = $2; $2 = $3; $3 = $1;",
|
|
||||||
[tmp, a.res, b.res])
|
[tmp, a.res, b.res])
|
||||||
|
|
||||||
proc getFieldPosition(f: PNode): int =
|
proc getFieldPosition(f: PNode): int =
|
||||||
|
|
@ -1011,10 +923,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
let b = if n.kind == nkHiddenAddr: n.sons[0] else: n
|
let b = if n.kind == nkHiddenAddr: n.sons[0] else: n
|
||||||
gen(p, b.sons[0], a)
|
gen(p, b.sons[0], a)
|
||||||
if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple:
|
if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple:
|
||||||
if p.target == targetJS:
|
|
||||||
r.res = makeJSString("Field" & $getFieldPosition(b.sons[1]))
|
r.res = makeJSString("Field" & $getFieldPosition(b.sons[1]))
|
||||||
else:
|
|
||||||
r.res = getFieldPosition(b.sons[1]).rope
|
|
||||||
else:
|
else:
|
||||||
if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
|
if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
|
||||||
var f = b.sons[1].sym
|
var f = b.sons[1].sym
|
||||||
|
|
@ -1029,19 +938,13 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
gen(p, n.sons[0], r)
|
gen(p, n.sons[0], r)
|
||||||
let otyp = skipTypes(n.sons[0].typ, abstractVarRange)
|
let otyp = skipTypes(n.sons[0].typ, abstractVarRange)
|
||||||
if otyp.kind == tyTuple:
|
if otyp.kind == tyTuple:
|
||||||
r.res = ("$1.Field$2" | "$1[$2]") %
|
r.res = ("$1.Field$2") %
|
||||||
[r.res, getFieldPosition(n.sons[1]).rope]
|
[r.res, getFieldPosition(n.sons[1]).rope]
|
||||||
else:
|
else:
|
||||||
if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess")
|
if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess")
|
||||||
var f = n.sons[1].sym
|
var f = n.sons[1].sym
|
||||||
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
|
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
|
||||||
if p.target == targetJS:
|
|
||||||
r.res = "$1.$2" % [r.res, f.loc.r]
|
r.res = "$1.$2" % [r.res, f.loc.r]
|
||||||
else:
|
|
||||||
if {sfImportc, sfExportc} * f.flags != {}:
|
|
||||||
r.res = "$1->$2" % [r.res, f.loc.r]
|
|
||||||
else:
|
|
||||||
r.res = "$1['$2']" % [r.res, f.loc.r]
|
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
proc genAddr(p: PProc, n: PNode, r: var TCompRes)
|
proc genAddr(p: PProc, n: PNode, r: var TCompRes)
|
||||||
|
|
@ -1069,12 +972,6 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
else: first = 0
|
else: first = 0
|
||||||
if optBoundsCheck in p.options:
|
if optBoundsCheck in p.options:
|
||||||
useMagic(p, "chckIndx")
|
useMagic(p, "chckIndx")
|
||||||
if p.target == targetPHP:
|
|
||||||
if typ.kind != tyString:
|
|
||||||
r.res = "chckIndx($1, $2, count($3)-1)-$2" % [b.res, rope(first), a.res]
|
|
||||||
else:
|
|
||||||
r.res = "chckIndx($1, $2, strlen($3))-$2" % [b.res, rope(first), a.res]
|
|
||||||
else:
|
|
||||||
r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), a.res]
|
r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), a.res]
|
||||||
elif first != 0:
|
elif first != 0:
|
||||||
r.res = "($1)-$2" % [b.res, rope(first)]
|
r.res = "($1)-$2" % [b.res, rope(first)]
|
||||||
|
|
@ -1089,27 +986,11 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of tyArray, tyOpenArray, tySequence, tyString, tyCString, tyVarargs:
|
of tyArray, tyOpenArray, tySequence, tyString, tyCString, tyVarargs:
|
||||||
genArrayAddr(p, n, r)
|
genArrayAddr(p, n, r)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
if p.target == targetPHP:
|
|
||||||
genFieldAccess(p, n, r)
|
|
||||||
return
|
|
||||||
genFieldAddr(p, n, r)
|
genFieldAddr(p, n, r)
|
||||||
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
||||||
r.typ = etyNone
|
r.typ = etyNone
|
||||||
if r.res == nil: internalError(n.info, "genArrayAccess")
|
if r.res == nil: internalError(n.info, "genArrayAccess")
|
||||||
if p.target == targetPHP:
|
if ty.kind == tyCString:
|
||||||
if n.sons[0].kind in nkCallKinds+{nkStrLit..nkTripleStrLit}:
|
|
||||||
useMagic(p, "nimAt")
|
|
||||||
if ty.kind in {tyString, tyCString}:
|
|
||||||
# XXX this needs to be more like substr($1,$2)
|
|
||||||
r.res = "ord(nimAt($1, $2))" % [r.address, r.res]
|
|
||||||
else:
|
|
||||||
r.res = "nimAt($1, $2)" % [r.address, r.res]
|
|
||||||
elif ty.kind in {tyString, tyCString}:
|
|
||||||
# XXX this needs to be more like substr($1,$2)
|
|
||||||
r.res = "ord(@$1[$2])" % [r.address, r.res]
|
|
||||||
else:
|
|
||||||
r.res = "$1[$2]" % [r.address, r.res]
|
|
||||||
elif ty.kind == tyCString:
|
|
||||||
r.res = "$1.charCodeAt($2)" % [r.address, r.res]
|
r.res = "$1.charCodeAt($2)" % [r.address, r.res]
|
||||||
else:
|
else:
|
||||||
r.res = "$1[$2]" % [r.address, r.res]
|
r.res = "$1[$2]" % [r.address, r.res]
|
||||||
|
|
@ -1122,7 +1003,7 @@ template isIndirect(x: PSym): bool =
|
||||||
#(mapType(v.typ) != etyObject) and
|
#(mapType(v.typ) != etyObject) and
|
||||||
{sfImportc, sfVolatile, sfExportc} * v.flags == {} and
|
{sfImportc, sfVolatile, sfExportc} * v.flags == {} and
|
||||||
v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
|
v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
|
||||||
skConst, skTemp, skLet} and p.target == targetJS)
|
skConst, skTemp, skLet})
|
||||||
|
|
||||||
proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
case n.sons[0].kind
|
case n.sons[0].kind
|
||||||
|
|
@ -1138,8 +1019,6 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.typ = etyNone
|
r.typ = etyNone
|
||||||
if isIndirect(s):
|
if isIndirect(s):
|
||||||
r.res = s.loc.r & "[0]"
|
r.res = s.loc.r & "[0]"
|
||||||
elif p.target == targetPHP:
|
|
||||||
r.res = "&" & s.loc.r
|
|
||||||
else:
|
else:
|
||||||
r.res = s.loc.r
|
r.res = s.loc.r
|
||||||
r.address = nil
|
r.address = nil
|
||||||
|
|
@ -1180,15 +1059,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
|
else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
|
||||||
|
|
||||||
proc thisParam(p: PProc; typ: PType): PType =
|
proc thisParam(p: PProc; typ: PType): PType =
|
||||||
if p.target == targetPHP:
|
discard
|
||||||
# XXX Might be very useful for the JS backend too?
|
|
||||||
let typ = skipTypes(typ, abstractInst)
|
|
||||||
assert(typ.kind == tyProc)
|
|
||||||
if 1 < sonsLen(typ.n):
|
|
||||||
assert(typ.n.sons[1].kind == nkSym)
|
|
||||||
let param = typ.n.sons[1].sym
|
|
||||||
if param.name.s == "this":
|
|
||||||
result = param.typ.skipTypes(abstractVar)
|
|
||||||
|
|
||||||
proc attachProc(p: PProc; content: Rope; s: PSym) =
|
proc attachProc(p: PProc; content: Rope; s: PSym) =
|
||||||
let otyp = thisParam(p, s.typ)
|
let otyp = thisParam(p, s.typ)
|
||||||
|
|
@ -1220,7 +1091,6 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of skVar, skLet, skParam, skTemp, skResult, skForVar:
|
of skVar, skLet, skParam, skTemp, skResult, skForVar:
|
||||||
if s.loc.r == nil:
|
if s.loc.r == nil:
|
||||||
internalError(n.info, "symbol has no generated name: " & s.name.s)
|
internalError(n.info, "symbol has no generated name: " & s.name.s)
|
||||||
if p.target == targetJS:
|
|
||||||
let k = mapType(p, s.typ)
|
let k = mapType(p, s.typ)
|
||||||
if k == etyBaseIndex:
|
if k == etyBaseIndex:
|
||||||
r.typ = etyBaseIndex
|
r.typ = etyBaseIndex
|
||||||
|
|
@ -1234,24 +1104,13 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.res = "$1[0]" % [s.loc.r]
|
r.res = "$1[0]" % [s.loc.r]
|
||||||
else:
|
else:
|
||||||
r.res = s.loc.r
|
r.res = s.loc.r
|
||||||
else:
|
|
||||||
r.res = "$" & s.loc.r
|
|
||||||
if sfGlobal in s.flags:
|
|
||||||
p.declareGlobal(s.id, r.res)
|
|
||||||
of skConst:
|
of skConst:
|
||||||
genConstant(p, s)
|
genConstant(p, s)
|
||||||
if s.loc.r == nil:
|
if s.loc.r == nil:
|
||||||
internalError(n.info, "symbol has no generated name: " & s.name.s)
|
internalError(n.info, "symbol has no generated name: " & s.name.s)
|
||||||
if p.target == targetJS:
|
|
||||||
r.res = s.loc.r
|
r.res = s.loc.r
|
||||||
else:
|
|
||||||
r.res = "$" & s.loc.r
|
|
||||||
p.declareGlobal(s.id, r.res)
|
|
||||||
of skProc, skFunc, skConverter, skMethod:
|
of skProc, skFunc, skConverter, skMethod:
|
||||||
discard mangleName(p.module, s)
|
discard mangleName(p.module, s)
|
||||||
if p.target == targetPHP and r.kind != resCallee:
|
|
||||||
r.res = makeJsString($s.loc.r)
|
|
||||||
else:
|
|
||||||
r.res = s.loc.r
|
r.res = s.loc.r
|
||||||
if lfNoDecl in s.loc.flags or s.magic != mNone or
|
if lfNoDecl in s.loc.flags or s.magic != mNone or
|
||||||
{sfImportc, sfInfixCall} * s.flags != {}:
|
{sfImportc, sfInfixCall} * s.flags != {}:
|
||||||
|
|
@ -1421,10 +1280,8 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.res = "$1[$2]" % [r.address, r.res]
|
r.res = "$1[$2]" % [r.address, r.res]
|
||||||
r.address = nil
|
r.address = nil
|
||||||
r.typ = etyNone
|
r.typ = etyNone
|
||||||
add(r.res, "." | "->")
|
add(r.res, ".")
|
||||||
var op: TCompRes
|
var op: TCompRes
|
||||||
if p.target == targetPHP:
|
|
||||||
op.kind = resCallee
|
|
||||||
gen(p, n.sons[0], op)
|
gen(p, n.sons[0], op)
|
||||||
add(r.res, op.res)
|
add(r.res, op.res)
|
||||||
genArgs(p, n, r, 2)
|
genArgs(p, n, r, 2)
|
||||||
|
|
@ -1433,28 +1290,21 @@ proc genCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if n.sons[0].kind == nkSym and thisParam(p, n.sons[0].typ) != nil:
|
if n.sons[0].kind == nkSym and thisParam(p, n.sons[0].typ) != nil:
|
||||||
genInfixCall(p, n, r)
|
genInfixCall(p, n, r)
|
||||||
return
|
return
|
||||||
if p.target == targetPHP:
|
|
||||||
r.kind = resCallee
|
|
||||||
gen(p, n.sons[0], r)
|
gen(p, n.sons[0], r)
|
||||||
genArgs(p, n, r)
|
genArgs(p, n, r)
|
||||||
|
|
||||||
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
let n = n[1].skipConv
|
let n = n[1].skipConv
|
||||||
internalAssert n.kind == nkBracket
|
internalAssert n.kind == nkBracket
|
||||||
if p.target == targetJS:
|
|
||||||
useMagic(p, "toJSStr") # Used in rawEcho
|
useMagic(p, "toJSStr") # Used in rawEcho
|
||||||
useMagic(p, "rawEcho")
|
useMagic(p, "rawEcho")
|
||||||
elif n.len == 0:
|
add(r.res, "rawEcho(")
|
||||||
r.kind = resExpr
|
|
||||||
add(r.res, """print("\n")""")
|
|
||||||
return
|
|
||||||
add(r.res, "rawEcho(" | "print(")
|
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
let it = n.sons[i]
|
let it = n.sons[i]
|
||||||
if it.typ.isCompileTimeOnly: continue
|
if it.typ.isCompileTimeOnly: continue
|
||||||
if i > 0: add(r.res, ", " | ".")
|
if i > 0: add(r.res, ", ")
|
||||||
genArgNoParam(p, it, r)
|
genArgNoParam(p, it, r)
|
||||||
add(r.res, ")" | """."\n")""")
|
add(r.res, ")")
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
proc putToSeq(s: string, indirect: bool): Rope =
|
proc putToSeq(s: string, indirect: bool): Rope =
|
||||||
|
|
@ -1474,10 +1324,7 @@ proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output:
|
||||||
of nkSym:
|
of nkSym:
|
||||||
if rec.sym.id notin excludedFieldIDs:
|
if rec.sym.id notin excludedFieldIDs:
|
||||||
if output.len > 0: output.add(", ")
|
if output.len > 0: output.add(", ")
|
||||||
if p.target == targetJS:
|
|
||||||
output.addf("$#: ", [mangleName(p.module, rec.sym)])
|
output.addf("$#: ", [mangleName(p.module, rec.sym)])
|
||||||
else:
|
|
||||||
output.addf("'$#' => ", [mangleName(p.module, rec.sym)])
|
|
||||||
output.add(createVar(p, rec.sym.typ, false))
|
output.add(createVar(p, rec.sym.typ, false))
|
||||||
else: internalError(rec.info, "createRecordVarAux")
|
else: internalError(rec.info, "createRecordVarAux")
|
||||||
|
|
||||||
|
|
@ -1485,7 +1332,7 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v
|
||||||
var t = typ
|
var t = typ
|
||||||
if objHasTypeField(t):
|
if objHasTypeField(t):
|
||||||
if output.len > 0: output.add(", ")
|
if output.len > 0: output.add(", ")
|
||||||
addf(output, "m_type: $1" | "'m_type' => $#", [genTypeInfo(p, t)])
|
addf(output, "m_type: $1", [genTypeInfo(p, t)])
|
||||||
while t != nil:
|
while t != nil:
|
||||||
t = t.skipTypes(skipPtrs)
|
t = t.skipTypes(skipPtrs)
|
||||||
createRecordVarAux(p, t.n, excludedFieldIDs, output)
|
createRecordVarAux(p, t.n, excludedFieldIDs, output)
|
||||||
|
|
@ -1514,32 +1361,31 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||||
of tyRange, tyGenericInst, tyAlias, tySink:
|
of tyRange, tyGenericInst, tyAlias, tySink:
|
||||||
result = createVar(p, lastSon(typ), indirect)
|
result = createVar(p, lastSon(typ), indirect)
|
||||||
of tySet:
|
of tySet:
|
||||||
result = putToSeq("{}" | "array()", indirect)
|
result = putToSeq("{}", indirect)
|
||||||
of tyBool:
|
of tyBool:
|
||||||
result = putToSeq("false", indirect)
|
result = putToSeq("false", indirect)
|
||||||
of tyArray:
|
of tyArray:
|
||||||
let length = int(lengthOrd(t))
|
let length = int(lengthOrd(t))
|
||||||
let e = elemType(t)
|
let e = elemType(t)
|
||||||
let jsTyp = arrayTypeForElemType(e)
|
let jsTyp = arrayTypeForElemType(e)
|
||||||
if not jsTyp.isNil and p.target == targetJS:
|
if not jsTyp.isNil:
|
||||||
result = "new $1($2)" % [rope(jsTyp), rope(length)]
|
result = "new $1($2)" % [rope(jsTyp), rope(length)]
|
||||||
elif length > 32:
|
elif length > 32:
|
||||||
useMagic(p, "arrayConstr")
|
useMagic(p, "arrayConstr")
|
||||||
# XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary.
|
# XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary.
|
||||||
if p.target == targetJS: useMagic(p, "nimCopy")
|
useMagic(p, "nimCopy")
|
||||||
result = "arrayConstr($1, $2, $3)" % [rope(length),
|
result = "arrayConstr($1, $2, $3)" % [rope(length),
|
||||||
createVar(p, e, false), genTypeInfo(p, e)]
|
createVar(p, e, false), genTypeInfo(p, e)]
|
||||||
else:
|
else:
|
||||||
result = rope("[" | "array(")
|
result = rope("[")
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < length:
|
while i < length:
|
||||||
if i > 0: add(result, ", ")
|
if i > 0: add(result, ", ")
|
||||||
add(result, createVar(p, e, false))
|
add(result, createVar(p, e, false))
|
||||||
inc(i)
|
inc(i)
|
||||||
add(result, "]" | ")")
|
add(result, "]")
|
||||||
if indirect: result = "[$1]" % [result]
|
if indirect: result = "[$1]" % [result]
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
if p.target == targetJS:
|
|
||||||
result = rope("{")
|
result = rope("{")
|
||||||
for i in 0..<t.sonsLen:
|
for i in 0..<t.sonsLen:
|
||||||
if i > 0: add(result, ", ")
|
if i > 0: add(result, ", ")
|
||||||
|
|
@ -1547,16 +1393,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||||
createVar(p, t.sons[i], false)])
|
createVar(p, t.sons[i], false)])
|
||||||
add(result, "}")
|
add(result, "}")
|
||||||
if indirect: result = "[$1]" % [result]
|
if indirect: result = "[$1]" % [result]
|
||||||
else:
|
|
||||||
result = rope("array(")
|
|
||||||
for i in 0..<t.sonsLen:
|
|
||||||
if i > 0: add(result, ", ")
|
|
||||||
add(result, createVar(p, t.sons[i], false))
|
|
||||||
add(result, ")")
|
|
||||||
of tyObject:
|
of tyObject:
|
||||||
var initList: Rope
|
var initList: Rope
|
||||||
createObjInitList(p, t, initIntSet(), initList)
|
createObjInitList(p, t, initIntSet(), initList)
|
||||||
result = ("{$1}" | "array($#)") % [initList]
|
result = ("{$1}") % [initList]
|
||||||
if indirect: result = "[$1]" % [result]
|
if indirect: result = "[$1]" % [result]
|
||||||
of tyVar, tyPtr, tyLent, tyRef:
|
of tyVar, tyPtr, tyLent, tyRef:
|
||||||
if mapType(p, t) == etyBaseIndex:
|
if mapType(p, t) == etyBaseIndex:
|
||||||
|
|
@ -1597,7 +1437,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||||
varCode = v.constraint.strVal
|
varCode = v.constraint.strVal
|
||||||
|
|
||||||
if n.kind == nkEmpty:
|
if n.kind == nkEmpty:
|
||||||
lineF(p, varCode & " = $3;$n" | "$$$2 = $3;$n",
|
lineF(p, varCode & " = $3;$n",
|
||||||
[returnType, varName, createVar(p, v.typ, isIndirect(v))])
|
[returnType, varName, createVar(p, v.typ, isIndirect(v))])
|
||||||
if v.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and mapType(p, v.typ) == etyBaseIndex:
|
if v.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and mapType(p, v.typ) == etyBaseIndex:
|
||||||
lineF(p, "var $1_Idx = 0;$n", [varName])
|
lineF(p, "var $1_Idx = 0;$n", [varName])
|
||||||
|
|
@ -1632,7 +1472,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||||
if isIndirect(v):
|
if isIndirect(v):
|
||||||
lineF(p, varCode & " = [$3];$n", [returnType, v.loc.r, s])
|
lineF(p, varCode & " = [$3];$n", [returnType, v.loc.r, s])
|
||||||
else:
|
else:
|
||||||
lineF(p, varCode & " = $3;$n" | "$$$2 = $3;$n", [returnType, v.loc.r, s])
|
lineF(p, varCode & " = $3;$n", [returnType, v.loc.r, s])
|
||||||
|
|
||||||
if useReloadingGuard:
|
if useReloadingGuard:
|
||||||
lineF(p, "}$n")
|
lineF(p, "}$n")
|
||||||
|
|
@ -1665,18 +1505,14 @@ proc genNew(p: PProc, n: PNode) =
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
gen(p, n.sons[1], a)
|
gen(p, n.sons[1], a)
|
||||||
var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
||||||
if p.target == targetJS:
|
|
||||||
lineF(p, "$1 = $2;$n", [a.res, createVar(p, t, false)])
|
lineF(p, "$1 = $2;$n", [a.res, createVar(p, t, false)])
|
||||||
else:
|
|
||||||
lineF(p, "$3 = $2; $1 = &$3;$n", [a.res, createVar(p, t, false), getTemp(p)])
|
|
||||||
|
|
||||||
proc genNewSeq(p: PProc, n: PNode) =
|
proc genNewSeq(p: PProc, n: PNode) =
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
||||||
lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}" |
|
lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
|
||||||
"$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$3;}", [
|
|
||||||
x.rdLoc, y.rdLoc, createVar(p, t, false)])
|
x.rdLoc, y.rdLoc, createVar(p, t, false)])
|
||||||
|
|
||||||
proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
|
proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
|
|
@ -1708,21 +1544,6 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
else:
|
else:
|
||||||
r.res.add("$1)" % [a.res])
|
r.res.add("$1)" % [a.res])
|
||||||
|
|
||||||
proc genConStrStrPHP(p: PProc, n: PNode, r: var TCompRes) =
|
|
||||||
var a: TCompRes
|
|
||||||
gen(p, n.sons[1], a)
|
|
||||||
r.kind = resExpr
|
|
||||||
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
|
|
||||||
r.res.add("chr($1)" % [a.res])
|
|
||||||
else:
|
|
||||||
r.res.add(a.res)
|
|
||||||
for i in countup(2, sonsLen(n) - 1):
|
|
||||||
gen(p, n.sons[i], a)
|
|
||||||
if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
|
|
||||||
r.res.add(".chr($1)" % [a.res])
|
|
||||||
else:
|
|
||||||
r.res.add(".$1" % [a.res])
|
|
||||||
|
|
||||||
proc genToArray(p: PProc; n: PNode; r: var TCompRes) =
|
proc genToArray(p: PProc; n: PNode; r: var TCompRes) =
|
||||||
# we map mArray to PHP's array constructor, a mild hack:
|
# we map mArray to PHP's array constructor, a mild hack:
|
||||||
var a, b: TCompRes
|
var a, b: TCompRes
|
||||||
|
|
@ -1766,9 +1587,6 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope =
|
||||||
add(r.res, ")")
|
add(r.res, ")")
|
||||||
|
|
||||||
proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
|
proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if p.target == targetPHP:
|
|
||||||
localError(n.info, "'repr' not available for PHP backend")
|
|
||||||
return
|
|
||||||
let t = skipTypes(n.sons[1].typ, abstractVarRange)
|
let t = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||||
case t.kind:
|
case t.kind:
|
||||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||||
|
|
@ -1828,23 +1646,16 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1")
|
if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1")
|
||||||
else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
|
else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
|
||||||
of mAppendStrCh:
|
of mAppendStrCh:
|
||||||
if p.target == targetJS:
|
|
||||||
binaryExpr(p, n, r, "addChar",
|
binaryExpr(p, n, r, "addChar",
|
||||||
"if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
|
"if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
|
||||||
else:
|
|
||||||
binaryExpr(p, n, r, "", "$1 .= chr($2)")
|
|
||||||
of mAppendStrStr:
|
of mAppendStrStr:
|
||||||
if p.target == targetJS:
|
|
||||||
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
|
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
|
||||||
binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
|
binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
|
||||||
else:
|
else:
|
||||||
binaryExpr(p, n, r, "",
|
binaryExpr(p, n, r, "",
|
||||||
"if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
|
"if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
|
||||||
# XXX: make a copy of $2, because of Javascript's sucking semantics
|
# XXX: make a copy of $2, because of Javascript's sucking semantics
|
||||||
else:
|
|
||||||
binaryExpr(p, n, r, "", "$1 .= $2;")
|
|
||||||
of mAppendSeqElem:
|
of mAppendSeqElem:
|
||||||
if p.target == targetJS:
|
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
|
|
@ -1857,28 +1668,14 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
[c, y.rdLoc, genTypeInfo(p, n[2].typ)])
|
[c, y.rdLoc, genTypeInfo(p, n[2].typ)])
|
||||||
r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, c]
|
r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, c]
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
else:
|
|
||||||
binaryExpr(p, n, r, "", "$1[] = $2")
|
|
||||||
of mConStrStr:
|
of mConStrStr:
|
||||||
if p.target == targetJS:
|
|
||||||
genConStrStr(p, n, r)
|
genConStrStr(p, n, r)
|
||||||
else:
|
|
||||||
genConStrStrPHP(p, n, r)
|
|
||||||
of mEqStr:
|
of mEqStr:
|
||||||
if p.target == targetJS:
|
|
||||||
binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
|
binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
|
||||||
else:
|
|
||||||
binaryExpr(p, n, r, "", "($1 == $2)")
|
|
||||||
of mLeStr:
|
of mLeStr:
|
||||||
if p.target == targetJS:
|
|
||||||
binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
|
binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
|
||||||
else:
|
|
||||||
binaryExpr(p, n, r, "", "($1 <= $2)")
|
|
||||||
of mLtStr:
|
of mLtStr:
|
||||||
if p.target == targetJS:
|
|
||||||
binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)")
|
binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)")
|
||||||
else:
|
|
||||||
binaryExpr(p, n, r, "", "($1 < $2)")
|
|
||||||
of mIsNil: unaryExpr(p, n, r, "", "($1 === null)")
|
of mIsNil: unaryExpr(p, n, r, "", "($1 === null)")
|
||||||
of mEnumToStr: genRepr(p, n, r)
|
of mEnumToStr: genRepr(p, n, r)
|
||||||
of mNew, mNewFinalize: genNew(p, n)
|
of mNew, mNewFinalize: genNew(p, n)
|
||||||
|
|
@ -1886,24 +1683,20 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
|
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
|
||||||
of mOrd: genOrd(p, n, r)
|
of mOrd: genOrd(p, n, r)
|
||||||
of mLengthStr:
|
of mLengthStr:
|
||||||
if p.target == targetJS and n.sons[1].typ.skipTypes(abstractInst).kind == tyCString:
|
if n.sons[1].typ.skipTypes(abstractInst).kind == tyCString:
|
||||||
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
|
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
|
||||||
else:
|
else:
|
||||||
unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)" |
|
unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)")
|
||||||
"strlen($1)")
|
of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1")
|
||||||
of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1" | "strlen($1)")
|
|
||||||
of mLengthSeq, mLengthOpenArray, mLengthArray:
|
of mLengthSeq, mLengthOpenArray, mLengthArray:
|
||||||
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)" |
|
unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
|
||||||
"count($1)")
|
|
||||||
of mXLenSeq:
|
of mXLenSeq:
|
||||||
unaryExpr(p, n, r, "", "$1.length" | "count($1)")
|
unaryExpr(p, n, r, "", "$1.length")
|
||||||
of mHigh:
|
of mHigh:
|
||||||
if skipTypes(n.sons[1].typ, abstractVar).kind == tyString:
|
if skipTypes(n.sons[1].typ, abstractVar).kind == tyString:
|
||||||
unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)" |
|
unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)")
|
||||||
"(strlen($1)-1)")
|
|
||||||
else:
|
else:
|
||||||
unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)" |
|
unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
|
||||||
"(count($1)-1)")
|
|
||||||
of mInc:
|
of mInc:
|
||||||
if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
|
if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
|
||||||
binaryUintExpr(p, n, r, "+", true)
|
binaryUintExpr(p, n, r, "+", true)
|
||||||
|
|
@ -1917,7 +1710,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
|
if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
|
||||||
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
|
else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
|
||||||
of mSetLengthStr:
|
of mSetLengthStr:
|
||||||
binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0" | "$1 = substr($1, 0, $2)")
|
binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0")
|
||||||
of mSetLengthSeq:
|
of mSetLengthSeq:
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
|
|
@ -1934,50 +1727,23 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of mPlusSet: binaryExpr(p, n, r, "SetPlus", "SetPlus($1, $2)")
|
of mPlusSet: binaryExpr(p, n, r, "SetPlus", "SetPlus($1, $2)")
|
||||||
of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
|
of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
|
||||||
of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
|
of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
|
||||||
of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]" | "unset $1[$2]")
|
of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]")
|
||||||
of mInSet:
|
of mInSet:
|
||||||
if p.target == targetJS:
|
|
||||||
binaryExpr(p, n, r, "", "($1[$2] != undefined)")
|
binaryExpr(p, n, r, "", "($1[$2] != undefined)")
|
||||||
else:
|
|
||||||
let s = n.sons[1]
|
|
||||||
if s.kind == nkCurly:
|
|
||||||
var a, b, x: TCompRes
|
|
||||||
gen(p, n.sons[2], x)
|
|
||||||
r.res = rope("(")
|
|
||||||
r.kind = resExpr
|
|
||||||
for i in countup(0, sonsLen(s) - 1):
|
|
||||||
if i > 0: add(r.res, " || ")
|
|
||||||
var it = s.sons[i]
|
|
||||||
if it.kind == nkRange:
|
|
||||||
gen(p, it.sons[0], a)
|
|
||||||
gen(p, it.sons[1], b)
|
|
||||||
addf(r.res, "($1 >= $2 && $1 <= $3)", [x.res, a.res, b.res,])
|
|
||||||
else:
|
|
||||||
gen(p, it, a)
|
|
||||||
addf(r.res, "($1 == $2)", [x.res, a.res])
|
|
||||||
add(r.res, ")")
|
|
||||||
else:
|
|
||||||
binaryExpr(p, n, r, "", "isset($1[$2])")
|
|
||||||
of mNewSeq: genNewSeq(p, n)
|
of mNewSeq: genNewSeq(p, n)
|
||||||
of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]" | "array()")
|
of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]")
|
||||||
of mOf: genOf(p, n, r)
|
of mOf: genOf(p, n, r)
|
||||||
of mReset: genReset(p, n)
|
of mReset: genReset(p, n)
|
||||||
of mEcho: genEcho(p, n, r)
|
of mEcho: genEcho(p, n, r)
|
||||||
of mNLen..mNError, mSlurp, mStaticExec:
|
of mNLen..mNError, mSlurp, mStaticExec:
|
||||||
localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
|
localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
|
||||||
of mCopyStr:
|
of mCopyStr:
|
||||||
binaryExpr(p, n, r, "", "($1.slice($2))" | "substr($1, $2)")
|
binaryExpr(p, n, r, "", "($1.slice($2))")
|
||||||
of mCopyStrLast:
|
of mCopyStrLast:
|
||||||
if p.target == targetJS:
|
|
||||||
ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
|
ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
|
||||||
else:
|
|
||||||
ternaryExpr(p, n, r, "nimSubstr", "nimSubstr($#, $#, $#)")
|
|
||||||
of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
|
of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
|
||||||
of mNewStringOfCap:
|
of mNewStringOfCap:
|
||||||
if p.target == targetJS:
|
|
||||||
unaryExpr(p, n, r, "mnewString", "mnewString(0)")
|
unaryExpr(p, n, r, "mnewString", "mnewString(0)")
|
||||||
else:
|
|
||||||
unaryExpr(p, n, r, "", "''")
|
|
||||||
of mDotDot:
|
of mDotDot:
|
||||||
genProcForSymIfNeeded(p, n.sons[0].sym)
|
genProcForSymIfNeeded(p, n.sons[0].sym)
|
||||||
genCall(p, n, r)
|
genCall(p, n, r)
|
||||||
|
|
@ -1985,8 +1751,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
useMagic(p, "nimParseBiggestFloat")
|
useMagic(p, "nimParseBiggestFloat")
|
||||||
genCall(p, n, r)
|
genCall(p, n, r)
|
||||||
of mArray:
|
of mArray:
|
||||||
if p.target == targetPHP: genToArray(p, n, r)
|
genCall(p, n, r)
|
||||||
else: genCall(p, n, r)
|
|
||||||
else:
|
else:
|
||||||
genCall(p, n, r)
|
genCall(p, n, r)
|
||||||
#else internalError(e.info, 'genMagic: ' + magicToStr[op]);
|
#else internalError(e.info, 'genMagic: ' + magicToStr[op]);
|
||||||
|
|
@ -2003,13 +1768,13 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if it.kind == nkRange:
|
if it.kind == nkRange:
|
||||||
gen(p, it.sons[0], a)
|
gen(p, it.sons[0], a)
|
||||||
gen(p, it.sons[1], b)
|
gen(p, it.sons[1], b)
|
||||||
addf(r.res, "[$1, $2]" | "array($#,$#)", [a.res, b.res])
|
addf(r.res, "[$1, $2]", [a.res, b.res])
|
||||||
else:
|
else:
|
||||||
gen(p, it, a)
|
gen(p, it, a)
|
||||||
add(r.res, a.res)
|
add(r.res, a.res)
|
||||||
add(r.res, ")")
|
add(r.res, ")")
|
||||||
# emit better code for constant sets:
|
# emit better code for constant sets:
|
||||||
if p.target == targetJS and isDeepConstExpr(n):
|
if isDeepConstExpr(n):
|
||||||
inc(p.g.unique)
|
inc(p.g.unique)
|
||||||
let tmp = rope("ConstSet") & rope(p.g.unique)
|
let tmp = rope("ConstSet") & rope(p.g.unique)
|
||||||
addf(p.g.constants, "var $1 = $2;$n", [tmp, r.res])
|
addf(p.g.constants, "var $1 = $2;$n", [tmp, r.res])
|
||||||
|
|
@ -2017,25 +1782,25 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
|
|
||||||
proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
|
proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
r.res = rope("[" | "array(")
|
r.res = rope("[")
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: add(r.res, ", ")
|
if i > 0: add(r.res, ", ")
|
||||||
gen(p, n.sons[i], a)
|
gen(p, n.sons[i], a)
|
||||||
add(r.res, a.res)
|
add(r.res, a.res)
|
||||||
add(r.res, "]" | ")")
|
add(r.res, "]")
|
||||||
|
|
||||||
proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
|
proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
r.res = rope("{" | "array(")
|
r.res = rope("{")
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: add(r.res, ", ")
|
if i > 0: add(r.res, ", ")
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
if it.kind == nkExprColonExpr: it = it.sons[1]
|
if it.kind == nkExprColonExpr: it = it.sons[1]
|
||||||
gen(p, it, a)
|
gen(p, it, a)
|
||||||
addf(r.res, "Field$#: $#" | "$2", [i.rope, a.res])
|
addf(r.res, "Field$#: $#", [i.rope, a.res])
|
||||||
r.res.add("}" | ")")
|
r.res.add("}")
|
||||||
|
|
||||||
proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
|
|
@ -2059,10 +1824,10 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
else:
|
else:
|
||||||
useMagic(p, "nimCopy")
|
useMagic(p, "nimCopy")
|
||||||
a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
|
a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
|
||||||
addf(initList, "$#: $#" | "'$#' => $#" , [f.loc.r, a.res])
|
addf(initList, "$#: $#", [f.loc.r, a.res])
|
||||||
let t = skipTypes(n.typ, abstractInst + skipPtrs)
|
let t = skipTypes(n.typ, abstractInst + skipPtrs)
|
||||||
createObjInitList(p, t, fieldIDs, initList)
|
createObjInitList(p, t, fieldIDs, initList)
|
||||||
r.res = ("{$1}" | "array($#)") % [initList]
|
r.res = ("{$1}") % [initList]
|
||||||
|
|
||||||
proc genConv(p: PProc, n: PNode, r: var TCompRes) =
|
proc genConv(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var dest = skipTypes(n.typ, abstractVarRange)
|
var dest = skipTypes(n.typ, abstractVarRange)
|
||||||
|
|
@ -2125,18 +1890,17 @@ proc genReturnStmt(p: PProc, n: PNode) =
|
||||||
genStmt(p, n.sons[0])
|
genStmt(p, n.sons[0])
|
||||||
else:
|
else:
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
lineF(p, "break BeforeRet;$n" | "goto BeforeRet;$n", [])
|
lineF(p, "break BeforeRet;$n", [])
|
||||||
|
|
||||||
proc frameCreate(p: PProc; procname, filename: Rope): Rope =
|
proc frameCreate(p: PProc; procname, filename: Rope): Rope =
|
||||||
let frameFmt =
|
let frameFmt =
|
||||||
"var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
|
"var F={procname:$1,prev:framePtr,filename:$2,line:0};$n"
|
||||||
"global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n"
|
|
||||||
|
|
||||||
result = p.indentLine(frameFmt % [procname, filename])
|
result = p.indentLine(frameFmt % [procname, filename])
|
||||||
result.add p.indentLine(ropes.`%`("framePtr = F;$n" | "$$framePtr = &$$F;$n", []))
|
result.add p.indentLine(ropes.`%`("framePtr = F;$n", []))
|
||||||
|
|
||||||
proc frameDestroy(p: PProc): Rope =
|
proc frameDestroy(p: PProc): Rope =
|
||||||
result = p.indentLine rope(("framePtr = F.prev;" | "$framePtr = $F['prev'];") & tnl)
|
result = p.indentLine rope(("framePtr = F.prev;") & tnl)
|
||||||
|
|
||||||
proc genProcBody(p: PProc, prc: PSym): Rope =
|
proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||||
if hasFrameInfo(p):
|
if hasFrameInfo(p):
|
||||||
|
|
@ -2146,15 +1910,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||||
else:
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
if p.beforeRetNeeded:
|
if p.beforeRetNeeded:
|
||||||
if p.target == targetJS:
|
|
||||||
result.add p.indentLine(~"BeforeRet: do {$n")
|
result.add p.indentLine(~"BeforeRet: do {$n")
|
||||||
result.add p.body
|
result.add p.body
|
||||||
result.add p.indentLine(~"} while (false);$n")
|
result.add p.indentLine(~"} while (false);$n")
|
||||||
else:
|
|
||||||
addF(result, "$# BeforeRet:;$n", [p.body])
|
|
||||||
else:
|
else:
|
||||||
add(result, p.body)
|
add(result, p.body)
|
||||||
if prc.typ.callConv == ccSysCall and p.target == targetJS:
|
if prc.typ.callConv == ccSysCall:
|
||||||
result = ("try {$n$1} catch (e) {$n" &
|
result = ("try {$n$1} catch (e) {$n" &
|
||||||
" alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}") % [result]
|
" alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}") % [result]
|
||||||
if hasFrameInfo(p):
|
if hasFrameInfo(p):
|
||||||
|
|
@ -2182,7 +1943,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||||
resultSym = prc.ast.sons[resultPos].sym
|
resultSym = prc.ast.sons[resultPos].sym
|
||||||
let mname = mangleName(p.module, resultSym)
|
let mname = mangleName(p.module, resultSym)
|
||||||
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
|
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
|
||||||
resultAsgn = p.indentLine(("var $# = $#;$n" | "$$$# = $#;$n") % [mname, resVar])
|
resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
|
||||||
if resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and
|
if resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and
|
||||||
mapType(p, resultSym.typ) == etyBaseIndex:
|
mapType(p, resultSym.typ) == etyBaseIndex:
|
||||||
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
|
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
|
||||||
|
|
@ -2267,8 +2028,7 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
elif fromUint:
|
elif fromUint:
|
||||||
if src.size == 4 and dest.size == 4:
|
if src.size == 4 and dest.size == 4:
|
||||||
# XXX prevent multi evaluations
|
# XXX prevent multi evaluations
|
||||||
r.res = "($1|0)" % [r.res] |
|
r.res = "($1|0)" % [r.res]
|
||||||
"($1>(float)2147483647?(int)$1-4294967296:$1)" % [r.res]
|
|
||||||
else:
|
else:
|
||||||
let trimmer = unsignedTrimmer(dest.size)
|
let trimmer = unsignedTrimmer(dest.size)
|
||||||
let minuend = case dest.size
|
let minuend = case dest.size
|
||||||
|
|
@ -2304,8 +2064,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.res = rope"null"
|
r.res = rope"null"
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
of nkStrLit..nkTripleStrLit:
|
of nkStrLit..nkTripleStrLit:
|
||||||
if skipTypes(n.typ, abstractVarRange).kind == tyString and
|
if skipTypes(n.typ, abstractVarRange).kind == tyString:
|
||||||
p.target == targetJS:
|
|
||||||
useMagic(p, "makeNimstrLit")
|
useMagic(p, "makeNimstrLit")
|
||||||
r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
|
r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
|
||||||
else:
|
else:
|
||||||
|
|
@ -2342,10 +2101,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of nkObjConstr: genObjConstr(p, n, r)
|
of nkObjConstr: genObjConstr(p, n, r)
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
|
||||||
of nkAddr, nkHiddenAddr:
|
of nkAddr, nkHiddenAddr:
|
||||||
if p.target == targetJS:
|
|
||||||
genAddr(p, n, r)
|
genAddr(p, n, r)
|
||||||
else:
|
|
||||||
gen(p, n.sons[0], r)
|
|
||||||
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
|
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
|
||||||
of nkBracketExpr: genArrayAccess(p, n, r)
|
of nkBracketExpr: genArrayAccess(p, n, r)
|
||||||
of nkDotExpr: genFieldAccess(p, n, r)
|
of nkDotExpr: genFieldAccess(p, n, r)
|
||||||
|
|
@ -2422,8 +2178,7 @@ proc newModule(module: PSym): BModule =
|
||||||
if globals == nil:
|
if globals == nil:
|
||||||
globals = newGlobals()
|
globals = newGlobals()
|
||||||
|
|
||||||
proc genHeader(target: TTarget): Rope =
|
proc genHeader(): Rope =
|
||||||
if target == targetJS:
|
|
||||||
result = (
|
result = (
|
||||||
"/* Generated by the Nim Compiler v$1 */$n" &
|
"/* Generated by the Nim Compiler v$1 */$n" &
|
||||||
"/* (c) " & copyrightYear & " Andreas Rumpf */$n$n" &
|
"/* (c) " & copyrightYear & " Andreas Rumpf */$n$n" &
|
||||||
|
|
@ -2439,14 +2194,6 @@ proc genHeader(target: TTarget): Rope =
|
||||||
"if (typeof Float32Array === 'undefined') Float32Array = Array;$n" &
|
"if (typeof Float32Array === 'undefined') Float32Array = Array;$n" &
|
||||||
"if (typeof Float64Array === 'undefined') Float64Array = Array;$n") %
|
"if (typeof Float64Array === 'undefined') Float64Array = Array;$n") %
|
||||||
[rope(VersionAsString)]
|
[rope(VersionAsString)]
|
||||||
else:
|
|
||||||
result = ("<?php$n" &
|
|
||||||
"/* Generated by the Nim Compiler v$1 */$n" &
|
|
||||||
"/* (c) " & copyrightYear & " Andreas Rumpf */$n$n" &
|
|
||||||
"$$framePtr = null;$n" &
|
|
||||||
"$$excHandler = 0;$n" &
|
|
||||||
"$$lastJSError = null;$n") %
|
|
||||||
[rope(VersionAsString)]
|
|
||||||
|
|
||||||
proc genModule(p: PProc, n: PNode) =
|
proc genModule(p: PProc, n: PNode) =
|
||||||
if optStackTrace in p.options:
|
if optStackTrace in p.options:
|
||||||
|
|
@ -2513,8 +2260,8 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||||
result = myProcess(b, n)
|
result = myProcess(b, n)
|
||||||
var m = BModule(b)
|
var m = BModule(b)
|
||||||
if sfMainModule in m.module.flags:
|
if sfMainModule in m.module.flags:
|
||||||
let ext = if m.target == targetJS: "js" else: "php"
|
let ext = "js"
|
||||||
let f = if globals.classes.len == 0: m.module.filename
|
let f = if globals.classes.len == 0: toFilename(FileIndex m.module.position)
|
||||||
else: "nimsystem"
|
else: "nimsystem"
|
||||||
let code = wholeCode(graph, m)
|
let code = wholeCode(graph, m)
|
||||||
let outfile =
|
let outfile =
|
||||||
|
|
@ -2523,7 +2270,7 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||||
else: getCurrentDir() / options.outFile
|
else: getCurrentDir() / options.outFile
|
||||||
else:
|
else:
|
||||||
changeFileExt(completeCFilePath(f), ext)
|
changeFileExt(completeCFilePath(f), ext)
|
||||||
discard writeRopeIfNotEqual(genHeader(m.target) & code, outfile)
|
discard writeRopeIfNotEqual(genHeader() & code, outfile)
|
||||||
for obj, content in items(globals.classes):
|
for obj, content in items(globals.classes):
|
||||||
genClass(obj, content, ext)
|
genClass(obj, content, ext)
|
||||||
|
|
||||||
|
|
@ -2533,7 +2280,6 @@ proc myOpenCached(graph: ModuleGraph; s: PSym, rd: PRodReader): PPassContext =
|
||||||
|
|
||||||
proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
|
proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
|
||||||
var r = newModule(s)
|
var r = newModule(s)
|
||||||
r.target = if gCmd == cmdCompileToPHP: targetPHP else: targetJS
|
|
||||||
result = r
|
result = r
|
||||||
|
|
||||||
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
||||||
|
|
|
||||||
|
|
@ -121,26 +121,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
|
||||||
addf(p.g.typeInfo, "$1.base = $2;$n",
|
addf(p.g.typeInfo, "$1.base = $2;$n",
|
||||||
[name, genTypeInfo(p, typ.sons[0])])
|
[name, genTypeInfo(p, typ.sons[0])])
|
||||||
|
|
||||||
proc genEnumInfoPHP(p: PProc; t: PType): Rope =
|
|
||||||
let t = t.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink})
|
|
||||||
result = "$$NTI$1" % [rope(t.id)]
|
|
||||||
p.declareGlobal(t.id, result)
|
|
||||||
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
|
|
||||||
|
|
||||||
let length = sonsLen(t.n)
|
|
||||||
var s: Rope = nil
|
|
||||||
for i in countup(0, length - 1):
|
|
||||||
if (t.n.sons[i].kind != nkSym): internalError(t.n.info, "genEnumInfo")
|
|
||||||
let field = t.n.sons[i].sym
|
|
||||||
if i > 0: add(s, ", " & tnl)
|
|
||||||
let extName = if field.ast == nil: field.name.s else: field.ast.strVal
|
|
||||||
addf(s, "$# => $#$n",
|
|
||||||
[rope(field.position), makeJSString(extName)])
|
|
||||||
prepend(p.g.typeInfo, "$$$# = $#;$n" % [result, s])
|
|
||||||
|
|
||||||
proc genTypeInfo(p: PProc, typ: PType): Rope =
|
proc genTypeInfo(p: PProc, typ: PType): Rope =
|
||||||
if p.target == targetPHP:
|
|
||||||
return makeJSString(typeToString(typ, preferModuleInfo))
|
|
||||||
let t = typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink})
|
let t = typ.skipTypes({tyGenericInst, tyDistinct, tyAlias, tySink})
|
||||||
result = "NTI$1" % [rope(t.id)]
|
result = "NTI$1" % [rope(t.id)]
|
||||||
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
|
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,7 @@ template isIterator*(owner: PSym): bool =
|
||||||
proc liftingHarmful(owner: PSym): bool {.inline.} =
|
proc liftingHarmful(owner: PSym): bool {.inline.} =
|
||||||
## lambda lifting can be harmful for JS-like code generators.
|
## lambda lifting can be harmful for JS-like code generators.
|
||||||
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
|
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
|
||||||
result = gCmd in {cmdCompileToPHP, cmdCompileToJS} and not isCompileTime
|
result = gCmd == cmdCompileToJS and not isCompileTime
|
||||||
|
|
||||||
proc liftIterSym*(n: PNode; owner: PSym): PNode =
|
proc liftIterSym*(n: PNode; owner: PSym): PNode =
|
||||||
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
||||||
|
|
@ -813,7 +813,7 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode =
|
||||||
let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
|
let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
|
||||||
|
|
||||||
if body.kind == nkEmpty or (
|
if body.kind == nkEmpty or (
|
||||||
gCmd in {cmdCompileToPHP, cmdCompileToJS} and not isCompileTime) or
|
gCmd == cmdCompileToJS and not isCompileTime) or
|
||||||
fn.skipGenericOwner.kind != skModule:
|
fn.skipGenericOwner.kind != skModule:
|
||||||
# ignore forward declaration:
|
# ignore forward declaration:
|
||||||
result = body
|
result = body
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ type
|
||||||
|
|
||||||
TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
|
TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
|
||||||
TLexer* = object of TBaseLexer
|
TLexer* = object of TBaseLexer
|
||||||
fileIdx*: int32
|
fileIdx*: FileIndex
|
||||||
indentAhead*: int # if > 0 an indendation has already been read
|
indentAhead*: int # if > 0 an indendation has already been read
|
||||||
# this is needed because scanning comments
|
# this is needed because scanning comments
|
||||||
# needs so much look-ahead
|
# needs so much look-ahead
|
||||||
|
|
@ -222,7 +222,7 @@ proc fillToken(L: var TToken) =
|
||||||
L.commentOffsetA = 0
|
L.commentOffsetA = 0
|
||||||
L.commentOffsetB = 0
|
L.commentOffsetB = 0
|
||||||
|
|
||||||
proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream;
|
proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
|
||||||
cache: IdentCache) =
|
cache: IdentCache) =
|
||||||
openBaseLexer(lex, inputstream)
|
openBaseLexer(lex, inputstream)
|
||||||
lex.fileIdx = fileidx
|
lex.fileIdx = fileidx
|
||||||
|
|
@ -274,7 +274,7 @@ template tokenEnd(tok, pos) {.dirty.} =
|
||||||
when defined(nimsuggest):
|
when defined(nimsuggest):
|
||||||
let colB = getColNumber(L, pos)+1
|
let colB = getColNumber(L, pos)+1
|
||||||
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
|
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
|
||||||
L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
|
L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
|
||||||
L.cursor = CursorPosition.InToken
|
L.cursor = CursorPosition.InToken
|
||||||
gTrackPos.col = colA.int16
|
gTrackPos.col = colA.int16
|
||||||
colA = 0
|
colA = 0
|
||||||
|
|
@ -285,9 +285,9 @@ template tokenEndIgnore(tok, pos) =
|
||||||
when defined(nimsuggest):
|
when defined(nimsuggest):
|
||||||
let colB = getColNumber(L, pos)
|
let colB = getColNumber(L, pos)
|
||||||
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
|
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
|
||||||
L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
|
L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
|
||||||
gTrackPos.fileIndex = trackPosInvalidFileIdx
|
gTrackPos.fileIndex = trackPosInvalidFileIdx
|
||||||
gTrackPos.line = -1
|
gTrackPos.line = 0'u16
|
||||||
colA = 0
|
colA = 0
|
||||||
when defined(nimpretty):
|
when defined(nimpretty):
|
||||||
tok.offsetB = L.offsetBase + pos
|
tok.offsetB = L.offsetBase + pos
|
||||||
|
|
@ -299,7 +299,7 @@ template tokenEndPrevious(tok, pos) =
|
||||||
# the cursor in a string literal or comment:
|
# the cursor in a string literal or comment:
|
||||||
let colB = getColNumber(L, pos)
|
let colB = getColNumber(L, pos)
|
||||||
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
|
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
|
||||||
L.lineNumber == gTrackPos.line and gIdeCmd in {ideSug, ideCon}:
|
L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
|
||||||
L.cursor = CursorPosition.BeforeToken
|
L.cursor = CursorPosition.BeforeToken
|
||||||
gTrackPos = L.previousToken
|
gTrackPos = L.previousToken
|
||||||
gTrackPosAttached = true
|
gTrackPosAttached = true
|
||||||
|
|
@ -1003,6 +1003,10 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||||
var buf = L.buf
|
var buf = L.buf
|
||||||
tokenBegin(tok, pos)
|
tokenBegin(tok, pos)
|
||||||
tok.strongSpaceA = 0
|
tok.strongSpaceA = 0
|
||||||
|
when defined(nimpretty):
|
||||||
|
var hasComment = false
|
||||||
|
tok.commentOffsetA = L.offsetBase + pos
|
||||||
|
tok.commentOffsetB = tok.commentOffsetA
|
||||||
while true:
|
while true:
|
||||||
case buf[pos]
|
case buf[pos]
|
||||||
of ' ':
|
of ' ':
|
||||||
|
|
@ -1021,6 +1025,7 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||||
inc(pos)
|
inc(pos)
|
||||||
inc(indent)
|
inc(indent)
|
||||||
elif buf[pos] == '#' and buf[pos+1] == '[':
|
elif buf[pos] == '#' and buf[pos+1] == '[':
|
||||||
|
when defined(nimpretty): hasComment = true
|
||||||
skipMultiLineComment(L, tok, pos+2, false)
|
skipMultiLineComment(L, tok, pos+2, false)
|
||||||
pos = L.bufpos
|
pos = L.bufpos
|
||||||
buf = L.buf
|
buf = L.buf
|
||||||
|
|
@ -1034,14 +1039,11 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||||
of '#':
|
of '#':
|
||||||
# do not skip documentation comment:
|
# do not skip documentation comment:
|
||||||
if buf[pos+1] == '#': break
|
if buf[pos+1] == '#': break
|
||||||
when defined(nimpretty):
|
when defined(nimpretty): hasComment = true
|
||||||
tok.commentOffsetA = L.offsetBase + pos
|
|
||||||
if buf[pos+1] == '[':
|
if buf[pos+1] == '[':
|
||||||
skipMultiLineComment(L, tok, pos+2, false)
|
skipMultiLineComment(L, tok, pos+2, false)
|
||||||
pos = L.bufpos
|
pos = L.bufpos
|
||||||
buf = L.buf
|
buf = L.buf
|
||||||
when defined(nimpretty):
|
|
||||||
tok.commentOffsetB = L.offsetBase + pos
|
|
||||||
else:
|
else:
|
||||||
tokenBegin(tok, pos)
|
tokenBegin(tok, pos)
|
||||||
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos)
|
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos)
|
||||||
|
|
@ -1053,6 +1055,9 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||||
tokenEndPrevious(tok, pos-1)
|
tokenEndPrevious(tok, pos-1)
|
||||||
L.bufpos = pos
|
L.bufpos = pos
|
||||||
when defined(nimpretty):
|
when defined(nimpretty):
|
||||||
|
if hasComment:
|
||||||
|
tok.commentOffsetB = L.offsetBase + pos
|
||||||
|
tok.tokType = tkComment
|
||||||
if gIndentationWidth <= 0:
|
if gIndentationWidth <= 0:
|
||||||
gIndentationWidth = tok.indent
|
gIndentationWidth = tok.indent
|
||||||
|
|
||||||
|
|
@ -1061,7 +1066,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||||
when defined(nimsuggest):
|
when defined(nimsuggest):
|
||||||
# we attach the cursor to the last *strong* token
|
# we attach the cursor to the last *strong* token
|
||||||
if tok.tokType notin weakTokens:
|
if tok.tokType notin weakTokens:
|
||||||
L.previousToken.line = tok.line.int16
|
L.previousToken.line = tok.line.uint16
|
||||||
L.previousToken.col = tok.col.int16
|
L.previousToken.col = tok.col.int16
|
||||||
|
|
||||||
when defined(nimsuggest):
|
when defined(nimsuggest):
|
||||||
|
|
@ -1074,6 +1079,10 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||||
else:
|
else:
|
||||||
tok.indent = -1
|
tok.indent = -1
|
||||||
skip(L, tok)
|
skip(L, tok)
|
||||||
|
when defined(nimpretty):
|
||||||
|
if tok.tokType == tkComment:
|
||||||
|
L.indentAhead = L.currLineIndent
|
||||||
|
return
|
||||||
var c = L.buf[L.bufpos]
|
var c = L.buf[L.bufpos]
|
||||||
tok.line = L.lineNumber
|
tok.line = L.lineNumber
|
||||||
tok.col = getColNumber(L, L.bufpos)
|
tok.col = getColNumber(L, L.bufpos)
|
||||||
|
|
@ -1109,7 +1118,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||||
tok.tokType = tkParLe
|
tok.tokType = tkParLe
|
||||||
when defined(nimsuggest):
|
when defined(nimsuggest):
|
||||||
if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and
|
if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and
|
||||||
tok.line == gTrackPos.line and gIdeCmd == ideCon:
|
tok.line == gTrackPos.line.int and gIdeCmd == ideCon:
|
||||||
gTrackPos.col = tok.col.int16
|
gTrackPos.col = tok.col.int16
|
||||||
of ')':
|
of ')':
|
||||||
tok.tokType = tkParRi
|
tok.tokType = tkParRi
|
||||||
|
|
@ -1130,7 +1139,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
|
||||||
of '.':
|
of '.':
|
||||||
when defined(nimsuggest):
|
when defined(nimsuggest):
|
||||||
if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and
|
if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and
|
||||||
tok.line == gTrackPos.line and gIdeCmd == ideSug:
|
tok.line == gTrackPos.line.int and gIdeCmd == ideSug:
|
||||||
tok.tokType = tkDot
|
tok.tokType = tkDot
|
||||||
L.cursor = CursorPosition.InToken
|
L.cursor = CursorPosition.InToken
|
||||||
gTrackPos.col = tok.col.int16
|
gTrackPos.col = tok.col.int16
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ proc writeDepsFile(g: ModuleGraph; project: string) =
|
||||||
let f = open(changeFileExt(project, "deps"), fmWrite)
|
let f = open(changeFileExt(project, "deps"), fmWrite)
|
||||||
for m in g.modules:
|
for m in g.modules:
|
||||||
if m != nil:
|
if m != nil:
|
||||||
f.writeLine(toFullPath(m.position.int32))
|
f.writeLine(toFullPath(m.position.FileIndex))
|
||||||
for k in g.inclToMod.keys:
|
for k in g.inclToMod.keys:
|
||||||
if g.getModule(k).isNil: # don't repeat includes which are also modules
|
if g.getModule(k).isNil: # don't repeat includes which are also modules
|
||||||
f.writeLine(k.toFullPath)
|
f.writeLine(k.toFullPath)
|
||||||
|
|
@ -94,7 +94,6 @@ proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
|
||||||
defineSymbol("nimrod") # 'nimrod' is always defined
|
defineSymbol("nimrod") # 'nimrod' is always defined
|
||||||
defineSymbol("ecmascript") # For backward compatibility
|
defineSymbol("ecmascript") # For backward compatibility
|
||||||
defineSymbol("js")
|
defineSymbol("js")
|
||||||
if gCmd == cmdCompileToPHP: defineSymbol("nimphp")
|
|
||||||
semanticPasses()
|
semanticPasses()
|
||||||
registerPass(JSgenPass)
|
registerPass(JSgenPass)
|
||||||
compileProject(graph, cache)
|
compileProject(graph, cache)
|
||||||
|
|
@ -189,9 +188,6 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
|
||||||
of "js", "compiletojs":
|
of "js", "compiletojs":
|
||||||
gCmd = cmdCompileToJS
|
gCmd = cmdCompileToJS
|
||||||
commandCompileToJS(graph, cache)
|
commandCompileToJS(graph, cache)
|
||||||
of "php":
|
|
||||||
gCmd = cmdCompileToPHP
|
|
||||||
commandCompileToJS(graph, cache)
|
|
||||||
of "doc0":
|
of "doc0":
|
||||||
wantMainModule()
|
wantMainModule()
|
||||||
gCmd = cmdDoc
|
gCmd = cmdDoc
|
||||||
|
|
@ -269,7 +265,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
|
||||||
of "parse":
|
of "parse":
|
||||||
gCmd = cmdParse
|
gCmd = cmdParse
|
||||||
wantMainModule()
|
wantMainModule()
|
||||||
discard parseFile(gProjectMainIdx, cache)
|
discard parseFile(FileIndex gProjectMainIdx, cache)
|
||||||
of "scan":
|
of "scan":
|
||||||
gCmd = cmdScan
|
gCmd = cmdScan
|
||||||
wantMainModule()
|
wantMainModule()
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
## - Its dependent module stays the same.
|
## - Its dependent module stays the same.
|
||||||
##
|
##
|
||||||
|
|
||||||
import ast, intsets, tables, options, rod
|
import ast, intsets, tables, options, rod, msgs, hashes
|
||||||
|
|
||||||
type
|
type
|
||||||
ModuleGraph* = ref object
|
ModuleGraph* = ref object
|
||||||
|
|
@ -34,9 +34,9 @@ type
|
||||||
deps*: IntSet # the dependency graph or potentially its transitive closure.
|
deps*: IntSet # the dependency graph or potentially its transitive closure.
|
||||||
suggestMode*: bool # whether we are in nimsuggest mode or not.
|
suggestMode*: bool # whether we are in nimsuggest mode or not.
|
||||||
invalidTransitiveClosure: bool
|
invalidTransitiveClosure: bool
|
||||||
inclToMod*: Table[int32, int32] # mapping of include file to the
|
inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the
|
||||||
# first module that included it
|
# first module that included it
|
||||||
importStack*: seq[int32] # The current import stack. Used for detecting recursive
|
importStack*: seq[FileIndex] # 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
|
config*: ConfigRef
|
||||||
|
|
@ -45,6 +45,8 @@ type
|
||||||
owners*: seq[PSym]
|
owners*: seq[PSym]
|
||||||
methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]]
|
methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]]
|
||||||
|
|
||||||
|
proc hash*(x: FileIndex): Hash {.borrow.}
|
||||||
|
|
||||||
{.this: g.}
|
{.this: g.}
|
||||||
|
|
||||||
proc stopCompile*(g: ModuleGraph): bool {.inline.} =
|
proc stopCompile*(g: ModuleGraph): bool {.inline.} =
|
||||||
|
|
@ -56,7 +58,7 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
|
||||||
result.deps = initIntSet()
|
result.deps = initIntSet()
|
||||||
result.modules = @[]
|
result.modules = @[]
|
||||||
result.importStack = @[]
|
result.importStack = @[]
|
||||||
result.inclToMod = initTable[int32, int32]()
|
result.inclToMod = initTable[FileIndex, FileIndex]()
|
||||||
if config.isNil:
|
if config.isNil:
|
||||||
result.config = newConfigRef()
|
result.config = newConfigRef()
|
||||||
else:
|
else:
|
||||||
|
|
@ -69,35 +71,35 @@ proc resetAllModules*(g: ModuleGraph) =
|
||||||
deps = initIntSet()
|
deps = initIntSet()
|
||||||
modules = @[]
|
modules = @[]
|
||||||
importStack = @[]
|
importStack = @[]
|
||||||
inclToMod = initTable[int32, int32]()
|
inclToMod = initTable[FileIndex, FileIndex]()
|
||||||
usageSym = nil
|
usageSym = nil
|
||||||
owners = @[]
|
owners = @[]
|
||||||
methods = @[]
|
methods = @[]
|
||||||
|
|
||||||
proc getModule*(g: ModuleGraph; fileIdx: int32): PSym =
|
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||||
if fileIdx >= 0 and fileIdx < modules.len:
|
if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len:
|
||||||
result = modules[fileIdx]
|
result = modules[fileIdx.int32]
|
||||||
|
|
||||||
proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
|
proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
|
||||||
|
|
||||||
proc addDep*(g: ModuleGraph; m: PSym, dep: int32) =
|
proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
|
||||||
assert m.position == m.info.fileIndex
|
assert m.position == m.info.fileIndex.int32
|
||||||
addModuleDep(m.info.fileIndex, dep, isIncludeFile = false)
|
addModuleDep(m.info.fileIndex, dep, isIncludeFile = false)
|
||||||
if suggestMode:
|
if suggestMode:
|
||||||
deps.incl m.position.dependsOn(dep)
|
deps.incl m.position.dependsOn(dep.int)
|
||||||
# we compute the transitive closure later when quering the graph lazily.
|
# we compute the transitive closure later when quering the graph lazily.
|
||||||
# this improve efficiency quite a lot:
|
# this improve efficiency quite a lot:
|
||||||
#invalidTransitiveClosure = true
|
#invalidTransitiveClosure = true
|
||||||
|
|
||||||
proc addIncludeDep*(g: ModuleGraph; module, includeFile: int32) =
|
proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) =
|
||||||
addModuleDep(module, includeFile, isIncludeFile = true)
|
addModuleDep(module, includeFile, isIncludeFile = true)
|
||||||
discard hasKeyOrPut(inclToMod, includeFile, module)
|
discard hasKeyOrPut(inclToMod, includeFile, module)
|
||||||
|
|
||||||
proc parentModule*(g: ModuleGraph; fileIdx: int32): int32 =
|
proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex =
|
||||||
## returns 'fileIdx' if the file belonging to this index is
|
## returns 'fileIdx' if the file belonging to this index is
|
||||||
## directly used as a module or else the module that first
|
## directly used as a module or else the module that first
|
||||||
## references this include file.
|
## references this include file.
|
||||||
if fileIdx >= 0 and fileIdx < modules.len and modules[fileIdx] != nil:
|
if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len and modules[fileIdx.int32] != nil:
|
||||||
result = fileIdx
|
result = fileIdx
|
||||||
else:
|
else:
|
||||||
result = inclToMod.getOrDefault(fileIdx)
|
result = inclToMod.getOrDefault(fileIdx)
|
||||||
|
|
@ -111,11 +113,11 @@ proc transitiveClosure(g: var IntSet; n: int) =
|
||||||
if g.contains(i.dependsOn(k)) and g.contains(k.dependsOn(j)):
|
if g.contains(i.dependsOn(k)) and g.contains(k.dependsOn(j)):
|
||||||
g.incl i.dependsOn(j)
|
g.incl i.dependsOn(j)
|
||||||
|
|
||||||
proc markDirty*(g: ModuleGraph; fileIdx: int32) =
|
proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||||
let m = getModule fileIdx
|
let m = getModule fileIdx
|
||||||
if m != nil: incl m.flags, sfDirty
|
if m != nil: incl m.flags, sfDirty
|
||||||
|
|
||||||
proc markClientsDirty*(g: ModuleGraph; fileIdx: int32) =
|
proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||||
# we need to mark its dependent modules D as dirty right away because after
|
# we need to mark its dependent modules D as dirty right away because after
|
||||||
# nimsuggest is done with this module, the module's dirty flag will be
|
# nimsuggest is done with this module, the module's dirty flag will be
|
||||||
# cleared but D still needs to be remembered as 'dirty'.
|
# cleared but D still needs to be remembered as 'dirty'.
|
||||||
|
|
@ -126,7 +128,7 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: int32) =
|
||||||
# every module that *depends* on this file is also dirty:
|
# every module that *depends* on this file is also dirty:
|
||||||
for i in 0i32..<modules.len.int32:
|
for i in 0i32..<modules.len.int32:
|
||||||
let m = modules[i]
|
let m = modules[i]
|
||||||
if m != nil and deps.contains(i.dependsOn(fileIdx)):
|
if m != nil and deps.contains(i.dependsOn(fileIdx.int)):
|
||||||
incl m.flags, sfDirty
|
incl m.flags, sfDirty
|
||||||
|
|
||||||
proc isDirty*(g: ModuleGraph; m: PSym): bool =
|
proc isDirty*(g: ModuleGraph; m: PSym): bool =
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ proc getModuleName*(n: PNode): string =
|
||||||
localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
|
localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
proc checkModuleName*(n: PNode; doLocalError=true): int32 =
|
proc checkModuleName*(n: PNode; doLocalError=true): FileIndex =
|
||||||
# This returns the full canonical path for a given module import
|
# This returns the full canonical path for a given module import
|
||||||
let modulename = n.getModuleName
|
let modulename = n.getModuleName
|
||||||
let fullPath = findModule(modulename, n.info.toFullPath)
|
let fullPath = findModule(modulename, n.info.toFullPath)
|
||||||
|
|
|
||||||
|
|
@ -13,115 +13,10 @@ import
|
||||||
ast, astalgo, magicsys, std / sha1, rodread, msgs, cgendata, sigmatch, options,
|
ast, astalgo, magicsys, std / sha1, rodread, msgs, cgendata, sigmatch, options,
|
||||||
idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod
|
idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod
|
||||||
|
|
||||||
when false:
|
|
||||||
type
|
|
||||||
TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
|
|
||||||
THashStatus* = enum hashNotTaken, hashCached, hashHasChanged, hashNotChanged
|
|
||||||
|
|
||||||
TModuleInMemory* = object
|
|
||||||
hash*: SecureHash
|
|
||||||
deps*: seq[int32] ## XXX: slurped files are currently not tracked
|
|
||||||
|
|
||||||
needsRecompile*: TNeedRecompile
|
|
||||||
hashStatus*: THashStatus
|
|
||||||
|
|
||||||
var
|
|
||||||
gCompiledModules: seq[PSym] = @[]
|
|
||||||
gMemCacheData*: seq[TModuleInMemory] = @[]
|
|
||||||
## XXX: we should implement recycling of file IDs
|
|
||||||
## if the user keeps renaming modules, the file IDs will keep growing
|
|
||||||
gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why.
|
|
||||||
|
|
||||||
proc hashChanged(fileIdx: int32): bool =
|
|
||||||
internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
|
|
||||||
|
|
||||||
template updateStatus =
|
|
||||||
gMemCacheData[fileIdx].hashStatus = if result: hashHasChanged
|
|
||||||
else: hashNotChanged
|
|
||||||
# echo "TESTING Hash: ", fileIdx.toFilename, " ", result
|
|
||||||
|
|
||||||
case gMemCacheData[fileIdx].hashStatus
|
|
||||||
of hashHasChanged:
|
|
||||||
result = true
|
|
||||||
of hashNotChanged:
|
|
||||||
result = false
|
|
||||||
of hashCached:
|
|
||||||
let newHash = secureHashFile(fileIdx.toFullPath)
|
|
||||||
result = newHash != gMemCacheData[fileIdx].hash
|
|
||||||
gMemCacheData[fileIdx].hash = newHash
|
|
||||||
updateStatus()
|
|
||||||
of hashNotTaken:
|
|
||||||
gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
|
|
||||||
result = true
|
|
||||||
updateStatus()
|
|
||||||
|
|
||||||
proc doHash(fileIdx: int32) =
|
|
||||||
if gMemCacheData[fileIdx].hashStatus == hashNotTaken:
|
|
||||||
# echo "FIRST Hash: ", fileIdx.ToFilename
|
|
||||||
gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
|
|
||||||
|
|
||||||
proc resetModule*(fileIdx: int32) =
|
|
||||||
# echo "HARD RESETTING ", fileIdx.toFilename
|
|
||||||
if fileIdx <% gMemCacheData.len:
|
|
||||||
gMemCacheData[fileIdx].needsRecompile = Yes
|
|
||||||
if fileIdx <% gCompiledModules.len:
|
|
||||||
gCompiledModules[fileIdx] = nil
|
|
||||||
if fileIdx <% cgendata.gModules.len:
|
|
||||||
cgendata.gModules[fileIdx] = nil
|
|
||||||
|
|
||||||
proc resetModule*(module: PSym) =
|
|
||||||
let conflict = getModule(module.position.int32)
|
|
||||||
if conflict == nil: return
|
|
||||||
doAssert conflict == module
|
|
||||||
resetModule(module.position.int32)
|
|
||||||
initStrTable(module.tab)
|
|
||||||
|
|
||||||
proc resetAllModules* =
|
|
||||||
for i in 0..gCompiledModules.high:
|
|
||||||
if gCompiledModules[i] != nil:
|
|
||||||
resetModule(i.int32)
|
|
||||||
resetPackageCache()
|
|
||||||
# for m in cgenModules(): echo "CGEN MODULE FOUND"
|
|
||||||
|
|
||||||
proc resetAllModulesHard* =
|
|
||||||
resetPackageCache()
|
|
||||||
gCompiledModules.setLen 0
|
|
||||||
gMemCacheData.setLen 0
|
|
||||||
magicsys.resetSysTypes()
|
|
||||||
# XXX
|
|
||||||
#gOwners = @[]
|
|
||||||
|
|
||||||
proc checkDepMem(fileIdx: int32): TNeedRecompile =
|
|
||||||
template markDirty =
|
|
||||||
resetModule(fileIdx)
|
|
||||||
return Yes
|
|
||||||
|
|
||||||
if gFuzzyGraphChecking:
|
|
||||||
if gMemCacheData[fileIdx].needsRecompile != Maybe:
|
|
||||||
return gMemCacheData[fileIdx].needsRecompile
|
|
||||||
else:
|
|
||||||
# cycle detection: We claim that a cycle does no harm.
|
|
||||||
if gMemCacheData[fileIdx].needsRecompile == Probing:
|
|
||||||
return No
|
|
||||||
|
|
||||||
if optForceFullMake in gGlobalOptions or hashChanged(fileIdx):
|
|
||||||
markDirty()
|
|
||||||
|
|
||||||
if gMemCacheData[fileIdx].deps != nil:
|
|
||||||
gMemCacheData[fileIdx].needsRecompile = Probing
|
|
||||||
for dep in gMemCacheData[fileIdx].deps:
|
|
||||||
let d = checkDepMem(dep)
|
|
||||||
if d in {Yes, Recompiled}:
|
|
||||||
# echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
|
|
||||||
markDirty()
|
|
||||||
|
|
||||||
gMemCacheData[fileIdx].needsRecompile = No
|
|
||||||
return No
|
|
||||||
|
|
||||||
proc resetSystemArtifacts*() =
|
proc resetSystemArtifacts*() =
|
||||||
magicsys.resetSysTypes()
|
magicsys.resetSysTypes()
|
||||||
|
|
||||||
proc newModule(graph: ModuleGraph; fileIdx: int32): PSym =
|
proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||||
# We cannot call ``newSym`` here, because we have to circumvent the ID
|
# We cannot call ``newSym`` here, because we have to circumvent the ID
|
||||||
# mechanism, which we do in order to assign each module a persistent ID.
|
# mechanism, which we do in order to assign each module a persistent ID.
|
||||||
new(result)
|
new(result)
|
||||||
|
|
@ -144,9 +39,9 @@ proc newModule(graph: ModuleGraph; fileIdx: int32): PSym =
|
||||||
graph.packageSyms.strTableAdd(packSym)
|
graph.packageSyms.strTableAdd(packSym)
|
||||||
|
|
||||||
result.owner = packSym
|
result.owner = packSym
|
||||||
result.position = fileIdx
|
result.position = int fileIdx
|
||||||
|
|
||||||
growCache graph.modules, fileIdx
|
growCache graph.modules, int fileIdx
|
||||||
graph.modules[result.position] = result
|
graph.modules[result.position] = result
|
||||||
|
|
||||||
incl(result.flags, sfUsed)
|
incl(result.flags, sfUsed)
|
||||||
|
|
@ -158,7 +53,7 @@ proc newModule(graph: ModuleGraph; fileIdx: int32): PSym =
|
||||||
# strTableIncl() for error corrections:
|
# strTableIncl() for error corrections:
|
||||||
discard strTableIncl(packSym.tab, result)
|
discard strTableIncl(packSym.tab, result)
|
||||||
|
|
||||||
proc compileModule*(graph: ModuleGraph; fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym =
|
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, flags: TSymFlags): PSym =
|
||||||
result = graph.getModule(fileIdx)
|
result = graph.getModule(fileIdx)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
#growCache gMemCacheData, fileIdx
|
#growCache gMemCacheData, fileIdx
|
||||||
|
|
@ -199,7 +94,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: int32; cache: IdentCache, flags
|
||||||
else:
|
else:
|
||||||
result = gCompiledModules[fileIdx]
|
result = gCompiledModules[fileIdx]
|
||||||
|
|
||||||
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
|
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
|
||||||
cache: IdentCache): PSym {.procvar.} =
|
cache: IdentCache): PSym {.procvar.} =
|
||||||
# this is called by the semantic checking phase
|
# this is called by the semantic checking phase
|
||||||
result = compileModule(graph, fileIdx, cache, {})
|
result = compileModule(graph, fileIdx, cache, {})
|
||||||
|
|
@ -210,11 +105,11 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
|
||||||
gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
|
gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
|
||||||
else: ForeignPackageNotes
|
else: ForeignPackageNotes
|
||||||
|
|
||||||
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
|
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
|
||||||
cache: IdentCache): PNode {.procvar.} =
|
cache: IdentCache): PNode {.procvar.} =
|
||||||
result = syntaxes.parseFile(fileIdx, cache)
|
result = syntaxes.parseFile(fileIdx, cache)
|
||||||
graph.addDep(s, fileIdx)
|
graph.addDep(s, fileIdx)
|
||||||
graph.addIncludeDep(s.position.int32, fileIdx)
|
graph.addIncludeDep(s.position.FileIndex, fileIdx)
|
||||||
|
|
||||||
proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
|
proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
|
||||||
if magicsys.systemModule == nil:
|
if magicsys.systemModule == nil:
|
||||||
|
|
@ -224,16 +119,16 @@ proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
|
||||||
proc wantMainModule* =
|
proc wantMainModule* =
|
||||||
if gProjectFull.len == 0:
|
if gProjectFull.len == 0:
|
||||||
fatal(gCmdLineInfo, errCommandExpectsFilename)
|
fatal(gCmdLineInfo, errCommandExpectsFilename)
|
||||||
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
|
gProjectMainIdx = int32 addFileExt(gProjectFull, NimExt).fileInfoIdx
|
||||||
|
|
||||||
passes.gIncludeFile = includeModule
|
passes.gIncludeFile = includeModule
|
||||||
passes.gImportModule = importModule
|
passes.gImportModule = importModule
|
||||||
|
|
||||||
proc compileProject*(graph: ModuleGraph; cache: IdentCache;
|
proc compileProject*(graph: ModuleGraph; cache: IdentCache;
|
||||||
projectFileIdx = -1'i32) =
|
projectFileIdx = InvalidFileIDX) =
|
||||||
wantMainModule()
|
wantMainModule()
|
||||||
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
|
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
|
||||||
let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx
|
let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(gProjectMainIdx) else: projectFileIdx
|
||||||
graph.importStack.add projectFile
|
graph.importStack.add projectFile
|
||||||
if projectFile == systemFileIdx:
|
if projectFile == systemFileIdx:
|
||||||
discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule})
|
discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule})
|
||||||
|
|
|
||||||
|
|
@ -10,21 +10,24 @@
|
||||||
import
|
import
|
||||||
options, strutils, os, tables, ropes, platform, terminal, macros
|
options, strutils, os, tables, ropes, platform, terminal, macros
|
||||||
|
|
||||||
|
const
|
||||||
|
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
|
||||||
|
|
||||||
type
|
type
|
||||||
TMsgKind* = enum
|
TMsgKind* = enum
|
||||||
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated,
|
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated,
|
||||||
errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
|
errStringLiteralExpected,
|
||||||
errIntLiteralExpected, errInvalidCharacterConstant,
|
errIntLiteralExpected, errInvalidCharacterConstant,
|
||||||
errClosingTripleQuoteExpected, errClosingQuoteExpected,
|
errClosingTripleQuoteExpected, errClosingQuoteExpected,
|
||||||
errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
|
errTabulatorsAreNotAllowed, errInvalidToken,
|
||||||
errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange,
|
errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange,
|
||||||
errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote,
|
errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote,
|
||||||
errIdentifierExpected, errNewlineExpected, errInvalidModuleName,
|
errIdentifierExpected, errNewlineExpected, errInvalidModuleName,
|
||||||
errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
|
errOperatorExpected, errTokenExpected,
|
||||||
errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
|
errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
|
||||||
errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
|
errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
|
||||||
errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
|
errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
|
||||||
errExceptionExpected, errExceptionAlreadyHandled,
|
errExceptionAlreadyHandled,
|
||||||
errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
|
errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
|
||||||
errInvalidNumberOfYieldExpr, errCannotReturnExpr,
|
errInvalidNumberOfYieldExpr, errCannotReturnExpr,
|
||||||
errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine,
|
errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine,
|
||||||
|
|
@ -68,7 +71,7 @@ type
|
||||||
errWrongNumberOfArgumentsInCall,
|
errWrongNumberOfArgumentsInCall,
|
||||||
errMissingGenericParamsForTemplate,
|
errMissingGenericParamsForTemplate,
|
||||||
errXCannotBePassedToProcVar,
|
errXCannotBePassedToProcVar,
|
||||||
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed,
|
errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed,
|
||||||
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
|
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
|
||||||
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
|
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
|
||||||
errInvalidOrderInArrayConstructor,
|
errInvalidOrderInArrayConstructor,
|
||||||
|
|
@ -87,7 +90,8 @@ type
|
||||||
errNoReturnTypeDeclared,
|
errNoReturnTypeDeclared,
|
||||||
errNoCommand, errInvalidCommandX, errXOnlyAtModuleScope,
|
errNoCommand, errInvalidCommandX, errXOnlyAtModuleScope,
|
||||||
errXNeedsParamObjectType,
|
errXNeedsParamObjectType,
|
||||||
errTemplateInstantiationTooNested, errInstantiationFrom,
|
errTemplateInstantiationTooNested, errMacroInstantiationTooNested,
|
||||||
|
errInstantiationFrom,
|
||||||
errInvalidIndexValueForTuple, errCommandExpectsFilename,
|
errInvalidIndexValueForTuple, errCommandExpectsFilename,
|
||||||
errMainModuleMustBeSpecified,
|
errMainModuleMustBeSpecified,
|
||||||
errXExpected,
|
errXExpected,
|
||||||
|
|
@ -144,7 +148,6 @@ const
|
||||||
errIllFormedAstX: "illformed AST: $1",
|
errIllFormedAstX: "illformed AST: $1",
|
||||||
errCannotOpenFile: "cannot open \'$1\'",
|
errCannotOpenFile: "cannot open \'$1\'",
|
||||||
errGenerated: "$1",
|
errGenerated: "$1",
|
||||||
errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++",
|
|
||||||
errStringLiteralExpected: "string literal expected",
|
errStringLiteralExpected: "string literal expected",
|
||||||
errIntLiteralExpected: "integer literal expected",
|
errIntLiteralExpected: "integer literal expected",
|
||||||
errInvalidCharacterConstant: "invalid character constant",
|
errInvalidCharacterConstant: "invalid character constant",
|
||||||
|
|
@ -152,7 +155,6 @@ const
|
||||||
errClosingQuoteExpected: "closing \" expected",
|
errClosingQuoteExpected: "closing \" expected",
|
||||||
errTabulatorsAreNotAllowed: "tabulators are not allowed",
|
errTabulatorsAreNotAllowed: "tabulators are not allowed",
|
||||||
errInvalidToken: "invalid token: $1",
|
errInvalidToken: "invalid token: $1",
|
||||||
errLineTooLong: "line too long",
|
|
||||||
errInvalidNumber: "$1 is not a valid number",
|
errInvalidNumber: "$1 is not a valid number",
|
||||||
errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.",
|
errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.",
|
||||||
errNumberOutOfRange: "number $1 out of valid range",
|
errNumberOutOfRange: "number $1 out of valid range",
|
||||||
|
|
@ -164,7 +166,6 @@ const
|
||||||
errInvalidModuleName: "invalid module name: '$1'",
|
errInvalidModuleName: "invalid module name: '$1'",
|
||||||
errOperatorExpected: "operator expected, but found \'$1\'",
|
errOperatorExpected: "operator expected, but found \'$1\'",
|
||||||
errTokenExpected: "\'$1\' expected",
|
errTokenExpected: "\'$1\' expected",
|
||||||
errStringAfterIncludeExpected: "string after \'include\' expected",
|
|
||||||
errRecursiveDependencyX: "recursive dependency: \'$1\'",
|
errRecursiveDependencyX: "recursive dependency: \'$1\'",
|
||||||
errOnOrOffExpected: "\'on\' or \'off\' expected",
|
errOnOrOffExpected: "\'on\' or \'off\' expected",
|
||||||
errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected",
|
errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected",
|
||||||
|
|
@ -174,7 +175,6 @@ const
|
||||||
errAtPopWithoutPush: "\'pop\' without a \'push\' pragma",
|
errAtPopWithoutPush: "\'pop\' without a \'push\' pragma",
|
||||||
errEmptyAsm: "empty asm statement",
|
errEmptyAsm: "empty asm statement",
|
||||||
errInvalidIndentation: "invalid indentation",
|
errInvalidIndentation: "invalid indentation",
|
||||||
errExceptionExpected: "exception expected",
|
|
||||||
errExceptionAlreadyHandled: "exception already handled",
|
errExceptionAlreadyHandled: "exception already handled",
|
||||||
errYieldNotAllowedHere: "'yield' only allowed in an iterator",
|
errYieldNotAllowedHere: "'yield' only allowed in an iterator",
|
||||||
errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
|
errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
|
||||||
|
|
@ -280,7 +280,6 @@ const
|
||||||
errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
|
errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
|
||||||
errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
|
errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
|
||||||
errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
|
errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
|
||||||
errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration",
|
|
||||||
errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
|
errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
|
||||||
errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
|
errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
|
||||||
errImplOfXexpected: "implementation of \'$1\' expected",
|
errImplOfXexpected: "implementation of \'$1\' expected",
|
||||||
|
|
@ -329,7 +328,8 @@ const
|
||||||
errInvalidCommandX: "invalid command: \'$1\'",
|
errInvalidCommandX: "invalid command: \'$1\'",
|
||||||
errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
|
errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
|
||||||
errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
|
errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
|
||||||
errTemplateInstantiationTooNested: "template/macro instantiation too nested",
|
errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N",
|
||||||
|
errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N",
|
||||||
errInstantiationFrom: "template/generic instantiation from here",
|
errInstantiationFrom: "template/generic instantiation from here",
|
||||||
errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
|
errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
|
||||||
errCommandExpectsFilename: "command expects a filename argument",
|
errCommandExpectsFilename: "command expects a filename argument",
|
||||||
|
|
@ -495,15 +495,18 @@ type
|
||||||
# and parsed; usually 'nil' but is used
|
# and parsed; usually 'nil' but is used
|
||||||
# for 'nimsuggest'
|
# for 'nimsuggest'
|
||||||
hash*: string # the checksum of the file
|
hash*: string # the checksum of the file
|
||||||
|
when defined(nimpretty):
|
||||||
|
fullContent*: string
|
||||||
|
FileIndex* = distinct int32
|
||||||
TLineInfo* = object # This is designed to be as small as possible,
|
TLineInfo* = object # This is designed to be as small as possible,
|
||||||
# because it is used
|
# because it is used
|
||||||
# in syntax nodes. We save space here by using
|
# in syntax nodes. We save space here by using
|
||||||
# two int16 and an int32.
|
# two int16 and an int32.
|
||||||
# On 64 bit and on 32 bit systems this is
|
# On 64 bit and on 32 bit systems this is
|
||||||
# only 8 bytes.
|
# only 8 bytes.
|
||||||
line*, col*: int16
|
line*: uint16
|
||||||
fileIndex*: int32
|
col*: int16
|
||||||
|
fileIndex*: FileIndex
|
||||||
when defined(nimpretty):
|
when defined(nimpretty):
|
||||||
offsetA*, offsetB*: int
|
offsetA*, offsetB*: int
|
||||||
commentOffsetA*, commentOffsetB*: int
|
commentOffsetA*, commentOffsetB*: int
|
||||||
|
|
@ -517,6 +520,8 @@ type
|
||||||
ERecoverableError* = object of ValueError
|
ERecoverableError* = object of ValueError
|
||||||
ESuggestDone* = object of Exception
|
ESuggestDone* = object of Exception
|
||||||
|
|
||||||
|
proc `==`*(a, b: FileIndex): bool {.borrow.}
|
||||||
|
|
||||||
const
|
const
|
||||||
NotesVerbosity*: array[0..3, TNoteKinds] = [
|
NotesVerbosity*: array[0..3, TNoteKinds] = [
|
||||||
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
||||||
|
|
@ -541,14 +546,14 @@ const
|
||||||
{low(TNoteKind)..high(TNoteKind)}]
|
{low(TNoteKind)..high(TNoteKind)}]
|
||||||
|
|
||||||
const
|
const
|
||||||
InvalidFileIDX* = int32(-1)
|
InvalidFileIDX* = FileIndex(-1)
|
||||||
|
|
||||||
var
|
var
|
||||||
ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
|
ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
|
||||||
hintQuitCalled, hintExecuting}
|
hintQuitCalled, hintExecuting}
|
||||||
filenameToIndexTbl = initTable[string, int32]()
|
filenameToIndexTbl = initTable[string, FileIndex]()
|
||||||
fileInfos*: seq[TFileInfo] = @[]
|
fileInfos*: seq[TFileInfo] = @[]
|
||||||
systemFileIdx*: int32
|
systemFileIdx*: FileIndex
|
||||||
|
|
||||||
proc toCChar*(c: char): string =
|
proc toCChar*(c: char): string =
|
||||||
case c
|
case c
|
||||||
|
|
@ -583,6 +588,18 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
|
||||||
result.quotedFullName = fullPath.makeCString
|
result.quotedFullName = fullPath.makeCString
|
||||||
if optEmbedOrigSrc in gGlobalOptions or true:
|
if optEmbedOrigSrc in gGlobalOptions or true:
|
||||||
result.lines = @[]
|
result.lines = @[]
|
||||||
|
when defined(nimpretty):
|
||||||
|
if result.fullPath.len > 0:
|
||||||
|
try:
|
||||||
|
result.fullContent = readFile(result.fullPath)
|
||||||
|
except IOError:
|
||||||
|
#rawMessage(errCannotOpenFile, result.fullPath)
|
||||||
|
# XXX fixme
|
||||||
|
result.fullContent = ""
|
||||||
|
|
||||||
|
when defined(nimpretty):
|
||||||
|
proc fileSection*(fid: FileIndex; a, b: int): string =
|
||||||
|
substr(fileInfos[fid.int].fullContent, a, b)
|
||||||
|
|
||||||
proc fileInfoKnown*(filename: string): bool =
|
proc fileInfoKnown*(filename: string): bool =
|
||||||
var
|
var
|
||||||
|
|
@ -593,7 +610,7 @@ proc fileInfoKnown*(filename: string): bool =
|
||||||
canon = filename
|
canon = filename
|
||||||
result = filenameToIndexTbl.hasKey(canon)
|
result = filenameToIndexTbl.hasKey(canon)
|
||||||
|
|
||||||
proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 =
|
proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
|
||||||
var
|
var
|
||||||
canon: string
|
canon: string
|
||||||
pseudoPath = false
|
pseudoPath = false
|
||||||
|
|
@ -611,28 +628,28 @@ proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 =
|
||||||
result = filenameToIndexTbl[canon]
|
result = filenameToIndexTbl[canon]
|
||||||
else:
|
else:
|
||||||
isKnownFile = false
|
isKnownFile = false
|
||||||
result = fileInfos.len.int32
|
result = fileInfos.len.FileIndex
|
||||||
fileInfos.add(newFileInfo(canon, if pseudoPath: filename
|
fileInfos.add(newFileInfo(canon, if pseudoPath: filename
|
||||||
else: canon.shortenDir))
|
else: canon.shortenDir))
|
||||||
filenameToIndexTbl[canon] = result
|
filenameToIndexTbl[canon] = result
|
||||||
|
|
||||||
proc fileInfoIdx*(filename: string): int32 =
|
proc fileInfoIdx*(filename: string): FileIndex =
|
||||||
var dummy: bool
|
var dummy: bool
|
||||||
result = fileInfoIdx(filename, dummy)
|
result = fileInfoIdx(filename, dummy)
|
||||||
|
|
||||||
proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo =
|
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
||||||
result.fileIndex = fileInfoIdx
|
result.fileIndex = fileInfoIdx
|
||||||
result.line = int16(line)
|
result.line = uint16(line)
|
||||||
result.col = int16(col)
|
result.col = int16(col)
|
||||||
|
|
||||||
proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} =
|
proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} =
|
||||||
result = newLineInfo(filename.fileInfoIdx, line, col)
|
result = newLineInfo(filename.fileInfoIdx, line, col)
|
||||||
|
|
||||||
fileInfos.add(newFileInfo("", "command line"))
|
fileInfos.add(newFileInfo("", "command line"))
|
||||||
var gCmdLineInfo* = newLineInfo(int32(0), 1, 1)
|
var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
|
||||||
|
|
||||||
fileInfos.add(newFileInfo("", "compilation artifact"))
|
fileInfos.add(newFileInfo("", "compilation artifact"))
|
||||||
var gCodegenLineInfo* = newLineInfo(int32(1), 1, 1)
|
var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1)
|
||||||
|
|
||||||
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
||||||
raise newException(ERecoverableError, msg)
|
raise newException(ERecoverableError, msg)
|
||||||
|
|
@ -648,9 +665,9 @@ var
|
||||||
gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
|
gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
|
||||||
|
|
||||||
proc unknownLineInfo*(): TLineInfo =
|
proc unknownLineInfo*(): TLineInfo =
|
||||||
result.line = int16(-1)
|
result.line = uint16(0)
|
||||||
result.col = int16(-1)
|
result.col = int16(-1)
|
||||||
result.fileIndex = -1
|
result.fileIndex = InvalidFileIDX
|
||||||
|
|
||||||
type
|
type
|
||||||
Severity* {.pure.} = enum ## VS Code only supports these three
|
Severity* {.pure.} = enum ## VS Code only supports these three
|
||||||
|
|
@ -712,32 +729,32 @@ proc getInfoContext*(index: int): TLineInfo =
|
||||||
if i >=% L: result = unknownLineInfo()
|
if i >=% L: result = unknownLineInfo()
|
||||||
else: result = msgContext[i]
|
else: result = msgContext[i]
|
||||||
|
|
||||||
template toFilename*(fileIdx: int32): string =
|
template toFilename*(fileIdx: FileIndex): string =
|
||||||
(if fileIdx < 0: "???" else: fileInfos[fileIdx].projPath)
|
(if fileIdx.int32 < 0: "???" else: fileInfos[fileIdx.int32].projPath)
|
||||||
|
|
||||||
proc toFullPath*(fileIdx: int32): string =
|
proc toFullPath*(fileIdx: FileIndex): string =
|
||||||
if fileIdx < 0: result = "???"
|
if fileIdx.int32 < 0: result = "???"
|
||||||
else: result = fileInfos[fileIdx].fullPath
|
else: result = fileInfos[fileIdx.int32].fullPath
|
||||||
|
|
||||||
proc setDirtyFile*(fileIdx: int32; filename: string) =
|
proc setDirtyFile*(fileIdx: FileIndex; filename: string) =
|
||||||
assert fileIdx >= 0
|
assert fileIdx.int32 >= 0
|
||||||
fileInfos[fileIdx].dirtyFile = filename
|
fileInfos[fileIdx.int32].dirtyFile = filename
|
||||||
|
|
||||||
proc setHash*(fileIdx: int32; hash: string) =
|
proc setHash*(fileIdx: FileIndex; hash: string) =
|
||||||
assert fileIdx >= 0
|
assert fileIdx.int32 >= 0
|
||||||
shallowCopy(fileInfos[fileIdx].hash, hash)
|
shallowCopy(fileInfos[fileIdx.int32].hash, hash)
|
||||||
|
|
||||||
proc getHash*(fileIdx: int32): string =
|
proc getHash*(fileIdx: FileIndex): string =
|
||||||
assert fileIdx >= 0
|
assert fileIdx.int32 >= 0
|
||||||
shallowCopy(result, fileInfos[fileIdx].hash)
|
shallowCopy(result, fileInfos[fileIdx.int32].hash)
|
||||||
|
|
||||||
proc toFullPathConsiderDirty*(fileIdx: int32): string =
|
proc toFullPathConsiderDirty*(fileIdx: FileIndex): string =
|
||||||
if fileIdx < 0:
|
if fileIdx.int32 < 0:
|
||||||
result = "???"
|
result = "???"
|
||||||
elif not fileInfos[fileIdx].dirtyFile.isNil:
|
elif not fileInfos[fileIdx.int32].dirtyFile.isNil:
|
||||||
result = fileInfos[fileIdx].dirtyFile
|
result = fileInfos[fileIdx.int32].dirtyFile
|
||||||
else:
|
else:
|
||||||
result = fileInfos[fileIdx].fullPath
|
result = fileInfos[fileIdx.int32].fullPath
|
||||||
|
|
||||||
template toFilename*(info: TLineInfo): string =
|
template toFilename*(info: TLineInfo): string =
|
||||||
info.fileIndex.toFilename
|
info.fileIndex.toFilename
|
||||||
|
|
@ -746,15 +763,15 @@ template toFullPath*(info: TLineInfo): string =
|
||||||
info.fileIndex.toFullPath
|
info.fileIndex.toFullPath
|
||||||
|
|
||||||
proc toMsgFilename*(info: TLineInfo): string =
|
proc toMsgFilename*(info: TLineInfo): string =
|
||||||
if info.fileIndex < 0:
|
if info.fileIndex.int32 < 0:
|
||||||
result = "???"
|
result = "???"
|
||||||
elif gListFullPaths:
|
elif gListFullPaths:
|
||||||
result = fileInfos[info.fileIndex].fullPath
|
result = fileInfos[info.fileIndex.int32].fullPath
|
||||||
else:
|
else:
|
||||||
result = fileInfos[info.fileIndex].projPath
|
result = fileInfos[info.fileIndex.int32].projPath
|
||||||
|
|
||||||
proc toLinenumber*(info: TLineInfo): int {.inline.} =
|
proc toLinenumber*(info: TLineInfo): int {.inline.} =
|
||||||
result = info.line
|
result = int info.line
|
||||||
|
|
||||||
proc toColumn*(info: TLineInfo): int {.inline.} =
|
proc toColumn*(info: TLineInfo): int {.inline.} =
|
||||||
result = info.col
|
result = info.col
|
||||||
|
|
@ -771,7 +788,7 @@ proc `??`* (info: TLineInfo, filename: string): bool =
|
||||||
# only for debugging purposes
|
# only for debugging purposes
|
||||||
result = filename in info.toFilename
|
result = filename in info.toFilename
|
||||||
|
|
||||||
const trackPosInvalidFileIdx* = -2 # special marker so that no suggestions
|
const trackPosInvalidFileIdx* = FileIndex(-2) # special marker so that no suggestions
|
||||||
# are produced within comments and string literals
|
# are produced within comments and string literals
|
||||||
var gTrackPos*: TLineInfo
|
var gTrackPos*: TLineInfo
|
||||||
var gTrackPosAttached*: bool ## whether the tracking position was attached to some
|
var gTrackPosAttached*: bool ## whether the tracking position was attached to some
|
||||||
|
|
@ -910,7 +927,7 @@ proc writeContext(lastinfo: TLineInfo) =
|
||||||
else:
|
else:
|
||||||
styledMsgWriteln(styleBright,
|
styledMsgWriteln(styleBright,
|
||||||
PosFormat % [toMsgFilename(msgContext[i]),
|
PosFormat % [toMsgFilename(msgContext[i]),
|
||||||
coordToStr(msgContext[i].line),
|
coordToStr(msgContext[i].line.int),
|
||||||
coordToStr(msgContext[i].col+1)],
|
coordToStr(msgContext[i].col+1)],
|
||||||
resetStyle,
|
resetStyle,
|
||||||
getMessageStr(errInstantiationFrom, ""))
|
getMessageStr(errInstantiationFrom, ""))
|
||||||
|
|
@ -978,7 +995,7 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||||
of warnMin..warnMax: WarningTitle
|
of warnMin..warnMax: WarningTitle
|
||||||
of hintMin..hintMax: HintTitle
|
of hintMin..hintMax: HintTitle
|
||||||
else: ErrorTitle
|
else: ErrorTitle
|
||||||
result = PosFormat % [toMsgFilename(info), coordToStr(info.line),
|
result = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
|
||||||
coordToStr(info.col+1)] &
|
coordToStr(info.col+1)] &
|
||||||
title &
|
title &
|
||||||
getMessageStr(msg, arg)
|
getMessageStr(msg, arg)
|
||||||
|
|
@ -1019,7 +1036,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||||
# NOTE: currently line info line numbers start with 1,
|
# NOTE: currently line info line numbers start with 1,
|
||||||
# but column numbers start with 0, however most editors expect
|
# but column numbers start with 0, however most editors expect
|
||||||
# first column to be 1, so we need to +1 here
|
# first column to be 1, so we need to +1 here
|
||||||
let x = PosFormat % [toMsgFilename(info), coordToStr(info.line),
|
let x = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
|
||||||
coordToStr(info.col+1)]
|
coordToStr(info.col+1)]
|
||||||
let s = getMessageStr(msg, arg)
|
let s = getMessageStr(msg, arg)
|
||||||
|
|
||||||
|
|
@ -1032,7 +1049,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||||
KindColor, `%`(KindFormat, kind))
|
KindColor, `%`(KindFormat, kind))
|
||||||
else:
|
else:
|
||||||
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
|
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
|
||||||
if msg in errMin..errMax and hintSource in gNotes:
|
if hintSource in gNotes:
|
||||||
info.writeSurroundingSrc
|
info.writeSurroundingSrc
|
||||||
handleError(msg, eh, s)
|
handleError(msg, eh, s)
|
||||||
|
|
||||||
|
|
@ -1077,30 +1094,30 @@ template assertNotNil*(e): untyped =
|
||||||
template internalAssert*(e: bool) =
|
template internalAssert*(e: bool) =
|
||||||
if not e: internalError($instantiationInfo())
|
if not e: internalError($instantiationInfo())
|
||||||
|
|
||||||
proc addSourceLine*(fileIdx: int32, line: string) =
|
proc addSourceLine*(fileIdx: FileIndex, line: string) =
|
||||||
fileInfos[fileIdx].lines.add line.rope
|
fileInfos[fileIdx.int32].lines.add line.rope
|
||||||
|
|
||||||
proc sourceLine*(i: TLineInfo): Rope =
|
proc sourceLine*(i: TLineInfo): Rope =
|
||||||
if i.fileIndex < 0: return nil
|
if i.fileIndex.int32 < 0: return nil
|
||||||
|
|
||||||
if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
|
if not optPreserveOrigSource and fileInfos[i.fileIndex.int32].lines.len == 0:
|
||||||
try:
|
try:
|
||||||
for line in lines(i.toFullPath):
|
for line in lines(i.toFullPath):
|
||||||
addSourceLine i.fileIndex, line.string
|
addSourceLine i.fileIndex, line.string
|
||||||
except IOError:
|
except IOError:
|
||||||
discard
|
discard
|
||||||
internalAssert i.fileIndex < fileInfos.len
|
internalAssert i.fileIndex.int32 < fileInfos.len
|
||||||
# can happen if the error points to EOF:
|
# can happen if the error points to EOF:
|
||||||
if i.line > fileInfos[i.fileIndex].lines.len: return nil
|
if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil
|
||||||
|
|
||||||
result = fileInfos[i.fileIndex].lines[i.line-1]
|
result = fileInfos[i.fileIndex.int32].lines[i.line.int-1]
|
||||||
|
|
||||||
proc quotedFilename*(i: TLineInfo): Rope =
|
proc quotedFilename*(i: TLineInfo): Rope =
|
||||||
internalAssert i.fileIndex >= 0
|
internalAssert i.fileIndex.int32 >= 0
|
||||||
if optExcessiveStackTrace in gGlobalOptions:
|
if optExcessiveStackTrace in gGlobalOptions:
|
||||||
result = fileInfos[i.fileIndex].quotedFullName
|
result = fileInfos[i.fileIndex.int32].quotedFullName
|
||||||
else:
|
else:
|
||||||
result = fileInfos[i.fileIndex].quotedName
|
result = fileInfos[i.fileIndex.int32].quotedName
|
||||||
|
|
||||||
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
|
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
|
||||||
case err
|
case err
|
||||||
|
|
|
||||||
|
|
@ -90,14 +90,6 @@ proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
|
||||||
ex = quoteShell(
|
ex = quoteShell(
|
||||||
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
|
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
|
||||||
execExternalProgram(findNodeJs() & " " & ex & ' ' & commands.arguments)
|
execExternalProgram(findNodeJs() & " " & ex & ' ' & commands.arguments)
|
||||||
elif gCmd == cmdCompileToPHP:
|
|
||||||
var ex: string
|
|
||||||
if options.outFile.len > 0:
|
|
||||||
ex = options.outFile.prependCurDir.quoteShell
|
|
||||||
else:
|
|
||||||
ex = quoteShell(
|
|
||||||
completeCFilePath(changeFileExt(gProjectFull, "php").prependCurDir))
|
|
||||||
execExternalProgram("php " & ex & ' ' & commands.arguments)
|
|
||||||
else:
|
else:
|
||||||
var binPath: string
|
var binPath: string
|
||||||
if options.outFile.len > 0:
|
if options.outFile.len > 0:
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ proc overwriteFiles*() =
|
||||||
let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
|
let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
|
||||||
for i in 0 .. high(gSourceFiles):
|
for i in 0 .. high(gSourceFiles):
|
||||||
if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
|
if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
|
||||||
(not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx):
|
(not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx.FileIndex):
|
||||||
let newFile = if gOverWrite: gSourceFiles[i].fullpath
|
let newFile = if gOverWrite: gSourceFiles[i].fullpath
|
||||||
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
|
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
|
||||||
try:
|
try:
|
||||||
|
|
@ -95,7 +95,7 @@ proc beautifyName(s: string, k: TSymKind): string =
|
||||||
proc replaceInFile(info: TLineInfo; newName: string) =
|
proc replaceInFile(info: TLineInfo; newName: string) =
|
||||||
loadFile(info)
|
loadFile(info)
|
||||||
|
|
||||||
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
|
let line = gSourceFiles[info.fileIndex.int].lines[info.line.int-1]
|
||||||
var first = min(info.col.int, line.len)
|
var first = min(info.col.int, line.len)
|
||||||
if first < 0: return
|
if first < 0: return
|
||||||
#inc first, skipIgnoreCase(line, "proc ", first)
|
#inc first, skipIgnoreCase(line, "proc ", first)
|
||||||
|
|
@ -107,8 +107,8 @@ proc replaceInFile(info: TLineInfo; newName: string) =
|
||||||
if differ(line, first, last, newName):
|
if differ(line, first, last, newName):
|
||||||
# last-first+1 != newName.len or
|
# last-first+1 != newName.len or
|
||||||
var x = line.substr(0, first-1) & newName & line.substr(last+1)
|
var x = line.substr(0, first-1) & newName & line.substr(last+1)
|
||||||
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
|
system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x)
|
||||||
gSourceFiles[info.fileIndex].dirty = true
|
gSourceFiles[info.fileIndex.int].dirty = true
|
||||||
|
|
||||||
proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
|
proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
|
||||||
let beau = beautifyName(s, k)
|
let beau = beautifyName(s, k)
|
||||||
|
|
@ -136,7 +136,7 @@ template styleCheckDef*(s: PSym) =
|
||||||
styleCheckDef(s.info, s, s.kind)
|
styleCheckDef(s.info, s, s.kind)
|
||||||
|
|
||||||
proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
|
proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
|
||||||
if info.fileIndex < 0: return
|
if info.fileIndex.int < 0: return
|
||||||
# we simply convert it to what it looks like in the definition
|
# we simply convert it to what it looks like in the definition
|
||||||
# for consistency
|
# for consistency
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@ type
|
||||||
lines*: seq[string]
|
lines*: seq[string]
|
||||||
dirty*, isNimfixFile*: bool
|
dirty*, isNimfixFile*: bool
|
||||||
fullpath*, newline*: string
|
fullpath*, newline*: string
|
||||||
fileIdx*: int32
|
fileIdx*: FileIndex
|
||||||
|
|
||||||
var
|
var
|
||||||
gSourceFiles*: seq[TSourceFile] = @[]
|
gSourceFiles*: seq[TSourceFile] = @[]
|
||||||
|
|
||||||
proc loadFile*(info: TLineInfo) =
|
proc loadFile*(info: TLineInfo) =
|
||||||
let i = info.fileIndex
|
let i = info.fileIndex.int
|
||||||
if i >= gSourceFiles.len:
|
if i >= gSourceFiles.len:
|
||||||
gSourceFiles.setLen(i+1)
|
gSourceFiles.setLen(i+1)
|
||||||
if gSourceFiles[i].lines.isNil:
|
if gSourceFiles[i].lines.isNil:
|
||||||
|
|
@ -64,7 +64,7 @@ proc differ*(line: string, a, b: int, x: string): bool =
|
||||||
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
|
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
|
||||||
loadFile(info)
|
loadFile(info)
|
||||||
|
|
||||||
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
|
let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1]
|
||||||
var first = min(info.col.int, line.len)
|
var first = min(info.col.int, line.len)
|
||||||
if first < 0: return
|
if first < 0: return
|
||||||
#inc first, skipIgnoreCase(line, "proc ", first)
|
#inc first, skipIgnoreCase(line, "proc ", first)
|
||||||
|
|
@ -75,8 +75,8 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
|
||||||
let last = first+identLen(line, first)-1
|
let last = first+identLen(line, first)-1
|
||||||
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
|
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
|
||||||
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
|
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
|
||||||
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
|
system.shallowCopy(gSourceFiles[info.fileIndex.int32].lines[info.line.int-1], x)
|
||||||
gSourceFiles[info.fileIndex].dirty = true
|
gSourceFiles[info.fileIndex.int32].dirty = true
|
||||||
#if newSym.s == "File": writeStackTrace()
|
#if newSym.s == "File": writeStackTrace()
|
||||||
|
|
||||||
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
|
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
|
||||||
|
|
@ -85,10 +85,10 @@ proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
|
||||||
proc replaceComment*(info: TLineInfo) =
|
proc replaceComment*(info: TLineInfo) =
|
||||||
loadFile(info)
|
loadFile(info)
|
||||||
|
|
||||||
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
|
let line = gSourceFiles[info.fileIndex.int32].lines[info.line.int-1]
|
||||||
var first = info.col.int
|
var first = info.col.int
|
||||||
if line[first] != '#': inc first
|
if line[first] != '#': inc first
|
||||||
|
|
||||||
var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
|
var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
|
||||||
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
|
system.shallowCopy(gSourceFiles[info.fileIndex.int32].lines[info.line.int-1], x)
|
||||||
gSourceFiles[info.fileIndex].dirty = true
|
gSourceFiles[info.fileIndex.int32].dirty = true
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,6 @@ type
|
||||||
# **keep binary compatible**
|
# **keep binary compatible**
|
||||||
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
|
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
|
||||||
cmdCompileToJS,
|
cmdCompileToJS,
|
||||||
cmdCompileToPHP,
|
|
||||||
cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
|
cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
|
||||||
cmdGenDepend, cmdDump,
|
cmdGenDepend, cmdDump,
|
||||||
cmdCheck, # semantic checking for whole project
|
cmdCheck, # semantic checking for whole project
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,8 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||||
result = arLValue
|
result = arLValue
|
||||||
else:
|
else:
|
||||||
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
|
result = isAssignable(owner, n.sons[0], isUnsafeAddr)
|
||||||
if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
|
if result != arNone and n[1].kind == nkSym and
|
||||||
|
sfDiscriminant in n[1].sym.flags:
|
||||||
result = arDiscriminant
|
result = arDiscriminant
|
||||||
of nkBracketExpr:
|
of nkBracketExpr:
|
||||||
if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in
|
if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ proc getTok(p: var TParser) =
|
||||||
rawGetTok(p.lex, p.tok)
|
rawGetTok(p.lex, p.tok)
|
||||||
p.hasProgress = true
|
p.hasProgress = true
|
||||||
|
|
||||||
proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
|
proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
|
||||||
cache: IdentCache;
|
cache: IdentCache;
|
||||||
strongSpaces=false) =
|
strongSpaces=false) =
|
||||||
## Open a parser, using the given arguments to set up its internal state.
|
## Open a parser, using the given arguments to set up its internal state.
|
||||||
|
|
@ -125,6 +125,12 @@ proc rawSkipComment(p: var TParser, node: PNode) =
|
||||||
if p.tok.tokType == tkComment:
|
if p.tok.tokType == tkComment:
|
||||||
if node != nil:
|
if node != nil:
|
||||||
if node.comment == nil: node.comment = ""
|
if node.comment == nil: node.comment = ""
|
||||||
|
when defined(nimpretty):
|
||||||
|
if p.tok.commentOffsetB > p.tok.commentOffsetA:
|
||||||
|
add node.comment, fileSection(p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB)
|
||||||
|
else:
|
||||||
|
add node.comment, p.tok.literal
|
||||||
|
else:
|
||||||
add(node.comment, p.tok.literal)
|
add(node.comment, p.tok.literal)
|
||||||
else:
|
else:
|
||||||
parMessage(p, errInternal, "skipComment")
|
parMessage(p, errInternal, "skipComment")
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@ proc makePass*(open: TPassOpen = nil,
|
||||||
|
|
||||||
# the semantic checker needs these:
|
# the semantic checker needs these:
|
||||||
var
|
var
|
||||||
gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.}
|
gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PSym {.nimcall.}
|
||||||
gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.}
|
gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.nimcall.}
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
|
|
@ -63,20 +63,6 @@ proc skipCodegen*(n: PNode): bool {.inline.} =
|
||||||
# error count instead.
|
# error count instead.
|
||||||
result = msgs.gErrorCounter > 0
|
result = msgs.gErrorCounter > 0
|
||||||
|
|
||||||
proc astNeeded*(s: PSym): bool =
|
|
||||||
# The ``rodwrite`` module uses this to determine if the body of a proc
|
|
||||||
# needs to be stored. The passes manager frees s.sons[codePos] when
|
|
||||||
# appropriate to free the procedure body's memory. This is important
|
|
||||||
# to keep memory usage down.
|
|
||||||
if (s.kind in {skMethod, skProc, skFunc}) and
|
|
||||||
({sfCompilerProc, sfCompileTime} * s.flags == {}) and
|
|
||||||
(s.typ.callConv != ccInline) and
|
|
||||||
(s.ast.sons[genericParamsPos].kind == nkEmpty):
|
|
||||||
result = false
|
|
||||||
# XXX this doesn't really make sense with excessive CTFE
|
|
||||||
else:
|
|
||||||
result = true
|
|
||||||
|
|
||||||
const
|
const
|
||||||
maxPasses = 10
|
maxPasses = 10
|
||||||
|
|
||||||
|
|
@ -153,7 +139,7 @@ proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) =
|
||||||
m = gPasses[i].close(graph, a[i], m)
|
m = gPasses[i].close(graph, a[i], m)
|
||||||
a[i] = nil # free the memory here
|
a[i] = nil # free the memory here
|
||||||
|
|
||||||
proc resolveMod(module, relativeTo: string): int32 =
|
proc resolveMod(module, relativeTo: string): FileIndex =
|
||||||
let fullPath = findModule(module, relativeTo)
|
let fullPath = findModule(module, relativeTo)
|
||||||
if fullPath.len == 0:
|
if fullPath.len == 0:
|
||||||
result = InvalidFileIDX
|
result = InvalidFileIDX
|
||||||
|
|
@ -166,7 +152,7 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
|
||||||
let relativeTo = m.info.toFullPath
|
let relativeTo = m.info.toFullPath
|
||||||
for module in items(implicits):
|
for module in items(implicits):
|
||||||
# implicit imports should not lead to a module importing itself
|
# implicit imports should not lead to a module importing itself
|
||||||
if m.position != resolveMod(module, relativeTo):
|
if m.position != resolveMod(module, relativeTo).int32:
|
||||||
var importStmt = newNodeI(nodeKind, gCmdLineInfo)
|
var importStmt = newNodeI(nodeKind, gCmdLineInfo)
|
||||||
var str = newStrNode(nkStrLit, module)
|
var str = newStrNode(nkStrLit, module)
|
||||||
str.info = gCmdLineInfo
|
str.info = gCmdLineInfo
|
||||||
|
|
@ -180,7 +166,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
|
||||||
p: TParsers
|
p: TParsers
|
||||||
a: TPassContextArray
|
a: TPassContextArray
|
||||||
s: PLLStream
|
s: PLLStream
|
||||||
fileIdx = module.fileIdx
|
fileIdx = FileIndex module.fileIdx
|
||||||
if module.id < 0:
|
if module.id < 0:
|
||||||
# new module caching mechanism:
|
# new module caching mechanism:
|
||||||
for i in 0..<gPassesLen:
|
for i in 0..<gPassesLen:
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ proc getTok(p: var TParser) =
|
||||||
## `tok` member.
|
## `tok` member.
|
||||||
rawGetTok(p.lex, p.tok)
|
rawGetTok(p.lex, p.tok)
|
||||||
|
|
||||||
proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream;
|
proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream;
|
||||||
cache: IdentCache) =
|
cache: IdentCache) =
|
||||||
## Open a parser, using the given arguments to set up its internal state.
|
## Open a parser, using the given arguments to set up its internal state.
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -543,7 +543,7 @@ proc pragmaLine(c: PContext, n: PNode) =
|
||||||
else:
|
else:
|
||||||
# XXX this produces weird paths which are not properly resolved:
|
# XXX this produces weird paths which are not properly resolved:
|
||||||
n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
|
n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
|
||||||
n.info.line = int16(y.intVal)
|
n.info.line = uint16(y.intVal)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errXExpected, "tuple")
|
localError(n.info, errXExpected, "tuple")
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -66,12 +66,10 @@ proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||||
proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||||
const flags = {ExactGenericParams, ExactTypeDescValues,
|
const flags = {ExactGenericParams, ExactTypeDescValues,
|
||||||
ExactConstraints, IgnoreCC}
|
ExactConstraints, IgnoreCC}
|
||||||
|
|
||||||
var it: TIdentIter
|
var it: TIdentIter
|
||||||
|
|
||||||
result = initIdentIter(it, scope.symbols, fn.name)
|
result = initIdentIter(it, scope.symbols, fn.name)
|
||||||
while result != nil:
|
while result != nil:
|
||||||
if result.kind == fn.kind and sameType(result.typ, fn.typ, flags):
|
if result.kind == fn.kind: #and sameType(result.typ, fn.typ, flags):
|
||||||
case equalParams(result.typ.n, fn.typ.n)
|
case equalParams(result.typ.n, fn.typ.n)
|
||||||
of paramsEqual:
|
of paramsEqual:
|
||||||
if (sfExported notin result.flags) and (sfExported in fn.flags):
|
if (sfExported notin result.flags) and (sfExported in fn.flags):
|
||||||
|
|
@ -85,11 +83,8 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||||
return
|
return
|
||||||
of paramsNotEqual:
|
of paramsNotEqual:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
result = nextIdentIter(it, scope.symbols)
|
result = nextIdentIter(it, scope.symbols)
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
|
proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||||
result = searchForProcNew(c, scope, fn)
|
result = searchForProcNew(c, scope, fn)
|
||||||
when false:
|
when false:
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,7 @@ type
|
||||||
inPragma: int
|
inPragma: int
|
||||||
when defined(nimpretty):
|
when defined(nimpretty):
|
||||||
pendingNewlineCount: int
|
pendingNewlineCount: int
|
||||||
origContent: string
|
fid*: FileIndex
|
||||||
|
|
||||||
|
|
||||||
# We render the source code in a two phases: The first
|
# We render the source code in a two phases: The first
|
||||||
# determines how long the subtree will likely be, the second
|
# determines how long the subtree will likely be, the second
|
||||||
|
|
@ -354,13 +353,13 @@ proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
|
||||||
proc atom(g: TSrcGen; n: PNode): string =
|
proc atom(g: TSrcGen; n: PNode): string =
|
||||||
when defined(nimpretty):
|
when defined(nimpretty):
|
||||||
let comment = if n.info.commentOffsetA < n.info.commentOffsetB:
|
let comment = if n.info.commentOffsetA < n.info.commentOffsetB:
|
||||||
" " & substr(g.origContent, n.info.commentOffsetA, n.info.commentOffsetB)
|
" " & fileSection(g.fid, n.info.commentOffsetA, n.info.commentOffsetB)
|
||||||
else:
|
else:
|
||||||
""
|
""
|
||||||
if n.info.offsetA <= n.info.offsetB:
|
if n.info.offsetA <= n.info.offsetB:
|
||||||
# for some constructed tokens this can not be the case and we're better
|
# for some constructed tokens this can not be the case and we're better
|
||||||
# off to not mess with the offset then.
|
# off to not mess with the offset then.
|
||||||
return substr(g.origContent, n.info.offsetA, n.info.offsetB) & comment
|
return fileSection(g.fid, n.info.offsetA, n.info.offsetB) & comment
|
||||||
var f: float32
|
var f: float32
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkEmpty: result = ""
|
of nkEmpty: result = ""
|
||||||
|
|
@ -1460,17 +1459,13 @@ proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string =
|
||||||
proc `$`*(n: PNode): string = n.renderTree
|
proc `$`*(n: PNode): string = n.renderTree
|
||||||
|
|
||||||
proc renderModule*(n: PNode, infile, outfile: string,
|
proc renderModule*(n: PNode, infile, outfile: string,
|
||||||
renderFlags: TRenderFlags = {}) =
|
renderFlags: TRenderFlags = {};
|
||||||
|
fid = FileIndex(-1)) =
|
||||||
var
|
var
|
||||||
f: File
|
f: File
|
||||||
g: TSrcGen
|
g: TSrcGen
|
||||||
initSrcGen(g, renderFlags)
|
initSrcGen(g, renderFlags)
|
||||||
when defined(nimpretty):
|
g.fid = fid
|
||||||
try:
|
|
||||||
g.origContent = readFile(infile)
|
|
||||||
except IOError:
|
|
||||||
rawMessage(errCannotOpenFile, infile)
|
|
||||||
|
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
gsub(g, n.sons[i])
|
gsub(g, n.sons[i])
|
||||||
optNL(g)
|
optNL(g)
|
||||||
|
|
|
||||||
|
|
@ -135,11 +135,11 @@ proc hasIncludes(n:PNode): bool =
|
||||||
if a.kind == nkIncludeStmt:
|
if a.kind == nkIncludeStmt:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
|
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
|
||||||
cache: IdentCache): PNode {.procvar.} =
|
cache: IdentCache): PNode {.procvar.} =
|
||||||
result = syntaxes.parseFile(fileIdx, cache)
|
result = syntaxes.parseFile(fileIdx, cache)
|
||||||
graph.addDep(s, fileIdx)
|
graph.addDep(s, fileIdx)
|
||||||
graph.addIncludeDep(s.position.int32, fileIdx)
|
graph.addIncludeDep(FileIndex s.position, fileIdx)
|
||||||
|
|
||||||
proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
|
proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
|
||||||
modulePath: string, includedFiles: var IntSet,
|
modulePath: string, includedFiles: var IntSet,
|
||||||
|
|
@ -153,13 +153,13 @@ proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
|
||||||
for i in 0..<a.len:
|
for i in 0..<a.len:
|
||||||
var f = checkModuleName(a.sons[i])
|
var f = checkModuleName(a.sons[i])
|
||||||
if f != InvalidFileIDX:
|
if f != InvalidFileIDX:
|
||||||
if containsOrIncl(includedFiles, f):
|
if containsOrIncl(includedFiles, f.int):
|
||||||
localError(a.info, errRecursiveDependencyX, f.toFilename)
|
localError(a.info, errRecursiveDependencyX, f.toFilename)
|
||||||
else:
|
else:
|
||||||
let nn = includeModule(graph, module, f, cache)
|
let nn = includeModule(graph, module, f, cache)
|
||||||
let nnn = expandIncludes(graph, module, nn, modulePath,
|
let nnn = expandIncludes(graph, module, nn, modulePath,
|
||||||
includedFiles, cache)
|
includedFiles, cache)
|
||||||
excl(includedFiles, f)
|
excl(includedFiles, f.int)
|
||||||
for b in nnn:
|
for b in nnn:
|
||||||
result.add b
|
result.add b
|
||||||
else:
|
else:
|
||||||
|
|
@ -429,7 +429,7 @@ proc reorder*(graph: ModuleGraph, n: PNode, module: PSym, cache: IdentCache): PN
|
||||||
if n.hasForbiddenPragma:
|
if n.hasForbiddenPragma:
|
||||||
return n
|
return n
|
||||||
var includedFiles = initIntSet()
|
var includedFiles = initIntSet()
|
||||||
let mpath = module.fileIdx.toFullPath
|
let mpath = module.fileIdx.FileIndex.toFullPath
|
||||||
let n = expandIncludes(graph, module, n, mpath,
|
let n = expandIncludes(graph, module, n, mpath,
|
||||||
includedFiles, cache).splitSections
|
includedFiles, cache).splitSections
|
||||||
result = newNodeI(nkStmtList, n.info)
|
result = newNodeI(nkStmtList, n.info)
|
||||||
|
|
|
||||||
112
compiler/rod.nim
112
compiler/rod.nim
|
|
@ -9,124 +9,18 @@
|
||||||
|
|
||||||
## This module implements the canonalization for the various caching mechanisms.
|
## This module implements the canonalization for the various caching mechanisms.
|
||||||
|
|
||||||
import ast, idgen
|
import ast, idgen, msgs
|
||||||
|
|
||||||
when not defined(nimSymbolfiles):
|
when not defined(nimSymbolfiles):
|
||||||
template setupModuleCache* = discard
|
template setupModuleCache* = discard
|
||||||
template storeNode*(module: PSym; n: PNode) = discard
|
template storeNode*(module: PSym; n: PNode) = discard
|
||||||
template loadNode*(module: PSym; index: var int): PNode = PNode(nil)
|
template loadNode*(module: PSym; index: var int): PNode = PNode(nil)
|
||||||
|
|
||||||
template getModuleId*(fileIdx: int32; fullpath: string): int = getID()
|
template getModuleId*(fileIdx: FileIndex; fullpath: string): int = getID()
|
||||||
|
|
||||||
template addModuleDep*(module, fileIdx: int32; isIncludeFile: bool) = discard
|
template addModuleDep*(module, fileIdx: FileIndex; isIncludeFile: bool) = discard
|
||||||
|
|
||||||
template storeRemaining*(module: PSym) = discard
|
template storeRemaining*(module: PSym) = discard
|
||||||
|
|
||||||
else:
|
else:
|
||||||
include rodimpl
|
include rodimpl
|
||||||
|
|
||||||
when false:
|
|
||||||
type
|
|
||||||
BlobWriter* = object
|
|
||||||
buf: string
|
|
||||||
pos: int
|
|
||||||
|
|
||||||
SerializationAction = enum acRead, acWrite
|
|
||||||
|
|
||||||
# Varint implementation inspired by SQLite.
|
|
||||||
proc rdVaruint64(z: ptr UncheckedArray[byte]; n: int; pResult: var uint64): int =
|
|
||||||
if z[0] <= 240:
|
|
||||||
pResult = z[0]
|
|
||||||
return 1
|
|
||||||
if z[0] <= 248:
|
|
||||||
if n < 2: return 0
|
|
||||||
pResult = (z[0] - 241) * 256 + z[1] + 240
|
|
||||||
return 2
|
|
||||||
if n < z[0]-246: return 0
|
|
||||||
if z[0] == 249:
|
|
||||||
pResult = 2288 + 256*z[1] + z[2]
|
|
||||||
return 3
|
|
||||||
if z[0] == 250:
|
|
||||||
pResult = (z[1] shl 16u64) + (z[2] shl 8u64) + z[3]
|
|
||||||
return 4
|
|
||||||
let x = (z[1] shl 24) + (z[2] shl 16) + (z[3] shl 8) + z[4]
|
|
||||||
if z[0] == 251:
|
|
||||||
pResult = x
|
|
||||||
return 5
|
|
||||||
if z[0] == 252:
|
|
||||||
pResult = (((uint64)x) shl 8) + z[5]
|
|
||||||
return 6
|
|
||||||
if z[0] == 253:
|
|
||||||
pResult = (((uint64)x) shl 16) + (z[5] shl 8) + z[6]
|
|
||||||
return 7
|
|
||||||
if z[0] == 254:
|
|
||||||
pResult = (((uint64)x) shl 24) + (z[5] shl 16) + (z[6] shl 8) + z[7]
|
|
||||||
return 8
|
|
||||||
pResult = (((uint64)x) shl 32) +
|
|
||||||
(0xffffffff & ((z[5] shl 24) + (z[6] shl 16) + (z[7] shl 8) + z[8]))
|
|
||||||
return 9
|
|
||||||
|
|
||||||
proc varintWrite32(z: ptr UncheckedArray[byte]; y: uint32) =
|
|
||||||
z[0] = uint8(y shr 24)
|
|
||||||
z[1] = uint8(y shr 16)
|
|
||||||
z[2] = uint8(y shr 8)
|
|
||||||
z[3] = uint8(y)
|
|
||||||
|
|
||||||
proc sqlite4PutVarint64(z: ptr UncheckedArray[byte], x: uint64): int =
|
|
||||||
## Write a varint into z. The buffer z must be at least 9 characters
|
|
||||||
## long to accommodate the largest possible varint. Returns the number of
|
|
||||||
## bytes used.
|
|
||||||
if x <= 240:
|
|
||||||
z[0] = uint8 x
|
|
||||||
return 1
|
|
||||||
if x <= 2287:
|
|
||||||
y = uint32(x - 240)
|
|
||||||
z[0] = uint8(y shr 8 + 241)
|
|
||||||
z[1] = uint8(y and 255)
|
|
||||||
return 2
|
|
||||||
if x <= 67823:
|
|
||||||
y = uint32(x - 2288)
|
|
||||||
z[0] = 249
|
|
||||||
z[1] = uint8(y shr 8)
|
|
||||||
z[2] = uint8(y and 255)
|
|
||||||
return 3
|
|
||||||
let y = uint32 x
|
|
||||||
let w = uint32(x shr 32)
|
|
||||||
if w == 0:
|
|
||||||
if y <= 16777215:
|
|
||||||
z[0] = 250
|
|
||||||
z[1] = uint8(y shr 16)
|
|
||||||
z[2] = uint8(y shr 8)
|
|
||||||
z[3] = uint8(y)
|
|
||||||
return 4
|
|
||||||
z[0] = 251
|
|
||||||
varintWrite32(z+1, y)
|
|
||||||
return 5
|
|
||||||
if w <= 255:
|
|
||||||
z[0] = 252
|
|
||||||
z[1] = uint8 w
|
|
||||||
varintWrite32(z+2, y)
|
|
||||||
return 6
|
|
||||||
if w <= 65535:
|
|
||||||
z[0] = 253
|
|
||||||
z[1] = uint8(w shr 8)
|
|
||||||
z[2] = uint8 w
|
|
||||||
varintWrite32(z+3, y)
|
|
||||||
return 7
|
|
||||||
if w <= 16777215:
|
|
||||||
z[0] = 254
|
|
||||||
z[1] = uint8(w shr 16)
|
|
||||||
z[2] = uint8(w shr 8)
|
|
||||||
z[3] = uint8 w
|
|
||||||
varintWrite32(z+4, y)
|
|
||||||
return 8
|
|
||||||
z[0] = 255
|
|
||||||
varintWrite32(z+1, w)
|
|
||||||
varintWrite32(z+5, y)
|
|
||||||
return 9
|
|
||||||
|
|
||||||
template field(x: BiggestInt; action: SerializationAction) =
|
|
||||||
when action == acRead:
|
|
||||||
readBiggestInt(x)
|
|
||||||
else:
|
|
||||||
writeBiggestInt()
|
|
||||||
|
|
|
||||||
|
|
@ -126,8 +126,8 @@ type
|
||||||
s: cstring # mmap'ed file contents
|
s: cstring # mmap'ed file contents
|
||||||
options: TOptions
|
options: TOptions
|
||||||
reason: TReasonForRecompile
|
reason: TReasonForRecompile
|
||||||
modDeps: seq[int32]
|
modDeps: seq[FileIndex]
|
||||||
files: seq[int32]
|
files: seq[FileIndex]
|
||||||
dataIdx: int # offset of start of data section
|
dataIdx: int # offset of start of data section
|
||||||
convertersIdx: int # offset of start of converters section
|
convertersIdx: int # offset of start of converters section
|
||||||
initIdx, interfIdx, compilerProcsIdx, methodsIdx: int
|
initIdx, interfIdx, compilerProcsIdx, methodsIdx: int
|
||||||
|
|
@ -163,11 +163,11 @@ proc decodeLineInfo(r: PRodReader, info: var TLineInfo) =
|
||||||
else: info.col = int16(decodeVInt(r.s, r.pos))
|
else: info.col = int16(decodeVInt(r.s, r.pos))
|
||||||
if r.s[r.pos] == ',':
|
if r.s[r.pos] == ',':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
if r.s[r.pos] == ',': info.line = -1'i16
|
if r.s[r.pos] == ',': info.line = 0'u16
|
||||||
else: info.line = int16(decodeVInt(r.s, r.pos))
|
else: info.line = uint16(decodeVInt(r.s, r.pos))
|
||||||
if r.s[r.pos] == ',':
|
if r.s[r.pos] == ',':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
info = newLineInfo(r.files[decodeVInt(r.s, r.pos)], info.line, info.col)
|
info = newLineInfo(r.files[decodeVInt(r.s, r.pos)], int info.line, info.col)
|
||||||
|
|
||||||
proc skipNode(r: PRodReader) =
|
proc skipNode(r: PRodReader) =
|
||||||
assert r.s[r.pos] == '('
|
assert r.s[r.pos] == '('
|
||||||
|
|
@ -586,7 +586,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
|
||||||
# new command forces us to consider it here :-)
|
# new command forces us to consider it here :-)
|
||||||
case old
|
case old
|
||||||
of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
|
of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
|
||||||
cmdCompileToJS, cmdCompileToPHP, cmdCompileToLLVM:
|
cmdCompileToJS, cmdCompileToLLVM:
|
||||||
if new in {cmdDoc, cmdCheck, cmdIdeTools, cmdPretty, cmdDef,
|
if new in {cmdDoc, cmdCheck, cmdIdeTools, cmdPretty, cmdDef,
|
||||||
cmdInteractive}:
|
cmdInteractive}:
|
||||||
return false
|
return false
|
||||||
|
|
@ -861,29 +861,29 @@ proc loadMethods(r: PRodReader) =
|
||||||
r.methods.add(rrGetSym(r, d, unknownLineInfo()))
|
r.methods.add(rrGetSym(r, d, unknownLineInfo()))
|
||||||
if r.s[r.pos] == ' ': inc(r.pos)
|
if r.s[r.pos] == ' ': inc(r.pos)
|
||||||
|
|
||||||
proc getHash*(fileIdx: int32): SecureHash =
|
proc getHash*(fileIdx: FileIndex): SecureHash =
|
||||||
if fileIdx <% gMods.len and gMods[fileIdx].hashDone:
|
if fileIdx.int32 <% gMods.len and gMods[fileIdx.int32].hashDone:
|
||||||
return gMods[fileIdx].hash
|
return gMods[fileIdx.int32].hash
|
||||||
|
|
||||||
result = secureHashFile(fileIdx.toFullPath)
|
result = secureHashFile(fileIdx.toFullPath)
|
||||||
if fileIdx >= gMods.len: setLen(gMods, fileIdx+1)
|
if fileIdx.int32 >= gMods.len: setLen(gMods, fileIdx.int32+1)
|
||||||
gMods[fileIdx].hash = result
|
gMods[fileIdx.int32].hash = result
|
||||||
|
|
||||||
template growCache*(cache, pos) =
|
template growCache*(cache, pos) =
|
||||||
if cache.len <= pos: cache.setLen(pos+1)
|
if cache.len <= pos: cache.setLen(pos+1)
|
||||||
|
|
||||||
proc checkDep(fileIdx: int32; cache: IdentCache): TReasonForRecompile =
|
proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
|
||||||
assert fileIdx != InvalidFileIDX
|
assert fileIdx != InvalidFileIDX
|
||||||
growCache gMods, fileIdx
|
growCache gMods, fileIdx.int32
|
||||||
if gMods[fileIdx].reason != rrEmpty:
|
if gMods[fileIdx.int32].reason != rrEmpty:
|
||||||
# reason has already been computed for this module:
|
# reason has already been computed for this module:
|
||||||
return gMods[fileIdx].reason
|
return gMods[fileIdx.int32].reason
|
||||||
let filename = fileIdx.toFilename
|
let filename = fileIdx.toFilename
|
||||||
var hash = getHash(fileIdx)
|
var hash = getHash(fileIdx)
|
||||||
gMods[fileIdx].reason = rrNone # we need to set it here to avoid cycles
|
gMods[fileIdx.int32].reason = rrNone # we need to set it here to avoid cycles
|
||||||
result = rrNone
|
result = rrNone
|
||||||
var rodfile = toGeneratedFile(filename.withPackageName, RodExt)
|
var rodfile = toGeneratedFile(filename.withPackageName, RodExt)
|
||||||
var r = newRodReader(rodfile, hash, fileIdx, cache)
|
var r = newRodReader(rodfile, hash, fileIdx.int32, cache)
|
||||||
if r == nil:
|
if r == nil:
|
||||||
result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
|
result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
|
||||||
else:
|
else:
|
||||||
|
|
@ -907,19 +907,18 @@ proc checkDep(fileIdx: int32; cache: IdentCache): TReasonForRecompile =
|
||||||
# recompilation is necessary:
|
# recompilation is necessary:
|
||||||
if r != nil: memfiles.close(r.memfile)
|
if r != nil: memfiles.close(r.memfile)
|
||||||
r = nil
|
r = nil
|
||||||
gMods[fileIdx].rd = r
|
gMods[fileIdx.int32].rd = r
|
||||||
gMods[fileIdx].reason = result # now we know better
|
gMods[fileIdx.int32].reason = result # now we know better
|
||||||
|
|
||||||
proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader =
|
proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader =
|
||||||
let fileIdx = module.fileIdx
|
|
||||||
if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}:
|
if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}:
|
||||||
module.id = getID()
|
module.id = getID()
|
||||||
return nil
|
return nil
|
||||||
idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
|
idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
|
||||||
|
let fileIdx = FileIndex module.fileIdx
|
||||||
discard checkDep(fileIdx, cache)
|
discard checkDep(fileIdx, cache)
|
||||||
if gMods[fileIdx].reason == rrEmpty: internalError("handleSymbolFile")
|
if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile")
|
||||||
result = gMods[fileIdx].rd
|
result = gMods[fileIdx.int32].rd
|
||||||
if result != nil:
|
if result != nil:
|
||||||
module.id = result.moduleID
|
module.id = result.moduleID
|
||||||
result.syms[module.id] = module
|
result.syms[module.id] = module
|
||||||
|
|
@ -1153,7 +1152,7 @@ proc viewFile(rodfile: string) =
|
||||||
if r.s[r.pos] == '\x0A':
|
if r.s[r.pos] == '\x0A':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
inc(r.line)
|
inc(r.line)
|
||||||
outf.write(w, " ", inclHash, "\n")
|
outf.write(w.int32, " ", inclHash, "\n")
|
||||||
if r.s[r.pos] == ')': inc(r.pos)
|
if r.s[r.pos] == ')': inc(r.pos)
|
||||||
outf.write(")\n")
|
outf.write(")\n")
|
||||||
of "DEPS":
|
of "DEPS":
|
||||||
|
|
@ -1163,7 +1162,7 @@ proc viewFile(rodfile: string) =
|
||||||
let v = int32(decodeVInt(r.s, r.pos))
|
let v = int32(decodeVInt(r.s, r.pos))
|
||||||
r.modDeps.add(r.files[v])
|
r.modDeps.add(r.files[v])
|
||||||
if r.s[r.pos] == ' ': inc(r.pos)
|
if r.s[r.pos] == ' ': inc(r.pos)
|
||||||
outf.write(" ", r.files[v])
|
outf.write(" ", r.files[v].int32)
|
||||||
outf.write("\n")
|
outf.write("\n")
|
||||||
of "INTERF", "COMPILERPROCS":
|
of "INTERF", "COMPILERPROCS":
|
||||||
inc r.pos, 2
|
inc r.pos, 2
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ proc fileIdx(w: PRodWriter, filename: string): int =
|
||||||
w.files[result] = filename
|
w.files[result] = filename
|
||||||
|
|
||||||
template filename*(w: PRodWriter): string =
|
template filename*(w: PRodWriter): string =
|
||||||
w.module.filename
|
toFilename(FileIndex w.module.position)
|
||||||
|
|
||||||
proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter =
|
proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter =
|
||||||
new(result)
|
new(result)
|
||||||
|
|
@ -125,14 +125,14 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
|
||||||
result.add('?')
|
result.add('?')
|
||||||
encodeVInt(n.info.col, result)
|
encodeVInt(n.info.col, result)
|
||||||
result.add(',')
|
result.add(',')
|
||||||
encodeVInt(n.info.line, result)
|
encodeVInt(int n.info.line, result)
|
||||||
result.add(',')
|
result.add(',')
|
||||||
encodeVInt(fileIdx(w, toFullPath(n.info)), result)
|
encodeVInt(fileIdx(w, toFullPath(n.info)), result)
|
||||||
elif fInfo.line != n.info.line:
|
elif fInfo.line != n.info.line:
|
||||||
result.add('?')
|
result.add('?')
|
||||||
encodeVInt(n.info.col, result)
|
encodeVInt(n.info.col, result)
|
||||||
result.add(',')
|
result.add(',')
|
||||||
encodeVInt(n.info.line, result)
|
encodeVInt(int n.info.line, result)
|
||||||
elif fInfo.col != n.info.col:
|
elif fInfo.col != n.info.col:
|
||||||
result.add('?')
|
result.add('?')
|
||||||
encodeVInt(n.info.col, result)
|
encodeVInt(n.info.col, result)
|
||||||
|
|
@ -303,7 +303,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
||||||
result.add('?')
|
result.add('?')
|
||||||
if s.info.col != -1'i16: encodeVInt(s.info.col, result)
|
if s.info.col != -1'i16: encodeVInt(s.info.col, result)
|
||||||
result.add(',')
|
result.add(',')
|
||||||
if s.info.line != -1'i16: encodeVInt(s.info.line, result)
|
if s.info.line != 0'u16: encodeVInt(int s.info.line, result)
|
||||||
result.add(',')
|
result.add(',')
|
||||||
encodeVInt(fileIdx(w, toFullPath(s.info)), result)
|
encodeVInt(fileIdx(w, toFullPath(s.info)), result)
|
||||||
if s.owner != nil:
|
if s.owner != nil:
|
||||||
|
|
@ -642,7 +642,7 @@ proc process(c: PPassContext, n: PNode): PNode =
|
||||||
|
|
||||||
proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
|
proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
|
||||||
if module.id < 0: internalError("rodwrite: module ID not set")
|
if module.id < 0: internalError("rodwrite: module ID not set")
|
||||||
var w = newRodWriter(rodread.getHash module.fileIdx, module, cache)
|
var w = newRodWriter(rodread.getHash FileIndex module.position, module, cache)
|
||||||
rawAddInterfaceSym(w, module)
|
rawAddInterfaceSym(w, module)
|
||||||
result = w
|
result = w
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -377,7 +377,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||||
## reassigned, and binding the unbound identifiers that the macro output
|
## reassigned, and binding the unbound identifiers that the macro output
|
||||||
## contains.
|
## contains.
|
||||||
inc(evalTemplateCounter)
|
inc(evalTemplateCounter)
|
||||||
if evalTemplateCounter > 100:
|
if evalTemplateCounter > evalTemplateLimit:
|
||||||
globalError(s.info, errTemplateInstantiationTooNested)
|
globalError(s.info, errTemplateInstantiationTooNested)
|
||||||
c.friendModules.add(s.owner.getModule)
|
c.friendModules.add(s.owner.getModule)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||||
|
|
||||||
proc filename*(c: PContext): string =
|
proc filename*(c: PContext): string =
|
||||||
# the module's filename
|
# the module's filename
|
||||||
return c.module.filename
|
return toFilename(FileIndex c.module.position)
|
||||||
|
|
||||||
proc scopeDepth*(c: PContext): int {.inline.} =
|
proc scopeDepth*(c: PContext): int {.inline.} =
|
||||||
result = if c.currentScope != nil: c.currentScope.depthLevel
|
result = if c.currentScope != nil: c.currentScope.depthLevel
|
||||||
|
|
|
||||||
|
|
@ -526,6 +526,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||||
if isAssignable(c, it) notin {arLValue, arLocalLValue}:
|
if isAssignable(c, it) notin {arLValue, arLocalLValue}:
|
||||||
if it.kind != nkHiddenAddr:
|
if it.kind != nkHiddenAddr:
|
||||||
localError(it.info, errVarForOutParamNeededX, $it)
|
localError(it.info, errVarForOutParamNeededX, $it)
|
||||||
|
# bug #5113: disallow newSeq(result) where result is a 'var T':
|
||||||
|
if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||||
|
var arg = n[1] #.skipAddr
|
||||||
|
if arg.kind == nkHiddenDeref: arg = arg[0]
|
||||||
|
if arg.kind == nkSym and arg.sym.kind == skResult and
|
||||||
|
arg.typ.skipTypes(abstractInst).kind in {tyVar, tyLent}:
|
||||||
|
localError(n.info, errXStackEscape, renderTree(n[1], {renderNoComments}))
|
||||||
|
|
||||||
return
|
return
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
if n.sons[i].kind == nkHiddenCallConv:
|
if n.sons[i].kind == nkHiddenCallConv:
|
||||||
|
|
@ -1334,11 +1342,11 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
|
||||||
let root = exprRoot(n)
|
let root = exprRoot(n)
|
||||||
if root != nil and root.owner == c.p.owner:
|
if root != nil and root.owner == c.p.owner:
|
||||||
if root.kind in {skLet, skVar, skTemp} and sfGlobal notin root.flags:
|
if root.kind in {skLet, skVar, skTemp} and sfGlobal notin root.flags:
|
||||||
localError(n.info, "'$1' escapes its stack frame; context: '$2'" % [
|
localError(n.info, "'$1' escapes its stack frame; context: '$2'; see $3/var_t_return.html" % [
|
||||||
root.name.s, renderTree(n, {renderNoComments})])
|
root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl])
|
||||||
elif root.kind == skParam and root.position != 0:
|
elif root.kind == skParam and root.position != 0:
|
||||||
localError(n.info, "'$1' is not the first parameter; context: '$2'" % [
|
localError(n.info, "'$1' is not the first parameter; context: '$2'; see $3/var_t_return.html" % [
|
||||||
root.name.s, renderTree(n, {renderNoComments})])
|
root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl])
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkHiddenAddr, nkAddr: return n
|
of nkHiddenAddr, nkAddr: return n
|
||||||
of nkHiddenDeref, nkDerefExpr: return n.sons[0]
|
of nkHiddenDeref, nkDerefExpr: return n.sons[0]
|
||||||
|
|
|
||||||
|
|
@ -483,6 +483,19 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
|
||||||
|
|
||||||
proc getConstExpr(m: PSym, n: PNode): PNode =
|
proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
|
proc getSrcTimestamp(): DateTime =
|
||||||
|
try:
|
||||||
|
result = utc(fromUnix(parseInt(getEnv("SOURCE_DATE_EPOCH",
|
||||||
|
"not a number"))))
|
||||||
|
except ValueError:
|
||||||
|
# Environment variable malformed.
|
||||||
|
# https://reproducible-builds.org/specs/source-date-epoch/: "If the
|
||||||
|
# value is malformed, the build process SHOULD exit with a non-zero
|
||||||
|
# error code", which this doesn't do. This uses local time, because
|
||||||
|
# that maintains compatibility with existing usage.
|
||||||
|
result = local(getTime())
|
||||||
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
var s = n.sym
|
var s = n.sym
|
||||||
|
|
@ -492,8 +505,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||||
of skConst:
|
of skConst:
|
||||||
case s.magic
|
case s.magic
|
||||||
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
|
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
|
||||||
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
|
of mCompileDate: result = newStrNodeT(format(getSrcTimestamp(),
|
||||||
of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
|
"yyyy-MM-dd"), n)
|
||||||
|
of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(),
|
||||||
|
"HH:mm:ss"), n)
|
||||||
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
|
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
|
||||||
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
|
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
|
||||||
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n)
|
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n)
|
||||||
|
|
|
||||||
|
|
@ -779,20 +779,15 @@ proc semRaise(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
if n[0].kind != nkEmpty:
|
if n[0].kind != nkEmpty:
|
||||||
|
|
||||||
n[0] = semExprWithType(c, n[0])
|
n[0] = semExprWithType(c, n[0])
|
||||||
let typ = n[0].typ
|
let typ = n[0].typ
|
||||||
|
|
||||||
if not isImportedException(typ):
|
if not isImportedException(typ):
|
||||||
|
|
||||||
if typ.kind != tyRef or typ.lastSon.kind != tyObject:
|
if typ.kind != tyRef or typ.lastSon.kind != tyObject:
|
||||||
localError(n.info, errExprCannotBeRaised)
|
localError(n.info, errExprCannotBeRaised)
|
||||||
|
|
||||||
if not isException(typ.lastSon):
|
if not isException(typ.lastSon):
|
||||||
localError(n.info, "raised object of type $1 does not inherit from Exception",
|
localError(n.info, "raised object of type $1 does not inherit from Exception",
|
||||||
[typeToString(typ)])
|
[typeToString(typ)])
|
||||||
|
|
||||||
|
|
||||||
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||||
if n.kind != nkGenericParams: illFormedAst(n)
|
if n.kind != nkGenericParams: illFormedAst(n)
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
|
|
@ -1100,12 +1095,12 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
|
||||||
for i in 0..<n.len:
|
for i in 0..<n.len:
|
||||||
var f = checkModuleName(n.sons[i])
|
var f = checkModuleName(n.sons[i])
|
||||||
if f != InvalidFileIDX:
|
if f != InvalidFileIDX:
|
||||||
if containsOrIncl(c.includedFiles, f):
|
if containsOrIncl(c.includedFiles, f.int):
|
||||||
localError(n.info, errRecursiveDependencyX, f.toFilename)
|
localError(n.info, errRecursiveDependencyX, f.toFilename)
|
||||||
else:
|
else:
|
||||||
let code = gIncludeFile(c.graph, c.module, f, c.cache)
|
let code = gIncludeFile(c.graph, c.module, f, c.cache)
|
||||||
gatherStmts c, code, result
|
gatherStmts c, code, result
|
||||||
excl(c.includedFiles, f)
|
excl(c.includedFiles, f.int)
|
||||||
of nkStmtList:
|
of nkStmtList:
|
||||||
for i in 0 ..< n.len:
|
for i in 0 ..< n.len:
|
||||||
gatherStmts(c, n.sons[i], result)
|
gatherStmts(c, n.sons[i], result)
|
||||||
|
|
@ -1789,11 +1784,11 @@ proc evalInclude(c: PContext, n: PNode): PNode =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var f = checkModuleName(n.sons[i])
|
var f = checkModuleName(n.sons[i])
|
||||||
if f != InvalidFileIDX:
|
if f != InvalidFileIDX:
|
||||||
if containsOrIncl(c.includedFiles, f):
|
if containsOrIncl(c.includedFiles, f.int):
|
||||||
localError(n.info, errRecursiveDependencyX, f.toFilename)
|
localError(n.info, errRecursiveDependencyX, f.toFilename)
|
||||||
else:
|
else:
|
||||||
addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache)))
|
addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache)))
|
||||||
excl(c.includedFiles, f)
|
excl(c.includedFiles, f.int)
|
||||||
|
|
||||||
proc setLine(n: PNode, info: TLineInfo) =
|
proc setLine(n: PNode, info: TLineInfo) =
|
||||||
for i in 0 ..< safeLen(n): setLine(n.sons[i], info)
|
for i in 0 ..< safeLen(n): setLine(n.sons[i], info)
|
||||||
|
|
|
||||||
|
|
@ -415,7 +415,7 @@ when defined(nimsuggest):
|
||||||
# Since TLineInfo defined a == operator that doesn't include the column,
|
# Since TLineInfo defined a == operator that doesn't include the column,
|
||||||
# we map TLineInfo to a unique int here for this lookup table:
|
# we map TLineInfo to a unique int here for this lookup table:
|
||||||
proc infoToInt(info: TLineInfo): int64 =
|
proc infoToInt(info: TLineInfo): int64 =
|
||||||
info.fileIndex + info.line.int64 shl 32 + info.col.int64 shl 48
|
info.fileIndex.int64 + info.line.int64 shl 32 + info.col.int64 shl 48
|
||||||
|
|
||||||
proc addNoDup(s: PSym; info: TLineInfo) =
|
proc addNoDup(s: PSym; info: TLineInfo) =
|
||||||
# ensure nothing gets too slow:
|
# ensure nothing gets too slow:
|
||||||
|
|
@ -574,7 +574,7 @@ proc suggestEnum*(c: PContext; n: PNode; t: PType) =
|
||||||
if outputs.len > 0: suggestQuit()
|
if outputs.len > 0: suggestQuit()
|
||||||
|
|
||||||
proc suggestSentinel*(c: PContext) =
|
proc suggestSentinel*(c: PContext) =
|
||||||
if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex: return
|
if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex.int32: return
|
||||||
if c.compilesContextId > 0: return
|
if c.compilesContextId > 0: return
|
||||||
inc(c.compilesContextId)
|
inc(c.compilesContextId)
|
||||||
var outputs: Suggestions = @[]
|
var outputs: Suggestions = @[]
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string,
|
||||||
else:
|
else:
|
||||||
result = applyFilter(p, n, filename, result)
|
result = applyFilter(p, n, filename, result)
|
||||||
|
|
||||||
proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream;
|
proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
|
||||||
cache: IdentCache) =
|
cache: IdentCache) =
|
||||||
var s: PLLStream
|
var s: PLLStream
|
||||||
p.skin = skinStandard
|
p.skin = skinStandard
|
||||||
|
|
@ -155,7 +155,7 @@ proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream;
|
||||||
proc closeParsers*(p: var TParsers) =
|
proc closeParsers*(p: var TParsers) =
|
||||||
parser.closeParser(p.parser)
|
parser.closeParser(p.parser)
|
||||||
|
|
||||||
proc parseFile*(fileIdx: int32; cache: IdentCache): PNode {.procvar.} =
|
proc parseFile*(fileIdx: FileIndex; cache: IdentCache): PNode {.procvar.} =
|
||||||
var
|
var
|
||||||
p: TParsers
|
p: TParsers
|
||||||
f: File
|
f: File
|
||||||
|
|
|
||||||
|
|
@ -777,8 +777,8 @@ proc equalParams(a, b: PNode): TParamsEquality =
|
||||||
return paramsNotEqual # paramsIncompatible;
|
return paramsNotEqual # paramsIncompatible;
|
||||||
# continue traversal! If not equal, we can return immediately; else
|
# continue traversal! If not equal, we can return immediately; else
|
||||||
# it stays incompatible
|
# it stays incompatible
|
||||||
if not sameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {ExactTypeDescValues}):
|
if not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}):
|
||||||
if (a.sons[0].typ == nil) or (b.sons[0].typ == nil):
|
if (a.typ == nil) or (b.typ == nil):
|
||||||
result = paramsNotEqual # one proc has a result, the other not is OK
|
result = paramsNotEqual # one proc has a result, the other not is OK
|
||||||
else:
|
else:
|
||||||
result = paramsIncompatible # overloading by different
|
result = paramsIncompatible # overloading by different
|
||||||
|
|
@ -970,7 +970,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
result = sameFlags(a, b)
|
result = sameFlags(a, b)
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
||||||
if result and ExactGenericParams in c.flags:
|
if result and {ExactGenericParams, ExactTypeDescValues} * c.flags != {}:
|
||||||
result = a.sym.position == b.sym.position
|
result = a.sym.position == b.sym.position
|
||||||
of tyGenericInvocation, tyGenericBody, tySequence,
|
of tyGenericInvocation, tyGenericBody, tySequence,
|
||||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyLent, tySink,
|
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyLent, tySink,
|
||||||
|
|
|
||||||
|
|
@ -1381,7 +1381,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcNGetLine:
|
of opcNGetLine:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
let n = regs[rb].node
|
let n = regs[rb].node
|
||||||
regs[ra].node = newIntNode(nkIntLit, n.info.line)
|
regs[ra].node = newIntNode(nkIntLit, n.info.line.int)
|
||||||
regs[ra].node.info = n.info
|
regs[ra].node.info = n.info
|
||||||
regs[ra].node.typ = n.typ
|
regs[ra].node.typ = n.typ
|
||||||
of opcNGetColumn:
|
of opcNGetColumn:
|
||||||
|
|
@ -1397,8 +1397,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
let bNode = regs[rc].node
|
let bNode = regs[rc].node
|
||||||
# these are cstring to prevent string copy, and cmpIgnoreStyle from
|
# these are cstring to prevent string copy, and cmpIgnoreStyle from
|
||||||
# takes cstring arguments
|
# takes cstring arguments
|
||||||
var aStrVal: cstring
|
var aStrVal: cstring = nil
|
||||||
var bStrVal: cstring
|
var bStrVal: cstring = nil
|
||||||
# extract strVal from argument ``a``
|
# extract strVal from argument ``a``
|
||||||
case aNode.kind
|
case aNode.kind
|
||||||
of {nkStrLit..nkTripleStrLit}:
|
of {nkStrLit..nkTripleStrLit}:
|
||||||
|
|
@ -1407,8 +1407,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
aStrVal = aNode.ident.s.cstring
|
aStrVal = aNode.ident.s.cstring
|
||||||
of nkSym:
|
of nkSym:
|
||||||
aStrVal = aNode.sym.name.s.cstring
|
aStrVal = aNode.sym.name.s.cstring
|
||||||
|
of nkOpenSymChoice, nkClosedSymChoice:
|
||||||
|
aStrVal = aNode[0].sym.name.s.cstring
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
discard
|
||||||
# extract strVal from argument ``b``
|
# extract strVal from argument ``b``
|
||||||
case bNode.kind
|
case bNode.kind
|
||||||
of {nkStrLit..nkTripleStrLit}:
|
of {nkStrLit..nkTripleStrLit}:
|
||||||
|
|
@ -1417,11 +1419,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
bStrVal = bNode.ident.s.cstring
|
bStrVal = bNode.ident.s.cstring
|
||||||
of nkSym:
|
of nkSym:
|
||||||
bStrVal = bNode.sym.name.s.cstring
|
bStrVal = bNode.sym.name.s.cstring
|
||||||
|
of nkOpenSymChoice, nkClosedSymChoice:
|
||||||
|
bStrVal = bNode[0].sym.name.s.cstring
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
discard
|
||||||
# set result
|
# set result
|
||||||
regs[ra].intVal =
|
regs[ra].intVal =
|
||||||
|
if aStrVal != nil and bStrVal != nil:
|
||||||
ord(idents.cmpIgnoreStyle(aStrVal,bStrVal,high(int)) == 0)
|
ord(idents.cmpIgnoreStyle(aStrVal,bStrVal,high(int)) == 0)
|
||||||
|
else:
|
||||||
|
0
|
||||||
|
|
||||||
of opcStrToIdent:
|
of opcStrToIdent:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
|
if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
|
||||||
|
|
@ -1513,7 +1521,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
let x = newNodeI(TNodeKind(int(k)),
|
let x = newNodeI(TNodeKind(int(k)),
|
||||||
if cc.kind != nkNilLit:
|
if cc.kind != nkNilLit:
|
||||||
cc.info
|
cc.info
|
||||||
elif c.comesFromHeuristic.line > -1:
|
elif c.comesFromHeuristic.line != 0'u16:
|
||||||
c.comesFromHeuristic
|
c.comesFromHeuristic
|
||||||
elif c.callsite != nil and c.callsite.safeLen > 1:
|
elif c.callsite != nil and c.callsite.safeLen > 1:
|
||||||
c.callsite[1].info
|
c.callsite[1].info
|
||||||
|
|
@ -1685,7 +1693,7 @@ proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode,
|
||||||
newSeq(tos.slots, c.prc.maxSlots)
|
newSeq(tos.slots, c.prc.maxSlots)
|
||||||
#for i in 0 ..< c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
#for i in 0 ..< c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||||
result = rawExecute(c, start, tos).regToNode
|
result = rawExecute(c, start, tos).regToNode
|
||||||
if result.info.line < 0: result.info = n.info
|
if result.info.col < 0: result.info = n.info
|
||||||
|
|
||||||
proc evalConstExpr*(module: PSym; cache: IdentCache, e: PNode): PNode =
|
proc evalConstExpr*(module: PSym; cache: IdentCache, e: PNode): PNode =
|
||||||
result = evalConstExprAux(module, cache, nil, e, emConst)
|
result = evalConstExprAux(module, cache, nil, e, emConst)
|
||||||
|
|
@ -1721,14 +1729,16 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
|
||||||
let posInCall = macroSym.typ.len + i
|
let posInCall = macroSym.typ.len + i
|
||||||
yield (genericParam, call[posInCall])
|
yield (genericParam, call[posInCall])
|
||||||
|
|
||||||
|
# to prevent endless recursion in macro instantiation
|
||||||
|
const evalMacroLimit = 1000
|
||||||
var evalMacroCounter: int
|
var evalMacroCounter: int
|
||||||
|
|
||||||
proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
|
proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
|
||||||
sym: PSym): PNode =
|
sym: PSym): PNode =
|
||||||
# XXX globalError() is ugly here, but I don't know a better solution for now
|
# XXX globalError() is ugly here, but I don't know a better solution for now
|
||||||
inc(evalMacroCounter)
|
inc(evalMacroCounter)
|
||||||
if evalMacroCounter > 100:
|
if evalMacroCounter > evalMacroLimit:
|
||||||
globalError(n.info, errTemplateInstantiationTooNested)
|
globalError(n.info, errMacroInstantiationTooNested)
|
||||||
|
|
||||||
# immediate macros can bypass any type and arity checking so we check the
|
# immediate macros can bypass any type and arity checking so we check the
|
||||||
# arity here too:
|
# arity here too:
|
||||||
|
|
@ -1738,7 +1748,7 @@ proc evalMacroCall*(module: PSym; cache: IdentCache, n, nOrig: PNode,
|
||||||
|
|
||||||
setupGlobalCtx(module, cache)
|
setupGlobalCtx(module, cache)
|
||||||
var c = globalCtx
|
var c = globalCtx
|
||||||
c.comesFromHeuristic.line = -1
|
c.comesFromHeuristic.line = 0'u16
|
||||||
|
|
||||||
c.callsite = nOrig
|
c.callsite = nOrig
|
||||||
let start = genProc(c, sym)
|
let start = genProc(c, sym)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ Options:
|
||||||
--app:console|gui|lib|staticlib
|
--app:console|gui|lib|staticlib
|
||||||
generate a console app|GUI app|DLL|static library
|
generate a console app|GUI app|DLL|static library
|
||||||
-r, --run run the compiled program with given arguments
|
-r, --run run the compiled program with given arguments
|
||||||
--advanced show advanced command line switches
|
--fullhelp show all command line switches
|
||||||
-h, --help show this help
|
-h, --help show this help
|
||||||
|
|
||||||
Note, single letter options that take an argument require a colon. E.g. -p:PATH.
|
Note, single letter options that take an argument require a colon. E.g. -p:PATH.
|
||||||
|
|
|
||||||
|
|
@ -3487,17 +3487,17 @@ returned value is an l-value and can be modified by the caller:
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
var g = 0
|
var g = 0
|
||||||
|
|
||||||
proc WriteAccessToG(): var int =
|
proc writeAccessToG(): var int =
|
||||||
result = g
|
result = g
|
||||||
|
|
||||||
WriteAccessToG() = 6
|
writeAccessToG() = 6
|
||||||
assert g == 6
|
assert g == 6
|
||||||
|
|
||||||
It is a compile time error if the implicitly introduced pointer could be
|
It is a compile time error if the implicitly introduced pointer could be
|
||||||
used to access a location beyond its lifetime:
|
used to access a location beyond its lifetime:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
proc WriteAccessToG(): var int =
|
proc writeAccessToG(): var int =
|
||||||
var g = 0
|
var g = 0
|
||||||
result = g # Error!
|
result = g # Error!
|
||||||
|
|
||||||
|
|
@ -3512,6 +3512,24 @@ In the standard library every name of a routine that returns a ``var`` type
|
||||||
starts with the prefix ``m`` per convention.
|
starts with the prefix ``m`` per convention.
|
||||||
|
|
||||||
|
|
||||||
|
.. include:: manual/var_t_return.rst
|
||||||
|
|
||||||
|
Future directions
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Later versions of Nim can be more precise about the borrowing rule with
|
||||||
|
a syntax like:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc foo(other: Y; container: var X): var T from container
|
||||||
|
|
||||||
|
Here ``var T from container`` explicitly exposes that the
|
||||||
|
location is deviated from the second parameter (called
|
||||||
|
'container' in this case). The syntax ``var T from p`` specifies a type
|
||||||
|
``varTy[T, 2]`` which is incompatible with ``varTy[T, 1]``.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Overloading of the subscript operator
|
Overloading of the subscript operator
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
|
|
@ -5241,15 +5259,21 @@ chance to convert it into a sequence.
|
||||||
Macros
|
Macros
|
||||||
======
|
======
|
||||||
|
|
||||||
A macro is a special kind of low level template. Macros can be used
|
A macro is a special function that is executed at compile-time.
|
||||||
to implement `domain specific languages`:idx:.
|
Normally the input for a macro is an abstract syntax
|
||||||
|
tree (AST) of the code that is passed to it. The macro can then do
|
||||||
|
transformations on it and return the transformed AST. The
|
||||||
|
transformed AST is then passed to the compiler as if the macro
|
||||||
|
invocation would have been replaced by its result in the source
|
||||||
|
code. This can be used to implement `domain specific
|
||||||
|
languages`:idx:.
|
||||||
|
|
||||||
While macros enable advanced compile-time code transformations, they
|
While macros enable advanced compile-time code transformations, they
|
||||||
cannot change Nim's syntax. However, this is no real restriction because
|
cannot change Nim's syntax. However, this is no real restriction because
|
||||||
Nim's syntax is flexible enough anyway.
|
Nim's syntax is flexible enough anyway.
|
||||||
|
|
||||||
To write macros, one needs to know how the Nim concrete syntax is converted
|
To write macros, one needs to know how the Nim concrete syntax is converted
|
||||||
to an abstract syntax tree.
|
to an AST.
|
||||||
|
|
||||||
There are two ways to invoke a macro:
|
There are two ways to invoke a macro:
|
||||||
(1) invoking a macro like a procedure call (`expression macros`)
|
(1) invoking a macro like a procedure call (`expression macros`)
|
||||||
|
|
@ -5269,19 +5293,21 @@ variable number of arguments:
|
||||||
# ``macros`` module:
|
# ``macros`` module:
|
||||||
import macros
|
import macros
|
||||||
|
|
||||||
macro debug(n: varargs[untyped]): untyped =
|
macro debug(args: varargs[untyped]): untyped =
|
||||||
# `n` is a Nim AST that contains the whole macro invocation
|
# `args` is a collection of `NimNode` values that each contain the
|
||||||
# this macro returns a list of statements:
|
# AST for an argument of the macro. A macro always has to
|
||||||
result = newNimNode(nnkStmtList, n)
|
# return a `NimNode`. A node of kind `nnkStmtList` is suitable for
|
||||||
|
# this use case.
|
||||||
|
result = nnkStmtList.newTree()
|
||||||
# iterate over any argument that is passed to this macro:
|
# iterate over any argument that is passed to this macro:
|
||||||
for i in 0..n.len-1:
|
for n in args:
|
||||||
# add a call to the statement list that writes the expression;
|
# add a call to the statement list that writes the expression;
|
||||||
# `toStrLit` converts an AST to its string representation:
|
# `toStrLit` converts an AST to its string representation:
|
||||||
add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
|
result.add newCall("write", newIdentNode("stdout"), newLit(n.repr))
|
||||||
# add a call to the statement list that writes ": "
|
# add a call to the statement list that writes ": "
|
||||||
add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
|
result.add newCall("write", newIdentNode("stdout"), newLit(": "))
|
||||||
# add a call to the statement list that writes the expressions value:
|
# add a call to the statement list that writes the expressions value:
|
||||||
add(result, newCall("writeLine", newIdentNode("stdout"), n[i]))
|
result.add newCall("writeLine", newIdentNode("stdout"), n)
|
||||||
|
|
||||||
var
|
var
|
||||||
a: array[0..10, int]
|
a: array[0..10, int]
|
||||||
|
|
@ -8187,5 +8213,3 @@ validation errors:
|
||||||
|
|
||||||
If the taint mode is turned off, ``TaintedString`` is simply an alias for
|
If the taint mode is turned off, ``TaintedString`` is simply an alias for
|
||||||
``string``.
|
``string``.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
20
doc/manual/var_t_return.rst
Normal file
20
doc/manual/var_t_return.rst
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
Memory safety for returning by ``var T`` is ensured by a simple borrowing
|
||||||
|
rule: If ``result`` does not refer to a location pointing to the heap
|
||||||
|
(that is in ``result = X`` the ``X`` involves a ``ptr`` or ``ref`` access)
|
||||||
|
then it has to be deviated by the routine's first parameter:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc forward[T](x: var T): var T =
|
||||||
|
result = x # ok, deviated from the first parameter.
|
||||||
|
|
||||||
|
proc p(param: var int): var int =
|
||||||
|
var x: int
|
||||||
|
# we know 'forward' provides a view into the location deviated by
|
||||||
|
# its first argument 'x'.
|
||||||
|
result = forward(x) # Error: location is derived from ``x``
|
||||||
|
# which is not p's first parameter and lives
|
||||||
|
# on the stack.
|
||||||
|
|
||||||
|
In other words, the lifetime of what ``result`` points to is attached to the
|
||||||
|
lifetime of the first parameter and that is enough knowledge to verify
|
||||||
|
memory safety at the callsite.
|
||||||
|
|
@ -706,8 +706,7 @@ proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
|
||||||
res.add(($n.kind).substr(3))
|
res.add(($n.kind).substr(3))
|
||||||
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nnkEmpty: discard # same as nil node in this representation
|
of nnkEmpty, nnkNilLit: discard # same as nil node in this representation
|
||||||
of nnkNilLit: res.add(" nil")
|
|
||||||
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
|
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
|
||||||
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
|
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
|
||||||
of nnkStrLit..nnkTripleStrLit, nnkIdent, nnkSym:
|
of nnkStrLit..nnkTripleStrLit, nnkIdent, nnkSym:
|
||||||
|
|
@ -730,8 +729,7 @@ proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
|
||||||
add(result, "(")
|
add(result, "(")
|
||||||
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nnkEmpty: discard # same as nil node in this representation
|
of nnkEmpty, nnkNilLit: discard # same as nil node in this representation
|
||||||
of nnkNilLit: add(result, "nil")
|
|
||||||
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
|
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
|
||||||
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
|
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
|
||||||
of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkident, nnkSym:
|
of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkident, nnkSym:
|
||||||
|
|
@ -766,7 +764,7 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
|
||||||
## See also `repr`, `treeRepr`, and `lispRepr`.
|
## See also `repr`, `treeRepr`, and `lispRepr`.
|
||||||
|
|
||||||
const
|
const
|
||||||
NodeKinds = {nnkEmpty, nnkNilLit, nnkIdent, nnkSym, nnkNone, nnkCommentStmt}
|
NodeKinds = {nnkEmpty, nnkIdent, nnkSym, nnkNone, nnkCommentStmt}
|
||||||
LitKinds = {nnkCharLit..nnkInt64Lit, nnkFloatLit..nnkFloat64Lit, nnkStrLit..nnkTripleStrLit}
|
LitKinds = {nnkCharLit..nnkInt64Lit, nnkFloatLit..nnkFloat64Lit, nnkStrLit..nnkTripleStrLit}
|
||||||
|
|
||||||
proc traverse(res: var string, level: int, n: NimNode) {.benign.} =
|
proc traverse(res: var string, level: int, n: NimNode) {.benign.} =
|
||||||
|
|
@ -775,12 +773,13 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
|
||||||
res.add("new" & ($n.kind).substr(3) & "Node(")
|
res.add("new" & ($n.kind).substr(3) & "Node(")
|
||||||
elif n.kind in LitKinds:
|
elif n.kind in LitKinds:
|
||||||
res.add("newLit(")
|
res.add("newLit(")
|
||||||
|
elif n.kind == nnkNilLit:
|
||||||
|
res.add("newNilLit()")
|
||||||
else:
|
else:
|
||||||
res.add($n.kind)
|
res.add($n.kind)
|
||||||
|
|
||||||
case n.kind
|
case n.kind
|
||||||
of nnkEmpty: discard
|
of nnkEmpty, nnkNilLit: discard
|
||||||
of nnkNilLit: res.add("nil")
|
|
||||||
of nnkCharLit: res.add("'" & $chr(n.intVal) & "'")
|
of nnkCharLit: res.add("'" & $chr(n.intVal) & "'")
|
||||||
of nnkIntLit..nnkInt64Lit: res.add($n.intVal)
|
of nnkIntLit..nnkInt64Lit: res.add($n.intVal)
|
||||||
of nnkFloatLit..nnkFloat64Lit: res.add($n.floatVal)
|
of nnkFloatLit..nnkFloat64Lit: res.add($n.floatVal)
|
||||||
|
|
@ -1289,7 +1288,11 @@ proc customPragmaNode(n: NimNode): NimNode =
|
||||||
typ = n.getTypeInst()
|
typ = n.getTypeInst()
|
||||||
|
|
||||||
if typ.typeKind == ntyTypeDesc:
|
if typ.typeKind == ntyTypeDesc:
|
||||||
return typ[1].getImpl()[0][1]
|
let impl = typ[1].getImpl()
|
||||||
|
if impl[0].kind == nnkPragmaExpr:
|
||||||
|
return impl[0][1]
|
||||||
|
else:
|
||||||
|
return impl[0] # handle types which don't have macro at all
|
||||||
|
|
||||||
if n.kind == nnkSym: # either an variable or a proc
|
if n.kind == nnkSym: # either an variable or a proc
|
||||||
let impl = n.getImpl()
|
let impl = n.getImpl()
|
||||||
|
|
|
||||||
|
|
@ -101,8 +101,8 @@ when defined(windows):
|
||||||
from winlean import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
|
from winlean import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
|
||||||
FD_ISSET, select
|
FD_ISSET, select
|
||||||
else:
|
else:
|
||||||
from posix import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
|
from posix import TimeVal, Time, Suseconds, SocketHandle, FD_SET, FD_ZERO,
|
||||||
FD_ISSET, select
|
TFdSet, FD_ISSET, select
|
||||||
|
|
||||||
type
|
type
|
||||||
DelegateObj* = object
|
DelegateObj* = object
|
||||||
|
|
@ -556,6 +556,10 @@ proc send*(sock: AsyncSocket, data: string) =
|
||||||
proc timeValFromMilliseconds(timeout = 500): Timeval =
|
proc timeValFromMilliseconds(timeout = 500): Timeval =
|
||||||
if timeout != -1:
|
if timeout != -1:
|
||||||
var seconds = timeout div 1000
|
var seconds = timeout div 1000
|
||||||
|
when defined(posix):
|
||||||
|
result.tv_sec = seconds.Time
|
||||||
|
result.tv_usec = ((timeout - seconds * 1000) * 1000).Suseconds
|
||||||
|
else:
|
||||||
result.tv_sec = seconds.int32
|
result.tv_sec = seconds.int32
|
||||||
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
|
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -953,6 +953,10 @@ when defined(ssl):
|
||||||
proc timeValFromMilliseconds(timeout = 500): Timeval =
|
proc timeValFromMilliseconds(timeout = 500): Timeval =
|
||||||
if timeout != -1:
|
if timeout != -1:
|
||||||
var seconds = timeout div 1000
|
var seconds = timeout div 1000
|
||||||
|
when defined(posix):
|
||||||
|
result.tv_sec = seconds.Time
|
||||||
|
result.tv_usec = ((timeout - seconds * 1000) * 1000).Suseconds
|
||||||
|
else:
|
||||||
result.tv_sec = seconds.int32
|
result.tv_sec = seconds.int32
|
||||||
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
|
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -351,8 +351,8 @@ type
|
||||||
|
|
||||||
Timeval* {.importc: "struct timeval", header: "<sys/select.h>",
|
Timeval* {.importc: "struct timeval", header: "<sys/select.h>",
|
||||||
final, pure.} = object ## struct timeval
|
final, pure.} = object ## struct timeval
|
||||||
tv_sec*: clong ## Seconds.
|
tv_sec*: Time ## Seconds.
|
||||||
tv_usec*: clong ## Microseconds.
|
tv_usec*: Suseconds ## Microseconds.
|
||||||
TFdSet* {.importc: "fd_set", header: "<sys/select.h>",
|
TFdSet* {.importc: "fd_set", header: "<sys/select.h>",
|
||||||
final, pure.} = object
|
final, pure.} = object
|
||||||
abi: array[1024 div (8 * sizeof(clong)), clong]
|
abi: array[1024 div (8 * sizeof(clong)), clong]
|
||||||
|
|
|
||||||
|
|
@ -335,8 +335,8 @@ type
|
||||||
|
|
||||||
Timeval* {.importc: "struct timeval", header: "<sys/select.h>",
|
Timeval* {.importc: "struct timeval", header: "<sys/select.h>",
|
||||||
final, pure.} = object ## struct timeval
|
final, pure.} = object ## struct timeval
|
||||||
tv_sec*: int ## Seconds.
|
tv_sec*: Time ## Seconds.
|
||||||
tv_usec*: int ## Microseconds.
|
tv_usec*: Suseconds ## Microseconds.
|
||||||
TFdSet* {.importc: "fd_set", header: "<sys/select.h>",
|
TFdSet* {.importc: "fd_set", header: "<sys/select.h>",
|
||||||
final, pure.} = object
|
final, pure.} = object
|
||||||
Mcontext* {.importc: "mcontext_t", header: "<ucontext.h>",
|
Mcontext* {.importc: "mcontext_t", header: "<ucontext.h>",
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,15 @@ proc wakeupWorkerToProcessQueue(w: ptr Worker) =
|
||||||
signal(w.q.empty)
|
signal(w.q.empty)
|
||||||
signal(w.taskArrived)
|
signal(w.taskArrived)
|
||||||
|
|
||||||
|
proc attach(fv: FlowVarBase; i: int): bool =
|
||||||
|
acquire(fv.cv.L)
|
||||||
|
if fv.cv.counter <= 0:
|
||||||
|
fv.idx = i
|
||||||
|
result = true
|
||||||
|
else:
|
||||||
|
result = false
|
||||||
|
release(fv.cv.L)
|
||||||
|
|
||||||
proc finished(fv: FlowVarBase) =
|
proc finished(fv: FlowVarBase) =
|
||||||
doAssert fv.ai.isNil, "flowVar is still attached to an 'awaitAny'"
|
doAssert fv.ai.isNil, "flowVar is still attached to an 'awaitAny'"
|
||||||
# we have to protect against the rare cases where the owner of the flowVar
|
# we have to protect against the rare cases where the owner of the flowVar
|
||||||
|
|
@ -245,26 +254,27 @@ proc `^`*[T](fv: FlowVar[T]): T =
|
||||||
proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
|
proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
|
||||||
## awaits any of the given flowVars. Returns the index of one flowVar for
|
## awaits any of the given flowVars. Returns the index of one flowVar for
|
||||||
## which a value arrived. A flowVar only supports one call to 'awaitAny' at
|
## which a value arrived. A flowVar only supports one call to 'awaitAny' at
|
||||||
## the same time. That means if you await([a,b]) and await([b,c]) the second
|
## the same time. That means if you awaitAny([a,b]) and awaitAny([b,c]) the second
|
||||||
## call will only await 'c'. If there is no flowVar left to be able to wait
|
## call will only await 'c'. If there is no flowVar left to be able to wait
|
||||||
## on, -1 is returned.
|
## on, -1 is returned.
|
||||||
## **Note**: This results in non-deterministic behaviour and so should be
|
## **Note**: This results in non-deterministic behaviour and should be avoided.
|
||||||
## avoided.
|
|
||||||
var ai: AwaitInfo
|
var ai: AwaitInfo
|
||||||
ai.cv.initSemaphore()
|
ai.cv.initSemaphore()
|
||||||
var conflicts = 0
|
var conflicts = 0
|
||||||
|
result = -1
|
||||||
for i in 0 .. flowVars.high:
|
for i in 0 .. flowVars.high:
|
||||||
if cas(addr flowVars[i].ai, nil, addr ai):
|
if cas(addr flowVars[i].ai, nil, addr ai):
|
||||||
flowVars[i].idx = i
|
if not attach(flowVars[i], i):
|
||||||
|
result = i
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
inc conflicts
|
inc conflicts
|
||||||
if conflicts < flowVars.len:
|
if conflicts < flowVars.len:
|
||||||
|
if result < 0:
|
||||||
await(ai.cv)
|
await(ai.cv)
|
||||||
result = ai.idx
|
result = ai.idx
|
||||||
for i in 0 .. flowVars.high:
|
for i in 0 .. flowVars.high:
|
||||||
discard cas(addr flowVars[i].ai, addr ai, nil)
|
discard cas(addr flowVars[i].ai, addr ai, nil)
|
||||||
else:
|
|
||||||
result = -1
|
|
||||||
destroySemaphore(ai.cv)
|
destroySemaphore(ai.cv)
|
||||||
|
|
||||||
proc isReady*(fv: FlowVarBase): bool =
|
proc isReady*(fv: FlowVarBase): bool =
|
||||||
|
|
|
||||||
|
|
@ -616,8 +616,12 @@ proc setBlocking*(s: SocketHandle, blocking: bool) =
|
||||||
proc timeValFromMilliseconds(timeout = 500): Timeval =
|
proc timeValFromMilliseconds(timeout = 500): Timeval =
|
||||||
if timeout != -1:
|
if timeout != -1:
|
||||||
var seconds = timeout div 1000
|
var seconds = timeout div 1000
|
||||||
|
when useWinVersion:
|
||||||
result.tv_sec = seconds.int32
|
result.tv_sec = seconds.int32
|
||||||
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
|
result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
|
||||||
|
else:
|
||||||
|
result.tv_sec = seconds.Time
|
||||||
|
result.tv_usec = ((timeout - seconds * 1000) * 1000).Suseconds
|
||||||
|
|
||||||
proc createFdSet(fd: var TFdSet, s: seq[SocketHandle], m: var int) =
|
proc createFdSet(fd: var TFdSet, s: seq[SocketHandle], m: var int) =
|
||||||
FD_ZERO(fd)
|
FD_ZERO(fd)
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,10 @@ proc none*(T: typedesc): Option[T] =
|
||||||
# the default is the none type
|
# the default is the none type
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
proc none*[T]: Option[T] =
|
||||||
|
## Alias for ``none(T)``.
|
||||||
|
none(T)
|
||||||
|
|
||||||
proc isSome*[T](self: Option[T]): bool {.inline.} =
|
proc isSome*[T](self: Option[T]): bool {.inline.} =
|
||||||
when T is SomePointer:
|
when T is SomePointer:
|
||||||
self.val != nil
|
self.val != nil
|
||||||
|
|
@ -290,3 +294,7 @@ when isMainModule:
|
||||||
|
|
||||||
let tmp = option(intref)
|
let tmp = option(intref)
|
||||||
check(sizeof(tmp) == sizeof(ptr int))
|
check(sizeof(tmp) == sizeof(ptr int))
|
||||||
|
|
||||||
|
test "none[T]":
|
||||||
|
check(none[int]().isNone)
|
||||||
|
check(none(int) == none[int]())
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1".}
|
||||||
var f: WIN32_FIND_DATA
|
var f: WIN32_FIND_DATA
|
||||||
var h = findFirstFile(file, f)
|
var h = findFirstFile(file, f)
|
||||||
if h == -1'i32: raiseOSError(osLastError())
|
if h == -1'i32: raiseOSError(osLastError())
|
||||||
result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftLastWriteTime)).int64)
|
result = fromWinTime(rdFileTime(f.ftLastWriteTime))
|
||||||
findClose(h)
|
findClose(h)
|
||||||
|
|
||||||
proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
|
proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
|
||||||
|
|
@ -201,7 +201,7 @@ proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
|
||||||
var f: WIN32_FIND_DATA
|
var f: WIN32_FIND_DATA
|
||||||
var h = findFirstFile(file, f)
|
var h = findFirstFile(file, f)
|
||||||
if h == -1'i32: raiseOSError(osLastError())
|
if h == -1'i32: raiseOSError(osLastError())
|
||||||
result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftLastAccessTime)).int64)
|
result = fromWinTime(rdFileTime(f.ftLastAccessTime))
|
||||||
findClose(h)
|
findClose(h)
|
||||||
|
|
||||||
proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
|
proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
|
||||||
|
|
@ -218,7 +218,7 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
|
||||||
var f: WIN32_FIND_DATA
|
var f: WIN32_FIND_DATA
|
||||||
var h = findFirstFile(file, f)
|
var h = findFirstFile(file, f)
|
||||||
if h == -1'i32: raiseOSError(osLastError())
|
if h == -1'i32: raiseOSError(osLastError())
|
||||||
result = fromUnix(winTimeToUnixTime(rdFileTime(f.ftCreationTime)).int64)
|
result = fromWinTime(rdFileTime(f.ftCreationTime))
|
||||||
findClose(h)
|
findClose(h)
|
||||||
|
|
||||||
proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
|
proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
|
||||||
|
|
@ -329,20 +329,21 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
|
||||||
c_free(cast[pointer](r))
|
c_free(cast[pointer](r))
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
proc openHandle(path: string, followSymlink=true): Handle =
|
proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle =
|
||||||
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
|
var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
|
||||||
if not followSymlink:
|
if not followSymlink:
|
||||||
flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
|
flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
|
||||||
|
let access = if writeAccess: GENERIC_WRITE else: 0'i32
|
||||||
|
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
result = createFileW(
|
result = createFileW(
|
||||||
newWideCString(path), 0'i32,
|
newWideCString(path), access,
|
||||||
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
|
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
|
||||||
nil, OPEN_EXISTING, flags, 0
|
nil, OPEN_EXISTING, flags, 0
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
result = createFileA(
|
result = createFileA(
|
||||||
path, 0'i32,
|
path, access,
|
||||||
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
|
FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
|
||||||
nil, OPEN_EXISTING, flags, 0
|
nil, OPEN_EXISTING, flags, 0
|
||||||
)
|
)
|
||||||
|
|
@ -1511,16 +1512,14 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
|
||||||
## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
|
## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
|
||||||
## or a 'Stat' structure on posix
|
## or a 'Stat' structure on posix
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
template toTime(e: FILETIME): untyped {.gensym.} =
|
|
||||||
fromUnix(winTimeToUnixTime(rdFileTime(e)).int64) # local templates default to bind semantics
|
|
||||||
template merge(a, b): untyped = a or (b shl 32)
|
template merge(a, b): untyped = a or (b shl 32)
|
||||||
formalInfo.id.device = rawInfo.dwVolumeSerialNumber
|
formalInfo.id.device = rawInfo.dwVolumeSerialNumber
|
||||||
formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
|
formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
|
||||||
formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)
|
formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)
|
||||||
formalInfo.linkCount = rawInfo.nNumberOfLinks
|
formalInfo.linkCount = rawInfo.nNumberOfLinks
|
||||||
formalInfo.lastAccessTime = toTime(rawInfo.ftLastAccessTime)
|
formalInfo.lastAccessTime = fromWinTime(rdFileTime(rawInfo.ftLastAccessTime))
|
||||||
formalInfo.lastWriteTime = toTime(rawInfo.ftLastWriteTime)
|
formalInfo.lastWriteTime = fromWinTime(rdFileTime(rawInfo.ftLastWriteTime))
|
||||||
formalInfo.creationTime = toTime(rawInfo.ftCreationTime)
|
formalInfo.creationTime = fromWinTime(rdFileTime(rawInfo.ftCreationTime))
|
||||||
|
|
||||||
# Retrieve basic permissions
|
# Retrieve basic permissions
|
||||||
if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32:
|
if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32:
|
||||||
|
|
@ -1654,3 +1653,18 @@ proc isHidden*(path: string): bool =
|
||||||
result = (fileName[0] == '.') and (fileName[3] != '.')
|
result = (fileName[0] == '.') and (fileName[3] != '.')
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
proc setLastModificationTime*(file: string, t: times.Time) =
|
||||||
|
## Sets the `file`'s last modification time. `OSError` is raised in case of
|
||||||
|
## an error.
|
||||||
|
when defined(posix):
|
||||||
|
let unixt = posix.Time(t.toUnix)
|
||||||
|
var timevals = [Timeval(tv_sec: unixt), Timeval(tv_sec: unixt)] # [last access, last modification]
|
||||||
|
if utimes(file, timevals.addr) != 0: raiseOSError(osLastError())
|
||||||
|
else:
|
||||||
|
let h = openHandle(path = file, writeAccess = true)
|
||||||
|
if h == INVALID_HANDLE_VALUE: raiseOSError(osLastError())
|
||||||
|
var ft = t.toWinTime.toFILETIME
|
||||||
|
let res = setFileTime(h, nil, nil, ft.addr)
|
||||||
|
discard h.closeHandle
|
||||||
|
if res == 0'i32: raiseOSError(osLastError())
|
||||||
|
|
@ -1001,12 +1001,20 @@ elif not defined(useNimRtl):
|
||||||
{.pop}
|
{.pop}
|
||||||
|
|
||||||
proc close(p: Process) =
|
proc close(p: Process) =
|
||||||
if p.inStream != nil: close(p.inStream)
|
|
||||||
if p.outStream != nil: close(p.outStream)
|
|
||||||
if p.errStream != nil: close(p.errStream)
|
|
||||||
if poParentStreams notin p.options:
|
if poParentStreams notin p.options:
|
||||||
|
if p.inStream != nil:
|
||||||
|
close(p.inStream)
|
||||||
|
else:
|
||||||
discard close(p.inHandle)
|
discard close(p.inHandle)
|
||||||
|
|
||||||
|
if p.outStream != nil:
|
||||||
|
close(p.outStream)
|
||||||
|
else:
|
||||||
discard close(p.outHandle)
|
discard close(p.outHandle)
|
||||||
|
|
||||||
|
if p.errStream != nil:
|
||||||
|
close(p.errStream)
|
||||||
|
else:
|
||||||
discard close(p.errHandle)
|
discard close(p.errHandle)
|
||||||
|
|
||||||
proc suspend(p: Process) =
|
proc suspend(p: Process) =
|
||||||
|
|
@ -1281,7 +1289,7 @@ elif not defined(useNimRtl):
|
||||||
|
|
||||||
proc select(readfds: var seq[Process], timeout = 500): int =
|
proc select(readfds: var seq[Process], timeout = 500): int =
|
||||||
var tv: Timeval
|
var tv: Timeval
|
||||||
tv.tv_sec = 0
|
tv.tv_sec = posix.Time(0)
|
||||||
tv.tv_usec = timeout * 1000
|
tv.tv_usec = timeout * 1000
|
||||||
|
|
||||||
var rd: TFdSet
|
var rd: TFdSet
|
||||||
|
|
|
||||||
|
|
@ -1647,11 +1647,15 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
|
||||||
let last = s.high
|
let last = s.high
|
||||||
var i = 0
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
var j = find(a, s, sub, i, last)
|
let j = find(a, s, sub, i, last)
|
||||||
if j < 0: break
|
if j < 0: break
|
||||||
add result, substr(s, i, j - 1)
|
add result, substr(s, i, j - 1)
|
||||||
add result, by
|
add result, by
|
||||||
i = j + len(sub)
|
if sub.len == 0:
|
||||||
|
if i < s.len: add result, s[i]
|
||||||
|
i = j + 1
|
||||||
|
else:
|
||||||
|
i = j + sub.len
|
||||||
# copy the rest:
|
# copy the rest:
|
||||||
add result, substr(s, i)
|
add result, substr(s, i)
|
||||||
|
|
||||||
|
|
@ -1680,6 +1684,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
|
||||||
initSkipTable(a, sub)
|
initSkipTable(a, sub)
|
||||||
var i = 0
|
var i = 0
|
||||||
let last = s.high
|
let last = s.high
|
||||||
|
let sublen = max(sub.len, 1)
|
||||||
while true:
|
while true:
|
||||||
var j = find(a, s, sub, i, last)
|
var j = find(a, s, sub, i, last)
|
||||||
if j < 0: break
|
if j < 0: break
|
||||||
|
|
@ -1688,7 +1693,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
|
||||||
(j+sub.len >= s.len or s[j+sub.len] notin wordChars):
|
(j+sub.len >= s.len or s[j+sub.len] notin wordChars):
|
||||||
add result, substr(s, i, j - 1)
|
add result, substr(s, i, j - 1)
|
||||||
add result, by
|
add result, by
|
||||||
i = j + len(sub)
|
i = j + sublen
|
||||||
else:
|
else:
|
||||||
add result, substr(s, i, j)
|
add result, substr(s, i, j)
|
||||||
i = j + 1
|
i = j + 1
|
||||||
|
|
@ -2546,6 +2551,9 @@ when isMainModule:
|
||||||
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
|
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
|
||||||
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
|
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
|
||||||
|
|
||||||
|
doAssert "-lda-ldz -ld abc".replaceWord("") == "lda-ldz ld abc"
|
||||||
|
doAssert "oo".replace("", "abc") == "abcoabcoabc"
|
||||||
|
|
||||||
type MyEnum = enum enA, enB, enC, enuD, enE
|
type MyEnum = enum enA, enB, enC, enuD, enE
|
||||||
doAssert parseEnum[MyEnum]("enu_D") == enuD
|
doAssert parseEnum[MyEnum]("enu_D") == enuD
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -557,8 +557,8 @@ proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) =
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
let h = conHandle(f)
|
let h = conHandle(f)
|
||||||
var old = getAttributes(h) and not FOREGROUND_RGB
|
var old = getAttributes(h) and not FOREGROUND_RGB
|
||||||
if bright:
|
old = if bright: old or FOREGROUND_INTENSITY
|
||||||
old = old or FOREGROUND_INTENSITY
|
else: old and not(FOREGROUND_INTENSITY)
|
||||||
const lookup: array[ForegroundColor, int] = [
|
const lookup: array[ForegroundColor, int] = [
|
||||||
0,
|
0,
|
||||||
(FOREGROUND_RED),
|
(FOREGROUND_RED),
|
||||||
|
|
@ -579,8 +579,8 @@ proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
let h = conHandle(f)
|
let h = conHandle(f)
|
||||||
var old = getAttributes(h) and not BACKGROUND_RGB
|
var old = getAttributes(h) and not BACKGROUND_RGB
|
||||||
if bright:
|
old = if bright: old or BACKGROUND_INTENSITY
|
||||||
old = old or BACKGROUND_INTENSITY
|
else: old and not(BACKGROUND_INTENSITY)
|
||||||
const lookup: array[BackgroundColor, int] = [
|
const lookup: array[BackgroundColor, int] = [
|
||||||
0,
|
0,
|
||||||
(BACKGROUND_RED),
|
(BACKGROUND_RED),
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,7 @@ const
|
||||||
secondsInHour = 60*60
|
secondsInHour = 60*60
|
||||||
secondsInDay = 60*60*24
|
secondsInDay = 60*60*24
|
||||||
minutesInHour = 60
|
minutesInHour = 60
|
||||||
|
rateDiff = 10000000'i64 # 100 nsecs
|
||||||
# The number of hectonanoseconds between 1601/01/01 (windows epoch)
|
# The number of hectonanoseconds between 1601/01/01 (windows epoch)
|
||||||
# and 1970/01/01 (unix epoch).
|
# and 1970/01/01 (unix epoch).
|
||||||
epochDiff = 116444736000000000'i64
|
epochDiff = 116444736000000000'i64
|
||||||
|
|
@ -352,7 +353,9 @@ proc `$`*(dur: Duration): string =
|
||||||
parts.add $quantity & " " & unitStrings[unit] & "s"
|
parts.add $quantity & " " & unitStrings[unit] & "s"
|
||||||
|
|
||||||
result = ""
|
result = ""
|
||||||
if parts.len == 1:
|
if parts.len == 0:
|
||||||
|
result.add "0 nanoseconds"
|
||||||
|
elif parts.len == 1:
|
||||||
result = parts[0]
|
result = parts[0]
|
||||||
elif parts.len == 2:
|
elif parts.len == 2:
|
||||||
result = parts[0] & " and " & parts[1]
|
result = parts[0] & " and " & parts[1]
|
||||||
|
|
@ -371,6 +374,21 @@ proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} =
|
||||||
## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``).
|
## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``).
|
||||||
t.seconds
|
t.seconds
|
||||||
|
|
||||||
|
proc fromWinTime*(win: int64): Time =
|
||||||
|
## Convert a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``)
|
||||||
|
## to a ``Time``.
|
||||||
|
let hnsecsSinceEpoch = (win - epochDiff)
|
||||||
|
var seconds = hnsecsSinceEpoch div rateDiff
|
||||||
|
var nanos = ((hnsecsSinceEpoch mod rateDiff) * 100).int
|
||||||
|
if nanos < 0:
|
||||||
|
nanos += convert(Seconds, Nanoseconds, 1)
|
||||||
|
seconds -= 1
|
||||||
|
result = initTime(seconds, nanos)
|
||||||
|
|
||||||
|
proc toWinTime*(t: Time): int64 =
|
||||||
|
## Convert ``t`` to a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``).
|
||||||
|
result = t.seconds * rateDiff + epochDiff + t.nanoseconds div 100
|
||||||
|
|
||||||
proc isLeapYear*(year: int): bool =
|
proc isLeapYear*(year: int): bool =
|
||||||
## Returns true if ``year`` is a leap year.
|
## Returns true if ``year`` is a leap year.
|
||||||
year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0)
|
year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0)
|
||||||
|
|
@ -853,10 +871,7 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} =
|
||||||
elif defined(windows):
|
elif defined(windows):
|
||||||
var f: FILETIME
|
var f: FILETIME
|
||||||
getSystemTimeAsFileTime(f)
|
getSystemTimeAsFileTime(f)
|
||||||
let nanosSinceEpoch = (rdFileTime(f) - epochDiff) * 100
|
result = fromWinTime(rdFileTime(f))
|
||||||
let seconds = convert(Nanoseconds, Seconds, nanosSinceEpoch)
|
|
||||||
let nanos = (nanosSinceEpoch mod convert(Seconds, Nanoseconds, 1)).int
|
|
||||||
result = initTime(seconds, nanos)
|
|
||||||
|
|
||||||
proc now*(): DateTime {.tags: [TimeEffect], benign.} =
|
proc now*(): DateTime {.tags: [TimeEffect], benign.} =
|
||||||
## Get the current time as a ``DateTime`` in the local timezone.
|
## Get the current time as a ``DateTime`` in the local timezone.
|
||||||
|
|
@ -1713,17 +1728,6 @@ when not defined(JS):
|
||||||
var
|
var
|
||||||
clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
|
clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
|
||||||
|
|
||||||
const
|
|
||||||
rateDiff = 10000000'i64 # 100 nsecs
|
|
||||||
|
|
||||||
proc unixTimeToWinTime*(time: CTime): int64 =
|
|
||||||
## converts a UNIX `Time` (``time_t``) to a Windows file time
|
|
||||||
result = int64(time) * rateDiff + epochDiff
|
|
||||||
|
|
||||||
proc winTimeToUnixTime*(time: int64): CTime =
|
|
||||||
## converts a Windows time to a UNIX `Time` (``time_t``)
|
|
||||||
result = CTime((time - epochDiff) div rateDiff)
|
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} =
|
proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} =
|
||||||
## gets time spent that the CPU spent to run the current process in
|
## gets time spent that the CPU spent to run the current process in
|
||||||
|
|
@ -1748,7 +1752,7 @@ when not defined(JS):
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
var a: Timeval
|
var a: Timeval
|
||||||
gettimeofday(a)
|
gettimeofday(a)
|
||||||
result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001
|
result = toBiggestFloat(a.tv_sec.int64) + toFloat(a.tv_usec)*0.00_0001
|
||||||
elif defined(windows):
|
elif defined(windows):
|
||||||
var f: winlean.FILETIME
|
var f: winlean.FILETIME
|
||||||
getSystemTimeAsFileTime(f)
|
getSystemTimeAsFileTime(f)
|
||||||
|
|
@ -1765,6 +1769,19 @@ when defined(JS):
|
||||||
|
|
||||||
# Deprecated procs
|
# Deprecated procs
|
||||||
|
|
||||||
|
when not defined(JS):
|
||||||
|
proc unixTimeToWinTime*(time: CTime): int64 {.deprecated: "Use toWinTime instead".} =
|
||||||
|
## Converts a UNIX `Time` (``time_t``) to a Windows file time
|
||||||
|
##
|
||||||
|
## **Deprecated:** use ``toWinTime`` instead.
|
||||||
|
result = int64(time) * rateDiff + epochDiff
|
||||||
|
|
||||||
|
proc winTimeToUnixTime*(time: int64): CTime {.deprecated: "Use fromWinTime instead".} =
|
||||||
|
## Converts a Windows time to a UNIX `Time` (``time_t``)
|
||||||
|
##
|
||||||
|
## **Deprecated:** use ``fromWinTime`` instead.
|
||||||
|
result = CTime((time - epochDiff) div rateDiff)
|
||||||
|
|
||||||
proc initInterval*(seconds, minutes, hours, days, months,
|
proc initInterval*(seconds, minutes, hours, days, months,
|
||||||
years: int = 0): TimeInterval {.deprecated.} =
|
years: int = 0): TimeInterval {.deprecated.} =
|
||||||
## **Deprecated since v0.18.0:** use ``initTimeInterval`` instead.
|
## **Deprecated since v0.18.0:** use ``initTimeInterval`` instead.
|
||||||
|
|
|
||||||
|
|
@ -2404,7 +2404,7 @@ proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
|
||||||
if x.isNil and y.isNil:
|
if x.isNil and y.isNil:
|
||||||
return true
|
return true
|
||||||
else:
|
else:
|
||||||
when not defined(JS) or defined(nimphp):
|
when not defined(JS):
|
||||||
proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} =
|
proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} =
|
||||||
result = cast[pointer](x)
|
result = cast[pointer](x)
|
||||||
else:
|
else:
|
||||||
|
|
@ -2766,9 +2766,6 @@ type
|
||||||
|
|
||||||
when defined(JS):
|
when defined(JS):
|
||||||
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
|
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """`x` .= `y`;"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var len = `x`[0].length-1;
|
var len = `x`[0].length-1;
|
||||||
for (var i = 0; i < `y`.length; ++i) {
|
for (var i = 0; i < `y`.length; ++i) {
|
||||||
|
|
@ -4139,17 +4136,18 @@ template doAssertRaises*(exception, code: untyped): typed =
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssertRaises(ValueError):
|
doAssertRaises(ValueError):
|
||||||
raise newException(ValueError, "Hello World")
|
raise newException(ValueError, "Hello World")
|
||||||
|
var wrong = false
|
||||||
try:
|
try:
|
||||||
block:
|
|
||||||
code
|
code
|
||||||
raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code))
|
wrong = true
|
||||||
except exception:
|
except exception:
|
||||||
discard
|
discard
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raiseAssert(astToStr(exception) &
|
raiseAssert(astToStr(exception) &
|
||||||
" wasn't raised, another error was raised instead by:\n"&
|
" wasn't raised, another error was raised instead by:\n"&
|
||||||
astToStr(code))
|
astToStr(code))
|
||||||
|
if wrong:
|
||||||
|
raiseAssert(astToStr(exception) & " wasn't raised by:\n" & astToStr(code))
|
||||||
|
|
||||||
when defined(cpp) and appType != "lib" and not defined(js) and
|
when defined(cpp) and appType != "lib" and not defined(js) and
|
||||||
not defined(nimscript) and hostOS != "standalone":
|
not defined(nimscript) and hostOS != "standalone":
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,12 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
|
||||||
GenericSeqSize),
|
GenericSeqSize),
|
||||||
mt.base, shallow)
|
mt.base, shallow)
|
||||||
of tyObject:
|
of tyObject:
|
||||||
if mt.base != nil:
|
var it = mt.base
|
||||||
genericAssignAux(dest, src, mt.base, shallow)
|
# don't use recursion here on the PNimType because the subtype
|
||||||
|
# check should only be done at the very end:
|
||||||
|
while it != nil:
|
||||||
|
genericAssignAux(dest, src, it.node, shallow)
|
||||||
|
it = it.base
|
||||||
genericAssignAux(dest, src, mt.node, shallow)
|
genericAssignAux(dest, src, mt.node, shallow)
|
||||||
# we need to copy m_type field for tyObject, as it could be empty for
|
# we need to copy m_type field for tyObject, as it could be empty for
|
||||||
# sequence reallocations:
|
# sequence reallocations:
|
||||||
|
|
@ -89,6 +93,8 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
|
||||||
# if p of TB:
|
# if p of TB:
|
||||||
# var tbObj = TB(p)
|
# var tbObj = TB(p)
|
||||||
# tbObj of TC # needs to be false!
|
# tbObj of TC # needs to be false!
|
||||||
|
#c_fprintf(stdout, "%s %s\n", pint[].name, mt.name)
|
||||||
|
chckObjAsgn(cast[ptr PNimType](src)[], mt)
|
||||||
pint[] = mt # cast[ptr PNimType](src)[]
|
pint[] = mt # cast[ptr PNimType](src)[]
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
genericAssignAux(dest, src, mt.node, shallow)
|
genericAssignAux(dest, src, mt.node, shallow)
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,6 @@ proc nimCharToStr(x: char): string {.compilerproc.} =
|
||||||
result[0] = x
|
result[0] = x
|
||||||
|
|
||||||
proc isNimException(): bool {.asmNoStackFrame.} =
|
proc isNimException(): bool {.asmNoStackFrame.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm "return isset(`lastJSError`['m_type']);"
|
|
||||||
else:
|
|
||||||
asm "return `lastJSError`.m_type;"
|
asm "return `lastJSError`.m_type;"
|
||||||
|
|
||||||
proc getCurrentException*(): ref Exception {.compilerRtl, benign.} =
|
proc getCurrentException*(): ref Exception {.compilerRtl, benign.} =
|
||||||
|
|
@ -61,7 +58,6 @@ proc getCurrentExceptionMsg*(): string =
|
||||||
if isNimException():
|
if isNimException():
|
||||||
return cast[Exception](lastJSError).msg
|
return cast[Exception](lastJSError).msg
|
||||||
else:
|
else:
|
||||||
when not defined(nimphp):
|
|
||||||
var msg: cstring
|
var msg: cstring
|
||||||
{.emit: """
|
{.emit: """
|
||||||
if (`lastJSError`.message !== undefined) {
|
if (`lastJSError`.message !== undefined) {
|
||||||
|
|
@ -140,9 +136,6 @@ proc raiseException(e: ref Exception, ename: cstring) {.
|
||||||
e.name = ename
|
e.name = ename
|
||||||
if excHandler == 0:
|
if excHandler == 0:
|
||||||
unhandledException(e)
|
unhandledException(e)
|
||||||
when defined(nimphp):
|
|
||||||
asm """throw new Exception($`e`["message"]);"""
|
|
||||||
else:
|
|
||||||
when NimStackTrace:
|
when NimStackTrace:
|
||||||
e.trace = rawWriteStackTrace()
|
e.trace = rawWriteStackTrace()
|
||||||
asm "throw `e`;"
|
asm "throw `e`;"
|
||||||
|
|
@ -173,22 +166,6 @@ proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
|
||||||
raise newException(FieldError, f & " is not accessible")
|
raise newException(FieldError, f & " is not accessible")
|
||||||
|
|
||||||
proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
|
proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
$args = func_get_args();
|
|
||||||
$result = array();
|
|
||||||
foreach ($args as $x) {
|
|
||||||
if (is_array($x)) {
|
|
||||||
for ($j = $x[0]; $j <= $x[1]; $j++) {
|
|
||||||
$result[$j] = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$result[$x] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = {};
|
var result = {};
|
||||||
for (var i = 0; i < arguments.length; ++i) {
|
for (var i = 0; i < arguments.length; ++i) {
|
||||||
|
|
@ -205,9 +182,6 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
{.emit: """return `c`;""".}
|
|
||||||
else:
|
|
||||||
{.emit: """
|
{.emit: """
|
||||||
var ln = `c`.length;
|
var ln = `c`.length;
|
||||||
var result = new Array(ln + 1);
|
var result = new Array(ln + 1);
|
||||||
|
|
@ -220,9 +194,6 @@ proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
||||||
""".}
|
""".}
|
||||||
|
|
||||||
proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
{.emit: """return `c`;""".}
|
|
||||||
else:
|
|
||||||
{.emit: """
|
{.emit: """
|
||||||
var ln = `c`.length;
|
var ln = `c`.length;
|
||||||
var result = new Array(ln);
|
var result = new Array(ln);
|
||||||
|
|
@ -261,9 +232,6 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
||||||
""".}
|
""".}
|
||||||
|
|
||||||
proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
|
proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
{.emit: """return `s`;""".}
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var len = `s`.length-1;
|
var len = `s`.length-1;
|
||||||
var asciiPart = new Array(len);
|
var asciiPart = new Array(len);
|
||||||
|
|
@ -295,11 +263,6 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
|
proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return str_repeat(chr(0),`len`);
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = new Array(`len`+1);
|
var result = new Array(`len`+1);
|
||||||
result[0] = 0;
|
result[0] = 0;
|
||||||
|
|
@ -307,24 +270,8 @@ proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
|
||||||
return result;
|
return result;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
when defined(nimphp):
|
|
||||||
proc nimAt(x: string; i: int): string {.asmNoStackFrame, compilerproc.} =
|
|
||||||
asm """
|
|
||||||
return `x`[`i`];
|
|
||||||
"""
|
|
||||||
|
|
||||||
when defined(nimphp):
|
|
||||||
proc nimSubstr(s: string; a, b: int): string {.
|
|
||||||
asmNoStackFrame, compilerproc.} =
|
|
||||||
asm """return substr(`s`,`a`,`b`-`a`+1);"""
|
|
||||||
|
|
||||||
proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
|
proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
|
||||||
# argument type is a fake
|
# argument type is a fake
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return count(`a`);
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = 0;
|
var result = 0;
|
||||||
for (var elem in `a`) { ++result; }
|
for (var elem in `a`) { ++result; }
|
||||||
|
|
@ -332,13 +279,6 @@ proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
|
proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
foreach (`a` as $elem=>$_) { if (!isset(`b`[$elem])) return false; }
|
|
||||||
foreach (`b` as $elem=>$_) { if (!isset(`a`[$elem])) return false; }
|
|
||||||
return true;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
for (var elem in `a`) { if (!`b`[elem]) return false; }
|
for (var elem in `a`) { if (!`b`[elem]) return false; }
|
||||||
for (var elem in `b`) { if (!`a`[elem]) return false; }
|
for (var elem in `b`) { if (!`a`[elem]) return false; }
|
||||||
|
|
@ -346,12 +286,6 @@ proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
|
proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
foreach (`a` as $elem=>$_) { if (!isset(`b`[$elem])) return false; }
|
|
||||||
return true;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
for (var elem in `a`) { if (!`b`[elem]) return false; }
|
for (var elem in `a`) { if (!`b`[elem]) return false; }
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -361,15 +295,6 @@ proc SetLt(a, b: int): bool {.compilerproc.} =
|
||||||
result = SetLe(a, b) and not SetEq(a, b)
|
result = SetLe(a, b) and not SetEq(a, b)
|
||||||
|
|
||||||
proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} =
|
proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
var $result = array();
|
|
||||||
foreach (`a` as $elem=>$_) {
|
|
||||||
if (isset(`b`[$elem])) { $result[$elem] = true; }
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = {};
|
var result = {};
|
||||||
for (var elem in `a`) {
|
for (var elem in `a`) {
|
||||||
|
|
@ -379,14 +304,6 @@ proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
|
proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
var $result = array();
|
|
||||||
foreach (`a` as $elem=>$_) { $result[$elem] = true; }
|
|
||||||
foreach (`b` as $elem=>$_) { $result[$elem] = true; }
|
|
||||||
return $result;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = {};
|
var result = {};
|
||||||
for (var elem in `a`) { result[elem] = true; }
|
for (var elem in `a`) { result[elem] = true; }
|
||||||
|
|
@ -395,15 +312,6 @@ proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
|
proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
$result = array();
|
|
||||||
foreach (`a` as $elem=>$_) {
|
|
||||||
if (!isset(`b`[$elem])) { $result[$elem] = true; }
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = {};
|
var result = {};
|
||||||
for (var elem in `a`) {
|
for (var elem in `a`) {
|
||||||
|
|
@ -425,13 +333,6 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc cmp(x, y: string): int =
|
proc cmp(x, y: string): int =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
if(`x` < `y`) `result` = -1;
|
|
||||||
elseif (`x` > `y`) `result` = 1;
|
|
||||||
else `result` = 0;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
return cmpStrings(x, y)
|
return cmpStrings(x, y)
|
||||||
|
|
||||||
proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} =
|
proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} =
|
||||||
|
|
@ -467,7 +368,7 @@ elif not defined(nimOldEcho):
|
||||||
console.log(buf);
|
console.log(buf);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
elif not defined(nimphp):
|
else:
|
||||||
proc ewriteln(x: cstring) =
|
proc ewriteln(x: cstring) =
|
||||||
var node : JSRef
|
var node : JSRef
|
||||||
{.emit: "`node` = document.getElementsByTagName('body')[0];".}
|
{.emit: "`node` = document.getElementsByTagName('body')[0];".}
|
||||||
|
|
@ -493,11 +394,6 @@ elif not defined(nimphp):
|
||||||
|
|
||||||
# Arithmetic:
|
# Arithmetic:
|
||||||
proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return `a` + `b`;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = `a` + `b`;
|
var result = `a` + `b`;
|
||||||
if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
|
if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
|
||||||
|
|
@ -505,11 +401,6 @@ proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return `a` - `b`;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = `a` - `b`;
|
var result = `a` - `b`;
|
||||||
if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
|
if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
|
||||||
|
|
@ -517,11 +408,6 @@ proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return `a` * `b`;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = `a` * `b`;
|
var result = `a` * `b`;
|
||||||
if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
|
if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
|
||||||
|
|
@ -529,11 +415,6 @@ proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return trunc(`a` / `b`);
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
if (`b` == 0) `raiseDivByZero`();
|
if (`b` == 0) `raiseDivByZero`();
|
||||||
if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
|
if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
|
||||||
|
|
@ -541,11 +422,6 @@ proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return `a` % `b`;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
if (`b` == 0) `raiseDivByZero`();
|
if (`b` == 0) `raiseDivByZero`();
|
||||||
if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
|
if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
|
||||||
|
|
@ -553,11 +429,6 @@ proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return `a` + `b`;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = `a` + `b`;
|
var result = `a` + `b`;
|
||||||
if (result > 9223372036854775807
|
if (result > 9223372036854775807
|
||||||
|
|
@ -566,11 +437,6 @@ proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return `a` - `b`;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = `a` - `b`;
|
var result = `a` - `b`;
|
||||||
if (result > 9223372036854775807
|
if (result > 9223372036854775807
|
||||||
|
|
@ -579,11 +445,6 @@ proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return `a` * `b`;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
var result = `a` * `b`;
|
var result = `a` * `b`;
|
||||||
if (result > 9223372036854775807
|
if (result > 9223372036854775807
|
||||||
|
|
@ -592,11 +453,6 @@ proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return trunc(`a` / `b`);
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
if (`b` == 0) `raiseDivByZero`();
|
if (`b` == 0) `raiseDivByZero`();
|
||||||
if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
|
if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
|
||||||
|
|
@ -604,11 +460,6 @@ proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
|
||||||
when defined(nimphp):
|
|
||||||
asm """
|
|
||||||
return `a` % `b`;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
asm """
|
asm """
|
||||||
if (`b` == 0) `raiseDivByZero`();
|
if (`b` == 0) `raiseDivByZero`();
|
||||||
if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
|
if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
|
||||||
|
|
@ -767,16 +618,6 @@ proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} =
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
when defined(nimphp):
|
|
||||||
proc arrayConstr(len: int, value: string, typ: string): JSRef {.
|
|
||||||
asmNoStackFrame, compilerproc.} =
|
|
||||||
# types are fake
|
|
||||||
asm """
|
|
||||||
$result = array();
|
|
||||||
for ($i = 0; $i < `len`; $i++) $result[] = `value`;
|
|
||||||
return $result;
|
|
||||||
"""
|
|
||||||
else:
|
|
||||||
proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {.
|
proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {.
|
||||||
asmNoStackFrame, compilerproc.} =
|
asmNoStackFrame, compilerproc.} =
|
||||||
# types are fake
|
# types are fake
|
||||||
|
|
|
||||||
|
|
@ -1086,3 +1086,14 @@ proc ConvertThreadToFiberEx*(param: pointer, flags: int32): pointer {.stdcall, d
|
||||||
proc DeleteFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.}
|
proc DeleteFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.}
|
||||||
proc SwitchToFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.}
|
proc SwitchToFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.}
|
||||||
proc GetCurrentFiber*(): pointer {.stdcall, importc, header: "Windows.h".}
|
proc GetCurrentFiber*(): pointer {.stdcall, importc, header: "Windows.h".}
|
||||||
|
|
||||||
|
proc toFILETIME*(t: int64): FILETIME =
|
||||||
|
## Convert the Windows file time timestamp ``t`` to ``FILETIME``.
|
||||||
|
result = FILETIME(dwLowDateTime: cast[DWORD](t), dwHighDateTime: DWORD(t shr 32))
|
||||||
|
|
||||||
|
type
|
||||||
|
LPFILETIME* = ptr FILETIME
|
||||||
|
|
||||||
|
proc setFileTime*(hFile: HANDLE, lpCreationTime: LPFILETIME,
|
||||||
|
lpLastAccessTime: LPFILETIME, lpLastWriteTime: LPFILETIME): WINBOOL
|
||||||
|
{.stdcall, dynlib: "kernel32", importc: "SetFileTime".}
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,8 @@ cat
|
||||||
cat
|
cat
|
||||||
dog
|
dog
|
||||||
dog
|
dog
|
||||||
dog value
|
|
||||||
cat value
|
|
||||||
dog value
|
|
||||||
cat value
|
|
||||||
dog
|
dog
|
||||||
dog
|
dog
|
||||||
dog value
|
|
||||||
cat value
|
|
||||||
dog 1
|
dog 1
|
||||||
dog 2
|
dog 2
|
||||||
'''
|
'''
|
||||||
|
|
@ -243,6 +237,7 @@ reject modifiesCovariantArray(dogRefsArray.addr)
|
||||||
|
|
||||||
var dogValues = @[vdog, vdog]
|
var dogValues = @[vdog, vdog]
|
||||||
var dogValuesArray = [vdog, vdog]
|
var dogValuesArray = [vdog, vdog]
|
||||||
|
when false:
|
||||||
var animalValues = @[Animal(vdog), Animal(vcat)]
|
var animalValues = @[Animal(vdog), Animal(vcat)]
|
||||||
var animalValuesArray = [Animal(vdog), Animal(vcat)]
|
var animalValuesArray = [Animal(vdog), Animal(vcat)]
|
||||||
|
|
||||||
|
|
@ -260,7 +255,6 @@ modifiesDerivedOperArray dogRefs
|
||||||
reject modifiesDerivedOperArray(dogValues)
|
reject modifiesDerivedOperArray(dogValues)
|
||||||
reject modifiesDerivedOperArray(animalRefs)
|
reject modifiesDerivedOperArray(animalRefs)
|
||||||
|
|
||||||
wantsNonCovariantOperArray animalValues
|
|
||||||
reject wantsNonCovariantOperArray(animalRefs)
|
reject wantsNonCovariantOperArray(animalRefs)
|
||||||
reject wantsNonCovariantOperArray(dogRefs)
|
reject wantsNonCovariantOperArray(dogRefs)
|
||||||
reject wantsNonCovariantOperArray(dogValues)
|
reject wantsNonCovariantOperArray(dogValues)
|
||||||
|
|
|
||||||
11
tests/errmsgs/t1154.nim
Normal file
11
tests/errmsgs/t1154.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "invalid type: 'expr' in this context: 'proc (a: varargs[expr])' for proc"
|
||||||
|
line: 8
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typetraits
|
||||||
|
|
||||||
|
proc foo(a:varargs[expr]) =
|
||||||
|
echo a[0].type.name
|
||||||
|
|
||||||
|
foo(1)
|
||||||
9
tests/errmsgs/tcant_overload_by_return_type.nim
Normal file
9
tests/errmsgs/tcant_overload_by_return_type.nim
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
discard """
|
||||||
|
errormsg: "overloaded 'x' leads to ambiguous calls"
|
||||||
|
line: 9
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #6393
|
||||||
|
|
||||||
|
proc x(): int = 7
|
||||||
|
proc x(): string = "strange"
|
||||||
|
|
@ -27,11 +27,19 @@ import strutils
|
||||||
template assertNot(arg: untyped): untyped =
|
template assertNot(arg: untyped): untyped =
|
||||||
assert(not(arg))
|
assert(not(arg))
|
||||||
|
|
||||||
|
|
||||||
|
proc foo(arg: int): void =
|
||||||
|
discard
|
||||||
|
|
||||||
|
proc foo(arg: float): void =
|
||||||
|
discard
|
||||||
|
|
||||||
static:
|
static:
|
||||||
## test eqIdent
|
## test eqIdent
|
||||||
let a = "abc_def"
|
let a = "abc_def"
|
||||||
let b = "abcDef"
|
let b = "abcDef"
|
||||||
let c = "AbcDef"
|
let c = "AbcDef"
|
||||||
|
let d = nnkBracketExpr.newTree() # not an identifier at all
|
||||||
|
|
||||||
assert eqIdent( a , b )
|
assert eqIdent( a , b )
|
||||||
assert eqIdent(newIdentNode(a), b )
|
assert eqIdent(newIdentNode(a), b )
|
||||||
|
|
@ -62,3 +70,12 @@ static:
|
||||||
assertNot eqIdent(genSym(nskLet, c), newIdentNode( b))
|
assertNot eqIdent(genSym(nskLet, c), newIdentNode( b))
|
||||||
assertNot eqIdent(newIdentNode( c), genSym(nskLet, b))
|
assertNot eqIdent(newIdentNode( c), genSym(nskLet, b))
|
||||||
assertNot eqIdent(genSym(nskLet, c), genSym(nskLet, b))
|
assertNot eqIdent(genSym(nskLet, c), genSym(nskLet, b))
|
||||||
|
|
||||||
|
# eqIdent on non identifier at all
|
||||||
|
assertNot eqIdent(a,d)
|
||||||
|
|
||||||
|
# eqIdent on sym choice
|
||||||
|
let fooSym = bindSym"foo"
|
||||||
|
assert fooSym.kind in {nnkOpenSymChoice, nnkClosedSymChoice}
|
||||||
|
assert fooSym.eqIdent("fOO")
|
||||||
|
assertNot fooSym.eqIdent("bar")
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''tbObj of TC false
|
output: '''tbObj of TC true
|
||||||
false
|
|
||||||
true
|
true
|
||||||
5
|
5'''
|
||||||
false'''
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# bug #1053
|
# bug #1053
|
||||||
|
|
@ -20,10 +18,10 @@ type
|
||||||
proc test(p: TA) =
|
proc test(p: TA) =
|
||||||
#echo "p of TB ", p of TB
|
#echo "p of TB ", p of TB
|
||||||
if p of TB:
|
if p of TB:
|
||||||
var tbObj = TB(p)
|
#var tbObj = TB(p)
|
||||||
|
|
||||||
# tbObj is actually no longer compatible with TC:
|
# tbObj is actually no longer compatible with TC:
|
||||||
echo "tbObj of TC ", tbObj of TC
|
echo "tbObj of TC ", p of TC
|
||||||
|
|
||||||
var v = TC()
|
var v = TC()
|
||||||
v.a = 1
|
v.a = 1
|
||||||
|
|
@ -48,8 +46,8 @@ proc isMyObject(obj: TObject) =
|
||||||
|
|
||||||
asd.x = 5
|
asd.x = 5
|
||||||
|
|
||||||
var asdCopy = TObject(asd)
|
#var asdCopy = TObject(asd)
|
||||||
echo asdCopy of MyObject
|
#echo asdCopy of MyObject
|
||||||
|
|
||||||
isMyObject(asd)
|
isMyObject(asd)
|
||||||
isMyObject(asdCopy)
|
#isMyObject(asdCopy)
|
||||||
|
|
|
||||||
24
tests/objects/tobj_asgn_dont_slice.nim
Normal file
24
tests/objects/tobj_asgn_dont_slice.nim
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
discard """
|
||||||
|
outputsub: '''ObjectAssignmentError'''
|
||||||
|
exitcode: "1"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #7637
|
||||||
|
type
|
||||||
|
Fruit = object of RootObj
|
||||||
|
name*: string
|
||||||
|
Apple = object of Fruit
|
||||||
|
Pear = object of Fruit
|
||||||
|
|
||||||
|
method eat(f: Fruit) {.base.} =
|
||||||
|
raise newException(Exception, "PURE VIRTUAL CALL")
|
||||||
|
|
||||||
|
method eat(f: Apple) =
|
||||||
|
echo "fruity"
|
||||||
|
|
||||||
|
method eat(f: Pear) =
|
||||||
|
echo "juicy"
|
||||||
|
|
||||||
|
let basket = [Apple(name:"a"), Pear(name:"b")]
|
||||||
|
|
||||||
|
eat(basket[0])
|
||||||
|
|
@ -9,8 +9,8 @@ discard """
|
||||||
(k: kindA, a: (x: "abc", z: [1, 8, 3]), method: ())
|
(k: kindA, a: (x: "abc", z: [1, 8, 3]), method: ())
|
||||||
(k: kindA, a: (x: "abc", z: [1, 9, 3]), method: ())
|
(k: kindA, a: (x: "abc", z: [1, 9, 3]), method: ())
|
||||||
(k: kindA, a: (x: "abc", z: [1, 10, 3]), method: ())
|
(k: kindA, a: (x: "abc", z: [1, 10, 3]), method: ())
|
||||||
(x: 123)
|
(y: 0, x: 123)
|
||||||
(x: 123)
|
(y: 678, x: 123)
|
||||||
(z: 89, y: 0, x: 128)
|
(z: 89, y: 0, x: 128)
|
||||||
(y: 678, x: 123)
|
(y: 678, x: 123)
|
||||||
(y: 678, x: 123)
|
(y: 678, x: 123)
|
||||||
|
|
@ -33,7 +33,6 @@ type
|
||||||
`method`: TEmpty # bug #1791
|
`method`: TEmpty # bug #1791
|
||||||
|
|
||||||
proc `$`[T](s: seq[T]): string =
|
proc `$`[T](s: seq[T]): string =
|
||||||
# XXX why is that not in the stdlib?
|
|
||||||
result = "["
|
result = "["
|
||||||
for i, x in s:
|
for i, x in s:
|
||||||
if i > 0: result.add(", ")
|
if i > 0: result.add(", ")
|
||||||
|
|
@ -59,7 +58,7 @@ type
|
||||||
# inherited fields are ignored, so no fields are set
|
# inherited fields are ignored, so no fields are set
|
||||||
when true:
|
when true:
|
||||||
var
|
var
|
||||||
o: A
|
o: B
|
||||||
o = B(x: 123)
|
o = B(x: 123)
|
||||||
echo o
|
echo o
|
||||||
o = B(y: 678, x: 123)
|
o = B(y: 678, x: 123)
|
||||||
|
|
|
||||||
24
tests/osproc/tclose.nim
Normal file
24
tests/osproc/tclose.nim
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
discard """
|
||||||
|
exitcode: 0
|
||||||
|
"""
|
||||||
|
|
||||||
|
when defined(linux):
|
||||||
|
import osproc, os
|
||||||
|
|
||||||
|
proc countFds(): int =
|
||||||
|
result = 0
|
||||||
|
for i in walkDir("/proc/self/fd"):
|
||||||
|
result += 1
|
||||||
|
|
||||||
|
let initCount = countFds()
|
||||||
|
|
||||||
|
let p = osproc.startProcess("echo", options={poUsePath})
|
||||||
|
assert countFds() == initCount + 3
|
||||||
|
p.close
|
||||||
|
assert countFds() == initCount
|
||||||
|
|
||||||
|
let p1 = osproc.startProcess("echo", options={poUsePath})
|
||||||
|
discard p1.inputStream
|
||||||
|
assert countFds() == initCount + 3
|
||||||
|
p.close
|
||||||
|
assert countFds() == initCount
|
||||||
|
|
@ -11,7 +11,7 @@ proc parseInt(x: float): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: bool): int {.noSideEffect.} = discard
|
proc parseInt(x: bool): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: float32): int {.noSideEffect.} = discard
|
proc parseInt(x: float32): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: int8): int {.noSideEffect.} = discard
|
proc parseInt(x: int8): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: TFile): int {.noSideEffect.} = discard
|
proc parseInt(x: File): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: char): int {.noSideEffect.} = discard
|
proc parseInt(x: char): int {.noSideEffect.} = discard
|
||||||
proc parseInt(x: int16): int {.noSideEffect.} = discard
|
proc parseInt(x: int16): int {.noSideEffect.} = discard
|
||||||
|
|
||||||
|
|
|
||||||
35
tests/parallel/twaitany.nim
Normal file
35
tests/parallel/twaitany.nim
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
discard """
|
||||||
|
output: '''true'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #7638
|
||||||
|
import threadpool, os, strformat
|
||||||
|
|
||||||
|
proc timer(d: int): int =
|
||||||
|
#echo fmt"sleeping {d}"
|
||||||
|
sleep(d)
|
||||||
|
#echo fmt"done {d}"
|
||||||
|
return d
|
||||||
|
|
||||||
|
var durations = [1000, 2000, 3000, 4000, 5000]
|
||||||
|
var tasks: seq[FlowVarBase] = @[]
|
||||||
|
var results: seq[int] = @[]
|
||||||
|
|
||||||
|
for i in 0 .. durations.high:
|
||||||
|
tasks.add spawn timer(durations[i])
|
||||||
|
|
||||||
|
var index = awaitAny(tasks)
|
||||||
|
while index != -1:
|
||||||
|
results.add ^cast[FlowVar[int]](tasks[index])
|
||||||
|
tasks.del(index)
|
||||||
|
#echo repr results
|
||||||
|
index = awaitAny(tasks)
|
||||||
|
|
||||||
|
doAssert results.len == 5
|
||||||
|
doAssert 1000 in results
|
||||||
|
doAssert 2000 in results
|
||||||
|
doAssert 3000 in results
|
||||||
|
doAssert 4000 in results
|
||||||
|
doAssert 5000 in results
|
||||||
|
sync()
|
||||||
|
echo "true"
|
||||||
|
|
@ -51,6 +51,9 @@ block: # A bit more advanced case
|
||||||
|
|
||||||
static: assert(hasCustomPragma(myproc, alternativeKey))
|
static: assert(hasCustomPragma(myproc, alternativeKey))
|
||||||
|
|
||||||
|
const hasFieldCustomPragma = s.field.hasCustomPragma(defaultValue)
|
||||||
|
static: assert(hasFieldCustomPragma == false)
|
||||||
|
|
||||||
# pragma on an object
|
# pragma on an object
|
||||||
static:
|
static:
|
||||||
assert Subfield.hasCustomPragma(defaultValue)
|
assert Subfield.hasCustomPragma(defaultValue)
|
||||||
|
|
@ -71,6 +74,8 @@ block: # ref types
|
||||||
MyFile {.defaultValue: "closed".} = ref object
|
MyFile {.defaultValue: "closed".} = ref object
|
||||||
path {.defaultValue: "invalid".}: string
|
path {.defaultValue: "invalid".}: string
|
||||||
|
|
||||||
|
TypeWithoutPragma = object
|
||||||
|
|
||||||
var s = NodeRef()
|
var s = NodeRef()
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -91,7 +96,7 @@ block: # ref types
|
||||||
|
|
||||||
var ptrS = NodePtr(nil)
|
var ptrS = NodePtr(nil)
|
||||||
const
|
const
|
||||||
ptrRightSerKey = getCustomPragmaVal(s.right, serializationKey)
|
ptrRightSerKey = getCustomPragmaVal(ptrS.right, serializationKey)
|
||||||
static:
|
static:
|
||||||
assert ptrRightSerKey == "r"
|
assert ptrRightSerKey == "r"
|
||||||
|
|
||||||
|
|
@ -103,6 +108,9 @@ block: # ref types
|
||||||
assert fileDefVal == "closed"
|
assert fileDefVal == "closed"
|
||||||
assert filePathDefVal == "invalid"
|
assert filePathDefVal == "invalid"
|
||||||
|
|
||||||
|
static:
|
||||||
|
assert TypeWithoutPragma.hasCustomPragma(defaultValue) == false
|
||||||
|
|
||||||
block:
|
block:
|
||||||
type
|
type
|
||||||
VariantKind = enum
|
VariantKind = enum
|
||||||
|
|
|
||||||
|
|
@ -410,3 +410,10 @@ suite "ttimes":
|
||||||
let day = 24.hours
|
let day = 24.hours
|
||||||
let tomorrow = now + day
|
let tomorrow = now + day
|
||||||
check tomorrow - now == initDuration(days = 1)
|
check tomorrow - now == initDuration(days = 1)
|
||||||
|
|
||||||
|
test "fromWinTime/toWinTime":
|
||||||
|
check 0.fromUnix.toWinTime.fromWinTime.toUnix == 0
|
||||||
|
check (-1).fromWinTime.nanoseconds == convert(Seconds, Nanoseconds, 1) - 100
|
||||||
|
check -1.fromWinTime.toWinTime == -1
|
||||||
|
# One nanosecond is discarded due to differences in time resolution
|
||||||
|
check initTime(0, 101).toWinTime.fromWinTime.nanoseconds == 100
|
||||||
1
tests/template/i2416.nim
Normal file
1
tests/template/i2416.nim
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
template i2416*() = echo "i2416"
|
||||||
2
tests/template/t2416.nim
Normal file
2
tests/template/t2416.nim
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
import i2416
|
||||||
|
i2416()
|
||||||
9
tests/varres/tnewseq_on_result_vart.nim
Normal file
9
tests/varres/tnewseq_on_result_vart.nim
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
discard """
|
||||||
|
line: 9
|
||||||
|
errormsg: "address of 'result' may not escape its stack frame"
|
||||||
|
"""
|
||||||
|
# bug #5113
|
||||||
|
|
||||||
|
proc makeSeqVar(size: Natural): var seq[int] =
|
||||||
|
newSeq(result, size)
|
||||||
|
|
@ -24,7 +24,7 @@ const
|
||||||
Usage:
|
Usage:
|
||||||
nimpretty [options] file.nim
|
nimpretty [options] file.nim
|
||||||
Options:
|
Options:
|
||||||
--backup:ON|OFF create a backup file before overwritting (default: ON)
|
--backup:on|off create a backup file before overwritting (default: ON)
|
||||||
--version show the version
|
--version show the version
|
||||||
--help show this help
|
--help show this help
|
||||||
"""
|
"""
|
||||||
|
|
@ -43,7 +43,7 @@ proc prettyPrint(infile: string) =
|
||||||
let fileIdx = fileInfoIdx(infile)
|
let fileIdx = fileInfoIdx(infile)
|
||||||
let tree = parseFile(fileIdx, newIdentCache())
|
let tree = parseFile(fileIdx, newIdentCache())
|
||||||
let outfile = changeFileExt(infile, ".pretty.nim")
|
let outfile = changeFileExt(infile, ".pretty.nim")
|
||||||
renderModule(tree, infile, outfile, {})
|
renderModule(tree, infile, outfile, {}, fileIdx)
|
||||||
|
|
||||||
proc main =
|
proc main =
|
||||||
var infile: string
|
var infile: string
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ file: ticker.html
|
||||||
[Documentation]
|
[Documentation]
|
||||||
doc: "endb.rst;intern.txt;apis.txt;lib.rst;manual.rst;tut1.rst;tut2.rst;nimc.rst;overview.rst;filters.rst"
|
doc: "endb.rst;intern.txt;apis.txt;lib.rst;manual.rst;tut1.rst;tut2.rst;nimc.rst;overview.rst;filters.rst"
|
||||||
doc: "tools.txt;niminst.rst;nimgrep.rst;gc.rst;estp.rst;idetools.rst;docgen.rst;koch.rst;backends.txt"
|
doc: "tools.txt;niminst.rst;nimgrep.rst;gc.rst;estp.rst;idetools.rst;docgen.rst;koch.rst;backends.txt"
|
||||||
doc: "nimfix.rst;nimsuggest.rst;nep1.rst;nims.rst;contributing.rst"
|
doc: "nimfix.rst;nimsuggest.rst;nep1.rst;nims.rst;contributing.rst;manual/*.rst"
|
||||||
pdf: "manual.rst;lib.rst;tut1.rst;tut2.rst;nimc.rst;niminst.rst;gc.rst"
|
pdf: "manual.rst;lib.rst;tut1.rst;tut2.rst;nimc.rst;niminst.rst;gc.rst"
|
||||||
srcdoc2: "system.nim;system/nimscript;pure/ospaths"
|
srcdoc2: "system.nim;system/nimscript;pure/ospaths"
|
||||||
srcdoc2: "core/macros;pure/marshal;core/typeinfo"
|
srcdoc2: "core/macros;pure/marshal;core/typeinfo"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue