mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 19:03:42 +00:00
Compare commits
61 Commits
pr_extend_
...
v1.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
193b3c66bb | ||
|
|
0b134412f8 | ||
|
|
1526ae8791 | ||
|
|
b914573d18 | ||
|
|
f579d29b68 | ||
|
|
f79f7fed98 | ||
|
|
e0c4015bbe | ||
|
|
7b500cbfad | ||
|
|
53e4692665 | ||
|
|
b0e595b3cf | ||
|
|
4e3c997d40 | ||
|
|
f16bb4d85b | ||
|
|
8f1dea614e | ||
|
|
63d710f5a1 | ||
|
|
2ebd47089a | ||
|
|
535f0b9c9d | ||
|
|
813b371758 | ||
|
|
a09379f5fd | ||
|
|
e9f7455bd6 | ||
|
|
e03b1b79ae | ||
|
|
0ea770c8f0 | ||
|
|
8a0012de42 | ||
|
|
1d4916b481 | ||
|
|
2de758e68a | ||
|
|
c8c9699850 | ||
|
|
5df7f3fd5c | ||
|
|
44d45b763c | ||
|
|
f7c150766a | ||
|
|
4ae143ca60 | ||
|
|
0a8dcd5e11 | ||
|
|
929aa99665 | ||
|
|
bae10d44fa | ||
|
|
4632e8b26e | ||
|
|
97e2e06b00 | ||
|
|
b827431499 | ||
|
|
99d448deeb | ||
|
|
9afd19b236 | ||
|
|
0d0cf86401 | ||
|
|
5785444520 | ||
|
|
1b3f5eed70 | ||
|
|
517538dcf8 | ||
|
|
59916007cc | ||
|
|
a5bcbe6dff | ||
|
|
cd3d4b5e05 | ||
|
|
ac2181c5b9 | ||
|
|
4675aae90b | ||
|
|
a0402b2012 | ||
|
|
cbdc48ec66 | ||
|
|
f19edae1b8 | ||
|
|
c5b9a44894 | ||
|
|
3009eafc89 | ||
|
|
1e97abec96 | ||
|
|
95a655a975 | ||
|
|
39f5a2b218 | ||
|
|
6c1f389d72 | ||
|
|
1ae9cac3a4 | ||
|
|
fa7f5742d3 | ||
|
|
c8314b7c9c | ||
|
|
52ea15cc24 | ||
|
|
7926440ae3 | ||
|
|
bda6e071cd |
148
azure-pipelines.yml
Normal file
148
azure-pipelines.yml
Normal file
@@ -0,0 +1,148 @@
|
||||
strategy:
|
||||
matrix:
|
||||
Linux_amd64:
|
||||
vmImage: 'ubuntu-16.04'
|
||||
CPU: amd64
|
||||
Linux_i386:
|
||||
vmImage: 'ubuntu-16.04'
|
||||
CPU: i386
|
||||
OSX_amd64:
|
||||
vmImage: 'macOS-10.14'
|
||||
CPU: amd64
|
||||
OSX_amd64_cpp:
|
||||
vmImage: 'macOS-10.14'
|
||||
CPU: amd64
|
||||
NIM_COMPILE_TO_CPP: true
|
||||
Windows_amd64:
|
||||
vmImage: 'windows-2019'
|
||||
CPU: amd64
|
||||
Windows_amd64_pkg:
|
||||
vmImage: 'windows-2019'
|
||||
CPU: amd64
|
||||
NIM_TEST_PACKAGES: true
|
||||
|
||||
pool:
|
||||
vmImage: $(vmImage)
|
||||
|
||||
workspace:
|
||||
clean: all
|
||||
|
||||
steps:
|
||||
- bash: git config --global core.autocrlf false
|
||||
displayName: 'Disable auto conversion to CRLF by git (Windows-only)'
|
||||
condition: eq(variables['Agent.OS'], 'Windows_NT')
|
||||
|
||||
- checkout: self
|
||||
|
||||
- bash: git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
displayName: 'Checkout csources'
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '8.x'
|
||||
displayName: 'Install node.js 8.x'
|
||||
|
||||
- bash: |
|
||||
sudo apt-fast update -qq
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
sudo apt-fast install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev
|
||||
displayName: 'Install dependencies (amd64 Linux)'
|
||||
condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64'))
|
||||
|
||||
- bash: |
|
||||
sudo dpkg --add-architecture i386
|
||||
|
||||
# Downgrade llvm, libgcc and libstdc++:
|
||||
# - llvm has to be downgraded to have 32bit version installed for sfml.
|
||||
# - libgcc and libstdc++ have to be downgraded as an optimization to
|
||||
# prevent the use of the toolchain ppa, which has a terrible download
|
||||
# speed.
|
||||
cat << EOF | sudo tee /etc/apt/preferences.d/pin-to-rel
|
||||
Package: libllvm6.0 libgcc1 libstdc++6
|
||||
Pin: origin "azure.archive.ubuntu.com"
|
||||
Pin-Priority: 1001
|
||||
|
||||
Package: *
|
||||
Pin: release o=LP-PPA-ubuntu-toolchain-r-test
|
||||
Pin-Priority: 100
|
||||
EOF
|
||||
|
||||
sudo apt-fast update -qq
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
sudo apt-fast install --no-install-recommends --allow-downgrades -yq \
|
||||
g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \
|
||||
libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386
|
||||
|
||||
cat << EOF > bin/gcc
|
||||
#!/bin/bash
|
||||
|
||||
exec $(which gcc) -m32 "\$@"
|
||||
EOF
|
||||
cat << EOF > bin/g++
|
||||
#!/bin/bash
|
||||
|
||||
exec $(which g++) -m32 "\$@"
|
||||
EOF
|
||||
|
||||
chmod 755 bin/gcc
|
||||
chmod 755 bin/g++
|
||||
|
||||
displayName: 'Install dependencies (i386 Linux)'
|
||||
condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'i386'))
|
||||
|
||||
- bash: brew install boehmgc make sfml
|
||||
displayName: 'Install dependencies (OSX)'
|
||||
condition: eq(variables['Agent.OS'], 'Darwin')
|
||||
|
||||
- bash: |
|
||||
mkdir dist
|
||||
curl -L https://nim-lang.org/download/mingw64-6.3.0.7z -o dist/mingw64.7z
|
||||
curl -L https://nim-lang.org/download/dlls.zip -o dist/dlls.zip
|
||||
7z x dist/mingw64.7z -odist
|
||||
7z x dist/dlls.zip -obin
|
||||
echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/dist/mingw64/bin'
|
||||
|
||||
displayName: 'Install dependencies (Windows)'
|
||||
condition: eq(variables['Agent.OS'], 'Windows_NT')
|
||||
|
||||
- bash: echo '##vso[task.prependpath]$(System.DefaultWorkingDirectory)/bin'
|
||||
displayName: 'Add build binaries to PATH'
|
||||
|
||||
- bash: |
|
||||
echo 'PATH:' "$PATH"
|
||||
echo '##[section]gcc version'
|
||||
gcc -v
|
||||
echo '##[section]nodejs version'
|
||||
node -v
|
||||
echo '##[section]make version'
|
||||
make -v
|
||||
displayName: 'System information'
|
||||
|
||||
- bash: |
|
||||
ncpu=
|
||||
case '$(Agent.OS)' in
|
||||
'Linux')
|
||||
ncpu=$(nproc)
|
||||
;;
|
||||
'Darwin')
|
||||
ncpu=$(sysctl -n hw.ncpu)
|
||||
;;
|
||||
'Windows_NT')
|
||||
ncpu=$NUMBER_OF_PROCESSORS
|
||||
;;
|
||||
esac
|
||||
[[ -z "$ncpu" || $ncpu -le 0 ]] && ncpu=1
|
||||
|
||||
make -C csources -j $ncpu CC=gcc ucpu=$(CPU)
|
||||
displayName: 'Build csources'
|
||||
|
||||
- bash: nim c koch
|
||||
displayName: 'Build koch'
|
||||
|
||||
# set result to omit the "bash exited with error code '1'" message
|
||||
- bash: |
|
||||
./koch runCI || echo '##vso[task.complete result=Failed]'
|
||||
displayName: 'Run CI'
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
16
build_all.bat
Normal file
16
build_all.bat
Normal file
@@ -0,0 +1,16 @@
|
||||
@echo off
|
||||
rem build development version of the compiler; can be rerun safely
|
||||
if not exist csources (
|
||||
git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||
)
|
||||
if not exist bin\nim.exe (
|
||||
cd csources
|
||||
if PROCESSOR_ARCHITECTURE == AMD64 (
|
||||
SET ARCH=64
|
||||
)
|
||||
CALL build.bat
|
||||
cd ..
|
||||
)
|
||||
bin\nim.exe c --skipUserCfg --skipParentCfg koch
|
||||
koch.exe boot -d:release
|
||||
koch.exe tools
|
||||
@@ -71,7 +71,7 @@ iterator parseTableCells*(s: string, delim = '\t'): Cell =
|
||||
proc alignTable*(s: string, delim = '\t', fill = ' ', sep = " "): string =
|
||||
## formats a `delim`-delimited `s` representing a table; each cell is aligned
|
||||
## to a width that's computed for each column; consecutive columns are
|
||||
## delimted by `sep`, and alignment space is filled using `fill`.
|
||||
## delimited by `sep`, and alignment space is filled using `fill`.
|
||||
## More customized formatting can be done by calling `parseTableCells` directly.
|
||||
for cell in parseTableCells(s, delim):
|
||||
result.add cell.text
|
||||
|
||||
@@ -185,7 +185,7 @@ type
|
||||
nkStmtListExpr, # a statement list followed by an expr; this is used
|
||||
# to allow powerful multi-line templates
|
||||
nkBlockExpr, # a statement block ending in an expr; this is used
|
||||
# to allowe powerful multi-line templates that open a
|
||||
# to allow powerful multi-line templates that open a
|
||||
# temporary scope
|
||||
nkStmtListType, # a statement list ending in a type; for macros
|
||||
nkBlockType, # a statement block ending in a type; for macros
|
||||
@@ -272,7 +272,7 @@ type
|
||||
sfNamedParamCall, # symbol needs named parameter call syntax in target
|
||||
# language; for interfacing with Objective C
|
||||
sfDiscardable, # returned value may be discarded implicitly
|
||||
sfOverriden, # proc is overriden
|
||||
sfOverriden, # proc is overridden
|
||||
sfCallsite # A flag for template symbols to tell the
|
||||
# compiler it should use line information from
|
||||
# the calling side of the macro, not from the
|
||||
@@ -535,8 +535,8 @@ type
|
||||
tfTriggersCompileTime # uses the NimNode type which make the proc
|
||||
# implicitly '.compiletime'
|
||||
tfRefsAnonObj # used for 'ref object' and 'ptr object'
|
||||
tfCovariant # covariant generic param mimicing a ptr type
|
||||
tfWeakCovariant # covariant generic param mimicing a seq/array type
|
||||
tfCovariant # covariant generic param mimicking a ptr type
|
||||
tfWeakCovariant # covariant generic param mimicking a seq/array type
|
||||
tfContravariant # contravariant generic param
|
||||
tfCheckedForDestructor # type was checked for having a destructor.
|
||||
# If it has one, t.destructor is not nil.
|
||||
@@ -1250,7 +1250,7 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||
|
||||
proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
|
||||
|
||||
# this is dirty. abstractVarRange isn't defined yet and therefor it
|
||||
# this is dirty. abstractVarRange isn't defined yet and therefore it
|
||||
# is duplicated here.
|
||||
const abstractVarRange = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
|
||||
tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned}
|
||||
|
||||
@@ -1027,7 +1027,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
dec p.splitDecls
|
||||
|
||||
proc genEcho(p: BProc, n: PNode) =
|
||||
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||
# this unusual way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||
# is threadsafe.
|
||||
internalAssert p.config, n.kind == nkBracket
|
||||
if p.config.target.targetOS == osGenode:
|
||||
|
||||
@@ -784,7 +784,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
||||
var branches: seq[Rope]
|
||||
newSeq(branches, bitMask + 1)
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
|
||||
initLocExpr(p, t.sons[0], a) # fist pass: generate ifs+goto:
|
||||
var labId = p.labels
|
||||
for i in 1 ..< len(t):
|
||||
inc(p.labels)
|
||||
|
||||
@@ -61,7 +61,7 @@ proc mangleParamName(m: BModule; s: PSym): Rope =
|
||||
var res = s.name.s.mangle
|
||||
# Take into account if HCR is on because of the following scenario:
|
||||
# if a module gets imported and it has some more importc symbols in it,
|
||||
# some param names might recieve the "_0" suffix to distinguish from what
|
||||
# some param names might receive the "_0" suffix to distinguish from what
|
||||
# is newly available. That might lead to changes in the C code in nimcache
|
||||
# that contain only a parameter name change, but that is enough to mandate
|
||||
# recompilation of that source file and thus a new shared object will be
|
||||
@@ -287,6 +287,7 @@ proc fillResult(conf: ConfigRef; param: PNode) =
|
||||
|
||||
proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope =
|
||||
if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
|
||||
useHeader(m, t.sym)
|
||||
result = t.sym.loc.r
|
||||
else:
|
||||
result = rope(literal)
|
||||
|
||||
@@ -997,13 +997,14 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
closureSetup(p, prc)
|
||||
genStmts(p, procBody) # modifies p.locals, p.init, etc.
|
||||
var generatedProc: Rope
|
||||
generatedProc.genCLineDir prc.info, m.config
|
||||
if sfNoReturn in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
|
||||
header = "__declspec(noreturn) " & header
|
||||
if sfPure in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
|
||||
header = "__declspec(naked) " & header
|
||||
generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N",
|
||||
generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N",
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||
else:
|
||||
if m.hcrOn and isReloadable(m, prc):
|
||||
@@ -1011,7 +1012,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
# This fixes the use of methods and also the case when 2 functions within the same module
|
||||
# call each other using directly the "_actual" versions (an optimization) - see issue #11608
|
||||
addf(m.s[cfsProcHeaders], "$1;\n", [header])
|
||||
generatedProc = ropecg(p.module, "$N$1 {$N", [header])
|
||||
generatedProc.add ropecg(p.module, "$1 {", [header])
|
||||
add(generatedProc, initGCFrame(p))
|
||||
if optStackTrace in prc.options:
|
||||
add(generatedProc, p.s(cpsLocals))
|
||||
@@ -1255,7 +1256,7 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
|
||||
|
||||
proc genMainProc(m: BModule) =
|
||||
## this function is called in cgenWriteModules after all modules are closed,
|
||||
## it means raising dependency on the symbols is too late as it will not propogate
|
||||
## it means raising dependency on the symbols is too late as it will not propagate
|
||||
## into other modules, only simple rope manipulations are allowed
|
||||
|
||||
var preMainCode: Rope
|
||||
@@ -1514,7 +1515,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
|
||||
proc genDatInitCode(m: BModule) =
|
||||
## this function is called in cgenWriteModules after all modules are closed,
|
||||
## it means raising dependency on the symbols is too late as it will not propogate
|
||||
## it means raising dependency on the symbols is too late as it will not propagate
|
||||
## into other modules, only simple rope manipulations are allowed
|
||||
|
||||
var moduleDatInitRequired = m.hcrOn
|
||||
@@ -1558,7 +1559,7 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
|
||||
|
||||
proc genInitCode(m: BModule) =
|
||||
## this function is called in cgenWriteModules after all modules are closed,
|
||||
## it means raising dependency on the symbols is too late as it will not propogate
|
||||
## it means raising dependency on the symbols is too late as it will not propagate
|
||||
## into other modules, only simple rope manipulations are allowed
|
||||
var moduleInitRequired = m.hcrOn
|
||||
let initname = getInitName(m)
|
||||
@@ -1746,7 +1747,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
|
||||
result.typeNodesName = getTempName(result)
|
||||
result.nimTypesName = getTempName(result)
|
||||
# no line tracing for the init sections of the system module so that we
|
||||
# don't generate a TFrame which can confuse the stack botton initialization:
|
||||
# don't generate a TFrame which can confuse the stack bottom initialization:
|
||||
if sfSystemModule in module.flags:
|
||||
incl result.flags, preventStackTrace
|
||||
excl(result.preInitProc.options, optStackTrace)
|
||||
|
||||
@@ -58,7 +58,7 @@ type
|
||||
id*: int # the ID of the label; positive means that it
|
||||
label*: Rope # generated text for the label
|
||||
# nil if label is not used
|
||||
sections*: TCProcSections # the code beloging
|
||||
sections*: TCProcSections # the code belonging
|
||||
isLoop*: bool # whether block is a loop
|
||||
nestedTryStmts*: int16 # how many try statements is it nested into
|
||||
nestedExceptStmts*: int16 # how many except statements is it nested into
|
||||
@@ -150,7 +150,7 @@ type
|
||||
initProc*: BProc # code for init procedure
|
||||
preInitProc*: BProc # code executed before the init proc
|
||||
hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on
|
||||
inHcrInitGuard*: bool # We are currently withing a HCR reloading guard.
|
||||
inHcrInitGuard*: bool # We are currently within a HCR reloading guard.
|
||||
typeStack*: TTypeSeq # used for type generation
|
||||
dataCache*: TNodeTable
|
||||
typeNodes*, nimTypes*: int # used for type info generation
|
||||
|
||||
@@ -683,7 +683,8 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
n[0] = ex
|
||||
result.add(n)
|
||||
|
||||
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv:
|
||||
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv, nkObjDownConv,
|
||||
nkDerefExpr, nkHiddenDeref:
|
||||
var ns = false
|
||||
for i in 0 ..< n.len:
|
||||
n[i] = ctx.lowerStmtListExprs(n[i], ns)
|
||||
@@ -757,7 +758,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
|
||||
n[0] = newSymNode(ctx.g.getSysSym(n[0].info, "true"))
|
||||
n[1] = newBody
|
||||
|
||||
of nkDotExpr:
|
||||
of nkDotExpr, nkCheckedFieldExpr:
|
||||
var ns = false
|
||||
n[0] = ctx.lowerStmtListExprs(n[0], ns)
|
||||
if ns:
|
||||
@@ -1288,7 +1289,7 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
|
||||
if getEnvParam(fn).isNil:
|
||||
# Lambda lifting was not done yet. Use temporary :state sym, which will
|
||||
# be handled specially by lambda lifting. Local temp vars (if needed)
|
||||
# should folllow the same logic.
|
||||
# should follow the same logic.
|
||||
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info)
|
||||
ctx.stateVarSym.typ = g.createClosureIterStateType(fn)
|
||||
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info)
|
||||
@@ -1309,7 +1310,7 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
|
||||
# Optimize empty states away
|
||||
ctx.deleteEmptyStates()
|
||||
|
||||
# Make new body by concating the list of states
|
||||
# Make new body by concatenating the list of states
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
for s in ctx.states:
|
||||
assert(s.len == 2)
|
||||
|
||||
@@ -87,7 +87,7 @@ proc loadConfigsAndRunMainCommand*(self: NimProg, cache: IdentCache; conf: Confi
|
||||
discard
|
||||
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwite the config file's settings
|
||||
# command line can overwrite the config file's settings
|
||||
extccomp.initVars(conf)
|
||||
self.processCmdLine(passCmd2, "", conf)
|
||||
if conf.command == "":
|
||||
|
||||
@@ -513,7 +513,7 @@ proc genTry(c: var Con; n: PNode) =
|
||||
let f = c.tryStmtFixups[i]
|
||||
c.patch(f)
|
||||
# we also need to produce join instructions
|
||||
# for the 'fork' that might preceed the goto instruction
|
||||
# for the 'fork' that might precede the goto instruction
|
||||
if f.int-1 >= 0 and c.code[f.int-1].kind == fork:
|
||||
c.joinI(TPosition(f.int-1), n)
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode
|
||||
else:
|
||||
addSon(result, default.copyTree)
|
||||
|
||||
# add any generic paramaters
|
||||
# add any generic parameters
|
||||
for i in 1 .. genericParams:
|
||||
result.addSon n.sons[givenRegularParams + i]
|
||||
|
||||
|
||||
@@ -404,7 +404,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
|
||||
CC[c].name & fullSuffix
|
||||
result = getConfigVar(conf, fullCCname)
|
||||
if result.len == 0:
|
||||
# not overriden for this cross compilation setting?
|
||||
# not overridden for this cross compilation setting?
|
||||
result = getConfigVar(conf, CC[c].name & fullSuffix)
|
||||
else:
|
||||
result = getConfigVar(conf, CC[c].name & fullSuffix)
|
||||
@@ -757,7 +757,7 @@ proc getLinkCmd(conf: ConfigRef; output: AbsoluteFile,
|
||||
# way of being able to debug and rebuild the program at the same time. This
|
||||
# is accomplished using the /PDB:<filename> flag (there also exists the
|
||||
# /PDBALTPATH:<filename> flag). The only downside is that the .pdb files are
|
||||
# atleast 300kb big (when linking statically to the runtime - or else 5mb+)
|
||||
# at least 300kb big (when linking statically to the runtime - or else 5mb+)
|
||||
# and will quickly accumulate. There is a hacky solution: we could try to
|
||||
# delete all .pdb files with a pattern and swallow exceptions.
|
||||
#
|
||||
|
||||
@@ -22,7 +22,7 @@ type
|
||||
info: TLineInfo
|
||||
indent, emitPar: int
|
||||
x: string # the current input line
|
||||
outp: PLLStream # the ouput will be parsed by pnimsyn
|
||||
outp: PLLStream # the output will be parsed by pnimsyn
|
||||
subsChar, nimDirective: char
|
||||
emit, conc, toStr: string
|
||||
curly, bracket, par: int
|
||||
|
||||
@@ -14,7 +14,7 @@ proc hlo(c: PContext, n: PNode): PNode
|
||||
proc evalPattern(c: PContext, n, orig: PNode): PNode =
|
||||
internalAssert c.config, n.kind == nkCall and n.sons[0].kind == nkSym
|
||||
# we need to ensure that the resulting AST is semchecked. However, it's
|
||||
# aweful to semcheck before macro invocation, so we don't and treat
|
||||
# awful to semcheck before macro invocation, so we don't and treat
|
||||
# templates and macros as immediate in this context.
|
||||
var rule: string
|
||||
if optHints in c.config.options and hintPattern in c.config.notes:
|
||||
|
||||
@@ -27,7 +27,7 @@ proc importPureEnumField*(c: PContext; s: PSym) =
|
||||
if checkB == nil:
|
||||
strTableAdd(c.pureEnumFields, s)
|
||||
else:
|
||||
# mark as ambigous:
|
||||
# mark as ambiguous:
|
||||
incl(c.ambiguousSymbols, checkB.id)
|
||||
incl(c.ambiguousSymbols, s.id)
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@ proc isLastRead(n: PNode; c: var Con): bool =
|
||||
|
||||
proc initialized(code: ControlFlowGraph; pc: int,
|
||||
init, uninit: var IntSet; comesFrom: int): int =
|
||||
## Computes the set of definitely initialized variables accross all code paths
|
||||
## Computes the set of definitely initialized variables across all code paths
|
||||
## as an IntSet of IDs.
|
||||
var pc = pc
|
||||
while pc < code.len:
|
||||
@@ -492,7 +492,7 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||
result.add pArg(arg[i], c, i < L and isSinkTypeForParam(parameters[i]))
|
||||
elif arg.containsConstSeq:
|
||||
# const sequences are not mutable and so we need to pass a copy to the
|
||||
# sink parameter (bug #11524). Note that the string implemenation is
|
||||
# sink parameter (bug #11524). Note that the string implementation is
|
||||
# different and can deal with 'const string sunk into var'.
|
||||
result = passCopyToSink(arg, c)
|
||||
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkCharLit..nkTripleStrLit}:
|
||||
|
||||
@@ -73,6 +73,15 @@ proc toInt64*(arg: Int128): int64 =
|
||||
|
||||
cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
|
||||
|
||||
proc toInt64Checked*(arg: Int128; onError: int64): int64 =
|
||||
if isNegative(arg):
|
||||
if arg.sdata(3) != -1 or arg.sdata(2) != -1:
|
||||
return onError
|
||||
else:
|
||||
if arg.sdata(3) != 0 or arg.sdata(2) != 0:
|
||||
return onError
|
||||
return cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
|
||||
|
||||
proc toInt32*(arg: Int128): int32 =
|
||||
if isNegative(arg):
|
||||
assert(arg.sdata(3) == -1, "out of range")
|
||||
@@ -427,7 +436,7 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
|
||||
result.quotient = -quotient
|
||||
else:
|
||||
result.quotient = quotient
|
||||
if isNegativeB:
|
||||
if isNegativeA:
|
||||
result.remainder = -dividend
|
||||
else:
|
||||
result.remainder = dividend
|
||||
@@ -667,3 +676,12 @@ when isMainModule:
|
||||
|
||||
doAssert $high(Int128) == "170141183460469231731687303715884105727"
|
||||
doAssert $low(Int128) == "-170141183460469231731687303715884105728"
|
||||
|
||||
var ma = 100'i64
|
||||
var mb = 13
|
||||
|
||||
# sign correctness
|
||||
doAssert divMod(toInt128( ma),toInt128( mb)) == (toInt128( ma div mb), toInt128( ma mod mb))
|
||||
doAssert divMod(toInt128(-ma),toInt128( mb)) == (toInt128(-ma div mb), toInt128(-ma mod mb))
|
||||
doAssert divMod(toInt128( ma),toInt128(-mb)) == (toInt128( ma div -mb), toInt128( ma mod -mb))
|
||||
doAssert divMod(toInt128(-ma),toInt128(-mb)) == (toInt128(-ma div -mb), toInt128(-ma mod -mb))
|
||||
|
||||
@@ -1295,12 +1295,16 @@ proc genCopyForParamIfNeeded(p: PProc, n: PNode) =
|
||||
return
|
||||
owner = owner.up
|
||||
|
||||
proc genVarInit(p: PProc, v: PSym, n: PNode)
|
||||
|
||||
proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var s = n.sym
|
||||
case s.kind
|
||||
of skVar, skLet, skParam, skTemp, skResult, skForVar:
|
||||
if s.loc.r == nil:
|
||||
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
|
||||
if sfCompileTime in s.flags:
|
||||
genVarInit(p, s, if s.ast != nil: s.ast else: newNodeI(nkEmpty, s.info))
|
||||
if s.kind == skParam:
|
||||
genCopyForParamIfNeeded(p, n)
|
||||
let k = mapType(p, s.typ)
|
||||
@@ -1732,7 +1736,11 @@ proc genVarStmt(p: PProc, n: PNode) =
|
||||
var v = a.sons[0].sym
|
||||
if lfNoDecl notin v.loc.flags and sfImportc notin v.flags:
|
||||
genLineDir(p, a)
|
||||
genVarInit(p, v, a.sons[2])
|
||||
if sfCompileTime notin v.flags:
|
||||
genVarInit(p, v, a.sons[2])
|
||||
else:
|
||||
# lazy emit, done when it's actually used.
|
||||
if v.ast == nil: v.ast = a[2]
|
||||
|
||||
proc genConstant(p: PProc, c: PSym) =
|
||||
if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
|
||||
|
||||
@@ -477,7 +477,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
w = up
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit,
|
||||
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef,
|
||||
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt:
|
||||
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt, nkTypeOfExpr:
|
||||
discard
|
||||
of nkLambdaKinds, nkIteratorDef:
|
||||
if n.typ != nil:
|
||||
@@ -760,6 +760,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
n[0].sons[1] = liftCapturedVars(n[0].sons[1], owner, d, c)
|
||||
else:
|
||||
n.sons[0] = liftCapturedVars(n[0], owner, d, c)
|
||||
of nkTypeOfExpr:
|
||||
result = n
|
||||
else:
|
||||
if owner.isIterator:
|
||||
if nfLL in n.flags:
|
||||
|
||||
@@ -499,7 +499,8 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
|
||||
rememberSplit(splitComma)
|
||||
wrSpace em
|
||||
of openPars:
|
||||
if tok.strongSpaceA > 0 and not em.endsInWhite and not em.wasExportMarker:
|
||||
if tok.strongSpaceA > 0 and not em.endsInWhite and
|
||||
(not em.wasExportMarker or tok.tokType == tkCurlyDotLe):
|
||||
wrSpace em
|
||||
wr(em, TokTypeToStr[tok.tokType], ltSomeParLe)
|
||||
rememberSplit(splitParLe)
|
||||
|
||||
@@ -134,7 +134,7 @@ type
|
||||
TErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string)
|
||||
TLexer* = object of TBaseLexer
|
||||
fileIdx*: FileIndex
|
||||
indentAhead*: int # if > 0 an indendation has already been read
|
||||
indentAhead*: int # if > 0 an indentation has already been read
|
||||
# this is needed because scanning comments
|
||||
# needs so much look-ahead
|
||||
currLineIndent*: int
|
||||
|
||||
@@ -233,7 +233,7 @@ proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||
addInterfaceDeclAux(c, sym)
|
||||
|
||||
when defined(nimfix):
|
||||
# when we cannot find the identifier, retry with a changed identifer:
|
||||
# when we cannot find the identifier, retry with a changed identifier:
|
||||
proc altSpelling(x: PIdent): PIdent =
|
||||
case x.s[0]
|
||||
of 'A'..'Z': result = getIdent(toLowerAscii(x.s[0]) & x.s.substr(1))
|
||||
|
||||
@@ -64,7 +64,7 @@ type
|
||||
importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.}
|
||||
includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.}
|
||||
recordStmt*: proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.}
|
||||
cacheSeqs*: Table[string, PNode] # state that is shared to suppor the 'macrocache' API
|
||||
cacheSeqs*: Table[string, PNode] # state that is shared to support the 'macrocache' API
|
||||
cacheCounters*: Table[string, BiggestInt]
|
||||
cacheTables*: Table[string, BTree[string, PNode]]
|
||||
passes*: seq[TPass]
|
||||
@@ -215,7 +215,7 @@ proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
|
||||
addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false)
|
||||
if g.suggestMode:
|
||||
g.deps.incl m.position.dependsOn(dep.int)
|
||||
# we compute the transitive closure later when quering the graph lazily.
|
||||
# we compute the transitive closure later when querying the graph lazily.
|
||||
# this improves efficiency quite a lot:
|
||||
#invalidTransitiveClosure = true
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ proc selectUniqueSymbol*(i: Interpreter; name: string;
|
||||
s = nextIdentIter(it, i.mainModule.tab)
|
||||
|
||||
proc selectRoutine*(i: Interpreter; name: string): PSym =
|
||||
## Selects a declared rountine (proc/func/etc) from the main module.
|
||||
## Selects a declared routine (proc/func/etc) from the main module.
|
||||
## The routine needs to have the export marker ``*``. The only matching
|
||||
## routine is returned and ``nil`` if it is overloaded.
|
||||
result = selectUniqueSymbol(i, name, {skTemplate, skMacro, skFunc,
|
||||
|
||||
@@ -98,7 +98,7 @@ proc handleCmdLine(config: ConfigRef) =
|
||||
gProjectPath = getCurrentDir()
|
||||
loadConfigs(DefaultConfig, config) # load all config files
|
||||
# now process command line arguments again, because some options in the
|
||||
# command line can overwite the config file's settings
|
||||
# command line can overwrite the config file's settings
|
||||
extccomp.initVars()
|
||||
processCmdLine(passCmd2, "", config)
|
||||
mainCommand()
|
||||
|
||||
@@ -15,6 +15,6 @@ const
|
||||
VersionAsString* = system.NimVersion
|
||||
RodFileVersion* = "1223" # modify this if the rod-format changes!
|
||||
|
||||
NimCompilerApiVersion* = 3 ## Check for the existance of this before accessing it
|
||||
NimCompilerApiVersion* = 3 ## Check for the existence of this before accessing it
|
||||
## as older versions of the compiler API do not
|
||||
## declare this.
|
||||
|
||||
@@ -138,7 +138,7 @@ type
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
## Allows to modify a NimNode where the type has already been
|
||||
## flaged with nfSem. If you actually do this, it will cause
|
||||
## flagged with nfSem. If you actually do this, it will cause
|
||||
## bugs.
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
@@ -727,7 +727,7 @@ proc `$`*(c: IdeCmd): string =
|
||||
|
||||
proc floatInt64Align*(conf: ConfigRef): int16 =
|
||||
## Returns either 4 or 8 depending on reasons.
|
||||
if conf.target.targetCPU == cpuI386:
|
||||
if conf != nil and conf.target.targetCPU == cpuI386:
|
||||
#on Linux/BSD i386, double are aligned to 4bytes (except with -malign-double)
|
||||
if conf.target.targetOS != osWindows:
|
||||
# on i386 for all known POSIX systems, 64bits ints are aligned
|
||||
|
||||
@@ -40,19 +40,16 @@ proc getPackageName*(conf: ConfigRef; path: string): string =
|
||||
|
||||
proc fakePackageName*(conf: ConfigRef; path: AbsoluteFile): string =
|
||||
# foo-#head/../bar becomes @foo-@hhead@s..@sbar
|
||||
result = "@m" & relativeTo(path, conf.projectPath, '/').string.multiReplace({"/": "@s", "#": "@h", "@": "@@"})
|
||||
result = "@m" & relativeTo(path, conf.projectPath, '/').string.multiReplace({"/": "@s", "#": "@h", "@": "@@", ":": "@c"})
|
||||
|
||||
proc demanglePackageName*(path: string): string =
|
||||
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": ""})
|
||||
result = path.multiReplace({"@@": "@", "@h": "#", "@s": "/", "@m": "", "@c": ":"})
|
||||
|
||||
proc withPackageName*(conf: ConfigRef; path: AbsoluteFile): AbsoluteFile =
|
||||
let x = getPackageName(conf, path.string)
|
||||
if x.len == 0:
|
||||
result = path
|
||||
let (p, file, ext) = path.splitFile
|
||||
if x == "stdlib":
|
||||
# Hot code reloading now relies on 'stdlib_system' names etc.
|
||||
result = p / RelativeFile((x & '_' & file) & ext)
|
||||
else:
|
||||
let (p, file, ext) = path.splitFile
|
||||
if x == "stdlib":
|
||||
# Hot code reloading now relies on 'stdlib_system' names etc.
|
||||
result = p / RelativeFile((x & '_' & file) & ext)
|
||||
else:
|
||||
result = p / RelativeFile(fakePackageName(conf, path))
|
||||
result = p / RelativeFile(fakePackageName(conf, path))
|
||||
|
||||
@@ -710,7 +710,7 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
result = parseCast(p)
|
||||
else:
|
||||
parMessage(p, errExprExpected, p.tok)
|
||||
getTok(p) # we must consume a token here to prevend endless loops!
|
||||
getTok(p) # we must consume a token here to prevent endless loops!
|
||||
result = p.emptyNode
|
||||
|
||||
proc namedParams(p: var TParser, callee: PNode,
|
||||
|
||||
@@ -720,7 +720,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
|
||||
proc semCustomPragma(c: PContext, n: PNode): PNode =
|
||||
var callNode: PNode
|
||||
|
||||
if n.kind == nkIdent:
|
||||
if n.kind in {nkIdent, nkSym}:
|
||||
# pragma -> pragma()
|
||||
callNode = newTree(nkCall, n)
|
||||
elif n.kind == nkExprColonExpr:
|
||||
|
||||
@@ -29,7 +29,7 @@ proc equalGenericParams(procA, procB: PNode): bool =
|
||||
result = true
|
||||
|
||||
proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||
# Searchs for a forward declaration or a "twin" symbol of fn
|
||||
# Searches for a forward declaration or a "twin" symbol of fn
|
||||
# in the symbol table. If the parameter lists are exactly
|
||||
# the same the sym in the symbol table is returned, else nil.
|
||||
var it: TIdentIter
|
||||
@@ -108,7 +108,7 @@ when false:
|
||||
result = true
|
||||
|
||||
proc searchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||
# Searchs for the fn in the symbol table. If the parameter lists are suitable
|
||||
# Searches for the fn in the symbol table. If the parameter lists are suitable
|
||||
# for borrowing the sym in the symbol table is returned, else nil.
|
||||
var it: TIdentIter
|
||||
for scope in walkScopes(startScope):
|
||||
|
||||
@@ -640,7 +640,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
result = explicitGenericInstError(c, n)
|
||||
|
||||
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||
# Searchs for the fn in the symbol table. If the parameter lists are suitable
|
||||
# Searches for the fn in the symbol table. If the parameter lists are suitable
|
||||
# for borrowing the sym in the symbol table is returned, else nil.
|
||||
# New approach: generate fn(x, y, z) where x, y, z have the proper types
|
||||
# and use the overloading resolution mechanism:
|
||||
|
||||
@@ -2038,7 +2038,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
let oldErrorMax = c.config.errorMax
|
||||
let oldCompilesId = c.compilesContextId
|
||||
# if this is a nested 'when compiles', do not increase the ID so that
|
||||
# generic instantations can still be cached for this level.
|
||||
# generic instantiations can still be cached for this level.
|
||||
if c.compilesContextId == 0:
|
||||
inc c.compilesContextIdGenerator
|
||||
c.compilesContextId = c.compilesContextIdGenerator
|
||||
|
||||
@@ -211,7 +211,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||
param.typ = makeTypeDesc(c, header[i+1])
|
||||
|
||||
# this scope was not created by the user,
|
||||
# unused params shoudn't be reported.
|
||||
# unused params shouldn't be reported.
|
||||
param.flags.incl sfUsed
|
||||
addDecl(c, param)
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ proc semDynamicBindSym(c: PContext, n: PNode): PNode =
|
||||
a.setResult opBindSym(c, scope, a.getNode(0), a.getInt(1).int, a.getNode(2))
|
||||
|
||||
let
|
||||
# altough we use VM callback here, it is not
|
||||
# although we use VM callback here, it is not
|
||||
# executed like 'normal' VM callback
|
||||
idx = vm.registerCallback("bindSymImpl", bindSymWrapper)
|
||||
# dummy node to carry idx information to VM
|
||||
|
||||
@@ -339,7 +339,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
|
||||
result = initPartial
|
||||
if discriminatorVal.kind == nkIntLit:
|
||||
# When the discriminator is a compile-time value, we also know
|
||||
# which brach will be selected:
|
||||
# which branch will be selected:
|
||||
let matchedBranch = recNode.pickCaseBranch discriminatorVal
|
||||
if matchedBranch != nil: checkMissingFields matchedBranch
|
||||
else:
|
||||
|
||||
@@ -575,7 +575,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode)
|
||||
notNilCheck(tracked, n, paramType)
|
||||
|
||||
proc breaksBlock(n: PNode): bool =
|
||||
# sematic check doesn't allow statements after raise, break, return or
|
||||
# semantic check doesn't allow statements after raise, break, return or
|
||||
# call to noreturn proc, so it is safe to check just the last statements
|
||||
var it = n
|
||||
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
|
||||
@@ -751,7 +751,9 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
discard
|
||||
else:
|
||||
message(tracked.config, arg.info, warnProveInit, $arg)
|
||||
createTypeBoundOps(tracked.graph, tracked.c, n[1].typ.lastSon, n.info)
|
||||
# check required for 'nim check':
|
||||
if n[1].typ.len > 0:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, n[1].typ.lastSon, n.info)
|
||||
for i in 0 ..< safeLen(n):
|
||||
track(tracked, n.sons[i])
|
||||
of nkDotExpr:
|
||||
|
||||
@@ -635,6 +635,12 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
errorUndeclaredIdentifier(c, n.sons[0].info, typ.sym.name.s)
|
||||
elif not isOrdinalType(typ):
|
||||
localError(c.config, n.sons[0].info, "selector must be of an ordinal type, float or string")
|
||||
elif firstOrd(c.config, typ) != 0:
|
||||
localError(c.config, n.info, "low(" & $a.sons[0].sym.name.s &
|
||||
") must be 0 for discriminant")
|
||||
elif lengthOrd(c.config, typ) > 0x00007FFF:
|
||||
localError(c.config, n.info, "len($1) must be less than 32768" % a.sons[0].sym.name.s)
|
||||
|
||||
for i in 1 ..< len(n):
|
||||
var b = copyTree(n.sons[i])
|
||||
addSon(a, b)
|
||||
|
||||
@@ -76,13 +76,13 @@ type
|
||||
c*: PContext
|
||||
typeMap*: ptr LayeredIdTable # map PType to PType
|
||||
symMap*: TIdTable # map PSym to PSym
|
||||
localCache*: TIdTable # local cache for remembering alraedy replaced
|
||||
localCache*: TIdTable # local cache for remembering already replaced
|
||||
# types during instantiation of meta types
|
||||
# (they are not stored in the global cache)
|
||||
info*: TLineInfo
|
||||
allowMetaTypes*: bool # allow types such as seq[Number]
|
||||
# i.e. the result contains unresolved generics
|
||||
skipTypedesc*: bool # wether we should skip typeDescs
|
||||
skipTypedesc*: bool # whether we should skip typeDescs
|
||||
isReturnType*: bool
|
||||
owner*: PSym # where this instantiation comes from
|
||||
recursionLimit: int
|
||||
@@ -249,7 +249,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
||||
return s
|
||||
|
||||
# XXX: Bound symbols in default parameter expressions may reach here.
|
||||
# We cannot process them, becase `sym.n` may point to a proc body with
|
||||
# We cannot process them, because `sym.n` may point to a proc body with
|
||||
# cyclic references that will lead to an infinite recursion.
|
||||
# Perhaps we should not use a black-list here, but a whitelist instead
|
||||
# (e.g. skGenericParam and skType).
|
||||
@@ -589,7 +589,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
for i in 0 ..< len(result):
|
||||
if result.sons[i] != nil:
|
||||
if result.sons[i].kind == tyGenericBody:
|
||||
localError(cl.c.config, t.sym.info,
|
||||
localError(cl.c.config, if t.sym != nil: t.sym.info else: cl.info,
|
||||
"cannot instantiate '" &
|
||||
typeToString(result.sons[i], preferDesc) &
|
||||
"' inside of type definition: '" &
|
||||
|
||||
@@ -16,11 +16,12 @@ proc align(address, alignment: int): int =
|
||||
result = (address + (alignment - 1)) and not (alignment - 1)
|
||||
|
||||
const
|
||||
## a size is concidered "unknown" when it is an imported type from C
|
||||
## a size is considered "unknown" when it is an imported type from C
|
||||
## or C++.
|
||||
szUnknownSize* = -3
|
||||
szIllegalRecursion* = -2
|
||||
szUncomputedSize* = -1
|
||||
szTooBigSize* = -4
|
||||
|
||||
type IllegalTypeRecursionError = object of Exception
|
||||
|
||||
@@ -33,14 +34,14 @@ type
|
||||
offset: int
|
||||
|
||||
proc inc(arg: var OffsetAccum; value: int) =
|
||||
if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if value == szUnknownSize or arg.offset == szUnknownSize:
|
||||
arg.offset = szUnknownSize
|
||||
else:
|
||||
arg.offset += value
|
||||
|
||||
proc alignmentMax(a,b: int): int =
|
||||
if unlikely(a == szIllegalRecursion or b == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if unlikely(a == szIllegalRecursion or b == szIllegalRecursion): raiseIllegalTypeRecursion()
|
||||
if a == szUnknownSize or b == szUnknownSize:
|
||||
szUnknownSize
|
||||
else:
|
||||
@@ -57,7 +58,7 @@ proc align(arg: var OffsetAccum; value: int) =
|
||||
|
||||
proc mergeBranch(arg: var OffsetAccum; value: OffsetAccum) =
|
||||
if value.maxAlign == szUnknownSize or arg.maxAlign == szUnknownSize or
|
||||
value.offset == szUnknownSize or arg.offset == szUnknownSize:
|
||||
value.offset == szUnknownSize or arg.offset == szUnknownSize:
|
||||
arg.maxAlign = szUnknownSize
|
||||
arg.offset = szUnknownSize
|
||||
else:
|
||||
@@ -111,7 +112,7 @@ proc setOffsetsToUnknown(n: PNode) =
|
||||
for i in 0 ..< safeLen(n):
|
||||
setOffsetsToUnknown(n[i])
|
||||
|
||||
proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, accum: var OffsetAccum): void =
|
||||
proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, accum: var OffsetAccum) =
|
||||
## ``offset`` is the offset within the object, after the node has been written, no padding bytes added
|
||||
## ``align`` maximum alignment from all sub nodes
|
||||
assert n != nil
|
||||
@@ -256,7 +257,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
|
||||
typ.size = elemSize
|
||||
typ.align = int16(elemSize)
|
||||
else:
|
||||
typ.size = toInt64(lengthOrd(conf, typ.sons[0]) * int32(elemSize))
|
||||
typ.size = toInt64Checked(lengthOrd(conf, typ.sons[0]) * int32(elemSize), szTooBigSize)
|
||||
typ.align = typ.sons[1].align
|
||||
|
||||
of tyUncheckedArray:
|
||||
|
||||
@@ -877,7 +877,7 @@ proc hoistParamsUsedInDefault(c: PTransf, call, letSection, defExpr: PNode): PNo
|
||||
# The recursion may confuse you. It performs two duties:
|
||||
#
|
||||
# 1) extracting all referenced params from default expressions
|
||||
# into a let section preceeding the call
|
||||
# into a let section preceding the call
|
||||
#
|
||||
# 2) replacing the "references" within the default expression
|
||||
# with these extracted skLet symbols.
|
||||
@@ -1140,7 +1140,7 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
|
||||
|
||||
let cache = cache or prc.typ.callConv == ccInline
|
||||
if cache:
|
||||
# genProc for inline procs will be called multiple times from diffrent modules,
|
||||
# genProc for inline procs will be called multiple times from different modules,
|
||||
# it is important to transform exactly once to get sym ids and locations right
|
||||
prc.transformedBody = result
|
||||
else:
|
||||
|
||||
@@ -303,7 +303,7 @@ proc analyseObjectWithTypeFieldAux(t: PType,
|
||||
|
||||
proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult =
|
||||
# this does a complex analysis whether a call to ``objectInit`` needs to be
|
||||
# made or intializing of the type field suffices or if there is no type field
|
||||
# made or initializing of the type field suffices or if there is no type field
|
||||
# at all in this type.
|
||||
var marker = initIntSet()
|
||||
result = analyseObjectWithTypeFieldAux(t, marker)
|
||||
@@ -814,11 +814,8 @@ proc floatRangeCheck*(x: BiggestFloat, t: PType): bool =
|
||||
false
|
||||
|
||||
proc lengthOrd*(conf: ConfigRef; t: PType): Int128 =
|
||||
case t.skipTypes(tyUserTypeClasses).kind
|
||||
of tyInt64, tyInt32, tyInt:
|
||||
# XXX: this is just wrong
|
||||
result = lastOrd(conf, t)
|
||||
of tyDistinct: result = lengthOrd(conf, t.sons[0])
|
||||
if t.skipTypes(tyUserTypeClasses).kind == tyDistinct:
|
||||
result = lengthOrd(conf, t.sons[0])
|
||||
else:
|
||||
let last = lastOrd(conf, t)
|
||||
let first = firstOrd(conf, t)
|
||||
|
||||
@@ -156,7 +156,7 @@ proc createStrKeepNode(x: var TFullReg; keepNode=true) =
|
||||
x.node = newNode(nkStrLit)
|
||||
# It not only hackey, it is also wrong for tgentemplate. The primary
|
||||
# cause of bugs like these is that the VM does not properly distinguish
|
||||
# between variable defintions (var foo = e) and variable updates (foo = e).
|
||||
# between variable definitions (var foo = e) and variable updates (foo = e).
|
||||
|
||||
include vmhooks
|
||||
|
||||
@@ -357,7 +357,7 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
|
||||
result = -1
|
||||
|
||||
# Traverse the stack starting from the end in order to execute the blocks in
|
||||
# the inteded order
|
||||
# the intended order
|
||||
for i in 1 .. f.safePoints.len:
|
||||
var pc = f.safePoints[^i]
|
||||
# Skip the `except` blocks
|
||||
@@ -436,12 +436,8 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType):
|
||||
let destDist = (sizeof(dest.intVal) - desttyp.size) * 8
|
||||
|
||||
var value = cast[BiggestUInt](src.intVal)
|
||||
when system.cpuEndian == bigEndian:
|
||||
value = (value shr srcDist) shl srcDist
|
||||
value = (value shr destDist) shl destDist
|
||||
else:
|
||||
value = (value shl srcDist) shr srcDist
|
||||
value = (value shl destDist) shr destDist
|
||||
value = (value shl srcDist) shr srcDist
|
||||
value = (value shl destDist) shr destDist
|
||||
dest.intVal = cast[BiggestInt](value)
|
||||
of tyFloat..tyFloat64:
|
||||
if dest.kind != rkFloat:
|
||||
@@ -714,7 +710,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of rkNode:
|
||||
if regs[ra].node.kind == nkNilLit:
|
||||
stackTrace(c, tos, pc, errNilAccess)
|
||||
assert nfIsRef in regs[ra].node.flags
|
||||
regs[ra].node[] = regs[rc].regToNode[]
|
||||
regs[ra].node.flags.incl nfIsRef
|
||||
else: stackTrace(c, tos, pc, errNilAccess)
|
||||
@@ -1189,7 +1184,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
tos.pushSafePoint(pc + rbx)
|
||||
assert c.code[pc+rbx].opcode in {opcExcept, opcFinally}
|
||||
of opcExcept:
|
||||
# This opcode is never executed, it only holds informations for the
|
||||
# This opcode is never executed, it only holds information for the
|
||||
# exception handling routines.
|
||||
doAssert(false)
|
||||
of opcFinally:
|
||||
@@ -1275,7 +1270,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
|
||||
# opcLdNull really is the gist of the VM's problems: should it load
|
||||
# a fresh null to regs[ra].node or to regs[ra].node[]? This really
|
||||
# depends on whether regs[ra] represents the variable itself or wether
|
||||
# depends on whether regs[ra] represents the variable itself or whether
|
||||
# it holds the indirection! Due to the way registers are re-used we cannot
|
||||
# say for sure here! --> The codegen has to deal with it
|
||||
# via 'genAsgnPatch'.
|
||||
@@ -1567,19 +1562,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc],
|
||||
c.module, c.config)
|
||||
of opcGorge:
|
||||
decodeBC(rkNode)
|
||||
inc pc
|
||||
let rd = c.code[pc].regA
|
||||
createStr regs[ra]
|
||||
if defined(nimsuggest) or c.config.cmd == cmdCheck:
|
||||
discard "don't run staticExec for 'nim suggest'"
|
||||
regs[ra].node.strVal = ""
|
||||
else:
|
||||
when defined(nimcore):
|
||||
decodeBC(rkNode)
|
||||
inc pc
|
||||
let rd = c.code[pc].regA
|
||||
|
||||
createStr regs[ra]
|
||||
regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
|
||||
regs[rc].node.strVal, regs[rd].node.strVal,
|
||||
c.debug[pc], c.config)[0]
|
||||
else:
|
||||
regs[ra].node.strVal = ""
|
||||
globalError(c.config, c.debug[pc], "VM is not built with 'gorge' support")
|
||||
of opcNError, opcNWarning, opcNHint:
|
||||
decodeB(rkNode)
|
||||
|
||||
@@ -127,7 +127,7 @@ proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
|
||||
ctx.debug.add(n.info)
|
||||
|
||||
proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
|
||||
# Takes the `b` register and the immediate `imm`, appies the operation `opc`,
|
||||
# Takes the `b` register and the immediate `imm`, applies the operation `opc`,
|
||||
# and stores the output value into `a`.
|
||||
# `imm` is signed and must be within [-128, 127]
|
||||
if imm >= -128 and imm <= 127:
|
||||
@@ -948,9 +948,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
c.genAddSubInt(n, dest, opcAddInt)
|
||||
of mInc, mDec:
|
||||
unused(c, n, dest)
|
||||
let opc = if m == mInc: opcAddInt else: opcSubInt
|
||||
let isUnsigned = n.sons[1].typ.skipTypes(abstractVarRange).kind in {tyUInt..tyUInt64}
|
||||
let opc = if not isUnsigned:
|
||||
if m == mInc: opcAddInt else: opcSubInt
|
||||
else:
|
||||
if m == mInc: opcAddu else: opcSubu
|
||||
let d = c.genx(n.sons[1])
|
||||
if n.sons[2].isInt8Lit:
|
||||
if n.sons[2].isInt8Lit and not isUnsigned:
|
||||
c.gABI(n, succ(opc), d, d, n.sons[2].intVal)
|
||||
else:
|
||||
let tmp = c.genx(n.sons[2])
|
||||
@@ -1316,7 +1320,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
of mMove:
|
||||
let arg = n[1]
|
||||
let a = c.genx(arg)
|
||||
assert dest >= 0
|
||||
if dest < 0: dest = c.getTemp(arg.typ)
|
||||
gABC(c, arg, whichAsgnOpc(arg, requiresCopy=false), dest, a)
|
||||
# XXX use ldNullOpcode() here?
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
# Unforunately this cannot be a module yet:
|
||||
# Unfortunately this cannot be a module yet:
|
||||
#import vmdeps, vm
|
||||
from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
|
||||
arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
|
||||
|
||||
30
doc/gc.rst
30
doc/gc.rst
@@ -119,9 +119,12 @@ procs ``GC_ref`` and ``GC_unref`` to mark objects as referenced to avoid them
|
||||
being freed by the GC. Other useful procs from `system <system.html>`_ you can
|
||||
use to keep track of memory are:
|
||||
|
||||
* getTotalMem(): returns the amount of total memory managed by the GC.
|
||||
* getOccupiedMem(): bytes reserved by the GC and used by objects.
|
||||
* getFreeMem(): bytes reserved by the GC and not in use.
|
||||
* ``getTotalMem()`` Returns the amount of total memory managed by the GC.
|
||||
* ``getOccupiedMem()`` Bytes reserved by the GC and used by objects.
|
||||
* ``getFreeMem()`` Bytes reserved by the GC and not in use.
|
||||
|
||||
These numbers are usually only for the running thread, not for the whole heap,
|
||||
with the exception of ``--gc:boehm`` and ``--gc:go``.
|
||||
|
||||
In addition to ``GC_ref`` and ``GC_unref`` you can avoid the GC by manually
|
||||
allocating memory with procs like ``alloc``, ``allocShared``, or
|
||||
@@ -144,3 +147,24 @@ The numbers count the number of objects in all GC heaps, they refer to
|
||||
all running threads, not only to the current thread. (The current thread
|
||||
would be the thread that calls ``dumpNumberOfInstances``.) This might
|
||||
change in later versions.
|
||||
|
||||
|
||||
Garbage collector options
|
||||
-------------------------
|
||||
|
||||
You can choose which garbage collector to use when compiling source code,
|
||||
you can pass ``--gc:`` on the compile command with the choosed garbage collector.
|
||||
|
||||
- ``--gc:refc`` Deferred `reference counting <https://en.wikipedia.org/wiki/Reference_counting>`_ with cycle detection, `thread local heap <https://en.wikipedia.org/wiki/Heap_(programming)>`_, default.
|
||||
- ``--gc:markAndSweep`` `Mark-And-Sweep <https://en.wikipedia.org/wiki/Tracing_garbage_collection#Copying_vs._mark-and-sweep_vs._mark-and-don't-sweep>`_ based garbage collector, `thread local heap <https://en.wikipedia.org/wiki/Heap_(programming)>`_.
|
||||
- ``--gc:boehm`` `Boehm <https://en.wikipedia.org/wiki/Boehm_garbage_collector>`_ based garbage collector, `stop-the-world <https://en.wikipedia.org/wiki/Tracing_garbage_collection#Stop-the-world_vs._incremental_vs._concurrent>`_, `shared heap <https://en.wikipedia.org/wiki/Heap_(programming)>`_.
|
||||
- ``--gc:go`` Go lang like garbage collector, `stop-the-world <https://en.wikipedia.org/wiki/Tracing_garbage_collection#Stop-the-world_vs._incremental_vs._concurrent>`_, `shared heap <https://en.wikipedia.org/wiki/Heap_(programming)>`_.
|
||||
- ``--gc:regions`` `Stack <https://en.wikipedia.org/wiki/Memory_management#Stack_allocation>`_ based garbage collector.
|
||||
- ``--gc:none`` No garbage collector.
|
||||
|
||||
The same Nim code can compile to use any of the garbage collectors,
|
||||
the Nim syntax mostly wont change from one garbage collector to another.
|
||||
No garbage collector is used for `JavaScript and NodeJS <https://nim-lang.github.io/Nim/backends.html#backends-the-javascript-target>`_ compilation targets.
|
||||
`NimScript <https://nim-lang.github.io/Nim/nims.html>`_ target uses Nim VM garbage collector.
|
||||
|
||||
If you are new to Nim and just starting, the default garbage collector is balanced to fit most common use cases.
|
||||
|
||||
@@ -450,9 +450,6 @@ Miscellaneous
|
||||
* `logging <logging.html>`_
|
||||
This module implements a simple logger.
|
||||
|
||||
* `quitprocs <quitprocs>`_
|
||||
Better implementation of ``system.addQuitProc``.
|
||||
|
||||
* `segfaults <segfaults.html>`_
|
||||
Turns access violations or segfaults into a ``NilAccessError`` exception.
|
||||
|
||||
|
||||
@@ -3508,8 +3508,8 @@ for details on how to change this behavior.
|
||||
Anonymous Procs
|
||||
---------------
|
||||
|
||||
Procs can also be treated as expressions, in which case it's allowed to omit
|
||||
the proc's name.
|
||||
Unnamed procedures can be used as lambda expressions to pass into other
|
||||
procedures:
|
||||
|
||||
.. code-block:: nim
|
||||
var cities = @["Frankfurt", "Tokyo", "New York", "Kyiv"]
|
||||
@@ -3519,7 +3519,9 @@ the proc's name.
|
||||
|
||||
|
||||
Procs as expressions can appear both as nested procs and inside top level
|
||||
executable code.
|
||||
executable code. The `sugar <sugar.html>`_ module contains the `=>` macro
|
||||
which enables a more succinct syntax for anonymous procedures resembling
|
||||
lambdas as they are in languages like JavaScript, C#, etc.
|
||||
|
||||
|
||||
Func
|
||||
@@ -3691,7 +3693,7 @@ type.
|
||||
|
||||
method eval(e: Expression): int {.base.} =
|
||||
# override this base method
|
||||
quit "to override!"
|
||||
raise newException(CatchableError, "Method without implementation override")
|
||||
|
||||
method eval(e: Literal): int = return e.x
|
||||
|
||||
@@ -6219,6 +6221,25 @@ but are used to override the settings temporarily. Example:
|
||||
# ... some code ...
|
||||
{.pop.} # restore old settings
|
||||
|
||||
`push/pop`:idx: can switch on/off some standard library pragmas, example:
|
||||
|
||||
.. code-block:: nim
|
||||
{.push inline.}
|
||||
proc thisIsInlined(): int = 42
|
||||
func willBeInlined(): float = 42.0
|
||||
{.pop.}
|
||||
proc notInlined(): int = 9
|
||||
|
||||
{.push discardable, boundChecks: off, compileTime, noSideEffect, experimental.}
|
||||
template example(): string = "https://nim-lang.org"
|
||||
{.pop.}
|
||||
|
||||
{.push deprecated, hint[LineTooLong]: off, used, stackTrace: off.}
|
||||
proc sample(): bool = true
|
||||
{.pop.}
|
||||
|
||||
For third party pragmas it depends on its implementation, but uses the same syntax.
|
||||
|
||||
|
||||
register pragma
|
||||
---------------
|
||||
|
||||
@@ -142,15 +142,6 @@ comments can also be nested.
|
||||
]#
|
||||
]#
|
||||
|
||||
You can also use the `discard statement <#procedures-discard-statement>`_ together with *long string
|
||||
literals* to create block comments:
|
||||
|
||||
.. code-block:: nim
|
||||
:test: "nim c $1"
|
||||
discard """ You can have any Nim code text commented
|
||||
out inside this with no indentation restrictions.
|
||||
yes("May I ask a pointless question?") """
|
||||
|
||||
|
||||
Numbers
|
||||
-------
|
||||
|
||||
12
koch.nim
12
koch.nim
@@ -169,6 +169,10 @@ proc bundleNimsuggest(args: string) =
|
||||
proc buildVccTool(args: string) =
|
||||
nimCompileFold("Compile Vcc", "tools/vccexe/vccexe.nim ", options = args)
|
||||
|
||||
proc bundleNimpretty(args: string) =
|
||||
nimCompileFold("Compile nimpretty", "nimpretty/nimpretty.nim",
|
||||
options = "-d:release " & args)
|
||||
|
||||
proc bundleWinTools(args: string) =
|
||||
nimCompile("tools/finish.nim", outputDir = "", options = args)
|
||||
|
||||
@@ -185,6 +189,7 @@ proc bundleWinTools(args: string) =
|
||||
proc zip(latest: bool; args: string) =
|
||||
bundleNimbleExe(latest, args)
|
||||
bundleNimsuggest(args)
|
||||
bundleNimpretty(args)
|
||||
bundleWinTools(args)
|
||||
nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
|
||||
[VersionAsString, compileNimInst])
|
||||
@@ -214,8 +219,7 @@ proc buildTools(args: string = "") =
|
||||
nimCompileFold("Compile nimgrep", "tools/nimgrep.nim",
|
||||
options = "-d:release " & args)
|
||||
when defined(windows): buildVccTool(args)
|
||||
nimCompileFold("Compile nimpretty", "nimpretty/nimpretty.nim",
|
||||
options = "-d:release " & args)
|
||||
bundleNimpretty(args)
|
||||
nimCompileFold("Compile nimfind", "tools/nimfind.nim",
|
||||
options = "-d:release " & args)
|
||||
nimCompileFold("Compile testament", "testament/testament.nim",
|
||||
@@ -316,8 +320,8 @@ proc boot(args: string) =
|
||||
# jsonbuild then uses the $project.json file to build the Nim binary.
|
||||
exec "$# $# $# $# --nimcache:$# --compileOnly compiler" / "nim.nim" %
|
||||
[nimi, bootOptions, extraOption, args, smartNimcache]
|
||||
exec "$# jsonscript --nimcache:$# compiler" / "nim.nim" %
|
||||
[nimi, smartNimcache]
|
||||
exec "$# jsonscript $# --nimcache:$# compiler" / "nim.nim" %
|
||||
[nimi, args, smartNimcache]
|
||||
|
||||
if sameFileContent(output, i.thVersion):
|
||||
copyExe(output, finalDest)
|
||||
|
||||
@@ -121,13 +121,13 @@ type
|
||||
|
||||
type
|
||||
NimIdent* {.deprecated.} = object of RootObj
|
||||
## represents a Nim identifier in the AST. **Note**: This is only
|
||||
## Represents a Nim identifier in the AST. **Note**: This is only
|
||||
## rarely useful, for identifier construction from a string
|
||||
## use ``ident"abc"``.
|
||||
|
||||
NimSymObj = object # hidden
|
||||
NimSym* {.deprecated.} = ref NimSymObj
|
||||
## represents a Nim *symbol* in the compiler; a *symbol* is a looked-up
|
||||
## Represents a Nim *symbol* in the compiler; a *symbol* is a looked-up
|
||||
## *ident*.
|
||||
|
||||
|
||||
@@ -141,45 +141,46 @@ const
|
||||
|
||||
proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.0: Use 'ident' or 'newIdentNode' instead.".}
|
||||
## constructs an identifier from the string `s`
|
||||
## Constructs an identifier from the string `s`.
|
||||
|
||||
proc toNimIdent*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.0: Use 'ident' or 'newIdentNode' instead.".}
|
||||
## constructs an identifier from the string `s`
|
||||
## Constructs an identifier from the string `s`.
|
||||
|
||||
proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.1; Use '==' on 'NimNode' instead.".}
|
||||
## compares two Nim identifiers
|
||||
## Compares two Nim identifiers.
|
||||
|
||||
proc `==`*(a, b: NimNode): bool {.magic: "EqNimrodNode", noSideEffect.}
|
||||
## compares two Nim nodes
|
||||
## Compare two Nim nodes. Return true if nodes are structurally
|
||||
## equivalent. This means two independently created nodes can be equal.
|
||||
|
||||
proc `==`*(a, b: NimSym): bool {.magic: "EqNimrodNode", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.1; Use '==(NimNode, NimNode)' instead.".}
|
||||
## compares two Nim symbols
|
||||
## Compares two Nim symbols.
|
||||
|
||||
{.pop.}
|
||||
|
||||
proc sameType*(a, b: NimNode): bool {.magic: "SameNodeType", noSideEffect.} =
|
||||
## compares two Nim nodes' types. Return true if the types are the same,
|
||||
## Compares two Nim nodes' types. Return true if the types are the same,
|
||||
## eg. true when comparing alias with original type.
|
||||
discard
|
||||
|
||||
proc len*(n: NimNode): int {.magic: "NLen", noSideEffect.}
|
||||
## returns the number of children of `n`.
|
||||
## Returns the number of children of `n`.
|
||||
|
||||
proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
|
||||
## get `n`'s `i`'th child.
|
||||
## Get `n`'s `i`'th child.
|
||||
|
||||
proc `[]`*(n: NimNode, i: BackwardsIndex): NimNode = n[n.len - i.int]
|
||||
## get `n`'s `i`'th child.
|
||||
## Get `n`'s `i`'th child.
|
||||
|
||||
template `^^`(n: NimNode, i: untyped): untyped =
|
||||
(when i is BackwardsIndex: n.len - int(i) else: int(i))
|
||||
|
||||
proc `[]`*[T, U](n: NimNode, x: HSlice[T, U]): seq[NimNode] =
|
||||
## slice operation for NimNode.
|
||||
## returns a seq of child of `n` who inclusive range [n[x.a], n[x.b]].
|
||||
## Slice operation for NimNode.
|
||||
## Returns a seq of child of `n` who inclusive range [n[x.a], n[x.b]].
|
||||
let xa = n ^^ x.a
|
||||
let L = (n ^^ x.b) - xa + 1
|
||||
result = newSeq[NimNode](L)
|
||||
@@ -188,10 +189,10 @@ proc `[]`*[T, U](n: NimNode, x: HSlice[T, U]): seq[NimNode] =
|
||||
|
||||
proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
|
||||
noSideEffect.}
|
||||
## set `n`'s `i`'th child to `child`.
|
||||
## Set `n`'s `i`'th child to `child`.
|
||||
|
||||
proc `[]=`*(n: NimNode, i: BackwardsIndex, child: NimNode) =
|
||||
## set `n`'s `i`'th child to `child`.
|
||||
## Set `n`'s `i`'th child to `child`.
|
||||
n[n.len - i.int] = child
|
||||
|
||||
template `or`*(x, y: NimNode): NimNode =
|
||||
@@ -220,10 +221,10 @@ proc add*(father: NimNode, children: varargs[NimNode]): NimNode {.
|
||||
## Returns the `father` node so that calls can be nested.
|
||||
|
||||
proc del*(father: NimNode, idx = 0, n = 1) {.magic: "NDel", noSideEffect.}
|
||||
## deletes `n` children of `father` starting at index `idx`.
|
||||
## Deletes `n` children of `father` starting at index `idx`.
|
||||
|
||||
proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
|
||||
## returns the `kind` of the node `n`.
|
||||
## Returns the `kind` of the node `n`.
|
||||
|
||||
proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
|
||||
## Returns an integer value from any integer literal or enum field symbol.
|
||||
@@ -244,17 +245,20 @@ proc getImpl*(s: NimSym): NimNode {.magic: "GetImpl", noSideEffect, deprecated:
|
||||
when defined(nimSymKind):
|
||||
proc symKind*(symbol: NimNode): NimSymKind {.magic: "NSymKind", noSideEffect.}
|
||||
proc getImpl*(symbol: NimNode): NimNode {.magic: "GetImpl", noSideEffect.}
|
||||
## Returns a copy of the declaration of a symbol or `nil`.
|
||||
proc strVal*(n: NimNode): string {.magic: "NStrVal", noSideEffect.}
|
||||
## retrieve the implementation of `symbol`. `symbol` can be a
|
||||
## routine or a const.
|
||||
## Returns the string value of an identifier, symbol, comment, or string literal.
|
||||
##
|
||||
## See also:
|
||||
## * `strVal= proc<#strVal=,NimNode,string>`_ for setting the string value.
|
||||
|
||||
proc `$`*(i: NimIdent): string {.magic: "NStrVal", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.1; Use 'strVal' instead.".}
|
||||
## converts a Nim identifier to a string
|
||||
## Converts a Nim identifier to a string.
|
||||
|
||||
proc `$`*(s: NimSym): string {.magic: "NStrVal", noSideEffect, deprecated:
|
||||
"Deprecated since version 0.18.1; Use 'strVal' instead.".}
|
||||
## converts a Nim symbol to a string
|
||||
## Converts a Nim symbol to a string.
|
||||
|
||||
else: # bootstrapping substitute
|
||||
proc getImpl*(symbol: NimNode): NimNode =
|
||||
@@ -278,22 +282,28 @@ else: # bootstrapping substitute
|
||||
|
||||
when defined(nimSymImplTransform):
|
||||
proc getImplTransformed*(symbol: NimNode): NimNode {.magic: "GetImplTransf", noSideEffect.}
|
||||
## for a typed proc returns the AST after transformation pass
|
||||
## For a typed proc returns the AST after transformation pass.
|
||||
|
||||
when defined(nimHasSymOwnerInMacro):
|
||||
proc owner*(sym: NimNode): NimNode {.magic: "SymOwner", noSideEffect.}
|
||||
## accepts node of kind nnkSym and returns its owner's symbol.
|
||||
## result is also mnde of kind nnkSym if owner exists otherwise
|
||||
## nnkNilLit is returned
|
||||
## Accepts a node of kind `nnkSym` and returns its owner's symbol.
|
||||
## The meaning of 'owner' depends on `sym`'s `NimSymKind` and declaration
|
||||
## context. For top level declarations this is an `nskModule` symbol,
|
||||
## for proc local variables an `nskProc` symbol, for enum/object fields an
|
||||
## `nskType` symbol, etc. For symbols without an owner, `nil` is returned.
|
||||
##
|
||||
## See also:
|
||||
## * `symKind proc<#symKind,NimNode>`_ to get the kind of a symbol
|
||||
## * `getImpl proc<#getImpl,NimNode>`_ to get the declaration of a symbol
|
||||
|
||||
when defined(nimHasInstantiationOfInMacro):
|
||||
proc isInstantiationOf*(instanceProcSym, genProcSym: NimNode): bool {.magic: "SymIsInstantiationOf", noSideEffect.}
|
||||
## check if proc symbol is instance of the generic proc symbol
|
||||
## useful to check proc symbols against generic symbols
|
||||
## returned by `bindSym`
|
||||
## Checks if a proc symbol is an instance of the generic proc symbol.
|
||||
## Useful to check proc symbols against generic symbols
|
||||
## returned by `bindSym`.
|
||||
|
||||
proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
|
||||
## with 'getType' you can access the node's `type`:idx:. A Nim type is
|
||||
## With 'getType' you can access the node's `type`:idx:. A Nim type is
|
||||
## mapped to a Nim AST too, so it's slightly confusing but it means the same
|
||||
## API can be used to traverse types. Recursive types are flattened for you
|
||||
## so there is no danger of infinite recursions during traversal. To
|
||||
@@ -301,10 +311,7 @@ proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
|
||||
## kind of type it is, call `typeKind` on getType's result.
|
||||
|
||||
proc getType*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
|
||||
## Returns the Nim type node for given type. This can be used to turn macro
|
||||
## typedesc parameter into proper NimNode representing type, since typedesc
|
||||
## are an exception in macro calls - they are not mapped implicitly to
|
||||
## NimNode like any other arguments.
|
||||
## Version of ``getType`` which takes a ``typedesc``.
|
||||
|
||||
proc typeKind*(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect.}
|
||||
## Returns the type kind of the node 'n' that should represent a type, that
|
||||
@@ -333,8 +340,8 @@ proc getTypeInst*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
|
||||
|
||||
proc getTypeImpl*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} =
|
||||
## Returns the `type`:idx: of a node in a form matching the implementation
|
||||
## of the type. Any intermediate aliases are expanded to arrive at the final
|
||||
## type implementation. You can instead use ``getImpl`` on a symbol if you
|
||||
## of the type. Any intermediate aliases are expanded to arrive at the final
|
||||
## type implementation. You can instead use ``getImpl`` on a symbol if you
|
||||
## want to find the intermediate aliases.
|
||||
runnableExamples:
|
||||
type
|
||||
@@ -364,7 +371,7 @@ when defined(nimHasSignatureHashInMacro):
|
||||
|
||||
proc symBodyHash*(s: NimNode): string {.noSideEffect.} =
|
||||
## Returns a stable digest for symbols derived not only from type signature
|
||||
## and owning module, but also implementation body. All procs/varibles used in
|
||||
## and owning module, but also implementation body. All procs/variables used in
|
||||
## the implementation of this symbol are hashed recursively as well, including
|
||||
## magics from system module.
|
||||
discard
|
||||
@@ -393,6 +400,14 @@ proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect, de
|
||||
# bracket[0] = fake # constructs a mixed array with ints and floats!
|
||||
|
||||
proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
|
||||
## Sets the string value of a string literal or comment.
|
||||
## Setting `strVal` is disallowed for `nnkIdent` and `nnkSym` nodes; a new node
|
||||
## must be created using `ident` or `bindSym` instead.
|
||||
##
|
||||
## See also:
|
||||
## * `strVal proc<#strVal,NimNode>`_ for getting the string value.
|
||||
## * `ident proc<#ident,string>`_ for creating an identifier.
|
||||
## * `bindSym proc<#bindSym%2C%2CBindSymRule>`_ for binding a symbol.
|
||||
|
||||
proc newNimNode*(kind: NimNodeKind,
|
||||
lineInfoFrom: NimNode = nil): NimNode
|
||||
@@ -407,47 +422,47 @@ proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.}
|
||||
proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
|
||||
|
||||
proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.}
|
||||
## writes an error message at compile time. The optional ``n: NimNode``
|
||||
## Writes an error message at compile time. The optional ``n: NimNode``
|
||||
## parameter is used as the source for file and line number information in
|
||||
## the compilation error message.
|
||||
|
||||
proc warning*(msg: string, n: NimNode = nil) {.magic: "NWarning", benign.}
|
||||
## writes a warning message at compile time
|
||||
## Writes a warning message at compile time.
|
||||
|
||||
proc hint*(msg: string, n: NimNode = nil) {.magic: "NHint", benign.}
|
||||
## writes a hint message at compile time
|
||||
## Writes a hint message at compile time.
|
||||
|
||||
proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} =
|
||||
## creates a string literal node from `s`
|
||||
## Creates a string literal node from `s`.
|
||||
result = newNimNode(nnkStrLit)
|
||||
result.strVal = s
|
||||
|
||||
proc newCommentStmtNode*(s: string): NimNode {.compileTime, noSideEffect.} =
|
||||
## creates a comment statement node
|
||||
## Creates a comment statement node.
|
||||
result = newNimNode(nnkCommentStmt)
|
||||
result.strVal = s
|
||||
|
||||
proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} =
|
||||
## creates a int literal node from `i`
|
||||
## Creates an int literal node from `i`.
|
||||
result = newNimNode(nnkIntLit)
|
||||
result.intVal = i
|
||||
|
||||
proc newFloatLitNode*(f: BiggestFloat): NimNode {.compileTime.} =
|
||||
## creates a float literal node from `f`
|
||||
## Creates a float literal node from `f`.
|
||||
result = newNimNode(nnkFloatLit)
|
||||
result.floatVal = f
|
||||
|
||||
{.push warnings: off.}
|
||||
|
||||
proc newIdentNode*(i: NimIdent): NimNode {.compileTime, deprecated.} =
|
||||
## creates an identifier node from `i`
|
||||
## Creates an identifier node from `i`.
|
||||
result = newNimNode(nnkIdent)
|
||||
result.ident = i
|
||||
|
||||
{.pop.}
|
||||
|
||||
proc newIdentNode*(i: string): NimNode {.magic: "StrToIdent", noSideEffect, compilerproc.}
|
||||
## creates an identifier node from `i`. It is simply an alias for
|
||||
## Creates an identifier node from `i`. It is simply an alias for
|
||||
## ``ident(string)``. Use that, it's shorter.
|
||||
|
||||
|
||||
@@ -463,35 +478,35 @@ type
|
||||
|
||||
proc bindSym*(ident: string | NimNode, rule: BindSymRule = brClosed): NimNode {.
|
||||
magic: "NBindSym", noSideEffect.}
|
||||
## creates a node that binds `ident` to a symbol node. The bound symbol
|
||||
## Ceates a node that binds `ident` to a symbol node. The bound symbol
|
||||
## may be an overloaded symbol.
|
||||
## if `ident` is a NimNode, it must have nkIdent kind.
|
||||
## If ``rule == brClosed`` either an ``nkClosedSymChoice`` tree is
|
||||
## returned or ``nkSym`` if the symbol is not ambiguous.
|
||||
## If ``rule == brOpen`` either an ``nkOpenSymChoice`` tree is
|
||||
## returned or ``nkSym`` if the symbol is not ambiguous.
|
||||
## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
|
||||
## if `ident` is a NimNode, it must have ``nnkIdent`` kind.
|
||||
## If ``rule == brClosed`` either an ``nnkClosedSymChoice`` tree is
|
||||
## returned or ``nnkSym`` if the symbol is not ambiguous.
|
||||
## If ``rule == brOpen`` either an ``nnkOpenSymChoice`` tree is
|
||||
## returned or ``nnkSym`` if the symbol is not ambiguous.
|
||||
## If ``rule == brForceOpen`` always an ``nnkOpenSymChoice`` tree is
|
||||
## returned even if the symbol is not ambiguous.
|
||||
##
|
||||
## experimental feature:
|
||||
## use {.experimental: "dynamicBindSym".} to activate it
|
||||
## if called from template / regular code, `ident` and `rule` must be
|
||||
## Experimental feature:
|
||||
## use {.experimental: "dynamicBindSym".} to activate it.
|
||||
## If called from template / regular code, `ident` and `rule` must be
|
||||
## constant expression / literal value.
|
||||
## if called from macros / compile time procs / static blocks,
|
||||
## If called from macros / compile time procs / static blocks,
|
||||
## `ident` and `rule` can be VM computed value.
|
||||
|
||||
proc genSym*(kind: NimSymKind = nskLet; ident = ""): NimNode {.
|
||||
magic: "NGenSym", noSideEffect.}
|
||||
## generates a fresh symbol that is guaranteed to be unique. The symbol
|
||||
## Generates a fresh symbol that is guaranteed to be unique. The symbol
|
||||
## needs to occur in a declaration context.
|
||||
|
||||
proc callsite*(): NimNode {.magic: "NCallSite", benign, deprecated:
|
||||
"Deprecated since v0.18.1; use varargs[untyped] in the macro prototype instead".}
|
||||
## returns the AST of the invocation expression that invoked this macro.
|
||||
## Returns the AST of the invocation expression that invoked this macro.
|
||||
|
||||
proc toStrLit*(n: NimNode): NimNode {.compileTime.} =
|
||||
## converts the AST `n` to the concrete Nim code and wraps that
|
||||
## in a string literal node
|
||||
## Converts the AST `n` to the concrete Nim code and wraps that
|
||||
## in a string literal node.
|
||||
return newStrLitNode(repr(n))
|
||||
|
||||
type
|
||||
@@ -500,27 +515,29 @@ type
|
||||
line*,column*: int
|
||||
|
||||
proc `$`*(arg: LineInfo): string =
|
||||
## Return a string representation in the form `filepath(line, column)`.
|
||||
# BUG: without `result = `, gives compile error
|
||||
result = arg.filename & "(" & $arg.line & ", " & $arg.column & ")"
|
||||
|
||||
#proc lineinfo*(n: NimNode): LineInfo {.magic: "NLineInfo", noSideEffect.}
|
||||
## returns the position the node appears in the original source file
|
||||
## in the form filename(line, col)
|
||||
# ## returns the position the node appears in the original source file
|
||||
# ## in the form filename(line, col)
|
||||
|
||||
proc getLine(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
|
||||
proc getColumn(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
|
||||
proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.}
|
||||
|
||||
proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.}
|
||||
## copy lineinfo from info node
|
||||
## Copy lineinfo from ``info``.
|
||||
|
||||
proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} =
|
||||
## returns ``LineInfo`` of ``n``, using absolute path for ``filename``
|
||||
## Returns ``LineInfo`` of ``n``, using absolute path for ``filename``.
|
||||
result.filename = n.getFile
|
||||
result.line = n.getLine
|
||||
result.column = n.getColumn
|
||||
|
||||
proc lineInfo*(arg: NimNode): string {.compileTime.} =
|
||||
## Return line info in the form `filepath(line, column)`.
|
||||
$arg.lineInfoObj
|
||||
|
||||
proc internalParseExpr(s: string): NimNode {.
|
||||
@@ -586,25 +603,25 @@ proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.}
|
||||
## echo `info` & ": Check failed: " & `expString`
|
||||
|
||||
proc expectKind*(n: NimNode, k: NimNodeKind) {.compileTime.} =
|
||||
## checks that `n` is of kind `k`. If this is not the case,
|
||||
## Checks that `n` is of kind `k`. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check the AST that is passed to them.
|
||||
if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind, n)
|
||||
|
||||
proc expectMinLen*(n: NimNode, min: int) {.compileTime.} =
|
||||
## checks that `n` has at least `min` children. If this is not the case,
|
||||
## Checks that `n` has at least `min` children. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check its number of arguments.
|
||||
if n.len < min: error("macro expects a node with " & $min & " children", n)
|
||||
|
||||
proc expectLen*(n: NimNode, len: int) {.compileTime.} =
|
||||
## checks that `n` has exactly `len` children. If this is not the case,
|
||||
## Checks that `n` has exactly `len` children. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check its number of arguments.
|
||||
if n.len != len: error("macro expects a node with " & $len & " children", n)
|
||||
|
||||
proc expectLen*(n: NimNode, min, max: int) {.compileTime.} =
|
||||
## checks that `n` has a number of children in the range ``min..max``.
|
||||
## Checks that `n` has a number of children in the range ``min..max``.
|
||||
## If this is not the case, compilation aborts with an error message.
|
||||
## This is useful for writing macros that check its number of arguments.
|
||||
if n.len < min or n.len > max:
|
||||
@@ -612,13 +629,13 @@ proc expectLen*(n: NimNode, min, max: int) {.compileTime.} =
|
||||
|
||||
proc newTree*(kind: NimNodeKind,
|
||||
children: varargs[NimNode]): NimNode {.compileTime.} =
|
||||
## produces a new node with children.
|
||||
## Produces a new node with children.
|
||||
result = newNimNode(kind)
|
||||
result.add(children)
|
||||
|
||||
proc newCall*(theProc: NimNode,
|
||||
args: varargs[NimNode]): NimNode {.compileTime.} =
|
||||
## produces a new call node. `theProc` is the proc that is called with
|
||||
## Produces a new call node. `theProc` is the proc that is called with
|
||||
## the arguments ``args[0..]``.
|
||||
result = newNimNode(nnkCall)
|
||||
result.add(theProc)
|
||||
@@ -628,7 +645,7 @@ proc newCall*(theProc: NimNode,
|
||||
|
||||
proc newCall*(theProc: NimIdent, args: varargs[NimNode]): NimNode {.compileTime, deprecated:
|
||||
"Deprecated since v0.18.1; use 'newCall(string, ...)' or 'newCall(NimNode, ...)' instead".} =
|
||||
## produces a new call node. `theProc` is the proc that is called with
|
||||
## Produces a new call node. `theProc` is the proc that is called with
|
||||
## the arguments ``args[0..]``.
|
||||
result = newNimNode(nnkCall)
|
||||
result.add(newIdentNode(theProc))
|
||||
@@ -638,91 +655,91 @@ proc newCall*(theProc: NimIdent, args: varargs[NimNode]): NimNode {.compileTime,
|
||||
|
||||
proc newCall*(theProc: string,
|
||||
args: varargs[NimNode]): NimNode {.compileTime.} =
|
||||
## produces a new call node. `theProc` is the proc that is called with
|
||||
## Produces a new call node. `theProc` is the proc that is called with
|
||||
## the arguments ``args[0..]``.
|
||||
result = newNimNode(nnkCall)
|
||||
result.add(newIdentNode(theProc))
|
||||
result.add(args)
|
||||
|
||||
proc newLit*(c: char): NimNode {.compileTime.} =
|
||||
## produces a new character literal node.
|
||||
## Produces a new character literal node.
|
||||
result = newNimNode(nnkCharLit)
|
||||
result.intVal = ord(c)
|
||||
|
||||
proc newLit*(i: int): NimNode {.compileTime.} =
|
||||
## produces a new integer literal node.
|
||||
## Produces a new integer literal node.
|
||||
result = newNimNode(nnkIntLit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(i: int8): NimNode {.compileTime.} =
|
||||
## produces a new integer literal node.
|
||||
## Produces a new integer literal node.
|
||||
result = newNimNode(nnkInt8Lit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(i: int16): NimNode {.compileTime.} =
|
||||
## produces a new integer literal node.
|
||||
## Produces a new integer literal node.
|
||||
result = newNimNode(nnkInt16Lit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(i: int32): NimNode {.compileTime.} =
|
||||
## produces a new integer literal node.
|
||||
## Produces a new integer literal node.
|
||||
result = newNimNode(nnkInt32Lit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(i: int64): NimNode {.compileTime.} =
|
||||
## produces a new integer literal node.
|
||||
## Produces a new integer literal node.
|
||||
result = newNimNode(nnkInt64Lit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(i: uint): NimNode {.compileTime.} =
|
||||
## produces a new unsigned integer literal node.
|
||||
## Produces a new unsigned integer literal node.
|
||||
result = newNimNode(nnkUIntLit)
|
||||
result.intVal = BiggestInt(i)
|
||||
|
||||
proc newLit*(i: uint8): NimNode {.compileTime.} =
|
||||
## produces a new unsigned integer literal node.
|
||||
## Produces a new unsigned integer literal node.
|
||||
result = newNimNode(nnkUInt8Lit)
|
||||
result.intVal = BiggestInt(i)
|
||||
|
||||
proc newLit*(i: uint16): NimNode {.compileTime.} =
|
||||
## produces a new unsigned integer literal node.
|
||||
## Produces a new unsigned integer literal node.
|
||||
result = newNimNode(nnkUInt16Lit)
|
||||
result.intVal = BiggestInt(i)
|
||||
|
||||
proc newLit*(i: uint32): NimNode {.compileTime.} =
|
||||
## produces a new unsigned integer literal node.
|
||||
## Produces a new unsigned integer literal node.
|
||||
result = newNimNode(nnkUInt32Lit)
|
||||
result.intVal = BiggestInt(i)
|
||||
|
||||
proc newLit*(i: uint64): NimNode {.compileTime.} =
|
||||
## produces a new unsigned integer literal node.
|
||||
## Produces a new unsigned integer literal node.
|
||||
result = newNimNode(nnkUInt64Lit)
|
||||
result.intVal = BiggestInt(i)
|
||||
|
||||
proc newLit*(b: bool): NimNode {.compileTime.} =
|
||||
## produces a new boolean literal node.
|
||||
## Produces a new boolean literal node.
|
||||
result = if b: bindSym"true" else: bindSym"false"
|
||||
|
||||
when false:
|
||||
# the float type is not really a distinct type as described in https://github.com/nim-lang/Nim/issues/5875
|
||||
proc newLit*(f: float): NimNode {.compileTime.} =
|
||||
## produces a new float literal node.
|
||||
## Produces a new float literal node.
|
||||
result = newNimNode(nnkFloatLit)
|
||||
result.floatVal = f
|
||||
|
||||
proc newLit*(f: float32): NimNode {.compileTime.} =
|
||||
## produces a new float literal node.
|
||||
## Produces a new float literal node.
|
||||
result = newNimNode(nnkFloat32Lit)
|
||||
result.floatVal = f
|
||||
|
||||
proc newLit*(f: float64): NimNode {.compileTime.} =
|
||||
## produces a new float literal node.
|
||||
## Produces a new float literal node.
|
||||
result = newNimNode(nnkFloat64Lit)
|
||||
result.floatVal = f
|
||||
|
||||
when declared(float128):
|
||||
proc newLit*(f: float128): NimNode {.compileTime.} =
|
||||
## produces a new float literal node.
|
||||
## Produces a new float literal node.
|
||||
result = newNimNode(nnkFloat128Lit)
|
||||
result.floatVal = f
|
||||
|
||||
@@ -771,12 +788,12 @@ proc newLit*(arg: tuple): NimNode {.compileTime.} =
|
||||
result.add nnkExprColonExpr.newTree(newIdentNode(a), newLit(b))
|
||||
|
||||
proc newLit*(s: string): NimNode {.compileTime.} =
|
||||
## produces a new string literal node.
|
||||
## Produces a new string literal node.
|
||||
result = newNimNode(nnkStrLit)
|
||||
result.strVal = s
|
||||
|
||||
proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} =
|
||||
## nests the list `pack` into a tree of call expressions:
|
||||
## Nests the list `pack` into a tree of call expressions:
|
||||
## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``.
|
||||
## This is also known as fold expression.
|
||||
if pack.len < 1:
|
||||
@@ -786,7 +803,7 @@ proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} =
|
||||
result = newCall(op, pack[i], result)
|
||||
|
||||
proc nestList*(op: NimNode; pack: NimNode; init: NimNode): NimNode {.compileTime.} =
|
||||
## nests the list `pack` into a tree of call expressions:
|
||||
## Nests the list `pack` into a tree of call expressions:
|
||||
## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``.
|
||||
## This is also known as fold expression.
|
||||
result = init
|
||||
@@ -973,37 +990,37 @@ macro dumpLispImm*(s: untyped): untyped {.deprecated.} = echo s.lispRepr
|
||||
## Deprecated. Use `dumpLisp` instead.
|
||||
|
||||
proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} =
|
||||
## Create a new empty node
|
||||
## Create a new empty node.
|
||||
result = newNimNode(nnkEmpty)
|
||||
|
||||
proc newStmtList*(stmts: varargs[NimNode]): NimNode {.compileTime.}=
|
||||
## Create a new statement list
|
||||
## Create a new statement list.
|
||||
result = newNimNode(nnkStmtList).add(stmts)
|
||||
|
||||
proc newPar*(exprs: varargs[NimNode]): NimNode {.compileTime.}=
|
||||
## Create a new parentheses-enclosed expression
|
||||
## Create a new parentheses-enclosed expression.
|
||||
newNimNode(nnkPar).add(exprs)
|
||||
|
||||
proc newBlockStmt*(label, body: NimNode): NimNode {.compileTime.} =
|
||||
## Create a new block statement with label
|
||||
## Create a new block statement with label.
|
||||
return newNimNode(nnkBlockStmt).add(label, body)
|
||||
|
||||
proc newBlockStmt*(body: NimNode): NimNode {.compileTime.} =
|
||||
## Create a new block: stmt
|
||||
## Create a new block: stmt.
|
||||
return newNimNode(nnkBlockStmt).add(newEmptyNode(), body)
|
||||
|
||||
proc newVarStmt*(name, value: NimNode): NimNode {.compileTime.} =
|
||||
## Create a new var stmt
|
||||
## Create a new var stmt.
|
||||
return newNimNode(nnkVarSection).add(
|
||||
newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
|
||||
|
||||
proc newLetStmt*(name, value: NimNode): NimNode {.compileTime.} =
|
||||
## Create a new let stmt
|
||||
## Create a new let stmt.
|
||||
return newNimNode(nnkLetSection).add(
|
||||
newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
|
||||
|
||||
proc newConstStmt*(name, value: NimNode): NimNode {.compileTime.} =
|
||||
## Create a new const stmt
|
||||
## Create a new const stmt.
|
||||
newNimNode(nnkConstSection).add(
|
||||
newNimNode(nnkConstDef).add(name, newNimNode(nnkEmpty), value))
|
||||
|
||||
@@ -1011,13 +1028,13 @@ proc newAssignment*(lhs, rhs: NimNode): NimNode {.compileTime.} =
|
||||
return newNimNode(nnkAsgn).add(lhs, rhs)
|
||||
|
||||
proc newDotExpr*(a, b: NimNode): NimNode {.compileTime.} =
|
||||
## Create new dot expression
|
||||
## a.dot(b) -> `a.b`
|
||||
## Create new dot expression.
|
||||
## a.dot(b) -> `a.b`
|
||||
return newNimNode(nnkDotExpr).add(a, b)
|
||||
|
||||
proc newColonExpr*(a, b: NimNode): NimNode {.compileTime.} =
|
||||
## Create new colon expression
|
||||
## newColonExpr(a, b) -> `a: b`
|
||||
## Create new colon expression.
|
||||
## newColonExpr(a, b) -> `a: b`
|
||||
newNimNode(nnkExprColonExpr).add(a, b)
|
||||
|
||||
proc newIdentDefs*(name, kind: NimNode;
|
||||
@@ -1053,11 +1070,11 @@ proc newIdentDefs*(name, kind: NimNode;
|
||||
newNimNode(nnkIdentDefs).add(name, kind, default)
|
||||
|
||||
proc newNilLit*(): NimNode {.compileTime.} =
|
||||
## New nil literal shortcut
|
||||
## New nil literal shortcut.
|
||||
result = newNimNode(nnkNilLit)
|
||||
|
||||
proc last*(node: NimNode): NimNode {.compileTime.} = node[node.len-1]
|
||||
## Return the last item in nodes children. Same as `node[^1]`
|
||||
## Return the last item in nodes children. Same as `node[^1]`.
|
||||
|
||||
|
||||
const
|
||||
@@ -1068,7 +1085,7 @@ const
|
||||
nnkCallStrLit, nnkHiddenCallConv}
|
||||
|
||||
proc expectKind*(n: NimNode; k: set[NimNodeKind]) {.compileTime.} =
|
||||
## checks that `n` is of kind `k`. If this is not the case,
|
||||
## Checks that `n` is of kind `k`. If this is not the case,
|
||||
## compilation aborts with an error message. This is useful for writing
|
||||
## macros that check the AST that is passed to them.
|
||||
if n.kind notin k: error("Expected one of " & $k & ", got " & $n.kind, n)
|
||||
@@ -1078,7 +1095,7 @@ proc newProc*(name = newEmptyNode();
|
||||
body: NimNode = newStmtList();
|
||||
procType = nnkProcDef;
|
||||
pragmas: NimNode = newEmptyNode()): NimNode {.compileTime.} =
|
||||
## shortcut for creating a new proc
|
||||
## Shortcut for creating a new proc.
|
||||
##
|
||||
## The ``params`` array must start with the return type of the proc,
|
||||
## followed by a list of IdentDefs which specify the params.
|
||||
@@ -1156,7 +1173,7 @@ proc newEnum*(name: NimNode, fields: openArray[NimNode],
|
||||
return typeSect
|
||||
|
||||
proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}=
|
||||
## Copy all children from `src` to `dest`
|
||||
## Copy all children from `src` to `dest`.
|
||||
for i in 0 ..< src.len:
|
||||
dest.add src[i].copyNimTree
|
||||
|
||||
@@ -1189,15 +1206,15 @@ proc `params=`* (someProc: NimNode; params: NimNode) {.compileTime.}=
|
||||
someProc[3] = params
|
||||
|
||||
proc pragma*(someProc: NimNode): NimNode {.compileTime.} =
|
||||
## Get the pragma of a proc type
|
||||
## These will be expanded
|
||||
## Get the pragma of a proc type.
|
||||
## These will be expanded.
|
||||
if someProc.kind == nnkProcTy:
|
||||
result = someProc[1]
|
||||
else:
|
||||
someProc.expectRoutine
|
||||
result = someProc[4]
|
||||
proc `pragma=`*(someProc: NimNode; val: NimNode) {.compileTime.}=
|
||||
## Set the pragma of a proc type
|
||||
## Set the pragma of a proc type.
|
||||
expectKind(val, {nnkEmpty, nnkPragma})
|
||||
if someProc.kind == nnkProcTy:
|
||||
someProc[1] = val
|
||||
@@ -1206,7 +1223,7 @@ proc `pragma=`*(someProc: NimNode; val: NimNode) {.compileTime.}=
|
||||
someProc[4] = val
|
||||
|
||||
proc addPragma*(someProc, pragma: NimNode) {.compileTime.} =
|
||||
## Adds pragma to routine definition
|
||||
## Adds pragma to routine definition.
|
||||
someProc.expectKind(RoutineNodes + {nnkProcTy})
|
||||
var pragmaNode = someProc.pragma
|
||||
if pragmaNode.isNil or pragmaNode.kind == nnkEmpty:
|
||||
@@ -1242,7 +1259,7 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
|
||||
proc basename*(a: NimNode): NimNode {.compileTime, benign.}
|
||||
|
||||
proc `$`*(node: NimNode): string {.compileTime.} =
|
||||
## Get the string of an identifier node
|
||||
## Get the string of an identifier node.
|
||||
case node.kind
|
||||
of nnkPostfix:
|
||||
result = node.basename.strVal & "*"
|
||||
@@ -1256,7 +1273,7 @@ proc `$`*(node: NimNode): string {.compileTime.} =
|
||||
badNodeKind node, "$"
|
||||
|
||||
proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.}
|
||||
## Create a new ident node from a string
|
||||
## Create a new ident node from a string.
|
||||
|
||||
iterator items*(n: NimNode): NimNode {.inline.} =
|
||||
## Iterates over the children of the NimNode ``n``.
|
||||
@@ -1288,22 +1305,22 @@ template findChild*(n: NimNode; cond: untyped): NimNode {.dirty.} =
|
||||
res
|
||||
|
||||
proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} =
|
||||
## Insert node B into A at pos
|
||||
## Insert node ``b`` into node ``a`` at ``pos``.
|
||||
if len(a)-1 < pos:
|
||||
## add some empty nodes first
|
||||
# add some empty nodes first
|
||||
for i in len(a)-1..pos-2:
|
||||
a.add newEmptyNode()
|
||||
a.add b
|
||||
else:
|
||||
## push the last item onto the list again
|
||||
## and shift each item down to pos up one
|
||||
# push the last item onto the list again
|
||||
# and shift each item down to pos up one
|
||||
a.add(a[a.len-1])
|
||||
for i in countdown(len(a) - 3, pos):
|
||||
a[i + 1] = a[i]
|
||||
a[pos] = b
|
||||
|
||||
proc basename*(a: NimNode): NimNode =
|
||||
## Pull an identifier from prefix/postfix expressions
|
||||
## Pull an identifier from prefix/postfix expressions.
|
||||
case a.kind
|
||||
of nnkIdent: return a
|
||||
of nnkPostfix, nnkPrefix: return a[1]
|
||||
@@ -1347,7 +1364,7 @@ proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string;
|
||||
result = (node[1], $node[0], node[2])
|
||||
|
||||
proc copy*(node: NimNode): NimNode {.compileTime.} =
|
||||
## An alias for copyNimTree().
|
||||
## An alias for `copyNimTree<#copyNimTree,NimNode>`_.
|
||||
return node.copyNimTree()
|
||||
|
||||
when defined(nimVmEqIdent):
|
||||
@@ -1388,7 +1405,7 @@ else:
|
||||
|
||||
|
||||
proc eqIdent*(a, b: string): bool = cmpIgnoreStyle(a, b) == 0
|
||||
## Check if two idents are identical.
|
||||
## Check if two idents are equal.
|
||||
|
||||
proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
|
||||
## Check if node is some identifier node (``nnkIdent``, ``nnkSym``, etc.)
|
||||
@@ -1403,7 +1420,7 @@ else:
|
||||
result = false
|
||||
|
||||
proc hasArgOfName*(params: NimNode; name: string): bool {.compileTime.}=
|
||||
## Search nnkFormalParams for an argument.
|
||||
## Search ``nnkFormalParams`` for an argument.
|
||||
expectKind(params, nnkFormalParams)
|
||||
for i in 1 ..< params.len:
|
||||
template node: untyped = params[i]
|
||||
@@ -1411,7 +1428,7 @@ proc hasArgOfName*(params: NimNode; name: string): bool {.compileTime.}=
|
||||
return true
|
||||
|
||||
proc addIdentIfAbsent*(dest: NimNode, ident: string) {.compileTime.} =
|
||||
## Add ident to dest if it is not present. This is intended for use
|
||||
## Add ``ident`` to ``dest`` if it is not present. This is intended for use
|
||||
## with pragmas.
|
||||
for node in dest.children:
|
||||
case node.kind
|
||||
@@ -1585,7 +1602,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped =
|
||||
|
||||
when not defined(booting):
|
||||
template emit*(e: static[string]): untyped {.deprecated.} =
|
||||
## accepts a single string argument and treats it as nim code
|
||||
## Accepts a single string argument and treats it as nim code
|
||||
## that should be inserted verbatim in the program
|
||||
## Example:
|
||||
##
|
||||
|
||||
@@ -391,7 +391,7 @@ proc setVal[K, V](table: var PConcTable[K, V], key: int, val: int,
|
||||
# Done spinning for a new slot
|
||||
var oldVal = atomic_load_n(table[idx].value.addr, ATOMIC_RELAXED)
|
||||
if val == oldVal:
|
||||
#echo("this val is alredy in the slot")
|
||||
#echo("this val is already in the slot")
|
||||
return oldVal
|
||||
nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST)
|
||||
if nextTable == nil and
|
||||
|
||||
@@ -42,7 +42,7 @@ type
|
||||
## the option was given a value
|
||||
|
||||
proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
|
||||
## Initalizes option parses with cmdline. cmdline should not contain
|
||||
## Initializes option parses with cmdline. cmdline should not contain
|
||||
## argument 0 - program name.
|
||||
## If cmdline.len == 0 default to current command line arguments.
|
||||
result.remainingShortOptions = ""
|
||||
|
||||
@@ -275,9 +275,9 @@ proc createDiffs(dataA, dataB: DiffData): seq[Item] =
|
||||
proc diffInt*(arrayA, arrayB: openArray[int]): seq[Item] =
|
||||
## Find the difference in 2 arrays of integers.
|
||||
##
|
||||
## ``arrayA`` A-version of the numbers (usualy the old one)
|
||||
## ``arrayA`` A-version of the numbers (usually the old one)
|
||||
##
|
||||
## ``arrayB`` B-version of the numbers (usualy the new one)
|
||||
## ``arrayB`` B-version of the numbers (usually the new one)
|
||||
##
|
||||
## Returns a sequence of Items that describe the differences.
|
||||
|
||||
@@ -301,7 +301,7 @@ proc diffText*(textA, textB: string): seq[Item] =
|
||||
##
|
||||
## The algorithm itself is comparing 2 arrays of numbers so when comparing 2 text documents
|
||||
## each line is converted into a (hash) number. This hash-value is computed by storing all
|
||||
## textlines into a common hashtable so i can find dublicates in there, and generating a
|
||||
## textlines into a common hashtable so i can find duplicates in there, and generating a
|
||||
## new number each time a new textline is inserted.
|
||||
##
|
||||
## ``textA`` A-version of the text (usually the old one)
|
||||
|
||||
@@ -272,7 +272,7 @@ iterator fastRows*(db: var DbConn, query: SqlQuery,
|
||||
## if you require **ALL** the rows.
|
||||
##
|
||||
## Breaking the fastRows() iterator during a loop may cause a driver error
|
||||
## for subsequenct queries
|
||||
## for subsequent queries
|
||||
##
|
||||
## Rows are retrieved from the server at each iteration.
|
||||
var
|
||||
@@ -303,7 +303,7 @@ iterator instantRows*(db: var DbConn, query: SqlQuery,
|
||||
args: varargs[string, `$`]): InstantRow
|
||||
{.tags: [ReadDbEffect, WriteDbEffect].} =
|
||||
## Same as fastRows but returns a handle that can be used to get column text
|
||||
## on demand using []. Returned handle is valid only within the interator body.
|
||||
## on demand using []. Returned handle is valid only within the iterator body.
|
||||
var
|
||||
rowRes: Row = @[]
|
||||
sz: TSqlInteger = 0
|
||||
|
||||
@@ -182,7 +182,7 @@ proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
|
||||
iterator fastRows*(db: DbConn, query: SqlQuery,
|
||||
args: varargs[string, `$`]): Row {.tags: [ReadDbEffect].} =
|
||||
## executes the query and iterates over the result dataset. This is very
|
||||
## fast, but potenially dangerous: If the for-loop-body executes another
|
||||
## fast, but potentially dangerous: If the for-loop-body executes another
|
||||
## query, the results can be undefined. For Postgres it is safe though.
|
||||
var res = setupQuery(db, query, args)
|
||||
var L = pqnfields(res)
|
||||
|
||||
@@ -94,6 +94,18 @@
|
||||
##
|
||||
## db.close()
|
||||
##
|
||||
##
|
||||
## Note
|
||||
## ====
|
||||
## This module does not implement any ORM features such as mapping the types from the schema.
|
||||
## Instead, a ``seq[string]`` is returned for each row.
|
||||
##
|
||||
## The reasoning is as follows:
|
||||
## 1. it's close to what many DBs offer natively (char**)
|
||||
## 2. it hides the number of types that the DB supports
|
||||
## (int? int64? decimal up to 10 places? geo coords?)
|
||||
## 3. it's convenient when all you do is to forward the data to somewhere else (echo, log, put the data into a new query)
|
||||
##
|
||||
## See also
|
||||
## ========
|
||||
##
|
||||
|
||||
@@ -137,7 +137,7 @@ type
|
||||
## into PCRE flags. These include ``NEVER_UTF``, ``ANCHORED``,
|
||||
## ``DOLLAR_ENDONLY``, ``FIRSTLINE``, ``NO_AUTO_CAPTURE``,
|
||||
## ``JAVASCRIPT_COMPAT``, ``U``, ``NO_STUDY``. In other PCRE wrappers, you
|
||||
## will need to pass these as seperate flags to PCRE.
|
||||
## will need to pass these as separate flags to PCRE.
|
||||
pattern*: string ## not nil
|
||||
pcreObj: ptr pcre.Pcre ## not nil
|
||||
pcreExtra: ptr pcre.ExtraData ## nil
|
||||
|
||||
@@ -498,7 +498,7 @@ macro bindMethod*(procedure: typed): auto =
|
||||
this = newIdentNode("this")
|
||||
# construct the `this` parameter:
|
||||
thisQuote = quote do:
|
||||
var `this` {.nodecl, importc.} : `thisType`
|
||||
var `this` {.nodecl, importc: "this".}: `thisType`
|
||||
call = newNimNode(nnkCall).add(rawProc[0], thisQuote[0][0][0])
|
||||
# construct the procedure call inside the method
|
||||
if args.len > 2:
|
||||
|
||||
@@ -101,7 +101,7 @@ proc initRstGenerator*(g: var RstGenerator, target: OutputTarget,
|
||||
## index hyperlinks to the file, but you can pass an empty string here if you
|
||||
## are parsing a stream in memory. If `filename` ends with the ``.nim``
|
||||
## extension, the title for the document will be set by default to ``Module
|
||||
## filename``. This default title can be overriden by the embedded rst, but
|
||||
## filename``. This default title can be overridden by the embedded rst, but
|
||||
## it helps to prettify the generated index if no title is found.
|
||||
##
|
||||
## The ``RstParseOptions``, ``FindFileHandler`` and ``MsgHandler`` types
|
||||
@@ -350,7 +350,7 @@ proc hash(n: PRstNode): int =
|
||||
proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
|
||||
## Renders the string decorated within \`foobar\`\:idx\: markers.
|
||||
##
|
||||
## Additionally adds the encosed text to the index as a term. Since we are
|
||||
## Additionally adds the enclosed text to the index as a term. Since we are
|
||||
## interested in different instances of the same term to have different
|
||||
## entries, a table is used to keep track of the amount of times a term has
|
||||
## previously appeared to give a different identifier value for each.
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
# Dead code elimination ensures that we don't accidentally generate #includes
|
||||
# for files that might not exist on a specific platform! The user will get an
|
||||
# error only if they actualy try to use the missing declaration
|
||||
# error only if they actually try to use the missing declaration
|
||||
{.deadCodeElim: on.} # dce option deprecated
|
||||
|
||||
when defined(nimHasStyleChecks):
|
||||
|
||||
@@ -83,7 +83,7 @@ proc sendSignal*(pid: Pid, signal: int) =
|
||||
proc mkstemp*(prefix: string): (string, File) =
|
||||
## Creates a unique temporary file from a prefix string. Adds a six chars suffix.
|
||||
## The file is created with perms 0600.
|
||||
## Returs the filename and a file opened in r/w mode.
|
||||
## Returns the filename and a file opened in r/w mode.
|
||||
var tmpl = cstring(prefix & "XXXXXX")
|
||||
let fd = mkstemp(tmpl)
|
||||
var f: File
|
||||
|
||||
@@ -172,8 +172,8 @@ proc binarySearch*[T, K](a: openArray[T], key: K,
|
||||
## ``cmp`` is the comparator function to use, the expected return values are
|
||||
## the same as that of system.cmp.
|
||||
runnableExamples:
|
||||
assert binarySearch(["a","b","c","d"], "d", system.cmp[string]) == 3
|
||||
assert binarySearch(["a","b","d","c"], "d", system.cmp[string]) == 2
|
||||
assert binarySearch(["a", "b", "c", "d"], "d", system.cmp[string]) == 3
|
||||
assert binarySearch(["a", "b", "d", "c"], "d", system.cmp[string]) == 2
|
||||
if a.len == 0:
|
||||
return -1
|
||||
|
||||
@@ -228,7 +228,8 @@ proc smartBinarySearch*[T](a: openArray[T], key: T): int {.deprecated:
|
||||
const
|
||||
onlySafeCode = true
|
||||
|
||||
proc lowerBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {.closure.}): int =
|
||||
proc lowerBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {.
|
||||
closure.}): int =
|
||||
## Returns a position to the first element in the ``a`` that is greater than
|
||||
## ``key``, or last if no such element is found.
|
||||
## In other words if you have a sorted sequence and you call
|
||||
@@ -244,12 +245,12 @@ proc lowerBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {.clo
|
||||
## * `upperBound proc<#upperBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order
|
||||
## * `upperBound proc<#upperBound,openArray[T],T>`_
|
||||
runnableExamples:
|
||||
var arr = @[1,2,3,5,6,7,8,9]
|
||||
var arr = @[1, 2, 3, 5, 6, 7, 8, 9]
|
||||
assert arr.lowerBound(3, system.cmp[int]) == 2
|
||||
assert arr.lowerBound(4, system.cmp[int]) == 3
|
||||
assert arr.lowerBound(5, system.cmp[int]) == 3
|
||||
arr.insert(4, arr.lowerBound(4, system.cmp[int]))
|
||||
assert arr == [1,2,3,4,5,6,7,8,9]
|
||||
assert arr == [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
result = a.low
|
||||
var count = a.high - a.low + 1
|
||||
var step, pos: int
|
||||
@@ -275,7 +276,8 @@ proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
|
||||
## * `upperBound proc<#upperBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order
|
||||
## * `upperBound proc<#upperBound,openArray[T],T>`_
|
||||
|
||||
proc upperBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {.closure.}): int =
|
||||
proc upperBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {.
|
||||
closure.}): int =
|
||||
## Returns a position to the first element in the ``a`` that is not less
|
||||
## (i.e. greater or equal to) than ``key``, or last if no such element is found.
|
||||
## In other words if you have a sorted sequence and you call
|
||||
@@ -291,12 +293,12 @@ proc upperBound*[T, K](a: openArray[T], key: K, cmp: proc(x: T, k: K): int {.clo
|
||||
## * `lowerBound proc<#lowerBound,openArray[T],K,proc(T,K)>`_ sorted by ``cmp`` in the specified order
|
||||
## * `lowerBound proc<#lowerBound,openArray[T],T>`_
|
||||
runnableExamples:
|
||||
var arr = @[1,2,3,5,6,7,8,9]
|
||||
var arr = @[1, 2, 3, 5, 6, 7, 8, 9]
|
||||
assert arr.upperBound(2, system.cmp[int]) == 2
|
||||
assert arr.upperBound(3, system.cmp[int]) == 3
|
||||
assert arr.upperBound(4, system.cmp[int]) == 3
|
||||
arr.insert(4, arr.upperBound(3, system.cmp[int]))
|
||||
assert arr == [1,2,3,4,5,6,7,8,9]
|
||||
assert arr == [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
result = a.low
|
||||
var count = a.high - a.low + 1
|
||||
var step, pos: int
|
||||
@@ -422,7 +424,8 @@ func sort*[T](a: var openArray[T],
|
||||
dec(m, s*2)
|
||||
s = s*2
|
||||
|
||||
proc sort*[T](a: var openArray[T], order = SortOrder.Ascending) = sort[T](a, system.cmp[T], order)
|
||||
proc sort*[T](a: var openArray[T], order = SortOrder.Ascending) = sort[T](a,
|
||||
system.cmp[T], order)
|
||||
## Shortcut version of ``sort`` that uses ``system.cmp[T]`` as the comparison function.
|
||||
##
|
||||
## **See also:**
|
||||
@@ -492,11 +495,13 @@ template sortedByIt*(seq1, op: untyped): untyped =
|
||||
p2: Person = (name: "p2", age: 20)
|
||||
p3: Person = (name: "p3", age: 30)
|
||||
p4: Person = (name: "p4", age: 30)
|
||||
people = @[p1,p2,p4,p3]
|
||||
people = @[p1, p2, p4, p3]
|
||||
|
||||
assert people.sortedByIt(it.name) == @[(name: "p1", age: 60), (name: "p2", age: 20), (name: "p3", age: 30), (name: "p4", age: 30)]
|
||||
assert people.sortedByIt(it.name) == @[(name: "p1", age: 60), (name: "p2",
|
||||
age: 20), (name: "p3", age: 30), (name: "p4", age: 30)]
|
||||
# Nested sort
|
||||
assert people.sortedByIt((it.age, it.name)) == @[(name: "p2", age: 20), (name: "p3", age: 30), (name: "p4", age: 30), (name: "p1", age: 60)]
|
||||
assert people.sortedByIt((it.age, it.name)) == @[(name: "p2", age: 20),
|
||||
(name: "p3", age: 30), (name: "p4", age: 30), (name: "p1", age: 60)]
|
||||
var result = sorted(seq1, proc(x, y: type(seq1[0])): int =
|
||||
var it {.inject.} = x
|
||||
let a = op
|
||||
@@ -529,7 +534,7 @@ func isSorted*[T](a: openArray[T],
|
||||
assert isSorted(e) == false
|
||||
result = true
|
||||
for i in 0..<len(a)-1:
|
||||
if cmp(a[i],a[i+1]) * order > 0:
|
||||
if cmp(a[i], a[i+1]) * order > 0:
|
||||
return false
|
||||
|
||||
proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool =
|
||||
@@ -665,19 +670,19 @@ proc prevPermutation*[T](x: var openArray[T]): bool {.discardable.} =
|
||||
|
||||
when isMainModule:
|
||||
# Tests for lowerBound
|
||||
var arr = @[1,2,3,5,6,7,8,9]
|
||||
var arr = @[1, 2, 3, 5, 6, 7, 8, 9]
|
||||
assert arr.lowerBound(0) == 0
|
||||
assert arr.lowerBound(4) == 3
|
||||
assert arr.lowerBound(5) == 3
|
||||
assert arr.lowerBound(10) == 8
|
||||
arr = @[1,5,10]
|
||||
arr = @[1, 5, 10]
|
||||
assert arr.lowerBound(4) == 1
|
||||
assert arr.lowerBound(5) == 1
|
||||
assert arr.lowerBound(6) == 2
|
||||
# Tests for isSorted
|
||||
var srt1 = [1,2,3,4,4,4,4,5]
|
||||
var srt2 = ["iello","hello"]
|
||||
var srt3 = [1.0,1.0,1.0]
|
||||
var srt1 = [1, 2, 3, 4, 4, 4, 4, 5]
|
||||
var srt2 = ["iello", "hello"]
|
||||
var srt3 = [1.0, 1.0, 1.0]
|
||||
var srt4: seq[int]
|
||||
assert srt1.isSorted(cmp) == true
|
||||
assert srt2.isSorted(cmp) == false
|
||||
@@ -686,8 +691,8 @@ when isMainModule:
|
||||
var srtseq = newSeq[int]()
|
||||
assert srtseq.isSorted(cmp) == true
|
||||
# Tests for reversed
|
||||
var arr1 = @[0,1,2,3,4]
|
||||
assert arr1.reversed() == @[4,3,2,1,0]
|
||||
var arr1 = @[0, 1, 2, 3, 4]
|
||||
assert arr1.reversed() == @[4, 3, 2, 1, 0]
|
||||
for i in 0 .. high(arr1):
|
||||
assert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)]
|
||||
assert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i]
|
||||
@@ -745,7 +750,8 @@ proc rotatedInternal[T](arg: openArray[T]; first, middle, last: int): seq[T] =
|
||||
for i in last ..< arg.len:
|
||||
result[i] = arg[i]
|
||||
|
||||
proc rotateLeft*[T](arg: var openArray[T]; slice: HSlice[int, int]; dist: int): int {.discardable.} =
|
||||
proc rotateLeft*[T](arg: var openArray[T]; slice: HSlice[int, int];
|
||||
dist: int): int {.discardable.} =
|
||||
## Performs a left rotation on a range of elements. If you want to rotate
|
||||
## right, use a negative ``dist``. Specifically, ``rotateLeft`` rotates
|
||||
## the elements at ``slice`` by ``dist`` positions.
|
||||
@@ -801,7 +807,8 @@ proc rotateLeft*[T](arg: var openArray[T]; dist: int): int {.discardable.} =
|
||||
let distLeft = ((dist mod arglen) + arglen) mod arglen
|
||||
arg.rotateInternal(0, distLeft, arglen)
|
||||
|
||||
proc rotatedLeft*[T](arg: openArray[T]; slice: HSlice[int, int], dist: int): seq[T] =
|
||||
proc rotatedLeft*[T](arg: openArray[T]; slice: HSlice[int, int],
|
||||
dist: int): seq[T] =
|
||||
## Same as ``rotateLeft``, just with the difference that it does
|
||||
## not modify the argument. It creates a new ``seq`` instead.
|
||||
##
|
||||
@@ -858,7 +865,7 @@ when isMainModule:
|
||||
doAssert list == expected
|
||||
doAssert list2 == @expected
|
||||
|
||||
var s0,s1,s2,s3,s4,s5 = "xxxabcdefgxxx"
|
||||
var s0, s1, s2, s3, s4, s5 = "xxxabcdefgxxx"
|
||||
|
||||
doAssert s0.rotateLeft(3 ..< 10, 3) == 7
|
||||
doAssert s0 == "xxxdefgabcxxx"
|
||||
@@ -876,20 +883,22 @@ when isMainModule:
|
||||
block product:
|
||||
doAssert product(newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input"
|
||||
doAssert product(@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input"
|
||||
doAssert product(@[@[1,2]]) == @[@[1,2]], "a simple case of one element"
|
||||
doAssert product(@[@[1,2], @[3,4]]) == @[@[2,4],@[1,4],@[2,3],@[1,3]], "two elements"
|
||||
doAssert product(@[@[1,2], @[3,4], @[5,6]]) == @[@[2,4,6],@[1,4,6],@[2,3,6],@[1,3,6], @[2,4,5],@[1,4,5],@[2,3,5],@[1,3,5]], "three elements"
|
||||
doAssert product(@[@[1,2], @[]]) == newSeq[seq[int]](), "two elements, but one empty"
|
||||
doAssert product(@[@[1, 2]]) == @[@[1, 2]], "a simple case of one element"
|
||||
doAssert product(@[@[1, 2], @[3, 4]]) == @[@[2, 4], @[1, 4], @[2, 3], @[1,
|
||||
3]], "two elements"
|
||||
doAssert product(@[@[1, 2], @[3, 4], @[5, 6]]) == @[@[2, 4, 6], @[1, 4, 6],
|
||||
@[2, 3, 6], @[1, 3, 6], @[2, 4, 5], @[1, 4, 5], @[2, 3, 5], @[1, 3, 5]], "three elements"
|
||||
doAssert product(@[@[1, 2], @[]]) == newSeq[seq[int]](), "two elements, but one empty"
|
||||
|
||||
block lowerBound:
|
||||
doAssert lowerBound([1,2,4], 3, system.cmp[int]) == 2
|
||||
doAssert lowerBound([1,2,2,3], 4, system.cmp[int]) == 4
|
||||
doAssert lowerBound([1,2,3,10], 11) == 4
|
||||
doAssert lowerBound([1, 2, 4], 3, system.cmp[int]) == 2
|
||||
doAssert lowerBound([1, 2, 2, 3], 4, system.cmp[int]) == 4
|
||||
doAssert lowerBound([1, 2, 3, 10], 11) == 4
|
||||
|
||||
block upperBound:
|
||||
doAssert upperBound([1,2,4], 3, system.cmp[int]) == 2
|
||||
doAssert upperBound([1,2,2,3], 3, system.cmp[int]) == 4
|
||||
doAssert upperBound([1,2,3,5], 3) == 3
|
||||
doAssert upperBound([1, 2, 4], 3, system.cmp[int]) == 2
|
||||
doAssert upperBound([1, 2, 2, 3], 3, system.cmp[int]) == 4
|
||||
doAssert upperBound([1, 2, 3, 5], 3) == 3
|
||||
|
||||
block fillEmptySeq:
|
||||
var s = newSeq[int]()
|
||||
@@ -901,16 +910,16 @@ when isMainModule:
|
||||
let oneData = @[1]
|
||||
doAssert binarySearch(oneData, 1) == 0
|
||||
doAssert binarySearch(onedata, 7) == -1
|
||||
let someData = @[1,3,4,7]
|
||||
let someData = @[1, 3, 4, 7]
|
||||
doAssert binarySearch(someData, 1) == 0
|
||||
doAssert binarySearch(somedata, 7) == 3
|
||||
doAssert binarySearch(someData, -1) == -1
|
||||
doAssert binarySearch(someData, 5) == -1
|
||||
doAssert binarySearch(someData, 13) == -1
|
||||
let moreData = @[1,3,5,7,4711]
|
||||
let moreData = @[1, 3, 5, 7, 4711]
|
||||
doAssert binarySearch(moreData, -1) == -1
|
||||
doAssert binarySearch(moreData, 1) == 0
|
||||
doAssert binarySearch(moreData, 5) == 2
|
||||
doAssert binarySearch(moreData, 6) == -1
|
||||
doAssert binarySearch(moreData, 4711) == 4
|
||||
doAssert binarySearch(moreData, 4712) == -1
|
||||
doAssert binarySearch(moreData, 1) == 0
|
||||
doAssert binarySearch(moreData, 5) == 2
|
||||
doAssert binarySearch(moreData, 6) == -1
|
||||
doAssert binarySearch(moreData, 4711) == 4
|
||||
doAssert binarySearch(moreData, 4712) == -1
|
||||
|
||||
@@ -198,7 +198,7 @@ proc processTimers(
|
||||
dec count
|
||||
didSomeWork = true
|
||||
|
||||
# Return the number of miliseconds in which the next timer will expire.
|
||||
# Return the number of milliseconds in which the next timer will expire.
|
||||
if p.timers.len == 0: return
|
||||
|
||||
let millisecs = (p.timers[0].finishAt - getMonoTime()).inMilliseconds
|
||||
@@ -236,7 +236,7 @@ when defined(windows) or defined(nimdoc):
|
||||
CompletionKey = ULONG_PTR
|
||||
|
||||
CompletionData* = object
|
||||
fd*: AsyncFD # TODO: Rename this.
|
||||
fd*: AsyncFD # TODO: Rename this.
|
||||
cb*: owned(proc (fd: AsyncFD, bytesTransferred: DWORD,
|
||||
errcode: OSErrorCode) {.closure, gcsafe.})
|
||||
cell*: ForeignCell # we need this `cell` to protect our `cb` environment,
|
||||
@@ -267,7 +267,7 @@ when defined(windows) or defined(nimdoc):
|
||||
pcd: PostCallbackDataPtr
|
||||
AsyncEvent* = ptr AsyncEventImpl
|
||||
|
||||
Callback = proc (fd: AsyncFD): bool {.closure,gcsafe.}
|
||||
Callback = proc (fd: AsyncFD): bool {.closure, gcsafe.}
|
||||
|
||||
proc hash(x: AsyncFD): Hash {.borrow.}
|
||||
proc `==`*(x: AsyncFD, y: AsyncFD): bool {.borrow.}
|
||||
@@ -795,7 +795,7 @@ when defined(windows) or defined(nimdoc):
|
||||
proc contains*(disp: PDispatcher, fd: AsyncFD): bool =
|
||||
return fd in disp.handles
|
||||
|
||||
{.push stackTrace:off.}
|
||||
{.push stackTrace: off.}
|
||||
proc waitableCallback(param: pointer,
|
||||
timerOrWaitFired: WINBOOL): void {.stdcall.} =
|
||||
var p = cast[PostCallbackDataPtr](param)
|
||||
@@ -953,10 +953,10 @@ when defined(windows) or defined(nimdoc):
|
||||
deallocShared(cast[pointer](pcd))
|
||||
p.handles.excl(fd)
|
||||
if unregisterWait(waitFd) == 0:
|
||||
let err = osLastError()
|
||||
if err.int32 != ERROR_IO_PENDING:
|
||||
discard closeHandle(handle)
|
||||
raiseOSError(err)
|
||||
let err = osLastError()
|
||||
if err.int32 != ERROR_IO_PENDING:
|
||||
discard closeHandle(handle)
|
||||
raiseOSError(err)
|
||||
if closeHandle(handle) == 0:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
@@ -1093,7 +1093,7 @@ else:
|
||||
# queue.
|
||||
type
|
||||
AsyncFD* = distinct cint
|
||||
Callback = proc (fd: AsyncFD): bool {.closure,gcsafe.}
|
||||
Callback = proc (fd: AsyncFD): bool {.closure, gcsafe.}
|
||||
|
||||
AsyncData = object
|
||||
readList: seq[Callback]
|
||||
@@ -1588,7 +1588,7 @@ proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
|
||||
createAsyncNativeSocketImpl(domain, sockType, protocol)
|
||||
|
||||
proc newAsyncNativeSocket*(domain: cint, sockType: cint,
|
||||
protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} =
|
||||
protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} =
|
||||
createAsyncNativeSocketImpl(domain, sockType, protocol)
|
||||
|
||||
proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
|
||||
|
||||
@@ -488,7 +488,7 @@ proc setFileSize*(f: AsyncFile, length: int64) =
|
||||
status = setFilePointer(f.fd.Handle, low, addr high, 0)
|
||||
lastErr = osLastError()
|
||||
if (status == INVALID_SET_FILE_POINTER and lastErr.int32 != NO_ERROR) or
|
||||
(setEndOfFile(f.fd.Handle) == 0):
|
||||
(setEndOfFile(f.fd.Handle) == 0):
|
||||
raiseOSError(osLastError())
|
||||
else:
|
||||
# will truncate if Off is a 32-bit type!
|
||||
|
||||
@@ -100,27 +100,27 @@ type
|
||||
of JRetr, JStore:
|
||||
file: File
|
||||
filename: string
|
||||
total: BiggestInt # In bytes.
|
||||
progress: BiggestInt # In bytes.
|
||||
oneSecond: BiggestInt # Bytes transferred in one second.
|
||||
total: BiggestInt # In bytes.
|
||||
progress: BiggestInt # In bytes.
|
||||
oneSecond: BiggestInt # Bytes transferred in one second.
|
||||
lastProgressReport: float # Time
|
||||
toStore: string # Data left to upload (Only used with async)
|
||||
toStore: string # Data left to upload (Only used with async)
|
||||
|
||||
FtpEventType* = enum
|
||||
EvTransferProgress, EvLines, EvRetr, EvStore
|
||||
|
||||
FtpEvent* = object ## Event
|
||||
FtpEvent* = object ## Event
|
||||
filename*: string
|
||||
case typ*: FtpEventType
|
||||
of EvLines:
|
||||
lines*: string ## Lines that have been transferred.
|
||||
of EvRetr, EvStore: ## Retr/Store operation finished.
|
||||
lines*: string ## Lines that have been transferred.
|
||||
of EvRetr, EvStore: ## Retr/Store operation finished.
|
||||
nil
|
||||
of EvTransferProgress:
|
||||
bytesTotal*: BiggestInt ## Bytes total.
|
||||
bytesFinished*: BiggestInt ## Bytes transferred.
|
||||
speed*: BiggestInt ## Speed in bytes/s
|
||||
currentJob*: FtpJobType ## The current job being performed.
|
||||
bytesTotal*: BiggestInt ## Bytes total.
|
||||
bytesFinished*: BiggestInt ## Bytes transferred.
|
||||
speed*: BiggestInt ## Speed in bytes/s
|
||||
currentJob*: FtpJobType ## The current job being performed.
|
||||
|
||||
ReplyError* = object of IOError
|
||||
|
||||
@@ -154,7 +154,7 @@ proc assertReply(received: TaintedString, expected: varargs[string]) =
|
||||
if received.string.startsWith(i): return
|
||||
raise newException(ReplyError,
|
||||
"Expected reply '$1' got: $2" %
|
||||
[expected.join("' or '"), received.string])
|
||||
[expected.join("' or '"), received.string])
|
||||
|
||||
proc pasv(ftp: AsyncFtpClient) {.async.} =
|
||||
## Negotiate a data connection.
|
||||
@@ -164,8 +164,8 @@ proc pasv(ftp: AsyncFtpClient) {.async.} =
|
||||
assertReply(pasvMsg, "227")
|
||||
var betweenParens = captureBetween(pasvMsg.string, '(', ')')
|
||||
var nums = betweenParens.split(',')
|
||||
var ip = nums[0.. ^3]
|
||||
var port = nums[^2.. ^1]
|
||||
var ip = nums[0 .. ^3]
|
||||
var port = nums[^2 .. ^1]
|
||||
var properPort = port[0].parseInt()*256+port[1].parseInt()
|
||||
await ftp.dsock.connect(ip.join("."), Port(properPort.toU16))
|
||||
ftp.dsockConnected = true
|
||||
|
||||
@@ -17,11 +17,11 @@ type
|
||||
function: CallbackFunc
|
||||
next: owned(ref CallbackList)
|
||||
|
||||
FutureBase* = ref object of RootObj ## Untyped future.
|
||||
FutureBase* = ref object of RootObj ## Untyped future.
|
||||
callbacks: CallbackList
|
||||
|
||||
finished: bool
|
||||
error*: ref Exception ## Stored exception
|
||||
error*: ref Exception ## Stored exception
|
||||
errorStackTrace*: string
|
||||
when not defined(release):
|
||||
stackTrace: seq[StackTraceEntry] ## For debugging purposes only.
|
||||
@@ -29,7 +29,7 @@ type
|
||||
fromProc: string
|
||||
|
||||
Future*[T] = ref object of FutureBase ## Typed future.
|
||||
value: T ## Stored value
|
||||
value: T ## Stored value
|
||||
|
||||
FutureVar*[T] = distinct Future[T]
|
||||
|
||||
@@ -260,7 +260,7 @@ proc clearCallbacks*(future: FutureBase) =
|
||||
future.callbacks.function = nil
|
||||
future.callbacks.next = nil
|
||||
|
||||
proc addCallback*(future: FutureBase, cb: proc() {.closure,gcsafe.}) =
|
||||
proc addCallback*(future: FutureBase, cb: proc() {.closure, gcsafe.}) =
|
||||
## Adds the callbacks proc to be called when the future completes.
|
||||
##
|
||||
## If future has already completed then ``cb`` will be called immediately.
|
||||
@@ -271,16 +271,16 @@ proc addCallback*(future: FutureBase, cb: proc() {.closure,gcsafe.}) =
|
||||
future.callbacks.add cb
|
||||
|
||||
proc addCallback*[T](future: Future[T],
|
||||
cb: proc (future: Future[T]) {.closure,gcsafe.}) =
|
||||
cb: proc (future: Future[T]) {.closure, gcsafe.}) =
|
||||
## Adds the callbacks proc to be called when the future completes.
|
||||
##
|
||||
## If future has already completed then ``cb`` will be called immediately.
|
||||
future.addCallback(
|
||||
proc() =
|
||||
cb(future)
|
||||
cb(future)
|
||||
)
|
||||
|
||||
proc `callback=`*(future: FutureBase, cb: proc () {.closure,gcsafe.}) =
|
||||
proc `callback=`*(future: FutureBase, cb: proc () {.closure, gcsafe.}) =
|
||||
## Clears the list of callbacks and sets the callback proc to be called when the future completes.
|
||||
##
|
||||
## If future has already completed then ``cb`` will be called immediately.
|
||||
@@ -290,7 +290,7 @@ proc `callback=`*(future: FutureBase, cb: proc () {.closure,gcsafe.}) =
|
||||
future.addCallback cb
|
||||
|
||||
proc `callback=`*[T](future: Future[T],
|
||||
cb: proc (future: Future[T]) {.closure,gcsafe.}) =
|
||||
cb: proc (future: Future[T]) {.closure, gcsafe.}) =
|
||||
## Sets the callback proc to be called when the future completes.
|
||||
##
|
||||
## If future has already completed then ``cb`` will be called immediately.
|
||||
|
||||
@@ -50,7 +50,7 @@ type
|
||||
headers*: HttpHeaders
|
||||
protocol*: tuple[orig: string, major, minor: int]
|
||||
url*: Uri
|
||||
hostname*: string ## The hostname of the client that made the request.
|
||||
hostname*: string ## The hostname of the client that made the request.
|
||||
body*: string
|
||||
|
||||
AsyncHttpServer* = ref object
|
||||
@@ -169,7 +169,7 @@ proc processRequest(
|
||||
for i in 0..1:
|
||||
lineFut.mget().setLen(0)
|
||||
lineFut.clean()
|
||||
await client.recvLineInto(lineFut, maxLength=maxLine) # TODO: Timeouts.
|
||||
await client.recvLineInto(lineFut, maxLength = maxLine) # TODO: Timeouts.
|
||||
|
||||
if lineFut.mget == "":
|
||||
client.close()
|
||||
@@ -214,7 +214,7 @@ proc processRequest(
|
||||
i = 0
|
||||
lineFut.mget.setLen(0)
|
||||
lineFut.clean()
|
||||
await client.recvLineInto(lineFut, maxLength=maxLine)
|
||||
await client.recvLineInto(lineFut, maxLength = maxLine)
|
||||
|
||||
if lineFut.mget == "":
|
||||
client.close(); return false
|
||||
@@ -242,7 +242,8 @@ proc processRequest(
|
||||
# - Check for Content-length header
|
||||
if request.headers.hasKey("Content-Length"):
|
||||
var contentLength = 0
|
||||
if parseSaturatedNatural(request.headers["Content-Length"], contentLength) == 0:
|
||||
if parseSaturatedNatural(request.headers["Content-Length"],
|
||||
contentLength) == 0:
|
||||
await request.respond(Http400, "Bad Request. Invalid Content-Length.")
|
||||
return true
|
||||
else:
|
||||
|
||||
@@ -163,7 +163,8 @@ proc processBody(node, retFutureSym: NimNode,
|
||||
if node[1][0].eqIdent("await"):
|
||||
# x = await y
|
||||
var newAsgn = node
|
||||
result.createVar("future" & $node[0].toStrLit, node[1][1], newAsgn[1], newAsgn, node)
|
||||
result.createVar("future" & $node[0].toStrLit, node[1][1], newAsgn[1],
|
||||
newAsgn, node)
|
||||
else: discard
|
||||
of nnkDiscardStmt:
|
||||
# discard await x
|
||||
@@ -212,8 +213,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||
## This macro transforms a single procedure into a closure iterator.
|
||||
## The ``async`` macro supports a stmtList holding multiple async procedures.
|
||||
if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
|
||||
error("Cannot transform this node kind into an async proc." &
|
||||
" proc/method definition or lambda node expected.")
|
||||
error("Cannot transform this node kind into an async proc." &
|
||||
" proc/method definition or lambda node expected.")
|
||||
|
||||
let prcName = prc.name.getName
|
||||
|
||||
@@ -296,11 +297,12 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
|
||||
|
||||
var closureIterator = newProc(iteratorNameSym, [parseExpr("owned(FutureBase)")],
|
||||
procBody, nnkIteratorDef)
|
||||
closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom=prc.body)
|
||||
closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom = prc.body)
|
||||
closureIterator.addPragma(newIdentNode("closure"))
|
||||
|
||||
# If proc has an explicit gcsafe pragma, we add it to iterator as well.
|
||||
if prc.pragma.findChild(it.kind in {nnkSym, nnkIdent} and $it == "gcsafe") != nil:
|
||||
if prc.pragma.findChild(it.kind in {nnkSym, nnkIdent} and $it ==
|
||||
"gcsafe") != nil:
|
||||
closureIterator.addPragma(newIdentNode("gcsafe"))
|
||||
outerProcBody.add(closureIterator)
|
||||
|
||||
@@ -414,20 +416,20 @@ proc splitProc(prc: NimNode): (NimNode, NimNode) =
|
||||
result[0] = prc.copyNimTree()
|
||||
# Retrieve the `T` inside `Future[T]`.
|
||||
let returnType = stripReturnType(result[0][3][0])
|
||||
result[0][3][0] = splitParamType(returnType, async=false)
|
||||
result[0][3][0] = splitParamType(returnType, async = false)
|
||||
for i in 1 ..< result[0][3].len:
|
||||
# Sync proc (0) -> FormalParams (3) -> IdentDefs, the parameter (i) ->
|
||||
# parameter type (1).
|
||||
result[0][3][i][1] = splitParamType(result[0][3][i][1], async=false)
|
||||
result[0][3][i][1] = splitParamType(result[0][3][i][1], async = false)
|
||||
result[0][6] = stripAwait(result[0][6])
|
||||
|
||||
result[1] = prc.copyNimTree()
|
||||
if result[1][3][0].kind == nnkBracketExpr:
|
||||
result[1][3][0][1] = splitParamType(result[1][3][0][1], async=true)
|
||||
result[1][3][0][1] = splitParamType(result[1][3][0][1], async = true)
|
||||
for i in 1 ..< result[1][3].len:
|
||||
# Async proc (1) -> FormalParams (3) -> IdentDefs, the parameter (i) ->
|
||||
# parameter type (1).
|
||||
result[1][3][i][1] = splitParamType(result[1][3][i][1], async=true)
|
||||
result[1][3][i][1] = splitParamType(result[1][3][i][1], async = true)
|
||||
|
||||
macro multisync*(prc: untyped): untyped =
|
||||
## Macro which processes async procedures into both asynchronous and
|
||||
|
||||
@@ -114,11 +114,11 @@ type
|
||||
# AsyncSocket* {.borrow: `.`.} = distinct Socket. But that doesn't work.
|
||||
AsyncSocketDesc = object
|
||||
fd: SocketHandle
|
||||
closed: bool ## determines whether this socket has been closed
|
||||
closed: bool ## determines whether this socket has been closed
|
||||
isBuffered: bool ## determines whether this socket is buffered.
|
||||
buffer: array[0..BufferSize, char]
|
||||
currPos: int # current index in buffer
|
||||
bufLen: int # current length of buffer
|
||||
currPos: int # current index in buffer
|
||||
bufLen: int # current length of buffer
|
||||
isSsl: bool
|
||||
when defineSsl:
|
||||
sslHandle: SslPtr
|
||||
@@ -603,7 +603,8 @@ proc recvLine*(socket: AsyncSocket,
|
||||
await socket.recvLineInto(resString, flags, maxLength)
|
||||
result = resString.mget()
|
||||
|
||||
proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
|
||||
proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [
|
||||
ReadIOEffect].} =
|
||||
## Marks ``socket`` as accepting connections.
|
||||
## ``Backlog`` specifies the maximum length of the
|
||||
## queue of pending connections.
|
||||
@@ -620,7 +621,7 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
|
||||
if realaddr == "":
|
||||
case socket.domain
|
||||
of AF_INET6: realaddr = "::"
|
||||
of AF_INET: realaddr = "0.0.0.0"
|
||||
of AF_INET: realaddr = "0.0.0.0"
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
"Unknown socket address family and no address specified to bindAddr")
|
||||
@@ -653,7 +654,7 @@ when defined(posix):
|
||||
|
||||
var socketAddr = makeUnixAddr(path)
|
||||
let ret = socket.fd.connect(cast[ptr SockAddr](addr socketAddr),
|
||||
(sizeof(socketAddr.sun_family) + path.len).SockLen)
|
||||
(sizeof(socketAddr.sun_family) + path.len).SockLen)
|
||||
if ret == 0:
|
||||
# Request to connect completed immediately.
|
||||
retFuture.complete()
|
||||
@@ -671,7 +672,7 @@ when defined(posix):
|
||||
when not defined(nimdoc):
|
||||
var socketAddr = makeUnixAddr(path)
|
||||
if socket.fd.bindAddr(cast[ptr SockAddr](addr socketAddr),
|
||||
(sizeof(socketAddr.sun_family) + path.len).SockLen) != 0'i32:
|
||||
(sizeof(socketAddr.sun_family) + path.len).SockLen) != 0'i32:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
elif defined(nimdoc):
|
||||
|
||||
@@ -14,10 +14,10 @@ import asyncfutures
|
||||
import deques
|
||||
|
||||
type
|
||||
FutureStream*[T] = ref object ## Special future that acts as
|
||||
## a queue. Its API is still
|
||||
## experimental and so is
|
||||
## subject to change.
|
||||
FutureStream*[T] = ref object ## Special future that acts as
|
||||
## a queue. Its API is still
|
||||
## experimental and so is
|
||||
## subject to change.
|
||||
queue: Deque[T]
|
||||
finished: bool
|
||||
cb: proc () {.closure, gcsafe.}
|
||||
@@ -45,7 +45,7 @@ proc complete*[T](future: FutureStream[T]) =
|
||||
future.cb()
|
||||
|
||||
proc `callback=`*[T](future: FutureStream[T],
|
||||
cb: proc (future: FutureStream[T]) {.closure,gcsafe.}) =
|
||||
cb: proc (future: FutureStream[T]) {.closure, gcsafe.}) =
|
||||
## Sets the callback proc to be called when data was placed inside the
|
||||
## future stream.
|
||||
##
|
||||
@@ -74,7 +74,7 @@ proc write*[T](future: FutureStream[T], value: T): Future[void] =
|
||||
result.fail(newException(ValueError, msg))
|
||||
return
|
||||
# TODO: Implement limiting of the streams storage to prevent it growing
|
||||
# infinitely when no reads are occuring.
|
||||
# infinitely when no reads are occurring.
|
||||
future.queue.addLast(value)
|
||||
if not future.cb.isNil: future.cb()
|
||||
result.complete()
|
||||
|
||||
@@ -112,7 +112,8 @@ template encodeInternal(s: typed, lineLen: int, newLine: string): untyped =
|
||||
#assert(r == result.len)
|
||||
discard
|
||||
|
||||
proc encode*[T: SomeInteger|char](s: openArray[T], lineLen = 75, newLine=""): string =
|
||||
proc encode*[T: SomeInteger|char](s: openArray[T], lineLen = 75,
|
||||
newLine = ""): string =
|
||||
## Encodes ``s`` into base64 representation. After ``lineLen`` characters, a
|
||||
## ``newline`` is added.
|
||||
##
|
||||
@@ -128,7 +129,7 @@ proc encode*[T: SomeInteger|char](s: openArray[T], lineLen = 75, newLine=""): st
|
||||
assert encode([1, 2, 3, 4, 5]) == "AQIDBAU="
|
||||
encodeInternal(s, lineLen, newLine)
|
||||
|
||||
proc encode*(s: string, lineLen = 75, newLine=""): string =
|
||||
proc encode*(s: string, lineLen = 75, newLine = ""): string =
|
||||
## Encodes ``s`` into base64 representation. After ``lineLen`` characters, a
|
||||
## ``newline`` is added.
|
||||
##
|
||||
@@ -208,5 +209,5 @@ when isMainModule:
|
||||
|
||||
for t in items(tests):
|
||||
assert decode(encode(t)) == t
|
||||
assert decode(encode(t, lineLen=40)) == t
|
||||
assert decode(encode(t, lineLen=76)) == t
|
||||
assert decode(encode(t, lineLen = 40)) == t
|
||||
assert decode(encode(t, lineLen = 76)) == t
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
## to force predictable behaviour for all input, causing a small performance hit.
|
||||
##
|
||||
## At this time only `fastLog2`, `firstSetBit, `countLeadingZeroBits`, `countTrailingZeroBits`
|
||||
## may return undefined and/or platform dependant value if given invalid input.
|
||||
## may return undefined and/or platform dependent value if given invalid input.
|
||||
|
||||
proc bitnot*[T: SomeInteger](x: T): T {.magic: "BitnotI", noSideEffect.}
|
||||
## Computes the `bitwise complement` of the integer `x`.
|
||||
@@ -39,7 +39,8 @@ proc bitxor*[T: SomeInteger](x, y: T): T {.magic: "BitxorI", noSideEffect.}
|
||||
|
||||
const useBuiltins = not defined(noIntrinsicsBitOpts)
|
||||
const noUndefined = defined(noUndefinedBitOpts)
|
||||
const useGCC_builtins = (defined(gcc) or defined(llvm_gcc) or defined(clang)) and useBuiltins
|
||||
const useGCC_builtins = (defined(gcc) or defined(llvm_gcc) or
|
||||
defined(clang)) and useBuiltins
|
||||
const useICC_builtins = defined(icc) and useBuiltins
|
||||
const useVCC_builtins = defined(vcc) and useBuiltins
|
||||
const arch64 = sizeof(int) == 8
|
||||
@@ -196,7 +197,8 @@ template parityImpl[T](value: T): int =
|
||||
when useGCC_builtins:
|
||||
# Returns the number of set 1-bits in value.
|
||||
proc builtin_popcount(x: cuint): cint {.importc: "__builtin_popcount", cdecl.}
|
||||
proc builtin_popcountll(x: culonglong): cint {.importc: "__builtin_popcountll", cdecl.}
|
||||
proc builtin_popcountll(x: culonglong): cint {.
|
||||
importc: "__builtin_popcountll", cdecl.}
|
||||
|
||||
# Returns the bit parity in value
|
||||
proc builtin_parity(x: cuint): cint {.importc: "__builtin_parity", cdecl.}
|
||||
@@ -216,17 +218,24 @@ when useGCC_builtins:
|
||||
|
||||
elif useVCC_builtins:
|
||||
# Counts the number of one bits (population count) in a 16-, 32-, or 64-byte unsigned integer.
|
||||
proc builtin_popcnt16(a2: uint16): uint16 {.importc: "__popcnt16" header: "<intrin.h>", noSideEffect.}
|
||||
proc builtin_popcnt32(a2: uint32): uint32 {.importc: "__popcnt" header: "<intrin.h>", noSideEffect.}
|
||||
proc builtin_popcnt64(a2: uint64): uint64 {.importc: "__popcnt64" header: "<intrin.h>", noSideEffect.}
|
||||
proc builtin_popcnt16(a2: uint16): uint16 {.
|
||||
importc: "__popcnt16"header: "<intrin.h>", noSideEffect.}
|
||||
proc builtin_popcnt32(a2: uint32): uint32 {.
|
||||
importc: "__popcnt"header: "<intrin.h>", noSideEffect.}
|
||||
proc builtin_popcnt64(a2: uint64): uint64 {.
|
||||
importc: "__popcnt64"header: "<intrin.h>", noSideEffect.}
|
||||
|
||||
# Search the mask data from most significant bit (MSB) to least significant bit (LSB) for a set bit (1).
|
||||
proc bitScanReverse(index: ptr culong, mask: culong): cuchar {.importc: "_BitScanReverse", header: "<intrin.h>", noSideEffect.}
|
||||
proc bitScanReverse64(index: ptr culong, mask: uint64): cuchar {.importc: "_BitScanReverse64", header: "<intrin.h>", noSideEffect.}
|
||||
proc bitScanReverse(index: ptr culong, mask: culong): cuchar {.
|
||||
importc: "_BitScanReverse", header: "<intrin.h>", noSideEffect.}
|
||||
proc bitScanReverse64(index: ptr culong, mask: uint64): cuchar {.
|
||||
importc: "_BitScanReverse64", header: "<intrin.h>", noSideEffect.}
|
||||
|
||||
# Search the mask data from least significant bit (LSB) to the most significant bit (MSB) for a set bit (1).
|
||||
proc bitScanForward(index: ptr culong, mask: culong): cuchar {.importc: "_BitScanForward", header: "<intrin.h>", noSideEffect.}
|
||||
proc bitScanForward64(index: ptr culong, mask: uint64): cuchar {.importc: "_BitScanForward64", header: "<intrin.h>", noSideEffect.}
|
||||
proc bitScanForward(index: ptr culong, mask: culong): cuchar {.
|
||||
importc: "_BitScanForward", header: "<intrin.h>", noSideEffect.}
|
||||
proc bitScanForward64(index: ptr culong, mask: uint64): cuchar {.
|
||||
importc: "_BitScanForward64", header: "<intrin.h>", noSideEffect.}
|
||||
|
||||
template vcc_scan_impl(fnc: untyped; v: untyped): int =
|
||||
var index: culong
|
||||
@@ -238,16 +247,22 @@ elif useICC_builtins:
|
||||
# Intel compiler intrinsics: http://fulla.fnal.gov/intel/compiler_c/main_cls/intref_cls/common/intref_allia_misc.htm
|
||||
# see also: https://software.intel.com/en-us/node/523362
|
||||
# Count the number of bits set to 1 in an integer a, and return that count in dst.
|
||||
proc builtin_popcnt32(a: cint): cint {.importc: "_popcnt" header: "<immintrin.h>", noSideEffect.}
|
||||
proc builtin_popcnt64(a: uint64): cint {.importc: "_popcnt64" header: "<immintrin.h>", noSideEffect.}
|
||||
proc builtin_popcnt32(a: cint): cint {.
|
||||
importc: "_popcnt"header: "<immintrin.h>", noSideEffect.}
|
||||
proc builtin_popcnt64(a: uint64): cint {.
|
||||
importc: "_popcnt64"header: "<immintrin.h>", noSideEffect.}
|
||||
|
||||
# Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined.
|
||||
proc bitScanForward(p: ptr uint32, b: uint32): cuchar {.importc: "_BitScanForward", header: "<immintrin.h>", noSideEffect.}
|
||||
proc bitScanForward64(p: ptr uint32, b: uint64): cuchar {.importc: "_BitScanForward64", header: "<immintrin.h>", noSideEffect.}
|
||||
proc bitScanForward(p: ptr uint32, b: uint32): cuchar {.
|
||||
importc: "_BitScanForward", header: "<immintrin.h>", noSideEffect.}
|
||||
proc bitScanForward64(p: ptr uint32, b: uint64): cuchar {.
|
||||
importc: "_BitScanForward64", header: "<immintrin.h>", noSideEffect.}
|
||||
|
||||
# Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
|
||||
proc bitScanReverse(p: ptr uint32, b: uint32): cuchar {.importc: "_BitScanReverse", header: "<immintrin.h>", noSideEffect.}
|
||||
proc bitScanReverse64(p: ptr uint32, b: uint64): cuchar {.importc: "_BitScanReverse64", header: "<immintrin.h>", noSideEffect.}
|
||||
proc bitScanReverse(p: ptr uint32, b: uint32): cuchar {.
|
||||
importc: "_BitScanReverse", header: "<immintrin.h>", noSideEffect.}
|
||||
proc bitScanReverse64(p: ptr uint32, b: uint64): cuchar {.
|
||||
importc: "_BitScanReverse64", header: "<immintrin.h>", noSideEffect.}
|
||||
|
||||
template icc_scan_impl(fnc: untyped; v: untyped): int =
|
||||
var index: uint32
|
||||
@@ -266,21 +281,21 @@ proc countSetBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
else:
|
||||
when useGCC_builtins:
|
||||
when sizeof(x) <= 4: result = builtin_popcount(x.cuint).int
|
||||
else: result = builtin_popcountll(x.culonglong).int
|
||||
else: result = builtin_popcountll(x.culonglong).int
|
||||
elif useVCC_builtins:
|
||||
when sizeof(x) <= 2: result = builtin_popcnt16(x.uint16).int
|
||||
elif sizeof(x) <= 4: result = builtin_popcnt32(x.uint32).int
|
||||
elif arch64: result = builtin_popcnt64(x.uint64).int
|
||||
else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).uint32 ).int +
|
||||
builtin_popcnt32((x.uint64 shr 32'u64).uint32 ).int
|
||||
elif arch64: result = builtin_popcnt64(x.uint64).int
|
||||
else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).uint32).int +
|
||||
builtin_popcnt32((x.uint64 shr 32'u64).uint32).int
|
||||
elif useICC_builtins:
|
||||
when sizeof(x) <= 4: result = builtin_popcnt32(x.cint).int
|
||||
elif arch64: result = builtin_popcnt64(x.uint64).int
|
||||
else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).cint ).int +
|
||||
builtin_popcnt32((x.uint64 shr 32'u64).cint ).int
|
||||
elif arch64: result = builtin_popcnt64(x.uint64).int
|
||||
else: result = builtin_popcnt32((x.uint64 and 0xFFFFFFFF'u64).cint).int +
|
||||
builtin_popcnt32((x.uint64 shr 32'u64).cint).int
|
||||
else:
|
||||
when sizeof(x) <= 4: result = countSetBitsNim(x.uint32)
|
||||
else: result = countSetBitsNim(x.uint64)
|
||||
else: result = countSetBitsNim(x.uint64)
|
||||
|
||||
proc popcount*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
## Alias for for countSetBits (Hamming weight.)
|
||||
@@ -298,10 +313,10 @@ proc parityBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
else:
|
||||
when useGCC_builtins:
|
||||
when sizeof(x) <= 4: result = builtin_parity(x.uint32).int
|
||||
else: result = builtin_parityll(x.uint64).int
|
||||
else: result = builtin_parityll(x.uint64).int
|
||||
else:
|
||||
when sizeof(x) <= 4: result = parityImpl(x.uint32)
|
||||
else: result = parityImpl(x.uint64)
|
||||
else: result = parityImpl(x.uint64)
|
||||
|
||||
proc firstSetBit*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
## Returns the 1-based index of the least significant set bit of x.
|
||||
@@ -321,7 +336,7 @@ proc firstSetBit*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
return 0
|
||||
when useGCC_builtins:
|
||||
when sizeof(x) <= 4: result = builtin_ffs(cast[cint](x.cuint)).int
|
||||
else: result = builtin_ffsll(cast[clonglong](x.culonglong)).int
|
||||
else: result = builtin_ffsll(cast[clonglong](x.culonglong)).int
|
||||
elif useVCC_builtins:
|
||||
when sizeof(x) <= 4:
|
||||
result = 1 + vcc_scan_impl(bitScanForward, x.culong)
|
||||
@@ -338,7 +353,7 @@ proc firstSetBit*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
result = firstSetBitNim(x.uint64)
|
||||
else:
|
||||
when sizeof(x) <= 4: result = firstSetBitNim(x.uint32)
|
||||
else: result = firstSetBitNim(x.uint64)
|
||||
else: result = firstSetBitNim(x.uint64)
|
||||
|
||||
proc fastLog2*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
## Quickly find the log base 2 of an integer.
|
||||
@@ -354,7 +369,7 @@ proc fastLog2*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
else:
|
||||
when useGCC_builtins:
|
||||
when sizeof(x) <= 4: result = 31 - builtin_clz(x.uint32).int
|
||||
else: result = 63 - builtin_clzll(x.uint64).int
|
||||
else: result = 63 - builtin_clzll(x.uint64).int
|
||||
elif useVCC_builtins:
|
||||
when sizeof(x) <= 4:
|
||||
result = vcc_scan_impl(bitScanReverse, x.culong)
|
||||
@@ -371,7 +386,7 @@ proc fastLog2*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
result = fastlog2Nim(x.uint64)
|
||||
else:
|
||||
when sizeof(x) <= 4: result = fastlog2Nim(x.uint32)
|
||||
else: result = fastlog2Nim(x.uint64)
|
||||
else: result = fastlog2Nim(x.uint64)
|
||||
|
||||
proc countLeadingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
## Returns the number of leading zero bits in integer.
|
||||
@@ -387,10 +402,10 @@ proc countLeadingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
else:
|
||||
when useGCC_builtins:
|
||||
when sizeof(x) <= 4: result = builtin_clz(x.uint32).int - (32 - sizeof(x)*8)
|
||||
else: result = builtin_clzll(x.uint64).int
|
||||
else: result = builtin_clzll(x.uint64).int
|
||||
else:
|
||||
when sizeof(x) <= 4: result = sizeof(x)*8 - 1 - fastlog2Nim(x.uint32)
|
||||
else: result = sizeof(x)*8 - 1 - fastlog2Nim(x.uint64)
|
||||
else: result = sizeof(x)*8 - 1 - fastlog2Nim(x.uint64)
|
||||
|
||||
proc countTrailingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
## Returns the number of trailing zeros in integer.
|
||||
@@ -406,7 +421,7 @@ proc countTrailingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||
else:
|
||||
when useGCC_builtins:
|
||||
when sizeof(x) <= 4: result = builtin_ctz(x.uint32).int
|
||||
else: result = builtin_ctzll(x.uint64).int
|
||||
else: result = builtin_ctzll(x.uint64).int
|
||||
else:
|
||||
result = firstSetBit(x) - 1
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ proc openDefaultBrowser*(url: string) =
|
||||
for b in getEnv("BROWSER").string.split(PathSep):
|
||||
try:
|
||||
# we use ``startProcess`` here because we don't want to block!
|
||||
discard startProcess(command=b, args=[url], options={poUsePath})
|
||||
discard startProcess(command = b, args = [url], options = {poUsePath})
|
||||
return
|
||||
except OSError:
|
||||
discard
|
||||
|
||||
@@ -58,11 +58,11 @@ proc xmlEncode*(s: string): string =
|
||||
for i in 0..len(s)-1: addXmlChar(result, s[i])
|
||||
|
||||
type
|
||||
CgiError* = object of IOError ## exception that is raised if a CGI error occurs
|
||||
RequestMethod* = enum ## the used request method
|
||||
methodNone, ## no REQUEST_METHOD environment variable
|
||||
methodPost, ## query uses the POST method
|
||||
methodGet ## query uses the GET method
|
||||
CgiError* = object of IOError ## exception that is raised if a CGI error occurs
|
||||
RequestMethod* = enum ## the used request method
|
||||
methodNone, ## no REQUEST_METHOD environment variable
|
||||
methodPost, ## query uses the POST method
|
||||
methodGet ## query uses the GET method
|
||||
|
||||
proc cgiError*(msg: string) {.noreturn.} =
|
||||
## raises an ECgi exception with message `msg`.
|
||||
|
||||
@@ -387,6 +387,7 @@ proc assign*(dest: var IntSet, src: IntSet) =
|
||||
else:
|
||||
dest.counter = src.counter
|
||||
dest.max = src.max
|
||||
dest.elems = src.elems
|
||||
newSeq(dest.data, src.data.len)
|
||||
|
||||
var it = src.head
|
||||
@@ -653,3 +654,19 @@ when isMainModule:
|
||||
xs = toSeq(items(x))
|
||||
xs.sort(cmp[int])
|
||||
assert xs == @[1, 4, 7, 1001, 1056]
|
||||
|
||||
proc bug12366 =
|
||||
var
|
||||
x = initIntSet()
|
||||
y = initIntSet()
|
||||
n = 3584
|
||||
|
||||
for i in 0..n:
|
||||
x.incl(i)
|
||||
y.incl(i)
|
||||
|
||||
let z = symmetricDifference(x, y)
|
||||
doAssert z.len == 0
|
||||
doAssert $z == "{}"
|
||||
|
||||
bug12366()
|
||||
|
||||
@@ -848,7 +848,7 @@ template mapIt*(s: typed, op: untyped): untyped =
|
||||
result
|
||||
|
||||
template mapIt*(s, typ, op: untyped): untyped {.error:
|
||||
"Deprecated since v0.12; Use 'mapIt(seq1, op)' - without specifying the type of the returned seqence".} =
|
||||
"Deprecated since v0.12; Use 'mapIt(seq1, op)' - without specifying the type of the returned sequence".} =
|
||||
var result: seq[typ] = @[]
|
||||
for it {.inject.} in items(s):
|
||||
result.add(op)
|
||||
@@ -883,7 +883,7 @@ template newSeqWith*(len: int, init: untyped): untyped =
|
||||
## or to populate fields of the created sequence.
|
||||
##
|
||||
runnableExamples:
|
||||
## Creates a seqence containing 5 bool sequences, each of length of 3.
|
||||
## Creates a sequence containing 5 bool sequences, each of length of 3.
|
||||
var seq2D = newSeqWith(5, newSeq[bool](3))
|
||||
assert seq2D.len == 5
|
||||
assert seq2D[0].len == 3
|
||||
|
||||
@@ -62,12 +62,12 @@ proc `==` *[T](x, y: Complex[T]): bool =
|
||||
## Compare two complex numbers ``x`` and ``y`` for equality.
|
||||
result = x.re == y.re and x.im == y.im
|
||||
|
||||
proc `+` *[T](x: T, y: Complex[T]): Complex[T] =
|
||||
proc `+` *[T](x: T; y: Complex[T]): Complex[T] =
|
||||
## Add a real number to a complex number.
|
||||
result.re = x + y.re
|
||||
result.im = y.im
|
||||
|
||||
proc `+` *[T](x: Complex[T], y: T): Complex[T] =
|
||||
proc `+` *[T](x: Complex[T]; y: T): Complex[T] =
|
||||
## Add a complex number to a real number.
|
||||
result.re = x.re + y
|
||||
result.im = x.im
|
||||
@@ -82,11 +82,11 @@ proc `-` *[T](z: Complex[T]): Complex[T] =
|
||||
result.re = -z.re
|
||||
result.im = -z.im
|
||||
|
||||
proc `-` *[T](x: T, y: Complex[T]): Complex[T] =
|
||||
proc `-` *[T](x: T; y: Complex[T]): Complex[T] =
|
||||
## Subtract a complex number from a real number.
|
||||
x + (-y)
|
||||
|
||||
proc `-` *[T](x: Complex[T], y: T): Complex[T] =
|
||||
proc `-` *[T](x: Complex[T]; y: T): Complex[T] =
|
||||
## Subtract a real number from a complex number.
|
||||
result.re = x.re - y
|
||||
result.im = x.im
|
||||
@@ -96,12 +96,12 @@ proc `-` *[T](x, y: Complex[T]): Complex[T] =
|
||||
result.re = x.re - y.re
|
||||
result.im = x.im - y.im
|
||||
|
||||
proc `/` *[T](x: Complex[T], y: T): Complex[T] =
|
||||
proc `/` *[T](x: Complex[T]; y: T): Complex[T] =
|
||||
## Divide complex number ``x`` by real number ``y``.
|
||||
result.re = x.re / y
|
||||
result.im = x.im / y
|
||||
|
||||
proc `/` *[T](x: T, y: Complex[T]): Complex[T] =
|
||||
proc `/` *[T](x: T; y: Complex[T]): Complex[T] =
|
||||
## Divide real number ``x`` by complex number ``y``.
|
||||
result = x * inv(y)
|
||||
|
||||
@@ -119,12 +119,12 @@ proc `/` *[T](x, y: Complex[T]): Complex[T] =
|
||||
result.re = (x.re + r * x.im) / den
|
||||
result.im = (x.im - r * x.re) / den
|
||||
|
||||
proc `*` *[T](x: T, y: Complex[T]): Complex[T] =
|
||||
proc `*` *[T](x: T; y: Complex[T]): Complex[T] =
|
||||
## Multiply a real number and a complex number.
|
||||
result.re = x * y.re
|
||||
result.im = x * y.im
|
||||
|
||||
proc `*` *[T](x: Complex[T], y: T): Complex[T] =
|
||||
proc `*` *[T](x: Complex[T]; y: T): Complex[T] =
|
||||
## Multiply a complex number with a real number.
|
||||
result.re = x.re * y
|
||||
result.im = x.im * y
|
||||
@@ -135,23 +135,23 @@ proc `*` *[T](x, y: Complex[T]): Complex[T] =
|
||||
result.im = x.im * y.re + x.re * y.im
|
||||
|
||||
|
||||
proc `+=` *[T](x: var Complex[T], y: Complex[T]) =
|
||||
proc `+=` *[T](x: var Complex[T]; y: Complex[T]) =
|
||||
## Add ``y`` to ``x``.
|
||||
x.re += y.re
|
||||
x.im += y.im
|
||||
|
||||
proc `-=` *[T](x: var Complex[T], y: Complex[T]) =
|
||||
proc `-=` *[T](x: var Complex[T]; y: Complex[T]) =
|
||||
## Subtract ``y`` from ``x``.
|
||||
x.re -= y.re
|
||||
x.im -= y.im
|
||||
|
||||
proc `*=` *[T](x: var Complex[T], y: Complex[T]) =
|
||||
proc `*=` *[T](x: var Complex[T]; y: Complex[T]) =
|
||||
## Multiply ``y`` to ``x``.
|
||||
let im = x.im * y.re + x.re * y.im
|
||||
x.re = x.re * y.re - x.im * y.im
|
||||
x.im = im
|
||||
|
||||
proc `/=` *[T](x: var Complex[T], y: Complex[T]) =
|
||||
proc `/=` *[T](x: var Complex[T]; y: Complex[T]) =
|
||||
## Divide ``x`` by ``y`` in place.
|
||||
x = x / y
|
||||
|
||||
@@ -222,7 +222,7 @@ proc pow*[T](x, y: Complex[T]): Complex[T] =
|
||||
result.re = s * cos(r)
|
||||
result.im = s * sin(r)
|
||||
|
||||
proc pow*[T](x: Complex[T], y: T): Complex[T] =
|
||||
proc pow*[T](x: Complex[T]; y: T): Complex[T] =
|
||||
## Complex number ``x`` raised to the power ``y``.
|
||||
pow(x, complex[T](y))
|
||||
|
||||
@@ -352,18 +352,18 @@ when isMainModule:
|
||||
proc `=~`[T](x, y: Complex[T]): bool =
|
||||
result = abs(x.re-y.re) < 1e-6 and abs(x.im-y.im) < 1e-6
|
||||
|
||||
proc `=~`[T](x: Complex[T], y: T): bool =
|
||||
proc `=~`[T](x: Complex[T]; y: T): bool =
|
||||
result = abs(x.re-y) < 1e-6 and abs(x.im) < 1e-6
|
||||
|
||||
var
|
||||
z: Complex64 = complex(0.0, 0.0)
|
||||
oo: Complex64 = complex(1.0, 1.0)
|
||||
a: Complex64 = complex(1.0, 2.0)
|
||||
b: Complex64 = complex(-1.0, -2.0)
|
||||
m1: Complex64 = complex(-1.0, 0.0)
|
||||
i: Complex64 = complex(0.0, 1.0)
|
||||
z: Complex64 = complex(0.0, 0.0)
|
||||
oo: Complex64 = complex(1.0, 1.0)
|
||||
a: Complex64 = complex(1.0, 2.0)
|
||||
b: Complex64 = complex(-1.0, -2.0)
|
||||
m1: Complex64 = complex(-1.0, 0.0)
|
||||
i: Complex64 = complex(0.0, 1.0)
|
||||
one: Complex64 = complex(1.0, 0.0)
|
||||
tt: Complex64 = complex(10.0, 20.0)
|
||||
tt: Complex64 = complex(10.0, 20.0)
|
||||
ipi: Complex64 = complex(0.0, -PI)
|
||||
|
||||
doAssert(a/2.0 =~ complex(0.5, 1.0))
|
||||
|
||||
@@ -47,7 +47,7 @@ when defined(cpp) or defined(nimdoc):
|
||||
## Behaves like Acquire when applied to load, like Release when
|
||||
## applied to a store and like AcquireRelease when applied to a
|
||||
## read-modify-write operation.
|
||||
## Also garantees that all threads observe the same total ordering
|
||||
## Also guarantees that all threads observe the same total ordering
|
||||
## with other moSequentiallyConsistent operations.
|
||||
|
||||
type
|
||||
|
||||
@@ -50,7 +50,7 @@ when defined(haiku):
|
||||
header: "<OS.h>".}
|
||||
|
||||
proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
|
||||
## returns the numer of the processors/cores the machine has.
|
||||
## returns the number of the processors/cores the machine has.
|
||||
## Returns 0 if it cannot be detected.
|
||||
when defined(windows):
|
||||
type
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Implements Nim's `spawn <manual.html#parallel-amp-spawn>`_.
|
||||
## Implements Nim's `spawn <manual_experimental.html#parallel-amp-spawn>`_.
|
||||
##
|
||||
## **See also:**
|
||||
## * `threads module <threads.html>`_
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
when not nimCoroutines and not defined(nimdoc):
|
||||
when defined(noNimCoroutines):
|
||||
{.error: "Coroutines can not be used with -d:noNimCoroutines"}
|
||||
{.error: "Coroutines can not be used with -d:noNimCoroutines".}
|
||||
else:
|
||||
{.error: "Coroutines require -d:nimCoroutines".}
|
||||
|
||||
@@ -75,13 +75,18 @@ elif coroBackend == CORO_BACKEND_UCONTEXT:
|
||||
|
||||
Context = ucontext_t
|
||||
|
||||
proc getcontext(context: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
|
||||
proc setcontext(context: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
|
||||
proc swapcontext(fromCtx, toCtx: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
|
||||
proc makecontext(context: var ucontext_t, fn: pointer, argc: int32) {.importc, header: "<ucontext.h>", varargs.}
|
||||
proc getcontext(context: var ucontext_t): int32 {.importc,
|
||||
header: "<ucontext.h>".}
|
||||
proc setcontext(context: var ucontext_t): int32 {.importc,
|
||||
header: "<ucontext.h>".}
|
||||
proc swapcontext(fromCtx, toCtx: var ucontext_t): int32 {.importc,
|
||||
header: "<ucontext.h>".}
|
||||
proc makecontext(context: var ucontext_t, fn: pointer, argc: int32) {.importc,
|
||||
header: "<ucontext.h>", varargs.}
|
||||
|
||||
elif coroBackend == CORO_BACKEND_SETJMP:
|
||||
proc coroExecWithStack*(fn: pointer, stack: pointer) {.noreturn, importc: "narch_$1", fastcall.}
|
||||
proc coroExecWithStack*(fn: pointer, stack: pointer) {.noreturn,
|
||||
importc: "narch_$1", fastcall.}
|
||||
when defined(amd64):
|
||||
{.compile: "../arch/x86/amd64.S".}
|
||||
elif defined(i386):
|
||||
@@ -105,14 +110,14 @@ elif coroBackend == CORO_BACKEND_SETJMP:
|
||||
{.error: "Unsupported architecture.".}
|
||||
|
||||
proc setjmp(ctx: var JmpBuf): int {.importc: "narch_$1".}
|
||||
proc longjmp(ctx: JmpBuf, ret=1) {.importc: "narch_$1".}
|
||||
proc longjmp(ctx: JmpBuf, ret = 1) {.importc: "narch_$1".}
|
||||
else:
|
||||
# Use setjmp/longjmp implementation provided by the system.
|
||||
type
|
||||
JmpBuf {.importc: "jmp_buf", header: "<setjmp.h>".} = object
|
||||
|
||||
proc setjmp(ctx: var JmpBuf): int {.importc, header: "<setjmp.h>".}
|
||||
proc longjmp(ctx: JmpBuf, ret=1) {.importc, header: "<setjmp.h>".}
|
||||
proc longjmp(ctx: JmpBuf, ret = 1) {.importc, header: "<setjmp.h>".}
|
||||
|
||||
type
|
||||
Context = JmpBuf
|
||||
@@ -134,8 +139,8 @@ const
|
||||
|
||||
type
|
||||
Stack {.pure.} = object
|
||||
top: pointer # Top of the stack. Pointer used for deallocating stack if we own it.
|
||||
bottom: pointer # Very bottom of the stack, acts as unique stack identifier.
|
||||
top: pointer # Top of the stack. Pointer used for deallocating stack if we own it.
|
||||
bottom: pointer # Very bottom of the stack, acts as unique stack identifier.
|
||||
size: int
|
||||
|
||||
Coroutine {.pure.} = object
|
||||
@@ -211,7 +216,7 @@ proc switchTo(current, to: CoroutinePtr) =
|
||||
setFrameState(frame)
|
||||
GC_setActiveStack(current.stack.bottom)
|
||||
|
||||
proc suspend*(sleepTime: float=0) =
|
||||
proc suspend*(sleepTime: float = 0) =
|
||||
## Stops coroutine execution and resumes no sooner than after ``sleeptime`` seconds.
|
||||
## Until then other coroutines are executed.
|
||||
var current = getCurrent()
|
||||
@@ -234,15 +239,15 @@ proc runCurrentTask() =
|
||||
GC_setActiveStack(sp)
|
||||
current.state = CORO_EXECUTING
|
||||
try:
|
||||
current.fn() # Start coroutine execution
|
||||
current.fn() # Start coroutine execution
|
||||
except:
|
||||
echo "Unhandled exception in coroutine."
|
||||
writeStackTrace()
|
||||
current.state = CORO_FINISHED
|
||||
suspend(0) # Exit coroutine without returning from coroExecWithStack()
|
||||
suspend(0) # Exit coroutine without returning from coroExecWithStack()
|
||||
doAssert false
|
||||
|
||||
proc start*(c: proc(), stacksize: int=defaultStackSize): CoroutineRef {.discardable.} =
|
||||
proc start*(c: proc(), stacksize: int = defaultStackSize): CoroutineRef {.discardable.} =
|
||||
## Schedule coroutine for execution. It does not run immediately.
|
||||
if ctx == nil:
|
||||
initialize()
|
||||
@@ -251,7 +256,9 @@ proc start*(c: proc(), stacksize: int=defaultStackSize): CoroutineRef {.discarda
|
||||
when coroBackend == CORO_BACKEND_FIBERS:
|
||||
coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine)))
|
||||
coro.execContext = CreateFiberEx(stacksize, stacksize,
|
||||
FIBER_FLAG_FLOAT_SWITCH, (proc(p: pointer): void {.stdcall.} = runCurrentTask()), nil)
|
||||
FIBER_FLAG_FLOAT_SWITCH,
|
||||
(proc(p: pointer): void {.stdcall.} = runCurrentTask()),
|
||||
nil)
|
||||
coro.stack.size = stacksize
|
||||
else:
|
||||
coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine) + stacksize))
|
||||
@@ -313,7 +320,7 @@ proc run*() =
|
||||
proc alive*(c: CoroutineRef): bool = c.coro != nil and c.coro.state != CORO_FINISHED
|
||||
## Returns ``true`` if coroutine has not returned, ``false`` otherwise.
|
||||
|
||||
proc wait*(c: CoroutineRef, interval=0.01) =
|
||||
proc wait*(c: CoroutineRef, interval = 0.01) =
|
||||
## Returns only after coroutine ``c`` has returned. ``interval`` is time in seconds how often.
|
||||
while alive(c):
|
||||
suspend(interval)
|
||||
|
||||
@@ -18,62 +18,62 @@ type
|
||||
|
||||
|
||||
DbEffect* = object of IOEffect ## effect that denotes a database operation
|
||||
ReadDbEffect* = object of DbEffect ## effect that denotes a read operation
|
||||
WriteDbEffect* = object of DbEffect ## effect that denotes a write operation
|
||||
ReadDbEffect* = object of DbEffect ## effect that denotes a read operation
|
||||
WriteDbEffect* = object of DbEffect ## effect that denotes a write operation
|
||||
|
||||
DbTypeKind* = enum ## a superset of datatypes that might be supported.
|
||||
dbUnknown, ## unknown datatype
|
||||
dbSerial, ## datatype used for primary auto-increment keys
|
||||
dbNull, ## datatype used for the NULL value
|
||||
dbBit, ## bit datatype
|
||||
dbBool, ## boolean datatype
|
||||
dbBlob, ## blob datatype
|
||||
dbFixedChar, ## string of fixed length
|
||||
dbVarchar, ## string datatype
|
||||
dbJson, ## JSON datatype
|
||||
dbXml, ## XML datatype
|
||||
dbInt, ## some integer type
|
||||
dbUInt, ## some unsigned integer type
|
||||
dbDecimal, ## decimal numbers (fixed-point number)
|
||||
dbFloat, ## some floating point type
|
||||
dbDate, ## a year-month-day description
|
||||
dbTime, ## HH:MM:SS information
|
||||
dbDatetime, ## year-month-day and HH:MM:SS information,
|
||||
## plus optional time or timezone information
|
||||
dbTimestamp, ## Timestamp values are stored as the number of seconds
|
||||
## since the epoch ('1970-01-01 00:00:00' UTC).
|
||||
dbTimeInterval, ## an interval [a,b] of times
|
||||
dbEnum, ## some enum
|
||||
dbSet, ## set of enum values
|
||||
dbArray, ## an array of values
|
||||
dbComposite, ## composite type (record, struct, etc)
|
||||
dbUrl, ## a URL
|
||||
dbUuid, ## a UUID
|
||||
dbInet, ## an IP address
|
||||
dbMacAddress, ## a MAC address
|
||||
dbGeometry, ## some geometric type
|
||||
dbPoint, ## Point on a plane (x,y)
|
||||
dbLine, ## Infinite line ((x1,y1),(x2,y2))
|
||||
dbLseg, ## Finite line segment ((x1,y1),(x2,y2))
|
||||
dbBox, ## Rectangular box ((x1,y1),(x2,y2))
|
||||
dbPath, ## Closed or open path (similar to polygon) ((x1,y1),...)
|
||||
dbPolygon, ## Polygon (similar to closed path) ((x1,y1),...)
|
||||
dbCircle, ## Circle <(x,y),r> (center point and radius)
|
||||
dbUser1, ## user definable datatype 1 (for unknown extensions)
|
||||
dbUser2, ## user definable datatype 2 (for unknown extensions)
|
||||
dbUser3, ## user definable datatype 3 (for unknown extensions)
|
||||
dbUser4, ## user definable datatype 4 (for unknown extensions)
|
||||
dbUser5 ## user definable datatype 5 (for unknown extensions)
|
||||
DbTypeKind* = enum ## a superset of datatypes that might be supported.
|
||||
dbUnknown, ## unknown datatype
|
||||
dbSerial, ## datatype used for primary auto-increment keys
|
||||
dbNull, ## datatype used for the NULL value
|
||||
dbBit, ## bit datatype
|
||||
dbBool, ## boolean datatype
|
||||
dbBlob, ## blob datatype
|
||||
dbFixedChar, ## string of fixed length
|
||||
dbVarchar, ## string datatype
|
||||
dbJson, ## JSON datatype
|
||||
dbXml, ## XML datatype
|
||||
dbInt, ## some integer type
|
||||
dbUInt, ## some unsigned integer type
|
||||
dbDecimal, ## decimal numbers (fixed-point number)
|
||||
dbFloat, ## some floating point type
|
||||
dbDate, ## a year-month-day description
|
||||
dbTime, ## HH:MM:SS information
|
||||
dbDatetime, ## year-month-day and HH:MM:SS information,
|
||||
## plus optional time or timezone information
|
||||
dbTimestamp, ## Timestamp values are stored as the number of seconds
|
||||
## since the epoch ('1970-01-01 00:00:00' UTC).
|
||||
dbTimeInterval, ## an interval [a,b] of times
|
||||
dbEnum, ## some enum
|
||||
dbSet, ## set of enum values
|
||||
dbArray, ## an array of values
|
||||
dbComposite, ## composite type (record, struct, etc)
|
||||
dbUrl, ## a URL
|
||||
dbUuid, ## a UUID
|
||||
dbInet, ## an IP address
|
||||
dbMacAddress, ## a MAC address
|
||||
dbGeometry, ## some geometric type
|
||||
dbPoint, ## Point on a plane (x,y)
|
||||
dbLine, ## Infinite line ((x1,y1),(x2,y2))
|
||||
dbLseg, ## Finite line segment ((x1,y1),(x2,y2))
|
||||
dbBox, ## Rectangular box ((x1,y1),(x2,y2))
|
||||
dbPath, ## Closed or open path (similar to polygon) ((x1,y1),...)
|
||||
dbPolygon, ## Polygon (similar to closed path) ((x1,y1),...)
|
||||
dbCircle, ## Circle <(x,y),r> (center point and radius)
|
||||
dbUser1, ## user definable datatype 1 (for unknown extensions)
|
||||
dbUser2, ## user definable datatype 2 (for unknown extensions)
|
||||
dbUser3, ## user definable datatype 3 (for unknown extensions)
|
||||
dbUser4, ## user definable datatype 4 (for unknown extensions)
|
||||
dbUser5 ## user definable datatype 5 (for unknown extensions)
|
||||
|
||||
DbType* = object ## describes a database type
|
||||
kind*: DbTypeKind ## the kind of the described type
|
||||
notNull*: bool ## does the type contain NULL?
|
||||
name*: string ## the name of the type
|
||||
size*: Natural ## the size of the datatype; 0 if of variable size
|
||||
maxReprLen*: Natural ## maximal length required for the representation
|
||||
DbType* = object ## describes a database type
|
||||
kind*: DbTypeKind ## the kind of the described type
|
||||
notNull*: bool ## does the type contain NULL?
|
||||
name*: string ## the name of the type
|
||||
size*: Natural ## the size of the datatype; 0 if of variable size
|
||||
maxReprLen*: Natural ## maximal length required for the representation
|
||||
precision*, scale*: Natural ## precision and scale of the number
|
||||
min*, max*: BiggestInt ## the minimum and maximum of allowed values
|
||||
validValues*: seq[string] ## valid values of an enum or a set
|
||||
min*, max*: BiggestInt ## the minimum and maximum of allowed values
|
||||
validValues*: seq[string] ## valid values of an enum or a set
|
||||
|
||||
DbColumn* = object ## information about a database column
|
||||
name*: string ## name of the column
|
||||
|
||||
@@ -32,10 +32,10 @@ when not defined(nimscript):
|
||||
|
||||
type
|
||||
Distribution* {.pure.} = enum ## the list of known distributions
|
||||
Windows ## some version of Windows
|
||||
Posix ## some Posix system
|
||||
MacOSX ## some version of OSX
|
||||
Linux ## some version of Linux
|
||||
Windows ## some version of Windows
|
||||
Posix ## some Posix system
|
||||
MacOSX ## some version of OSX
|
||||
Linux ## some version of Linux
|
||||
Ubuntu
|
||||
Debian
|
||||
Gentoo
|
||||
@@ -133,8 +133,9 @@ const
|
||||
LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware,
|
||||
Distribution.ArchLinux}
|
||||
|
||||
var unameRes, releaseRes, hostnamectlRes: string ## we cache the result of the 'uname -a'
|
||||
## execution for faster platform detections.
|
||||
# we cache the result of the 'uname -a'
|
||||
# execution for faster platform detections.
|
||||
var unameRes, releaseRes, hostnamectlRes: string
|
||||
|
||||
template unameRelease(cmd, cache): untyped =
|
||||
if cache.len == 0:
|
||||
@@ -173,7 +174,8 @@ proc detectOsImpl(d: Distribution): bool =
|
||||
result = defined(haiku)
|
||||
else:
|
||||
let dd = toLowerAscii($d)
|
||||
result = dd in toLowerAscii(uname()) or dd in toLowerAscii(release()) or ("operating system: " & dd) in toLowerAscii(hostnamectl())
|
||||
result = dd in toLowerAscii(uname()) or dd in toLowerAscii(release()) or
|
||||
("operating system: " & dd) in toLowerAscii(hostnamectl())
|
||||
|
||||
template detectOs*(d: untyped): bool =
|
||||
## Distro/OS detection. For convenience the
|
||||
@@ -184,7 +186,7 @@ template detectOs*(d: untyped): bool =
|
||||
when not defined(nimble):
|
||||
var foreignDeps: seq[string] = @[]
|
||||
|
||||
proc foreignCmd*(cmd: string; requiresSudo=false) =
|
||||
proc foreignCmd*(cmd: string; requiresSudo = false) =
|
||||
## Registers a foreign command to the intern list of commands
|
||||
## that can be queried later.
|
||||
let c = (if requiresSudo: "sudo " else: "") & cmd
|
||||
|
||||
@@ -59,7 +59,7 @@ import strutils
|
||||
type
|
||||
LibHandle* = pointer ## a handle to a dynamically loaded library
|
||||
|
||||
proc loadLib*(path: string, globalSymbols=false): LibHandle {.gcsafe.}
|
||||
proc loadLib*(path: string, globalSymbols = false): LibHandle {.gcsafe.}
|
||||
## loads a library from `path`. Returns nil if the library could not
|
||||
## be loaded.
|
||||
|
||||
@@ -96,7 +96,7 @@ proc libCandidates*(s: string, dest: var seq[string]) =
|
||||
else:
|
||||
add(dest, s)
|
||||
|
||||
proc loadLibPattern*(pattern: string, globalSymbols=false): LibHandle =
|
||||
proc loadLibPattern*(pattern: string, globalSymbols = false): LibHandle =
|
||||
## loads a library with name matching `pattern`, similar to what `dlimport`
|
||||
## pragma does. Returns nil if the library could not be loaded.
|
||||
## Warning: this proc uses the GC and so cannot be used to load the GC.
|
||||
@@ -117,7 +117,7 @@ when defined(posix) and not defined(nintendoswitch):
|
||||
#
|
||||
import posix
|
||||
|
||||
proc loadLib(path: string, globalSymbols=false): LibHandle =
|
||||
proc loadLib(path: string, globalSymbols = false): LibHandle =
|
||||
let flags =
|
||||
if globalSymbols: RTLD_NOW or RTLD_GLOBAL
|
||||
else: RTLD_NOW
|
||||
@@ -141,7 +141,7 @@ elif defined(nintendoswitch):
|
||||
raise newException(OSError, "dlopen not implemented on Nintendo Switch!")
|
||||
proc dlsym(lib: LibHandle, name: cstring): pointer =
|
||||
raise newException(OSError, "dlsym not implemented on Nintendo Switch!")
|
||||
proc loadLib(path: string, global_symbols=false): LibHandle =
|
||||
proc loadLib(path: string, global_symbols = false): LibHandle =
|
||||
raise newException(OSError, "loadLib not implemented on Nintendo Switch!")
|
||||
proc loadLib(): LibHandle =
|
||||
raise newException(OSError, "loadLib not implemented on Nintendo Switch!")
|
||||
@@ -158,7 +158,7 @@ elif defined(windows) or defined(dos):
|
||||
#
|
||||
type
|
||||
HMODULE {.importc: "HMODULE".} = pointer
|
||||
FARPROC {.importc: "FARPROC".} = pointer
|
||||
FARPROC {.importc: "FARPROC".} = pointer
|
||||
|
||||
proc FreeLibrary(lib: HMODULE) {.importc, header: "<windows.h>", stdcall.}
|
||||
proc winLoadLibrary(path: cstring): HMODULE {.
|
||||
@@ -166,7 +166,7 @@ elif defined(windows) or defined(dos):
|
||||
proc getProcAddress(lib: HMODULE, name: cstring): FARPROC {.
|
||||
importc: "GetProcAddress", header: "<windows.h>", stdcall.}
|
||||
|
||||
proc loadLib(path: string, globalSymbols=false): LibHandle =
|
||||
proc loadLib(path: string, globalSymbols = false): LibHandle =
|
||||
result = cast[LibHandle](winLoadLibrary(path))
|
||||
proc loadLib(): LibHandle =
|
||||
result = cast[LibHandle](winLoadLibrary(nil))
|
||||
|
||||
@@ -34,66 +34,68 @@ when defined(windows):
|
||||
while i < a.len and j < b.len:
|
||||
if a[i] in {'-', '_'}: inc i
|
||||
if b[j] in {'-', '_'}: inc j
|
||||
if i < a.len and j < b.len and a[i].toLowerAscii != b[j].toLowerAscii: return false
|
||||
if i < a.len and j < b.len and
|
||||
a[i].toLowerAscii != b[j].toLowerAscii:
|
||||
return false
|
||||
inc i
|
||||
inc j
|
||||
result = i == a.len and j == b.len
|
||||
|
||||
const
|
||||
winEncodings = [
|
||||
(1, "OEMCP"), # current OEM codepage
|
||||
(037, "IBM037"), # IBM EBCDIC US-Canada
|
||||
(437, "IBM437"), # OEM United States
|
||||
(500, "IBM500"), # IBM EBCDIC International
|
||||
(708, "ASMO-708"), # Arabic (ASMO 708)
|
||||
(709, "ASMO_449"), # Arabic (ASMO-449+, BCON V4)
|
||||
(710, ""), # Arabic - Transparent Arabic
|
||||
(720, "DOS-720"), # Arabic (Transparent ASMO); Arabic (DOS)
|
||||
(737, "ibm737"), # OEM Greek (formerly 437G); Greek (DOS)
|
||||
(775, "ibm775"), # OEM Baltic; Baltic (DOS)
|
||||
(850, "ibm850"), # OEM Multilingual Latin 1; Western European (DOS)
|
||||
(852, "ibm852"), # OEM Latin 2; Central European (DOS)
|
||||
(855, "IBM855"), # OEM Cyrillic (primarily Russian)
|
||||
(857, "ibm857"), # OEM Turkish; Turkish (DOS)
|
||||
(858, "IBM00858"), # OEM Multilingual Latin 1 + Euro symbol
|
||||
(860, "IBM860"), # OEM Portuguese; Portuguese (DOS)
|
||||
(861, "ibm861"), # OEM Icelandic; Icelandic (DOS)
|
||||
(862, "DOS-862"), # OEM Hebrew; Hebrew (DOS)
|
||||
(863, "IBM863"), # OEM French Canadian; French Canadian (DOS)
|
||||
(864, "IBM864"), # OEM Arabic; Arabic (864)
|
||||
(865, "IBM865"), # OEM Nordic; Nordic (DOS)
|
||||
(866, "cp866"), # OEM Russian; Cyrillic (DOS)
|
||||
(869, "ibm869"), # OEM Modern Greek; Greek, Modern (DOS)
|
||||
(870, "IBM870"), # IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2
|
||||
(874, "windows-874"), # ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows)
|
||||
(875, "cp875"), # IBM EBCDIC Greek Modern
|
||||
(932, "shift_jis"), # ANSI/OEM Japanese; Japanese (Shift-JIS)
|
||||
(936, "gb2312"), # ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
|
||||
(1, "OEMCP"), # current OEM codepage
|
||||
(037, "IBM037"), # IBM EBCDIC US-Canada
|
||||
(437, "IBM437"), # OEM United States
|
||||
(500, "IBM500"), # IBM EBCDIC International
|
||||
(708, "ASMO-708"), # Arabic (ASMO 708)
|
||||
(709, "ASMO_449"), # Arabic (ASMO-449+, BCON V4)
|
||||
(710, ""), # Arabic - Transparent Arabic
|
||||
(720, "DOS-720"), # Arabic (Transparent ASMO); Arabic (DOS)
|
||||
(737, "ibm737"), # OEM Greek (formerly 437G); Greek (DOS)
|
||||
(775, "ibm775"), # OEM Baltic; Baltic (DOS)
|
||||
(850, "ibm850"), # OEM Multilingual Latin 1; Western European (DOS)
|
||||
(852, "ibm852"), # OEM Latin 2; Central European (DOS)
|
||||
(855, "IBM855"), # OEM Cyrillic (primarily Russian)
|
||||
(857, "ibm857"), # OEM Turkish; Turkish (DOS)
|
||||
(858, "IBM00858"), # OEM Multilingual Latin 1 + Euro symbol
|
||||
(860, "IBM860"), # OEM Portuguese; Portuguese (DOS)
|
||||
(861, "ibm861"), # OEM Icelandic; Icelandic (DOS)
|
||||
(862, "DOS-862"), # OEM Hebrew; Hebrew (DOS)
|
||||
(863, "IBM863"), # OEM French Canadian; French Canadian (DOS)
|
||||
(864, "IBM864"), # OEM Arabic; Arabic (864)
|
||||
(865, "IBM865"), # OEM Nordic; Nordic (DOS)
|
||||
(866, "cp866"), # OEM Russian; Cyrillic (DOS)
|
||||
(869, "ibm869"), # OEM Modern Greek; Greek, Modern (DOS)
|
||||
(870, "IBM870"), # IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2
|
||||
(874, "windows-874"), # ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows)
|
||||
(875, "cp875"), # IBM EBCDIC Greek Modern
|
||||
(932, "shift_jis"), # ANSI/OEM Japanese; Japanese (Shift-JIS)
|
||||
(936, "gb2312"), # ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
|
||||
(949, "ks_c_5601-1987"), # ANSI/OEM Korean (Unified Hangul Code)
|
||||
(950, "big5"), # ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
|
||||
(1026, "IBM1026"), # IBM EBCDIC Turkish (Latin 5)
|
||||
(1047, "IBM01047"), # IBM EBCDIC Latin 1/Open System
|
||||
(1140, "IBM01140"), # IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)
|
||||
(1141, "IBM01141"), # IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)
|
||||
(1142, "IBM01142"), # IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)
|
||||
(1143, "IBM01143"), # IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)
|
||||
(1144, "IBM01144"), # IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)
|
||||
(1145, "IBM01145"), # IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)
|
||||
(1146, "IBM01146"), # IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)
|
||||
(1147, "IBM01147"), # IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)
|
||||
(1148, "IBM01148"), # IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)
|
||||
(1149, "IBM01149"), # IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)
|
||||
(1200, "utf-16"), # Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications
|
||||
(1201, "unicodeFFFE"), # Unicode UTF-16, big endian byte order; available only to managed applications
|
||||
(1250, "windows-1250"), # ANSI Central European; Central European (Windows)
|
||||
(1251, "windows-1251"), # ANSI Cyrillic; Cyrillic (Windows)
|
||||
(1252, "windows-1252"), # ANSI Latin 1; Western European (Windows)
|
||||
(1253, "windows-1253"), # ANSI Greek; Greek (Windows)
|
||||
(1254, "windows-1254"), # ANSI Turkish; Turkish (Windows)
|
||||
(1255, "windows-1255"), # ANSI Hebrew; Hebrew (Windows)
|
||||
(1256, "windows-1256"), # ANSI Arabic; Arabic (Windows)
|
||||
(1257, "windows-1257"), # ANSI Baltic; Baltic (Windows)
|
||||
(1258, "windows-1258"), # ANSI/OEM Vietnamese; Vietnamese (Windows)
|
||||
(950, "big5"), # ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
|
||||
(1026, "IBM1026"), # IBM EBCDIC Turkish (Latin 5)
|
||||
(1047, "IBM01047"), # IBM EBCDIC Latin 1/Open System
|
||||
(1140, "IBM01140"), # IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)
|
||||
(1141, "IBM01141"), # IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)
|
||||
(1142, "IBM01142"), # IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)
|
||||
(1143, "IBM01143"), # IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)
|
||||
(1144, "IBM01144"), # IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)
|
||||
(1145, "IBM01145"), # IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)
|
||||
(1146, "IBM01146"), # IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)
|
||||
(1147, "IBM01147"), # IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)
|
||||
(1148, "IBM01148"), # IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)
|
||||
(1149, "IBM01149"), # IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)
|
||||
(1200, "utf-16"), # Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications
|
||||
(1201, "unicodeFFFE"), # Unicode UTF-16, big endian byte order; available only to managed applications
|
||||
(1250, "windows-1250"), # ANSI Central European; Central European (Windows)
|
||||
(1251, "windows-1251"), # ANSI Cyrillic; Cyrillic (Windows)
|
||||
(1252, "windows-1252"), # ANSI Latin 1; Western European (Windows)
|
||||
(1253, "windows-1253"), # ANSI Greek; Greek (Windows)
|
||||
(1254, "windows-1254"), # ANSI Turkish; Turkish (Windows)
|
||||
(1255, "windows-1255"), # ANSI Hebrew; Hebrew (Windows)
|
||||
(1256, "windows-1256"), # ANSI Arabic; Arabic (Windows)
|
||||
(1257, "windows-1257"), # ANSI Baltic; Baltic (Windows)
|
||||
(1258, "windows-1258"), # ANSI/OEM Vietnamese; Vietnamese (Windows)
|
||||
|
||||
(1250, "cp-1250"), # ANSI Central European; Central European (Windows)
|
||||
(1251, "cp-1251"), # ANSI Cyrillic; Cyrillic (Windows)
|
||||
@@ -105,106 +107,106 @@ when defined(windows):
|
||||
(1257, "cp-1257"), # ANSI Baltic; Baltic (Windows)
|
||||
(1258, "cp-1258"), # ANSI/OEM Vietnamese; Vietnamese (Windows)
|
||||
|
||||
(1361, "Johab"), # Korean (Johab)
|
||||
(10000, "macintosh"), # MAC Roman; Western European (Mac)
|
||||
(10001, "x-mac-japanese"), # Japanese (Mac)
|
||||
(10002, "x-mac-chinesetrad"), # MAC Traditional Chinese (Big5); Chinese Traditional (Mac)
|
||||
(10003, "x-mac-korean"), # Korean (Mac)
|
||||
(10004, "x-mac-arabic"), # Arabic (Mac)
|
||||
(10005, "x-mac-hebrew"), # Hebrew (Mac)
|
||||
(10006, "x-mac-greek"), # Greek (Mac)
|
||||
(10007, "x-mac-cyrillic"), # Cyrillic (Mac)
|
||||
(10008, "x-mac-chinesesimp"), # MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)
|
||||
(10010, "x-mac-romanian"), # Romanian (Mac)
|
||||
(10017, "x-mac-ukrainian"), # Ukrainian (Mac)
|
||||
(10021, "x-mac-thai"), # Thai (Mac)
|
||||
(10029, "x-mac-ce"), # MAC Latin 2; Central European (Mac)
|
||||
(10079, "x-mac-icelandic"), # Icelandic (Mac)
|
||||
(10081, "x-mac-turkish"), # Turkish (Mac)
|
||||
(10082, "x-mac-croatian"), # Croatian (Mac)
|
||||
(12000, "utf-32"), # Unicode UTF-32, little endian byte order; available only to managed applications
|
||||
(12001, "utf-32BE"), # Unicode UTF-32, big endian byte order; available only to managed applications
|
||||
(20000, "x-Chinese_CNS"), # CNS Taiwan; Chinese Traditional (CNS)
|
||||
(20001, "x-cp20001"), # TCA Taiwan
|
||||
(20002, "x_Chinese-Eten"), # Eten Taiwan; Chinese Traditional (Eten)
|
||||
(20003, "x-cp20003"), # IBM5550 Taiwan
|
||||
(20004, "x-cp20004"), # TeleText Taiwan
|
||||
(20005, "x-cp20005"), # Wang Taiwan
|
||||
(20105, "x-IA5"), # IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)
|
||||
(20106, "x-IA5-German"), # IA5 German (7-bit)
|
||||
(20107, "x-IA5-Swedish"), # IA5 Swedish (7-bit)
|
||||
(20108, "x-IA5-Norwegian"), # IA5 Norwegian (7-bit)
|
||||
(20127, "us-ascii"), # US-ASCII (7-bit)
|
||||
(20261, "x-cp20261"), # T.61
|
||||
(20269, "x-cp20269"), # ISO 6937 Non-Spacing Accent
|
||||
(20273, "IBM273"), # IBM EBCDIC Germany
|
||||
(20277, "IBM277"), # IBM EBCDIC Denmark-Norway
|
||||
(20278, "IBM278"), # IBM EBCDIC Finland-Sweden
|
||||
(20280, "IBM280"), # IBM EBCDIC Italy
|
||||
(20284, "IBM284"), # IBM EBCDIC Latin America-Spain
|
||||
(20285, "IBM285"), # IBM EBCDIC United Kingdom
|
||||
(20290, "IBM290"), # IBM EBCDIC Japanese Katakana Extended
|
||||
(20297, "IBM297"), # IBM EBCDIC France
|
||||
(20420, "IBM420"), # IBM EBCDIC Arabic
|
||||
(20423, "IBM423"), # IBM EBCDIC Greek
|
||||
(20424, "IBM424"), # IBM EBCDIC Hebrew
|
||||
(1361, "Johab"), # Korean (Johab)
|
||||
(10000, "macintosh"), # MAC Roman; Western European (Mac)
|
||||
(10001, "x-mac-japanese"), # Japanese (Mac)
|
||||
(10002, "x-mac-chinesetrad"), # MAC Traditional Chinese (Big5); Chinese Traditional (Mac)
|
||||
(10003, "x-mac-korean"), # Korean (Mac)
|
||||
(10004, "x-mac-arabic"), # Arabic (Mac)
|
||||
(10005, "x-mac-hebrew"), # Hebrew (Mac)
|
||||
(10006, "x-mac-greek"), # Greek (Mac)
|
||||
(10007, "x-mac-cyrillic"), # Cyrillic (Mac)
|
||||
(10008, "x-mac-chinesesimp"), # MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)
|
||||
(10010, "x-mac-romanian"), # Romanian (Mac)
|
||||
(10017, "x-mac-ukrainian"), # Ukrainian (Mac)
|
||||
(10021, "x-mac-thai"), # Thai (Mac)
|
||||
(10029, "x-mac-ce"), # MAC Latin 2; Central European (Mac)
|
||||
(10079, "x-mac-icelandic"), # Icelandic (Mac)
|
||||
(10081, "x-mac-turkish"), # Turkish (Mac)
|
||||
(10082, "x-mac-croatian"), # Croatian (Mac)
|
||||
(12000, "utf-32"), # Unicode UTF-32, little endian byte order; available only to managed applications
|
||||
(12001, "utf-32BE"), # Unicode UTF-32, big endian byte order; available only to managed applications
|
||||
(20000, "x-Chinese_CNS"), # CNS Taiwan; Chinese Traditional (CNS)
|
||||
(20001, "x-cp20001"), # TCA Taiwan
|
||||
(20002, "x_Chinese-Eten"), # Eten Taiwan; Chinese Traditional (Eten)
|
||||
(20003, "x-cp20003"), # IBM5550 Taiwan
|
||||
(20004, "x-cp20004"), # TeleText Taiwan
|
||||
(20005, "x-cp20005"), # Wang Taiwan
|
||||
(20105, "x-IA5"), # IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)
|
||||
(20106, "x-IA5-German"), # IA5 German (7-bit)
|
||||
(20107, "x-IA5-Swedish"), # IA5 Swedish (7-bit)
|
||||
(20108, "x-IA5-Norwegian"), # IA5 Norwegian (7-bit)
|
||||
(20127, "us-ascii"), # US-ASCII (7-bit)
|
||||
(20261, "x-cp20261"), # T.61
|
||||
(20269, "x-cp20269"), # ISO 6937 Non-Spacing Accent
|
||||
(20273, "IBM273"), # IBM EBCDIC Germany
|
||||
(20277, "IBM277"), # IBM EBCDIC Denmark-Norway
|
||||
(20278, "IBM278"), # IBM EBCDIC Finland-Sweden
|
||||
(20280, "IBM280"), # IBM EBCDIC Italy
|
||||
(20284, "IBM284"), # IBM EBCDIC Latin America-Spain
|
||||
(20285, "IBM285"), # IBM EBCDIC United Kingdom
|
||||
(20290, "IBM290"), # IBM EBCDIC Japanese Katakana Extended
|
||||
(20297, "IBM297"), # IBM EBCDIC France
|
||||
(20420, "IBM420"), # IBM EBCDIC Arabic
|
||||
(20423, "IBM423"), # IBM EBCDIC Greek
|
||||
(20424, "IBM424"), # IBM EBCDIC Hebrew
|
||||
(20833, "x-EBCDIC-KoreanExtended"), # IBM EBCDIC Korean Extended
|
||||
(20838, "IBM-Thai"), # IBM EBCDIC Thai
|
||||
(20866, "koi8-r"), # Russian (KOI8-R); Cyrillic (KOI8-R)
|
||||
(20871, "IBM871"), # IBM EBCDIC Icelandic
|
||||
(20880, "IBM880"), # IBM EBCDIC Cyrillic Russian
|
||||
(20905, "IBM905"), # IBM EBCDIC Turkish
|
||||
(20924, "IBM00924"), # IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)
|
||||
(20932, "EUC-JP"), # Japanese (JIS 0208-1990 and 0121-1990)
|
||||
(20936, "x-cp20936"), # Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)
|
||||
(20949, "x-cp20949"), # Korean Wansung
|
||||
(21025, "cp1025"), # IBM EBCDIC Cyrillic Serbian-Bulgarian
|
||||
(21027, ""), # (deprecated)
|
||||
(21866, "koi8-u"), # Ukrainian (KOI8-U); Cyrillic (KOI8-U)
|
||||
(28591, "iso-8859-1"), # ISO 8859-1 Latin 1; Western European (ISO)
|
||||
(28592, "iso-8859-2"), # ISO 8859-2 Central European; Central European (ISO)
|
||||
(28593, "iso-8859-3"), # ISO 8859-3 Latin 3
|
||||
(28594, "iso-8859-4"), # ISO 8859-4 Baltic
|
||||
(28595, "iso-8859-5"), # ISO 8859-5 Cyrillic
|
||||
(28596, "iso-8859-6"), # ISO 8859-6 Arabic
|
||||
(28597, "iso-8859-7"), # ISO 8859-7 Greek
|
||||
(28598, "iso-8859-8"), # ISO 8859-8 Hebrew; Hebrew (ISO-Visual)
|
||||
(28599, "iso-8859-9"), # ISO 8859-9 Turkish
|
||||
(28603, "iso-8859-13"), # ISO 8859-13 Estonian
|
||||
(28605, "iso-8859-15"), # ISO 8859-15 Latin 9
|
||||
(29001, "x-Europa"), # Europa 3
|
||||
(38598, "iso-8859-8-i"), # ISO 8859-8 Hebrew; Hebrew (ISO-Logical)
|
||||
(50220, "iso-2022-jp"), # ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
|
||||
(50221, "csISO2022JP"), # ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)
|
||||
(50222, "iso-2022-jp"), # ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)
|
||||
(50225, "iso-2022-kr"), # ISO 2022 Korean
|
||||
(50227, "x-cp50227"), # ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)
|
||||
(50229, ""), # ISO 2022 Traditional Chinese
|
||||
(50930, ""), # EBCDIC Japanese (Katakana) Extended
|
||||
(50931, ""), # EBCDIC US-Canada and Japanese
|
||||
(50933, ""), # EBCDIC Korean Extended and Korean
|
||||
(50935, ""), # EBCDIC Simplified Chinese Extended and Simplified Chinese
|
||||
(50936, ""), # EBCDIC Simplified Chinese
|
||||
(50937, ""), # EBCDIC US-Canada and Traditional Chinese
|
||||
(50939, ""), # EBCDIC Japanese (Latin) Extended and Japanese
|
||||
(51932, "euc-jp"), # EUC Japanese
|
||||
(51936, "EUC-CN"), # EUC Simplified Chinese; Chinese Simplified (EUC)
|
||||
(51949, "euc-kr"), # EUC Korean
|
||||
(51950, ""), # EUC Traditional Chinese
|
||||
(52936, "hz-gb-2312"), # HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)
|
||||
(54936, "GB18030"), # Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)
|
||||
(57002, "x-iscii-de"), # ISCII Devanagari
|
||||
(57003, "x-iscii-be"), # ISCII Bengali
|
||||
(57004, "x-iscii-ta"), # ISCII Tamil
|
||||
(57005, "x-iscii-te"), # ISCII Telugu
|
||||
(57006, "x-iscii-as"), # ISCII Assamese
|
||||
(57007, "x-iscii-or"), # ISCII Oriya
|
||||
(57008, "x-iscii-ka"), # ISCII Kannada
|
||||
(57009, "x-iscii-ma"), # ISCII Malayalam
|
||||
(57010, "x-iscii-gu"), # ISCII Gujarati
|
||||
(57011, "x-iscii-pa"), # ISCII Punjabi
|
||||
(65000, "utf-7"), # Unicode (UTF-7)
|
||||
(65001, "utf-8")] # Unicode (UTF-8)
|
||||
(20838, "IBM-Thai"), # IBM EBCDIC Thai
|
||||
(20866, "koi8-r"), # Russian (KOI8-R); Cyrillic (KOI8-R)
|
||||
(20871, "IBM871"), # IBM EBCDIC Icelandic
|
||||
(20880, "IBM880"), # IBM EBCDIC Cyrillic Russian
|
||||
(20905, "IBM905"), # IBM EBCDIC Turkish
|
||||
(20924, "IBM00924"), # IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)
|
||||
(20932, "EUC-JP"), # Japanese (JIS 0208-1990 and 0121-1990)
|
||||
(20936, "x-cp20936"), # Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)
|
||||
(20949, "x-cp20949"), # Korean Wansung
|
||||
(21025, "cp1025"), # IBM EBCDIC Cyrillic Serbian-Bulgarian
|
||||
(21027, ""), # (deprecated)
|
||||
(21866, "koi8-u"), # Ukrainian (KOI8-U); Cyrillic (KOI8-U)
|
||||
(28591, "iso-8859-1"), # ISO 8859-1 Latin 1; Western European (ISO)
|
||||
(28592, "iso-8859-2"), # ISO 8859-2 Central European; Central European (ISO)
|
||||
(28593, "iso-8859-3"), # ISO 8859-3 Latin 3
|
||||
(28594, "iso-8859-4"), # ISO 8859-4 Baltic
|
||||
(28595, "iso-8859-5"), # ISO 8859-5 Cyrillic
|
||||
(28596, "iso-8859-6"), # ISO 8859-6 Arabic
|
||||
(28597, "iso-8859-7"), # ISO 8859-7 Greek
|
||||
(28598, "iso-8859-8"), # ISO 8859-8 Hebrew; Hebrew (ISO-Visual)
|
||||
(28599, "iso-8859-9"), # ISO 8859-9 Turkish
|
||||
(28603, "iso-8859-13"), # ISO 8859-13 Estonian
|
||||
(28605, "iso-8859-15"), # ISO 8859-15 Latin 9
|
||||
(29001, "x-Europa"), # Europa 3
|
||||
(38598, "iso-8859-8-i"), # ISO 8859-8 Hebrew; Hebrew (ISO-Logical)
|
||||
(50220, "iso-2022-jp"), # ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
|
||||
(50221, "csISO2022JP"), # ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)
|
||||
(50222, "iso-2022-jp"), # ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)
|
||||
(50225, "iso-2022-kr"), # ISO 2022 Korean
|
||||
(50227, "x-cp50227"), # ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)
|
||||
(50229, ""), # ISO 2022 Traditional Chinese
|
||||
(50930, ""), # EBCDIC Japanese (Katakana) Extended
|
||||
(50931, ""), # EBCDIC US-Canada and Japanese
|
||||
(50933, ""), # EBCDIC Korean Extended and Korean
|
||||
(50935, ""), # EBCDIC Simplified Chinese Extended and Simplified Chinese
|
||||
(50936, ""), # EBCDIC Simplified Chinese
|
||||
(50937, ""), # EBCDIC US-Canada and Traditional Chinese
|
||||
(50939, ""), # EBCDIC Japanese (Latin) Extended and Japanese
|
||||
(51932, "euc-jp"), # EUC Japanese
|
||||
(51936, "EUC-CN"), # EUC Simplified Chinese; Chinese Simplified (EUC)
|
||||
(51949, "euc-kr"), # EUC Korean
|
||||
(51950, ""), # EUC Traditional Chinese
|
||||
(52936, "hz-gb-2312"), # HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)
|
||||
(54936, "GB18030"), # Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)
|
||||
(57002, "x-iscii-de"), # ISCII Devanagari
|
||||
(57003, "x-iscii-be"), # ISCII Bengali
|
||||
(57004, "x-iscii-ta"), # ISCII Tamil
|
||||
(57005, "x-iscii-te"), # ISCII Telugu
|
||||
(57006, "x-iscii-as"), # ISCII Assamese
|
||||
(57007, "x-iscii-or"), # ISCII Oriya
|
||||
(57008, "x-iscii-ka"), # ISCII Kannada
|
||||
(57009, "x-iscii-ma"), # ISCII Malayalam
|
||||
(57010, "x-iscii-gu"), # ISCII Gujarati
|
||||
(57011, "x-iscii-pa"), # ISCII Punjabi
|
||||
(65000, "utf-7"), # Unicode (UTF-7)
|
||||
(65001, "utf-8")] # Unicode (UTF-8)
|
||||
|
||||
when false:
|
||||
# not needed yet:
|
||||
@@ -231,7 +233,8 @@ when defined(windows):
|
||||
result = ""
|
||||
|
||||
proc getACP(): CodePage {.stdcall, importc: "GetACP", dynlib: "kernel32".}
|
||||
proc getGetConsoleCP(): CodePage {.stdcall, importc: "GetConsoleCP", dynlib: "kernel32".}
|
||||
proc getGetConsoleCP(): CodePage {.stdcall, importc: "GetConsoleCP",
|
||||
dynlib: "kernel32".}
|
||||
|
||||
proc multiByteToWideChar(
|
||||
codePage: CodePage,
|
||||
@@ -249,8 +252,8 @@ when defined(windows):
|
||||
cchWideChar: cint,
|
||||
lpMultiByteStr: cstring,
|
||||
cbMultiByte: cint,
|
||||
lpDefaultChar: cstring=nil,
|
||||
lpUsedDefaultChar: pointer=nil): cint {.
|
||||
lpDefaultChar: cstring = nil,
|
||||
lpUsedDefaultChar: pointer = nil): cint {.
|
||||
stdcall, importc: "WideCharToMultiByte", dynlib: "kernel32".}
|
||||
|
||||
else:
|
||||
@@ -394,7 +397,8 @@ when defined(windows):
|
||||
else:
|
||||
assert(false) # cannot happen
|
||||
|
||||
proc convertWin(codePageFrom: CodePage, codePageTo: CodePage, s: string): string =
|
||||
proc convertWin(codePageFrom: CodePage, codePageTo: CodePage,
|
||||
s: string): string =
|
||||
# special case: empty string: needed because MultiByteToWideChar, WideCharToMultiByte
|
||||
# return 0 in case of error
|
||||
if s.len == 0: return ""
|
||||
@@ -410,8 +414,10 @@ when defined(windows):
|
||||
raise newException(EncodingError, message)
|
||||
|
||||
# in case it's already UTF-16 little endian - conversion can be simplified
|
||||
let wideString = if int(codePageFrom) == 1200: s else: convertToWideString(codePageFrom, s)
|
||||
return if int(codePageTo) == 1200: wideString else: convertFromWideString(codePageTo, wideString)
|
||||
let wideString = if int(codePageFrom) == 1200: s
|
||||
else: convertToWideString(codePageFrom, s)
|
||||
return if int(codePageTo) == 1200: wideString
|
||||
else: convertFromWideString(codePageTo, wideString)
|
||||
|
||||
proc convert*(c: EncodingConverter, s: string): string =
|
||||
## converts `s` to `destEncoding` that was given to the converter `c`. It
|
||||
@@ -540,4 +546,4 @@ when not defined(testing) and isMainModule and defined(windows):
|
||||
result = convert(original, "utf-8", "utf-16")
|
||||
doAssert(result == "")
|
||||
result = convert(original, "windows-1251", "koi8-r")
|
||||
doAssert(result == "")
|
||||
doAssert(result == "")
|
||||
|
||||
@@ -55,13 +55,13 @@ when useBuiltinSwap:
|
||||
tmp = op(tmp)
|
||||
copyMem(outp, addr tmp, sizeof(T))
|
||||
|
||||
proc swapEndian64*(outp, inp: pointer) {.inline, noSideEffect.}=
|
||||
proc swapEndian64*(outp, inp: pointer) {.inline, noSideEffect.} =
|
||||
swapOpImpl(uint64, builtin_bswap64)
|
||||
|
||||
proc swapEndian32*(outp, inp: pointer) {.inline, noSideEffect.}=
|
||||
proc swapEndian32*(outp, inp: pointer) {.inline, noSideEffect.} =
|
||||
swapOpImpl(uint32, builtin_bswap32)
|
||||
|
||||
proc swapEndian16*(outp, inp: pointer) {.inline, noSideEffect.}=
|
||||
proc swapEndian16*(outp, inp: pointer) {.inline, noSideEffect.} =
|
||||
swapOpImpl(uint16, builtin_bswap16)
|
||||
|
||||
else:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Floating-point environment. Handling of floating-point rounding and
|
||||
## exceptions (overflow, division by zero, etc.).
|
||||
|
||||
{.deadCodeElim: on.} # dce option deprecated
|
||||
{.deadCodeElim: on.} # dce option deprecated
|
||||
|
||||
when defined(Posix) and not defined(genode):
|
||||
{.passl: "-lm".}
|
||||
@@ -103,26 +103,26 @@ proc feupdateenv*(envp: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
|
||||
## according to saved exceptions.
|
||||
|
||||
const
|
||||
FLT_RADIX = 2 ## the radix of the exponent representation
|
||||
FLT_RADIX = 2 ## the radix of the exponent representation
|
||||
|
||||
FLT_MANT_DIG = 24 ## the number of base FLT_RADIX digits in the mantissa part of a float
|
||||
FLT_DIG = 6 ## the number of digits of precision of a float
|
||||
FLT_MIN_EXP = -125 # the minimum value of base FLT_RADIX in the exponent part of a float
|
||||
FLT_MAX_EXP = 128 # the maximum value of base FLT_RADIX in the exponent part of a float
|
||||
FLT_MIN_10_EXP = -37 ## the minimum value in base 10 of the exponent part of a float
|
||||
FLT_MAX_10_EXP = 38 ## the maximum value in base 10 of the exponent part of a float
|
||||
FLT_MIN = 1.17549435e-38'f32 ## the minimum value of a float
|
||||
FLT_MAX = 3.40282347e+38'f32 ## the maximum value of a float
|
||||
FLT_EPSILON = 1.19209290e-07'f32 ## the difference between 1 and the least value greater than 1 of a float
|
||||
FLT_MANT_DIG = 24 ## the number of base FLT_RADIX digits in the mantissa part of a float
|
||||
FLT_DIG = 6 ## the number of digits of precision of a float
|
||||
FLT_MIN_EXP = -125 ## the minimum value of base FLT_RADIX in the exponent part of a float
|
||||
FLT_MAX_EXP = 128 ## the maximum value of base FLT_RADIX in the exponent part of a float
|
||||
FLT_MIN_10_EXP = -37 ## the minimum value in base 10 of the exponent part of a float
|
||||
FLT_MAX_10_EXP = 38 ## the maximum value in base 10 of the exponent part of a float
|
||||
FLT_MIN = 1.17549435e-38'f32 ## the minimum value of a float
|
||||
FLT_MAX = 3.40282347e+38'f32 ## the maximum value of a float
|
||||
FLT_EPSILON = 1.19209290e-07'f32 ## the difference between 1 and the least value greater than 1 of a float
|
||||
|
||||
DBL_MANT_DIG = 53 ## the number of base FLT_RADIX digits in the mantissa part of a double
|
||||
DBL_DIG = 15 ## the number of digits of precision of a double
|
||||
DBL_MIN_EXP = -1021 ## the minimum value of base FLT_RADIX in the exponent part of a double
|
||||
DBL_MAX_EXP = 1024 ## the maximum value of base FLT_RADIX in the exponent part of a double
|
||||
DBL_MIN_10_EXP = -307 ## the minimum value in base 10 of the exponent part of a double
|
||||
DBL_MAX_10_EXP = 308 ## the maximum value in base 10 of the exponent part of a double
|
||||
DBL_MIN = 2.2250738585072014E-308 ## the minimal value of a double
|
||||
DBL_MAX = 1.7976931348623157E+308 ## the minimal value of a double
|
||||
DBL_MANT_DIG = 53 ## the number of base FLT_RADIX digits in the mantissa part of a double
|
||||
DBL_DIG = 15 ## the number of digits of precision of a double
|
||||
DBL_MIN_EXP = -1021 ## the minimum value of base FLT_RADIX in the exponent part of a double
|
||||
DBL_MAX_EXP = 1024 ## the maximum value of base FLT_RADIX in the exponent part of a double
|
||||
DBL_MIN_10_EXP = -307 ## the minimum value in base 10 of the exponent part of a double
|
||||
DBL_MAX_10_EXP = 308 ## the maximum value in base 10 of the exponent part of a double
|
||||
DBL_MIN = 2.2250738585072014E-308 ## the minimal value of a double
|
||||
DBL_MAX = 1.7976931348623157E+308 ## the minimal value of a double
|
||||
DBL_EPSILON = 2.2204460492503131E-16 ## the difference between 1 and the least value greater than 1 of a double
|
||||
|
||||
template fpRadix*: int = FLT_RADIX
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
## * `tables module <tables.html>`_ for hash tables
|
||||
|
||||
type
|
||||
Hash* = int ## A hash value. Hash tables using these values should
|
||||
Hash* = int ## A hash value. Hash tables using these values should
|
||||
## always have a size of a power of two and can use the ``and``
|
||||
## operator instead of ``mod`` for truncation of the hash value.
|
||||
|
||||
@@ -451,7 +451,7 @@ when isMainModule:
|
||||
doAssert hashIgnoreStyle("aa_bb_AAaa1234") == hashIgnoreCase("aaBBAAAa1234")
|
||||
block smallSize: # no multibyte hashing
|
||||
let
|
||||
xx = @['H','i']
|
||||
xx = @['H', 'i']
|
||||
ii = @[72'u8, 105]
|
||||
ss = "Hi"
|
||||
doAssert hash(xx) == hash(ii)
|
||||
@@ -460,8 +460,8 @@ when isMainModule:
|
||||
doAssert hash(ss) == hash(ss, 0, ss.high)
|
||||
block largeSize: # longer than 4 characters
|
||||
let
|
||||
xx = @['H','e','l','l','o']
|
||||
xxl = @['H','e','l','l','o','w','e','e','n','s']
|
||||
xx = @['H', 'e', 'l', 'l', 'o']
|
||||
xxl = @['H', 'e', 'l', 'l', 'o', 'w', 'e', 'e', 'n', 's']
|
||||
ssl = "Helloweens"
|
||||
doAssert hash(xxl) == hash(ssl)
|
||||
doAssert hash(xxl) == hash(xxl, 0, xxl.high)
|
||||
|
||||
@@ -32,7 +32,7 @@ import
|
||||
|
||||
const
|
||||
coreAttr* = " accesskey class contenteditable dir hidden id lang " &
|
||||
"spellcheck style tabindex title translate " ## HTML DOM Core Attributes
|
||||
"spellcheck style tabindex title translate " ## HTML DOM Core Attributes
|
||||
eventAttr* = "onabort onblur oncancel oncanplay oncanplaythrough onchange " &
|
||||
"onclick oncuechange ondblclick ondurationchange onemptied onended " &
|
||||
"onerror onfocus oninput oninvalid onkeydown onkeypress onkeyup onload " &
|
||||
@@ -41,7 +41,7 @@ const
|
||||
"onpause onplay onplaying onprogress onratechange onreset onresize " &
|
||||
"onscroll onseeked onseeking onselect onshow onstalled onsubmit " &
|
||||
"onsuspend ontimeupdate ontoggle onvolumechange onwaiting " ## HTML DOM Event Attributes
|
||||
ariaAttr* = " role " ## HTML DOM Aria Attributes
|
||||
ariaAttr* = " role " ## HTML DOM Aria Attributes
|
||||
commonAttr* = coreAttr & eventAttr & ariaAttr ## HTML DOM Common Attributes
|
||||
|
||||
proc getIdent(e: NimNode): string {.compileTime.} =
|
||||
@@ -572,7 +572,7 @@ macro title*(e: varargs[untyped]): untyped =
|
||||
|
||||
macro tr*(e: varargs[untyped]): untyped =
|
||||
## generates the HTML ``tr`` element.
|
||||
result = xmlCheckedTag(e, "tr", commonAttr)
|
||||
result = xmlCheckedTag(e, "tr", commonAttr)
|
||||
|
||||
macro track*(e: varargs[untyped]): untyped =
|
||||
## generates the HTML ``track`` element.
|
||||
@@ -606,7 +606,7 @@ macro wbr*(e: varargs[untyped]): untyped =
|
||||
|
||||
runnableExamples:
|
||||
let nim = "Nim"
|
||||
assert h1(a(href="http://nim-lang.org", nim)) ==
|
||||
assert h1(a(href = "http://nim-lang.org", nim)) ==
|
||||
"""<h1><a href="http://nim-lang.org">Nim</a></h1>"""
|
||||
assert form(action="test", `accept-charset` = "Content-Type") ==
|
||||
assert form(action = "test", `accept-charset` = "Content-Type") ==
|
||||
"""<form action="test" accept-charset="Content-Type"></form>"""
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
import strutils, streams, parsexml, xmltree, unicode, strtabs
|
||||
|
||||
type
|
||||
HtmlTag* = enum ## list of all supported HTML tags; order will always be
|
||||
HtmlTag* = enum ## list of all supported HTML tags; order will always be
|
||||
## alphabetically
|
||||
tagUnknown, ## unknown HTML element
|
||||
tagA, ## the HTML ``a`` element
|
||||
@@ -1945,7 +1945,8 @@ proc untilElementEnd(x: var XmlParser, result: XmlNode,
|
||||
adderr(expected(x, result))
|
||||
# this seems to do better match error corrections in browsers:
|
||||
while x.kind in {xmlElementEnd, xmlWhitespace}:
|
||||
if x.kind == xmlElementEnd and cmpIgnoreCase(x.elemName, result.tag) == 0:
|
||||
if x.kind == xmlElementEnd and cmpIgnoreCase(x.elemName,
|
||||
result.tag) == 0:
|
||||
break
|
||||
next(x)
|
||||
next(x)
|
||||
@@ -2025,7 +2026,7 @@ proc parseHtml*(s: Stream, filename: string,
|
||||
#if x.kind != xmlEof:
|
||||
# adderr(errorMsg(x, "EOF expected"))
|
||||
while x.kind != xmlEof:
|
||||
var oldPos = x.bufpos # little hack to see if we made any progess
|
||||
var oldPos = x.bufpos # little hack to see if we made any progress
|
||||
result.addNode(parse(x, errors))
|
||||
if x.bufpos == oldPos:
|
||||
# force progress!
|
||||
|
||||
@@ -254,9 +254,9 @@ type
|
||||
MultipartData* = ref object
|
||||
content: seq[string]
|
||||
|
||||
ProtocolError* = object of IOError ## exception that is raised when server
|
||||
## does not conform to the implemented
|
||||
## protocol
|
||||
ProtocolError* = object of IOError ## exception that is raised when server
|
||||
## does not conform to the implemented
|
||||
## protocol
|
||||
|
||||
HttpRequestError* = object of IOError ## Thrown in the ``getContent`` proc
|
||||
## and ``postContent`` proc,
|
||||
@@ -302,11 +302,11 @@ proc add*(p: var MultipartData, name, content: string, filename: string = "",
|
||||
## Add a value to the multipart data. Raises a `ValueError` exception if
|
||||
## `name`, `filename` or `contentType` contain newline characters.
|
||||
|
||||
if {'\c','\L'} in name:
|
||||
if {'\c', '\L'} in name:
|
||||
raise newException(ValueError, "name contains a newline character")
|
||||
if {'\c','\L'} in filename:
|
||||
if {'\c', '\L'} in filename:
|
||||
raise newException(ValueError, "filename contains a newline character")
|
||||
if {'\c','\L'} in contentType:
|
||||
if {'\c', '\L'} in contentType:
|
||||
raise newException(ValueError, "contentType contains a newline character")
|
||||
|
||||
var str = "Content-Disposition: form-data; name=\"" & name & "\""
|
||||
@@ -470,11 +470,11 @@ type
|
||||
HttpClientBase*[SocketType] = ref object
|
||||
socket: SocketType
|
||||
connected: bool
|
||||
currentURL: Uri ## Where we are currently connected.
|
||||
currentURL: Uri ## Where we are currently connected.
|
||||
headers*: HttpHeaders ## Headers to send in requests.
|
||||
maxRedirects: int
|
||||
userAgent: string
|
||||
timeout*: int ## Only used for blocking HttpClient for now.
|
||||
timeout*: int ## Only used for blocking HttpClient for now.
|
||||
proxy: Proxy
|
||||
## ``nil`` or the callback to call when request progress changes.
|
||||
when SocketType is Socket:
|
||||
@@ -492,7 +492,7 @@ type
|
||||
parseBodyFut: Future[void]
|
||||
else:
|
||||
bodyStream: Stream
|
||||
getBody: bool ## When `false`, the body is never read in requestAux.
|
||||
getBody: bool ## When `false`, the body is never read in requestAux.
|
||||
|
||||
type
|
||||
HttpClient* = HttpClientBase[Socket]
|
||||
@@ -563,7 +563,7 @@ proc close*(client: HttpClient | AsyncHttpClient) =
|
||||
client.socket.close()
|
||||
client.connected = false
|
||||
|
||||
proc getSocket*(client: HttpClient): Socket =
|
||||
proc getSocket*(client: HttpClient): Socket =
|
||||
## Get network socket, useful if you want to find out more details about the connection
|
||||
##
|
||||
## this example shows info about local and remote endpoints
|
||||
@@ -575,7 +575,7 @@ proc getSocket*(client: HttpClient): Socket =
|
||||
##
|
||||
return client.socket
|
||||
|
||||
proc getSocket*(client: AsyncHttpClient): AsyncSocket =
|
||||
proc getSocket*(client: AsyncHttpClient): AsyncSocket =
|
||||
return client.socket
|
||||
|
||||
proc reportProgress(client: HttpClient | AsyncHttpClient,
|
||||
@@ -756,7 +756,7 @@ proc parseResponse(client: HttpClient | AsyncHttpClient,
|
||||
if line[linei] != ':': httpError("invalid headers")
|
||||
inc(linei) # Skip :
|
||||
|
||||
result.headers.add(name, line[linei.. ^1].strip())
|
||||
result.headers.add(name, line[linei .. ^1].strip())
|
||||
if result.headers.len > headerLimit:
|
||||
httpError("too many headers")
|
||||
|
||||
@@ -827,7 +827,8 @@ proc newConnection(client: HttpClient | AsyncHttpClient,
|
||||
connectUrl.hostname = url.hostname
|
||||
connectUrl.port = if url.port != "": url.port else: "443"
|
||||
|
||||
let proxyHeaderString = generateHeaders(connectUrl, $HttpConnect, newHttpHeaders(), "", client.proxy)
|
||||
let proxyHeaderString = generateHeaders(connectUrl, $HttpConnect,
|
||||
newHttpHeaders(), "", client.proxy)
|
||||
await client.socket.send(proxyHeaderString)
|
||||
let proxyResp = await parseResponse(client, false)
|
||||
|
||||
|
||||
@@ -28,24 +28,24 @@ type
|
||||
HttpVer11,
|
||||
HttpVer10
|
||||
|
||||
HttpMethod* = enum ## the requested HttpMethod
|
||||
HttpHead, ## Asks for the response identical to the one that would
|
||||
## correspond to a GET request, but without the response
|
||||
## body.
|
||||
HttpGet, ## Retrieves the specified resource.
|
||||
HttpPost, ## Submits data to be processed to the identified
|
||||
## resource. The data is included in the body of the
|
||||
## request.
|
||||
HttpPut, ## Uploads a representation of the specified resource.
|
||||
HttpDelete, ## Deletes the specified resource.
|
||||
HttpTrace, ## Echoes back the received request, so that a client
|
||||
## can see what intermediate servers are adding or
|
||||
## changing in the request.
|
||||
HttpOptions, ## Returns the HTTP methods that the server supports
|
||||
## for specified address.
|
||||
HttpConnect, ## Converts the request connection to a transparent
|
||||
## TCP/IP tunnel, usually used for proxies.
|
||||
HttpPatch ## Applies partial modifications to a resource.
|
||||
HttpMethod* = enum ## the requested HttpMethod
|
||||
HttpHead, ## Asks for the response identical to the one that would
|
||||
## correspond to a GET request, but without the response
|
||||
## body.
|
||||
HttpGet, ## Retrieves the specified resource.
|
||||
HttpPost, ## Submits data to be processed to the identified
|
||||
## resource. The data is included in the body of the
|
||||
## request.
|
||||
HttpPut, ## Uploads a representation of the specified resource.
|
||||
HttpDelete, ## Deletes the specified resource.
|
||||
HttpTrace, ## Echoes back the received request, so that a client
|
||||
## can see what intermediate servers are adding or
|
||||
## changing in the request.
|
||||
HttpOptions, ## Returns the HTTP methods that the server supports
|
||||
## for specified address.
|
||||
HttpConnect, ## Converts the request connection to a transparent
|
||||
## TCP/IP tunnel, usually used for proxies.
|
||||
HttpPatch ## Applies partial modifications to a resource.
|
||||
|
||||
|
||||
const
|
||||
@@ -323,4 +323,4 @@ when isMainModule:
|
||||
test[key] = value
|
||||
doAssert test["foobar"] == ""
|
||||
|
||||
doAssert parseHeader("foobar:") == ("foobar", @[""])
|
||||
doAssert parseHeader("foobar:") == ("foobar", @[""])
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
## ``JNull``. You check the kind of this object variant by using the ``kind``
|
||||
## accessor.
|
||||
##
|
||||
## For a ``JsonNode`` who's kind is ``JObject``, you can acess its fields using
|
||||
## For a ``JsonNode`` who's kind is ``JObject``, you can access its fields using
|
||||
## the ``[]`` operator. The following example shows how to do this:
|
||||
##
|
||||
## .. code-block:: Nim
|
||||
@@ -406,7 +406,7 @@ macro `%*`*(x: untyped): untyped =
|
||||
## `%` for every element.
|
||||
result = toJson(x)
|
||||
|
||||
proc `==`* (a, b: JsonNode): bool =
|
||||
proc `==`*(a, b: JsonNode): bool =
|
||||
## Check two nodes for equality
|
||||
if a.isNil:
|
||||
if b.isNil: return true
|
||||
@@ -428,13 +428,13 @@ proc `==`* (a, b: JsonNode): bool =
|
||||
of JArray:
|
||||
result = a.elems == b.elems
|
||||
of JObject:
|
||||
# we cannot use OrderedTable's equality here as
|
||||
# the order does not matter for equality here.
|
||||
if a.fields.len != b.fields.len: return false
|
||||
for key, val in a.fields:
|
||||
if not b.fields.hasKey(key): return false
|
||||
if b.fields[key] != val: return false
|
||||
result = true
|
||||
# we cannot use OrderedTable's equality here as
|
||||
# the order does not matter for equality here.
|
||||
if a.fields.len != b.fields.len: return false
|
||||
for key, val in a.fields:
|
||||
if not b.fields.hasKey(key): return false
|
||||
if b.fields[key] != val: return false
|
||||
result = true
|
||||
|
||||
proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
|
||||
|
||||
@@ -502,7 +502,8 @@ proc contains*(node: JsonNode, val: JsonNode): bool =
|
||||
assert(node.kind == JArray)
|
||||
find(node.elems, val) >= 0
|
||||
|
||||
proc existsKey*(node: JsonNode, key: string): bool {.deprecated: "use 'hasKey' instead".} =
|
||||
proc existsKey*(node: JsonNode, key: string): bool {.
|
||||
deprecated: "use 'hasKey' instead".} =
|
||||
node.hasKey(key)
|
||||
|
||||
proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
|
||||
@@ -538,7 +539,8 @@ proc getOrDefault*(node: JsonNode, key: string): JsonNode =
|
||||
if not isNil(node) and node.kind == JObject:
|
||||
result = node.fields.getOrDefault(key)
|
||||
|
||||
template simpleGetOrDefault*{`{}`(node, [key])}(node: JsonNode, key: string): JsonNode = node.getOrDefault(key)
|
||||
template simpleGetOrDefault*{`{}`(node, [key])}(node: JsonNode,
|
||||
key: string): JsonNode = node.getOrDefault(key)
|
||||
|
||||
proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
|
||||
## Traverses the node and tries to set the value at the given location
|
||||
@@ -691,7 +693,7 @@ proc pretty*(node: JsonNode, indent = 2): string =
|
||||
## Similar to prettyprint in Python.
|
||||
runnableExamples:
|
||||
let j = %* {"name": "Isaac", "books": ["Robot Dreams"],
|
||||
"details": {"age":35, "pi":3.1415}}
|
||||
"details": {"age": 35, "pi": 3.1415}}
|
||||
doAssert pretty(j) == """
|
||||
{
|
||||
"name": "Isaac",
|
||||
@@ -721,14 +723,14 @@ proc toUgly*(result: var string, node: JsonNode) =
|
||||
result.add "["
|
||||
for child in node.elems:
|
||||
if comma: result.add ","
|
||||
else: comma = true
|
||||
else: comma = true
|
||||
result.toUgly child
|
||||
result.add "]"
|
||||
of JObject:
|
||||
result.add "{"
|
||||
for key, value in pairs(node.fields):
|
||||
if comma: result.add ","
|
||||
else: comma = true
|
||||
else: comma = true
|
||||
key.escapeJson(result)
|
||||
result.add ":"
|
||||
result.toUgly value
|
||||
@@ -1331,7 +1333,8 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
||||
(
|
||||
var map = `tableInit`[`tableKeyType`, `tableValueType`]();
|
||||
verifyJsonKind(`jsonNode`, {JObject}, astToStr(`jsonNode`));
|
||||
for `forLoopKey` in keys(`jsonNode`.fields): map[`forLoopKey`] = `constructorNode`;
|
||||
for `forLoopKey` in keys(`jsonNode`.fields): map[
|
||||
`forLoopKey`] = `constructorNode`;
|
||||
map
|
||||
)
|
||||
of "ref":
|
||||
@@ -1374,7 +1377,8 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
|
||||
(
|
||||
var list: `typeSym`;
|
||||
verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
|
||||
for `forLoopI` in 0 ..< `jsonNode`.len: list[`forLoopI`] =`constructorNode`;
|
||||
for `forLoopI` in 0 ..< `jsonNode`.len: list[
|
||||
`forLoopI`] = `constructorNode`;
|
||||
list
|
||||
)
|
||||
of "tuple":
|
||||
@@ -1640,11 +1644,11 @@ when isMainModule:
|
||||
except:
|
||||
doAssert(false, "IndexError thrown for valid index")
|
||||
|
||||
doAssert(testJson{"b"}.getStr()=="asd", "Couldn't fetch a singly nested key with {}")
|
||||
doAssert(testJson{"b"}.getStr() == "asd", "Couldn't fetch a singly nested key with {}")
|
||||
doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
|
||||
doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
|
||||
doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
|
||||
doAssert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
|
||||
doAssert(testJson{"a"} == parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
|
||||
doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
|
||||
|
||||
# Generator:
|
||||
@@ -1669,10 +1673,10 @@ when isMainModule:
|
||||
const hisAge = 31
|
||||
|
||||
var j3 = %*
|
||||
[ { "name": "John"
|
||||
[ {"name": "John"
|
||||
, "age": herAge
|
||||
}
|
||||
, { "name": "Susan"
|
||||
, {"name": "Susan"
|
||||
, "age": hisAge
|
||||
}
|
||||
]
|
||||
@@ -1708,7 +1712,8 @@ when isMainModule:
|
||||
except IndexError: doAssert(true)
|
||||
|
||||
var parsed2 = parseFile("tests/testdata/jsontest2.json")
|
||||
doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
|
||||
doAssert(parsed2{"repository", "description"}.str ==
|
||||
"IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
|
||||
|
||||
doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ"
|
||||
doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0014" # for #7887
|
||||
@@ -1752,15 +1757,15 @@ when isMainModule:
|
||||
# Generate constructors for range[T] types
|
||||
block:
|
||||
type
|
||||
Q1 = range[0'u8 .. 50'u8]
|
||||
Q1 = range[0'u8 .. 50'u8]
|
||||
Q2 = range[0'u16 .. 50'u16]
|
||||
Q3 = range[0'u32 .. 50'u32]
|
||||
Q4 = range[0'i8 .. 50'i8]
|
||||
Q4 = range[0'i8 .. 50'i8]
|
||||
Q5 = range[0'i16 .. 50'i16]
|
||||
Q6 = range[0'i32 .. 50'i32]
|
||||
Q7 = range[0'f32 .. 50'f32]
|
||||
Q8 = range[0'f64 .. 50'f64]
|
||||
Q9 = range[0 .. 50]
|
||||
Q9 = range[0 .. 50]
|
||||
|
||||
X = object
|
||||
m1: Q1
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
## which work for mixed float/int operands.
|
||||
## All operations convert the integer operand into the
|
||||
## type of the float operand. For numerical expressions, the return
|
||||
## type is always the type of the float involved in the expresssion,
|
||||
## type is always the type of the float involved in the expression,
|
||||
## i.e., there is no auto conversion from float32 to float64.
|
||||
##
|
||||
## Note: In general, auto-converting from int to float loses
|
||||
|
||||
@@ -15,7 +15,7 @@ import
|
||||
strutils, streams
|
||||
|
||||
const
|
||||
EndOfFile* = '\0' ## end of file marker
|
||||
EndOfFile* = '\0' ## end of file marker
|
||||
NewLines* = {'\c', '\L'}
|
||||
|
||||
# Buffer handling:
|
||||
@@ -27,13 +27,13 @@ const
|
||||
type
|
||||
BaseLexer* = object of RootObj ## the base lexer. Inherit your lexer from
|
||||
## this object.
|
||||
bufpos*: int ## the current position within the buffer
|
||||
buf*: string ## the buffer itself
|
||||
input: Stream ## the input stream
|
||||
lineNumber*: int ## the current line number
|
||||
bufpos*: int ## the current position within the buffer
|
||||
buf*: string ## the buffer itself
|
||||
input: Stream ## the input stream
|
||||
lineNumber*: int ## the current line number
|
||||
sentinel: int
|
||||
lineStart: int # index of last line start in buffer
|
||||
offsetBase*: int # use ``offsetBase + bufpos`` to get the offset
|
||||
lineStart: int # index of last line start in buffer
|
||||
offsetBase*: int # use ``offsetBase + bufpos`` to get the offset
|
||||
refillChars: set[char]
|
||||
|
||||
proc close*(L: var BaseLexer) =
|
||||
@@ -65,11 +65,11 @@ proc fillBuffer(L: var BaseLexer) =
|
||||
charsRead = L.input.readDataStr(L.buf, toCopy ..< toCopy + L.sentinel + 1)
|
||||
s = toCopy + charsRead
|
||||
if charsRead < L.sentinel + 1:
|
||||
L.buf[s] = EndOfFile # set end marker
|
||||
L.buf[s] = EndOfFile # set end marker
|
||||
L.sentinel = s
|
||||
else:
|
||||
# compute sentinel:
|
||||
dec(s) # BUGFIX (valgrind)
|
||||
dec(s) # BUGFIX (valgrind)
|
||||
while true:
|
||||
assert(s < L.buf.len)
|
||||
while s >= 0 and L.buf[s] notin L.refillChars: dec(s)
|
||||
@@ -92,7 +92,7 @@ proc fillBuffer(L: var BaseLexer) =
|
||||
proc fillBaseLexer(L: var BaseLexer, pos: int): int =
|
||||
assert(pos <= L.sentinel)
|
||||
if pos < L.sentinel:
|
||||
result = pos + 1 # nothing to do
|
||||
result = pos + 1 # nothing to do
|
||||
else:
|
||||
fillBuffer(L)
|
||||
L.offsetBase += pos
|
||||
@@ -142,7 +142,7 @@ proc open*(L: var BaseLexer, input: Stream, bufLen: int = 8192;
|
||||
L.buf = newString(bufLen)
|
||||
L.sentinel = bufLen - 1
|
||||
L.lineStart = 0
|
||||
L.lineNumber = 1 # lines start at 1
|
||||
L.lineNumber = 1 # lines start at 1
|
||||
fillBuffer(L)
|
||||
skipUtf8Bom(L)
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ when not defined(js):
|
||||
import os
|
||||
|
||||
type
|
||||
Level* = enum
|
||||
Level* = enum ## \
|
||||
## Enumeration of logging levels.
|
||||
##
|
||||
## Debug messages represent the lowest logging level, and fatal error
|
||||
@@ -173,22 +173,21 @@ type
|
||||
## any messages with a level lower than the threshold. There is also
|
||||
## a global filter that applies to all log messages, and it can be changed
|
||||
## using the `setLogFilter proc<#setLogFilter,Level>`_.
|
||||
lvlAll, ## All levels active
|
||||
lvlDebug, ## Debug level and above are active
|
||||
lvlInfo, ## Info level and above are active
|
||||
lvlNotice, ## Notice level and above are active
|
||||
lvlWarn, ## Warn level and above are active
|
||||
lvlError, ## Error level and above are active
|
||||
lvlFatal, ## Fatal level and above are active
|
||||
lvlNone ## No levels active; nothing is logged
|
||||
lvlAll, ## All levels active
|
||||
lvlDebug, ## Debug level and above are active
|
||||
lvlInfo, ## Info level and above are active
|
||||
lvlNotice, ## Notice level and above are active
|
||||
lvlWarn, ## Warn level and above are active
|
||||
lvlError, ## Error level and above are active
|
||||
lvlFatal, ## Fatal level and above are active
|
||||
lvlNone ## No levels active; nothing is logged
|
||||
|
||||
const
|
||||
LevelNames*: array[Level, string] = [
|
||||
"DEBUG", "DEBUG", "INFO", "NOTICE", "WARN", "ERROR", "FATAL", "NONE"
|
||||
] ## Array of strings representing each logging level.
|
||||
] ## Array of strings representing each logging level.
|
||||
|
||||
defaultFmtStr* = "$levelname " ## \
|
||||
## The default format string.
|
||||
defaultFmtStr* = "$levelname " ## The default format string.
|
||||
verboseFmtStr* = "$levelid, [$datetime] -- $appname: " ## \
|
||||
## A more verbose format string.
|
||||
##
|
||||
@@ -211,8 +210,8 @@ type
|
||||
## * `ConsoleLogger<#ConsoleLogger>`_
|
||||
## * `FileLogger<#FileLogger>`_
|
||||
## * `RollingFileLogger<#RollingFileLogger>`_
|
||||
levelThreshold*: Level ## Only messages that are at or above this
|
||||
## threshold will be logged
|
||||
levelThreshold*: Level ## Only messages that are at or above this
|
||||
## threshold will be logged
|
||||
fmtStr*: string ## Format string to prepend to each log message;
|
||||
## defaultFmtStr is the default
|
||||
|
||||
@@ -240,7 +239,7 @@ when not defined(js):
|
||||
## See also:
|
||||
## * `ConsoleLogger<#ConsoleLogger>`_
|
||||
## * `RollingFileLogger<#RollingFileLogger>`_
|
||||
file*: File ## The wrapped file
|
||||
file*: File ## The wrapped file
|
||||
|
||||
RollingFileLogger* = ref object of FileLogger
|
||||
## A logger that writes log messages to a file while performing log
|
||||
@@ -255,17 +254,18 @@ when not defined(js):
|
||||
## * `ConsoleLogger<#ConsoleLogger>`_
|
||||
## * `FileLogger<#FileLogger>`_
|
||||
maxLines: int # maximum number of lines
|
||||
curLine : int
|
||||
curLine: int
|
||||
baseName: string # initial filename
|
||||
baseMode: FileMode # initial file mode
|
||||
logFiles: int # how many log files already created, e.g. basename.1, basename.2...
|
||||
bufSize: int # size of output buffer (-1: use system defaults, 0: unbuffered, >0: fixed buffer size)
|
||||
|
||||
var
|
||||
level {.threadvar.}: Level ## global log filter
|
||||
level {.threadvar.}: Level ## global log filter
|
||||
handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
|
||||
|
||||
proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string =
|
||||
proc substituteLog*(frmt: string, level: Level,
|
||||
args: varargs[string, `$`]): string =
|
||||
## Formats a log message at the specified level with the given format string.
|
||||
##
|
||||
## The `format variables<#basic-usage-format-strings>`_ present within
|
||||
@@ -307,7 +307,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str
|
||||
of "date": result.add(getDateStr())
|
||||
of "time": result.add(getClockStr())
|
||||
of "datetime": result.add(getDateStr() & "T" & getClockStr())
|
||||
of "app": result.add(app)
|
||||
of "app": result.add(app)
|
||||
of "appdir":
|
||||
when not defined(js): result.add(app.splitFile.dir)
|
||||
of "appname":
|
||||
@@ -369,13 +369,14 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
|
||||
try:
|
||||
var handle = stdout
|
||||
if logger.useStderr:
|
||||
handle = stderr
|
||||
handle = stderr
|
||||
writeLine(handle, ln)
|
||||
if level in {lvlError, lvlFatal}: flushFile(handle)
|
||||
except IOError:
|
||||
discard
|
||||
|
||||
proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, useStderr=false): ConsoleLogger =
|
||||
proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr,
|
||||
useStderr = false): ConsoleLogger =
|
||||
## Creates a new `ConsoleLogger<#ConsoleLogger>`_.
|
||||
##
|
||||
## By default, log messages are written to ``stdout``. If ``useStderr`` is
|
||||
@@ -563,7 +564,7 @@ when not defined(js):
|
||||
result.fmtStr = fmtStr
|
||||
result.maxLines = maxLines
|
||||
result.bufSize = bufSize
|
||||
result.file = open(filename, mode, bufSize=result.bufSize)
|
||||
result.file = open(filename, mode, bufSize = result.bufSize)
|
||||
result.curLine = 0
|
||||
result.baseName = filename
|
||||
result.baseMode = mode
|
||||
@@ -616,7 +617,8 @@ when not defined(js):
|
||||
rotate(logger)
|
||||
logger.logFiles.inc
|
||||
logger.curLine = 0
|
||||
logger.file = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
|
||||
logger.file = open(logger.baseName, logger.baseMode,
|
||||
bufSize = logger.bufSize)
|
||||
|
||||
writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
|
||||
if level in {lvlError, lvlFatal}: flushFile(logger.file)
|
||||
|
||||
@@ -384,7 +384,7 @@ when not defined(testing) and isMainModule:
|
||||
test4.b = "ref string test: B"
|
||||
testit(test4)
|
||||
|
||||
var test5 = @[(0,1),(2,3),(4,5)]
|
||||
var test5 = @[(0, 1), (2, 3), (4, 5)]
|
||||
testit(test5)
|
||||
|
||||
var test6: set[char] = {'A'..'Z', '_'}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user