Compare commits

..

5 Commits

Author SHA1 Message Date
ringabout
3e6a2a13d9 fixes 2024-10-22 21:53:56 +08:00
ringabout
8af81e3d24 redefining field variables is disabled 2024-10-22 21:51:19 +08:00
ringabout
aca59572c7 oops 2024-10-22 21:40:57 +08:00
ringabout
07463c00fc wordy 2024-10-22 21:34:45 +08:00
ringabout
1c79ef1090 prohibits field variables from being used as lvalues in a 'fields' loop 2024-10-22 21:32:39 +08:00
88 changed files with 1450 additions and 3653 deletions

76
.github/workflows/ci_gcc14.yml vendored Normal file
View 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

View File

@@ -4,7 +4,6 @@ on:
push:
branches:
- 'devel'
- 'version-2-2'
- 'version-2-0'
- 'version-1-6'
- 'version-1-2'

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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")

View File

@@ -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 & ")"

View File

@@ -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")

View File

@@ -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

View File

@@ -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)

View File

@@ -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),

View File

@@ -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 != "":

View File

@@ -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

View File

@@ -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)

View File

@@ -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(

View File

@@ -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
View 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

View File

@@ -229,7 +229,6 @@ type
# alternative to above:
genericsOpenSym
vtables
typeBoundOps
LegacyFeature* = enum
allowSemcheckedAstModification,

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -17,17 +17,9 @@ type
field: PSym
replaceByFieldName: bool
c: PContext
leftPartOfDefinition: bool
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 =
proc instFieldLoopBody(c: var TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
if c.field != nil and isEmptyType(c.field.typ):
result = newNode(nkEmpty)
return
@@ -38,6 +30,9 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
let ident = considerQuotedIdent(c.c, n)
if c.replaceByFieldName:
if ident.id == considerQuotedIdent(c.c, forLoop[0]).id:
if c.leftPartOfDefinition:
localError(c.c.config, n.info,
"redefine field variable '$1' in a 'fields' loop" % [ident.s])
let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
else: c.tupleType.n[c.tupleIndex].sym.name.s
@@ -46,6 +41,9 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
# other fields:
for i in ord(c.replaceByFieldName)..<forLoop.len-2:
if ident.id == considerQuotedIdent(c.c, forLoop[i]).id:
if c.leftPartOfDefinition:
localError(c.c.config, n.info,
"redefine field variable '$1' in a 'fields' loop" % [ident.s])
var call = forLoop[^2]
var tupl = call[i+1-ord(c.replaceByFieldName)]
if c.field.isNil:
@@ -57,6 +55,13 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
result.add(tupl)
result.add(newSymNode(c.field, n.info))
break
of nkIdentDefs, nkVarTuple, nkConstDef:
result = shallowCopy(n)
c.leftPartOfDefinition = true
result[0] = instFieldLoopBody(c, n[0], forLoop)
c.leftPartOfDefinition = false
for i in 1..<n.len:
result[i] = instFieldLoopBody(c, n[i], forLoop)
else:
if n.kind == nkContinueStmt:
localError(c.c.config, n.info,
@@ -81,9 +86,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 +162,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

View File

@@ -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 =

View File

@@ -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 =

View File

@@ -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)

View File

@@ -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

View File

@@ -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:

View File

@@ -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})

View File

@@ -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

View File

@@ -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

View File

@@ -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)
```

View File

@@ -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

View File

@@ -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

View File

@@ -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))
## ```
##

View File

@@ -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")

View File

@@ -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".} =

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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)

View File

@@ -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())[])

View File

@@ -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

View File

@@ -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()

View File

@@ -43,4 +43,3 @@ when not defined(testsConciseTypeMismatch):
switch("legacy", "verboseTypeMismatch")
switch("experimental", "vtables")
switch("experimental", "openSym")
switch("experimental", "typeBoundOps")

View File

@@ -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()

View File

@@ -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()

View File

@@ -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]

View File

@@ -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]])

View File

@@ -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

View File

@@ -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()

View File

@@ -1 +0,0 @@
switch("experimental", "typeBoundOps")

View File

@@ -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]

View File

@@ -1,5 +0,0 @@
type Foo* = object
x*, y*: int
proc `$`*(f: Foo): string =
"Foo(" & $f.x & ", " & $f.y & ")"

View File

@@ -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

View File

@@ -1,2 +0,0 @@
proc debug*[T](obj: T) =
echo "debugging: ", obj # calls generic `$`

View File

@@ -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))

View File

@@ -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)

View File

@@ -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) & ")"

View File

@@ -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)

View File

@@ -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))

View File

@@ -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)

View File

@@ -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

View File

@@ -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()

View File

@@ -1,4 +0,0 @@
import sets, sequtils
proc dedupe*[T](arr: openArray[T]): seq[T] =
arr.toHashSet.toSeq

View File

@@ -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 & ")"

View File

@@ -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

View File

@@ -1,12 +0,0 @@
discard """
output: '''
Success
'''
"""
# modified issue #12620, see placeholder procs in mlistdeques
# runtime.nim
import ./mcontext_thread_local
var localCtx* : TLContext

View File

@@ -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)

View File

@@ -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

View File

@@ -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)"

View File

@@ -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

View File

@@ -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)

View File

@@ -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()

View File

@@ -1,4 +0,0 @@
# issue #18150
import msetin
foo(1)

View File

@@ -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)

View File

@@ -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

View File

@@ -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)"

View File

@@ -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');

View File

@@ -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())

View File

@@ -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/"

View File

@@ -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()

View File

@@ -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"),

View File

@@ -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