mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
125 Commits
v1.6.14
...
version-1-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a598a4945 | ||
|
|
5360d076f3 | ||
|
|
71467ecd86 | ||
|
|
ec324ad073 | ||
|
|
9ce81868a8 | ||
|
|
d993aff496 | ||
|
|
786bbff1ae | ||
|
|
fda43d1f0a | ||
|
|
6789859503 | ||
|
|
d9b1477b81 | ||
|
|
3864066408 | ||
|
|
53424c0036 | ||
|
|
6a63df181f | ||
|
|
b7b3f87719 | ||
|
|
8ebb4dc30a | ||
|
|
19fdbfc173 | ||
|
|
8f9fde0615 | ||
|
|
e6ee956845 | ||
|
|
afced7d9ab | ||
|
|
51c86fdae7 | ||
|
|
d08bba579d | ||
|
|
ac1dc03258 | ||
|
|
e8fe9275b5 | ||
|
|
0f97dd6fb3 | ||
|
|
e3bcbf5f15 | ||
|
|
d84e2d3f63 | ||
|
|
7912685905 | ||
|
|
2cc4da8fd4 | ||
|
|
a749a8b742 | ||
|
|
9a87057f0b | ||
|
|
efd5ed7328 | ||
|
|
2e87171e14 | ||
|
|
9cbd8695e7 | ||
|
|
6f0cad6843 | ||
|
|
ef10224e61 | ||
|
|
f3382743dd | ||
|
|
1dab585a26 | ||
|
|
a77ca1a4bf | ||
|
|
0779a5e11b | ||
|
|
a17c077f78 | ||
|
|
47010a3919 | ||
|
|
3c9b68dc15 | ||
|
|
ec72abc7b7 | ||
|
|
a08f56f9ba | ||
|
|
246267aa52 | ||
|
|
ce8d9dd1cb | ||
|
|
4fc535fbd6 | ||
|
|
2d529edf3e | ||
|
|
d37901fe06 | ||
|
|
dc59e67a12 | ||
|
|
09f7be13b6 | ||
|
|
d80397c7d7 | ||
|
|
efa3479e4e | ||
|
|
e8ec3efd3d | ||
|
|
8f102f9e62 | ||
|
|
876f6d69a8 | ||
|
|
50173ec7ec | ||
|
|
ecab260330 | ||
|
|
43ce0558b4 | ||
|
|
19b3f8c0ea | ||
|
|
5ad4b72ac7 | ||
|
|
d7dfbf026b | ||
|
|
79a1990774 | ||
|
|
106cde1ff8 | ||
|
|
965eeb68e2 | ||
|
|
0dbac38d12 | ||
|
|
f16e4dd22a | ||
|
|
ede6bc4d67 | ||
|
|
d2f91ab1b9 | ||
|
|
69faab3cf6 | ||
|
|
b7a1210964 | ||
|
|
0d5999e6a8 | ||
|
|
60dc41a5e4 | ||
|
|
ba5d873f63 | ||
|
|
f55f3d6ffd | ||
|
|
118f83f965 | ||
|
|
72afd29a9a | ||
|
|
30921aaff5 | ||
|
|
a3b65da80f | ||
|
|
ba2d8ba468 | ||
|
|
0ac3461c7d | ||
|
|
e7fc94e130 | ||
|
|
44708f4b01 | ||
|
|
0e9250264b | ||
|
|
5ffd507014 | ||
|
|
322fc31041 | ||
|
|
5ab9945345 | ||
|
|
b0cee7c0c5 | ||
|
|
5e4648232b | ||
|
|
3bd03d71a0 | ||
|
|
238efc025e | ||
|
|
a66158dd3d | ||
|
|
6863b5d289 | ||
|
|
9d573f4a1d | ||
|
|
070ecb036c | ||
|
|
107ec62baf | ||
|
|
ffcccd5986 | ||
|
|
c001b11320 | ||
|
|
e4c13c3fd4 | ||
|
|
6b11a9ec28 | ||
|
|
173a15b370 | ||
|
|
c4380107d6 | ||
|
|
09fe696fdd | ||
|
|
6fbff263e6 | ||
|
|
fcaacbf374 | ||
|
|
2d19520b5c | ||
|
|
1cca8ccca0 | ||
|
|
a9f1e2dfcd | ||
|
|
7a747fe320 | ||
|
|
547f205794 | ||
|
|
fa3639ba33 | ||
|
|
cd0f805832 | ||
|
|
579efdabb0 | ||
|
|
7b99712bcf | ||
|
|
58c7474838 | ||
|
|
a2521b1dc7 | ||
|
|
5d39a8283c | ||
|
|
01ef1e1500 | ||
|
|
80ece5921f | ||
|
|
bd4609f20e | ||
|
|
b901e94936 | ||
|
|
0cb84726d0 | ||
|
|
1cd48e4b2a | ||
|
|
bb56a37732 | ||
|
|
d1b5df06b0 |
23
.github/workflows/ci_docs.yml
vendored
23
.github/workflows/ci_docs.yml
vendored
@@ -2,10 +2,10 @@ name: Nim Docs CI
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'compiler/docgen.nim'
|
||||
- 'compiler/renderverbatim.nim'
|
||||
- 'compiler/**.nim'
|
||||
- 'config/nimdoc.cfg'
|
||||
- 'doc/**.rst'
|
||||
- 'doc/**.md'
|
||||
- 'doc/nimdoc.css'
|
||||
- 'lib/**.nim'
|
||||
- 'nimdoc/testproject/expected/testproject.html'
|
||||
@@ -13,13 +13,14 @@ on:
|
||||
- 'tools/kochdocs.nim'
|
||||
- '.github/workflows/ci_docs.yml'
|
||||
- 'koch.nim'
|
||||
|
||||
pull_request:
|
||||
# Run only on changes on these files.
|
||||
paths:
|
||||
- 'compiler/docgen.nim'
|
||||
- 'compiler/renderverbatim.nim'
|
||||
- 'compiler/**.nim'
|
||||
- 'config/nimdoc.cfg'
|
||||
- 'doc/**.rst'
|
||||
- 'doc/**.md'
|
||||
- 'doc/nimdoc.css'
|
||||
- 'lib/**.nim'
|
||||
- 'nimdoc/testproject/expected/testproject.html'
|
||||
@@ -28,6 +29,10 @@ on:
|
||||
- '.github/workflows/ci_docs.yml'
|
||||
- 'koch.nim'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
@@ -36,11 +41,11 @@ jobs:
|
||||
target: [linux, windows, osx]
|
||||
include:
|
||||
- target: linux
|
||||
os: ubuntu-20.04
|
||||
os: ubuntu-22.04
|
||||
- target: windows
|
||||
os: windows-2019
|
||||
os: windows-latest
|
||||
- target: osx
|
||||
os: macos-11
|
||||
os: macos-15
|
||||
|
||||
name: ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -48,7 +53,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -104,7 +109,7 @@ jobs:
|
||||
if: |
|
||||
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
|
||||
matrix.target == 'linux'
|
||||
uses: crazy-max/ghaction-github-pages@v1
|
||||
uses: crazy-max/ghaction-github-pages@v5
|
||||
with:
|
||||
build_dir: doc/html
|
||||
env:
|
||||
|
||||
32
.github/workflows/ci_packages.yml
vendored
32
.github/workflows/ci_packages.yml
vendored
@@ -1,13 +1,24 @@
|
||||
name: Packages CI
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- 'devel'
|
||||
- 'version-2-2'
|
||||
- 'version-2-0'
|
||||
- 'version-1-6'
|
||||
- 'version-1-2'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-20.04, macos-11]
|
||||
cpu: [amd64]
|
||||
os: [ubuntu-latest, macos-14]
|
||||
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
|
||||
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -17,26 +28,27 @@ jobs:
|
||||
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v2
|
||||
- name: 'Install node.js'
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '16.x'
|
||||
node-version: 24
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
run: |
|
||||
sudo apt-fast update -qq
|
||||
sudo apt-get update -qq
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
sudo apt-fast install --no-install-recommends -yq \
|
||||
sudo apt-get install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
|
||||
valgrind libc6-dbg libblas-dev xorg-dev
|
||||
valgrind libc6-dbg libblas-dev liblapack-dev libpcre3 xorg-dev
|
||||
- name: 'Install dependencies (macOS)'
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install boehmgc make sfml gtk+3
|
||||
# XXX can't find boehm and gtk on macos 13
|
||||
- name: 'Install dependencies (Windows)'
|
||||
if: runner.os == 'Windows'
|
||||
shell: bash
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- '*'
|
||||
- 'devel'
|
||||
- 'version-*'
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
@@ -19,32 +20,32 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
Linux_amd64:
|
||||
vmImage: 'ubuntu-20.04'
|
||||
vmImage: 'ubuntu-24.04'
|
||||
CPU: amd64
|
||||
# regularly breaks, refs bug #17325
|
||||
# Linux_i386:
|
||||
# # on 'ubuntu-16.04' (not supported anymore anyways) it errored with:
|
||||
# # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
|
||||
# vmImage: 'ubuntu-20.04'
|
||||
# CPU: i386
|
||||
OSX_amd64:
|
||||
vmImage: 'macOS-11'
|
||||
CPU: amd64
|
||||
OSX_amd64_cpp:
|
||||
vmImage: 'macOS-11'
|
||||
CPU: amd64
|
||||
# Linux_i386:
|
||||
# # on 'ubuntu-16.04' (not supported anymore anyways) it errored with:
|
||||
# # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
|
||||
# vmImage: 'ubuntu-18.04'
|
||||
# CPU: i386
|
||||
OSX_arm64:
|
||||
vmImage: 'macos-15'
|
||||
CPU: arm64
|
||||
OSX_arm64_cpp:
|
||||
vmImage: 'macos-15'
|
||||
CPU: arm64
|
||||
NIM_COMPILE_TO_CPP: true
|
||||
Windows_amd64_batch0_3:
|
||||
vmImage: 'windows-2019'
|
||||
vmImage: 'windows-2025'
|
||||
CPU: amd64
|
||||
# see also: `NIM_TEST_PACKAGES`
|
||||
NIM_TESTAMENT_BATCH: "0_3"
|
||||
Windows_amd64_batch1_3:
|
||||
vmImage: 'windows-2019'
|
||||
vmImage: 'windows-2025'
|
||||
CPU: amd64
|
||||
NIM_TESTAMENT_BATCH: "1_3"
|
||||
Windows_amd64_batch2_3:
|
||||
vmImage: 'windows-2019'
|
||||
vmImage: 'windows-2025'
|
||||
CPU: amd64
|
||||
NIM_TESTAMENT_BATCH: "2_3"
|
||||
|
||||
@@ -72,17 +73,19 @@ jobs:
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: '16.x'
|
||||
displayName: 'Install node.js 16.x'
|
||||
versionSpec: '20.x'
|
||||
displayName: 'Install node.js 20.x'
|
||||
condition: and(succeeded(), eq(variables['skipci'], 'false'))
|
||||
|
||||
- bash: |
|
||||
set -e
|
||||
. ci/funs.sh
|
||||
echo_run sudo apt-fast update -qq
|
||||
echo_run sudo add-apt-repository universe
|
||||
echo_run sudo apt-get update -qq
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
echo_run sudo apt-fast install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
|
||||
echo_run sudo apt-get install --no-install-recommends -yq \
|
||||
gcc-14 g++-14 libpcre3 liblapack-dev libpcre3 liblapack-dev libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
|
||||
echo_run sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 60 --slave /usr/bin/g++ g++ /usr/bin/g++-14
|
||||
displayName: 'Install dependencies (amd64 Linux)'
|
||||
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64'))
|
||||
|
||||
@@ -99,15 +102,16 @@ jobs:
|
||||
Pin-Priority: 1001
|
||||
EOF
|
||||
|
||||
# echo_run sudo apt-fast update -qq
|
||||
echo_run sudo apt-fast update -qq || echo "failed, see bug #17343"
|
||||
# echo_run sudo apt-get update -qq
|
||||
echo_run sudo apt-get update -qq || echo "failed, see bug #17343"
|
||||
# `:i386` (e.g. in `libffi-dev:i386`) is needed otherwise you may get:
|
||||
# `could not load: libffi.so` during dynamic loading.
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
echo_run sudo apt-fast install --no-install-recommends --allow-downgrades -yq \
|
||||
echo_run sudo apt-get install --no-install-recommends --allow-downgrades -yq \
|
||||
g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \
|
||||
libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386 libffi-dev:i386
|
||||
|
||||
|
||||
cat << EOF > bin/gcc
|
||||
#!/bin/bash
|
||||
|
||||
@@ -129,6 +133,7 @@ jobs:
|
||||
- bash: brew install boehmgc make sfml
|
||||
displayName: 'Install dependencies (OSX)'
|
||||
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Darwin'))
|
||||
# XXX can't find boehm on macos 13
|
||||
|
||||
- bash: |
|
||||
set -e
|
||||
|
||||
@@ -887,6 +887,7 @@ type
|
||||
info*: TLineInfo
|
||||
when defined(nimsuggest):
|
||||
endInfo*: TLineInfo
|
||||
hasUserSpecifiedType*: bool # used for determining whether to display inlay type hints
|
||||
owner*: PSym
|
||||
flags*: TSymFlags
|
||||
ast*: PNode # syntax tree of proc, iterator, etc.:
|
||||
|
||||
@@ -444,9 +444,10 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
|
||||
[addrLoc(p.config, dest), rdLoc(src),
|
||||
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
|
||||
of tyOpenArray, tyVarargs:
|
||||
let source = addrLocOrTemp(src)
|
||||
linefmt(p, cpsStmts,
|
||||
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
|
||||
[addrLoc(p.config, dest), addrLocOrTemp(src),
|
||||
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $2->Field1, $3);$n",
|
||||
[addrLoc(p.config, dest), source,
|
||||
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
|
||||
of tySet:
|
||||
if mapSetType(p.config, ty) == ctArray:
|
||||
@@ -599,7 +600,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
if t.kind == tyInt64: prc64[m] else: prc[m])
|
||||
putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
|
||||
else:
|
||||
let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
|
||||
let res = "($1)(($2) $3 ($4))" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
|
||||
putIntoDest(p, d, e, res)
|
||||
|
||||
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
@@ -1446,6 +1447,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
||||
getSeqPayloadType(p.module, seqtype),
|
||||
])
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) # bug #22560
|
||||
putIntoDest(p, d, e, ropecg(p.module,
|
||||
"($1)#nimNewSeqOfCap($2, $3)", [
|
||||
getTypeDesc(p.module, seqtype),
|
||||
@@ -1804,9 +1806,9 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
if optBoundsCheck in p.options:
|
||||
genBoundsCheck(p, m, b, c)
|
||||
if op == mHigh:
|
||||
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)", [rdLoc(b), rdLoc(c)]))
|
||||
putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1))", [rdLoc(b), rdLoc(c)]))
|
||||
else:
|
||||
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)]))
|
||||
putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1)+1)", [rdLoc(b), rdLoc(c)]))
|
||||
else:
|
||||
if not reifiedOpenArray(a):
|
||||
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
|
||||
@@ -2566,15 +2568,30 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
if not handleConstExpr(p, n, d):
|
||||
let t = n.typ
|
||||
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
||||
if d.k == locNone: getTemp(p, t, d)
|
||||
|
||||
var tmp: TLoc
|
||||
# bug #16331
|
||||
let doesAlias = lhsDoesAlias(d.lode, n)
|
||||
let dest = if doesAlias: addr(tmp) else: addr(d)
|
||||
if doesAlias:
|
||||
getTemp(p, n.typ, tmp)
|
||||
elif d.k == locNone:
|
||||
getTemp(p, n.typ, d)
|
||||
|
||||
for i in 0..<n.len:
|
||||
var it = n[i]
|
||||
if it.kind == nkExprColonExpr: it = it[1]
|
||||
initLoc(rec, locExpr, it, d.storage)
|
||||
rec.r = "$1.Field$2" % [rdLoc(d), rope(i)]
|
||||
initLoc(rec, locExpr, it, dest[].storage)
|
||||
rec.r = "$1.Field$2" % [rdLoc(dest[]), rope(i)]
|
||||
rec.flags.incl(lfEnforceDeref)
|
||||
expr(p, it, rec)
|
||||
|
||||
if doesAlias:
|
||||
if d.k == locNone:
|
||||
d = tmp
|
||||
else:
|
||||
genAssignment(p, d, tmp, {})
|
||||
|
||||
proc isConstClosure(n: PNode): bool {.inline.} =
|
||||
result = n[0].kind == nkSym and isRoutine(n[0].sym) and
|
||||
n[1].kind == nkNilLit
|
||||
|
||||
@@ -83,7 +83,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor])
|
||||
else:
|
||||
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
|
||||
of tyChar, tyBool, tyEnum, tyInt..tyUInt64:
|
||||
of tyChar, tyBool, tyEnum, tyRange, tyInt..tyUInt64:
|
||||
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
|
||||
of tyCstring, tyPointer, tyPtr, tyVar, tyLent:
|
||||
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
|
||||
@@ -97,7 +97,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
|
||||
else:
|
||||
doAssert false, "unexpected set type kind"
|
||||
of {tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
|
||||
tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs,
|
||||
tyGenericParam, tyOrdinal, tyOpenArray, tyForward, tyVarargs,
|
||||
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
||||
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
|
||||
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable}:
|
||||
|
||||
@@ -35,14 +35,94 @@ proc mangleField(m: BModule; name: PIdent): string =
|
||||
if isKeyword(name):
|
||||
result.add "_0"
|
||||
|
||||
|
||||
proc encodeName*(name: string): string =
|
||||
result = mangle(name)
|
||||
result = $result.len & result
|
||||
|
||||
proc makeUnique(m: BModule; s: PSym, name: string = ""): Rope =
|
||||
let str = if name == "": s.name.s else: name
|
||||
result.add str
|
||||
result.add "__"
|
||||
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
|
||||
result.add "_u"
|
||||
result.add $s.itemId.item
|
||||
|
||||
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
|
||||
#Module::Type
|
||||
var name = s.name.s
|
||||
if makeUnique:
|
||||
name = $makeUnique(m, s, name)
|
||||
"N" & encodeName(s.skipGenericOwner.name.s) & encodeName(name) & "E"
|
||||
|
||||
proc elementType*(n: PType): PType {.inline.} = n.sons[^1]
|
||||
|
||||
proc encodeType*(m: BModule; t: PType): string =
|
||||
result = ""
|
||||
var kindName = ($t.kind)[2..^1]
|
||||
kindName[0] = toLower($kindName[0])[0]
|
||||
case t.kind
|
||||
of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam:
|
||||
result = encodeSym(m, t.sym)
|
||||
of tyGenericInst, tyUserTypeClassInst, tyGenericBody:
|
||||
result = encodeName(t[0].sym.name.s)
|
||||
result.add "I"
|
||||
for i in 1..<t.len - 1:
|
||||
result.add encodeType(m, t[i])
|
||||
result.add "E"
|
||||
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
|
||||
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
|
||||
result =
|
||||
case t.kind:
|
||||
of tySequence: encodeName("seq")
|
||||
else: encodeName(kindName)
|
||||
result.add "I"
|
||||
for i in 0..<t.len:
|
||||
let s = t[i]
|
||||
if s.isNil: continue
|
||||
result.add encodeType(m, s)
|
||||
result.add "E"
|
||||
of tyRange:
|
||||
var val = "range_"
|
||||
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
|
||||
val.addFloat t.n[0].floatVal
|
||||
val.add "_"
|
||||
val.addFloat t.n[1].floatVal
|
||||
else:
|
||||
val.add $t.n[0].intVal & "_" & $t.n[1].intVal
|
||||
result = encodeName(val)
|
||||
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
|
||||
result = encodeName(kindName)
|
||||
of tyAlias, tyInferred, tyOwned:
|
||||
result = encodeType(m, t.elementType)
|
||||
else:
|
||||
assert false, "encodeType " & $t.kind
|
||||
|
||||
proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
|
||||
result = "_Z" # Common prefix in Itanium ABI
|
||||
result.add encodeSym(m, s, makeUnique)
|
||||
if s.typ.len > 1: #we dont care about the return param
|
||||
for i in 1..<s.typ.len:
|
||||
if s.typ[i].isNil: continue
|
||||
result.add encodeType(m, s.typ[i])
|
||||
|
||||
if result in m.g.mangledPrcs:
|
||||
result = mangleProc(m, s, true)
|
||||
else:
|
||||
m.g.mangledPrcs.incl(result)
|
||||
|
||||
proc mangleName(m: BModule; s: PSym): Rope =
|
||||
result = s.loc.r
|
||||
if result == nil:
|
||||
result = s.name.s.mangle.rope
|
||||
result.add "__"
|
||||
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
|
||||
result.add "_"
|
||||
result.add rope s.itemId.item
|
||||
if $s.loc.r == "":
|
||||
var result: Rope
|
||||
if s.kind in routineKinds and optCDebug in m.g.config.globalOptions and
|
||||
m.g.config.symbolFiles == disabledSf:
|
||||
result = mangleProc(m, s, false).rope
|
||||
else:
|
||||
result = s.name.s.mangle.rope
|
||||
result.add "__"
|
||||
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
|
||||
result.add "_u"
|
||||
result.add $s.itemId.item # s.disamb #
|
||||
if m.hcrOn:
|
||||
result.add "_"
|
||||
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
|
||||
|
||||
@@ -13,6 +13,11 @@ import
|
||||
ast, types, hashes, strutils, msgs, wordrecg,
|
||||
platform, trees, options, cgendata
|
||||
|
||||
import std/[hashes, strutils]
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
@@ -141,4 +146,3 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
|
||||
if s.position == 0 and retType != nil and retType.kind == tyLent:
|
||||
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
|
||||
pt.kind == tySet and mapSetType(conf, pt) == ctArray)
|
||||
|
||||
|
||||
@@ -1266,10 +1266,10 @@ proc genVarPrototype(m: BModule, n: PNode) =
|
||||
if sym.owner.id != m.module.id:
|
||||
# else we already have the symbol generated!
|
||||
assert(sym.loc.r != nil)
|
||||
incl(m.declaredThings, sym.id)
|
||||
if sfThread in sym.flags:
|
||||
declareThreadVar(m, sym, true)
|
||||
else:
|
||||
incl(m.declaredThings, sym.id)
|
||||
if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0:
|
||||
m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)]
|
||||
m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ")
|
||||
|
||||
@@ -138,6 +138,7 @@ type
|
||||
# unconditionally...
|
||||
# nimtvDeps is VERY hard to cache because it's
|
||||
# not a list of IDs nor can it be made to be one.
|
||||
mangledPrcs*: HashSet[string]
|
||||
|
||||
TCGen = object of PPassContext # represents a C source file
|
||||
s*: TCFileSections # sections of the C file
|
||||
|
||||
@@ -852,7 +852,9 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkReturnStmt:
|
||||
# We're somewhere in try, transform to finally unrolling
|
||||
assert(ctx.nearestFinally != 0)
|
||||
if ctx.nearestFinally == 0:
|
||||
# return is within the finally
|
||||
return
|
||||
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
|
||||
@@ -58,12 +58,16 @@ proc toNimblePath(s: string, isStdlib: bool): string =
|
||||
sub.add "/pkgs/"
|
||||
var start = s.find(sub)
|
||||
if start < 0:
|
||||
result = s
|
||||
else:
|
||||
start += sub.len
|
||||
start += skipUntil(s, '/', start)
|
||||
start += 1
|
||||
result = pkgPrefix & s[start..^1]
|
||||
sub[^1] = '2'
|
||||
sub.add '/'
|
||||
start = s.find(sub) # /pkgs2
|
||||
if start < 0:
|
||||
return s
|
||||
|
||||
start += sub.len
|
||||
start += skipUntil(s, '/', start)
|
||||
start += 1
|
||||
result = pkgPrefix & s[start..^1]
|
||||
|
||||
proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
|
||||
doAssert n.kind == nkSym, $n.kind
|
||||
|
||||
@@ -565,7 +565,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
|
||||
|
||||
compilePattern = joinPath(conf.cCompilerPath, exe)
|
||||
else:
|
||||
compilePattern = getCompilerExe(conf, c, isCpp)
|
||||
compilePattern = exe
|
||||
|
||||
includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)]))
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool)
|
||||
result.options.incl optImportHidden
|
||||
c.unusedImports.add((result, n.info))
|
||||
c.importModuleMap[result.id] = realModule.id
|
||||
c.importModuleLookup.mgetOrPut(realModule.name.id, @[]).addUnique realModule.id
|
||||
c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id
|
||||
|
||||
proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] =
|
||||
var ret: typeof(result)
|
||||
|
||||
@@ -706,6 +706,11 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false) =
|
||||
of nkWhen: # This should be a "when nimvm" node.
|
||||
result = copyTree(n)
|
||||
result[1][0] = processCall(n[1][0], s)
|
||||
of nkPragmaBlock:
|
||||
result = shallowCopy(n)
|
||||
for i in 0 ..< n.len-1:
|
||||
result[i] = p(n[i], c, s, normal)
|
||||
result[^1] = maybeVoid(n[^1], s)
|
||||
else: assert(false)
|
||||
|
||||
proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
|
||||
@@ -735,7 +740,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
|
||||
|
||||
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
||||
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
|
||||
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt}:
|
||||
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
|
||||
template process(child, s): untyped = p(child, c, s, mode)
|
||||
handleNestedTempl(n, process)
|
||||
elif mode == sinkArg:
|
||||
@@ -915,7 +920,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
||||
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
|
||||
result = n
|
||||
|
||||
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
|
||||
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange:
|
||||
result = shallowCopy(n)
|
||||
for i in 0 ..< n.len:
|
||||
result[i] = p(n[i], c, s, normal)
|
||||
@@ -997,7 +1002,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
||||
|
||||
proc sameLocation*(a, b: PNode): bool =
|
||||
proc sameConstant(a, b: PNode): bool =
|
||||
a.kind in nkLiterals and a.intVal == b.intVal
|
||||
a.kind in nkLiterals and b.kind in nkLiterals and a.intVal == b.intVal
|
||||
|
||||
const nkEndPoint = {nkSym, nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}
|
||||
if a.kind in nkEndPoint and b.kind in nkEndPoint:
|
||||
@@ -1054,7 +1059,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod
|
||||
else:
|
||||
result = newTree(nkFastAsgn, dest, p(ri, c, s, normal))
|
||||
else:
|
||||
case ri.kind
|
||||
let ri2 = if ri.kind == nkWhen: ri[1][0] else: ri
|
||||
case ri2.kind
|
||||
of nkCallKinds:
|
||||
result = c.genSink(dest, p(ri, c, s, consumed), isDecl)
|
||||
of nkBracketExpr:
|
||||
|
||||
@@ -298,6 +298,7 @@ type
|
||||
processed, capturedVars: IntSet
|
||||
ownerToType: Table[int, PType]
|
||||
somethingToDo: bool
|
||||
inTypeOf: bool
|
||||
graph: ModuleGraph
|
||||
idgen: IdGenerator
|
||||
|
||||
@@ -401,6 +402,9 @@ Consider:
|
||||
|
||||
"""
|
||||
|
||||
proc isTypeOf(n: PNode): bool =
|
||||
n.kind == nkSym and n.sym.magic in {mTypeOf, mType}
|
||||
|
||||
proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
|
||||
var cp = getEnvParam(fn)
|
||||
let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner
|
||||
@@ -437,7 +441,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
c.somethingToDo = true
|
||||
addClosureParam(c, owner, n.info)
|
||||
if interestingIterVar(s):
|
||||
if not c.capturedVars.containsOrIncl(s.id):
|
||||
if not c.capturedVars.contains(s.id):
|
||||
if not c.inTypeOf: c.capturedVars.incl(s.id)
|
||||
let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
#let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr})
|
||||
|
||||
@@ -463,10 +468,12 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
addClosureParam(c, owner, n.info)
|
||||
#echo "capturing ", n.info
|
||||
# variable 's' is actually captured:
|
||||
if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id):
|
||||
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
|
||||
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
discard addField(obj, s, c.graph.cache, c.idgen)
|
||||
if interestingVar(s):
|
||||
if not c.capturedVars.contains(s.id):
|
||||
if not c.inTypeOf: c.capturedVars.incl(s.id)
|
||||
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
|
||||
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
|
||||
discard addField(obj, s, c.graph.cache, c.idgen)
|
||||
# create required upFields:
|
||||
var w = owner.skipGenericOwner
|
||||
if isInnerProc(w) or owner.isIterator:
|
||||
@@ -498,9 +505,14 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
detectCapturedVars(n[namePos], owner, c)
|
||||
of nkReturnStmt:
|
||||
detectCapturedVars(n[0], owner, c)
|
||||
of nkIdentDefs:
|
||||
detectCapturedVars(n[^1], owner, c)
|
||||
else:
|
||||
if n.isCallExpr and n[0].isTypeOf:
|
||||
c.inTypeOf = true
|
||||
for i in 0..<n.len:
|
||||
detectCapturedVars(n[i], owner, c)
|
||||
c.inTypeOf = false
|
||||
|
||||
type
|
||||
LiftingPass = object
|
||||
@@ -780,6 +792,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
|
||||
of nkTypeOfExpr:
|
||||
result = n
|
||||
else:
|
||||
if n.isCallExpr and n[0].isTypeOf:
|
||||
return
|
||||
if owner.isIterator:
|
||||
if nfLL in n.flags:
|
||||
# special case 'when nimVm' due to bug #3636:
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import std/[algorithm, strutils, tables]
|
||||
import
|
||||
intsets, ast, astalgo, idents, semdata, types, msgs, options,
|
||||
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs
|
||||
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs, wordrecg
|
||||
|
||||
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
|
||||
|
||||
@@ -311,10 +311,10 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string;
|
||||
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
|
||||
let conflict = scope.addUniqueSym(sym)
|
||||
if conflict != nil:
|
||||
if sym.kind == skModule and conflict.kind == skModule:
|
||||
if sym.kind == skModule and conflict.kind == skModule:
|
||||
# e.g.: import foo; import foo
|
||||
# xxx we could refine this by issuing a different hint for the case
|
||||
# where a duplicate import happens inside an include.
|
||||
# where a duplicate import happens inside an include.
|
||||
if c.importModuleMap[sym.id] == c.importModuleMap[conflict.id]:
|
||||
#only hints if the conflict is the actual module not just a shared name
|
||||
localError(c.config, info, hintDuplicateModuleImport,
|
||||
@@ -604,6 +604,9 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
|
||||
result = errorUndeclaredIdentifierHint(c, n[1], ident)
|
||||
elif n[1].kind == nkSym:
|
||||
result = n[1].sym
|
||||
if result.owner != nil and result.owner != m and checkUndeclared in flags:
|
||||
# dotExpr in templates can end up here
|
||||
result = errorUndeclaredIdentifierHint(c, n[1], considerQuotedIdent(c, n[1]))
|
||||
elif checkUndeclared in flags and
|
||||
n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
|
||||
localError(c.config, n[1].info, "identifier expected, but got: " &
|
||||
|
||||
@@ -129,7 +129,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o
|
||||
|
||||
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
|
||||
vpart[0] = tempAsNode
|
||||
vpart[1] = newNodeI(nkEmpty, value.info)
|
||||
vpart[1] = newNodeI(nkTupleClassTy, value.info)
|
||||
vpart[2] = value
|
||||
v.add vpart
|
||||
result.add(v)
|
||||
@@ -235,6 +235,9 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
|
||||
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
|
||||
let t = skipIntLit(s.typ, idgen)
|
||||
field.typ = t
|
||||
if s.kind in {skLet, skVar, skField, skForVar}:
|
||||
#field.bitsize = s.bitsize
|
||||
field.alignment = s.alignment
|
||||
assert t.kind != tyTyped
|
||||
propagateToOwner(obj, t)
|
||||
field.position = obj.n.len
|
||||
|
||||
@@ -53,6 +53,7 @@ type
|
||||
SymInfoPair* = object
|
||||
sym*: PSym
|
||||
info*: TLineInfo
|
||||
isDecl*: bool
|
||||
|
||||
ModuleGraph* {.acyclic.} = ref object
|
||||
ifaces*: seq[Iface] ## indexed by int32 fileIdx
|
||||
|
||||
@@ -36,11 +36,14 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
|
||||
localError(n.info, "only '/' supported with $package notation")
|
||||
result = ""
|
||||
else:
|
||||
let modname = getModuleName(conf, n[2])
|
||||
# hacky way to implement 'x / y /../ z':
|
||||
result = getModuleName(conf, n1)
|
||||
result.add renderTree(n0, {renderNoComments}).replace(" ")
|
||||
result.add modname
|
||||
if n0.kind == nkIdent and n0.ident.s[0] == '/':
|
||||
let modname = getModuleName(conf, n[2])
|
||||
# hacky way to implement 'x / y /../ z':
|
||||
result = getModuleName(conf, n1)
|
||||
result.add renderTree(n0, {renderNoComments}).replace(" ")
|
||||
result.add modname
|
||||
else:
|
||||
result = ""
|
||||
of nkPrefix:
|
||||
when false:
|
||||
if n[0].kind == nkIdent and n[0].ident.s == "$":
|
||||
|
||||
@@ -417,14 +417,18 @@ To create a stacktrace, rerun compilation with './koch temp $1 <file>', see $2 f
|
||||
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string, ignoreMsg: bool) =
|
||||
if msg in fatalMsgs:
|
||||
if conf.cmd == cmdIdeTools: log(s)
|
||||
quit(conf, msg)
|
||||
if conf.cmd != cmdIdeTools or msg != errFatal:
|
||||
quit(conf, msg)
|
||||
if msg >= errMin and msg <= errMax or
|
||||
(msg in warnMin..hintMax and msg in conf.warningAsErrors and not ignoreMsg):
|
||||
inc(conf.errorCounter)
|
||||
conf.exitcode = 1'i8
|
||||
if conf.errorCounter >= conf.errorMax:
|
||||
# only really quit when we're not in the new 'nim check --def' mode:
|
||||
if conf.ideCmd == ideNone:
|
||||
when defined(nimsuggest):
|
||||
#we need to inform the user that something went wrong when initializing NimSuggest
|
||||
raiseRecoverableError(s)
|
||||
else:
|
||||
quit(conf, msg)
|
||||
elif eh == doAbort and conf.cmd != cmdIdeTools:
|
||||
quit(conf, msg)
|
||||
|
||||
@@ -12,7 +12,9 @@ import
|
||||
ast, astalgo, modules, passes, condsyms,
|
||||
options, sem, llstream, lineinfos, vm,
|
||||
vmdef, modulegraphs, idents, os, pathutils,
|
||||
passaux, scriptconfig, std/compilesettings
|
||||
passaux,
|
||||
scriptconfig, std/[compilesettings, tables]
|
||||
|
||||
|
||||
type
|
||||
Interpreter* = ref object ## Use Nim as an interpreter with this object
|
||||
@@ -72,6 +74,9 @@ proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) =
|
||||
assert i != nil
|
||||
assert i.mainModule != nil, "no main module selected"
|
||||
initStrTables(i.graph, i.mainModule)
|
||||
i.graph.cacheSeqs.clear()
|
||||
i.graph.cacheCounters.clear()
|
||||
i.graph.cacheTables.clear()
|
||||
i.mainModule.ast = nil
|
||||
|
||||
let s = if scriptStream != nil: scriptStream
|
||||
|
||||
@@ -185,7 +185,7 @@ type
|
||||
IdeCmd* = enum
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
|
||||
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand, ideInlayHints
|
||||
|
||||
Feature* = enum ## experimental features; DO NOT RENAME THESE!
|
||||
implicitDeref,
|
||||
@@ -266,9 +266,24 @@ type
|
||||
version*: int
|
||||
endLine*: uint16
|
||||
endCol*: int
|
||||
inlayHintInfo*: SuggestInlayHint
|
||||
|
||||
Suggestions* = seq[Suggest]
|
||||
|
||||
SuggestInlayHintKind* = enum
|
||||
sihkType = "Type",
|
||||
sihkParameter = "Parameter"
|
||||
|
||||
SuggestInlayHint* = ref object
|
||||
kind*: SuggestInlayHintKind
|
||||
line*: int # Starts at 1
|
||||
column*: int # Starts at 0
|
||||
label*: string
|
||||
paddingLeft*: bool
|
||||
paddingRight*: bool
|
||||
allowInsert*: bool
|
||||
tooltip*: string
|
||||
|
||||
ProfileInfo* = object
|
||||
time*: float
|
||||
count*: int
|
||||
@@ -402,6 +417,8 @@ type
|
||||
expandNodeResult*: string
|
||||
expandPosition*: TLineInfo
|
||||
|
||||
clientProcessId*: int
|
||||
|
||||
proc parseNimVersion*(a: string): NimVer =
|
||||
# could be moved somewhere reusable
|
||||
if a.len > 0:
|
||||
@@ -1035,6 +1052,7 @@ proc `$`*(c: IdeCmd): string =
|
||||
of ideRecompile: "recompile"
|
||||
of ideChanged: "changed"
|
||||
of ideType: "type"
|
||||
of ideInlayHints: "inlayHints"
|
||||
|
||||
proc floatInt64Align*(conf: ConfigRef): int16 =
|
||||
## Returns either 4 or 8 depending on reasons.
|
||||
|
||||
@@ -816,7 +816,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
validPragmas: TSpecialWords,
|
||||
comesFromPush, isStatement: bool): bool =
|
||||
var it = n[i]
|
||||
var key = if it.kind in nkPragmaCallKinds and it.len > 1: it[0] else: it
|
||||
let keyDeep = it.kind in nkPragmaCallKinds and it.len > 1
|
||||
var key = if keyDeep: it[0] else: it
|
||||
if key.kind == nkBracketExpr:
|
||||
processNote(c, it)
|
||||
return
|
||||
@@ -842,6 +843,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
if c.instCounter > 100:
|
||||
globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s)
|
||||
|
||||
if keyDeep:
|
||||
localError(c.config, it.info, "user pragma cannot have arguments")
|
||||
|
||||
pragma(c, sym, userPragma.ast, validPragmas, isStatement)
|
||||
n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
|
||||
i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
|
||||
|
||||
@@ -203,12 +203,58 @@ proc commonType*(c: PContext; x, y: PType): PType =
|
||||
result.addSonSkipIntLit(r, c.idgen)
|
||||
|
||||
proc endsInNoReturn(n: PNode): bool =
|
||||
# check if expr ends in raise exception or call of noreturn proc
|
||||
## check if expr ends the block like raising or call of noreturn procs do
|
||||
result = false # assume it does return
|
||||
|
||||
template checkBranch(branch) =
|
||||
if not endsInNoReturn(branch):
|
||||
# proved a branch returns
|
||||
return false
|
||||
|
||||
var it = n
|
||||
# skip these beforehand, no special handling needed
|
||||
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
|
||||
it = it.lastSon
|
||||
result = it.kind in nkLastBlockStmts or
|
||||
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
|
||||
|
||||
case it.kind
|
||||
of nkIfStmt:
|
||||
var hasElse = false
|
||||
for branch in it:
|
||||
checkBranch:
|
||||
if branch.len == 2:
|
||||
branch[1]
|
||||
elif branch.len == 1:
|
||||
hasElse = true
|
||||
branch[0]
|
||||
else:
|
||||
raiseAssert "Malformed `if` statement during endsInNoReturn"
|
||||
# none of the branches returned
|
||||
result = hasElse # Only truly a no-return when it's exhaustive
|
||||
of nkCaseStmt:
|
||||
for i in 1 ..< it.len:
|
||||
let branch = it[i]
|
||||
checkBranch:
|
||||
case branch.kind
|
||||
of nkOfBranch:
|
||||
branch[^1]
|
||||
of nkElifBranch:
|
||||
branch[1]
|
||||
of nkElse:
|
||||
branch[0]
|
||||
else:
|
||||
raiseAssert "Malformed `case` statement in endsInNoReturn"
|
||||
# none of the branches returned
|
||||
result = true
|
||||
of nkTryStmt:
|
||||
checkBranch(it[0])
|
||||
for i in 1 ..< it.len:
|
||||
let branch = it[i]
|
||||
checkBranch(branch[^1])
|
||||
# none of the branches returned
|
||||
result = true
|
||||
else:
|
||||
result = it.kind in nkLastBlockStmts or
|
||||
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
|
||||
|
||||
proc commonType*(c: PContext; x: PType, y: PNode): PType =
|
||||
# ignore exception raising branches in case/if expressions
|
||||
|
||||
@@ -660,14 +660,18 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
onUse(info, s)
|
||||
result = newSymNode(newInst, info)
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
proc setGenericParams(c: PContext, n: PNode) =
|
||||
## sems generic params in subscript expression
|
||||
for i in 1..<n.len:
|
||||
let e = semExprWithType(c, n[i])
|
||||
if e.typ == nil:
|
||||
n[i].typ = errorType(c)
|
||||
else:
|
||||
n[i].typ = e.typ.skipTypes({tyTypeDesc})
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
setGenericParams(c, n)
|
||||
var s = s
|
||||
var a = n[0]
|
||||
if a.kind == nkSym:
|
||||
|
||||
@@ -946,10 +946,6 @@ proc bracketedMacro(n: PNode): PSym =
|
||||
if result.kind notin {skMacro, skTemplate}:
|
||||
result = nil
|
||||
|
||||
proc setGenericParams(c: PContext, n: PNode) =
|
||||
for i in 1..<n.len:
|
||||
n[i].typ = semTypeNode(c, n[i], nil)
|
||||
|
||||
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
|
||||
if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError:
|
||||
return errorNode(c, n)
|
||||
@@ -1054,7 +1050,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
|
||||
msg.addDeclaredLocMaybe(c.config, typ)
|
||||
localError(c.config, n.info, msg)
|
||||
return errorNode(c, n)
|
||||
result = nil
|
||||
else:
|
||||
result = m.call
|
||||
instGenericConvertersSons(c, result, m)
|
||||
@@ -1627,7 +1622,10 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
{tyInt..tyInt64}:
|
||||
let idx = getOrdValue(n[1])
|
||||
if idx >= 0 and idx < arr.len: n.typ = arr[toInt(idx)]
|
||||
else: localError(c.config, n.info, "invalid index value for tuple subscript")
|
||||
else:
|
||||
localError(c.config, n.info,
|
||||
"invalid index $1 in subscript for tuple of length $2" %
|
||||
[$idx, $arr.len])
|
||||
result = n
|
||||
else:
|
||||
result = nil
|
||||
@@ -1805,7 +1803,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
result.add(n[1])
|
||||
if mode == noOverloadedSubscript:
|
||||
bracketNotFoundError(c, result)
|
||||
return n
|
||||
return errorNode(c, n)
|
||||
else:
|
||||
result = semExprNoType(c, result)
|
||||
return result
|
||||
@@ -2881,7 +2879,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
|
||||
defer:
|
||||
if isCompilerDebug():
|
||||
echo ("<", c.config$n.info, n, ?.result.typ)
|
||||
|
||||
|
||||
template directLiteral(typeKind: TTypeKind) =
|
||||
if result.typ == nil:
|
||||
if expectedType != nil and (
|
||||
@@ -2927,6 +2925,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
|
||||
else:
|
||||
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
|
||||
s = qualifiedLookUp(c, n, checks)
|
||||
if s == nil:
|
||||
return
|
||||
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
|
||||
case s.kind
|
||||
of skProc, skFunc, skMethod, skConverter, skIterator:
|
||||
@@ -3214,7 +3214,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
|
||||
of nkDefer:
|
||||
if c.currentScope == c.topLevelScope:
|
||||
localError(c.config, n.info, "defer statement not supported at top level")
|
||||
openScope(c)
|
||||
n[0] = semExpr(c, n[0])
|
||||
closeScope(c)
|
||||
if not n[0].typ.isEmptyType and not implicitlyDiscardable(n[0]):
|
||||
localError(c.config, n.info, "'defer' takes a 'void' expression")
|
||||
#localError(c.config, n.info, errGenerated, "'defer' not allowed in this context")
|
||||
|
||||
@@ -371,7 +371,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
|
||||
openScope(c)
|
||||
let gp = n[genericParamsPos]
|
||||
internalAssert c.config, gp.kind == nkGenericParams
|
||||
if gp.kind != nkGenericParams:
|
||||
# bug #22137
|
||||
globalError(c.config, info, "generic instantiation too nested")
|
||||
n[namePos] = newSymNode(result)
|
||||
pushInfoContext(c.config, info, fn.detailedInfo)
|
||||
var entry = TInstantiation.new
|
||||
|
||||
@@ -51,7 +51,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
|
||||
x[0] = newIdentNode(getIdent(c.cache, "[]"), n.info)
|
||||
bracketNotFoundError(c, x)
|
||||
#localError(c.config, n.info, "could not resolve: " & $n)
|
||||
result = n
|
||||
result = errorNode(c, n)
|
||||
|
||||
proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
|
||||
# rewrite `[]=`(a, i, x) back to ``a[i] = x``.
|
||||
|
||||
@@ -1076,7 +1076,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
elif child.kind == nkVarTuple and last.kind != nkEmpty:
|
||||
for i in 0..<child.len-1:
|
||||
if child[i].kind == nkEmpty or
|
||||
child[i].kind == nkSym and child[i].sym.name.s == "_":
|
||||
child[i].kind == nkSym and child[i].sym.name.id == ord(wUnderscore):
|
||||
continue
|
||||
initVar(tracked, child[i], volatileCheck=false)
|
||||
if last.kind in {nkPar, nkTupleConstr}:
|
||||
|
||||
@@ -181,13 +181,15 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil):
|
||||
it[0] = forceBool(c, semExprWithType(c, it[0], expectedType = getSysType(c.graph, n.info, tyBool)))
|
||||
it[1] = semExprBranch(c, it[1], flags, expectedType)
|
||||
typ = commonType(c, typ, it[1])
|
||||
expectedType = typ
|
||||
if not endsInNoReturn(it[1]):
|
||||
expectedType = typ
|
||||
closeScope(c)
|
||||
elif it.len == 1:
|
||||
hasElse = true
|
||||
it[0] = semExprBranchScope(c, it[0], expectedType)
|
||||
typ = commonType(c, typ, it[0])
|
||||
expectedType = typ
|
||||
if not endsInNoReturn(it[0]):
|
||||
expectedType = typ
|
||||
else: illFormedAst(it, c.config)
|
||||
if isEmptyType(typ) or typ.kind in {tyNil, tyUntyped} or
|
||||
(not hasElse and efInTypeof notin flags):
|
||||
@@ -227,8 +229,9 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
|
||||
var typ = commonTypeBegin
|
||||
var expectedType = expectedType
|
||||
n[0] = semExprBranchScope(c, n[0], expectedType)
|
||||
typ = commonType(c, typ, n[0].typ)
|
||||
expectedType = typ
|
||||
if not endsInNoReturn(n[0]):
|
||||
typ = commonType(c, typ, n[0].typ)
|
||||
expectedType = typ
|
||||
|
||||
var last = n.len - 1
|
||||
var catchAllExcepts = 0
|
||||
@@ -289,7 +292,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
|
||||
if a.kind != nkFinally:
|
||||
a[^1] = semExprBranchScope(c, a[^1], expectedType)
|
||||
typ = commonType(c, typ, a[^1])
|
||||
expectedType = typ
|
||||
if not endsInNoReturn(a[^1]):
|
||||
expectedType = typ
|
||||
else:
|
||||
a[^1] = semExprBranchScope(c, a[^1])
|
||||
dec last
|
||||
@@ -302,7 +306,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil)
|
||||
result.typ = c.enforceVoidContext
|
||||
else:
|
||||
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags)
|
||||
n[0] = fitNode(c, typ, n[0], n[0].info)
|
||||
if not endsInNoReturn(n[0]):
|
||||
n[0] = fitNode(c, typ, n[0], n[0].info)
|
||||
for i in 1..last:
|
||||
var it = n[i]
|
||||
let j = it.len-1
|
||||
@@ -383,7 +388,7 @@ proc addToVarSection(c: PContext; result: PNode; orig, identDefs: PNode) =
|
||||
result.add identDefs
|
||||
|
||||
proc isDiscardUnderscore(v: PSym): bool =
|
||||
if v.name.s == "_":
|
||||
if v.name.id == ord(wUnderscore):
|
||||
v.flags.incl(sfGenSym)
|
||||
result = true
|
||||
|
||||
@@ -564,9 +569,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
if a.kind notin {nkIdentDefs, nkVarTuple}: illFormedAst(a, c.config)
|
||||
checkMinSonsLen(a, 3, c.config)
|
||||
|
||||
var hasUserSpecifiedType = false
|
||||
var typ: PType = nil
|
||||
if a[^2].kind != nkEmpty:
|
||||
typ = semTypeNode(c, a[^2], nil)
|
||||
hasUserSpecifiedType = true
|
||||
|
||||
var typFlags: TTypeAllowedFlags
|
||||
|
||||
@@ -639,6 +646,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
addToVarSection(c, result, n, a)
|
||||
continue
|
||||
var v = semIdentDef(c, a[j], symkind, false)
|
||||
when defined(nimsuggest):
|
||||
v.hasUserSpecifiedType = hasUserSpecifiedType
|
||||
styleCheckDef(c, v)
|
||||
onDef(a[j].info, v)
|
||||
if sfGenSym notin v.flags:
|
||||
@@ -719,9 +728,11 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||
if a.kind notin {nkConstDef, nkVarTuple}: illFormedAst(a, c.config)
|
||||
checkMinSonsLen(a, 3, c.config)
|
||||
|
||||
var hasUserSpecifiedType = false
|
||||
var typ: PType = nil
|
||||
if a[^2].kind != nkEmpty:
|
||||
typ = semTypeNode(c, a[^2], nil)
|
||||
hasUserSpecifiedType = true
|
||||
|
||||
var typFlags: TTypeAllowedFlags
|
||||
|
||||
@@ -766,6 +777,8 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||
|
||||
for j in 0..<a.len-2:
|
||||
var v = semIdentDef(c, a[j], skConst)
|
||||
when defined(nimsuggest):
|
||||
v.hasUserSpecifiedType = hasUserSpecifiedType
|
||||
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
||||
elif v.owner == nil: v.owner = getCurrOwner(c)
|
||||
styleCheckDef(c, v)
|
||||
@@ -1059,7 +1072,8 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil
|
||||
var last = x.len-1
|
||||
x[last] = semExprBranchScope(c, x[last], expectedType)
|
||||
typ = commonType(c, typ, x[last])
|
||||
expectedType = typ
|
||||
if not endsInNoReturn(x[last]):
|
||||
expectedType = typ
|
||||
of nkElifBranch:
|
||||
chckCovered = false
|
||||
checkSonsLen(x, 2, c.config)
|
||||
@@ -1067,13 +1081,15 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil
|
||||
x[0] = forceBool(c, semExprWithType(c, x[0], expectedType = getSysType(c.graph, n.info, tyBool)))
|
||||
x[1] = semExprBranch(c, x[1], expectedType = expectedType)
|
||||
typ = commonType(c, typ, x[1])
|
||||
expectedType = typ
|
||||
if not endsInNoReturn(x[1]):
|
||||
expectedType = typ
|
||||
closeScope(c)
|
||||
of nkElse:
|
||||
checkSonsLen(x, 1, c.config)
|
||||
x[0] = semExprBranchScope(c, x[0], expectedType)
|
||||
typ = commonType(c, typ, x[0])
|
||||
expectedType = typ
|
||||
if not endsInNoReturn(x[0]):
|
||||
expectedType = typ
|
||||
if (chckCovered and covered == toCover(c, n[0].typ)) or hasElse:
|
||||
message(c.config, x.info, warnUnreachableElse)
|
||||
hasElse = true
|
||||
@@ -2419,9 +2435,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType =
|
||||
var m = n[i]
|
||||
while m.kind in {nkStmtListExpr, nkStmtList} and m.len > 0: # from templates
|
||||
m = m.lastSon
|
||||
if m.kind in nkLastBlockStmts or
|
||||
m.kind in nkCallKinds and m[0].kind == nkSym and
|
||||
sfNoReturn in m[0].sym.flags:
|
||||
if endsInNoReturn(m):
|
||||
for j in i + 1..<n.len:
|
||||
case n[j].kind
|
||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkState: discard
|
||||
|
||||
@@ -70,6 +70,9 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
|
||||
onUse(info, s)
|
||||
else:
|
||||
result = n
|
||||
elif i == 0:
|
||||
# forced open but symbol not in scope, retain information
|
||||
result = n
|
||||
else:
|
||||
# semantic checking requires a type; ``fitNode`` deals with it
|
||||
# appropriately
|
||||
@@ -110,14 +113,10 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
|
||||
|
||||
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
|
||||
result = copyNode(n)
|
||||
var count = 0
|
||||
for i in 0..<n.len:
|
||||
toMixin.incl(considerQuotedIdent(c, n[i]).id)
|
||||
let x = symChoice(c, n[i], nil, scForceOpen)
|
||||
inc count, x.len
|
||||
result.add x
|
||||
if count == 0:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
|
||||
proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
|
||||
case n.kind
|
||||
@@ -187,11 +186,12 @@ proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
|
||||
incl(result.flags, sfShadowed)
|
||||
|
||||
proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
||||
# locals default to 'gensym':
|
||||
if n.kind == nkPragmaExpr and symBinding(n[1]) == spInject:
|
||||
# locals default to 'gensym', fields default to 'inject':
|
||||
if (n.kind == nkPragmaExpr and symBinding(n[1]) == spInject) or
|
||||
k == skField:
|
||||
# even if injected, don't produce a sym choice here:
|
||||
#n = semTemplBody(c, n)
|
||||
var x = n[0]
|
||||
var x = n
|
||||
while true:
|
||||
case x.kind
|
||||
of nkPostfix: x = x[1]
|
||||
@@ -206,7 +206,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
||||
illFormedAst(x, c.c.config)
|
||||
let ident = getIdentNode(c, x)
|
||||
if not isTemplParam(c, ident):
|
||||
c.toInject.incl(x.ident.id)
|
||||
if k != skField: c.toInject.incl(x.ident.id)
|
||||
else:
|
||||
replaceIdentBySym(c.c, n, ident)
|
||||
else:
|
||||
@@ -227,7 +227,7 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
||||
closeScope(c)
|
||||
let ident = getIdentNode(c, n)
|
||||
if not isTemplParam(c, ident):
|
||||
if n.kind != nkSym and not (n.kind == nkIdent and n.ident.s == "_"):
|
||||
if n.kind != nkSym and not (n.kind == nkIdent and n.ident.id == ord(wUnderscore)):
|
||||
let local = newGenSym(k, ident, c)
|
||||
addPrelimDecl(c.c, local)
|
||||
styleCheckDef(c.c, n.info, local)
|
||||
@@ -331,21 +331,24 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
|
||||
# close scope for parameters
|
||||
closeScope(c)
|
||||
|
||||
proc semTemplIdentDef(c: var TemplCtx, a: PNode, symKind: TSymKind) =
|
||||
checkMinSonsLen(a, 3, c.c.config)
|
||||
when defined(nimsuggest):
|
||||
inc c.c.inTypeContext
|
||||
a[^2] = semTemplBody(c, a[^2])
|
||||
when defined(nimsuggest):
|
||||
dec c.c.inTypeContext
|
||||
a[^1] = semTemplBody(c, a[^1])
|
||||
for j in 0..<a.len-2:
|
||||
addLocalDecl(c, a[j], symKind)
|
||||
|
||||
proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start = 0) =
|
||||
for i in start..<n.len:
|
||||
var a = n[i]
|
||||
case a.kind:
|
||||
of nkCommentStmt: continue
|
||||
of nkIdentDefs, nkVarTuple, nkConstDef:
|
||||
checkMinSonsLen(a, 3, c.c.config)
|
||||
when defined(nimsuggest):
|
||||
inc c.c.inTypeContext
|
||||
a[^2] = semTemplBody(c, a[^2])
|
||||
when defined(nimsuggest):
|
||||
dec c.c.inTypeContext
|
||||
a[^1] = semTemplBody(c, a[^1])
|
||||
for j in 0..<a.len-2:
|
||||
addLocalDecl(c, a[j], symKind)
|
||||
semTemplIdentDef(c, a, symKind)
|
||||
else:
|
||||
illFormedAst(a, c.c.config)
|
||||
|
||||
@@ -485,6 +488,25 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
closeScope(c)
|
||||
else:
|
||||
a[2] = semTemplBody(c, a[2])
|
||||
of nkObjectTy:
|
||||
openScope(c)
|
||||
result = semTemplBodySons(c, n)
|
||||
closeScope(c)
|
||||
of nkRecList:
|
||||
for i in 0..<n.len:
|
||||
var a = n[i]
|
||||
case a.kind:
|
||||
of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue
|
||||
of nkIdentDefs:
|
||||
semTemplIdentDef(c, a, skField)
|
||||
of nkRecCase, nkRecWhen:
|
||||
n[i] = semTemplBody(c, a)
|
||||
else:
|
||||
illFormedAst(a, c.c.config)
|
||||
of nkRecCase:
|
||||
semTemplIdentDef(c, n[0], skField)
|
||||
for i in 1..<n.len:
|
||||
n[i] = semTemplBody(c, n[i])
|
||||
of nkProcDef, nkLambdaKinds:
|
||||
result = semRoutineInTemplBody(c, n, skProc)
|
||||
of nkFuncDef:
|
||||
@@ -548,6 +570,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
# so we use the generic code for nkDotExpr too
|
||||
let s = qualifiedLookUp(c.c, n, {})
|
||||
if s != nil:
|
||||
# mirror the nkIdent case
|
||||
# do not symchoice a quoted template parameter (bug #2390):
|
||||
if s.owner == c.owner and s.kind == skParam and
|
||||
n.kind == nkAccQuoted and n.len == 1:
|
||||
@@ -559,7 +582,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
elif contains(c.toMixin, s.name.id):
|
||||
return symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
|
||||
else:
|
||||
return symChoice(c.c, n, s, scOpen, c.noGenSym > 0)
|
||||
if s.kind in {skType, skVar, skLet, skConst}:
|
||||
discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
|
||||
return semTemplSymbol(c.c, n, s, c.noGenSym > 0)
|
||||
if n.kind == nkDotExpr:
|
||||
result = n
|
||||
result[0] = semTemplBody(c, n[0])
|
||||
@@ -653,6 +678,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
# a template's parameters are not gensym'ed even if that was originally the
|
||||
# case as we determine whether it's a template parameter in the template
|
||||
# body by the absence of the sfGenSym flag:
|
||||
let retType = s.typ[0]
|
||||
if retType != nil and retType.kind != tyUntyped:
|
||||
allUntyped = false
|
||||
for i in 1..<s.typ.n.len:
|
||||
let param = s.typ.n[i].sym
|
||||
param.flags.incl sfTemplateParam
|
||||
|
||||
@@ -142,6 +142,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
result.n.add symNode
|
||||
styleCheckDef(c, e)
|
||||
onDef(e.info, e)
|
||||
suggestSym(c.graph, e.info, e, c.graph.usageSym)
|
||||
if sfGenSym notin e.flags:
|
||||
if not isPure:
|
||||
if overloadableEnums in c.features:
|
||||
@@ -276,7 +277,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||
|
||||
elif not isOrdinalType(rangeT[0]) and rangeT[0].kind notin {tyFloat..tyFloat128} or
|
||||
rangeT[0].kind == tyBool:
|
||||
localError(c.config, n.info, "ordinal or float type expected")
|
||||
localError(c.config, n.info, "ordinal or float type expected, but got " & typeToString(rangeT[0]))
|
||||
elif enumHasHoles(rangeT[0]):
|
||||
localError(c.config, n.info, "enum '$1' has holes" % typeToString(rangeT[0]))
|
||||
|
||||
@@ -287,9 +288,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||
else:
|
||||
result.n.add semConstExpr(c, range[i])
|
||||
|
||||
if (result.n[0].kind in {nkFloatLit..nkFloat64Lit} and result.n[0].floatVal.isNaN) or
|
||||
(result.n[1].kind in {nkFloatLit..nkFloat64Lit} and result.n[1].floatVal.isNaN):
|
||||
localError(c.config, n.info, "NaN is not a valid start or end for a range")
|
||||
if result.n[i].kind in {nkFloatLit..nkFloat64Lit} and result.n[i].floatVal.isNaN:
|
||||
localError(c.config, n.info, "NaN is not a valid range " & (if i == 0: "start" else: "end"))
|
||||
|
||||
if weakLeValue(result.n[0], result.n[1]) == impNo:
|
||||
localError(c.config, n.info, "range is empty")
|
||||
@@ -882,12 +882,18 @@ proc skipGenericInvocation(t: PType): PType {.inline.} =
|
||||
while result.kind in {tyGenericInst, tyGenericBody, tyRef, tyPtr, tyAlias, tySink, tyOwned}:
|
||||
result = lastSon(result)
|
||||
|
||||
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||
obj: PType) =
|
||||
assert obj.kind == tyObject
|
||||
if (obj.len > 0) and (obj[0] != nil):
|
||||
addInheritedFields(c, check, pos, obj[0].skipGenericInvocation)
|
||||
addInheritedFieldsAux(c, check, pos, obj.n)
|
||||
proc tryAddInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||
obj: PType, n: PNode, isPartial = false): bool =
|
||||
if (not isPartial) and (obj.kind notin {tyObject, tyGenericParam} or tfFinal in obj.flags):
|
||||
localError(c.config, n.info, "Cannot inherit from: '" & $obj & "'")
|
||||
result = false
|
||||
elif obj.kind == tyObject:
|
||||
result = true
|
||||
if (obj.len > 0) and (obj[0] != nil):
|
||||
result = result and tryAddInheritedFields(c, check, pos, obj[0].skipGenericInvocation, n)
|
||||
addInheritedFieldsAux(c, check, pos, obj.n)
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType =
|
||||
if n.len == 0:
|
||||
@@ -914,7 +920,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
|
||||
if concreteBase.sym != nil and concreteBase.sym.magic == mException and
|
||||
sfSystemModule notin c.module.flags:
|
||||
message(c.config, n.info, warnInheritFromException, "")
|
||||
addInheritedFields(c, check, pos, concreteBase)
|
||||
if not tryAddInheritedFields(c, check, pos, concreteBase, n):
|
||||
return newType(tyError, nextTypeId c.idgen, result.owner)
|
||||
|
||||
else:
|
||||
if concreteBase.kind != tyError:
|
||||
localError(c.config, n[1].info, "inheritance only works with non-final objects; " &
|
||||
@@ -932,7 +940,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType
|
||||
result.n = newNodeI(nkRecList, n.info)
|
||||
else:
|
||||
# partial object so add things to the check
|
||||
addInheritedFields(c, check, pos, result)
|
||||
if not tryAddInheritedFields(c, check, pos, result, n, isPartial = true):
|
||||
return newType(tyError, nextTypeId c.idgen, result.owner)
|
||||
|
||||
semRecordNodeAux(c, n[2], check, pos, result.n, result)
|
||||
if n[0].kind != nkEmpty:
|
||||
# dummy symbol for `pragma`:
|
||||
@@ -1443,19 +1453,21 @@ proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
|
||||
result = semTypeNode(c, n, nil)
|
||||
n.typ = makeTypeDesc(c, result)
|
||||
|
||||
proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
|
||||
proc trySemObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType): bool =
|
||||
var
|
||||
check = initIntSet()
|
||||
pos = 0
|
||||
let
|
||||
realBase = t[0]
|
||||
base = skipTypesOrNil(realBase, skipPtrs)
|
||||
result = true
|
||||
if base.isNil:
|
||||
localError(c.config, n.info, errIllegalRecursionInTypeX % "object")
|
||||
else:
|
||||
let concreteBase = skipGenericInvocation(base)
|
||||
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
||||
addInheritedFields(c, check, pos, concreteBase)
|
||||
if not tryAddInheritedFields(c, check, pos, concreteBase, n):
|
||||
return false
|
||||
else:
|
||||
if concreteBase.kind != tyError:
|
||||
localError(c.config, n.info, errInheritanceOnlyWithNonFinalObjects)
|
||||
@@ -1535,7 +1547,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
return errorType(c)
|
||||
if tx != result and tx.kind == tyObject:
|
||||
if tx[0] != nil:
|
||||
semObjectTypeForInheritedGenericInst(c, n, tx)
|
||||
if not trySemObjectTypeForInheritedGenericInst(c, n, tx):
|
||||
return newOrPrevType(tyError, prev, c)
|
||||
var position = 0
|
||||
recomputeFieldPositions(tx, tx.n, position)
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType =
|
||||
# XXX: This happens for prematurely cached
|
||||
# types such as Channel[empty]. Why?
|
||||
# See the notes for PActor in handleGenericInvocation
|
||||
return
|
||||
# if this is return the same type gets cached more than it needs to
|
||||
continue
|
||||
if not sameFlags(inst, key):
|
||||
continue
|
||||
|
||||
@@ -200,7 +201,7 @@ proc hasValuelessStatics(n: PNode): bool =
|
||||
a
|
||||
proc doThing(_: MyThing)
|
||||
]#
|
||||
if n.safeLen == 0:
|
||||
if n.safeLen == 0 and n.kind != nkEmpty: # Some empty nodes can get in here
|
||||
n.typ == nil or n.typ.kind == tyStatic
|
||||
else:
|
||||
for x in n:
|
||||
|
||||
@@ -211,7 +211,7 @@ proc sumGeneric(t: PType): int =
|
||||
# and Foo[T] has the value 2 so that we know Foo[Foo[T]] is more
|
||||
# specific than Foo[T].
|
||||
var t = t
|
||||
var isvar = 1
|
||||
var isvar = 0
|
||||
while true:
|
||||
case t.kind
|
||||
of tyGenericInst, tyArray, tyRef, tyPtr, tyDistinct, tyUncheckedArray,
|
||||
@@ -247,6 +247,8 @@ proc sumGeneric(t: PType): int =
|
||||
of tyBool, tyChar, tyEnum, tyObject, tyPointer,
|
||||
tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
tyUInt..tyUInt64, tyCompositeTypeClass:
|
||||
return isvar + 1
|
||||
of tyBuiltInTypeClass:
|
||||
return isvar
|
||||
else:
|
||||
return 0
|
||||
@@ -362,7 +364,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
|
||||
of tyOwned:
|
||||
# bug #11257: the comparison system.`==`[T: proc](x, y: T) works
|
||||
# better without the 'owned' type:
|
||||
if f != nil and f.len > 0 and f[0].skipTypes({tyBuiltInTypeClass}).kind == tyProc:
|
||||
if f != nil and f.len > 0 and f[0].skipTypes({tyBuiltInTypeClass, tyOr}).kind == tyProc:
|
||||
result = t.lastSon
|
||||
else:
|
||||
result = t
|
||||
@@ -1169,7 +1171,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
of tyArray:
|
||||
var fRange = f[0]
|
||||
var aRange = a[0]
|
||||
if fRange.kind == tyGenericParam:
|
||||
if fRange.kind in {tyGenericParam, tyAnything}:
|
||||
var prev = PType(idTableGet(c.bindings, fRange))
|
||||
if prev == nil:
|
||||
put(c, fRange, a[0])
|
||||
@@ -1264,8 +1266,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
result = isSubtype
|
||||
else:
|
||||
result = isNone
|
||||
elif tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||
result = isNilConversion
|
||||
of tyNil: result = isNone
|
||||
else: discard
|
||||
of tyOrdinal:
|
||||
@@ -1362,11 +1362,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
else: discard
|
||||
of tyString:
|
||||
case a.kind
|
||||
of tyString:
|
||||
if tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||
result = isNilConversion
|
||||
else:
|
||||
result = isEqual
|
||||
of tyString: result = isEqual
|
||||
of tyNil: result = isNone
|
||||
else: discard
|
||||
of tyCstring:
|
||||
@@ -1501,6 +1497,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
if x.kind == tyGenericInvocation:
|
||||
if f[0] == x[0]:
|
||||
for i in 1..<f.len:
|
||||
# Handle when checking against a generic that isn't fully instantiated
|
||||
if i >= x.len: return
|
||||
let tr = typeRel(c, f[i], x[i], flags)
|
||||
if tr <= isSubtype: return
|
||||
result = isGeneric
|
||||
@@ -1636,7 +1634,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
elif a.len > 0 and a.lastSon == f:
|
||||
# Needed for checking `Y` == `Addable` in the following
|
||||
#[
|
||||
type
|
||||
type
|
||||
Addable = concept a, type A
|
||||
a + a is A
|
||||
MyType[T: Addable; Y: static T] = object
|
||||
@@ -1894,10 +1892,21 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
||||
else:
|
||||
result.typ = errorType(c)
|
||||
else:
|
||||
result.typ = f.skipTypes({tySink, tyVar})
|
||||
result.typ = f.skipTypes({tySink})
|
||||
# keep varness
|
||||
if arg.typ != nil and arg.typ.kind == tyVar:
|
||||
result.typ = toVar(result.typ, tyVar, c.idgen)
|
||||
else:
|
||||
result.typ = result.typ.skipTypes({tyVar})
|
||||
|
||||
if result.typ == nil: internalError(c.graph.config, arg.info, "implicitConv")
|
||||
result.add c.graph.emptyNode
|
||||
result.add arg
|
||||
if arg.typ != nil and arg.typ.kind == tyLent:
|
||||
let a = newNodeIT(nkHiddenDeref, arg.info, arg.typ[0])
|
||||
a.add arg
|
||||
result.add a
|
||||
else:
|
||||
result.add arg
|
||||
|
||||
proc isLValue(c: PContext; n: PNode): bool {.inline.} =
|
||||
let aa = isAssignable(nil, n)
|
||||
|
||||
@@ -81,7 +81,16 @@ proc cmpSuggestions(a, b: Suggest): int =
|
||||
# independent of hashing order:
|
||||
result = cmp(a.name[], b.name[])
|
||||
|
||||
proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int =
|
||||
proc scanForTrailingAsterisk(line: string, start: int): int =
|
||||
result = 0
|
||||
while start+result < line.len and line[start+result] in {' ', '\t'}:
|
||||
inc result
|
||||
if start+result < line.len and line[start+result] == '*':
|
||||
inc result
|
||||
else:
|
||||
result = 0
|
||||
|
||||
proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo; skipTrailingAsterisk: bool = false): int =
|
||||
let
|
||||
line = sourceLine(conf, info)
|
||||
column = toColumn(info)
|
||||
@@ -103,8 +112,10 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int
|
||||
result = 0
|
||||
elif ident[0] in linter.Letters and ident[^1] != '=':
|
||||
result = identLen(line, column)
|
||||
if cmpIgnoreStyle(line[column..column + result - 1], ident) != 0:
|
||||
if cmpIgnoreStyle(line[column..column + result - 1], ident[0..min(result-1,len(ident)-1)]) != 0:
|
||||
result = 0
|
||||
if skipTrailingAsterisk and result > 0:
|
||||
result += scanForTrailingAsterisk(line, column + result)
|
||||
else:
|
||||
var sourceIdent: string
|
||||
result = parseWhile(line, sourceIdent,
|
||||
@@ -154,7 +165,10 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
|
||||
result.qualifiedPath.add(s.name.s)
|
||||
|
||||
if s.typ != nil:
|
||||
result.forth = typeToString(s.typ)
|
||||
if section == ideInlayHints:
|
||||
result.forth = typeToString(s.typ, preferInlayHint)
|
||||
else:
|
||||
result.forth = typeToString(s.typ, preferInferredEffects)
|
||||
else:
|
||||
result.forth = ""
|
||||
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
|
||||
@@ -173,58 +187,90 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
|
||||
result.filePath = toFullPath(g.config, infox)
|
||||
result.line = toLinenumber(infox)
|
||||
result.column = toColumn(infox)
|
||||
result.tokenLen = if section != ideHighlight:
|
||||
result.tokenLen = if section notin {ideHighlight, ideInlayHints}:
|
||||
s.name.s.len
|
||||
else:
|
||||
getTokenLenFromSource(g.config, s.name.s, infox)
|
||||
getTokenLenFromSource(g.config, s.name.s, infox, section == ideInlayHints)
|
||||
result.version = g.config.suggestVersion
|
||||
result.endLine = endLine
|
||||
result.endCol = endCol
|
||||
|
||||
proc `$`*(suggest: Suggest): string =
|
||||
result = $suggest.section
|
||||
proc `$`*(suggest: SuggestInlayHint): string =
|
||||
result = $suggest.kind
|
||||
result.add(sep)
|
||||
if suggest.section == ideHighlight:
|
||||
if suggest.symkind.TSymKind == skVar and suggest.isGlobal:
|
||||
result.add("skGlobalVar")
|
||||
elif suggest.symkind.TSymKind == skLet and suggest.isGlobal:
|
||||
result.add("skGlobalLet")
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
result.add(suggest.label)
|
||||
result.add(sep)
|
||||
result.add($suggest.paddingLeft)
|
||||
result.add(sep)
|
||||
result.add($suggest.paddingRight)
|
||||
result.add(sep)
|
||||
result.add($suggest.allowInsert)
|
||||
result.add(sep)
|
||||
result.add(suggest.tooltip)
|
||||
|
||||
proc `$`*(suggest: Suggest): string =
|
||||
if suggest.section == ideInlayHints:
|
||||
result = $suggest.inlayHintInfo
|
||||
else:
|
||||
result = $suggest.section
|
||||
result.add(sep)
|
||||
if suggest.section == ideHighlight:
|
||||
if suggest.symkind.TSymKind == skVar and suggest.isGlobal:
|
||||
result.add("skGlobalVar")
|
||||
elif suggest.symkind.TSymKind == skLet and suggest.isGlobal:
|
||||
result.add("skGlobalLet")
|
||||
else:
|
||||
result.add($suggest.symkind.TSymKind)
|
||||
result.add(sep)
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
result.add($suggest.tokenLen)
|
||||
else:
|
||||
result.add($suggest.symkind.TSymKind)
|
||||
result.add(sep)
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
result.add($suggest.tokenLen)
|
||||
else:
|
||||
result.add($suggest.symkind.TSymKind)
|
||||
result.add(sep)
|
||||
if suggest.qualifiedPath.len != 0:
|
||||
result.add(suggest.qualifiedPath.join("."))
|
||||
result.add(sep)
|
||||
result.add(suggest.forth)
|
||||
result.add(sep)
|
||||
result.add(suggest.filePath)
|
||||
result.add(sep)
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
|
||||
result.add(suggest.doc.escape)
|
||||
if suggest.version in {0, 3}:
|
||||
result.add(sep)
|
||||
result.add($suggest.quality)
|
||||
if suggest.section == ideSug:
|
||||
if suggest.qualifiedPath.len != 0:
|
||||
result.add(suggest.qualifiedPath.join("."))
|
||||
result.add(sep)
|
||||
result.add(suggest.forth)
|
||||
result.add(sep)
|
||||
result.add(suggest.filePath)
|
||||
result.add(sep)
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
|
||||
result.add(suggest.doc.escape)
|
||||
if suggest.version in {0, 3}:
|
||||
result.add(sep)
|
||||
result.add($suggest.prefix)
|
||||
result.add($suggest.quality)
|
||||
if suggest.section == ideSug:
|
||||
result.add(sep)
|
||||
result.add($suggest.prefix)
|
||||
|
||||
if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}):
|
||||
result.add(sep)
|
||||
result.add($suggest.endLine)
|
||||
result.add(sep)
|
||||
result.add($suggest.endCol)
|
||||
if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}):
|
||||
result.add(sep)
|
||||
result.add($suggest.endLine)
|
||||
result.add(sep)
|
||||
result.add($suggest.endCol)
|
||||
|
||||
proc suggestToSuggestInlayHint*(sug: Suggest): SuggestInlayHint =
|
||||
SuggestInlayHint(
|
||||
kind: sihkType,
|
||||
line: sug.line,
|
||||
column: sug.column + sug.tokenLen,
|
||||
label: ": " & sug.forth,
|
||||
paddingLeft: false,
|
||||
paddingRight: false,
|
||||
allowInsert: true,
|
||||
tooltip: ""
|
||||
)
|
||||
|
||||
proc suggestResult*(conf: ConfigRef; s: Suggest) =
|
||||
if not isNil(conf.suggestionResultHook):
|
||||
@@ -439,7 +485,15 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
|
||||
if t[0] == nil: break
|
||||
t = skipTypes(t[0], skipPtrs)
|
||||
elif typ.kind == tyTuple and typ.n != nil:
|
||||
suggestSymList(c, typ.n, field, n.info, outputs)
|
||||
# All tuple fields are in scope
|
||||
# So go through each field and add it to the suggestions (If it passes the filter)
|
||||
for node in typ.n:
|
||||
if node.kind == nkSym:
|
||||
let s = node.sym
|
||||
var pm: PrefixMatch
|
||||
if filterSym(s, field, pm):
|
||||
outputs.add(symToSuggest(c.graph, s, isLocal=true, ideSug, n.info,
|
||||
s.getQuality, pm, c.inTypeContext > 0, 0))
|
||||
|
||||
suggestOperations(c, n, field, orig, outputs)
|
||||
if typ != orig:
|
||||
@@ -498,7 +552,7 @@ proc findDefinition(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym
|
||||
if s.isNil: return
|
||||
if isTracked(info, g.config.m.trackPos, s.name.s.len) or (s == usageSym and sfForward notin s.flags):
|
||||
suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0, useSuppliedInfo = s == usageSym))
|
||||
if sfForward notin s.flags and g.config.suggestVersion != 3:
|
||||
if sfForward notin s.flags and g.config.suggestVersion < 3:
|
||||
suggestQuit()
|
||||
else:
|
||||
usageSym = s
|
||||
@@ -513,7 +567,7 @@ proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; i
|
||||
## misnamed: should be 'symDeclared'
|
||||
let conf = g.config
|
||||
when defined(nimsuggest):
|
||||
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info)
|
||||
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info, isDecl: isDecl)
|
||||
|
||||
if conf.suggestVersion == 0:
|
||||
if s.allUsages.len == 0:
|
||||
@@ -712,7 +766,7 @@ proc suggestSentinel*(c: PContext) =
|
||||
|
||||
when defined(nimsuggest):
|
||||
proc onDef(graph: ModuleGraph, s: PSym, info: TLineInfo) =
|
||||
if graph.config.suggestVersion == 3 and info.exactEquals(s.info):
|
||||
if graph.config.suggestVersion >= 3 and info.exactEquals(s.info):
|
||||
suggestSym(graph, info, s, graph.usageSym)
|
||||
|
||||
template getPContext(): untyped =
|
||||
|
||||
@@ -316,6 +316,14 @@ proc introduceNewLocalVars(c: PTransf, n: PNode): PNode =
|
||||
if a.kind == nkSym:
|
||||
n[1] = transformSymAux(c, a)
|
||||
return n
|
||||
of nkProcDef: # todo optimize nosideeffects?
|
||||
result = newTransNode(n)
|
||||
let x = freshVar(c, n[namePos].sym)
|
||||
idNodeTablePut(c.transCon.mapping, n[namePos].sym, x)
|
||||
result[namePos] = x # we have to copy proc definitions for iters
|
||||
for i in 1..<n.len:
|
||||
result[i] = introduceNewLocalVars(c, n[i])
|
||||
result[namePos].sym.ast = result
|
||||
else:
|
||||
result = newTransNode(n)
|
||||
for i in 0..<n.len:
|
||||
@@ -638,7 +646,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
|
||||
else:
|
||||
for i in 0..<n.safeLen: findWrongOwners(c, n[i])
|
||||
|
||||
proc isSimpleIteratorVar(c: PTransf; iter: PSym): bool =
|
||||
proc isSimpleIteratorVar(c: PTransf; iter: PSym; call: PNode; owner: PSym): bool =
|
||||
proc rec(n: PNode; owner: PSym; dangerousYields: var int) =
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: discard
|
||||
@@ -650,9 +658,22 @@ proc isSimpleIteratorVar(c: PTransf; iter: PSym): bool =
|
||||
else:
|
||||
for c in n: rec(c, owner, dangerousYields)
|
||||
|
||||
proc recSym(n: PNode; owner: PSym; sameOwner: var bool) =
|
||||
case n.kind
|
||||
of {nkEmpty..nkNilLit} - {nkSym}: discard
|
||||
of nkSym:
|
||||
if n.sym.owner != owner:
|
||||
sameOwner = false
|
||||
else:
|
||||
for c in n: recSym(c, owner, sameOwner)
|
||||
|
||||
var dangerousYields = 0
|
||||
rec(getBody(c.graph, iter), iter, dangerousYields)
|
||||
result = dangerousYields == 0
|
||||
# the parameters should be owned by the owner
|
||||
# bug #22237
|
||||
for i in 1..<call.len:
|
||||
recSym(call[i], owner, result)
|
||||
|
||||
template destructor(t: PType): PSym = getAttachedOp(c.graph, t, attachedDestructor)
|
||||
|
||||
@@ -696,7 +717,7 @@ proc transformFor(c: PTransf, n: PNode): PNode =
|
||||
for j in 0..<n[i].len-1:
|
||||
addVar(v, copyTree(n[i][j])) # declare new vars
|
||||
else:
|
||||
if n[i].kind == nkSym and isSimpleIteratorVar(c, iter):
|
||||
if n[i].kind == nkSym and isSimpleIteratorVar(c, iter, call, n[i].sym.owner):
|
||||
incl n[i].sym.flags, sfCursor
|
||||
addVar(v, copyTree(n[i])) # declare new vars
|
||||
stmtList.add(v)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options,
|
||||
lineinfos, int128, modulegraphs, astmsgs
|
||||
lineinfos, int128, modulegraphs, astmsgs, wordrecg
|
||||
|
||||
type
|
||||
TPreferedDesc* = enum
|
||||
@@ -25,6 +25,8 @@ type
|
||||
preferMixed,
|
||||
# most useful, shows: symbol + resolved symbols if it differs, e.g.:
|
||||
# tuple[a: MyInt{int}, b: float]
|
||||
preferInlayHint,
|
||||
preferInferredEffects,
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
isNone, isConvertible,
|
||||
@@ -372,15 +374,18 @@ proc canFormAcycleAux(g: ModuleGraph; marker: var IntSet, typ: PType, orig: PTyp
|
||||
proc canFormAcycleNode(g: ModuleGraph; marker: var IntSet, n: PNode, orig: PType, withRef: bool, hasTrace: bool): bool =
|
||||
result = false
|
||||
if n != nil:
|
||||
result = canFormAcycleAux(g, marker, n.typ, orig, withRef, hasTrace)
|
||||
if not result:
|
||||
case n.kind
|
||||
of nkNone..nkNilLit:
|
||||
discard
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
result = canFormAcycleNode(g, marker, n[i], orig, withRef, hasTrace)
|
||||
if result: return
|
||||
var hasCursor = n.kind == nkSym and sfCursor in n.sym.flags
|
||||
# cursor fields don't own the refs, which cannot form reference cycles
|
||||
if hasTrace or not hasCursor:
|
||||
result = canFormAcycleAux(g, marker, n.typ, orig, withRef, hasTrace)
|
||||
if not result:
|
||||
case n.kind
|
||||
of nkNone..nkNilLit:
|
||||
discard
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
result = canFormAcycleNode(g, marker, n[i], orig, withRef, hasTrace)
|
||||
if result: return
|
||||
|
||||
|
||||
proc sameBackendType*(x, y: PType): bool
|
||||
@@ -500,7 +505,7 @@ const
|
||||
"void", "iterable"]
|
||||
|
||||
const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo,
|
||||
preferGenericArg, preferResolved, preferMixed}
|
||||
preferGenericArg, preferResolved, preferMixed, preferInlayHint, preferInferredEffects}
|
||||
|
||||
template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
|
||||
tc.add concrete
|
||||
@@ -534,7 +539,10 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
if prefer in preferToResolveSymbols and t.sym != nil and
|
||||
sfAnon notin t.sym.flags and t.kind != tySequence:
|
||||
if t.kind == tyInt and isIntLit(t):
|
||||
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
||||
if prefer == preferInlayHint:
|
||||
result = t.sym.name.s
|
||||
else:
|
||||
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
||||
elif t.kind == tyAlias and t[0].kind != tyAlias:
|
||||
result = typeToString(t[0])
|
||||
elif prefer in {preferResolved, preferMixed}:
|
||||
@@ -550,7 +558,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
result = t.sym.name.s
|
||||
if prefer == preferMixed and result != t.sym.name.s:
|
||||
result = t.sym.name.s & "{" & result & "}"
|
||||
elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil:
|
||||
elif prefer in {preferName, preferTypeName, preferInlayHint, preferInferredEffects} or t.sym.owner.isNil:
|
||||
# note: should probably be: {preferName, preferTypeName, preferGenericArg}
|
||||
result = t.sym.name.s
|
||||
if t.kind == tyGenericParam and t.len > 0:
|
||||
@@ -569,8 +577,11 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
if not isIntLit(t) or prefer == preferExported:
|
||||
result = typeToStr[t.kind]
|
||||
else:
|
||||
if prefer == preferGenericArg:
|
||||
case prefer:
|
||||
of preferGenericArg:
|
||||
result = $t.n.intVal
|
||||
of preferInlayHint:
|
||||
result = "int"
|
||||
else:
|
||||
result = "int literal(" & $t.n.intVal & ")"
|
||||
of tyGenericInst, tyGenericInvocation:
|
||||
@@ -743,6 +754,15 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
result.add(')')
|
||||
if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0]))
|
||||
var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv
|
||||
var hasImplicitRaises = false
|
||||
if not isNil(t.owner) and not isNil(t.owner.ast) and (t.owner.ast.len - 1) >= pragmasPos:
|
||||
let pragmasNode = t.owner.ast[pragmasPos]
|
||||
let raisesSpec = effectSpec(pragmasNode, wRaises)
|
||||
if not isNil(raisesSpec):
|
||||
addSep(prag)
|
||||
prag.add("raises: ")
|
||||
prag.add($raisesSpec)
|
||||
hasImplicitRaises = true
|
||||
if tfNoSideEffect in t.flags:
|
||||
addSep(prag)
|
||||
prag.add("noSideEffect")
|
||||
@@ -752,6 +772,20 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
if t.lockLevel.ord != UnspecifiedLockLevel.ord:
|
||||
addSep(prag)
|
||||
prag.add("locks: " & $t.lockLevel)
|
||||
if not hasImplicitRaises and prefer == preferInferredEffects and not isNil(t.owner) and not isNil(t.owner.typ) and not isNil(t.owner.typ.n) and (t.owner.typ.n.len > 0):
|
||||
let effects = t.owner.typ.n[0]
|
||||
if effects.kind == nkEffectList and effects.len == effectListLen:
|
||||
var inferredRaisesStr = ""
|
||||
let effs = effects[exceptionEffects]
|
||||
if not isNil(effs):
|
||||
for eff in items(effs):
|
||||
if not isNil(eff):
|
||||
addSep(inferredRaisesStr)
|
||||
inferredRaisesStr.add($eff.typ)
|
||||
addSep(prag)
|
||||
prag.add("raises: <inferred> [")
|
||||
prag.add(inferredRaisesStr)
|
||||
prag.add("]")
|
||||
if prag.len != 0: result.add("{." & prag & ".}")
|
||||
of tyVarargs:
|
||||
result = typeToStr[t.kind] % typeToString(t[0])
|
||||
@@ -797,11 +831,11 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 =
|
||||
result = firstOrd(conf, lastSon(t))
|
||||
of tyOrdinal:
|
||||
if t.len > 0: result = firstOrd(conf, lastSon(t))
|
||||
else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')')
|
||||
else: fatal(conf, unknownLineInfo, "invalid kind for firstOrd(" & $t.kind & ')')
|
||||
of tyUncheckedArray, tyCstring:
|
||||
result = Zero
|
||||
else:
|
||||
internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')')
|
||||
fatal(conf, unknownLineInfo, "invalid kind for firstOrd(" & $t.kind & ')')
|
||||
result = Zero
|
||||
|
||||
proc firstFloat*(t: PType): BiggestFloat =
|
||||
@@ -856,11 +890,11 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
|
||||
of tyProxy: result = Zero
|
||||
of tyOrdinal:
|
||||
if t.len > 0: result = lastOrd(conf, lastSon(t))
|
||||
else: internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')')
|
||||
else: fatal(conf, unknownLineInfo, "invalid kind for lastOrd(" & $t.kind & ')')
|
||||
of tyUncheckedArray:
|
||||
result = Zero
|
||||
else:
|
||||
internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')')
|
||||
fatal(conf, unknownLineInfo, "invalid kind for lastOrd(" & $t.kind & ')')
|
||||
result = Zero
|
||||
|
||||
proc lastFloat*(t: PType): BiggestFloat =
|
||||
@@ -1223,7 +1257,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
assert a[0].len == 0
|
||||
assert b.len == 1
|
||||
assert b[0].len == 0
|
||||
result = a[0].kind == b[0].kind
|
||||
result = a[0].kind == b[0].kind and sameFlags(a[0], b[0])
|
||||
if result and a[0].kind == tyProc and IgnoreCC notin c.flags:
|
||||
let ecc = a[0].flags * {tfExplicitCallConv}
|
||||
result = ecc == b[0].flags * {tfExplicitCallConv} and
|
||||
(ecc == {} or a[0].callConv == b[0].callConv)
|
||||
of tyGenericInvocation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef,
|
||||
tyPtr, tyVar, tyLent, tySink, tyUncheckedArray, tyArray, tyProc, tyVarargs,
|
||||
tyOrdinal, tyCompositeTypeClass, tyUserTypeClass, tyUserTypeClassInst,
|
||||
|
||||
@@ -772,6 +772,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
else:
|
||||
if src.kind notin {nkEmpty..nkTripleStrLit} and idx <% src.len:
|
||||
takeAddress regs[ra], src.sons[idx]
|
||||
elif src.kind in nkStrKinds and idx <% src.strVal.len:
|
||||
regs[ra] = takeCharAddress(c, src, idx, pc)
|
||||
else:
|
||||
stackTrace(c, tos, pc, formatErrorIndexBound(idx, src.safeLen-1))
|
||||
of opcLdStrIdx:
|
||||
@@ -995,7 +997,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcLenCstring:
|
||||
decodeBImm(rkInt)
|
||||
assert regs[rb].kind == rkNode
|
||||
regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm
|
||||
if regs[rb].node.kind == nkNilLit:
|
||||
regs[ra].intVal = -imm
|
||||
else:
|
||||
regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm
|
||||
of opcIncl:
|
||||
decodeB(rkNode)
|
||||
let b = regs[rb].regToNode
|
||||
@@ -1193,6 +1198,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcEqStr:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord(regs[rb].node.strVal == regs[rc].node.strVal)
|
||||
of opcEqCString:
|
||||
decodeBC(rkInt)
|
||||
let bNil = regs[rb].node.kind == nkNilLit
|
||||
let cNil = regs[rc].node.kind == nkNilLit
|
||||
regs[ra].intVal = ord((bNil and cNil) or
|
||||
(not bNil and not cNil and regs[rb].node.strVal == regs[rc].node.strVal))
|
||||
of opcLeStr:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord(regs[rb].node.strVal <= regs[rc].node.strVal)
|
||||
@@ -1463,7 +1474,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[ra].node
|
||||
c.currentExceptionA = raised
|
||||
# Set the `name` field of the exception
|
||||
c.currentExceptionA[2].skipColon.strVal = c.currentExceptionA.typ.sym.name.s
|
||||
var exceptionNameNode = newStrNode(nkStrLit, c.currentExceptionA.typ.sym.name.s)
|
||||
if c.currentExceptionA[2].kind == nkExprColonExpr:
|
||||
exceptionNameNode.typ = c.currentExceptionA[2][1].typ
|
||||
c.currentExceptionA[2][1] = exceptionNameNode
|
||||
else:
|
||||
exceptionNameNode.typ = c.currentExceptionA[2].typ
|
||||
c.currentExceptionA[2] = exceptionNameNode
|
||||
c.exceptionInstr = pc
|
||||
|
||||
var frame = tos
|
||||
|
||||
@@ -99,7 +99,7 @@ type
|
||||
opcLeFloat, opcLtFloat, opcLeu, opcLtu,
|
||||
opcEqRef, opcEqNimNode, opcSameNodeType,
|
||||
opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
|
||||
opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
|
||||
opcEqStr, opcEqCString, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
|
||||
opcMulSet, opcPlusSet, opcMinusSet, opcConcatStr,
|
||||
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
|
||||
opcIsNil, opcOf, opcIs,
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
import tables
|
||||
|
||||
import
|
||||
strutils, ast, types, msgs, renderer, vmdef, trees,
|
||||
strutils, ast, types, msgs, renderer, vmdef,
|
||||
intsets, magicsys, options, lowerings, lineinfos, transf, astmsgs
|
||||
|
||||
from modulegraphs import getBody
|
||||
@@ -408,13 +408,19 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
|
||||
c.gen(it[0], tmp)
|
||||
elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false
|
||||
c.clearDest(n, dest)
|
||||
c.gen(it[1], dest) # then part
|
||||
if isEmptyType(it[1].typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(it[1])
|
||||
else:
|
||||
c.gen(it[1], dest) # then part
|
||||
if i < n.len-1:
|
||||
endings.add(c.xjmp(it[1], opcJmp, 0))
|
||||
c.patch(elsePos)
|
||||
else:
|
||||
c.clearDest(n, dest)
|
||||
c.gen(it[0], dest)
|
||||
if isEmptyType(it[0].typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(it[0])
|
||||
else:
|
||||
c.gen(it[0], dest)
|
||||
for endPos in endings: c.patch(endPos)
|
||||
c.clearDest(n, dest)
|
||||
|
||||
@@ -508,17 +514,25 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
|
||||
let it = n[i]
|
||||
if it.len == 1:
|
||||
# else stmt:
|
||||
if it[0].kind != nkNilLit or it[0].typ != nil:
|
||||
let body = it[0]
|
||||
if body.kind != nkNilLit or body.typ != nil:
|
||||
# an nkNilLit with nil for typ implies there is no else branch, this
|
||||
# avoids unused related errors as we've already consumed the dest
|
||||
c.gen(it[0], dest)
|
||||
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(body)
|
||||
else:
|
||||
c.gen(body, dest)
|
||||
else:
|
||||
let b = rawGenLiteral(c, it)
|
||||
c.gABx(it, opcBranch, tmp, b)
|
||||
let elsePos = c.xjmp(it.lastSon, opcFJmp, tmp)
|
||||
c.gen(it.lastSon, dest)
|
||||
let body = it.lastSon
|
||||
let elsePos = c.xjmp(body, opcFJmp, tmp)
|
||||
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(body)
|
||||
else:
|
||||
c.gen(body, dest)
|
||||
if i < n.len-1:
|
||||
endings.add(c.xjmp(it.lastSon, opcJmp, 0))
|
||||
endings.add(c.xjmp(body, opcJmp, 0))
|
||||
c.patch(elsePos)
|
||||
c.clearDest(n, dest)
|
||||
for endPos in endings: c.patch(endPos)
|
||||
@@ -534,7 +548,10 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
|
||||
if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
|
||||
var endings: seq[TPosition] = @[]
|
||||
let ehPos = c.xjmp(n, opcTry, 0)
|
||||
c.gen(n[0], dest)
|
||||
if isEmptyType(n[0].typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(n[0])
|
||||
else:
|
||||
c.gen(n[0], dest)
|
||||
c.clearDest(n, dest)
|
||||
# Add a jump past the exception handling code
|
||||
let jumpToFinally = c.xjmp(n, opcJmp, 0)
|
||||
@@ -552,7 +569,11 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
|
||||
if it.len == 1:
|
||||
# general except section:
|
||||
c.gABx(it, opcExcept, 0, 0)
|
||||
c.gen(it.lastSon, dest)
|
||||
let body = it.lastSon
|
||||
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(body)
|
||||
else:
|
||||
c.gen(body, dest)
|
||||
c.clearDest(n, dest)
|
||||
if i < n.len:
|
||||
endings.add(c.xjmp(it, opcJmp, 0))
|
||||
@@ -884,6 +905,8 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
|
||||
let dst = n[0].typ.skipTypes(abstractRange)#.kind
|
||||
let srcSize = getSize(c.config, src)
|
||||
let dstSize = getSize(c.config, dst)
|
||||
const unsupportedCastDifferentSize =
|
||||
"VM does not support 'cast' from $1 with size $2 to $3 with size $4 due to different sizes"
|
||||
if src.kind in allowedIntegers and dst.kind in allowedIntegers:
|
||||
let tmp = c.genx(n[1])
|
||||
if dest < 0: dest = c.getTemp(n[0].typ)
|
||||
@@ -900,8 +923,11 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
|
||||
# is smaller than source.
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(dstSize*8))
|
||||
c.freeTemp(tmp)
|
||||
elif srcSize == dstSize and src.kind in allowedIntegers and
|
||||
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
|
||||
elif src.kind in allowedIntegers and
|
||||
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
|
||||
if srcSize != dstSize:
|
||||
globalError(c.config, n.info, unsupportedCastDifferentSize %
|
||||
[$src.kind, $srcSize, $dst.kind, $dstSize])
|
||||
let tmp = c.genx(n[1])
|
||||
if dest < 0: dest = c.getTemp(n[0].typ)
|
||||
if dst.kind == tyFloat32:
|
||||
@@ -910,8 +936,11 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
|
||||
c.gABC(n, opcCastIntToFloat64, dest, tmp)
|
||||
c.freeTemp(tmp)
|
||||
|
||||
elif srcSize == dstSize and src.kind in {tyFloat, tyFloat32, tyFloat64} and
|
||||
elif src.kind in {tyFloat, tyFloat32, tyFloat64} and
|
||||
dst.kind in allowedIntegers:
|
||||
if srcSize != dstSize:
|
||||
globalError(c.config, n.info, unsupportedCastDifferentSize %
|
||||
[$src.kind, $srcSize, $dst.kind, $dstSize])
|
||||
let tmp = c.genx(n[1])
|
||||
if dest < 0: dest = c.getTemp(n[0].typ)
|
||||
if src.kind == tyFloat32:
|
||||
@@ -1153,7 +1182,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
|
||||
genConv(c, n, n[1], dest)
|
||||
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
|
||||
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
|
||||
of mEqCString: genBinaryABC(c, n, dest, opcEqCString)
|
||||
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
|
||||
of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
|
||||
of mEqSet: genBinarySet(c, n, dest, opcEqSet)
|
||||
@@ -1541,6 +1571,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
|
||||
# little hack ahead for bug #12612: assume gensym'ed variables
|
||||
# are in the right scope:
|
||||
if sfGenSym in s.flags and c.prc.sym == nil: discard
|
||||
elif s.kind == skParam and s.typ.kind == tyTypeDesc: discard
|
||||
else: cannotEval(c, n)
|
||||
elif s.kind in {skProc, skFunc, skConverter, skMethod,
|
||||
skIterator} and sfForward in s.flags:
|
||||
@@ -1794,7 +1825,6 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
|
||||
let setLit = c.genx(checkExpr[1])
|
||||
var rs = c.getTemp(getSysType(c.graph, n.info, tyBool))
|
||||
c.gABC(n, opcContainsSet, rs, setLit, discVal)
|
||||
c.freeTemp(discVal)
|
||||
c.freeTemp(setLit)
|
||||
# If the check fails let the user know
|
||||
let lab1 = c.xjmp(n, if negCheck: opcFJmp else: opcTJmp, rs)
|
||||
@@ -1807,6 +1837,7 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
|
||||
strLit.typ = strType
|
||||
c.genLit(strLit, msgReg)
|
||||
c.gABC(n, opcInvalidField, msgReg, discVal)
|
||||
c.freeTemp(discVal)
|
||||
c.freeTemp(msgReg)
|
||||
c.patch(lab1)
|
||||
|
||||
@@ -1878,10 +1909,10 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
|
||||
result = newNodeIT(nkUIntLit, info, t)
|
||||
of tyFloat..tyFloat128:
|
||||
result = newNodeIT(nkFloatLit, info, t)
|
||||
of tyCstring, tyString:
|
||||
of tyString:
|
||||
result = newNodeIT(nkStrLit, info, t)
|
||||
result.strVal = ""
|
||||
of tyVar, tyLent, tyPointer, tyPtr, tyUntyped,
|
||||
of tyCstring, tyVar, tyLent, tyPointer, tyPtr, tyUntyped,
|
||||
tyTyped, tyTypeDesc, tyRef, tyNil:
|
||||
result = newNodeIT(nkNilLit, info, t)
|
||||
of tyProc:
|
||||
@@ -2085,8 +2116,13 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
let s = n.sym
|
||||
checkCanEval(c, n)
|
||||
case s.kind
|
||||
of skVar, skForVar, skTemp, skLet, skParam, skResult:
|
||||
of skVar, skForVar, skTemp, skLet, skResult:
|
||||
genRdVar(c, n, dest, flags)
|
||||
of skParam:
|
||||
if s.typ.kind == tyTypeDesc:
|
||||
genTypeLit(c, s.typ, dest)
|
||||
else:
|
||||
genRdVar(c, n, dest, flags)
|
||||
of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator:
|
||||
# 'skTemplate' is only allowed for 'getAst' support:
|
||||
if s.kind == skIterator and s.typ.callConv == TCallingConvention.ccClosure:
|
||||
@@ -2096,10 +2132,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
genLit(c, n, dest)
|
||||
of skConst:
|
||||
let constVal = if s.ast != nil: s.ast else: s.typ.n
|
||||
if dontInlineConstant(n, constVal):
|
||||
genLit(c, constVal, dest)
|
||||
else:
|
||||
gen(c, constVal, dest)
|
||||
gen(c, constVal, dest)
|
||||
of skEnumField:
|
||||
# we never reach this case - as of the time of this comment,
|
||||
# skEnumField is folded to an int in semfold.nim, but this code
|
||||
|
||||
@@ -32,6 +32,7 @@ type
|
||||
|
||||
wColon = ":", wColonColon = "::", wEquals = "=", wDot = ".", wDotDot = "..",
|
||||
wStar = "*", wMinus = "-",
|
||||
wUnderscore = "_",
|
||||
wMagic = "magic", wThread = "thread", wFinal = "final", wProfiler = "profiler",
|
||||
wMemTracker = "memtracker", wObjChecks = "objchecks",
|
||||
wIntDefine = "intdefine", wStrDefine = "strdefine", wBoolDefine = "booldefine",
|
||||
|
||||
@@ -156,7 +156,10 @@ nimblepath="$home/.nimble/pkgs/"
|
||||
# Configuration for the GNU C/C++ compiler:
|
||||
@if windows:
|
||||
#gcc.path = r"$nim\dist\mingw\bin"
|
||||
@if gcc or tcc:
|
||||
@if gcc:
|
||||
gcc.options.linker %= "-Wl,-Bstatic -lpthread"
|
||||
@end
|
||||
@if tcc:
|
||||
tlsEmulation:on
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -10,6 +10,6 @@ const
|
||||
## is the minor number of Nim's version.
|
||||
## Odd for devel, even for releases.
|
||||
|
||||
NimPatch* {.intdefine.}: int = 14
|
||||
NimPatch* {.intdefine.}: int = 21
|
||||
## is the patch number of Nim's version.
|
||||
## Odd for devel, even for releases.
|
||||
|
||||
@@ -135,8 +135,9 @@ type
|
||||
|
||||
const
|
||||
nnkLiterals* = {nnkCharLit..nnkNilLit}
|
||||
# see matching set CallNodes below
|
||||
nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
|
||||
nnkCallStrLit}
|
||||
nnkCallStrLit, nnkHiddenCallConv}
|
||||
nnkPragmaCallKinds = {nnkExprColonExpr, nnkCall, nnkCallStrLit}
|
||||
|
||||
{.push warnings: off.}
|
||||
@@ -1174,8 +1175,8 @@ const
|
||||
RoutineNodes* = {nnkProcDef, nnkFuncDef, nnkMethodDef, nnkDo, nnkLambda,
|
||||
nnkIteratorDef, nnkTemplateDef, nnkConverterDef, nnkMacroDef}
|
||||
AtomicNodes* = {nnkNone..nnkNilLit}
|
||||
CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
|
||||
nnkCallStrLit, nnkHiddenCallConv}
|
||||
# see matching set nnkCallKinds above
|
||||
CallNodes* = nnkCallKinds
|
||||
|
||||
proc expectKind*(n: NimNode; k: set[NimNodeKind]) =
|
||||
## Checks that `n` is of kind `k`. If this is not the case,
|
||||
|
||||
@@ -309,7 +309,7 @@ type
|
||||
sa_mask*: Sigset ## Set of signals to be blocked during execution of
|
||||
## the signal handling function.
|
||||
sa_flags*: cint ## Special flags.
|
||||
sa_sigaction*: proc (x: cint, y: ptr SigInfo, z: pointer) {.noconv.}
|
||||
sa_restorer: proc() {.noconv.} ## not intended for application use.
|
||||
|
||||
Stack* {.importc: "stack_t",
|
||||
header: "<signal.h>", final, pure.} = object ## stack_t
|
||||
@@ -325,9 +325,9 @@ type
|
||||
SigInfo* {.importc: "siginfo_t",
|
||||
header: "<signal.h>", final, pure.} = object ## siginfo_t
|
||||
si_signo*: cint ## Signal number.
|
||||
si_code*: cint ## Signal code.
|
||||
si_errno*: cint ## If non-zero, an errno value associated with
|
||||
## this signal, as defined in <errno.h>.
|
||||
si_code*: cint ## Signal code.
|
||||
si_pid*: Pid ## Sending process ID.
|
||||
si_uid*: Uid ## Real user ID of sending process.
|
||||
si_addr*: pointer ## Address of faulting instruction.
|
||||
@@ -336,6 +336,12 @@ type
|
||||
si_value*: SigVal ## Signal value.
|
||||
pad {.importc: "_pad".}: array[128 - 56, uint8]
|
||||
|
||||
template sa_sigaction*(v: Sigaction): proc (x: cint, y: ptr SigInfo, z: pointer) {.noconv.} =
|
||||
cast[proc (x: cint, y: ptr SigInfo, z: pointer) {.noconv.}](v.sa_handler)
|
||||
proc `sa_sigaction=`*(v: var Sigaction, x: proc (x: cint, y: ptr SigInfo, z: pointer) {.noconv.}) =
|
||||
v.sa_handler = cast[proc (x: cint) {.noconv.}](x)
|
||||
|
||||
type
|
||||
Nl_item* {.importc: "nl_item", header: "<nl_types.h>".} = cint
|
||||
Nl_catd* {.importc: "nl_catd", header: "<nl_types.h>".} = pointer
|
||||
|
||||
|
||||
@@ -464,6 +464,7 @@ const MSG_EOR* = cint(128)
|
||||
const MSG_OOB* = cint(1)
|
||||
const SCM_RIGHTS* = cint(1)
|
||||
const SO_ACCEPTCONN* = cint(30)
|
||||
const SO_BINDTODEVICE* = cint(25)
|
||||
const SO_BROADCAST* = cint(6)
|
||||
const SO_DEBUG* = cint(1)
|
||||
const SO_DONTROUTE* = cint(5)
|
||||
|
||||
@@ -473,6 +473,7 @@ var MSG_EOR* {.importc: "MSG_EOR", header: "<sys/socket.h>".}: cint
|
||||
var MSG_OOB* {.importc: "MSG_OOB", header: "<sys/socket.h>".}: cint
|
||||
var SCM_RIGHTS* {.importc: "SCM_RIGHTS", header: "<sys/socket.h>".}: cint
|
||||
var SO_ACCEPTCONN* {.importc: "SO_ACCEPTCONN", header: "<sys/socket.h>".}: cint
|
||||
var SO_BINDTODEVICE* {.importc: "SO_BINDTODEVICE", header: "<sys/socket.h>".}: cint
|
||||
var SO_BROADCAST* {.importc: "SO_BROADCAST", header: "<sys/socket.h>".}: cint
|
||||
var SO_DEBUG* {.importc: "SO_DEBUG", header: "<sys/socket.h>".}: cint
|
||||
var SO_DONTROUTE* {.importc: "SO_DONTROUTE", header: "<sys/socket.h>".}: cint
|
||||
|
||||
@@ -149,7 +149,7 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
|
||||
protocol)
|
||||
result.orig = protocol
|
||||
i.inc protocol.parseSaturatedNatural(result.major, i)
|
||||
i.inc # Skip .
|
||||
if i < protocol.len: inc i # Skip .
|
||||
i.inc protocol.parseSaturatedNatural(result.minor, i)
|
||||
|
||||
proc sendStatus(client: AsyncSocket, status: string): Future[void] =
|
||||
@@ -375,7 +375,7 @@ const
|
||||
proc listen*(server: AsyncHttpServer; port: Port; address = ""; domain = AF_INET) =
|
||||
## Listen to the given port and address.
|
||||
when declared(maxDescriptors):
|
||||
server.maxFDs = try: maxDescriptors() except: nimMaxDescriptorsFallback
|
||||
server.maxFDs = try: maxDescriptors() except OSError: nimMaxDescriptorsFallback
|
||||
else:
|
||||
server.maxFDs = nimMaxDescriptorsFallback
|
||||
server.socket = newAsyncSocket(domain)
|
||||
|
||||
@@ -66,14 +66,10 @@ template cbBase(a, b): untyped = [
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', a, b]
|
||||
|
||||
let
|
||||
const
|
||||
cb64 = cbBase('+', '/')
|
||||
cb64safe = cbBase('-', '_')
|
||||
|
||||
const
|
||||
cb64VM = cbBase('+', '/')
|
||||
cb64safeVM = cbBase('-', '_')
|
||||
|
||||
const
|
||||
invalidChar = 255
|
||||
|
||||
@@ -132,14 +128,10 @@ template encodeInternal(s, alphabet: typed): untyped =
|
||||
result.setLen(outputIndex)
|
||||
|
||||
template encodeImpl() {.dirty.} =
|
||||
when nimvm:
|
||||
block:
|
||||
let lookupTableVM = if safe: cb64safeVM else: cb64VM
|
||||
encodeInternal(s, lookupTableVM)
|
||||
if safe:
|
||||
encodeInternal(s, cb64safe)
|
||||
else:
|
||||
block:
|
||||
let lookupTable = if safe: unsafeAddr(cb64safe) else: unsafeAddr(cb64)
|
||||
encodeInternal(s, lookupTable)
|
||||
encodeInternal(s, cb64)
|
||||
|
||||
proc encode*[T: SomeInteger|char](s: openArray[T], safe = false): string =
|
||||
## Encodes `s` into base64 representation.
|
||||
@@ -247,7 +239,7 @@ proc decode*(s: string): string =
|
||||
inputLen = s.len
|
||||
inputEnds = 0
|
||||
# strip trailing characters
|
||||
while s[inputLen - 1] in {'\n', '\r', ' ', '='}:
|
||||
while inputLen > 0 and s[inputLen - 1] in {'\n', '\r', ' ', '='}:
|
||||
dec inputLen
|
||||
# hot loop: read 4 characters at at time
|
||||
inputEnds = inputLen - 4
|
||||
|
||||
@@ -71,9 +71,8 @@ template initImpl(result: typed, initialSize: int) =
|
||||
newSeq(result.data, correctSize)
|
||||
|
||||
template checkIfInitialized(deq: typed) =
|
||||
when compiles(defaultInitialSize):
|
||||
if deq.mask == 0:
|
||||
initImpl(deq, defaultInitialSize)
|
||||
if deq.mask == 0:
|
||||
initImpl(deq, defaultInitialSize)
|
||||
|
||||
proc initDeque*[T](initialSize: int = defaultInitialSize): Deque[T] =
|
||||
## Creates a new empty deque.
|
||||
|
||||
@@ -166,28 +166,6 @@ proc newSinglyLinkedNode*[T](value: T): SinglyLinkedNode[T] =
|
||||
new(result)
|
||||
result.value = value
|
||||
|
||||
func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} =
|
||||
## Creates a new `SinglyLinkedList` from the members of `elems`.
|
||||
runnableExamples:
|
||||
from std/sequtils import toSeq
|
||||
let a = [1, 2, 3, 4, 5].toSinglyLinkedList
|
||||
assert a.toSeq == [1, 2, 3, 4, 5]
|
||||
|
||||
result = initSinglyLinkedList[T]()
|
||||
for elem in elems.items:
|
||||
result.add(elem)
|
||||
|
||||
func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} =
|
||||
## Creates a new `DoublyLinkedList` from the members of `elems`.
|
||||
runnableExamples:
|
||||
from std/sequtils import toSeq
|
||||
let a = [1, 2, 3, 4, 5].toDoublyLinkedList
|
||||
assert a.toSeq == [1, 2, 3, 4, 5]
|
||||
|
||||
result = initDoublyLinkedList[T]()
|
||||
for elem in elems.items:
|
||||
result.add(elem)
|
||||
|
||||
template itemsListImpl() {.dirty.} =
|
||||
var it = L.head
|
||||
while it != nil:
|
||||
@@ -994,3 +972,25 @@ proc appendMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} =
|
||||
## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_
|
||||
## * `addMoved proc <#addMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_
|
||||
a.addMoved(b)
|
||||
|
||||
func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} =
|
||||
## Creates a new `SinglyLinkedList` from the members of `elems`.
|
||||
runnableExamples:
|
||||
from std/sequtils import toSeq
|
||||
let a = [1, 2, 3, 4, 5].toSinglyLinkedList
|
||||
assert a.toSeq == [1, 2, 3, 4, 5]
|
||||
|
||||
result = initSinglyLinkedList[T]()
|
||||
for elem in elems.items:
|
||||
result.add(elem)
|
||||
|
||||
func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} =
|
||||
## Creates a new `DoublyLinkedList` from the members of `elems`.
|
||||
runnableExamples:
|
||||
from std/sequtils import toSeq
|
||||
let a = [1, 2, 3, 4, 5].toDoublyLinkedList
|
||||
assert a.toSeq == [1, 2, 3, 4, 5]
|
||||
|
||||
result = initDoublyLinkedList[T]()
|
||||
for elem in elems.items:
|
||||
result.add(elem)
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
include hashcommon
|
||||
|
||||
const
|
||||
defaultInitialSize* = 32
|
||||
|
||||
template rawGetDeepImpl() {.dirty.} = # Search algo for unconditional add
|
||||
genHashImpl(key, hc)
|
||||
var h: Hash = hc and maxHash(t)
|
||||
@@ -31,9 +34,8 @@ proc rawInsert[X, A, B](t: var X, data: var KeyValuePairSeq[A, B],
|
||||
rawInsertImpl()
|
||||
|
||||
template checkIfInitialized() =
|
||||
when compiles(defaultInitialSize):
|
||||
if t.dataLen == 0:
|
||||
initImpl(t, defaultInitialSize)
|
||||
if t.dataLen == 0:
|
||||
initImpl(t, defaultInitialSize)
|
||||
|
||||
template addImpl(enlarge) {.dirty.} =
|
||||
checkIfInitialized()
|
||||
|
||||
@@ -217,8 +217,6 @@ type
|
||||
## For creating a new empty TableRef, use `newTable proc
|
||||
## <#newTable>`_.
|
||||
|
||||
const
|
||||
defaultInitialSize* = 32
|
||||
|
||||
# ------------------------------ helpers ---------------------------------
|
||||
|
||||
@@ -2891,3 +2889,18 @@ iterator mvalues*[A](t: CountTableRef[A]): var int =
|
||||
if t.data[h].val != 0:
|
||||
yield t.data[h].val
|
||||
assert(len(t) == L, "the length of the table changed while iterating over it")
|
||||
|
||||
proc hash*[K,V](s: Table[K,V]): Hash =
|
||||
for p in pairs(s):
|
||||
result = result xor hash(p)
|
||||
result = !$result
|
||||
|
||||
proc hash*[K,V](s: OrderedTable[K,V]): Hash =
|
||||
for p in pairs(s):
|
||||
result = result !& hash(p)
|
||||
result = !$result
|
||||
|
||||
proc hash*[V](s: CountTable[V]): Hash =
|
||||
for p in pairs(s):
|
||||
result = result xor hash(p)
|
||||
result = !$result
|
||||
@@ -315,16 +315,24 @@ proc murmurHash(x: openArray[byte]): Hash =
|
||||
h1: uint32
|
||||
i = 0
|
||||
|
||||
|
||||
template impl =
|
||||
var j = stepSize
|
||||
while j > 0:
|
||||
dec j
|
||||
k1 = (k1 shl 8) or (ord(x[i+j])).uint32
|
||||
|
||||
# body
|
||||
while i < n * stepSize:
|
||||
var k1: uint32
|
||||
when defined(js) or defined(sparc) or defined(sparc64):
|
||||
var j = stepSize
|
||||
while j > 0:
|
||||
dec j
|
||||
k1 = (k1 shl 8) or (ord(x[i+j])).uint32
|
||||
|
||||
when nimvm:
|
||||
impl()
|
||||
else:
|
||||
k1 = cast[ptr uint32](unsafeAddr x[i])[]
|
||||
when declared(copyMem):
|
||||
copyMem(unsafeAddr k1, unsafeAddr x[i], 4)
|
||||
else:
|
||||
impl()
|
||||
inc i, stepSize
|
||||
|
||||
k1 = imul(k1, c1)
|
||||
|
||||
@@ -328,68 +328,8 @@ func nextPowerOfTwo*(x: int): int =
|
||||
result = result or (result shr 1)
|
||||
result += 1 + ord(x <= 0)
|
||||
|
||||
func sum*[T](x: openArray[T]): T =
|
||||
## Computes the sum of the elements in `x`.
|
||||
##
|
||||
## If `x` is empty, 0 is returned.
|
||||
##
|
||||
## **See also:**
|
||||
## * `prod func <#prod,openArray[T]>`_
|
||||
## * `cumsum func <#cumsum,openArray[T]>`_
|
||||
## * `cumsummed func <#cumsummed,openArray[T]>`_
|
||||
runnableExamples:
|
||||
doAssert sum([1, 2, 3, 4]) == 10
|
||||
doAssert sum([-4, 3, 5]) == 4
|
||||
|
||||
for i in items(x): result = result + i
|
||||
|
||||
func prod*[T](x: openArray[T]): T =
|
||||
## Computes the product of the elements in `x`.
|
||||
##
|
||||
## If `x` is empty, 1 is returned.
|
||||
##
|
||||
## **See also:**
|
||||
## * `sum func <#sum,openArray[T]>`_
|
||||
## * `fac func <#fac,int>`_
|
||||
runnableExamples:
|
||||
doAssert prod([1, 2, 3, 4]) == 24
|
||||
doAssert prod([-4, 3, 5]) == -60
|
||||
|
||||
result = T(1)
|
||||
for i in items(x): result = result * i
|
||||
|
||||
func cumsummed*[T](x: openArray[T]): seq[T] =
|
||||
## Returns the cumulative (aka prefix) summation of `x`.
|
||||
##
|
||||
## If `x` is empty, `@[]` is returned.
|
||||
##
|
||||
## **See also:**
|
||||
## * `sum func <#sum,openArray[T]>`_
|
||||
## * `cumsum func <#cumsum,openArray[T]>`_ for the in-place version
|
||||
runnableExamples:
|
||||
doAssert cumsummed([1, 2, 3, 4]) == @[1, 3, 6, 10]
|
||||
|
||||
let xLen = x.len
|
||||
if xLen == 0:
|
||||
return @[]
|
||||
result.setLen(xLen)
|
||||
result[0] = x[0]
|
||||
for i in 1 ..< xLen: result[i] = result[i - 1] + x[i]
|
||||
|
||||
func cumsum*[T](x: var openArray[T]) =
|
||||
## Transforms `x` in-place (must be declared as `var`) into its
|
||||
## cumulative (aka prefix) summation.
|
||||
##
|
||||
## **See also:**
|
||||
## * `sum func <#sum,openArray[T]>`_
|
||||
## * `cumsummed func <#cumsummed,openArray[T]>`_ for a version which
|
||||
## returns a cumsummed sequence
|
||||
runnableExamples:
|
||||
var a = [1, 2, 3, 4]
|
||||
cumsum(a)
|
||||
doAssert a == @[1, 3, 6, 10]
|
||||
|
||||
for i in 1 ..< x.len: x[i] = x[i - 1] + x[i]
|
||||
|
||||
when not defined(js): # C
|
||||
func sqrt*(x: float32): float32 {.importc: "sqrtf", header: "<math.h>".}
|
||||
@@ -1135,6 +1075,69 @@ func sgn*[T: SomeNumber](x: T): int {.inline.} =
|
||||
{.pop.}
|
||||
{.pop.}
|
||||
|
||||
func sum*[T](x: openArray[T]): T =
|
||||
## Computes the sum of the elements in `x`.
|
||||
##
|
||||
## If `x` is empty, 0 is returned.
|
||||
##
|
||||
## **See also:**
|
||||
## * `prod func <#prod,openArray[T]>`_
|
||||
## * `cumsum func <#cumsum,openArray[T]>`_
|
||||
## * `cumsummed func <#cumsummed,openArray[T]>`_
|
||||
runnableExamples:
|
||||
doAssert sum([1, 2, 3, 4]) == 10
|
||||
doAssert sum([-4, 3, 5]) == 4
|
||||
|
||||
for i in items(x): result = result + i
|
||||
|
||||
func prod*[T](x: openArray[T]): T =
|
||||
## Computes the product of the elements in `x`.
|
||||
##
|
||||
## If `x` is empty, 1 is returned.
|
||||
##
|
||||
## **See also:**
|
||||
## * `sum func <#sum,openArray[T]>`_
|
||||
## * `fac func <#fac,int>`_
|
||||
runnableExamples:
|
||||
doAssert prod([1, 2, 3, 4]) == 24
|
||||
doAssert prod([-4, 3, 5]) == -60
|
||||
|
||||
result = T(1)
|
||||
for i in items(x): result = result * i
|
||||
|
||||
func cumsummed*[T](x: openArray[T]): seq[T] =
|
||||
## Returns the cumulative (aka prefix) summation of `x`.
|
||||
##
|
||||
## If `x` is empty, `@[]` is returned.
|
||||
##
|
||||
## **See also:**
|
||||
## * `sum func <#sum,openArray[T]>`_
|
||||
## * `cumsum func <#cumsum,openArray[T]>`_ for the in-place version
|
||||
runnableExamples:
|
||||
doAssert cumsummed([1, 2, 3, 4]) == @[1, 3, 6, 10]
|
||||
|
||||
let xLen = x.len
|
||||
if xLen == 0:
|
||||
return @[]
|
||||
result.setLen(xLen)
|
||||
result[0] = x[0]
|
||||
for i in 1 ..< xLen: result[i] = result[i - 1] + x[i]
|
||||
|
||||
func cumsum*[T](x: var openArray[T]) =
|
||||
## Transforms `x` in-place (must be declared as `var`) into its
|
||||
## cumulative (aka prefix) summation.
|
||||
##
|
||||
## **See also:**
|
||||
## * `sum func <#sum,openArray[T]>`_
|
||||
## * `cumsummed func <#cumsummed,openArray[T]>`_ for a version which
|
||||
## returns a cumsummed sequence
|
||||
runnableExamples:
|
||||
var a = [1, 2, 3, 4]
|
||||
cumsum(a)
|
||||
doAssert a == @[1, 3, 6, 10]
|
||||
|
||||
for i in 1 ..< x.len: x[i] = x[i - 1] + x[i]
|
||||
|
||||
func `^`*[T: SomeNumber](x: T, y: Natural): T =
|
||||
## Computes `x` to the power of `y`.
|
||||
##
|
||||
|
||||
@@ -3145,14 +3145,14 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW
|
||||
when defined(windows):
|
||||
var bufsize = int32(MAX_PATH)
|
||||
when useWinUnicode:
|
||||
var buf = newWideCString("", bufsize)
|
||||
var buf = newWideCString(bufsize)
|
||||
while true:
|
||||
var L = getModuleFileNameW(0, buf, bufsize)
|
||||
if L == 0'i32:
|
||||
result = "" # error!
|
||||
break
|
||||
elif L > bufsize:
|
||||
buf = newWideCString("", L)
|
||||
buf = newWideCString(L)
|
||||
bufsize = L
|
||||
else:
|
||||
result = buf$L
|
||||
|
||||
@@ -559,7 +559,7 @@ template matchOrParse(mopProc: untyped) =
|
||||
# procs. For the former, *enter* and *leave* event handler code generators
|
||||
# are provided which just return *discard*.
|
||||
|
||||
proc mopProc(s: string, p: Peg, start: int, c: var Captures): int =
|
||||
proc mopProc(s: string, p: Peg, start: int, c: var Captures): int {.gcsafe, raises: [].} =
|
||||
proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int =
|
||||
# Parse handler code must run in an *of* clause of its own for each
|
||||
# *PegKind*, so we encapsulate the identical clause body for
|
||||
|
||||
@@ -573,7 +573,8 @@ template formatValue(result: var string; value: char; specifier: string) =
|
||||
template formatValue(result: var string; value: cstring; specifier: string) =
|
||||
result.add value
|
||||
|
||||
proc strformatImpl(f: string; openChar, closeChar: char): NimNode =
|
||||
proc strformatImpl(f: string; openChar, closeChar: char,
|
||||
lineInfoNode: NimNode = nil): NimNode =
|
||||
template missingCloseChar =
|
||||
error("invalid format string: missing closing character '" & closeChar & "'")
|
||||
|
||||
@@ -581,7 +582,7 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode =
|
||||
error "openChar and closeChar must not be ':'"
|
||||
var i = 0
|
||||
let res = genSym(nskVar, "fmtRes")
|
||||
result = newNimNode(nnkStmtListExpr)
|
||||
result = newNimNode(nnkStmtListExpr, lineInfoNode)
|
||||
# XXX: https://github.com/nim-lang/Nim/issues/8405
|
||||
# When compiling with -d:useNimRtl, certain procs such as `count` from the strutils
|
||||
# module are not accessible at compile-time:
|
||||
@@ -640,6 +641,7 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode =
|
||||
x = parseExpr(subexpr)
|
||||
except ValueError as e:
|
||||
error("could not parse `$#` in `$#`.\n$#" % [subexpr, f, e.msg])
|
||||
x.copyLineInfo(lineInfoNode)
|
||||
let formatSym = bindSym("formatValue", brOpen)
|
||||
var options = ""
|
||||
if f[i] == ':':
|
||||
@@ -665,10 +667,22 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode =
|
||||
if strlit.len > 0:
|
||||
result.add newCall(bindSym"add", res, newLit(strlit))
|
||||
result.add res
|
||||
# workaround for #20381
|
||||
var blockExpr = newNimNode(nnkBlockExpr, lineInfoNode)
|
||||
blockExpr.add(newEmptyNode())
|
||||
blockExpr.add(result)
|
||||
result = blockExpr
|
||||
when defined(debugFmtDsl):
|
||||
echo repr result
|
||||
|
||||
macro fmt*(pattern: static string; openChar: static char, closeChar: static char): string =
|
||||
macro fmt(pattern: static string; openChar: static char, closeChar: static char, lineInfoNode: untyped): string =
|
||||
## version of `fmt` with dummy untyped param for line info
|
||||
strformatImpl(pattern, openChar, closeChar, lineInfoNode)
|
||||
|
||||
when not defined(nimHasCallsitePragma):
|
||||
{.pragma: callsite.}
|
||||
|
||||
template fmt*(pattern: static string; openChar: static char, closeChar: static char): string {.callsite.} =
|
||||
## Interpolates `pattern` using symbols in scope.
|
||||
runnableExamples:
|
||||
let x = 7
|
||||
@@ -685,13 +699,13 @@ macro fmt*(pattern: static string; openChar: static char, closeChar: static char
|
||||
assert "<x>".fmt('<', '>') == "7"
|
||||
assert "<<<x>>>".fmt('<', '>') == "<7>"
|
||||
assert "`x`".fmt('`', '`') == "7"
|
||||
strformatImpl(pattern, openChar, closeChar)
|
||||
fmt(pattern, openChar, closeChar, dummyForLineInfo)
|
||||
|
||||
template fmt*(pattern: static string): untyped =
|
||||
template fmt*(pattern: static string): untyped {.callsite.} =
|
||||
## Alias for `fmt(pattern, '{', '}')`.
|
||||
fmt(pattern, '{', '}')
|
||||
fmt(pattern, '{', '}', dummyForLineInfo)
|
||||
|
||||
macro `&`*(pattern: string{lit}): string =
|
||||
template `&`*(pattern: string{lit}): string {.callsite.} =
|
||||
## `&pattern` is the same as `pattern.fmt`.
|
||||
## For a specification of the `&` macro, see the module level documentation.
|
||||
# pending bug #18275, bug #18278, use `pattern: static string`
|
||||
@@ -701,6 +715,6 @@ macro `&`*(pattern: string{lit}): string =
|
||||
runnableExamples:
|
||||
let x = 7
|
||||
assert &"{x}\n" == "7\n" # regular string literal
|
||||
assert &"{x}\n" == "7\n".fmt # `fmt` can be used instead
|
||||
assert &"{x}\n" != fmt"7\n" # see `fmt` docs, this would use a raw string literal
|
||||
strformatImpl(pattern.strVal, '{', '}')
|
||||
assert &"{x}\n" == "{x}\n".fmt # `fmt` can be used instead
|
||||
assert &"{x}\n" != fmt"{x}\n" # see `fmt` docs, this would use a raw string literal
|
||||
fmt(pattern, '{', '}', dummyForLineInfo)
|
||||
|
||||
@@ -346,11 +346,14 @@ func cmpIgnoreStyle*(a, b: string): int {.rtl, extern: "nsuCmpIgnoreStyle".} =
|
||||
# --------- Private templates for different split separators -----------
|
||||
|
||||
func substrEq(s: string, pos: int, substr: string): bool =
|
||||
var i = 0
|
||||
# Always returns false for empty `substr`
|
||||
var length = substr.len
|
||||
while i < length and pos+i < s.len and s[pos+i] == substr[i]:
|
||||
inc i
|
||||
return i == length
|
||||
if length > 0:
|
||||
var i = 0
|
||||
while i < length and pos+i < s.len and s[pos+i] == substr[i]:
|
||||
inc i
|
||||
i == length
|
||||
else: false
|
||||
|
||||
template stringHasSep(s: string, index: int, seps: set[char]): bool =
|
||||
s[index] in seps
|
||||
@@ -492,12 +495,17 @@ iterator split*(s: string, sep: string, maxsplit: int = -1): string =
|
||||
## "is"
|
||||
## "corrupted"
|
||||
##
|
||||
## .. note:: Empty separator string results in returning an original string,
|
||||
## following the interpretation "split by no element".
|
||||
##
|
||||
## See also:
|
||||
## * `rsplit iterator<#rsplit.i,string,string,int,bool>`_
|
||||
## * `splitLines iterator<#splitLines.i,string>`_
|
||||
## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_
|
||||
## * `split func<#split,string,string,int>`_
|
||||
splitCommon(s, sep, maxsplit, sep.len)
|
||||
let sepLen = if sep.len == 0: 1 # prevents infinite loop
|
||||
else: sep.len
|
||||
splitCommon(s, sep, maxsplit, sepLen)
|
||||
|
||||
|
||||
template rsplitCommon(s, sep, maxsplit, sepLen) =
|
||||
@@ -567,6 +575,9 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace,
|
||||
##
|
||||
## Substrings are separated from the right by the set of chars `seps`
|
||||
##
|
||||
## .. note:: Empty separator set results in returning an original string,
|
||||
## following the interpretation "split by no element".
|
||||
##
|
||||
## See also:
|
||||
## * `split iterator<#split.i,string,set[char],int>`_
|
||||
## * `splitLines iterator<#splitLines.i,string>`_
|
||||
@@ -592,12 +603,17 @@ iterator rsplit*(s: string, sep: string, maxsplit: int = -1,
|
||||
##
|
||||
## Substrings are separated from the right by the string `sep`
|
||||
##
|
||||
## .. note:: Empty separator string results in returning an original string,
|
||||
## following the interpretation "split by no element".
|
||||
##
|
||||
## See also:
|
||||
## * `split iterator<#split.i,string,string,int>`_
|
||||
## * `splitLines iterator<#splitLines.i,string>`_
|
||||
## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_
|
||||
## * `rsplit func<#rsplit,string,string,int>`_
|
||||
rsplitCommon(s, sep, maxsplit, sep.len)
|
||||
let sepLen = if sep.len == 0: 1 # prevents infinite loop
|
||||
else: sep.len
|
||||
rsplitCommon(s, sep, maxsplit, sepLen)
|
||||
|
||||
iterator splitLines*(s: string, keepEol = false): string =
|
||||
## Splits the string `s` into its containing lines.
|
||||
@@ -708,6 +724,9 @@ func split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[
|
||||
## The same as the `split iterator <#split.i,string,set[char],int>`_ (see its
|
||||
## documentation), but is a func that returns a sequence of substrings.
|
||||
##
|
||||
## .. note:: Empty separator set results in returning an original string,
|
||||
## following the interpretation "split by no element".
|
||||
##
|
||||
## See also:
|
||||
## * `split iterator <#split.i,string,set[char],int>`_
|
||||
## * `rsplit func<#rsplit,string,set[char],int>`_
|
||||
@@ -716,6 +735,7 @@ func split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[
|
||||
runnableExamples:
|
||||
doAssert "a,b;c".split({',', ';'}) == @["a", "b", "c"]
|
||||
doAssert "".split({' '}) == @[""]
|
||||
doAssert "empty seps return unsplit s".split({}) == @["empty seps return unsplit s"]
|
||||
accResult(split(s, seps, maxsplit))
|
||||
|
||||
func split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl,
|
||||
@@ -725,6 +745,9 @@ func split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl,
|
||||
## Substrings are separated by the string `sep`. This is a wrapper around the
|
||||
## `split iterator <#split.i,string,string,int>`_.
|
||||
##
|
||||
## .. note:: Empty separator string results in returning an original string,
|
||||
## following the interpretation "split by no element".
|
||||
##
|
||||
## See also:
|
||||
## * `split iterator <#split.i,string,string,int>`_
|
||||
## * `rsplit func<#rsplit,string,string,int>`_
|
||||
@@ -737,8 +760,7 @@ func split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl,
|
||||
doAssert "a largely spaced sentence".split(" ") == @["a", "", "largely",
|
||||
"", "", "", "spaced", "sentence"]
|
||||
doAssert "a largely spaced sentence".split(" ", maxsplit = 1) == @["a", " largely spaced sentence"]
|
||||
doAssert(sep.len > 0)
|
||||
|
||||
doAssert "empty sep returns unsplit s".split("") == @["empty sep returns unsplit s"]
|
||||
accResult(split(s, sep, maxsplit))
|
||||
|
||||
func rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string] {.rtl,
|
||||
@@ -788,6 +810,9 @@ func rsplit*(s: string, seps: set[char] = Whitespace,
|
||||
## .. code-block:: nim
|
||||
## @["Root#Object#Method", "Index"]
|
||||
##
|
||||
## .. note:: Empty separator set results in returning an original string,
|
||||
## following the interpretation "split by no element".
|
||||
##
|
||||
## See also:
|
||||
## * `rsplit iterator <#rsplit.i,string,set[char],int>`_
|
||||
## * `split func<#split,string,set[char],int>`_
|
||||
@@ -815,6 +840,9 @@ func rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl,
|
||||
## .. code-block:: nim
|
||||
## @["Root#Object#Method", "Index"]
|
||||
##
|
||||
## .. note:: Empty separator string results in returning an original string,
|
||||
## following the interpretation "split by no element".
|
||||
##
|
||||
## See also:
|
||||
## * `rsplit iterator <#rsplit.i,string,string,int,bool>`_
|
||||
## * `split func<#split,string,string,int>`_
|
||||
@@ -829,6 +857,7 @@ func rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl,
|
||||
doAssert "".rsplit("Elon Musk") == @[""]
|
||||
doAssert "a largely spaced sentence".rsplit(" ") == @["a", "",
|
||||
"largely", "", "", "", "spaced", "sentence"]
|
||||
doAssert "empty sep returns unsplit s".rsplit("") == @["empty sep returns unsplit s"]
|
||||
accResult(rsplit(s, sep, maxsplit))
|
||||
result.reverse()
|
||||
|
||||
|
||||
@@ -111,7 +111,6 @@ proc intSetPut[A](t: var PackedSet[A], key: int): Trunk =
|
||||
t.data[h] = result
|
||||
|
||||
proc bitincl[A](s: var PackedSet[A], key: int) {.inline.} =
|
||||
var ret: Trunk
|
||||
var t = intSetPut(s, key shr TrunkShift)
|
||||
var u = key and TrunkMask
|
||||
t.bits[u shr IntShift] = t.bits[u shr IntShift] or
|
||||
|
||||
@@ -1619,7 +1619,7 @@ proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
|
||||
proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".}
|
||||
proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".}
|
||||
proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".}
|
||||
proc isNil*[T: proc](x: T): bool {.noSideEffect, magic: "IsNil".}
|
||||
proc isNil*[T: proc | iterator {.closure.}](x: T): bool {.noSideEffect, magic: "IsNil".}
|
||||
## Fast check whether `x` is nil. This is sometimes more efficient than
|
||||
## `== nil`.
|
||||
|
||||
|
||||
@@ -992,7 +992,7 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =
|
||||
proc realloc0Impl(p: pointer, oldSize, newSize: Natural): pointer =
|
||||
result = realloc(allocator, p, newSize)
|
||||
if newSize > oldSize:
|
||||
zeroMem(cast[pointer](cast[int](result) + oldSize), newSize - oldSize)
|
||||
zeroMem(cast[pointer](cast[uint](result) + uint(oldSize)), newSize - oldSize)
|
||||
|
||||
when false:
|
||||
proc countFreeMem(): int =
|
||||
|
||||
@@ -16,18 +16,21 @@ type
|
||||
d: PCellArray
|
||||
|
||||
proc contains(s: CellSeq, c: PCell): bool {.inline.} =
|
||||
for i in 0 .. s.len-1:
|
||||
if s.d[i] == c: return true
|
||||
for i in 0 ..< s.len:
|
||||
if s.d[i] == c:
|
||||
return true
|
||||
return false
|
||||
|
||||
proc resize(s: var CellSeq) =
|
||||
s.cap = s.cap * 3 div 2
|
||||
let d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
|
||||
copyMem(d, s.d, s.len * sizeof(PCell))
|
||||
dealloc(s.d)
|
||||
s.d = d
|
||||
|
||||
proc add(s: var CellSeq, c: PCell) {.inline.} =
|
||||
if s.len >= s.cap:
|
||||
s.cap = s.cap * 3 div 2
|
||||
var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
|
||||
copyMem(d, s.d, s.len * sizeof(PCell))
|
||||
dealloc(s.d)
|
||||
s.d = d
|
||||
# XXX: realloc?
|
||||
resize(s)
|
||||
s.d[s.len] = c
|
||||
inc(s.len)
|
||||
|
||||
|
||||
@@ -16,20 +16,17 @@ type
|
||||
len, cap: int
|
||||
d: CellArray[T]
|
||||
|
||||
proc add[T](s: var CellSeq[T], c: T; t: PNimTypeV2) {.inline.} =
|
||||
proc resize[T](s: var CellSeq[T]) =
|
||||
s.cap = s.cap * 3 div 2
|
||||
var newSize = s.cap * sizeof(CellTuple[T])
|
||||
when compileOption("threads"):
|
||||
s.d = cast[CellArray[T]](reallocShared(s.d, newSize))
|
||||
else:
|
||||
s.d = cast[CellArray[T]](realloc(s.d, newSize))
|
||||
|
||||
proc add[T](s: var CellSeq[T], c: T, t: PNimTypeV2) {.inline.} =
|
||||
if s.len >= s.cap:
|
||||
s.cap = s.cap * 3 div 2
|
||||
when compileOption("threads"):
|
||||
var d = cast[CellArray[T]](allocShared(uint(s.cap * sizeof(CellTuple[T]))))
|
||||
else:
|
||||
var d = cast[CellArray[T]](alloc(s.cap * sizeof(CellTuple[T])))
|
||||
copyMem(d, s.d, s.len * sizeof(CellTuple[T]))
|
||||
when compileOption("threads"):
|
||||
deallocShared(s.d)
|
||||
else:
|
||||
dealloc(s.d)
|
||||
s.d = d
|
||||
# XXX: realloc?
|
||||
s.resize()
|
||||
s.d[s.len] = (c, t)
|
||||
inc(s.len)
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ proc `==`*[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.}
|
||||
## Checks that two `ref` variables refer to the same item.
|
||||
proc `==`*[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.}
|
||||
## Checks that two `ptr` variables refer to the same item.
|
||||
proc `==`*[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.}
|
||||
proc `==`*[T: proc | iterator](x, y: T): bool {.magic: "EqProc", noSideEffect.}
|
||||
## Checks that two `proc` variables refer to the same procedure.
|
||||
|
||||
proc `<=`*[Enum: enum](x, y: Enum): bool {.magic: "LeEnum", noSideEffect.}
|
||||
|
||||
@@ -116,9 +116,6 @@ when hasAlloc and not defined(js):
|
||||
##
|
||||
## See also:
|
||||
## * `create <#create,typedesc>`_
|
||||
static:
|
||||
when sizeof(T) <= 0:
|
||||
{.fatal: "createU does not support types T where sizeof(T) == 0".}
|
||||
cast[ptr T](alloc(T.sizeof * size))
|
||||
|
||||
template alloc0*(size: Natural): pointer =
|
||||
@@ -144,9 +141,6 @@ when hasAlloc and not defined(js):
|
||||
##
|
||||
## The allocated memory belongs to its allocating thread!
|
||||
## Use `createShared <#createShared,typedesc>`_ to allocate from a shared heap.
|
||||
static:
|
||||
when sizeof(T) <= 0:
|
||||
{.fatal: "create does not support types T where sizeof(T) == 0".}
|
||||
cast[ptr T](alloc0(sizeof(T) * size))
|
||||
|
||||
template realloc*(p: pointer, newSize: Natural): pointer =
|
||||
|
||||
@@ -22,7 +22,7 @@ proc reallocImpl(p: pointer, newSize: Natural): pointer =
|
||||
proc realloc0Impl(p: pointer, oldsize, newSize: Natural): pointer =
|
||||
result = realloc(p, newSize.csize_t)
|
||||
if newSize > oldSize:
|
||||
zeroMem(cast[pointer](cast[int](result) + oldSize), newSize - oldSize)
|
||||
zeroMem(cast[pointer](cast[uint](result) + uint(oldSize)), newSize - oldSize)
|
||||
|
||||
proc deallocImpl(p: pointer) =
|
||||
c_free(p)
|
||||
@@ -88,7 +88,7 @@ type
|
||||
|
||||
proc alloc(r: var MemRegion, size: int): pointer =
|
||||
result = alloc(size)
|
||||
proc alloc0Impl(r: var MemRegion, size: int): pointer =
|
||||
proc alloc0(r: var MemRegion, size: int): pointer =
|
||||
result = alloc0Impl(size)
|
||||
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
|
||||
proc deallocOsPages(r: var MemRegion) = discard
|
||||
|
||||
@@ -88,7 +88,7 @@ proc repr*(p: pointer): string =
|
||||
result[j] = HexChars[n and 0xF]
|
||||
n = n shr 4
|
||||
|
||||
proc repr*(p: proc): string =
|
||||
proc repr*(p: proc | iterator {.closure.}): string =
|
||||
## repr of a proc as its address
|
||||
repr(cast[ptr pointer](unsafeAddr p)[])
|
||||
|
||||
|
||||
@@ -13,9 +13,11 @@
|
||||
proc cardSetImpl(s: ptr UncheckedArray[uint8], len: int): int {.inline.} =
|
||||
var i = 0
|
||||
result = 0
|
||||
var num = 0'u64
|
||||
when defined(x86) or defined(amd64):
|
||||
while i < len - 8:
|
||||
inc(result, countBits64((cast[ptr uint64](s[i].unsafeAddr))[]))
|
||||
copyMem(addr num, addr s[i], 8)
|
||||
inc(result, countBits64(num))
|
||||
inc(i, 8)
|
||||
|
||||
while i < len:
|
||||
|
||||
@@ -34,53 +34,72 @@ template frees(s) =
|
||||
else:
|
||||
dealloc(s.p)
|
||||
|
||||
template allocPayload(newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](allocShared(contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](alloc(contentSize(newLen)))
|
||||
|
||||
template allocPayload0(newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](allocShared0(contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](alloc0(contentSize(newLen)))
|
||||
|
||||
template reallocPayload(p: pointer, newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](reallocShared(p, contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](realloc(p, contentSize(newLen)))
|
||||
|
||||
template reallocPayload0(p: pointer; oldLen, newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](reallocShared0(p, contentSize(oldLen), contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](realloc0(p, contentSize(oldLen), contentSize(newLen)))
|
||||
|
||||
proc resize(old: int): int {.inline.} =
|
||||
if old <= 0: result = 4
|
||||
elif old < 65536: result = old * 2
|
||||
else: result = old * 3 div 2 # for large arrays * 3/2 is better
|
||||
|
||||
proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} =
|
||||
let newLen = s.len + addlen
|
||||
proc prepareAdd(s: var NimStringV2; addLen: int) {.compilerRtl.} =
|
||||
let newLen = s.len + addLen
|
||||
if isLiteral(s):
|
||||
let oldP = s.p
|
||||
# can't mutate a literal, so we need a fresh copy here:
|
||||
when compileOption("threads"):
|
||||
s.p = cast[ptr NimStrPayload](allocShared0(contentSize(newLen)))
|
||||
else:
|
||||
s.p = cast[ptr NimStrPayload](alloc0(contentSize(newLen)))
|
||||
s.p = allocPayload(newLen)
|
||||
s.p.cap = newLen
|
||||
if s.len > 0:
|
||||
# we are about to append, so there is no need to copy the \0 terminator:
|
||||
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], min(s.len, newLen))
|
||||
elif oldP == nil:
|
||||
# In the case of `newString(0) & ""`, since `src.len == 0`, `appendString`
|
||||
# will not set the `\0` terminator, so we set it here.
|
||||
s.p.data[0] = '\0'
|
||||
else:
|
||||
let oldCap = s.p.cap and not strlitFlag
|
||||
if newLen > oldCap:
|
||||
let newCap = max(newLen, resize(oldCap))
|
||||
when compileOption("threads"):
|
||||
s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap)))
|
||||
else:
|
||||
s.p = cast[ptr NimStrPayload](realloc0(s.p, contentSize(oldCap), contentSize(newCap)))
|
||||
s.p = reallocPayload(s.p, newCap)
|
||||
s.p.cap = newCap
|
||||
if newLen < newCap:
|
||||
zeroMem(cast[pointer](addr s.p.data[newLen+1]), newCap - newLen)
|
||||
|
||||
proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl, inline.} =
|
||||
#if (s.p == nil) or (s.len+1 > s.p.cap and not strlitFlag):
|
||||
prepareAdd(s, 1)
|
||||
s.p.data[s.len] = c
|
||||
s.p.data[s.len+1] = '\0'
|
||||
inc s.len
|
||||
s.p.data[s.len] = '\0'
|
||||
|
||||
proc toNimStr(str: cstring, len: int): NimStringV2 {.compilerproc.} =
|
||||
if len <= 0:
|
||||
result = NimStringV2(len: 0, p: nil)
|
||||
else:
|
||||
when compileOption("threads"):
|
||||
var p = cast[ptr NimStrPayload](allocShared0(contentSize(len)))
|
||||
else:
|
||||
var p = cast[ptr NimStrPayload](alloc0(contentSize(len)))
|
||||
var p = allocPayload(len)
|
||||
p.cap = len
|
||||
if len > 0:
|
||||
# we are about to append, so there is no need to copy the \0 terminator:
|
||||
copyMem(unsafeAddr p.data[0], str, len)
|
||||
copyMem(unsafeAddr p.data[0], str, len+1)
|
||||
result = NimStringV2(len: len, p: p)
|
||||
|
||||
proc cstrToNimstr(str: cstring): NimStringV2 {.compilerRtl.} =
|
||||
@@ -99,29 +118,24 @@ proc appendString(dest: var NimStringV2; src: NimStringV2) {.compilerproc, inlin
|
||||
|
||||
proc appendChar(dest: var NimStringV2; c: char) {.compilerproc, inline.} =
|
||||
dest.p.data[dest.len] = c
|
||||
dest.p.data[dest.len+1] = '\0'
|
||||
inc dest.len
|
||||
dest.p.data[dest.len] = '\0'
|
||||
|
||||
proc rawNewString(space: int): NimStringV2 {.compilerproc.} =
|
||||
# this is also 'system.newStringOfCap'.
|
||||
if space <= 0:
|
||||
result = NimStringV2(len: 0, p: nil)
|
||||
else:
|
||||
when compileOption("threads"):
|
||||
var p = cast[ptr NimStrPayload](allocShared0(contentSize(space)))
|
||||
else:
|
||||
var p = cast[ptr NimStrPayload](alloc0(contentSize(space)))
|
||||
var p = allocPayload(space)
|
||||
p.cap = space
|
||||
p.data[0] = '\0'
|
||||
result = NimStringV2(len: 0, p: p)
|
||||
|
||||
proc mnewString(len: int): NimStringV2 {.compilerproc.} =
|
||||
if len <= 0:
|
||||
result = NimStringV2(len: 0, p: nil)
|
||||
else:
|
||||
when compileOption("threads"):
|
||||
var p = cast[ptr NimStrPayload](allocShared0(contentSize(len)))
|
||||
else:
|
||||
var p = cast[ptr NimStrPayload](alloc0(contentSize(len)))
|
||||
var p = allocPayload0(len)
|
||||
p.cap = len
|
||||
result = NimStringV2(len: len, p: p)
|
||||
|
||||
@@ -129,8 +143,25 @@ proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} =
|
||||
if newLen == 0:
|
||||
discard "do not free the buffer here, pattern 's.setLen 0' is common for avoiding allocations"
|
||||
else:
|
||||
if newLen > s.len or isLiteral(s):
|
||||
prepareAdd(s, newLen - s.len)
|
||||
if isLiteral(s):
|
||||
let oldP = s.p
|
||||
s.p = allocPayload(newLen)
|
||||
s.p.cap = newLen
|
||||
if s.len > 0:
|
||||
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], min(s.len, newLen))
|
||||
if newLen > s.len:
|
||||
zeroMem(cast[pointer](addr s.p.data[s.len]), newLen - s.len + 1)
|
||||
else:
|
||||
s.p.data[newLen] = '\0'
|
||||
else:
|
||||
zeroMem(cast[pointer](addr s.p.data[0]), newLen + 1)
|
||||
elif newLen > s.len:
|
||||
let oldCap = s.p.cap and not strlitFlag
|
||||
if newLen > oldCap:
|
||||
let newCap = max(newLen, resize(oldCap))
|
||||
s.p = reallocPayload0(s.p, oldCap, newCap)
|
||||
s.p.cap = newCap
|
||||
|
||||
s.p.data[newLen] = '\0'
|
||||
s.len = newLen
|
||||
|
||||
@@ -147,10 +178,7 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
|
||||
# 'let y = newStringOfCap(); var x = y'
|
||||
# on the other hand... These get turned into moves now.
|
||||
frees(a)
|
||||
when compileOption("threads"):
|
||||
a.p = cast[ptr NimStrPayload](allocShared0(contentSize(b.len)))
|
||||
else:
|
||||
a.p = cast[ptr NimStrPayload](alloc0(contentSize(b.len)))
|
||||
a.p = allocPayload(b.len)
|
||||
a.p.cap = b.len
|
||||
a.len = b.len
|
||||
copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
|
||||
@@ -158,10 +186,7 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
|
||||
proc nimPrepareStrMutationImpl(s: var NimStringV2) =
|
||||
let oldP = s.p
|
||||
# can't mutate a literal, so we need a fresh copy here:
|
||||
when compileOption("threads"):
|
||||
s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len)))
|
||||
else:
|
||||
s.p = cast[ptr NimStrPayload](alloc0(contentSize(s.len)))
|
||||
s.p = allocPayload(s.len)
|
||||
s.p.cap = s.len
|
||||
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1)
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import algorithm
|
||||
import tables
|
||||
import std/sha1
|
||||
import times
|
||||
import procmonitor
|
||||
|
||||
## Nimsuggest is a tool that helps to give editors IDE like capabilities.
|
||||
|
||||
@@ -35,6 +36,7 @@ when defined(windows):
|
||||
else:
|
||||
import posix
|
||||
|
||||
const HighestSuggestProtocolVersion = 4
|
||||
const DummyEof = "!EOF!"
|
||||
const Usage = """
|
||||
Nimsuggest - Tool to give every editor IDE like capabilities for Nim
|
||||
@@ -47,12 +49,18 @@ Options:
|
||||
--address:HOST binds to that address, by default ""
|
||||
--stdin read commands from stdin and write results to
|
||||
stdout instead of using sockets
|
||||
--clientProcessId:PID shutdown nimsuggest in case this process dies
|
||||
--epc use emacs epc mode
|
||||
--debug enable debug output
|
||||
--log enable verbose logging to nimsuggest.log file
|
||||
--v1 use version 1 of the protocol; for backwards compatibility
|
||||
--v2 use version 2(default) of the protocol
|
||||
--v3 use version 3 of the protocol
|
||||
--v4 use version 4 of the protocol
|
||||
--info:X information
|
||||
--info:nimVer return the Nim compiler version that nimsuggest uses internally
|
||||
--info:protocolVer return the newest protocol version that is supported
|
||||
--info:capabilities return the capabilities supported by nimsuggest
|
||||
--refresh perform automatic refreshes to keep the analysis precise
|
||||
--maxresults:N limit the number of suggestions to N
|
||||
--tester implies --stdin and outputs a line
|
||||
@@ -109,6 +117,11 @@ const
|
||||
"type 'quit' to quit\n" &
|
||||
"type 'debug' to toggle debug mode on/off\n" &
|
||||
"type 'terse' to toggle terse mode on/off"
|
||||
#List of currently supported capabilities. So lang servers/ides can iterate over and check for what's enabled
|
||||
Capabilities = [
|
||||
"con", #current NimSuggest supports the `con` commmand
|
||||
"unknownFile", #current NimSuggest can handle unknown files
|
||||
]
|
||||
|
||||
proc parseQuoted(cmd: string; outp: var string; start: int): int =
|
||||
var i = start
|
||||
@@ -153,7 +166,7 @@ proc listEpc(): SexpNode =
|
||||
argspecs = sexp("file line column dirtyfile".split(" ").map(newSSymbol))
|
||||
docstring = sexp("line starts at 1, column at 0, dirtyfile is optional")
|
||||
result = newSList()
|
||||
for command in ["sug", "con", "def", "use", "dus", "chk", "mod", "globalSymbols", "recompile", "saved", "chkFile", "declaration"]:
|
||||
for command in ["sug", "con", "def", "use", "dus", "chk", "mod", "globalSymbols", "recompile", "saved", "chkFile", "declaration", "inlayHints"]:
|
||||
let
|
||||
cmd = sexp(command)
|
||||
methodDesc = newSList()
|
||||
@@ -189,7 +202,7 @@ proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int,
|
||||
graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
|
||||
if conf.suggestVersion == 3:
|
||||
if conf.suggestVersion >= 3:
|
||||
let command = fmt "cmd = {cmd} {file}:{line}:{col}"
|
||||
benchmark command:
|
||||
executeNoHooksV3(cmd, file, dirtyfile, line, col, tag, graph)
|
||||
@@ -478,6 +491,11 @@ proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) =
|
||||
of "chkfile": conf.ideCmd = ideChkFile
|
||||
of "recompile": conf.ideCmd = ideRecompile
|
||||
of "type": conf.ideCmd = ideType
|
||||
of "inlayhints":
|
||||
if conf.suggestVersion >= 4:
|
||||
conf.ideCmd = ideInlayHints
|
||||
else:
|
||||
err()
|
||||
else: err()
|
||||
var dirtyfile = ""
|
||||
var orig = ""
|
||||
@@ -542,7 +560,7 @@ proc mainThread(graph: ModuleGraph) =
|
||||
else:
|
||||
os.sleep 250
|
||||
idle += 1
|
||||
if idle == 20 and gRefresh and conf.suggestVersion != 3:
|
||||
if idle == 20 and gRefresh and conf.suggestVersion < 3:
|
||||
# we use some nimsuggest activity to enable a lazy recompile:
|
||||
conf.ideCmd = ideChk
|
||||
conf.writelnHook = proc (s: string) = discard
|
||||
@@ -572,7 +590,7 @@ proc mainCommand(graph: ModuleGraph) =
|
||||
# do not print errors, but log them
|
||||
conf.writelnHook = proc (msg: string) = discard
|
||||
|
||||
if graph.config.suggestVersion == 3:
|
||||
if graph.config.suggestVersion >= 3:
|
||||
graph.config.structuredErrorHook = proc (conf: ConfigRef; info: TLineInfo; msg: string; sev: Severity) =
|
||||
let suggest = Suggest(section: ideChk, filePath: toFullPath(conf, info),
|
||||
line: toLinenumber(info), column: toColumn(info), doc: msg, forth: $sev)
|
||||
@@ -586,6 +604,9 @@ proc mainCommand(graph: ModuleGraph) =
|
||||
open(requests)
|
||||
open(results)
|
||||
|
||||
if graph.config.clientProcessId != 0:
|
||||
hookProcMonitor(graph.config.clientProcessId)
|
||||
|
||||
case gMode
|
||||
of mstdin: createThread(inputThread, replStdin, (gPort, gAddress))
|
||||
of mtcp: createThread(inputThread, replTcp, (gPort, gAddress))
|
||||
@@ -636,6 +657,20 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) =
|
||||
of "v1": conf.suggestVersion = 1
|
||||
of "v2": conf.suggestVersion = 0
|
||||
of "v3": conf.suggestVersion = 3
|
||||
of "v4": conf.suggestVersion = 4
|
||||
of "info":
|
||||
case p.val.normalize
|
||||
of "protocolver":
|
||||
stdout.writeLine(HighestSuggestProtocolVersion)
|
||||
quit 0
|
||||
of "nimver":
|
||||
stdout.writeLine(system.NimVersion)
|
||||
quit 0
|
||||
of "capabilities":
|
||||
stdout.writeLine(Capabilities.toSeq.mapIt($it).join(" "))
|
||||
quit 0
|
||||
else:
|
||||
processSwitch(pass, p, conf)
|
||||
of "tester":
|
||||
gMode = mstdin
|
||||
gEmitEof = true
|
||||
@@ -650,6 +685,8 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) =
|
||||
conf.suggestMaxResults = parseInt(p.val)
|
||||
of "find":
|
||||
findProject = true
|
||||
of "clientprocessid":
|
||||
conf.clientProcessId = parseInt(p.val)
|
||||
else: processSwitch(pass, p, conf)
|
||||
of cmdArgument:
|
||||
let a = unixToNativePath(p.key)
|
||||
@@ -747,6 +784,18 @@ proc findSymData(graph: ModuleGraph, trackPos: TLineInfo):
|
||||
result[] = s
|
||||
break
|
||||
|
||||
func isInRange*(current, startPos, endPos: TLineInfo, tokenLen: int): bool =
|
||||
result = current.fileIndex == startPos.fileIndex and
|
||||
(current.line > startPos.line or (current.line == startPos.line and current.col>=startPos.col)) and
|
||||
(current.line < endPos.line or (current.line == endPos.line and current.col <= endPos.col))
|
||||
|
||||
proc findSymDataInRange(graph: ModuleGraph, startPos, endPos: TLineInfo):
|
||||
seq[SymInfoPair] =
|
||||
result = newSeq[SymInfoPair]()
|
||||
for s in graph.fileSymbols(startPos.fileIndex).deduplicateSymInfoPair:
|
||||
if isInRange(s.info, startPos, endPos, s.sym.name.s.len):
|
||||
result.add(s)
|
||||
|
||||
proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int):
|
||||
ref SymInfoPair =
|
||||
let
|
||||
@@ -754,6 +803,14 @@ proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int):
|
||||
trackPos = newLineInfo(fileIdx, line, col)
|
||||
result = findSymData(graph, trackPos)
|
||||
|
||||
proc findSymDataInRange(graph: ModuleGraph, file: AbsoluteFile; startLine, startCol, endLine, endCol: int):
|
||||
seq[SymInfoPair] =
|
||||
let
|
||||
fileIdx = fileInfoIdx(graph.config, file)
|
||||
startPos = newLineInfo(fileIdx, startLine, startCol)
|
||||
endPos = newLineInfo(fileIdx, endLine, endCol)
|
||||
result = findSymDataInRange(graph, startPos, endPos)
|
||||
|
||||
proc markDirtyIfNeeded(graph: ModuleGraph, file: string, originalFileIdx: FileIndex) =
|
||||
let sha = $sha1.secureHashFile(file)
|
||||
if graph.config.m.fileInfos[originalFileIdx.int32].hash != sha or graph.config.ideCmd == ideSug:
|
||||
@@ -776,6 +833,23 @@ proc suggestResult(graph: ModuleGraph, sym: PSym, info: TLineInfo,
|
||||
endLine = endLine, endCol = endCol)
|
||||
suggestResult(graph.config, suggest)
|
||||
|
||||
proc suggestInlayHintResult(graph: ModuleGraph, sym: PSym, info: TLineInfo,
|
||||
defaultSection = ideNone, endLine: uint16 = 0, endCol = 0) =
|
||||
let section = if defaultSection != ideNone:
|
||||
defaultSection
|
||||
elif sym.info.exactEquals(info):
|
||||
ideDef
|
||||
else:
|
||||
ideUse
|
||||
var suggestDef = symToSuggest(graph, sym, isLocal=false, section,
|
||||
info, 100, PrefixMatch.None, false, 0, true,
|
||||
endLine = endLine, endCol = endCol)
|
||||
suggestDef.inlayHintInfo = suggestToSuggestInlayHint(suggestDef)
|
||||
suggestDef.section = ideInlayHints
|
||||
if sym.kind == skForVar:
|
||||
suggestDef.inlayHintInfo.allowInsert = false
|
||||
suggestResult(graph.config, suggestDef)
|
||||
|
||||
const
|
||||
# kinds for ideOutline and ideGlobalSymbols
|
||||
searchableSymKinds = {skField, skEnumField, skIterator, skMethod, skFunc, skProc, skConverter, skTemplate}
|
||||
@@ -869,10 +943,6 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
var fileIndex: FileIndex
|
||||
|
||||
if not (cmd in {ideRecompile, ideGlobalSymbols}):
|
||||
if not fileInfoKnown(conf, file):
|
||||
myLog fmt "{file} is unknown, returning no results"
|
||||
return
|
||||
|
||||
fileIndex = fileInfoIdx(conf, file)
|
||||
msgs.setDirtyFile(
|
||||
conf,
|
||||
@@ -883,7 +953,7 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
graph.markDirtyIfNeeded(dirtyFile.string, fileInfoIdx(conf, file))
|
||||
|
||||
# these commands require fully compiled project
|
||||
if cmd in {ideUse, ideDus, ideGlobalSymbols, ideChk} and graph.needsCompilation():
|
||||
if cmd in {ideUse, ideDus, ideGlobalSymbols, ideChk, ideInlayHints} and graph.needsCompilation():
|
||||
graph.recompilePartially()
|
||||
# when doing incremental build for the project root we should make sure that
|
||||
# everything is unmarked as no longer beeing dirty in case there is no
|
||||
@@ -892,10 +962,10 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
graph.unmarkAllDirty()
|
||||
|
||||
# these commands require partially compiled project
|
||||
elif cmd in {ideSug, ideOutline, ideHighlight, ideDef, ideChkFile, ideType, ideDeclaration, ideExpand} and
|
||||
(graph.needsCompilation(fileIndex) or cmd == ideSug):
|
||||
elif cmd in {ideSug, ideCon, ideOutline, ideHighlight, ideDef, ideChkFile, ideType, ideDeclaration, ideExpand} and
|
||||
(graph.needsCompilation(fileIndex) or cmd in {ideSug, ideCon}):
|
||||
# for ideSug use v2 implementation
|
||||
if cmd == ideSug:
|
||||
if cmd in {ideSug, ideCon}:
|
||||
conf.m.trackPos = newLineInfo(fileIndex, line, col)
|
||||
conf.m.trackPosAttached = false
|
||||
else:
|
||||
@@ -941,6 +1011,9 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
# ideSug performs partial build of the file, thus mark it dirty for the
|
||||
# future calls.
|
||||
graph.markDirtyIfNeeded(file.string, fileIndex)
|
||||
of ideCon:
|
||||
graph.markDirty fileIndex
|
||||
graph.markClientsDirty fileIndex
|
||||
of ideOutline:
|
||||
let n = parseFile(fileIndex, graph.cache, graph.config)
|
||||
graph.iterateOutlineNodes(n, graph.fileSymbols(fileIndex).deduplicateSymInfoPair)
|
||||
@@ -1039,6 +1112,19 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
|
||||
graph.markDirty fileIndex
|
||||
graph.markClientsDirty fileIndex
|
||||
of ideInlayHints:
|
||||
myLog fmt "Executing inlayHints"
|
||||
var endLine = 0
|
||||
var endCol = -1
|
||||
var i = 0
|
||||
i += skipWhile(tag, seps, i)
|
||||
i += parseInt(tag, endLine, i)
|
||||
i += skipWhile(tag, seps, i)
|
||||
i += parseInt(tag, endCol, i)
|
||||
let s = graph.findSymDataInRange(file, line, col, endLine, endCol)
|
||||
for q in s:
|
||||
if q.sym.kind in {skLet, skVar, skForVar, skConst} and q.isDecl and not q.sym.hasUserSpecifiedType:
|
||||
graph.suggestInlayHintResult(q.sym, q.info, ideInlayHints)
|
||||
else:
|
||||
myLog fmt "Discarding {cmd}"
|
||||
|
||||
|
||||
34
nimsuggest/procmonitor.nim
Normal file
34
nimsuggest/procmonitor.nim
Normal file
@@ -0,0 +1,34 @@
|
||||
# Monitor a client process and shutdown the current process, if the client
|
||||
# process is found to be dead
|
||||
|
||||
import os
|
||||
|
||||
when defined(posix):
|
||||
import posix_utils
|
||||
import posix
|
||||
|
||||
when defined(windows):
|
||||
import winlean
|
||||
|
||||
when defined(posix):
|
||||
proc monitorClientProcessIdThreadProc(pid: int) {.thread.} =
|
||||
while true:
|
||||
sleep(1000)
|
||||
try:
|
||||
sendSignal(Pid(pid), 0)
|
||||
except:
|
||||
discard kill(Pid(getCurrentProcessId()), cint(SIGTERM))
|
||||
|
||||
when defined(windows):
|
||||
proc monitorClientProcessIdThreadProc(pid: int) {.thread.} =
|
||||
var process = openProcess(SYNCHRONIZE, 0, DWORD(pid))
|
||||
if process != 0:
|
||||
discard waitForSingleObject(process, INFINITE)
|
||||
discard closeHandle(process)
|
||||
quit(0)
|
||||
|
||||
var tid: Thread[int]
|
||||
|
||||
proc hookProcMonitor*(pid: int) =
|
||||
when defined(posix) or defined(windows):
|
||||
createThread(tid, monitorClientProcessIdThreadProc, pid)
|
||||
6
nimsuggest/tests/module_20265.nim
Normal file
6
nimsuggest/tests/module_20265.nim
Normal file
@@ -0,0 +1,6 @@
|
||||
type A* = tuple
|
||||
a: int
|
||||
b: int
|
||||
|
||||
var x*: A = (a: 2, b: 10)
|
||||
var y* = (a: 2, b: 10)
|
||||
8
nimsuggest/tests/t20265_1.nim
Normal file
8
nimsuggest/tests/t20265_1.nim
Normal file
@@ -0,0 +1,8 @@
|
||||
discard """
|
||||
$nimsuggest --tester $file
|
||||
>sug $1
|
||||
sug;;skField;;a;;int;;*module_20265.nim;;6;;10;;"";;100;;None
|
||||
sug;;skField;;b;;int;;*module_20265.nim;;6;;16;;"";;100;;None
|
||||
"""
|
||||
import module_20265
|
||||
y.#[!]#
|
||||
8
nimsuggest/tests/t20265_2.nim
Normal file
8
nimsuggest/tests/t20265_2.nim
Normal file
@@ -0,0 +1,8 @@
|
||||
discard """
|
||||
$nimsuggest --tester $file
|
||||
>sug $1
|
||||
sug;;skField;;a;;int;;*module_20265.nim;;2;;2;;"";;100;;None
|
||||
sug;;skField;;b;;int;;*module_20265.nim;;3;;2;;"";;100;;None
|
||||
"""
|
||||
import module_20265
|
||||
x.#[!]#
|
||||
@@ -1,9 +1,9 @@
|
||||
discard """
|
||||
$nimsuggest --tester $file
|
||||
>def $1
|
||||
def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"Return hello";;100
|
||||
def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].};;$file;;9;;5;;"Return hello";;100
|
||||
>def $1
|
||||
def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"Return hello";;100
|
||||
def;;skProc;;tdef1.hello;;proc (): string{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].};;$file;;9;;5;;"Return hello";;100
|
||||
"""
|
||||
|
||||
proc hello(): string =
|
||||
|
||||
@@ -15,7 +15,7 @@ discard """
|
||||
$nimsuggest --tester --maxresults:2 $file
|
||||
>sug $1
|
||||
sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;6;;5;;"";;100;;None
|
||||
sug;;skFunc;;mstrutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;*fixtures/mstrutils.nim;;9;;5;;"this is a test version of strutils.replace, it simply returns `by`";;100;;None
|
||||
sug;;skFunc;;mstrutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].};;*fixtures/mstrutils.nim;;9;;5;;"this is a test version of strutils.replace, it simply returns `by`";;100;;None
|
||||
"""
|
||||
|
||||
# TODO - determine appropriate behaviour for further suggest output and test it
|
||||
|
||||
15
nimsuggest/tests/tfatal1.nim
Normal file
15
nimsuggest/tests/tfatal1.nim
Normal file
@@ -0,0 +1,15 @@
|
||||
{.warning: "I'm a warning!".}
|
||||
{.error: "I'm an error!".}
|
||||
{.fatal: "I'm a fatal error!".}
|
||||
{.error: "I'm an error after fatal error!".}
|
||||
|
||||
#[!]#
|
||||
discard """
|
||||
$nimsuggest --tester $file
|
||||
>chk $1
|
||||
chk;;skUnknown;;;;Hint;;???;;0;;-1;;">> (toplevel): import(dirty): tests/tfatal1.nim [Processing]";;0
|
||||
chk;;skUnknown;;;;Warning;;$file;;1;;9;;"I\'m a warning! [User]";;0
|
||||
chk;;skUnknown;;;;Error;;$file;;2;;7;;"I\'m an error!";;0
|
||||
chk;;skUnknown;;;;Error;;$file;;3;;7;;"fatal error: I\'m a fatal error!";;0
|
||||
chk;;skUnknown;;;;Error;;$file;;4;;7;;"I\'m an error after fatal error!";;0
|
||||
"""
|
||||
@@ -11,7 +11,7 @@ go()
|
||||
discard """
|
||||
$nimsuggest --tester $file
|
||||
>def $path/tinclude.nim:7:14
|
||||
def;;skProc;;minclude_import.create;;proc (greeting: string, subject: string): Greet{.noSideEffect, gcsafe, locks: 0.};;*fixtures/minclude_include.nim;;3;;5;;"";;100
|
||||
def;;skProc;;minclude_import.create;;proc (greeting: string, subject: string): Greet{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].};;*fixtures/minclude_include.nim;;3;;5;;"";;100
|
||||
>def $path/fixtures/minclude_include.nim:3:71
|
||||
def;;skType;;minclude_types.Greet;;Greet;;*fixtures/minclude_types.nim;;4;;2;;"";;100
|
||||
>def $path/fixtures/minclude_include.nim:3:71
|
||||
|
||||
@@ -6,7 +6,7 @@ tmp#[!]#
|
||||
discard """
|
||||
$nimsuggest --tester $file
|
||||
>sug $1
|
||||
sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe, locks: 0.};;$file;;2;;6;;"";;100;;Prefix
|
||||
sug;;skMacro;;tsug_template.tmpb;;macro (){.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].};;$file;;2;;6;;"";;100;;Prefix
|
||||
sug;;skConverter;;tsug_template.tmpc;;converter ();;$file;;3;;10;;"";;100;;Prefix
|
||||
sug;;skTemplate;;tsug_template.tmpa;;template ();;$file;;1;;9;;"";;100;;Prefix
|
||||
"""
|
||||
|
||||
@@ -14,9 +14,9 @@ proc #[!]#someProc*() =
|
||||
discard """
|
||||
$nimsuggest --tester $file
|
||||
>use $1
|
||||
def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"";;100
|
||||
use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;12;;0;;"";;100
|
||||
def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].};;$file;;9;;5;;"";;100
|
||||
use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].};;$file;;12;;0;;"";;100
|
||||
>use $2
|
||||
def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;9;;5;;"";;100
|
||||
use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0.};;$file;;12;;0;;"";;100
|
||||
def;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].};;$file;;9;;5;;"";;100
|
||||
use;;skProc;;tuse.someProc;;proc (){.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].};;$file;;12;;0;;"";;100
|
||||
"""
|
||||
|
||||
15
nimsuggest/tests/tuse_enum.nim
Normal file
15
nimsuggest/tests/tuse_enum.nim
Normal file
@@ -0,0 +1,15 @@
|
||||
discard """
|
||||
$nimsuggest --tester $file
|
||||
>use $1
|
||||
def;;skEnumField;;tuse_enum.Colour.Red;;Colour;;$file;;10;;4;;"";;100
|
||||
use;;skEnumField;;tuse_enum.Colour.Red;;Colour;;$file;;14;;8;;"";;100
|
||||
"""
|
||||
|
||||
type
|
||||
Colour = enum
|
||||
Red
|
||||
Green
|
||||
Blue
|
||||
|
||||
discard #[!]#Red
|
||||
|
||||
@@ -19,7 +19,7 @@ def skField tv3.Foo.bar string $file 5 4 "" 100
|
||||
>sug $1
|
||||
sug skField bar string $file 5 4 "" 100 Prefix
|
||||
>globalSymbols test
|
||||
def skProc tv3.test proc (f: Foo){.gcsafe, locks: 0.} $file 7 5 "" 100
|
||||
def skProc tv3.test proc (f: Foo){.gcsafe, locks: 0, raises: <inferred> [].} $file 7 5 "" 100
|
||||
>globalSymbols Foo
|
||||
def skType tv3.Foo Foo $file 4 2 "" 100
|
||||
>def $2
|
||||
|
||||
13
nimsuggest/tests/tv3_con.nim
Normal file
13
nimsuggest/tests/tv3_con.nim
Normal file
@@ -0,0 +1,13 @@
|
||||
# tests v3
|
||||
|
||||
proc test(a: string, b:string) = discard
|
||||
proc test(a: int) = discard
|
||||
|
||||
test(#[!]#
|
||||
|
||||
discard """
|
||||
$nimsuggest --v3 --tester $file
|
||||
>con $1
|
||||
con;;skProc;;tv3_con.test;;proc (a: string, b: string);;$file;;3;;5;;"";;100
|
||||
con;;skProc;;tv3_con.test;;proc (a: int);;$file;;4;;5;;"";;100
|
||||
"""
|
||||
@@ -7,17 +7,17 @@ let a = de#[!]#mo()
|
||||
discard """
|
||||
$nimsuggest --v3 --tester $file
|
||||
>use $1
|
||||
use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 1 5 "" 100
|
||||
def skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 3 5 "" 100
|
||||
use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 5 8 "" 100
|
||||
use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 1 5 "" 100
|
||||
def skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 3 5 "" 100
|
||||
use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 5 8 "" 100
|
||||
>use $2
|
||||
use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 1 5 "" 100
|
||||
def skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 3 5 "" 100
|
||||
use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 5 8 "" 100
|
||||
use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 1 5 "" 100
|
||||
def skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 3 5 "" 100
|
||||
use skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 5 8 "" 100
|
||||
>declaration $1
|
||||
declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 3 5 "" 100
|
||||
declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 3 5 "" 100
|
||||
>declaration $2
|
||||
declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 1 5 "" 100
|
||||
declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 1 5 "" 100
|
||||
>declaration $3
|
||||
declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 1 5 "" 100
|
||||
declaration skProc tv3_forward_definition.demo proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 1 5 "" 100
|
||||
"""
|
||||
|
||||
@@ -7,8 +7,8 @@ proc BBtokenA(): int = 5
|
||||
discard """
|
||||
$nimsuggest --v3 --tester $file
|
||||
>globalSymbols token
|
||||
def skProc tv3_globalSymbols.token proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 4 5 "" 100
|
||||
def skProc tv3_globalSymbols.tokenA proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 3 5 "" 100
|
||||
def skProc tv3_globalSymbols.Btoken proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 2 5 "" 100
|
||||
def skProc tv3_globalSymbols.BBtokenA proc (): int{.noSideEffect, gcsafe, locks: 0.} $file 5 5 "" 100
|
||||
def skProc tv3_globalSymbols.token proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 4 5 "" 100
|
||||
def skProc tv3_globalSymbols.tokenA proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 3 5 "" 100
|
||||
def skProc tv3_globalSymbols.Btoken proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 2 5 "" 100
|
||||
def skProc tv3_globalSymbols.BBtokenA proc (): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 5 5 "" 100
|
||||
"""
|
||||
|
||||
@@ -33,13 +33,13 @@ outline skType tv3_outline.FooEnum FooEnum $file 6 2 "" 100 6 31
|
||||
outline skEnumField tv3_outline.FooEnum.value1 FooEnum $file 6 17 "" 100 6 23
|
||||
outline skEnumField tv3_outline.FooEnum.value2 FooEnum $file 6 25 "" 100 6 31
|
||||
outline skType tv3_outline.FooPrivate FooPrivate $file 7 2 "" 100 8 22
|
||||
outline skMacro tv3_outline.m macro (arg: untyped): untyped{.noSideEffect, gcsafe, locks: 0.} $file 10 6 "" 100 10 40
|
||||
outline skMacro tv3_outline.m macro (arg: untyped): untyped{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 10 6 "" 100 10 40
|
||||
outline skTemplate tv3_outline.t template (arg: untyped): untyped $file 11 9 "" 100 11 43
|
||||
outline skProc tv3_outline.p proc (){.noSideEffect, gcsafe, locks: 0.} $file 12 5 "" 100 12 24
|
||||
outline skConverter tv3_outline.c converter (s: string): int{.noSideEffect, gcsafe, locks: 0.} $file 14 10 "" 100 14 37
|
||||
outline skFunc tv3_outline.f proc (){.noSideEffect, gcsafe, locks: 0.} $file 16 5 "" 100 16 24
|
||||
outline skProc tv3_outline.p proc (){.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 12 5 "" 100 12 24
|
||||
outline skConverter tv3_outline.c converter (s: string): int{.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 14 10 "" 100 14 37
|
||||
outline skFunc tv3_outline.f proc (){.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 16 5 "" 100 16 24
|
||||
outline skConst tv3_outline.con int literal(2) $file 20 6 "" 100 20 13
|
||||
outline skProc tv3_outline.outer proc (){.noSideEffect, gcsafe, locks: 0.} $file 22 5 "" 100 23 24
|
||||
outline skProc tv3_outline.outer.inner proc (){.noSideEffect, gcsafe, locks: 0.} $file 23 7 "" 100 23 24
|
||||
outline skProc tv3_outline.procWithLocal proc (){.noSideEffect, gcsafe, locks: 0.} $file 25 5 "" 100 26 16
|
||||
outline skProc tv3_outline.outer proc (){.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 22 5 "" 100 23 24
|
||||
outline skProc tv3_outline.outer.inner proc (){.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 23 7 "" 100 23 24
|
||||
outline skProc tv3_outline.procWithLocal proc (){.noSideEffect, gcsafe, locks: 0, raises: <inferred> [].} $file 25 5 "" 100 26 16
|
||||
"""
|
||||
|
||||
@@ -45,7 +45,7 @@ $nimsuggest --tester --maxresults:5 $file
|
||||
>sug $1
|
||||
sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;None
|
||||
sug;;skField;;name;;string;;$file;;5;;6;;"";;100;;None
|
||||
sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;None
|
||||
sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string;;$file;;7;;9;;"";;100;;None
|
||||
sug;;skMethod;;twithin_macro.age_human_yrs;;proc (self: Animal): int{.raises: <inferred> [].};;$file;;8;;9;;"";;100;;None
|
||||
sug;;skMethod;;twithin_macro.vocalize;;proc (self: Animal): string{.raises: <inferred> [].};;$file;;7;;9;;"";;100;;None
|
||||
sug;;skMethod;;twithin_macro.vocalize;;proc (self: Rabbit): string;;$file;;23;;9;;"";;100;;None
|
||||
"""
|
||||
|
||||
@@ -44,5 +44,5 @@ discard """
|
||||
$nimsuggest --tester $file
|
||||
>sug $1
|
||||
sug;;skField;;age;;int;;$file;;6;;6;;"";;100;;Prefix
|
||||
sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int;;$file;;8;;9;;"";;100;;Prefix
|
||||
sug;;skMethod;;twithin_macro_prefix.age_human_yrs;;proc (self: Animal): int{.raises: <inferred> [].};;$file;;8;;9;;"";;100;;Prefix
|
||||
"""
|
||||
|
||||
@@ -50,7 +50,7 @@ pkg "c2nim", "nim c testsuite/tester.nim"
|
||||
pkg "cascade"
|
||||
pkg "cello"
|
||||
pkg "chroma"
|
||||
pkg "chronicles", "nim c -o:chr -r chronicles.nim", url = "https://github.com/nim-lang/nim-chronicles"
|
||||
pkg "chronicles", "nim c -o:chr -r chronicles.nim"
|
||||
pkg "chronos", "nim c -r -d:release tests/testall"
|
||||
pkg "cligen", "nim c --path:. -r cligen.nim"
|
||||
pkg "combparser", "nimble test --gc:orc"
|
||||
@@ -112,7 +112,6 @@ pkg "nimquery"
|
||||
pkg "nimsl"
|
||||
pkg "nimsvg"
|
||||
pkg "nimterop", "nimble minitest"
|
||||
pkg "nimwc", "nim c nimwc.nim"
|
||||
pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true
|
||||
pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter"
|
||||
# pkg "norm", "testament r tests/sqlite/trows.nim"
|
||||
@@ -128,7 +127,7 @@ pkg "pnm"
|
||||
pkg "polypbren"
|
||||
pkg "prologue", "nimble tcompile"
|
||||
pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim"
|
||||
pkg "pylib"
|
||||
# pkg "pylib"
|
||||
pkg "rbtree"
|
||||
pkg "react", "nimble example"
|
||||
pkg "regex", "nim c src/regex"
|
||||
@@ -140,7 +139,7 @@ pkg "sdl2_nim", "nim c -r sdl2/sdl.nim"
|
||||
pkg "sigv4", "nim c --gc:arc -r sigv4.nim", "https://github.com/disruptek/sigv4"
|
||||
pkg "sim"
|
||||
pkg "snip", "nimble test", "https://github.com/genotrance/snip"
|
||||
pkg "stint", "nim r stint.nim"
|
||||
pkg "stint", "nim c stint.nim"
|
||||
pkg "strslice"
|
||||
pkg "strunicode", "nim c -r src/strunicode.nim"
|
||||
pkg "supersnappy"
|
||||
@@ -162,6 +161,6 @@ pkg "websocket", "nim c websocket.nim"
|
||||
pkg "winim", "nim c winim.nim"
|
||||
pkg "with"
|
||||
pkg "ws", allowFailure = true
|
||||
pkg "yaml", "nim c -r test/tserialization.nim"
|
||||
# pkg "yaml", "nim c -r test/tserialization.nim"
|
||||
pkg "zero_functional", "nim c -r -d:nimNoLentIterators test.nim"
|
||||
pkg "zippy"
|
||||
|
||||
@@ -51,3 +51,19 @@ type Bug[T] = object
|
||||
|
||||
var bug: Bug[int]
|
||||
doAssert sizeof(bug) == 128, "Oops my size is " & $sizeof(bug) # 16
|
||||
|
||||
|
||||
block: # bug #22419
|
||||
type
|
||||
ValidatorPubKey = object
|
||||
blob: array[96, byte]
|
||||
|
||||
proc f(): auto =
|
||||
return iterator() =
|
||||
var pad: int8 = 0
|
||||
var y {.align: 16.}: ValidatorPubKey
|
||||
let value = cast[uint64](addr y)
|
||||
doAssert value mod 16 == 0
|
||||
|
||||
f()()
|
||||
|
||||
|
||||
55
tests/arc/t22237.nim
Normal file
55
tests/arc/t22237.nim
Normal file
@@ -0,0 +1,55 @@
|
||||
discard """
|
||||
matrix: "--mm:arc; --mm:orc"
|
||||
"""
|
||||
|
||||
import std/macros
|
||||
import std/streams
|
||||
|
||||
# bug #22237
|
||||
|
||||
proc iterlines_closure2(f: File | Stream): iterator (): string =
|
||||
result = iterator(): string =
|
||||
for line in f.lines:
|
||||
if line.len == 0:
|
||||
break
|
||||
yield line
|
||||
|
||||
proc test() =
|
||||
let f = newStringStream("""
|
||||
1
|
||||
2
|
||||
|
||||
3
|
||||
4
|
||||
|
||||
5
|
||||
6
|
||||
7
|
||||
|
||||
8
|
||||
""")
|
||||
while not f.atEnd():
|
||||
let iterator_inst = iterlines_closure2(f)
|
||||
for item in iterator_inst(): # Fails with "SIGSEGV: Illegal storage access. (Attempt to read from nil?)"
|
||||
discard
|
||||
|
||||
test()
|
||||
|
||||
# bug #21160
|
||||
import sequtils
|
||||
|
||||
iterator allMoves(fls: seq[int]): seq[int] =
|
||||
yield fls
|
||||
|
||||
proc neighbors(flrs: seq[int]): iterator: seq[int] =
|
||||
return iterator(): seq[int] =
|
||||
for flrs2 in allMoves(flrs):
|
||||
yield flrs2
|
||||
for flrs3 in allMoves(flrs2):
|
||||
yield flrs3
|
||||
|
||||
let f = @[1]
|
||||
for _ in neighbors(f):
|
||||
discard
|
||||
for _ in neighbors(f):
|
||||
discard
|
||||
@@ -45,3 +45,33 @@ proc main() = # todo bug with templates
|
||||
doAssert b() == @[]
|
||||
static: main()
|
||||
main()
|
||||
|
||||
block: # bug #21974
|
||||
type Test[T] = ref object
|
||||
values : seq[T]
|
||||
counter: int
|
||||
|
||||
proc newTest[T](): Test[T] =
|
||||
result = new(Test[T])
|
||||
result.values = newSeq[T](16)
|
||||
result.counter = 0
|
||||
|
||||
proc push[T](self: Test[T], value: T) =
|
||||
self.counter += 1
|
||||
if self.counter >= self.values.len:
|
||||
self.values.setLen(self.values.len * 2)
|
||||
self.values[self.counter - 1] = value
|
||||
|
||||
proc pop[T](self: Test[T]): T =
|
||||
result = self.values[0]
|
||||
self.values[0] = self.values[self.counter - 1] # <--- This line
|
||||
self.counter -= 1
|
||||
|
||||
|
||||
type X = tuple
|
||||
priority: int
|
||||
value : string
|
||||
|
||||
var a = newTest[X]()
|
||||
a.push((1, "One"))
|
||||
doAssert a.pop.value == "One"
|
||||
|
||||
@@ -76,7 +76,7 @@ var c = Control(x: 7)
|
||||
|
||||
run(c)
|
||||
|
||||
proc sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} =
|
||||
proc sysFatal(exceptn: typedesc, message: string) {.inline.} =
|
||||
var buf = newStringOfCap(200)
|
||||
add(buf, "##")
|
||||
add(buf, message)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
discard """
|
||||
cmd: "nim $target --hints:on --define:ssl $options $file"
|
||||
disabled: osx
|
||||
"""
|
||||
|
||||
import asyncdispatch, asyncnet, net, strutils
|
||||
|
||||
22
tests/ccgbugs/t15428.nim
Normal file
22
tests/ccgbugs/t15428.nim
Normal file
@@ -0,0 +1,22 @@
|
||||
discard """
|
||||
cmd: "nim $target --mm:refc $file"
|
||||
output: '''5
|
||||
5
|
||||
[1, 2, 3, 4, 5]
|
||||
(data: [1, 2, 3, 4, 5])
|
||||
'''
|
||||
"""
|
||||
|
||||
proc take[T](f: openArray[T]) =
|
||||
echo f.len
|
||||
let f = @[0,1,2,3,4]
|
||||
take(f.toOpenArray(0,4))
|
||||
|
||||
{.experimental: "views".}
|
||||
type
|
||||
Foo = object
|
||||
data: openArray[int]
|
||||
let f2 = Foo(data: [1,2,3,4,5])
|
||||
echo f2.data.len
|
||||
echo f2.data
|
||||
echo f2
|
||||
19
tests/ccgbugs/t22462.nim
Normal file
19
tests/ccgbugs/t22462.nim
Normal file
@@ -0,0 +1,19 @@
|
||||
discard """
|
||||
action: "run"
|
||||
output: '''
|
||||
1
|
||||
1
|
||||
1
|
||||
'''
|
||||
targets: "c cpp"
|
||||
"""
|
||||
|
||||
type Object = object
|
||||
someComplexType: seq[int]
|
||||
index: Natural
|
||||
|
||||
func newObject(): Object = result.index.inc
|
||||
|
||||
for i in 1..3:
|
||||
let o = newObject()
|
||||
echo o.index
|
||||
@@ -122,3 +122,13 @@ proc bug19613 =
|
||||
doAssert x.bid.root.data[0] == 42
|
||||
|
||||
bug19613()
|
||||
|
||||
proc foo = # bug #23280
|
||||
let foo = @[1,2,3,4,5,6]
|
||||
doAssert toOpenArray(foo, 0, 5).len == 6
|
||||
doAssert toOpenArray(foo, 0, 5).len mod 6 == 0 # this should output 0
|
||||
doAssert toOpenArray(foo, 0, 5).max mod 6 == 0
|
||||
let L = toOpenArray(foo, 0, 5).len
|
||||
doAssert L mod 6 == 0
|
||||
|
||||
foo()
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
discard """
|
||||
targets: "c cpp"
|
||||
matrix: "--gc:refc; --gc:arc"
|
||||
"""
|
||||
|
||||
# bug #1833
|
||||
iterator myitems*[T](a: var seq[T]): var T {.inline.} =
|
||||
## iterates over each item of `a` so that you can modify the yielded value.
|
||||
@@ -18,3 +23,13 @@ var ys = @[(1,"a"),(2,"b"),(3,"c")]
|
||||
for y in myitems(ys):
|
||||
inc y[0]
|
||||
|
||||
# bug #16331
|
||||
type T1 = tuple[a, b: int]
|
||||
|
||||
proc p(b: bool): string =
|
||||
var x: T1 = (10, 20)
|
||||
x = if b: (x.b, x.a) else: (-x.b, -x.a)
|
||||
$x
|
||||
|
||||
assert p(false) == "(a: -20, b: -10)"
|
||||
assert p(true) == "(a: 20, b: 10)"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user