mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 11:23:40 +00:00
Compare commits
1 Commits
fix_15097
...
pr_distinc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64a40b9579 |
76
.github/workflows/ci_gcc14.yml
vendored
Normal file
76
.github/workflows/ci_gcc14.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
name: GCC 14
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- 'devel'
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04]
|
||||
cpu: [amd64]
|
||||
name: '${{ matrix.os }}'
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60 # refs bug #18178
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
run: |
|
||||
sudo apt update -qq
|
||||
sudo apt remove needrestart
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
sudo apt install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
|
||||
valgrind libc6-dbg libblas-dev xorg-dev
|
||||
- name: 'Install dependencies (Linux amd64 gcc 14)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
run: |
|
||||
sudo add-apt-repository universe
|
||||
sudo apt update -qq
|
||||
sudo apt install -y gcc-14 g++-14 libpcre3 liblapack-dev
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 60 --slave /usr/bin/g++ g++ /usr/bin/g++-14
|
||||
- name: 'Install dependencies (macOS)'
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install boehmgc make sfml gtk+3
|
||||
- name: 'Install dependencies (Windows)'
|
||||
if: runner.os == 'Windows'
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
. ci/funs.sh
|
||||
nimInternalInstallDepsWindows
|
||||
echo_run echo "${{ github.workspace }}/dist/mingw64/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'Add build binaries to PATH'
|
||||
shell: bash
|
||||
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: 'NIM_TESTAMENT_DISABLE_SSL'
|
||||
shell: bash
|
||||
run: echo "NIM_TESTAMENT_DISABLE_SSL=1" >> $GITHUB_ENV
|
||||
|
||||
- name: 'System information'
|
||||
shell: bash
|
||||
run: . ci/funs.sh && nimCiSystemInfo
|
||||
|
||||
- name: 'Build csourcesAny'
|
||||
shell: bash
|
||||
run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
|
||||
|
||||
- name: 'koch, Run CI'
|
||||
shell: bash
|
||||
run: . ci/funs.sh && nimInternalBuildKochAndRunCI
|
||||
1
.github/workflows/ci_packages.yml
vendored
1
.github/workflows/ci_packages.yml
vendored
@@ -4,7 +4,6 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- 'devel'
|
||||
- 'version-2-2'
|
||||
- 'version-2-0'
|
||||
- 'version-1-6'
|
||||
- 'version-1-2'
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
Linux_amd64:
|
||||
vmImage: 'ubuntu-24.04'
|
||||
vmImage: 'ubuntu-20.04'
|
||||
CPU: amd64
|
||||
# regularly breaks, refs bug #17325
|
||||
# Linux_i386:
|
||||
@@ -80,12 +80,10 @@ jobs:
|
||||
- bash: |
|
||||
set -e
|
||||
. ci/funs.sh
|
||||
echo_run sudo add-apt-repository universe
|
||||
echo_run sudo apt-get update -qq
|
||||
echo_run sudo apt-fast update -qq
|
||||
DEBIAN_FRONTEND='noninteractive' \
|
||||
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
|
||||
echo_run sudo apt-fast install --no-install-recommends -yq \
|
||||
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
|
||||
displayName: 'Install dependencies (amd64 Linux)'
|
||||
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64'))
|
||||
|
||||
@@ -102,16 +100,15 @@ jobs:
|
||||
Pin-Priority: 1001
|
||||
EOF
|
||||
|
||||
# echo_run sudo apt-get update -qq
|
||||
echo_run sudo apt-get update -qq || echo "failed, see bug #17343"
|
||||
# echo_run sudo apt-fast update -qq
|
||||
echo_run sudo apt-fast 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-get install --no-install-recommends --allow-downgrades -yq \
|
||||
echo_run sudo apt-fast install --no-install-recommends --allow-downgrades -yq \
|
||||
g++-multilib gcc-multilib libcurl4-openssl-dev:i386 libgc-dev:i386 \
|
||||
libsdl1.2-dev:i386 libsfml-dev:i386 libglib2.0-dev:i386 libffi-dev:i386
|
||||
|
||||
|
||||
cat << EOF > bin/gcc
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
34
changelog.md
34
changelog.md
@@ -24,40 +24,6 @@ rounding guarantees (via the
|
||||
|
||||
## Language changes
|
||||
|
||||
- An experimental option `--experimental:typeBoundOps` has been added that
|
||||
implements the RFC https://github.com/nim-lang/RFCs/issues/380.
|
||||
This makes the behavior of interfaces like `hash`, `$`, `==` etc. more
|
||||
reliable for nominal types across indirect/restricted imports.
|
||||
|
||||
```nim
|
||||
# objs.nim
|
||||
import std/hashes
|
||||
|
||||
type
|
||||
Obj* = object
|
||||
x*, y*: int
|
||||
z*: string # to be ignored for equality
|
||||
|
||||
proc `==`*(a, b: Obj): bool =
|
||||
a.x == b.x and a.y == b.y
|
||||
|
||||
proc hash*(a: Obj): Hash =
|
||||
$!(hash(a.x) &! hash(a.y))
|
||||
```
|
||||
|
||||
```nim
|
||||
# main.nim
|
||||
{.experimental: "typeBoundOps".}
|
||||
from objs import Obj # objs.hash, objs.`==` not imported
|
||||
import std/tables
|
||||
|
||||
var t: Table[Obj, int]
|
||||
t[Obj(x: 3, y: 4, z: "debug")] = 34
|
||||
echo t[Obj(x: 3, y: 4, z: "ignored")] # 34
|
||||
```
|
||||
|
||||
See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#typeminusbound-overloads)
|
||||
for more information.
|
||||
|
||||
## Compiler changes
|
||||
|
||||
|
||||
@@ -1645,7 +1645,7 @@ proc propagateToOwner*(owner, elem: PType; propagateHasAsgn = true) =
|
||||
if mask != {} and propagateHasAsgn:
|
||||
let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
if o2.kind in {tyTuple, tyObject, tyArray,
|
||||
tySequence, tyString, tySet, tyDistinct}:
|
||||
tySequence, tySet, tyDistinct}:
|
||||
o2.flags.incl mask
|
||||
owner.flags.incl mask
|
||||
|
||||
@@ -1902,7 +1902,7 @@ proc skipGenericOwner*(s: PSym): PSym =
|
||||
|
||||
proc originatingModule*(s: PSym): PSym =
|
||||
result = s
|
||||
while result != nil and result.kind != skModule: result = result.owner
|
||||
while result.kind != skModule: result = result.owner
|
||||
|
||||
proc isRoutine*(s: PSym): bool {.inline.} =
|
||||
result = s.kind in skProcKinds
|
||||
|
||||
@@ -1,88 +1,6 @@
|
||||
import ropes, int128
|
||||
|
||||
type
|
||||
Snippet* = string
|
||||
Builder* = object
|
||||
buf*: string
|
||||
Snippet = string
|
||||
Builder = string
|
||||
|
||||
template newBuilder*(s: string): Builder =
|
||||
Builder(buf: s)
|
||||
|
||||
proc extract*(builder: Builder): Snippet =
|
||||
builder.buf
|
||||
|
||||
proc add*(builder: var Builder, s: string) =
|
||||
builder.buf.add(s)
|
||||
|
||||
proc add*(builder: var Builder, s: char) =
|
||||
builder.buf.add(s)
|
||||
|
||||
proc addIntValue*(builder: var Builder, val: int) =
|
||||
builder.buf.addInt(val)
|
||||
|
||||
proc addIntValue*(builder: var Builder, val: int64) =
|
||||
builder.buf.addInt(val)
|
||||
|
||||
proc addIntValue*(builder: var Builder, val: uint64) =
|
||||
builder.buf.addInt(val)
|
||||
|
||||
proc addIntValue*(builder: var Builder, val: Int128) =
|
||||
builder.buf.addInt128(val)
|
||||
|
||||
template cIntValue*(val: int): Snippet = $val
|
||||
template cIntValue*(val: int64): Snippet = $val
|
||||
template cIntValue*(val: uint64): Snippet = $val
|
||||
template cIntValue*(val: Int128): Snippet = $val
|
||||
|
||||
import std/formatfloat
|
||||
|
||||
proc addFloatValue*(builder: var Builder, val: float) =
|
||||
builder.buf.addFloat(val)
|
||||
|
||||
template cFloatValue*(val: float): Snippet = $val
|
||||
|
||||
proc addInt64Literal*(result: var Builder; i: BiggestInt) =
|
||||
if i > low(int64):
|
||||
result.add "IL64($1)" % [rope(i)]
|
||||
else:
|
||||
result.add "(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc addUint64Literal*(result: var Builder; i: uint64) =
|
||||
result.add rope($i & "ULL")
|
||||
|
||||
proc addIntLiteral*(result: var Builder; i: BiggestInt) =
|
||||
if i > low(int32) and i <= high(int32):
|
||||
result.addIntValue(i)
|
||||
elif i == low(int32):
|
||||
# Nim has the same bug for the same reasons :-)
|
||||
result.add "(-2147483647 -1)"
|
||||
elif i > low(int64):
|
||||
result.add "IL64($1)" % [rope(i)]
|
||||
else:
|
||||
result.add "(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc addIntLiteral*(result: var Builder; i: Int128) =
|
||||
addIntLiteral(result, toInt64(i))
|
||||
|
||||
proc cInt64Literal*(i: BiggestInt): Snippet =
|
||||
if i > low(int64):
|
||||
result = "IL64($1)" % [rope(i)]
|
||||
else:
|
||||
result = "(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc cUint64Literal*(i: uint64): Snippet =
|
||||
result = $i & "ULL"
|
||||
|
||||
proc cIntLiteral*(i: BiggestInt): Snippet =
|
||||
if i > low(int32) and i <= high(int32):
|
||||
result = rope(i)
|
||||
elif i == low(int32):
|
||||
# Nim has the same bug for the same reasons :-)
|
||||
result = "(-2147483647 -1)"
|
||||
elif i > low(int64):
|
||||
result = "IL64($1)" % [rope(i)]
|
||||
else:
|
||||
result = "(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc cIntLiteral*(i: Int128): Snippet =
|
||||
result = cIntLiteral(toInt64(i))
|
||||
template newBuilder(s: string): Builder =
|
||||
s
|
||||
|
||||
@@ -42,18 +42,6 @@ template addVarWithType(builder: var Builder, kind: VarKind = Local, name: strin
|
||||
builder.add(name)
|
||||
builder.add(";\n")
|
||||
|
||||
template addVarWithInitializer(builder: var Builder, kind: VarKind = Local, name: string,
|
||||
typ: Snippet, initializerBody: typed) =
|
||||
## adds a variable declaration to the builder, with
|
||||
## `initializerBody` building the initializer. initializer must be provided
|
||||
builder.addVarHeader(kind)
|
||||
builder.add(typ)
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.add(" = ")
|
||||
initializerBody
|
||||
builder.add(";\n")
|
||||
|
||||
template addVarWithTypeAndInitializer(builder: var Builder, kind: VarKind = Local, name: string,
|
||||
typeBody, initializerBody: typed) =
|
||||
## adds a variable declaration to the builder, with `typeBody` building the type, and
|
||||
@@ -73,7 +61,7 @@ proc addArrayVar(builder: var Builder, kind: VarKind = Local, name: string, elem
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.add("[")
|
||||
builder.addIntValue(len)
|
||||
builder.addInt(len)
|
||||
builder.add("]")
|
||||
if initializer.len != 0:
|
||||
builder.add(" = ")
|
||||
@@ -87,7 +75,7 @@ template addArrayVarWithInitializer(builder: var Builder, kind: VarKind = Local,
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.add("[")
|
||||
builder.addIntValue(len)
|
||||
builder.addInt(len)
|
||||
builder.add("] = ")
|
||||
body
|
||||
builder.add(";\n")
|
||||
@@ -101,18 +89,7 @@ template addTypedef(builder: var Builder, name: string, typeBody: typed) =
|
||||
builder.add(name)
|
||||
builder.add(";\n")
|
||||
|
||||
proc addProcTypedef(builder: var Builder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
|
||||
builder.add("typedef ")
|
||||
builder.add(CallingConvToStr[callConv])
|
||||
builder.add("_PTR(")
|
||||
builder.add(rettype)
|
||||
builder.add(", ")
|
||||
builder.add(name)
|
||||
builder.add(")")
|
||||
builder.add(params)
|
||||
builder.add(";\n")
|
||||
|
||||
template addArrayTypedef(builder: var Builder, name: string, len: BiggestInt, typeBody: typed) =
|
||||
template addArrayTypedef(builder: var Builder, name: string, len: int, typeBody: typed) =
|
||||
## adds an array typedef declaration to the builder with name `name`,
|
||||
## length `len`, and element type as built in `typeBody`
|
||||
builder.add("typedef ")
|
||||
@@ -120,7 +97,7 @@ template addArrayTypedef(builder: var Builder, name: string, len: BiggestInt, ty
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
builder.add("[")
|
||||
builder.addIntValue(len)
|
||||
builder.addInt(len)
|
||||
builder.add("];\n")
|
||||
|
||||
type
|
||||
@@ -196,7 +173,7 @@ proc addArrayField(obj: var Builder; name, elementType: Snippet; len: int; initi
|
||||
obj.add(" ")
|
||||
obj.add(name)
|
||||
obj.add("[")
|
||||
obj.addIntValue(len)
|
||||
obj.addInt(len)
|
||||
obj.add("]")
|
||||
if initializer.len != 0:
|
||||
obj.add(initializer)
|
||||
@@ -207,7 +184,7 @@ proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bo
|
||||
obj.add('\t')
|
||||
if field.alignment > 0:
|
||||
obj.add("NIM_ALIGN(")
|
||||
obj.addIntValue(field.alignment)
|
||||
obj.addInt(field.alignment)
|
||||
obj.add(") ")
|
||||
obj.add(typ)
|
||||
if sfNoalias in field.flags:
|
||||
@@ -218,21 +195,11 @@ proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bo
|
||||
obj.add("[SEQ_DECL_SIZE]")
|
||||
if field.bitsize != 0:
|
||||
obj.add(":")
|
||||
obj.addIntValue(field.bitsize)
|
||||
obj.addInt(field.bitsize)
|
||||
if initializer.len != 0:
|
||||
obj.add(initializer)
|
||||
obj.add(";\n")
|
||||
|
||||
proc addProcField(obj: var Builder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
|
||||
obj.add(CallingConvToStr[callConv])
|
||||
obj.add("_PTR(")
|
||||
obj.add(rettype)
|
||||
obj.add(", ")
|
||||
obj.add(name)
|
||||
obj.add(")")
|
||||
obj.add(params)
|
||||
obj.add(";\n")
|
||||
|
||||
type
|
||||
BaseClassKind = enum
|
||||
## denotes how and whether or not the base class/RTTI should be stored
|
||||
@@ -264,12 +231,12 @@ proc startSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Sni
|
||||
obj.add(baseType)
|
||||
obj.add(" ")
|
||||
obj.add("{\n")
|
||||
result.preFieldsLen = obj.buf.len
|
||||
result.preFieldsLen = obj.len
|
||||
if result.baseKind == bcSupField:
|
||||
obj.addField(name = "Sup", typ = baseType)
|
||||
|
||||
proc finishSimpleStruct(obj: var Builder; m: BModule; info: StructBuilderInfo) =
|
||||
if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len:
|
||||
if info.baseKind == bcNone and info.preFieldsLen == obj.len:
|
||||
# no fields were added, add dummy field
|
||||
obj.addField(name = "dummy", typ = "char")
|
||||
if info.named:
|
||||
@@ -320,7 +287,7 @@ proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType:
|
||||
obj.add(baseType)
|
||||
obj.add(" ")
|
||||
obj.add("{\n")
|
||||
result.preFieldsLen = obj.buf.len
|
||||
result.preFieldsLen = obj.len
|
||||
case result.baseKind
|
||||
of bcNone:
|
||||
# rest of the options add a field or don't need it due to inheritance,
|
||||
@@ -340,7 +307,7 @@ proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType:
|
||||
obj.addField(name = "Sup", typ = baseType)
|
||||
|
||||
proc finishStruct(obj: var Builder; m: BModule; t: PType; info: StructBuilderInfo) =
|
||||
if info.baseKind == bcNone and info.preFieldsLen == obj.buf.len and
|
||||
if info.baseKind == bcNone and info.preFieldsLen == obj.len and
|
||||
t.itemId notin m.g.graph.memberProcsPerType:
|
||||
# no fields were added, add dummy field
|
||||
obj.addField(name = "dummy", typ = "char")
|
||||
@@ -380,148 +347,3 @@ template addAnonUnion(obj: var Builder; body: typed) =
|
||||
obj.add "union{\n"
|
||||
body
|
||||
obj.add("};\n")
|
||||
|
||||
type DeclVisibility = enum
|
||||
None
|
||||
Extern
|
||||
ExternC
|
||||
ImportLib
|
||||
ExportLib
|
||||
ExportLibVar
|
||||
Private
|
||||
StaticProc
|
||||
|
||||
template addDeclWithVisibility(builder: var Builder, visibility: DeclVisibility, declBody: typed) =
|
||||
## adds a declaration as in `declBody` with the given visibility
|
||||
case visibility
|
||||
of None: discard
|
||||
of Extern:
|
||||
builder.add("extern ")
|
||||
of ExternC:
|
||||
builder.add("extern \"C\" ")
|
||||
of ImportLib:
|
||||
builder.add("N_LIB_IMPORT ")
|
||||
of ExportLib:
|
||||
builder.add("N_LIB_EXPORT ")
|
||||
of ExportLibVar:
|
||||
builder.add("N_LIB_EXPORT_VAR ")
|
||||
of Private:
|
||||
builder.add("N_LIB_PRIVATE ")
|
||||
of StaticProc:
|
||||
builder.add("static ")
|
||||
declBody
|
||||
|
||||
type ProcParamBuilder = object
|
||||
needsComma: bool
|
||||
|
||||
proc initProcParamBuilder(builder: var Builder): ProcParamBuilder =
|
||||
result = ProcParamBuilder(needsComma: false)
|
||||
builder.add("(")
|
||||
|
||||
proc finishProcParamBuilder(builder: var Builder, params: ProcParamBuilder) =
|
||||
if params.needsComma:
|
||||
builder.add(")")
|
||||
else:
|
||||
builder.add("void)")
|
||||
|
||||
template cgDeclFrmt*(s: PSym): string =
|
||||
s.constraint.strVal
|
||||
|
||||
proc addParam(builder: var Builder, params: var ProcParamBuilder, name: string, typ: Snippet) =
|
||||
if params.needsComma:
|
||||
builder.add(", ")
|
||||
else:
|
||||
params.needsComma = true
|
||||
builder.add(typ)
|
||||
builder.add(" ")
|
||||
builder.add(name)
|
||||
|
||||
proc addParam(builder: var Builder, params: var ProcParamBuilder, param: PSym, typ: Snippet) =
|
||||
if params.needsComma:
|
||||
builder.add(", ")
|
||||
else:
|
||||
params.needsComma = true
|
||||
var modifiedTyp = typ
|
||||
if sfNoalias in param.flags:
|
||||
modifiedTyp.add(" NIM_NOALIAS")
|
||||
if sfCodegenDecl notin param.flags:
|
||||
builder.add(modifiedTyp)
|
||||
builder.add(" ")
|
||||
builder.add(param.loc.snippet)
|
||||
else:
|
||||
builder.add runtimeFormat(param.cgDeclFrmt, [modifiedTyp, param.loc.snippet])
|
||||
|
||||
proc addUnnamedParam(builder: var Builder, params: var ProcParamBuilder, typ: Snippet) =
|
||||
if params.needsComma:
|
||||
builder.add(", ")
|
||||
else:
|
||||
params.needsComma = true
|
||||
builder.add(typ)
|
||||
|
||||
proc addVarargsParam(builder: var Builder, params: var ProcParamBuilder) =
|
||||
# does not exist in NIFC, needs to be proc pragma
|
||||
if params.needsComma:
|
||||
builder.add(", ")
|
||||
else:
|
||||
params.needsComma = true
|
||||
builder.add("...")
|
||||
|
||||
template addProcParams(builder: var Builder, params: out ProcParamBuilder, body: typed) =
|
||||
params = initProcParamBuilder(builder)
|
||||
body
|
||||
finishProcParamBuilder(builder, params)
|
||||
|
||||
proc addProcHeader(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet, addAttributes: bool) =
|
||||
# on nifc should build something like (proc name params type pragmas
|
||||
# with no body given
|
||||
let noreturn = isNoReturn(m, prc)
|
||||
if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add("__declspec(naked) ")
|
||||
if noreturn and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add("__declspec(noreturn) ")
|
||||
builder.add(CallingConvToStr[prc.typ.callConv])
|
||||
builder.add("(")
|
||||
builder.add(rettype)
|
||||
builder.add(", ")
|
||||
builder.add(name)
|
||||
builder.add(")")
|
||||
builder.add(params)
|
||||
if addAttributes:
|
||||
if sfPure in prc.flags and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add(" __attribute__((naked))")
|
||||
if noreturn and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add(" __attribute__((noreturn))")
|
||||
|
||||
proc finishProcHeaderAsProto(builder: var Builder) =
|
||||
builder.add(";\n")
|
||||
|
||||
template finishProcHeaderWithBody(builder: var Builder, body: typed) =
|
||||
builder.add(" {\n")
|
||||
body
|
||||
builder.add("}\n\n")
|
||||
|
||||
proc addProcVar(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet,
|
||||
isStatic = false, ignoreAttributes = false) =
|
||||
# on nifc, builds full variable
|
||||
if isStatic:
|
||||
builder.add("static ")
|
||||
let noreturn = isNoReturn(m, prc)
|
||||
if not ignoreAttributes:
|
||||
if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add("__declspec(naked) ")
|
||||
if noreturn and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add("__declspec(noreturn) ")
|
||||
builder.add(CallingConvToStr[prc.typ.callConv])
|
||||
builder.add("_PTR(")
|
||||
builder.add(rettype)
|
||||
builder.add(", ")
|
||||
builder.add(name)
|
||||
builder.add(")")
|
||||
builder.add(params)
|
||||
if not ignoreAttributes:
|
||||
if sfPure in prc.flags and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add(" __attribute__((naked))")
|
||||
if noreturn and hasAttribute in extccomp.CC[m.config.cCompiler].props:
|
||||
builder.add(" __attribute__((noreturn))")
|
||||
# ensure we are just adding a variable:
|
||||
builder.add(";\n")
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
# XXX make complex ones like bitOr use builder instead
|
||||
# XXX add stuff like NI, NIM_NIL as constants
|
||||
|
||||
proc constType(t: Snippet): Snippet =
|
||||
# needs manipulation of `t` in nifc
|
||||
"NIM_CONST " & t
|
||||
|
||||
proc constPtrType(t: Snippet): Snippet =
|
||||
t & "* NIM_CONST"
|
||||
|
||||
proc ptrConstType(t: Snippet): Snippet =
|
||||
"NIM_CONST " & t & "*"
|
||||
|
||||
proc ptrType(t: Snippet): Snippet =
|
||||
t & "*"
|
||||
|
||||
@@ -23,210 +13,14 @@ const
|
||||
"N_NOCONV" #ccMember is N_NOCONV
|
||||
]
|
||||
|
||||
proc procPtrTypeUnnamed(rettype, params: Snippet): Snippet =
|
||||
rettype & "(*)" & params
|
||||
|
||||
proc procPtrTypeUnnamedNimCall(rettype, params: Snippet): Snippet =
|
||||
rettype & "(N_RAW_NIMCALL*)" & params
|
||||
proc procPtrType(conv: TCallingConvention, rettype: Snippet, name: string): Snippet =
|
||||
CallingConvToStr[conv] & "_PTR(" & rettype & ", " & name & ")"
|
||||
|
||||
proc cCast(typ, value: Snippet): Snippet =
|
||||
"((" & typ & ") " & value & ")"
|
||||
|
||||
proc wrapPar(value: Snippet): Snippet =
|
||||
# used for expression group, no-op on sexp
|
||||
"(" & value & ")"
|
||||
|
||||
proc removeSinglePar(value: Snippet): Snippet =
|
||||
# removes a single paren layer expected to exist, to silence Wparentheses-equality
|
||||
assert value[0] == '(' and value[^1] == ')'
|
||||
value[1..^2]
|
||||
|
||||
template addCast(builder: var Builder, typ: Snippet, valueBody: typed) =
|
||||
## adds a cast to `typ` with value built by `valueBody`
|
||||
builder.add "(("
|
||||
builder.add typ
|
||||
builder.add ") "
|
||||
valueBody
|
||||
builder.add ")"
|
||||
|
||||
proc cAddr(value: Snippet): Snippet =
|
||||
"&" & value
|
||||
|
||||
proc cDeref(value: Snippet): Snippet =
|
||||
"(*" & value & ")"
|
||||
|
||||
proc subscript(a, b: Snippet): Snippet =
|
||||
a & "[" & b & "]"
|
||||
|
||||
proc dotField(a, b: Snippet): Snippet =
|
||||
a & "." & b
|
||||
|
||||
proc derefField(a, b: Snippet): Snippet =
|
||||
a & "->" & b
|
||||
|
||||
proc bitOr(a, b: Snippet): Snippet =
|
||||
"(" & a & " | " & b & ")"
|
||||
|
||||
type CallBuilder = object
|
||||
needsComma: bool
|
||||
|
||||
proc initCallBuilder(builder: var Builder, callee: Snippet): CallBuilder =
|
||||
result = CallBuilder(needsComma: false)
|
||||
builder.add(callee)
|
||||
builder.add("(")
|
||||
|
||||
template addArgument(builder: var Builder, call: var CallBuilder, valueBody: typed) =
|
||||
if call.needsComma:
|
||||
builder.add(", ")
|
||||
else:
|
||||
call.needsComma = true
|
||||
valueBody
|
||||
|
||||
proc finishCallBuilder(builder: var Builder, call: CallBuilder) =
|
||||
builder.add(")")
|
||||
|
||||
template addCall(builder: var Builder, call: out CallBuilder, callee: Snippet, body: typed) =
|
||||
call = initCallBuilder(builder, callee)
|
||||
body
|
||||
finishCallBuilder(builder, call)
|
||||
|
||||
proc addCall(builder: var Builder, callee: Snippet, args: varargs[Snippet]) =
|
||||
builder.add(callee)
|
||||
builder.add("(")
|
||||
if args.len != 0:
|
||||
builder.add(args[0])
|
||||
for i in 1 ..< args.len:
|
||||
builder.add(", ")
|
||||
builder.add(args[i])
|
||||
builder.add(")")
|
||||
|
||||
proc cCall(callee: Snippet, args: varargs[Snippet]): Snippet =
|
||||
result = callee
|
||||
result.add("(")
|
||||
if args.len != 0:
|
||||
result.add(args[0])
|
||||
for i in 1 ..< args.len:
|
||||
result.add(", ")
|
||||
result.add(args[i])
|
||||
result.add(")")
|
||||
|
||||
proc addSizeof(builder: var Builder, val: Snippet) =
|
||||
builder.add("sizeof(")
|
||||
builder.add(val)
|
||||
builder.add(")")
|
||||
|
||||
proc addAlignof(builder: var Builder, val: Snippet) =
|
||||
builder.add("NIM_ALIGNOF(")
|
||||
builder.add(val)
|
||||
builder.add(")")
|
||||
|
||||
proc addOffsetof(builder: var Builder, val, member: Snippet) =
|
||||
builder.add("offsetof(")
|
||||
builder.add(val)
|
||||
builder.add(", ")
|
||||
builder.add(member)
|
||||
builder.add(")")
|
||||
|
||||
template cSizeof(val: Snippet): Snippet =
|
||||
"sizeof(" & val & ")"
|
||||
|
||||
template cAlignof(val: Snippet): Snippet =
|
||||
"NIM_ALIGNOF(" & val & ")"
|
||||
|
||||
template cOffsetof(val, member: Snippet): Snippet =
|
||||
"offsetof(" & val & ", " & member & ")"
|
||||
|
||||
type TypedBinaryOp = enum
|
||||
Add, Sub, Mul, Div, Mod
|
||||
Shr, Shl, BitAnd, BitOr, BitXor
|
||||
|
||||
const typedBinaryOperators: array[TypedBinaryOp, string] = [
|
||||
Add: "+",
|
||||
Sub: "-",
|
||||
Mul: "*",
|
||||
Div: "/",
|
||||
Mod: "%",
|
||||
Shr: ">>",
|
||||
Shl: "<<",
|
||||
BitAnd: "&",
|
||||
BitOr: "|",
|
||||
BitXor: "^"
|
||||
]
|
||||
|
||||
type TypedUnaryOp = enum
|
||||
Neg, BitNot
|
||||
|
||||
const typedUnaryOperators: array[TypedUnaryOp, string] = [
|
||||
Neg: "-",
|
||||
BitNot: "~",
|
||||
]
|
||||
|
||||
type UntypedBinaryOp = enum
|
||||
LessEqual, LessThan, GreaterEqual, GreaterThan, Equal, NotEqual
|
||||
And, Or
|
||||
|
||||
const untypedBinaryOperators: array[UntypedBinaryOp, string] = [
|
||||
LessEqual: "<=",
|
||||
LessThan: "<",
|
||||
GreaterEqual: ">=",
|
||||
GreaterThan: ">",
|
||||
Equal: "==",
|
||||
NotEqual: "!=",
|
||||
And: "&&",
|
||||
Or: "||"
|
||||
]
|
||||
|
||||
type UntypedUnaryOp = enum
|
||||
Not
|
||||
|
||||
const untypedUnaryOperators: array[UntypedUnaryOp, string] = [
|
||||
Not: "!"
|
||||
]
|
||||
|
||||
proc addOp(builder: var Builder, binOp: TypedBinaryOp, t: Snippet, a, b: Snippet) =
|
||||
builder.add('(')
|
||||
builder.add(a)
|
||||
builder.add(' ')
|
||||
builder.add(typedBinaryOperators[binOp])
|
||||
builder.add(' ')
|
||||
builder.add(b)
|
||||
builder.add(')')
|
||||
|
||||
proc addOp(builder: var Builder, unOp: TypedUnaryOp, t: Snippet, a: Snippet) =
|
||||
builder.add('(')
|
||||
builder.add(typedUnaryOperators[unOp])
|
||||
builder.add('(')
|
||||
builder.add(a)
|
||||
builder.add("))")
|
||||
|
||||
proc addOp(builder: var Builder, binOp: UntypedBinaryOp, a, b: Snippet) =
|
||||
builder.add('(')
|
||||
builder.add(a)
|
||||
builder.add(' ')
|
||||
builder.add(untypedBinaryOperators[binOp])
|
||||
builder.add(' ')
|
||||
builder.add(b)
|
||||
builder.add(')')
|
||||
|
||||
proc addOp(builder: var Builder, unOp: UntypedUnaryOp, a: Snippet) =
|
||||
builder.add('(')
|
||||
builder.add(untypedUnaryOperators[unOp])
|
||||
builder.add('(')
|
||||
builder.add(a)
|
||||
builder.add("))")
|
||||
|
||||
template cOp(binOp: TypedBinaryOp, t: Snippet, a, b: Snippet): Snippet =
|
||||
'(' & a & ' ' & typedBinaryOperators[binOp] & ' ' & b & ')'
|
||||
|
||||
template cOp(binOp: TypedUnaryOp, t: Snippet, a: Snippet): Snippet =
|
||||
'(' & typedUnaryOperators[binOp] & '(' & a & "))"
|
||||
|
||||
template cOp(binOp: UntypedBinaryOp, a, b: Snippet): Snippet =
|
||||
'(' & a & ' ' & untypedBinaryOperators[binOp] & ' ' & b & ')'
|
||||
|
||||
template cOp(binOp: UntypedUnaryOp, a: Snippet): Snippet =
|
||||
'(' & untypedUnaryOperators[binOp] & '(' & a & "))"
|
||||
|
||||
template cIfExpr(cond, a, b: Snippet): Snippet =
|
||||
# XXX used for `min` and `max`, maybe add nifc primitives for these
|
||||
"(" & cond & " ? " & a & " : " & b & ")"
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
template addAssignmentWithValue(builder: var Builder, lhs: Snippet, valueBody: typed) =
|
||||
builder.add(lhs)
|
||||
builder.add(" = ")
|
||||
valueBody
|
||||
builder.add(";\n")
|
||||
|
||||
template addFieldAssignmentWithValue(builder: var Builder, lhs: Snippet, name: string, valueBody: typed) =
|
||||
builder.add(lhs)
|
||||
builder.add("." & name & " = ")
|
||||
valueBody
|
||||
builder.add(";\n")
|
||||
|
||||
template addAssignment(builder: var Builder, lhs, rhs: Snippet) =
|
||||
builder.addAssignmentWithValue(lhs):
|
||||
builder.add(rhs)
|
||||
|
||||
template addFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: Snippet) =
|
||||
builder.addFieldAssignmentWithValue(lhs, name):
|
||||
builder.add(rhs)
|
||||
|
||||
template addMutualFieldAssignment(builder: var Builder, lhs, rhs: Snippet, name: string) =
|
||||
builder.addFieldAssignmentWithValue(lhs, name):
|
||||
builder.add(rhs)
|
||||
builder.add("." & name)
|
||||
|
||||
template addAssignment(builder: var Builder, lhs: Snippet, rhs: int | int64 | uint64 | Int128) =
|
||||
builder.addAssignmentWithValue(lhs):
|
||||
builder.addIntValue(rhs)
|
||||
|
||||
template addFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: int | int64 | uint64 | Int128) =
|
||||
builder.addFieldAssignmentWithValue(lhs, name):
|
||||
builder.addIntValue(rhs)
|
||||
|
||||
template addDerefFieldAssignment(builder: var Builder, lhs: Snippet, name: string, rhs: Snippet) =
|
||||
builder.add(lhs)
|
||||
builder.add("->" & name & " = ")
|
||||
builder.add(rhs)
|
||||
builder.add(";\n")
|
||||
|
||||
template addSubscriptAssignment(builder: var Builder, lhs: Snippet, index: Snippet, rhs: Snippet) =
|
||||
builder.add(lhs)
|
||||
builder.add("[" & index & "] = ")
|
||||
builder.add(rhs)
|
||||
builder.add(";\n")
|
||||
|
||||
template addStmt(builder: var Builder, stmtBody: typed) =
|
||||
## makes an expression built by `stmtBody` into a statement
|
||||
stmtBody
|
||||
builder.add(";\n")
|
||||
|
||||
proc addCallStmt(builder: var Builder, callee: Snippet, args: varargs[Snippet]) =
|
||||
builder.addStmt():
|
||||
builder.addCall(callee, args)
|
||||
|
||||
# XXX blocks need indent tracker in `Builder` object
|
||||
|
||||
template addSingleIfStmt(builder: var Builder, cond: Snippet, body: typed) =
|
||||
builder.add("if (")
|
||||
builder.add(cond)
|
||||
builder.add(") {\n")
|
||||
body
|
||||
builder.add("}\n")
|
||||
|
||||
template addSingleIfStmtWithCond(builder: var Builder, condBody: typed, body: typed) =
|
||||
builder.add("if (")
|
||||
condBody
|
||||
builder.add(") {\n")
|
||||
body
|
||||
builder.add("}\n")
|
||||
|
||||
type IfStmt = object
|
||||
needsElse: bool
|
||||
|
||||
template addIfStmt(builder: var Builder, stmt: out IfStmt, body: typed) =
|
||||
stmt = IfStmt(needsElse: false)
|
||||
body
|
||||
builder.add("\n")
|
||||
|
||||
template addElifBranch(builder: var Builder, stmt: var IfStmt, cond: Snippet, body: typed) =
|
||||
if stmt.needsElse:
|
||||
builder.add(" else ")
|
||||
else:
|
||||
stmt.needsElse = true
|
||||
builder.add("if (")
|
||||
builder.add(cond)
|
||||
builder.add(") {\n")
|
||||
body
|
||||
builder.add("}")
|
||||
|
||||
template addElseBranch(builder: var Builder, stmt: var IfStmt, body: typed) =
|
||||
assert stmt.needsElse
|
||||
builder.add(" else {\n")
|
||||
body
|
||||
builder.add("}")
|
||||
|
||||
proc addForRangeHeader(builder: var Builder, i, start, bound: Snippet, inclusive: bool = false) =
|
||||
builder.add("for (")
|
||||
builder.add(i)
|
||||
builder.add(" = ")
|
||||
builder.add(start)
|
||||
builder.add("; ")
|
||||
builder.add(i)
|
||||
if inclusive:
|
||||
builder.add(" <= ")
|
||||
else:
|
||||
builder.add(" < ")
|
||||
builder.add(bound)
|
||||
builder.add("; ")
|
||||
builder.add(i)
|
||||
builder.add("++) {\n")
|
||||
|
||||
template addForRangeExclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
|
||||
addForRangeHeader(builder, i, start, bound, false)
|
||||
body
|
||||
builder.add("}\n")
|
||||
|
||||
template addForRangeInclusive(builder: var Builder, i, start, bound: Snippet, body: typed) =
|
||||
addForRangeHeader(builder, i, start, bound, true)
|
||||
body
|
||||
builder.add("}\n")
|
||||
|
||||
template addScope(builder: var Builder, body: typed) =
|
||||
builder.add("{")
|
||||
body
|
||||
builder.add("\t}")
|
||||
|
||||
proc addLabel(builder: var Builder, name: TLabel) =
|
||||
builder.add(name)
|
||||
builder.add(": ;\n")
|
||||
|
||||
proc addReturn(builder: var Builder) =
|
||||
builder.add("return;\n")
|
||||
|
||||
proc addReturn(builder: var Builder, value: string) =
|
||||
builder.add("return ")
|
||||
builder.add(value)
|
||||
builder.add(";\n")
|
||||
|
||||
template addGoto(builder: var Builder, label: TLabel) =
|
||||
builder.add("goto ")
|
||||
builder.add(label)
|
||||
builder.add(";\n")
|
||||
|
||||
template addIncr(builder: var Builder, val: Snippet) =
|
||||
builder.add(val)
|
||||
builder.add("++;\n")
|
||||
|
||||
template addDecr(builder: var Builder, val: Snippet) =
|
||||
builder.add(val)
|
||||
builder.add("--;\n")
|
||||
@@ -209,7 +209,8 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
|
||||
result = ("($3*)(($1)+($2))" % [rdLoc(a), rdLoc(b), dest],
|
||||
lengthExpr)
|
||||
else:
|
||||
let lit = cIntLiteral(first)
|
||||
var lit = newRopeAppender()
|
||||
intLiteral(first, lit)
|
||||
result = ("($4*)($1)+(($2)-($3))" %
|
||||
[rdLoc(a), rdLoc(b), lit, dest],
|
||||
lengthExpr)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,14 +48,14 @@ proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) =
|
||||
var seqInit: StructInitializer
|
||||
res.addStructInitializer(seqInit, kind = siOrderedStruct):
|
||||
res.addField(seqInit, name = "len"):
|
||||
res.addIntValue(s.len)
|
||||
res.add(rope(s.len))
|
||||
res.addField(seqInit, name = "reserved"):
|
||||
res.add(cCast("NI", bitOr(cCast("NU", rope(s.len)), "NIM_STRLIT_FLAG")))
|
||||
res.addField(strInit, name = "data"):
|
||||
res.add(makeCString(s))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
m.s[cfsStrData].add(res)
|
||||
|
||||
proc genStringLiteralV1(m: BModule; n: PNode; result: var Builder) =
|
||||
proc genStringLiteralV1(m: BModule; n: PNode; result: var Rope) =
|
||||
if s.isNil:
|
||||
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), "NIM_NIL"))
|
||||
else:
|
||||
@@ -85,9 +85,9 @@ proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bo
|
||||
res.add(bitOr(rope(s.len), "NIM_STRLIT_FLAG"))
|
||||
res.addField(structInit, name = "data"):
|
||||
res.add(makeCString(s))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
m.s[cfsStrData].add(res)
|
||||
|
||||
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Builder) =
|
||||
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Rope) =
|
||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||
var litName: string
|
||||
if id == m.labels:
|
||||
@@ -101,19 +101,20 @@ proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Builder
|
||||
let tmp = getTempName(m)
|
||||
result.add tmp
|
||||
var res = newBuilder("")
|
||||
res.addVarWithInitializer(
|
||||
res.addVarWithTypeAndInitializer(
|
||||
if isConst: AlwaysConst else: Global,
|
||||
name = tmp,
|
||||
typ = "NimStringV2"):
|
||||
name = tmp):
|
||||
res.add("NimStringV2")
|
||||
do:
|
||||
var strInit: StructInitializer
|
||||
res.addStructInitializer(strInit, kind = siOrderedStruct):
|
||||
res.addField(strInit, name = "len"):
|
||||
res.addIntValue(n.strVal.len)
|
||||
res.add(rope(n.strVal.len))
|
||||
res.addField(strInit, name = "p"):
|
||||
res.add(cCast(ptrType("NimStrPayload"), cAddr(litName)))
|
||||
m.s[cfsStrData].add(extract(res))
|
||||
m.s[cfsStrData].add(res)
|
||||
|
||||
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Builder) =
|
||||
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
|
||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||
var pureLit: Rope
|
||||
if id == m.labels:
|
||||
@@ -127,7 +128,7 @@ proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Bu
|
||||
var strInit: StructInitializer
|
||||
result.addStructInitializer(strInit, kind = siOrderedStruct):
|
||||
result.addField(strInit, name = "len"):
|
||||
result.addIntValue(n.strVal.len)
|
||||
result.add(rope(n.strVal.len))
|
||||
result.addField(strInit, name = "p"):
|
||||
result.add(cCast(ptrType("NimStrPayload"), cAddr(pureLit)))
|
||||
|
||||
@@ -144,10 +145,10 @@ proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
|
||||
else:
|
||||
localError(m.config, info, "cannot determine how to produce code for string literal")
|
||||
|
||||
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Builder) =
|
||||
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Rope) =
|
||||
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), "NIM_NIL"))
|
||||
|
||||
proc genStringLiteral(m: BModule; n: PNode; result: var Builder) =
|
||||
proc genStringLiteral(m: BModule; n: PNode; result: var Rope) =
|
||||
case detectStrVersion(m)
|
||||
of 0, 1: genStringLiteralV1(m, n, result)
|
||||
of 2: genStringLiteralV2(m, n, isConst = true, result)
|
||||
|
||||
@@ -146,16 +146,16 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
|
||||
a.flags.incl(lfEnforceDeref)
|
||||
expr(p, ri, a)
|
||||
|
||||
proc assignLabel(b: var TBlock; result: var Builder) {.inline.} =
|
||||
proc assignLabel(b: var TBlock; result: var Rope) {.inline.} =
|
||||
b.label = "LA" & b.id.rope
|
||||
result.add b.label
|
||||
|
||||
proc blockBody(b: var TBlock; result: var Builder) =
|
||||
result.add extract(b.sections[cpsLocals])
|
||||
proc blockBody(b: var TBlock; result: var Rope) =
|
||||
result.add b.sections[cpsLocals]
|
||||
if b.frameLen > 0:
|
||||
result.addf("FR_.len+=$1;$n", [b.frameLen.rope])
|
||||
result.add(extract(b.sections[cpsInit]))
|
||||
result.add(extract(b.sections[cpsStmts]))
|
||||
result.add(b.sections[cpsInit])
|
||||
result.add(b.sections[cpsStmts])
|
||||
|
||||
proc endBlock(p: BProc, blockEnd: Rope) =
|
||||
let topBlock = p.blocks.len-1
|
||||
@@ -281,7 +281,7 @@ proc genGotoVar(p: BProc; value: PNode) =
|
||||
|
||||
proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; result: var Builder)
|
||||
|
||||
proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Builder) =
|
||||
proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
|
||||
if lfDynamicLib in v.loc.flags or sfThread in v.flags or p.hcrOn:
|
||||
discard "nothing to do"
|
||||
elif sfGlobal in v.flags and value != nil and isDeepConstExpr(value, p.module.compileToCpp) and
|
||||
@@ -330,9 +330,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
value.kind in nkCallKinds and value[0].kind == nkSym and
|
||||
v.typ.kind != tyPtr and sfConstructor in value[0].sym.flags
|
||||
var targetProc = p
|
||||
var valueBuilder = newBuilder("")
|
||||
potentialValueInit(p, v, value, valueBuilder)
|
||||
let valueAsRope = extract(valueBuilder)
|
||||
var valueAsRope = ""
|
||||
potentialValueInit(p, v, value, valueAsRope)
|
||||
if sfGlobal in v.flags:
|
||||
if v.flags * {sfImportc, sfExportc} == {sfImportc} and
|
||||
value.kind == nkEmpty and
|
||||
@@ -595,7 +594,8 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
return
|
||||
|
||||
let val = getOrdValue(it[j])
|
||||
let lit = cIntLiteral(toInt64(val)+id+1)
|
||||
var lit = newRopeAppender()
|
||||
intLiteral(toInt64(val)+id+1, lit)
|
||||
lineF(p, cpsStmts, "TMP$#_:$n", [lit])
|
||||
|
||||
genStmts(p, it.lastSon)
|
||||
@@ -775,7 +775,7 @@ proc finallyActions(p: BProc) =
|
||||
if finallyBlock != nil:
|
||||
genSimpleBlock(p, finallyBlock[0])
|
||||
|
||||
proc raiseInstr(p: BProc; result: var Builder) =
|
||||
proc raiseInstr(p: BProc; result: var Rope) =
|
||||
if p.config.exc == excGoto:
|
||||
let L = p.nestedTryStmts.len
|
||||
if L == 0:
|
||||
@@ -925,7 +925,8 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
[rdLoc(a), bitMask])
|
||||
for j in 0..high(branches):
|
||||
if branches[j] != "":
|
||||
let lit = cIntLiteral(j)
|
||||
var lit = newRopeAppender()
|
||||
intLiteral(j, lit)
|
||||
lineF(p, cpsStmts, "case $1: $n$2break;$n",
|
||||
[lit, branches[j]])
|
||||
lineF(p, cpsStmts, "}$n", []) # else statement:
|
||||
@@ -963,22 +964,22 @@ proc genCaseRange(p: BProc, branch: PNode) =
|
||||
for j in 0..<branch.len-1:
|
||||
if branch[j].kind == nkRange:
|
||||
if hasSwitchRange in CC[p.config.cCompiler].props:
|
||||
var litA = newBuilder("")
|
||||
var litB = newBuilder("")
|
||||
var litA = newRopeAppender()
|
||||
var litB = newRopeAppender()
|
||||
genLiteral(p, branch[j][0], litA)
|
||||
genLiteral(p, branch[j][1], litB)
|
||||
lineF(p, cpsStmts, "case $1 ... $2:$n", [extract(litA), extract(litB)])
|
||||
lineF(p, cpsStmts, "case $1 ... $2:$n", [litA, litB])
|
||||
else:
|
||||
var v = copyNode(branch[j][0])
|
||||
while v.intVal <= branch[j][1].intVal:
|
||||
var litA = newBuilder("")
|
||||
var litA = newRopeAppender()
|
||||
genLiteral(p, v, litA)
|
||||
lineF(p, cpsStmts, "case $1:$n", [extract(litA)])
|
||||
lineF(p, cpsStmts, "case $1:$n", [litA])
|
||||
inc(v.intVal)
|
||||
else:
|
||||
var litA = newBuilder("")
|
||||
var litA = newRopeAppender()
|
||||
genLiteral(p, branch[j], litA)
|
||||
lineF(p, cpsStmts, "case $1:$n", [extract(litA)])
|
||||
lineF(p, cpsStmts, "case $1:$n", [litA])
|
||||
|
||||
proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
# analyse 'case' statement:
|
||||
@@ -1640,7 +1641,8 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||
if not containsOrIncl(p.module.declaredThings, field.id):
|
||||
appcg(p.module, cfsVars, "extern $1",
|
||||
[discriminatorTableDecl(p.module, t, field)])
|
||||
let lit = cIntLiteral(toInt64(lengthOrd(p.config, field.typ))+1)
|
||||
var lit = newRopeAppender()
|
||||
intLiteral(toInt64(lengthOrd(p.config, field.typ))+1, lit)
|
||||
lineCg(p, cpsStmts,
|
||||
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
|
||||
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
|
||||
|
||||
@@ -47,9 +47,11 @@ proc generateThreadLocalStorage(m: BModule) =
|
||||
if m.g.nimtv != "" and (usesThreadVars in m.flags or sfMainModule in m.module.flags):
|
||||
for t in items(m.g.nimtvDeps): discard getTypeDesc(m, t)
|
||||
finishTypeDescriptions(m)
|
||||
m.s[cfsSeqTypes].addTypedef(name = "NimThreadVars"):
|
||||
m.s[cfsSeqTypes].addSimpleStruct(m, name = "", baseType = ""):
|
||||
m.s[cfsSeqTypes].add(m.g.nimtv)
|
||||
var typedef = newBuilder("")
|
||||
typedef.addTypedef(name = "NimThreadVars"):
|
||||
typedef.addSimpleStruct(m, name = "", baseType = ""):
|
||||
typedef.add(m.g.nimtv)
|
||||
m.s[cfsSeqTypes].add(typedef)
|
||||
|
||||
proc generateThreadVarsSize(m: BModule) =
|
||||
if m.g.nimtv != "":
|
||||
|
||||
@@ -76,11 +76,12 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
let arraySize = lengthOrd(c.p.config, typ.indexType)
|
||||
var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
|
||||
var oldCode = p.s(cpsStmts)
|
||||
freeze oldCode
|
||||
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
[i.snippet, arraySize])
|
||||
let oldLen = p.s(cpsStmts).buf.len
|
||||
let oldLen = p.s(cpsStmts).len
|
||||
genTraverseProc(c, ropecg(c.p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
|
||||
if p.s(cpsStmts).buf.len == oldLen:
|
||||
if p.s(cpsStmts).len == oldLen:
|
||||
# do not emit dummy long loops for faster debug builds:
|
||||
p.s(cpsStmts) = oldCode
|
||||
else:
|
||||
@@ -118,13 +119,14 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||
assert typ.kind == tySequence
|
||||
var i = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt))
|
||||
var oldCode = p.s(cpsStmts)
|
||||
freeze oldCode
|
||||
var a = TLoc(snippet: accessor)
|
||||
|
||||
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
|
||||
[i.snippet, lenExpr(c.p, a)])
|
||||
let oldLen = p.s(cpsStmts).buf.len
|
||||
let oldLen = p.s(cpsStmts).len
|
||||
genTraverseProc(c, "$1$3[$2]" % [accessor, i.snippet, dataField(c.p)], typ.elementType)
|
||||
if p.s(cpsStmts).buf.len == oldLen:
|
||||
if p.s(cpsStmts).len == oldLen:
|
||||
# do not emit dummy long loops for faster debug builds:
|
||||
p.s(cpsStmts) = oldCode
|
||||
else:
|
||||
@@ -158,7 +160,7 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
|
||||
genTraverseProc(c, "(*a)".rope, typ.elementType)
|
||||
|
||||
let generatedProc = "$1 {$n$2$3$4}\n" %
|
||||
[header, extract(p.s(cpsLocals)), extract(p.s(cpsInit)), extract(p.s(cpsStmts))]
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
|
||||
|
||||
m.s[cfsProcHeaders].addf("$1;\n", [header])
|
||||
m.s[cfsProcs].add(generatedProc)
|
||||
@@ -187,7 +189,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
|
||||
genTraverseProc(c, sLoc, s.loc.t)
|
||||
|
||||
let generatedProc = "$1 {$n$2$3$4}$n" %
|
||||
[header, extract(p.s(cpsLocals)), extract(p.s(cpsInit)), extract(p.s(cpsStmts))]
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
|
||||
|
||||
m.s[cfsProcHeaders].addf("$1;$n", [header])
|
||||
m.s[cfsProcs].add(generatedProc)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,9 +14,9 @@ import
|
||||
nversion, nimsets, msgs, bitsets, idents, types,
|
||||
ccgutils, ropes, wordrecg, treetab, cgmeth,
|
||||
rodutils, renderer, cgendata, aliases,
|
||||
lowerings, lineinfos, pathutils, transf,
|
||||
lowerings, ndi, lineinfos, pathutils, transf,
|
||||
injectdestructors, astmsgs, modulepaths, pushpoppragmas,
|
||||
mangleutils, cbuilderbase
|
||||
mangleutils
|
||||
|
||||
from expanddefaults import caseObjDefaultBranch
|
||||
|
||||
@@ -138,9 +138,6 @@ proc cgFormatValue(result: var string; value: BiggestInt) =
|
||||
proc cgFormatValue(result: var string; value: Int128) =
|
||||
result.addInt128 value
|
||||
|
||||
template addf(result: var Builder, args: varargs[untyped]) =
|
||||
result.buf.addf(args)
|
||||
|
||||
# TODO: please document
|
||||
macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
|
||||
args.expectKind nnkBracket
|
||||
@@ -240,15 +237,7 @@ proc addIndent(p: BProc; result: var Rope) =
|
||||
result[i] = '\t'
|
||||
inc i
|
||||
|
||||
proc addIndent(p: BProc; result: var Builder) =
|
||||
var i = result.buf.len
|
||||
let newLen = i + p.blocks.len
|
||||
result.buf.setLen newLen
|
||||
while i < newLen:
|
||||
result.buf[i] = '\t'
|
||||
inc i
|
||||
|
||||
template appcg(m: BModule, c: var (Rope | Builder), frmt: FormatStr,
|
||||
template appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
||||
args: untyped) =
|
||||
c.add(ropecg(m, frmt, args))
|
||||
|
||||
@@ -286,7 +275,7 @@ proc safeLineNm(info: TLineInfo): int =
|
||||
proc genPostprocessDir(field1, field2, field3: string): string =
|
||||
result = postprocessDirStart & field1 & postprocessDirSep & field2 & postprocessDirSep & field3 & postprocessDirEnd
|
||||
|
||||
proc genCLineDir(r: var Builder, fileIdx: FileIndex, line: int; conf: ConfigRef) =
|
||||
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; conf: ConfigRef) =
|
||||
assert line >= 0
|
||||
if optLineDir in conf.options and line > 0:
|
||||
if fileIdx == InvalidFileIdx:
|
||||
@@ -294,7 +283,7 @@ proc genCLineDir(r: var Builder, fileIdx: FileIndex, line: int; conf: ConfigRef)
|
||||
else:
|
||||
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
|
||||
|
||||
proc genCLineDir(r: var Builder, fileIdx: FileIndex, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
|
||||
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
|
||||
assert line >= 0
|
||||
if optLineDir in p.config.options and line > 0:
|
||||
if fileIdx == InvalidFileIdx:
|
||||
@@ -302,7 +291,7 @@ proc genCLineDir(r: var Builder, fileIdx: FileIndex, line: int; p: BProc; info:
|
||||
else:
|
||||
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
|
||||
|
||||
proc genCLineDir(r: var Builder, info: TLineInfo; conf: ConfigRef) =
|
||||
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
|
||||
if optLineDir in conf.options:
|
||||
genCLineDir(r, info.fileIndex, info.safeLineNm, conf)
|
||||
|
||||
@@ -315,7 +304,7 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc genCLineDir(r: var Builder, p: BProc, info: TLineInfo; conf: ConfigRef) =
|
||||
proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
|
||||
if optLineDir in conf.options:
|
||||
let lastFileIndex = p.lastLineInfo.fileIndex
|
||||
if freshLineInfo(p, info):
|
||||
@@ -339,7 +328,7 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
|
||||
proc genProc(m: BModule, prc: PSym)
|
||||
proc raiseInstr(p: BProc; result: var Builder)
|
||||
proc raiseInstr(p: BProc; result: var Rope)
|
||||
|
||||
template compileToCpp(m: BModule): untyped =
|
||||
m.config.backend == backendCpp or sfCompileToCpp in m.module.flags
|
||||
@@ -348,45 +337,31 @@ proc getTempName(m: BModule): Rope =
|
||||
result = m.tmpBase & rope(m.labels)
|
||||
inc m.labels
|
||||
|
||||
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
|
||||
sfNoReturn in s.flags and m.config.exc != excGoto
|
||||
|
||||
include cbuilderexprs
|
||||
include cbuilderdecls
|
||||
include cbuilderstmts
|
||||
|
||||
proc rdLoc(a: TLoc): Rope =
|
||||
# 'read' location (deref if indirect)
|
||||
if lfIndirect in a.flags:
|
||||
result = cDeref(a.snippet)
|
||||
result = "(*" & a.snippet & ")"
|
||||
else:
|
||||
result = a.snippet
|
||||
|
||||
proc addRdLoc(a: TLoc; result: var Rope) =
|
||||
if lfIndirect in a.flags:
|
||||
result.add cDeref(a.snippet)
|
||||
result.add "(*" & a.snippet & ")"
|
||||
else:
|
||||
result.add a.snippet
|
||||
|
||||
proc lenField(p: BProc): Rope {.inline.} =
|
||||
result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
|
||||
|
||||
proc lenField(p: BProc, val: Rope): Rope {.inline.} =
|
||||
if p.module.compileToCpp:
|
||||
result = derefField(val, "len")
|
||||
else:
|
||||
result = dotField(derefField(val, "Sup"), "len")
|
||||
|
||||
proc lenExpr(p: BProc; a: TLoc): Rope =
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
result = dotField(rdLoc(a), "len")
|
||||
result = rdLoc(a) & ".len"
|
||||
else:
|
||||
let ra = rdLoc(a)
|
||||
result = cIfExpr(ra, lenField(p, ra), cIntValue(0))
|
||||
result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)]
|
||||
|
||||
proc dataFieldAccessor(p: BProc, sym: Rope): Rope =
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
result = dotField(wrapPar(sym), "p")
|
||||
result = "(" & sym & ").p"
|
||||
else:
|
||||
result = sym
|
||||
|
||||
@@ -396,11 +371,11 @@ proc dataField(p: BProc): Rope =
|
||||
else:
|
||||
result = rope"->data"
|
||||
|
||||
proc dataField(p: BProc, val: Rope): Rope {.inline.} =
|
||||
result = derefField(dataFieldAccessor(p, val), "data")
|
||||
|
||||
proc genProcPrototype(m: BModule, sym: PSym)
|
||||
|
||||
include cbuilderbase
|
||||
include cbuilderexprs
|
||||
include cbuilderdecls
|
||||
include ccgliterals
|
||||
include ccgtypes
|
||||
|
||||
@@ -413,20 +388,20 @@ template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
|
||||
|
||||
proc addAddrLoc(conf: ConfigRef; a: TLoc; result: var Rope) =
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
|
||||
result.add wrapPar(cAddr(a.snippet))
|
||||
result.add "(&" & a.snippet & ")"
|
||||
else:
|
||||
result.add a.snippet
|
||||
|
||||
proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
|
||||
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
|
||||
result = wrapPar(cAddr(a.snippet))
|
||||
result = "(&" & a.snippet & ")"
|
||||
else:
|
||||
result = a.snippet
|
||||
|
||||
proc byRefLoc(p: BProc; a: TLoc): Rope =
|
||||
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a) == skParam) != ctArray and not
|
||||
p.module.compileToCpp:
|
||||
result = wrapPar(cAddr(a.snippet))
|
||||
result = "(&" & a.snippet & ")"
|
||||
else:
|
||||
result = a.snippet
|
||||
|
||||
@@ -434,7 +409,7 @@ proc rdCharLoc(a: TLoc): Rope =
|
||||
# read a location that may need a char-cast:
|
||||
result = rdLoc(a)
|
||||
if skipTypes(a.t, abstractRange).kind == tyChar:
|
||||
result = cCast("NU8", result)
|
||||
result = "((NU8)($1))" % [result]
|
||||
|
||||
type
|
||||
TAssignmentFlag = enum
|
||||
@@ -623,29 +598,28 @@ proc getIntTemp(p: BProc): TLoc =
|
||||
linefmt(p, cpsLocals, "NI $1;$n", [result.snippet])
|
||||
|
||||
proc localVarDecl(p: BProc; n: PNode): Rope =
|
||||
var res = newBuilder("")
|
||||
result = ""
|
||||
let s = n.sym
|
||||
if s.loc.k == locNone:
|
||||
fillLocalName(p, s)
|
||||
fillLoc(s.loc, locLocalVar, n, OnStack)
|
||||
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||
res.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
|
||||
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
|
||||
|
||||
genCLineDir(res, p, n.info, p.config)
|
||||
genCLineDir(result, p, n.info, p.config)
|
||||
|
||||
res.add getTypeDesc(p.module, s.typ, dkVar)
|
||||
result.add getTypeDesc(p.module, s.typ, dkVar)
|
||||
if sfCodegenDecl notin s.flags:
|
||||
if sfRegister in s.flags: res.add(" register")
|
||||
if sfRegister in s.flags: result.add(" register")
|
||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||
# decl.add(" GC_GUARD")
|
||||
if sfVolatile in s.flags: res.add(" volatile")
|
||||
if sfNoalias in s.flags: res.add(" NIM_NOALIAS")
|
||||
res.add(" ")
|
||||
res.add(s.loc.snippet)
|
||||
result = extract(res)
|
||||
if sfVolatile in s.flags: result.add(" volatile")
|
||||
if sfNoalias in s.flags: result.add(" NIM_NOALIAS")
|
||||
result.add(" ")
|
||||
result.add(s.loc.snippet)
|
||||
else:
|
||||
result = runtimeFormat(s.cgDeclFrmt, [extract(res), s.loc.snippet])
|
||||
result = runtimeFormat(s.cgDeclFrmt, [result, s.loc.snippet])
|
||||
|
||||
proc assignLocalVar(p: BProc, n: PNode) =
|
||||
#assert(s.loc.k == locNone) # not yet assigned
|
||||
@@ -773,7 +747,7 @@ proc getLabel(p: BProc): TLabel =
|
||||
result = "LA" & rope(p.labels) & "_"
|
||||
|
||||
proc fixLabel(p: BProc, labl: TLabel) =
|
||||
p.s(cpsStmts).addLabel(labl)
|
||||
p.s(cpsStmts).add("$1: ;$n" % [labl])
|
||||
|
||||
proc genVarPrototype(m: BModule, n: PNode)
|
||||
proc requestConstImpl(p: BProc, sym: PSym)
|
||||
@@ -781,7 +755,8 @@ proc genStmts(p: BProc, t: PNode)
|
||||
proc expr(p: BProc, n: PNode, d: var TLoc)
|
||||
|
||||
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
|
||||
proc genLiteral(p: BProc, n: PNode; result: var Builder)
|
||||
proc intLiteral(i: BiggestInt; result: var Rope)
|
||||
proc genLiteral(p: BProc, n: PNode; result: var Rope)
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
|
||||
proc raiseExit(p: BProc)
|
||||
proc raiseExitCleanup(p: BProc, destroy: string)
|
||||
@@ -818,7 +793,7 @@ $1define nimlf_(n, file) \
|
||||
FR_.line = n; FR_.filename = file;
|
||||
|
||||
"""
|
||||
if p.module.s[cfsFrameDefines].buf.len == 0:
|
||||
if p.module.s[cfsFrameDefines].len == 0:
|
||||
appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"])
|
||||
|
||||
cgsym(p.module, "nimFrame")
|
||||
@@ -859,7 +834,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
var s: TStringSeq = @[]
|
||||
libCandidates(lib.path.strVal, s)
|
||||
rawMessage(m.config, hintDependency, lib.path.strVal)
|
||||
var loadlib = newBuilder("")
|
||||
var loadlib: Rope = ""
|
||||
for i in 0..high(s):
|
||||
inc(m.labels)
|
||||
if i > 0: loadlib.add("||")
|
||||
@@ -870,7 +845,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
loadlib.addf "))$n", []
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"if (!($1)) #nimLoadLibraryError(",
|
||||
[extract(loadlib)])
|
||||
[loadlib])
|
||||
genStringLiteral(m, lib.path, m.s[cfsDynLibInit])
|
||||
m.s[cfsDynLibInit].addf ");$n", []
|
||||
|
||||
@@ -884,9 +859,9 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
[getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
|
||||
expr(p, lib.path, dest)
|
||||
|
||||
m.s[cfsVars].add(extract(p.s(cpsLocals)))
|
||||
m.s[cfsDynLibInit].add(extract(p.s(cpsInit)))
|
||||
m.s[cfsDynLibInit].add(extract(p.s(cpsStmts)))
|
||||
m.s[cfsVars].add(p.s(cpsLocals))
|
||||
m.s[cfsDynLibInit].add(p.s(cpsInit))
|
||||
m.s[cfsDynLibInit].add(p.s(cpsStmts))
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
|
||||
[tmp, rdLoc(dest)])
|
||||
@@ -1006,12 +981,12 @@ proc generateHeaders(m: BModule) =
|
||||
#undef unix
|
||||
""")
|
||||
|
||||
proc openNamespaceNim(namespace: string; result: var Builder) =
|
||||
proc openNamespaceNim(namespace: string; result: var Rope) =
|
||||
result.add("namespace ")
|
||||
result.add(namespace)
|
||||
result.add(" {\L")
|
||||
|
||||
proc closeNamespaceNim(result: var Builder) =
|
||||
proc closeNamespaceNim(result: var Rope) =
|
||||
result.add("}\L")
|
||||
|
||||
proc closureSetup(p: BProc, prc: PSym) =
|
||||
@@ -1195,32 +1170,30 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
|
||||
proc getProcTypeCast(m: BModule, prc: PSym): Rope =
|
||||
result = getTypeDesc(m, prc.loc.t)
|
||||
if prc.typ.callConv == ccClosure:
|
||||
var rettype: Snippet = ""
|
||||
var desc = newBuilder("")
|
||||
var rettype, params: Rope = ""
|
||||
var check = initIntSet()
|
||||
genProcParams(m, prc.typ, rettype, desc, check)
|
||||
let params = extract(desc)
|
||||
result = procPtrTypeUnnamed(rettype = rettype, params = params)
|
||||
genProcParams(m, prc.typ, rettype, params, check)
|
||||
result = "$1(*)$2" % [rettype, params]
|
||||
|
||||
proc genProcBody(p: BProc; procBody: PNode) =
|
||||
genStmts(p, procBody) # modifies p.locals, p.init, etc.
|
||||
if {nimErrorFlagAccessed, nimErrorFlagDeclared, nimErrorFlagDisabled} * p.flags == {nimErrorFlagAccessed}:
|
||||
p.flags.incl nimErrorFlagDeclared
|
||||
p.blocks[0].sections[cpsLocals].addVar(kind = Local,
|
||||
name = "nimErr_", typ = ptrType("NIM_BOOL"))
|
||||
p.blocks[0].sections[cpsInit].addAssignmentWithValue("nimErr_"):
|
||||
p.blocks[0].sections[cpsInit].addCall(cgsymValue(p.module, "nimErrorFlag"))
|
||||
p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", []))
|
||||
p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", []))
|
||||
|
||||
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
|
||||
sfNoReturn in s.flags and m.config.exc != excGoto
|
||||
|
||||
proc genProcAux*(m: BModule, prc: PSym) =
|
||||
var p = newProc(prc, m)
|
||||
var header = newBuilder("")
|
||||
var header = newRopeAppender()
|
||||
let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {}
|
||||
var visibility: DeclVisibility = None
|
||||
if isCppMember:
|
||||
genMemberProcHeader(m, prc, header)
|
||||
else:
|
||||
genProcHeader(m, prc, header, visibility, asPtr = false, addAttributes = false)
|
||||
var returnStmt: Snippet = ""
|
||||
genProcHeader(m, prc, header)
|
||||
var returnStmt: Rope = ""
|
||||
assert(prc.ast != nil)
|
||||
|
||||
var procBody = transformBody(m.g.graph, m.idgen, prc, {})
|
||||
@@ -1240,8 +1213,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
|
||||
var decl = localVarDecl(p, resNode)
|
||||
var a: TLoc = initLocExprSingleUse(p, val)
|
||||
let ra = rdLoc(a)
|
||||
p.s(cpsStmts).addAssignment(decl, ra)
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)])
|
||||
else:
|
||||
# declare the result symbol:
|
||||
assignLocalVar(p, resNode)
|
||||
@@ -1253,10 +1225,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
discard "result init optimized out"
|
||||
else:
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
var returnBuilder = newBuilder("\t")
|
||||
let rres = rdLoc(res.loc)
|
||||
returnBuilder.addReturn(rres)
|
||||
returnStmt = extract(returnBuilder)
|
||||
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
|
||||
elif sfConstructor in prc.flags:
|
||||
resNode.sym.loc.flags.incl lfIndirect
|
||||
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
|
||||
@@ -1287,56 +1256,45 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
|
||||
prc.info = tmpInfo
|
||||
|
||||
var generatedProc = newBuilder("")
|
||||
var generatedProc: Rope = ""
|
||||
generatedProc.genCLineDir prc.info, m.config
|
||||
generatedProc.addDeclWithVisibility(visibility):
|
||||
if sfPure in prc.flags:
|
||||
generatedProc.add(extract(header))
|
||||
generatedProc.finishProcHeaderWithBody():
|
||||
generatedProc.add(extract(p.s(cpsLocals)))
|
||||
generatedProc.add(extract(p.s(cpsInit)))
|
||||
generatedProc.add(extract(p.s(cpsStmts)))
|
||||
if isNoReturn(p.module, prc):
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
|
||||
header = "__declspec(noreturn) " & header
|
||||
if sfPure in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
|
||||
header = "__declspec(naked) " & header
|
||||
generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N",
|
||||
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
|
||||
else:
|
||||
if m.hcrOn and isReloadable(m, prc):
|
||||
# Add forward declaration for "_actual"-suffixed functions defined in the same module (or inline).
|
||||
# This fixes the use of methods and also the case when 2 functions within the same module
|
||||
# call each other using directly the "_actual" versions (an optimization) - see issue #11608
|
||||
m.s[cfsProcHeaders].addf("$1;\n", [header])
|
||||
generatedProc.add ropecg(p.module, "$1 {$n", [header])
|
||||
if optStackTrace in prc.options:
|
||||
generatedProc.add(p.s(cpsLocals))
|
||||
var procname = makeCString(prc.name.s)
|
||||
generatedProc.add(initFrame(p, procname, quotedFilename(p.config, prc.info)))
|
||||
else:
|
||||
if m.hcrOn and isReloadable(m, prc):
|
||||
m.s[cfsProcHeaders].addDeclWithVisibility(visibility):
|
||||
# Add forward declaration for "_actual"-suffixed functions defined in the same module (or inline).
|
||||
# This fixes the use of methods and also the case when 2 functions within the same module
|
||||
# call each other using directly the "_actual" versions (an optimization) - see issue #11608
|
||||
m.s[cfsProcHeaders].add(extract(header))
|
||||
m.s[cfsProcHeaders].finishProcHeaderAsProto()
|
||||
generatedProc.add(extract(header))
|
||||
generatedProc.finishProcHeaderWithBody():
|
||||
if optStackTrace in prc.options:
|
||||
generatedProc.add(extract(p.s(cpsLocals)))
|
||||
var procname = makeCString(prc.name.s)
|
||||
generatedProc.add(initFrame(p, procname, quotedFilename(p.config, prc.info)))
|
||||
else:
|
||||
generatedProc.add(extract(p.s(cpsLocals)))
|
||||
if optProfiler in prc.options:
|
||||
# invoke at proc entry for recursion:
|
||||
p.s(cpsInit).add('\t')
|
||||
p.s(cpsInit).addCallStmt(cgsymValue(m, "nimProfile"))
|
||||
if beforeRetNeeded in p.flags:
|
||||
# this pair of {} is required for C++ (C++ is weird with its
|
||||
# control flow integrity checks):
|
||||
generatedProc.addScope():
|
||||
generatedProc.add(extract(p.s(cpsInit)))
|
||||
generatedProc.add(extract(p.s(cpsStmts)))
|
||||
generatedProc.addLabel("BeforeRet_")
|
||||
else:
|
||||
generatedProc.add(extract(p.s(cpsInit)))
|
||||
generatedProc.add(extract(p.s(cpsStmts)))
|
||||
if optStackTrace in prc.options: generatedProc.add(deinitFrame(p))
|
||||
generatedProc.add(returnStmt)
|
||||
m.s[cfsProcs].add(extract(generatedProc))
|
||||
generatedProc.add(p.s(cpsLocals))
|
||||
if optProfiler in prc.options:
|
||||
# invoke at proc entry for recursion:
|
||||
appcg(p, cpsInit, "\t#nimProfile();$n", [])
|
||||
# this pair of {} is required for C++ (C++ is weird with its
|
||||
# control flow integrity checks):
|
||||
if beforeRetNeeded in p.flags: generatedProc.add("{")
|
||||
generatedProc.add(p.s(cpsInit))
|
||||
generatedProc.add(p.s(cpsStmts))
|
||||
if beforeRetNeeded in p.flags: generatedProc.add("\t}BeforeRet_: ;\n")
|
||||
if optStackTrace in prc.options: generatedProc.add(deinitFrame(p))
|
||||
generatedProc.add(returnStmt)
|
||||
generatedProc.add("}\n")
|
||||
m.s[cfsProcs].add(generatedProc)
|
||||
if isReloadable(m, prc):
|
||||
m.s[cfsDynLibInit].add('\t')
|
||||
m.s[cfsDynLibInit].addAssignmentWithValue(prc.loc.snippet):
|
||||
m.s[cfsDynLibInit].addCast(getProcTypeCast(m, prc)):
|
||||
m.s[cfsDynLibInit].addCall("hcrRegisterProc",
|
||||
getModuleDllPath(m, prc),
|
||||
'"' & prc.loc.snippet & '"',
|
||||
cCast("void*", prc.loc.snippet & "_actual"))
|
||||
m.s[cfsDynLibInit].addf("\t$1 = ($3) hcrRegisterProc($4, \"$1\", (void*)$2);$n",
|
||||
[prc.loc.snippet, prc.loc.snippet & "_actual", getProcTypeCast(m, prc), getModuleDllPath(m, prc)])
|
||||
|
||||
proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
|
||||
result = (sfCompileToCpp in m.module.flags and
|
||||
@@ -1353,39 +1311,26 @@ proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
if lfDynamicLib in sym.loc.flags:
|
||||
if sym.itemId.module != m.module.position and
|
||||
not containsOrIncl(m.declaredThings, sym.id):
|
||||
let vis = if isReloadable(m, sym): StaticProc else: Extern
|
||||
let name = mangleDynLibProc(sym)
|
||||
let t = getTypeDesc(m, sym.loc.t)
|
||||
m.s[cfsVars].addDeclWithVisibility(vis):
|
||||
m.s[cfsVars].addVar(kind = Local,
|
||||
name = name,
|
||||
typ = t)
|
||||
m.s[cfsVars].add(ropecg(m, "$1 $2 $3;$n",
|
||||
[(if isReloadable(m, sym): "static" else: "extern"),
|
||||
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)]))
|
||||
if isReloadable(m, sym):
|
||||
m.s[cfsDynLibInit].add('\t')
|
||||
m.s[cfsDynLibInit].addAssignmentWithValue(name):
|
||||
m.s[cfsDynLibInit].addCast(t):
|
||||
m.s[cfsDynLibInit].addCall("hcrGetProc",
|
||||
getModuleDllPath(m, sym),
|
||||
'"' & name & '"')
|
||||
m.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n",
|
||||
[mangleDynLibProc(sym), getTypeDesc(m, sym.loc.t), getModuleDllPath(m, sym)])
|
||||
elif not containsOrIncl(m.declaredProtos, sym.id):
|
||||
let asPtr = isReloadable(m, sym)
|
||||
var header = newBuilder("")
|
||||
var visibility: DeclVisibility = None
|
||||
genProcHeader(m, sym, header, visibility, asPtr = asPtr, addAttributes = true)
|
||||
if asPtr:
|
||||
m.s[cfsProcHeaders].addDeclWithVisibility(visibility):
|
||||
# genProcHeader would give variable declaration, add it directly
|
||||
m.s[cfsProcHeaders].add(extract(header))
|
||||
else:
|
||||
let extraVis =
|
||||
if sym.typ.callConv != ccInline and requiresExternC(m, sym):
|
||||
ExternC
|
||||
else:
|
||||
None
|
||||
m.s[cfsProcHeaders].addDeclWithVisibility(extraVis):
|
||||
m.s[cfsProcHeaders].addDeclWithVisibility(visibility):
|
||||
m.s[cfsProcHeaders].add(extract(header))
|
||||
m.s[cfsProcHeaders].finishProcHeaderAsProto()
|
||||
var header = newRopeAppender()
|
||||
genProcHeader(m, sym, header, asPtr)
|
||||
if not asPtr:
|
||||
if isNoReturn(m, sym) and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
|
||||
header = "__declspec(noreturn) " & header
|
||||
if sym.typ.callConv != ccInline and requiresExternC(m, sym):
|
||||
header = "extern \"C\" " & header
|
||||
if sfPure in sym.flags and hasAttribute in CC[m.config.cCompiler].props:
|
||||
header.add(" __attribute__((naked))")
|
||||
if isNoReturn(m, sym) and hasAttribute in CC[m.config.cCompiler].props:
|
||||
header.add(" __attribute__((noreturn))")
|
||||
m.s[cfsProcHeaders].add(ropecg(m, "$1;$N", [header]))
|
||||
|
||||
# TODO: figure out how to rename this - it DOES generate a forward declaration
|
||||
proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
@@ -1511,7 +1456,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
|
||||
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.snippet,
|
||||
getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(m, sym)])
|
||||
|
||||
proc addNimDefines(result: var Builder; conf: ConfigRef) {.inline.} =
|
||||
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
|
||||
result.addf("#define NIM_INTBITS $1\L", [
|
||||
platform.CPU[conf.target.targetCPU].intSize.rope])
|
||||
if conf.cppCustomNamespace.len > 0:
|
||||
@@ -1535,10 +1480,9 @@ proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
|
||||
rope(getCompileCFileCmd(conf, cfile))]
|
||||
|
||||
proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
|
||||
var res = newBuilder(getCopyright(conf, cfile))
|
||||
if conf.hcrOn: res.add("#define NIM_HOT_CODE_RELOADING\L")
|
||||
addNimDefines(res, conf)
|
||||
result = extract(res)
|
||||
result = getCopyright(conf, cfile)
|
||||
if conf.hcrOn: result.add("#define NIM_HOT_CODE_RELOADING\L")
|
||||
addNimDefines(result, conf)
|
||||
|
||||
proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope =
|
||||
## Returns a mangled module name.
|
||||
@@ -1581,9 +1525,8 @@ proc genMainProc(m: BModule) =
|
||||
assert prc != nil
|
||||
let n = newStrNode(nkStrLit, prc.annex.path.strVal)
|
||||
n.info = prc.annex.path.info
|
||||
var strLitBuilder = newBuilder("")
|
||||
genStringLiteral(m, n, strLitBuilder)
|
||||
let strLit = extract(strLitBuilder)
|
||||
var strLit = newRopeAppender()
|
||||
genStringLiteral(m, n, strLit)
|
||||
appcg(m, result, "\tif (!($1 = #nimLoadLibrary($2)))$N" &
|
||||
"\t\t#nimLoadLibraryError($2);$N",
|
||||
[handle, strLit])
|
||||
@@ -1795,10 +1738,10 @@ proc registerInitProcs*(g: BModuleList; m: PSym; flags: set[ModuleBackendFlag])
|
||||
proc whichInitProcs*(m: BModule): set[ModuleBackendFlag] =
|
||||
# called from IC.
|
||||
result = {}
|
||||
if m.hcrOn or m.preInitProc.s(cpsInit).buf.len > 0 or m.preInitProc.s(cpsStmts).buf.len > 0:
|
||||
if m.hcrOn or m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0:
|
||||
result.incl HasModuleInitProc
|
||||
for i in cfsTypeInit1..cfsDynLibInit:
|
||||
if m.s[i].buf.len != 0:
|
||||
if m.s[i].len != 0:
|
||||
result.incl HasDatInitProc
|
||||
break
|
||||
|
||||
@@ -1851,7 +1794,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
m.s[cfsInitProc].add(hcrModuleMeta)
|
||||
return
|
||||
|
||||
if m.s[cfsDatInitProc].buf.len > 0:
|
||||
if m.s[cfsDatInitProc].len > 0:
|
||||
g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit])
|
||||
g.mainDatInit.addf("\t$1();$N", [datInit])
|
||||
|
||||
@@ -1863,7 +1806,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
|
||||
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
|
||||
|
||||
if m.s[cfsInitProc].buf.len > 0:
|
||||
if m.s[cfsInitProc].len > 0:
|
||||
g.mainModProcs.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init])
|
||||
let initCall = "\t$1();$N" % [init]
|
||||
if sfMainModule in m.module.flags:
|
||||
@@ -1880,22 +1823,22 @@ proc genDatInitCode(m: BModule) =
|
||||
|
||||
var moduleDatInitRequired = m.hcrOn
|
||||
|
||||
var prc = newBuilder("$1 N_NIMCALL(void, $2)(void) {$N" %
|
||||
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), getDatInitName(m)])
|
||||
var prc = "$1 N_NIMCALL(void, $2)(void) {$N" %
|
||||
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), getDatInitName(m)]
|
||||
|
||||
# we don't want to break into such init code - could happen if a line
|
||||
# directive from a function written by the user spills after itself
|
||||
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
|
||||
|
||||
for i in cfsTypeInit1..cfsDynLibInit:
|
||||
if m.s[i].buf.len != 0:
|
||||
if m.s[i].len != 0:
|
||||
moduleDatInitRequired = true
|
||||
prc.add(extract(m.s[i]))
|
||||
prc.add(m.s[i])
|
||||
|
||||
prc.addf("}$N$N", [])
|
||||
|
||||
if moduleDatInitRequired:
|
||||
m.s[cfsDatInitProc].add(extract(prc))
|
||||
m.s[cfsDatInitProc].add(prc)
|
||||
#rememberFlag(m.g.graph, m.module, HasDatInitProc)
|
||||
|
||||
# Very similar to the contents of symInDynamicLib - basically only the
|
||||
@@ -1922,8 +1865,8 @@ proc genInitCode(m: BModule) =
|
||||
## into other modules, only simple rope manipulations are allowed
|
||||
var moduleInitRequired = m.hcrOn
|
||||
let initname = getInitName(m)
|
||||
var prc = newBuilder("$1 N_NIMCALL(void, $2)(void) {$N" %
|
||||
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname])
|
||||
var prc = "$1 N_NIMCALL(void, $2)(void) {$N" %
|
||||
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname]
|
||||
# we don't want to break into such init code - could happen if a line
|
||||
# directive from a function written by the user spills after itself
|
||||
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
|
||||
@@ -1946,13 +1889,13 @@ proc genInitCode(m: BModule) =
|
||||
[getModuleDllPath(m, m.module)])
|
||||
|
||||
template writeSection(thing: untyped, section: TCProcSection, addHcrGuards = false) =
|
||||
if m.thing.s(section).buf.len > 0:
|
||||
if m.thing.s(section).len > 0:
|
||||
moduleInitRequired = true
|
||||
if addHcrGuards: prc.add("\tif (nim_hcr_do_init_) {\n\n")
|
||||
prc.add(extract(m.thing.s(section)))
|
||||
prc.add(m.thing.s(section))
|
||||
if addHcrGuards: prc.add("\n\t} // nim_hcr_do_init_\n")
|
||||
|
||||
if m.preInitProc.s(cpsInit).buf.len > 0 or m.preInitProc.s(cpsStmts).buf.len > 0:
|
||||
if m.preInitProc.s(cpsInit).len > 0 or m.preInitProc.s(cpsStmts).len > 0:
|
||||
# Give this small function its own scope
|
||||
prc.addf("{$N", [])
|
||||
# Keep a bogus frame in case the code needs one
|
||||
@@ -1972,7 +1915,7 @@ proc genInitCode(m: BModule) =
|
||||
prc.addf("{$N", [])
|
||||
writeSection(initProc, cpsLocals)
|
||||
|
||||
if m.initProc.s(cpsInit).buf.len > 0 or m.initProc.s(cpsStmts).buf.len > 0:
|
||||
if m.initProc.s(cpsInit).len > 0 or m.initProc.s(cpsStmts).len > 0:
|
||||
moduleInitRequired = true
|
||||
if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
|
||||
# BUT: the generated init code might depend on a current frame, so
|
||||
@@ -2026,14 +1969,14 @@ proc genInitCode(m: BModule) =
|
||||
prc.add(ex)
|
||||
|
||||
if moduleInitRequired or sfMainModule in m.module.flags:
|
||||
m.s[cfsInitProc].add(extract(prc))
|
||||
m.s[cfsInitProc].add(prc)
|
||||
#rememberFlag(m.g.graph, m.module, HasModuleInitProc)
|
||||
|
||||
genDatInitCode(m)
|
||||
|
||||
if m.hcrOn:
|
||||
m.s[cfsInitProc].addf("N_LIB_EXPORT N_NIMCALL(void, HcrCreateTypeInfos)(void) {$N", [])
|
||||
m.s[cfsInitProc].add(extract(m.hcrCreateTypeInfosProc))
|
||||
m.s[cfsInitProc].add(m.hcrCreateTypeInfosProc)
|
||||
m.s[cfsInitProc].addf("}$N$N", [])
|
||||
|
||||
registerModuleToMain(m.g, m)
|
||||
@@ -2075,32 +2018,31 @@ proc postprocessCode(conf: ConfigRef, r: var Rope) =
|
||||
proc genModule(m: BModule, cfile: Cfile): Rope =
|
||||
var moduleIsEmpty = true
|
||||
|
||||
var res = newBuilder(getFileHeader(m.config, cfile))
|
||||
result = getFileHeader(m.config, cfile)
|
||||
|
||||
generateThreadLocalStorage(m)
|
||||
generateHeaders(m)
|
||||
res.add(extract(m.s[cfsHeaders]))
|
||||
result.add(m.s[cfsHeaders])
|
||||
if m.config.cppCustomNamespace.len > 0:
|
||||
openNamespaceNim(m.config.cppCustomNamespace, res)
|
||||
if m.s[cfsFrameDefines].buf.len > 0:
|
||||
res.add(extract(m.s[cfsFrameDefines]))
|
||||
openNamespaceNim(m.config.cppCustomNamespace, result)
|
||||
if m.s[cfsFrameDefines].len > 0:
|
||||
result.add(m.s[cfsFrameDefines])
|
||||
|
||||
for i in cfsForwardTypes..cfsProcs:
|
||||
if m.s[i].buf.len > 0:
|
||||
if m.s[i].len > 0:
|
||||
moduleIsEmpty = false
|
||||
res.add(extract(m.s[i]))
|
||||
result.add(m.s[i])
|
||||
|
||||
if m.s[cfsInitProc].buf.len > 0:
|
||||
if m.s[cfsInitProc].len > 0:
|
||||
moduleIsEmpty = false
|
||||
res.add(extract(m.s[cfsInitProc]))
|
||||
if m.s[cfsDatInitProc].buf.len > 0 or m.hcrOn:
|
||||
result.add(m.s[cfsInitProc])
|
||||
if m.s[cfsDatInitProc].len > 0 or m.hcrOn:
|
||||
moduleIsEmpty = false
|
||||
res.add(extract(m.s[cfsDatInitProc]))
|
||||
result.add(m.s[cfsDatInitProc])
|
||||
|
||||
if m.config.cppCustomNamespace.len > 0:
|
||||
closeNamespaceNim(res)
|
||||
closeNamespaceNim(result)
|
||||
|
||||
result = extract(res)
|
||||
if optLineDir in m.config.options:
|
||||
var srcFileDefs = ""
|
||||
for fi in 0..m.config.m.fileInfos.high:
|
||||
@@ -2131,12 +2073,11 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
|
||||
result.typeInfoMarker = initTable[SigHash, Rope]()
|
||||
result.sigConflicts = initCountTable[SigHash]()
|
||||
result.initProc = newProc(nil, result)
|
||||
for i in low(result.s)..high(result.s): result.s[i] = newBuilder("")
|
||||
for i in low(result.s)..high(result.s): result.s[i] = newRopeAppender()
|
||||
result.initProc.options = initProcOptions(result)
|
||||
result.preInitProc = newProc(nil, result)
|
||||
result.preInitProc.flags.incl nimErrorFlagDisabled
|
||||
result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated
|
||||
result.hcrCreateTypeInfosProc = newBuilder("")
|
||||
result.dataCache = initNodeTable()
|
||||
result.typeStack = @[]
|
||||
result.typeNodesName = getTempName(result)
|
||||
@@ -2146,6 +2087,9 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
|
||||
if sfSystemModule in module.flags:
|
||||
incl result.flags, preventStackTrace
|
||||
excl(result.preInitProc.options, optStackTrace)
|
||||
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCfilePath(g.config, filename), "ndi")
|
||||
else: AbsoluteFile""
|
||||
open(result.ndi, ndiName, g.config)
|
||||
|
||||
proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
|
||||
result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex))
|
||||
@@ -2175,7 +2119,7 @@ proc setupCgen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassCont
|
||||
incl g.generatedHeader.flags, isHeaderFile
|
||||
|
||||
proc writeHeader(m: BModule) =
|
||||
var result = newBuilder(headerTop())
|
||||
var result = headerTop()
|
||||
var guard = "__$1__" % [m.filename.splitFile.name.rope]
|
||||
result.addf("#ifndef $1$n#define $1$n", [guard])
|
||||
addNimDefines(result, m.config)
|
||||
@@ -2183,17 +2127,17 @@ proc writeHeader(m: BModule) =
|
||||
|
||||
generateThreadLocalStorage(m)
|
||||
for i in cfsHeaders..cfsProcs:
|
||||
result.add(extract(m.s[i]))
|
||||
result.add(m.s[i])
|
||||
if m.config.cppCustomNamespace.len > 0 and i == cfsHeaders:
|
||||
openNamespaceNim(m.config.cppCustomNamespace, result)
|
||||
result.add(extract(m.s[cfsInitProc]))
|
||||
result.add(m.s[cfsInitProc])
|
||||
|
||||
if optGenDynLib in m.config.globalOptions:
|
||||
result.add("N_LIB_IMPORT ")
|
||||
result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix])
|
||||
if m.config.cppCustomNamespace.len > 0: closeNamespaceNim(result)
|
||||
result.addf("#endif /* $1 */$n", [guard])
|
||||
if not writeRope(extract(result), m.filename):
|
||||
if not writeRope(result, m.filename):
|
||||
rawMessage(m.config, errCannotOpenFile, m.filename.string)
|
||||
|
||||
proc getCFile(m: BModule): AbsoluteFile =
|
||||
@@ -2275,6 +2219,7 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
|
||||
# it would generate multiple 'main' procs, for instance.
|
||||
|
||||
proc writeModule(m: BModule, pending: bool) =
|
||||
template onExit() = close(m.ndi, m.config)
|
||||
let cfile = getCFile(m)
|
||||
if moduleHasChanged(m.g.graph, m.module):
|
||||
genInitCode(m)
|
||||
@@ -2292,10 +2237,12 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
when hasTinyCBackend:
|
||||
if m.config.cmd == cmdTcc:
|
||||
tccgen.compileCCode($code, m.config)
|
||||
onExit()
|
||||
return
|
||||
|
||||
if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(m.config, cf)
|
||||
onExit()
|
||||
|
||||
proc updateCachedModule(m: BModule) =
|
||||
let cfile = getCFile(m)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
ast, ropes, options,
|
||||
lineinfos, pathutils, modulegraphs, cbuilderbase
|
||||
ndi, lineinfos, pathutils, modulegraphs
|
||||
|
||||
import std/[intsets, tables, sets]
|
||||
|
||||
@@ -43,12 +43,12 @@ type
|
||||
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
|
||||
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
|
||||
ctCString
|
||||
TCFileSections* = array[TCFileSection, Builder] # represents a generated C file
|
||||
TCFileSections* = array[TCFileSection, Rope] # represents a generated C file
|
||||
TCProcSection* = enum # the sections a generated C proc consists of
|
||||
cpsLocals, # section of local variables for C proc
|
||||
cpsInit, # section for init of variables for C proc
|
||||
cpsStmts # section of local statements for C proc
|
||||
TCProcSections* = array[TCProcSection, Builder] # represents a generated C proc
|
||||
TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
|
||||
BModule* = ref TCGen
|
||||
BProc* = ref TCProc
|
||||
TBlock* = object
|
||||
@@ -161,7 +161,7 @@ type
|
||||
typeInfoMarkerV2*: TypeCache
|
||||
initProc*: BProc # code for init procedure
|
||||
preInitProc*: BProc # code executed before the init proc
|
||||
hcrCreateTypeInfosProc*: Builder # type info globals are in here when HCR=on
|
||||
hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on
|
||||
inHcrInitGuard*: bool # We are currently within a HCR reloading guard.
|
||||
typeStack*: TTypeSeq # used for type generation
|
||||
dataCache*: TNodeTable
|
||||
@@ -172,6 +172,7 @@ type
|
||||
# OpenGL wrapper
|
||||
sigConflicts*: CountTable[SigHash]
|
||||
g*: BModuleList
|
||||
ndi*: NdiFile
|
||||
|
||||
template config*(m: BModule): ConfigRef = m.g.config
|
||||
template config*(p: BProc): ConfigRef = p.module.g.config
|
||||
@@ -181,18 +182,18 @@ proc includeHeader*(this: BModule; header: string) =
|
||||
if not this.headerFiles.contains header:
|
||||
this.headerFiles.add header
|
||||
|
||||
proc s*(p: BProc, s: TCProcSection): var Builder {.inline.} =
|
||||
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
|
||||
# section in the current block
|
||||
result = p.blocks[^1].sections[s]
|
||||
|
||||
proc procSec*(p: BProc, s: TCProcSection): var Builder {.inline.} =
|
||||
proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
|
||||
# top level proc sections
|
||||
result = p.blocks[0].sections[s]
|
||||
|
||||
proc initBlock*(): TBlock =
|
||||
result = TBlock()
|
||||
for i in low(result.sections)..high(result.sections):
|
||||
result.sections[i] = newBuilder("")
|
||||
result.sections[i] = newRopeAppender()
|
||||
|
||||
proc newProc*(prc: PSym, module: BModule): BProc =
|
||||
result = BProc(
|
||||
|
||||
@@ -1585,8 +1585,15 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else: internalError(p.config, n[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
|
||||
of nkObjDownConv:
|
||||
gen(p, n[0], r)
|
||||
of nkHiddenDeref, nkDerefExpr:
|
||||
of nkHiddenDeref:
|
||||
gen(p, n[0], r)
|
||||
of nkDerefExpr:
|
||||
var x = n[0]
|
||||
if n.kind == nkHiddenAddr:
|
||||
x = n[0][0]
|
||||
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||
x.typ() = n.typ
|
||||
gen(p, x, r)
|
||||
of nkHiddenAddr:
|
||||
gen(p, n[0], r)
|
||||
of nkConv:
|
||||
|
||||
52
compiler/ndi.nim
Normal file
52
compiler/ndi.nim
Normal file
@@ -0,0 +1,52 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2017 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements the generation of ``.ndi`` files for better debugging
|
||||
## support of Nim code. "ndi" stands for "Nim debug info".
|
||||
|
||||
import ast, msgs, ropes, options, pathutils
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
type
|
||||
NdiFile* = object
|
||||
enabled: bool
|
||||
f: File
|
||||
buf: string
|
||||
filename: AbsoluteFile
|
||||
syms: seq[PSym]
|
||||
|
||||
proc doWrite(f: var NdiFile; s: PSym; conf: ConfigRef) =
|
||||
f.buf.setLen 0
|
||||
f.buf.addInt s.info.line.int
|
||||
f.buf.add "\t"
|
||||
f.buf.addInt s.info.col.int
|
||||
f.f.write(s.name.s, "\t")
|
||||
f.f.writeRope(s.loc.snippet)
|
||||
f.f.writeLine("\t", toFullPath(conf, s.info), "\t", f.buf)
|
||||
|
||||
template writeMangledName*(f: NdiFile; s: PSym; conf: ConfigRef) =
|
||||
if f.enabled: f.syms.add s
|
||||
|
||||
proc open*(f: var NdiFile; filename: AbsoluteFile; conf: ConfigRef) =
|
||||
f.enabled = not filename.isEmpty
|
||||
if f.enabled:
|
||||
f.filename = filename
|
||||
f.buf = newStringOfCap(20)
|
||||
|
||||
proc close*(f: var NdiFile, conf: ConfigRef) =
|
||||
if f.enabled:
|
||||
f.f = open(f.filename.string, fmWrite, 8000)
|
||||
doAssert f.f != nil, f.filename.string
|
||||
for s in f.syms:
|
||||
doWrite(f, s, conf)
|
||||
close(f.f)
|
||||
f.syms.reset
|
||||
f.filename.reset
|
||||
@@ -229,7 +229,6 @@ type
|
||||
# alternative to above:
|
||||
genericsOpenSym
|
||||
vtables
|
||||
typeBoundOps
|
||||
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
|
||||
@@ -42,7 +42,10 @@ proc makePass*(open: TPassOpen = nil,
|
||||
process: TPassProcess = nil,
|
||||
close: TPassClose = nil,
|
||||
isFrontend = false): TPass =
|
||||
result = (open, process, close, isFrontend)
|
||||
result.open = open
|
||||
result.close = close
|
||||
result.process = process
|
||||
result.isFrontend = isFrontend
|
||||
|
||||
const
|
||||
maxPasses = 10
|
||||
@@ -97,8 +100,8 @@ proc processModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator;
|
||||
stream: PLLStream): bool {.discardable.} =
|
||||
if graph.stopCompile(): return true
|
||||
var
|
||||
p: Parser = default(Parser)
|
||||
a: TPassContextArray = default(TPassContextArray)
|
||||
p: Parser
|
||||
a: TPassContextArray
|
||||
s: PLLStream
|
||||
fileIdx = module.fileIdx
|
||||
prepareConfigNotes(graph, module)
|
||||
|
||||
@@ -733,7 +733,6 @@ proc preparePContext*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PCo
|
||||
result.semInferredLambda = semInferredLambda
|
||||
result.semGenerateInstance = generateInstance
|
||||
result.instantiateOnlyProcType = instantiateOnlyProcType
|
||||
result.fitDefaultNode = fitDefaultNode
|
||||
result.semTypeNode = semTypeNode
|
||||
result.instTypeBoundOp = sigmatch.instTypeBoundOp
|
||||
result.hasUnresolvedArgs = hasUnresolvedArgs
|
||||
|
||||
@@ -69,39 +69,6 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode,
|
||||
result[0].scope, diagnostics)
|
||||
best.state = csNoMatch
|
||||
|
||||
proc isAttachableRoutineTo(prc: PSym, arg: PType): bool =
|
||||
result = false
|
||||
if arg.owner != prc.owner: return false
|
||||
for i in 1 ..< prc.typ.len:
|
||||
if prc.typ.n[i].kind == nkSym and prc.typ.n[i].sym.ast != nil:
|
||||
# has default value, parameter is not considered in type attachment
|
||||
continue
|
||||
let t = nominalRoot(prc.typ[i])
|
||||
if t != nil and t.itemId == arg.itemId:
|
||||
# parameter `i` is a nominal type in this module
|
||||
# attachable if the nominal root `t` has the same id as `arg`
|
||||
return true
|
||||
|
||||
proc addTypeBoundSymbols(graph: ModuleGraph, arg: PType, name: PIdent,
|
||||
filter: TSymKinds, marker: var IntSet,
|
||||
syms: var seq[tuple[s: PSym, scope: int]]) =
|
||||
# add type bound ops for `name` based on the argument type `arg`
|
||||
if arg != nil:
|
||||
# argument must be typed first, meaning arguments always
|
||||
# matching `untyped` are ignored
|
||||
let t = nominalRoot(arg)
|
||||
if t != nil and t.owner.kind == skModule:
|
||||
# search module for routines attachable to `t`
|
||||
let module = t.owner
|
||||
var iter = default(ModuleIter)
|
||||
var s = initModuleIter(iter, graph, module, name)
|
||||
while s != nil:
|
||||
if s.kind in filter and s.isAttachableRoutineTo(t) and
|
||||
not containsOrIncl(marker, s.id):
|
||||
# least priority scope, less than explicit imports:
|
||||
syms.add((s, -2))
|
||||
s = nextModuleIter(iter, graph)
|
||||
|
||||
proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
n, orig: PNode,
|
||||
initialBinding: PNode,
|
||||
@@ -121,23 +88,10 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
best, alt, o, diagnosticsFlag)
|
||||
if len(syms) == 0:
|
||||
return
|
||||
let allowTypeBoundOps = typeBoundOps in c.features and
|
||||
# qualified or bound symbols cannot refer to type bound ops
|
||||
headSymbol.kind in {nkIdent, nkAccQuoted, nkOpenSymChoice, nkOpenSym}
|
||||
var symMarker = initIntSet()
|
||||
for s in syms:
|
||||
symMarker.incl(s.s.id)
|
||||
# current overload being considered
|
||||
var sym = syms[0].s
|
||||
let name = sym.name
|
||||
var scope = syms[0].scope
|
||||
|
||||
if allowTypeBoundOps:
|
||||
for a in 1 ..< n.len:
|
||||
# for every already typed argument, add type bound ops
|
||||
let arg = n[a]
|
||||
addTypeBoundSymbols(c.graph, arg.typ, name, filter, symMarker, syms)
|
||||
|
||||
# starts at 1 because 0 is already done with setup, only needs checking
|
||||
var nextSymIndex = 1
|
||||
var z: TCandidate # current candidate
|
||||
@@ -152,14 +106,6 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
# may introduce new symbols with caveats described in recalc branch
|
||||
matches(c, n, orig, z)
|
||||
|
||||
if allowTypeBoundOps:
|
||||
# this match may have given some arguments new types,
|
||||
# in which case add their type bound ops as well
|
||||
# type bound ops of arguments always matching `untyped` are not considered
|
||||
for x in z.newlyTypedOperands:
|
||||
let arg = n[x]
|
||||
addTypeBoundSymbols(c.graph, arg.typ, name, filter, symMarker, syms)
|
||||
|
||||
if z.state == csMatch:
|
||||
# little hack so that iterators are preferred over everything else:
|
||||
if sym.kind == skIterator:
|
||||
@@ -190,14 +136,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
# before any further candidate init and compare. SLOW, but rare case.
|
||||
syms = initCandidateSymbols(c, headSymbol, initialBinding, filter,
|
||||
best, alt, o, diagnosticsFlag)
|
||||
symMarker = initIntSet()
|
||||
for s in syms:
|
||||
symMarker.incl(s.s.id)
|
||||
if allowTypeBoundOps:
|
||||
for a in 1 ..< n.len:
|
||||
# for every already typed argument, add type bound ops
|
||||
let arg = n[a]
|
||||
addTypeBoundSymbols(c.graph, arg.typ, name, filter, symMarker, syms)
|
||||
|
||||
# reset counter because syms may be in a new order
|
||||
symCount = c.currentScope.symbols.counter
|
||||
nextSymIndex = 0
|
||||
|
||||
@@ -142,7 +142,6 @@ type
|
||||
instantiateOnlyProcType*: proc (c: PContext, pt: LayeredIdTable,
|
||||
prc: PSym, info: TLineInfo): PType
|
||||
# used by sigmatch for explicit generic instantiations
|
||||
fitDefaultNode*: proc (c: PContext, n: var PNode, expectedType: PType)
|
||||
includedFiles*: IntSet # used to detect recursive include files
|
||||
pureEnumFields*: TStrTable # pure enum fields that can be used unambiguously
|
||||
userPragmas*: TStrTable
|
||||
|
||||
@@ -1006,9 +1006,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||
n.typ.flags.incl tfUnresolved
|
||||
|
||||
# optimization pass: not necessary for correctness of the semantic pass
|
||||
if (callee.kind == skConst or
|
||||
if callee.kind == skConst or
|
||||
{sfNoSideEffect, sfCompileTime} * callee.flags != {} and
|
||||
{sfForward, sfImportc} * callee.flags == {}) and n.typ != nil:
|
||||
{sfForward, sfImportc} * callee.flags == {} and n.typ != nil:
|
||||
|
||||
if callee.kind != skConst and
|
||||
sfCompileTime notin callee.flags and
|
||||
@@ -1492,8 +1492,6 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess
|
||||
markUsed(c, n.info, s)
|
||||
onUse(n.info, s)
|
||||
if s.typ == nil:
|
||||
return localErrorNode(c, n, "symbol '$1' has no type" % [s.name.s])
|
||||
if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
|
||||
return s.typ.n
|
||||
result = newSymNode(s, n.info)
|
||||
|
||||
@@ -18,15 +18,6 @@ type
|
||||
replaceByFieldName: bool
|
||||
c: PContext
|
||||
|
||||
proc wrapNewScope(c: PContext, n: PNode): PNode {.inline.} =
|
||||
# use `if true` to not interfere with `break`
|
||||
# just opening scope via `openScope(c)` isn't enough,
|
||||
# a scope has to be opened in the codegen as well for reused
|
||||
# template instantiations
|
||||
let trueLit = newIntLit(c.graph, n.info, 1)
|
||||
trueLit.typ() = getSysType(c.graph, n.info, tyBool)
|
||||
result = newTreeI(nkIfStmt, n.info, newTreeI(nkElifBranch, n.info, trueLit, n))
|
||||
|
||||
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
if c.field != nil and isEmptyType(c.field.typ):
|
||||
result = newNode(nkEmpty)
|
||||
@@ -81,9 +72,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
|
||||
)
|
||||
openScope(c.c)
|
||||
inc c.c.inUnrolledContext
|
||||
var body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
|
||||
# new scope for each field that codegen should know about:
|
||||
body = wrapNewScope(c.c, body)
|
||||
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
|
||||
father.add(semStmt(c.c, body, {}))
|
||||
dec c.c.inUnrolledContext
|
||||
closeScope(c.c)
|
||||
@@ -159,8 +148,6 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
replaceByFieldName: m == mFieldPairs
|
||||
)
|
||||
var body = instFieldLoopBody(fc, loopBody, n)
|
||||
# new scope for each field that codegen should know about:
|
||||
body = wrapNewScope(c, body)
|
||||
inc c.inUnrolledContext
|
||||
stmts.add(semStmt(c, body, {}))
|
||||
dec c.inUnrolledContext
|
||||
|
||||
@@ -536,33 +536,31 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
|
||||
else:
|
||||
if fin.instantiatedFrom != nil and fin.instantiatedFrom != fin.owner: #undo move
|
||||
setOwner(fin, fin.instantiatedFrom)
|
||||
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info)
|
||||
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen))
|
||||
selfSymNode.typ() = fin.typ.firstParamType
|
||||
wrapperSym.flags.incl sfUsed
|
||||
|
||||
if fin.typ[1].skipTypes(abstractInst).kind != tyRef:
|
||||
bindTypeHook(c, fin, n, attachedDestructor)
|
||||
else:
|
||||
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info)
|
||||
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen))
|
||||
selfSymNode.typ() = fin.typ.firstParamType
|
||||
wrapperSym.flags.incl sfUsed
|
||||
let wrapper = c.semExpr(c, newProcNode(nkProcDef, fin.info, body = newTree(nkCall, newSymNode(fin), selfSymNode),
|
||||
params = nkFormalParams.newTree(c.graph.emptyNode,
|
||||
newTree(nkIdentDefs, selfSymNode, newNodeIT(nkType,
|
||||
fin.ast[paramsPos][1][1].info, fin.typ.firstParamType), c.graph.emptyNode)
|
||||
),
|
||||
name = newSymNode(wrapperSym), pattern = fin.ast[patternPos],
|
||||
genericParams = fin.ast[genericParamsPos], pragmas = fin.ast[pragmasPos], exceptions = fin.ast[miscPos]), {})
|
||||
|
||||
let wrapper = c.semExpr(c, newProcNode(nkProcDef, fin.info, body = newTree(nkCall, newSymNode(fin), selfSymNode),
|
||||
params = nkFormalParams.newTree(c.graph.emptyNode,
|
||||
newTree(nkIdentDefs, selfSymNode, newNodeIT(nkType,
|
||||
fin.ast[paramsPos][1][1].info, fin.typ.firstParamType), c.graph.emptyNode)
|
||||
),
|
||||
name = newSymNode(wrapperSym), pattern = fin.ast[patternPos],
|
||||
genericParams = fin.ast[genericParamsPos], pragmas = fin.ast[pragmasPos], exceptions = fin.ast[miscPos]), {})
|
||||
|
||||
var transFormedSym = turnFinalizerIntoDestructor(c, wrapperSym, wrapper.info)
|
||||
setOwner(transFormedSym, fin)
|
||||
if c.config.backend == backendCpp or sfCompileToCpp in c.module.flags:
|
||||
let origParamType = transFormedSym.ast[bodyPos][1].typ
|
||||
let selfSymbolType = makePtrType(c, origParamType.skipTypes(abstractPtrs))
|
||||
let selfPtr = newNodeI(nkHiddenAddr, transFormedSym.ast[bodyPos][1].info)
|
||||
selfPtr.add transFormedSym.ast[bodyPos][1]
|
||||
selfPtr.typ() = selfSymbolType
|
||||
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
|
||||
bindTypeHook(c, transFormedSym, n, attachedDestructor)
|
||||
var transFormedSym = turnFinalizerIntoDestructor(c, wrapperSym, wrapper.info)
|
||||
setOwner(transFormedSym, fin)
|
||||
if c.config.backend == backendCpp or sfCompileToCpp in c.module.flags:
|
||||
let origParamType = transFormedSym.ast[bodyPos][1].typ
|
||||
let selfSymbolType = makePtrType(c, origParamType.skipTypes(abstractPtrs))
|
||||
let selfPtr = newNodeI(nkHiddenAddr, transFormedSym.ast[bodyPos][1].info)
|
||||
selfPtr.add transFormedSym.ast[bodyPos][1]
|
||||
selfPtr.typ() = selfSymbolType
|
||||
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
|
||||
# TODO: suppress var destructor warnings; if newFinalizer is not
|
||||
# TODO: deprecated, try to implement plain T destructor
|
||||
bindTypeHook(c, transFormedSym, n, attachedDestructor, suppressVarDestructorWarning = true)
|
||||
result = addDefaultFieldForNew(c, n)
|
||||
|
||||
proc semPrivateAccess(c: PContext, n: PNode): PNode =
|
||||
|
||||
@@ -2092,7 +2092,7 @@ proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
|
||||
incl(s.flags, sfUsed)
|
||||
incl(s.flags, sfOverridden)
|
||||
|
||||
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
|
||||
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp; suppressVarDestructorWarning = false) =
|
||||
let t = s.typ
|
||||
var noError = false
|
||||
let cond = case op
|
||||
@@ -2116,7 +2116,7 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
|
||||
elif obj.kind == tyGenericInvocation: obj = obj.genericHead
|
||||
else: break
|
||||
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
|
||||
if op == attachedDestructor and t.firstParamType.kind == tyVar and
|
||||
if (not suppressVarDestructorWarning) and op == attachedDestructor and t.firstParamType.kind == tyVar and
|
||||
c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
|
||||
message(c.config, n.info, warnDeprecated, "A custom '=destroy' hook which takes a 'var T' parameter is deprecated; it should take a 'T' parameter")
|
||||
obj = canonType(c, obj)
|
||||
@@ -2622,8 +2622,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
proc determineType(c: PContext, s: PSym) =
|
||||
if s.typ != nil: return
|
||||
#if s.magic != mNone: return
|
||||
if s.ast.isNil and sfForward notin s.flags:
|
||||
globalError(c.config, s.info, errIllFormedAstX, "symbol of kind " & $s.kind & " has no implementation")
|
||||
#if s.ast.isNil: return
|
||||
discard semProcAux(c, s.ast, s.kind, {})
|
||||
|
||||
proc semIterator(c: PContext, n: PNode): PNode =
|
||||
|
||||
@@ -84,7 +84,6 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
let isPure = result.sym != nil and sfPure in result.sym.flags
|
||||
var symbols: TStrTable = initStrTable()
|
||||
var hasNull = false
|
||||
var needsReorder = false
|
||||
for i in 1..<n.len:
|
||||
if n[i].kind == nkEmpty: continue
|
||||
var useAutoCounter = false
|
||||
@@ -123,9 +122,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
else:
|
||||
localError(c.config, v.info, errOrdinalTypeExpected % typeToString(v.typ, preferDesc))
|
||||
if i != 1:
|
||||
if x != counter:
|
||||
needsReorder = true
|
||||
incl(result.flags, tfEnumHasHoles)
|
||||
if x != counter: incl(result.flags, tfEnumHasHoles)
|
||||
e.ast = strVal # might be nil
|
||||
counter = x
|
||||
of nkSym:
|
||||
@@ -176,13 +173,6 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
localError(c.config, n[i].info, errOverflowInEnumX % [e.name.s, $high(typeof(counter))])
|
||||
else:
|
||||
inc(counter)
|
||||
|
||||
if needsReorder:
|
||||
result.n.sons.sort(
|
||||
proc (x, y: PNode): int =
|
||||
result = cmp(x.sym.position, y.sym.position)
|
||||
)
|
||||
|
||||
if isPure and sfExported in result.sym.flags:
|
||||
addPureEnum(c, LazySym(sym: result.sym))
|
||||
if tfNotNil in e.typ.flags and not hasNull:
|
||||
@@ -257,39 +247,27 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool =
|
||||
else:
|
||||
return false
|
||||
|
||||
proc annotateClosureConv(n: PNode) =
|
||||
case n.kind
|
||||
of {nkNone..nkNilLit}:
|
||||
discard
|
||||
of nkTupleConstr:
|
||||
if n.typ.kind == tyProc and n.typ.callConv == ccClosure and
|
||||
n[0].typ.kind == tyProc and n[0].typ.callConv != ccClosure:
|
||||
# restores `transf.generateThunk`
|
||||
n[0] = newTreeIT(nkHiddenSubConv, n[0].info, n.typ,
|
||||
newNodeI(nkEmpty, n[0].info), n[0])
|
||||
n.transitionSonsKind(nkClosure)
|
||||
n.flags.incl nfTransf
|
||||
else:
|
||||
for i in 0..<n.len:
|
||||
annotateClosureConv(n[i])
|
||||
|
||||
proc fitDefaultNode(c: PContext, n: var PNode, expectedType: PType) =
|
||||
proc fitDefaultNode(c: PContext, n: PNode): PType =
|
||||
inc c.inStaticContext
|
||||
n = semConstExpr(c, n, expectedType = expectedType)
|
||||
let oldType = n.typ
|
||||
n.flags.incl nfSem
|
||||
if expectedType != nil and oldType != expectedType:
|
||||
n = fitNodeConsiderViewType(c, expectedType, n, n.info)
|
||||
changeType(c, n, expectedType, true) # infer types for default fields value
|
||||
# bug #22926; be cautious that it uses `semConstExpr` to
|
||||
# evaulate the default fields; it's only natural to use
|
||||
# `changeType` to infer types for constant values
|
||||
# that's also the reason why we don't use `semExpr` to check
|
||||
# the type since two overlapping error messages might be produced
|
||||
annotateClosureConv(n)
|
||||
let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil
|
||||
n[^1] = semConstExpr(c, n[^1], expectedType = expectedType)
|
||||
let oldType = n[^1].typ
|
||||
n[^1].flags.incl nfSem
|
||||
if n[^2].kind != nkEmpty:
|
||||
if expectedType != nil and oldType != expectedType:
|
||||
n[^1] = fitNodeConsiderViewType(c, expectedType, n[^1], n[^1].info)
|
||||
changeType(c, n[^1], expectedType, true) # infer types for default fields value
|
||||
# bug #22926; be cautious that it uses `semConstExpr` to
|
||||
# evaulate the default fields; it's only natural to use
|
||||
# `changeType` to infer types for constant values
|
||||
# that's also the reason why we don't use `semExpr` to check
|
||||
# the type since two overlapping error messages might be produced
|
||||
result = n[^1].typ
|
||||
else:
|
||||
result = n[^1].typ
|
||||
# xxx any troubles related to defaults fields, consult `semConst` for a potential answer
|
||||
if n.kind != nkNilLit:
|
||||
typeAllowedCheck(c, n.info, n.typ, skConst, {taProcContextIsNotMacro, taIsDefaultField})
|
||||
if n[^1].kind != nkNilLit:
|
||||
typeAllowedCheck(c, n.info, result, skConst, {taProcContextIsNotMacro, taIsDefaultField})
|
||||
dec c.inStaticContext
|
||||
|
||||
proc isRecursiveType*(t: PType): bool =
|
||||
@@ -516,14 +494,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
checkMinSonsLen(a, 3, c.config)
|
||||
var hasDefaultField = a[^1].kind != nkEmpty
|
||||
if hasDefaultField:
|
||||
typ = if a[^2].kind != nkEmpty: semTypeNode(c, a[^2], nil) else: nil
|
||||
if c.inGenericContext > 0:
|
||||
a[^1] = semExprWithType(c, a[^1], {efDetermineType, efAllowSymChoice}, typ)
|
||||
if typ == nil:
|
||||
typ = a[^1].typ
|
||||
else:
|
||||
fitDefaultNode(c, a[^1], typ)
|
||||
typ = a[^1].typ
|
||||
typ = fitDefaultNode(c, a)
|
||||
elif a[^2].kind != nkEmpty:
|
||||
typ = semTypeNode(c, a[^2], nil)
|
||||
if c.graph.config.isDefined("nimPreviewRangeDefault") and typ.skipTypes(abstractInst).kind == tyRange:
|
||||
@@ -887,15 +858,8 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
var typ: PType
|
||||
var hasDefaultField = n[^1].kind != nkEmpty
|
||||
if hasDefaultField:
|
||||
typ = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil
|
||||
if c.inGenericContext > 0:
|
||||
n[^1] = semExprWithType(c, n[^1], {efDetermineType, efAllowSymChoice}, typ)
|
||||
if typ == nil:
|
||||
typ = n[^1].typ
|
||||
else:
|
||||
fitDefaultNode(c, n[^1], typ)
|
||||
typ = n[^1].typ
|
||||
propagateToOwner(rectype, typ)
|
||||
typ = fitDefaultNode(c, n)
|
||||
propagateToOwner(rectype, typ)
|
||||
elif n[^2].kind == nkEmpty:
|
||||
localError(c.config, n.info, errTypeExpected)
|
||||
typ = errorType(c)
|
||||
|
||||
@@ -276,11 +276,6 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PT
|
||||
replaceTypeVarsS(cl, n.sym, result.typ)
|
||||
else:
|
||||
replaceTypeVarsS(cl, n.sym, replaceTypeVarsT(cl, n.sym.typ))
|
||||
if result.sym.kind == skField and result.sym.ast != nil and
|
||||
(cl.owner == nil or result.sym.owner == cl.owner):
|
||||
# instantiate default value of object/tuple field
|
||||
cl.c.fitDefaultNode(cl.c, result.sym.ast, result.sym.typ)
|
||||
result.sym.typ = result.sym.ast.typ
|
||||
# sym type can be nil if was gensym created by macro, see #24048
|
||||
if result.sym.typ != nil and result.sym.typ.kind == tyVoid:
|
||||
# don't add the 'void' field
|
||||
|
||||
@@ -85,9 +85,6 @@ type
|
||||
inheritancePenalty: int
|
||||
firstMismatch*: MismatchInfo # mismatch info for better error messages
|
||||
diagnosticsEnabled*: bool
|
||||
newlyTypedOperands*: seq[int]
|
||||
## indexes of arguments that are newly typechecked in this match
|
||||
## used for type bound op additions
|
||||
|
||||
TTypeRelFlag* = enum
|
||||
trDontBind
|
||||
@@ -2731,7 +2728,7 @@ proc setSon(father: PNode, at: int, son: PNode) =
|
||||
# father[i] = newNodeIT(nkEmpty, son.info, getSysType(tyVoid))
|
||||
|
||||
# we are allowed to modify the calling node in the 'prepare*' procs:
|
||||
proc prepareOperand(c: PContext; formal: PType; a: PNode, newlyTyped: var bool): PNode =
|
||||
proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
|
||||
if formal.kind == tyUntyped and formal.len != 1:
|
||||
# {tyTypeDesc, tyUntyped, tyTyped, tyError}:
|
||||
# a.typ == nil is valid
|
||||
@@ -2749,17 +2746,15 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode, newlyTyped: var bool):
|
||||
#elif formal.kind == tyTyped: {efDetermineType, efWantStmt}
|
||||
#else: {efDetermineType}
|
||||
result = c.semOperand(c, a, flags)
|
||||
newlyTyped = true
|
||||
else:
|
||||
result = a
|
||||
considerGenSyms(c, result)
|
||||
if result.kind != nkHiddenDeref and result.typ.kind in {tyVar, tyLent} and c.matchedConcept == nil:
|
||||
result = newDeref(result)
|
||||
|
||||
proc prepareOperand(c: PContext; a: PNode, newlyTyped: var bool): PNode =
|
||||
proc prepareOperand(c: PContext; a: PNode): PNode =
|
||||
if a.typ.isNil:
|
||||
result = c.semOperand(c, a, {efDetermineType})
|
||||
newlyTyped = true
|
||||
else:
|
||||
result = a
|
||||
considerGenSyms(c, result)
|
||||
@@ -2885,9 +2880,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
|
||||
noMatch()
|
||||
m.baseTypeMatch = false
|
||||
m.typedescMatched = false
|
||||
var newlyTyped = false
|
||||
n[a][1] = prepareOperand(c, formal.typ, n[a][1], newlyTyped)
|
||||
if newlyTyped: m.newlyTypedOperands.add(a)
|
||||
n[a][1] = prepareOperand(c, formal.typ, n[a][1])
|
||||
n[a].typ() = n[a][1].typ
|
||||
arg = paramTypesMatch(m, formal.typ, n[a].typ,
|
||||
n[a][1], n[a][1])
|
||||
@@ -2911,9 +2904,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
|
||||
if tfVarargs in m.callee.flags:
|
||||
# is ok... but don't increment any counters...
|
||||
# we have no formal here to snoop at:
|
||||
var newlyTyped = false
|
||||
n[a] = prepareOperand(c, n[a], newlyTyped)
|
||||
if newlyTyped: m.newlyTypedOperands.add(a)
|
||||
n[a] = prepareOperand(c, n[a])
|
||||
if skipTypes(n[a].typ, abstractVar-{tyTypeDesc}).kind==tyString:
|
||||
m.call.add implicitConv(nkHiddenStdConv,
|
||||
getSysType(c.graph, n[a].info, tyCstring),
|
||||
@@ -2927,9 +2918,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
|
||||
m.baseTypeMatch = false
|
||||
m.typedescMatched = false
|
||||
incl(marker, formal.position)
|
||||
var newlyTyped = false
|
||||
n[a] = prepareOperand(c, formal.typ, n[a], newlyTyped)
|
||||
if newlyTyped: m.newlyTypedOperands.add(a)
|
||||
n[a] = prepareOperand(c, formal.typ, n[a])
|
||||
arg = paramTypesMatch(m, formal.typ, n[a].typ,
|
||||
n[a], nOrig[a])
|
||||
if arg != nil and m.baseTypeMatch and container != nil:
|
||||
@@ -2965,9 +2954,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
|
||||
else:
|
||||
m.baseTypeMatch = false
|
||||
m.typedescMatched = false
|
||||
var newlyTyped = false
|
||||
n[a] = prepareOperand(c, formal.typ, n[a], newlyTyped)
|
||||
if newlyTyped: m.newlyTypedOperands.add(a)
|
||||
n[a] = prepareOperand(c, formal.typ, n[a])
|
||||
arg = paramTypesMatch(m, formal.typ, n[a].typ,
|
||||
n[a], nOrig[a])
|
||||
if arg == nil:
|
||||
|
||||
@@ -507,9 +507,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds, isAddr = false)
|
||||
) and not (n[0][0].kind == nkSym and n[0][0].sym.kind == skParam and
|
||||
n.typ.kind == tyVar and
|
||||
n.typ.skipTypes(abstractVar).kind == tyOpenArray and
|
||||
n[0][0].typ.skipTypes(abstractVar).kind == tyString) and
|
||||
not (isAddr and n.typ.kind == tyVar and n[0][0].typ.kind == tyRef and
|
||||
n[0][0].kind == nkObjConstr)
|
||||
n[0][0].typ.skipTypes(abstractVar).kind == tyString)
|
||||
: # elimination is harmful to `for tuple unpack` because of newTupleAccess
|
||||
# it is also harmful to openArrayLoc (var openArray) for strings
|
||||
# addr ( deref ( x )) --> x
|
||||
@@ -639,12 +637,6 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
||||
case arg.kind
|
||||
of nkStmtListExpr:
|
||||
return paComplexOpenarray
|
||||
of nkCall:
|
||||
if skipTypes(arg.typ, abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||
# XXX incorrect, causes #13417 when `arg` has side effects.
|
||||
return paDirectMapping
|
||||
else:
|
||||
return paComplexOpenarray
|
||||
of nkBracket:
|
||||
return paFastAsgnTakeTypeFromArg
|
||||
else:
|
||||
@@ -811,7 +803,7 @@ proc transformFor(c: PTransf, n: PNode): PNode =
|
||||
stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, addrExp, true))
|
||||
newC.mapping[formal.itemId] = newDeref(temp)
|
||||
of paComplexOpenarray:
|
||||
# XXX arrays will deep copy here (pretty bad).
|
||||
# arrays will deep copy here (pretty bad).
|
||||
var temp = newTemp(c, arg.typ, formal.info)
|
||||
addVar(v, temp)
|
||||
stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg, true))
|
||||
@@ -1077,7 +1069,9 @@ proc transform(c: PTransf, n: PNode, noConstFold = false): PNode =
|
||||
of nkBreakStmt: result = transformBreak(c, n)
|
||||
of nkCallKinds:
|
||||
result = transformCall(c, n)
|
||||
of nkAddr, nkHiddenAddr:
|
||||
of nkHiddenAddr:
|
||||
result = transformAddrDeref(c, n, {nkHiddenDeref}, isAddr = true)
|
||||
of nkAddr:
|
||||
result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref}, isAddr = true)
|
||||
of nkDerefExpr:
|
||||
result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
|
||||
|
||||
@@ -1935,66 +1935,3 @@ proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool =
|
||||
result = false
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc nominalRoot*(t: PType): PType =
|
||||
## the "name" type of a given instance of a nominal type,
|
||||
## i.e. the type directly associated with the symbol where the root
|
||||
## nominal type of `t` was defined, skipping things like generic instances,
|
||||
## aliases, `var`/`sink`/`typedesc` modifiers
|
||||
##
|
||||
## instead of returning the uninstantiated body of a generic type,
|
||||
## returns the type of the symbol instead (with tyGenericBody type)
|
||||
result = nil
|
||||
case t.kind
|
||||
of tyAlias, tyVar, tySink:
|
||||
# varargs?
|
||||
result = nominalRoot(t.skipModifier)
|
||||
of tyTypeDesc:
|
||||
# for proc foo(_: type T)
|
||||
result = nominalRoot(t.skipModifier)
|
||||
of tyGenericInvocation, tyGenericInst:
|
||||
result = t
|
||||
# skip aliases, so this works in the same module but not in another module:
|
||||
# type Foo[T] = object
|
||||
# type Bar[T] = Foo[T]
|
||||
# proc foo[T](x: Bar[T]) = ... # attached to type
|
||||
while result.skipModifier.kind in {tyGenericInvocation, tyGenericInst}:
|
||||
result = result.skipModifier
|
||||
result = nominalRoot(result[0])
|
||||
of tyGenericBody:
|
||||
result = t
|
||||
# this time skip the aliases but take the generic body
|
||||
while result.skipModifier.kind in {tyGenericInvocation, tyGenericInst}:
|
||||
result = result.skipModifier[0]
|
||||
let val = result.skipModifier
|
||||
if val.kind in {tyDistinct, tyEnum, tyObject} or
|
||||
(val.kind in {tyRef, tyPtr} and tfRefsAnonObj in val.flags):
|
||||
# atomic nominal types, this generic body is attached to them
|
||||
discard
|
||||
else:
|
||||
result = nominalRoot(val)
|
||||
of tyCompositeTypeClass:
|
||||
# parameter with type Foo
|
||||
result = nominalRoot(t.skipModifier)
|
||||
of tyGenericParam:
|
||||
if t.genericParamHasConstraints:
|
||||
# T: Foo
|
||||
result = nominalRoot(t.genericConstraint)
|
||||
else:
|
||||
result = nil
|
||||
of tyDistinct, tyEnum, tyObject:
|
||||
result = t
|
||||
of tyPtr, tyRef:
|
||||
if tfRefsAnonObj in t.flags:
|
||||
# in the case that we have `type Foo = ref object` etc
|
||||
result = t
|
||||
else:
|
||||
# we could allow this in general, but there's things like `seq[Foo]`
|
||||
#result = nominalRoot(t.skipModifier)
|
||||
result = nil
|
||||
of tyStatic:
|
||||
result = nominalRoot(t.base)
|
||||
else:
|
||||
# skips all typeclasses
|
||||
# is this correct for `concept`?
|
||||
result = nil
|
||||
|
||||
@@ -1543,9 +1543,7 @@ proc setSlot(c: PCtx; v: PSym) =
|
||||
v.position = getFreeRegister(c, if v.kind == skLet: slotFixedLet else: slotFixedVar, start = 1)
|
||||
|
||||
template cannotEval(c: PCtx; n: PNode) =
|
||||
if c.config.cmd == cmdCheck and c.config.m.errorOutputs != {}:
|
||||
# nim check command with no error outputs doesn't need to cascade here,
|
||||
# includes `tryConstExpr` case which should not continue generating code
|
||||
if c.config.cmd == cmdCheck:
|
||||
localError(c.config, n.info, "cannot evaluate at compile time: " &
|
||||
n.renderTree)
|
||||
c.cannotEval = true
|
||||
|
||||
@@ -2667,114 +2667,3 @@ proc nothing() =
|
||||
```
|
||||
|
||||
The current C(C++) backend implementation cannot generate code for gcc and for vcc at the same time. For example, `{.asmSyntax: "vcc".}` with the ICC compiler will not generate code with intel asm syntax, even though ICC can use both gcc-like and vcc-like asm.
|
||||
|
||||
Type-bound overloads
|
||||
====================
|
||||
|
||||
With the experimental option `--experimental:typeBoundOps`, each "root"
|
||||
nominal type (namely `object`, `enum`, `distinct`, direct `Foo = ref object`
|
||||
types as well as their generic versions) can have operations attached to it.
|
||||
Exported top-level routines declared in the same scope as a nominal type
|
||||
with a parameter having a type directly deriving from that nominal type (i.e.
|
||||
with `var`/`sink`/`typedesc` modifiers or being in a generic constraint)
|
||||
are considered "attached" to the respective nominal type.
|
||||
This applies to every parameter regardless of placement.
|
||||
|
||||
When a call to a symbol is openly overloaded and overload matching starts,
|
||||
for all arguments in the call that have already undergone type checking,
|
||||
routines with the same name attached to the root nominal type (if it exists)
|
||||
of each given argument are added as a candidate to the overload match.
|
||||
This also happens as arguments gradually get typed after every match to an overload.
|
||||
This is so that the only overloads considered out of scope are
|
||||
attached to the types of the given arguments, and that matches to
|
||||
`untyped` or missing parameters are not influenced by outside overloads.
|
||||
|
||||
If no overloads with a given name are in scope, then overload matching
|
||||
will not begin, and so type-bound overloads are not considered for that name.
|
||||
Similarly, if the only overloads with a given name require a parameter to be
|
||||
`untyped` or missing, then type-bound overloads will not be considered for
|
||||
the argument in that position.
|
||||
Generally this means that a "base" overload with a compliant signature should
|
||||
be in scope so that type-bound overloads can be used.
|
||||
|
||||
In the case of ambiguity between distinct local/imported and type-bound symbols
|
||||
in overload matching, type-bound symbols are considered as a less specific
|
||||
scope than imports.
|
||||
|
||||
An example with the `hash` interface in the standard library is as follows:
|
||||
|
||||
```nim
|
||||
# objs.nim
|
||||
import std/hashes
|
||||
|
||||
type
|
||||
Obj* = object
|
||||
x*, y*: int
|
||||
z*: string # to be ignored for equality
|
||||
|
||||
proc `==`*(a, b: Obj): bool =
|
||||
a.x == b.x and a.y == b.y
|
||||
|
||||
proc hash*(a: Obj): Hash =
|
||||
$!(hash(a.x) &! hash(a.y))
|
||||
|
||||
# here both `==` and `hash` are attached to Obj
|
||||
# 1. they are both exported
|
||||
# 2. they are in the same scope as Obj
|
||||
# 3. they have parameters with types directly deriving from Obj
|
||||
# 4. Obj is nominal
|
||||
```
|
||||
|
||||
```nim
|
||||
# main.nim
|
||||
{.experimental: "typeBoundOps".}
|
||||
from objs import Obj # objs.hash, objs.`==` not imported
|
||||
import std/tables
|
||||
# tables use `hash`, only using the overloads in `std/hashes` and
|
||||
# the ones in instantiation scope (in this case, there are none)
|
||||
|
||||
var t: Table[Obj, int]
|
||||
# because tables use `hash` and `==` in a compliant way,
|
||||
# the overloads bound to Obj are also considered, and in this case match best
|
||||
t[Obj(x: 3, y: 4, z: "debug")] = 34
|
||||
# if `hash` for all objects as in `std/hashes` was used, this would error:
|
||||
echo t[Obj(x: 3, y: 4, z: "ignored")] # 34
|
||||
```
|
||||
|
||||
Another example, this time with `$` and indirect imports:
|
||||
|
||||
```nim
|
||||
# foo.nim
|
||||
type Foo* = object
|
||||
x*, y*: int
|
||||
|
||||
proc `$`*(f: Foo): string =
|
||||
"Foo(" & $f.x & ", " & $f.y & ")"
|
||||
```
|
||||
|
||||
```nim
|
||||
# bar.nim
|
||||
import foo
|
||||
|
||||
proc makeFoo*(x, y: int): Foo =
|
||||
Foo(x: x, y: y)
|
||||
|
||||
proc useFoo*(f: Foo) =
|
||||
echo "used: ", f # directly calls `foo.$` from scope
|
||||
```
|
||||
|
||||
```nim
|
||||
# debugger.nim
|
||||
proc debug*[T](obj: T) =
|
||||
echo "debugging: ", obj # calls generic `$`
|
||||
```
|
||||
|
||||
```nim
|
||||
# main.nim
|
||||
{.experimental: "typeBoundOps".}
|
||||
import bar, debugger # `foo` not imported, so `foo.$` not in scope
|
||||
|
||||
let f = makeFoo(123, 456)
|
||||
useFoo(f) # used: Foo(123, 456)
|
||||
debug(f) # debugging: Foo(123, 456)
|
||||
```
|
||||
|
||||
@@ -74,14 +74,7 @@ when defined(nimPreviewSlimSystem):
|
||||
export options
|
||||
|
||||
type
|
||||
RegexDesc* = object
|
||||
pattern*: string
|
||||
pcreObj: ptr pcre.Pcre ## not nil
|
||||
pcreExtra: ptr pcre.ExtraData ## nil
|
||||
|
||||
captureNameToId: Table[string, int]
|
||||
|
||||
Regex* = ref RegexDesc
|
||||
Regex* = ref object
|
||||
## Represents the pattern that things are matched against, constructed with
|
||||
## `re(string)`. Examples: `re"foo"`, `re(r"(*ANYCRLF)(?x)foo #
|
||||
## comment".`
|
||||
@@ -152,6 +145,11 @@ type
|
||||
## `DOLLAR_ENDONLY`, `FIRSTLINE`, `NO_AUTO_CAPTURE`,
|
||||
## `JAVASCRIPT_COMPAT`, `U`, `NO_STUDY`. In other PCRE wrappers, you
|
||||
## will need to pass these as separate flags to PCRE.
|
||||
pattern*: string
|
||||
pcreObj: ptr pcre.Pcre ## not nil
|
||||
pcreExtra: ptr pcre.ExtraData ## nil
|
||||
|
||||
captureNameToId: Table[string, int]
|
||||
|
||||
RegexMatch* = object
|
||||
## Usually seen as Option[RegexMatch], it represents the result of an
|
||||
@@ -218,28 +216,12 @@ type
|
||||
## for whatever reason. The message contains the error
|
||||
## code.
|
||||
|
||||
when defined(gcDestructors):
|
||||
when defined(nimAllowNonVarDestructor) and defined(nimPreviewNonVarDestructor):
|
||||
proc `=destroy`(pattern: RegexDesc) =
|
||||
`=destroy`(pattern.pattern)
|
||||
pcre.free_substring(cast[cstring](pattern.pcreObj))
|
||||
if pattern.pcreExtra != nil:
|
||||
pcre.free_study(pattern.pcreExtra)
|
||||
`=destroy`(pattern.captureNameToId)
|
||||
else:
|
||||
proc `=destroy`(pattern: var RegexDesc) =
|
||||
`=destroy`(pattern.pattern)
|
||||
pcre.free_substring(cast[cstring](pattern.pcreObj))
|
||||
if pattern.pcreExtra != nil:
|
||||
pcre.free_study(pattern.pcreExtra)
|
||||
`=destroy`(pattern.captureNameToId)
|
||||
else:
|
||||
proc destroyRegex(pattern: Regex) =
|
||||
`=destroy`(pattern.pattern)
|
||||
pcre.free_substring(cast[cstring](pattern.pcreObj))
|
||||
if pattern.pcreExtra != nil:
|
||||
pcre.free_study(pattern.pcreExtra)
|
||||
`=destroy`(pattern.captureNameToId)
|
||||
proc destroyRegex(pattern: Regex) =
|
||||
`=destroy`(pattern.pattern)
|
||||
pcre.free_substring(cast[cstring](pattern.pcreObj))
|
||||
if pattern.pcreExtra != nil:
|
||||
pcre.free_study(pattern.pcreExtra)
|
||||
`=destroy`(pattern.captureNameToId)
|
||||
|
||||
proc getinfo[T](pattern: Regex, opt: cint): T =
|
||||
let retcode = pcre.fullinfo(pattern.pcreObj, pattern.pcreExtra, opt, addr result)
|
||||
@@ -269,10 +251,7 @@ proc getNameToNumberTable(pattern: Regex): Table[string, int] =
|
||||
result[name] = num
|
||||
|
||||
proc initRegex(pattern: string, flags: int, study = true): Regex =
|
||||
when defined(gcDestructors):
|
||||
result = Regex()
|
||||
else:
|
||||
new(result, destroyRegex)
|
||||
new(result, destroyRegex)
|
||||
result.pattern = pattern
|
||||
|
||||
var errorMsg: cstring
|
||||
|
||||
@@ -472,8 +472,7 @@ typedef char* NCSTRING;
|
||||
/* declared size of a sequence/variable length array: */
|
||||
#if defined(__cplusplus) && defined(__clang__)
|
||||
# define SEQ_DECL_SIZE 1
|
||||
#elif defined(__GNUC__) || defined(_MSC_VER) || defined(__TINYC__) || \
|
||||
(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)) // C99
|
||||
#elif defined(__GNUC__) || defined(_MSC_VER)
|
||||
# define SEQ_DECL_SIZE /* empty is correct! */
|
||||
#else
|
||||
# define SEQ_DECL_SIZE 1000000
|
||||
|
||||
@@ -306,10 +306,10 @@ else:
|
||||
type
|
||||
# Atomic*[T] {.importcpp: "_Atomic('0)".} = object
|
||||
|
||||
AtomicInt8 {.importc: "_Atomic NI8".} = int8
|
||||
AtomicInt16 {.importc: "_Atomic NI16".} = int16
|
||||
AtomicInt32 {.importc: "_Atomic NI32".} = int32
|
||||
AtomicInt64 {.importc: "_Atomic NI64".} = int64
|
||||
AtomicInt8 {.importc: "_Atomic NI8".} = distinct int8
|
||||
AtomicInt16 {.importc: "_Atomic NI16".} = distinct int16
|
||||
AtomicInt32 {.importc: "_Atomic NI32".} = distinct int32
|
||||
AtomicInt64 {.importc: "_Atomic NI64".} = distinct int64
|
||||
|
||||
type
|
||||
AtomicFlag* {.importc: "atomic_flag".maybeWrapStd, size: 1.} = object
|
||||
|
||||
@@ -62,7 +62,6 @@
|
||||
## validated to the server.
|
||||
##
|
||||
## ```Nim
|
||||
## import std/[httpclient]
|
||||
## var client = newHttpClient()
|
||||
## var data = newMultipartData()
|
||||
## data["output"] = "soap12"
|
||||
@@ -80,7 +79,6 @@
|
||||
## it, you can pass your own via the `mimeDb` parameter to avoid this.
|
||||
##
|
||||
## ```Nim
|
||||
## import std/[httpclient, mimetypes]
|
||||
## let mimes = newMimetypes()
|
||||
## var client = newHttpClient()
|
||||
## var data = newMultipartData()
|
||||
@@ -162,7 +160,7 @@
|
||||
## Example of setting SSL verification parameters in a new client:
|
||||
##
|
||||
## ```Nim
|
||||
## import std/[net, httpclient]
|
||||
## import httpclient
|
||||
## var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer))
|
||||
## ```
|
||||
##
|
||||
|
||||
@@ -507,14 +507,12 @@ type
|
||||
nkAsgn,
|
||||
nkFrom,
|
||||
nkFromItemPair,
|
||||
nkJoin,
|
||||
nkNaturalJoin,
|
||||
nkUsing,
|
||||
nkGroup,
|
||||
nkLimit,
|
||||
nkOffset,
|
||||
nkHaving,
|
||||
nkOrder,
|
||||
nkJoin,
|
||||
nkDesc,
|
||||
nkUnion,
|
||||
nkIntersect,
|
||||
@@ -938,75 +936,18 @@ proc parseWhere(p: var SqlParser): SqlNode =
|
||||
result = newNode(nkWhere)
|
||||
result.add(parseExpr(p))
|
||||
|
||||
proc parseJoinType(p: var SqlParser): SqlNode =
|
||||
## parse [ INNER ] JOIN | ( LEFT | RIGHT | FULL ) [ OUTER ] JOIN
|
||||
if isKeyw(p, "inner"):
|
||||
getTok(p)
|
||||
eat(p, "join")
|
||||
return newNode(nkIdent, "inner")
|
||||
elif isKeyw(p, "join"):
|
||||
getTok(p)
|
||||
return newNode(nkIdent, "")
|
||||
elif isKeyw(p, "left") or isKeyw(p, "full") or isKeyw(p, "right"):
|
||||
var joinType = newNode(nkIdent, p.tok.literal.toLowerAscii())
|
||||
getTok(p)
|
||||
optKeyw(p, "outer")
|
||||
eat(p, "join")
|
||||
return joinType
|
||||
else:
|
||||
sqlError(p, "join type expected")
|
||||
|
||||
proc parseFromItem(p: var SqlParser): SqlNode =
|
||||
result = newNode(nkFromItemPair)
|
||||
var expectAs = true
|
||||
if p.tok.kind == tkParLe:
|
||||
getTok(p)
|
||||
if isKeyw(p, "select"):
|
||||
result.add(parseSelect(p))
|
||||
else:
|
||||
result = parseFromItem(p)
|
||||
expectAs = false
|
||||
var select = parseSelect(p)
|
||||
result.add(select)
|
||||
eat(p, tkParRi)
|
||||
else:
|
||||
result.add(parseExpr(p))
|
||||
if expectAs and isKeyw(p, "as"):
|
||||
if isKeyw(p, "as"):
|
||||
getTok(p)
|
||||
result.add(parseExpr(p))
|
||||
while true:
|
||||
if isKeyw(p, "cross"):
|
||||
var join = newNode(nkJoin)
|
||||
join.add(newNode(nkIdent, "cross"))
|
||||
join.add(result)
|
||||
getTok(p)
|
||||
eat(p, "join")
|
||||
join.add(parseFromItem(p))
|
||||
result = join
|
||||
elif isKeyw(p, "natural"):
|
||||
var join = newNode(nkNaturalJoin)
|
||||
getTok(p)
|
||||
join.add(parseJoinType(p))
|
||||
join.add(result)
|
||||
join.add(parseFromItem(p))
|
||||
result = join
|
||||
elif isKeyw(p, "inner") or isKeyw(p, "join") or isKeyw(p, "left") or
|
||||
iskeyw(p, "full") or isKeyw(p, "right"):
|
||||
var join = newNode(nkJoin)
|
||||
join.add(parseJoinType(p))
|
||||
join.add(result)
|
||||
join.add(parseFromItem(p))
|
||||
if isKeyw(p, "on"):
|
||||
getTok(p)
|
||||
join.add(parseExpr(p))
|
||||
elif isKeyw(p, "using"):
|
||||
getTok(p)
|
||||
var n = newNode(nkUsing)
|
||||
parseParIdentList(p, n)
|
||||
join.add n
|
||||
else:
|
||||
sqlError(p, "ON or USING expected")
|
||||
result = join
|
||||
else:
|
||||
break
|
||||
|
||||
proc parseIndexDef(p: var SqlParser): SqlNode =
|
||||
result = parseIfNotExists(p, nkCreateIndex)
|
||||
@@ -1168,6 +1109,19 @@ proc parseSelect(p: var SqlParser): SqlNode =
|
||||
elif isKeyw(p, "except"):
|
||||
result.add(newNode(nkExcept))
|
||||
getTok(p)
|
||||
if isKeyw(p, "join") or isKeyw(p, "inner") or isKeyw(p, "outer") or isKeyw(p, "cross"):
|
||||
var join = newNode(nkJoin)
|
||||
result.add(join)
|
||||
if isKeyw(p, "join"):
|
||||
join.add(newNode(nkIdent, ""))
|
||||
getTok(p)
|
||||
else:
|
||||
join.add(newNode(nkIdent, p.tok.literal.toLowerAscii()))
|
||||
getTok(p)
|
||||
eat(p, "join")
|
||||
join.add(parseFromItem(p))
|
||||
eat(p, "on")
|
||||
join.add(parseExpr(p))
|
||||
if isKeyw(p, "limit"):
|
||||
getTok(p)
|
||||
var l = newNode(nkLimit)
|
||||
@@ -1434,30 +1388,6 @@ proc ra(n: SqlNode, s: var SqlWriter) =
|
||||
of nkFrom:
|
||||
s.addKeyw("from")
|
||||
s.addMulti(n)
|
||||
of nkJoin, nkNaturalJoin:
|
||||
var joinType = n.sons[0].strVal
|
||||
if joinType == "":
|
||||
joinType = "join"
|
||||
else:
|
||||
joinType &= " " & "join"
|
||||
if n.kind == nkNaturalJoin:
|
||||
joinType = "natural " & joinType
|
||||
ra(n.sons[1], s)
|
||||
s.addKeyw(joinType)
|
||||
# If the right part of the join is not leaf, parenthesize it
|
||||
if n.sons[2].kind != nkFromItemPair:
|
||||
s.add('(')
|
||||
ra(n.sons[2], s)
|
||||
s.add(')')
|
||||
else:
|
||||
ra(n.sons[2], s)
|
||||
if n.sons.len > 3:
|
||||
if n.sons[3].kind != nkUsing:
|
||||
s.addKeyw("on")
|
||||
ra(n.sons[3], s)
|
||||
of nkUsing:
|
||||
s.addKeyw("using")
|
||||
rs(n, s)
|
||||
of nkGroup:
|
||||
s.addKeyw("group by")
|
||||
s.addMulti(n)
|
||||
@@ -1473,6 +1403,16 @@ proc ra(n: SqlNode, s: var SqlWriter) =
|
||||
of nkOrder:
|
||||
s.addKeyw("order by")
|
||||
s.addMulti(n)
|
||||
of nkJoin:
|
||||
var joinType = n.sons[0].strVal
|
||||
if joinType == "":
|
||||
joinType = "join"
|
||||
else:
|
||||
joinType &= " " & "join"
|
||||
s.addKeyw(joinType)
|
||||
ra(n.sons[1], s)
|
||||
s.addKeyw("on")
|
||||
ra(n.sons[2], s)
|
||||
of nkDesc:
|
||||
ra(n.sons[0], s)
|
||||
s.addKeyw("desc")
|
||||
|
||||
@@ -125,38 +125,18 @@ proc unsafeAddr*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} =
|
||||
|
||||
const ThisIsSystem = true
|
||||
|
||||
const arcLikeMem = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc)
|
||||
|
||||
when defined(nimAllowNonVarDestructor) and arcLikeMem:
|
||||
proc new*[T](a: var ref T, finalizer: proc (x: T) {.nimcall.}) {.
|
||||
magic: "NewFinalize", noSideEffect.}
|
||||
## Creates a new object of type `T` and returns a safe (traced)
|
||||
## reference to it in `a`.
|
||||
##
|
||||
## When the garbage collector frees the object, `finalizer` is called.
|
||||
## The `finalizer` may not keep a reference to the
|
||||
## object pointed to by `x`. The `finalizer` cannot prevent the GC from
|
||||
## freeing the object.
|
||||
##
|
||||
## **Note**: The `finalizer` refers to the type `T`, not to the object!
|
||||
## This means that for each object of type `T` the finalizer will be called!
|
||||
|
||||
proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
|
||||
magic: "NewFinalize", noSideEffect, deprecated: "pass a finalizer of the 'proc (x: T) {.nimcall.}' type".}
|
||||
|
||||
else:
|
||||
proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
|
||||
magic: "NewFinalize", noSideEffect.}
|
||||
## Creates a new object of type `T` and returns a safe (traced)
|
||||
## reference to it in `a`.
|
||||
##
|
||||
## When the garbage collector frees the object, `finalizer` is called.
|
||||
## The `finalizer` may not keep a reference to the
|
||||
## object pointed to by `x`. The `finalizer` cannot prevent the GC from
|
||||
## freeing the object.
|
||||
##
|
||||
## **Note**: The `finalizer` refers to the type `T`, not to the object!
|
||||
## This means that for each object of type `T` the finalizer will be called!
|
||||
proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
|
||||
magic: "NewFinalize", noSideEffect.}
|
||||
## Creates a new object of type `T` and returns a safe (traced)
|
||||
## reference to it in `a`.
|
||||
##
|
||||
## When the garbage collector frees the object, `finalizer` is called.
|
||||
## The `finalizer` may not keep a reference to the
|
||||
## object pointed to by `x`. The `finalizer` cannot prevent the GC from
|
||||
## freeing the object.
|
||||
##
|
||||
## **Note**: The `finalizer` refers to the type `T`, not to the object!
|
||||
## This means that for each object of type `T` the finalizer will be called!
|
||||
|
||||
proc `=wasMoved`*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} =
|
||||
## Generic `wasMoved`:idx: implementation that can be overridden.
|
||||
@@ -382,6 +362,8 @@ proc arrGet[I: Ordinal;T](a: T; i: I): T {.
|
||||
proc arrPut[I: Ordinal;T,S](a: T; i: I;
|
||||
x: S) {.noSideEffect, magic: "ArrPut".}
|
||||
|
||||
const arcLikeMem = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc)
|
||||
|
||||
|
||||
when defined(nimAllowNonVarDestructor) and arcLikeMem and defined(nimPreviewNonVarDestructor):
|
||||
proc `=destroy`*[T](x: T) {.inline, magic: "Destroy".} =
|
||||
|
||||
@@ -144,10 +144,10 @@ types, as well as their subtypes.
|
||||
===================== =======================================
|
||||
Proc Usage
|
||||
===================== =======================================
|
||||
succ_ Successor of the value
|
||||
pred_ Predecessor of the value
|
||||
inc_ Increment the ordinal
|
||||
dec_ Decrement the ordinal
|
||||
`succ<#succ,T,int>`_ Successor of the value
|
||||
`pred<#pred,T,int>`_ Predecessor of the value
|
||||
`inc<#inc,T,int>`_ Increment the ordinal
|
||||
`dec<#dec,T,int>`_ Decrement the ordinal
|
||||
`high<#high,T>`_ Return the highest possible value
|
||||
`low<#low,T>`_ Return the lowest possible value
|
||||
`ord<#ord,T>`_ Return `int` value of an ordinal value
|
||||
|
||||
@@ -449,9 +449,14 @@ type
|
||||
|
||||
SockLen* = cuint
|
||||
|
||||
type
|
||||
Timeval* {.importc: "struct timeval", header: "<time.h>".} = object
|
||||
tv_sec*, tv_usec*: int32
|
||||
when defined(cpp):
|
||||
type
|
||||
Timeval* {.importc: "timeval", header: "<time.h>".} = object
|
||||
tv_sec*, tv_usec*: int32
|
||||
else:
|
||||
type
|
||||
Timeval* = object
|
||||
tv_sec*, tv_usec*: int32
|
||||
|
||||
var
|
||||
SOMAXCONN* {.importc, header: "winsock2.h".}: cint
|
||||
|
||||
@@ -124,7 +124,6 @@ pkg "nimsvg"
|
||||
pkg "nimterop", "nimble minitest", url = "https://github.com/nim-lang/nimterop"
|
||||
pkg "nimwc", "nim c nimwc.nim"
|
||||
pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter"
|
||||
pkg "noise"
|
||||
pkg "norm", "testament r tests/common/tmodel.nim"
|
||||
pkg "normalize"
|
||||
pkg "npeg", "nimble testarc"
|
||||
|
||||
@@ -834,30 +834,3 @@ block: # bug #24141
|
||||
doAssert abc == "fbc"
|
||||
|
||||
main()
|
||||
|
||||
block:
|
||||
type
|
||||
FooObj = object
|
||||
data: int
|
||||
Foo = ref FooObj
|
||||
|
||||
|
||||
proc delete(self: FooObj) =
|
||||
discard
|
||||
|
||||
var s = Foo()
|
||||
new(s, delete)
|
||||
|
||||
block:
|
||||
type
|
||||
FooObj = object
|
||||
data: int
|
||||
i1, i2, i3, i4: float
|
||||
Foo = ref FooObj
|
||||
|
||||
|
||||
proc delete(self: FooObj) =
|
||||
discard
|
||||
|
||||
var s = Foo()
|
||||
new(s, delete)
|
||||
|
||||
@@ -31,39 +31,3 @@ elif defined(gcRefc):
|
||||
doAssert x.repr == "[p = nil]"
|
||||
else: # fixme # bug #20081
|
||||
doAssert x.repr == "Pledge(p: nil)"
|
||||
|
||||
block:
|
||||
block: # bug #18081
|
||||
type
|
||||
Foo = object
|
||||
discard
|
||||
|
||||
Bar = object
|
||||
x: Foo
|
||||
|
||||
proc baz(state: var Bar) =
|
||||
state.x = Foo()
|
||||
|
||||
baz((ref Bar)(x: (new Foo)[])[])
|
||||
|
||||
block: # bug #18079
|
||||
type
|
||||
Foo = object
|
||||
discard
|
||||
|
||||
Bar = object
|
||||
x: Foo
|
||||
|
||||
proc baz(state: var Bar) = discard
|
||||
baz((ref Bar)(x: (new Foo)[])[])
|
||||
|
||||
block: # bug #18080
|
||||
type
|
||||
Foo = object
|
||||
discard
|
||||
|
||||
Bar = object
|
||||
x: Foo
|
||||
|
||||
proc baz(state: var Bar) = discard
|
||||
baz((ref Bar)(x: Foo())[])
|
||||
|
||||
@@ -502,53 +502,3 @@ block: # bug #22297
|
||||
let s = f
|
||||
doAssert s() == 12
|
||||
doAssert s() == 14
|
||||
|
||||
# bug #19984
|
||||
import std/[sets]
|
||||
|
||||
block:
|
||||
type
|
||||
i8 = int8
|
||||
seq8 = seq[int8]
|
||||
Cell = seq8
|
||||
NODE = tuple[d_in:int8,Strong:bool,link:Cell]
|
||||
PATH = seq[NODE]
|
||||
|
||||
var
|
||||
max_level : int
|
||||
|
||||
var
|
||||
Seen:HashSet[NODE]
|
||||
path:PATH
|
||||
|
||||
iterator Loop_next(strong_link:bool, d_in:int8, node:Cell, head:int8,
|
||||
Seen:var HashSet[NODE], path: var PATH, level:int ) : PATH {.closure.} =
|
||||
|
||||
if level > max_level :
|
||||
return
|
||||
let GNode= len(node) > 1 # without this line, the code compiles
|
||||
|
||||
var
|
||||
rt, ct, st : seq8
|
||||
column_type : bool
|
||||
|
||||
#[ with this code commented out the compiler error does not occurs ]#
|
||||
|
||||
st= filter(st, proc(x:int8) : bool = x notin node)
|
||||
if column_type :
|
||||
rt= @[]
|
||||
ct= filter(ct, proc(x:int8) : bool = x notin node)
|
||||
else : # row type
|
||||
rt= filter(rt, proc(x:int8) : bool = x notin node)
|
||||
ct= @[]
|
||||
|
||||
#[]#
|
||||
iterator Nice_Loop( ) : PATH {.closure.} =
|
||||
for cell in 0i8..80i8 :
|
||||
let head= cell
|
||||
|
||||
for pt in Loop_next(true,0.i8,@[cell], head,Seen,path,0) :
|
||||
yield pt
|
||||
|
||||
for P in Nice_Loop() :
|
||||
continue
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
discard """
|
||||
disabled: "arm64"
|
||||
"""
|
||||
|
||||
proc testAsm() =
|
||||
let src = 41
|
||||
var dst = 0
|
||||
@@ -16,4 +12,4 @@ proc testAsm() =
|
||||
|
||||
when defined(gcc) or defined(clang) and not defined(cpp):
|
||||
{.passc: "-std=c99".}
|
||||
testAsm()
|
||||
testAsm()
|
||||
@@ -43,4 +43,3 @@ when not defined(testsConciseTypeMismatch):
|
||||
switch("legacy", "verboseTypeMismatch")
|
||||
switch("experimental", "vtables")
|
||||
switch("experimental", "openSym")
|
||||
switch("experimental", "typeBoundOps")
|
||||
|
||||
@@ -197,7 +197,7 @@ block: # unordered enum
|
||||
b = 0
|
||||
|
||||
doAssert (ord(a), ord(b)) == (1, 0)
|
||||
doAssert unordered_enum.toSeq == @[b, a]
|
||||
doAssert unordered_enum.toSeq == @[a, b]
|
||||
|
||||
block:
|
||||
type
|
||||
@@ -227,7 +227,7 @@ block: # unordered enum
|
||||
d
|
||||
|
||||
doAssert (ord(a), ord(b), ord(c), ord(d)) == (7, 6, 5, 8)
|
||||
doAssert unordered_enum.toSeq == @[c, b, a, d]
|
||||
doAssert unordered_enum.toSeq == @[a, b, c, d]
|
||||
|
||||
block:
|
||||
type
|
||||
@@ -265,21 +265,3 @@ block: # unordered enum
|
||||
seC = "foo"
|
||||
|
||||
doAssert (ord(seA), ord(seB), ord(seC)) == (3, 2, 4)
|
||||
|
||||
block: # bug #23952
|
||||
block:
|
||||
proc foo =
|
||||
type Foo = enum A B = -1
|
||||
doAssert cast[Foo](-1) == B
|
||||
doAssert ord(A) == 0
|
||||
static: foo()
|
||||
foo()
|
||||
|
||||
block:
|
||||
proc foo =
|
||||
type Foo = enum A B=8, C=1
|
||||
let s1 = {A}
|
||||
let s2 = {B}
|
||||
doAssert s1 != s2
|
||||
static: foo()
|
||||
foo()
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# issue #15097
|
||||
|
||||
import macros
|
||||
|
||||
macro foo: untyped =
|
||||
result = newStmtList()
|
||||
let tmp = genSym(nskProc, "tmp") #[tt.Error
|
||||
^ illformed AST: symbol of kind skProc has no implementation]#
|
||||
result.add quote do:
|
||||
let bar = `tmp`()
|
||||
|
||||
foo()
|
||||
@@ -1,32 +0,0 @@
|
||||
block: # issue #13417
|
||||
var s: seq[int] = @[]
|
||||
proc p1(): seq[int] =
|
||||
s.add(3)
|
||||
@[1,2]
|
||||
|
||||
iterator ip1(v: openArray[int]): auto =
|
||||
for x in v:
|
||||
yield x
|
||||
|
||||
for x in ip1(p1()):
|
||||
s.add(x)
|
||||
|
||||
doAssert s == @[3, 1, 2]
|
||||
|
||||
import std / sequtils
|
||||
|
||||
block: # issue #19703
|
||||
iterator combinations[T](s: seq[T], r: Positive): seq[T] =
|
||||
yield @[s[0], s[1]]
|
||||
|
||||
iterator pairwise[T](s: openArray[T]): seq[T] =
|
||||
yield @[s[0], s[0]]
|
||||
|
||||
proc checkSpecialSubset5(s: seq[int]): bool =
|
||||
toSeq(
|
||||
toSeq(
|
||||
s.combinations(2)
|
||||
).map(proc(a: auto): int = a[0]).pairwise()
|
||||
).any(proc(a: auto): bool = a == @[s[0], s[0]])
|
||||
|
||||
doAssert checkSpecialSubset5 @[1, 2]
|
||||
@@ -1,7 +1,3 @@
|
||||
discard """
|
||||
joinable: false
|
||||
"""
|
||||
|
||||
import typetraits
|
||||
import macros
|
||||
|
||||
@@ -406,26 +402,3 @@ when true: # Odd bug where alias can seep inside of `distinctBase`
|
||||
proc `$`*[T: AdtChild](adtChild: T): string = ""
|
||||
|
||||
check 10 is int
|
||||
|
||||
|
||||
block: # bug #24378
|
||||
macro forked(body: typed): untyped = # typed or untyped does not matter
|
||||
result = quote do:
|
||||
type Win = typeof(`body`)
|
||||
doAssert not supportsCopyMem((int, Win))
|
||||
doAssert not supportsCopyMem(tuple[a: int, b: Win])
|
||||
|
||||
type Win2[T] = typeof(`body`)
|
||||
doAssert not supportsCopyMem((int, Win2[int]))
|
||||
doAssert not supportsCopyMem(tuple[a: int, b: Win2[int]])
|
||||
forked:
|
||||
"foobar"
|
||||
|
||||
|
||||
type Win111 = typeof("foobar")
|
||||
doAssert not supportsCopyMem((int, Win111))
|
||||
doAssert not supportsCopyMem(tuple[a: int, b: Win111])
|
||||
|
||||
type Win222[T] = typeof("foobar")
|
||||
doAssert not supportsCopyMem((int, Win222[int]))
|
||||
doAssert not supportsCopyMem(tuple[a: int, b: Win222[int]])
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
block: # issue #23594
|
||||
type
|
||||
Gen[T] = object
|
||||
a: T = 1.0
|
||||
|
||||
Spec32 = Gen[float32]
|
||||
Spec64 = Gen[float64]
|
||||
|
||||
var
|
||||
a: Spec32
|
||||
b: Spec64
|
||||
doAssert sizeof(a) == 4
|
||||
doAssert sizeof(b) == 8
|
||||
doAssert a.a is float32
|
||||
doAssert b.a is float64
|
||||
|
||||
block: # issue #21941
|
||||
func what[T](): T =
|
||||
123
|
||||
|
||||
type MyObject[T] = object
|
||||
f: T = what[T]()
|
||||
|
||||
var m: MyObject[float] = MyObject[float]()
|
||||
doAssert m.f is float
|
||||
doAssert m.f == 123.0
|
||||
@@ -776,18 +776,5 @@ template main {.dirty.} =
|
||||
var d: limited_int;
|
||||
doAssert d == 1
|
||||
|
||||
block: # bug #23545
|
||||
proc evaluate(params: int) =
|
||||
discard
|
||||
|
||||
proc evaluate() =
|
||||
discard
|
||||
|
||||
type SearchInfo = object
|
||||
evaluation: proc() = evaluate
|
||||
|
||||
var a = SearchInfo()
|
||||
a.evaluation()
|
||||
|
||||
static: main()
|
||||
main()
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
switch("experimental", "typeBoundOps")
|
||||
@@ -1,15 +0,0 @@
|
||||
# context_thread_local
|
||||
import ./mtasks, ./mlistdeques
|
||||
|
||||
export mlistdeques # Exporting the type with destructor doesn't help
|
||||
# export tasks # solution 1. Exporting the inner type
|
||||
|
||||
type MagicCompile = object
|
||||
dq: ListDeque[Task]
|
||||
|
||||
# var x: MagicCompile # solution 2. Instantiating the type with destructors
|
||||
echo "Success"
|
||||
|
||||
type
|
||||
TLContext* = object
|
||||
deque*: ListDeque[Task]
|
||||
@@ -1,5 +0,0 @@
|
||||
type Foo* = object
|
||||
x*, y*: int
|
||||
|
||||
proc `$`*(f: Foo): string =
|
||||
"Foo(" & $f.x & ", " & $f.y & ")"
|
||||
@@ -1,7 +0,0 @@
|
||||
import mdollar1
|
||||
|
||||
proc makeFoo*(x, y: int): Foo =
|
||||
Foo(x: x, y: y)
|
||||
|
||||
proc useFoo*(f: Foo) =
|
||||
echo "used: ", f # directly calls `foo.$` from scope
|
||||
@@ -1,2 +0,0 @@
|
||||
proc debug*[T](obj: T) =
|
||||
echo "debugging: ", obj # calls generic `$`
|
||||
@@ -1,11 +0,0 @@
|
||||
import mhandles
|
||||
|
||||
type
|
||||
File* = ref object
|
||||
handle: Handle[FD]
|
||||
|
||||
proc close*[T: File](f: T) =
|
||||
f.handle.close()
|
||||
|
||||
proc newFile*(fd: FD): File =
|
||||
File(handle: initHandle(FD -1))
|
||||
@@ -1,19 +0,0 @@
|
||||
type
|
||||
FD* = distinct cint
|
||||
|
||||
type
|
||||
AnyFD* = concept fd
|
||||
close(fd)
|
||||
|
||||
proc close*(fd: FD) =
|
||||
discard
|
||||
|
||||
type
|
||||
Handle*[T: AnyFD] = object
|
||||
fd: T
|
||||
|
||||
proc close*[T: AnyFD](h: var Handle[T]) =
|
||||
close h.fd
|
||||
|
||||
proc initHandle*[T: AnyFD](fd: T): Handle[T] =
|
||||
Handle[T](fd: fd)
|
||||
@@ -1,52 +0,0 @@
|
||||
import sets, hashes
|
||||
|
||||
type
|
||||
Fruit* = ref object
|
||||
id*: int
|
||||
|
||||
# Generic implementation. This doesn't work
|
||||
EntGroup*[T] = ref object
|
||||
freed*: HashSet[T]
|
||||
|
||||
proc hash*(self: Fruit): Hash = hash(self.id)
|
||||
|
||||
##
|
||||
## VVV The Generic implementation. This doesn't work VVV
|
||||
##
|
||||
|
||||
proc initEntGroup*[T: Fruit](): EntGroup[T] =
|
||||
result = EntGroup[T]()
|
||||
result.freed = initHashSet[Fruit]()
|
||||
var apple = Fruit(id: 20)
|
||||
result.freed.incl(apple)
|
||||
|
||||
proc get*[T: Fruit](fg: EntGroup[T]): T =
|
||||
if len(fg.freed) == 0: return
|
||||
# vvv It errors here
|
||||
# type mismatch: ([1] fg.freed: HashSet[grouptest.Fruit])
|
||||
for it in fg.freed:
|
||||
return it
|
||||
|
||||
##
|
||||
## VVV The Non-Generic implementation works VVV
|
||||
##
|
||||
type
|
||||
# Non-generic implementation. This works.
|
||||
FruitGroup* = ref object
|
||||
freed*: HashSet[Fruit]
|
||||
|
||||
proc initFruitGroup*(): FruitGroup =
|
||||
result = FruitGroup()
|
||||
result.freed = initHashSet[Fruit]()
|
||||
var apple = Fruit(id: 20)
|
||||
result.freed.incl(apple)
|
||||
|
||||
proc getNoGeneric*(fg: FruitGroup): Fruit =
|
||||
if len(fg.freed) == 0: return
|
||||
for it in fg.freed:
|
||||
return it
|
||||
|
||||
proc `$`*(self: Fruit): string =
|
||||
# For echo
|
||||
if self == nil: return "Fruit()"
|
||||
return "Fruit(" & $(self.id) & ")"
|
||||
@@ -1,35 +0,0 @@
|
||||
# listdeques
|
||||
|
||||
# needed, type bound ops aren't considered for undeclared procs
|
||||
type Placeholder = object
|
||||
proc allocate(_: Placeholder) = discard
|
||||
proc delete(_: Placeholder) = discard
|
||||
|
||||
type
|
||||
StealableTask* = concept task, var mutTask, type T
|
||||
task is ptr
|
||||
task.prev is T
|
||||
task.next is T
|
||||
task.parent is T
|
||||
task.fn is proc (param: pointer) {.nimcall.}
|
||||
allocate(mutTask)
|
||||
delete(task)
|
||||
|
||||
ListDeque*[T: StealableTask] = object
|
||||
head, tail: T
|
||||
|
||||
func isEmpty*(dq: ListDeque): bool {.inline.} =
|
||||
discard
|
||||
|
||||
func popFirst*[T](dq: var ListDeque[T]): T =
|
||||
discard
|
||||
|
||||
proc `=destroy`*[T: StealableTask](dq: var ListDeque[T]) =
|
||||
mixin delete
|
||||
if dq.isEmpty():
|
||||
return
|
||||
|
||||
while (let task = dq.popFirst(); not task.isNil):
|
||||
delete(task)
|
||||
|
||||
delete(dq.head)
|
||||
@@ -1,80 +0,0 @@
|
||||
import hashes
|
||||
|
||||
type
|
||||
Obj* = object
|
||||
x*, y*: int
|
||||
z*: string # to be ignored for equality
|
||||
|
||||
proc `==`*(a, b: Obj): bool =
|
||||
a.x == b.x and a.y == b.y
|
||||
|
||||
proc hash*(a: Obj): Hash =
|
||||
!$(hash(a.x) !& hash(a.y))
|
||||
|
||||
type
|
||||
RefObj* = ref object
|
||||
x*, y*: int
|
||||
z*: string # to be ignored for equality
|
||||
|
||||
proc `==`*(a, b: RefObj): bool =
|
||||
a.x == b.x and a.y == b.y
|
||||
|
||||
proc hash*(a: RefObj): Hash =
|
||||
!$(hash(a.x) !& hash(a.y))
|
||||
|
||||
type
|
||||
GenericObj1*[T] = object
|
||||
x*, y*: T
|
||||
z*: string # to be ignored for equality
|
||||
|
||||
proc `==`*[T](a, b: GenericObj1[T]): bool =
|
||||
a.x == b.x and a.y == b.y
|
||||
|
||||
proc hash*[T](a: GenericObj1[T]): Hash =
|
||||
!$(hash(a.x) !& hash(a.y))
|
||||
|
||||
type
|
||||
GenericObj2*[T] = object
|
||||
x*, y*: T
|
||||
z*: string # to be ignored for equality
|
||||
|
||||
proc `==`*(a, b: GenericObj2): bool =
|
||||
a.x == b.x and a.y == b.y
|
||||
|
||||
proc hash*(a: GenericObj2): Hash =
|
||||
!$(hash(a.x) !& hash(a.y))
|
||||
|
||||
type
|
||||
GenericObj3*[T] = object
|
||||
x*, y*: T
|
||||
z*: string # to be ignored for equality
|
||||
GenericObj3Alias*[T] = GenericObj3[T]
|
||||
|
||||
proc `==`*[T](a, b: GenericObj3Alias[T]): bool =
|
||||
a.x == b.x and a.y == b.y
|
||||
|
||||
proc hash*[T](a: GenericObj3Alias[T]): Hash =
|
||||
!$(hash(a.x) !& hash(a.y))
|
||||
|
||||
type
|
||||
GenericObj4*[T] = object
|
||||
x*, y*: T
|
||||
z*: string # to be ignored for equality
|
||||
GenericObj4Alias*[T] = GenericObj4[T]
|
||||
|
||||
proc `==`*(a, b: GenericObj4): bool =
|
||||
a.x == b.x and a.y == b.y
|
||||
|
||||
proc hash*(a: GenericObj4): Hash =
|
||||
!$(hash(a.x) !& hash(a.y))
|
||||
|
||||
type
|
||||
GenericRefObj*[T] = ref object
|
||||
x*, y*: T
|
||||
z*: string # to be ignored for equality
|
||||
|
||||
proc `==`*[T](a, b: GenericRefObj[T]): bool =
|
||||
a.x == b.x and a.y == b.y
|
||||
|
||||
proc hash*[T](a: GenericRefObj[T]): Hash =
|
||||
!$(hash(a.x) !& hash(a.y))
|
||||
@@ -1,13 +0,0 @@
|
||||
# original example used queues
|
||||
import deques
|
||||
|
||||
type
|
||||
QueueContainer*[T] = object
|
||||
q: ref Deque[T]
|
||||
|
||||
proc init*[T](c: var QueueContainer[T]) =
|
||||
new(c.q)
|
||||
c.q[] = initDeque[T](64)
|
||||
|
||||
proc addToQ*[T](c: var QueueContainer[T], item: T) =
|
||||
c.q[].addLast(item)
|
||||
@@ -1,10 +0,0 @@
|
||||
import std/sets
|
||||
template foo*[T](a: T) =
|
||||
# proc foo*[T](a: T) = # works
|
||||
var s: HashSet[T]
|
||||
# echo contains(s, a) # works
|
||||
let x = a in s # BUG
|
||||
doAssert not x
|
||||
doAssert not (a in s)
|
||||
doAssert a notin s
|
||||
when isMainModule: foo(1) # works
|
||||
@@ -1,7 +0,0 @@
|
||||
import sets
|
||||
|
||||
proc initH*[V]: HashSet[V] =
|
||||
result = initHashSet[V]()
|
||||
|
||||
proc foo*[V](h: var HashSet[V], c: seq[V]) =
|
||||
h = h + c.toHashSet()
|
||||
@@ -1,4 +0,0 @@
|
||||
import sets, sequtils
|
||||
|
||||
proc dedupe*[T](arr: openArray[T]): seq[T] =
|
||||
arr.toHashSet.toSeq
|
||||
@@ -1,8 +0,0 @@
|
||||
type Foo* = object
|
||||
x*, y*: int
|
||||
|
||||
proc `$`*(x: static Foo): string =
|
||||
"static Foo(" & $x.x & ", " & $x.y & ")"
|
||||
|
||||
proc `$`*(x: Foo): string =
|
||||
"runtime Foo(" & $x.x & ", " & $x.y & ")"
|
||||
@@ -1,14 +0,0 @@
|
||||
# tasks.nim
|
||||
type
|
||||
Task* = ptr object
|
||||
parent*: Task
|
||||
prev*: Task
|
||||
next*: Task
|
||||
fn*: proc (param: pointer) {.nimcall.}
|
||||
|
||||
# StealableTask API
|
||||
proc allocate*(task: var Task) =
|
||||
discard
|
||||
|
||||
proc delete*(task: Task) =
|
||||
discard
|
||||
@@ -1,12 +0,0 @@
|
||||
discard """
|
||||
output: '''
|
||||
Success
|
||||
'''
|
||||
"""
|
||||
|
||||
# modified issue #12620, see placeholder procs in mlistdeques
|
||||
|
||||
# runtime.nim
|
||||
import ./mcontext_thread_local
|
||||
|
||||
var localCtx* : TLContext
|
||||
@@ -1,12 +0,0 @@
|
||||
discard """
|
||||
output: '''
|
||||
used: Foo(123, 456)
|
||||
debugging: Foo(123, 456)
|
||||
'''
|
||||
"""
|
||||
|
||||
import mdollar2, mdollar3 # `mdollar1` not imported, so `mdollar1.$` not in scope
|
||||
|
||||
let f = makeFoo(123, 456)
|
||||
useFoo(f) # used: Foo(123, 456)
|
||||
debug(f) # debugging: Foo(123, 456)
|
||||
@@ -1,8 +0,0 @@
|
||||
# issue #16755
|
||||
|
||||
import mfiles
|
||||
from mhandles import FD
|
||||
#import handles <- do this and it works
|
||||
|
||||
let wr = newFile(FD -1)
|
||||
close wr
|
||||
@@ -1,13 +0,0 @@
|
||||
# issue #22984
|
||||
# import sets # <<-- Uncomment this to make the error go away
|
||||
|
||||
import mitems
|
||||
|
||||
## The generic implementation
|
||||
var grp: EntGroup[Fruit] = initEntGroup[Fruit]()
|
||||
doAssert $get(grp) == "Fruit(20)" ## Errors here
|
||||
|
||||
|
||||
## This works though (Non-generic)
|
||||
var fruitGroup: FruitGroup = initFruitGroup()
|
||||
doAssert $getNoGeneric(fruitGroup) == "Fruit(20)"
|
||||
@@ -1,59 +0,0 @@
|
||||
# https://github.com/nim-lang/RFCs/issues/380
|
||||
|
||||
from mobjhash import Obj, RefObj, GenericObj1, GenericObj2, GenericObj3, GenericObj4, GenericRefObj
|
||||
import tables
|
||||
|
||||
block:
|
||||
var t: Table[Obj, int]
|
||||
t[Obj(x: 3, y: 4, z: "debug")] = 34
|
||||
doAssert t[Obj(x: 3, y: 4, z: "ignored")] == 34
|
||||
doAssert Obj(x: 4, y: 3, z: "debug") notin t
|
||||
|
||||
block:
|
||||
var t: Table[RefObj, int]
|
||||
t[RefObj(x: 3, y: 4, z: "debug")] = 34
|
||||
doAssert t[RefObj(x: 3, y: 4, z: "ignored")] == 34
|
||||
doAssert RefObj(x: 4, y: 3, z: "debug") notin t
|
||||
|
||||
block:
|
||||
var t: Table[GenericObj1[float], int]
|
||||
t[GenericObj1[float](x: 3, y: 4, z: "debug")] = 34
|
||||
doAssert t[GenericObj1[float](x: 3, y: 4, z: "ignored")] == 34
|
||||
doAssert GenericObj1[float](x: 4, y: 3, z: "debug") notin t
|
||||
|
||||
block:
|
||||
var t: Table[GenericObj1[int], int]
|
||||
t[GenericObj1[int](x: 3, y: 4, z: "debug")] = 34
|
||||
doAssert t[GenericObj1[int](x: 3, y: 4, z: "ignored")] == 34
|
||||
doAssert GenericObj1[int](x: 4, y: 3, z: "debug") notin t
|
||||
|
||||
block:
|
||||
var t: Table[GenericObj2[float], int]
|
||||
t[GenericObj2[float](x: 3, y: 4, z: "debug")] = 34
|
||||
doAssert t[GenericObj2[float](x: 3, y: 4, z: "ignored")] == 34
|
||||
doAssert GenericObj2[float](x: 4, y: 3, z: "debug") notin t
|
||||
|
||||
block:
|
||||
var t: Table[GenericObj3[float], int]
|
||||
t[GenericObj3[float](x: 3, y: 4, z: "debug")] = 34
|
||||
doAssert t[GenericObj3[float](x: 3, y: 4, z: "ignored")] == 34
|
||||
doAssert GenericObj3[float](x: 4, y: 3, z: "debug") notin t
|
||||
|
||||
block:
|
||||
var t: Table[GenericObj4[float], int]
|
||||
t[GenericObj4[float](x: 3, y: 4, z: "debug")] = 34
|
||||
doAssert t[GenericObj4[float](x: 3, y: 4, z: "ignored")] == 34
|
||||
doAssert GenericObj4[float](x: 4, y: 3, z: "debug") notin t
|
||||
|
||||
block:
|
||||
var t: Table[GenericRefObj[float], int]
|
||||
t[GenericRefObj[float](x: 3, y: 4, z: "debug")] = 34
|
||||
doAssert t[GenericRefObj[float](x: 3, y: 4, z: "ignored")] == 34
|
||||
doAssert GenericRefObj[float](x: 4, y: 3, z: "debug") notin t
|
||||
|
||||
block:
|
||||
type LocalAlias[T] = GenericObj4[T]
|
||||
var t: Table[LocalAlias[float], int]
|
||||
t[LocalAlias[float](x: 3, y: 4, z: "debug")] = 34
|
||||
doAssert t[LocalAlias[float](x: 3, y: 4, z: "ignored")] == 34
|
||||
doAssert LocalAlias[float](x: 4, y: 3, z: "debug") notin t
|
||||
@@ -1,10 +0,0 @@
|
||||
# issue #4773
|
||||
|
||||
import mqueuecontainer
|
||||
|
||||
# works if this is uncommented (or if the `queuecontainer` exports `queues`):
|
||||
# import queues
|
||||
|
||||
var c: QueueContainer[int]
|
||||
c.init()
|
||||
c.addToQ(1)
|
||||
@@ -1,24 +0,0 @@
|
||||
# issue #14729
|
||||
|
||||
import sets, hashes
|
||||
|
||||
type
|
||||
Iterable[T] = concept x
|
||||
for value in items(x):
|
||||
type(value) is T
|
||||
|
||||
Foo[T] = object
|
||||
t: T
|
||||
|
||||
proc myToSet[T](keys: Iterable[T]): HashSet[T] =
|
||||
for x in items(keys): result.incl(x)
|
||||
|
||||
proc hash[T](foo: Foo[T]): Hash =
|
||||
echo "specific hash"
|
||||
|
||||
proc `==`[T](lhs, rhs: Foo[T]): bool =
|
||||
echo "specific equals"
|
||||
|
||||
let
|
||||
f = Foo[string](t: "test")
|
||||
hs = [f, f].myToSet()
|
||||
@@ -1,4 +0,0 @@
|
||||
# issue #18150
|
||||
|
||||
import msetin
|
||||
foo(1)
|
||||
@@ -1,17 +0,0 @@
|
||||
# comment on issue #11167
|
||||
|
||||
import hashes
|
||||
|
||||
import msetiter1
|
||||
|
||||
type
|
||||
Choice = object
|
||||
i: int
|
||||
|
||||
proc hash(c: Choice): Hash =
|
||||
result = Hash(c.i)
|
||||
|
||||
var h = initH[Choice]()
|
||||
let c = @[Choice(i: 1)]
|
||||
|
||||
foo(h, c)
|
||||
@@ -1,9 +0,0 @@
|
||||
# comment on issue #11167
|
||||
|
||||
import msetiter2
|
||||
|
||||
let x = dedupe([1, 2, 3])
|
||||
doAssert x.len == 3
|
||||
doAssert 1 in x
|
||||
doAssert 2 in x
|
||||
doAssert 3 in x
|
||||
@@ -1,5 +0,0 @@
|
||||
from mstatic import Foo
|
||||
|
||||
doAssert $Foo(x: 1, y: 2) == "static Foo(1, 2)"
|
||||
let foo = Foo(x: 3, y: 4)
|
||||
doAssert $foo == "runtime Foo(3, 4)"
|
||||
@@ -159,76 +159,17 @@ INNER JOIN b
|
||||
ON a.id == b.id
|
||||
""") == "select id from a inner join b on a.id == b.id;"
|
||||
|
||||
# For OUTER joins, LEFT | RIGHT | FULL specifier is not optional
|
||||
doAssertRaises(SqlParseError): discard parseSql("""
|
||||
doAssert $parseSql("""
|
||||
SELECT id FROM a
|
||||
OUTER JOIN b
|
||||
ON a.id = b.id
|
||||
""")
|
||||
ON a.id == b.id
|
||||
""") == "select id from a outer join b on a.id == b.id;"
|
||||
|
||||
# For NATURAL JOIN and CROSS JOIN, ON and USING clauses are forbidden
|
||||
doAssertRaises(SqlParseError): discard parseSql("""
|
||||
doAssert $parseSql("""
|
||||
SELECT id FROM a
|
||||
CROSS JOIN b
|
||||
ON a.id = b.id
|
||||
""")
|
||||
|
||||
# JOIN should parse as part of FROM, not after WHERE
|
||||
doAssertRaises(SqlParseError): discard parseSql("""
|
||||
SELECT id FROM a
|
||||
WHERE a.id IS NOT NULL
|
||||
INNER JOIN b
|
||||
ON a.id = b.id
|
||||
""")
|
||||
|
||||
# JOIN should parse as part of FROM, other fromItems may follow
|
||||
doAssert $parseSql("""
|
||||
SELECT id
|
||||
FROM
|
||||
a JOIN b ON a.id = b.id,
|
||||
c
|
||||
""") == "select id from a join b on a.id = b.id, c;"
|
||||
|
||||
# LEFT JOIN should parse
|
||||
doAssert $parseSql("""
|
||||
SELECT id FROM a
|
||||
LEFT JOIN b
|
||||
ON a.id = b.id
|
||||
""") == "select id from a left join b on a.id = b.id;"
|
||||
|
||||
# NATURAL JOIN should parse
|
||||
doAssert $parseSql("""
|
||||
SELECT id FROM a
|
||||
NATURAL JOIN b
|
||||
""") == "select id from a natural join b;"
|
||||
|
||||
# USING should parse
|
||||
doAssert $parseSql("""
|
||||
SELECT id FROM a
|
||||
JOIN b
|
||||
USING (id)
|
||||
""") == "select id from a join b using (id );"
|
||||
|
||||
# Multiple JOINs should parse
|
||||
doAssert $parseSql("""
|
||||
SELECT id FROM a
|
||||
JOIN b
|
||||
ON a.id = b.id
|
||||
LEFT JOIN c
|
||||
USING (id)
|
||||
""") == "select id from a join b on a.id = b.id left join c using (id );"
|
||||
|
||||
# Parenthesized JOIN expressions should parse
|
||||
doAssert $parseSql("""
|
||||
SELECT id
|
||||
FROM a JOIN (b JOIN c USING (id)) ON a.id = b.id
|
||||
""") == "select id from a join(b join c using (id )) on a.id = b.id;"
|
||||
|
||||
# Left-side parenthesized JOIN expressions should parse
|
||||
doAssert $parseSql("""
|
||||
SELECT id
|
||||
FROM (b JOIN c USING (id)) JOIN a ON a.id = b.id
|
||||
""") == "select id from b join c using (id ) join a on a.id = b.id;"
|
||||
ON a.id == b.id
|
||||
""") == "select id from a cross join b on a.id == b.id;"
|
||||
|
||||
doAssert $parseSql("""
|
||||
CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
|
||||
|
||||
@@ -105,48 +105,4 @@ block timplicit_with_partial:
|
||||
echo x
|
||||
echo x
|
||||
|
||||
foo(FooTask())
|
||||
|
||||
block: # issue #24338
|
||||
var innerCount = 0
|
||||
var outerCount = 0
|
||||
template c(w: int): int =
|
||||
let q = w
|
||||
inc innerCount
|
||||
0
|
||||
|
||||
template t(r: (int, int); x: int) =
|
||||
for _ in r.fields:
|
||||
let w = x
|
||||
doAssert w == 0
|
||||
dec outerCount
|
||||
|
||||
proc k() =
|
||||
t((0, 0), c(0))
|
||||
|
||||
k()
|
||||
doAssert innerCount == 2
|
||||
doAssert outerCount == -2
|
||||
|
||||
block: # issue #24338 with object
|
||||
type Foo = object
|
||||
x, y: int
|
||||
var innerCount = 0
|
||||
var outerCount = 0
|
||||
template c(w: int): int =
|
||||
let q = w
|
||||
inc innerCount
|
||||
0
|
||||
|
||||
template t(r: Foo; x: int) =
|
||||
for _ in r.fields:
|
||||
let w = x
|
||||
doAssert w == 0
|
||||
dec outerCount
|
||||
|
||||
proc k() =
|
||||
t(Foo(x: 0, y: 0), c(0))
|
||||
|
||||
k()
|
||||
doAssert innerCount == 2
|
||||
doAssert outerCount == -2
|
||||
foo(FooTask())
|
||||
@@ -9,8 +9,7 @@
|
||||
## nim r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:nimDisableCertificateValidation -d:ssl -p:. tests/untestable/thttpclient_ssl_disabled.nim
|
||||
|
||||
from stdtest/testutils import enableRemoteNetworking
|
||||
# badssl tests disabled indefinitely
|
||||
when false and enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(openbsd)):
|
||||
when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(openbsd)):
|
||||
import httpclient, net, unittest
|
||||
|
||||
const expired = "https://expired.badssl.com/"
|
||||
|
||||
@@ -19,6 +19,7 @@ from net import newSocket, newContext, wrapSocket, connect, close, Port,
|
||||
from strutils import contains
|
||||
|
||||
const
|
||||
expired = "https://expired.badssl.com/"
|
||||
good = "https://google.com/"
|
||||
|
||||
|
||||
@@ -55,13 +56,12 @@ suite "SSL certificate check":
|
||||
var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars)
|
||||
ctx.wrapSocket(sock)
|
||||
checkpoint("Socket created")
|
||||
when false: # badssl tests disabled indefinitely
|
||||
try:
|
||||
sock.connect("expired.badssl.com", 443.Port)
|
||||
fail()
|
||||
except:
|
||||
sock.close
|
||||
check getCurrentExceptionMsg().contains("certificate verify failed")
|
||||
try:
|
||||
sock.connect("expired.badssl.com", 443.Port)
|
||||
fail()
|
||||
except:
|
||||
sock.close
|
||||
check getCurrentExceptionMsg().contains("certificate verify failed")
|
||||
|
||||
elif existsEnv("SSL_CERT_DIR"):
|
||||
var sock = newSocket()
|
||||
|
||||
@@ -33,8 +33,7 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win
|
||||
CertTest = tuple[url:string, category:Category, desc: string]
|
||||
|
||||
# badssl certs sometimes expire, set to false when that happens
|
||||
# badssl now disabled indefinitely
|
||||
when false:
|
||||
when true:
|
||||
const certificate_tests: array[0..54, CertTest] = [
|
||||
("https://wrong.host.badssl.com/", bad, "wrong.host"),
|
||||
("https://captive-portal.badssl.com/", bad, "captive-portal"),
|
||||
@@ -198,7 +197,7 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win
|
||||
|
||||
type NetSocketTest = tuple[hostname: string, port: Port, category:Category, desc: string]
|
||||
# badssl certs sometimes expire, set to false when that happens
|
||||
when false:
|
||||
when true:
|
||||
const net_tests:array[0..3, NetSocketTest] = [
|
||||
("imap.gmail.com", 993.Port, good, "IMAP"),
|
||||
("wrong.host.badssl.com", 443.Port, bad, "wrong.host"),
|
||||
|
||||
@@ -16,18 +16,3 @@ const G = proc ():int =
|
||||
y()
|
||||
|
||||
echo G()
|
||||
|
||||
|
||||
block: # bug #24359
|
||||
block:
|
||||
proc h(_: bool) = discard
|
||||
const m = h
|
||||
static: m(true) # works
|
||||
m(true) # does not work
|
||||
|
||||
block:
|
||||
block:
|
||||
proc h(_: bool): int = result = 1
|
||||
const m = h
|
||||
static: doAssert m(true) == 1 # works
|
||||
doAssert m(true) == 1 # does not work
|
||||
|
||||
Reference in New Issue
Block a user