Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
This commit is contained in:
commit
826d529256
26 changed files with 778 additions and 228 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -291,6 +291,8 @@ const
|
||||||
|
|
||||||
sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
|
sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
|
||||||
# require RC ops
|
# require RC ops
|
||||||
|
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
|
||||||
|
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
|
||||||
|
|
||||||
const
|
const
|
||||||
# getting ready for the future expr/stmt merge
|
# getting ready for the future expr/stmt merge
|
||||||
|
|
@ -476,7 +478,7 @@ type
|
||||||
# and first phase symbol lookup in generics
|
# and first phase symbol lookup in generics
|
||||||
skConditional, # symbol for the preprocessor (may become obsolete)
|
skConditional, # symbol for the preprocessor (may become obsolete)
|
||||||
skDynLib, # symbol represents a dynamic library; this is used
|
skDynLib, # symbol represents a dynamic library; this is used
|
||||||
# internally; it does not exist in Nimrod code
|
# internally; it does not exist in Nim code
|
||||||
skParam, # a parameter
|
skParam, # a parameter
|
||||||
skGenericParam, # a generic parameter; eq in ``proc x[eq=`==`]()``
|
skGenericParam, # a generic parameter; eq in ``proc x[eq=`==`]()``
|
||||||
skTemp, # a temporary variable (introduced by compiler)
|
skTemp, # a temporary variable (introduced by compiler)
|
||||||
|
|
@ -501,7 +503,8 @@ type
|
||||||
skStub, # symbol is a stub and not yet loaded from the ROD
|
skStub, # symbol is a stub and not yet loaded from the ROD
|
||||||
# file (it is loaded on demand, which may
|
# file (it is loaded on demand, which may
|
||||||
# mean: never)
|
# mean: never)
|
||||||
skPackage # symbol is a package (used for canonicalization)
|
skPackage, # symbol is a package (used for canonicalization)
|
||||||
|
skAlias # an alias (needs to be resolved immediately)
|
||||||
TSymKinds* = set[TSymKind]
|
TSymKinds* = set[TSymKind]
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -678,7 +681,7 @@ type
|
||||||
heapRoot*: PRope # keeps track of the enclosing heap object that
|
heapRoot*: PRope # keeps track of the enclosing heap object that
|
||||||
# owns this location (required by GC algorithms
|
# owns this location (required by GC algorithms
|
||||||
# employing heap snapshots or sliding views)
|
# employing heap snapshots or sliding views)
|
||||||
a*: int # location's "address", i.e. slot for temporaries
|
a*: int
|
||||||
|
|
||||||
# ---------------- end of backend information ------------------------------
|
# ---------------- end of backend information ------------------------------
|
||||||
|
|
||||||
|
|
@ -731,8 +734,9 @@ type
|
||||||
# check for the owner when touching 'usedGenerics'.
|
# check for the owner when touching 'usedGenerics'.
|
||||||
usedGenerics*: seq[PInstantiation]
|
usedGenerics*: seq[PInstantiation]
|
||||||
tab*: TStrTable # interface table for modules
|
tab*: TStrTable # interface table for modules
|
||||||
|
of skLet, skVar, skField:
|
||||||
|
guard*: PSym
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
magic*: TMagic
|
magic*: TMagic
|
||||||
typ*: PType
|
typ*: PType
|
||||||
name*: PIdent
|
name*: PIdent
|
||||||
|
|
@ -872,7 +876,7 @@ const
|
||||||
tyProc, tyString, tyError}
|
tyProc, tyString, tyError}
|
||||||
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
|
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
|
||||||
skIterator, skClosureIterator,
|
skIterator, skClosureIterator,
|
||||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
|
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
||||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
|
||||||
nfDotSetter, nfDotField,
|
nfDotSetter, nfDotField,
|
||||||
nfIsRef}
|
nfIsRef}
|
||||||
|
|
@ -1162,7 +1166,6 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
|
||||||
result.sons = @[name, pattern, genericParams, params,
|
result.sons = @[name, pattern, genericParams, params,
|
||||||
pragmas, exceptions, body]
|
pragmas, exceptions, body]
|
||||||
|
|
||||||
|
|
||||||
proc newType(kind: TTypeKind, owner: PSym): PType =
|
proc newType(kind: TTypeKind, owner: PSym): PType =
|
||||||
new(result)
|
new(result)
|
||||||
result.kind = kind
|
result.kind = kind
|
||||||
|
|
@ -1172,8 +1175,8 @@ proc newType(kind: TTypeKind, owner: PSym): PType =
|
||||||
result.id = getID()
|
result.id = getID()
|
||||||
when debugIds:
|
when debugIds:
|
||||||
registerId(result)
|
registerId(result)
|
||||||
#if result.id < 2000 then
|
#if result.id < 2000:
|
||||||
# MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
# messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
||||||
|
|
||||||
proc mergeLoc(a: var TLoc, b: TLoc) =
|
proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||||
if a.k == low(a.k): a.k = b.k
|
if a.k == low(a.k): a.k = b.k
|
||||||
|
|
@ -1229,6 +1232,8 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
|
||||||
result.position = s.position
|
result.position = s.position
|
||||||
result.loc = s.loc
|
result.loc = s.loc
|
||||||
result.annex = s.annex # BUGFIX
|
result.annex = s.annex # BUGFIX
|
||||||
|
if result.kind in {skVar, skLet, skField}:
|
||||||
|
result.guard = s.guard
|
||||||
|
|
||||||
proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
|
proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
|
||||||
result = newSym(s.kind, newIdent, s.owner, info)
|
result = newSym(s.kind, newIdent, s.owner, info)
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,10 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||||
if sfCompileTime in v.flags: return
|
if sfCompileTime in v.flags: return
|
||||||
var targetProc = p
|
var targetProc = p
|
||||||
if sfGlobal in v.flags:
|
if sfGlobal in v.flags:
|
||||||
|
if v.flags * {sfImportc, sfExportc} == {sfImportc} and
|
||||||
|
a.sons[2].kind == nkEmpty and
|
||||||
|
v.loc.flags * {lfHeader, lfNoDecl} != {}:
|
||||||
|
return
|
||||||
if sfPure in v.flags:
|
if sfPure in v.flags:
|
||||||
# v.owner.kind != skModule:
|
# v.owner.kind != skModule:
|
||||||
targetProc = p.module.preInitProc
|
targetProc = p.module.preInitProc
|
||||||
|
|
@ -828,7 +832,14 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||||
discard cgsym(p.module, "E_Base")
|
discard cgsym(p.module, "E_Base")
|
||||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
||||||
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
||||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
if isDefined("nimStdSetjmp"):
|
||||||
|
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||||
|
elif isDefined("nimSigSetjmp"):
|
||||||
|
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
|
||||||
|
elif isDefined("nimRawSetjmp"):
|
||||||
|
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
|
||||||
|
else:
|
||||||
|
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||||
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||||
var length = sonsLen(t)
|
var length = sonsLen(t)
|
||||||
add(p.nestedTryStmts, t)
|
add(p.nestedTryStmts, t)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import
|
||||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||||
options, intsets,
|
options, intsets,
|
||||||
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
||||||
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
|
||||||
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
|
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
|
||||||
semparallel
|
semparallel
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,9 +80,9 @@ proc writeVersionInfo(pass: TCmdLinePass) =
|
||||||
platform.OS[platform.hostOS].name,
|
platform.OS[platform.hostOS].name,
|
||||||
CPU[platform.hostCPU].name]))
|
CPU[platform.hostCPU].name]))
|
||||||
|
|
||||||
const gitHash = gorge("git log -n 1 --format=%H")
|
discard """const gitHash = gorge("git log -n 1 --format=%H")
|
||||||
if gitHash.strip.len == 40:
|
if gitHash.strip.len == 40:
|
||||||
msgWriteln("git hash: " & gitHash)
|
msgWriteln("git hash: " & gitHash)"""
|
||||||
|
|
||||||
msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
|
msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
|
||||||
usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
|
usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -60,7 +60,7 @@ const
|
||||||
quick
|
quick
|
||||||
release debug
|
release debug
|
||||||
useWinAnsi useFork useNimRtl useMalloc useRealtimeGC ssl memProfiler
|
useWinAnsi useFork useNimRtl useMalloc useRealtimeGC ssl memProfiler
|
||||||
nodejs kwin
|
nodejs kwin nimfix
|
||||||
|
|
||||||
usesysassert usegcassert tinyC useFFI
|
usesysassert usegcassert tinyC useFFI
|
||||||
useStdoutAsStdmsg createNimRtl
|
useStdoutAsStdmsg createNimRtl
|
||||||
|
|
@ -69,6 +69,8 @@ const
|
||||||
reportMissedDeadlines avoidTimeMachine useClone ignoreAllocationSize
|
reportMissedDeadlines avoidTimeMachine useClone ignoreAllocationSize
|
||||||
debugExecProcesses pcreDll useLipzipSrc
|
debugExecProcesses pcreDll useLipzipSrc
|
||||||
preventDeadlocks UNICODE winUnicode trackGcHeaders posixRealtime
|
preventDeadlocks UNICODE winUnicode trackGcHeaders posixRealtime
|
||||||
|
|
||||||
|
nimStdSetjmp nimRawSetjmp nimSigSetjmp
|
||||||
""".split
|
""".split
|
||||||
|
|
||||||
proc initDefines*() =
|
proc initDefines*() =
|
||||||
|
|
@ -85,6 +87,7 @@ proc initDefines*() =
|
||||||
defineSymbol("nimnewshared")
|
defineSymbol("nimnewshared")
|
||||||
defineSymbol("nimrequiresnimframe")
|
defineSymbol("nimrequiresnimframe")
|
||||||
defineSymbol("nimparsebiggestfloatmagic")
|
defineSymbol("nimparsebiggestfloatmagic")
|
||||||
|
defineSymbol("nimalias")
|
||||||
|
|
||||||
# add platform specific symbols:
|
# add platform specific symbols:
|
||||||
for c in low(CPU)..high(CPU):
|
for c in low(CPU)..high(CPU):
|
||||||
|
|
@ -136,3 +139,7 @@ proc initDefines*() =
|
||||||
declareSymbol("emulatedthreadvars")
|
declareSymbol("emulatedthreadvars")
|
||||||
if platform.OS[targetOS].props.contains(ospLacksThreadVars):
|
if platform.OS[targetOS].props.contains(ospLacksThreadVars):
|
||||||
defineSymbol("emulatedthreadvars")
|
defineSymbol("emulatedthreadvars")
|
||||||
|
case targetOS
|
||||||
|
of osSolaris, osNetbsd, osFreebsd, osOpenbsd, osMacosx:
|
||||||
|
defineSymbol("nimRawSetjmp")
|
||||||
|
else: discard
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
|
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
|
||||||
renderer, wordrecg, idgen
|
renderer, wordrecg, idgen, nimfix.prettybase
|
||||||
|
|
||||||
proc ensureNoMissingOrUnusedSymbols(scope: PScope)
|
proc ensureNoMissingOrUnusedSymbols(scope: PScope)
|
||||||
|
|
||||||
|
|
@ -40,11 +40,8 @@ proc considerQuotedIdent*(n: PNode): PIdent =
|
||||||
template addSym*(scope: PScope, s: PSym) =
|
template addSym*(scope: PScope, s: PSym) =
|
||||||
strTableAdd(scope.symbols, s)
|
strTableAdd(scope.symbols, s)
|
||||||
|
|
||||||
proc addUniqueSym*(scope: PScope, s: PSym): TResult =
|
proc addUniqueSym*(scope: PScope, s: PSym): bool =
|
||||||
if strTableIncl(scope.symbols, s):
|
result = not strTableIncl(scope.symbols, s)
|
||||||
result = Failure
|
|
||||||
else:
|
|
||||||
result = Success
|
|
||||||
|
|
||||||
proc openScope*(c: PContext): PScope {.discardable.} =
|
proc openScope*(c: PContext): PScope {.discardable.} =
|
||||||
result = PScope(parent: c.currentScope,
|
result = PScope(parent: c.currentScope,
|
||||||
|
|
@ -65,6 +62,17 @@ iterator walkScopes*(scope: PScope): PScope =
|
||||||
yield current
|
yield current
|
||||||
current = current.parent
|
current = current.parent
|
||||||
|
|
||||||
|
proc skipAlias*(s: PSym; n: PNode): PSym =
|
||||||
|
if s == nil or s.kind != skAlias:
|
||||||
|
result = s
|
||||||
|
else:
|
||||||
|
result = s.owner
|
||||||
|
if gCmd == cmdPretty:
|
||||||
|
prettybase.replaceDeprecated(n.info, s, result)
|
||||||
|
else:
|
||||||
|
message(n.info, warnDeprecated, "use " & result.name.s & " instead; " &
|
||||||
|
s.name.s)
|
||||||
|
|
||||||
proc localSearchInScope*(c: PContext, s: PIdent): PSym =
|
proc localSearchInScope*(c: PContext, s: PIdent): PSym =
|
||||||
result = strTableGet(c.currentScope.symbols, s)
|
result = strTableGet(c.currentScope.symbols, s)
|
||||||
|
|
||||||
|
|
@ -139,14 +147,14 @@ proc wrongRedefinition*(info: TLineInfo, s: string) =
|
||||||
localError(info, errAttemptToRedefine, s)
|
localError(info, errAttemptToRedefine, s)
|
||||||
|
|
||||||
proc addDecl*(c: PContext, sym: PSym) =
|
proc addDecl*(c: PContext, sym: PSym) =
|
||||||
if c.currentScope.addUniqueSym(sym) == Failure:
|
if not c.currentScope.addUniqueSym(sym):
|
||||||
wrongRedefinition(sym.info, sym.name.s)
|
wrongRedefinition(sym.info, sym.name.s)
|
||||||
|
|
||||||
proc addPrelimDecl*(c: PContext, sym: PSym) =
|
proc addPrelimDecl*(c: PContext, sym: PSym) =
|
||||||
discard c.currentScope.addUniqueSym(sym)
|
discard c.currentScope.addUniqueSym(sym)
|
||||||
|
|
||||||
proc addDeclAt*(scope: PScope, sym: PSym) =
|
proc addDeclAt*(scope: PScope, sym: PSym) =
|
||||||
if scope.addUniqueSym(sym) == Failure:
|
if not scope.addUniqueSym(sym):
|
||||||
wrongRedefinition(sym.info, sym.name.s)
|
wrongRedefinition(sym.info, sym.name.s)
|
||||||
|
|
||||||
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||||
|
|
@ -163,7 +171,7 @@ proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
|
||||||
if fn.kind notin OverloadableSyms:
|
if fn.kind notin OverloadableSyms:
|
||||||
internalError(fn.info, "addOverloadableSymAt")
|
internalError(fn.info, "addOverloadableSymAt")
|
||||||
return
|
return
|
||||||
var check = strTableGet(scope.symbols, fn.name)
|
let check = strTableGet(scope.symbols, fn.name)
|
||||||
if check != nil and check.kind notin OverloadableSyms:
|
if check != nil and check.kind notin OverloadableSyms:
|
||||||
wrongRedefinition(fn.info, fn.name.s)
|
wrongRedefinition(fn.info, fn.name.s)
|
||||||
else:
|
else:
|
||||||
|
|
@ -179,20 +187,41 @@ proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||||
addOverloadableSymAt(scope, sym)
|
addOverloadableSymAt(scope, sym)
|
||||||
addInterfaceDeclAux(c, sym)
|
addInterfaceDeclAux(c, sym)
|
||||||
|
|
||||||
|
when defined(nimfix):
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
# when we cannot find the identifier, retry with a changed identifer:
|
||||||
|
proc altSpelling(x: PIdent): PIdent =
|
||||||
|
case x.s[0]
|
||||||
|
of 'A'..'Z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
|
||||||
|
of 'a'..'z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
|
||||||
|
else: result = x
|
||||||
|
|
||||||
|
template fixSpelling(n: PNode; ident: PIdent; op: expr) =
|
||||||
|
let alt = ident.altSpelling
|
||||||
|
result = op(c, alt).skipAlias(n)
|
||||||
|
if result != nil:
|
||||||
|
prettybase.replaceDeprecated(n.info, ident, alt)
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
template fixSpelling(n: PNode; ident: PIdent; op: expr) = discard
|
||||||
|
|
||||||
proc lookUp*(c: PContext, n: PNode): PSym =
|
proc lookUp*(c: PContext, n: PNode): PSym =
|
||||||
# Looks up a symbol. Generates an error in case of nil.
|
# Looks up a symbol. Generates an error in case of nil.
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkIdent:
|
of nkIdent:
|
||||||
result = searchInScopes(c, n.ident)
|
result = searchInScopes(c, n.ident).skipAlias(n)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
fixSpelling(n, n.ident, searchInScopes)
|
||||||
localError(n.info, errUndeclaredIdentifier, n.ident.s)
|
localError(n.info, errUndeclaredIdentifier, n.ident.s)
|
||||||
result = errorSym(c, n)
|
result = errorSym(c, n)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = n.sym
|
result = n.sym
|
||||||
of nkAccQuoted:
|
of nkAccQuoted:
|
||||||
var ident = considerQuotedIdent(n)
|
var ident = considerQuotedIdent(n)
|
||||||
result = searchInScopes(c, ident)
|
result = searchInScopes(c, ident).skipAlias(n)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
fixSpelling(n, ident, searchInScopes)
|
||||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||||
result = errorSym(c, n)
|
result = errorSym(c, n)
|
||||||
else:
|
else:
|
||||||
|
|
@ -206,36 +235,38 @@ type
|
||||||
TLookupFlag* = enum
|
TLookupFlag* = enum
|
||||||
checkAmbiguity, checkUndeclared
|
checkAmbiguity, checkUndeclared
|
||||||
|
|
||||||
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkIdent, nkAccQuoted:
|
of nkIdent, nkAccQuoted:
|
||||||
var ident = considerQuotedIdent(n)
|
var ident = considerQuotedIdent(n)
|
||||||
result = searchInScopes(c, ident)
|
result = searchInScopes(c, ident).skipAlias(n)
|
||||||
if result == nil and checkUndeclared in flags:
|
if result == nil and checkUndeclared in flags:
|
||||||
|
fixSpelling(n, ident, searchInScopes)
|
||||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||||
result = errorSym(c, n)
|
result = errorSym(c, n)
|
||||||
elif checkAmbiguity in flags and result != nil and
|
elif checkAmbiguity in flags and result != nil and
|
||||||
contains(c.ambiguousSymbols, result.id):
|
contains(c.ambiguousSymbols, result.id):
|
||||||
localError(n.info, errUseQualifier, ident.s)
|
localError(n.info, errUseQualifier, ident.s)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = n.sym
|
result = n.sym
|
||||||
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
|
if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
|
||||||
localError(n.info, errUseQualifier, n.sym.name.s)
|
localError(n.info, errUseQualifier, n.sym.name.s)
|
||||||
of nkDotExpr:
|
of nkDotExpr:
|
||||||
result = nil
|
result = nil
|
||||||
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
|
var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
|
||||||
if (m != nil) and (m.kind == skModule):
|
if m != nil and m.kind == skModule:
|
||||||
var ident: PIdent = nil
|
var ident: PIdent = nil
|
||||||
if n.sons[1].kind == nkIdent:
|
if n.sons[1].kind == nkIdent:
|
||||||
ident = n.sons[1].ident
|
ident = n.sons[1].ident
|
||||||
elif n.sons[1].kind == nkAccQuoted:
|
elif n.sons[1].kind == nkAccQuoted:
|
||||||
ident = considerQuotedIdent(n.sons[1])
|
ident = considerQuotedIdent(n.sons[1])
|
||||||
if ident != nil:
|
if ident != nil:
|
||||||
if m == c.module:
|
if m == c.module:
|
||||||
result = strTableGet(c.topLevelScope.symbols, ident)
|
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n)
|
||||||
else:
|
else:
|
||||||
result = strTableGet(m.tab, ident)
|
result = strTableGet(m.tab, ident).skipAlias(n)
|
||||||
if result == nil and checkUndeclared in flags:
|
if result == nil and checkUndeclared in flags:
|
||||||
|
fixSpelling(n.sons[1], ident, searchInScopes)
|
||||||
localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
|
||||||
result = errorSym(c, n.sons[1])
|
result = errorSym(c, n.sons[1])
|
||||||
elif n.sons[1].kind == nkSym:
|
elif n.sons[1].kind == nkSym:
|
||||||
|
|
@ -256,7 +287,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||||
o.scope = c.currentScope
|
o.scope = c.currentScope
|
||||||
o.mode = oimNoQualifier
|
o.mode = oimNoQualifier
|
||||||
while true:
|
while true:
|
||||||
result = initIdentIter(o.it, o.scope.symbols, ident)
|
result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n)
|
||||||
if result != nil:
|
if result != nil:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
|
@ -277,11 +308,12 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||||
if ident != nil:
|
if ident != nil:
|
||||||
if o.m == c.module:
|
if o.m == c.module:
|
||||||
# a module may access its private members:
|
# a module may access its private members:
|
||||||
result = initIdentIter(o.it, c.topLevelScope.symbols, ident)
|
result = initIdentIter(o.it, c.topLevelScope.symbols,
|
||||||
|
ident).skipAlias(n)
|
||||||
o.mode = oimSelfModule
|
o.mode = oimSelfModule
|
||||||
else:
|
else:
|
||||||
result = initIdentIter(o.it, o.m.tab, ident)
|
result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n)
|
||||||
else:
|
else:
|
||||||
localError(n.sons[1].info, errIdentifierExpected,
|
localError(n.sons[1].info, errIdentifierExpected,
|
||||||
renderTree(n.sons[1]))
|
renderTree(n.sons[1]))
|
||||||
result = errorSym(c, n.sons[1])
|
result = errorSym(c, n.sons[1])
|
||||||
|
|
@ -307,18 +339,18 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||||
result = nil
|
result = nil
|
||||||
of oimNoQualifier:
|
of oimNoQualifier:
|
||||||
if o.scope != nil:
|
if o.scope != nil:
|
||||||
result = nextIdentIter(o.it, o.scope.symbols)
|
result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n)
|
||||||
while result == nil:
|
while result == nil:
|
||||||
o.scope = o.scope.parent
|
o.scope = o.scope.parent
|
||||||
if o.scope == nil: break
|
if o.scope == nil: break
|
||||||
result = initIdentIter(o.it, o.scope.symbols, o.it.name)
|
result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n)
|
||||||
# BUGFIX: o.it.name <-> n.ident
|
# BUGFIX: o.it.name <-> n.ident
|
||||||
else:
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
of oimSelfModule:
|
of oimSelfModule:
|
||||||
result = nextIdentIter(o.it, c.topLevelScope.symbols)
|
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n)
|
||||||
of oimOtherModule:
|
of oimOtherModule:
|
||||||
result = nextIdentIter(o.it, o.m.tab)
|
result = nextIdentIter(o.it, o.m.tab).skipAlias(n)
|
||||||
of oimSymChoice:
|
of oimSymChoice:
|
||||||
if o.symChoiceIndex < sonsLen(n):
|
if o.symChoiceIndex < sonsLen(n):
|
||||||
result = n.sons[o.symChoiceIndex].sym
|
result = n.sons[o.symChoiceIndex].sym
|
||||||
|
|
@ -329,31 +361,27 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
|
||||||
o.mode = oimSymChoiceLocalLookup
|
o.mode = oimSymChoiceLocalLookup
|
||||||
o.scope = c.currentScope
|
o.scope = c.currentScope
|
||||||
result = firstIdentExcluding(o.it, o.scope.symbols,
|
result = firstIdentExcluding(o.it, o.scope.symbols,
|
||||||
n.sons[0].sym.name, o.inSymChoice)
|
n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
|
||||||
while result == nil:
|
while result == nil:
|
||||||
o.scope = o.scope.parent
|
o.scope = o.scope.parent
|
||||||
if o.scope == nil: break
|
if o.scope == nil: break
|
||||||
result = firstIdentExcluding(o.it, o.scope.symbols,
|
result = firstIdentExcluding(o.it, o.scope.symbols,
|
||||||
n.sons[0].sym.name, o.inSymChoice)
|
n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
|
||||||
of oimSymChoiceLocalLookup:
|
of oimSymChoiceLocalLookup:
|
||||||
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice)
|
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n)
|
||||||
while result == nil:
|
while result == nil:
|
||||||
o.scope = o.scope.parent
|
o.scope = o.scope.parent
|
||||||
if o.scope == nil: break
|
if o.scope == nil: break
|
||||||
result = firstIdentExcluding(o.it, o.scope.symbols,
|
result = firstIdentExcluding(o.it, o.scope.symbols,
|
||||||
n.sons[0].sym.name, o.inSymChoice)
|
n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
|
||||||
|
|
||||||
if result != nil and result.kind == skStub: loadStub(result)
|
if result != nil and result.kind == skStub: loadStub(result)
|
||||||
|
|
||||||
when false:
|
proc pickSym*(c: PContext, n: PNode; kind: TSymKind;
|
||||||
proc qualifiedLookUpPreferImmediate*(c: PContext, n: PNode,
|
flags: TSymFlags = {}): PSym =
|
||||||
flags = {checkUndeclared}): PSym =
|
var o: TOverloadIter
|
||||||
var o: TOverloadIter
|
var a = initOverloadIter(o, c, n)
|
||||||
result = initOverloadIter(o, c, n)
|
while a != nil:
|
||||||
var a = result
|
if a.kind == kind and flags <= a.flags:
|
||||||
while a != nil:
|
return a
|
||||||
if sfImmediate in a.flags: return a
|
a = nextOverloadIter(o, c, n)
|
||||||
a = nextOverloadIter(o, c, n)
|
|
||||||
if result == nil and checkUndeclared in flags:
|
|
||||||
localError(n.info, errUndeclaredIdentifier, n.considerQuotedIdent.s)
|
|
||||||
result = errorSym(c, n)
|
|
||||||
|
|
|
||||||
106
compiler/nimfix/nimfix.nim
Normal file
106
compiler/nimfix/nimfix.nim
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code.
|
||||||
|
|
||||||
|
import strutils, os, parseopt
|
||||||
|
import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf,
|
||||||
|
extccomp, condsyms, lists
|
||||||
|
|
||||||
|
const Usage = """
|
||||||
|
Nimfix - Tool to patch Nim code
|
||||||
|
Usage:
|
||||||
|
nimfix [options] projectflie.nim
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--overwriteFiles:on|off overwrite the original nim files.
|
||||||
|
DEFAULT is ON!
|
||||||
|
--wholeProject overwrite every processed file.
|
||||||
|
--checkExtern:on|off style check also extern names
|
||||||
|
--styleCheck:on|off|auto performs style checking for identifiers
|
||||||
|
and suggests an alternative spelling;
|
||||||
|
'auto' corrects the spelling.
|
||||||
|
|
||||||
|
In addition, all command line options of Nim are supported.
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc mainCommand =
|
||||||
|
#msgs.gErrorMax = high(int) # do not stop after first error
|
||||||
|
registerPass verbosePass
|
||||||
|
registerPass semPass
|
||||||
|
gCmd = cmdPretty
|
||||||
|
appendStr(searchPaths, options.libpath)
|
||||||
|
if gProjectFull.len != 0:
|
||||||
|
# current path is always looked first for modules
|
||||||
|
prependStr(searchPaths, gProjectPath)
|
||||||
|
|
||||||
|
compileProject()
|
||||||
|
pretty.overwriteFiles()
|
||||||
|
|
||||||
|
proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||||
|
var p = parseopt.initOptParser(cmd)
|
||||||
|
var argsCount = 0
|
||||||
|
gOnlyMainfile = true
|
||||||
|
while true:
|
||||||
|
parseopt.next(p)
|
||||||
|
case p.kind
|
||||||
|
of cmdEnd: break
|
||||||
|
of cmdLongoption, cmdShortOption:
|
||||||
|
case p.key.normalize
|
||||||
|
of "overwritefiles":
|
||||||
|
case p.val.normalize
|
||||||
|
of "on": gOverWrite = true
|
||||||
|
of "off": gOverWrite = false
|
||||||
|
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||||
|
of "checkextern":
|
||||||
|
case p.val.normalize
|
||||||
|
of "on": gCheckExtern = true
|
||||||
|
of "off": gCheckExtern = false
|
||||||
|
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||||
|
of "stylecheck":
|
||||||
|
case p.val.normalize
|
||||||
|
of "off": gStyleCheck = StyleCheck.None
|
||||||
|
of "on": gStyleCheck = StyleCheck.Warn
|
||||||
|
of "auto": gStyleCheck = StyleCheck.Auto
|
||||||
|
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||||
|
of "wholeproject": gOnlyMainfile = false
|
||||||
|
else:
|
||||||
|
processSwitch(pass, p)
|
||||||
|
of cmdArgument:
|
||||||
|
options.gProjectName = unixToNativePath(p.key)
|
||||||
|
# if processArgument(pass, p, argsCount): break
|
||||||
|
|
||||||
|
proc handleCmdLine() =
|
||||||
|
if paramCount() == 0:
|
||||||
|
stdout.writeln(Usage)
|
||||||
|
else:
|
||||||
|
processCmdLine(passCmd1, "")
|
||||||
|
if gProjectName != "":
|
||||||
|
try:
|
||||||
|
gProjectFull = canonicalizePath(gProjectName)
|
||||||
|
except OSError:
|
||||||
|
gProjectFull = gProjectName
|
||||||
|
var p = splitFile(gProjectFull)
|
||||||
|
gProjectPath = p.dir
|
||||||
|
gProjectName = p.name
|
||||||
|
else:
|
||||||
|
gProjectPath = getCurrentDir()
|
||||||
|
loadConfigs(DefaultConfig) # load all config files
|
||||||
|
# now process command line arguments again, because some options in the
|
||||||
|
# command line can overwite the config file's settings
|
||||||
|
extccomp.initVars()
|
||||||
|
processCmdLine(passCmd2, "")
|
||||||
|
mainCommand()
|
||||||
|
|
||||||
|
when compileOption("gc", "v2") or compileOption("gc", "refc"):
|
||||||
|
GC_disableMarkAndSweep()
|
||||||
|
|
||||||
|
condsyms.initDefines()
|
||||||
|
defineSymbol "nimfix"
|
||||||
|
handleCmdline()
|
||||||
17
compiler/nimfix/nimfix.nim.cfg
Normal file
17
compiler/nimfix/nimfix.nim.cfg
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Special configuration file for the Nim project
|
||||||
|
# gc:markAndSweep
|
||||||
|
|
||||||
|
hint[XDeclaredButNotUsed]:off
|
||||||
|
path:"$projectPath/../.."
|
||||||
|
|
||||||
|
path:"$lib/packages/docutils"
|
||||||
|
path:"$nim/compiler"
|
||||||
|
|
||||||
|
define:useStdoutAsStdmsg
|
||||||
|
symbol:nimfix
|
||||||
|
define:nimfix
|
||||||
|
|
||||||
|
cs:partial
|
||||||
|
#define:useNodeIds
|
||||||
|
define:booting
|
||||||
|
define:noDocgen
|
||||||
152
compiler/nimfix/pretty.nim
Normal file
152
compiler/nimfix/pretty.nim
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## This module implements the code "prettifier". This is part of the toolchain
|
||||||
|
## to convert Nim code into a consistent style.
|
||||||
|
|
||||||
|
import
|
||||||
|
strutils, os, options, ast, astalgo, msgs, ropes, idents,
|
||||||
|
intsets, strtabs, semdata, prettybase
|
||||||
|
|
||||||
|
type
|
||||||
|
StyleCheck* {.pure.} = enum None, Warn, Auto
|
||||||
|
|
||||||
|
var
|
||||||
|
gOverWrite* = true
|
||||||
|
gStyleCheck*: StyleCheck
|
||||||
|
gCheckExtern*, gOnlyMainfile*: bool
|
||||||
|
|
||||||
|
proc overwriteFiles*() =
|
||||||
|
let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
|
||||||
|
for i in 0 .. high(gSourceFiles):
|
||||||
|
if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
|
||||||
|
(not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx):
|
||||||
|
let newFile = if gOverWrite: gSourceFiles[i].fullpath
|
||||||
|
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
|
||||||
|
try:
|
||||||
|
var f = open(newFile, fmWrite)
|
||||||
|
for line in gSourceFiles[i].lines:
|
||||||
|
if doStrip:
|
||||||
|
f.write line.strip(leading = false, trailing = true)
|
||||||
|
else:
|
||||||
|
f.write line
|
||||||
|
f.write(gSourceFiles[i].newline)
|
||||||
|
f.close
|
||||||
|
except IOError:
|
||||||
|
rawMessage(errCannotOpenFile, newFile)
|
||||||
|
|
||||||
|
proc `=~`(s: string, a: openArray[string]): bool =
|
||||||
|
for x in a:
|
||||||
|
if s.startsWith(x): return true
|
||||||
|
|
||||||
|
proc beautifyName(s: string, k: TSymKind): string =
|
||||||
|
# minimal set of rules here for transition:
|
||||||
|
# GC_ is allowed
|
||||||
|
|
||||||
|
let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
|
||||||
|
if allUpper and k in {skConst, skEnumField, skType}: return s
|
||||||
|
result = newStringOfCap(s.len)
|
||||||
|
var i = 0
|
||||||
|
case k
|
||||||
|
of skType, skGenericParam:
|
||||||
|
# Types should start with a capital unless builtins like 'int' etc.:
|
||||||
|
if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
|
||||||
|
"char", "byte", "bool", "openArray", "seq", "array", "void",
|
||||||
|
"pointer", "float", "csize", "cdouble", "cchar", "cschar",
|
||||||
|
"cshort", "cu", "nil", "expr", "stmt", "typedesc", "auto", "any",
|
||||||
|
"range", "openarray", "varargs", "set", "cfloat"
|
||||||
|
]:
|
||||||
|
result.add s[i]
|
||||||
|
else:
|
||||||
|
result.add toUpper(s[i])
|
||||||
|
of skConst, skEnumField:
|
||||||
|
# for 'const' we keep how it's spelt; either upper case or lower case:
|
||||||
|
result.add s[0]
|
||||||
|
else:
|
||||||
|
# as a special rule, don't transform 'L' to 'l'
|
||||||
|
if s.len == 1 and s[0] == 'L': result.add 'L'
|
||||||
|
elif '_' in s: result.add(s[i])
|
||||||
|
else: result.add toLower(s[0])
|
||||||
|
inc i
|
||||||
|
while i < s.len:
|
||||||
|
if s[i] == '_':
|
||||||
|
if i > 0 and s[i-1] in {'A'..'Z'}:
|
||||||
|
# don't skip '_' as it's essential for e.g. 'GC_disable'
|
||||||
|
result.add('_')
|
||||||
|
inc i
|
||||||
|
result.add s[i]
|
||||||
|
else:
|
||||||
|
inc i
|
||||||
|
result.add toUpper(s[i])
|
||||||
|
elif allUpper:
|
||||||
|
result.add toLower(s[i])
|
||||||
|
else:
|
||||||
|
result.add s[i]
|
||||||
|
inc i
|
||||||
|
|
||||||
|
proc replaceInFile(info: TLineInfo; newName: string) =
|
||||||
|
loadFile(info)
|
||||||
|
|
||||||
|
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
|
||||||
|
var first = min(info.col.int, line.len)
|
||||||
|
if first < 0: return
|
||||||
|
#inc first, skipIgnoreCase(line, "proc ", first)
|
||||||
|
while first > 0 and line[first-1] in prettybase.Letters: dec first
|
||||||
|
if first < 0: return
|
||||||
|
if line[first] == '`': inc first
|
||||||
|
|
||||||
|
let last = first+identLen(line, first)-1
|
||||||
|
if differ(line, first, last, newName):
|
||||||
|
# last-first+1 != newName.len or
|
||||||
|
var x = line.substr(0, first-1) & newName & line.substr(last+1)
|
||||||
|
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
|
||||||
|
gSourceFiles[info.fileIndex].dirty = true
|
||||||
|
|
||||||
|
proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
|
||||||
|
let beau = beautifyName(s, k)
|
||||||
|
if s != beau:
|
||||||
|
if gStyleCheck == StyleCheck.Auto:
|
||||||
|
sym.name = getIdent(beau)
|
||||||
|
replaceInFile(info, beau)
|
||||||
|
else:
|
||||||
|
message(info, hintName, beau)
|
||||||
|
|
||||||
|
proc styleCheckDefImpl(info: TLineInfo; s: PSym; k: TSymKind) =
|
||||||
|
# operators stay as they are:
|
||||||
|
if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return
|
||||||
|
if k in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||||
|
if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
|
||||||
|
checkStyle(info, s.name.s, k, s)
|
||||||
|
|
||||||
|
template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) =
|
||||||
|
when defined(nimfix):
|
||||||
|
if gStyleCheck != StyleCheck.None: styleCheckDefImpl(info, s, k)
|
||||||
|
|
||||||
|
template styleCheckDef*(info: TLineInfo; s: PSym) =
|
||||||
|
styleCheckDef(info, s, s.kind)
|
||||||
|
template styleCheckDef*(s: PSym) =
|
||||||
|
styleCheckDef(s.info, s, s.kind)
|
||||||
|
|
||||||
|
proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
|
||||||
|
if info.fileIndex < 0: return
|
||||||
|
# we simply convert it to what it looks like in the definition
|
||||||
|
# for consistency
|
||||||
|
|
||||||
|
# operators stay as they are:
|
||||||
|
if s.kind in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters:
|
||||||
|
return
|
||||||
|
if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
|
||||||
|
let newName = s.name.s
|
||||||
|
|
||||||
|
replaceInFile(info, newName)
|
||||||
|
#if newName == "File": writeStackTrace()
|
||||||
|
|
||||||
|
template styleCheckUse*(info: TLineInfo; s: PSym) =
|
||||||
|
when defined(nimfix):
|
||||||
|
if gStyleCheck != StyleCheck.None: styleCheckUseImpl(info, s)
|
||||||
93
compiler/nimfix/prettybase.nim
Normal file
93
compiler/nimfix/prettybase.nim
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
import ast, msgs, strutils, idents, lexbase, streams
|
||||||
|
from os import splitFile
|
||||||
|
|
||||||
|
type
|
||||||
|
TSourceFile* = object
|
||||||
|
lines*: seq[string]
|
||||||
|
dirty*, isNimfixFile*: bool
|
||||||
|
fullpath*, newline*: string
|
||||||
|
fileIdx*: int32
|
||||||
|
|
||||||
|
var
|
||||||
|
gSourceFiles*: seq[TSourceFile] = @[]
|
||||||
|
|
||||||
|
proc loadFile*(info: TLineInfo) =
|
||||||
|
let i = info.fileIndex
|
||||||
|
if i >= gSourceFiles.len:
|
||||||
|
gSourceFiles.setLen(i+1)
|
||||||
|
if gSourceFiles[i].lines.isNil:
|
||||||
|
gSourceFiles[i].fileIdx = info.fileIndex
|
||||||
|
gSourceFiles[i].lines = @[]
|
||||||
|
let path = info.toFullPath
|
||||||
|
gSourceFiles[i].fullpath = path
|
||||||
|
gSourceFiles[i].isNimfixFile = path.splitFile.ext == ".nimfix"
|
||||||
|
# we want to die here for IOError:
|
||||||
|
for line in lines(path):
|
||||||
|
gSourceFiles[i].lines.add(line)
|
||||||
|
# extract line ending of the file:
|
||||||
|
var lex: TBaseLexer
|
||||||
|
open(lex, newFileStream(path, fmRead))
|
||||||
|
var pos = lex.bufpos
|
||||||
|
while true:
|
||||||
|
case lex.buf[pos]
|
||||||
|
of '\c':
|
||||||
|
gSourceFiles[i].newline = "\c\L"
|
||||||
|
break
|
||||||
|
of '\L', '\0':
|
||||||
|
gSourceFiles[i].newline = "\L"
|
||||||
|
break
|
||||||
|
else: discard
|
||||||
|
inc pos
|
||||||
|
close(lex)
|
||||||
|
|
||||||
|
const
|
||||||
|
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
|
||||||
|
|
||||||
|
proc identLen*(line: string, start: int): int =
|
||||||
|
while start+result < line.len and line[start+result] in Letters:
|
||||||
|
inc result
|
||||||
|
|
||||||
|
proc differ*(line: string, a, b: int, x: string): bool =
|
||||||
|
let y = line[a..b]
|
||||||
|
result = cmpIgnoreStyle(y, x) == 0 and y != x
|
||||||
|
|
||||||
|
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
|
||||||
|
loadFile(info)
|
||||||
|
|
||||||
|
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
|
||||||
|
var first = min(info.col.int, line.len)
|
||||||
|
if first < 0: return
|
||||||
|
#inc first, skipIgnoreCase(line, "proc ", first)
|
||||||
|
while first > 0 and line[first-1] in Letters: dec first
|
||||||
|
if first < 0: return
|
||||||
|
if line[first] == '`': inc first
|
||||||
|
|
||||||
|
let last = first+identLen(line, first)-1
|
||||||
|
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
|
||||||
|
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
|
||||||
|
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
|
||||||
|
gSourceFiles[info.fileIndex].dirty = true
|
||||||
|
#if newSym.s == "File": writeStackTrace()
|
||||||
|
|
||||||
|
proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
|
||||||
|
replaceDeprecated(info, oldSym.name, newSym.name)
|
||||||
|
|
||||||
|
proc replaceComment*(info: TLineInfo) =
|
||||||
|
loadFile(info)
|
||||||
|
|
||||||
|
let line = gSourceFiles[info.fileIndex].lines[info.line-1]
|
||||||
|
var first = info.col.int
|
||||||
|
if line[first] != '#': inc first
|
||||||
|
|
||||||
|
var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
|
||||||
|
system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
|
||||||
|
gSourceFiles[info.fileIndex].dirty = true
|
||||||
|
|
@ -14,7 +14,7 @@ const
|
||||||
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
||||||
VersionMajor* = 0
|
VersionMajor* = 0
|
||||||
VersionMinor* = 9
|
VersionMinor* = 9
|
||||||
VersionPatch* = 5
|
VersionPatch* = 6
|
||||||
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
||||||
|
|
||||||
RodFileVersion* = "1215" # modify this if the rod-format changes!
|
RodFileVersion* = "1215" # modify this if the rod-format changes!
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -24,7 +24,7 @@ const
|
||||||
wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||||
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
||||||
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
|
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
|
||||||
wGensym, wInject, wRaises, wTags, wUses, wOperator, wDelegator, wGcSafe,
|
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
|
||||||
wOverride}
|
wOverride}
|
||||||
converterPragmas* = procPragmas
|
converterPragmas* = procPragmas
|
||||||
methodPragmas* = procPragmas
|
methodPragmas* = procPragmas
|
||||||
|
|
@ -36,8 +36,8 @@ const
|
||||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
|
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
|
||||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||||
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
|
||||||
wTags, wUses, wOperator, wGcSafe}
|
wTags, wLocks, wGcSafe}
|
||||||
exprPragmas* = {wLine}
|
exprPragmas* = {wLine, wLocks}
|
||||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
|
||||||
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
|
||||||
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
|
||||||
|
|
@ -45,27 +45,27 @@ const
|
||||||
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
||||||
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||||
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
||||||
wInjectStmt}
|
wInjectStmt, wDeprecated}
|
||||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||||
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||||
wRaises, wUses, wTags, wGcSafe}
|
wRaises, wLocks, wTags, wGcSafe}
|
||||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||||
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
|
wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
|
||||||
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
|
||||||
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
|
||||||
wBorrow, wGcSafe}
|
wBorrow, wGcSafe}
|
||||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||||
wImportCpp, wImportObjC, wError}
|
wImportCpp, wImportObjC, wError, wGuard}
|
||||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||||
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
|
wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
|
||||||
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
|
wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
|
||||||
wGensym, wInject, wCodegenDecl}
|
wGensym, wInject, wCodegenDecl, wGuard}
|
||||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
|
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
|
||||||
letPragmas* = varPragmas
|
letPragmas* = varPragmas
|
||||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
||||||
wThread, wRaises, wUses, wTags, wGcSafe}
|
wThread, wRaises, wLocks, wTags, wGcSafe}
|
||||||
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
||||||
|
|
||||||
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
||||||
|
|
@ -128,12 +128,16 @@ proc processImportCpp(s: PSym, extname: string) =
|
||||||
incl(s.flags, sfImportc)
|
incl(s.flags, sfImportc)
|
||||||
incl(s.flags, sfInfixCall)
|
incl(s.flags, sfInfixCall)
|
||||||
excl(s.flags, sfForward)
|
excl(s.flags, sfForward)
|
||||||
|
let m = s.getModule()
|
||||||
|
incl(m.flags, sfCompileToCpp)
|
||||||
|
|
||||||
proc processImportObjC(s: PSym, extname: string) =
|
proc processImportObjC(s: PSym, extname: string) =
|
||||||
setExternName(s, extname)
|
setExternName(s, extname)
|
||||||
incl(s.flags, sfImportc)
|
incl(s.flags, sfImportc)
|
||||||
incl(s.flags, sfNamedParamCall)
|
incl(s.flags, sfNamedParamCall)
|
||||||
excl(s.flags, sfForward)
|
excl(s.flags, sfForward)
|
||||||
|
let m = s.getModule()
|
||||||
|
incl(m.flags, sfCompileToObjC)
|
||||||
|
|
||||||
proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
|
proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
|
||||||
result = newNodeIT(nkStrLit, n.info, getSysType(tyString))
|
result = newNodeIT(nkStrLit, n.info, getSysType(tyString))
|
||||||
|
|
@ -514,27 +518,6 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
|
||||||
else:
|
else:
|
||||||
invalidPragma(n)
|
invalidPragma(n)
|
||||||
|
|
||||||
proc pragmaUses(c: PContext, n: PNode) =
|
|
||||||
proc processExc(c: PContext, x: PNode): PNode =
|
|
||||||
if x.kind in {nkAccQuoted, nkIdent, nkSym,
|
|
||||||
nkOpenSymChoice, nkClosedSymChoice}:
|
|
||||||
if considerQuotedIdent(x).s == "*":
|
|
||||||
return newSymNode(ast.anyGlobal)
|
|
||||||
result = c.semExpr(c, x)
|
|
||||||
if result.kind != nkSym or sfGlobal notin result.sym.flags:
|
|
||||||
localError(x.info, "'$1' is not a global variable" % result.renderTree)
|
|
||||||
result = newSymNode(ast.anyGlobal)
|
|
||||||
|
|
||||||
if n.kind == nkExprColonExpr:
|
|
||||||
let it = n.sons[1]
|
|
||||||
if it.kind notin {nkCurly, nkBracket}:
|
|
||||||
n.sons[1] = processExc(c, it)
|
|
||||||
else:
|
|
||||||
for i in 0 .. <it.len:
|
|
||||||
it.sons[i] = processExc(c, it.sons[i])
|
|
||||||
else:
|
|
||||||
invalidPragma(n)
|
|
||||||
|
|
||||||
proc typeBorrow(sym: PSym, n: PNode) =
|
proc typeBorrow(sym: PSym, n: PNode) =
|
||||||
if n.kind == nkExprColonExpr:
|
if n.kind == nkExprColonExpr:
|
||||||
let it = n.sons[1]
|
let it = n.sons[1]
|
||||||
|
|
@ -542,11 +525,50 @@ proc typeBorrow(sym: PSym, n: PNode) =
|
||||||
localError(n.info, "a type can only borrow `.` for now")
|
localError(n.info, "a type can only borrow `.` for now")
|
||||||
incl(sym.typ.flags, tfBorrowDot)
|
incl(sym.typ.flags, tfBorrowDot)
|
||||||
|
|
||||||
|
proc markCompilerProc(s: PSym) =
|
||||||
|
makeExternExport(s, "$1", s.info)
|
||||||
|
incl(s.flags, sfCompilerProc)
|
||||||
|
incl(s.flags, sfUsed)
|
||||||
|
registerCompilerProc(s)
|
||||||
|
|
||||||
|
proc deprecatedStmt(c: PContext; pragma: PNode) =
|
||||||
|
let pragma = pragma[1]
|
||||||
|
if pragma.kind != nkBracket:
|
||||||
|
localError(pragma.info, "list of key:value pairs expected"); return
|
||||||
|
for n in pragma:
|
||||||
|
if n.kind in {nkExprColonExpr, nkExprEqExpr}:
|
||||||
|
let dest = qualifiedLookUp(c, n[1])
|
||||||
|
let src = considerQuotedIdent(n[0])
|
||||||
|
let alias = newSym(skAlias, src, dest, n[0].info)
|
||||||
|
incl(alias.flags, sfExported)
|
||||||
|
if sfCompilerProc in dest.flags: markCompilerProc(alias)
|
||||||
|
addInterfaceDecl(c, alias)
|
||||||
|
else:
|
||||||
|
localError(n.info, "key:value pair expected")
|
||||||
|
|
||||||
|
proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
|
||||||
|
if it.kind != nkExprColonExpr:
|
||||||
|
invalidPragma(it); return
|
||||||
|
let n = it[1]
|
||||||
|
if n.kind == nkSym:
|
||||||
|
result = n.sym
|
||||||
|
elif kind == skField:
|
||||||
|
# First check if the guard is a global variable:
|
||||||
|
result = qualifiedLookUp(c, n, {})
|
||||||
|
if result.isNil or result.kind notin {skLet, skVar} or
|
||||||
|
sfGlobal notin result.flags:
|
||||||
|
# We return a dummy symbol; later passes over the type will repair it.
|
||||||
|
# Generic instantiation needs to know about this too. But we're lazy
|
||||||
|
# and perform the lookup on demand instead.
|
||||||
|
result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
|
||||||
|
else:
|
||||||
|
result = qualifiedLookUp(c, n)
|
||||||
|
|
||||||
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
validPragmas: TSpecialWords): bool =
|
validPragmas: TSpecialWords): bool =
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
||||||
if key.kind == nkIdent:
|
if key.kind == nkIdent:
|
||||||
var userPragma = strTableGet(c.userPragmas, key.ident)
|
var userPragma = strTableGet(c.userPragmas, key.ident)
|
||||||
if userPragma != nil:
|
if userPragma != nil:
|
||||||
inc c.instCounter
|
inc c.instCounter
|
||||||
|
|
@ -578,11 +600,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
of wAlign:
|
of wAlign:
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
var align = expectIntLit(c, it)
|
var align = expectIntLit(c, it)
|
||||||
if not isPowerOfTwo(align) and align != 0:
|
if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
|
||||||
localError(it.info, errPowerOfTwoExpected)
|
localError(it.info, errPowerOfTwoExpected)
|
||||||
else:
|
else:
|
||||||
sym.typ.align = align
|
sym.typ.align = align.int16
|
||||||
of wSize:
|
of wSize:
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
var size = expectIntLit(c, it)
|
var size = expectIntLit(c, it)
|
||||||
if not isPowerOfTwo(size) or size <= 0 or size > 8:
|
if not isPowerOfTwo(size) or size <= 0 or size > 8:
|
||||||
|
|
@ -648,17 +670,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
processDynLib(c, it, sym)
|
processDynLib(c, it, sym)
|
||||||
of wCompilerproc:
|
of wCompilerproc:
|
||||||
noVal(it) # compilerproc may not get a string!
|
noVal(it) # compilerproc may not get a string!
|
||||||
if sfFromGeneric notin sym.flags:
|
if sfFromGeneric notin sym.flags: markCompilerProc(sym)
|
||||||
makeExternExport(sym, "$1", it.info)
|
of wProcVar:
|
||||||
incl(sym.flags, sfCompilerProc)
|
|
||||||
incl(sym.flags, sfUsed) # suppress all those stupid warnings
|
|
||||||
registerCompilerProc(sym)
|
|
||||||
of wProcVar:
|
|
||||||
noVal(it)
|
noVal(it)
|
||||||
incl(sym.flags, sfProcvar)
|
incl(sym.flags, sfProcvar)
|
||||||
of wDeprecated:
|
of wDeprecated:
|
||||||
noVal(it)
|
if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
|
||||||
if sym != nil: incl(sym.flags, sfDeprecated)
|
elif sym != nil: incl(sym.flags, sfDeprecated)
|
||||||
else: incl(c.module.flags, sfDeprecated)
|
else: incl(c.module.flags, sfDeprecated)
|
||||||
of wVarargs:
|
of wVarargs:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
|
|
@ -789,10 +807,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
if sym == nil: invalidPragma(it)
|
if sym == nil: invalidPragma(it)
|
||||||
of wLine: pragmaLine(c, it)
|
of wLine: pragmaLine(c, it)
|
||||||
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
||||||
of wUses: pragmaUses(c, it)
|
of wGuard:
|
||||||
of wOperator:
|
if sym == nil or sym.kind notin {skVar, skLet, skField}:
|
||||||
if sym == nil: invalidPragma(it)
|
invalidPragma(it)
|
||||||
else: sym.position = expectIntLit(c, it)
|
else:
|
||||||
|
sym.guard = pragmaGuard(c, it, sym.kind)
|
||||||
of wInjectStmt:
|
of wInjectStmt:
|
||||||
if it.kind != nkExprColonExpr:
|
if it.kind != nkExprColonExpr:
|
||||||
localError(it.info, errExprExpected)
|
localError(it.info, errExprExpected)
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,15 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||||
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 in skProcKinds and
|
if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags):
|
||||||
sameType(result.typ, fn.typ, flags): return
|
case equalParams(result.typ.n, fn.typ.n)
|
||||||
|
of paramsEqual:
|
||||||
|
return
|
||||||
|
of paramsIncompatible:
|
||||||
|
localError(fn.info, errNotOverloadable, fn.name.s)
|
||||||
|
return
|
||||||
|
of paramsNotEqual:
|
||||||
|
discard
|
||||||
|
|
||||||
result = nextIdentIter(it, scope.symbols)
|
result = nextIdentIter(it, scope.symbols)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1614,6 +1614,11 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
|
||||||
initIdTable(bindings)
|
initIdTable(bindings)
|
||||||
bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t)
|
bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t)
|
||||||
result = c.semGenerateInstance(c, sym, bindings, info)
|
result = c.semGenerateInstance(c, sym, bindings, info)
|
||||||
|
# since it's an instantiation, we unmark it as a compilerproc. Otherwise
|
||||||
|
# codegen would fail:
|
||||||
|
if sfCompilerProc in result.flags:
|
||||||
|
result.flags = result.flags - {sfCompilerProc, sfExportC, sfImportC}
|
||||||
|
result.loc.r = nil
|
||||||
|
|
||||||
proc setMs(n: PNode, s: PSym): PNode =
|
proc setMs(n: PNode, s: PSym): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
|
||||||
|
|
@ -315,7 +315,6 @@ proc documentRaises*(n: PNode) =
|
||||||
if n.sons[namePos].kind != nkSym: return
|
if n.sons[namePos].kind != nkSym: return
|
||||||
documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects)
|
documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects)
|
||||||
documentEffect(n, n.sons[pragmasPos], wTags, tagEffects)
|
documentEffect(n, n.sons[pragmasPos], wTags, tagEffects)
|
||||||
documentEffect(n, n.sons[pragmasPos], wUses, usesEffects)
|
|
||||||
|
|
||||||
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
||||||
|
|
||||||
|
|
@ -335,10 +334,6 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
||||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
||||||
tracked.gcUnsafe = true
|
tracked.gcUnsafe = true
|
||||||
|
|
||||||
when trackGlobals:
|
|
||||||
let usesSpec = effectSpec(pragma, wUses)
|
|
||||||
mergeUses(tracked, usesSpec, n)
|
|
||||||
|
|
||||||
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
let n = n.skipConv
|
let n = n.skipConv
|
||||||
if paramType != nil and tfNotNil in paramType.flags and
|
if paramType != nil and tfNotNil in paramType.flags and
|
||||||
|
|
@ -641,10 +636,6 @@ proc checkMethodEffects*(disp, branch: PSym) =
|
||||||
if not isNil(tagsSpec):
|
if not isNil(tagsSpec):
|
||||||
checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
|
checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
|
||||||
"can have an unlisted effect: ", hints=off, subtypeRelation)
|
"can have an unlisted effect: ", hints=off, subtypeRelation)
|
||||||
let usesSpec = effectSpec(p, wUses)
|
|
||||||
if not isNil(usesSpec):
|
|
||||||
checkRaisesSpec(usesSpec, actual.sons[usesEffects],
|
|
||||||
"may use an unlisted global variable: ", hints=off, symbolPredicate)
|
|
||||||
if sfThread in disp.flags and notGcSafe(branch.typ):
|
if sfThread in disp.flags and notGcSafe(branch.typ):
|
||||||
localError(branch.info, "base method is GC-safe, but '$1' is not" %
|
localError(branch.info, "base method is GC-safe, but '$1' is not" %
|
||||||
branch.name.s)
|
branch.name.s)
|
||||||
|
|
@ -656,16 +647,13 @@ proc setEffectsForProcType*(t: PType, n: PNode) =
|
||||||
let
|
let
|
||||||
raisesSpec = effectSpec(n, wRaises)
|
raisesSpec = effectSpec(n, wRaises)
|
||||||
tagsSpec = effectSpec(n, wTags)
|
tagsSpec = effectSpec(n, wTags)
|
||||||
usesSpec = effectSpec(n, wUses)
|
if not isNil(raisesSpec) or not isNil(tagsSpec):
|
||||||
if not isNil(raisesSpec) or not isNil(tagsSpec) or not isNil(usesSpec):
|
|
||||||
internalAssert effects.len == 0
|
internalAssert effects.len == 0
|
||||||
newSeq(effects.sons, effectListLen)
|
newSeq(effects.sons, effectListLen)
|
||||||
if not isNil(raisesSpec):
|
if not isNil(raisesSpec):
|
||||||
effects.sons[exceptionEffects] = raisesSpec
|
effects.sons[exceptionEffects] = raisesSpec
|
||||||
if not isNil(tagsSpec):
|
if not isNil(tagsSpec):
|
||||||
effects.sons[tagEffects] = tagsSpec
|
effects.sons[tagEffects] = tagsSpec
|
||||||
if not isNil(usesSpec):
|
|
||||||
effects.sons[usesEffects] = usesSpec
|
|
||||||
|
|
||||||
proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
||||||
newSeq(effects.sons, effectListLen)
|
newSeq(effects.sons, effectListLen)
|
||||||
|
|
@ -710,12 +698,6 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||||
# after the check, use the formal spec:
|
# after the check, use the formal spec:
|
||||||
effects.sons[tagEffects] = tagsSpec
|
effects.sons[tagEffects] = tagsSpec
|
||||||
|
|
||||||
when trackGlobals:
|
|
||||||
let usesSpec = effectSpec(p, wUses)
|
|
||||||
if not isNil(usesSpec):
|
|
||||||
checkRaisesSpec(usesSpec, t.uses,
|
|
||||||
"uses an unlisted global variable: ", hints=on, symbolPredicate)
|
|
||||||
effects.sons[usesEffects] = usesSpec
|
|
||||||
if optThreadAnalysis in gGlobalOptions:
|
if optThreadAnalysis in gGlobalOptions:
|
||||||
if sfThread in s.flags and t.gcUnsafe:
|
if sfThread in s.flags and t.gcUnsafe:
|
||||||
#localError(s.info, warnGcUnsafe2, s.name.s)
|
#localError(s.info, warnGcUnsafe2, s.name.s)
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ type
|
||||||
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
|
||||||
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
|
||||||
wAsmNoStackFrame,
|
wAsmNoStackFrame,
|
||||||
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wUses,
|
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
|
||||||
|
|
||||||
wAuto, wBool, wCatch, wChar, wClass,
|
wAuto, wBool, wCatch, wChar, wClass,
|
||||||
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
|
||||||
|
|
@ -147,7 +147,7 @@ const
|
||||||
"computedgoto", "injectstmt",
|
"computedgoto", "injectstmt",
|
||||||
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
|
||||||
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
|
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
|
||||||
"guard", "uses",
|
"guard", "locks",
|
||||||
|
|
||||||
"auto", "bool", "catch", "char", "class",
|
"auto", "bool", "catch", "char", "class",
|
||||||
"const_cast", "default", "delete", "double",
|
"const_cast", "default", "delete", "double",
|
||||||
|
|
|
||||||
|
|
@ -1421,7 +1421,7 @@ Examples:
|
||||||
proc forEach(c: proc (x: int) {.cdecl.}) =
|
proc forEach(c: proc (x: int) {.cdecl.}) =
|
||||||
...
|
...
|
||||||
|
|
||||||
forEach(printItem) # this will NOT work because calling conventions differ
|
forEach(printItem) # this will NOT compile because calling conventions differ
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -5039,6 +5039,27 @@ first implementation to play with a language feature before a nicer syntax
|
||||||
to access the feature becomes available.
|
to access the feature becomes available.
|
||||||
|
|
||||||
|
|
||||||
|
deprecated pragma
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The deprecated pragma is used to mark a symbol as deprecated:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc p() {.deprecated.}
|
||||||
|
var x {.deprecated.}: char
|
||||||
|
|
||||||
|
It can also be used as a statement. Then it takes a list of *renamings*. The
|
||||||
|
upcoming ``nimfix`` tool can automatically update the code and perform these
|
||||||
|
renamings:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
type
|
||||||
|
File = object
|
||||||
|
Stream = ref object
|
||||||
|
{.deprecated: [TFile: File, PStream: Stream].}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
noSideEffect pragma
|
noSideEffect pragma
|
||||||
-------------------
|
-------------------
|
||||||
The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
|
The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@ customize this style sheet.
|
||||||
Andreas Rumpf
|
Andreas Rumpf
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: black;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
/* used to remove borders from tables and images */
|
/* used to remove borders from tables and images */
|
||||||
.borderless, table.borderless td, table.borderless th {
|
.borderless, table.borderless td, table.borderless th {
|
||||||
border: 0 }
|
border: 0 }
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,13 @@ type
|
||||||
EDb* = object of EIO ## exception that is raised if a database error occurs
|
EDb* = object of EIO ## exception that is raised if a database error occurs
|
||||||
|
|
||||||
TSqlQuery* = distinct string ## an SQL query string
|
TSqlQuery* = distinct string ## an SQL query string
|
||||||
|
TSqlPrepared* = distinct string ## a identifier for the prepared queries
|
||||||
|
|
||||||
FDb* = object of FIO ## effect that denotes a database operation
|
FDb* = object of FIO ## effect that denotes a database operation
|
||||||
FReadDb* = object of FDB ## effect that denotes a read operation
|
FReadDb* = object of FDB ## effect that denotes a read operation
|
||||||
FWriteDb* = object of FDB ## effect that denotes a write operation
|
FWriteDb* = object of FDB ## effect that denotes a write operation
|
||||||
|
|
||||||
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
||||||
## constructs a TSqlQuery from the string `query`. This is supposed to be
|
## constructs a TSqlQuery from the string `query`. This is supposed to be
|
||||||
## used as a raw-string-literal modifier:
|
## used as a raw-string-literal modifier:
|
||||||
## ``sql"update user set counter = counter + 1"``
|
## ``sql"update user set counter = counter + 1"``
|
||||||
|
|
@ -33,14 +34,14 @@ proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
|
||||||
## on, later versions will check the string for valid syntax.
|
## on, later versions will check the string for valid syntax.
|
||||||
result = TSqlQuery(query)
|
result = TSqlQuery(query)
|
||||||
|
|
||||||
proc dbError(db: TDbConn) {.noreturn.} =
|
proc dbError*(db: TDbConn) {.noreturn.} =
|
||||||
## raises an EDb exception.
|
## raises an EDb exception.
|
||||||
var e: ref EDb
|
var e: ref EDb
|
||||||
new(e)
|
new(e)
|
||||||
e.msg = $PQerrorMessage(db)
|
e.msg = $PQerrorMessage(db)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc dbError*(msg: string) {.noreturn.} =
|
proc dbError*(msg: string) {.noreturn.} =
|
||||||
## raises an EDb exception with message `msg`.
|
## raises an EDb exception with message `msg`.
|
||||||
var e: ref EDb
|
var e: ref EDb
|
||||||
new(e)
|
new(e)
|
||||||
|
|
@ -61,41 +62,70 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
|
||||||
if c == '?':
|
if c == '?':
|
||||||
add(result, dbQuote(args[a]))
|
add(result, dbQuote(args[a]))
|
||||||
inc(a)
|
inc(a)
|
||||||
else:
|
else:
|
||||||
add(result, c)
|
add(result, c)
|
||||||
|
|
||||||
proc tryExec*(db: TDbConn, query: TSqlQuery,
|
proc tryExec*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
|
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
|
||||||
## tries to execute the query and returns true if successful, false otherwise.
|
## tries to execute the query and returns true if successful, false otherwise.
|
||||||
var q = dbFormat(query, args)
|
var arr = allocCStringArray(args)
|
||||||
var res = PQExec(db, q)
|
var res = PQexecParams(db, query.string, int32(args.len), nil, arr,
|
||||||
|
nil, nil, 0)
|
||||||
|
deallocCStringArray(arr)
|
||||||
result = PQresultStatus(res) == PGRES_COMMAND_OK
|
result = PQresultStatus(res) == PGRES_COMMAND_OK
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
|
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
|
||||||
tags: [FReadDB, FWriteDb].} =
|
tags: [FReadDB, FWriteDb].} =
|
||||||
## executes the query and raises EDB if not successful.
|
## executes the query and raises EDB if not successful.
|
||||||
var q = dbFormat(query, args)
|
var arr = allocCStringArray(args)
|
||||||
var res = PQExec(db, q)
|
var res = PQexecParams(db, query.string, int32(args.len), nil, arr,
|
||||||
|
nil, nil, 0)
|
||||||
|
deallocCStringArray(arr)
|
||||||
if PQresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
if PQresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
|
proc exec*(db: TDbConn, stmtName: TSqlPrepared,
|
||||||
|
args: varargs[string]) {.tags: [FReadDB, FWriteDb].} =
|
||||||
|
var arr = allocCStringArray(args)
|
||||||
|
var res = PQexecPrepared(db, stmtName.string, int32(args.len), arr,
|
||||||
|
nil, nil, 0)
|
||||||
|
deallocCStringArray(arr)
|
||||||
|
if PQResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
||||||
|
PQclear(res)
|
||||||
|
|
||||||
proc newRow(L: int): TRow =
|
proc newRow(L: int): TRow =
|
||||||
newSeq(result, L)
|
newSeq(result, L)
|
||||||
for i in 0..L-1: result[i] = ""
|
for i in 0..L-1: result[i] = ""
|
||||||
|
|
||||||
proc setupQuery(db: TDbConn, query: TSqlQuery,
|
proc setupQuery(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string]): PPGresult =
|
args: varargs[string]): PPGresult =
|
||||||
var q = dbFormat(query, args)
|
var arr = allocCStringArray(args)
|
||||||
result = PQExec(db, q)
|
result = PQexecParams(db, query.string, int32(args.len), nil, arr,
|
||||||
if PQresultStatus(result) != PGRES_TUPLES_OK: dbError(db)
|
nil, nil, 0)
|
||||||
|
deallocCStringArray(arr)
|
||||||
|
if PQResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
|
||||||
|
|
||||||
|
proc setupQuery(db: TDbConn, stmtName: TSqlPrepared,
|
||||||
|
args: varargs[string]): PPGresult =
|
||||||
|
var arr = allocCStringArray(args)
|
||||||
|
result = PQexecPrepared(db, stmtName.string, int32(args.len), arr,
|
||||||
|
nil, nil, 0)
|
||||||
|
deallocCStringArray(arr)
|
||||||
|
if PQResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
|
||||||
|
|
||||||
|
proc prepare*(db: TDbConn; stmtName: string, query: TSqlQuery;
|
||||||
|
nParams: int): TSqlPrepared =
|
||||||
|
var res = PQprepare(db, stmtName, query.string, int32(nParams), nil)
|
||||||
|
if PQResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
|
||||||
|
return TSqlPrepared(stmtName)
|
||||||
|
|
||||||
proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
|
proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
|
||||||
for col in 0..cols-1:
|
for col in 0..cols-1:
|
||||||
setLen(r[col], 0)
|
setLen(r[col], 0)
|
||||||
var x = PQgetvalue(res, line, col)
|
var x = PQgetvalue(res, line, col)
|
||||||
add(r[col], x)
|
add(r[col], x)
|
||||||
|
|
||||||
iterator fastRows*(db: TDbConn, query: TSqlQuery,
|
iterator fastRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## executes the query and iterates over the result dataset. This is very
|
## executes the query and iterates over the result dataset. This is very
|
||||||
|
|
@ -109,6 +139,17 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery,
|
||||||
yield result
|
yield result
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
|
iterator fastRows*(db: TDbConn, stmtName: TSqlPrepared,
|
||||||
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
|
## executes the prepared query and iterates over the result dataset.
|
||||||
|
var res = setupQuery(db, stmtName, args)
|
||||||
|
var L = PQnfields(res)
|
||||||
|
var result = newRow(L)
|
||||||
|
for i in 0..PQntuples(res)-1:
|
||||||
|
setRow(res, result, i, L)
|
||||||
|
yield result
|
||||||
|
PQclear(res)
|
||||||
|
|
||||||
proc getRow*(db: TDbConn, query: TSqlQuery,
|
proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## retrieves a single row. If the query doesn't return any rows, this proc
|
## retrieves a single row. If the query doesn't return any rows, this proc
|
||||||
|
|
@ -119,40 +160,55 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
setRow(res, result, 0, L)
|
setRow(res, result, 0, L)
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
proc getAllRows*(db: TDbConn, query: TSqlQuery,
|
proc getRow*(db: TDbConn, stmtName: TSqlPrepared,
|
||||||
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
|
var res = setupQuery(db, stmtName, args)
|
||||||
|
var L = PQnfields(res)
|
||||||
|
result = newRow(L)
|
||||||
|
setRow(res, result, 0, L)
|
||||||
|
PQclear(res)
|
||||||
|
|
||||||
|
proc getAllRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
|
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
|
||||||
## executes the query and returns the whole result dataset.
|
## executes the query and returns the whole result dataset.
|
||||||
result = @[]
|
result = @[]
|
||||||
for r in FastRows(db, query, args):
|
for r in FastRows(db, query, args):
|
||||||
result.add(r)
|
result.add(r)
|
||||||
|
|
||||||
iterator rows*(db: TDbConn, query: TSqlQuery,
|
proc getAllRows*(db: TDbConn, stmtName: TSqlPrepared,
|
||||||
|
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
|
||||||
|
## executes the prepared query and returns the whole result dataset.
|
||||||
|
result = @[]
|
||||||
|
for r in FastRows(db, stmtName, args):
|
||||||
|
result.add(r)
|
||||||
|
|
||||||
|
iterator rows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
|
||||||
## same as `FastRows`, but slower and safe.
|
## same as `FastRows`, but slower and safe.
|
||||||
for r in items(GetAllRows(db, query, args)): yield r
|
for r in items(GetAllRows(db, query, args)): yield r
|
||||||
|
|
||||||
proc getValue*(db: TDbConn, query: TSqlQuery,
|
proc getValue*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
|
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
|
||||||
## executes the query and returns the first column of the first row of the
|
## executes the query and returns the first column of the first row of the
|
||||||
## result dataset. Returns "" if the dataset contains no rows or the database
|
## result dataset. Returns "" if the dataset contains no rows or the database
|
||||||
## value is NULL.
|
## value is NULL.
|
||||||
var x = PQgetvalue(setupQuery(db, query, args), 0, 0)
|
var x = PQgetvalue(setupQuery(db, query, args), 0, 0)
|
||||||
result = if isNil(x): "" else: $x
|
result = if isNil(x): "" else: $x
|
||||||
|
|
||||||
proc tryInsertID*(db: TDbConn, query: TSqlQuery,
|
proc tryInsertID*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].}=
|
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].}=
|
||||||
## executes the query (typically "INSERT") and returns the
|
## executes the query (typically "INSERT") and returns the
|
||||||
## generated ID for the row or -1 in case of an error. For Postgre this adds
|
## generated ID for the row or -1 in case of an error. For Postgre this adds
|
||||||
## ``RETURNING id`` to the query, so it only works if your primary key is
|
## ``RETURNING id`` to the query, so it only works if your primary key is
|
||||||
## named ``id``.
|
## named ``id``.
|
||||||
var x = PQgetvalue(setupQuery(db, TSqlQuery(string(query) & " RETURNING id"),
|
var x = PQgetvalue(setupQuery(db, TSqlQuery(string(query) & " RETURNING id"),
|
||||||
args), 0, 0)
|
args), 0, 0)
|
||||||
if not isNil(x):
|
if not isNil(x):
|
||||||
result = ParseBiggestInt($x)
|
result = ParseBiggestInt($x)
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
|
|
||||||
proc insertID*(db: TDbConn, query: TSqlQuery,
|
proc insertID*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
|
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
|
||||||
## executes the query (typically "INSERT") and returns the
|
## executes the query (typically "INSERT") and returns the
|
||||||
## generated ID for the row. For Postgre this adds
|
## generated ID for the row. For Postgre this adds
|
||||||
|
|
@ -161,9 +217,9 @@ proc insertID*(db: TDbConn, query: TSqlQuery,
|
||||||
result = TryInsertID(db, query, args)
|
result = TryInsertID(db, query, args)
|
||||||
if result < 0: dbError(db)
|
if result < 0: dbError(db)
|
||||||
|
|
||||||
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
|
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
|
||||||
args: varargs[string, `$`]): int64 {.tags: [
|
args: varargs[string, `$`]): int64 {.tags: [
|
||||||
FReadDB, FWriteDb].} =
|
FReadDB, FWriteDb].} =
|
||||||
## executes the query (typically "UPDATE") and returns the
|
## executes the query (typically "UPDATE") and returns the
|
||||||
## number of affected rows.
|
## number of affected rows.
|
||||||
var q = dbFormat(query, args)
|
var q = dbFormat(query, args)
|
||||||
|
|
@ -172,7 +228,7 @@ proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
|
||||||
result = parseBiggestInt($PQcmdTuples(res))
|
result = parseBiggestInt($PQcmdTuples(res))
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
proc close*(db: TDbConn) {.tags: [FDb].} =
|
proc close*(db: TDbConn) {.tags: [FDb].} =
|
||||||
## closes the database connection.
|
## closes the database connection.
|
||||||
if db != nil: PQfinish(db)
|
if db != nil: PQfinish(db)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,12 @@ when not defined(windows):
|
||||||
|
|
||||||
when defined(linux):
|
when defined(linux):
|
||||||
import linux
|
import linux
|
||||||
|
|
||||||
|
when defined(freebsd) or defined(macosx):
|
||||||
|
{.emit:"#include <sys/types.h>".}
|
||||||
|
|
||||||
|
when defined(openbsd) or defined(netbsd):
|
||||||
|
{.emit:"#include <sys/param.h>".}
|
||||||
|
|
||||||
when defined(macosx) or defined(bsd):
|
when defined(macosx) or defined(bsd):
|
||||||
const
|
const
|
||||||
|
|
@ -26,7 +32,7 @@ when defined(macosx) or defined(bsd):
|
||||||
HW_NCPU = 3
|
HW_NCPU = 3
|
||||||
proc sysctl(x: ptr array[0..3, cint], y: cint, z: pointer,
|
proc sysctl(x: ptr array[0..3, cint], y: cint, z: pointer,
|
||||||
a: var csize, b: pointer, c: int): cint {.
|
a: var csize, b: pointer, c: int): cint {.
|
||||||
importc: "sysctl", header: "<sys/sysctl.h>".}
|
importc: "sysctl", header: "<sys/sysctl.h>".}
|
||||||
|
|
||||||
proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
|
proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
|
||||||
## returns the numer of the processors/cores the machine has.
|
## returns the numer of the processors/cores the machine has.
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ type
|
||||||
|
|
||||||
FlowVarBase* = ref FlowVarBaseObj ## untyped base class for 'FlowVar[T]'
|
FlowVarBase* = ref FlowVarBaseObj ## untyped base class for 'FlowVar[T]'
|
||||||
FlowVarBaseObj = object of TObject
|
FlowVarBaseObj = object of TObject
|
||||||
ready, usesCondVar: bool
|
ready, usesCondVar, awaited: bool
|
||||||
cv: CondVar #\
|
cv: CondVar #\
|
||||||
# for 'awaitAny' support
|
# for 'awaitAny' support
|
||||||
ai: ptr AwaitInfo
|
ai: ptr AwaitInfo
|
||||||
|
|
@ -129,8 +129,8 @@ type
|
||||||
proc await*(fv: FlowVarBase) =
|
proc await*(fv: FlowVarBase) =
|
||||||
## waits until the value for the flowVar arrives. Usually it is not necessary
|
## waits until the value for the flowVar arrives. Usually it is not necessary
|
||||||
## to call this explicitly.
|
## to call this explicitly.
|
||||||
if fv.usesCondVar:
|
if fv.usesCondVar and not fv.awaited:
|
||||||
fv.usesCondVar = false
|
fv.awaited = true
|
||||||
await(fv.cv)
|
await(fv.cv)
|
||||||
destroyCondVar(fv.cv)
|
destroyCondVar(fv.cv)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1332,10 +1332,10 @@ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
||||||
|
|
||||||
proc rawCreateDir(dir: string) =
|
proc rawCreateDir(dir: string) =
|
||||||
when defined(solaris):
|
when defined(solaris):
|
||||||
if mkdir(dir, 0o711) != 0'i32 and errno != EEXIST and errno != ENOSYS:
|
if mkdir(dir, 0o777) != 0'i32 and errno != EEXIST and errno != ENOSYS:
|
||||||
osError(osLastError())
|
osError(osLastError())
|
||||||
elif defined(unix):
|
elif defined(unix):
|
||||||
if mkdir(dir, 0o711) != 0'i32 and errno != EEXIST:
|
if mkdir(dir, 0o777) != 0'i32 and errno != EEXIST:
|
||||||
osError(osLastError())
|
osError(osLastError())
|
||||||
else:
|
else:
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
|
|
|
||||||
|
|
@ -78,10 +78,23 @@ when defined(macosx):
|
||||||
else:
|
else:
|
||||||
template SIGBUS: expr = SIGSEGV
|
template SIGBUS: expr = SIGSEGV
|
||||||
|
|
||||||
proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
|
when defined(nimSigSetjmp) and not defined(nimStdSetjmp):
|
||||||
header: "<setjmp.h>", importc: "longjmp".}
|
proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
|
||||||
proc c_setjmp(jmpb: C_JmpBuf): cint {.
|
header: "<setjmp.h>", importc: "siglongjmp".}
|
||||||
header: "<setjmp.h>", importc: "setjmp".}
|
template c_setjmp(jmpb: C_JmpBuf): cint =
|
||||||
|
proc c_sigsetjmp(jmpb: C_JmpBuf, savemask: cint): cint {.
|
||||||
|
header: "<setjmp.h>", importc: "sigsetjmp".}
|
||||||
|
c_sigsetjmp(jmpb, 0)
|
||||||
|
elif defined(nimRawSetjmp) and not defined(nimStdSetjmp):
|
||||||
|
proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
|
||||||
|
header: "<setjmp.h>", importc: "_longjmp".}
|
||||||
|
proc c_setjmp(jmpb: C_JmpBuf): cint {.
|
||||||
|
header: "<setjmp.h>", importc: "_setjmp".}
|
||||||
|
else:
|
||||||
|
proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
|
||||||
|
header: "<setjmp.h>", importc: "longjmp".}
|
||||||
|
proc c_setjmp(jmpb: C_JmpBuf): cint {.
|
||||||
|
header: "<setjmp.h>", importc: "setjmp".}
|
||||||
|
|
||||||
proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.
|
proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.
|
||||||
importc: "signal", header: "<signal.h>".}
|
importc: "signal", header: "<signal.h>".}
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,14 @@ when defined(boehmgc):
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc deallocShared(p: pointer) = boehmDealloc(p)
|
proc deallocShared(p: pointer) = boehmDealloc(p)
|
||||||
|
|
||||||
|
when hasThreadSupport:
|
||||||
|
proc getFreeSharedMem(): int =
|
||||||
|
boehmGetFreeBytes()
|
||||||
|
proc getTotalSharedMem(): int =
|
||||||
|
boehmGetHeapSize()
|
||||||
|
proc getOccupiedSharedMem(): int =
|
||||||
|
getTotalSharedMem() - getFreeSharedMem()
|
||||||
|
|
||||||
#boehmGCincremental()
|
#boehmGCincremental()
|
||||||
|
|
||||||
proc GC_disable() = boehmGC_disable()
|
proc GC_disable() = boehmGC_disable()
|
||||||
|
|
@ -164,11 +172,11 @@ when defined(boehmgc):
|
||||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
|
|
||||||
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -180,7 +188,7 @@ when defined(boehmgc):
|
||||||
proc alloc0(r: var TMemRegion, size: int): pointer =
|
proc alloc0(r: var TMemRegion, size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
proc dealloc(r: var TMemRegion, p: Pointer) = boehmDealloc(p)
|
proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)
|
||||||
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
|
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
|
||||||
proc deallocOsPages() {.inline.} = discard
|
proc deallocOsPages() {.inline.} = discard
|
||||||
|
|
||||||
|
|
@ -239,11 +247,11 @@ elif defined(nogc) and defined(useMalloc):
|
||||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
|
|
||||||
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -292,11 +300,11 @@ elif defined(nogc):
|
||||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
|
|
||||||
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
|
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
var allocator {.rtlThreadVar.}: TMemRegion
|
var allocator {.rtlThreadVar.}: TMemRegion
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,8 @@ proc PQexecParams*(conn: PPGconn, command: cstring, nParams: int32,
|
||||||
paramTypes: POid, paramValues: cstringArray,
|
paramTypes: POid, paramValues: cstringArray,
|
||||||
paramLengths, paramFormats: ptr int32, resultFormat: int32): PPGresult{.
|
paramLengths, paramFormats: ptr int32, resultFormat: int32): PPGresult{.
|
||||||
cdecl, dynlib: dllName, importc: "PQexecParams".}
|
cdecl, dynlib: dllName, importc: "PQexecParams".}
|
||||||
|
proc PQprepare*(conn: PPGconn, stmtName, query: cstring, nParams: int32,
|
||||||
|
paramTypes: POid): PPGresult{.cdecl, dynlib: dllName, importc: "PQprepare".}
|
||||||
proc PQexecPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32,
|
proc PQexecPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32,
|
||||||
paramValues: cstringArray,
|
paramValues: cstringArray,
|
||||||
paramLengths, paramFormats: ptr int32, resultFormat: int32): PPGresult{.
|
paramLengths, paramFormats: ptr int32, resultFormat: int32): PPGresult{.
|
||||||
|
|
|
||||||
85
web/news.txt
85
web/news.txt
|
|
@ -2,51 +2,58 @@
|
||||||
News
|
News
|
||||||
====
|
====
|
||||||
|
|
||||||
..
|
2014-10-11 Version 0.9.6 released
|
||||||
2014-06-29 Version 0.9.6 released
|
=================================
|
||||||
=================================
|
|
||||||
|
|
||||||
Changes affecting backwards compatibility
|
**Note: This is the last release of Nimrod. The language has been renamed to
|
||||||
-----------------------------------------
|
Nim. Nim slightly breaks compatibility.**
|
||||||
|
|
||||||
- ``spawn`` now uses an elaborate self-adapting thread pool and as such
|
This is a maintenance release. The upcoming 0.10.0 release has all
|
||||||
has been moved into its own module. So to use it, you now have to import
|
the new features and exciting developments.
|
||||||
``threadpool``.
|
|
||||||
- The symbol binding rules in generics changed: ``bar`` in ``foo.bar`` is
|
|
||||||
now considered for implicit early binding.
|
|
||||||
- ``c2nim`` moved into its own repository and is now a Babel package.
|
|
||||||
- ``pas2nim`` moved into its own repository and is now a Babel package.
|
|
||||||
- ``system.$`` for floating point types now produces a human friendly string
|
|
||||||
representation.
|
|
||||||
- ``uri.TUrl`` as well as the ``parseurl`` module are now deprecated in favour
|
|
||||||
of the new ``TUri`` type in the ``uri`` module.
|
|
||||||
- The ``destructor`` pragma has been deprecated. Use the ``override`` pragma
|
|
||||||
instead. The destructor's name has to be ``destroy`` now.
|
|
||||||
- ``lambda`` is not a keyword anymore.
|
|
||||||
- **system.defined has been split into system.defined and system.declared**.
|
|
||||||
You have to use ``--symbol`` to declare new conditional symbols that can be
|
|
||||||
set via ``--define``.
|
|
||||||
- ``--threadanalysis:on`` is now the default. To make your program compile
|
|
||||||
you can disable it but this is only a temporary solution as this option
|
|
||||||
will disappear soon!
|
|
||||||
|
|
||||||
|
|
||||||
Language Additions
|
|
||||||
------------------
|
|
||||||
|
|
||||||
- There is a new ``parallel`` statement for safe fork&join parallel computing.
|
Changes affecting backwards compatibility
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
Library Additions
|
- ``spawn`` now uses an elaborate self-adapting thread pool and as such
|
||||||
-----------------
|
has been moved into its own module. So to use it, you now have to import
|
||||||
|
``threadpool``.
|
||||||
|
- The symbol binding rules in generics changed: ``bar`` in ``foo.bar`` is
|
||||||
|
now considered for implicit early binding.
|
||||||
|
- ``c2nim`` moved into its own repository and is now a Babel package.
|
||||||
|
- ``pas2nim`` moved into its own repository and is now a Babel package.
|
||||||
|
- ``system.$`` for floating point types now produces a human friendly string
|
||||||
|
representation.
|
||||||
|
- ``uri.TUrl`` as well as the ``parseurl`` module are now deprecated in favour
|
||||||
|
of the new ``TUri`` type in the ``uri`` module.
|
||||||
|
- The ``destructor`` pragma has been deprecated. Use the ``override`` pragma
|
||||||
|
instead. The destructor's name has to be ``destroy`` now.
|
||||||
|
- ``lambda`` is not a keyword anymore.
|
||||||
|
- **system.defined has been split into system.defined and system.declared**.
|
||||||
|
You have to use ``--symbol`` to declare new conditional symbols that can be
|
||||||
|
set via ``--define``.
|
||||||
|
- ``--threadanalysis:on`` is now the default. To make your program compile
|
||||||
|
you can disable it but this is only a temporary solution as this option
|
||||||
|
will disappear soon!
|
||||||
|
|
||||||
- Added module ``cpuinfo``.
|
|
||||||
- Added module ``threadpool``.
|
Language Additions
|
||||||
- ``sequtils.distnct`` has been renamed to ``sequtils.deduplicate``.
|
------------------
|
||||||
- Added ``algorithm.reversed``
|
|
||||||
- Added ``uri.combine`` and ``uri.parseUri``.
|
- This version introduces the new ``deprecated`` pragma statement that is used
|
||||||
- Some sockets procedures now support a ``SafeDisconn`` flag which causes
|
to handle the upcoming massive amount of symbol renames.
|
||||||
them to handle disconnection errors and not raise them.
|
|
||||||
|
|
||||||
|
Library Additions
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
- Added module ``cpuinfo``.
|
||||||
|
- Added module ``threadpool``.
|
||||||
|
- ``sequtils.distnct`` has been renamed to ``sequtils.deduplicate``.
|
||||||
|
- Added ``algorithm.reversed``
|
||||||
|
- Added ``uri.combine`` and ``uri.parseUri``.
|
||||||
|
- Some sockets procedures now support a ``SafeDisconn`` flag which causes
|
||||||
|
them to handle disconnection errors and not raise them.
|
||||||
|
|
||||||
|
|
||||||
2014-04-21 Version 0.9.4 released
|
2014-04-21 Version 0.9.4 released
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue