fixes merge conflict
This commit is contained in:
commit
696c0c48c7
195 changed files with 2049 additions and 1344 deletions
|
|
@ -51,5 +51,3 @@ script:
|
||||||
- ./koch csource
|
- ./koch csource
|
||||||
- ./koch nimsuggest
|
- ./koch nimsuggest
|
||||||
# - nim c -r nimsuggest/tester
|
# - nim c -r nimsuggest/tester
|
||||||
- ( ! grep -F '.. code-block' -l -r --include '*.html' --exclude contributing.html --exclude docgen.html --exclude tut2.html )
|
|
||||||
- ( ! grep -F '..code-block' -l -r --include '*.html' --exclude contributing.html --exclude docgen.html --exclude tut2.html )
|
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ build_script:
|
||||||
- nimble install jester@#head -y
|
- nimble install jester@#head -y
|
||||||
- nimble install niminst
|
- nimble install niminst
|
||||||
- nim c --taintMode:on -d:nimCoroutines tests/testament/tester
|
- nim c --taintMode:on -d:nimCoroutines tests/testament/tester
|
||||||
|
- nim c --taintMode:on -d:nimCoroutines --os:genode -d:posix --compileOnly tests/testament/tester
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- tests\testament\tester --pedantic all -d:nimCoroutines
|
- tests\testament\tester --pedantic all -d:nimCoroutines
|
||||||
|
|
|
||||||
31
build_all.sh
Normal file
31
build_all.sh
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
# build development version of the compiler; can be rerun safely
|
||||||
|
|
||||||
|
set -u # error on undefined variables
|
||||||
|
set -e # exit on first error
|
||||||
|
|
||||||
|
echo_run(){
|
||||||
|
echo "\n$@"
|
||||||
|
"$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
[ -d csources ] || echo_run git clone --depth 1 https://github.com/nim-lang/csources.git
|
||||||
|
|
||||||
|
nim_csources=bin/nim_csources
|
||||||
|
build_nim_csources(){
|
||||||
|
## avoid changing dir in case of failure
|
||||||
|
(
|
||||||
|
echo_run cd csources
|
||||||
|
echo_run sh build.sh
|
||||||
|
)
|
||||||
|
# keep $nim_csources in case needed to investigate bootstrap issues
|
||||||
|
# without having to rebuild from csources
|
||||||
|
echo_run cp bin/nim $nim_csources
|
||||||
|
}
|
||||||
|
|
||||||
|
[ -f $nim_csources ] || echo_run build_nim_csources
|
||||||
|
|
||||||
|
echo_run bin/nim c koch
|
||||||
|
echo_run ./koch boot -d:release
|
||||||
|
echo_run ./koch tools # Compile Nimble and other tools.
|
||||||
63
changelog.md
63
changelog.md
|
|
@ -20,7 +20,7 @@
|
||||||
- The parser now warns about inconsistent spacing around binary operators as
|
- The parser now warns about inconsistent spacing around binary operators as
|
||||||
these can easily be confused with unary operators. This warning will likely
|
these can easily be confused with unary operators. This warning will likely
|
||||||
become an error in the future.
|
become an error in the future.
|
||||||
- The ``'c`` and ``'C'`` prefix for octal literals is now deprecated to
|
- The ``'c`` and ``'C'`` suffix for octal literals is now deprecated to
|
||||||
bring the language in line with the standard library (e.g. ``parseOct``).
|
bring the language in line with the standard library (e.g. ``parseOct``).
|
||||||
- The dot style for import paths (e.g ``import path.to.module`` instead of
|
- The dot style for import paths (e.g ``import path.to.module`` instead of
|
||||||
``import path/to/module``) has been deprecated.
|
``import path/to/module``) has been deprecated.
|
||||||
|
|
@ -37,9 +37,18 @@
|
||||||
strings anymore for its ``unit`` parameter. Instead the space is controlled
|
strings anymore for its ``unit`` parameter. Instead the space is controlled
|
||||||
by a new parameter ``useUnitSpace``.
|
by a new parameter ``useUnitSpace``.
|
||||||
|
|
||||||
|
- The ``times.parse`` and ``times.format`` procs have been rewritten.
|
||||||
|
The proc signatures are the same so it should generally not break anything.
|
||||||
|
However, the new implementation is a bit stricter, which is a breaking change.
|
||||||
|
For example ``parse("2017-01-01 foo", "yyyy-MM-dd")`` will now raise an error.
|
||||||
|
|
||||||
- ``proc `-`*(a, b: Time): int64`` in the ``times`` module has changed return type
|
- ``proc `-`*(a, b: Time): int64`` in the ``times`` module has changed return type
|
||||||
to ``times.Duration`` in order to support higher time resolutions.
|
to ``times.Duration`` in order to support higher time resolutions.
|
||||||
The proc is no longer deprecated.
|
The proc is no longer deprecated.
|
||||||
|
|
||||||
|
- The ``times.Timezone`` is now an immutable ref-type that must be initialized
|
||||||
|
with an explicit constructor (``newTimezone``).
|
||||||
|
|
||||||
- ``posix.Timeval.tv_sec`` has changed type to ``posix.Time``.
|
- ``posix.Timeval.tv_sec`` has changed type to ``posix.Time``.
|
||||||
|
|
||||||
- ``math.`mod` `` for floats now behaves the same as ``mod`` for integers
|
- ``math.`mod` `` for floats now behaves the same as ``mod`` for integers
|
||||||
|
|
@ -63,10 +72,17 @@
|
||||||
- ``lineInfoObj`` now returns absolute path instead of project path.
|
- ``lineInfoObj`` now returns absolute path instead of project path.
|
||||||
It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc.
|
It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc.
|
||||||
|
|
||||||
|
- `threadpool`'s `await` and derivatives have been renamed to `blockUntil`
|
||||||
|
to avoid confusions with `await` from the `async` macro.
|
||||||
|
|
||||||
|
|
||||||
#### Breaking changes in the compiler
|
#### Breaking changes in the compiler
|
||||||
|
|
||||||
- The undocumented ``#? braces`` parsing mode was removed.
|
- The undocumented ``#? braces`` parsing mode was removed.
|
||||||
- The undocumented PHP backend was removed.
|
- The undocumented PHP backend was removed.
|
||||||
|
- The default location of ``nimcache`` for the native code targets was
|
||||||
|
changed. Read [the compiler user guide](https://nim-lang.org/docs/nimc.html#generated-c-code-directory)
|
||||||
|
for more information.
|
||||||
|
|
||||||
### Library additions
|
### Library additions
|
||||||
|
|
||||||
|
|
@ -88,9 +104,11 @@
|
||||||
- Added the procs ``rationals.`div```, ``rationals.`mod```, ``rationals.floorDiv`` and ``rationals.floorMod`` for rationals.
|
- Added the procs ``rationals.`div```, ``rationals.`mod```, ``rationals.floorDiv`` and ``rationals.floorMod`` for rationals.
|
||||||
- Added the proc ``math.prod`` for product of elements in openArray.
|
- Added the proc ``math.prod`` for product of elements in openArray.
|
||||||
- Added the proc ``parseBinInt`` to parse a binary integer from a string, which returns the value.
|
- Added the proc ``parseBinInt`` to parse a binary integer from a string, which returns the value.
|
||||||
- ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt``
|
- ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt``.
|
||||||
- Added the proc ``flush`` for memory mapped files.
|
- Added the proc ``flush`` for memory mapped files.
|
||||||
- Added the ``MemMapFileStream``.
|
- Added the ``MemMapFileStream``.
|
||||||
|
- Added ``macros.copyLineInfo`` to copy lineInfo from other node.
|
||||||
|
- Added ``system.ashr`` an arithmetic right shift for integers.
|
||||||
|
|
||||||
### Library changes
|
### Library changes
|
||||||
|
|
||||||
|
|
@ -129,7 +147,13 @@
|
||||||
- ``func`` is now an alias for ``proc {.noSideEffect.}``.
|
- ``func`` is now an alias for ``proc {.noSideEffect.}``.
|
||||||
- In order to make ``for`` loops and iterators more flexible to use Nim now
|
- In order to make ``for`` loops and iterators more flexible to use Nim now
|
||||||
supports so called "for-loop macros". See
|
supports so called "for-loop macros". See
|
||||||
the `manual <manual.html#macros-for-loop-macros>`_ for more details.
|
the [manual](manual.html#macros-for-loop-macros) for more details.
|
||||||
|
This feature enables a Python-like generic ``enumerate`` implementation.
|
||||||
|
|
||||||
|
- Case statements can now be rewritten via macros. See the [manual](manual.html#macros-case-statement-macros) for more information.
|
||||||
|
This feature enables custom pattern matchers.
|
||||||
|
|
||||||
|
|
||||||
- the `typedesc` special type has been renamed to just `type`.
|
- the `typedesc` special type has been renamed to just `type`.
|
||||||
- `static` and `type` are now also modifiers similar to `ref` and `ptr`.
|
- `static` and `type` are now also modifiers similar to `ref` and `ptr`.
|
||||||
They denote the special types `static[T]` and `type[T]`.
|
They denote the special types `static[T]` and `type[T]`.
|
||||||
|
|
@ -150,7 +174,7 @@
|
||||||
More details in language manual.
|
More details in language manual.
|
||||||
|
|
||||||
- ``nil`` for strings/seqs is finally gone. Instead the default value for
|
- ``nil`` for strings/seqs is finally gone. Instead the default value for
|
||||||
these is ``"" / @[]``.
|
these is ``"" / @[]``. Use ``--nilseqs:on`` for a transition period.
|
||||||
|
|
||||||
- Accessing the binary zero terminator in Nim's native strings
|
- Accessing the binary zero terminator in Nim's native strings
|
||||||
is now invalid. Internally a Nim string still has the trailing zero for
|
is now invalid. Internally a Nim string still has the trailing zero for
|
||||||
|
|
@ -160,11 +184,22 @@
|
||||||
- The command syntax now supports keyword arguments after the first comma.
|
- The command syntax now supports keyword arguments after the first comma.
|
||||||
|
|
||||||
- Thread-local variables can now be declared inside procs. This implies all
|
- Thread-local variables can now be declared inside procs. This implies all
|
||||||
the effects of the `global` pragma.
|
the effects of the ``global`` pragma.
|
||||||
|
|
||||||
- Nim now supports `except` clause in the export statement.
|
- Nim now supports the ``except`` clause in the export statement.
|
||||||
|
|
||||||
|
- Range float types, example ``range[0.0 .. Inf]``. More details in language manual.
|
||||||
|
- The ``{.this.}`` pragma has been deprecated. It never worked within generics and
|
||||||
|
we found the resulting code harder to read than the more explicit ``obj.field``
|
||||||
|
syntax.
|
||||||
|
- "Memory regions" for pointer types have been deprecated, they were hardly used
|
||||||
|
anywhere. Note that this has **nothing** to do with the ``--gc:regions`` switch
|
||||||
|
of managing memory.
|
||||||
|
|
||||||
|
- The exception hierarchy was slightly reworked, ``SystemError`` was renamed to
|
||||||
|
``CatchableError`` and is the new base class for any exception that is guaranteed to
|
||||||
|
be catchable. This change should have minimal impact on most existing Nim code.
|
||||||
|
|
||||||
- Range float types, example `range[0.0 .. Inf]`. More details in language manual.
|
|
||||||
|
|
||||||
### Tool changes
|
### Tool changes
|
||||||
|
|
||||||
|
|
@ -173,7 +208,7 @@
|
||||||
|
|
||||||
### Compiler changes
|
### Compiler changes
|
||||||
|
|
||||||
- The VM's instruction count limit was raised to 1 billion instructions in
|
- The VM's instruction count limit was raised to 3 million instructions in
|
||||||
order to support more complex computations at compile-time.
|
order to support more complex computations at compile-time.
|
||||||
|
|
||||||
- Support for hot code reloading has been implemented for the JavaScript
|
- Support for hot code reloading has been implemented for the JavaScript
|
||||||
|
|
@ -199,6 +234,16 @@
|
||||||
- macros.bindSym now capable to accepts not only literal string or string constant expression.
|
- macros.bindSym now capable to accepts not only literal string or string constant expression.
|
||||||
bindSym enhancement make it also can accepts computed string or ident node inside macros /
|
bindSym enhancement make it also can accepts computed string or ident node inside macros /
|
||||||
compile time functions / static blocks. Only in templates / regular code it retains it's old behavior.
|
compile time functions / static blocks. Only in templates / regular code it retains it's old behavior.
|
||||||
This new feature can be accessed via {.experimental: "dynamicBindSym".} pragma/switch
|
This new feature can be accessed via {.experimental: "dynamicBindSym".} pragma/switch.
|
||||||
|
|
||||||
|
- On Posix systems the global system wide configuration is now put under ``/etc/nim/nim.cfg``,
|
||||||
|
it used to be ``/etc/nim.cfg``. Usually it does not exist, however.
|
||||||
|
|
||||||
|
- On Posix systems the user configuration is now looked under ``$XDG_CONFIG_HOME/nim/nim.cfg``
|
||||||
|
(if ``XDG_CONFIG_HOME`` is not defined, then under ``~/.config/nim/nim.cfg``). It used to be
|
||||||
|
``$XDG_CONFIG_DIR/nim.cfg`` (and ``~/.config/nim.cfg``).
|
||||||
|
|
||||||
|
Similarly, on Windows, the user configuration is now looked under ``%APPDATA%/nim/nim.cfg``.
|
||||||
|
This used to be ``%APPDATA%/nim.cfg``.
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
|
|
|
||||||
|
|
@ -591,7 +591,7 @@ type
|
||||||
mAddI, mSubI, mMulI, mDivI, mModI,
|
mAddI, mSubI, mMulI, mDivI, mModI,
|
||||||
mSucc, mPred,
|
mSucc, mPred,
|
||||||
mAddF64, mSubF64, mMulF64, mDivF64,
|
mAddF64, mSubF64, mMulF64, mDivF64,
|
||||||
mShrI, mShlI, mBitandI, mBitorI, mBitxorI,
|
mShrI, mShlI, mAshrI, mBitandI, mBitorI, mBitxorI,
|
||||||
mMinI, mMaxI,
|
mMinI, mMaxI,
|
||||||
mMinF64, mMaxF64,
|
mMinF64, mMaxF64,
|
||||||
mAddU, mSubU, mMulU, mDivU, mModU,
|
mAddU, mSubU, mMulU, mDivU, mModU,
|
||||||
|
|
@ -972,8 +972,8 @@ const
|
||||||
tyFloat..tyFloat128, tyUInt..tyUInt64}
|
tyFloat..tyFloat128, tyUInt..tyUInt64}
|
||||||
ConstantDataTypes*: TTypeKinds = {tyArray, tySet,
|
ConstantDataTypes*: TTypeKinds = {tyArray, tySet,
|
||||||
tyTuple, tySequence}
|
tyTuple, tySequence}
|
||||||
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
|
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr,
|
||||||
tyProc, tyString, tyError}
|
tyProc, tyError}
|
||||||
ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType,
|
ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType,
|
||||||
skIterator,
|
skIterator,
|
||||||
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
|
||||||
|
|
@ -1151,6 +1151,9 @@ proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
||||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||||
|
|
||||||
proc discardSons*(father: PNode) =
|
proc discardSons*(father: PNode) =
|
||||||
|
when defined(nimNoNilSeqs):
|
||||||
|
father.sons = @[]
|
||||||
|
else:
|
||||||
father.sons = nil
|
father.sons = nil
|
||||||
|
|
||||||
proc withInfo*(n: PNode, info: TLineInfo): PNode =
|
proc withInfo*(n: PNode, info: TLineInfo): PNode =
|
||||||
|
|
@ -1368,7 +1371,7 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo;
|
||||||
result.loc = s.loc
|
result.loc = s.loc
|
||||||
result.annex = s.annex
|
result.annex = s.annex
|
||||||
# XXX once usedGenerics is used, ensure module aliases keep working!
|
# XXX once usedGenerics is used, ensure module aliases keep working!
|
||||||
assert s.usedGenerics == nil
|
assert s.usedGenerics.len == 0
|
||||||
|
|
||||||
proc initStrTable*(x: var TStrTable) =
|
proc initStrTable*(x: var TStrTable) =
|
||||||
x.counter = 0
|
x.counter = 0
|
||||||
|
|
@ -1593,6 +1596,9 @@ proc getStr*(a: PNode): string =
|
||||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||||
of nkNilLit:
|
of nkNilLit:
|
||||||
# let's hope this fixes more problems than it creates:
|
# let's hope this fixes more problems than it creates:
|
||||||
|
when defined(nimNoNilSeqs):
|
||||||
|
result = ""
|
||||||
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
else:
|
else:
|
||||||
doAssert false, "getStr"
|
doAssert false, "getStr"
|
||||||
|
|
@ -1675,6 +1681,14 @@ proc skipStmtList*(n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
|
proc toVar*(typ: PType): PType =
|
||||||
|
## If ``typ`` is not a tyVar then it is converted into a `var <typ>` and
|
||||||
|
## returned. Otherwise ``typ`` is simply returned as-is.
|
||||||
|
result = typ
|
||||||
|
if typ.kind != tyVar:
|
||||||
|
result = newType(tyVar, typ.owner)
|
||||||
|
rawAddSon(result, typ)
|
||||||
|
|
||||||
proc toRef*(typ: PType): PType =
|
proc toRef*(typ: PType): PType =
|
||||||
## If ``typ`` is a tyObject then it is converted into a `ref <typ>` and
|
## If ``typ`` is a tyObject then it is converted into a `ref <typ>` and
|
||||||
## returned. Otherwise ``typ`` is simply returned as-is.
|
## returned. Otherwise ``typ`` is simply returned as-is.
|
||||||
|
|
|
||||||
|
|
@ -412,6 +412,8 @@ proc debugTree(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int;
|
||||||
else:
|
else:
|
||||||
addf(result, ",$N$1\"ident\": null", [istr])
|
addf(result, ",$N$1\"ident\": null", [istr])
|
||||||
else:
|
else:
|
||||||
|
if renderType and n.typ != nil:
|
||||||
|
addf(result, ",$N$1\"typ\": $2", [istr, debugType(conf, n.typ, 2)])
|
||||||
if sonsLen(n) > 0:
|
if sonsLen(n) > 0:
|
||||||
addf(result, ",$N$1\"sons\": [", [istr])
|
addf(result, ",$N$1\"sons\": [", [istr])
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
|
|
|
||||||
|
|
@ -435,7 +435,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||||
# don't call '$' here for efficiency:
|
# don't call '$' here for efficiency:
|
||||||
let pat = ri.sons[0].sym.loc.r.data
|
let pat = ri.sons[0].sym.loc.r.data
|
||||||
internalAssert p.config, pat != nil
|
internalAssert p.config, pat.len > 0
|
||||||
if pat.contains({'#', '(', '@', '\''}):
|
if pat.contains({'#', '(', '@', '\''}):
|
||||||
var pl = genPatternCall(p, ri, pat, typ)
|
var pl = genPatternCall(p, ri, pat, typ)
|
||||||
# simpler version of 'fixupCall' that works with the pl+params combination:
|
# simpler version of 'fixupCall' that works with the pl+params combination:
|
||||||
|
|
@ -484,7 +484,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||||
|
|
||||||
# don't call '$' here for efficiency:
|
# don't call '$' here for efficiency:
|
||||||
let pat = ri.sons[0].sym.loc.r.data
|
let pat = ri.sons[0].sym.loc.r.data
|
||||||
internalAssert p.config, pat != nil
|
internalAssert p.config, pat.len > 0
|
||||||
var start = 3
|
var start = 3
|
||||||
if ' ' in pat:
|
if ' ' in pat:
|
||||||
start = 1
|
start = 1
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,9 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||||
of tyString:
|
of tyString:
|
||||||
# with the new semantics for 'nil' strings, we can map "" to nil and
|
# with the new semantics for 'nil' strings, we can map "" to nil and
|
||||||
# save tons of allocations:
|
# save tons of allocations:
|
||||||
#if n.strVal.len == 0: result = genNilStringLiteral(p.module, n.info)
|
if n.strVal.len == 0 and optNilSeqs notin p.options:
|
||||||
#else:
|
result = genNilStringLiteral(p.module, n.info)
|
||||||
|
else:
|
||||||
result = genStringLiteral(p.module, n)
|
result = genStringLiteral(p.module, n)
|
||||||
else:
|
else:
|
||||||
if n.strVal.isNil: result = rope("NIM_NIL")
|
if n.strVal.isNil: result = rope("NIM_NIL")
|
||||||
|
|
@ -567,9 +568,9 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
"(($4)($1) - ($4)($2))", # SubF64
|
"(($4)($1) - ($4)($2))", # SubF64
|
||||||
"(($4)($1) * ($4)($2))", # MulF64
|
"(($4)($1) * ($4)($2))", # MulF64
|
||||||
"(($4)($1) / ($4)($2))", # DivF64
|
"(($4)($1) / ($4)($2))", # DivF64
|
||||||
|
|
||||||
"($4)((NU$5)($1) >> (NU$3)($2))", # ShrI
|
"($4)((NU$5)($1) >> (NU$3)($2))", # ShrI
|
||||||
"($4)((NU$3)($1) << (NU$3)($2))", # ShlI
|
"($4)((NU$3)($1) << (NU$3)($2))", # ShlI
|
||||||
|
"($4)((NI$3)($1) >> (NU$3)($2))", # AshrI
|
||||||
"($4)($1 & $2)", # BitandI
|
"($4)($1 & $2)", # BitandI
|
||||||
"($4)($1 | $2)", # BitorI
|
"($4)($1 | $2)", # BitorI
|
||||||
"($4)($1 ^ $2)", # BitxorI
|
"($4)($1 ^ $2)", # BitxorI
|
||||||
|
|
@ -996,7 +997,7 @@ proc genEcho(p: BProc, n: PNode) =
|
||||||
# is threadsafe.
|
# is threadsafe.
|
||||||
internalAssert p.config, n.kind == nkBracket
|
internalAssert p.config, n.kind == nkBracket
|
||||||
if p.config.target.targetOS == osGenode:
|
if p.config.target.targetOS == osGenode:
|
||||||
# bypass libc and print directly to the Genode LOG session
|
# echo directly to the Genode LOG session
|
||||||
var args: Rope = nil
|
var args: Rope = nil
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
for it in n.sons:
|
for it in n.sons:
|
||||||
|
|
@ -1004,8 +1005,9 @@ proc genEcho(p: BProc, n: PNode) =
|
||||||
add(args, ", \"\"")
|
add(args, ", \"\"")
|
||||||
else:
|
else:
|
||||||
initLocExpr(p, it, a)
|
initLocExpr(p, it, a)
|
||||||
add(args, ropecg(p.module, ", #nimToCStringConv($1)", [rdLoc(a)]))
|
add(args, ropecg(p.module, ", Genode::Cstring($1->data, $1->len)", [rdLoc(a)]))
|
||||||
p.module.includeHeader("<base/log.h>")
|
p.module.includeHeader("<base/log.h>")
|
||||||
|
p.module.includeHeader("<util/string.h>")
|
||||||
linefmt(p, cpsStmts, """Genode::log(""$1);$n""", args)
|
linefmt(p, cpsStmts, """Genode::log(""$1);$n""", args)
|
||||||
else:
|
else:
|
||||||
if n.len == 0:
|
if n.len == 0:
|
||||||
|
|
@ -1112,8 +1114,8 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
initLoc(call, locCall, e, OnHeap)
|
initLoc(call, locCall, e, OnHeap)
|
||||||
call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)])
|
call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)])
|
||||||
genAssignment(p, dest, call, {})
|
genAssignment(p, dest, call, {})
|
||||||
add(p.s(cpsStmts), appends)
|
|
||||||
gcUsage(p.config, e)
|
gcUsage(p.config, e)
|
||||||
|
add(p.s(cpsStmts), appends)
|
||||||
|
|
||||||
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
# seq &= x -->
|
# seq &= x -->
|
||||||
|
|
@ -1201,7 +1203,7 @@ proc genNew(p: BProc, e: PNode) =
|
||||||
rawGenNew(p, a, nil)
|
rawGenNew(p, a, nil)
|
||||||
gcUsage(p.config, e)
|
gcUsage(p.config, e)
|
||||||
|
|
||||||
proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
|
proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
|
||||||
let seqtype = skipTypes(dest.t, abstractVarRange)
|
let seqtype = skipTypes(dest.t, abstractVarRange)
|
||||||
let args = [getTypeDesc(p.module, seqtype),
|
let args = [getTypeDesc(p.module, seqtype),
|
||||||
genTypeInfo(p.module, seqtype, dest.lode.info), length]
|
genTypeInfo(p.module, seqtype, dest.lode.info), length]
|
||||||
|
|
@ -1212,8 +1214,12 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
|
||||||
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
|
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", dest.rdLoc)
|
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", dest.rdLoc)
|
||||||
|
if not lenIsZero:
|
||||||
call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
|
call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
|
linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
|
||||||
|
else:
|
||||||
|
if lenIsZero:
|
||||||
|
call.r = rope"NIM_NIL"
|
||||||
else:
|
else:
|
||||||
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
|
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
|
||||||
genAssignment(p, dest, call, {})
|
genAssignment(p, dest, call, {})
|
||||||
|
|
@ -1228,7 +1234,9 @@ proc genNewSeq(p: BProc, e: PNode) =
|
||||||
a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
|
a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
|
||||||
getSeqPayloadType(p.module, seqtype))
|
getSeqPayloadType(p.module, seqtype))
|
||||||
else:
|
else:
|
||||||
genNewSeqAux(p, a, b.rdLoc)
|
let lenIsZero = optNilSeqs notin p.options and
|
||||||
|
e[2].kind == nkIntLit and e[2].intVal == 0
|
||||||
|
genNewSeqAux(p, a, b.rdLoc, lenIsZero)
|
||||||
gcUsage(p.config, e)
|
gcUsage(p.config, e)
|
||||||
|
|
||||||
proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
||||||
|
|
@ -1328,7 +1336,8 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
elif d.k == locNone:
|
elif d.k == locNone:
|
||||||
getTemp(p, n.typ, d)
|
getTemp(p, n.typ, d)
|
||||||
# generate call to newSeq before adding the elements per hand:
|
# generate call to newSeq before adding the elements per hand:
|
||||||
genNewSeqAux(p, dest[], intLiteral(sonsLen(n)))
|
genNewSeqAux(p, dest[], intLiteral(sonsLen(n)),
|
||||||
|
optNilSeqs notin p.options and n.len == 0)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
initLoc(arr, locExpr, n[i], OnHeap)
|
initLoc(arr, locExpr, n[i], OnHeap)
|
||||||
arr.r = ropecg(p.module, "$1$3[$2]", rdLoc(dest[]), intLiteral(i), dataField(p))
|
arr.r = ropecg(p.module, "$1$3[$2]", rdLoc(dest[]), intLiteral(i), dataField(p))
|
||||||
|
|
@ -1351,7 +1360,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
|
||||||
getTemp(p, n.typ, d)
|
getTemp(p, n.typ, d)
|
||||||
# generate call to newSeq before adding the elements per hand:
|
# generate call to newSeq before adding the elements per hand:
|
||||||
let L = int(lengthOrd(p.config, n.sons[1].typ))
|
let L = int(lengthOrd(p.config, n.sons[1].typ))
|
||||||
genNewSeqAux(p, d, intLiteral(L))
|
genNewSeqAux(p, d, intLiteral(L), optNilSeqs notin p.options and L == 0)
|
||||||
initLocExpr(p, n.sons[1], a)
|
initLocExpr(p, n.sons[1], a)
|
||||||
# bug #5007; do not produce excessive C source code:
|
# bug #5007; do not produce excessive C source code:
|
||||||
if L < 10:
|
if L < 10:
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
|
||||||
|
|
||||||
proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
|
proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
|
||||||
if compilationCachePresent(conf):
|
if compilationCachePresent(conf):
|
||||||
result = rope(nil)
|
result = rope("")
|
||||||
add(result, "\n/*\t")
|
add(result, "\n/*\t")
|
||||||
add(result, CProcSectionNames[ps])
|
add(result, CProcSectionNames[ps])
|
||||||
add(result, ":*/\n")
|
add(result, ":*/\n")
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,15 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||||
# That's why we are doing the construction inside the preInitProc.
|
# That's why we are doing the construction inside the preInitProc.
|
||||||
# genObjectInit relies on the C runtime's guarantees that
|
# genObjectInit relies on the C runtime's guarantees that
|
||||||
# global variables will be initialized to zero.
|
# global variables will be initialized to zero.
|
||||||
genObjectInit(p.module.preInitProc, cpsInit, v.typ, v.loc, true)
|
var loc = v.loc
|
||||||
|
|
||||||
|
# When the native TLS is unavailable, a global thread-local variable needs
|
||||||
|
# one more layer of indirection in order to access the TLS block.
|
||||||
|
# Only do this for complex types that may need a call to `objectInit`
|
||||||
|
if sfThread in v.flags and emulatedThreadVars(p.config) and
|
||||||
|
isComplexValueType(v.typ):
|
||||||
|
initLocExprSingleUse(p.module.preInitProc, vn, loc)
|
||||||
|
genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, true)
|
||||||
# Alternative construction using default constructor (which may zeromem):
|
# Alternative construction using default constructor (which may zeromem):
|
||||||
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
|
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
|
||||||
if sfExportc in v.flags and p.module.g.generatedHeader != nil:
|
if sfExportc in v.flags and p.module.g.generatedHeader != nil:
|
||||||
|
|
@ -1130,8 +1138,8 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||||
patchAsgnStmtListExpr(patchedTree, e, ri)
|
patchAsgnStmtListExpr(patchedTree, e, ri)
|
||||||
genStmts(p, patchedTree)
|
genStmts(p, patchedTree)
|
||||||
return
|
return
|
||||||
|
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
|
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs))
|
||||||
if le.kind in {nkDerefExpr, nkHiddenDeref}:
|
if le.kind in {nkDerefExpr, nkHiddenDeref}:
|
||||||
genDeref(p, le, a, enforceDeref=true)
|
genDeref(p, le, a, enforceDeref=true)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1147,12 +1147,29 @@ proc genInitCode(m: BModule) =
|
||||||
appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
|
appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
|
||||||
[m.nimTypesName, rope(m.nimTypes)])
|
[m.nimTypesName, rope(m.nimTypes)])
|
||||||
|
|
||||||
add(prc, initGCFrame(m.initProc))
|
# Give this small function its own scope
|
||||||
|
addf(prc, "{$N", [])
|
||||||
|
block:
|
||||||
|
# Keep a bogus frame in case the code needs one
|
||||||
|
add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
|
||||||
|
|
||||||
add(prc, genSectionStart(cpsLocals, m.config))
|
add(prc, genSectionStart(cpsLocals, m.config))
|
||||||
add(prc, m.preInitProc.s(cpsLocals))
|
add(prc, m.preInitProc.s(cpsLocals))
|
||||||
|
add(prc, genSectionEnd(cpsLocals, m.config))
|
||||||
|
|
||||||
|
add(prc, genSectionStart(cpsInit, m.config))
|
||||||
|
add(prc, m.preInitProc.s(cpsInit))
|
||||||
|
add(prc, genSectionEnd(cpsInit, m.config))
|
||||||
|
|
||||||
|
add(prc, genSectionStart(cpsStmts, m.config))
|
||||||
|
add(prc, m.preInitProc.s(cpsStmts))
|
||||||
|
add(prc, genSectionEnd(cpsStmts, m.config))
|
||||||
|
addf(prc, "}$N", [])
|
||||||
|
|
||||||
|
add(prc, initGCFrame(m.initProc))
|
||||||
|
|
||||||
|
add(prc, genSectionStart(cpsLocals, m.config))
|
||||||
add(prc, m.initProc.s(cpsLocals))
|
add(prc, m.initProc.s(cpsLocals))
|
||||||
add(prc, m.postInitProc.s(cpsLocals))
|
|
||||||
add(prc, genSectionEnd(cpsLocals, m.config))
|
add(prc, genSectionEnd(cpsLocals, m.config))
|
||||||
|
|
||||||
if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
|
if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
|
||||||
|
|
@ -1166,16 +1183,13 @@ proc genInitCode(m: BModule) =
|
||||||
add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
|
add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
|
||||||
|
|
||||||
add(prc, genSectionStart(cpsInit, m.config))
|
add(prc, genSectionStart(cpsInit, m.config))
|
||||||
add(prc, m.preInitProc.s(cpsInit))
|
|
||||||
add(prc, m.initProc.s(cpsInit))
|
add(prc, m.initProc.s(cpsInit))
|
||||||
add(prc, m.postInitProc.s(cpsInit))
|
|
||||||
add(prc, genSectionEnd(cpsInit, m.config))
|
add(prc, genSectionEnd(cpsInit, m.config))
|
||||||
|
|
||||||
add(prc, genSectionStart(cpsStmts, m.config))
|
add(prc, genSectionStart(cpsStmts, m.config))
|
||||||
add(prc, m.preInitProc.s(cpsStmts))
|
|
||||||
add(prc, m.initProc.s(cpsStmts))
|
add(prc, m.initProc.s(cpsStmts))
|
||||||
add(prc, m.postInitProc.s(cpsStmts))
|
|
||||||
add(prc, genSectionEnd(cpsStmts, m.config))
|
add(prc, genSectionEnd(cpsStmts, m.config))
|
||||||
|
|
||||||
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
|
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
|
||||||
add(prc, deinitFrame(m.initProc))
|
add(prc, deinitFrame(m.initProc))
|
||||||
add(prc, deinitGCFrame(m.initProc))
|
add(prc, deinitGCFrame(m.initProc))
|
||||||
|
|
@ -1221,11 +1235,6 @@ proc newPreInitProc(m: BModule): BProc =
|
||||||
# little hack so that unique temporaries are generated:
|
# little hack so that unique temporaries are generated:
|
||||||
result.labels = 100_000
|
result.labels = 100_000
|
||||||
|
|
||||||
proc newPostInitProc(m: BModule): BProc =
|
|
||||||
result = newProc(nil, m)
|
|
||||||
# little hack so that unique temporaries are generated:
|
|
||||||
result.labels = 200_000
|
|
||||||
|
|
||||||
proc initProcOptions(m: BModule): TOptions =
|
proc initProcOptions(m: BModule): TOptions =
|
||||||
let opts = m.config.options
|
let opts = m.config.options
|
||||||
if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
|
if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
|
||||||
|
|
@ -1247,7 +1256,6 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
|
||||||
result.initProc = newProc(nil, result)
|
result.initProc = newProc(nil, result)
|
||||||
result.initProc.options = initProcOptions(result)
|
result.initProc.options = initProcOptions(result)
|
||||||
result.preInitProc = newPreInitProc(result)
|
result.preInitProc = newPreInitProc(result)
|
||||||
result.postInitProc = newPostInitProc(result)
|
|
||||||
initNodeTable(result.dataCache)
|
initNodeTable(result.dataCache)
|
||||||
result.typeStack = @[]
|
result.typeStack = @[]
|
||||||
result.forwardedProcs = @[]
|
result.forwardedProcs = @[]
|
||||||
|
|
@ -1258,7 +1266,6 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
|
||||||
if sfSystemModule in module.flags:
|
if sfSystemModule in module.flags:
|
||||||
incl result.flags, preventStackTrace
|
incl result.flags, preventStackTrace
|
||||||
excl(result.preInitProc.options, optStackTrace)
|
excl(result.preInitProc.options, optStackTrace)
|
||||||
excl(result.postInitProc.options, optStackTrace)
|
|
||||||
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi")
|
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi")
|
||||||
else: ""
|
else: ""
|
||||||
open(result.ndi, ndiName, g.config)
|
open(result.ndi, ndiName, g.config)
|
||||||
|
|
@ -1276,7 +1283,6 @@ proc resetModule*(m: BModule) =
|
||||||
m.initProc = newProc(nil, m)
|
m.initProc = newProc(nil, m)
|
||||||
m.initProc.options = initProcOptions(m)
|
m.initProc.options = initProcOptions(m)
|
||||||
m.preInitProc = newPreInitProc(m)
|
m.preInitProc = newPreInitProc(m)
|
||||||
m.postInitProc = newPostInitProc(m)
|
|
||||||
initNodeTable(m.dataCache)
|
initNodeTable(m.dataCache)
|
||||||
m.typeStack = @[]
|
m.typeStack = @[]
|
||||||
m.forwardedProcs = @[]
|
m.forwardedProcs = @[]
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,6 @@ type
|
||||||
headerFiles*: seq[string] # needed headers to include
|
headerFiles*: seq[string] # needed headers to include
|
||||||
typeInfoMarker*: TypeCache # needed for generating type information
|
typeInfoMarker*: TypeCache # needed for generating type information
|
||||||
initProc*: BProc # code for init procedure
|
initProc*: BProc # code for init procedure
|
||||||
postInitProc*: BProc # code to be executed after the init proc
|
|
||||||
preInitProc*: BProc # code executed before the init proc
|
preInitProc*: BProc # code executed before the init proc
|
||||||
typeStack*: TTypeSeq # used for type generation
|
typeStack*: TTypeSeq # used for type generation
|
||||||
dataCache*: TNodeTable
|
dataCache*: TNodeTable
|
||||||
|
|
|
||||||
|
|
@ -279,6 +279,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
|
||||||
of "implicitstatic": result = contains(conf.options, optImplicitStatic)
|
of "implicitstatic": result = contains(conf.options, optImplicitStatic)
|
||||||
of "patterns": result = contains(conf.options, optPatterns)
|
of "patterns": result = contains(conf.options, optPatterns)
|
||||||
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
|
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
|
||||||
|
of "nilseqs": result = contains(conf.options, optNilSeqs)
|
||||||
else: invalidCmdLineOption(conf, passCmd1, switch, info)
|
else: invalidCmdLineOption(conf, passCmd1, switch, info)
|
||||||
|
|
||||||
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
|
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
|
||||||
|
|
@ -497,6 +498,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
else:
|
else:
|
||||||
localError(conf, info, errOnOrOffExpectedButXFound % arg)
|
localError(conf, info, errOnOrOffExpectedButXFound % arg)
|
||||||
of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info)
|
of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info)
|
||||||
|
of "nilseqs": processOnOffSwitch(conf, {optNilSeqs}, arg, pass, info)
|
||||||
of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
|
of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info)
|
||||||
of "floatchecks":
|
of "floatchecks":
|
||||||
processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)
|
processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
import
|
import
|
||||||
strtabs, platform, strutils, idents
|
strtabs, platform, strutils, idents
|
||||||
|
|
||||||
|
from options import Feature
|
||||||
|
|
||||||
const
|
const
|
||||||
catNone = "false"
|
catNone = "false"
|
||||||
|
|
||||||
|
|
@ -74,3 +76,10 @@ proc initDefines*(symbols: StringTableRef) =
|
||||||
defineSymbol("nimVmExportFixed")
|
defineSymbol("nimVmExportFixed")
|
||||||
defineSymbol("nimNewRuntime")
|
defineSymbol("nimNewRuntime")
|
||||||
defineSymbol("nimIncrSeqV3")
|
defineSymbol("nimIncrSeqV3")
|
||||||
|
defineSymbol("nimAshr")
|
||||||
|
defineSymbol("nimNoNilSeqs")
|
||||||
|
defineSymbol("nimNoNilSeqs2")
|
||||||
|
|
||||||
|
defineSymbol("nimHasNilSeqs")
|
||||||
|
for f in low(Feature)..high(Feature):
|
||||||
|
defineSymbol("nimHas" & $f)
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
|
||||||
proc genComment(d: PDoc, n: PNode): string =
|
proc genComment(d: PDoc, n: PNode): string =
|
||||||
result = ""
|
result = ""
|
||||||
var dummyHasToc: bool
|
var dummyHasToc: bool
|
||||||
if n.comment != nil:
|
if n.comment.len > 0:
|
||||||
renderRstToOut(d[], parseRst(n.comment, toFilename(d.conf, n.info),
|
renderRstToOut(d[], parseRst(n.comment, toFilename(d.conf, n.info),
|
||||||
toLinenumber(n.info), toColumn(n.info),
|
toLinenumber(n.info), toColumn(n.info),
|
||||||
dummyHasToc, d.options, d.conf), result)
|
dummyHasToc, d.options, d.conf), result)
|
||||||
|
|
@ -205,7 +205,8 @@ proc genRecComment(d: PDoc, n: PNode): Rope =
|
||||||
result = genRecComment(d, n.sons[i])
|
result = genRecComment(d, n.sons[i])
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
else:
|
else:
|
||||||
n.comment = nil
|
when defined(nimNoNilSeqs): n.comment = ""
|
||||||
|
else: n.comment = nil
|
||||||
|
|
||||||
proc getPlainDocstring(n: PNode): string =
|
proc getPlainDocstring(n: PNode): string =
|
||||||
## Gets the plain text docstring of a node non destructively.
|
## Gets the plain text docstring of a node non destructively.
|
||||||
|
|
@ -215,7 +216,7 @@ proc getPlainDocstring(n: PNode): string =
|
||||||
## the concatenated ``##`` comments of the node.
|
## the concatenated ``##`` comments of the node.
|
||||||
result = ""
|
result = ""
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
if n.comment != nil and startsWith(n.comment, "##"):
|
if startsWith(n.comment, "##"):
|
||||||
result = n.comment
|
result = n.comment
|
||||||
if result.len < 1:
|
if result.len < 1:
|
||||||
for i in countup(0, safeLen(n)-1):
|
for i in countup(0, safeLen(n)-1):
|
||||||
|
|
@ -564,9 +565,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||||
|
|
||||||
result = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
|
result = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
|
||||||
"col": %n.info.col}
|
"col": %n.info.col}
|
||||||
if comm != nil and comm != "":
|
if comm.len > 0:
|
||||||
result["description"] = %comm
|
result["description"] = %comm
|
||||||
if r.buf != nil:
|
if r.buf.len > 0:
|
||||||
result["code"] = %r.buf
|
result["code"] = %r.buf
|
||||||
|
|
||||||
proc checkForFalse(n: PNode): bool =
|
proc checkForFalse(n: PNode): bool =
|
||||||
|
|
@ -634,7 +635,7 @@ proc add(d: PDoc; j: JsonNode) =
|
||||||
proc generateJson*(d: PDoc, n: PNode) =
|
proc generateJson*(d: PDoc, n: PNode) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCommentStmt:
|
of nkCommentStmt:
|
||||||
if n.comment != nil and startsWith(n.comment, "##"):
|
if startsWith(n.comment, "##"):
|
||||||
let stripped = n.comment.substr(2).strip
|
let stripped = n.comment.substr(2).strip
|
||||||
d.add %{ "comment": %stripped, "line": %n.info.line.int,
|
d.add %{ "comment": %stripped, "line": %n.info.line.int,
|
||||||
"col": %n.info.col }
|
"col": %n.info.col }
|
||||||
|
|
@ -678,7 +679,7 @@ proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string =
|
||||||
proc generateTags*(d: PDoc, n: PNode, r: var Rope) =
|
proc generateTags*(d: PDoc, n: PNode, r: var Rope) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCommentStmt:
|
of nkCommentStmt:
|
||||||
if n.comment != nil and startsWith(n.comment, "##"):
|
if startsWith(n.comment, "##"):
|
||||||
let stripped = n.comment.substr(2).strip
|
let stripped = n.comment.substr(2).strip
|
||||||
r.add stripped
|
r.add stripped
|
||||||
of nkProcDef:
|
of nkProcDef:
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,7 @@ type
|
||||||
wordCounter: int
|
wordCounter: int
|
||||||
idAnon*, idDelegator*, emptyIdent*: PIdent
|
idAnon*, idDelegator*, emptyIdent*: PIdent
|
||||||
|
|
||||||
when false:
|
proc resetIdentCache*() = discard
|
||||||
var
|
|
||||||
legacy: IdentCache
|
|
||||||
|
|
||||||
proc resetIdentCache*() =
|
|
||||||
when false:
|
|
||||||
for i in low(legacy.buckets)..high(legacy.buckets):
|
|
||||||
legacy.buckets[i] = nil
|
|
||||||
|
|
||||||
proc cmpIgnoreStyle*(a, b: cstring, blen: int): int =
|
proc cmpIgnoreStyle*(a, b: cstring, blen: int): int =
|
||||||
if a[0] != b[0]: return 1
|
if a[0] != b[0]: return 1
|
||||||
|
|
@ -73,11 +66,9 @@ proc cmpExact(a, b: cstring, blen: int): int =
|
||||||
if result == 0:
|
if result == 0:
|
||||||
if a[i] != '\0': result = 1
|
if a[i] != '\0': result = 1
|
||||||
|
|
||||||
{.this: self.}
|
proc getIdent*(ic: IdentCache; identifier: cstring, length: int, h: Hash): PIdent =
|
||||||
|
var idx = h and high(ic.buckets)
|
||||||
proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PIdent =
|
result = ic.buckets[idx]
|
||||||
var idx = h and high(buckets)
|
|
||||||
result = buckets[idx]
|
|
||||||
var last: PIdent = nil
|
var last: PIdent = nil
|
||||||
var id = 0
|
var id = 0
|
||||||
while result != nil:
|
while result != nil:
|
||||||
|
|
@ -85,8 +76,8 @@ proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PId
|
||||||
if last != nil:
|
if last != nil:
|
||||||
# make access to last looked up identifier faster:
|
# make access to last looked up identifier faster:
|
||||||
last.next = result.next
|
last.next = result.next
|
||||||
result.next = buckets[idx]
|
result.next = ic.buckets[idx]
|
||||||
buckets[idx] = result
|
ic.buckets[idx] = result
|
||||||
return
|
return
|
||||||
elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0:
|
elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0:
|
||||||
assert((id == 0) or (id == result.id))
|
assert((id == 0) or (id == result.id))
|
||||||
|
|
@ -97,20 +88,20 @@ proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PId
|
||||||
result.h = h
|
result.h = h
|
||||||
result.s = newString(length)
|
result.s = newString(length)
|
||||||
for i in countup(0, length - 1): result.s[i] = identifier[i]
|
for i in countup(0, length - 1): result.s[i] = identifier[i]
|
||||||
result.next = buckets[idx]
|
result.next = ic.buckets[idx]
|
||||||
buckets[idx] = result
|
ic.buckets[idx] = result
|
||||||
if id == 0:
|
if id == 0:
|
||||||
inc(wordCounter)
|
inc(ic.wordCounter)
|
||||||
result.id = -wordCounter
|
result.id = -ic.wordCounter
|
||||||
else:
|
else:
|
||||||
result.id = id
|
result.id = id
|
||||||
|
|
||||||
proc getIdent*(self: IdentCache; identifier: string): PIdent =
|
proc getIdent*(ic: IdentCache; identifier: string): PIdent =
|
||||||
result = getIdent(cstring(identifier), len(identifier),
|
result = getIdent(ic, cstring(identifier), len(identifier),
|
||||||
hashIgnoreStyle(identifier))
|
hashIgnoreStyle(identifier))
|
||||||
|
|
||||||
proc getIdent*(self: IdentCache; identifier: string, h: Hash): PIdent =
|
proc getIdent*(ic: IdentCache; identifier: string, h: Hash): PIdent =
|
||||||
result = getIdent(cstring(identifier), len(identifier), h)
|
result = getIdent(ic, cstring(identifier), len(identifier), h)
|
||||||
|
|
||||||
proc newIdentCache*(): IdentCache =
|
proc newIdentCache*(): IdentCache =
|
||||||
result = IdentCache()
|
result = IdentCache()
|
||||||
|
|
|
||||||
|
|
@ -379,6 +379,7 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
||||||
["", "", "($1 / $2)", "($1 / $2)"], # DivF64
|
["", "", "($1 / $2)", "($1 / $2)"], # DivF64
|
||||||
["", "", "", ""], # ShrI
|
["", "", "", ""], # ShrI
|
||||||
["", "", "($1 << $2)", "($1 << $2)"], # ShlI
|
["", "", "($1 << $2)", "($1 << $2)"], # ShlI
|
||||||
|
["", "", "($1 >> $2)", "($1 >> $2)"], # AshrI
|
||||||
["", "", "($1 & $2)", "($1 & $2)"], # BitandI
|
["", "", "($1 & $2)", "($1 & $2)"], # BitandI
|
||||||
["", "", "($1 | $2)", "($1 | $2)"], # BitorI
|
["", "", "($1 | $2)", "($1 | $2)"], # BitorI
|
||||||
["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI
|
["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI
|
||||||
|
|
@ -1266,7 +1267,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
|
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
|
||||||
if sfInfixCall in f.flags:
|
if sfInfixCall in f.flags:
|
||||||
let pat = n.sons[0].sym.loc.r.data
|
let pat = n.sons[0].sym.loc.r.data
|
||||||
internalAssert p.config, pat != nil
|
internalAssert p.config, pat.len > 0
|
||||||
if pat.contains({'#', '(', '@'}):
|
if pat.contains({'#', '(', '@'}):
|
||||||
var typ = skipTypes(n.sons[0].typ, abstractInst)
|
var typ = skipTypes(n.sons[0].typ, abstractInst)
|
||||||
assert(typ.kind == tyProc)
|
assert(typ.kind == tyProc)
|
||||||
|
|
@ -1349,7 +1350,7 @@ proc arrayTypeForElemType(typ: PType): string =
|
||||||
of tyUint8: "Uint8Array"
|
of tyUint8: "Uint8Array"
|
||||||
of tyFloat32: "Float32Array"
|
of tyFloat32: "Float32Array"
|
||||||
of tyFloat64, tyFloat: "Float64Array"
|
of tyFloat64, tyFloat: "Float64Array"
|
||||||
else: nil
|
else: ""
|
||||||
|
|
||||||
proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
|
||||||
var t = skipTypes(typ, abstractInst)
|
var t = skipTypes(typ, abstractInst)
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ const
|
||||||
warnResultShadowed: "Special variable 'result' is shadowed.",
|
warnResultShadowed: "Special variable 'result' is shadowed.",
|
||||||
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
|
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
|
||||||
warnUser: "$1",
|
warnUser: "$1",
|
||||||
hintSuccess: "operation successful",
|
hintSuccess: "operation successful: $#",
|
||||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
|
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
|
||||||
hintCC: "CC: \'$1\'", # unused
|
hintCC: "CC: \'$1\'", # unused
|
||||||
hintLineTooLong: "line too long",
|
hintLineTooLong: "line too long",
|
||||||
|
|
@ -169,8 +169,8 @@ proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
|
||||||
result[1] = result[2] - {warnShadowIdent, warnProveField, warnProveIndex,
|
result[1] = result[2] - {warnShadowIdent, warnProveField, warnProveIndex,
|
||||||
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
|
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
|
||||||
hintSource, hintGlobalVar, hintGCStats}
|
hintSource, hintGlobalVar, hintGCStats}
|
||||||
result[0] = result[1] - {hintSuccessX, hintConf, hintProcessing,
|
result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
|
||||||
hintPattern, hintExecuting, hintLinking}
|
hintProcessing, hintPattern, hintExecuting, hintLinking}
|
||||||
|
|
||||||
const
|
const
|
||||||
NotesVerbosity* = computeNotesVerbosity()
|
NotesVerbosity* = computeNotesVerbosity()
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, idents, semdata, types, msgs, options,
|
intsets, ast, astalgo, idents, semdata, types, msgs, options,
|
||||||
renderer, wordrecg, idgen, nimfix.prettybase, lineinfos, strutils
|
renderer, wordrecg, idgen, nimfix/prettybase, lineinfos, strutils
|
||||||
|
|
||||||
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
|
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
|
||||||
|
|
||||||
|
|
@ -262,7 +262,7 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) =
|
||||||
err.add "\nThis might be caused by a recursive module dependency: "
|
err.add "\nThis might be caused by a recursive module dependency: "
|
||||||
err.add c.recursiveDep
|
err.add c.recursiveDep
|
||||||
# prevent excessive errors for 'nim check'
|
# prevent excessive errors for 'nim check'
|
||||||
c.recursiveDep = nil
|
c.recursiveDep = ""
|
||||||
localError(c.config, info, errGenerated, err)
|
localError(c.config, info, errGenerated, err)
|
||||||
|
|
||||||
proc lookUp*(c: PContext, n: PNode): PSym =
|
proc lookUp*(c: PContext, n: PNode): PSym =
|
||||||
|
|
|
||||||
|
|
@ -65,10 +65,8 @@ type
|
||||||
|
|
||||||
proc hash*(x: FileIndex): Hash {.borrow.}
|
proc hash*(x: FileIndex): Hash {.borrow.}
|
||||||
|
|
||||||
{.this: g.}
|
|
||||||
|
|
||||||
proc stopCompile*(g: ModuleGraph): bool {.inline.} =
|
proc stopCompile*(g: ModuleGraph): bool {.inline.} =
|
||||||
result = doStopCompile != nil and doStopCompile()
|
result = g.doStopCompile != nil and g.doStopCompile()
|
||||||
|
|
||||||
proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
|
proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
|
||||||
result = newSym(skProc, getIdent(g.cache, name), nil, unknownLineInfo(), {})
|
result = newSym(skProc, getIdent(g.cache, name), nil, unknownLineInfo(), {})
|
||||||
|
|
@ -98,44 +96,44 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
|
||||||
result.cacheTables = initTable[string, BTree[string, PNode]]()
|
result.cacheTables = initTable[string, BTree[string, PNode]]()
|
||||||
|
|
||||||
proc resetAllModules*(g: ModuleGraph) =
|
proc resetAllModules*(g: ModuleGraph) =
|
||||||
initStrTable(packageSyms)
|
initStrTable(g.packageSyms)
|
||||||
deps = initIntSet()
|
g.deps = initIntSet()
|
||||||
modules = @[]
|
g.modules = @[]
|
||||||
importStack = @[]
|
g.importStack = @[]
|
||||||
inclToMod = initTable[FileIndex, FileIndex]()
|
g.inclToMod = initTable[FileIndex, FileIndex]()
|
||||||
usageSym = nil
|
g.usageSym = nil
|
||||||
owners = @[]
|
g.owners = @[]
|
||||||
methods = @[]
|
g.methods = @[]
|
||||||
initStrTable(compilerprocs)
|
initStrTable(g.compilerprocs)
|
||||||
initStrTable(exposed)
|
initStrTable(g.exposed)
|
||||||
|
|
||||||
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
|
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
|
||||||
if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len:
|
if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len:
|
||||||
result = modules[fileIdx.int32]
|
result = g.modules[fileIdx.int32]
|
||||||
|
|
||||||
proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
|
proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b
|
||||||
|
|
||||||
proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
|
proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) =
|
||||||
assert m.position == m.info.fileIndex.int32
|
assert m.position == m.info.fileIndex.int32
|
||||||
addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false)
|
addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false)
|
||||||
if suggestMode:
|
if g.suggestMode:
|
||||||
deps.incl m.position.dependsOn(dep.int)
|
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 quering the graph lazily.
|
||||||
# this improves efficiency quite a lot:
|
# this improves efficiency quite a lot:
|
||||||
#invalidTransitiveClosure = true
|
#invalidTransitiveClosure = true
|
||||||
|
|
||||||
proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) =
|
proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) =
|
||||||
addModuleDep(g.incr, g.config, module, includeFile, isIncludeFile = true)
|
addModuleDep(g.incr, g.config, module, includeFile, isIncludeFile = true)
|
||||||
discard hasKeyOrPut(inclToMod, includeFile, module)
|
discard hasKeyOrPut(g.inclToMod, includeFile, module)
|
||||||
|
|
||||||
proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex =
|
proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex =
|
||||||
## returns 'fileIdx' if the file belonging to this index is
|
## returns 'fileIdx' if the file belonging to this index is
|
||||||
## directly used as a module or else the module that first
|
## directly used as a module or else the module that first
|
||||||
## references this include file.
|
## references this include file.
|
||||||
if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len and modules[fileIdx.int32] != nil:
|
if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len and g.modules[fileIdx.int32] != nil:
|
||||||
result = fileIdx
|
result = fileIdx
|
||||||
else:
|
else:
|
||||||
result = inclToMod.getOrDefault(fileIdx)
|
result = g.inclToMod.getOrDefault(fileIdx)
|
||||||
|
|
||||||
proc transitiveClosure(g: var IntSet; n: int) =
|
proc transitiveClosure(g: var IntSet; n: int) =
|
||||||
# warshall's algorithm
|
# warshall's algorithm
|
||||||
|
|
@ -147,22 +145,22 @@ proc transitiveClosure(g: var IntSet; n: int) =
|
||||||
g.incl i.dependsOn(j)
|
g.incl i.dependsOn(j)
|
||||||
|
|
||||||
proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||||
let m = getModule fileIdx
|
let m = g.getModule fileIdx
|
||||||
if m != nil: incl m.flags, sfDirty
|
if m != nil: incl m.flags, sfDirty
|
||||||
|
|
||||||
proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
|
||||||
# we need to mark its dependent modules D as dirty right away because after
|
# we need to mark its dependent modules D as dirty right away because after
|
||||||
# nimsuggest is done with this module, the module's dirty flag will be
|
# nimsuggest is done with this module, the module's dirty flag will be
|
||||||
# cleared but D still needs to be remembered as 'dirty'.
|
# cleared but D still needs to be remembered as 'dirty'.
|
||||||
if invalidTransitiveClosure:
|
if g.invalidTransitiveClosure:
|
||||||
invalidTransitiveClosure = false
|
g.invalidTransitiveClosure = false
|
||||||
transitiveClosure(deps, modules.len)
|
transitiveClosure(g.deps, g.modules.len)
|
||||||
|
|
||||||
# every module that *depends* on this file is also dirty:
|
# every module that *depends* on this file is also dirty:
|
||||||
for i in 0i32..<modules.len.int32:
|
for i in 0i32..<g.modules.len.int32:
|
||||||
let m = modules[i]
|
let m = g.modules[i]
|
||||||
if m != nil and deps.contains(i.dependsOn(fileIdx.int)):
|
if m != nil and g.deps.contains(i.dependsOn(fileIdx.int)):
|
||||||
incl m.flags, sfDirty
|
incl m.flags, sfDirty
|
||||||
|
|
||||||
proc isDirty*(g: ModuleGraph; m: PSym): bool =
|
proc isDirty*(g: ModuleGraph; m: PSym): bool =
|
||||||
result = suggestMode and sfDirty in m.flags
|
result = g.suggestMode and sfDirty in m.flags
|
||||||
|
|
|
||||||
|
|
@ -391,10 +391,10 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
|
||||||
|
|
||||||
if conf.structuredErrorHook != nil:
|
if conf.structuredErrorHook != nil:
|
||||||
conf.structuredErrorHook(conf, unknownLineInfo(),
|
conf.structuredErrorHook(conf, unknownLineInfo(),
|
||||||
s & (if kind != nil: KindFormat % kind else: ""), sev)
|
s & (if kind.len > 0: KindFormat % kind else: ""), sev)
|
||||||
|
|
||||||
if not ignoreMsgBecauseOfIdeTools(conf, msg):
|
if not ignoreMsgBecauseOfIdeTools(conf, msg):
|
||||||
if kind != nil:
|
if kind.len > 0:
|
||||||
styledMsgWriteln(color, title, resetStyle, s,
|
styledMsgWriteln(color, title, resetStyle, s,
|
||||||
KindColor, `%`(KindFormat, kind))
|
KindColor, `%`(KindFormat, kind))
|
||||||
else:
|
else:
|
||||||
|
|
@ -483,9 +483,9 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
||||||
|
|
||||||
if not ignoreMsg:
|
if not ignoreMsg:
|
||||||
if conf.structuredErrorHook != nil:
|
if conf.structuredErrorHook != nil:
|
||||||
conf.structuredErrorHook(conf, info, s & (if kind != nil: KindFormat % kind else: ""), sev)
|
conf.structuredErrorHook(conf, info, s & (if kind.len > 0: KindFormat % kind else: ""), sev)
|
||||||
if not ignoreMsgBecauseOfIdeTools(conf, msg):
|
if not ignoreMsgBecauseOfIdeTools(conf, msg):
|
||||||
if kind != nil:
|
if kind.len > 0:
|
||||||
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
|
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
|
||||||
KindColor, `%`(KindFormat, kind))
|
KindColor, `%`(KindFormat, kind))
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ proc readConfigFile(
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc getUserConfigPath(filename: string): string =
|
proc getUserConfigPath(filename: string): string =
|
||||||
result = joinPath(getConfigDir(), filename)
|
result = joinPath([getConfigDir(), "nim", filename])
|
||||||
|
|
||||||
proc getSystemConfigPath(conf: ConfigRef; filename: string): string =
|
proc getSystemConfigPath(conf: ConfigRef; filename: string): string =
|
||||||
# try standard configuration file (installation did not distribute files
|
# try standard configuration file (installation did not distribute files
|
||||||
|
|
@ -228,8 +228,8 @@ proc getSystemConfigPath(conf: ConfigRef; filename: string): string =
|
||||||
let p = getPrefixDir(conf)
|
let p = getPrefixDir(conf)
|
||||||
result = joinPath([p, "config", filename])
|
result = joinPath([p, "config", filename])
|
||||||
when defined(unix):
|
when defined(unix):
|
||||||
if not existsFile(result): result = joinPath([p, "etc", filename])
|
if not existsFile(result): result = joinPath([p, "etc/nim", filename])
|
||||||
if not existsFile(result): result = "/etc/" & filename
|
if not existsFile(result): result = "/etc/nim/" & filename
|
||||||
|
|
||||||
proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
|
proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
|
||||||
setDefaultLibpath(conf)
|
setDefaultLibpath(conf)
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ type # please make sure we have under 32 options
|
||||||
optPatterns, # en/disable pattern matching
|
optPatterns, # en/disable pattern matching
|
||||||
optMemTracker,
|
optMemTracker,
|
||||||
optHotCodeReloading,
|
optHotCodeReloading,
|
||||||
optLaxStrings
|
optLaxStrings,
|
||||||
|
optNilSeqs
|
||||||
|
|
||||||
TOptions* = set[TOption]
|
TOptions* = set[TOption]
|
||||||
TGlobalOption* = enum # **keep binary compatible**
|
TGlobalOption* = enum # **keep binary compatible**
|
||||||
|
|
@ -110,14 +111,16 @@ type
|
||||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
|
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
|
||||||
ideHighlight, ideOutline, ideKnown, ideMsg
|
ideHighlight, ideOutline, ideKnown, ideMsg
|
||||||
|
|
||||||
Feature* = enum ## experimental features
|
Feature* = enum ## experimental features; DO NOT RENAME THESE!
|
||||||
implicitDeref,
|
implicitDeref,
|
||||||
dotOperators,
|
dotOperators,
|
||||||
callOperator,
|
callOperator,
|
||||||
parallel,
|
parallel,
|
||||||
destructor,
|
destructor,
|
||||||
notnil,
|
notnil,
|
||||||
dynamicBindSym
|
dynamicBindSym,
|
||||||
|
forLoopMacros,
|
||||||
|
caseStmtMacros
|
||||||
|
|
||||||
SymbolFilesOption* = enum
|
SymbolFilesOption* = enum
|
||||||
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
disabledSf, writeOnlySf, readOnlySf, v2Sf
|
||||||
|
|
@ -354,6 +357,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||||
of "msdos": result = conf.target.targetOS == osDos
|
of "msdos": result = conf.target.targetOS == osDos
|
||||||
of "mswindows", "win32": result = conf.target.targetOS == osWindows
|
of "mswindows", "win32": result = conf.target.targetOS == osWindows
|
||||||
of "macintosh": result = conf.target.targetOS in {osMacos, osMacosx}
|
of "macintosh": result = conf.target.targetOS in {osMacos, osMacosx}
|
||||||
|
of "osx": result = conf.target.targetOS == osMacosx
|
||||||
of "sunos": result = conf.target.targetOS == osSolaris
|
of "sunos": result = conf.target.targetOS == osSolaris
|
||||||
of "nintendoswitch":
|
of "nintendoswitch":
|
||||||
result = conf.target.targetOS == osNintendoSwitch
|
result = conf.target.targetOS == osNintendoSwitch
|
||||||
|
|
@ -479,9 +483,20 @@ proc disableNimblePath*(conf: ConfigRef) =
|
||||||
|
|
||||||
include packagehandling
|
include packagehandling
|
||||||
|
|
||||||
|
proc getOsCacheDir(): string =
|
||||||
|
when defined(posix):
|
||||||
|
result = getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache") / "nim"
|
||||||
|
else:
|
||||||
|
result = getHomeDir() / genSubDir
|
||||||
|
|
||||||
proc getNimcacheDir*(conf: ConfigRef): string =
|
proc getNimcacheDir*(conf: ConfigRef): string =
|
||||||
result = if conf.nimcacheDir.len > 0: conf.nimcacheDir
|
# XXX projectName should always be without a file extension!
|
||||||
else: shortenDir(conf, conf.projectPath) / genSubDir
|
result = if conf.nimcacheDir.len > 0:
|
||||||
|
conf.nimcacheDir
|
||||||
|
elif conf.cmd == cmdCompileToJS:
|
||||||
|
shortenDir(conf, conf.projectPath) / genSubDir
|
||||||
|
else: getOsCacheDir() / splitFile(conf.projectName).name &
|
||||||
|
(if isDefined(conf, "release"): "_r" else: "_d")
|
||||||
|
|
||||||
proc pathSubs*(conf: ConfigRef; p, config: string): string =
|
proc pathSubs*(conf: ConfigRef; p, config: string): string =
|
||||||
let home = removeTrailingDirSep(os.getHomeDir())
|
let home = removeTrailingDirSep(os.getHomeDir())
|
||||||
|
|
@ -588,11 +603,13 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
|
||||||
proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =
|
proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =
|
||||||
const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
|
const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
|
||||||
var candidates: seq[string] = @[]
|
var candidates: seq[string] = @[]
|
||||||
for k, f in os.walkDir(pkg, relative=true):
|
var dir = pkg
|
||||||
|
while true:
|
||||||
|
for k, f in os.walkDir(dir, relative=true):
|
||||||
if k == pcFile and f != "config.nims":
|
if k == pcFile and f != "config.nims":
|
||||||
let (_, name, ext) = splitFile(f)
|
let (_, name, ext) = splitFile(f)
|
||||||
if ext in extensions:
|
if ext in extensions:
|
||||||
let x = changeFileExt(pkg / name, ".nim")
|
let x = changeFileExt(dir / name, ".nim")
|
||||||
if fileExists(x):
|
if fileExists(x):
|
||||||
candidates.add x
|
candidates.add x
|
||||||
for c in candidates:
|
for c in candidates:
|
||||||
|
|
@ -600,6 +617,8 @@ proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =
|
||||||
if (pkg in c) or (c in pkg): return c
|
if (pkg in c) or (c in pkg): return c
|
||||||
if candidates.len >= 1:
|
if candidates.len >= 1:
|
||||||
return candidates[0]
|
return candidates[0]
|
||||||
|
dir = parentDir(dir)
|
||||||
|
if dir == "": break
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
proc canonDynlibName(s: string): string =
|
proc canonDynlibName(s: string): string =
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||||
if n.typ != nil and n.typ.kind == tyVar:
|
if n.typ != nil and n.typ.kind == tyVar:
|
||||||
result = arLValue
|
result = arLValue
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet}
|
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar}
|
||||||
else: {skVar, skResult, skTemp}
|
else: {skVar, skResult, skTemp}
|
||||||
if n.sym.kind in kinds:
|
if n.sym.kind in kinds:
|
||||||
if owner != nil and owner == n.sym.owner and
|
if owner != nil and owner == n.sym.owner and
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,7 @@ template sameOrNoInd(p): bool = p.tok.indent == p.currInd or p.tok.indent < 0
|
||||||
proc rawSkipComment(p: var TParser, node: PNode) =
|
proc rawSkipComment(p: var TParser, node: PNode) =
|
||||||
if p.tok.tokType == tkComment:
|
if p.tok.tokType == tkComment:
|
||||||
if node != nil:
|
if node != nil:
|
||||||
|
when not defined(nimNoNilSeqs):
|
||||||
if node.comment == nil: node.comment = ""
|
if node.comment == nil: node.comment = ""
|
||||||
when defined(nimpretty):
|
when defined(nimpretty):
|
||||||
if p.tok.commentOffsetB > p.tok.commentOffsetA:
|
if p.tok.commentOffsetB > p.tok.commentOffsetA:
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,17 @@ type
|
||||||
formals: int
|
formals: int
|
||||||
c: PContext
|
c: PContext
|
||||||
subMatch: bool # subnode matches are special
|
subMatch: bool # subnode matches are special
|
||||||
|
mappingIsFull: bool
|
||||||
PPatternContext = var TPatternContext
|
PPatternContext = var TPatternContext
|
||||||
|
|
||||||
proc getLazy(c: PPatternContext, sym: PSym): PNode =
|
proc getLazy(c: PPatternContext, sym: PSym): PNode =
|
||||||
if not isNil(c.mapping):
|
if c.mappingIsFull:
|
||||||
result = c.mapping[sym.position]
|
result = c.mapping[sym.position]
|
||||||
|
|
||||||
proc putLazy(c: PPatternContext, sym: PSym, n: PNode) =
|
proc putLazy(c: PPatternContext, sym: PSym, n: PNode) =
|
||||||
if isNil(c.mapping): newSeq(c.mapping, c.formals)
|
if not c.mappingIsFull:
|
||||||
|
newSeq(c.mapping, c.formals)
|
||||||
|
c.mappingIsFull = true
|
||||||
c.mapping[sym.position] = n
|
c.mapping[sym.position] = n
|
||||||
|
|
||||||
proc matches(c: PPatternContext, p, n: PNode): bool
|
proc matches(c: PPatternContext, p, n: PNode): bool
|
||||||
|
|
@ -209,6 +212,10 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
|
||||||
for j in 0 ..< p.len:
|
for j in 0 ..< p.len:
|
||||||
if not matches(c, p.sons[j], n.sons[i+j]):
|
if not matches(c, p.sons[j], n.sons[i+j]):
|
||||||
# we need to undo any bindings:
|
# we need to undo any bindings:
|
||||||
|
when defined(nimNoNilSeqs):
|
||||||
|
c.mapping = @[]
|
||||||
|
c.mappingIsFull = false
|
||||||
|
else:
|
||||||
if not isNil(c.mapping): c.mapping = nil
|
if not isNil(c.mapping): c.mapping = nil
|
||||||
return false
|
return false
|
||||||
result = true
|
result = true
|
||||||
|
|
|
||||||
|
|
@ -1066,8 +1066,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||||
of wThis:
|
of wThis:
|
||||||
if it.kind in nkPragmaCallKinds and it.len == 2:
|
if it.kind in nkPragmaCallKinds and it.len == 2:
|
||||||
c.selfName = considerQuotedIdent(c, it[1])
|
c.selfName = considerQuotedIdent(c, it[1])
|
||||||
|
message(c.config, n.info, warnDeprecated, "the '.this' pragma")
|
||||||
elif it.kind == nkIdent or it.len == 1:
|
elif it.kind == nkIdent or it.len == 1:
|
||||||
c.selfName = getIdent(c.cache, "self")
|
c.selfName = getIdent(c.cache, "self")
|
||||||
|
message(c.config, n.info, warnDeprecated, "the '.this' pragma")
|
||||||
else:
|
else:
|
||||||
localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments")
|
localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments")
|
||||||
of wNoRewrite:
|
of wNoRewrite:
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ const
|
||||||
|
|
||||||
proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
|
proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
|
||||||
result = false
|
result = false
|
||||||
if n.comment != nil:
|
if n.comment.len > 0:
|
||||||
result = (renderNoComments notin g.flags) or
|
result = (renderNoComments notin g.flags) or
|
||||||
(renderDocComments in g.flags)
|
(renderDocComments in g.flags)
|
||||||
|
|
||||||
|
|
@ -402,7 +402,7 @@ proc lsons(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
|
||||||
proc lsub(g: TSrcGen; n: PNode): int =
|
proc lsub(g: TSrcGen; n: PNode): int =
|
||||||
# computes the length of a tree
|
# computes the length of a tree
|
||||||
if isNil(n): return 0
|
if isNil(n): return 0
|
||||||
if n.comment != nil: return MaxLineLen + 1
|
if n.comment.len > 0: return MaxLineLen + 1
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkEmpty: result = 0
|
of nkEmpty: result = 0
|
||||||
of nkTripleStrLit:
|
of nkTripleStrLit:
|
||||||
|
|
@ -500,7 +500,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
|
||||||
of nkBreakStmt: result = lsub(g, n.sons[0]) + len("break_")
|
of nkBreakStmt: result = lsub(g, n.sons[0]) + len("break_")
|
||||||
of nkContinueStmt: result = lsub(g, n.sons[0]) + len("continue_")
|
of nkContinueStmt: result = lsub(g, n.sons[0]) + len("continue_")
|
||||||
of nkPragma: result = lcomma(g, n) + 4
|
of nkPragma: result = lcomma(g, n) + 4
|
||||||
of nkCommentStmt: result = if n.comment.isNil: 0 else: len(n.comment)
|
of nkCommentStmt: result = len(n.comment)
|
||||||
of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
|
of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
|
||||||
of nkImportAs: result = lsub(g, n.sons[0]) + len("_as_") + lsub(g, n.sons[1])
|
of nkImportAs: result = lsub(g, n.sons[0]) + len("_as_") + lsub(g, n.sons[1])
|
||||||
of nkElifBranch: result = lsons(g, n) + len("elif_:_")
|
of nkElifBranch: result = lsons(g, n) + len("elif_:_")
|
||||||
|
|
@ -539,7 +539,7 @@ proc gsub(g: var TSrcGen, n: PNode) =
|
||||||
proc hasCom(n: PNode): bool =
|
proc hasCom(n: PNode): bool =
|
||||||
result = false
|
result = false
|
||||||
if n.isNil: return false
|
if n.isNil: return false
|
||||||
if n.comment != nil: return true
|
if n.comment.len > 0: return true
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkEmpty..nkNilLit: discard
|
of nkEmpty..nkNilLit: discard
|
||||||
else:
|
else:
|
||||||
|
|
@ -602,7 +602,7 @@ proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
|
||||||
dedent(g)
|
dedent(g)
|
||||||
|
|
||||||
proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool =
|
proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool =
|
||||||
result = n.comment != nil
|
result = n.comment.len > 0
|
||||||
if not result:
|
if not result:
|
||||||
# check further
|
# check further
|
||||||
for i in countup(start, sonsLen(n) + theEnd):
|
for i in countup(start, sonsLen(n) + theEnd):
|
||||||
|
|
@ -864,7 +864,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
if isNil(n): return
|
if isNil(n): return
|
||||||
var
|
var
|
||||||
a: TContext
|
a: TContext
|
||||||
if n.comment != nil: pushCom(g, n)
|
if n.comment.len > 0: pushCom(g, n)
|
||||||
case n.kind # atoms:
|
case n.kind # atoms:
|
||||||
of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n))
|
of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n))
|
||||||
of nkEmpty: discard
|
of nkEmpty: discard
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,27 @@
|
||||||
## Serialization utilities for the compiler.
|
## Serialization utilities for the compiler.
|
||||||
import strutils, math
|
import strutils, math
|
||||||
|
|
||||||
|
# MSVC prior to 2013 doesn't have C99 functions
|
||||||
|
when defined(windows) and (defined(vcc) or defined(bcc)):
|
||||||
|
{.emit: """#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
|
#include <stdarg.h>
|
||||||
|
static int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) {
|
||||||
|
int count = -1;
|
||||||
|
if (size != 0) count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
|
||||||
|
if (count == -1) count = _vscprintf(format, ap);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
int snprintf(char *outBuf, size_t size, const char *format, ...) {
|
||||||
|
int count;
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
count = c99_vsnprintf(outBuf, size, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
""".}
|
||||||
|
|
||||||
proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "<stdio.h>", nodecl, varargs.}
|
proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "<stdio.h>", nodecl, varargs.}
|
||||||
|
|
||||||
proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
|
proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
|
||||||
|
|
|
||||||
|
|
@ -66,30 +66,20 @@ type
|
||||||
Rope* = ref RopeObj
|
Rope* = ref RopeObj
|
||||||
RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
|
RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
|
||||||
# by nil to safe space
|
# by nil to safe space
|
||||||
left*, right*: Rope
|
left, right: Rope
|
||||||
length*: int
|
L: int # <= 0 if a leaf
|
||||||
data*: string # != nil if a leaf
|
data*: string
|
||||||
|
|
||||||
proc len*(a: Rope): int =
|
proc len*(a: Rope): int =
|
||||||
## the rope's length
|
## the rope's length
|
||||||
if a == nil: result = 0
|
if a == nil: result = 0
|
||||||
else: result = a.length
|
else: result = abs a.L
|
||||||
|
|
||||||
proc newRope(data: string = nil): Rope =
|
proc newRope(data: string = ""): Rope =
|
||||||
new(result)
|
new(result)
|
||||||
if data != nil:
|
result.L = -len(data)
|
||||||
result.length = len(data)
|
|
||||||
result.data = data
|
result.data = data
|
||||||
|
|
||||||
proc newMutableRope*(capacity = 30): Rope =
|
|
||||||
## creates a new rope that supports direct modifications of the rope's
|
|
||||||
## 'data' and 'length' fields.
|
|
||||||
new(result)
|
|
||||||
result.data = newStringOfCap(capacity)
|
|
||||||
|
|
||||||
proc freezeMutableRope*(r: Rope) {.inline.} =
|
|
||||||
r.length = r.data.len
|
|
||||||
|
|
||||||
var
|
var
|
||||||
cache: array[0..2048*2 - 1, Rope] # XXX Global here!
|
cache: array[0..2048*2 - 1, Rope] # XXX Global here!
|
||||||
|
|
||||||
|
|
@ -147,7 +137,7 @@ proc `&`*(a, b: Rope): Rope =
|
||||||
result = a
|
result = a
|
||||||
else:
|
else:
|
||||||
result = newRope()
|
result = newRope()
|
||||||
result.length = a.length + b.length
|
result.L = abs(a.L) + abs(b.L)
|
||||||
result.left = a
|
result.left = a
|
||||||
result.right = b
|
result.right = b
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
|
||||||
template cbos(name, body) {.dirty.} =
|
template cbos(name, body) {.dirty.} =
|
||||||
result.registerCallback "stdlib.system." & astToStr(name),
|
result.registerCallback "stdlib.system." & astToStr(name),
|
||||||
proc (a: VmArgs) =
|
proc (a: VmArgs) =
|
||||||
errorMsg = nil
|
errorMsg = ""
|
||||||
try:
|
try:
|
||||||
body
|
body
|
||||||
except OSError:
|
except OSError:
|
||||||
|
|
@ -159,8 +159,11 @@ proc runNimScript*(cache: IdentCache; scriptName: string;
|
||||||
|
|
||||||
defineSymbol(conf.symbols, "nimscript")
|
defineSymbol(conf.symbols, "nimscript")
|
||||||
defineSymbol(conf.symbols, "nimconfig")
|
defineSymbol(conf.symbols, "nimconfig")
|
||||||
|
var registeredPasses {.global.} = false
|
||||||
|
if not registeredPasses:
|
||||||
registerPass(graph, semPass)
|
registerPass(graph, semPass)
|
||||||
registerPass(graph, evalPass)
|
registerPass(graph, evalPass)
|
||||||
|
registeredPasses = true
|
||||||
|
|
||||||
conf.searchPaths.add(conf.libpath)
|
conf.searchPaths.add(conf.libpath)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ import
|
||||||
procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch,
|
procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||||
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
||||||
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
|
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
|
||||||
semparallel, lowerings, pluginsupport, plugins.active, rod, lineinfos
|
semparallel, lowerings, pluginsupport, plugins/active, rod, lineinfos
|
||||||
|
|
||||||
from modulegraphs import ModuleGraph
|
from modulegraphs import ModuleGraph
|
||||||
|
|
||||||
when defined(nimfix):
|
when defined(nimfix):
|
||||||
import nimfix.prettybase
|
import nimfix/prettybase
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
|
|
@ -119,7 +119,7 @@ proc commonType*(x, y: PType): PType =
|
||||||
elif b.kind == tyStmt: result = b
|
elif b.kind == tyStmt: result = b
|
||||||
elif a.kind == tyTypeDesc:
|
elif a.kind == tyTypeDesc:
|
||||||
# turn any concrete typedesc into the abstract typedesc type
|
# turn any concrete typedesc into the abstract typedesc type
|
||||||
if a.sons == nil: result = a
|
if a.len == 0: result = a
|
||||||
else:
|
else:
|
||||||
result = newType(tyTypeDesc, a.owner)
|
result = newType(tyTypeDesc, a.owner)
|
||||||
rawAddSon(result, newType(tyNone, a.owner))
|
rawAddSon(result, newType(tyNone, a.owner))
|
||||||
|
|
@ -621,7 +621,8 @@ proc testExamples(c: PContext) =
|
||||||
if os.execShellCmd(os.getAppFilename() & " " & backend & " --nimcache:" & nimcache & " -r " & outp) != 0:
|
if os.execShellCmd(os.getAppFilename() & " " & backend & " --nimcache:" & nimcache & " -r " & outp) != 0:
|
||||||
quit "[Examples] failed: see " & outp
|
quit "[Examples] failed: see " & outp
|
||||||
else:
|
else:
|
||||||
removeFile(outp)
|
# keep generated source file `outp` to allow inspection.
|
||||||
|
rawMessage(c.config, hintSuccess, ["runnableExamples: " & outp])
|
||||||
removeFile(outp.changeFileExt(ExeExt))
|
removeFile(outp.changeFileExt(ExeExt))
|
||||||
try:
|
try:
|
||||||
removeDir(nimcache)
|
removeDir(nimcache)
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
continue
|
continue
|
||||||
determineType(c, sym)
|
determineType(c, sym)
|
||||||
initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag)
|
initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag)
|
||||||
if c.currentScope.symbols.counter == counterInitial or syms != nil:
|
if c.currentScope.symbols.counter == counterInitial or syms.len != 0:
|
||||||
matches(c, n, orig, z)
|
matches(c, n, orig, z)
|
||||||
if z.state == csMatch:
|
if z.state == csMatch:
|
||||||
#if sym.name.s == "==" and (n.info ?? "temp3"):
|
#if sym.name.s == "==" and (n.info ?? "temp3"):
|
||||||
|
|
@ -237,7 +237,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
|
||||||
if symx.kind in routineKinds:
|
if symx.kind in routineKinds:
|
||||||
errors.add(CandidateError(sym: symx,
|
errors.add(CandidateError(sym: symx,
|
||||||
unmatchedVarParam: 0, firstMismatch: 0,
|
unmatchedVarParam: 0, firstMismatch: 0,
|
||||||
diagnostics: nil,
|
diagnostics: @[],
|
||||||
enabled: false))
|
enabled: false))
|
||||||
symx = nextOverloadIter(o, c, headSymbol)
|
symx = nextOverloadIter(o, c, headSymbol)
|
||||||
if errors.len == 0:
|
if errors.len == 0:
|
||||||
|
|
@ -455,7 +455,7 @@ proc tryDeref(n: PNode): PNode =
|
||||||
|
|
||||||
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||||
filter: TSymKinds, flags: TExprFlags): PNode =
|
filter: TSymKinds, flags: TExprFlags): PNode =
|
||||||
var errors: CandidateErrors = if efExplain in flags: @[] else: nil
|
var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil
|
||||||
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
|
var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags)
|
||||||
if r.state == csMatch:
|
if r.state == csMatch:
|
||||||
# this may be triggered, when the explain pragma is used
|
# this may be triggered, when the explain pragma is used
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ type
|
||||||
# in standalone ``except`` and ``finally``
|
# in standalone ``except`` and ``finally``
|
||||||
next*: PProcCon # used for stacking procedure contexts
|
next*: PProcCon # used for stacking procedure contexts
|
||||||
wasForwarded*: bool # whether the current proc has a separate header
|
wasForwarded*: bool # whether the current proc has a separate header
|
||||||
|
mappingExists*: bool
|
||||||
mapping*: TIdTable
|
mapping*: TIdTable
|
||||||
|
|
||||||
TMatchedConcept* = object
|
TMatchedConcept* = object
|
||||||
|
|
@ -176,12 +177,14 @@ proc lastOptionEntry*(c: PContext): POptionEntry =
|
||||||
proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
|
proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
|
||||||
|
|
||||||
proc put*(p: PProcCon; key, val: PSym) =
|
proc put*(p: PProcCon; key, val: PSym) =
|
||||||
if p.mapping.data == nil: initIdTable(p.mapping)
|
if not p.mappingExists:
|
||||||
|
initIdTable(p.mapping)
|
||||||
|
p.mappingExists = true
|
||||||
#echo "put into table ", key.info
|
#echo "put into table ", key.info
|
||||||
p.mapping.idTablePut(key, val)
|
p.mapping.idTablePut(key, val)
|
||||||
|
|
||||||
proc get*(p: PProcCon; key: PSym): PSym =
|
proc get*(p: PProcCon; key: PSym): PSym =
|
||||||
if p.mapping.data == nil: return nil
|
if not p.mappingExists: return nil
|
||||||
result = PSym(p.mapping.idTableGet(key))
|
result = PSym(p.mapping.idTableGet(key))
|
||||||
|
|
||||||
proc getGenSym*(c: PContext; s: PSym): PSym =
|
proc getGenSym*(c: PContext; s: PSym): PSym =
|
||||||
|
|
|
||||||
|
|
@ -268,6 +268,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||||
of tyInt64, tyInt, tyUInt..tyUInt64:
|
of tyInt64, tyInt, tyUInt..tyUInt64:
|
||||||
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n, g)
|
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n, g)
|
||||||
else: internalError(g.config, n.info, "constant folding for shr")
|
else: internalError(g.config, n.info, "constant folding for shr")
|
||||||
|
of mAshrI:
|
||||||
|
case skipTypes(n.typ, abstractRange).kind
|
||||||
|
of tyInt8: result = newIntNodeT(ashr(int8(getInt(a)), int8(getInt(b))), n, g)
|
||||||
|
of tyInt16: result = newIntNodeT(ashr(int16(getInt(a)), int16(getInt(b))), n, g)
|
||||||
|
of tyInt32: result = newIntNodeT(ashr(int32(getInt(a)), int32(getInt(b))), n, g)
|
||||||
|
of tyInt64, tyInt:
|
||||||
|
result = newIntNodeT(ashr(getInt(a), getInt(b)), n, g)
|
||||||
|
else: internalError(g.config, n.info, "constant folding for ashr")
|
||||||
of mDivI: result = foldDiv(getInt(a), getInt(b), n, g)
|
of mDivI: result = foldDiv(getInt(a), getInt(b), n, g)
|
||||||
of mModI: result = foldMod(getInt(a), getInt(b), n, g)
|
of mModI: result = foldMod(getInt(a), getInt(b), n, g)
|
||||||
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g)
|
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g)
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,6 @@ proc sameInstantiation(a, b: TInstantiation): bool =
|
||||||
|
|
||||||
proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
|
proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
|
||||||
id: CompilesId): PSym =
|
id: CompilesId): PSym =
|
||||||
if genericSym.procInstCache != nil:
|
|
||||||
for inst in genericSym.procInstCache:
|
for inst in genericSym.procInstCache:
|
||||||
if inst.compilesId == id and sameInstantiation(entry, inst[]):
|
if inst.compilesId == id and sameInstantiation(entry, inst[]):
|
||||||
return inst.sym
|
return inst.sym
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
|
||||||
else:
|
else:
|
||||||
globalError(conf, n.info, "string literal must be of some string type")
|
globalError(conf, n.info, "string literal must be of some string type")
|
||||||
of nkNilLit:
|
of nkNilLit:
|
||||||
if x.kind in NilableTypes:
|
if x.kind in NilableTypes+{tyString, tySequence}:
|
||||||
n.typ = t
|
n.typ = t
|
||||||
else:
|
else:
|
||||||
globalError(conf, n.info, "nil literal must be of some pointer type")
|
globalError(conf, n.info, "nil literal must be of some pointer type")
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string
|
||||||
if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}:
|
if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}:
|
||||||
let assignment = locateFieldInInitExpr(c, r.sym, initExpr)
|
let assignment = locateFieldInInitExpr(c, r.sym, initExpr)
|
||||||
if assignment == nil:
|
if assignment == nil:
|
||||||
if result == nil:
|
if result.len == 0:
|
||||||
result = r.sym.name.s
|
result = r.sym.name.s
|
||||||
else:
|
else:
|
||||||
result.add ", "
|
result.add ", "
|
||||||
|
|
@ -129,7 +129,7 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string
|
||||||
|
|
||||||
proc checkForMissingFields(c: PContext, recList, initExpr: PNode) =
|
proc checkForMissingFields(c: PContext, recList, initExpr: PNode) =
|
||||||
let missing = missingMandatoryFields(c, recList, initExpr)
|
let missing = missingMandatoryFields(c, recList, initExpr)
|
||||||
if missing != nil:
|
if missing.len > 0:
|
||||||
localError(c.config, initExpr.info, "fields not initialized: $1.", [missing])
|
localError(c.config, initExpr.info, "fields not initialized: $1.", [missing])
|
||||||
|
|
||||||
proc semConstructFields(c: PContext, recNode: PNode,
|
proc semConstructFields(c: PContext, recNode: PNode,
|
||||||
|
|
|
||||||
|
|
@ -178,71 +178,6 @@ proc semIf(c: PContext, n: PNode): PNode =
|
||||||
result.kind = nkIfExpr
|
result.kind = nkIfExpr
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
proc semCase(c: PContext, n: PNode): PNode =
|
|
||||||
result = n
|
|
||||||
checkMinSonsLen(n, 2, c.config)
|
|
||||||
openScope(c)
|
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
|
||||||
var chckCovered = false
|
|
||||||
var covered: BiggestInt = 0
|
|
||||||
var typ = commonTypeBegin
|
|
||||||
var hasElse = false
|
|
||||||
let caseTyp = skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc})
|
|
||||||
case caseTyp.kind
|
|
||||||
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
|
|
||||||
chckCovered = true
|
|
||||||
of tyFloat..tyFloat128, tyString, tyError:
|
|
||||||
discard
|
|
||||||
else:
|
|
||||||
localError(c.config, n.info, errSelectorMustBeOfCertainTypes)
|
|
||||||
return
|
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
|
||||||
var x = n.sons[i]
|
|
||||||
when defined(nimsuggest):
|
|
||||||
if c.config.ideCmd == ideSug and exactEquals(c.config.m.trackPos, x.info) and caseTyp.kind == tyEnum:
|
|
||||||
suggestEnum(c, x, caseTyp)
|
|
||||||
case x.kind
|
|
||||||
of nkOfBranch:
|
|
||||||
checkMinSonsLen(x, 2, c.config)
|
|
||||||
semCaseBranch(c, n, x, i, covered)
|
|
||||||
var last = sonsLen(x)-1
|
|
||||||
x.sons[last] = semExprBranchScope(c, x.sons[last])
|
|
||||||
typ = commonType(typ, x.sons[last])
|
|
||||||
of nkElifBranch:
|
|
||||||
chckCovered = false
|
|
||||||
checkSonsLen(x, 2, c.config)
|
|
||||||
openScope(c)
|
|
||||||
x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0]))
|
|
||||||
x.sons[1] = semExprBranch(c, x.sons[1])
|
|
||||||
typ = commonType(typ, x.sons[1])
|
|
||||||
closeScope(c)
|
|
||||||
of nkElse:
|
|
||||||
chckCovered = false
|
|
||||||
checkSonsLen(x, 1, c.config)
|
|
||||||
x.sons[0] = semExprBranchScope(c, x.sons[0])
|
|
||||||
typ = commonType(typ, x.sons[0])
|
|
||||||
hasElse = true
|
|
||||||
else:
|
|
||||||
illFormedAst(x, c.config)
|
|
||||||
if chckCovered:
|
|
||||||
if covered == toCover(c, n.sons[0].typ):
|
|
||||||
hasElse = true
|
|
||||||
else:
|
|
||||||
localError(c.config, n.info, "not all cases are covered")
|
|
||||||
closeScope(c)
|
|
||||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
|
|
||||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
|
|
||||||
# propagate any enforced VoidContext:
|
|
||||||
if typ == c.enforceVoidContext:
|
|
||||||
result.typ = c.enforceVoidContext
|
|
||||||
else:
|
|
||||||
for i in 1..n.len-1:
|
|
||||||
var it = n.sons[i]
|
|
||||||
let j = it.len-1
|
|
||||||
if not endsInNoReturn(it.sons[j]):
|
|
||||||
it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
|
|
||||||
result.typ = typ
|
|
||||||
|
|
||||||
proc semTry(c: PContext, n: PNode): PNode =
|
proc semTry(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
var check = initIntSet()
|
var check = initIntSet()
|
||||||
|
|
@ -683,29 +618,28 @@ proc isTrivalStmtExpr(n: PNode): bool =
|
||||||
return false
|
return false
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc handleForLoopMacro(c: PContext; n: PNode): PNode =
|
proc handleStmtMacro(c: PContext; n, selector: PNode; magicType: string): PNode =
|
||||||
let iterExpr = n[^2]
|
if selector.kind in nkCallKinds:
|
||||||
if iterExpr.kind in nkCallKinds:
|
|
||||||
# we transform
|
# we transform
|
||||||
# n := for a, b, c in m(x, y, z): Y
|
# n := for a, b, c in m(x, y, z): Y
|
||||||
# to
|
# to
|
||||||
# m(n)
|
# m(n)
|
||||||
let forLoopStmt = magicsys.getCompilerProc(c.graph, "ForLoopStmt")
|
let maType = magicsys.getCompilerProc(c.graph, magicType)
|
||||||
if forLoopStmt == nil: return
|
if maType == nil: return
|
||||||
|
|
||||||
let headSymbol = iterExpr[0]
|
let headSymbol = selector[0]
|
||||||
var o: TOverloadIter
|
var o: TOverloadIter
|
||||||
var match: PSym = nil
|
var match: PSym = nil
|
||||||
var symx = initOverloadIter(o, c, headSymbol)
|
var symx = initOverloadIter(o, c, headSymbol)
|
||||||
while symx != nil:
|
while symx != nil:
|
||||||
if symx.kind in {skTemplate, skMacro}:
|
if symx.kind in {skTemplate, skMacro}:
|
||||||
if symx.typ.len == 2 and symx.typ[1] == forLoopStmt.typ:
|
if symx.typ.len == 2 and symx.typ[1] == maType.typ:
|
||||||
if match == nil:
|
if match == nil:
|
||||||
match = symx
|
match = symx
|
||||||
else:
|
else:
|
||||||
localError(c.config, n.info, errAmbiguousCallXYZ % [
|
localError(c.config, n.info, errAmbiguousCallXYZ % [
|
||||||
getProcHeader(c.config, match),
|
getProcHeader(c.config, match),
|
||||||
getProcHeader(c.config, symx), $iterExpr])
|
getProcHeader(c.config, symx), $selector])
|
||||||
symx = nextOverloadIter(o, c, headSymbol)
|
symx = nextOverloadIter(o, c, headSymbol)
|
||||||
|
|
||||||
if match == nil: return
|
if match == nil: return
|
||||||
|
|
@ -717,9 +651,42 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode =
|
||||||
of skTemplate: result = semTemplateExpr(c, callExpr, match, {})
|
of skTemplate: result = semTemplateExpr(c, callExpr, match, {})
|
||||||
else: result = nil
|
else: result = nil
|
||||||
|
|
||||||
|
proc handleForLoopMacro(c: PContext; n: PNode): PNode =
|
||||||
|
result = handleStmtMacro(c, n, n[^2], "ForLoopStmt")
|
||||||
|
|
||||||
|
proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
|
||||||
|
# n[0] has been sem'checked and has a type. We use this to resolve
|
||||||
|
# 'match(n[0])' but then we pass 'n' to the 'match' macro. This seems to
|
||||||
|
# be the best solution.
|
||||||
|
var toResolve = newNodeI(nkCall, n.info)
|
||||||
|
toResolve.add newIdentNode(getIdent(c.cache, "match"), n.info)
|
||||||
|
toResolve.add n[0]
|
||||||
|
|
||||||
|
var errors: CandidateErrors
|
||||||
|
var r = resolveOverloads(c, toResolve, toResolve, {skTemplate, skMacro}, {},
|
||||||
|
errors, false)
|
||||||
|
if r.state == csMatch:
|
||||||
|
var match = r.calleeSym
|
||||||
|
markUsed(c.config, n[0].info, match, c.graph.usageSym)
|
||||||
|
styleCheckUse(n[0].info, match)
|
||||||
|
|
||||||
|
# but pass 'n' to the 'match' macro, not 'n[0]':
|
||||||
|
r.call.sons[1] = n
|
||||||
|
let toExpand = semResolvedCall(c, r, r.call, {})
|
||||||
|
case match.kind
|
||||||
|
of skMacro: result = semMacroExpr(c, toExpand, toExpand, match, {})
|
||||||
|
of skTemplate: result = semTemplateExpr(c, toExpand, match, {})
|
||||||
|
else: result = nil
|
||||||
|
# this would be the perfectly consistent solution with 'for loop macros',
|
||||||
|
# but it kinda sucks for pattern matching as the matcher is not attached to
|
||||||
|
# a type then:
|
||||||
|
when false:
|
||||||
|
result = handleStmtMacro(c, n, n[0], "CaseStmt")
|
||||||
|
|
||||||
proc semFor(c: PContext, n: PNode): PNode =
|
proc semFor(c: PContext, n: PNode): PNode =
|
||||||
checkMinSonsLen(n, 3, c.config)
|
checkMinSonsLen(n, 3, c.config)
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
|
if forLoopMacros in c.features:
|
||||||
result = handleForLoopMacro(c, n)
|
result = handleForLoopMacro(c, n)
|
||||||
if result != nil: return result
|
if result != nil: return result
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -757,6 +724,75 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||||
result.typ = c.enforceVoidContext
|
result.typ = c.enforceVoidContext
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
|
proc semCase(c: PContext, n: PNode): PNode =
|
||||||
|
result = n
|
||||||
|
checkMinSonsLen(n, 2, c.config)
|
||||||
|
openScope(c)
|
||||||
|
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||||
|
var chckCovered = false
|
||||||
|
var covered: BiggestInt = 0
|
||||||
|
var typ = commonTypeBegin
|
||||||
|
var hasElse = false
|
||||||
|
let caseTyp = skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc})
|
||||||
|
case caseTyp.kind
|
||||||
|
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
|
||||||
|
chckCovered = true
|
||||||
|
of tyFloat..tyFloat128, tyString, tyError:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
if caseStmtMacros in c.features:
|
||||||
|
result = handleCaseStmtMacro(c, n)
|
||||||
|
if result != nil: return result
|
||||||
|
|
||||||
|
localError(c.config, n.info, errSelectorMustBeOfCertainTypes)
|
||||||
|
return
|
||||||
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
|
var x = n.sons[i]
|
||||||
|
when defined(nimsuggest):
|
||||||
|
if c.config.ideCmd == ideSug and exactEquals(c.config.m.trackPos, x.info) and caseTyp.kind == tyEnum:
|
||||||
|
suggestEnum(c, x, caseTyp)
|
||||||
|
case x.kind
|
||||||
|
of nkOfBranch:
|
||||||
|
checkMinSonsLen(x, 2, c.config)
|
||||||
|
semCaseBranch(c, n, x, i, covered)
|
||||||
|
var last = sonsLen(x)-1
|
||||||
|
x.sons[last] = semExprBranchScope(c, x.sons[last])
|
||||||
|
typ = commonType(typ, x.sons[last])
|
||||||
|
of nkElifBranch:
|
||||||
|
chckCovered = false
|
||||||
|
checkSonsLen(x, 2, c.config)
|
||||||
|
openScope(c)
|
||||||
|
x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0]))
|
||||||
|
x.sons[1] = semExprBranch(c, x.sons[1])
|
||||||
|
typ = commonType(typ, x.sons[1])
|
||||||
|
closeScope(c)
|
||||||
|
of nkElse:
|
||||||
|
chckCovered = false
|
||||||
|
checkSonsLen(x, 1, c.config)
|
||||||
|
x.sons[0] = semExprBranchScope(c, x.sons[0])
|
||||||
|
typ = commonType(typ, x.sons[0])
|
||||||
|
hasElse = true
|
||||||
|
else:
|
||||||
|
illFormedAst(x, c.config)
|
||||||
|
if chckCovered:
|
||||||
|
if covered == toCover(c, n.sons[0].typ):
|
||||||
|
hasElse = true
|
||||||
|
else:
|
||||||
|
localError(c.config, n.info, "not all cases are covered")
|
||||||
|
closeScope(c)
|
||||||
|
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse:
|
||||||
|
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
|
||||||
|
# propagate any enforced VoidContext:
|
||||||
|
if typ == c.enforceVoidContext:
|
||||||
|
result.typ = c.enforceVoidContext
|
||||||
|
else:
|
||||||
|
for i in 1..n.len-1:
|
||||||
|
var it = n.sons[i]
|
||||||
|
let j = it.len-1
|
||||||
|
if not endsInNoReturn(it.sons[j]):
|
||||||
|
it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info)
|
||||||
|
result.typ = typ
|
||||||
|
|
||||||
proc semRaise(c: PContext, n: PNode): PNode =
|
proc semRaise(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1, c.config)
|
checkSonsLen(n, 1, c.config)
|
||||||
|
|
@ -970,6 +1006,9 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
var body = s.typ.lastSon
|
var body = s.typ.lastSon
|
||||||
if body.kind == tyObject:
|
if body.kind == tyObject:
|
||||||
# erases all declared fields
|
# erases all declared fields
|
||||||
|
when defined(nimNoNilSeqs):
|
||||||
|
body.n.sons = @[]
|
||||||
|
else:
|
||||||
body.n.sons = nil
|
body.n.sons = nil
|
||||||
|
|
||||||
popOwner(c)
|
popOwner(c)
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,8 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||||
if region.skipTypes({tyGenericInst, tyAlias, tySink}).kind notin {
|
if region.skipTypes({tyGenericInst, tyAlias, tySink}).kind notin {
|
||||||
tyError, tyObject}:
|
tyError, tyObject}:
|
||||||
message c.config, n[i].info, errGenerated, "region needs to be an object type"
|
message c.config, n[i].info, errGenerated, "region needs to be an object type"
|
||||||
|
else:
|
||||||
|
message(c.config, n.info, warnDeprecated, "region for pointer types")
|
||||||
addSonSkipIntLit(result, region)
|
addSonSkipIntLit(result, region)
|
||||||
addSonSkipIntLit(result, t)
|
addSonSkipIntLit(result, t)
|
||||||
if tfPartial in result.flags:
|
if tfPartial in result.flags:
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ proc searchInstTypes*(key: PType): PType =
|
||||||
if not (genericTyp.kind == tyGenericBody and
|
if not (genericTyp.kind == tyGenericBody and
|
||||||
key.sons[0] == genericTyp and genericTyp.sym != nil): return
|
key.sons[0] == genericTyp and genericTyp.sym != nil): return
|
||||||
|
|
||||||
if genericTyp.sym.typeInstCache == nil:
|
when not defined(nimNoNilSeqs):
|
||||||
return
|
if genericTyp.sym.typeInstCache == nil: return
|
||||||
|
|
||||||
for inst in genericTyp.sym.typeInstCache:
|
for inst in genericTyp.sym.typeInstCache:
|
||||||
if inst.id == key.id: return inst
|
if inst.id == key.id: return inst
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||||
c.calleeScope = 1
|
c.calleeScope = 1
|
||||||
else:
|
else:
|
||||||
c.calleeScope = calleeScope
|
c.calleeScope = calleeScope
|
||||||
c.diagnostics = if diagnosticsEnabled: @[] else: nil
|
c.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil
|
||||||
c.diagnosticsEnabled = diagnosticsEnabled
|
c.diagnosticsEnabled = diagnosticsEnabled
|
||||||
c.magic = c.calleeSym.magic
|
c.magic = c.calleeSym.magic
|
||||||
initIdTable(c.bindings)
|
initIdTable(c.bindings)
|
||||||
|
|
@ -535,6 +535,12 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
proc allowsNil(f: PType): TTypeRelation {.inline.} =
|
proc allowsNil(f: PType): TTypeRelation {.inline.} =
|
||||||
result = if tfNotNil notin f.flags: isSubtype else: isNone
|
result = if tfNotNil notin f.flags: isSubtype else: isNone
|
||||||
|
|
||||||
|
proc allowsNilDeprecated(c: TCandidate, f: PType): TTypeRelation =
|
||||||
|
if optNilSeqs in c.c.config.options:
|
||||||
|
result = allowsNil(f)
|
||||||
|
else:
|
||||||
|
result = isNone
|
||||||
|
|
||||||
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
|
||||||
result = f.kind != a.kind and (f.kind in {tyVar, tyLent} or a.kind in {tyVar, tyLent})
|
result = f.kind != a.kind and (f.kind in {tyVar, tyLent} or a.kind in {tyVar, tyLent})
|
||||||
|
|
||||||
|
|
@ -741,7 +747,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
|
||||||
diagnostics = @[]
|
diagnostics = @[]
|
||||||
flags = {efExplain}
|
flags = {efExplain}
|
||||||
m.c.config.writelnHook = proc (s: string) =
|
m.c.config.writelnHook = proc (s: string) =
|
||||||
if errorPrefix == nil: errorPrefix = typeClass.sym.name.s & ":"
|
if errorPrefix.len == 0: errorPrefix = typeClass.sym.name.s & ":"
|
||||||
let msg = s.replace("Error:", errorPrefix)
|
let msg = s.replace("Error:", errorPrefix)
|
||||||
if oldWriteHook != nil: oldWriteHook msg
|
if oldWriteHook != nil: oldWriteHook msg
|
||||||
diagnostics.add msg
|
diagnostics.add msg
|
||||||
|
|
@ -858,6 +864,10 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
|
||||||
if lhs[2].kind == nkIntLit:
|
if lhs[2].kind == nkIntLit:
|
||||||
return inferStaticParam(c, lhs[1], rhs shl lhs[2].intVal)
|
return inferStaticParam(c, lhs[1], rhs shl lhs[2].intVal)
|
||||||
|
|
||||||
|
of mAshrI:
|
||||||
|
if lhs[2].kind == nkIntLit:
|
||||||
|
return inferStaticParam(c, lhs[1], ashr(rhs, lhs[2].intVal))
|
||||||
|
|
||||||
of mUnaryMinusI:
|
of mUnaryMinusI:
|
||||||
return inferStaticParam(c, lhs[1], -rhs)
|
return inferStaticParam(c, lhs[1], -rhs)
|
||||||
|
|
||||||
|
|
@ -1249,7 +1259,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
||||||
result = isNone
|
result = isNone
|
||||||
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||||
result = isNilConversion
|
result = isNilConversion
|
||||||
of tyNil: result = f.allowsNil
|
of tyNil: result = allowsNilDeprecated(c, f)
|
||||||
else: discard
|
else: discard
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
if isOrdinalType(a):
|
if isOrdinalType(a):
|
||||||
|
|
@ -1334,7 +1344,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
||||||
result = isNilConversion
|
result = isNilConversion
|
||||||
else:
|
else:
|
||||||
result = isEqual
|
result = isEqual
|
||||||
of tyNil: result = f.allowsNil
|
of tyNil: result = allowsNilDeprecated(c, f)
|
||||||
else: discard
|
else: discard
|
||||||
of tyCString:
|
of tyCString:
|
||||||
# conversion from string to cstring is automatic:
|
# conversion from string to cstring is automatic:
|
||||||
|
|
@ -1608,7 +1618,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
|
||||||
if f.sonsLen == 0:
|
if f.sonsLen == 0:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
internalAssert c.c.graph.config, a.sons != nil and a.sons.len > 0
|
internalAssert c.c.graph.config, a.len > 0
|
||||||
c.typedescMatched = true
|
c.typedescMatched = true
|
||||||
var aa = a
|
var aa = a
|
||||||
while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
|
while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
|
||||||
|
|
@ -1806,6 +1816,10 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
let srca = typeRel(m, src, a)
|
let srca = typeRel(m, src, a)
|
||||||
if srca notin {isEqual, isGeneric, isSubtype}: continue
|
if srca notin {isEqual, isGeneric, isSubtype}: continue
|
||||||
|
|
||||||
|
let constraint = c.converters[i].typ.n[1].sym.constraint
|
||||||
|
if not constraint.isNil and not matchNodeKinds(constraint, arg):
|
||||||
|
continue
|
||||||
|
|
||||||
let destIsGeneric = containsGenericType(dest)
|
let destIsGeneric = containsGenericType(dest)
|
||||||
if destIsGeneric:
|
if destIsGeneric:
|
||||||
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
||||||
|
|
|
||||||
|
|
@ -369,6 +369,8 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
||||||
result = PTransNode(n.sons[0])
|
result = PTransNode(n.sons[0])
|
||||||
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||||
PNode(result).typ = n.typ
|
PNode(result).typ = n.typ
|
||||||
|
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
|
||||||
|
PNode(result).typ = toVar(PNode(result).typ)
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
var m = n.sons[0].sons[1]
|
var m = n.sons[0].sons[1]
|
||||||
if m.kind == a or m.kind == b:
|
if m.kind == a or m.kind == b:
|
||||||
|
|
@ -377,6 +379,8 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
||||||
result = PTransNode(n.sons[0])
|
result = PTransNode(n.sons[0])
|
||||||
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||||
PNode(result).typ = n.typ
|
PNode(result).typ = n.typ
|
||||||
|
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
|
||||||
|
PNode(result).typ = toVar(PNode(result).typ)
|
||||||
else:
|
else:
|
||||||
if n.sons[0].kind == a or n.sons[0].kind == b:
|
if n.sons[0].kind == a or n.sons[0].kind == b:
|
||||||
# addr ( deref ( x )) --> x
|
# addr ( deref ( x )) --> x
|
||||||
|
|
@ -539,11 +543,8 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
||||||
call.sons[0].typ.callConv == ccClosure:
|
call.sons[0].typ.callConv == ccClosure:
|
||||||
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
||||||
if not c.tooEarly:
|
|
||||||
n.sons[length-2] = transform(c, n.sons[length-2]).PNode
|
n.sons[length-2] = transform(c, n.sons[length-2]).PNode
|
||||||
result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode
|
result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode
|
||||||
else:
|
|
||||||
result[1] = newNode(nkEmpty).PTransNode
|
|
||||||
discard c.breakSyms.pop
|
discard c.breakSyms.pop
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -430,7 +430,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
||||||
elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil:
|
elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil:
|
||||||
result = t.sym.name.s
|
result = t.sym.name.s
|
||||||
if t.kind == tyGenericParam and t.sons != nil and t.sonsLen > 0:
|
if t.kind == tyGenericParam and t.sonsLen > 0:
|
||||||
result.add ": "
|
result.add ": "
|
||||||
var first = true
|
var first = true
|
||||||
for son in t.sons:
|
for son in t.sons:
|
||||||
|
|
@ -1202,7 +1202,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
tyNone, tyForward, tyFromExpr:
|
tyNone, tyForward, tyFromExpr:
|
||||||
result = t
|
result = t
|
||||||
of tyNil:
|
of tyNil:
|
||||||
if kind != skConst: result = t
|
if kind != skConst and kind != skParam: result = t
|
||||||
of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer:
|
of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer:
|
||||||
result = nil
|
result = nil
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
|
|
@ -1539,7 +1539,6 @@ proc isCompileTimeOnly*(t: PType): bool {.inline.} =
|
||||||
|
|
||||||
proc containsCompileTimeOnly*(t: PType): bool =
|
proc containsCompileTimeOnly*(t: PType): bool =
|
||||||
if isCompileTimeOnly(t): return true
|
if isCompileTimeOnly(t): return true
|
||||||
if t.sons != nil:
|
|
||||||
for i in 0 ..< t.sonsLen:
|
for i in 0 ..< t.sonsLen:
|
||||||
if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
|
if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
|
|
@ -752,6 +752,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcShlInt:
|
of opcShlInt:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
regs[ra].intVal = regs[rb].intVal shl regs[rc].intVal
|
regs[ra].intVal = regs[rb].intVal shl regs[rc].intVal
|
||||||
|
of opcAshrInt:
|
||||||
|
decodeBC(rkInt)
|
||||||
|
regs[ra].intVal = ashr(regs[rb].intVal, regs[rc].intVal)
|
||||||
of opcBitandInt:
|
of opcBitandInt:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
regs[ra].intVal = regs[rb].intVal and regs[rc].intVal
|
regs[ra].intVal = regs[rb].intVal and regs[rc].intVal
|
||||||
|
|
@ -1422,24 +1425,23 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
ensureKind(rkNode)
|
ensureKind(rkNode)
|
||||||
if c.callsite != nil: regs[ra].node = c.callsite
|
if c.callsite != nil: regs[ra].node = c.callsite
|
||||||
else: stackTrace(c, tos, pc, errFieldXNotFound & "callsite")
|
else: stackTrace(c, tos, pc, errFieldXNotFound & "callsite")
|
||||||
of opcNGetFile:
|
of opcNGetLineInfo:
|
||||||
decodeB(rkNode)
|
decodeBImm(rkNode)
|
||||||
let n = regs[rb].node
|
let n = regs[rb].node
|
||||||
|
case imm
|
||||||
|
of 0: # getFile
|
||||||
regs[ra].node = newStrNode(nkStrLit, toFullPath(c.config, n.info))
|
regs[ra].node = newStrNode(nkStrLit, toFullPath(c.config, n.info))
|
||||||
regs[ra].node.info = n.info
|
of 1: # getLine
|
||||||
regs[ra].node.typ = n.typ
|
|
||||||
of opcNGetLine:
|
|
||||||
decodeB(rkNode)
|
|
||||||
let n = regs[rb].node
|
|
||||||
regs[ra].node = newIntNode(nkIntLit, n.info.line.int)
|
regs[ra].node = newIntNode(nkIntLit, n.info.line.int)
|
||||||
regs[ra].node.info = n.info
|
of 2: # getColumn
|
||||||
regs[ra].node.typ = n.typ
|
|
||||||
of opcNGetColumn:
|
|
||||||
decodeB(rkNode)
|
|
||||||
let n = regs[rb].node
|
|
||||||
regs[ra].node = newIntNode(nkIntLit, n.info.col)
|
regs[ra].node = newIntNode(nkIntLit, n.info.col)
|
||||||
|
else:
|
||||||
|
internalAssert c.config, false
|
||||||
regs[ra].node.info = n.info
|
regs[ra].node.info = n.info
|
||||||
regs[ra].node.typ = n.typ
|
regs[ra].node.typ = n.typ
|
||||||
|
of opcNSetLineInfo:
|
||||||
|
decodeB(rkNode)
|
||||||
|
regs[ra].node.info = regs[rb].node.info
|
||||||
of opcEqIdent:
|
of opcEqIdent:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
# aliases for shorter and easier to understand code below
|
# aliases for shorter and easier to understand code below
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ const
|
||||||
byteExcess* = 128 # we use excess-K for immediates
|
byteExcess* = 128 # we use excess-K for immediates
|
||||||
wordExcess* = 32768
|
wordExcess* = 32768
|
||||||
|
|
||||||
MaxLoopIterations* = 1_000_000_000 # max iterations of all loops
|
MaxLoopIterations* = 3_000_000 # max iterations of all loops
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -57,7 +57,8 @@ type
|
||||||
opcLenStr,
|
opcLenStr,
|
||||||
|
|
||||||
opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt,
|
opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt,
|
||||||
opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, opcShrInt, opcShlInt,
|
opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat,
|
||||||
|
opcShrInt, opcShlInt, opcAshrInt,
|
||||||
opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
|
opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
|
||||||
opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
|
opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
|
||||||
opcLeFloat, opcLtFloat, opcLeu, opcLtu,
|
opcLeFloat, opcLtFloat, opcLeu, opcLtu,
|
||||||
|
|
@ -102,7 +103,7 @@ type
|
||||||
opcNError,
|
opcNError,
|
||||||
opcNWarning,
|
opcNWarning,
|
||||||
opcNHint,
|
opcNHint,
|
||||||
opcNGetLine, opcNGetColumn, opcNGetFile,
|
opcNGetLineInfo, opcNSetLineInfo,
|
||||||
opcEqIdent,
|
opcEqIdent,
|
||||||
opcStrToIdent,
|
opcStrToIdent,
|
||||||
opcGetImpl,
|
opcGetImpl,
|
||||||
|
|
|
||||||
|
|
@ -939,6 +939,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||||
c.freeTemp(tmp2)
|
c.freeTemp(tmp2)
|
||||||
|
|
||||||
of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt)
|
of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt)
|
||||||
|
of mAshrI: genBinaryABCnarrow(c, n, dest, opcAshrInt)
|
||||||
of mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
|
of mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
|
||||||
of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
|
of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
|
||||||
of mBitxorI: genBinaryABCnarrowU(c, n, dest, opcBitxorInt)
|
of mBitxorI: genBinaryABCnarrowU(c, n, dest, opcBitxorInt)
|
||||||
|
|
@ -1181,14 +1182,14 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||||
of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType)
|
of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType)
|
||||||
of mNLineInfo:
|
of mNLineInfo:
|
||||||
case n[0].sym.name.s
|
case n[0].sym.name.s
|
||||||
of "getFile":
|
of "getFile": genUnaryABI(c, n, dest, opcNGetLineInfo, 0)
|
||||||
genUnaryABC(c, n, dest, opcNGetFile)
|
of "getLine": genUnaryABI(c, n, dest, opcNGetLineInfo, 1)
|
||||||
of "getLine":
|
of "getColumn": genUnaryABI(c, n, dest, opcNGetLineInfo, 2)
|
||||||
genUnaryABC(c, n, dest, opcNGetLine)
|
of "copyLineInfo":
|
||||||
of "getColumn":
|
internalAssert c.config, n.len == 3
|
||||||
genUnaryABC(c, n, dest, opcNGetColumn)
|
unused(c, n, dest)
|
||||||
else:
|
genBinaryStmt(c, n, opcNSetLineInfo)
|
||||||
internalAssert c.config, false
|
else: internalAssert c.config, false
|
||||||
of mNHint:
|
of mNHint:
|
||||||
unused(c, n, dest)
|
unused(c, n, dest)
|
||||||
genUnaryStmt(c, n, opcNHint)
|
genUnaryStmt(c, n, opcNHint)
|
||||||
|
|
|
||||||
|
|
@ -82,19 +82,21 @@ path="$lib/pure"
|
||||||
clang.cpp.options.linker = "-ldl"
|
clang.cpp.options.linker = "-ldl"
|
||||||
tcc.options.linker = "-ldl"
|
tcc.options.linker = "-ldl"
|
||||||
@end
|
@end
|
||||||
@if bsd or haiku:
|
@if bsd:
|
||||||
# BSD got posix_spawn only recently, so we deactivate it for osproc:
|
# BSD got posix_spawn only recently, so we deactivate it for osproc:
|
||||||
define:useFork
|
define:useFork
|
||||||
# at least NetBSD has problems with thread local storage:
|
# at least NetBSD has problems with thread local storage:
|
||||||
tlsEmulation:on
|
tlsEmulation:on
|
||||||
@end
|
@end
|
||||||
@if haiku:
|
@if haiku:
|
||||||
# -fopenmp
|
# Haiku currently have problems with TLS
|
||||||
gcc.options.linker = "-lroot -lnetwork"
|
# https://dev.haiku-os.org/ticket/14342
|
||||||
gcc.cpp.options.linker = "-lroot -lnetwork"
|
tlsEmulation:on
|
||||||
clang.options.linker = "-lroot -lnetwork"
|
gcc.options.linker = "-Wl,--as-needed -lnetwork"
|
||||||
clang.cpp.options.linker = "-lroot -lnetwork"
|
gcc.cpp.options.linker = "-Wl,--as-needed -lnetwork"
|
||||||
tcc.options.linker = "-lroot -lnetwork"
|
clang.options.linker = "-Wl,--as-needed -lnetwork"
|
||||||
|
clang.cpp.options.linker = "-Wl,--as-needed -lnetwork"
|
||||||
|
tcc.options.linker = "-Wl,--as-needed -lnetwork"
|
||||||
@end
|
@end
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
@ -253,9 +255,14 @@ vcc.cpp.options.size = "/O1"
|
||||||
tcc.options.always = "-w"
|
tcc.options.always = "-w"
|
||||||
|
|
||||||
# Configuration for the Genode toolchain
|
# Configuration for the Genode toolchain
|
||||||
amd64.genode.gcc.cpp.exe = "genode-x86-g++"
|
@if genode:
|
||||||
amd64.genode.gcc.exe = "genode-x86-gcc"
|
gcc.path = "/usr/local/genode-gcc/bin"
|
||||||
amd64.genode.gcc.path = "/usr/local/genode-gcc/bin"
|
gcc.cpp.options.always = "-D__GENODE__ -fno-stack-protector"
|
||||||
arm.genode.gcc.cpp.exe = "genode-arm-g++"
|
@if i386 or amd64:
|
||||||
arm.genode.gcc.exe = "genode-arm-gcc"
|
gcc.exe = "genode-x86-gcc"
|
||||||
arm.genode.gcc.path = "/usr/local/genode-gcc/bin"
|
gcc.cpp.exe = "genode-x86-g++"
|
||||||
|
@elif arm:
|
||||||
|
gcc.exe = "genode-arm-gcc"
|
||||||
|
gcc.cpp.exe = "genode-arm-g++"
|
||||||
|
@end
|
||||||
|
@end
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ Advanced options:
|
||||||
--oldNewlines:on|off turn on|off the old behaviour of "\n"
|
--oldNewlines:on|off turn on|off the old behaviour of "\n"
|
||||||
--laxStrings:on|off when turned on, accessing the zero terminator in
|
--laxStrings:on|off when turned on, accessing the zero terminator in
|
||||||
strings is allowed; only for backwards compatibility
|
strings is allowed; only for backwards compatibility
|
||||||
|
--nilseqs:on|off allow 'nil' for strings/seqs for
|
||||||
|
backwards compatibility
|
||||||
--skipCfg do not read the general configuration file
|
--skipCfg do not read the general configuration file
|
||||||
--skipUserCfg do not read the user's configuration file
|
--skipUserCfg do not read the user's configuration file
|
||||||
--skipParentCfg do not read the parent dirs' configuration files
|
--skipParentCfg do not read the parent dirs' configuration files
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ The JavaScript target
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
Nim can also generate `JavaScript`:idx: code through the ``js`` command.
|
Nim can also generate `JavaScript`:idx: code through the ``js`` command.
|
||||||
However, the JavaScript code generator is experimental!
|
|
||||||
|
|
||||||
Nim targets JavaScript 1.5 which is supported by any widely used browser.
|
Nim targets JavaScript 1.5 which is supported by any widely used browser.
|
||||||
Since JavaScript does not have a portable means to include another module,
|
Since JavaScript does not have a portable means to include another module,
|
||||||
|
|
@ -77,7 +76,7 @@ available. This includes:
|
||||||
* manual memory management (``alloc``, etc.)
|
* manual memory management (``alloc``, etc.)
|
||||||
* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
|
* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
|
||||||
* file management
|
* file management
|
||||||
* most modules of the Standard library
|
* most modules of the standard library
|
||||||
* proper 64 bit integer arithmetic
|
* proper 64 bit integer arithmetic
|
||||||
* unsigned integer arithmetic
|
* unsigned integer arithmetic
|
||||||
|
|
||||||
|
|
@ -87,9 +86,8 @@ However, the modules `strutils <strutils.html>`_, `math <math.html>`_, and
|
||||||
|
|
||||||
To compile a Nim module into a ``.js`` file use the ``js`` command; the
|
To compile a Nim module into a ``.js`` file use the ``js`` command; the
|
||||||
default is a ``.js`` file that is supposed to be referenced in an ``.html``
|
default is a ``.js`` file that is supposed to be referenced in an ``.html``
|
||||||
file. However, you can also run the code with `nodejs`:idx:, a `software
|
file. However, you can also run the code with `nodejs`:idx:
|
||||||
platform for easily building fast, scalable network applications
|
(`<http://nodejs.org>`_)::
|
||||||
<http://nodejs.org>`_::
|
|
||||||
|
|
||||||
nim js -d:nodejs -r examples/hallo.nim
|
nim js -d:nodejs -r examples/hallo.nim
|
||||||
|
|
||||||
|
|
@ -330,8 +328,9 @@ Nimcache naming logic
|
||||||
|
|
||||||
The `nimcache`:idx: directory is generated during compilation and will hold
|
The `nimcache`:idx: directory is generated during compilation and will hold
|
||||||
either temporary or final files depending on your backend target. The default
|
either temporary or final files depending on your backend target. The default
|
||||||
name for the directory is ``nimcache`` but you can use the ``--nimcache``
|
name for the directory depends on the used backend and on your OS but you can
|
||||||
`compiler switch <nimc.html#command-line-switches>`_ to change it.
|
use the ``--nimcache`` `compiler switch <nimc.html#command-line-switches>`_ to
|
||||||
|
change it.
|
||||||
|
|
||||||
Nimcache and C like targets
|
Nimcache and C like targets
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
||||||
|
|
@ -97,24 +97,9 @@ Partial Output::
|
||||||
proc helloWorld(times: int) {.raises: [], tags: [].}
|
proc helloWorld(times: int) {.raises: [], tags: [].}
|
||||||
...
|
...
|
||||||
|
|
||||||
The full output can be seen here: `docgen_sample2.html <docgen_sample2.html>`_.
|
The full output can be seen here: `docgen_sample.html <docgen_sample.html>`_.
|
||||||
|
It runs after semantic checking, and includes pragmas attached implicitly by the
|
||||||
The older version of the ``doc`` command, now renamed ``doc0`` runs before
|
compiler.
|
||||||
semantic checking which means it lacks some of the things ``doc`` will output.
|
|
||||||
|
|
||||||
The ``doc0`` command::
|
|
||||||
nim doc0 sample
|
|
||||||
|
|
||||||
Partial Output::
|
|
||||||
...
|
|
||||||
proc helloWorld*(times: int)
|
|
||||||
...
|
|
||||||
|
|
||||||
Output can be viewed in full here: `docgen_sample.html <docgen_sample.html>`_.
|
|
||||||
As you can see, the tool has extracted less information than what the ``doc``
|
|
||||||
command provides, such as pragmas attached implicitly by the compiler. This type
|
|
||||||
of information is not available from looking at the AST (Abstract Syntax Tree)
|
|
||||||
prior to semantic checking, which is why ``doc0`` doesn't show it.
|
|
||||||
|
|
||||||
|
|
||||||
JSON
|
JSON
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
* `Exception <system.html#Exception>`_
|
|
||||||
* `AccessViolationError <system.html#AccessViolationError>`_
|
|
||||||
* `ArithmeticError <system.html#ArithmeticError>`_
|
|
||||||
* `DivByZeroError <system.html#DivByZeroError>`_
|
|
||||||
* `OverflowError <system.html#OverflowError>`_
|
|
||||||
* `AssertionError <system.html#AssertionError>`_
|
|
||||||
* `DeadThreadError <system.html#DeadThreadError>`_
|
|
||||||
* `FloatingPointError <system.html#FloatingPointError>`_
|
|
||||||
* `FloatDivByZeroError <system.html#FloatDivByZeroError>`_
|
|
||||||
* `FloatInexactError <system.html#FloatInexactError>`_
|
|
||||||
* `FloatInvalidOpError <system.html#FloatInvalidOpError>`_
|
|
||||||
* `FloatOverflowError <system.html#FloatOverflowError>`_
|
|
||||||
* `FloatUnderflowError <system.html#FloatUnderflowError>`_
|
|
||||||
* `FieldError <system.html#FieldError>`_
|
|
||||||
* `IndexError <system.html#IndexError>`_
|
|
||||||
* `ObjectAssignmentError <system.html#ObjectAssignmentError>`_
|
|
||||||
* `ObjectConversionError <system.html#ObjectConversionError>`_
|
|
||||||
* `ValueError <system.html#ValueError>`_
|
|
||||||
* `KeyError <system.html#KeyError>`_
|
|
||||||
* `ReraiseError <system.html#ReraiseError>`_
|
|
||||||
* `RangeError <system.html#RangeError>`_
|
|
||||||
* `OutOfMemoryError <system.html#OutOfMemoryError>`_
|
|
||||||
* `ResourceExhaustedError <system.html#ResourceExhaustedError>`_
|
|
||||||
* `StackOverflowError <system.html#StackOverflowError>`_
|
|
||||||
* `SystemError <system.html#SystemError>`_
|
|
||||||
* `IOError <system.html#IOError>`_
|
|
||||||
* `OSError <system.html#OSError>`_
|
|
||||||
* `LibraryError <system.html#LibraryError>`_
|
|
||||||
144
doc/manual.rst
144
doc/manual.rst
|
|
@ -769,8 +769,8 @@ Pre-defined floating point types
|
||||||
The following floating point types are pre-defined:
|
The following floating point types are pre-defined:
|
||||||
|
|
||||||
``float``
|
``float``
|
||||||
the generic floating point type; its size is platform dependent
|
the generic floating point type; its size used to be platform dependent,
|
||||||
(the compiler chooses the processor's fastest floating point type).
|
but now it is always mapped to ``float64``.
|
||||||
This type should be used in general.
|
This type should be used in general.
|
||||||
|
|
||||||
floatXX
|
floatXX
|
||||||
|
|
@ -1507,68 +1507,6 @@ non nilable pointers. The details of this analysis are still to be specified
|
||||||
here.
|
here.
|
||||||
|
|
||||||
|
|
||||||
Memory regions
|
|
||||||
--------------
|
|
||||||
|
|
||||||
The types ``ref`` and ``ptr`` can get an optional ``region`` annotation.
|
|
||||||
A region has to be an object type.
|
|
||||||
|
|
||||||
Regions are very useful to separate user space and kernel memory in the
|
|
||||||
development of OS kernels:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
type
|
|
||||||
Kernel = object
|
|
||||||
Userspace = object
|
|
||||||
|
|
||||||
var a: Kernel ptr Stat
|
|
||||||
var b: Userspace ptr Stat
|
|
||||||
|
|
||||||
# the following does not compile as the pointer types are incompatible:
|
|
||||||
a = b
|
|
||||||
|
|
||||||
As the example shows ``ptr`` can also be used as a binary
|
|
||||||
operator, ``region ptr T`` is a shortcut for ``ptr[region, T]``.
|
|
||||||
|
|
||||||
In order to make generic code easier to write ``ptr T`` is a subtype
|
|
||||||
of ``ptr[R, T]`` for any ``R``.
|
|
||||||
|
|
||||||
Furthermore the subtype relation of the region object types is lifted to
|
|
||||||
the pointer types: If ``A <: B`` then ``ptr[A, T] <: ptr[B, T]``. This can be
|
|
||||||
used to model subregions of memory. As a special typing rule ``ptr[R, T]`` is
|
|
||||||
not compatible to ``pointer`` to prevent the following from compiling:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
# from system
|
|
||||||
proc dealloc(p: pointer)
|
|
||||||
|
|
||||||
# wrap some scripting language
|
|
||||||
type
|
|
||||||
PythonsHeap = object
|
|
||||||
PyObjectHeader = object
|
|
||||||
rc: int
|
|
||||||
typ: pointer
|
|
||||||
PyObject = ptr[PythonsHeap, PyObjectHeader]
|
|
||||||
|
|
||||||
proc createPyObject(): PyObject {.importc: "...".}
|
|
||||||
proc destroyPyObject(x: PyObject) {.importc: "...".}
|
|
||||||
|
|
||||||
var foo = createPyObject()
|
|
||||||
# type error here, how convenient:
|
|
||||||
dealloc(foo)
|
|
||||||
|
|
||||||
|
|
||||||
Future directions:
|
|
||||||
|
|
||||||
* Memory regions might become available for ``string`` and ``seq`` too.
|
|
||||||
* Builtin regions like ``private``, ``global`` and ``local`` might be
|
|
||||||
useful for an OpenCL target.
|
|
||||||
* Builtin "regions" can model ``lent`` and ``unique`` pointers.
|
|
||||||
* An assignment operator can be attached to a region so that proper write
|
|
||||||
barriers can be generated. This would imply that the GC can be implemented
|
|
||||||
completely in user-space.
|
|
||||||
|
|
||||||
|
|
||||||
Procedural type
|
Procedural type
|
||||||
---------------
|
---------------
|
||||||
A procedural type is internally a pointer to a procedure. ``nil`` is
|
A procedural type is internally a pointer to a procedure. ``nil`` is
|
||||||
|
|
@ -1673,7 +1611,8 @@ A ``distinct`` type is new type derived from a `base type`:idx: that is
|
||||||
incompatible with its base type. In particular, it is an essential property
|
incompatible with its base type. In particular, it is an essential property
|
||||||
of a distinct type that it **does not** imply a subtype relation between it
|
of a distinct type that it **does not** imply a subtype relation between it
|
||||||
and its base type. Explicit type conversions from a distinct type to its
|
and its base type. Explicit type conversions from a distinct type to its
|
||||||
base type and vice versa are allowed.
|
base type and vice versa are allowed. See also ``distinctBase`` to get the
|
||||||
|
reverse operation.
|
||||||
|
|
||||||
|
|
||||||
Modelling currencies
|
Modelling currencies
|
||||||
|
|
@ -2336,6 +2275,8 @@ pointer type and overloading resolution is tried with ``a[]`` instead.
|
||||||
Automatic self insertions
|
Automatic self insertions
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
**Note**: The ``.this`` pragma is deprecated and should not be used anymore.
|
||||||
|
|
||||||
Starting with version 0.14 of the language, Nim supports ``field`` as a
|
Starting with version 0.14 of the language, Nim supports ``field`` as a
|
||||||
shortcut for ``self.field`` comparable to the `this`:idx: keyword in Java
|
shortcut for ``self.field`` comparable to the `this`:idx: keyword in Java
|
||||||
or C++. This feature has to be explicitly enabled via a ``{.this: self.}``
|
or C++. This feature has to be explicitly enabled via a ``{.this: self.}``
|
||||||
|
|
@ -4028,9 +3969,13 @@ exception.
|
||||||
Exception hierarchy
|
Exception hierarchy
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
The exception tree is defined in the `system <system.html>`_ module:
|
The exception tree is defined in the `system <system.html>`_ module.
|
||||||
|
Every exception inherits from ``system.Exception``. Exceptions that indicate
|
||||||
.. include:: exception_hierarchy_fragment.txt
|
programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``)
|
||||||
|
and are stricly speaking not catchable as they can also be mapped to an operation
|
||||||
|
that terminates the whole process. Exceptions that indicate any other runtime error
|
||||||
|
that can be caught inherit from ``system.CatchableError``
|
||||||
|
(which is a subtype of ``Exception``).
|
||||||
|
|
||||||
|
|
||||||
Imported exceptions
|
Imported exceptions
|
||||||
|
|
@ -5435,6 +5380,7 @@ type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop:
|
||||||
:test: "nim c $1"
|
:test: "nim c $1"
|
||||||
|
|
||||||
import macros
|
import macros
|
||||||
|
{.experimental: "forLoopMacros".}
|
||||||
|
|
||||||
macro enumerate(x: ForLoopStmt): untyped =
|
macro enumerate(x: ForLoopStmt): untyped =
|
||||||
expectKind x, nnkForStmt
|
expectKind x, nnkForStmt
|
||||||
|
|
@ -5461,6 +5407,62 @@ type ``system.ForLoopStmt`` can rewrite the entirety of a ``for`` loop:
|
||||||
echo a2, " ", b2
|
echo a2, " ", b2
|
||||||
|
|
||||||
|
|
||||||
|
Currently for loop macros must be enabled explicitly
|
||||||
|
via ``{.experimental: "forLoopMacros".}``.
|
||||||
|
|
||||||
|
|
||||||
|
Case statement macros
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
A macro that needs to be called `match`:idx: can be used to
|
||||||
|
rewrite ``case`` statements in order to
|
||||||
|
implement `pattern matching`:idx: for certain types. The following
|
||||||
|
example implements a simplistic form of pattern matching for tuples,
|
||||||
|
leveraging the existing equality operator for tuples (as provided in
|
||||||
|
``system.==``):
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
:test: "nim c $1"
|
||||||
|
|
||||||
|
{.experimental: "caseStmtMacros".}
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
macro match(n: tuple): untyped =
|
||||||
|
result = newTree(nnkIfStmt)
|
||||||
|
let selector = n[0]
|
||||||
|
for i in 1 ..< n.len:
|
||||||
|
let it = n[i]
|
||||||
|
case it.kind
|
||||||
|
of nnkElse, nnkElifBranch, nnkElifExpr, nnkElseExpr:
|
||||||
|
result.add it
|
||||||
|
of nnkOfBranch:
|
||||||
|
for j in 0..it.len-2:
|
||||||
|
let cond = newCall("==", selector, it[j])
|
||||||
|
result.add newTree(nnkElifBranch, cond, it[^1])
|
||||||
|
else:
|
||||||
|
error "'match' cannot handle this node", it
|
||||||
|
echo repr result
|
||||||
|
|
||||||
|
case ("foo", 78)
|
||||||
|
of ("foo", 78): echo "yes"
|
||||||
|
of ("bar", 88): echo "no"
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
|
||||||
|
Currently case statement macros must be enabled explicitly
|
||||||
|
via ``{.experimental: "caseStmtMacros".}``.
|
||||||
|
|
||||||
|
``match`` macros are subject to overload resolution. First the
|
||||||
|
``case``'s selector expression is used to determine which ``match``
|
||||||
|
macro to call. To this macro is then the complete ``case`` statement
|
||||||
|
body is passed and the macro is evaluated.
|
||||||
|
|
||||||
|
In other words, the macro needs to transform the full ``case`` statement
|
||||||
|
but only the statement's selector expression is used to determine which
|
||||||
|
``macro`` to call.
|
||||||
|
|
||||||
|
|
||||||
Special Types
|
Special Types
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
@ -7932,7 +7934,7 @@ that ``spawn`` takes is restricted:
|
||||||
|
|
||||||
``spawn`` executes the passed expression on the thread pool and returns
|
``spawn`` executes the passed expression on the thread pool and returns
|
||||||
a `data flow variable`:idx: ``FlowVar[T]`` that can be read from. The reading
|
a `data flow variable`:idx: ``FlowVar[T]`` that can be read from. The reading
|
||||||
with the ``^`` operator is **blocking**. However, one can use ``awaitAny`` to
|
with the ``^`` operator is **blocking**. However, one can use ``blockUntilAny`` to
|
||||||
wait on multiple flow variables at the same time:
|
wait on multiple flow variables at the same time:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
@ -7943,10 +7945,10 @@ wait on multiple flow variables at the same time:
|
||||||
var responses = newSeq[FlowVarBase](3)
|
var responses = newSeq[FlowVarBase](3)
|
||||||
for i in 0..2:
|
for i in 0..2:
|
||||||
responses[i] = spawn tellServer(Update, "key", "value")
|
responses[i] = spawn tellServer(Update, "key", "value")
|
||||||
var index = awaitAny(responses)
|
var index = blockUntilAny(responses)
|
||||||
assert index >= 0
|
assert index >= 0
|
||||||
responses.del(index)
|
responses.del(index)
|
||||||
discard awaitAny(responses)
|
discard blockUntilAny(responses)
|
||||||
|
|
||||||
Data flow variables ensure that no data races
|
Data flow variables ensure that no data races
|
||||||
are possible. Due to technical limitations not every type ``T`` is possible in
|
are possible. Due to technical limitations not every type ``T`` is possible in
|
||||||
|
|
|
||||||
78
doc/nimc.rst
78
doc/nimc.rst
|
|
@ -68,6 +68,46 @@ User Some user defined warning.
|
||||||
========================== ============================================
|
========================== ============================================
|
||||||
|
|
||||||
|
|
||||||
|
List of hints
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Each hint can be activated individually with ``--hint[NAME]:on|off`` or in a
|
||||||
|
``push`` pragma.
|
||||||
|
|
||||||
|
========================== ============================================
|
||||||
|
Name Description
|
||||||
|
========================== ============================================
|
||||||
|
CC Shows when the C compiler is called.
|
||||||
|
CodeBegin
|
||||||
|
CodeEnd
|
||||||
|
CondTrue
|
||||||
|
Conf A config file was loaded.
|
||||||
|
ConvToBaseNotNeeded
|
||||||
|
ConvFromXtoItselfNotNeeded
|
||||||
|
Dependency
|
||||||
|
Exec Program is executed.
|
||||||
|
ExprAlwaysX
|
||||||
|
ExtendedContext
|
||||||
|
GCStats Dumps statistics about the Garbage Collector.
|
||||||
|
GlobalVar Shows global variables declarations.
|
||||||
|
LineTooLong Line exceeds the maximum length.
|
||||||
|
Link Linking phase.
|
||||||
|
Name
|
||||||
|
Path Search paths modifications.
|
||||||
|
Pattern
|
||||||
|
Performance
|
||||||
|
Processing Artifact being compiled.
|
||||||
|
QuitCalled
|
||||||
|
Source The source line that triggered a diagnostic
|
||||||
|
message.
|
||||||
|
StackTrace
|
||||||
|
Success, SuccessX Successful compilation of a library or a binary.
|
||||||
|
User
|
||||||
|
UserRaw
|
||||||
|
XDeclaredButNotUsed Unused symbols in the code.
|
||||||
|
========================== ============================================
|
||||||
|
|
||||||
|
|
||||||
Verbosity levels
|
Verbosity levels
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
@ -114,7 +154,7 @@ passed as a command line argument to the compiler.
|
||||||
The ``nim`` executable processes configuration files in the following
|
The ``nim`` executable processes configuration files in the following
|
||||||
directories (in this order; later files overwrite previous settings):
|
directories (in this order; later files overwrite previous settings):
|
||||||
|
|
||||||
1) ``$nim/config/nim.cfg``, ``/etc/nim.cfg`` (UNIX) or ``%NIMROD%/config/nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option.
|
1) ``$nim/config/nim.cfg``, ``/etc/nim/nim.cfg`` (UNIX) or ``%NIM%/config/nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option.
|
||||||
2) ``$HOME/.config/nim.cfg`` (POSIX) or ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option.
|
2) ``$HOME/.config/nim.cfg`` (POSIX) or ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option.
|
||||||
3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option.
|
3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option.
|
||||||
4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project file's path. This file can be skipped with the ``--skipProjCfg`` command line option.
|
4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project file's path. This file can be skipped with the ``--skipProjCfg`` command line option.
|
||||||
|
|
@ -157,38 +197,28 @@ the first matching file is used.
|
||||||
Generated C code directory
|
Generated C code directory
|
||||||
--------------------------
|
--------------------------
|
||||||
The generated files that Nim produces all go into a subdirectory called
|
The generated files that Nim produces all go into a subdirectory called
|
||||||
``nimcache`` in your project directory. This makes it easy to delete all
|
``nimcache``. Its full path is
|
||||||
|
|
||||||
|
- ``$XDG_CACHE_HOME/nim/$projectname(_r|_d)`` or ``~/.cache/nim/$projectname(_r|_d)``
|
||||||
|
on Posix
|
||||||
|
- ``$HOME/nimcache/$projectname(_r|_d)`` on Windows.
|
||||||
|
|
||||||
|
The ``_r`` suffix is used for release builds, ``_d`` is for debug builds.
|
||||||
|
|
||||||
|
This makes it easy to delete all
|
||||||
generated files. Files generated in this directory follow a naming logic which
|
generated files. Files generated in this directory follow a naming logic which
|
||||||
you can read about in the `Nim Backend Integration document
|
you can read about in the `Nim Backend Integration document
|
||||||
<backends.html#nimcache-naming-logic>`_.
|
<backends.html#nimcache-naming-logic>`_.
|
||||||
|
|
||||||
|
The ``--nimcache``
|
||||||
|
`compiler switch <nimc.html#command-line-switches>`_ can be used to
|
||||||
|
to change the ``nimcache`` directory.
|
||||||
|
|
||||||
However, the generated C code is not platform independent. C code generated for
|
However, the generated C code is not platform independent. C code generated for
|
||||||
Linux does not compile on Windows, for instance. The comment on top of the
|
Linux does not compile on Windows, for instance. The comment on top of the
|
||||||
C file lists the OS, CPU and CC the file has been compiled for.
|
C file lists the OS, CPU and CC the file has been compiled for.
|
||||||
|
|
||||||
|
|
||||||
Compilation cache
|
|
||||||
=================
|
|
||||||
|
|
||||||
**Warning**: The compilation cache is still highly experimental!
|
|
||||||
|
|
||||||
The ``nimcache`` directory may also contain so called `rod`:idx:
|
|
||||||
or `symbol files`:idx:. These files are pre-compiled modules that are used by
|
|
||||||
the compiler to perform `incremental compilation`:idx:. This means that only
|
|
||||||
modules that have changed since the last compilation (or the modules depending
|
|
||||||
on them etc.) are re-compiled. However, per default no symbol files are
|
|
||||||
generated; use the ``--symbolFiles:on`` command line switch to activate them.
|
|
||||||
|
|
||||||
Unfortunately due to technical reasons the ``--symbolFiles:on`` needs
|
|
||||||
to *aggregate* some generated C code. This means that the resulting executable
|
|
||||||
might contain some cruft even with dead code elimination. So
|
|
||||||
the final release build should be done with ``--symbolFiles:off``.
|
|
||||||
|
|
||||||
Due to the aggregation of C code it is also recommended that each project
|
|
||||||
resides in its own directory so that the generated ``nimcache`` directory
|
|
||||||
is not shared between different projects.
|
|
||||||
|
|
||||||
|
|
||||||
Compiler Selection
|
Compiler Selection
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ Spawn statement
|
||||||
A standalone ``spawn`` statement is a simple construct. It executes
|
A standalone ``spawn`` statement is a simple construct. It executes
|
||||||
the passed expression on the thread pool and returns a `data flow variable`:idx:
|
the passed expression on the thread pool and returns a `data flow variable`:idx:
|
||||||
``FlowVar[T]`` that can be read from. The reading with the ``^`` operator is
|
``FlowVar[T]`` that can be read from. The reading with the ``^`` operator is
|
||||||
**blocking**. However, one can use ``awaitAny`` to wait on multiple flow
|
**blocking**. However, one can use ``blockUntilAny`` to wait on multiple flow
|
||||||
variables at the same time:
|
variables at the same time:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
@ -36,10 +36,10 @@ variables at the same time:
|
||||||
var responses = newSeq[FlowVarBase](3)
|
var responses = newSeq[FlowVarBase](3)
|
||||||
for i in 0..2:
|
for i in 0..2:
|
||||||
responses[i] = spawn tellServer(Update, "key", "value")
|
responses[i] = spawn tellServer(Update, "key", "value")
|
||||||
var index = awaitAny(responses)
|
var index = blockUntilAny(responses)
|
||||||
assert index >= 0
|
assert index >= 0
|
||||||
responses.del(index)
|
responses.del(index)
|
||||||
discard awaitAny(responses)
|
discard blockUntilAny(responses)
|
||||||
|
|
||||||
Data flow variables ensure that no data races
|
Data flow variables ensure that no data races
|
||||||
are possible. Due to technical limitations not every type ``T`` is possible in
|
are possible. Due to technical limitations not every type ``T`` is possible in
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,6 @@ test "arithmetic failure":
|
||||||
expect(ArithmeticError):
|
expect(ArithmeticError):
|
||||||
err()
|
err()
|
||||||
|
|
||||||
expect(ArithmeticError, SystemError):
|
expect(ArithmeticError, CatchableError):
|
||||||
discard foo()
|
discard foo()
|
||||||
|
|
||||||
|
|
|
||||||
7
koch.nim
7
koch.nim
|
|
@ -57,7 +57,8 @@ Commands for core developers:
|
||||||
zip builds the installation zip package
|
zip builds the installation zip package
|
||||||
xz builds the installation tar.xz package
|
xz builds the installation tar.xz package
|
||||||
testinstall test tar.xz package; Unix only!
|
testinstall test tar.xz package; Unix only!
|
||||||
tests [options] run the testsuite
|
tests [options] run the testsuite (run a subset of tests by
|
||||||
|
specifying a category, e.g. `tests cat async`)
|
||||||
temp options creates a temporary compiler for testing
|
temp options creates a temporary compiler for testing
|
||||||
winrelease creates a Windows release
|
winrelease creates a Windows release
|
||||||
pushcsource push generated C sources to its repo
|
pushcsource push generated C sources to its repo
|
||||||
|
|
@ -182,7 +183,7 @@ proc bundleNimbleExe() =
|
||||||
bundleNimbleSrc()
|
bundleNimbleSrc()
|
||||||
# now compile Nimble and copy it to $nim/bin for the installer.ini
|
# now compile Nimble and copy it to $nim/bin for the installer.ini
|
||||||
# to pick it up:
|
# to pick it up:
|
||||||
nimexec("c -d:release dist/nimble/src/nimble.nim")
|
nimexec("c -d:release --nilseqs:on dist/nimble/src/nimble.nim")
|
||||||
copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe)
|
copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe)
|
||||||
|
|
||||||
proc buildNimble(latest: bool) =
|
proc buildNimble(latest: bool) =
|
||||||
|
|
@ -209,7 +210,7 @@ proc buildNimble(latest: bool) =
|
||||||
else:
|
else:
|
||||||
exec("git checkout -f stable")
|
exec("git checkout -f stable")
|
||||||
exec("git pull")
|
exec("git pull")
|
||||||
nimexec("c --noNimblePath -p:compiler -d:release " & installDir / "src/nimble.nim")
|
nimexec("c --noNimblePath -p:compiler --nilseqs:on -d:release " & installDir / "src/nimble.nim")
|
||||||
copyExe(installDir / "src/nimble".exe, "bin/nimble".exe)
|
copyExe(installDir / "src/nimble".exe, "bin/nimble".exe)
|
||||||
|
|
||||||
proc bundleNimsuggest(buildExe: bool) =
|
proc bundleNimsuggest(buildExe: bool) =
|
||||||
|
|
|
||||||
|
|
@ -432,6 +432,9 @@ proc getLine(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
|
||||||
proc getColumn(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
|
proc getColumn(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.}
|
||||||
proc getFile(arg: NimNode): string {.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
|
||||||
|
|
||||||
proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} =
|
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.filename = n.getFile
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@ type
|
||||||
t: Thread[ptr Actor[In, Out]]
|
t: Thread[ptr Actor[In, Out]]
|
||||||
|
|
||||||
PActor*[In, Out] = ptr Actor[In, Out] ## an actor
|
PActor*[In, Out] = ptr Actor[In, Out] ## an actor
|
||||||
{.deprecated: [TTask: Task, TActor: Actor].}
|
|
||||||
|
|
||||||
proc spawn*[In, Out](action: proc(
|
proc spawn*[In, Out](action: proc(
|
||||||
self: PActor[In, Out]){.thread.}): PActor[In, Out] =
|
self: PActor[In, Out]){.thread.}): PActor[In, Out] =
|
||||||
|
|
@ -168,7 +167,7 @@ proc terminate*[In, Out](a: var ActorPool[In, Out]) =
|
||||||
for i in 0..<a.actors.len: join(a.actors[i])
|
for i in 0..<a.actors.len: join(a.actors[i])
|
||||||
when Out isnot void:
|
when Out isnot void:
|
||||||
close(a.outputs)
|
close(a.outputs)
|
||||||
a.actors = nil
|
a.actors = @[]
|
||||||
|
|
||||||
proc join*[In, Out](a: var ActorPool[In, Out]) =
|
proc join*[In, Out](a: var ActorPool[In, Out]) =
|
||||||
## short-cut for `sync` and then `terminate`.
|
## short-cut for `sync` and then `terminate`.
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ include "system/inclrtl"
|
||||||
|
|
||||||
when hostOS == "solaris":
|
when hostOS == "solaris":
|
||||||
{.passl: "-lsocket -lnsl".}
|
{.passl: "-lsocket -lnsl".}
|
||||||
|
elif hostOS == "haiku":
|
||||||
|
{.passl: "-lnetwork".}
|
||||||
|
|
||||||
import os, parseutils
|
import os, parseutils
|
||||||
from times import epochTime
|
from times import epochTime
|
||||||
|
|
|
||||||
|
|
@ -128,9 +128,6 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
|
||||||
var a = 0
|
var a = 0
|
||||||
for c in items(string(formatstr)):
|
for c in items(string(formatstr)):
|
||||||
if c == '?':
|
if c == '?':
|
||||||
if args[a].isNil:
|
|
||||||
add(result, "NULL")
|
|
||||||
else:
|
|
||||||
add(result, dbQuote(args[a]))
|
add(result, dbQuote(args[a]))
|
||||||
inc(a)
|
inc(a)
|
||||||
else:
|
else:
|
||||||
|
|
@ -183,24 +180,8 @@ iterator fastRows*(db: DbConn, query: SqlQuery,
|
||||||
row = mysql.fetchRow(sqlres)
|
row = mysql.fetchRow(sqlres)
|
||||||
if row == nil: break
|
if row == nil: break
|
||||||
for i in 0..L-1:
|
for i in 0..L-1:
|
||||||
if row[i] == nil:
|
|
||||||
if backup == nil:
|
|
||||||
newSeq(backup, L)
|
|
||||||
if backup[i] == nil and result[i] != nil:
|
|
||||||
shallowCopy(backup[i], result[i])
|
|
||||||
result[i] = nil
|
|
||||||
else:
|
|
||||||
if result[i] == nil:
|
|
||||||
if backup != nil:
|
|
||||||
if backup[i] == nil:
|
|
||||||
backup[i] = ""
|
|
||||||
shallowCopy(result[i], backup[i])
|
|
||||||
setLen(result[i], 0)
|
setLen(result[i], 0)
|
||||||
else:
|
result[i].add row[i]
|
||||||
result[i] = ""
|
|
||||||
else:
|
|
||||||
setLen(result[i], 0)
|
|
||||||
add(result[i], row[i])
|
|
||||||
yield result
|
yield result
|
||||||
properFreeResult(sqlres, row)
|
properFreeResult(sqlres, row)
|
||||||
|
|
||||||
|
|
@ -323,9 +304,6 @@ proc getRow*(db: DbConn, query: SqlQuery,
|
||||||
if row != nil:
|
if row != nil:
|
||||||
for i in 0..L-1:
|
for i in 0..L-1:
|
||||||
setLen(result[i], 0)
|
setLen(result[i], 0)
|
||||||
if row[i] == nil:
|
|
||||||
result[i] = nil
|
|
||||||
else:
|
|
||||||
add(result[i], row[i])
|
add(result[i], row[i])
|
||||||
properFreeResult(sqlres, row)
|
properFreeResult(sqlres, row)
|
||||||
|
|
||||||
|
|
@ -345,9 +323,6 @@ proc getAllRows*(db: DbConn, query: SqlQuery,
|
||||||
setLen(result, j+1)
|
setLen(result, j+1)
|
||||||
newSeq(result[j], L)
|
newSeq(result[j], L)
|
||||||
for i in 0..L-1:
|
for i in 0..L-1:
|
||||||
if row[i] == nil:
|
|
||||||
result[j][i] = nil
|
|
||||||
else:
|
|
||||||
result[j][i] = $row[i]
|
result[j][i] = $row[i]
|
||||||
inc(j)
|
inc(j)
|
||||||
mysql.freeResult(sqlres)
|
mysql.freeResult(sqlres)
|
||||||
|
|
|
||||||
|
|
@ -103,9 +103,6 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
|
||||||
else:
|
else:
|
||||||
for c in items(string(formatstr)):
|
for c in items(string(formatstr)):
|
||||||
if c == '?':
|
if c == '?':
|
||||||
if args[a] == nil:
|
|
||||||
add(result, "NULL")
|
|
||||||
else:
|
|
||||||
add(result, dbQuote(args[a]))
|
add(result, dbQuote(args[a]))
|
||||||
inc(a)
|
inc(a)
|
||||||
else:
|
else:
|
||||||
|
|
@ -179,7 +176,7 @@ proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
|
||||||
setLen(r[col], 0)
|
setLen(r[col], 0)
|
||||||
let x = pqgetvalue(res, line, col)
|
let x = pqgetvalue(res, line, col)
|
||||||
if x.isNil:
|
if x.isNil:
|
||||||
r[col] = nil
|
r[col] = ""
|
||||||
else:
|
else:
|
||||||
add(r[col], x)
|
add(r[col], x)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,6 @@ proc dbError*(db: DbConn) {.noreturn.} =
|
||||||
|
|
||||||
proc dbQuote*(s: string): string =
|
proc dbQuote*(s: string): string =
|
||||||
## DB quotes the string.
|
## DB quotes the string.
|
||||||
if s.isNil: return "NULL"
|
|
||||||
result = "'"
|
result = "'"
|
||||||
for c in items(s):
|
for c in items(s):
|
||||||
if c == '\'': add(result, "''")
|
if c == '\'': add(result, "''")
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,7 @@ proc `[]`*(pattern: Captures, i: int): string =
|
||||||
let bounds = bounds.get
|
let bounds = bounds.get
|
||||||
return pattern.str.substr(bounds.a, bounds.b)
|
return pattern.str.substr(bounds.a, bounds.b)
|
||||||
else:
|
else:
|
||||||
return nil
|
return ""
|
||||||
|
|
||||||
proc match*(pattern: RegexMatch): string =
|
proc match*(pattern: RegexMatch): string =
|
||||||
return pattern.captures[-1]
|
return pattern.captures[-1]
|
||||||
|
|
@ -291,9 +291,9 @@ template toTableImpl(cond: untyped) {.dirty.} =
|
||||||
else:
|
else:
|
||||||
result[key] = nextVal
|
result[key] = nextVal
|
||||||
|
|
||||||
proc toTable*(pattern: Captures, default: string = nil): Table[string, string] =
|
proc toTable*(pattern: Captures, default: string = ""): Table[string, string] =
|
||||||
result = initTable[string, string]()
|
result = initTable[string, string]()
|
||||||
toTableImpl(nextVal == nil)
|
toTableImpl(nextVal.len == 0)
|
||||||
|
|
||||||
proc toTable*(pattern: CaptureBounds, default = none(HSlice[int, int])):
|
proc toTable*(pattern: CaptureBounds, default = none(HSlice[int, int])):
|
||||||
Table[string, Option[HSlice[int, int]]] =
|
Table[string, Option[HSlice[int, int]]] =
|
||||||
|
|
@ -312,13 +312,13 @@ template itemsImpl(cond: untyped) {.dirty.} =
|
||||||
iterator items*(pattern: CaptureBounds, default = none(HSlice[int, int])): Option[HSlice[int, int]] =
|
iterator items*(pattern: CaptureBounds, default = none(HSlice[int, int])): Option[HSlice[int, int]] =
|
||||||
itemsImpl(nextVal.isNone)
|
itemsImpl(nextVal.isNone)
|
||||||
|
|
||||||
iterator items*(pattern: Captures, default: string = nil): string =
|
iterator items*(pattern: Captures, default: string = ""): string =
|
||||||
itemsImpl(nextVal == nil)
|
itemsImpl(nextVal.len == 0)
|
||||||
|
|
||||||
proc toSeq*(pattern: CaptureBounds, default = none(HSlice[int, int])): seq[Option[HSlice[int, int]]] =
|
proc toSeq*(pattern: CaptureBounds, default = none(HSlice[int, int])): seq[Option[HSlice[int, int]]] =
|
||||||
accumulateResult(pattern.items(default))
|
accumulateResult(pattern.items(default))
|
||||||
|
|
||||||
proc toSeq*(pattern: Captures, default: string = nil): seq[string] =
|
proc toSeq*(pattern: Captures, default: string = ""): seq[string] =
|
||||||
accumulateResult(pattern.items(default))
|
accumulateResult(pattern.items(default))
|
||||||
|
|
||||||
proc `$`*(pattern: RegexMatch): string =
|
proc `$`*(pattern: RegexMatch): string =
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,7 @@ proc fget*[K, V](self: Table[K, V], key: K): V =
|
||||||
const Ident = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
|
const Ident = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
|
||||||
const StartIdent = Ident - {'0'..'9'}
|
const StartIdent = Ident - {'0'..'9'}
|
||||||
|
|
||||||
proc checkNil(arg: string): string =
|
template checkNil(arg: string): string = arg
|
||||||
if arg == nil:
|
|
||||||
raise newException(ValueError, "Cannot use nil capture")
|
|
||||||
else:
|
|
||||||
return arg
|
|
||||||
|
|
||||||
template formatStr*(howExpr, namegetter, idgetter): untyped =
|
template formatStr*(howExpr, namegetter, idgetter): untyped =
|
||||||
let how = howExpr
|
let how = howExpr
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string],
|
||||||
var b = rawMatches[i * 2 + 1]
|
var b = rawMatches[i * 2 + 1]
|
||||||
if a >= 0'i32:
|
if a >= 0'i32:
|
||||||
matches[i-1] = bufSubstr(buf, int(a), int(b))
|
matches[i-1] = bufSubstr(buf, int(a), int(b))
|
||||||
else: matches[i-1] = nil
|
else: matches[i-1] = ""
|
||||||
return rawMatches[1] - rawMatches[0]
|
return rawMatches[1] - rawMatches[0]
|
||||||
|
|
||||||
proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string],
|
proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string],
|
||||||
|
|
@ -133,7 +133,7 @@ proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string],
|
||||||
var a = rawMatches[i * 2]
|
var a = rawMatches[i * 2]
|
||||||
var b = rawMatches[i * 2 + 1]
|
var b = rawMatches[i * 2 + 1]
|
||||||
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b))
|
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b))
|
||||||
else: matches[i-1] = nil
|
else: matches[i-1] = ""
|
||||||
return (rawMatches[0].int, rawMatches[1].int - 1)
|
return (rawMatches[0].int, rawMatches[1].int - 1)
|
||||||
|
|
||||||
proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
|
proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
|
||||||
|
|
@ -287,7 +287,7 @@ proc find*(buf: cstring, pattern: Regex, matches: var openArray[string],
|
||||||
var a = rawMatches[i * 2]
|
var a = rawMatches[i * 2]
|
||||||
var b = rawMatches[i * 2 + 1]
|
var b = rawMatches[i * 2 + 1]
|
||||||
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b))
|
if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b))
|
||||||
else: matches[i-1] = nil
|
else: matches[i-1] = ""
|
||||||
return rawMatches[0]
|
return rawMatches[0]
|
||||||
|
|
||||||
proc find*(s: string, pattern: Regex, matches: var openArray[string],
|
proc find*(s: string, pattern: Regex, matches: var openArray[string],
|
||||||
|
|
@ -456,8 +456,6 @@ proc replacef*(s: string, sub: Regex, by: string): string =
|
||||||
while true:
|
while true:
|
||||||
var match = findBounds(s, sub, caps, prev)
|
var match = findBounds(s, sub, caps, prev)
|
||||||
if match.first < 0: break
|
if match.first < 0: break
|
||||||
assert result != nil
|
|
||||||
assert s != nil
|
|
||||||
add(result, substr(s, prev, match.first-1))
|
add(result, substr(s, prev, match.first-1))
|
||||||
addf(result, by, caps)
|
addf(result, by, caps)
|
||||||
prev = match.last + 1
|
prev = match.last + 1
|
||||||
|
|
@ -615,7 +613,7 @@ when isMainModule:
|
||||||
doAssert false
|
doAssert false
|
||||||
|
|
||||||
if "abc" =~ re"(cba)?.*":
|
if "abc" =~ re"(cba)?.*":
|
||||||
doAssert matches[0] == nil
|
doAssert matches[0] == ""
|
||||||
else: doAssert false
|
else: doAssert false
|
||||||
|
|
||||||
if "abc" =~ re"().*":
|
if "abc" =~ re"().*":
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,12 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nim's Runtime Library
|
||||||
|
# (c) Copyright 2018 Nim contributors
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
## This module wraps core JavaScript functions.
|
## This module wraps core JavaScript functions.
|
||||||
##
|
##
|
||||||
## Unless your application has very
|
## Unless your application has very
|
||||||
|
|
@ -19,49 +28,47 @@ var
|
||||||
Date* {.importc, nodecl.}: DateLib
|
Date* {.importc, nodecl.}: DateLib
|
||||||
JSON* {.importc, nodecl.}: JsonLib
|
JSON* {.importc, nodecl.}: JsonLib
|
||||||
|
|
||||||
{.push importcpp.}
|
|
||||||
|
|
||||||
# Math library
|
# Math library
|
||||||
proc abs*(m: MathLib, a: SomeNumber): SomeNumber
|
proc abs*(m: MathLib, a: SomeNumber): SomeNumber {.importcpp.}
|
||||||
proc acos*(m: MathLib, a: SomeNumber): float
|
proc acos*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc acosh*(m: MathLib, a: SomeNumber): float
|
proc acosh*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc asin*(m: MathLib, a: SomeNumber): float
|
proc asin*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc asinh*(m: MathLib, a: SomeNumber): float
|
proc asinh*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc atan*(m: MathLib, a: SomeNumber): float
|
proc atan*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc atan2*(m: MathLib, a: SomeNumber): float
|
proc atan2*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc atanh*(m: MathLib, a: SomeNumber): float
|
proc atanh*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc cbrt*(m: MathLib, f: SomeFloat): SomeFloat
|
proc cbrt*(m: MathLib, f: SomeFloat): SomeFloat {.importcpp.}
|
||||||
proc ceil*(m: MathLib, f: SomeFloat): SomeFloat
|
proc ceil*(m: MathLib, f: SomeFloat): SomeFloat {.importcpp.}
|
||||||
proc clz32*(m: MathLib, f: SomeInteger): int
|
proc clz32*(m: MathLib, f: SomeInteger): int {.importcpp.}
|
||||||
proc cos*(m: MathLib, a: SomeNumber): float
|
proc cos*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc cosh*(m: MathLib, a: SomeNumber): float
|
proc cosh*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc exp*(m: MathLib, a: SomeNumber): float
|
proc exp*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc expm1*(m: MathLib, a: SomeNumber): float
|
proc expm1*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc floor*(m: MathLib, f: SomeFloat): int
|
proc floor*(m: MathLib, f: SomeFloat): int {.importcpp.}
|
||||||
proc fround*(m: MathLib, f: SomeFloat): float32
|
proc fround*(m: MathLib, f: SomeFloat): float32 {.importcpp.}
|
||||||
proc hypot*(m: MathLib, args: varargs[distinct SomeNumber]): float
|
proc hypot*(m: MathLib, args: varargs[distinct SomeNumber]): float {.importcpp.}
|
||||||
proc imul*(m: MathLib, a, b: int32): int32
|
proc imul*(m: MathLib, a, b: int32): int32 {.importcpp.}
|
||||||
proc log*(m: MathLib, a: SomeNumber): float
|
proc log*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc log10*(m: MathLib, a: SomeNumber): float
|
proc log10*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc log1p*(m: MathLib, a: SomeNumber): float
|
proc log1p*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc log2*(m: MathLib, a: SomeNumber): float
|
proc log2*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc max*(m: MathLib, a, b: SomeNumber): SomeNumber
|
proc max*(m: MathLib, a, b: SomeNumber): SomeNumber {.importcpp.}
|
||||||
proc min*[T: SomeNumber | JsRoot](m: MathLib, a, b: T): T
|
proc min*[T: SomeNumber | JsRoot](m: MathLib, a, b: T): T {.importcpp.}
|
||||||
proc pow*(m: MathLib, a, b: distinct SomeNumber): float
|
proc pow*(m: MathLib, a, b: distinct SomeNumber): float {.importcpp.}
|
||||||
proc random*(m: MathLib): float
|
proc random*(m: MathLib): float {.importcpp.}
|
||||||
proc round*(m: MathLib, f: SomeFloat): int
|
proc round*(m: MathLib, f: SomeFloat): int {.importcpp.}
|
||||||
proc sign*(m: MathLib, f: SomeNumber): int
|
proc sign*(m: MathLib, f: SomeNumber): int {.importcpp.}
|
||||||
proc sin*(m: MathLib, a: SomeNumber): float
|
proc sin*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc sinh*(m: MathLib, a: SomeNumber): float
|
proc sinh*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc sqrt*(m: MathLib, f: SomeFloat): SomeFloat
|
proc sqrt*(m: MathLib, f: SomeFloat): SomeFloat {.importcpp.}
|
||||||
proc tan*(m: MathLib, a: SomeNumber): float
|
proc tan*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc tanh*(m: MathLib, a: SomeNumber): float
|
proc tanh*(m: MathLib, a: SomeNumber): float {.importcpp.}
|
||||||
proc trunc*(m: MathLib, f: SomeFloat): int
|
proc trunc*(m: MathLib, f: SomeFloat): int {.importcpp.}
|
||||||
|
|
||||||
# Date library
|
# Date library
|
||||||
proc now*(d: DateLib): int
|
proc now*(d: DateLib): int {.importcpp.}
|
||||||
proc UTC*(d: DateLib): int
|
proc UTC*(d: DateLib): int {.importcpp.}
|
||||||
proc parse*(d: DateLib, s: cstring): int
|
proc parse*(d: DateLib, s: cstring): int {.importcpp.}
|
||||||
|
|
||||||
proc newDate*(): DateTime {.
|
proc newDate*(): DateTime {.
|
||||||
importcpp: "new Date()".}
|
importcpp: "new Date()".}
|
||||||
|
|
@ -73,19 +80,17 @@ proc newDate*(year, month, day, hours, minutes,
|
||||||
seconds, milliseconds: int): DateTime {.
|
seconds, milliseconds: int): DateTime {.
|
||||||
importcpp: "new Date(#,#,#,#,#,#,#)".}
|
importcpp: "new Date(#,#,#,#,#,#,#)".}
|
||||||
|
|
||||||
proc getDay*(d: DateTime): int
|
proc getDay*(d: DateTime): int {.importcpp.}
|
||||||
proc getFullYear*(d: DateTime): int
|
proc getFullYear*(d: DateTime): int {.importcpp.}
|
||||||
proc getHours*(d: DateTime): int
|
proc getHours*(d: DateTime): int {.importcpp.}
|
||||||
proc getMilliseconds*(d: DateTime): int
|
proc getMilliseconds*(d: DateTime): int {.importcpp.}
|
||||||
proc getMinutes*(d: DateTime): int
|
proc getMinutes*(d: DateTime): int {.importcpp.}
|
||||||
proc getMonth*(d: DateTime): int
|
proc getMonth*(d: DateTime): int {.importcpp.}
|
||||||
proc getSeconds*(d: DateTime): int
|
proc getSeconds*(d: DateTime): int {.importcpp.}
|
||||||
proc getYear*(d: DateTime): int
|
proc getYear*(d: DateTime): int {.importcpp.}
|
||||||
proc getTime*(d: DateTime): int
|
proc getTime*(d: DateTime): int {.importcpp.}
|
||||||
proc toString*(d: DateTime): cstring
|
proc toString*(d: DateTime): cstring {.importcpp.}
|
||||||
|
|
||||||
#JSON library
|
#JSON library
|
||||||
proc stringify*(l: JsonLib, s: JsRoot): cstring
|
proc stringify*(l: JsonLib, s: JsRoot): cstring {.importcpp.}
|
||||||
proc parse*(l: JsonLib, s: cstring): JsRoot
|
proc parse*(l: JsonLib, s: cstring): JsRoot {.importcpp.}
|
||||||
|
|
||||||
{.pop.}
|
|
||||||
|
|
|
||||||
|
|
@ -129,13 +129,13 @@ __clang__
|
||||||
defined __DMC__ || \
|
defined __DMC__ || \
|
||||||
defined __BORLANDC__ )
|
defined __BORLANDC__ )
|
||||||
# define NIM_THREADVAR __declspec(thread)
|
# define NIM_THREADVAR __declspec(thread)
|
||||||
|
#elif defined(__TINYC__) || defined(__GENODE__)
|
||||||
|
# define NIM_THREADVAR
|
||||||
/* note that ICC (linux) and Clang are covered by __GNUC__ */
|
/* note that ICC (linux) and Clang are covered by __GNUC__ */
|
||||||
#elif defined __GNUC__ || \
|
#elif defined __GNUC__ || \
|
||||||
defined __SUNPRO_C || \
|
defined __SUNPRO_C || \
|
||||||
defined __xlC__
|
defined __xlC__
|
||||||
# define NIM_THREADVAR __thread
|
# define NIM_THREADVAR __thread
|
||||||
#elif defined __TINYC__
|
|
||||||
# define NIM_THREADVAR
|
|
||||||
#else
|
#else
|
||||||
# error "Cannot define NIM_THREADVAR"
|
# error "Cannot define NIM_THREADVAR"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -293,9 +293,9 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode =
|
||||||
(key: "kind", val: %($node.kind)),
|
(key: "kind", val: %($node.kind)),
|
||||||
(key: "level", val: %BiggestInt(node.level))
|
(key: "level", val: %BiggestInt(node.level))
|
||||||
]
|
]
|
||||||
if node.text != nil:
|
if node.text.len > 0:
|
||||||
result.add("text", %node.text)
|
result.add("text", %node.text)
|
||||||
if node.sons != nil and len(node.sons) > 0:
|
if len(node.sons) > 0:
|
||||||
var accm = newSeq[JsonNode](len(node.sons))
|
var accm = newSeq[JsonNode](len(node.sons))
|
||||||
for i, son in node.sons:
|
for i, son in node.sons:
|
||||||
accm[i] = renderRstToJsonNode(son)
|
accm[i] = renderRstToJsonNode(son)
|
||||||
|
|
|
||||||
|
|
@ -312,7 +312,6 @@ proc setIndexTerm*(d: var RstGenerator, id, term: string,
|
||||||
## The index won't be written to disk unless you call `writeIndexFile()
|
## The index won't be written to disk unless you call `writeIndexFile()
|
||||||
## <#writeIndexFile>`_. The purpose of the index is documented in the `docgen
|
## <#writeIndexFile>`_. The purpose of the index is documented in the `docgen
|
||||||
## tools guide <docgen.html#index-switch>`_.
|
## tools guide <docgen.html#index-switch>`_.
|
||||||
assert(not d.theIndex.isNil)
|
|
||||||
var
|
var
|
||||||
entry = term
|
entry = term
|
||||||
isTitle = false
|
isTitle = false
|
||||||
|
|
@ -337,7 +336,7 @@ proc hash(n: PRstNode): int =
|
||||||
result = hash(n.text)
|
result = hash(n.text)
|
||||||
elif n.len > 0:
|
elif n.len > 0:
|
||||||
result = hash(n.sons[0])
|
result = hash(n.sons[0])
|
||||||
for i in 1 .. <len(n):
|
for i in 1 ..< len(n):
|
||||||
result = result !& hash(n.sons[i])
|
result = result !& hash(n.sons[i])
|
||||||
result = !$result
|
result = !$result
|
||||||
|
|
||||||
|
|
@ -398,9 +397,9 @@ proc hash(x: IndexEntry): Hash =
|
||||||
proc `<-`(a: var IndexEntry, b: IndexEntry) =
|
proc `<-`(a: var IndexEntry, b: IndexEntry) =
|
||||||
shallowCopy a.keyword, b.keyword
|
shallowCopy a.keyword, b.keyword
|
||||||
shallowCopy a.link, b.link
|
shallowCopy a.link, b.link
|
||||||
if b.linkTitle.isNil: a.linkTitle = nil
|
if b.linkTitle.isNil: a.linkTitle = ""
|
||||||
else: shallowCopy a.linkTitle, b.linkTitle
|
else: shallowCopy a.linkTitle, b.linkTitle
|
||||||
if b.linkDesc.isNil: a.linkDesc = nil
|
if b.linkDesc.isNil: a.linkDesc = ""
|
||||||
else: shallowCopy a.linkDesc, b.linkDesc
|
else: shallowCopy a.linkDesc, b.linkDesc
|
||||||
|
|
||||||
proc sortIndex(a: var openArray[IndexEntry]) =
|
proc sortIndex(a: var openArray[IndexEntry]) =
|
||||||
|
|
@ -608,8 +607,8 @@ proc readIndexDir(dir: string):
|
||||||
fileEntries[F].linkTitle = extraCols[1].unquoteIndexColumn
|
fileEntries[F].linkTitle = extraCols[1].unquoteIndexColumn
|
||||||
fileEntries[F].linkDesc = extraCols[2].unquoteIndexColumn
|
fileEntries[F].linkDesc = extraCols[2].unquoteIndexColumn
|
||||||
else:
|
else:
|
||||||
fileEntries[F].linkTitle = nil
|
fileEntries[F].linkTitle = ""
|
||||||
fileEntries[F].linkDesc = nil
|
fileEntries[F].linkDesc = ""
|
||||||
inc F
|
inc F
|
||||||
# Depending on type add this to the list of symbols or table of APIs.
|
# Depending on type add this to the list of symbols or table of APIs.
|
||||||
if title.keyword.isNil:
|
if title.keyword.isNil:
|
||||||
|
|
@ -657,7 +656,6 @@ proc mergeIndexes*(dir: string): string =
|
||||||
## Returns the merged and sorted indices into a single HTML block which can
|
## Returns the merged and sorted indices into a single HTML block which can
|
||||||
## be further embedded into nimdoc templates.
|
## be further embedded into nimdoc templates.
|
||||||
var (modules, symbols, docs) = readIndexDir(dir)
|
var (modules, symbols, docs) = readIndexDir(dir)
|
||||||
assert(not symbols.isNil)
|
|
||||||
|
|
||||||
result = ""
|
result = ""
|
||||||
# Generate a quick jump list of documents.
|
# Generate a quick jump list of documents.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
{.deadCodeElim: on.} # dce option deprecated
|
{.deadCodeElim: on.} # dce option deprecated
|
||||||
|
|
||||||
const
|
const
|
||||||
hasSpawnH = not defined(haiku) # should exist for every Posix system nowadays
|
hasSpawnH = true # should exist for every Posix system nowadays
|
||||||
hasAioH = defined(linux)
|
hasAioH = defined(linux)
|
||||||
|
|
||||||
when defined(linux) and not defined(android):
|
when defined(linux) and not defined(android):
|
||||||
|
|
@ -43,6 +43,9 @@ type
|
||||||
|
|
||||||
Dirent* {.importc: "struct dirent",
|
Dirent* {.importc: "struct dirent",
|
||||||
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
|
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
|
||||||
|
when defined(haiku):
|
||||||
|
d_dev*: Dev ## Device (not POSIX)
|
||||||
|
d_pdev*: Dev ## Parent device (only for queries) (not POSIX)
|
||||||
d_ino*: Ino ## File serial number.
|
d_ino*: Ino ## File serial number.
|
||||||
when defined(dragonfly):
|
when defined(dragonfly):
|
||||||
# DragonflyBSD doesn't have `d_reclen` field.
|
# DragonflyBSD doesn't have `d_reclen` field.
|
||||||
|
|
@ -54,6 +57,9 @@ type
|
||||||
## (not POSIX)
|
## (not POSIX)
|
||||||
when defined(linux) or defined(openbsd):
|
when defined(linux) or defined(openbsd):
|
||||||
d_off*: Off ## Not an offset. Value that ``telldir()`` would return.
|
d_off*: Off ## Not an offset. Value that ``telldir()`` would return.
|
||||||
|
elif defined(haiku):
|
||||||
|
d_pino*: Ino ## Parent inode (only for queries) (not POSIX)
|
||||||
|
d_reclen*: cushort ## Length of this record. (not POSIX)
|
||||||
|
|
||||||
d_name*: array[0..255, char] ## Name of entry.
|
d_name*: array[0..255, char] ## Name of entry.
|
||||||
|
|
||||||
|
|
@ -599,6 +605,10 @@ else:
|
||||||
MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint
|
MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint
|
||||||
## No SIGPIPE generated when an attempt to send is made on a stream-oriented socket that is no longer connected.
|
## No SIGPIPE generated when an attempt to send is made on a stream-oriented socket that is no longer connected.
|
||||||
|
|
||||||
|
when defined(haiku):
|
||||||
|
const
|
||||||
|
SIGKILLTHR* = 21 ## BeOS specific: Kill just the thread, not team
|
||||||
|
|
||||||
when hasSpawnH:
|
when hasSpawnH:
|
||||||
when defined(linux):
|
when defined(linux):
|
||||||
# better be safe than sorry; Linux has this flag, macosx doesn't, don't
|
# better be safe than sorry; Linux has this flag, macosx doesn't, don't
|
||||||
|
|
|
||||||
|
|
@ -219,10 +219,10 @@ proc getHint(entry: StackTraceEntry): string =
|
||||||
## We try to provide some hints about stack trace entries that the user
|
## We try to provide some hints about stack trace entries that the user
|
||||||
## may not be familiar with, in particular calls inside the stdlib.
|
## may not be familiar with, in particular calls inside the stdlib.
|
||||||
result = ""
|
result = ""
|
||||||
if entry.procname == "processPendingCallbacks":
|
if entry.procname == cstring"processPendingCallbacks":
|
||||||
if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
|
if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
|
||||||
return "Executes pending callbacks"
|
return "Executes pending callbacks"
|
||||||
elif entry.procname == "poll":
|
elif entry.procname == cstring"poll":
|
||||||
if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
|
if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0:
|
||||||
return "Processes asynchronous completion events"
|
return "Processes asynchronous completion events"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -493,8 +493,6 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
|
||||||
## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the
|
## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the
|
||||||
## protocol uses ``\r\L`` to delimit a new line.
|
## protocol uses ``\r\L`` to delimit a new line.
|
||||||
assert SocketFlag.Peek notin flags ## TODO:
|
assert SocketFlag.Peek notin flags ## TODO:
|
||||||
assert(not resString.mget.isNil(),
|
|
||||||
"String inside resString future needs to be initialised")
|
|
||||||
result = newFuture[void]("asyncnet.recvLineInto")
|
result = newFuture[void]("asyncnet.recvLineInto")
|
||||||
|
|
||||||
# TODO: Make the async transformation check for FutureVar params and complete
|
# TODO: Make the async transformation check for FutureVar params and complete
|
||||||
|
|
@ -657,7 +655,7 @@ when defineSsl:
|
||||||
|
|
||||||
proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket,
|
proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket,
|
||||||
handshake: SslHandshakeType,
|
handshake: SslHandshakeType,
|
||||||
hostname: string = nil) =
|
hostname: string = "") =
|
||||||
## Wraps a connected socket in an SSL context. This function effectively
|
## Wraps a connected socket in an SSL context. This function effectively
|
||||||
## turns ``socket`` into an SSL socket.
|
## turns ``socket`` into an SSL socket.
|
||||||
## ``hostname`` should be specified so that the client knows which hostname
|
## ``hostname`` should be specified so that the client knows which hostname
|
||||||
|
|
@ -672,7 +670,7 @@ when defineSsl:
|
||||||
|
|
||||||
case handshake
|
case handshake
|
||||||
of handshakeAsClient:
|
of handshakeAsClient:
|
||||||
if not hostname.isNil and not isIpAddress(hostname):
|
if hostname.len > 0 and not isIpAddress(hostname):
|
||||||
# Set the SNI address for this connection. This call can fail if
|
# Set the SNI address for this connection. This call can fail if
|
||||||
# we're not using TLSv1+.
|
# we're not using TLSv1+.
|
||||||
discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
|
discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,9 @@ proc initIntSet*: IntSet =
|
||||||
|
|
||||||
#newSeq(result.data, InitIntSetSize)
|
#newSeq(result.data, InitIntSetSize)
|
||||||
#result.max = InitIntSetSize-1
|
#result.max = InitIntSetSize-1
|
||||||
|
when defined(nimNoNilSeqs):
|
||||||
|
result.data = @[]
|
||||||
|
else:
|
||||||
result.data = nil
|
result.data = nil
|
||||||
result.max = 0
|
result.max = 0
|
||||||
result.counter = 0
|
result.counter = 0
|
||||||
|
|
@ -222,6 +225,9 @@ proc clear*(result: var IntSet) =
|
||||||
#setLen(result.data, InitIntSetSize)
|
#setLen(result.data, InitIntSetSize)
|
||||||
#for i in 0..InitIntSetSize-1: result.data[i] = nil
|
#for i in 0..InitIntSetSize-1: result.data[i] = nil
|
||||||
#result.max = InitIntSetSize-1
|
#result.max = InitIntSetSize-1
|
||||||
|
when defined(nimNoNilSeqs):
|
||||||
|
result.data = @[]
|
||||||
|
else:
|
||||||
result.data = nil
|
result.data = nil
|
||||||
result.max = 0
|
result.max = 0
|
||||||
result.counter = 0
|
result.counter = 0
|
||||||
|
|
@ -234,6 +240,9 @@ proc assign*(dest: var IntSet, src: IntSet) =
|
||||||
## copies `src` to `dest`. `dest` does not need to be initialized by
|
## copies `src` to `dest`. `dest` does not need to be initialized by
|
||||||
## `initIntSet`.
|
## `initIntSet`.
|
||||||
if src.elems <= src.a.len:
|
if src.elems <= src.a.len:
|
||||||
|
when defined(nimNoNilSeqs):
|
||||||
|
dest.data = @[]
|
||||||
|
else:
|
||||||
dest.data = nil
|
dest.data = nil
|
||||||
dest.max = 0
|
dest.max = 0
|
||||||
dest.counter = src.counter
|
dest.counter = src.counter
|
||||||
|
|
@ -247,11 +256,9 @@ proc assign*(dest: var IntSet, src: IntSet) =
|
||||||
|
|
||||||
var it = src.head
|
var it = src.head
|
||||||
while it != nil:
|
while it != nil:
|
||||||
|
|
||||||
var h = it.key and dest.max
|
var h = it.key and dest.max
|
||||||
while dest.data[h] != nil: h = nextTry(h, dest.max)
|
while dest.data[h] != nil: h = nextTry(h, dest.max)
|
||||||
assert(dest.data[h] == nil)
|
assert(dest.data[h] == nil)
|
||||||
|
|
||||||
var n: PTrunk
|
var n: PTrunk
|
||||||
new(n)
|
new(n)
|
||||||
n.next = dest.head
|
n.next = dest.head
|
||||||
|
|
@ -259,7 +266,6 @@ proc assign*(dest: var IntSet, src: IntSet) =
|
||||||
n.bits = it.bits
|
n.bits = it.bits
|
||||||
dest.head = n
|
dest.head = n
|
||||||
dest.data[h] = n
|
dest.data[h] = n
|
||||||
|
|
||||||
it = it.next
|
it = it.next
|
||||||
|
|
||||||
proc union*(s1, s2: IntSet): IntSet =
|
proc union*(s1, s2: IntSet): IntSet =
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,28 @@ import macros
|
||||||
when not defined(nimhygiene):
|
when not defined(nimhygiene):
|
||||||
{.pragma: dirty.}
|
{.pragma: dirty.}
|
||||||
|
|
||||||
|
|
||||||
|
macro evalOnceAs(expAlias, exp: untyped, letAssigneable: static[bool]): untyped =
|
||||||
|
## Injects ``expAlias`` in caller scope, to avoid bugs involving multiple
|
||||||
|
## substitution in macro arguments such as
|
||||||
|
## https://github.com/nim-lang/Nim/issues/7187
|
||||||
|
## ``evalOnceAs(myAlias, myExp)`` will behave as ``let myAlias = myExp``
|
||||||
|
## except when ``letAssigneable`` is false (eg to handle openArray) where
|
||||||
|
## it just forwards ``exp`` unchanged
|
||||||
|
expectKind(expAlias, nnkIdent)
|
||||||
|
var val = exp
|
||||||
|
|
||||||
|
result = newStmtList()
|
||||||
|
# If `exp` is not a symbol we evaluate it once here and then use the temporary
|
||||||
|
# symbol as alias
|
||||||
|
if exp.kind != nnkSym and letAssigneable:
|
||||||
|
val = genSym()
|
||||||
|
result.add(newLetStmt(val, exp))
|
||||||
|
|
||||||
|
result.add(
|
||||||
|
newProc(name = genSym(nskTemplate, $expAlias), params = [getType(untyped)],
|
||||||
|
body = val, procType = nnkTemplateDef))
|
||||||
|
|
||||||
proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
||||||
## Takes several sequences' items and returns them inside a new sequence.
|
## Takes several sequences' items and returns them inside a new sequence.
|
||||||
##
|
##
|
||||||
|
|
@ -496,10 +518,14 @@ template toSeq*(iter: untyped): untyped =
|
||||||
## result = true)
|
## result = true)
|
||||||
## assert odd_numbers == @[1, 3, 5, 7, 9]
|
## assert odd_numbers == @[1, 3, 5, 7, 9]
|
||||||
|
|
||||||
|
# Note: see also `mapIt` for explanation of some of the implementation
|
||||||
|
# subtleties.
|
||||||
when compiles(iter.len):
|
when compiles(iter.len):
|
||||||
|
block:
|
||||||
|
evalOnceAs(iter2, iter, true)
|
||||||
|
var result = newSeq[type(iter)](iter2.len)
|
||||||
var i = 0
|
var i = 0
|
||||||
var result = newSeq[type(iter)](iter.len)
|
for x in iter2:
|
||||||
for x in iter:
|
|
||||||
result[i] = x
|
result[i] = x
|
||||||
inc i
|
inc i
|
||||||
result
|
result
|
||||||
|
|
@ -635,8 +661,7 @@ template mapIt*(s, typ, op: untyped): untyped =
|
||||||
result.add(op)
|
result.add(op)
|
||||||
result
|
result
|
||||||
|
|
||||||
|
template mapIt*(s: typed, op: untyped): untyped =
|
||||||
template mapIt*(s, op: untyped): untyped =
|
|
||||||
## Convenience template around the ``map`` proc to reduce typing.
|
## Convenience template around the ``map`` proc to reduce typing.
|
||||||
##
|
##
|
||||||
## The template injects the ``it`` variable which you can use directly in an
|
## The template injects the ``it`` variable which you can use directly in an
|
||||||
|
|
@ -653,16 +678,21 @@ template mapIt*(s, op: untyped): untyped =
|
||||||
block:
|
block:
|
||||||
var it{.inject.}: type(items(s));
|
var it{.inject.}: type(items(s));
|
||||||
op))
|
op))
|
||||||
var result: seq[outType]
|
|
||||||
when compiles(s.len):
|
when compiles(s.len):
|
||||||
let t = s
|
block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580
|
||||||
|
|
||||||
|
# BUG: `evalOnceAs(s2, s, false)` would lead to C compile errors
|
||||||
|
# (`error: use of undeclared identifier`) instead of Nim compile errors
|
||||||
|
evalOnceAs(s2, s, compiles((let _ = s)))
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
result = newSeq[outType](t.len)
|
var result = newSeq[outType](s2.len)
|
||||||
for it {.inject.} in t:
|
for it {.inject.} in s2:
|
||||||
result[i] = op
|
result[i] = op
|
||||||
i += 1
|
i += 1
|
||||||
|
result
|
||||||
else:
|
else:
|
||||||
result = @[]
|
var result: seq[outType] = @[]
|
||||||
for it {.inject.} in s:
|
for it {.inject.} in s:
|
||||||
result.add(op)
|
result.add(op)
|
||||||
result
|
result
|
||||||
|
|
@ -752,6 +782,14 @@ macro mapLiterals*(constructor, op: untyped;
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
import strutils
|
import strutils
|
||||||
|
|
||||||
|
# helper for testing double substitution side effects which are handled
|
||||||
|
# by `evalOnceAs`
|
||||||
|
var counter = 0
|
||||||
|
proc identity[T](a:T):auto=
|
||||||
|
counter.inc
|
||||||
|
a
|
||||||
|
|
||||||
block: # concat test
|
block: # concat test
|
||||||
let
|
let
|
||||||
s1 = @[1, 2, 3]
|
s1 = @[1, 2, 3]
|
||||||
|
|
@ -997,6 +1035,12 @@ when isMainModule:
|
||||||
result = true)
|
result = true)
|
||||||
assert odd_numbers == @[1, 3, 5, 7, 9]
|
assert odd_numbers == @[1, 3, 5, 7, 9]
|
||||||
|
|
||||||
|
block:
|
||||||
|
# tests https://github.com/nim-lang/Nim/issues/7187
|
||||||
|
counter = 0
|
||||||
|
let ret = toSeq(@[1, 2, 3].identity().filter(proc (x: int): bool = x < 3))
|
||||||
|
doAssert ret == @[1, 2]
|
||||||
|
doAssert counter == 1
|
||||||
block: # foldl tests
|
block: # foldl tests
|
||||||
let
|
let
|
||||||
numbers = @[5, 9, 11]
|
numbers = @[5, 9, 11]
|
||||||
|
|
@ -1023,10 +1067,12 @@ when isMainModule:
|
||||||
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
|
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
|
||||||
assert concatenation == "nimiscool"
|
assert concatenation == "nimiscool"
|
||||||
|
|
||||||
block: # mapIt tests
|
block: # mapIt + applyIt test
|
||||||
|
counter = 0
|
||||||
var
|
var
|
||||||
nums = @[1, 2, 3, 4]
|
nums = @[1, 2, 3, 4]
|
||||||
strings = nums.mapIt($(4 * it))
|
strings = nums.identity.mapIt($(4 * it))
|
||||||
|
doAssert counter == 1
|
||||||
nums.applyIt(it * 3)
|
nums.applyIt(it * 3)
|
||||||
assert nums[0] + nums[3] == 15
|
assert nums[0] + nums[3] == 15
|
||||||
assert strings[2] == "12"
|
assert strings[2] == "12"
|
||||||
|
|
@ -1044,5 +1090,51 @@ when isMainModule:
|
||||||
doAssert mapLiterals((1, ("abc"), 2), float, nested=false) == (float(1), "abc", float(2))
|
doAssert mapLiterals((1, ("abc"), 2), float, nested=false) == (float(1), "abc", float(2))
|
||||||
doAssert mapLiterals(([1], ("abc"), 2), `$`, nested=true) == (["1"], "abc", "2")
|
doAssert mapLiterals(([1], ("abc"), 2), `$`, nested=true) == (["1"], "abc", "2")
|
||||||
|
|
||||||
|
block: # mapIt with openArray
|
||||||
|
counter = 0
|
||||||
|
proc foo(x: openArray[int]): seq[int] = x.mapIt(it * 10)
|
||||||
|
doAssert foo([identity(1),identity(2)]) == @[10, 20]
|
||||||
|
doAssert counter == 2
|
||||||
|
|
||||||
|
block: # mapIt with direct openArray
|
||||||
|
proc foo1(x: openArray[int]): seq[int] = x.mapIt(it * 10)
|
||||||
|
counter = 0
|
||||||
|
doAssert foo1(openArray[int]([identity(1),identity(2)])) == @[10,20]
|
||||||
|
doAssert counter == 2
|
||||||
|
|
||||||
|
# Corner cases (openArray litterals should not be common)
|
||||||
|
template foo2(x: openArray[int]): seq[int] = x.mapIt(it * 10)
|
||||||
|
counter = 0
|
||||||
|
doAssert foo2(openArray[int]([identity(1),identity(2)])) == @[10,20]
|
||||||
|
# TODO: this fails; not sure how to fix this case
|
||||||
|
# doAssert counter == 2
|
||||||
|
|
||||||
|
counter = 0
|
||||||
|
doAssert openArray[int]([identity(1), identity(2)]).mapIt(it) == @[1,2]
|
||||||
|
# ditto
|
||||||
|
# doAssert counter == 2
|
||||||
|
|
||||||
|
block: # mapIt empty test, see https://github.com/nim-lang/Nim/pull/8584#pullrequestreview-144723468
|
||||||
|
# NOTE: `[].mapIt(it)` is illegal, just as `let a = @[]` is (lacks type
|
||||||
|
# of elements)
|
||||||
|
doAssert: not compiles(mapIt(@[], it))
|
||||||
|
doAssert: not compiles(mapIt([], it))
|
||||||
|
doAssert newSeq[int](0).mapIt(it) == @[]
|
||||||
|
|
||||||
|
block: # mapIt redifinition check, see https://github.com/nim-lang/Nim/issues/8580
|
||||||
|
let s2 = [1,2].mapIt(it)
|
||||||
|
doAssert s2 == @[1,2]
|
||||||
|
|
||||||
|
block:
|
||||||
|
counter = 0
|
||||||
|
doAssert [1,2].identity().mapIt(it*2).mapIt(it*10) == @[20, 40]
|
||||||
|
# https://github.com/nim-lang/Nim/issues/7187 test case
|
||||||
|
doAssert counter == 1
|
||||||
|
|
||||||
|
block: # mapIt with invalid RHS for `let` (#8566)
|
||||||
|
type X = enum
|
||||||
|
A, B
|
||||||
|
doAssert mapIt(X, $it) == @["A", "B"]
|
||||||
|
|
||||||
when not defined(testing):
|
when not defined(testing):
|
||||||
echo "Finished doc tests"
|
echo "Finished doc tests"
|
||||||
|
|
|
||||||
|
|
@ -1329,7 +1329,7 @@ when isMainModule:
|
||||||
doAssert clearTable[42] == "asd"
|
doAssert clearTable[42] == "asd"
|
||||||
clearTable.clear()
|
clearTable.clear()
|
||||||
doAssert(not clearTable.hasKey(123123))
|
doAssert(not clearTable.hasKey(123123))
|
||||||
doAssert clearTable.getOrDefault(42) == nil
|
doAssert clearTable.getOrDefault(42) == ""
|
||||||
|
|
||||||
block: #5482
|
block: #5482
|
||||||
var a = [("wrong?","foo"), ("wrong?", "foo2")].newOrderedTable()
|
var a = [("wrong?","foo"), ("wrong?", "foo2")].newOrderedTable()
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,14 @@ when defined(genode):
|
||||||
proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
|
proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
|
||||||
importcpp: "@->cpu().affinity_space().total()".}
|
importcpp: "@->cpu().affinity_space().total()".}
|
||||||
|
|
||||||
|
when defined(haiku):
|
||||||
|
{.emit: "#include <OS.h>".}
|
||||||
|
type
|
||||||
|
SystemInfo {.importc: "system_info", bycopy.} = object
|
||||||
|
cpuCount {.importc: "cpu_count".}: uint32
|
||||||
|
|
||||||
|
proc getSystemInfo(info: ptr SystemInfo): int32 {.importc: "get_system_info".}
|
||||||
|
|
||||||
proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
|
proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
|
||||||
## returns the numer of the processors/cores the machine has.
|
## returns the numer of the processors/cores the machine has.
|
||||||
## Returns 0 if it cannot be detected.
|
## Returns 0 if it cannot be detected.
|
||||||
|
|
@ -86,6 +94,10 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
|
||||||
result = sysconf(SC_NPROC_ONLN)
|
result = sysconf(SC_NPROC_ONLN)
|
||||||
elif defined(genode):
|
elif defined(genode):
|
||||||
result = runtimeEnv.affinitySpaceTotal().int
|
result = runtimeEnv.affinitySpaceTotal().int
|
||||||
|
elif defined(haiku):
|
||||||
|
var sysinfo: SystemInfo
|
||||||
|
if getSystemInfo(addr sysinfo) == 0:
|
||||||
|
result = sysinfo.cpuCount.int
|
||||||
else:
|
else:
|
||||||
result = sysconf(SC_NPROCESSORS_ONLN)
|
result = sysconf(SC_NPROCESSORS_ONLN)
|
||||||
if result <= 0: result = 0
|
if result <= 0: result = 0
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ proc destroySemaphore(cv: var Semaphore) {.inline.} =
|
||||||
deinitCond(cv.c)
|
deinitCond(cv.c)
|
||||||
deinitLock(cv.L)
|
deinitLock(cv.L)
|
||||||
|
|
||||||
proc await(cv: var Semaphore) =
|
proc blockUntil(cv: var Semaphore) =
|
||||||
acquire(cv.L)
|
acquire(cv.L)
|
||||||
while cv.counter <= 0:
|
while cv.counter <= 0:
|
||||||
wait(cv.c, cv.L)
|
wait(cv.c, cv.L)
|
||||||
|
|
@ -81,7 +81,7 @@ proc closeBarrier(b: ptr Barrier) {.compilerProc.} =
|
||||||
fence()
|
fence()
|
||||||
b.interest = true
|
b.interest = true
|
||||||
fence()
|
fence()
|
||||||
while b.left != b.entered: await(b.cv)
|
while b.left != b.entered: blockUntil(b.cv)
|
||||||
destroySemaphore(b.cv)
|
destroySemaphore(b.cv)
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
@ -89,8 +89,6 @@ proc closeBarrier(b: ptr Barrier) {.compilerProc.} =
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
type
|
type
|
||||||
foreign* = object ## a region that indicates the pointer comes from a
|
|
||||||
## foreign thread heap.
|
|
||||||
AwaitInfo = object
|
AwaitInfo = object
|
||||||
cv: Semaphore
|
cv: Semaphore
|
||||||
idx: int
|
idx: int
|
||||||
|
|
@ -99,7 +97,7 @@ type
|
||||||
FlowVarBaseObj = object of RootObj
|
FlowVarBaseObj = object of RootObj
|
||||||
ready, usesSemaphore, awaited: bool
|
ready, usesSemaphore, awaited: bool
|
||||||
cv: Semaphore #\
|
cv: Semaphore #\
|
||||||
# for 'awaitAny' support
|
# for 'blockUntilAny' support
|
||||||
ai: ptr AwaitInfo
|
ai: ptr AwaitInfo
|
||||||
idx: int
|
idx: int
|
||||||
data: pointer # we incRef and unref it to keep it alive; note this MUST NOT
|
data: pointer # we incRef and unref it to keep it alive; note this MUST NOT
|
||||||
|
|
@ -130,12 +128,12 @@ type
|
||||||
q: ToFreeQueue
|
q: ToFreeQueue
|
||||||
readyForTask: Semaphore
|
readyForTask: Semaphore
|
||||||
|
|
||||||
proc await*(fv: FlowVarBase) =
|
proc blockUntil*(fv: FlowVarBase) =
|
||||||
## waits until the value for the flowVar arrives. Usually it is not necessary
|
## waits until the value for the flowVar arrives. Usually it is not necessary
|
||||||
## to call this explicitly.
|
## to call this explicitly.
|
||||||
if fv.usesSemaphore and not fv.awaited:
|
if fv.usesSemaphore and not fv.awaited:
|
||||||
fv.awaited = true
|
fv.awaited = true
|
||||||
await(fv.cv)
|
blockUntil(fv.cv)
|
||||||
destroySemaphore(fv.cv)
|
destroySemaphore(fv.cv)
|
||||||
|
|
||||||
proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool =
|
proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool =
|
||||||
|
|
@ -143,7 +141,7 @@ proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool =
|
||||||
w.data = data
|
w.data = data
|
||||||
w.f = fn
|
w.f = fn
|
||||||
signal(w.taskArrived)
|
signal(w.taskArrived)
|
||||||
await(w.taskStarted)
|
blockUntil(w.taskStarted)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc cleanFlowVars(w: ptr Worker) =
|
proc cleanFlowVars(w: ptr Worker) =
|
||||||
|
|
@ -178,11 +176,11 @@ proc attach(fv: FlowVarBase; i: int): bool =
|
||||||
release(fv.cv.L)
|
release(fv.cv.L)
|
||||||
|
|
||||||
proc finished(fv: FlowVarBase) =
|
proc finished(fv: FlowVarBase) =
|
||||||
doAssert fv.ai.isNil, "flowVar is still attached to an 'awaitAny'"
|
doAssert fv.ai.isNil, "flowVar is still attached to an 'blockUntilAny'"
|
||||||
# we have to protect against the rare cases where the owner of the flowVar
|
# we have to protect against the rare cases where the owner of the flowVar
|
||||||
# simply disregards the flowVar and yet the "flowVar" has not yet written
|
# simply disregards the flowVar and yet the "flowVar" has not yet written
|
||||||
# anything to it:
|
# anything to it:
|
||||||
await(fv)
|
blockUntil(fv)
|
||||||
if fv.data.isNil: return
|
if fv.data.isNil: return
|
||||||
let owner = cast[ptr Worker](fv.owner)
|
let owner = cast[ptr Worker](fv.owner)
|
||||||
let q = addr(owner.q)
|
let q = addr(owner.q)
|
||||||
|
|
@ -191,7 +189,7 @@ proc finished(fv: FlowVarBase) =
|
||||||
#echo "EXHAUSTED!"
|
#echo "EXHAUSTED!"
|
||||||
release(q.lock)
|
release(q.lock)
|
||||||
wakeupWorkerToProcessQueue(owner)
|
wakeupWorkerToProcessQueue(owner)
|
||||||
await(q.empty)
|
blockUntil(q.empty)
|
||||||
acquire(q.lock)
|
acquire(q.lock)
|
||||||
q.data[q.len] = cast[pointer](fv.data)
|
q.data[q.len] = cast[pointer](fv.data)
|
||||||
inc q.len
|
inc q.len
|
||||||
|
|
@ -222,7 +220,7 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
|
||||||
## to ``action``. Note that due to Nim's parameter passing semantics this
|
## to ``action``. Note that due to Nim's parameter passing semantics this
|
||||||
## means that ``T`` doesn't need to be copied and so ``awaitAndThen`` can
|
## means that ``T`` doesn't need to be copied and so ``awaitAndThen`` can
|
||||||
## sometimes be more efficient than ``^``.
|
## sometimes be more efficient than ``^``.
|
||||||
await(fv)
|
blockUntil(fv)
|
||||||
when T is string or T is seq:
|
when T is string or T is seq:
|
||||||
action(cast[T](fv.data))
|
action(cast[T](fv.data))
|
||||||
elif T is ref:
|
elif T is ref:
|
||||||
|
|
@ -231,31 +229,31 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
|
||||||
action(fv.blob)
|
action(fv.blob)
|
||||||
finished(fv)
|
finished(fv)
|
||||||
|
|
||||||
proc unsafeRead*[T](fv: FlowVar[ref T]): foreign ptr T =
|
proc unsafeRead*[T](fv: FlowVar[ref T]): ptr T =
|
||||||
## blocks until the value is available and then returns this value.
|
## blocks until the value is available and then returns this value.
|
||||||
await(fv)
|
blockUntil(fv)
|
||||||
result = cast[foreign ptr T](fv.data)
|
result = cast[ptr T](fv.data)
|
||||||
|
|
||||||
proc `^`*[T](fv: FlowVar[ref T]): ref T =
|
proc `^`*[T](fv: FlowVar[ref T]): ref T =
|
||||||
## blocks until the value is available and then returns this value.
|
## blocks until the value is available and then returns this value.
|
||||||
await(fv)
|
blockUntil(fv)
|
||||||
let src = cast[ref T](fv.data)
|
let src = cast[ref T](fv.data)
|
||||||
deepCopy result, src
|
deepCopy result, src
|
||||||
|
|
||||||
proc `^`*[T](fv: FlowVar[T]): T =
|
proc `^`*[T](fv: FlowVar[T]): T =
|
||||||
## blocks until the value is available and then returns this value.
|
## blocks until the value is available and then returns this value.
|
||||||
await(fv)
|
blockUntil(fv)
|
||||||
when T is string or T is seq:
|
when T is string or T is seq:
|
||||||
# XXX closures? deepCopy?
|
# XXX closures? deepCopy?
|
||||||
result = cast[T](fv.data)
|
result = cast[T](fv.data)
|
||||||
else:
|
else:
|
||||||
result = fv.blob
|
result = fv.blob
|
||||||
|
|
||||||
proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
|
proc blockUntilAny*(flowVars: openArray[FlowVarBase]): int =
|
||||||
## awaits any of the given flowVars. Returns the index of one flowVar for
|
## awaits any of the given flowVars. Returns the index of one flowVar for
|
||||||
## which a value arrived. A flowVar only supports one call to 'awaitAny' at
|
## which a value arrived. A flowVar only supports one call to 'blockUntilAny' at
|
||||||
## the same time. That means if you awaitAny([a,b]) and awaitAny([b,c]) the second
|
## the same time. That means if you blockUntilAny([a,b]) and blockUntilAny([b,c]) the second
|
||||||
## call will only await 'c'. If there is no flowVar left to be able to wait
|
## call will only blockUntil 'c'. If there is no flowVar left to be able to wait
|
||||||
## on, -1 is returned.
|
## on, -1 is returned.
|
||||||
## **Note**: This results in non-deterministic behaviour and should be avoided.
|
## **Note**: This results in non-deterministic behaviour and should be avoided.
|
||||||
var ai: AwaitInfo
|
var ai: AwaitInfo
|
||||||
|
|
@ -271,7 +269,7 @@ proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
|
||||||
inc conflicts
|
inc conflicts
|
||||||
if conflicts < flowVars.len:
|
if conflicts < flowVars.len:
|
||||||
if result < 0:
|
if result < 0:
|
||||||
await(ai.cv)
|
blockUntil(ai.cv)
|
||||||
result = ai.idx
|
result = ai.idx
|
||||||
for i in 0 .. flowVars.high:
|
for i in 0 .. flowVars.high:
|
||||||
discard cas(addr flowVars[i].ai, addr ai, nil)
|
discard cas(addr flowVars[i].ai, addr ai, nil)
|
||||||
|
|
@ -328,7 +326,7 @@ proc slave(w: ptr Worker) {.thread.} =
|
||||||
w.ready = true
|
w.ready = true
|
||||||
readyWorker = w
|
readyWorker = w
|
||||||
signal(gSomeReady)
|
signal(gSomeReady)
|
||||||
await(w.taskArrived)
|
blockUntil(w.taskArrived)
|
||||||
# XXX Somebody needs to look into this (why does this assertion fail
|
# XXX Somebody needs to look into this (why does this assertion fail
|
||||||
# in Visual Studio?)
|
# in Visual Studio?)
|
||||||
when not defined(vcc) and not defined(tcc): assert(not w.ready)
|
when not defined(vcc) and not defined(tcc): assert(not w.ready)
|
||||||
|
|
@ -353,7 +351,7 @@ proc distinguishedSlave(w: ptr Worker) {.thread.} =
|
||||||
else:
|
else:
|
||||||
w.ready = true
|
w.ready = true
|
||||||
signal(w.readyForTask)
|
signal(w.readyForTask)
|
||||||
await(w.taskArrived)
|
blockUntil(w.taskArrived)
|
||||||
assert(not w.ready)
|
assert(not w.ready)
|
||||||
w.f(w, w.data)
|
w.f(w, w.data)
|
||||||
if w.q.len != 0: w.cleanFlowVars
|
if w.q.len != 0: w.cleanFlowVars
|
||||||
|
|
@ -501,7 +499,7 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} =
|
||||||
# on the current thread instead.
|
# on the current thread instead.
|
||||||
var self = addr(workersData[localThreadId-1])
|
var self = addr(workersData[localThreadId-1])
|
||||||
fn(self, data)
|
fn(self, data)
|
||||||
await(self.taskStarted)
|
blockUntil(self.taskStarted)
|
||||||
return
|
return
|
||||||
|
|
||||||
if isSlave:
|
if isSlave:
|
||||||
|
|
@ -526,7 +524,7 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} =
|
||||||
|
|
||||||
inc numSlavesWaiting
|
inc numSlavesWaiting
|
||||||
|
|
||||||
await(gSomeReady)
|
blockUntil(gSomeReady)
|
||||||
|
|
||||||
if isSlave:
|
if isSlave:
|
||||||
withLock numSlavesLock:
|
withLock numSlavesLock:
|
||||||
|
|
@ -544,7 +542,7 @@ proc nimSpawn4(fn: WorkerProc; data: pointer; id: ThreadId) {.compilerProc.} =
|
||||||
release(distinguishedLock)
|
release(distinguishedLock)
|
||||||
while true:
|
while true:
|
||||||
if selectWorker(addr(distinguishedData[id]), fn, data): break
|
if selectWorker(addr(distinguishedData[id]), fn, data): break
|
||||||
await(distinguishedData[id].readyForTask)
|
blockUntil(distinguishedData[id].readyForTask)
|
||||||
|
|
||||||
|
|
||||||
proc sync*() =
|
proc sync*() =
|
||||||
|
|
@ -557,7 +555,7 @@ proc sync*() =
|
||||||
if not allReady: break
|
if not allReady: break
|
||||||
allReady = allReady and workersData[i].ready
|
allReady = allReady and workersData[i].ready
|
||||||
if allReady: break
|
if allReady: break
|
||||||
await(gSomeReady)
|
blockUntil(gSomeReady)
|
||||||
inc toRelease
|
inc toRelease
|
||||||
|
|
||||||
for i in 0 ..< toRelease:
|
for i in 0 ..< toRelease:
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@ when defined(windows):
|
||||||
{.warning: "ucontext coroutine backend is not available on windows, defaulting to fibers.".}
|
{.warning: "ucontext coroutine backend is not available on windows, defaulting to fibers.".}
|
||||||
when defined(nimCoroutinesSetjmp):
|
when defined(nimCoroutinesSetjmp):
|
||||||
{.warning: "setjmp coroutine backend is not available on windows, defaulting to fibers.".}
|
{.warning: "setjmp coroutine backend is not available on windows, defaulting to fibers.".}
|
||||||
|
elif defined(haiku):
|
||||||
|
const coroBackend = CORO_BACKEND_SETJMP
|
||||||
|
when defined(nimCoroutinesUcontext):
|
||||||
|
{.warning: "ucontext coroutine backend is not available on haiku, defaulting to setjmp".}
|
||||||
elif defined(nimCoroutinesSetjmp) or defined(nimCoroutinesSetjmpBundled):
|
elif defined(nimCoroutinesSetjmp) or defined(nimCoroutinesSetjmpBundled):
|
||||||
const coroBackend = CORO_BACKEND_SETJMP
|
const coroBackend = CORO_BACKEND_SETJMP
|
||||||
else:
|
else:
|
||||||
|
|
@ -55,21 +59,21 @@ when coroBackend == CORO_BACKEND_FIBERS:
|
||||||
|
|
||||||
elif coroBackend == CORO_BACKEND_UCONTEXT:
|
elif coroBackend == CORO_BACKEND_UCONTEXT:
|
||||||
type
|
type
|
||||||
stack_t {.importc, header: "<sys/ucontext.h>".} = object
|
stack_t {.importc, header: "<ucontext.h>".} = object
|
||||||
ss_sp: pointer
|
ss_sp: pointer
|
||||||
ss_flags: int
|
ss_flags: int
|
||||||
ss_size: int
|
ss_size: int
|
||||||
|
|
||||||
ucontext_t {.importc, header: "<sys/ucontext.h>".} = object
|
ucontext_t {.importc, header: "<ucontext.h>".} = object
|
||||||
uc_link: ptr ucontext_t
|
uc_link: ptr ucontext_t
|
||||||
uc_stack: stack_t
|
uc_stack: stack_t
|
||||||
|
|
||||||
Context = ucontext_t
|
Context = ucontext_t
|
||||||
|
|
||||||
proc getcontext(context: var ucontext_t): int32 {.importc, header: "<sys/ucontext.h>".}
|
proc getcontext(context: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
|
||||||
proc setcontext(context: var ucontext_t): int32 {.importc, header: "<sys/ucontext.h>".}
|
proc setcontext(context: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
|
||||||
proc swapcontext(fromCtx, toCtx: var ucontext_t): int32 {.importc, header: "<sys/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: "<sys/ucontext.h>", varargs.}
|
proc makecontext(context: var ucontext_t, fn: pointer, argc: int32) {.importc, header: "<ucontext.h>", varargs.}
|
||||||
|
|
||||||
elif coroBackend == CORO_BACKEND_SETJMP:
|
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.}
|
||||||
|
|
@ -190,7 +194,7 @@ proc switchTo(current, to: CoroutinePtr) =
|
||||||
elif to.state == CORO_CREATED:
|
elif to.state == CORO_CREATED:
|
||||||
# Coroutine is started.
|
# Coroutine is started.
|
||||||
coroExecWithStack(runCurrentTask, to.stack.bottom)
|
coroExecWithStack(runCurrentTask, to.stack.bottom)
|
||||||
doAssert false
|
#doAssert false
|
||||||
else:
|
else:
|
||||||
{.error: "Invalid coroutine backend set.".}
|
{.error: "Invalid coroutine backend set.".}
|
||||||
# Execution was just resumed. Restore frame information and set active stack.
|
# Execution was just resumed. Restore frame information and set active stack.
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,8 @@ type
|
||||||
OpenBSD
|
OpenBSD
|
||||||
DragonFlyBSD
|
DragonFlyBSD
|
||||||
|
|
||||||
|
Haiku
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware,
|
LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware,
|
||||||
|
|
@ -166,6 +168,8 @@ proc detectOsImpl(d: Distribution): bool =
|
||||||
of Distribution.Solaris:
|
of Distribution.Solaris:
|
||||||
let uname = toLowerAscii(uname())
|
let uname = toLowerAscii(uname())
|
||||||
result = ("sun" in uname) or ("solaris" in uname)
|
result = ("sun" in uname) or ("solaris" in uname)
|
||||||
|
of Distribution.Haiku:
|
||||||
|
result = defined(haiku)
|
||||||
else:
|
else:
|
||||||
let dd = toLowerAscii($d)
|
let dd = toLowerAscii($d)
|
||||||
result = dd in toLowerAscii(uname()) or dd in toLowerAscii(release())
|
result = dd in toLowerAscii(uname()) or dd in toLowerAscii(release())
|
||||||
|
|
@ -224,6 +228,8 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) =
|
||||||
result = ("pacman -S " & p, true)
|
result = ("pacman -S " & p, true)
|
||||||
else:
|
else:
|
||||||
result = ("<your package manager here> install " & p, true)
|
result = ("<your package manager here> install " & p, true)
|
||||||
|
elif defined(haiku):
|
||||||
|
result = ("pkgman install " & p, true)
|
||||||
else:
|
else:
|
||||||
result = ("brew install " & p, false)
|
result = ("brew install " & p, false)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ when defined(windows):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
when defined(haiku):
|
when defined(haiku):
|
||||||
const iconvDll = "(libc.so.6|libiconv.so|libtextencoding.so)"
|
const iconvDll = "libiconv.so"
|
||||||
elif defined(macosx):
|
elif defined(macosx):
|
||||||
const iconvDll = "libiconv.dylib"
|
const iconvDll = "libiconv.dylib"
|
||||||
else:
|
else:
|
||||||
|
|
@ -272,6 +272,8 @@ else:
|
||||||
const EILSEQ = 86.cint
|
const EILSEQ = 86.cint
|
||||||
elif defined(solaris):
|
elif defined(solaris):
|
||||||
const EILSEQ = 88.cint
|
const EILSEQ = 88.cint
|
||||||
|
elif defined(haiku):
|
||||||
|
const EILSEQ = -2147454938.cint
|
||||||
|
|
||||||
var errno {.importc, header: "<errno.h>".}: cint
|
var errno {.importc, header: "<errno.h>".}: cint
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
{.deadCodeElim: on.} # dce option deprecated
|
{.deadCodeElim: on.} # dce option deprecated
|
||||||
|
|
||||||
when defined(Posix) and not defined(haiku):
|
when defined(Posix):
|
||||||
{.passl: "-lm".}
|
{.passl: "-lm".}
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
|
||||||
|
|
@ -1869,7 +1869,6 @@ proc entityToUtf8*(entity: string): string =
|
||||||
## "" is returned if the entity name is unknown. The HTML parser
|
## "" is returned if the entity name is unknown. The HTML parser
|
||||||
## already converts entities to UTF-8.
|
## already converts entities to UTF-8.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert entityToUtf8(nil) == ""
|
|
||||||
doAssert entityToUtf8("") == ""
|
doAssert entityToUtf8("") == ""
|
||||||
doAssert entityToUtf8("a") == ""
|
doAssert entityToUtf8("a") == ""
|
||||||
doAssert entityToUtf8("gt") == ">"
|
doAssert entityToUtf8("gt") == ">"
|
||||||
|
|
|
||||||
|
|
@ -378,23 +378,23 @@ proc newMultipartData*: MultipartData =
|
||||||
## Constructs a new ``MultipartData`` object.
|
## Constructs a new ``MultipartData`` object.
|
||||||
MultipartData(content: @[])
|
MultipartData(content: @[])
|
||||||
|
|
||||||
proc add*(p: var MultipartData, name, content: string, filename: string = nil,
|
proc add*(p: var MultipartData, name, content: string, filename: string = "",
|
||||||
contentType: string = nil) =
|
contentType: string = "") =
|
||||||
## Add a value to the multipart data. Raises a `ValueError` exception if
|
## Add a value to the multipart data. Raises a `ValueError` exception if
|
||||||
## `name`, `filename` or `contentType` contain newline characters.
|
## `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")
|
raise newException(ValueError, "name contains a newline character")
|
||||||
if filename != nil and {'\c','\L'} in filename:
|
if {'\c','\L'} in filename:
|
||||||
raise newException(ValueError, "filename contains a newline character")
|
raise newException(ValueError, "filename contains a newline character")
|
||||||
if contentType != nil and {'\c','\L'} in contentType:
|
if {'\c','\L'} in contentType:
|
||||||
raise newException(ValueError, "contentType contains a newline character")
|
raise newException(ValueError, "contentType contains a newline character")
|
||||||
|
|
||||||
var str = "Content-Disposition: form-data; name=\"" & name & "\""
|
var str = "Content-Disposition: form-data; name=\"" & name & "\""
|
||||||
if filename != nil:
|
if filename.len > 0:
|
||||||
str.add("; filename=\"" & filename & "\"")
|
str.add("; filename=\"" & filename & "\"")
|
||||||
str.add("\c\L")
|
str.add("\c\L")
|
||||||
if contentType != nil:
|
if contentType.len > 0:
|
||||||
str.add("Content-Type: " & contentType & "\c\L")
|
str.add("Content-Type: " & contentType & "\c\L")
|
||||||
str.add("\c\L" & content & "\c\L")
|
str.add("\c\L" & content & "\c\L")
|
||||||
|
|
||||||
|
|
@ -434,7 +434,7 @@ proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
|
||||||
var contentType: string
|
var contentType: string
|
||||||
let (_, fName, ext) = splitFile(file)
|
let (_, fName, ext) = splitFile(file)
|
||||||
if ext.len > 0:
|
if ext.len > 0:
|
||||||
contentType = m.getMimetype(ext[1..ext.high], nil)
|
contentType = m.getMimetype(ext[1..ext.high], "")
|
||||||
p.add(name, readFile(file), fName & ext, contentType)
|
p.add(name, readFile(file), fName & ext, contentType)
|
||||||
result = p
|
result = p
|
||||||
|
|
||||||
|
|
@ -457,7 +457,7 @@ proc `[]=`*(p: var MultipartData, name: string,
|
||||||
p.add(name, file.content, file.name, file.contentType)
|
p.add(name, file.content, file.name, file.contentType)
|
||||||
|
|
||||||
proc format(p: MultipartData): tuple[contentType, body: string] =
|
proc format(p: MultipartData): tuple[contentType, body: string] =
|
||||||
if p == nil or p.content == nil or p.content.len == 0:
|
if p == nil or p.content.len == 0:
|
||||||
return ("", "")
|
return ("", "")
|
||||||
|
|
||||||
# Create boundary that is not in the data to be formatted
|
# Create boundary that is not in the data to be formatted
|
||||||
|
|
@ -807,6 +807,7 @@ type
|
||||||
lastProgressReport: float
|
lastProgressReport: float
|
||||||
when SocketType is AsyncSocket:
|
when SocketType is AsyncSocket:
|
||||||
bodyStream: FutureStream[string]
|
bodyStream: FutureStream[string]
|
||||||
|
parseBodyFut: Future[void]
|
||||||
else:
|
else:
|
||||||
bodyStream: Stream
|
bodyStream: Stream
|
||||||
getBody: bool ## When `false`, the body is never read in requestAux.
|
getBody: bool ## When `false`, the body is never read in requestAux.
|
||||||
|
|
@ -1066,10 +1067,14 @@ proc parseResponse(client: HttpClient | AsyncHttpClient,
|
||||||
if getBody:
|
if getBody:
|
||||||
when client is HttpClient:
|
when client is HttpClient:
|
||||||
client.bodyStream = newStringStream()
|
client.bodyStream = newStringStream()
|
||||||
|
result.bodyStream = client.bodyStream
|
||||||
|
parseBody(client, result.headers, result.version)
|
||||||
else:
|
else:
|
||||||
client.bodyStream = newFutureStream[string]("parseResponse")
|
client.bodyStream = newFutureStream[string]("parseResponse")
|
||||||
await parseBody(client, result.headers, result.version)
|
|
||||||
result.bodyStream = client.bodyStream
|
result.bodyStream = client.bodyStream
|
||||||
|
assert(client.parseBodyFut.isNil or client.parseBodyFut.finished)
|
||||||
|
client.parseBodyFut = parseBody(client, result.headers, result.version)
|
||||||
|
# do not wait here for the body request to complete
|
||||||
|
|
||||||
proc newConnection(client: HttpClient | AsyncHttpClient,
|
proc newConnection(client: HttpClient | AsyncHttpClient,
|
||||||
url: Uri) {.multisync.} =
|
url: Uri) {.multisync.} =
|
||||||
|
|
@ -1159,6 +1164,12 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: string,
|
||||||
# Helper that actually makes the request. Does not handle redirects.
|
# Helper that actually makes the request. Does not handle redirects.
|
||||||
let requestUrl = parseUri(url)
|
let requestUrl = parseUri(url)
|
||||||
|
|
||||||
|
when client is AsyncHttpClient:
|
||||||
|
if not client.parseBodyFut.isNil:
|
||||||
|
# let the current operation finish before making another request
|
||||||
|
await client.parseBodyFut
|
||||||
|
client.parseBodyFut = nil
|
||||||
|
|
||||||
await newConnection(client, requestUrl)
|
await newConnection(client, requestUrl)
|
||||||
|
|
||||||
let effectiveHeaders = client.headers.override(headers)
|
let effectiveHeaders = client.headers.override(headers)
|
||||||
|
|
|
||||||
|
|
@ -567,8 +567,11 @@ proc selectInto*[T](s: Selector[T], timeout: int,
|
||||||
doAssert(true, "Unsupported kqueue filter in the queue!")
|
doAssert(true, "Unsupported kqueue filter in the queue!")
|
||||||
|
|
||||||
if (kevent.flags and EV_EOF) != 0:
|
if (kevent.flags and EV_EOF) != 0:
|
||||||
|
# TODO this error handling needs to be rethought.
|
||||||
|
# `fflags` can sometimes be `0x80000000` and thus we use 'cast'
|
||||||
|
# here:
|
||||||
if kevent.fflags != 0:
|
if kevent.fflags != 0:
|
||||||
rkey.errorCode = kevent.fflags.OSErrorCode
|
rkey.errorCode = cast[OSErrorCode](kevent.fflags)
|
||||||
else:
|
else:
|
||||||
# This assumes we are dealing with sockets.
|
# This assumes we are dealing with sockets.
|
||||||
# TODO: For future-proofing it might be a good idea to give the
|
# TODO: For future-proofing it might be a good idea to give the
|
||||||
|
|
|
||||||
|
|
@ -310,6 +310,9 @@ proc selectInto*[T](s: Selector[T], timeout: int,
|
||||||
var rset, wset, eset: FdSet
|
var rset, wset, eset: FdSet
|
||||||
|
|
||||||
if timeout != -1:
|
if timeout != -1:
|
||||||
|
when defined(genode):
|
||||||
|
tv.tv_sec = Time(timeout div 1_000)
|
||||||
|
else:
|
||||||
tv.tv_sec = timeout.int32 div 1_000
|
tv.tv_sec = timeout.int32 div 1_000
|
||||||
tv.tv_usec = (timeout.int32 %% 1_000) * 1_000
|
tv.tv_usec = (timeout.int32 %% 1_000) * 1_000
|
||||||
else:
|
else:
|
||||||
|
|
@ -391,7 +394,6 @@ proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} =
|
||||||
for i in 0..<FD_SETSIZE:
|
for i in 0..<FD_SETSIZE:
|
||||||
if s.fds[i].ident == fdi:
|
if s.fds[i].ident == fdi:
|
||||||
return true
|
return true
|
||||||
inc(i)
|
|
||||||
|
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
template withSelectLock[T](s: Selector[T], body: untyped) =
|
template withSelectLock[T](s: Selector[T], body: untyped) =
|
||||||
|
|
|
||||||
|
|
@ -1144,7 +1144,7 @@ proc processType(typeName: NimNode, obj: NimNode,
|
||||||
result = quote do:
|
result = quote do:
|
||||||
(
|
(
|
||||||
verifyJsonKind(`jsonNode`, {JString, JNull}, astToStr(`jsonNode`));
|
verifyJsonKind(`jsonNode`, {JString, JNull}, astToStr(`jsonNode`));
|
||||||
if `jsonNode`.kind == JNull: nil else: `jsonNode`.str
|
if `jsonNode`.kind == JNull: "" else: `jsonNode`.str
|
||||||
)
|
)
|
||||||
of "biggestint":
|
of "biggestint":
|
||||||
result = quote do:
|
result = quote do:
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ proc fac*(n: int): int =
|
||||||
|
|
||||||
{.push checks:off, line_dir:off, stack_trace:off.}
|
{.push checks:off, line_dir:off, stack_trace:off.}
|
||||||
|
|
||||||
when defined(Posix) and not defined(haiku):
|
when defined(Posix):
|
||||||
{.passl: "-lm".}
|
{.passl: "-lm".}
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -162,9 +162,6 @@ when not defined(JS): # C
|
||||||
proc log10*(x: float32): float32 {.importc: "log10f", header: "<math.h>".}
|
proc log10*(x: float32): float32 {.importc: "log10f", header: "<math.h>".}
|
||||||
proc log10*(x: float64): float64 {.importc: "log10", header: "<math.h>".}
|
proc log10*(x: float64): float64 {.importc: "log10", header: "<math.h>".}
|
||||||
## Computes the common logarithm (base 10) of `x`
|
## Computes the common logarithm (base 10) of `x`
|
||||||
proc log2*(x: float32): float32 {.importc: "log2f", header: "<math.h>".}
|
|
||||||
proc log2*(x: float64): float64 {.importc: "log2", header: "<math.h>".}
|
|
||||||
## Computes the binary logarithm (base 2) of `x`
|
|
||||||
proc exp*(x: float32): float32 {.importc: "expf", header: "<math.h>".}
|
proc exp*(x: float32): float32 {.importc: "expf", header: "<math.h>".}
|
||||||
proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".}
|
proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".}
|
||||||
## Computes the exponential function of `x` (pow(E, x))
|
## Computes the exponential function of `x` (pow(E, x))
|
||||||
|
|
@ -268,6 +265,8 @@ proc arcsech*[T: float32|float64](x: T): T = arccosh(1.0 / x)
|
||||||
proc arccsch*[T: float32|float64](x: T): T = arcsinh(1.0 / x)
|
proc arccsch*[T: float32|float64](x: T): T = arcsinh(1.0 / x)
|
||||||
## Computes the inverse hyperbolic cosecant of `x`
|
## Computes the inverse hyperbolic cosecant of `x`
|
||||||
|
|
||||||
|
const windowsCC89 = defined(windows) and (defined(vcc) or defined(bcc))
|
||||||
|
|
||||||
when not defined(JS): # C
|
when not defined(JS): # C
|
||||||
proc hypot*(x, y: float32): float32 {.importc: "hypotf", header: "<math.h>".}
|
proc hypot*(x, y: float32): float32 {.importc: "hypotf", header: "<math.h>".}
|
||||||
proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "<math.h>".}
|
proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "<math.h>".}
|
||||||
|
|
@ -280,6 +279,8 @@ when not defined(JS): # C
|
||||||
##
|
##
|
||||||
## To compute power between integers, use `^` e.g. 2 ^ 6
|
## To compute power between integers, use `^` e.g. 2 ^ 6
|
||||||
|
|
||||||
|
# TODO: add C89 version on windows
|
||||||
|
when not windowsCC89:
|
||||||
proc erf*(x: float32): float32 {.importc: "erff", header: "<math.h>".}
|
proc erf*(x: float32): float32 {.importc: "erff", header: "<math.h>".}
|
||||||
proc erf*(x: float64): float64 {.importc: "erf", header: "<math.h>".}
|
proc erf*(x: float64): float64 {.importc: "erf", header: "<math.h>".}
|
||||||
## The error function
|
## The error function
|
||||||
|
|
@ -314,7 +315,7 @@ when not defined(JS): # C
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## echo ceil(-2.1) ## -2.0
|
## echo ceil(-2.1) ## -2.0
|
||||||
|
|
||||||
when defined(windows) and (defined(vcc) or defined(bcc)):
|
when windowsCC89:
|
||||||
# MSVC 2010 don't have trunc/truncf
|
# MSVC 2010 don't have trunc/truncf
|
||||||
# this implementation was inspired by Go-lang Math.Trunc
|
# this implementation was inspired by Go-lang Math.Trunc
|
||||||
proc truncImpl(f: float64): float64 =
|
proc truncImpl(f: float64): float64 =
|
||||||
|
|
@ -452,6 +453,28 @@ when not defined(JS):
|
||||||
var exp: int32
|
var exp: int32
|
||||||
result = c_frexp(x, exp)
|
result = c_frexp(x, exp)
|
||||||
exponent = exp
|
exponent = exp
|
||||||
|
|
||||||
|
when windowsCC89:
|
||||||
|
# taken from Go-lang Math.Log2
|
||||||
|
const ln2 = 0.693147180559945309417232121458176568075500134360255254120680009
|
||||||
|
template log2Impl[T](x: T): T =
|
||||||
|
var exp: int32
|
||||||
|
var frac = frexp(x, exp)
|
||||||
|
# Make sure exact powers of two give an exact answer.
|
||||||
|
# Don't depend on Log(0.5)*(1/Ln2)+exp being exactly exp-1.
|
||||||
|
if frac == 0.5: return T(exp - 1)
|
||||||
|
log10(frac)*(1/ln2) + T(exp)
|
||||||
|
|
||||||
|
proc log2*(x: float32): float32 = log2Impl(x)
|
||||||
|
proc log2*(x: float64): float64 = log2Impl(x)
|
||||||
|
## Log2 returns the binary logarithm of x.
|
||||||
|
## The special cases are the same as for Log.
|
||||||
|
|
||||||
|
else:
|
||||||
|
proc log2*(x: float32): float32 {.importc: "log2f", header: "<math.h>".}
|
||||||
|
proc log2*(x: float64): float64 {.importc: "log2", header: "<math.h>".}
|
||||||
|
## Computes the binary logarithm (base 2) of `x`
|
||||||
|
|
||||||
else:
|
else:
|
||||||
proc frexp*[T: float32|float64](x: T, exponent: var int): T =
|
proc frexp*[T: float32|float64](x: T, exponent: var int): T =
|
||||||
if x == 0.0:
|
if x == 0.0:
|
||||||
|
|
@ -506,8 +529,8 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} =
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc `^`*[T](x: T, y: Natural): T =
|
proc `^`*[T](x: T, y: Natural): T =
|
||||||
## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use
|
## Computes ``x`` to the power ``y``. ``x`` must be non-negative, use
|
||||||
## `pow <#pow,float,float>` for negative exponents.
|
## `pow <#pow,float,float>`_ for negative exponents.
|
||||||
when compiles(y >= T(0)):
|
when compiles(y >= T(0)):
|
||||||
assert y >= T(0)
|
assert y >= T(0)
|
||||||
else:
|
else:
|
||||||
|
|
@ -564,7 +587,7 @@ proc lcm*[T](x, y: T): T =
|
||||||
## Computes the least common multiple of ``x`` and ``y``.
|
## Computes the least common multiple of ``x`` and ``y``.
|
||||||
x div gcd(x, y) * y
|
x div gcd(x, y) * y
|
||||||
|
|
||||||
when isMainModule and not defined(JS):
|
when isMainModule and not defined(JS) and not windowsCC89:
|
||||||
# Check for no side effect annotation
|
# Check for no side effect annotation
|
||||||
proc mySqrt(num: float): float {.noSideEffect.} =
|
proc mySqrt(num: float): float {.noSideEffect.} =
|
||||||
return sqrt(num)
|
return sqrt(num)
|
||||||
|
|
@ -692,3 +715,14 @@ when isMainModule:
|
||||||
|
|
||||||
block: # log
|
block: # log
|
||||||
doAssert log(4.0, 3.0) == ln(4.0) / ln(3.0)
|
doAssert log(4.0, 3.0) == ln(4.0) / ln(3.0)
|
||||||
|
doAssert log2(8.0'f64) == 3.0'f64
|
||||||
|
doAssert log2(4.0'f64) == 2.0'f64
|
||||||
|
doAssert log2(2.0'f64) == 1.0'f64
|
||||||
|
doAssert log2(1.0'f64) == 0.0'f64
|
||||||
|
doAssert classify(log2(0.0'f64)) == fcNegInf
|
||||||
|
|
||||||
|
doAssert log2(8.0'f32) == 3.0'f32
|
||||||
|
doAssert log2(4.0'f32) == 2.0'f32
|
||||||
|
doAssert log2(2.0'f32) == 1.0'f32
|
||||||
|
doAssert log2(1.0'f32) == 0.0'f32
|
||||||
|
doAssert classify(log2(0.0'f32)) == fcNegInf
|
||||||
|
|
|
||||||
|
|
@ -248,9 +248,10 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
|
||||||
hints.ai_socktype = toInt(sockType)
|
hints.ai_socktype = toInt(sockType)
|
||||||
hints.ai_protocol = toInt(protocol)
|
hints.ai_protocol = toInt(protocol)
|
||||||
# OpenBSD doesn't support AI_V4MAPPED and doesn't define the macro AI_V4MAPPED.
|
# OpenBSD doesn't support AI_V4MAPPED and doesn't define the macro AI_V4MAPPED.
|
||||||
# FreeBSD doesn't support AI_V4MAPPED but defines the macro.
|
# FreeBSD, Haiku don't support AI_V4MAPPED but defines the macro.
|
||||||
# https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198092
|
# https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198092
|
||||||
when not defined(freebsd) and not defined(openbsd) and not defined(netbsd) and not defined(android):
|
# https://dev.haiku-os.org/ticket/14323
|
||||||
|
when not defined(freebsd) and not defined(openbsd) and not defined(netbsd) and not defined(android) and not defined(haiku):
|
||||||
if domain == AF_INET6:
|
if domain == AF_INET6:
|
||||||
hints.ai_flags = AI_V4MAPPED
|
hints.ai_flags = AI_V4MAPPED
|
||||||
var gaiResult = getaddrinfo(address, $port, addr(hints), result)
|
var gaiResult = getaddrinfo(address, $port, addr(hints), result)
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
result = newSocket(fd, domain, sockType, protocol, buffered)
|
result = newSocket(fd, domain, sockType, protocol, buffered)
|
||||||
|
|
||||||
proc parseIPv4Address(address_str: string): IpAddress =
|
proc parseIPv4Address(addressStr: string): IpAddress =
|
||||||
## Parses IPv4 adresses
|
## Parses IPv4 adresses
|
||||||
## Raises EInvalidValue on errors
|
## Raises EInvalidValue on errors
|
||||||
var
|
var
|
||||||
|
|
@ -241,15 +241,15 @@ proc parseIPv4Address(address_str: string): IpAddress =
|
||||||
|
|
||||||
result.family = IpAddressFamily.IPv4
|
result.family = IpAddressFamily.IPv4
|
||||||
|
|
||||||
for i in 0 .. high(address_str):
|
for i in 0 .. high(addressStr):
|
||||||
if address_str[i] in strutils.Digits: # Character is a number
|
if addressStr[i] in strutils.Digits: # Character is a number
|
||||||
currentByte = currentByte * 10 +
|
currentByte = currentByte * 10 +
|
||||||
cast[uint16](ord(address_str[i]) - ord('0'))
|
cast[uint16](ord(addressStr[i]) - ord('0'))
|
||||||
if currentByte > 255'u16:
|
if currentByte > 255'u16:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Value is out of range")
|
"Invalid IP Address. Value is out of range")
|
||||||
seperatorValid = true
|
seperatorValid = true
|
||||||
elif address_str[i] == '.': # IPv4 address separator
|
elif addressStr[i] == '.': # IPv4 address separator
|
||||||
if not seperatorValid or byteCount >= 3:
|
if not seperatorValid or byteCount >= 3:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too many groups")
|
"Invalid IP Address. The address consists of too many groups")
|
||||||
|
|
@ -265,11 +265,11 @@ proc parseIPv4Address(address_str: string): IpAddress =
|
||||||
raise newException(ValueError, "Invalid IP Address")
|
raise newException(ValueError, "Invalid IP Address")
|
||||||
result.address_v4[byteCount] = cast[uint8](currentByte)
|
result.address_v4[byteCount] = cast[uint8](currentByte)
|
||||||
|
|
||||||
proc parseIPv6Address(address_str: string): IpAddress =
|
proc parseIPv6Address(addressStr: string): IpAddress =
|
||||||
## Parses IPv6 adresses
|
## Parses IPv6 adresses
|
||||||
## Raises EInvalidValue on errors
|
## Raises EInvalidValue on errors
|
||||||
result.family = IpAddressFamily.IPv6
|
result.family = IpAddressFamily.IPv6
|
||||||
if address_str.len < 2:
|
if addressStr.len < 2:
|
||||||
raise newException(ValueError, "Invalid IP Address")
|
raise newException(ValueError, "Invalid IP Address")
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -282,7 +282,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
|
||||||
v4StartPos = -1
|
v4StartPos = -1
|
||||||
byteCount = 0
|
byteCount = 0
|
||||||
|
|
||||||
for i,c in address_str:
|
for i,c in addressStr:
|
||||||
if c == ':':
|
if c == ':':
|
||||||
if not seperatorValid:
|
if not seperatorValid:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
|
|
@ -293,7 +293,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
|
||||||
"Invalid IP Address. Address contains more than one \"::\" seperator")
|
"Invalid IP Address. Address contains more than one \"::\" seperator")
|
||||||
dualColonGroup = groupCount
|
dualColonGroup = groupCount
|
||||||
seperatorValid = false
|
seperatorValid = false
|
||||||
elif i != 0 and i != high(address_str):
|
elif i != 0 and i != high(addressStr):
|
||||||
if groupCount >= 8:
|
if groupCount >= 8:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too many groups")
|
"Invalid IP Address. The address consists of too many groups")
|
||||||
|
|
@ -303,11 +303,11 @@ proc parseIPv6Address(address_str: string): IpAddress =
|
||||||
groupCount.inc()
|
groupCount.inc()
|
||||||
if dualColonGroup != -1: seperatorValid = false
|
if dualColonGroup != -1: seperatorValid = false
|
||||||
elif i == 0: # only valid if address starts with ::
|
elif i == 0: # only valid if address starts with ::
|
||||||
if address_str[1] != ':':
|
if addressStr[1] != ':':
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Address may not start with \":\"")
|
"Invalid IP Address. Address may not start with \":\"")
|
||||||
else: # i == high(address_str) - only valid if address ends with ::
|
else: # i == high(addressStr) - only valid if address ends with ::
|
||||||
if address_str[high(address_str)-1] != ':':
|
if addressStr[high(addressStr)-1] != ':':
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. Address may not end with \":\"")
|
"Invalid IP Address. Address may not end with \":\"")
|
||||||
lastWasColon = true
|
lastWasColon = true
|
||||||
|
|
@ -345,7 +345,7 @@ proc parseIPv6Address(address_str: string): IpAddress =
|
||||||
result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
|
result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
|
||||||
groupCount.inc()
|
groupCount.inc()
|
||||||
else: # Must parse IPv4 address
|
else: # Must parse IPv4 address
|
||||||
for i,c in address_str[v4StartPos..high(address_str)]:
|
for i,c in addressStr[v4StartPos..high(addressStr)]:
|
||||||
if c in strutils.Digits: # Character is a number
|
if c in strutils.Digits: # Character is a number
|
||||||
currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
|
currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
|
||||||
if currentShort > 255'u32:
|
if currentShort > 255'u32:
|
||||||
|
|
@ -386,21 +386,21 @@ proc parseIPv6Address(address_str: string): IpAddress =
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too many groups")
|
"Invalid IP Address. The address consists of too many groups")
|
||||||
|
|
||||||
proc parseIpAddress*(address_str: string): IpAddress =
|
proc parseIpAddress*(addressStr: string): IpAddress =
|
||||||
## Parses an IP address
|
## Parses an IP address
|
||||||
## Raises EInvalidValue on error
|
## Raises EInvalidValue on error
|
||||||
if address_str == nil:
|
if addressStr.len == 0:
|
||||||
raise newException(ValueError, "IP Address string is nil")
|
raise newException(ValueError, "IP Address string is empty")
|
||||||
if address_str.contains(':'):
|
if addressStr.contains(':'):
|
||||||
return parseIPv6Address(address_str)
|
return parseIPv6Address(addressStr)
|
||||||
else:
|
else:
|
||||||
return parseIPv4Address(address_str)
|
return parseIPv4Address(addressStr)
|
||||||
|
|
||||||
proc isIpAddress*(address_str: string): bool {.tags: [].} =
|
proc isIpAddress*(addressStr: string): bool {.tags: [].} =
|
||||||
## Checks if a string is an IP address
|
## Checks if a string is an IP address
|
||||||
## Returns true if it is, false otherwise
|
## Returns true if it is, false otherwise
|
||||||
try:
|
try:
|
||||||
discard parseIpAddress(address_str)
|
discard parseIpAddress(addressStr)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
@ -587,7 +587,7 @@ when defineSsl:
|
||||||
proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar;
|
proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar;
|
||||||
max_psk_len: cuint): cuint {.cdecl.} =
|
max_psk_len: cuint): cuint {.cdecl.} =
|
||||||
let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX)
|
let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX)
|
||||||
let hintString = if hint == nil: nil else: $hint
|
let hintString = if hint == nil: "" else: $hint
|
||||||
let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString)
|
let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString)
|
||||||
if psk.len.cuint > max_psk_len:
|
if psk.len.cuint > max_psk_len:
|
||||||
return 0
|
return 0
|
||||||
|
|
@ -657,7 +657,7 @@ when defineSsl:
|
||||||
|
|
||||||
proc wrapConnectedSocket*(ctx: SSLContext, socket: Socket,
|
proc wrapConnectedSocket*(ctx: SSLContext, socket: Socket,
|
||||||
handshake: SslHandshakeType,
|
handshake: SslHandshakeType,
|
||||||
hostname: string = nil) =
|
hostname: string = "") =
|
||||||
## Wraps a connected socket in an SSL context. This function effectively
|
## Wraps a connected socket in an SSL context. This function effectively
|
||||||
## turns ``socket`` into an SSL socket.
|
## turns ``socket`` into an SSL socket.
|
||||||
## ``hostname`` should be specified so that the client knows which hostname
|
## ``hostname`` should be specified so that the client knows which hostname
|
||||||
|
|
@ -671,7 +671,7 @@ when defineSsl:
|
||||||
wrapSocket(ctx, socket)
|
wrapSocket(ctx, socket)
|
||||||
case handshake
|
case handshake
|
||||||
of handshakeAsClient:
|
of handshakeAsClient:
|
||||||
if not hostname.isNil and not isIpAddress(hostname):
|
if hostname.len > 0 and not isIpAddress(hostname):
|
||||||
# Discard result in case OpenSSL version doesn't support SNI, or we're
|
# Discard result in case OpenSSL version doesn't support SNI, or we're
|
||||||
# not using TLSv1+
|
# not using TLSv1+
|
||||||
discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
|
discard SSL_set_tlsext_host_name(socket.sslHandle, hostname)
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ proc get*[T](self: Option[T]): T =
|
||||||
## Returns contents of the Option. If it is none, then an exception is
|
## Returns contents of the Option. If it is none, then an exception is
|
||||||
## thrown.
|
## thrown.
|
||||||
if self.isNone:
|
if self.isNone:
|
||||||
raise UnpackError(msg : "Can't obtain a value from a `none`")
|
raise UnpackError(msg: "Can't obtain a value from a `none`")
|
||||||
self.val
|
self.val
|
||||||
|
|
||||||
proc get*[T](self: Option[T], otherwise: T): T =
|
proc get*[T](self: Option[T], otherwise: T): T =
|
||||||
|
|
@ -139,6 +139,13 @@ proc get*[T](self: Option[T], otherwise: T): T =
|
||||||
else:
|
else:
|
||||||
otherwise
|
otherwise
|
||||||
|
|
||||||
|
proc get*[T](self: var Option[T]): var T =
|
||||||
|
## Returns contents of the Option. If it is none, then an exception is
|
||||||
|
## thrown.
|
||||||
|
if self.isNone:
|
||||||
|
raise UnpackError(msg: "Can't obtain a value from a `none`")
|
||||||
|
return self.val
|
||||||
|
|
||||||
proc map*[T](self: Option[T], callback: proc (input: T)) =
|
proc map*[T](self: Option[T], callback: proc (input: T)) =
|
||||||
## Applies a callback to the value in this Option
|
## Applies a callback to the value in this Option
|
||||||
if self.isSome:
|
if self.isSome:
|
||||||
|
|
@ -187,9 +194,11 @@ proc `$`*[T](self: Option[T]): string =
|
||||||
## If the option does not have a value, the result will be `None[T]` where `T` is the name of
|
## If the option does not have a value, the result will be `None[T]` where `T` is the name of
|
||||||
## the type contained in the option.
|
## the type contained in the option.
|
||||||
if self.isSome:
|
if self.isSome:
|
||||||
"Some(" & $self.val & ")"
|
result = "Some("
|
||||||
|
result.addQuoted self.val
|
||||||
|
result.add ")"
|
||||||
else:
|
else:
|
||||||
"None[" & name(T) & "]"
|
result = "None[" & name(T) & "]"
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
import unittest, sequtils
|
import unittest, sequtils
|
||||||
|
|
@ -240,7 +249,7 @@ when isMainModule:
|
||||||
check(stringNone.get("Correct") == "Correct")
|
check(stringNone.get("Correct") == "Correct")
|
||||||
|
|
||||||
test "$":
|
test "$":
|
||||||
check($(some("Correct")) == "Some(Correct)")
|
check($(some("Correct")) == "Some(\"Correct\")")
|
||||||
check($(stringNone) == "None[string]")
|
check($(stringNone) == "None[string]")
|
||||||
|
|
||||||
test "map with a void result":
|
test "map with a void result":
|
||||||
|
|
|
||||||
|
|
@ -615,7 +615,10 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
|
|
||||||
when not declared(ENOENT) and not defined(Windows):
|
when not declared(ENOENT) and not defined(Windows):
|
||||||
when NoFakeVars:
|
when NoFakeVars:
|
||||||
|
when not defined(haiku):
|
||||||
const ENOENT = cint(2) # 2 on most systems including Solaris
|
const ENOENT = cint(2) # 2 on most systems including Solaris
|
||||||
|
else:
|
||||||
|
const ENOENT = cint(-2147459069)
|
||||||
else:
|
else:
|
||||||
var ENOENT {.importc, header: "<errno.h>".}: cint
|
var ENOENT {.importc, header: "<errno.h>".}: cint
|
||||||
|
|
||||||
|
|
@ -972,6 +975,14 @@ proc rawCreateDir(dir: string): bool =
|
||||||
result = false
|
result = false
|
||||||
else:
|
else:
|
||||||
raiseOSError(osLastError(), dir)
|
raiseOSError(osLastError(), dir)
|
||||||
|
elif defined(haiku):
|
||||||
|
let res = mkdir(dir, 0o777)
|
||||||
|
if res == 0'i32:
|
||||||
|
result = true
|
||||||
|
elif errno == EEXIST or errno == EROFS:
|
||||||
|
result = false
|
||||||
|
else:
|
||||||
|
raiseOSError(osLastError(), dir)
|
||||||
elif defined(posix):
|
elif defined(posix):
|
||||||
let res = mkdir(dir, 0o777)
|
let res = mkdir(dir, 0o777)
|
||||||
if res == 0'i32:
|
if res == 0'i32:
|
||||||
|
|
@ -1352,9 +1363,15 @@ elif defined(nintendoswitch):
|
||||||
proc paramCount*(): int {.tags: [ReadIOEffect].} =
|
proc paramCount*(): int {.tags: [ReadIOEffect].} =
|
||||||
raise newException(OSError, "paramCount is not implemented on Nintendo Switch")
|
raise newException(OSError, "paramCount is not implemented on Nintendo Switch")
|
||||||
|
|
||||||
|
elif defined(genode):
|
||||||
|
proc paramStr*(i: int): TaintedString =
|
||||||
|
raise newException(OSError, "paramStr is not implemented on Genode")
|
||||||
|
|
||||||
|
proc paramCount*(): int =
|
||||||
|
raise newException(OSError, "paramCount is not implemented on Genode")
|
||||||
|
|
||||||
elif not defined(createNimRtl) and
|
elif not defined(createNimRtl) and
|
||||||
not(defined(posix) and appType == "lib") and
|
not(defined(posix) and appType == "lib"):
|
||||||
not defined(genode):
|
|
||||||
# On Posix, there is no portable way to get the command line from a DLL.
|
# On Posix, there is no portable way to get the command line from a DLL.
|
||||||
var
|
var
|
||||||
cmdCount {.importc: "cmdCount".}: cint
|
cmdCount {.importc: "cmdCount".}: cint
|
||||||
|
|
|
||||||
|
|
@ -525,14 +525,14 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1",
|
||||||
## Returns the config directory of the current user for applications.
|
## Returns the config directory of the current user for applications.
|
||||||
##
|
##
|
||||||
## On non-Windows OSs, this proc conforms to the XDG Base Directory
|
## On non-Windows OSs, this proc conforms to the XDG Base Directory
|
||||||
## spec. Thus, this proc returns the value of the XDG_CONFIG_DIR environment
|
## spec. Thus, this proc returns the value of the XDG_CONFIG_HOME environment
|
||||||
## variable if it is set, and returns the default configuration directory,
|
## variable if it is set, and returns the default configuration directory,
|
||||||
## "~/.config/", otherwise.
|
## "~/.config/", otherwise.
|
||||||
##
|
##
|
||||||
## An OS-dependent trailing slash is always present at the end of the
|
## An OS-dependent trailing slash is always present at the end of the
|
||||||
## returned string; `\\` on Windows and `/` on all other OSs.
|
## returned string; `\\` on Windows and `/` on all other OSs.
|
||||||
when defined(windows): return string(getEnv("APPDATA")) & "\\"
|
when defined(windows): return string(getEnv("APPDATA")) & "\\"
|
||||||
elif getEnv("XDG_CONFIG_DIR"): return string(getEnv("XDG_CONFIG_DIR")) & "/"
|
elif getEnv("XDG_CONFIG_HOME"): return string(getEnv("XDG_CONFIG_HOME")) & "/"
|
||||||
else: return string(getEnv("HOME")) & "/.config/"
|
else: return string(getEnv("HOME")) & "/.config/"
|
||||||
|
|
||||||
proc getTempDir*(): string {.rtl, extern: "nos$1",
|
proc getTempDir*(): string {.rtl, extern: "nos$1",
|
||||||
|
|
@ -553,25 +553,25 @@ proc getTempDir*(): string {.rtl, extern: "nos$1",
|
||||||
|
|
||||||
proc expandTilde*(path: string): string {.
|
proc expandTilde*(path: string): string {.
|
||||||
tags: [ReadEnvEffect, ReadIOEffect].} =
|
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||||
## Expands a path starting with ``~/`` to a full path.
|
## Expands ``~`` or a path starting with ``~/`` to a full path, replacing
|
||||||
|
## ``~`` with ``getHomeDir()`` (otherwise returns ``path`` unmodified).
|
||||||
##
|
##
|
||||||
## If `path` starts with the tilde character and is followed by `/` or `\\`
|
## Windows: this is still supported despite Windows platform not having this
|
||||||
## this proc will return the reminder of the path appended to the result of
|
## convention; also, both ``~/`` and ``~\`` are handled.
|
||||||
## the getHomeDir() proc, otherwise the input path will be returned without
|
runnableExamples:
|
||||||
## modification.
|
doAssert expandTilde("~" / "appname.cfg") == getHomeDir() / "appname.cfg"
|
||||||
##
|
if len(path) == 0 or path[0] != '~':
|
||||||
## The behaviour of this proc is the same on the Windows platform despite
|
result = path
|
||||||
## not having this convention. Example:
|
elif len(path) == 1:
|
||||||
##
|
result = getHomeDir()
|
||||||
## .. code-block:: nim
|
elif (path[1] in {DirSep, AltSep}):
|
||||||
## let configFile = expandTilde("~" / "appname.cfg")
|
|
||||||
## echo configFile
|
|
||||||
## # --> C:\Users\amber\appname.cfg
|
|
||||||
if len(path) > 1 and path[0] == '~' and (path[1] == '/' or path[1] == '\\'):
|
|
||||||
result = getHomeDir() / path.substr(2)
|
result = getHomeDir() / path.substr(2)
|
||||||
else:
|
else:
|
||||||
|
# TODO: handle `~bob` and `~bob/` which means home of bob
|
||||||
result = path
|
result = path
|
||||||
|
|
||||||
|
# TODO: consider whether quoteShellPosix, quoteShellWindows, quoteShell, quoteShellCommand
|
||||||
|
# belong in `strutils` instead; they are not specific to paths
|
||||||
proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
|
proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
|
||||||
## Quote s, so it can be safely passed to Windows API.
|
## Quote s, so it can be safely passed to Windows API.
|
||||||
## Based on Python's subprocess.list2cmdline
|
## Based on Python's subprocess.list2cmdline
|
||||||
|
|
@ -623,6 +623,18 @@ when defined(windows) or defined(posix) or defined(nintendoswitch):
|
||||||
else:
|
else:
|
||||||
return quoteShellPosix(s)
|
return quoteShellPosix(s)
|
||||||
|
|
||||||
|
proc quoteShellCommand*(args: openArray[string]): string =
|
||||||
|
## Concatenates and quotes shell arguments `args`
|
||||||
|
runnableExamples:
|
||||||
|
when defined(posix):
|
||||||
|
assert quoteShellCommand(["aaa", "", "c d"]) == "aaa '' 'c d'"
|
||||||
|
when defined(windows):
|
||||||
|
assert quoteShellCommand(["aaa", "", "c d"]) == "aaa \"\" \"c d\""
|
||||||
|
# can't use `map` pending https://github.com/nim-lang/Nim/issues/8303
|
||||||
|
for i in 0..<args.len:
|
||||||
|
if i > 0: result.add " "
|
||||||
|
result.add quoteShell(args[i])
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
assert quoteShellWindows("aaa") == "aaa"
|
assert quoteShellWindows("aaa") == "aaa"
|
||||||
assert quoteShellWindows("aaa\"") == "aaa\\\""
|
assert quoteShellWindows("aaa\"") == "aaa\\\""
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,10 @@ type
|
||||||
proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
|
proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
|
||||||
## Initalizes option parses with cmdline. cmdline should not contain
|
## Initalizes option parses with cmdline. cmdline should not contain
|
||||||
## argument 0 - program name.
|
## argument 0 - program name.
|
||||||
## If cmdline == nil default to current command line arguments.
|
## If cmdline.len == 0 default to current command line arguments.
|
||||||
result.remainingShortOptions = ""
|
result.remainingShortOptions = ""
|
||||||
when not defined(createNimRtl):
|
when not defined(createNimRtl):
|
||||||
if cmdline == nil:
|
if cmdline.len == 0:
|
||||||
result.cmd = commandLineParams()
|
result.cmd = commandLineParams()
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
|
@ -60,7 +60,7 @@ proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} =
|
||||||
## and calls initOptParser(openarray[string])
|
## and calls initOptParser(openarray[string])
|
||||||
## Do not use.
|
## Do not use.
|
||||||
if cmdline == "": # backward compatibility
|
if cmdline == "": # backward compatibility
|
||||||
return initOptParser(seq[string](nil))
|
return initOptParser(@[])
|
||||||
else:
|
else:
|
||||||
return initOptParser(cmdline.split)
|
return initOptParser(cmdline.split)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ type
|
||||||
kind: XmlEventKind
|
kind: XmlEventKind
|
||||||
err: XmlErrorKind
|
err: XmlErrorKind
|
||||||
state: ParserState
|
state: ParserState
|
||||||
|
cIsEmpty: bool
|
||||||
filename: string
|
filename: string
|
||||||
options: set[XmlParseOption]
|
options: set[XmlParseOption]
|
||||||
|
|
||||||
|
|
@ -125,7 +126,8 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
|
||||||
my.kind = xmlError
|
my.kind = xmlError
|
||||||
my.a = ""
|
my.a = ""
|
||||||
my.b = ""
|
my.b = ""
|
||||||
my.c = nil
|
my.c = ""
|
||||||
|
my.cIsEmpty = true
|
||||||
my.options = options
|
my.options = options
|
||||||
|
|
||||||
proc close*(my: var XmlParser) {.inline.} =
|
proc close*(my: var XmlParser) {.inline.} =
|
||||||
|
|
@ -482,6 +484,7 @@ proc parseTag(my: var XmlParser) =
|
||||||
my.kind = xmlElementOpen
|
my.kind = xmlElementOpen
|
||||||
my.state = stateAttr
|
my.state = stateAttr
|
||||||
my.c = my.a # save for later
|
my.c = my.a # save for later
|
||||||
|
my.cIsEmpty = false
|
||||||
else:
|
else:
|
||||||
my.kind = xmlElementStart
|
my.kind = xmlElementStart
|
||||||
let slash = my.buf[my.bufpos] == '/'
|
let slash = my.buf[my.bufpos] == '/'
|
||||||
|
|
@ -490,7 +493,8 @@ proc parseTag(my: var XmlParser) =
|
||||||
if slash and my.buf[my.bufpos] == '>':
|
if slash and my.buf[my.bufpos] == '>':
|
||||||
inc(my.bufpos)
|
inc(my.bufpos)
|
||||||
my.state = stateEmptyElementTag
|
my.state = stateEmptyElementTag
|
||||||
my.c = nil
|
my.c = ""
|
||||||
|
my.cIsEmpty = true
|
||||||
elif my.buf[my.bufpos] == '>':
|
elif my.buf[my.bufpos] == '>':
|
||||||
inc(my.bufpos)
|
inc(my.bufpos)
|
||||||
else:
|
else:
|
||||||
|
|
@ -678,7 +682,7 @@ proc next*(my: var XmlParser) =
|
||||||
of stateEmptyElementTag:
|
of stateEmptyElementTag:
|
||||||
my.state = stateNormal
|
my.state = stateNormal
|
||||||
my.kind = xmlElementEnd
|
my.kind = xmlElementEnd
|
||||||
if not my.c.isNil:
|
if not my.cIsEmpty:
|
||||||
my.a = my.c
|
my.a = my.c
|
||||||
of stateError:
|
of stateError:
|
||||||
my.kind = xmlError
|
my.kind = xmlError
|
||||||
|
|
|
||||||
|
|
@ -765,7 +765,7 @@ template fillMatches(s, caps, c) =
|
||||||
if startIdx != -1:
|
if startIdx != -1:
|
||||||
caps[k] = substr(s, startIdx, endIdx)
|
caps[k] = substr(s, startIdx, endIdx)
|
||||||
else:
|
else:
|
||||||
caps[k] = nil
|
caps[k] = ""
|
||||||
|
|
||||||
proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
|
proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
|
||||||
start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
|
start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
|
||||||
|
|
@ -1854,7 +1854,7 @@ when isMainModule:
|
||||||
assert match("prefix/start", peg"^start$", 7)
|
assert match("prefix/start", peg"^start$", 7)
|
||||||
|
|
||||||
if "foo" =~ peg"{'a'}?.*":
|
if "foo" =~ peg"{'a'}?.*":
|
||||||
assert matches[0] == nil
|
assert matches[0].len == 0
|
||||||
else: assert false
|
else: assert false
|
||||||
|
|
||||||
if "foo" =~ peg"{''}.*":
|
if "foo" =~ peg"{''}.*":
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ type
|
||||||
length: int
|
length: int
|
||||||
data: string # != nil if a leaf
|
data: string # != nil if a leaf
|
||||||
|
|
||||||
proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
|
proc isConc(r: Rope): bool {.inline.} = return r.length > 0
|
||||||
|
|
||||||
# Note that the left and right pointers are not needed for leafs.
|
# Note that the left and right pointers are not needed for leafs.
|
||||||
# Leaves have relatively high memory overhead (~30 bytes on a 32
|
# Leaves have relatively high memory overhead (~30 bytes on a 32
|
||||||
|
|
@ -50,12 +50,12 @@ proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
|
||||||
proc len*(a: Rope): int {.rtl, extern: "nro$1".} =
|
proc len*(a: Rope): int {.rtl, extern: "nro$1".} =
|
||||||
## the rope's length
|
## the rope's length
|
||||||
if a == nil: result = 0
|
if a == nil: result = 0
|
||||||
else: result = a.length
|
else: result = abs a.length
|
||||||
|
|
||||||
proc newRope(): Rope = new(result)
|
proc newRope(): Rope = new(result)
|
||||||
proc newRope(data: string): Rope =
|
proc newRope(data: string): Rope =
|
||||||
new(result)
|
new(result)
|
||||||
result.length = len(data)
|
result.length = -len(data)
|
||||||
result.data = data
|
result.data = data
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -129,7 +129,7 @@ proc insertInCache(s: string, tree: Rope): Rope =
|
||||||
result.left = t
|
result.left = t
|
||||||
t.right = nil
|
t.right = nil
|
||||||
|
|
||||||
proc rope*(s: string = nil): Rope {.rtl, extern: "nro$1Str".} =
|
proc rope*(s: string = ""): Rope {.rtl, extern: "nro$1Str".} =
|
||||||
## Converts a string to a rope.
|
## Converts a string to a rope.
|
||||||
if s.len == 0:
|
if s.len == 0:
|
||||||
result = nil
|
result = nil
|
||||||
|
|
@ -170,17 +170,7 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
|
||||||
result = a
|
result = a
|
||||||
else:
|
else:
|
||||||
result = newRope()
|
result = newRope()
|
||||||
result.length = a.length + b.length
|
result.length = abs(a.length) + abs(b.length)
|
||||||
when false:
|
|
||||||
# XXX rebalancing would be nice, but is too expensive.
|
|
||||||
result.left = a.left
|
|
||||||
var x = newRope()
|
|
||||||
x.left = a.right
|
|
||||||
x.right = b
|
|
||||||
result.right = x
|
|
||||||
else:
|
|
||||||
result.left = a
|
|
||||||
result.right = b
|
|
||||||
|
|
||||||
proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
|
proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
|
||||||
## the concatenation operator for ropes.
|
## the concatenation operator for ropes.
|
||||||
|
|
@ -229,7 +219,6 @@ iterator leaves*(r: Rope): string =
|
||||||
stack.add(it.right)
|
stack.add(it.right)
|
||||||
it = it.left
|
it = it.left
|
||||||
assert(it != nil)
|
assert(it != nil)
|
||||||
assert(it.data != nil)
|
|
||||||
yield it.data
|
yield it.data
|
||||||
|
|
||||||
iterator items*(r: Rope): char =
|
iterator items*(r: Rope): char =
|
||||||
|
|
@ -250,54 +239,6 @@ proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}=
|
||||||
result = newStringOfCap(r.len)
|
result = newStringOfCap(r.len)
|
||||||
for s in leaves(r): add(result, s)
|
for s in leaves(r): add(result, s)
|
||||||
|
|
||||||
when false:
|
|
||||||
# Format string caching seems reasonable: All leaves can be shared and format
|
|
||||||
# string parsing has to be done only once. A compiled format string is stored
|
|
||||||
# as a rope. A negative length is used for the index into the args array.
|
|
||||||
proc compiledArg(idx: int): Rope =
|
|
||||||
new(result)
|
|
||||||
result.length = -idx
|
|
||||||
|
|
||||||
proc compileFrmt(frmt: string): Rope =
|
|
||||||
var i = 0
|
|
||||||
var length = len(frmt)
|
|
||||||
result = nil
|
|
||||||
var num = 0
|
|
||||||
while i < length:
|
|
||||||
if frmt[i] == '$':
|
|
||||||
inc(i)
|
|
||||||
case frmt[i]
|
|
||||||
of '$':
|
|
||||||
add(result, "$")
|
|
||||||
inc(i)
|
|
||||||
of '#':
|
|
||||||
inc(i)
|
|
||||||
add(result, compiledArg(num+1))
|
|
||||||
inc(num)
|
|
||||||
of '0'..'9':
|
|
||||||
var j = 0
|
|
||||||
while true:
|
|
||||||
j = j * 10 + ord(frmt[i]) - ord('0')
|
|
||||||
inc(i)
|
|
||||||
if frmt[i] notin {'0'..'9'}: break
|
|
||||||
add(s, compiledArg(j))
|
|
||||||
of '{':
|
|
||||||
inc(i)
|
|
||||||
var j = 0
|
|
||||||
while frmt[i] in {'0'..'9'}:
|
|
||||||
j = j * 10 + ord(frmt[i]) - ord('0')
|
|
||||||
inc(i)
|
|
||||||
if frmt[i] == '}': inc(i)
|
|
||||||
else: raise newException(EInvalidValue, "invalid format string")
|
|
||||||
add(s, compiledArg(j))
|
|
||||||
else: raise newException(EInvalidValue, "invalid format string")
|
|
||||||
var start = i
|
|
||||||
while i < length:
|
|
||||||
if frmt[i] != '$': inc(i)
|
|
||||||
else: break
|
|
||||||
if i - 1 >= start:
|
|
||||||
add(result, substr(frmt, start, i-1))
|
|
||||||
|
|
||||||
proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
|
proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
|
||||||
rtl, extern: "nroFormat".} =
|
rtl, extern: "nroFormat".} =
|
||||||
## `%` substitution operator for ropes. Does not support the ``$identifier``
|
## `%` substitution operator for ropes. Does not support the ``$identifier``
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,7 @@ proc newSmtp*(useSsl = false, debug=false,
|
||||||
when compiledWithSsl:
|
when compiledWithSsl:
|
||||||
sslContext.wrapSocket(result.sock)
|
sslContext.wrapSocket(result.sock)
|
||||||
else:
|
else:
|
||||||
raise newException(SystemError,
|
{.error: "SMTP module compiled without SSL support".}
|
||||||
"SMTP module compiled without SSL support")
|
|
||||||
|
|
||||||
proc newAsyncSmtp*(useSsl = false, debug=false,
|
proc newAsyncSmtp*(useSsl = false, debug=false,
|
||||||
sslContext = defaultSslContext): AsyncSmtp =
|
sslContext = defaultSslContext): AsyncSmtp =
|
||||||
|
|
@ -133,8 +132,7 @@ proc newAsyncSmtp*(useSsl = false, debug=false,
|
||||||
when compiledWithSsl:
|
when compiledWithSsl:
|
||||||
sslContext.wrapSocket(result.sock)
|
sslContext.wrapSocket(result.sock)
|
||||||
else:
|
else:
|
||||||
raise newException(SystemError,
|
{.error: "SMTP module compiled without SSL support".}
|
||||||
"SMTP module compiled without SSL support")
|
|
||||||
|
|
||||||
proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] =
|
proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] =
|
||||||
var retFuture = newFuture[void]()
|
var retFuture = newFuture[void]()
|
||||||
|
|
|
||||||
|
|
@ -377,6 +377,9 @@ when not defined(js):
|
||||||
|
|
||||||
proc ssClose(s: Stream) =
|
proc ssClose(s: Stream) =
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
|
when defined(nimNoNilSeqs):
|
||||||
|
s.data = ""
|
||||||
|
else:
|
||||||
s.data = nil
|
s.data = nil
|
||||||
|
|
||||||
proc newStringStream*(s: string = ""): StringStream =
|
proc newStringStream*(s: string = ""): StringStream =
|
||||||
|
|
|
||||||
|
|
@ -358,9 +358,6 @@ proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl,
|
||||||
|
|
||||||
proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrWhitespace".} =
|
proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrWhitespace".} =
|
||||||
## Checks if `s` is nil or consists entirely of whitespace characters.
|
## Checks if `s` is nil or consists entirely of whitespace characters.
|
||||||
if len(s) == 0:
|
|
||||||
return true
|
|
||||||
|
|
||||||
result = true
|
result = true
|
||||||
for c in s:
|
for c in s:
|
||||||
if not c.isSpaceAscii():
|
if not c.isSpaceAscii():
|
||||||
|
|
@ -624,12 +621,13 @@ iterator rsplit*(s: string, sep: string, maxsplit: int = -1,
|
||||||
## Substrings are separated from the right by the string `sep`
|
## Substrings are separated from the right by the string `sep`
|
||||||
rsplitCommon(s, sep, maxsplit, sep.len)
|
rsplitCommon(s, sep, maxsplit, sep.len)
|
||||||
|
|
||||||
iterator splitLines*(s: string): string =
|
iterator splitLines*(s: string, keepEol = false): string =
|
||||||
## Splits the string `s` into its containing lines.
|
## Splits the string `s` into its containing lines.
|
||||||
##
|
##
|
||||||
## Every `character literal <manual.html#character-literals>`_ newline
|
## Every `character literal <manual.html#character-literals>`_ newline
|
||||||
## combination (CR, LF, CR-LF) is supported. The result strings contain no
|
## combination (CR, LF, CR-LF) is supported. The result strings contain no
|
||||||
## trailing ``\n``.
|
## trailing end of line characters unless parameter ``keepEol`` is set to
|
||||||
|
## ``true``.
|
||||||
##
|
##
|
||||||
## Example:
|
## Example:
|
||||||
##
|
##
|
||||||
|
|
@ -649,22 +647,30 @@ iterator splitLines*(s: string): string =
|
||||||
## ""
|
## ""
|
||||||
var first = 0
|
var first = 0
|
||||||
var last = 0
|
var last = 0
|
||||||
|
var eolpos = 0
|
||||||
while true:
|
while true:
|
||||||
while last < s.len and s[last] notin {'\c', '\l'}: inc(last)
|
while last < s.len and s[last] notin {'\c', '\l'}: inc(last)
|
||||||
yield substr(s, first, last-1)
|
|
||||||
# skip newlines:
|
eolpos = last
|
||||||
if last >= s.len: break
|
if last < s.len:
|
||||||
if s[last] == '\l': inc(last)
|
if s[last] == '\l': inc(last)
|
||||||
elif s[last] == '\c':
|
elif s[last] == '\c':
|
||||||
inc(last)
|
inc(last)
|
||||||
if last < s.len and s[last] == '\l': inc(last)
|
if last < s.len and s[last] == '\l': inc(last)
|
||||||
|
|
||||||
|
yield substr(s, first, if keepEol: last-1 else: eolpos-1)
|
||||||
|
|
||||||
|
# no eol characters consumed means that the string is over
|
||||||
|
if eolpos == last:
|
||||||
|
break
|
||||||
|
|
||||||
first = last
|
first = last
|
||||||
|
|
||||||
proc splitLines*(s: string): seq[string] {.noSideEffect,
|
proc splitLines*(s: string, keepEol = false): seq[string] {.noSideEffect,
|
||||||
rtl, extern: "nsuSplitLines".} =
|
rtl, extern: "nsuSplitLines".} =
|
||||||
## The same as the `splitLines <#splitLines.i,string>`_ iterator, but is a
|
## The same as the `splitLines <#splitLines.i,string>`_ iterator, but is a
|
||||||
## proc that returns a sequence of substrings.
|
## proc that returns a sequence of substrings.
|
||||||
accumulateResult(splitLines(s))
|
accumulateResult(splitLines(s, keepEol=keepEol))
|
||||||
|
|
||||||
proc countLines*(s: string): int {.noSideEffect,
|
proc countLines*(s: string): int {.noSideEffect,
|
||||||
rtl, extern: "nsuCountLines".} =
|
rtl, extern: "nsuCountLines".} =
|
||||||
|
|
@ -1369,7 +1375,9 @@ proc find*(s: string, sub: char, start: Natural = 0, last: Natural = 0): int {.n
|
||||||
if sub == s[i]: return i
|
if sub == s[i]: return i
|
||||||
else:
|
else:
|
||||||
when hasCStringBuiltin:
|
when hasCStringBuiltin:
|
||||||
let found = c_memchr(s[start].unsafeAddr, sub, last-start+1)
|
let L = last-start+1
|
||||||
|
if L > 0:
|
||||||
|
let found = c_memchr(s[start].unsafeAddr, sub, L)
|
||||||
if not found.isNil:
|
if not found.isNil:
|
||||||
return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring)
|
return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1518,7 +1526,7 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
|
||||||
elif subLen == 1:
|
elif subLen == 1:
|
||||||
# when the pattern is a single char, we use a faster
|
# when the pattern is a single char, we use a faster
|
||||||
# char-based search that doesn't need a skip table:
|
# char-based search that doesn't need a skip table:
|
||||||
var c = sub[0]
|
let c = sub[0]
|
||||||
let last = s.high
|
let last = s.high
|
||||||
var i = 0
|
var i = 0
|
||||||
while true:
|
while true:
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue