diff --git a/.github/workflows/bisects.yml b/.github/workflows/bisects.yml index e73736d2996a..4a6a92f018a0 100644 --- a/.github/workflows/bisects.yml +++ b/.github/workflows/bisects.yml @@ -22,5 +22,10 @@ jobs: nim-version: 'devel' - uses: juancarlospaco/nimrun-action@nim + if: | + runner.os == 'Linux' && contains(github.event.comment.body, '-d:linux' ) || + runner.os == 'Windows' && contains(github.event.comment.body, '-d:windows') || + runner.os == 'macOS' && contains(github.event.comment.body, '-d:osx' ) || + runner.os == 'Linux' && !contains(github.event.comment.body, '-d:linux') && !contains(github.event.comment.body, '-d:windows') && !contains(github.event.comment.body, '-d:osx') with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci_bench.yml b/.github/workflows/ci_bench.yml index 535b52355b44..7c76ed89bc1f 100644 --- a/.github/workflows/ci_bench.yml +++ b/.github/workflows/ci_bench.yml @@ -21,10 +21,10 @@ jobs: with: fetch-depth: 2 - - name: 'Install node.js 16.x' - uses: actions/setup-node@v3 + - name: 'Install node.js 20.x' + uses: actions/setup-node@v4 with: - node-version: '16.x' + node-version: '20.x' - name: 'Install dependencies (Linux amd64)' if: runner.os == 'Linux' && matrix.cpu == 'amd64' diff --git a/.github/workflows/ci_packages.yml b/.github/workflows/ci_packages.yml index 1dabd6077140..91ac83aecd14 100644 --- a/.github/workflows/ci_packages.yml +++ b/.github/workflows/ci_packages.yml @@ -32,10 +32,10 @@ jobs: with: fetch-depth: 2 - - name: 'Install node.js 16.x' - uses: actions/setup-node@v3 + - name: 'Install node.js 20.x' + uses: actions/setup-node@v4 with: - node-version: '16.x' + node-version: '20.x' - name: 'Install dependencies (Linux amd64)' if: runner.os == 'Linux' && matrix.cpu == 'amd64' diff --git a/.github/workflows/ci_publish.yml b/.github/workflows/ci_publish.yml index 26c617a8e3e8..58da92206dea 100644 --- a/.github/workflows/ci_publish.yml +++ b/.github/workflows/ci_publish.yml @@ -21,10 +21,10 @@ jobs: with: fetch-depth: 2 - - name: 'Install node.js 16.x' - uses: actions/setup-node@v3 + - name: 'Install node.js 20.x' + uses: actions/setup-node@v4 with: - node-version: '16.x' + node-version: '20.x' - name: 'Install dependencies (Linux amd64)' if: runner.os == 'Linux' && matrix.cpu == 'amd64' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5809084f030f..3f20fb86690c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -73,8 +73,8 @@ jobs: - task: NodeTool@0 inputs: - versionSpec: '16.x' - displayName: 'Install node.js 16.x' + versionSpec: '20.x' + displayName: 'Install node.js 20.x' condition: and(succeeded(), eq(variables['skipci'], 'false')) - bash: | diff --git a/changelog.md b/changelog.md index 72d0a2a2dd7a..3351a6f7a052 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,8 @@ ## Changes affecting backward compatibility +- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility. +- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/` instead of `Nim httpclient/` which was incorrect according to the HTTP spec. ## Standard library additions and changes @@ -10,6 +12,7 @@ - Changed `std/osfiles.copyFile` to allow to specify `bufferSize` instead of a hardcoded one. - Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads. +- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it. [//]: # "Additions:" @@ -29,6 +32,9 @@ slots when enlarging a sequence. ## Language changes - `noInit` can be used in types and fields to disable member initializers in the C++ backend. +- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.htm#constructor-initializer +- `member` can be used to attach a procedure to a C++ type. +- C++ `constructor` now reuses `result` instead creating `this`. ## Compiler changes diff --git a/compiler/aliases.nim b/compiler/aliases.nim index fa9824c41e47..40d6e272c68f 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -10,7 +10,9 @@ ## Simple alias analysis for the HLO and the code generators. import - ast, astalgo, types, trees, intsets + ast, astalgo, types, trees + +import std/intsets when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/ast.nim b/compiler/ast.nim index 3017aedcf6e8..661a82703c5d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,8 +10,10 @@ # abstract syntax tree + symbol table import - lineinfos, hashes, options, ropes, idents, int128, tables, wordrecg -from strutils import toLowerAscii + lineinfos, options, ropes, idents, int128, wordrecg + +import std/[tables, hashes] +from std/strutils import toLowerAscii when defined(nimPreviewSlimSystem): import std/assertions @@ -901,6 +903,7 @@ type info*: TLineInfo when defined(nimsuggest): endInfo*: TLineInfo + hasUserSpecifiedType*: bool # used for determining whether to display inlay type hints owner*: PSym flags*: TSymFlags ast*: PNode # syntax tree of proc, iterator, etc.: @@ -924,7 +927,7 @@ type # for variables a slot index for the evaluator offset*: int32 # offset of record field disamb*: int32 # disambiguation number; the basic idea is that - # `___` + # `___` is unique loc*: TLoc annex*: PLib # additional fields (seldom used, so we use a # reference to another object to save space) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 1873d231fe8c..720f6087f966 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -12,10 +12,11 @@ # the data structures here are used in various places of the compiler. import - ast, hashes, intsets, options, lineinfos, ropes, idents, rodutils, + ast, options, lineinfos, ropes, idents, rodutils, msgs -import strutils except addf +import std/[hashes, intsets] +import std/strutils except addf when defined(nimPreviewSlimSystem): import std/assertions @@ -408,7 +409,7 @@ proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1 var marker = initIntSet() result = symToYamlAux(conf, n, marker, indent, maxRecDepth) -import tables +import std/tables const backrefStyle = "\e[90m" const enumStyle = "\e[34m" diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 494f3c8c698e..ad84be3f9ed8 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -221,7 +221,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) = let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0]) result.add x & ", " & y else: - var a: TLoc = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n) + var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n) case skipTypes(a.t, abstractVar+{tyStatic}).kind of tyOpenArray, tyVarargs: if reifiedOpenArray(n): @@ -277,7 +277,7 @@ proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc = genAssignment(p, result, a, {}) proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} = - var a: TLoc = initLocExpr(p, n[0]) + var a = initLocExpr(p, n[0]) appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc]) proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) = @@ -287,7 +287,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: var n = if n.kind != nkHiddenAddr: n else: n[0] openArrayLoc(p, param.typ, n, result) - elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and + elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and (optByRef notin param.options or not p.module.compileToCpp): a = initLocExpr(p, n) if n.kind in {nkCharLit..nkNilLit}: @@ -417,7 +417,7 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) = proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = # this is a hotspot in the compiler - var op: TLoc = initLocExpr(p, ri[0]) + var op = initLocExpr(p, ri[0]) # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInstOwned) assert(typ.kind == tyProc) @@ -439,7 +439,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)" const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists - var op: TLoc = initLocExpr(p, ri[0]) + var op = initLocExpr(p, ri[0]) # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInstOwned) @@ -672,7 +672,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro result.add(substr(pat, start, i - 1)) proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = - var op: TLoc = initLocExpr(p, ri[0]) + var op = initLocExpr(p, ri[0]) # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInst) assert(typ.kind == tyProc) @@ -716,7 +716,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = # generates a crappy ObjC call - var op: TLoc = initLocExpr(p, ri[0]) + var op = initLocExpr(p, ri[0]) var pl = "[" # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInst) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index eca6fa9958a1..2612c5c12172 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -851,6 +851,12 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope; proc genRecordField(p: BProc, e: PNode, d: var TLoc) = var a: TLoc = default(TLoc) + if p.module.compileToCpp and e.kind == nkDotExpr and e[1].kind == nkSym and e[1].typ.kind == tyPtr: + # special case for C++: we need to pull the type of the field as member and friends require the complete type. + let typ = e[1].typ[0] + if typ.itemId in p.module.g.graph.memberProcsPerType: + discard getTypeDesc(p.module, typ) + genRecordFieldAux(p, e, d, a) var r = rdLoc(a) var f = e[1].sym diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index a591ce93ba39..4103e0afb06c 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -11,7 +11,7 @@ # ------------------------- Name Mangling -------------------------------- -import sighashes, modulegraphs, strscans +import sighashes, modulegraphs, std/strscans import ../dist/checksums/src/checksums/md5 type diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 87fed300bb1e..bfb429f8277c 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -10,9 +10,11 @@ # This module declares some helpers for the C code generator. import - ast, types, hashes, strutils, msgs, wordrecg, + ast, types, msgs, wordrecg, platform, trees, options, cgendata +import std/[hashes, strutils] + when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/cgen.nim b/compiler/cgen.nim index a2b2c429ef15..0011cb90e3a9 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -10,11 +10,11 @@ ## This module implements the C code generator. import - ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets, + ast, astalgo, trees, platform, magicsys, extccomp, options, nversion, nimsets, msgs, bitsets, idents, types, - ccgutils, os, ropes, math, wordrecg, treetab, cgmeth, + ccgutils, ropes, wordrecg, treetab, cgmeth, rodutils, renderer, cgendata, aliases, - lowerings, tables, sets, ndi, lineinfos, pathutils, transf, + lowerings, ndi, lineinfos, pathutils, transf, injectdestructors, astmsgs, modulepaths, backendpragmas from expanddefaults import caseObjDefaultBranch @@ -27,10 +27,10 @@ when defined(nimPreviewSlimSystem): when not defined(leanCompiler): import spawn, semparallel -import strutils except `%`, addf # collides with ropes.`%` +import std/strutils except `%`, addf # collides with ropes.`%` from ic / ic import ModuleBackendFlag -import dynlib +import std/[dynlib, math, tables, sets, os, intsets, hashes] when not declared(dynlib.libCandidates): proc libCandidates(s: string, dest: var seq[string]) = @@ -121,7 +121,7 @@ proc getModuleDllPath(m: BModule, module: int): Rope = proc getModuleDllPath(m: BModule, s: PSym): Rope = result = getModuleDllPath(m.g.modules[s.itemId.module]) -import macros +import std/macros proc cgFormatValue(result: var string; value: string) = result.add value diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 9cc146c4db5f..30d778bc23ac 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -10,8 +10,10 @@ ## This module contains the data structures for the C code generation phase. import - ast, ropes, options, intsets, - tables, ndi, lineinfos, pathutils, modulegraphs, sets + ast, ropes, options, + ndi, lineinfos, pathutils, modulegraphs + +import std/[intsets, tables, sets] type TLabel* = Rope # for the C generator a label is just a rope diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index ed8f33630ef0..8ad6bf3f4b92 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -10,9 +10,12 @@ ## This module implements code generation for methods. import - intsets, options, ast, msgs, idents, renderer, types, magicsys, + options, ast, msgs, idents, renderer, types, magicsys, sempass2, modulegraphs, lineinfos + +import std/intsets + when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 15c627dcdf85..63e8d2fe90d2 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -134,7 +134,9 @@ import ast, msgs, idents, renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos, - tables, options + options + +import std/tables when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/cmdlinehelper.nim b/compiler/cmdlinehelper.nim index e35e5d2db8ed..031ad755e06b 100644 --- a/compiler/cmdlinehelper.nim +++ b/compiler/cmdlinehelper.nim @@ -11,7 +11,9 @@ import options, idents, nimconf, extccomp, commands, msgs, - lineinfos, modulegraphs, condsyms, os, pathutils, parseopt + lineinfos, modulegraphs, condsyms, pathutils + +import std/[os, parseopt] proc prependCurDir*(f: AbsoluteFile): AbsoluteFile = when defined(unix): diff --git a/compiler/commands.nim b/compiler/commands.nim index f36d82306f3e..e758ed09b99c 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -27,7 +27,9 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none") import std/[setutils, os, strutils, parseutils, parseopt, sequtils, strtabs] import msgs, options, nversion, condsyms, extccomp, platform, - wordrecg, nimblecmd, lineinfos, pathutils, pathnorm + wordrecg, nimblecmd, lineinfos, pathutils + +import std/pathnorm from ast import setUseIc, eqTypeFlags, tfGcSafe, tfNoSideEffect @@ -460,6 +462,7 @@ proc handleCmdInput*(conf: ConfigRef) = proc parseCommand*(command: string): Command = case command.normalize of "c", "cc", "compile", "compiletoc": cmdCompileToC + of "nir": cmdCompileToNir of "cpp", "compiletocpp": cmdCompileToCpp of "objc", "compiletooc": cmdCompileToOC of "js", "compiletojs": cmdCompileToJS @@ -496,6 +499,7 @@ proc setCmd*(conf: ConfigRef, cmd: Command) = of cmdCompileToCpp: conf.backend = backendCpp of cmdCompileToOC: conf.backend = backendObjc of cmdCompileToJS: conf.backend = backendJs + of cmdCompileToNir: conf.backend = backendNir else: discard proc setCommandEarly*(conf: ConfigRef, command: string) = @@ -794,7 +798,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if conf.backend == backendJs or conf.cmd == cmdNimscript: discard else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info) #if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe) - of "tlsemulation": + of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info) if optTlsEmulation in conf.globalOptions: conf.legacyFeatures.incl emitGenerics diff --git a/compiler/concepts.nim b/compiler/concepts.nim index 55088740c888..d8b65720b609 100644 --- a/compiler/concepts.nim +++ b/compiler/concepts.nim @@ -11,7 +11,9 @@ ## for details. Note this is a first implementation and only the "Concept matching" ## section has been implemented. -import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types, intsets +import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types + +import std/intsets when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 520545a81534..aa619c93204b 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -10,7 +10,7 @@ # This module handles the conditional symbols. import - strtabs + std/strtabs from options import Feature from lineinfos import hintMin, hintMax, warnMin, warnMax @@ -162,3 +162,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasNolineTooLong") defineSymbol("nimHasCastExtendedVm") + defineSymbol("nimHasWarnStdPrefix") diff --git a/compiler/depends.nim b/compiler/depends.nim index 84e66f78063b..638f1eb51aee 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -14,7 +14,7 @@ import options, ast, ropes, pathutils, msgs, lineinfos import modulegraphs import std/[os, parseutils] -import strutils except addf +import std/strutils except addf import std/private/globs when defined(nimPreviewSlimSystem): diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 4cae9ec42bf0..1511628dd6f7 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -22,8 +22,9 @@ ## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen. ## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf -import ast, intsets, lineinfos, renderer, aliasanalysis +import ast, lineinfos, renderer, aliasanalysis import std/private/asciitables +import std/intsets when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 7edee1663f6b..ea7cfad8cf00 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -15,15 +15,16 @@ ## For corresponding users' documentation see [Nim DocGen Tools Guide]. import - ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents, + ast, options, msgs, idents, wordrecg, syntaxes, renderer, lexer, packages/docutils/[rst, rstidx, rstgen, dochelpers], - json, xmltree, trees, types, - typesrenderer, astalgo, lineinfos, intsets, - pathutils, tables, nimpaths, renderverbatim, osproc, packages + trees, types, + typesrenderer, astalgo, lineinfos, + pathutils, nimpaths, renderverbatim, packages import packages/docutils/rstast except FileIndex, TLineInfo -from uri import encodeUrl +import std/[os, strutils, strtabs, algorithm, json, osproc, tables, intsets, xmltree, sequtils] +from std/uri import encodeUrl from nodejs import findNodeJs when defined(nimPreviewSlimSystem): diff --git a/compiler/errorhandling.nim b/compiler/errorhandling.nim index a8361105ecec..2ad0f8806424 100644 --- a/compiler/errorhandling.nim +++ b/compiler/errorhandling.nim @@ -10,7 +10,8 @@ ## This module contains support code for new-styled error ## handling via an `nkError` node kind. -import ast, renderer, options, strutils, types +import ast, renderer, options, types +import std/strutils when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index 3f386f76ecce..ab26ca1bbeab 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -9,10 +9,12 @@ ## This file implements the FFI part of the evaluator for Nim code. -import ast, types, options, tables, dynlib, msgs, lineinfos -from os import getAppFilename +import ast, types, options, msgs, lineinfos +from std/os import getAppFilename import libffi/libffi +import std/[tables, dynlib] + when defined(windows): const libcDll = "msvcrt.dll" elif defined(linux): diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index a5d888858f3a..5ebb4fa55340 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -9,8 +9,8 @@ ## Template evaluation engine. Now hygienic. -import - strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents, trees +import options, ast, astalgo, msgs, renderer, lineinfos, idents, trees +import std/strutils type TemplCtx = object diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 75d462b06d47..3deab0b7468b 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -319,7 +319,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string = var fullSuffix = suffix case conf.backend of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix - of backendC: discard + of backendC, backendNir: discard of backendInvalid: # during parsing of cfg files; we don't know the backend yet, no point in # guessing wrong thing diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index d04388b96a0c..921a94b31436 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -10,9 +10,11 @@ # This module implements Nim's standard template filter. import - llstream, strutils, ast, msgs, options, + llstream, ast, msgs, options, filters, lineinfos, pathutils +import std/strutils + type TParseState = enum psDirective, psTempl diff --git a/compiler/filters.nim b/compiler/filters.nim index 8d8af6b1c87c..3cd56e3be5dd 100644 --- a/compiler/filters.nim +++ b/compiler/filters.nim @@ -10,9 +10,11 @@ # This module implements Nim's simple filters and helpers for filters. import - llstream, idents, strutils, ast, msgs, options, + llstream, idents, ast, msgs, options, renderer, pathutils +import std/strutils + proc invalidPragma(conf: ConfigRef; n: PNode) = localError(conf, n.info, "'$1' not allowed here" % renderTree(n, {renderNoComments})) diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim index fb0fafc98530..da911c84cf51 100644 --- a/compiler/gorgeimpl.nim +++ b/compiler/gorgeimpl.nim @@ -9,8 +9,9 @@ ## Module that implements ``gorge`` for the compiler. -import msgs, os, osproc, streams, options, - lineinfos, pathutils +import msgs, options, lineinfos, pathutils + +import std/[os, osproc, streams] when defined(nimPreviewSlimSystem): import std/syncio diff --git a/compiler/guards.nim b/compiler/guards.nim index 1366a2382c43..21c7cd045bfa 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -870,7 +870,7 @@ template isSub(x): untyped = x.getMagic in someSub template isVal(x): untyped = x.kind in {nkCharLit..nkUInt64Lit} template isIntVal(x, y): untyped = x.intVal == y -import macros +import std/macros macro `=~`(x: PNode, pat: untyped): bool = proc m(x, pat, conds: NimNode) = diff --git a/compiler/ic/bitabs.nim b/compiler/ic/bitabs.nim index edbaeb240ea6..c8798e0ca4bf 100644 --- a/compiler/ic/bitabs.nim +++ b/compiler/ic/bitabs.nim @@ -1,7 +1,8 @@ ## A BiTable is a table that can be seen as an optimized pair ## of `(Table[LitId, Val], Table[Val, LitId])`. -import hashes, rodfiles +import std/hashes +import rodfiles when defined(nimPreviewSlimSystem): import std/assertions @@ -35,9 +36,7 @@ proc mustRehash(length, counter: int): bool {.inline.} = result = (length * 2 < counter * 3) or (length - counter < 4) const - idStart = 256 ## - ## Ids do not start with 0 but with this value. The IR needs it. - ## TODO: explain why + idStart = 1 template idToIdx(x: LitId): int = x.int - idStart diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim index a1922c812d32..97462f0955f6 100644 --- a/compiler/ic/cbackend.nim +++ b/compiler/ic/cbackend.nim @@ -18,7 +18,7 @@ ## also doing cross-module dependency tracking and DCE that we don't need ## anymore. DCE is now done as prepass over the entire packed module graph. -import std/packedsets, algorithm, tables +import std/[packedsets, algorithm, tables] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 8b0a3105438a..4d02822b2e30 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -7,12 +7,12 @@ # distribution, for details about the copyright. # -import hashes, tables, intsets +import std/[hashes, tables, intsets] import packed_ast, bitabs, rodfiles import ".." / [ast, idents, lineinfos, msgs, ropes, options, pathutils, condsyms, packages, modulepaths] #import ".." / [renderer, astalgo] -from os import removeFile, isAbsolute +from std/os import removeFile, isAbsolute import ../../dist/checksums/src/checksums/sha1 diff --git a/compiler/ic/integrity.nim b/compiler/ic/integrity.nim index d341fd653638..ed87ae59db60 100644 --- a/compiler/ic/integrity.nim +++ b/compiler/ic/integrity.nim @@ -10,7 +10,7 @@ ## Integrity checking for a set of .rod files. ## The set must cover a complete Nim project. -import sets +import std/sets when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim index ab49b3b7a18d..aea5e12e7f76 100644 --- a/compiler/ic/navigator.nim +++ b/compiler/ic/navigator.nim @@ -11,9 +11,9 @@ ## IDE-like features. It uses the set of .rod files to accomplish ## its task. The set must cover a complete Nim project. -import sets +import std/sets -from os import nil +from std/os import nil from std/private/miscdollars import toLocation when defined(nimPreviewSlimSystem): diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index b87348c5a049..e7443c3c711e 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -12,7 +12,7 @@ ## use this representation directly in all the transformations, ## it is superior. -import hashes, tables, strtabs +import std/[hashes, tables, strtabs] import bitabs import ".." / [ast, options] diff --git a/compiler/ic/replayer.nim b/compiler/ic/replayer.nim index 8eee0b3d89da..3bbe4fa31047 100644 --- a/compiler/ic/replayer.nim +++ b/compiler/ic/replayer.nim @@ -14,7 +14,7 @@ import ".." / [ast, modulegraphs, trees, extccomp, btrees, msgs, lineinfos, pathutils, options, cgmeth] -import tables +import std/tables when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index 41e85084f156..be5095fbb70a 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -14,7 +14,7 @@ ## compiler works and less a storage format, you're probably looking for ## the `ic` or `packed_ast` modules to understand the logical format. -from typetraits import supportsCopyMem +from std/typetraits import supportsCopyMem when defined(nimPreviewSlimSystem): import std/[syncio, assertions] @@ -97,6 +97,9 @@ type typeInfoSection # required by the backend backendFlagsSection aliveSymsSection # beware, this is stored in a `.alivesyms` file. + sideChannelSection + namespaceSection + symnamesSection RodFileError* = enum ok, tooBig, cannotOpen, ioFailure, wrongHeader, wrongSection, configMismatch, @@ -110,7 +113,7 @@ type const RodVersion = 1 - cookie = [byte(0), byte('R'), byte('O'), byte('D'), + defaultCookie = [byte(0), byte('R'), byte('O'), byte('D'), byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(RodVersion)] proc setError(f: var RodFile; err: RodFileError) {.inline.} = @@ -206,13 +209,13 @@ proc loadSeq*[T](f: var RodFile; s: var seq[T]) = for i in 0..>3] |=(1U<<($2&7U)) - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, a buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: copyTree c.code, b - addIntVal c.code, c.m.integers, info, c.m.nativeUIntId, 3 + addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitOr, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, a buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: copyTree c.code, b - addIntVal c.code, c.m.integers, info, c.m.nativeUIntId, 3 + addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.m.integers, info, t, 1 + c.code.addIntVal c.lit.numbers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, b - c.code.addIntVal c.m.integers, info, t, 7 + c.code.addIntVal c.lit.numbers, info, t, 7 else: # $1[(NU)($2)>>3] &= ~(1U<<($2&7U)) - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, a buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: copyTree c.code, b - addIntVal c.code, c.m.integers, info, c.m.nativeUIntId, 3 + addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitAnd, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, a buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: copyTree c.code, b - addIntVal c.code, c.m.integers, info, c.m.nativeUIntId, 3 + addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitNot, t: buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.m.integers, info, t, 1 + c.code.addIntVal c.lit.numbers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, b - c.code.addIntVal c.m.integers, info, t, 7 + c.code.addIntVal c.lit.numbers, info, t, 7 else: copyTree c.code, a @@ -1145,20 +1262,20 @@ proc genInclExcl(c: var ProcCon; n: PNode; m: TMagic) = buildTyped c.code, info, BitOr, setType: copyTree c.code, a buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.m.integers, info, t, 1 + c.code.addIntVal c.lit.numbers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, b - c.code.addIntVal c.m.integers, info, t, mask + c.code.addIntVal c.lit.numbers, info, t, mask else: # $1 &= ~(((NU8)1) << (($2) & 7)) buildTyped c.code, info, BitAnd, setType: copyTree c.code, a buildTyped c.code, info, BitNot, t: buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.m.integers, info, t, 1 + c.code.addIntVal c.lit.numbers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, b - c.code.addIntVal c.m.integers, info, t, mask + c.code.addIntVal c.lit.numbers, info, t, mask freeTemp c, b freeTemp c, a @@ -1168,9 +1285,9 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = # nimZeroMem(tmp, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c); # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g); let info = toLineInfo(c, n.info) - let setType = typeToIr(c.m.types, n.typ) + let setType = typeToIr(c.m, n.typ) let size = int(getSize(c.config, n.typ)) - let t = bitsetBasetype(c.m.types, n.typ) + let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ) let mask = case t of UInt8Id: 7 @@ -1179,10 +1296,10 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = else: 63 if isEmpty(d): d = getTemp(c, n) - if c.m.types.g[setType].kind != ArrayTy: + if c.m.nirm.types[setType].kind != ArrayTy: buildTyped c.code, info, Asgn, setType: copyTree c.code, d - c.code.addIntVal c.m.integers, info, t, 0 + c.code.addIntVal c.lit.numbers, info, t, 0 for it in n: if it.kind == nkRange: @@ -1195,10 +1312,10 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = copyTree c.code, d buildTyped c.code, info, BitNot, t: buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.m.integers, info, t, 1 + c.code.addIntVal c.lit.numbers, info, t, 1 buildTyped c.code, info, BitAnd, t: c.code.addSymUse info, idx - c.code.addIntVal c.m.integers, info, t, mask + c.code.addIntVal c.lit.numbers, info, t, mask endLoop(c, info, idx, backLabel, endLabel) freeTemp c, b @@ -1212,10 +1329,10 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = copyTree c.code, d buildTyped c.code, info, BitNot, t: buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.m.integers, info, t, 1 + c.code.addIntVal c.lit.numbers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, a - c.code.addIntVal c.m.integers, info, t, mask + c.code.addIntVal c.lit.numbers, info, t, mask freeTemp c, a else: @@ -1223,7 +1340,7 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = let (idx, backLabel, endLabel) = beginCountLoop(c, info, 0, size) buildTyped c.code, info, Asgn, t: copyTree c.code, d - c.code.addIntVal c.m.integers, info, t, 0 + c.code.addIntVal c.lit.numbers, info, t, 0 endLoop(c, info, idx, backLabel, endLabel) # incl elements: @@ -1234,24 +1351,24 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = let (idx, backLabel, endLabel) = beginCountLoop(c, info, a, b) buildTyped c.code, info, Asgn, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, d buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: c.code.addSymUse info, idx - addIntVal c.code, c.m.integers, info, c.m.nativeUIntId, 3 + addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitOr, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, d buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: c.code.addSymUse info, idx - addIntVal c.code, c.m.integers, info, c.m.nativeUIntId, 3 + addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.m.integers, info, t, 1 + c.code.addIntVal c.lit.numbers, info, t, 1 buildTyped c.code, info, BitAnd, t: c.code.addSymUse info, idx - c.code.addIntVal c.m.integers, info, t, 7 + c.code.addIntVal c.lit.numbers, info, t, 7 endLoop(c, info, idx, backLabel, endLabel) freeTemp c, b @@ -1261,43 +1378,43 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = let a = genx(c, it) # $1[(NU)($2)>>3] |=(1U<<($2&7U)) buildTyped c.code, info, Asgn, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, d buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: copyTree c.code, a - addIntVal c.code, c.m.integers, info, c.m.nativeUIntId, 3 + addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitOr, t: - buildTyped c.code, info, ArrayAt, t: + buildTyped c.code, info, ArrayAt, setType: copyTree c.code, d buildTyped c.code, info, BitShr, t: buildTyped c.code, info, Cast, c.m.nativeUIntId: copyTree c.code, a - addIntVal c.code, c.m.integers, info, c.m.nativeUIntId, 3 + addIntVal c.code, c.lit.numbers, info, c.m.nativeUIntId, 3 buildTyped c.code, info, BitShl, t: - c.code.addIntVal c.m.integers, info, t, 1 + c.code.addIntVal c.lit.numbers, info, t, 1 buildTyped c.code, info, BitAnd, t: copyTree c.code, a - c.code.addIntVal c.m.integers, info, t, 7 + c.code.addIntVal c.lit.numbers, info, t, 7 freeTemp c, a proc genSetConstr(c: var ProcCon; n: PNode; d: var Value) = if isDeepConstExpr(n): let info = toLineInfo(c, n.info) - let setType = typeToIr(c.m.types, n.typ) + let setType = typeToIr(c.m, n.typ) let size = int(getSize(c.config, n.typ)) let cs = toBitSet(c.config, n) - if c.m.types.g[setType].kind != ArrayTy: + if c.m.nirm.types[setType].kind != ArrayTy: template body(target) = - target.addIntVal c.m.integers, info, setType, cast[BiggestInt](bitSetToWord(cs, size)) + target.addIntVal c.lit.numbers, info, setType, cast[BiggestInt](bitSetToWord(cs, size)) intoDest d, info, setType, body else: - let t = bitsetBasetype(c.m.types, n.typ) + let t = bitsetBasetype(c.m.types, c.m.nirm.types, n.typ) template body(target) = buildTyped target, info, ArrayConstr, setType: for i in 0..high(cs): - target.addIntVal c.m.integers, info, t, int64 cs[i] + target.addIntVal c.lit.numbers, info, t, int64 cs[i] intoDest d, info, setType, body else: genSetConstrDyn c, n, d @@ -1321,32 +1438,37 @@ proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) = # asgn(s, tmp0); # } var args: seq[Value] = @[] + var argsRuntimeLen: seq[Value] = @[] + var precomputedLen = 0 for i in 1 ..< n.len: let it = n[i] + args.add genx(c, it) if skipTypes(it.typ, abstractVarRange).kind == tyChar: inc precomputedLen elif it.kind in {nkStrLit..nkTripleStrLit}: inc precomputedLen, it.strVal.len - args.add genx(c, it) + else: + argsRuntimeLen.add args[^1] # generate length computation: - var tmpLen = allocTemp(c.sm, c.m.nativeIntId) + var tmpLen = allocTemp(c, c.m.nativeIntId) buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmpLen - c.code.addIntVal c.m.integers, info, c.m.nativeIntId, precomputedLen - for a in mitems(args): + c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, precomputedLen + for a in mitems(argsRuntimeLen): buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmpLen buildTyped c.code, info, CheckedAdd, c.m.nativeIntId: + c.code.addLabel info, CheckedGoto, c.exitLabel c.code.addSymUse info, tmpLen - buildTyped c.code, info, FieldAt, c.m.nativeIntId: + buildTyped c.code, info, FieldAt, typeToIr(c.m, n.typ): copyTree c.code, a c.code.addImmediateVal info, 0 # (len, p)-pair so len is at index 0 var tmpStr = getTemp(c, n) # ^ because of aliasing, we always go through a temporary - let t = typeToIr(c.m.types, n.typ) + let t = typeToIr(c.m, n.typ) buildTyped c.code, info, Asgn, t: copyTree c.code, tmpStr buildTyped c.code, info, Call, t: @@ -1366,7 +1488,7 @@ proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) = #assert codegenProc != nil, $n & " " & (c.m.graph.config $ n.info) let theProc = c.genx newSymNode(codegenProc, n.info) copyTree c.code, theProc - buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, t): + buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, t): copyTree c.code, tmpStr copyTree c.code, args[i-1] freeTemp c, args[i-1] @@ -1403,31 +1525,32 @@ proc genMove(c: var ProcCon; n: PNode; d: var Value) = # if ($1.p == $2.p) goto lab1 let lab1 = newLabel(c.labelGen) - let payloadType = seqPayloadPtrType(c.m.types, n1.typ) + let n1t = typeToIr(c.m, n1.typ) + let payloadType = seqPayloadPtrType(c.m.types, c.m.nirm.types, n1.typ)[0] buildTyped c.code, info, Select, Bool8Id: buildTyped c.code, info, Eq, payloadType: - buildTyped c.code, info, FieldAt, payloadType: + buildTyped c.code, info, FieldAt, n1t: copyTree c.code, a c.code.addImmediateVal info, 1 # (len, p)-pair - buildTyped c.code, info, FieldAt, payloadType: + buildTyped c.code, info, FieldAt, n1t: copyTree c.code, src c.code.addImmediateVal info, 1 # (len, p)-pair build c.code, info, SelectPair: build c.code, info, SelectValue: - c.code.boolVal(info, true) + c.code.boolVal(c.lit.numbers, info, true) c.code.gotoLabel info, Goto, lab1 gen(c, n[3]) c.patch n, lab1 - buildTyped c.code, info, Asgn, typeToIr(c.m.types, n1.typ): + buildTyped c.code, info, Asgn, typeToIr(c.m, n1.typ): copyTree c.code, a copyTree c.code, src else: if isEmpty(d): d = getTemp(c, n) - buildTyped c.code, info, Asgn, typeToIr(c.m.types, n1.typ): + buildTyped c.code, info, Asgn, typeToIr(c.m, n1.typ): copyTree c.code, d copyTree c.code, a var op = getAttachedOp(c.m.graph, n.typ, attachedWasMoved) @@ -1436,11 +1559,62 @@ proc genMove(c: var ProcCon; n: PNode; d: var Value) = gen c, m, a else: var opB = c.genx(newSymNode(op)) - buildTyped c.code, info, Call, typeToIr(c.m.types, n.typ): + buildTyped c.code, info, Call, typeToIr(c.m, n.typ): copyTree c.code, opB - buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, typeToIr(c.m.types, n1.typ)): + buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.nirm.types, typeToIr(c.m, n1.typ)): copyTree c.code, a +template fieldAt(x: Value; i: int; t: TypeId): Tree = + var result = default(Tree) + buildTyped result, info, FieldAt, t: + copyTree result, x + result.addImmediateVal info, i + result + +template eqNil(x: Tree; t: TypeId): Tree = + var result = default(Tree) + buildTyped result, info, Eq, t: + copyTree result, x + result.addNilVal info, t + result + +template eqZero(x: Tree): Tree = + var result = default(Tree) + buildTyped result, info, Eq, c.m.nativeIntId: + copyTree result, x + result.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0 + result + +template bitOp(x: Tree; opc: Opcode; y: int): Tree = + var result = default(Tree) + buildTyped result, info, opc, c.m.nativeIntId: + copyTree result, x + result.addIntVal c.lit.numbers, info, c.m.nativeIntId, y + result + +proc genDestroySeq(c: var ProcCon; n: PNode; t: PType) = + let info = toLineInfo(c, n.info) + let strLitFlag = 1 shl (c.m.graph.config.target.intSize * 8 - 2) # see also NIM_STRLIT_FLAG + + let x = c.genx(n[1]) + let baseType = t.lastSon + + let seqType = typeToIr(c.m, t) + let p = fieldAt(x, 0, seqType) + + # if $1.p != nil and ($1.p.cap and NIM_STRLIT_FLAG) == 0: + # alignedDealloc($1.p, NIM_ALIGNOF($2)) + buildIfNot p.eqNil(seqType): + buildIf fieldAt(Value(p), 0, seqPayloadPtrType(c.m.types, c.m.nirm.types, t)[0]).bitOp(BitAnd, 0).eqZero(): + let codegenProc = getCompilerProc(c.m.graph, "alignedDealloc") + buildTyped c.code, info, Call, VoidId: + let theProc = c.genx newSymNode(codegenProc, n.info) + copyTree c.code, theProc + copyTree c.code, p + c.code.addImmediateVal info, int(getAlign(c.config, baseType)) + + freeTemp c, x + proc genDestroy(c: var ProcCon; n: PNode) = let t = n[1].typ.skipTypes(abstractInst) case t.kind @@ -1448,29 +1622,143 @@ proc genDestroy(c: var ProcCon; n: PNode) = var unused = default(Value) genUnaryCp(c, n, unused, "nimDestroyStrV1") of tySequence: - #[ - var a = initLocExpr(c, arg) - linefmt(c, cpsStmts, "if ($1.p && ($1.p->cap & NIM_STRLIT_FLAG) == 0) {$n" & - " #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" & - "}$n", - [rdLoc(a), getTypeDesc(c.module, t.lastSon)]) - ]# - globalError(c.config, n.info, "not implemented: =destroy for seqs") + genDestroySeq(c, n, t) else: discard "nothing to do" +type + IndexFor = enum + ForSeq, ForStr, ForOpenArray, ForArray + +proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PType): Value = + if optBoundsCheck in c.options: + let info = toLineInfo(c, n.info) + result = default(Value) + let idx = genx(c, n) + build result, info, CheckedIndex: + result.Tree.addLabel info, CheckedGoto, c.exitLabel + copyTree result.Tree, idx + case kind + of ForSeq, ForStr: + buildTyped result, info, FieldAt, typeToIr(c.m, arr): + copyTree result.Tree, a + result.addImmediateVal info, 0 # (len, p)-pair + of ForOpenArray: + buildTyped result, info, FieldAt, typeToIr(c.m, arr): + copyTree result.Tree, a + result.addImmediateVal info, 1 # (p, len)-pair + of ForArray: + let x = toInt64 lengthOrd(c.config, arr) + result.addIntVal c.lit.numbers, info, c.m.nativeIntId, x + freeTemp c, idx + else: + result = genx(c, n) + +proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo; + x: Value; n: PNode; arrType: PType) = + let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.lastSon)) + case arrType.kind + of tyString, tySequence: + let checkKind = if arrType.kind == tyString: ForStr else: ForSeq + let pay = if checkKind == ForStr: c.m.strPayloadId + else: seqPayloadPtrType(c.m.types, c.m.nirm.types, arrType) + + let y = genIndexCheck(c, n[2], x, checkKind, arrType) + let z = genIndexCheck(c, n[3], x, checkKind, arrType) + + buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ): + target.addImmediateVal info, 0 + buildTyped target, info, AddrOf, elemType: + buildTyped target, info, DerefArrayAt, pay[1]: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): + copyTree target, x + target.addImmediateVal info, 1 # (len, p)-pair + copyTree target, y + + # len: + target.addImmediateVal info, 1 + buildTyped target, info, Add, c.m.nativeIntId: + buildTyped target, info, Sub, c.m.nativeIntId: + copyTree target, z + copyTree target, y + target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1 + + freeTemp c, z + freeTemp c, y + of tyArray: + # XXX This evaluates the index check for `y` twice. + # This check is also still insufficient for non-zero based arrays. + let y = genIndexCheck(c, n[2], x, ForArray, arrType) + let z = genIndexCheck(c, n[3], x, ForArray, arrType) + + buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ): + target.addImmediateVal info, 0 + buildTyped target, info, AddrOf, elemType: + buildTyped target, info, ArrayAt, typeToIr(c.m, arrType): + copyTree target, x + copyTree target, y + + target.addImmediateVal info, 1 + buildTyped target, info, Add, c.m.nativeIntId: + buildTyped target, info, Sub, c.m.nativeIntId: + copyTree target, z + copyTree target, y + target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1 + + freeTemp c, z + freeTemp c, y + of tyOpenArray: + # XXX This evaluates the index check for `y` twice. + let y = genIndexCheck(c, n[2], x, ForOpenArray, arrType) + let z = genIndexCheck(c, n[3], x, ForOpenArray, arrType) + let pay = openArrayPayloadType(c.m.types, c.m.nirm.types, arrType) + + buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ): + target.addImmediateVal info, 0 + buildTyped target, info, AddrOf, elemType: + buildTyped target, info, DerefArrayAt, pay: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): + copyTree target, x + target.addImmediateVal info, 0 # (p, len)-pair + copyTree target, y + + target.addImmediateVal info, 1 + buildTyped target, info, Add, c.m.nativeIntId: + buildTyped target, info, Sub, c.m.nativeIntId: + copyTree target, z + copyTree target, y + target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 1 + + freeTemp c, z + freeTemp c, y + else: + raiseAssert "addSliceFields: " & typeToString(arrType) + +proc genSlice(c: var ProcCon; n: PNode; d: var Value) = + let info = toLineInfo(c, n.info) + + let x = c.genx(n[1]) + + let arrType = n[1].typ.skipTypes(abstractVar) + + template body(target) = + c.addSliceFields target, info, x, n, arrType + + valueIntoDest c, info, d, arrType, body + freeTemp c, x + proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) = case m of mAnd: c.genAndOr(n, opcFJmp, d) of mOr: c.genAndOr(n, opcTJmp, d) - of mPred, mSubI: c.genBinaryOp(n, d, CheckedSub) - of mSucc, mAddI: c.genBinaryOp(n, d, CheckedAdd) + of mPred, mSubI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedSub else: Sub) + of mSucc, mAddI: c.genBinaryOp(n, d, if optOverflowCheck in c.options: CheckedAdd else: Add) of mInc: unused(c, n, d) - c.genIncDec(n, CheckedAdd) + c.genIncDec(n, if optOverflowCheck in c.options: CheckedAdd else: Add) of mDec: unused(c, n, d) - c.genIncDec(n, CheckedSub) - of mOrd, mChr, mArrToSeq, mUnown: + c.genIncDec(n, if optOverflowCheck in c.options: CheckedSub else: Sub) + of mOrd, mChr, mUnown: c.gen(n[1], d) of generatedMagics: genCall(c, n, d) @@ -1484,9 +1772,9 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) = of mNewString, mNewStringOfCap, mExit: c.genCall(n, d) of mLengthOpenArray, mLengthArray, mLengthSeq, mLengthStr: genArrayLen(c, n, d) - of mMulI: genBinaryOp(c, n, d, CheckedMul) - of mDivI: genBinaryOp(c, n, d, CheckedDiv) - of mModI: genBinaryOp(c, n, d, CheckedMod) + of mMulI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMul else: Mul) + of mDivI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedDiv else: Div) + of mModI: genBinaryOp(c, n, d, if optOverflowCheck in c.options: CheckedMod else: Mod) of mAddF64: genBinaryOp(c, n, d, Add) of mSubF64: genBinaryOp(c, n, d, Sub) of mMulF64: genBinaryOp(c, n, d, Mul) @@ -1621,154 +1909,12 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) = of mDestroy: genDestroy(c, n) #of mAccessEnv: unaryExpr(d, n, d, "$1.ClE_0") #of mAccessTypeField: genAccessTypeField(c, n, d) - #of mSlice: genSlice(c, n, d) + of mSlice: genSlice(c, n, d) of mTrace: discard "no code to generate" else: # mGCref, mGCunref: unused by ORC globalError(c.config, n.info, "cannot generate code for: " & $m) -#[ - - of mRepr: genUnaryABC(c, n, d, opcRepr) - - of mNodeId: - c.genUnaryABC(n, d, opcNodeId) - - of mExpandToAst: - if n.len != 2: - globalError(c.config, n.info, "expandToAst requires 1 argument") - let arg = n[1] - if arg.kind in nkCallKinds: - #if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}: - # "ExpandToAst: expanded symbol is no macro or template" - if isEmpty(d): d = c.getTemp(n) - c.genCall(arg, d) - # do not call clearDest(n, d) here as getAst has a meta-type as such - # produces a value - else: - globalError(c.config, n.info, "expandToAst requires a call expression") - of mParseExprToAst: - genBinaryABC(c, n, d, opcParseExprToAst) - of mParseStmtToAst: - genBinaryABC(c, n, d, opcParseStmtToAst) - of mTypeTrait: - let tmp = c.genx(n[1]) - if isEmpty(d): d = c.getTemp(n) - c.gABx(n, opcSetType, tmp, c.genType(n[1].typ)) - c.gABC(n, opcTypeTrait, d, tmp) - c.freeTemp(tmp) - of mSlurp: genUnaryABC(c, n, d, opcSlurp) - of mNLen: genUnaryABI(c, n, d, opcLenSeq, nimNodeFlag) - of mGetImpl: genUnaryABC(c, n, d, opcGetImpl) - of mGetImplTransf: genUnaryABC(c, n, d, opcGetImplTransf) - of mSymOwner: genUnaryABC(c, n, d, opcSymOwner) - of mSymIsInstantiationOf: genBinaryABC(c, n, d, opcSymIsInstantiationOf) - of mNChild: genBinaryABC(c, n, d, opcNChild) - of mNAdd: genBinaryABC(c, n, d, opcNAdd) - of mNAddMultiple: genBinaryABC(c, n, d, opcNAddMultiple) - of mNKind: genUnaryABC(c, n, d, opcNKind) - of mNSymKind: genUnaryABC(c, n, d, opcNSymKind) - - of mNccValue: genUnaryABC(c, n, d, opcNccValue) - of mNccInc: genBinaryABC(c, n, d, opcNccInc) - of mNcsAdd: genBinaryABC(c, n, d, opcNcsAdd) - of mNcsIncl: genBinaryABC(c, n, d, opcNcsIncl) - of mNcsLen: genUnaryABC(c, n, d, opcNcsLen) - of mNcsAt: genBinaryABC(c, n, d, opcNcsAt) - of mNctLen: genUnaryABC(c, n, d, opcNctLen) - of mNctGet: genBinaryABC(c, n, d, opcNctGet) - of mNctHasNext: genBinaryABC(c, n, d, opcNctHasNext) - of mNctNext: genBinaryABC(c, n, d, opcNctNext) - - of mNIntVal: genUnaryABC(c, n, d, opcNIntVal) - of mNFloatVal: genUnaryABC(c, n, d, opcNFloatVal) - of mNSymbol: genUnaryABC(c, n, d, opcNSymbol) - of mNIdent: genUnaryABC(c, n, d, opcNIdent) - of mNGetType: - let tmp = c.genx(n[1]) - if isEmpty(d): d = c.getTemp(n) - let rc = case n[0].sym.name.s: - of "getType": 0 - of "typeKind": 1 - of "getTypeInst": 2 - else: 3 # "getTypeImpl" - c.gABC(n, opcNGetType, d, tmp, rc) - c.freeTemp(tmp) - #genUnaryABC(c, n, d, opcNGetType) - of mNSizeOf: - let imm = case n[0].sym.name.s: - of "getSize": 0 - of "getAlign": 1 - else: 2 # "getOffset" - c.genUnaryABI(n, d, opcNGetSize, imm) - of mNStrVal: genUnaryABC(c, n, d, opcNStrVal) - of mNSigHash: genUnaryABC(c, n , d, opcNSigHash) - of mNSetIntVal: - unused(c, n, d) - genBinaryStmt(c, n, opcNSetIntVal) - of mNSetFloatVal: - unused(c, n, d) - genBinaryStmt(c, n, opcNSetFloatVal) - of mNSetSymbol: - unused(c, n, d) - genBinaryStmt(c, n, opcNSetSymbol) - of mNSetIdent: - unused(c, n, d) - genBinaryStmt(c, n, opcNSetIdent) - of mNSetStrVal: - unused(c, n, d) - genBinaryStmt(c, n, opcNSetStrVal) - of mNNewNimNode: genBinaryABC(c, n, d, opcNNewNimNode) - of mNCopyNimNode: genUnaryABC(c, n, d, opcNCopyNimNode) - of mNCopyNimTree: genUnaryABC(c, n, d, opcNCopyNimTree) - of mNBindSym: genBindSym(c, n, d) - of mStrToIdent: genUnaryABC(c, n, d, opcStrToIdent) - of mEqIdent: genBinaryABC(c, n, d, opcEqIdent) - of mEqNimrodNode: genBinaryABC(c, n, d, opcEqNimNode) - of mSameNodeType: genBinaryABC(c, n, d, opcSameNodeType) - of mNLineInfo: - case n[0].sym.name.s - of "getFile": genUnaryABI(c, n, d, opcNGetLineInfo, 0) - of "getLine": genUnaryABI(c, n, d, opcNGetLineInfo, 1) - of "getColumn": genUnaryABI(c, n, d, opcNGetLineInfo, 2) - of "copyLineInfo": - internalAssert c.config, n.len == 3 - unused(c, n, d) - genBinaryStmt(c, n, opcNCopyLineInfo) - of "setLine": - internalAssert c.config, n.len == 3 - unused(c, n, d) - genBinaryStmt(c, n, opcNSetLineInfoLine) - of "setColumn": - internalAssert c.config, n.len == 3 - unused(c, n, d) - genBinaryStmt(c, n, opcNSetLineInfoColumn) - of "setFile": - internalAssert c.config, n.len == 3 - unused(c, n, d) - genBinaryStmt(c, n, opcNSetLineInfoFile) - else: internalAssert c.config, false - of mNHint: - unused(c, n, d) - genBinaryStmt(c, n, opcNHint) - of mNWarning: - unused(c, n, d) - genBinaryStmt(c, n, opcNWarning) - of mNError: - if n.len <= 1: - # query error condition: - c.gABC(n, opcQueryErrorFlag, d) - else: - # setter - unused(c, n, d) - genBinaryStmt(c, n, opcNError) - of mNCallSite: - if isEmpty(d): d = c.getTemp(n) - c.gABC(n, opcCallSite, d) - of mNGenSym: genBinaryABC(c, n, d, opcGenSym) - -]# - proc canElimAddr(n: PNode; idgen: IdGenerator): PNode = result = nil case n[0].kind @@ -1798,14 +1944,6 @@ proc canElimAddr(n: PNode; idgen: IdGenerator): PNode = # addr ( deref ( x )) --> x result = n[0][0] -template valueIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: PType; body: untyped) = - if isEmpty(d): - body(Tree d) - else: - buildTyped c.code, info, Asgn, typeToIr(c.m.types, typ): - copyTree c.code, d - body(c.code) - proc genAddr(c: var ProcCon; n: PNode; d: var Value, flags: GenFlags) = if (let m = canElimAddr(n, c.m.idgen); m != nil): gen(c, m, d, flags) @@ -1814,7 +1952,7 @@ proc genAddr(c: var ProcCon; n: PNode; d: var Value, flags: GenFlags) = let info = toLineInfo(c, n.info) let tmp = c.genx(n[0], flags) template body(target) = - buildTyped target, info, AddrOf, typeToIr(c.m.types, n.typ): + buildTyped target, info, AddrOf, typeToIr(c.m, n.typ): copyTree target, tmp valueIntoDest c, info, d, n.typ, body @@ -1824,7 +1962,7 @@ proc genDeref(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let info = toLineInfo(c, n.info) let tmp = c.genx(n[0], flags) template body(target) = - buildTyped target, info, Load, typeToIr(c.m.types, n.typ): + buildTyped target, info, Load, typeToIr(c.m, n.typ): copyTree target, tmp valueIntoDest c, info, d, n.typ, body @@ -1832,47 +1970,47 @@ proc genDeref(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; tmp: Value; typ: PType) = let arrType = typ.skipTypes(abstractVar) - let elemType = arrayPtrTypeOf(c.m.types.g, typeToIr(c.m.types, arrType.lastSon)) + let elemType = arrayPtrTypeOf(c.m.nirm.types, typeToIr(c.m, arrType.lastSon)) case arrType.kind of tyString: - let t = typeToIr(c.m.types, typ.lastSon) + let t = typeToIr(c.m, typ) target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, strPayloadPtrType(c.m.types): + buildTyped target, info, DerefArrayAt, c.m.strPayloadId[1]: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): copyTree target, tmp target.addImmediateVal info, 1 # (len, p)-pair - target.addIntVal c.m.integers, info, c.m.nativeIntId, 0 + target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0 # len: target.addImmediateVal info, 1 - buildTyped target, info, FieldAt, c.m.nativeIntId: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): copyTree target, tmp target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0 of tySequence: - let t = typeToIr(c.m.types, typ.lastSon) + let t = typeToIr(c.m, typ) target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, seqPayloadPtrType(c.m.types, typ): + buildTyped target, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, typ)[1]: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): copyTree target, tmp target.addImmediateVal info, 1 # (len, p)-pair - target.addIntVal c.m.integers, info, c.m.nativeIntId, 0 + target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0 # len: target.addImmediateVal info, 1 - buildTyped target, info, FieldAt, c.m.nativeIntId: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): copyTree target, tmp target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0 of tyArray: - let t = typeToIr(c.m.types, typ.lastSon) + let t = typeToIr(c.m, arrType) target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: buildTyped target, info, ArrayAt, t: copyTree target, tmp - target.addIntVal c.m.integers, info, c.m.nativeIntId, 0 + target.addIntVal c.lit.numbers, info, c.m.nativeIntId, 0 target.addImmediateVal info, 1 - target.addIntVal(c.m.integers, info, c.m.nativeIntId, toInt lengthOrd(c.config, typ)) + target.addIntVal(c.lit.numbers, info, c.m.nativeIntId, toInt lengthOrd(c.config, arrType)) else: raiseAssert "addAddrOfFirstElem: " & typeToString(typ) @@ -1881,7 +2019,7 @@ proc genToOpenArrayConv(c: var ProcCon; arg: PNode; d: var Value; flags: GenFlag let tmp = c.genx(arg, flags) let arrType = destType.skipTypes(abstractVar) template body(target) = - buildTyped target, info, ObjConstr, typeToIr(c.m.types, arrType): + buildTyped target, info, ObjConstr, typeToIr(c.m, arrType): c.addAddrOfFirstElem target, info, tmp, arg.typ valueIntoDest c, info, d, arrType, body @@ -1905,7 +2043,7 @@ proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: let info = toLineInfo(c, n.info) let tmp = c.genx(arg, flags) template body(target) = - buildTyped target, info, opc, typeToIr(c.m.types, n.typ): + buildTyped target, info, opc, typeToIr(c.m, n.typ): if opc == CheckedObjConv: target.addLabel info, CheckedGoto, c.exitLabel copyTree target, tmp @@ -1913,11 +2051,11 @@ proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: valueIntoDest c, info, d, n.typ, body freeTemp c, tmp -proc genObjOrTupleConstr(c: var ProcCon; n: PNode, d: var Value) = +proc genObjOrTupleConstr(c: var ProcCon; n: PNode; d: var Value; t: PType) = # XXX x = (x.old, 22) produces wrong code ... stupid self assignments let info = toLineInfo(c, n.info) template body(target) = - buildTyped target, info, ObjConstr, typeToIr(c.m.types, n.typ): + buildTyped target, info, ObjConstr, typeToIr(c.m, t): for i in ord(n.kind == nkObjConstr)..= 0, typeToString(s.typ) & (c.config $ n.info) + let symId = toSymId(c, s) + c.code.addSummon toLineInfo(c, a.info), symId, t, opc + c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s) if a[2].kind != nkEmpty: genAsgn2(c, vn, a[2]) else: @@ -1992,41 +2200,46 @@ proc convStrToCStr(c: var ProcCon; n: PNode; d: var Value) = proc convCStrToStr(c: var ProcCon; n: PNode; d: var Value) = genUnaryCp(c, n, d, "cstrToNimstr", argAt = 0) -proc irModule(c: var ProcCon; owner: PSym): string = - #if owner == c.m.module: "" else: - customPath(toFullPath(c.config, owner.info)) - proc genRdVar(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let info = toLineInfo(c, n.info) let s = n.sym - if ast.originatingModule(s) != c.m.module: + if fromForeignModule(c, s): + if s.kind in {skVar, skConst, skLet} and not c.m.pendingVarsAsSet.containsOrIncl(s.itemId): + c.m.pendingVars.add s + template body(target) = build target, info, ModuleSymUse: - target.addStrVal c.m.strings, info, irModule(c, ast.originatingModule(s)) + target.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s)) target.addImmediateVal info, s.itemId.item.int valueIntoDest c, info, d, s.typ, body else: template body(target) = - target.addSymUse info, SymId(s.itemId.item) + target.addSymUse info, toSymId(c, s) valueIntoDest c, info, d, s.typ, body proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = let s = n.sym case s.kind - of skVar, skForVar, skTemp, skLet, skResult, skParam, skConst: + of skConst: + if dontInlineConstant(n, s.astdef): + genRdVar(c, n, d, flags) + else: + gen(c, s.astdef, d, flags) + of skVar, skForVar, skTemp, skLet, skResult, skParam: genRdVar(c, n, d, flags) of skProc, skFunc, skConverter, skMethod, skIterator: - if ast.originatingModule(s) == c.m.module: + if not c.m.noModularity: # anon and generic procs have no AST so we need to remember not to forget # to emit these: - if not c.m.pendingProcs.hasKey(s.itemId): - c.m.pendingProcs[s.itemId] = s + if not c.m.processedProcs.contains(s.itemId): + if not c.m.pendingProcsAsSet.containsOrIncl(s.itemId): + c.m.pendingProcs.add s genRdVar(c, n, d, flags) of skEnumField: let info = toLineInfo(c, n.info) template body(target) = - target.addIntVal c.m.integers, info, typeToIr(c.m.types, n.typ), s.position + target.addIntVal c.lit.numbers, info, typeToIr(c.m, n.typ), s.position valueIntoDest c, info, d, n.typ, body else: localError(c.config, n.info, "cannot generate code for: " & s.name.s) @@ -2034,19 +2247,19 @@ proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = proc genNumericLit(c: var ProcCon; n: PNode; d: var Value; bits: int64) = let info = toLineInfo(c, n.info) template body(target) = - target.addIntVal c.m.integers, info, typeToIr(c.m.types, n.typ), bits + target.addIntVal c.lit.numbers, info, typeToIr(c.m, n.typ), bits valueIntoDest c, info, d, n.typ, body proc genStringLit(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) template body(target) = - target.addStrVal c.m.strings, info, n.strVal + target.addStrVal c.lit.strings, info, n.strVal valueIntoDest c, info, d, n.typ, body proc genNilLit(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) template body(target) = - target.addNilVal info, typeToIr(c.m.types, n.typ) + target.addNilVal info, typeToIr(c.m, n.typ) valueIntoDest c, info, d, n.typ, body proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) = @@ -2056,11 +2269,11 @@ proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) = let a = c.genx n[1] let b = c.genx n[2] template body(target) = - buildTyped target, info, CheckedRange, typeToIr(c.m.types, n.typ): + buildTyped target, info, CheckedRange, typeToIr(c.m, n.typ): + target.addLabel info, CheckedGoto, c.exitLabel copyTree target, tmp copyTree target, a copyTree target, b - target.addLabel info, CheckedGoto, c.exitLabel valueIntoDest c, info, d, n.typ, body freeTemp c, tmp freeTemp c, a @@ -2068,42 +2281,18 @@ proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) = else: gen c, n[0], d -type - IndexFor = enum - ForSeq, ForStr, ForOpenArray - -proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor): Value = - if optBoundsCheck in c.options: - let info = toLineInfo(c, n.info) - result = default(Value) - let idx = genx(c, n) - build result, info, CheckedIndex: - copyTree result.Tree, idx - case kind - of ForSeq, ForStr: - buildTyped result, info, FieldAt, c.m.nativeIntId: - copyTree result.Tree, a - result.addImmediateVal info, 0 # (len, p)-pair - of ForOpenArray: - buildTyped result, info, FieldAt, c.m.nativeIntId: - copyTree result.Tree, a - result.addImmediateVal info, 1 # (p, len)-pair - result.Tree.addLabel info, CheckedGoto, c.exitLabel - freeTemp c, idx - else: - result = genx(c, n) - proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = - let arrayKind = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind + let arrayType = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}) + let arrayKind = arrayType.kind let info = toLineInfo(c, n.info) case arrayKind of tyString: let a = genx(c, n[0], flags) - let b = genIndexCheck(c, n[1], a, ForStr) - let t = typeToIr(c.m.types, n.typ) + let b = genIndexCheck(c, n[1], a, ForStr, arrayType) + let t = typeToIr(c.m, n.typ) template body(target) = - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, strPayloadPtrType(c.m.types): + buildTyped target, info, DerefArrayAt, c.m.strPayloadId[1]: + buildTyped target, info, FieldAt, typeToIr(c.m, arrayType): copyTree target, a target.addImmediateVal info, 1 # (len, p)-pair copyTree target, b @@ -2115,7 +2304,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let a = genx(c, n[0], flags) let b = genx(c, n[1]) template body(target) = - buildTyped target, info, ArrayAt, typeToIr(c.m.types, n.typ): + buildTyped target, info, DerefArrayAt, typeToIr(c.m, arrayType): copyTree target, a copyTree target, b valueIntoDest c, info, d, n.typ, body @@ -2126,7 +2315,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let a = genx(c, n[0], flags) let b = int n[1].intVal template body(target) = - buildTyped target, info, FieldAt, typeToIr(c.m.types, n.typ): + buildTyped target, info, FieldAt, typeToIr(c.m, arrayType): copyTree target, a target.addImmediateVal info, b valueIntoDest c, info, d, n.typ, body @@ -2134,11 +2323,11 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = freeTemp c, a of tyOpenArray, tyVarargs: let a = genx(c, n[0], flags) - let b = genIndexCheck(c, n[1], a, ForOpenArray) - let t = typeToIr(c.m.types, n.typ) + let b = genIndexCheck(c, n[1], a, ForOpenArray, arrayType) + let t = typeToIr(c.m, n.typ) template body(target) = - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, openArrayPayloadType(c.m.types, n[0].typ): + buildTyped target, info, DerefArrayAt, openArrayPayloadType(c.m.types, c.m.nirm.types, n[0].typ): + buildTyped target, info, FieldAt, typeToIr(c.m, arrayType): copyTree target, a target.addImmediateVal info, 0 # (p, len)-pair copyTree target, b @@ -2152,7 +2341,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = genIndex(c, n[1], n[0].typ, b) template body(target) = - buildTyped target, info, ArrayAt, typeToIr(c.m.types, n.typ): + buildTyped target, info, ArrayAt, typeToIr(c.m, arrayType): copyTree target, a copyTree target, b valueIntoDest c, info, d, n.typ, body @@ -2160,11 +2349,11 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = freeTemp c, a of tySequence: let a = genx(c, n[0], flags) - let b = genIndexCheck(c, n[1], a, ForSeq) - let t = typeToIr(c.m.types, n.typ) + let b = genIndexCheck(c, n[1], a, ForSeq, arrayType) + let t = typeToIr(c.m, n.typ) template body(target) = - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, seqPayloadPtrType(c.m.types, n[0].typ): + buildTyped target, info, DerefArrayAt, seqPayloadPtrType(c.m.types, c.m.nirm.types, n[0].typ)[1]: + buildTyped target, info, FieldAt, t: copyTree target, a target.addImmediateVal info, 1 # (len, p)-pair copyTree target, b @@ -2176,20 +2365,45 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = proc genObjAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let info = toLineInfo(c, n.info) - let a = genx(c, n[0], flags) + + var n0 = n[0] + var opc = FieldAt + if n0.kind == nkDotExpr: + # obj[].a --> DerefFieldAt instead of FieldAt: + n0 = n[0] + opc = DerefFieldAt + + let a = genx(c, n0, flags) template body(target) = - buildTyped target, info, FieldAt, typeToIr(c.m.types, n.typ): + buildTyped target, info, opc, typeToIr(c.m, n0.typ): copyTree target, a genField c, n[1], Value(target) valueIntoDest c, info, d, n.typ, body freeTemp c, a -proc genParams(c: var ProcCon; params: PNode) = +proc genParams(c: var ProcCon; params: PNode; prc: PSym): PSym = + result = nil + if params.len > 0 and resultPos < prc.ast.len: + let resNode = prc.ast[resultPos] + result = resNode.sym # get result symbol + c.code.addSummon toLineInfo(c, result.info), toSymId(c, result), + typeToIr(c.m, result.typ), SummonResult + elif prc.typ.len > 0 and not isEmptyType(prc.typ[0]) and not isCompileTimeOnly(prc.typ[0]): + # happens for procs without bodies: + let t = typeToIr(c.m, prc.typ[0]) + let tmp = allocTemp(c, t) + c.code.addSummon toLineInfo(c, params.info), tmp, t, SummonResult + for i in 1.. 0: + if not cOuter.m.pendingProcsAsSet.containsOrIncl(prc.itemId): + cOuter.m.pendingProcs.add prc + return + inc cOuter.m.inProc var c = initProcCon(cOuter.m, prc, cOuter.m.graph.config) - genParams(c, prc.typ.n) - - let body = transformBody(c.m.graph, c.m.idgen, prc, {useCache, keepOpenArrayConversions}) - - let info = toLineInfo(c, body.info) - build c.code, info, ProcDecl: - addSymDef c.code, info, SymId(prc.itemId.item) + let body = + if not fromForeignModule(c, prc): + transformBody(c.m.graph, c.m.idgen, prc, {useCache, keepOpenArrayConversions}) + else: + nil + + let info = toLineInfo(c, prc.info) + build c.code, info, (if body != nil: ProcDecl else: ForeignProcDecl): + if body != nil: + let symId = toSymId(c, prc) + addSymDef c.code, info, symId + c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(prc.name.s) + else: + build c.code, info, ModuleSymUse: + c.code.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(prc)) + c.code.addImmediateVal info, prc.itemId.item.int addCallConv c, info, prc.typ.callConv + if sfCompilerProc in prc.flags: + build c.code, info, PragmaPair: + c.code.addPragmaId info, CoreName + c.code.addStrVal c.lit.strings, info, prc.name.s if {sfImportc, sfExportc} * prc.flags != {}: build c.code, info, PragmaPair: c.code.addPragmaId info, ExternName - c.code.addStrVal c.m.strings, info, prc.loc.r + c.code.addStrVal c.lit.strings, info, prc.loc.r if sfImportc in prc.flags: if lfHeader in prc. loc.flags: assert(prc. annex != nil) let str = getStr(prc. annex.path) build c.code, info, PragmaPair: c.code.addPragmaId info, HeaderImport - c.code.addStrVal c.m.strings, info, str + c.code.addStrVal c.lit.strings, info, str elif lfDynamicLib in prc. loc.flags: assert(prc. annex != nil) let str = getStr(prc. annex.path) build c.code, info, PragmaPair: c.code.addPragmaId info, DllImport - c.code.addStrVal c.m.strings, info, str + c.code.addStrVal c.lit.strings, info, str elif sfExportc in prc.flags: if lfDynamicLib in prc. loc.flags: c.code.addPragmaId info, DllExport else: c.code.addPragmaId info, ObjExport - gen(c, body) - patch c, body, c.exitLabel + let resultSym = genParams(c, prc.typ.n, prc) + if body != nil: + gen(c, body) + patch c, body, c.exitLabel + if resultSym != nil: + build c.code, info, Ret: + c.code.addSymUse info, toSymId(c, resultSym) + else: + build c.code, info, Ret: + c.code.addNop info + + #copyTree cOuter.code, c.code + dec cOuter.m.inProc + +proc genProc(cOuter: var ProcCon; n: PNode) = + if n.len == 0 or n[namePos].kind != nkSym: return + let prc = n[namePos].sym + if isGenericRoutineStrict(prc) or isCompileTimeProc(prc) or sfForward in prc.flags: return + genProc cOuter, prc - copyTree cOuter.code, c.code +proc genClosureCall(c: var ProcCon; n: PNode; d: var Value) = + let typ = skipTypes(n[0].typ, abstractInstOwned) + if tfIterator in typ.flags: + const PatIter = "$1.ClP_0($3, $1.ClE_0)" # we know the env exists + + else: + const PatProc = "$1.ClE_0? $1.ClP_0($3, $1.ClE_0):(($4)($1.ClP_0))($2)" + + +proc genComplexCall(c: var ProcCon; n: PNode; d: var Value) = + if n[0].typ != nil and n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure: + # XXX genClosureCall p, n, d + genCall c, n, d + else: + genCall c, n, d proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = when defined(nimCompilerStacktraceHints): @@ -2260,11 +2524,9 @@ proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = localError(c.config, n.info, "cannot call method " & s.name.s & " at compile time") else: - genCall(c, n, d) - clearDest(c, n, d) + genComplexCall(c, n, d) else: - genCall(c, n, d) - clearDest(c, n, d) + genComplexCall(c, n, d) of nkCharLit..nkInt64Lit, nkUIntLit..nkUInt64Lit: genNumericLit(c, n, d, n.intVal) of nkFloatLit..nkFloat128Lit: @@ -2333,25 +2595,44 @@ proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = of nkCStringToString: convCStrToStr(c, n, d) of nkBracket: genArrayConstr(c, n, d) of nkCurly: genSetConstr(c, n, d) - of nkObjConstr, nkPar, nkClosure, nkTupleConstr: - genObjOrTupleConstr(c, n, d) + of nkObjConstr: + if n.typ.skipTypes(abstractInstOwned).kind == tyRef: + genRefObjConstr(c, n, d) + else: + genObjOrTupleConstr(c, n, d, n.typ) + of nkPar, nkClosure, nkTupleConstr: + genObjOrTupleConstr(c, n, d, n.typ) of nkCast: genConv(c, n, n[1], d, flags, Cast) of nkComesFrom: discard "XXX to implement for better stack traces" + #of nkState: genState(c, n) + #of nkGotoState: genGotoState(c, n) + #of nkBreakState: genBreakState(c, n, d) else: localError(c.config, n.info, "cannot generate IR code for " & $n) -proc genStmt*(c: var ProcCon; n: PNode): int = - result = c.code.len +proc genPendingProcs(c: var ProcCon) = + while c.m.pendingProcs.len > 0 or c.m.pendingVars.len > 0: + let procs = move(c.m.pendingProcs) + for v in procs: + genProc(c, v) + let vars = move(c.m.pendingVars) + for v in vars: + genForeignVar(c, v) + +proc genStmt*(c: var ProcCon; n: PNode): NodePos = + result = NodePos c.code.len var d = default(Value) c.gen(n, d) unused c, n, d + genPendingProcs c proc genExpr*(c: var ProcCon; n: PNode, requiresValue = true): int = result = c.code.len var d = default(Value) c.gen(n, d) + genPendingProcs c if isEmpty d: if requiresValue: globalError(c.config, n.info, "VM problem: d register is not set") diff --git a/compiler/nir/cir.nim b/compiler/nir/cir.nim index 90a3035ddb65..0b9746856525 100644 --- a/compiler/nir/cir.nim +++ b/compiler/nir/cir.nim @@ -9,8 +9,11 @@ # We produce C code as a list of tokens. -import std / assertions -import .. / ic / bitabs +import std / [assertions, syncio, tables, intsets] +from std / strutils import toOctal +import .. / ic / [bitabs, rodfiles] +import nirtypes, nirinsts, nirfiles +import ../../dist/checksums/src/checksums/md5 type Token = LitId # indexing into the tokens BiTable[string] @@ -18,7 +21,6 @@ type PredefinedToken = enum IgnoreMe = "" EmptyToken = "" - DeclPrefix = "" # the next token is the name of a definition CurlyLe = "{" CurlyRi = "}" ParLe = "(" @@ -29,7 +31,7 @@ type Semicolon = ";" Comma = ", " Space = " " - Colon = ":" + Colon = ": " Dot = "." Arrow = "->" Star = "*" @@ -38,36 +40,41 @@ type ScopeOpr = "::" ConstKeyword = "const " StaticKeyword = "static " - NimString = "NimString" - StrLitPrefix = "(NimChar*)" - StrLitNamePrefix = "Qstr" - LoopKeyword = "while (true) " - WhileKeyword = "while (" + ExternKeyword = "extern " + WhileKeyword = "while " IfKeyword = "if (" ElseKeyword = "else " - SwitchKeyword = "switch (" + SwitchKeyword = "switch " CaseKeyword = "case " DefaultKeyword = "default:" BreakKeyword = "break" NullPtr = "nullptr" IfNot = "if (!(" ReturnKeyword = "return " - -const - ModulePrefix = Token(int(ReturnKeyword)+1) + TypedefStruct = "typedef struct " + TypedefUnion = "typedef union " + IncludeKeyword = "#include " proc fillTokenTable(tab: var BiTable[string]) = for e in EmptyToken..high(PredefinedToken): let id = tab.getOrIncl $e - assert id == LitId(e) + assert id == LitId(e), $(id, " ", ord(e)) type GeneratedCode* = object + m: NirModule + includes: seq[LitId] + includedHeaders: IntSet + data: seq[LitId] + protos: seq[LitId] code: seq[LitId] tokens: BiTable[string] + emittedStrings: IntSet + needsPrefix: IntSet + mangledModules: Table[LitId, LitId] -proc initGeneratedCode*(): GeneratedCode = - result = GeneratedCode(code: @[], tokens: initBiTable[string]()) +proc initGeneratedCode*(m: sink NirModule): GeneratedCode = + result = GeneratedCode(m: m, code: @[], tokens: initBiTable[string]()) fillTokenTable(result.tokens) proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} = @@ -76,3 +83,845 @@ proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} = proc add*(g: var GeneratedCode; s: string) {.inline.} = g.code.add g.tokens.getOrIncl(s) +proc mangleModuleName(c: var GeneratedCode; key: LitId): LitId = + result = c.mangledModules.getOrDefault(key, LitId(0)) + if result == LitId(0): + let u {.cursor.} = c.m.lit.strings[key] + var last = u.len - len(".nim") - 1 + var start = last + while start >= 0 and u[start] != '/': dec start + var sum = getMD5(u) + sum.setLen(8) + let dest = u.substr(start+1, last) & sum + result = c.tokens.getOrIncl(dest) + c.mangledModules[key] = result + +type + CppFile = object + f: File + +proc write(f: var CppFile; s: string) = write(f.f, s) +proc write(f: var CppFile; c: char) = write(f.f, c) + +proc writeTokenSeq(f: var CppFile; s: seq[Token]; c: GeneratedCode) = + var indent = 0 + for i in 0.. 0: g.add Comma + genType g, types, lit, ch + inc i + g.add ParRi + of ObjectDecl, UnionDecl: + atom lit.strings[types[t.firstSon].litId] + of IntVal, SizeVal, AlignVal, OffsetVal, FieldDecl: + #raiseAssert "did not expect: " & $types[t].kind + g.add "BUG " + atom $types[t].kind + +proc generateTypes(g: var GeneratedCode; types: TypeGraph; lit: Literals; c: TypeOrder) = + for (t, declKeyword) in c.forwardedDecls.s: + let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon + let s {.cursor.} = lit.strings[types[name].litId] + g.add declKeyword + g.add s + g.add Space + g.add s + g.add Semicolon + + for (t, declKeyword) in c.ordered.s: + let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon + let s {.cursor.} = lit.strings[types[name].litId] + g.add declKeyword + g.add CurlyLe + if types[t].kind == ArrayTy: + #let name = arrayName(types, t) + + genType g, types, lit, elementType(types, t), "a" + g.add BracketLe + g.add $arrayLen(types, t) + g.add BracketRi + g.add Semicolon + else: + var i = 0 + for x in sons(types, t): + case types[x].kind + of FieldDecl: + genType g, types, lit, x.firstSon, "F" & $i + g.add Semicolon + inc i + of ObjectTy: + genType g, types, lit, x, "P" + g.add Semicolon + else: discard + + g.add CurlyRi + g.add s + g.add Semicolon + +# Procs + +proc toCChar*(c: char; result: var string) {.inline.} = + case c + of '\0'..'\x1F', '\x7F'..'\xFF': + result.add '\\' + result.add toOctal(c) + of '\'', '\"', '\\', '?': + result.add '\\' + result.add c + else: + result.add c + +proc makeCString(s: string): string = + result = newStringOfCap(s.len + 10) + result.add('"') + for c in s: toCChar(c, result) + result.add('"') + +template emitData(s: string) = c.data.add c.tokens.getOrIncl(s) +template emitData(t: Token) = c.data.add t +template emitData(t: PredefinedToken) = c.data.add Token(t) + +proc genStrLit(c: var GeneratedCode; lit: Literals; litId: LitId): Token = + result = Token(c.tokens.getOrIncl "QStr" & $litId) + if not containsOrIncl(c.emittedStrings, int(litId)): + let s {.cursor.} = lit.strings[litId] + emitData "static const struct " + emitData CurlyLe + emitData " NI cap" + emitData Semicolon + emitData "NC8 data" + emitData BracketLe + emitData $s.len + emitData "+1" + emitData BracketRi + emitData Semicolon + emitData CurlyRi + emitData result + emitData AsgnOpr + emitData CurlyLe + emitData $s.len + emitData " | NIM_STRLIT_FLAG" + emitData Comma + emitData makeCString(s) + emitData CurlyRi + emitData Semicolon + +proc genIntLit(c: var GeneratedCode; lit: Literals; litId: LitId) = + let i = lit.numbers[litId] + if i > low(int32) and i <= high(int32): + c.add $i + elif i == low(int32): + # Nim has the same bug for the same reasons :-) + c.add "(-2147483647 -1)" + elif i > low(int64): + c.add "IL64(" + c.add $i + c.add ")" + else: + c.add "(IL64(-9223372036854775807) - IL64(1))" + +proc gen(c: var GeneratedCode; t: Tree; n: NodePos) + +proc genSymDef(c: var GeneratedCode; t: Tree; n: NodePos) = + if t[n].kind == SymDef: + c.needsPrefix.incl t[n].symId.int + gen c, t, n + +proc genGlobal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) = + c.add annotation + let m: string + if t[name].kind == SymDef: + m = c.tokens[mangleModuleName(c, c.m.namespace)] & "__" & $t[name].symId + else: + assert t[name].kind == ModuleSymUse + let (x, y) = sons2(t, name) + m = c.tokens[mangleModuleName(c, t[x].litId)] & "__" & $t[y].immediateVal + genType c, c.m.types, c.m.lit, t[typ].typeId, m + +proc genLocal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) = + assert t[name].kind == SymDef + c.add annotation + genType c, c.m.types, c.m.lit, t[typ].typeId, "q" & $t[name].symId + # XXX Use proper names here + +proc genProcDecl(c: var GeneratedCode; t: Tree; n: NodePos; isExtern: bool) = + let signatureBegin = c.code.len + let name = n.firstSon + + var prc = n.firstSon + next t, prc + + while true: + case t[prc].kind + of PragmaPair: + let (x, y) = sons2(t, prc) + let key = cast[PragmaKey](t[x].rawOperand) + case key + of HeaderImport: + let lit = t[y].litId + let headerAsStr {.cursor.} = c.m.lit.strings[lit] + let header = c.tokens.getOrIncl(headerAsStr) + # headerAsStr can be empty, this has the semantics of the `nodecl` pragma: + if headerAsStr.len > 0 and not c.includedHeaders.containsOrIncl(int header): + if headerAsStr[0] == '#': + discard "skip the #include" + else: + c.includes.add Token(IncludeKeyword) + c.includes.add header + c.includes.add Token NewLine + # do not generate code for importc'ed procs: + return + of DllImport: + let lit = t[y].litId + raiseAssert "cannot eval: " & c.m.lit.strings[lit] + else: discard + of PragmaId: discard + else: break + next t, prc + + var resultDeclPos = NodePos(-1) + if t[prc].kind == SummonResult: + resultDeclPos = prc + gen c, t, prc.firstSon + next t, prc + else: + c.add "void" + c.add Space + genSymDef c, t, name + c.add ParLe + var params = 0 + while t[prc].kind == SummonParam: + if params > 0: c.add Comma + let (typ, sym) = sons2(t, prc) + genLocal c, t, sym, typ, "" + next t, prc + inc params + if params == 0: + c.add "void" + c.add ParRi + + for i in signatureBegin ..< c.code.len: + c.protos.add c.code[i] + c.protos.add Token Semicolon + + if isExtern: + c.code.setLen signatureBegin + else: + c.add CurlyLe + if resultDeclPos.int >= 0: + gen c, t, resultDeclPos + for ch in sonsRest(t, n, prc): + gen c, t, ch + c.add CurlyRi + +template triop(opr) = + let (typ, a, b) = sons3(t, n) + c.add ParLe + c.add ParLe + gen c, t, typ + c.add ParRi + gen c, t, a + c.add opr + gen c, t, b + c.add ParRi + +template cmpop(opr) = + let (_, a, b) = sons3(t, n) + c.add ParLe + gen c, t, a + c.add opr + gen c, t, b + c.add ParRi + +template binaryop(opr) = + let (typ, a) = sons2(t, n) + c.add ParLe + c.add ParLe + gen c, t, typ + c.add ParRi + c.add opr + gen c, t, a + c.add ParRi + +template checkedBinaryop(opr) = + let (typ, labIdx, a, b) = sons4(t, n) + let bits = integralBits(c.m.types[t[typ].typeId]) + let lab = t[labIdx].label + + c.add (opr & $bits) + c.add ParLe + c.gen t, a + c.add Comma + c.gen t, b + c.add Comma + c.add "L" & $lab.int + c.add ParRi + +template moveToDataSection(body: untyped) = + let oldLen = c.code.len + body + for i in oldLen ..< c.code.len: + c.data.add c.code[i] + setLen c.code, oldLen + +proc gen(c: var GeneratedCode; t: Tree; n: NodePos) = + case t[n].kind + of Nop: + discard "nothing to emit" + of ImmediateVal: + c.add "BUG: " & $t[n].kind + of IntVal: + genIntLit c, c.m.lit, t[n].litId + of StrVal: + c.code.add genStrLit(c, c.m.lit, t[n].litId) + of Typed: + genType c, c.m.types, c.m.lit, t[n].typeId + of SymDef, SymUse: + let s = t[n].symId + if c.needsPrefix.contains(s.int): + c.code.add mangleModuleName(c, c.m.namespace) + c.add "__" + c.add $s + else: + # XXX Use proper names here + c.add "q" + c.add $s + + of ModuleSymUse: + let (x, y) = sons2(t, n) + let u = mangleModuleName(c, t[x].litId) + let s = t[y].immediateVal + c.code.add u + c.add "__" + c.add $s + + of NilVal: + c.add NullPtr + of LoopLabel: + c.add WhileKeyword + c.add ParLe + c.add "1" + c.add ParRi + c.add CurlyLe + of GotoLoop: + c.add CurlyRi + of Label: + let lab = t[n].label + c.add "L" + c.add $lab.int + c.add Colon + c.add Semicolon + of Goto: + let lab = t[n].label + c.add "goto L" + c.add $lab.int + c.add Semicolon + of CheckedGoto: + discard "XXX todo" + of ArrayConstr: + c.add CurlyLe + var i = 0 + for ch in sonsFrom1(t, n): + if i > 0: c.add Comma + c.gen t, ch + inc i + c.add CurlyRi + of ObjConstr: + c.add CurlyLe + var i = 0 + for ch in sonsFrom1(t, n): + if i mod 2 == 0: + if i > 0: c.add Comma + c.add ".F" & $t[ch].immediateVal + c.add AsgnOpr + else: + c.gen t, ch + inc i + c.add CurlyRi + of Ret: + c.add ReturnKeyword + c.gen t, n.firstSon + c.add Semicolon + of Select: + c.add SwitchKeyword + c.add ParLe + let (_, selector) = sons2(t, n) + c.gen t, selector + c.add ParRi + c.add CurlyLe + for ch in sonsFromN(t, n, 2): + c.gen t, ch + c.add CurlyRi + of SelectPair: + let (le, ri) = sons2(t, n) + c.gen t, le + c.gen t, ri + of SelectList: + for ch in sons(t, n): + c.gen t, ch + of SelectValue: + c.add CaseKeyword + c.gen t, n.firstSon + c.add Colon + of SelectRange: + let (le, ri) = sons2(t, n) + c.add CaseKeyword + c.gen t, le + c.add " ... " + c.gen t, ri + c.add Colon + of ForeignDecl: + c.data.add LitId(ExternKeyword) + c.gen t, n.firstSon + of SummonGlobal: + moveToDataSection: + let (typ, sym) = sons2(t, n) + c.genGlobal t, sym, typ, "" + c.add Semicolon + of SummonThreadLocal: + moveToDataSection: + let (typ, sym) = sons2(t, n) + c.genGlobal t, sym, typ, "__thread " + c.add Semicolon + of SummonConst: + moveToDataSection: + let (typ, sym) = sons2(t, n) + c.genGlobal t, sym, typ, "const " + c.add Semicolon + of Summon, SummonResult: + let (typ, sym) = sons2(t, n) + c.genLocal t, sym, typ, "" + c.add Semicolon + + of SummonParam: + raiseAssert "SummonParam should have been handled in genProc" + of Kill: + discard "we don't care about Kill instructions" + of AddrOf: + let (_, arg) = sons2(t, n) + c.add "&" + gen c, t, arg + of DerefArrayAt: + let (_, a, i) = sons3(t, n) + gen c, t, a + c.add BracketLe + gen c, t, i + c.add BracketRi + of ArrayAt: + let (_, a, i) = sons3(t, n) + gen c, t, a + c.add Dot + c.add "a" + c.add BracketLe + gen c, t, i + c.add BracketRi + of FieldAt: + let (_, a, b) = sons3(t, n) + gen c, t, a + let field = t[b].immediateVal + c.add Dot + c.add "F" & $field + of DerefFieldAt: + let (_, a, b) = sons3(t, n) + gen c, t, a + let field = t[b].immediateVal + c.add Arrow + c.add "F" & $field + of Load: + let (_, arg) = sons2(t, n) + c.add ParLe + c.add "*" + gen c, t, arg + c.add ParRi + of Store: + raiseAssert "Assumption was that Store is unused!" + of Asgn: + let (_, dest, src) = sons3(t, n) + gen c, t, dest + c.add AsgnOpr + gen c, t, src + c.add Semicolon + of CheckedRange: + c.add "nimCheckRange" + c.add ParLe + let (_, gotoInstr, x, a, b) = sons5(t, n) + gen c, t, x + c.add Comma + gen c, t, a + c.add Comma + gen c, t, b + c.add Comma + c.add "L" & $t[gotoInstr].label.int + c.add ParRi + of CheckedIndex: + c.add "nimCheckIndex" + c.add ParLe + let (gotoInstr, x, a) = sons3(t, n) + gen c, t, x + c.add Comma + gen c, t, a + c.add Comma + c.add "L" & $t[gotoInstr].label.int + c.add ParRi + of Call, IndirectCall: + let (typ, fn) = sons2(t, n) + gen c, t, fn + c.add ParLe + var i = 0 + for ch in sonsFromN(t, n, 2): + if i > 0: c.add Comma + gen c, t, ch + inc i + c.add ParRi + if c.m.types[t[typ].typeId].kind == VoidTy: + c.add Semicolon + of CheckedCall, CheckedIndirectCall: + let (typ, gotoInstr, fn) = sons3(t, n) + gen c, t, fn + c.add ParLe + var i = 0 + for ch in sonsFromN(t, n, 3): + if i > 0: c.add Comma + gen c, t, ch + inc i + c.add ParRi + if c.m.types[t[typ].typeId].kind == VoidTy: + c.add Semicolon + + of CheckedAdd: checkedBinaryop "nimAddInt" + of CheckedSub: checkedBinaryop "nimSubInt" + of CheckedMul: checkedBinaryop "nimMulInt" + of CheckedDiv: checkedBinaryop "nimDivInt" + of CheckedMod: checkedBinaryop "nimModInt" + of Add: triop " + " + of Sub: triop " - " + of Mul: triop " * " + of Div: triop " / " + of Mod: triop " % " + of BitShl: triop " << " + of BitShr: triop " >> " + of BitAnd: triop " & " + of BitOr: triop " | " + of BitXor: triop " ^ " + of BitNot: binaryop " ~ " + of BoolNot: binaryop " !" + of Eq: cmpop " == " + of Le: cmpop " <= " + of Lt: cmpop " < " + of Cast: binaryop "" + of NumberConv: binaryop "" + of CheckedObjConv: binaryop "" + of ObjConv: binaryop "" + of Emit: raiseAssert "cannot interpret: Emit" + of ProcDecl: genProcDecl c, t, n, false + of ForeignProcDecl: genProcDecl c, t, n, true + of PragmaPair, PragmaId, TestOf, Yld, SetExc, TestExc: + c.add "cannot interpret: " & $t[n].kind + +const + Prelude = """ +/* GENERATED CODE. DO NOT EDIT. */ + +#ifdef __cplusplus +#define NB8 bool +#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901) +// see #13798: to avoid conflicts for code emitting `#include ` +#define NB8 _Bool +#else +typedef unsigned char NB8; // best effort +#endif + +typedef unsigned char NC8; + +typedef float NF32; +typedef double NF64; +#if defined(__BORLANDC__) || defined(_MSC_VER) +typedef signed char NI8; +typedef signed short int NI16; +typedef signed int NI32; +typedef __int64 NI64; +/* XXX: Float128? */ +typedef unsigned char NU8; +typedef unsigned short int NU16; +typedef unsigned int NU32; +typedef unsigned __int64 NU64; +#elif defined(HAVE_STDINT_H) +#ifndef USE_NIM_NAMESPACE +# include +#endif +typedef int8_t NI8; +typedef int16_t NI16; +typedef int32_t NI32; +typedef int64_t NI64; +typedef uint8_t NU8; +typedef uint16_t NU16; +typedef uint32_t NU32; +typedef uint64_t NU64; +#elif defined(HAVE_CSTDINT) +#ifndef USE_NIM_NAMESPACE +# include +#endif +typedef std::int8_t NI8; +typedef std::int16_t NI16; +typedef std::int32_t NI32; +typedef std::int64_t NI64; +typedef std::uint8_t NU8; +typedef std::uint16_t NU16; +typedef std::uint32_t NU32; +typedef std::uint64_t NU64; +#else +/* Unknown compiler/version, do our best */ +#ifdef __INT8_TYPE__ +typedef __INT8_TYPE__ NI8; +#else +typedef signed char NI8; +#endif +#ifdef __INT16_TYPE__ +typedef __INT16_TYPE__ NI16; +#else +typedef signed short int NI16; +#endif +#ifdef __INT32_TYPE__ +typedef __INT32_TYPE__ NI32; +#else +typedef signed int NI32; +#endif +#ifdef __INT64_TYPE__ +typedef __INT64_TYPE__ NI64; +#else +typedef long long int NI64; +#endif +/* XXX: Float128? */ +#ifdef __UINT8_TYPE__ +typedef __UINT8_TYPE__ NU8; +#else +typedef unsigned char NU8; +#endif +#ifdef __UINT16_TYPE__ +typedef __UINT16_TYPE__ NU16; +#else +typedef unsigned short int NU16; +#endif +#ifdef __UINT32_TYPE__ +typedef __UINT32_TYPE__ NU32; +#else +typedef unsigned int NU32; +#endif +#ifdef __UINT64_TYPE__ +typedef __UINT64_TYPE__ NU64; +#else +typedef unsigned long long int NU64; +#endif +#endif + +#ifdef NIM_INTBITS +# if NIM_INTBITS == 64 +typedef NI64 NI; +typedef NU64 NU; +# elif NIM_INTBITS == 32 +typedef NI32 NI; +typedef NU32 NU; +# elif NIM_INTBITS == 16 +typedef NI16 NI; +typedef NU16 NU; +# elif NIM_INTBITS == 8 +typedef NI8 NI; +typedef NU8 NU; +# else +# error "invalid bit width for int" +# endif +#endif + +#define NIM_STRLIT_FLAG ((NU64)(1) << ((NIM_INTBITS) - 2)) /* This has to be the same as system.strlitFlag! */ + +#define nimAddInt64(a, b, L) ({long long int res; if(__builtin_saddll_overflow(a, b, &res)) goto L; res}) +#define nimSubInt64(a, b, L) ({long long int res; if(__builtin_ssubll_overflow(a, b, &res)) goto L; res}) +#define nimMulInt64(a, b, L) ({long long int res; if(__builtin_smulll_overflow(a, b, &res)) goto L; res}) + +#define nimAddInt32(a, b, L) ({long int res; if(__builtin_sadd_overflow(a, b, &res)) goto L; res}) +#define nimSubInt32(a, b, L) ({long int res; if(__builtin_ssub_overflow(a, b, &res)) goto L; res}) +#define nimMulInt32(a, b, L) ({long int res; if(__builtin_smul_overflow(a, b, &res)) goto L; res}) + +#define nimCheckRange(x, a, b, L) ({if (x < a || x > b) goto L; x}) +#define nimCheckIndex(x, a, L) ({if (x >= a) goto L; x}) + +""" + +proc generateCode*(inp, outp: string) = + var c = initGeneratedCode(load(inp)) + + var co = TypeOrder() + traverseTypes(c.m.types, c.m.lit, co) + + generateTypes(c, c.m.types, c.m.lit, co) + let typeDecls = move c.code + + var i = NodePos(0) + while i.int < c.m.code.len: + gen c, c.m.code, NodePos(i) + next c.m.code, i + + var f = CppFile(f: open(outp, fmWrite)) + f.write "#define NIM_INTBITS " & $c.m.intbits & "\n" + f.write Prelude + writeTokenSeq f, c.includes, c + writeTokenSeq f, typeDecls, c + writeTokenSeq f, c.data, c + writeTokenSeq f, c.protos, c + writeTokenSeq f, c.code, c + f.f.close diff --git a/compiler/nir/nir.nim b/compiler/nir/nir.nim index 1994a1be7247..6f7077fb058c 100644 --- a/compiler/nir/nir.nim +++ b/compiler/nir/nir.nim @@ -10,21 +10,31 @@ ## Nim Intermediate Representation, designed to capture all of Nim's semantics without losing too much ## precious information. Can easily be translated into C. And to JavaScript, hopefully. -import ".." / [ast, modulegraphs, renderer, transf] -import nirtypes, nirinsts, ast2ir +from std/os import addFileExt, `/`, createDir + +import std / assertions +import ".." / [ast, modulegraphs, renderer, transf, options, msgs, lineinfos] +import nirtypes, nirinsts, ast2ir, nirlineinfos, nirfiles, nirvm + +import ".." / ic / [rodfiles, bitabs] type PCtx* = ref object of TPassContext m: ModuleCon c: ProcCon oldErrorCount: int + bytecode: Bytecode proc newCtx*(module: PSym; g: ModuleGraph; idgen: IdGenerator): PCtx = - let m = initModuleCon(g, g.config, idgen, module) - PCtx(m: m, c: initProcCon(m, nil, g.config), idgen: idgen) + var lit = Literals() + var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit) + var m = initModuleCon(g, g.config, idgen, module, nirm) + m.noModularity = true + PCtx(m: m, c: initProcCon(m, nil, g.config), idgen: idgen, bytecode: initBytecode(nirm)) proc refresh*(c: PCtx; module: PSym; idgen: IdGenerator) = - c.m = initModuleCon(c.m.graph, c.m.graph.config, idgen, module) + #c.m = initModuleCon(c.m.graph, c.m.graph.config, idgen, module, c.m.nirm) + #c.m.noModularity = true c.c = initProcCon(c.m, nil, c.m.graph.config) c.idgen = idgen @@ -42,14 +52,14 @@ proc setupNirReplGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPa proc evalStmt(c: PCtx; n: PNode) = let n = transformExpr(c.m.graph, c.idgen, c.m.module, n) let pc = genStmt(c.c, n) - - var res = "" - if pc < c.c.code.len: - toString c.c.code, NodePos(pc), c.m.strings, c.m.integers, res - #res.add "\n" + #var res = "" + #toString c.m.nirm.code, NodePos(pc), c.m.nirm.lit.strings, c.m.nirm.lit.numbers, c.m.symnames, res + #res.add "\n--------------------------\n" #toString res, c.m.types.g - echo res - + if pc.int < c.m.nirm.code.len: + c.bytecode.interactive = c.m.graph.interactive + execCode c.bytecode, c.m.nirm.code, pc + #echo res proc runCode*(c: PPassContext; n: PNode): PNode = let c = PCtx(c) @@ -61,11 +71,35 @@ proc runCode*(c: PPassContext; n: PNode): PNode = result = n c.oldErrorCount = c.m.graph.config.errorCounter -when false: - type - Module* = object - types: TypeGraph - data: seq[Tree] - init: seq[Tree] - procs: seq[Tree] +type + NirPassContext* = ref object of TPassContext + m: ModuleCon + c: ProcCon + +proc openNirBackend*(g: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = + var lit = Literals() + var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit) + let m = initModuleCon(g, g.config, idgen, module, nirm) + NirPassContext(m: m, c: initProcCon(m, nil, g.config), idgen: idgen) + +proc gen(c: NirPassContext; n: PNode) = + let n = transformExpr(c.m.graph, c.idgen, c.m.module, n) + let pc = genStmt(c.c, n) + +proc nirBackend*(c: PPassContext; n: PNode): PNode = + gen(NirPassContext(c), n) + result = n + +proc closeNirBackend*(c: PPassContext; finalNode: PNode) = + discard nirBackend(c, finalNode) + let c = NirPassContext(c) + let nimcache = getNimcacheDir(c.c.config).string + createDir nimcache + let outp = nimcache / c.m.module.name.s.addFileExt("nir") + #c.m.nirm.code = move c.c.code + try: + store c.m.nirm[], outp + echo "created: ", outp + except IOError: + rawMessage(c.c.config, errFatal, "serialization failed: " & outp) diff --git a/compiler/nir/nirc.nim b/compiler/nir/nirc.nim new file mode 100644 index 000000000000..a2cf69988abe --- /dev/null +++ b/compiler/nir/nirc.nim @@ -0,0 +1,52 @@ +# +# +# The Nim Compiler +# (c) Copyright 2023 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Nir Compiler. + +import ".." / ic / [bitabs, rodfiles] +import nirinsts, nirtypes, nirlineinfos, nirfiles, cir + +proc view(filename: string) = + let m = load(filename) + var res = "" + allTreesToString m.code, m.lit.strings, m.lit.numbers, m.symnames, res + res.add "\n# TYPES\n" + nirtypes.toString res, m.types + echo res + +import std / [syncio, parseopt] + +proc writeHelp = + echo """Usage: nirc view|c """ + quit 0 + +proc main = + var inp = "" + var cmd = "" + for kind, key, val in getopt(): + case kind + of cmdArgument: + if cmd.len == 0: cmd = key + elif inp.len == 0: inp = key + else: quit "Error: too many arguments" + of cmdLongOption, cmdShortOption: + case key + of "help", "h": writeHelp() + of "version", "v": stdout.write "1.0\n" + of cmdEnd: discard + if inp.len == 0: + quit "Error: no input file specified" + case cmd + of "", "view": + view inp + of "c": + let outp = inp & ".c" + cir.generateCode inp, outp + +main() diff --git a/compiler/nir/nirfiles.nim b/compiler/nir/nirfiles.nim new file mode 100644 index 000000000000..cd5a79f06e44 --- /dev/null +++ b/compiler/nir/nirfiles.nim @@ -0,0 +1,83 @@ +# +# +# The Nim Compiler +# (c) Copyright 2023 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import ".." / ic / [bitabs, rodfiles] +import nirinsts, nirtypes, nirlineinfos + +type + NirModule* = object + code*: Tree + man*: LineInfoManager + types*: TypeGraph + lit*: Literals + namespace*: LitId + intbits*: uint32 + symnames*: SymNames + +proc load*(filename: string): NirModule = + let lit = Literals() + result = NirModule(lit: lit, types: initTypeGraph(lit)) + var r = rodfiles.open(filename) + try: + r.loadHeader(nirCookie) + r.loadSection stringsSection + r.load result.lit.strings + + r.loadSection numbersSection + r.load result.lit.numbers + + r.loadSection bodiesSection + r.load result.code + + r.loadSection typesSection + r.load result.types + + r.loadSection sideChannelSection + r.load result.man + + r.loadSection namespaceSection + r.loadPrim result.namespace + r.loadPrim result.intbits + + r.loadSection symnamesSection + r.load result.symnames + + finally: + r.close() + +proc store*(m: NirModule; outp: string) = + var r = rodfiles.create(outp) + try: + r.storeHeader(nirCookie) + r.storeSection stringsSection + r.store m.lit.strings + + r.storeSection numbersSection + r.store m.lit.numbers + + r.storeSection bodiesSection + r.store m.code + + r.storeSection typesSection + r.store m.types + + r.storeSection sideChannelSection + r.store m.man + + r.storeSection namespaceSection + r.storePrim m.namespace + r.storePrim m.intbits + + r.storeSection symnamesSection + r.store m.symnames + + finally: + r.close() + if r.err != ok: + raise newException(IOError, "could store into: " & outp) diff --git a/compiler/nir/nirinsts.nim b/compiler/nir/nirinsts.nim index 2c0dc3d1143a..6cffc1a8938d 100644 --- a/compiler/nir/nirinsts.nim +++ b/compiler/nir/nirinsts.nim @@ -10,9 +10,14 @@ ## NIR instructions. Somewhat inspired by LLVM's instructions. import std / [assertions, hashes] -import .. / ic / bitabs +import .. / ic / [bitabs, rodfiles] import nirlineinfos, nirtypes +const + NirVersion = 1 + nirCookie* = [byte(0), byte('N'), byte('I'), byte('R'), + byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(NirVersion)] + type SymId* = distinct int @@ -49,16 +54,20 @@ type SelectList, # (values...) SelectValue, # (value) SelectRange, # (valueA..valueB) + ForeignDecl, # Can wrap SummonGlobal, SummonThreadLocal, SummonConst SummonGlobal, SummonThreadLocal, Summon, # x = Summon Typed ; x begins to live + SummonResult, SummonParam, SummonConst, Kill, # `Kill x`: scope end for `x` AddrOf, - ArrayAt, # addr(a[i]) - FieldAt, # addr(obj.field) + ArrayAt, # a[i] + DerefArrayAt, # a[i] where `a` is a PtrArray; `a[][i]` + FieldAt, # obj.field + DerefFieldAt, # obj[].field Load, # a[] Store, # a[] = b @@ -100,11 +109,13 @@ type TestOf, Emit, ProcDecl, + ForeignProcDecl, PragmaPair type PragmaKey* = enum FastCall, StdCall, CDeclCall, SafeCall, SysCall, InlineCall, NoinlineCall, ThisCall, NoCall, + CoreName, ExternName, HeaderImport, DllImport, @@ -155,18 +166,22 @@ const AddrOf, Load, ArrayAt, + DerefArrayAt, FieldAt, + DerefFieldAt, TestOf } type Instr* = object # 8 bytes x: uint32 - info: PackedLineInfo + info*: PackedLineInfo template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask) template operand(n: Instr): uint32 = (n.x shr OpcodeBits) +template rawOperand*(n: Instr): uint32 = (n.x shr OpcodeBits) + template toX(k: Opcode; operand: uint32): uint32 = uint32(k) or (operand shl OpcodeBits) @@ -227,6 +242,12 @@ proc nextChild(tree: Tree; pos: var int) {.inline.} = else: inc pos +proc next*(tree: Tree; pos: var NodePos) {.inline.} = nextChild tree, int(pos) + +template firstSon*(n: NodePos): NodePos = NodePos(n.int+1) + +template skipTyped*(n: NodePos): NodePos = NodePos(n.int+2) + iterator sons*(tree: Tree; n: NodePos): NodePos = var pos = n.int assert tree.nodes[pos].kind > LastAtomicValue @@ -236,8 +257,37 @@ iterator sons*(tree: Tree; n: NodePos): NodePos = yield NodePos pos nextChild tree, pos +iterator sonsFrom1*(tree: Tree; n: NodePos): NodePos = + var pos = n.int + assert tree.nodes[pos].kind > LastAtomicValue + let last = pos + tree.nodes[pos].rawSpan + inc pos + nextChild tree, pos + while pos < last: + yield NodePos pos + nextChild tree, pos + +iterator sonsFromN*(tree: Tree; n: NodePos; toSkip = 2): NodePos = + var pos = n.int + assert tree.nodes[pos].kind > LastAtomicValue + let last = pos + tree.nodes[pos].rawSpan + inc pos + for i in 1..toSkip: + nextChild tree, pos + while pos < last: + yield NodePos pos + nextChild tree, pos + template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int] +iterator sonsRest*(tree: Tree; parent, n: NodePos): NodePos = + var pos = n.int + assert tree[parent].kind > LastAtomicValue + let last = parent.int + tree[parent].rawSpan + while pos < last: + yield NodePos pos + nextChild tree, pos + proc span(tree: Tree; pos: int): int {.inline.} = if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand) @@ -250,22 +300,77 @@ proc copyTree*(dest: var Tree; src: Tree) = for i in 0..= 0 t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info) proc addSummon*(t: var Tree; info: PackedLineInfo; s: SymId; typ: TypeId; opc = Summon) {.inline.} = - assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam} + assert typ.int >= 0 + assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam, SummonResult} let x = prepare(t, info, opc) t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info) t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info) @@ -301,14 +411,24 @@ proc addIntVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; buildTyped t, info, NumberConv, typ: t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(x))), info: info) +proc boolVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; b: bool) = + buildTyped t, info, NumberConv, Bool8Id: + t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(ord b))), info: info) + proc addStrVal*(t: var Tree; strings: var BiTable[string]; info: PackedLineInfo; s: string) = t.nodes.add Instr(x: toX(StrVal, uint32(strings.getOrIncl(s))), info: info) +proc addStrLit*(t: var Tree; info: PackedLineInfo; s: LitId) = + t.nodes.add Instr(x: toX(StrVal, uint32(s)), info: info) + proc addNilVal*(t: var Tree; info: PackedLineInfo; typ: TypeId) = buildTyped t, info, NumberConv, typ: t.nodes.add Instr(x: toX(NilVal, uint32(0)), info: info) -proc escapeToNimLit(s: string; result: var string) = +proc store*(r: var RodFile; t: Tree) = storeSeq r, t.nodes +proc load*(r: var RodFile; t: var Tree) = loadSeq r, t.nodes + +proc escapeToNimLit*(s: string; result: var string) = result.add '"' for c in items s: if c < ' ' or int(c) >= 128: @@ -326,7 +446,32 @@ proc escapeToNimLit(s: string; result: var string) = result.add c result.add '"' +type + SymNames* = object + s: seq[LitId] + +proc `[]=`*(t: var SymNames; key: SymId; val: LitId) = + let k = int(key) + if k >= t.s.len: t.s.setLen k+1 + t.s[k] = val + +proc `[]`*(t: SymNames; key: SymId): LitId = + let k = int(key) + if k < t.s.len: result = t.s[k] + else: result = LitId(0) + +template localName(s: SymId): string = + let name = names[s] + if name != LitId(0): + strings[name] + else: + $s.int + +proc store*(r: var RodFile; t: SymNames) = storeSeq(r, t.s) +proc load*(r: var RodFile; t: var SymNames) = loadSeq(r, t.s) + proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTable[int64]; + names: SymNames; r: var string; nesting = 0) = if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}: r.add ' ' @@ -342,34 +487,47 @@ proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTabl escapeToNimLit(strings[LitId t[pos].operand], r) of SymDef: r.add "SymDef " - r.add $t[pos].operand + r.add localName(SymId t[pos].operand) of SymUse: r.add "SymUse " - r.add $t[pos].operand + r.add localName(SymId t[pos].operand) of PragmaId: r.add $cast[PragmaKey](t[pos].operand) of Typed: - r.add "Typed " + r.add "T<" r.add $t[pos].operand + r.add ">" of NilVal: r.add "NilVal" of Label: - r.add "L" + # undo the nesting: + var spaces = r.len-1 + while spaces >= 0 and r[spaces] == ' ': dec spaces + r.setLen spaces+1 + r.add "\n L" r.add $t[pos].operand of Goto, CheckedGoto, LoopLabel, GotoLoop: r.add $t[pos].kind - r.add ' ' + r.add " L" r.add $t[pos].operand else: r.add $t[pos].kind r.add "{\n" for i in 0..<(nesting+1)*2: r.add ' ' for p in sons(t, pos): - toString t, p, strings, integers, r, nesting+1 + toString t, p, strings, integers, names, r, nesting+1 r.add "\n" for i in 0.. 0: result = m.dead[t].pop() else: - result = SymId(m.locGen[]) - inc m.locGen[] + inc symIdgen + result = SymId(symIdgen) m.inScope.add result m.live[result] = (k, t) -proc allocTemp*(m: var SlotManager; t: TypeId): SymId {.inline.} = - result = allocRaw(m, t, ReuseTemps, Temp) +proc allocTemp*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} = + result = allocRaw(m, t, ReuseTemps, Temp, symIdgen) -proc allocVar*(m: var SlotManager; t: TypeId): SymId {.inline.} = - result = allocRaw(m, t, ReuseVars, Perm) +proc allocVar*(m: var SlotManager; t: TypeId; symIdgen: var int32): SymId {.inline.} = + result = allocRaw(m, t, ReuseVars, Perm, symIdgen) proc freeLoc*(m: var SlotManager; s: SymId) = let t = m.live.getOrDefault(s) @@ -74,32 +74,31 @@ proc closeScope*(m: var SlotManager) = dec i when isMainModule: - var m = initSlotManager({ReuseTemps}, new(int)) + var symIdgen: int32 + var m = initSlotManager({ReuseTemps}) - var g = initTypeGraph() + var g = initTypeGraph(Literals()) let a = g.openType ArrayTy g.addBuiltinType Int8Id - g.addArrayLen 5'u64 - let finalArrayType = sealType(g, a) + g.addArrayLen 5 + let finalArrayType = finishType(g, a) let obj = g.openType ObjectDecl g.addName "MyType" - g.addField "p", finalArrayType - let objB = sealType(g, obj) + g.addField "p", finalArrayType, 0 + let objB = finishType(g, obj) - let x = m.allocTemp(objB) + let x = m.allocTemp(objB, symIdgen) assert x.int == 0 - let y = m.allocTemp(objB) + let y = m.allocTemp(objB, symIdgen) assert y.int == 1 - let z = m.allocTemp(Int8Id) + let z = m.allocTemp(Int8Id, symIdgen) assert z.int == 2 m.freeLoc y - let y2 = m.allocTemp(objB) + let y2 = m.allocTemp(objB, symIdgen) assert y2.int == 1 - - diff --git a/compiler/nir/nirtypes.nim b/compiler/nir/nirtypes.nim index a42feab005c8..a79bf6d012a3 100644 --- a/compiler/nir/nirtypes.nim +++ b/compiler/nir/nirtypes.nim @@ -10,12 +10,15 @@ ## Type system for NIR. Close to C's type system but without its quirks. import std / [assertions, hashes] -import .. / ic / bitabs +import .. / ic / [bitabs, rodfiles] type NirTypeKind* = enum - VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal, IntVal, + VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal, + IntVal, SizeVal, AlignVal, OffsetVal, AnnotationVal, + ObjectTy, + UnionTy, VarargsTy, # the `...` in a C prototype; also the last "atom" APtrTy, # pointer to aliasable memory UPtrTy, # pointer to unique/unaliasable memory @@ -23,8 +26,6 @@ type UArrayPtrTy, # pointer to array of unique/unaliasable memory ArrayTy, LastArrayTy, # array of unspecified size as a last field inside an object - ObjectTy, - UnionTy, ProcTy, ObjectDecl, UnionDecl, @@ -41,6 +42,11 @@ type template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask) template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits) +proc integralBits*(n: TypeNode): int {.inline.} = + # Number of bits in the IntTy, etc. Only valid for integral types. + assert n.kind in {IntTy, UIntTy, FloatTy, BoolTy, CharTy} + result = int(n.operand) + template toX(k: NirTypeKind; operand: uint32): uint32 = uint32(k) or (operand shl TypeKindBits) @@ -54,10 +60,13 @@ proc `==`*(a, b: TypeId): bool {.borrow.} proc hash*(a: TypeId): Hash {.borrow.} type + Literals* = ref object + strings*: BiTable[string] + numbers*: BiTable[int64] + TypeGraph* = object nodes: seq[TypeNode] - names: BiTable[string] - numbers: BiTable[uint64] + lit: Literals const VoidId* = TypeId 0 @@ -76,7 +85,7 @@ const VoidPtrId* = TypeId 13 LastBuiltinId* = 13 -proc initTypeGraph*(): TypeGraph = +proc initTypeGraph*(lit: Literals): TypeGraph = result = TypeGraph(nodes: @[ TypeNode(x: toX(VoidTy, 0'u32)), TypeNode(x: toX(BoolTy, 8'u32)), @@ -93,7 +102,7 @@ proc initTypeGraph*(): TypeGraph = TypeNode(x: toX(FloatTy, 64'u32)), TypeNode(x: toX(APtrTy, 2'u32)), TypeNode(x: toX(VoidTy, 0'u32)) - ]) + ], lit: lit) assert result.nodes.len == LastBuiltinId+2 type @@ -146,6 +155,10 @@ proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} = assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy} result = TypeId(n.int+1) +proc litId*(n: TypeNode): LitId {.inline.} = + assert n.kind in {NameVal, IntVal, SizeVal, AlignVal, OffsetVal, AnnotationVal, ObjectTy, UnionTy} + result = LitId(n.operand) + proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind proc span(tree: TypeGraph; pos: int): int {.inline.} = @@ -164,9 +177,34 @@ proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) = let c = b + span(tree, b) result = (TypeId a, TypeId b, TypeId c) -proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestUInt = +proc arrayName*(tree: TypeGraph; n: TypeId): TypeId {.inline.} = assert tree[n].kind == ArrayTy - result = tree.numbers[LitId tree[n].operand] + let (_, _, c) = sons3(tree, n) + result = c + +proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestInt = + assert tree[n].kind == ArrayTy + let (_, b) = sons2(tree, n) + result = tree.lit.numbers[LitId tree[b].operand] + +proc returnType*(tree: TypeGraph; n: TypeId): (TypeId, TypeId) = + # Returns the positions of the return type + calling convention. + var pos = n.int + assert tree.nodes[pos].kind == ProcTy + let a = n.int+1 + let b = a + span(tree, a) + result = (TypeId b, TypeId a) # not a typo, order is reversed + +iterator params*(tree: TypeGraph; n: TypeId): TypeId = + var pos = n.int + assert tree.nodes[pos].kind == ProcTy + let last = pos + tree.nodes[pos].rawSpan + inc pos + nextChild tree, pos + nextChild tree, pos + while pos < last: + yield TypeId pos + nextChild tree, pos proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos = assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, @@ -174,20 +212,58 @@ proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos = FieldDecl} result = prepare(tree, kind) -proc sealType*(tree: var TypeGraph; p: TypePatchPos): TypeId = - # TODO: Search for an existing instance of this type in - # order to reduce memory consumption. - result = TypeId(p) +template typeInvariant(p: TypePatchPos) = + when false: + if tree[TypeId(p)].kind == FieldDecl: + var k = 0 + for ch in sons(tree, TypeId(p)): + inc k + assert k > 2, "damn! " & $k + +proc sealType*(tree: var TypeGraph; p: TypePatchPos) = patch tree, p + typeInvariant(p) + +proc finishType*(tree: var TypeGraph; p: TypePatchPos): TypeId = + # Search for an existing instance of this type in + # order to reduce memory consumption: + patch tree, p + typeInvariant(p) + + let s = span(tree, p.int) + var i = 0 + while i < p.int: + if tree.nodes[i].x == tree.nodes[p.int].x: + var isMatch = true + for j in 1.. " toString(dest, g, TypeId i) dest.add '\n' nextChild g, i +iterator allTypes*(g: TypeGraph; start = 0): TypeId = + var i = start + while i < g.len: + yield TypeId i + nextChild g, i + +iterator allTypesIncludingInner*(g: TypeGraph; start = 0): TypeId = + var i = start + while i < g.len: + yield TypeId i + inc i + proc `$`(g: TypeGraph): string = result = "" toString(result, g) when isMainModule: - var g = initTypeGraph() + var g = initTypeGraph(Literals()) let a = g.openType ArrayTy g.addBuiltinType Int8Id - g.addArrayLen 5'u64 - let finalArrayType = sealType(g, a) + g.addArrayLen 5 + g.addName "SomeArray" + let finalArrayType = finishType(g, a) let obj = g.openType ObjectDecl - g.nodes.add TypeNode(x: toX(NameVal, g.names.getOrIncl("MyType"))) + g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl("MyType"))) - g.addField "p", finalArrayType - discard sealType(g, obj) + g.addField "p", finalArrayType, 0 + sealType(g, obj) echo g diff --git a/compiler/nir/nirvm.nim b/compiler/nir/nirvm.nim new file mode 100644 index 000000000000..faa7a1fb7eb3 --- /dev/null +++ b/compiler/nir/nirvm.nim @@ -0,0 +1,1175 @@ +# +# +# The Nim Compiler +# (c) Copyright 2023 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +##[ NIR is a little too high level to interpret it efficiently. Thus +we compute `addresses` for SymIds, labels and offsets for object fields +in a preprocessing step. + +We also split the instruction stream into separate (code, debug) seqs while +we're at it. +]## + +import std / [syncio, assertions, tables, intsets] +import ".." / ic / bitabs +import nirinsts, nirtypes, nirfiles, nirlineinfos + +type + OpcodeM = enum + ImmediateValM, + IntValM, + StrValM, + LoadLocalM, # with local ID + LoadGlobalM, + LoadProcM, + TypedM, # with type ID + PragmaIdM, # with Pragma ID, possible values: see PragmaKey enum + NilValM, + AllocLocals, + SummonParamM, + GotoM, + CheckedGotoM, # last atom + + ArrayConstrM, + ObjConstrM, + RetM, + YldM, + + SelectM, + SelectPairM, # ((values...), Label) + SelectListM, # (values...) + SelectValueM, # (value) + SelectRangeM, # (valueA..valueB) + + AddrOfM, + ArrayAtM, # (elemSize, addr(a), i) + DerefArrayAtM, + FieldAtM, # addr(obj.field) + DerefFieldAtM, + + LoadM, # a[] + AsgnM, # a = b + StoreM, # a[] = b + SetExcM, + TestExcM, + + CheckedRangeM, + CheckedIndexM, + + CallM, + CheckedAddM, # with overflow checking etc. + CheckedSubM, + CheckedMulM, + CheckedDivM, + CheckedModM, + AddM, + SubM, + MulM, + DivM, + ModM, + BitShlM, + BitShrM, + BitAndM, + BitOrM, + BitXorM, + BitNotM, + BoolNotM, + EqM, + LeM, + LtM, + CastM, + NumberConvM, + CheckedObjConvM, + ObjConvM, + TestOfM, + ProcDeclM, + PragmaPairM + +const + LastAtomicValue = CheckedGotoM + + OpcodeBits = 8'u32 + OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32 + +type + Instr = distinct uint32 + +template kind(n: Instr): OpcodeM = OpcodeM(n.uint32 and OpcodeMask) +template operand(n: Instr): uint32 = (n.uint32 shr OpcodeBits) + +template toIns(k: OpcodeM; operand: uint32): Instr = + Instr(uint32(k) or (operand shl OpcodeBits)) + +template toIns(k: OpcodeM; operand: LitId): Instr = + Instr(uint32(k) or (operand.uint32 shl OpcodeBits)) + +type + NimStrPayloadVM = object + cap: int + data: UncheckedArray[char] + NimStringVM = object + len: int + p: ptr NimStrPayloadVM + +const + GlobalsSize = 1024*24 + +type + PatchPos = distinct int + CodePos = distinct int + + Bytecode* = object + code: seq[Instr] + debug: seq[PackedLineInfo] + m: ref NirModule + procs: Table[SymId, CodePos] + globals: Table[SymId, (uint32, int)] + strings: Table[LitId, NimStringVM] + globalData: pointer + globalsAddr: uint32 + typeImpls: Table[string, TypeId] + offsets: Table[TypeId, seq[(int, TypeId)]] + sizes: Table[TypeId, (int, int)] # (size, alignment) + oldTypeLen: int + procUsagesToPatch: Table[SymId, seq[CodePos]] + interactive*: bool + + Universe* = object ## all units: For interpretation we need that + units: seq[Bytecode] + unitNames: Table[string, int] + current: int + +proc initBytecode*(m: ref NirModule): Bytecode = Bytecode(m: m, globalData: alloc0(GlobalsSize)) + +proc debug(bc: Bytecode; t: TypeId) = + var buf = "" + toString buf, bc.m.types, t + echo buf + +proc debug(bc: Bytecode; info: PackedLineInfo) = + let (litId, line, col) = bc.m.man.unpack(info) + echo bc.m.lit.strings[litId], ":", line, ":", col + +proc debug(bc: Bytecode; t: Tree; n: NodePos) = + var buf = "" + toString(t, n, bc.m.lit.strings, bc.m.lit.numbers, bc.m.symnames, buf) + echo buf + +template `[]`(t: seq[Instr]; n: CodePos): Instr = t[n.int] + +proc traverseObject(b: var Bytecode; t, offsetKey: TypeId) = + var size = -1 + var align = -1 + for x in sons(b.m.types, t): + case b.m.types[x].kind + of FieldDecl: + var offset = -1 + for y in sons(b.m.types, x): + if b.m.types[y].kind == OffsetVal: + offset = int(b.m.lit.numbers[b.m.types[y].litId]) + break + b.offsets.mgetOrPut(offsetKey, @[]).add (offset, x.firstSon) + of SizeVal: + size = int(b.m.lit.numbers[b.m.types[x].litId]) + of AlignVal: + align = int(b.m.lit.numbers[b.m.types[x].litId]) + of ObjectTy: + # inheritance + let impl = b.typeImpls.getOrDefault(b.m.lit.strings[b.m.types[x].litId]) + assert impl.int > 0 + traverseObject b, impl, offsetKey + else: discard + if t == offsetKey: + b.sizes[t] = (size, align) + +proc computeSize(b: var Bytecode; t: TypeId): (int, int) = + case b.m.types[t].kind + of ObjectDecl, UnionDecl: + result = b.sizes[t] + of ObjectTy, UnionTy: + let impl = b.typeImpls[b.m.lit.strings[b.m.types[t].litId]] + result = computeSize(b, impl) + of IntTy, UIntTy, FloatTy, BoolTy, CharTy: + let s = b.m.types[t].integralBits div 8 + result = (s, s) + of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ProcTy: + result = (sizeof(pointer), sizeof(pointer)) + of ArrayTy: + let e = elementType(b.m.types, t) + let n = arrayLen(b.m.types, t) + let inner = computeSize(b, e) + result = (inner[0] * n.int, inner[1]) + else: + result = (0, 0) + +proc computeElemSize(b: var Bytecode; t: TypeId): int = + case b.m.types[t].kind + of ArrayTy, APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, LastArrayTy: + result = computeSize(b, elementType(b.m.types, t))[0] + else: + raiseAssert "not an array type" + +proc traverseTypes(b: var Bytecode) = + for t in allTypes(b.m.types, b.oldTypeLen): + if b.m.types[t].kind in {ObjectDecl, UnionDecl}: + assert b.m.types[t.firstSon].kind == NameVal + b.typeImpls[b.m.lit.strings[b.m.types[t.firstSon].litId]] = t + + for t in allTypes(b.m.types, b.oldTypeLen): + if b.m.types[t].kind in {ObjectDecl, UnionDecl}: + assert b.m.types[t.firstSon].kind == NameVal + traverseObject b, t, t + b.oldTypeLen = b.m.types.len + +const + InvalidPatchPos* = PatchPos(-1) + +proc isValid(p: PatchPos): bool {.inline.} = p.int != -1 + +proc prepare(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM): PatchPos = + result = PatchPos bc.code.len + bc.code.add toIns(kind, 1'u32) + bc.debug.add info + +proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; raw: uint32) = + bc.code.add toIns(kind, raw) + bc.debug.add info + +proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; lit: LitId) = + add bc, info, kind, uint32(lit) + +proc isAtom(bc: Bytecode; pos: int): bool {.inline.} = bc.code[pos].kind <= LastAtomicValue +proc isAtom(bc: Bytecode; pos: CodePos): bool {.inline.} = bc.code[pos.int].kind <= LastAtomicValue + +proc patch(bc: var Bytecode; pos: PatchPos) = + let pos = pos.int + let k = bc.code[pos].kind + assert k > LastAtomicValue + let distance = int32(bc.code.len - pos) + assert distance > 0 + bc.code[pos] = toIns(k, cast[uint32](distance)) + +template build(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; body: untyped) = + let pos = prepare(bc, info, kind) + body + patch(bc, pos) + +proc len*(bc: Bytecode): int {.inline.} = bc.code.len + +template rawSpan(n: Instr): int = int(operand(n)) + +proc nextChild(bc: Bytecode; pos: var int) {.inline.} = + if bc.code[pos].kind > LastAtomicValue: + assert bc.code[pos].operand > 0'u32 + inc pos, bc.code[pos].rawSpan + else: + inc pos + +proc next(bc: Bytecode; pos: var CodePos) {.inline.} = nextChild bc, int(pos) + +iterator sons(bc: Bytecode; n: CodePos): CodePos = + var pos = n.int + assert bc.code[pos].kind > LastAtomicValue + let last = pos + bc.code[pos].rawSpan + inc pos + while pos < last: + yield CodePos pos + nextChild bc, pos + +iterator sonsFrom1(bc: Bytecode; n: CodePos): CodePos = + var pos = n.int + assert bc.code[pos].kind > LastAtomicValue + let last = pos + bc.code[pos].rawSpan + inc pos + nextChild bc, pos + while pos < last: + yield CodePos pos + nextChild bc, pos + +iterator sonsFrom2(bc: Bytecode; n: CodePos): CodePos = + var pos = n.int + assert bc.code[pos].kind > LastAtomicValue + let last = pos + bc.code[pos].rawSpan + inc pos + nextChild bc, pos + nextChild bc, pos + while pos < last: + yield CodePos pos + nextChild bc, pos + +template firstSon(n: CodePos): CodePos = CodePos(n.int+1) + +template `[]`(t: Bytecode; n: CodePos): Instr = t.code[n.int] + +proc span(bc: Bytecode; pos: int): int {.inline.} = + if bc.code[pos].kind <= LastAtomicValue: 1 else: int(bc.code[pos].operand) + +iterator triples*(bc: Bytecode; n: CodePos): (uint32, int, CodePos) = + var pos = n.int + assert bc.code[pos].kind > LastAtomicValue + let last = pos + bc.code[pos].rawSpan + inc pos + while pos < last: + let offset = bc.code[pos].operand + nextChild bc, pos + let size = bc.code[pos].operand.int + nextChild bc, pos + let val = CodePos pos + yield (offset, size, val) + nextChild bc, pos + +proc toString*(t: Bytecode; pos: CodePos; + r: var string; nesting = 0) = + if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}: + r.add ' ' + + case t[pos].kind + of ImmediateValM: + r.add $t[pos].operand + of IntValM: + r.add "IntVal " + r.add $t.m.lit.numbers[LitId t[pos].operand] + of StrValM: + escapeToNimLit(t.m.lit.strings[LitId t[pos].operand], r) + of LoadLocalM, LoadGlobalM, LoadProcM, AllocLocals, SummonParamM: + r.add $t[pos].kind + r.add ' ' + r.add $t[pos].operand + of PragmaIdM: + r.add $cast[PragmaKey](t[pos].operand) + of TypedM: + r.add "T<" + r.add $t[pos].operand + r.add ">" + of NilValM: + r.add "NilVal" + of GotoM, CheckedGotoM: + r.add $t[pos].kind + r.add " L" + r.add $t[pos].operand + else: + r.add $t[pos].kind + r.add "{\n" + for i in 0..<(nesting+1)*2: r.add ' ' + for p in sons(t, pos): + toString t, p, r, nesting+1 + r.add "\n" + for i in 0..= 0: + bc.add info, opc, uint32 dest + else: + let here = CodePos(bc.code.len) + c.toPatch.mgetOrPut(lab, @[]).add here + bc.add info, opc, 1u32 # will be patched once we traversed the label + +type + AddrMode = enum + InDotExpr, WantAddr + +template maybeDeref(doDeref: bool; size: int; body: untyped) = + var pos = PatchPos(-1) + if doDeref: + pos = prepare(bc, info, LoadM) + bc.add info, ImmediateValM, uint32 size + body + if doDeref: + patch(bc, pos) + +proc toReadonlyString(s: string): NimStringVM = + if s.len == 0: + result = NimStringVM(len: 0, p: nil) + else: + result = NimStringVM(len: s.len, p: cast[ptr NimStrPayloadVM](alloc(s.len+1+sizeof(int)))) + copyMem(addr result.p.data[0], addr s[0], s.len+1) + result.p.cap = s.len or (1 shl (8 * 8 - 2)) # see also NIM_STRLIT_FLAG + +const + ForwardedProc = 10_000_000'u32 + +proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; flags: set[AddrMode]) = + let info = t[n].info + + template recurse(opc) = + build bc, info, opc: + for ch in sons(t, n): preprocess(c, bc, t, ch, {WantAddr}) + + case t[n].kind + of Nop, ForeignDecl, ForeignProcDecl: + discard "don't use Nop" + of ImmediateVal: + bc.add info, ImmediateValM, t[n].rawOperand + of IntVal: + bc.add info, IntValM, t[n].rawOperand + of StrVal: + let litId = LitId t[n].rawOperand + if not bc.strings.hasKey(litId): + bc.strings[litId] = toReadonlyString(bc.m.lit.strings[litId]) + bc.add info, StrValM, t[n].rawOperand + of SymDef: + discard "happens for proc decls. Don't copy the node as we don't need it" + of SymUse: + let s = t[n].symId + if c.locals.hasKey(s): + let (address, size) = c.locals[s] + maybeDeref(WantAddr notin flags, size): + bc.add info, LoadLocalM, address + elif bc.procs.hasKey(s): + bc.add info, LoadProcM, uint32 bc.procs[s] + elif bc.globals.hasKey(s): + let (address, size) = bc.globals[s] + maybeDeref(WantAddr notin flags, size): + bc.add info, LoadGlobalM, address + else: + let here = CodePos(bc.code.len) + bc.add info, LoadProcM, ForwardedProc + uint32(s) + bc.procUsagesToPatch.mgetOrPut(s, @[]).add here + #raiseAssert "don't understand SymUse ID " & $int(s) + + of ModuleSymUse: + when false: + let (x, y) = sons2(t, n) + let unit = c.u.unitNames.getOrDefault(bc.m.lit.strings[t[x].litId], -1) + let s = t[y].symId + if c.u.units[unit].procs.hasKey(s): + bc.add info, LoadProcM, uint32 c.u.units[unit].procs[s] + elif bc.globals.hasKey(s): + maybeDeref(WantAddr notin flags): + build bc, info, LoadGlobalM: + bc.add info, ImmediateValM, uint32 unit + bc.add info, LoadLocalM, uint32 s + else: + raiseAssert "don't understand ModuleSymUse ID" + + raiseAssert "don't understand ModuleSymUse ID" + of Typed: + bc.add info, TypedM, t[n].rawOperand + of PragmaId: + bc.add info, PragmaIdM, t[n].rawOperand + of NilVal: + bc.add info, NilValM, t[n].rawOperand + of LoopLabel, Label: + let lab = t[n].label + let here = CodePos(bc.code.len) + c.known[lab] = here + var p: seq[CodePos] = @[] + if c.toPatch.take(lab, p): + for x in p: (bc.code[x]) = toIns(bc.code[x].kind, uint32 here) + c.markedWithLabel.incl here.int # for toString() + of Goto, GotoLoop: + c.genGoto(bc, info, t[n].label, GotoM) + of CheckedGoto: + c.genGoto(bc, info, t[n].label, CheckedGotoM) + of ArrayConstr: + let typ = t[n.firstSon].typeId + let s = computeElemSize(bc, typ) + build bc, info, ArrayConstrM: + bc.add info, ImmediateValM, uint32 s + for ch in sonsFrom1(t, n): + preprocess(c, bc, t, ch, {WantAddr}) + of ObjConstr: + #debug bc, t, n + var i = 0 + let typ = t[n.firstSon].typeId + build bc, info, ObjConstrM: + for ch in sons(t, n): + if i > 0: + if (i mod 2) == 1: + let (offset, typ) = bc.offsets[typ][t[ch].immediateVal] + let size = computeSize(bc, typ)[0] + bc.add info, ImmediateValM, uint32(offset) + bc.add info, ImmediateValM, uint32(size) + else: + preprocess(c, bc, t, ch, {WantAddr}) + inc i + of Ret: + recurse RetM + of Yld: + recurse YldM + of Select: + recurse SelectM + of SelectPair: + recurse SelectPairM + of SelectList: + recurse SelectListM + of SelectValue: + recurse SelectValueM + of SelectRange: + recurse SelectRangeM + of SummonGlobal, SummonThreadLocal, SummonConst: + let (typ, sym) = sons2(t, n) + + let s = t[sym].symId + let tid = t[typ].typeId + let (size, alignment) = computeSize(bc, tid) + + let global = align(bc.globalsAddr, uint32 alignment) + bc.globals[s] = (global, size) + bc.globalsAddr += uint32 size + assert bc.globalsAddr < GlobalsSize + + of Summon: + let (typ, sym) = sons2(t, n) + + let s = t[sym].symId + let tid = t[typ].typeId + let (size, alignment) = computeSize(bc, tid) + + let local = align(c.localsAddr, uint32 alignment) + c.locals[s] = (local, size) + c.localsAddr += uint32 size + # allocation is combined into the frame allocation so there is no + # instruction to emit + of SummonParam, SummonResult: + let (typ, sym) = sons2(t, n) + + let s = t[sym].symId + let tid = t[typ].typeId + let (size, alignment) = computeSize(bc, tid) + + let local = align(c.localsAddr, uint32 alignment) + c.locals[s] = (local, size) + c.localsAddr += uint32 size + bc.add info, SummonParamM, local + bc.add info, ImmediateValM, uint32 size + of Kill: + discard "we don't care about Kill instructions" + of AddrOf: + let (_, arg) = sons2(t, n) + preprocess(c, bc, t, arg, {WantAddr}) + # the address of x is what the VM works with all the time so there is + # nothing to compute. + of ArrayAt: + let (arrayType, a, i) = sons3(t, n) + let tid = t[arrayType].typeId + let size = uint32 computeElemSize(bc, tid) + build bc, info, ArrayAtM: + bc.add info, ImmediateValM, size + preprocess(c, bc, t, a, {WantAddr}) + preprocess(c, bc, t, i, {WantAddr}) + of DerefArrayAt: + let (arrayType, a, i) = sons3(t, n) + let tid = t[arrayType].typeId + let size = uint32 computeElemSize(bc, tid) + build bc, info, DerefArrayAtM: + bc.add info, ImmediateValM, size + preprocess(c, bc, t, a, {WantAddr}) + preprocess(c, bc, t, i, {WantAddr}) + of FieldAt: + let (typ, a, b) = sons3(t, n) + let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0] + build bc, info, FieldAtM: + preprocess(c, bc, t, a, flags+{WantAddr}) + bc.add info, ImmediateValM, uint32(offset) + of DerefFieldAt: + let (typ, a, b) = sons3(t, n) + let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0] + build bc, info, DerefFieldAtM: + preprocess(c, bc, t, a, flags+{WantAddr}) + bc.add info, ImmediateValM, uint32(offset) + of Load: + let (elemType, a) = sons2(t, n) + let tid = t[elemType].typeId + build bc, info, LoadM: + bc.add info, ImmediateValM, uint32 computeSize(bc, tid)[0] + preprocess(c, bc, t, a, {}) + + of Store: + raiseAssert "Assumption was that Store is unused!" + of Asgn: + let (elemType, dest, src) = sons3(t, n) + let tid = t[elemType].typeId + if t[src].kind in {Call, IndirectCall}: + # No support for return values, these are mapped to `var T` parameters! + build bc, info, CallM: + preprocess(c, bc, t, src.skipTyped, {WantAddr}) + preprocess(c, bc, t, dest, {WantAddr}) + for ch in sonsFromN(t, src, 2): preprocess(c, bc, t, ch, {WantAddr}) + elif t[src].kind in {CheckedCall, CheckedIndirectCall}: + let (_, gotoInstr, fn) = sons3(t, src) + build bc, info, CallM: + preprocess(c, bc, t, fn, {WantAddr}) + preprocess(c, bc, t, dest, {WantAddr}) + for ch in sonsFromN(t, src, 3): preprocess(c, bc, t, ch, {WantAddr}) + preprocess c, bc, t, gotoInstr, {} + elif t[dest].kind == Load: + let (typ, a) = sons2(t, dest) + let s = computeSize(bc, tid)[0] + build bc, info, StoreM: + bc.add info, ImmediateValM, uint32 s + preprocess(c, bc, t, a, {WantAddr}) + preprocess(c, bc, t, src, {}) + else: + let s = computeSize(bc, tid)[0] + build bc, info, AsgnM: + bc.add info, ImmediateValM, uint32 s + preprocess(c, bc, t, dest, {WantAddr}) + preprocess(c, bc, t, src, {}) + of SetExc: + recurse SetExcM + of TestExc: + recurse TestExcM + of CheckedRange: + recurse CheckedRangeM + of CheckedIndex: + recurse CheckedIndexM + of Call, IndirectCall: + # avoid the Typed thing at position 0: + build bc, info, CallM: + for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr}) + of CheckedCall, CheckedIndirectCall: + # avoid the Typed thing at position 0: + let (_, gotoInstr, fn) = sons3(t, n) + build bc, info, CallM: + preprocess(c, bc, t, fn, {WantAddr}) + for ch in sonsFromN(t, n, 3): preprocess(c, bc, t, ch, {WantAddr}) + preprocess c, bc, t, gotoInstr, {WantAddr} + of CheckedAdd: + recurse CheckedAddM + of CheckedSub: + recurse CheckedSubM + of CheckedMul: + recurse CheckedMulM + of CheckedDiv: + recurse CheckedDivM + of CheckedMod: + recurse CheckedModM + of Add: + recurse AddM + of Sub: + recurse SubM + of Mul: + recurse MulM + of Div: + recurse DivM + of Mod: + recurse ModM + of BitShl: + recurse BitShlM + of BitShr: + recurse BitShrM + of BitAnd: + recurse BitAndM + of BitOr: + recurse BitOrM + of BitXor: + recurse BitXorM + of BitNot: + recurse BitNotM + of BoolNot: + recurse BoolNotM + of Eq: + recurse EqM + of Le: + recurse LeM + of Lt: + recurse LtM + of Cast: + recurse CastM + of NumberConv: + recurse NumberConvM + of CheckedObjConv: + recurse CheckedObjConvM + of ObjConv: + recurse ObjConvM + of TestOf: + recurse TestOfM + of Emit: + raiseAssert "cannot interpret: Emit" + of ProcDecl: + var c2 = Preprocessing(u: c.u, thisModule: c.thisModule) + let sym = t[n.firstSon].symId + let here = CodePos(bc.len) + var p: seq[CodePos] = @[] + if bc.procUsagesToPatch.take(sym, p): + for x in p: (bc.code[x]) = toIns(bc.code[x].kind, uint32 here) + bc.procs[sym] = here + build bc, info, ProcDeclM: + let toPatch = bc.code.len + bc.add info, AllocLocals, 0'u32 + for ch in sons(t, n): preprocess(c2, bc, t, ch, {}) + bc.code[toPatch] = toIns(AllocLocals, c2.localsAddr) + when false: + if here.int == 39850: + debug bc, t, n + debug bc, here + + of PragmaPair: + recurse PragmaPairM + +const PayloadSize = 128 + +type + StackFrame = ref object + locals: pointer # usually points into `payload` if size is small enough, otherwise it's `alloc`'ed. + payload: array[PayloadSize, byte] + caller: StackFrame + returnAddr: CodePos + jumpTo: CodePos # exception handling + u: ref Universe + +proc newStackFrame(size: int; caller: StackFrame; returnAddr: CodePos): StackFrame = + result = StackFrame(caller: caller, returnAddr: returnAddr, u: caller.u) + if size <= PayloadSize: + result.locals = addr(result.payload) + else: + result.locals = alloc0(size) + +proc popStackFrame(s: StackFrame): StackFrame = + if s.locals != addr(s.payload): + dealloc s.locals + result = s.caller + +template `+!`(p: pointer; diff: uint): pointer = cast[pointer](cast[uint](p) + diff) + +proc isAtom(tree: seq[Instr]; pos: CodePos): bool {.inline.} = tree[pos.int].kind <= LastAtomicValue + +proc span(bc: seq[Instr]; pos: int): int {.inline.} = + if bc[pos].kind <= LastAtomicValue: 1 else: int(bc[pos].operand) + +proc sons2(tree: seq[Instr]; n: CodePos): (CodePos, CodePos) = + assert(not isAtom(tree, n)) + let a = n.int+1 + let b = a + span(tree, a) + result = (CodePos a, CodePos b) + +proc sons3(tree: seq[Instr]; n: CodePos): (CodePos, CodePos, CodePos) = + assert(not isAtom(tree, n)) + let a = n.int+1 + let b = a + span(tree, a) + let c = b + span(tree, b) + result = (CodePos a, CodePos b, CodePos c) + +proc sons4(tree: seq[Instr]; n: CodePos): (CodePos, CodePos, CodePos, CodePos) = + assert(not isAtom(tree, n)) + let a = n.int+1 + let b = a + span(tree, a) + let c = b + span(tree, b) + let d = c + span(tree, c) + result = (CodePos a, CodePos b, CodePos c, CodePos d) + +proc typeId*(ins: Instr): TypeId {.inline.} = + assert ins.kind == TypedM + result = TypeId(ins.operand) + +proc immediateVal*(ins: Instr): int {.inline.} = + assert ins.kind == ImmediateValM + result = cast[int](ins.operand) + +proc litId*(ins: Instr): LitId {.inline.} = + assert ins.kind in {StrValM, IntValM} + result = LitId(ins.operand) + +proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) + +proc evalAddr(c: Bytecode; pc: CodePos; s: StackFrame): pointer = + case c.code[pc].kind + of LoadLocalM: + result = s.locals +! c.code[pc].operand + of FieldAtM: + let (x, offset) = sons2(c.code, pc) + result = evalAddr(c, x, s) + result = result +! c.code[offset].operand + of DerefFieldAtM: + let (x, offset) = sons2(c.code, pc) + let p = evalAddr(c, x, s) + result = cast[ptr pointer](p)[] +! c.code[offset].operand + of ArrayAtM: + let (e, a, i) = sons3(c.code, pc) + let elemSize = c.code[e].operand + result = evalAddr(c, a, s) + var idx: int = 0 + eval(c, i, s, addr idx, sizeof(int)) + result = result +! (uint32(idx) * elemSize) + of DerefArrayAtM: + let (e, a, i) = sons3(c.code, pc) + let elemSize = c.code[e].operand + var p = evalAddr(c, a, s) + var idx: int = 0 + eval(c, i, s, addr idx, sizeof(int)) + result = cast[ptr pointer](p)[] +! (uint32(idx) * elemSize) + of LoadGlobalM: + result = c.globalData +! c.code[pc].operand + else: + raiseAssert("unimplemented addressing mode") + +proc `div`(x, y: float32): float32 {.inline.} = x / y +proc `div`(x, y: float64): float64 {.inline.} = x / y + +from std / math import `mod` + +template binop(opr) {.dirty.} = + template impl(typ) {.dirty.} = + var x = default(typ) + var y = default(typ) + eval c, a, s, addr x, sizeof(typ) + eval c, b, s, addr y, sizeof(typ) + cast[ptr typ](result)[] = opr(x, y) + + let (t, a, b) = sons3(c.code, pc) + let tid = TypeId c.code[t].operand + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + of Float32Id: impl float32 + of Float64Id: impl float64 + else: discard + +template checkedBinop(opr) {.dirty.} = + template impl(typ) {.dirty.} = + var x = default(typ) + var y = default(typ) + eval c, a, s, addr x, sizeof(typ) + eval c, b, s, addr y, sizeof(typ) + try: + cast[ptr typ](result)[] = opr(x, y) + except OverflowDefect, DivByZeroDefect: + s.jumpTo = CodePos c.code[j].operand + + let (t, j, a, b) = sons4(c.code, pc) + let tid = TypeId c.code[t].operand + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + of Float32Id: impl float32 + of Float64Id: impl float64 + else: discard + +template bitop(opr) {.dirty.} = + template impl(typ) {.dirty.} = + var x = default(typ) + var y = default(typ) + eval c, a, s, addr x, sizeof(typ) + eval c, b, s, addr y, sizeof(typ) + cast[ptr typ](result)[] = opr(x, y) + + let (t, a, b) = sons3(c.code, pc) + let tid = c.code[t].typeId + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + else: discard + +template cmpop(opr) {.dirty.} = + template impl(typ) {.dirty.} = + var x = default(typ) + var y = default(typ) + eval c, a, s, addr x, sizeof(typ) + eval c, b, s, addr y, sizeof(typ) + cast[ptr bool](result)[] = opr(x, y) + + let (t, a, b) = sons3(c.code, pc) + let tid = c.code[t].typeId + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + of Float32Id: impl float32 + of Float64Id: impl float64 + else: discard + +proc evalSelect(c: Bytecode; pc: CodePos; s: StackFrame): CodePos = + template impl(typ) {.dirty.} = + var selector = default(typ) + eval c, sel, s, addr selector, sizeof(typ) + for pair in sonsFrom2(c, pc): + assert c.code[pair].kind == SelectPairM + let (values, action) = sons2(c.code, pair) + if c.code[values].kind == SelectValueM: + var a = default(typ) + eval c, values.firstSon, s, addr a, sizeof(typ) + if selector == a: + return CodePos c.code[action].operand + else: + assert c.code[values].kind == SelectListM, $c.code[values].kind + for v in sons(c, values): + case c.code[v].kind + of SelectValueM: + var a = default(typ) + eval c, v.firstSon, s, addr a, sizeof(typ) + if selector == a: + return CodePos c.code[action].operand + of SelectRangeM: + let (va, vb) = sons2(c.code, v) + var a = default(typ) + eval c, va, s, addr a, sizeof(typ) + var b = default(typ) + eval c, vb, s, addr a, sizeof(typ) + if a <= selector and selector <= b: + return CodePos c.code[action].operand + else: raiseAssert "unreachable" + result = CodePos(-1) + + let (t, sel) = sons2(c.code, pc) + let tid = c.code[t].typeId + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + else: raiseAssert "unreachable" + +proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) = + case c.code[pc].kind + of LoadLocalM: + let src = s.locals +! c.code[pc].operand + copyMem result, src, size + of FieldAtM, DerefFieldAtM, ArrayAtM, DerefArrayAtM, LoadGlobalM: + let src = evalAddr(c, pc, s) + copyMem result, src, size + of LoadProcM: + let procAddr = c.code[pc].operand + cast[ptr pointer](result)[] = cast[pointer](procAddr) + of LoadM: + let (_, arg) = sons2(c.code, pc) + let src = evalAddr(c, arg, s) + copyMem result, src, size + of CheckedAddM: checkedBinop `+` + of CheckedSubM: checkedBinop `-` + of CheckedMulM: checkedBinop `*` + of CheckedDivM: checkedBinop `div` + of CheckedModM: checkedBinop `mod` + of AddM: binop `+` + of SubM: binop `-` + of MulM: binop `*` + of DivM: binop `div` + of ModM: binop `mod` + of BitShlM: bitop `shl` + of BitShrM: bitop `shr` + of BitAndM: bitop `and` + of BitOrM: bitop `or` + of BitXorM: bitop `xor` + of EqM: cmpop `==` + of LeM: cmpop `<=` + of LtM: cmpop `<` + + of StrValM: + # binary compatible and no deep copy required: + copyMem(cast[ptr string](result), addr(c.strings[c[pc].litId]), sizeof(string)) + of ObjConstrM: + for offset, size, val in triples(c, pc): + eval c, val, s, result+!offset, size + of ArrayConstrM: + let elemSize = c.code[pc.firstSon].operand + var r = result + for ch in sonsFrom1(c, pc): + eval c, ch, s, r, elemSize.int + r = r+!elemSize # can even do strength reduction here! + of NumberConvM: + let (t, x) = sons2(c.code, pc) + let word = if c[x].kind == NilValM: 0'i64 else: c.m.lit.numbers[c[x].litId] + + template impl(typ: typedesc) {.dirty.} = + cast[ptr typ](result)[] = cast[typ](word) + + let tid = c.code[t].typeId + case tid + of Bool8Id, Char8Id, UInt8Id: impl uint8 + of Int8Id: impl int8 + of Int16Id: impl int16 + of Int32Id: impl int32 + of Int64Id: impl int64 + of UInt16Id: impl uint16 + of UInt32Id: impl uint32 + of UInt64Id: impl uint64 + of Float32Id: impl float32 + of Float64Id: impl float64 + else: + case c.m.types[tid].kind + of ProcTy, UPtrTy, APtrTy, AArrayPtrTy, UArrayPtrTy: + # the VM always uses 64 bit pointers: + impl uint64 + else: + raiseAssert "cannot happen: " & $c.m.types[tid].kind + else: + #debug c, c.debug[pc.int] + raiseAssert "cannot happen: " & $c.code[pc].kind + +proc evalProc(c: Bytecode; pc: CodePos; s: StackFrame): CodePos = + assert c.code[pc].kind == LoadProcM + let procSym = c[pc].operand + when false: + if procSym >= ForwardedProc: + for k, v in c.procUsagesToPatch: + if uint32(k) == procSym - ForwardedProc: + echo k.int, " ", v.len, " <-- this one" + else: + echo k.int, " ", v.len + + assert procSym < ForwardedProc + result = CodePos(procSym) + +proc echoImpl(c: Bytecode; pc: CodePos; frame: StackFrame) = + var s = default(NimStringVM) + for a in sonsFrom1(c, pc): + assert c[a].kind == ArrayConstrM + let elemSize = c.code[a.firstSon].operand.int + for ch in sonsFrom1(c, a): + eval c, ch, frame, addr s, elemSize + if s.len > 0: + discard stdout.writeBuffer(addr(s.p.data[0]), s.len) + stdout.write "\n" + stdout.flushFile() + +type + EvalBuiltinState = enum + DidNothing, DidEval, DidError + +proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; state: var EvalBuiltinState): CodePos = + var prc = prc + while true: + case c[prc].kind + of PragmaPairM: + let (x, y) = sons2(c.code, prc) + let key = cast[PragmaKey](c[x].operand) + case key + of CoreName: + let lit = c[y].litId + case c.m.lit.strings[lit] + of "echoBinSafe": echoImpl(c, pc, s) + else: + raiseAssert "cannot eval: " & c.m.lit.strings[lit] + state = DidEval + of HeaderImport, DllImport: + let lit = c[y].litId + raiseAssert "cannot eval: " & c.m.lit.strings[lit] + else: discard + of PragmaIdM, AllocLocals: discard + else: break + next c, prc + result = prc + +proc exec(c: Bytecode; pc: CodePos; u: ref Universe) = + var pc = pc + var frame = StackFrame(u: u) + while pc.int < c.code.len: + when false: # c.interactive: + echo "running: ", pc.int + debug c, pc + + case c.code[pc].kind + of GotoM: + pc = CodePos(c.code[pc].operand) + of AsgnM: + let (sz, a, b) = sons3(c.code, pc) + let dest = evalAddr(c, a, frame) + eval(c, b, frame, dest, c.code[sz].operand.int) + next c, pc + of StoreM: + let (sz, a, b) = sons3(c.code, pc) + let destPtr = evalAddr(c, a, frame) + let dest = cast[ptr pointer](destPtr)[] + eval(c, b, frame, dest, c.code[sz].operand.int) + next c, pc + of CallM: + # No support for return values, these are mapped to `var T` parameters! + var prc = evalProc(c, pc.firstSon, frame) + assert c.code[prc.firstSon].kind == AllocLocals + let frameSize = int c.code[prc.firstSon].operand + # skip stupid stuff: + var evalState = DidNothing + prc = evalBuiltin(c, pc, frame, prc.firstSon, evalState) + if evalState != DidNothing: + next c, pc + if pc.int < c.code.len and c.code[pc].kind == CheckedGotoM: + if evalState == DidEval: + next c, pc + else: + pc = CodePos(c.code[pc].operand) + else: + # setup storage for the proc already: + let callInstr = pc + next c, pc + let s2 = newStackFrame(frameSize, frame, pc) + for a in sonsFrom1(c, callInstr): + assert c[prc].kind == SummonParamM + let paramAddr = c[prc].operand + next c, prc + assert c[prc].kind == ImmediateValM + let paramSize = c[prc].operand.int + next c, prc + eval(c, a, s2, s2.locals +! paramAddr, paramSize) + frame = s2 + pc = prc + of RetM: + pc = frame.returnAddr + if c.code[pc].kind == CheckedGotoM: + pc = frame.jumpTo + frame = popStackFrame(frame) + of SelectM: + let pc2 = evalSelect(c, pc, frame) + if pc2.int >= 0: + pc = pc2 + else: + next c, pc + of ProcDeclM: + next c, pc + else: + #debug c, c.debug[pc.int] + raiseAssert "unreachable: " & $c.code[pc].kind + +proc execCode*(bc: var Bytecode; t: Tree; n: NodePos) = + traverseTypes bc + var c = Preprocessing(u: nil, thisModule: 1'u32) + let start = CodePos(bc.code.len) + var pc = n + while pc.int < t.len: + #if bc.interactive: + # echo "RUnning: " + # debug bc, t, pc + preprocess c, bc, t, pc, {} + next t, pc + exec bc, start, nil diff --git a/compiler/nir/stringcases.nim b/compiler/nir/stringcases.nim new file mode 100644 index 000000000000..afdf8fda4f4a --- /dev/null +++ b/compiler/nir/stringcases.nim @@ -0,0 +1,200 @@ +# +# +# The Nim Compiler +# (c) Copyright 2023 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## included from ast2ir.nim + +#[ + +case s +of "abc", "abbd": + echo 1 +of "hah": + echo 2 +of "gah": + echo 3 + +# we produce code like this: + +if s[0] <= 'a': + if s == "abc: goto L1 + elif s == "abbd": goto L1 +else: + if s[2] <= 'h': + if s == "hah": goto L2 + elif s == "gah": goto L3 +goto afterCase + +L1: + echo 1 + goto afterCase +L2: + echo 2 + goto afterCase +L3: + echo 3 + goto afterCase + +afterCase: ... + +]# + +# We split the set of strings into 2 sets of roughly the same size. +# The condition used for splitting is a (position, char) tuple. +# Every string of length > position for which s[position] <= char is in one +# set else it is in the other set. + +from std/sequtils import addUnique + +type + Key = (LitId, LabelId) + +proc splitValue(strings: BiTable[string]; a: openArray[Key]; position: int): (char, float) = + var cand: seq[char] = @[] + for t in items a: + let s = strings[t[0]] + if s.len > position: cand.addUnique s[position] + + result = ('\0', -1.0) + for disc in items cand: + var hits = 0 + for t in items a: + let s = strings[t[0]] + if s.len > position and s[position] <= disc: + inc hits + # the split is the better, the more `hits` is close to `a.len / 2`: + let grade = 100000.0 - abs(hits.float - a.len.float / 2.0) + if grade > result[1]: + result = (disc, grade) + +proc tryAllPositions(strings: BiTable[string]; a: openArray[Key]): (char, int) = + var m = 0 + for t in items a: + m = max(m, strings[t[0]].len) + + result = ('\0', -1) + var best = -1.0 + for i in 0 ..< m: + let current = splitValue(strings, a, i) + if current[1] > best: + best = current[1] + result = (current[0], i) + +type + SearchKind = enum + LinearSearch, SplitSearch + SearchResult* = object + case kind: SearchKind + of LinearSearch: + a: seq[Key] + of SplitSearch: + span: int + best: (char, int) + +proc emitLinearSearch(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) = + var d = SearchResult(kind: LinearSearch, a: @[]) + for x in a: d.a.add x + dest.add d + +proc split(strings: BiTable[string]; a: openArray[Key]; dest: var seq[SearchResult]) = + if a.len <= 4: + emitLinearSearch strings, a, dest + else: + let best = tryAllPositions(strings, a) + var groupA: seq[Key] = @[] + var groupB: seq[Key] = @[] + for t in items a: + let s = strings[t[0]] + if s.len > best[1] and s[best[1]] <= best[0]: + groupA.add t + else: + groupB.add t + if groupA.len == 0 or groupB.len == 0: + emitLinearSearch strings, a, dest + else: + let toPatch = dest.len + dest.add SearchResult(kind: SplitSearch, span: 1, best: best) + split strings, groupA, dest + split strings, groupB, dest + let dist = dest.len - toPatch + assert dist > 0 + dest[toPatch].span = dist + +proc toProblemDescription(c: var ProcCon; n: PNode): (seq[Key], LabelId) = + result = (@[], newLabels(c.labelGen, n.len)) + assert n.kind == nkCaseStmt + for i in 1..= 0, typeToString(t) - let p = openType(c.g, ObjectDecl) - c.g.addName typeName - - let f = c.g.openType FieldDecl - let arr = c.g.openType AArrayPtrTy - c.g.addType elementType - discard sealType(c.g, arr) # LastArrayTy - c.g.addName "data" - discard sealType(c.g, f) # FieldDecl - - c.g.addField "len", c.nativeInt - - result = sealType(c.g, p) # ObjectDecl - -proc strPayloadType(c: var TypesCon): string = - result = "NimStrPayload" - let p = openType(c.g, ObjectDecl) - c.g.addName result - c.g.addField "cap", c.nativeInt - - let f = c.g.openType FieldDecl - let arr = c.g.openType LastArrayTy - c.g.addBuiltinType Char8Id - discard sealType(c.g, arr) # LastArrayTy - c.g.addName "data" - discard sealType(c.g, f) # FieldDecl - - discard sealType(c.g, p) - -proc strPayloadPtrType*(c: var TypesCon): TypeId = - let mangled = strPayloadType(c) - let ffp = c.g.openType APtrTy - c.g.addNominalType ObjectTy, mangled - result = sealType(c.g, ffp) # APtrTy - -proc stringToIr(c: var TypesCon): TypeId = + let p = openType(g, ObjectDecl) + g.addName typeName + g.addSize c.conf.target.ptrSize*2 + g.addAlign c.conf.target.ptrSize + + let f = g.openType FieldDecl + let arr = g.openType AArrayPtrTy + g.addType elementType + sealType(g, arr) # LastArrayTy + g.addOffset 0 + g.addName "data" + sealType(g, f) # FieldDecl + + g.addField "len", c.nativeInt, c.conf.target.ptrSize + + result = finishType(g, p) # ObjectDecl + +proc strPayloadType(c: var TypesCon; g: var TypeGraph): (string, TypeId) = + result = ("NimStrPayload", TypeId(-1)) + let p = openType(g, ObjectDecl) + g.addName result[0] + g.addSize c.conf.target.ptrSize*2 + g.addAlign c.conf.target.ptrSize + + g.addField "cap", c.nativeInt, 0 + + let f = g.openType FieldDecl + let arr = g.openType LastArrayTy + g.addBuiltinType Char8Id + result[1] = finishType(g, arr) # LastArrayTy + g.addOffset c.conf.target.ptrSize # comes after the len field + g.addName "data" + sealType(g, f) # FieldDecl + + sealType(g, p) + +proc strPayloadPtrType*(c: var TypesCon; g: var TypeGraph): (TypeId, TypeId) = + let (mangled, arrayType) = strPayloadType(c, g) + let ffp = g.openType APtrTy + g.addNominalType ObjectTy, mangled + result = (finishType(g, ffp), arrayType) # APtrTy + +proc stringToIr(c: var TypesCon; g: var TypeGraph): TypeId = #[ NimStrPayload = object @@ -212,74 +240,91 @@ proc stringToIr(c: var TypesCon): TypeId = p: ptr NimStrPayload ]# - let payload = strPayloadType(c) + let payload = strPayloadType(c, g) - let str = openType(c.g, ObjectDecl) - c.g.addName "NimStringV2" - c.g.addField "len", c.nativeInt + let str = openType(g, ObjectDecl) + g.addName "NimStringV2" + g.addSize c.conf.target.ptrSize*2 + g.addAlign c.conf.target.ptrSize - let fp = c.g.openType FieldDecl - let ffp = c.g.openType APtrTy - c.g.addNominalType ObjectTy, "NimStrPayload" - discard sealType(c.g, ffp) # APtrTy - c.g.addName "p" - discard sealType(c.g, fp) # FieldDecl + g.addField "len", c.nativeInt, 0 - result = sealType(c.g, str) # ObjectDecl + let fp = g.openType FieldDecl + let ffp = g.openType APtrTy + g.addNominalType ObjectTy, "NimStrPayload" + sealType(g, ffp) # APtrTy + g.addOffset c.conf.target.ptrSize # comes after 'len' field + g.addName "p" + sealType(g, fp) # FieldDecl -proc seqPayloadType(c: var TypesCon; t: PType): string = + result = finishType(g, str) # ObjectDecl + +proc seqPayloadType(c: var TypesCon; g: var TypeGraph; t: PType): (string, TypeId) = #[ NimSeqPayload[T] = object cap: int data: UncheckedArray[T] ]# let e = lastSon(t) - result = mangle(c, e) - let payloadName = "NimSeqPayload" & result - - let elementType = typeToIr(c, e) - - let p = openType(c.g, ObjectDecl) - c.g.addName payloadName - c.g.addField "cap", c.nativeInt - - let f = c.g.openType FieldDecl - let arr = c.g.openType LastArrayTy - c.g.addType elementType - discard sealType(c.g, arr) # LastArrayTy - c.g.addName "data" - discard sealType(c.g, f) # FieldDecl - discard sealType(c.g, p) - -proc seqPayloadPtrType*(c: var TypesCon; t: PType): TypeId = - let mangledBase = seqPayloadType(c, t) - let ffp = c.g.openType APtrTy - c.g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase - result = sealType(c.g, ffp) # APtrTy - -proc seqToIr(c: var TypesCon; t: PType): TypeId = + result = (mangle(c, e), TypeId(-1)) + let payloadName = "NimSeqPayload" & result[0] + + let elementType = typeToIr(c, g, e) + + let p = openType(g, ObjectDecl) + g.addName payloadName + g.addSize c.conf.target.intSize + g.addAlign c.conf.target.intSize + + g.addField "cap", c.nativeInt, 0 + + let f = g.openType FieldDecl + let arr = g.openType LastArrayTy + g.addType elementType + # DO NOT USE `finishType` here as it is an inner type. This is subtle and we + # probably need an even better API here. + sealType(g, arr) + result[1] = TypeId(arr) + + g.addOffset c.conf.target.ptrSize + g.addName "data" + sealType(g, f) # FieldDecl + + sealType(g, p) + +proc seqPayloadPtrType*(c: var TypesCon; g: var TypeGraph; t: PType): (TypeId, TypeId) = + let (mangledBase, arrayType) = seqPayloadType(c, g, t) + let ffp = g.openType APtrTy + g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase + result = (finishType(g, ffp), arrayType) # APtrTy + +proc seqToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = #[ NimSeqV2*[T] = object len: int p: ptr NimSeqPayload[T] ]# - let mangledBase = seqPayloadType(c, t) + let (mangledBase, _) = seqPayloadType(c, g, t) - let sq = openType(c.g, ObjectDecl) - c.g.addName "NimSeqV2" & mangledBase - c.g.addField "len", c.nativeInt + let sq = openType(g, ObjectDecl) + g.addName "NimSeqV2" & mangledBase + g.addSize c.conf.getSize(t) + g.addAlign c.conf.getAlign(t) - let fp = c.g.openType FieldDecl - let ffp = c.g.openType APtrTy - c.g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase - discard sealType(c.g, ffp) # APtrTy - c.g.addName "p" - discard sealType(c.g, fp) # FieldDecl + g.addField "len", c.nativeInt, 0 - result = sealType(c.g, sq) # ObjectDecl + let fp = g.openType FieldDecl + let ffp = g.openType APtrTy + g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase + sealType(g, ffp) # APtrTy + g.addOffset c.conf.target.ptrSize + g.addName "p" + sealType(g, fp) # FieldDecl + result = finishType(g, sq) # ObjectDecl -proc closureToIr(c: var TypesCon; t: PType): TypeId = + +proc closureToIr(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = # struct {fn(args, void* env), env} # typedef struct {$n" & # "N_NIMCALL_PTR($2, ClP_0) $3;$n" & @@ -287,27 +332,31 @@ proc closureToIr(c: var TypesCon; t: PType): TypeId = let mangledBase = mangle(c, t) let typeName = "NimClosure" & mangledBase - let procType = procToIr(c, t, addEnv=true) + let procType = procToIr(c, g, t, addEnv=true) - let p = openType(c.g, ObjectDecl) - c.g.addName typeName + let p = openType(g, ObjectDecl) + g.addName typeName + g.addSize c.conf.getSize(t) + g.addAlign c.conf.getAlign(t) - let f = c.g.openType FieldDecl - c.g.addType procType - c.g.addName "ClP_0" - discard sealType(c.g, f) # FieldDecl + let f = g.openType FieldDecl + g.addType procType + g.addOffset 0 + g.addName "ClP_0" + sealType(g, f) # FieldDecl - let f2 = c.g.openType FieldDecl - let voidPtr = openType(c.g, APtrTy) - c.g.addBuiltinType(VoidId) - discard sealType(c.g, voidPtr) + let f2 = g.openType FieldDecl + let voidPtr = openType(g, APtrTy) + g.addBuiltinType(VoidId) + sealType(g, voidPtr) - c.g.addName "ClE_0" - discard sealType(c.g, f2) # FieldDecl + g.addOffset c.conf.target.ptrSize + g.addName "ClE_0" + sealType(g, f2) # FieldDecl - result = sealType(c.g, p) # ObjectDecl + result = finishType(g, p) # ObjectDecl -proc bitsetBasetype*(c: var TypesCon; t: PType): TypeId = +proc bitsetBasetype*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = let s = int(getSize(c.conf, t)) case s of 1: result = UInt8Id @@ -316,7 +365,7 @@ proc bitsetBasetype*(c: var TypesCon; t: PType): TypeId = of 8: result = UInt64Id else: result = UInt8Id -proc typeToIr*(c: var TypesCon; t: PType): TypeId = +proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = if t == nil: return VoidId case t.kind of tyInt: @@ -334,7 +383,7 @@ proc typeToIr*(c: var TypesCon; t: PType): TypeId = else: result = Float64Id of tyFloat32: result = Float32Id of tyFloat64: result = Float64Id - of tyFloat128: result = getFloat128Type(c.g) + of tyFloat128: result = getFloat128Type(g) of tyUInt: case int(getSize(c.conf, t)) of 2: result = UInt16Id @@ -348,7 +397,7 @@ proc typeToIr*(c: var TypesCon; t: PType): TypeId = of tyChar: result = Char8Id of tyVoid: result = VoidId of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange: - result = typeToIr(c, t.lastSon) + result = typeToIr(c, g, t.lastSon) of tyEnum: if firstOrd(c.conf, t) < 0: result = Int32Id @@ -361,47 +410,48 @@ proc typeToIr*(c: var TypesCon; t: PType): TypeId = else: result = Int32Id of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic: if t.len > 0: - result = typeToIr(c, t.lastSon) + result = typeToIr(c, g, t.lastSon) else: result = TypeId(-1) of tyFromExpr: if t.n != nil and t.n.typ != nil: - result = typeToIr(c, t.n.typ) + result = typeToIr(c, g, t.n.typ) else: result = TypeId(-1) of tyArray: cached(c, t): var n = toInt64(lengthOrd(c.conf, t)) if n <= 0: n = 1 # make an array of at least one element - let elemType = typeToIr(c, t[1]) - let a = openType(c.g, ArrayTy) - c.g.addType(elemType) - c.g.addArrayLen uint64(n) - result = sealType(c.g, a) + let elemType = typeToIr(c, g, t[1]) + let a = openType(g, ArrayTy) + g.addType(elemType) + g.addArrayLen n + g.addName mangle(c, t) + result = finishType(g, a) of tyPtr, tyRef: cached(c, t): let e = t.lastSon if e.kind == tyUncheckedArray: - let elemType = typeToIr(c, e.lastSon) - let a = openType(c.g, AArrayPtrTy) - c.g.addType(elemType) - result = sealType(c.g, a) + let elemType = typeToIr(c, g, e.lastSon) + let a = openType(g, AArrayPtrTy) + g.addType(elemType) + result = finishType(g, a) else: - let elemType = typeToIr(c, t.lastSon) - let a = openType(c.g, APtrTy) - c.g.addType(elemType) - result = sealType(c.g, a) + let elemType = typeToIr(c, g, t.lastSon) + let a = openType(g, APtrTy) + g.addType(elemType) + result = finishType(g, a) of tyVar, tyLent: cached(c, t): let e = t.lastSon if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}: # skip the modifier, `var openArray` is a (ptr, len) pair too: - result = typeToIr(c, e) + result = typeToIr(c, g, e) else: - let elemType = typeToIr(c, e) - let a = openType(c.g, APtrTy) - c.g.addType(elemType) - result = sealType(c.g, a) + let elemType = typeToIr(c, g, e) + let a = openType(g, APtrTy) + g.addType(elemType) + result = finishType(g, a) of tySet: let s = int(getSize(c.conf, t)) case s @@ -412,59 +462,64 @@ proc typeToIr*(c: var TypesCon; t: PType): TypeId = else: # array[U8, s] cached(c, t): - let a = openType(c.g, ArrayTy) - c.g.addType(UInt8Id) - c.g.addArrayLen uint64(s) - result = sealType(c.g, a) - of tyPointer: - let a = openType(c.g, APtrTy) - c.g.addBuiltinType(VoidId) - result = sealType(c.g, a) + let a = openType(g, ArrayTy) + g.addType(UInt8Id) + g.addArrayLen s + g.addName mangle(c, t) + result = finishType(g, a) + of tyPointer, tyNil: + # tyNil can happen for code like: `const CRAP = nil` which we have in posix.nim + let a = openType(g, APtrTy) + g.addBuiltinType(VoidId) + result = finishType(g, a) of tyObject: # Objects are special as they can be recursive in Nim. This is easily solvable. # We check if we are already "processing" t. If so, we produce `ObjectTy` # instead of `ObjectDecl`. cached(c, t): if not c.recursionCheck.containsOrIncl(t.itemId): - result = objectToIr(c, t) + result = objectToIr(c, g, t) else: - result = objectHeaderToIr(c, t) + result = objectHeaderToIr(c, g, t) of tyTuple: - cached(c, t): - result = tupleToIr(c, t) + cachedByName(c, t): + result = tupleToIr(c, g, t) of tyProc: cached(c, t): if t.callConv == ccClosure: - result = closureToIr(c, t) + result = closureToIr(c, g, t) else: - result = procToIr(c, t) + result = procToIr(c, g, t) of tyVarargs, tyOpenArray: cached(c, t): - result = openArrayToIr(c, t) + result = openArrayToIr(c, g, t) of tyString: - cached(c, t): - result = stringToIr(c) + if c.stringType.int < 0: + result = stringToIr(c, g) + c.stringType = result + else: + result = c.stringType of tySequence: - cached(c, t): - result = seqToIr(c, t) + cachedByName(c, t): + result = seqToIr(c, g, t) of tyCstring: cached(c, t): - let a = openType(c.g, AArrayPtrTy) - c.g.addBuiltinType Char8Id - result = sealType(c.g, a) + let a = openType(g, AArrayPtrTy) + g.addBuiltinType Char8Id + result = finishType(g, a) of tyUncheckedArray: # We already handled the `ptr UncheckedArray` in a special way. cached(c, t): - let elemType = typeToIr(c, t.lastSon) - let a = openType(c.g, LastArrayTy) - c.g.addType(elemType) - result = sealType(c.g, a) + let elemType = typeToIr(c, g, t.lastSon) + let a = openType(g, LastArrayTy) + g.addType(elemType) + result = finishType(g, a) of tyUntyped, tyTyped: # this avoids a special case for system.echo which is not a generic but # uses `varargs[typed]`: result = VoidId of tyNone, tyEmpty, tyTypeDesc, - tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass, + tyGenericInvocation, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward: result = TypeId(-1) diff --git a/compiler/nodejs.nim b/compiler/nodejs.nim index c1feb196a070..9753e1c99127 100644 --- a/compiler/nodejs.nim +++ b/compiler/nodejs.nim @@ -1,4 +1,4 @@ -import os +import std/os proc findNodeJs*(): string {.inline.} = ## Find NodeJS executable and return it as a string. diff --git a/compiler/optimizer.nim b/compiler/optimizer.nim index 7e46f3d0b5f4..d39d598ba8ca 100644 --- a/compiler/optimizer.nim +++ b/compiler/optimizer.nim @@ -12,11 +12,11 @@ ## - recognize "all paths lead to 'wasMoved(x)'" import - ast, renderer, idents, intsets + ast, renderer, idents from trees import exprStructuralEquivalent -import std/strutils +import std/[strutils, intsets] const nfMarkForDeletion = nfNone # faster than a lookup table diff --git a/compiler/options.nim b/compiler/options.nim index a2f50b12bd28..704248d78936 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -8,11 +8,12 @@ # import - os, strutils, strtabs, sets, lineinfos, platform, - prefixmatches, pathutils, nimpaths, tables + lineinfos, platform, + prefixmatches, pathutils, nimpaths -from terminal import isatty -from times import utc, fromUnix, local, getTime, format, DateTime +import std/[tables, os, strutils, strtabs, sets] +from std/terminal import isatty +from std/times import utc, fromUnix, local, getTime, format, DateTime from std/private/globs import nativeToUnixPath when defined(nimPreviewSlimSystem): @@ -137,13 +138,15 @@ type backendCpp = "cpp" backendJs = "js" backendObjc = "objc" + backendNir = "nir" # backendNimscript = "nimscript" # this could actually work # backendLlvm = "llvm" # probably not well supported; was cmdCompileToLLVM Command* = enum ## Nim's commands cmdNone # not yet processed command cmdUnknown # command unmapped - cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS + cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS, + cmdCompileToNir, cmdCrun # compile and run in nimache cmdTcc # run the project via TCC backend cmdCheck # semantic checking for whole project @@ -170,7 +173,8 @@ type # old unused: cmdInterpret, cmdDef: def feature (find definition for IDEs) const - cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS, cmdCrun} + cmdBackends* = {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, + cmdCompileToJS, cmdCrun, cmdCompileToNir} cmdDocLike* = {cmdDoc0, cmdDoc, cmdDoc2tex, cmdJsondoc0, cmdJsondoc, cmdCtags, cmdBuildindex} @@ -195,7 +199,7 @@ type IdeCmd* = enum ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod, ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols, - ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand + ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand, ideInlayHints Feature* = enum ## experimental features; DO NOT RENAME THESE! dotOperators, @@ -235,9 +239,9 @@ type laxEffects ## Lax effects system prior to Nim 2.0. verboseTypeMismatch - emitGenerics - ## generics are emitted in the module that contains them. - ## Useful for libraries that rely on local passC + emitGenerics + ## generics are emitted in the module that contains them. + ## Useful for libraries that rely on local passC SymbolFilesOption* = enum disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest @@ -284,9 +288,24 @@ type version*: int endLine*: uint16 endCol*: int + inlayHintInfo*: SuggestInlayHint Suggestions* = seq[Suggest] + SuggestInlayHintKind* = enum + sihkType = "Type", + sihkParameter = "Parameter" + + SuggestInlayHint* = ref object + kind*: SuggestInlayHintKind + line*: int # Starts at 1 + column*: int # Starts at 0 + label*: string + paddingLeft*: bool + paddingRight*: bool + allowInsert*: bool + tooltip*: string + ProfileInfo* = object time*: float count*: int @@ -887,7 +906,7 @@ const stdlibDirs* = [ const pkgPrefix = "pkg/" - stdPrefix = "std/" + stdPrefix* = "std/" proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile, isTitle = false): RelativeFile = result = RelativeFile("") @@ -1067,6 +1086,7 @@ proc `$`*(c: IdeCmd): string = of ideRecompile: "recompile" of ideChanged: "changed" of ideType: "type" + of ideInlayHints: "inlayHints" proc floatInt64Align*(conf: ConfigRef): int16 = ## Returns either 4 or 8 depending on reasons. diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 98f5099d688e..84c2980c465c 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -10,9 +10,11 @@ ## This module implements the pattern matching features for term rewriting ## macro support. -import strutils, ast, types, msgs, idents, renderer, wordrecg, trees, +import ast, types, msgs, idents, renderer, wordrecg, trees, options +import std/strutils + # we precompile the pattern here for efficiency into some internal # stack based VM :-) Why? Because it's fun; I did no benchmarks to see if that # actually improves performance. diff --git a/compiler/parser.nim b/compiler/parser.nim index 7caeca95e15c..20f6868cd2c8 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -49,9 +49,11 @@ when isMainModule or defined(nimTestGrammar): checkGrammarFile() import - llstream, lexer, idents, strutils, ast, msgs, options, lineinfos, + llstream, lexer, idents, ast, msgs, options, lineinfos, pathutils +import std/strutils + when defined(nimpretty): import layouter diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index d9779deabdae..5f6212bb2221 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -10,7 +10,7 @@ ## Path handling utilities for Nim. Strictly typed code in order ## to avoid the never ending time sink in getting path handling right. -import os, pathnorm, strutils +import std/[os, pathnorm, strutils] when defined(nimPreviewSlimSystem): import std/[syncio, assertions] diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index e9ee1ee8be79..8f40ac031da7 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -45,6 +45,8 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext): result = interpreterCode(bModule, semNode) of NirReplPass: result = runCode(bModule, semNode) + of NirPass: + result = nirBackend(bModule, semNode) of NonePass: raiseAssert "use setPipeLinePass to set a proper PipelinePass" @@ -107,6 +109,8 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator case graph.pipelinePass of CgenPass: setupCgen(graph, module, idgen) + of NirPass: + openNirBackend(graph, module, idgen) of JSgenPass: when not defined(leanCompiler): setupJSgen(graph, module, idgen) @@ -144,9 +148,10 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator if s == nil: rawMessage(graph.config, errCannotOpenFile, filename.string) return false + graph.interactive = false else: s = stream - + graph.interactive = stream.kind == llsStdIn while true: syntaxes.openParser(p, fileIdx, s, graph.cache, graph.config) @@ -203,6 +208,8 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator discard interpreterCode(bModule, finalNode) of NirReplPass: discard runCode(bModule, finalNode) + of NirPass: + closeNirBackend(bModule, finalNode) of SemPass, GenDependPass: discard of Docgen2Pass, Docgen2TexPass: diff --git a/compiler/platform.nim b/compiler/platform.nim index 613ebf7ecd03..03d0cc461c28 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -14,7 +14,7 @@ # Feel free to test for your excentric platform! import - strutils + std/strutils when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index e6867aa5d286..53b4f53a8a87 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -10,10 +10,12 @@ # This module implements semantic checking for pragmas import - os, condsyms, ast, astalgo, idents, semdata, msgs, renderer, - wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees, + condsyms, ast, astalgo, idents, semdata, msgs, renderer, + wordrecg, ropes, options, extccomp, magicsys, trees, types, lookups, lineinfos, pathutils, linter, modulepaths +import std/[os, math, strutils] + when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/prefixmatches.nim b/compiler/prefixmatches.nim index 71ae9a844c96..bfbe3d888b21 100644 --- a/compiler/prefixmatches.nim +++ b/compiler/prefixmatches.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -from strutils import toLowerAscii +from std/strutils import toLowerAscii type PrefixMatch* {.pure.} = enum diff --git a/compiler/procfind.nim b/compiler/procfind.nim index 0bdb3dae6d5b..468879ba2ddb 100644 --- a/compiler/procfind.nim +++ b/compiler/procfind.nim @@ -11,7 +11,9 @@ # This is needed for proper handling of forward declarations. import - ast, astalgo, msgs, semdata, types, trees, strutils, lookups + ast, astalgo, msgs, semdata, types, trees, lookups + +import std/strutils proc equalGenericParams(procA, procB: PNode): bool = if procA.len != procB.len: return false diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 3a6d0ae6502e..43ac91e92e68 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -14,7 +14,9 @@ {.used.} import - lexer, options, idents, strutils, ast, msgs, lineinfos, wordrecg + lexer, options, idents, ast, msgs, lineinfos, wordrecg + +import std/[strutils] when defined(nimPreviewSlimSystem): import std/[syncio, assertions, formatfloat] diff --git a/compiler/renderverbatim.nim b/compiler/renderverbatim.nim index 00d546198aab..c12595156a16 100644 --- a/compiler/renderverbatim.nim +++ b/compiler/renderverbatim.nim @@ -1,4 +1,4 @@ -import strutils +import std/strutils import ast, options, msgs diff --git a/compiler/reorder.nim b/compiler/reorder.nim index aedebc7d420a..f5ec0b2d3293 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -1,9 +1,11 @@ import - intsets, ast, idents, algorithm, renderer, strutils, + ast, idents, renderer, msgs, modulegraphs, syntaxes, options, modulepaths, lineinfos +import std/[algorithm, strutils, intsets] + when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index ed5126859807..e1b56800c25d 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -8,7 +8,7 @@ # ## Serialization utilities for the compiler. -import strutils, math +import std/[strutils, math] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index c89767296b26..e3d2bcd45841 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -13,14 +13,16 @@ import ast, modules, idents, condsyms, options, llstream, vm, vmdef, commands, - os, times, osproc, wordrecg, strtabs, modulegraphs, + wordrecg, modulegraphs, pathutils, pipelines when defined(nimPreviewSlimSystem): import std/[syncio, assertions] +import std/[strtabs, os, times, osproc] + # we support 'cmpIgnoreStyle' natively for efficiency: -from strutils import cmpIgnoreStyle, contains +from std/strutils import cmpIgnoreStyle, contains proc listDirs(a: VmArgs, filter: set[PathComponent]) = let dir = getString(a, 0) diff --git a/compiler/sem.nim b/compiler/sem.nim index 55c6a427f519..1908b5a0de72 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -9,19 +9,18 @@ # This module implements the semantic checking pass. -import tables - import - ast, strutils, options, astalgo, trees, - wordrecg, ropes, msgs, idents, renderer, types, platform, math, + ast, options, astalgo, trees, + wordrecg, ropes, msgs, idents, renderer, types, platform, magicsys, nversion, nimsets, semfold, modulepaths, importer, procfind, lookups, pragmas, semdata, semtypinst, sigmatch, - intsets, transf, vmdef, vm, aliases, cgmeth, lambdalifting, + transf, vmdef, vm, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, - lowerings, plugins/active, lineinfos, strtabs, int128, + lowerings, plugins/active, lineinfos, int128, isolation_check, typeallowed, modulegraphs, enumtostr, concepts, astmsgs, extccomp +import std/[strtabs, math, tables, intsets, strutils] when not defined(leanCompiler): import spawn diff --git a/compiler/semcall.nim b/compiler/semcall.nim index a4114497fb98..2c1939c3cf50 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -827,7 +827,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PS if resolved != nil: result.s = resolved[0].sym result.state = bsMatch - if not compareTypes(result.s.typ[0], fn.typ[0], dcEqIgnoreDistinct): + if not compareTypes(result.s.typ[0], fn.typ[0], dcEqIgnoreDistinct, {IgnoreFlags}): result.state = bsReturnNotMatch elif result.s.magic in {mArrPut, mArrGet}: # cannot borrow these magics for now diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 32e557f1860f..91b15d5c7729 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -9,14 +9,14 @@ ## This module contains the data structures for the semantic checking phase. -import tables +import std/[tables, intsets, sets] when defined(nimPreviewSlimSystem): import std/assertions import - intsets, options, ast, astalgo, msgs, idents, renderer, - magicsys, vmdef, modulegraphs, lineinfos, sets, pathutils + options, ast, astalgo, msgs, idents, renderer, + magicsys, vmdef, modulegraphs, lineinfos, pathutils import ic / ic diff --git a/compiler/semfold.nim b/compiler/semfold.nim index f1a1c8a82f66..e722f932fd20 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -11,10 +11,11 @@ # and evaluation phase import - strutils, options, ast, trees, nimsets, - platform, math, msgs, idents, renderer, types, - commands, magicsys, modulegraphs, strtabs, lineinfos, wordrecg + options, ast, trees, nimsets, + platform, msgs, idents, renderer, types, + commands, magicsys, modulegraphs, lineinfos, wordrecg +import std/[strutils, math, strtabs] from system/memory import nimCStrLen when defined(nimPreviewSlimSystem): diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index ebc8be0c332d..33278af2fbc3 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -11,7 +11,7 @@ # included from sem.nim -from sugar import dup +from std/sugar import dup type ObjConstrContext = object diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index 41ec3e4809af..af77a197273f 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -26,7 +26,7 @@ import renderer, types, modulegraphs, options, spawn, lineinfos from trees import getMagic, getRoot -from strutils import `%` +from std/strutils import `%` discard """ diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 423cfbb3419a..54f46fa73c2c 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -8,11 +8,13 @@ # import - intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - wordrecg, strutils, options, guards, lineinfos, semfold, semdata, - modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, tables, + ast, astalgo, msgs, renderer, magicsys, types, idents, trees, + wordrecg, options, guards, lineinfos, semfold, semdata, + modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, semstrictfuncs +import std/[tables, intsets, strutils] + when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a4de874ba9df..0196b9d03cf7 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -672,9 +672,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = addToVarSection(c, result, b) continue + var hasUserSpecifiedType = false var typ: PType = nil if a[^2].kind != nkEmpty: typ = semTypeNode(c, a[^2], nil) + hasUserSpecifiedType = true var typFlags: TTypeAllowedFlags = {} @@ -746,6 +748,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = addToVarSection(c, result, n, a) continue var v = semIdentDef(c, a[j], symkind, false) + when defined(nimsuggest): + v.hasUserSpecifiedType = hasUserSpecifiedType styleCheckDef(c, v) onDef(a[j].info, v) if sfGenSym notin v.flags: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index dda78c69f175..65eaf1a89df2 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -2161,6 +2161,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = semProcTypeWithScope(c, n, prev, symKind) if n.kind == nkIteratorTy and result.kind == tyProc: result.flags.incl(tfIterator) + if result.callConv == ccClosure and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: + result.flags.incl tfHasAsgn of nkEnumTy: result = semEnum(c, n, prev) of nkType: result = n.typ of nkStmtListType: result = semStmtListType(c, n, prev) diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index dbf16df3d70d..2f1a72fd65fb 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -9,8 +9,9 @@ ## Computes hash values for routine (proc, method etc) signatures. -import ast, tables, ropes, modulegraphs, options, msgs, pathutils -from hashes import Hash +import ast, ropes, modulegraphs, options, msgs, pathutils +from std/hashes import Hash +import std/tables import types import ../dist/checksums/src/checksums/md5 diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 3867a67b7047..77f8de68bdfe 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -11,10 +11,12 @@ ## the call to overloaded procs, generic procs and operators. import - intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, - magicsys, idents, lexer, options, parampatterns, strutils, trees, + ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, + magicsys, idents, lexer, options, parampatterns, trees, linter, lineinfos, lowerings, modulegraphs, concepts +import std/[intsets, strutils] + when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 424d7450f811..9e5a9ab900d6 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -29,11 +29,11 @@ proc raiseIllegalTypeRecursion() = raise newException(IllegalTypeRecursionError, "illegal type recursion") type - OffsetAccum = object - maxAlign: int32 - offset: int32 + OffsetAccum* = object + maxAlign*: int32 + offset*: int32 -proc inc(arg: var OffsetAccum; value: int32) = +proc inc*(arg: var OffsetAccum; value: int32) = if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion() if value == szUnknownSize or arg.offset == szUnknownSize: arg.offset = szUnknownSize @@ -47,7 +47,7 @@ proc alignmentMax(a, b: int32): int32 = else: max(a, b) -proc align(arg: var OffsetAccum; value: int32) = +proc align*(arg: var OffsetAccum; value: int32) = if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion() if value == szUnknownSize or arg.maxAlign == szUnknownSize or arg.offset == szUnknownSize: arg.maxAlign = szUnknownSize @@ -73,7 +73,7 @@ proc finish(arg: var OffsetAccum): int32 = result = align(arg.offset, arg.maxAlign) - arg.offset arg.offset += result -proc computeSizeAlign(conf: ConfigRef; typ: PType) +proc computeSizeAlign*(conf: ConfigRef; typ: PType) proc computeSubObjectAlign(conf: ConfigRef; n: PNode): BiggestInt = ## returns object alignment diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 5554991bd736..1d84fada52ff 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -32,11 +32,13 @@ # included from sigmatch.nim -import algorithm, sets, prefixmatches, parseutils, tables +import prefixmatches from wordrecg import wDeprecated, wError, wAddr, wYield +import std/[algorithm, sets, parseutils, tables] + when defined(nimsuggest): - import tables, pathutils # importer + import std/tables, pathutils # importer const sep = '\t' @@ -105,7 +107,7 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int result = 0 elif ident[0] in linter.Letters and ident[^1] != '=': result = identLen(line, column) - if cmpIgnoreStyle(line[column..column + result - 1], ident) != 0: + if cmpIgnoreStyle(line[column..column + result - 1], ident[0..min(result-1,len(ident)-1)]) != 0: result = 0 else: var sourceIdent: string = "" @@ -175,7 +177,7 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info result.filePath = toFullPath(g.config, infox) result.line = toLinenumber(infox) result.column = toColumn(infox) - result.tokenLen = if section != ideHighlight: + result.tokenLen = if section notin {ideHighlight, ideInlayHints}: s.name.s.len else: getTokenLenFromSource(g.config, s.name.s, infox) @@ -183,50 +185,82 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info result.endLine = endLine result.endCol = endCol -proc `$`*(suggest: Suggest): string = - result = $suggest.section +proc `$`*(suggest: SuggestInlayHint): string = + result = $suggest.kind result.add(sep) - if suggest.section == ideHighlight: - if suggest.symkind.TSymKind == skVar and suggest.isGlobal: - result.add("skGlobalVar") - elif suggest.symkind.TSymKind == skLet and suggest.isGlobal: - result.add("skGlobalLet") - else: - result.add($suggest.symkind.TSymKind) - result.add(sep) - result.add($suggest.line) - result.add(sep) - result.add($suggest.column) - result.add(sep) - result.add($suggest.tokenLen) + result.add($suggest.line) + result.add(sep) + result.add($suggest.column) + result.add(sep) + result.add(suggest.label) + result.add(sep) + result.add($suggest.paddingLeft) + result.add(sep) + result.add($suggest.paddingRight) + result.add(sep) + result.add($suggest.allowInsert) + result.add(sep) + result.add(suggest.tooltip) + +proc `$`*(suggest: Suggest): string = + if suggest.section == ideInlayHints: + result = $suggest.inlayHintInfo else: - result.add($suggest.symkind.TSymKind) - result.add(sep) - if suggest.qualifiedPath.len != 0: - result.add(suggest.qualifiedPath.join(".")) - result.add(sep) - result.add(suggest.forth) - result.add(sep) - result.add(suggest.filePath) + result = $suggest.section result.add(sep) - result.add($suggest.line) - result.add(sep) - result.add($suggest.column) - result.add(sep) - when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): - result.add(suggest.doc.escape) - if suggest.version == 0 or suggest.version == 3: + if suggest.section == ideHighlight: + if suggest.symkind.TSymKind == skVar and suggest.isGlobal: + result.add("skGlobalVar") + elif suggest.symkind.TSymKind == skLet and suggest.isGlobal: + result.add("skGlobalLet") + else: + result.add($suggest.symkind.TSymKind) + result.add(sep) + result.add($suggest.line) + result.add(sep) + result.add($suggest.column) + result.add(sep) + result.add($suggest.tokenLen) + else: + result.add($suggest.symkind.TSymKind) result.add(sep) - result.add($suggest.quality) - if suggest.section == ideSug: + if suggest.qualifiedPath.len != 0: + result.add(suggest.qualifiedPath.join(".")) + result.add(sep) + result.add(suggest.forth) + result.add(sep) + result.add(suggest.filePath) + result.add(sep) + result.add($suggest.line) + result.add(sep) + result.add($suggest.column) + result.add(sep) + when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler): + result.add(suggest.doc.escape) + if suggest.version == 0 or suggest.version == 3: result.add(sep) - result.add($suggest.prefix) + result.add($suggest.quality) + if suggest.section == ideSug: + result.add(sep) + result.add($suggest.prefix) - if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}): - result.add(sep) - result.add($suggest.endLine) - result.add(sep) - result.add($suggest.endCol) + if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}): + result.add(sep) + result.add($suggest.endLine) + result.add(sep) + result.add($suggest.endCol) + +proc suggestToSuggestInlayHint*(sug: Suggest): SuggestInlayHint = + SuggestInlayHint( + kind: sihkType, + line: sug.line, + column: sug.column + sug.tokenLen, + label: ": " & sug.forth, + paddingLeft: false, + paddingRight: false, + allowInsert: true, + tooltip: "" + ) proc suggestResult*(conf: ConfigRef; s: Suggest) = if not isNil(conf.suggestionResultHook): @@ -535,7 +569,7 @@ proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; i ## misnamed: should be 'symDeclared' let conf = g.config when defined(nimsuggest): - g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info) + g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info, isDecl: isDecl) if conf.suggestVersion == 0: if s.allUsages.len == 0: diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 1c8acf2a6420..ef6b1da58693 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -10,9 +10,10 @@ ## Implements the dispatcher for the different parsers. import - strutils, llstream, ast, idents, lexer, options, msgs, parser, + llstream, ast, idents, lexer, options, msgs, parser, filters, filter_tmpl, renderer, lineinfos, pathutils +import std/strutils when defined(nimPreviewSlimSystem): import std/[syncio, assertions] diff --git a/compiler/treetab.nim b/compiler/treetab.nim index 92e04c13a654..6685c4a8997c 100644 --- a/compiler/treetab.nim +++ b/compiler/treetab.nim @@ -9,8 +9,9 @@ # Implements a table from trees to trees. Does structural equivalence checking. -import - hashes, ast, astalgo, types +import ast, astalgo, types + +import std/hashes when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/typeallowed.nim b/compiler/typeallowed.nim index fe0d7b8855a6..d0df66f1851f 100644 --- a/compiler/typeallowed.nim +++ b/compiler/typeallowed.nim @@ -10,8 +10,8 @@ ## This module contains 'typeAllowed' and friends which check ## for invalid types like `openArray[var int]`. -import - intsets, ast, renderer, options, semdata, types +import ast, renderer, options, semdata, types +import std/intsets when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/types.nim b/compiler/types.nim index f5e965df98ff..46433a2306dd 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -10,9 +10,11 @@ # this module contains routines for accessing and iterating over types import - intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options, + ast, astalgo, trees, msgs, platform, renderer, options, lineinfos, int128, modulegraphs, astmsgs +import std/[intsets, strutils] + when defined(nimPreviewSlimSystem): import std/[assertions, formatfloat] @@ -970,6 +972,7 @@ type ExactGcSafety AllowCommonBase PickyCAliases # be picky about the distinction between 'cint' and 'int32' + IgnoreFlags # used for borrowed functions; ignores the tfVarIsPtr flag TTypeCmpFlags* = set[TTypeCmpFlag] @@ -1202,12 +1205,12 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = if containsOrIncl(c, a, b): return true if x == y: return true - var a = skipTypes(x, {tyGenericInst, tyAlias}) + var a = skipTypes(x, {tyAlias}) while a.kind == tyUserTypeClass and tfResolved in a.flags: - a = skipTypes(a[^1], {tyGenericInst, tyAlias}) - var b = skipTypes(y, {tyGenericInst, tyAlias}) + a = skipTypes(a[^1], {tyAlias}) + var b = skipTypes(y, {tyAlias}) while b.kind == tyUserTypeClass and tfResolved in b.flags: - b = skipTypes(b[^1], {tyGenericInst, tyAlias}) + b = skipTypes(b[^1], {tyAlias}) assert(a != nil) assert(b != nil) if a.kind != b.kind: @@ -1304,7 +1307,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = cycleCheck() if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n result = sameChildrenAux(a, b, c) - if result: + if result and IgnoreFlags notin c.flags: if IgnoreTupleFields in c.flags: result = a.flags * {tfVarIsPtr, tfIsOutParam} == b.flags * {tfVarIsPtr, tfIsOutParam} else: diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index ff8ec8d5767f..72bcddb05972 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -7,7 +7,8 @@ # distribution, for details about the copyright. # -import renderer, strutils, ast, types +import renderer, ast, types +import std/strutils when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index a47d034c7a46..18f9fe5caddf 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -7,9 +7,11 @@ # distribution, for details about the copyright. # -import ast, types, msgs, os, options, idents, lineinfos +import ast, types, msgs, options, idents, lineinfos from pathutils import AbsoluteFile +import std/os + when defined(nimPreviewSlimSystem): import std/syncio diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index efcd0ec35b04..53b2974bab73 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -26,14 +26,14 @@ # solves the opcLdConst vs opcAsgnConst issue. Of course whether we need # this copy depends on the involved types. -import tables +import std/[tables, intsets, strutils] when defined(nimPreviewSlimSystem): import std/assertions import - strutils, ast, types, msgs, renderer, vmdef, trees, - intsets, magicsys, options, lowerings, lineinfos, transf, astmsgs + ast, types, msgs, renderer, vmdef, trees, + magicsys, options, lowerings, lineinfos, transf, astmsgs from modulegraphs import getBody diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index e1e69f6cc503..8ce1133691ef 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -9,9 +9,11 @@ ## Implements marshaling for the VM. -import streams, json, intsets, tables, ast, astalgo, idents, types, msgs, +import ast, astalgo, idents, types, msgs, options, lineinfos +import std/[streams, json, intsets, tables] + when defined(nimPreviewSlimSystem): import std/[assertions, formatfloat] diff --git a/compiler/vmprofiler.nim b/compiler/vmprofiler.nim index edbd71813a4f..3f0db84bddb5 100644 --- a/compiler/vmprofiler.nim +++ b/compiler/vmprofiler.nim @@ -1,7 +1,7 @@ -import - options, vmdef, times, lineinfos, strutils, tables, - msgs +import options, vmdef, lineinfos, msgs + +import std/[times, strutils, tables] proc enter*(prof: var Profiler, c: PCtx, tos: PStackFrame) {.inline.} = if optProfileVM in c.config.globalOptions: diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index aa25f7fd1aa7..55a8921af909 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -145,6 +145,6 @@ const from std/enumutils import genEnumCaseStmt -from strutils import normalize +from std/strutils import normalize proc findStr*[T: enum](a, b: static[T], s: string, default: T): T = genEnumCaseStmt(T, s, default, ord(a), ord(b), normalize) diff --git a/doc/astspec.txt b/doc/astspec.txt index 9929d8ccd832..7a7053a2d05a 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -893,7 +893,7 @@ on what keywords are present. Let's start with the simplest form. Concrete syntax: ```nim - import math + import std/math ``` AST: @@ -907,7 +907,7 @@ With ``except``, we get ``nnkImportExceptStmt``. Concrete syntax: ```nim - import math except pow + import std/math except pow ``` AST: @@ -916,13 +916,13 @@ AST: nnkImportExceptStmt(nnkIdent("math"),nnkIdent("pow")) ``` -Note that ``import math as m`` does not use a different node; rather, +Note that ``import std/math as m`` does not use a different node; rather, we use ``nnkImportStmt`` with ``as`` as an infix operator. Concrete syntax: ```nim - import strutils as su + import std/strutils as su ``` AST: @@ -945,7 +945,7 @@ If we use ``from ... import``, the result is different, too. Concrete syntax: ```nim - from math import pow + from std/math import pow ``` AST: @@ -954,7 +954,7 @@ AST: nnkFromStmt(nnkIdent("math"), nnkIdent("pow")) ``` -Using ``from math as m import pow`` works identically to the ``as`` modifier +Using ``from std/math as m import pow`` works identically to the ``as`` modifier with the ``import`` statement, but wrapped in ``nnkFromStmt``. Export statement diff --git a/doc/docgen.md b/doc/docgen.md index 21058e88d55f..3cc75fc18023 100644 --- a/doc/docgen.md +++ b/doc/docgen.md @@ -621,7 +621,7 @@ compilation options are different: .. Note:: markup documents are just placed into the specified directory `OUTDIR`:option: by default (i.e. they are **not** affected by `--project`:option:), so if you have ``PROJECT/doc/manual.md`` - document and want to use complex hirearchy (with ``doc/``), + document and want to use complex hierarchy (with ``doc/``), compile it with `--docroot`:option:\: ```cmd # 1st stage @@ -688,7 +688,7 @@ the rest optional. See the [Index (idx) file format] section for details. .. Note:: `--index`:option: switch only affects creation of ``.idx`` index files, while user-searchable Index HTML file is created by - `buildIndex`:option: commmand. + `buildIndex`:option: command. Buildindex command ------------------ diff --git a/doc/docgen_sample.nim b/doc/docgen_sample.nim index 7a167cb4572f..06b8d7f8e2ce 100644 --- a/doc/docgen_sample.nim +++ b/doc/docgen_sample.nim @@ -1,6 +1,6 @@ ## This module is a sample. -import strutils +import std/strutils proc helloWorld*(times: int) = ## Takes an integer and outputs diff --git a/doc/estp.md b/doc/estp.md index d0ef4f1bac1c..8a986bdf3081 100644 --- a/doc/estp.md +++ b/doc/estp.md @@ -28,7 +28,7 @@ Otherwise your program is profiled. ```nim when compileOption("profiler"): - import nimprof + import std/nimprof ``` After your program has finished the profiler will create a diff --git a/doc/manual.md b/doc/manual.md index 8f419705efd3..0e167be04202 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -655,7 +655,7 @@ string containing the literal. The callable identifier needs to be declared with a special ``'`` prefix: ```nim - import strutils + import std/strutils type u4 = distinct uint8 # a 4-bit unsigned integer aka "nibble" proc `'u4`(n: string): u4 = # The leading ' is required. @@ -670,7 +670,7 @@ corresponds to this transformation. The transformation naturally handles the case that additional parameters are passed to the callee: ```nim - import strutils + import std/strutils type u4 = distinct uint8 # a 4-bit unsigned integer aka "nibble" proc `'u4`(n: string; moreData: int): u4 = result = (parseInt(n) and 0x0F).u4 @@ -1495,7 +1495,8 @@ it can be modified: ```nim var x = "123456" - var s: cstring = x + prepareMutation(x) # call `prepareMutation` before modifying the strings + var s: cstring = cstring(x) s[0] = 'u' # This is ok ``` @@ -5230,7 +5231,7 @@ conservative in its effect analysis: ```nim test = "nim c $1" status = 1 {.push warningAsError[Effect]: on.} - import algorithm + import std/algorithm type MyInt = distinct int diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 4bafd408ff0b..071668aa1bd9 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -1368,7 +1368,7 @@ to be computed dynamically. ```nim {.experimental: "dynamicBindSym".} - import macros + import std/macros macro callOp(opName, arg1, arg2): untyped = result = newCall(bindSym($opName), arg1, arg2) @@ -2378,7 +2378,7 @@ proc makeCppClass(): NimClass {.constructor: "NimClass() : CppClass(0, 0)".} = result.x = 1 ``` -In the example above `CppClass` has a deleted default constructor. Notice how by using the constructor syntax, one can call the appropiate constructor. +In the example above `CppClass` has a deleted default constructor. Notice how by using the constructor syntax, one can call the appropriate constructor. Notice when calling a constructor in the section of a global variable initialization, it will be called before `NimMain` meaning Nim is not fully initialized. diff --git a/doc/markdown_rst.md b/doc/markdown_rst.md index b7f0916494b6..c7977f75a7dd 100644 --- a/doc/markdown_rst.md +++ b/doc/markdown_rst.md @@ -246,7 +246,7 @@ nim md2html file2.md # creates ``htmldocs/file2.html`` ``` To allow cross-references between any files in any order (especially, if -circular references are present), it's strongly reccommended +circular references are present), it's strongly recommended to make a run for creating all the indexes first: ```cmd diff --git a/doc/nimc.md b/doc/nimc.md index 9c6ea70330e0..08bd016e114b 100644 --- a/doc/nimc.md +++ b/doc/nimc.md @@ -486,7 +486,7 @@ DLL generation ============== **Note**: The same rules apply to `lib*.so` shared object files on UNIX. For better -readability only the DLL version is decribed here. +readability only the DLL version is described here. Nim supports the generation of DLLs. However, there must be only one instance of the GC per process/address space. This instance is contained in diff --git a/lib/core/hotcodereloading.nim b/lib/core/hotcodereloading.nim index 73f38402de93..3a876885cead 100644 --- a/lib/core/hotcodereloading.nim +++ b/lib/core/hotcodereloading.nim @@ -11,7 +11,7 @@ when defined(hotcodereloading): import - macros + std/macros template beforeCodeReload*(body: untyped) = hcrAddEventHandler(true, proc = body) {.executeOnReload.} diff --git a/lib/deprecated/pure/future.nim b/lib/deprecated/pure/future.nim index 3f7b63a30db0..0e06161f2081 100644 --- a/lib/deprecated/pure/future.nim +++ b/lib/deprecated/pure/future.nim @@ -2,5 +2,5 @@ {.deprecated: "Use the new 'sugar' module instead".} -import sugar +import std/sugar export sugar diff --git a/lib/deprecated/pure/ospaths.nim b/lib/deprecated/pure/ospaths.nim index b57839d1aa3f..43fcb17ccf04 100644 --- a/lib/deprecated/pure/ospaths.nim +++ b/lib/deprecated/pure/ospaths.nim @@ -11,7 +11,7 @@ {.deprecated: "use `std/os` instead".} -import os +import std/os export ReadEnvEffect, WriteEnvEffect, ReadDirEffect, WriteDirEffect, OSErrorCode, doslikeFileSystem, CurDir, ParDir, DirSep, AltSep, PathSep, FileSystemCaseSensitive, ExeExt, ScriptExt, DynlibFormat, ExtSep, joinPath, `/`, splitPath, parentDir, diff --git a/lib/deprecated/pure/oswalkdir.nim b/lib/deprecated/pure/oswalkdir.nim index 866f9ed70262..57a2cb81d7f9 100644 --- a/lib/deprecated/pure/oswalkdir.nim +++ b/lib/deprecated/pure/oswalkdir.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -## This module is deprecated, `import os` instead. -{.deprecated: "import os.nim instead".} -import os +## This module is deprecated, `import std/os` instead. +{.deprecated: "import 'std/os' instead".} +import std/os export PathComponent, walkDir, walkDirRec diff --git a/lib/experimental/diff.nim b/lib/experimental/diff.nim index 4ca5eb31977c..669e9f613f09 100644 --- a/lib/experimental/diff.nim +++ b/lib/experimental/diff.nim @@ -43,7 +43,7 @@ jkl""" # "An O(ND) Difference Algorithm and its Variations" by Eugene Myers # Algorithmica Vol. 1 No. 2, 1986, p 251. -import tables, strutils +import std/[tables, strutils] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 2c1b1deaeee0..39d238055dcc 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -61,12 +61,12 @@ runnableExamples: assert find("uxabc", re"(?<=x|y)ab", start = 1).get.captures[-1] == "ab" assert find("uxabc", re"ab", start = 3).isNone -from pcre import nil +from std/pcre import nil import nre/private/util -import tables -from strutils import `%` -import options -from unicode import runeLenAt +import std/tables +from std/strutils import `%` +import std/options +from std/unicode import runeLenAt when defined(nimPreviewSlimSystem): import std/assertions @@ -217,9 +217,11 @@ type ## code. 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) diff --git a/lib/impure/nre/private/util.nim b/lib/impure/nre/private/util.nim index d227dcba3bfb..ed842077661e 100644 --- a/lib/impure/nre/private/util.nim +++ b/lib/impure/nre/private/util.nim @@ -1,5 +1,5 @@ ## INTERNAL FILE FOR USE ONLY BY nre.nim. -import tables +import std/tables const Ident = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'} const StartIdent = Ident - {'0'..'9'} diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index b0c648373d90..f4fc26380b39 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -55,7 +55,7 @@ elif defined(genode): stdin.readLine(line) else: - import linenoise + import std/linenoise proc readLineFromStdin*(prompt: string, line: var string): bool {. tags: [ReadIOEffect, WriteIOEffect].} = diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 5e84091c7748..053c6ab5555c 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -36,7 +36,7 @@ runnableExamples: # can't match start of string since we're starting at 1 import - pcre, strutils, rtarrays + std/[pcre, strutils, rtarrays] when defined(nimPreviewSlimSystem): import std/syncio diff --git a/lib/nimhcr.nim b/lib/nimhcr.nim index 2a74cc92de6e..e87bb24139db 100644 --- a/lib/nimhcr.nim +++ b/lib/nimhcr.nim @@ -219,7 +219,7 @@ when defined(createNimHcr): when system.appType != "lib": {.error: "This file has to be compiled as a library!".} - import os, tables, sets, times, strutils, reservedmem, dynlib + import std/[os, tables, sets, times, strutils, reservedmem, dynlib] template trace(args: varargs[untyped]) = when defined(testNimHcr) or defined(traceHcr): diff --git a/lib/nimrtl.nim b/lib/nimrtl.nim index 93349b287311..a2fb6ce600c4 100644 --- a/lib/nimrtl.nim +++ b/lib/nimrtl.nim @@ -36,5 +36,5 @@ when not defined(createNimRtl): {.error: "This file has to be compiled with '-d:createNimRtl'".} import - parseutils, strutils, parseopt, parsecfg, strtabs, unicode, pegs, ropes, - os, osproc, times, cstrutils + std/[parseutils, strutils, parseopt, parsecfg, strtabs, unicode, pegs, ropes, + os, osproc, times, cstrutils] diff --git a/lib/packages/docutils/dochelpers.nim b/lib/packages/docutils/dochelpers.nim index 7b257ffff98c..0a41d85b53d6 100644 --- a/lib/packages/docutils/dochelpers.nim +++ b/lib/packages/docutils/dochelpers.nim @@ -13,7 +13,8 @@ ## `type LangSymbol`_ in ``rst.nim``, while `match(generated, docLink)`_ ## matches it with `generated`, produced from `PNode` by ``docgen.rst``. -import rstast, strutils +import rstast +import std/strutils when defined(nimPreviewSlimSystem): import std/[assertions, syncio] diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index c3caf31b4c8e..f0da1545c743 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -57,8 +57,8 @@ ## as program output. import - strutils -from algorithm import binarySearch + std/strutils +from std/algorithm import binarySearch when defined(nimPreviewSlimSystem): import std/[assertions, syncio] diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index a9bc4db9164a..342ce0108248 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -21,8 +21,10 @@ ## turned on by passing ``options:`` [RstParseOptions] to [proc rstParse]. import - os, strutils, rstast, dochelpers, std/enumutils, algorithm, lists, sequtils, - std/private/miscdollars, tables, strscans, rstidx + std/[os, strutils, enumutils, algorithm, lists, sequtils, + tables, strscans] +import dochelpers, rstidx, rstast +import std/private/miscdollars from highlite import SourceLanguage, getSourceLanguage when defined(nimPreviewSlimSystem): diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index c808318b5b5d..2bbb0d0b83a9 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -9,7 +9,7 @@ ## This module implements an AST for the `reStructuredText`:idx: parser. -import strutils, json +import std/[strutils, json] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index f06e11de25fb..7fc0ac03a894 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -39,10 +39,10 @@ ## No backreferences are generated since finding all references of a footnote ## can be done by simply searching for ``[footnoteName]``. -import strutils, os, hashes, strtabs, rstast, rst, rstidx, - highlite, tables, sequtils, - algorithm, parseutils, std/strbasics +import std/[strutils, os, hashes, strtabs, tables, sequtils, + algorithm, parseutils, strbasics] +import rstast, rst, rstidx, highlite when defined(nimPreviewSlimSystem): import std/[assertions, syncio, formatfloat] diff --git a/lib/packages/docutils/rstidx.nim b/lib/packages/docutils/rstidx.nim index 236b8361ac53..1472d28fd74a 100644 --- a/lib/packages/docutils/rstidx.nim +++ b/lib/packages/docutils/rstidx.nim @@ -7,8 +7,8 @@ ## Nim `idx`:idx: file format related definitions. -import strutils, std/syncio, hashes -from os import splitFile +import std/[strutils, syncio, hashes] +from std/os import splitFile type IndexEntryKind* = enum ## discriminator tag diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim index 7ee062e4fb99..007488354a12 100644 --- a/lib/posix/epoll.nim +++ b/lib/posix/epoll.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -from posix import SocketHandle +from std/posix import SocketHandle const EPOLLIN* = 0x00000001 diff --git a/lib/posix/kqueue.nim b/lib/posix/kqueue.nim index c83ae33ea300..2450cdb4243e 100644 --- a/lib/posix/kqueue.nim +++ b/lib/posix/kqueue.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -from posix import Timespec +from std/posix import Timespec when defined(macosx) or defined(freebsd) or defined(openbsd) or defined(dragonfly): diff --git a/lib/posix/linux.nim b/lib/posix/linux.nim index 9a5e9f062f91..29fd4288d099 100644 --- a/lib/posix/linux.nim +++ b/lib/posix/linux.nim @@ -1,4 +1,4 @@ -import posix +import std/posix ## Flags of `clone` syscall. ## See `clone syscall manual diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index 7e4a2eedadaf..b12950f7bbf9 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -11,7 +11,7 @@ # Where possible, contribute OS-independent procs in `os `_ instead. -import posix, parsecfg, os +import std/[posix, parsecfg, os] import std/private/since when defined(nimPreviewSlimSystem): diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index f755c720dced..7fb6bb81c63d 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -import posix +import std/posix type Speed* = cuint diff --git a/lib/pure/async.nim b/lib/pure/async.nim index 249c5f6392c9..e4d8d41c3d9e 100644 --- a/lib/pure/async.nim +++ b/lib/pure/async.nim @@ -2,8 +2,8 @@ ## and [asyncjs](asyncjs.html) on the JS backend. when defined(js): - import asyncjs + import std/asyncjs export asyncjs else: - import asyncmacro, asyncfutures + import std/[asyncmacro, asyncfutures] export asyncmacro, asyncfutures diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 24c1ec3d56ba..e009fee2de3e 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -226,11 +226,11 @@ ## ``none`` can be used when a library supports both a synchronous and ## asynchronous API, to disable the latter. -import os, tables, strutils, times, heapqueue, options, asyncstreams -import options, math, std/monotimes -import asyncfutures except callSoon +import std/[os, tables, strutils, times, heapqueue, options, asyncstreams] +import std/[math, monotimes] +import std/asyncfutures except callSoon -import nativesockets, net, deques +import std/[nativesockets, net, deques] when defined(nimPreviewSlimSystem): import std/[assertions, syncio] @@ -302,7 +302,7 @@ template implementSetInheritable() {.dirty.} = fd.FileHandle.setInheritable(inheritable) when defined(windows) or defined(nimdoc): - import winlean, sets, hashes + import std/[winlean, sets, hashes] type CompletionKey = ULONG_PTR @@ -1166,11 +1166,11 @@ when defined(windows) or defined(nimdoc): initAll() else: - import selectors - from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, + import std/selectors + from std/posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, MSG_NOSIGNAL when declared(posix.accept4): - from posix import accept4, SOCK_CLOEXEC + from std/posix import accept4, SOCK_CLOEXEC when defined(genode): import genode/env # get the implicit Genode env import genode/signals @@ -1994,7 +1994,7 @@ proc send*(socket: AsyncFD, data: string, return retFuture # -- Await Macro -import asyncmacro +import std/asyncmacro export asyncmacro proc readAll*(future: FutureStream[string]): owned(Future[string]) {.async.} = @@ -2032,7 +2032,7 @@ proc activeDescriptors*(): int {.inline.} = result = getGlobalDispatcher().selector.count when defined(posix): - import posix + import std/posix when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or defined(solaris) or defined(zephyr) or defined(freertos) or defined(nuttx) or defined(haiku): diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index 118f94748616..185d59fa6972 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -23,7 +23,7 @@ ## waitFor main() ## ``` -import asyncdispatch, os +import std/[asyncdispatch, os] when defined(nimPreviewSlimSystem): import std/[assertions, syncio] @@ -33,9 +33,9 @@ when defined(nimPreviewSlimSystem): # TODO: Fix duplication introduced by PR #4683. when defined(windows) or defined(nimdoc): - import winlean + import std/winlean else: - import posix + import std/posix type AsyncFile* = ref object diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 51aaaca367aa..edb4e14d3152 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -import os, tables, strutils, times, heapqueue, options, deques, cstrutils +import std/[os, tables, strutils, times, heapqueue, options, deques, cstrutils] import system/stacktraces @@ -51,7 +51,7 @@ const NimAsyncContinueSuffix* = "NimAsyncContinue" ## For internal usage. Do not use. when isFutureLoggingEnabled: - import hashes + import std/hashes type FutureInfo* = object stackTrace*: seq[StackTraceEntry] diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 07eed9a5143b..39e945d5e679 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -39,9 +39,9 @@ runnableExamples("-r:off"): waitFor main() -import asyncnet, asyncdispatch, parseutils, uri, strutils -import httpcore -from nativesockets import getLocalAddr, Domain, AF_INET, AF_INET6 +import std/[asyncnet, asyncdispatch, parseutils, uri, strutils] +import std/httpcore +from std/nativesockets import getLocalAddr, Domain, AF_INET, AF_INET6 import std/private/since when defined(nimPreviewSlimSystem): diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index a026e159e855..d4e72c28a689 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -9,7 +9,7 @@ ## Implements the `async` and `multisync` macros for `asyncdispatch`. -import macros, strutils, asyncfutures +import std/[macros, strutils, asyncfutures] type Context = ref object diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 2fc8d366e840..f69c5bc73b99 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -99,7 +99,7 @@ import std/private/since when defined(nimPreviewSlimSystem): import std/[assertions, syncio] -import asyncdispatch, nativesockets, net, os +import std/[asyncdispatch, nativesockets, net, os] export SOBool @@ -110,7 +110,7 @@ const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr defined(nuttx) when defineSsl: - import openssl + import std/openssl type # TODO: I would prefer to just do: diff --git a/lib/pure/asyncstreams.nim b/lib/pure/asyncstreams.nim index 3f7774ed8661..c97b98d55c12 100644 --- a/lib/pure/asyncstreams.nim +++ b/lib/pure/asyncstreams.nim @@ -9,12 +9,12 @@ ## Unstable API. -import asyncfutures +import std/asyncfutures when defined(nimPreviewSlimSystem): import std/assertions -import deques +import std/deques type FutureStream*[T] = ref object ## Special future that acts as diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 005c7fa8fa78..0d3351ee51a5 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -25,7 +25,7 @@ ## At this time only `fastLog2`, `firstSetBit`, `countLeadingZeroBits` and `countTrailingZeroBits` ## may return undefined and/or platform dependent values if given invalid input. -import macros +import std/macros import std/private/since from std/private/bitops_utils import forwardImpl, castToUnsigned @@ -463,7 +463,7 @@ elif useVCC_builtins: importc: "_BitScanForward64", header: "".} template vcc_scan_impl(fnc: untyped; v: untyped): int = - var index: culong + var index {.inject.}: culong = 0 discard fnc(index.addr, v) index.int diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index a98d9d5b8a08..5708582e1460 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -14,20 +14,20 @@ import std/private/since -import strutils +import std/strutils when defined(nimPreviewSlimSystem): import std/assertions when defined(windows): - import winlean + import std/winlean when defined(nimPreviewSlimSystem): import std/widestrs - from os import absolutePath + from std/os import absolutePath else: - import os + import std/os when not defined(osx): - import osproc + import std/osproc const osOpenCmd* = when defined(macos) or defined(macosx) or defined(windows): "open" else: "xdg-open" ## \ diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index e761569a1c0b..034f224ac780 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -29,7 +29,7 @@ ## writeLine(stdout, "") ## ``` -import strutils, os, strtabs, cookies, uri +import std/[strutils, os, strtabs, cookies, uri] export uri.encodeUrl, uri.decodeUrl when defined(nimPreviewSlimSystem): diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index ed58028c8e75..b07138e842e2 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -50,7 +50,7 @@ runnableExamples: import std/private/since -import math +import std/math type Deque*[T] = object diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index a32060e183cc..3c0d8dc0ebee 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -82,8 +82,8 @@ runnableExamples: import std/private/since -import macros -from typetraits import supportsCopyMem +import std/macros +from std/typetraits import supportsCopyMem when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index dbd4ce1d5e12..360a075d67ad 100644 --- a/lib/pure/collections/setimpl.nim +++ b/lib/pure/collections/setimpl.nim @@ -87,7 +87,9 @@ proc exclImpl[A](s: var HashSet[A], key: A): bool {.inline.} = var j = i # The correctness of this depends on (h+1) in nextTry, var r = j # though may be adaptable to other simple sequences. s.data[i].hcode = 0 # mark current EMPTY - s.data[i].key = default(typeof(s.data[i].key)) + {.push warning[UnsafeDefault]:off.} + reset(s.data[i].key) + {.pop.} doWhile((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): i = (i + 1) and msk # increment mod table size if isEmpty(s.data[i].hcode): # end of collision cluster; So all done diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 62abd68d4442..af13135aabbf 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -50,7 +50,7 @@ import - hashes, math + std/[hashes, math] when not defined(nimHasEffectsOf): {.pragma: effectsOf.} @@ -382,7 +382,9 @@ proc clear*[A](s: var HashSet[A]) = s.counter = 0 for i in 0 ..< s.data.len: s.data[i].hcode = 0 - s.data[i].key = default(typeof(s.data[i].key)) + {.push warning[UnsafeDefault]:off.} + reset(s.data[i].key) + {.pop.} proc union*[A](s1, s2: HashSet[A]): HashSet[A] = @@ -816,7 +818,9 @@ proc clear*[A](s: var OrderedSet[A]) = for i in 0 ..< s.data.len: s.data[i].hcode = 0 s.data[i].next = 0 - s.data[i].key = default(typeof(s.data[i].key)) + {.push warning[UnsafeDefault]:off.} + reset(s.data[i].key) + {.pop.} proc len*[A](s: OrderedSet[A]): int {.inline.} = ## Returns the number of elements in `s`. diff --git a/lib/pure/collections/sharedlist.nim b/lib/pure/collections/sharedlist.nim index e61883220ae0..ec8f1cd866ff 100644 --- a/lib/pure/collections/sharedlist.nim +++ b/lib/pure/collections/sharedlist.nim @@ -16,7 +16,7 @@ {.push stackTrace: off.} import - locks + std/locks const ElemsPerNode = 100 diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 8b49066aca0d..b474ecd31549 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -17,7 +17,7 @@ {.deprecated.} import - hashes, math, locks + std/[hashes, math, locks] type KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B] diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index 112aaa7d0697..630af397026c 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -119,8 +119,10 @@ template delImplIdx(t, i, makeEmpty, cellEmpty, cellHash) = var j = i # The correctness of this depends on (h+1) in nextTry var r = j # though may be adaptable to other simple sequences. makeEmpty(i) # mark current EMPTY - t.data[i].key = default(typeof(t.data[i].key)) - t.data[i].val = default(typeof(t.data[i].val)) + {.push warning[UnsafeDefault]:off.} + reset(t.data[i].key) + reset(t.data[i].val) + {.pop.} while true: i = (i + 1) and msk # increment mod table size if cellEmpty(i): # end of collision cluster; So all done @@ -151,8 +153,10 @@ template clearImpl() {.dirty.} = for i in 0 ..< t.dataLen: when compiles(t.data[i].hcode): # CountTable records don't contain a hcode t.data[i].hcode = 0 - t.data[i].key = default(typeof(t.data[i].key)) - t.data[i].val = default(typeof(t.data[i].val)) + {.push warning[UnsafeDefault]:off.} + reset(t.data[i].key) + reset(t.data[i].val) + {.pop.} t.counter = 0 template ctAnd(a, b): bool = diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 6ea4a9a45eaa..0a902ba8412d 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -194,7 +194,7 @@ runnableExamples: import std/private/since -import hashes, math, algorithm +import std/[hashes, math, algorithm] when not defined(nimHasEffectsOf): diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index eccccbfafc88..d3e6dc06313e 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -9,8 +9,8 @@ ## This module implements color handling for Nim, ## namely color mixing and parsing the CSS color names. -import strutils -from algorithm import binarySearch +import std/strutils +from std/algorithm import binarySearch type Color* = distinct int ## A color stored as RGB, e.g. `0xff00cc`. diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index 1e8349ef6499..5304d093056e 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -36,7 +36,7 @@ runnableExamples: {.push checks: off, line_dir: off, stack_trace: off, debugger: off.} # the user does not want to trace a part of the standard library! -import math +import std/math type Complex*[T: SomeFloat] = object diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index 1d2ff63e16df..0b2c915b24bd 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -16,7 +16,7 @@ runnableExamples: include "system/inclrtl" when defined(posix) and not (defined(macosx) or defined(bsd)): - import posix + import std/posix when defined(windows): import std/private/win_getsysteminfo diff --git a/lib/pure/concurrency/cpuload.nim b/lib/pure/concurrency/cpuload.nim index 137dd67ad3a6..bfbf16721263 100644 --- a/lib/pure/concurrency/cpuload.nim +++ b/lib/pure/concurrency/cpuload.nim @@ -13,11 +13,11 @@ ## Unstable API. when defined(windows): - import winlean, os, strutils, math + import std/[winlean, os, strutils, math] proc `-`(a, b: FILETIME): int64 = a.rdFileTime - b.rdFileTime elif defined(linux): - from cpuinfo import countProcessors + from std/cpuinfo import countProcessors when defined(nimPreviewSlimSystem): import std/syncio @@ -87,7 +87,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice = inc s.calls when not defined(testing) and isMainModule and not defined(nimdoc): - import random + import std/random proc busyLoop() = while true: diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index e34162fa4cd5..06ed2fe54298 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -22,7 +22,7 @@ when not compileOption("threads"): {.error: "Threadpool requires --threads:on option.".} -import cpuinfo, cpuload, locks, os +import std/[cpuinfo, cpuload, locks, os] when defined(nimPreviewSlimSystem): import std/[assertions, typedthreads, sysatomics] diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index 22704e4348f9..f628aaf6b774 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -9,7 +9,7 @@ ## This module implements helper procs for parsing Cookies. -import strtabs, times, options +import std/[strtabs, times, options] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index 5cdcb75fe70a..24836e316400 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -29,8 +29,7 @@ when not nimCoroutines and not defined(nimdoc): else: {.error: "Coroutines require -d:nimCoroutines".} -import os -import lists +import std/[os, lists] include system/timers when defined(nimPreviewSlimSystem): @@ -68,7 +67,7 @@ else: const coroBackend = CORO_BACKEND_UCONTEXT when coroBackend == CORO_BACKEND_FIBERS: - import windows/winlean + import std/winlean type Context = pointer diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index 48fd91b8f33c..1980129af200 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -105,7 +105,7 @@ when defined(posix) and not defined(nintendoswitch): # as an emulation layer on top of native functions. # ========================================================================= # - import posix + import std/posix proc loadLib(path: string, globalSymbols = false): LibHandle = let flags = diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 0d7e878e596c..c8683ee40f34 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -39,7 +39,7 @@ runnableExamples: assert fromGB2312.convert(second) == "有白头如新,倾盖如故" -import os +import std/os when defined(nimPreviewSlimSystem): import std/assertions @@ -59,7 +59,7 @@ type ## for encoding errors. when defined(windows): - import parseutils, strutils + import std/[parseutils, strutils] proc eqEncodingNames(a, b: string): bool = var i = 0 var j = 0 diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index be9e1fe90fb7..fafa72463b40 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -8,7 +8,7 @@ # ## Do yourself a favor and import the module -## as `from htmlgen import nil` and then fully qualify the macros. +## as `from std/htmlgen import nil` and then fully qualify the macros. ## ## *Note*: The Karax project (`nimble install karax`) has a better ## way to achieve the same, see https://github.com/pragmagic/karax/blob/master/tests/nativehtmlgen.nim @@ -41,7 +41,7 @@ ## import - macros, strutils + std/[macros, strutils] const coreAttr* = " accesskey class contenteditable dir hidden id lang " & diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index 0de384a8e645..62919546f2b2 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -47,7 +47,9 @@ ## writeFile("output.html", $html) ## ``` -import strutils, streams, parsexml, xmltree, unicode, strtabs +{.deprecated: "use `nimble install htmlparser` and import `pkg/htmlparser` instead".} + +import std/[strutils, streams, parsexml, xmltree, unicode, strtabs] when defined(nimPreviewSlimSystem): import std/syncio @@ -2062,7 +2064,7 @@ proc loadHtml*(path: string): XmlNode = result = loadHtml(path, errors) when not defined(testing) and isMainModule: - import os + import std/os var errors: seq[string] = @[] var x = loadHtml(paramStr(1), errors) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 9444618db652..fc66b96f522f 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -359,7 +359,7 @@ type ## and `postContent` proc, ## when the server returns an error -const defUserAgent* = "Nim httpclient/" & NimVersion +const defUserAgent* = "Nim-httpclient/" & NimVersion proc httpError(msg: string) = var e: ref ProtocolError @@ -856,6 +856,7 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, var parsedStatus = false var linei = 0 var fullyRead = false + var lastHeaderName = "" var line = "" result.headers = newHttpHeaders() while true: @@ -890,16 +891,29 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, parsedStatus = true else: # Parse headers - var name = "" - var le = parseUntil(line, name, ':', linei) - if le <= 0: httpError("invalid headers") - inc(linei, le) - if line[linei] != ':': httpError("invalid headers") - inc(linei) # Skip : - - result.headers.add(name, line[linei .. ^1].strip()) - if result.headers.len > headerLimit: - httpError("too many headers") + # There's at least one char because empty lines are handled above (with client.close) + if line[0] in {' ', '\t'}: + # Check if it's a multiline header value, if so, append to the header we're currently parsing + # This works because a line with a header must start with the header name without any leading space + # See https://datatracker.ietf.org/doc/html/rfc7230, section 3.2 and 3.2.4 + # Multiline headers are deprecated in the spec, but it's better to parse them than crash + if lastHeaderName == "": + # Some extra unparsable lines in the HTTP output - we ignore them + discard + else: + result.headers.table[result.headers.toCaseInsensitive(lastHeaderName)][^1].add "\n" & line + else: + var name = "" + var le = parseUntil(line, name, ':', linei) + if le <= 0: httpError("Invalid headers - received empty header name") + if line.len == le: httpError("Invalid headers - no colon after header name") + inc(linei, le) # Skip the parsed header name + inc(linei) # Skip : + # If we want to be HTTP spec compliant later, error on linei == line.len (for empty header value) + lastHeaderName = name # Remember the header name for the possible multi-line header + result.headers.add(name, line[linei .. ^1].strip()) + if result.headers.len > headerLimit: + httpError("too many headers") if not fullyRead: httpError("Connection was closed before full request has been made") diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 3b5cbc3cfc9e..ab0c030a5c73 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -12,7 +12,7 @@ ## ## Unstable API. import std/private/since -import tables, strutils, parseutils +import std/[tables, strutils, parseutils] type HttpHeaders* = ref object @@ -126,7 +126,8 @@ func toTitleCase(s: string): string = result[i] = if upper: toUpperAscii(s[i]) else: toLowerAscii(s[i]) upper = s[i] == '-' -func toCaseInsensitive(headers: HttpHeaders, s: string): string {.inline.} = +func toCaseInsensitive*(headers: HttpHeaders, s: string): string {.inline.} = + ## For internal usage only. Do not use. return if headers.isTitleCase: toTitleCase(s) else: toLowerAscii(s) func newHttpHeaders*(titleCase=false): HttpHeaders = diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 510de8c51435..10658b78eff6 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -9,7 +9,7 @@ # This module implements Linux epoll(). -import posix, times, epoll +import std/[posix, times, epoll] # Maximum number of events that can be returned const MAX_EPOLL_EVENTS = 64 diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim index 68be969c7f6b..e28218a97f6a 100644 --- a/lib/pure/ioselects/ioselectors_kqueue.nim +++ b/lib/pure/ioselects/ioselectors_kqueue.nim @@ -9,7 +9,7 @@ # This module implements BSD kqueue(). -import posix, times, kqueue, nativesockets +import std/[posix, times, kqueue, nativesockets] const # Maximum number of events that can be returned. diff --git a/lib/pure/ioselects/ioselectors_poll.nim b/lib/pure/ioselects/ioselectors_poll.nim index 12812ac807bd..7c5347156327 100644 --- a/lib/pure/ioselects/ioselectors_poll.nim +++ b/lib/pure/ioselects/ioselectors_poll.nim @@ -9,7 +9,7 @@ # This module implements Posix poll(). -import posix, times +import std/[posix, times] # Maximum number of events that can be returned const MAX_POLL_EVENTS = 64 diff --git a/lib/pure/ioselects/ioselectors_select.nim b/lib/pure/ioselects/ioselectors_select.nim index a6f54e7911c6..11bc62b78d6f 100644 --- a/lib/pure/ioselects/ioselectors_select.nim +++ b/lib/pure/ioselects/ioselectors_select.nim @@ -9,10 +9,10 @@ # This module implements Posix and Windows select(). -import times, nativesockets +import std/[times, nativesockets] when defined(windows): - import winlean + import std/winlean when defined(gcc): {.passl: "-lws2_32".} elif defined(vcc): diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 8c1f19fd3427..704d330c5db9 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -165,9 +165,9 @@ runnableExamples: a1, a2, a0, a3, a4: int doAssert $(%* Foo()) == """{"a1":0,"a2":0,"a0":0,"a3":0,"a4":0}""" -import hashes, tables, strutils, lexbase, streams, macros, parsejson +import std/[hashes, tables, strutils, lexbase, streams, macros, parsejson] -import options # xxx remove this dependency using same approach as https://github.com/nim-lang/Nim/pull/14563 +import std/options # xxx remove this dependency using same approach as https://github.com/nim-lang/Nim/pull/14563 import std/private/since when defined(nimPreviewSlimSystem): @@ -549,7 +549,7 @@ proc `[]`*[U, V](a: JsonNode, x: HSlice[U, V]): JsonNode = ## ## Returns the inclusive range `[a[x.a], a[x.b]]`: runnableExamples: - import json + import std/json let arr = %[0,1,2,3,4,5] doAssert arr[2..4] == %[2,3,4] doAssert arr[2..^2] == %[2,3,4] @@ -965,7 +965,7 @@ proc parseJson*(s: Stream, filename: string = ""; rawIntegers = false, rawFloats p.close() when defined(js): - from math import `mod` + from std/math import `mod` from std/jsffi import JsObject, `[]`, to from std/private/jsutils import getProtoName, isInteger, isSafeInteger @@ -1366,7 +1366,7 @@ proc to*[T](node: JsonNode, t: typedesc[T]): T = initFromJson(result, node, jsonPath) when false: - import os + import std/os var s = newFileStream(paramStr(1), fmRead) if s == nil: quit("cannot open the file" & paramStr(1)) var x: JsonParser diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim index 336a57ec11dc..1b6b2b3a2c64 100644 --- a/lib/pure/lexbase.nim +++ b/lib/pure/lexbase.nim @@ -12,7 +12,7 @@ ## needs refilling. import - strutils, streams + std/[strutils, streams] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 1767ee3f682e..e3f0240a292b 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -146,9 +146,9 @@ ## * `strscans module`_ for ``scanf`` and ``scanp`` macros, which ## offer easier substring extraction than regular expressions -import strutils, times +import std/[strutils, times] when not defined(js): - import os + import std/os when defined(nimPreviewSlimSystem): import std/syncio diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 7c092973f004..5785605c6de8 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -54,7 +54,7 @@ Please use alternative packages for serialization. It is possible to reimplement this module using generics and type traits. Please contribute a new implementation.""".} -import streams, typeinfo, json, intsets, tables, unicode +import std/[streams, typeinfo, json, intsets, tables, unicode] when defined(nimPreviewSlimSystem): import std/[assertions, formatfloat] diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 4bc720a465a3..00f42ec1d261 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -57,7 +57,7 @@ import std/private/since {.push debugger: off.} # the user does not want to trace a part # of the standard library! -import bitops, fenv +import std/[bitops, fenv] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index e27f9a79c3b3..df5b8c46ff1e 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -16,15 +16,15 @@ ## other "line-like", variable length, delimited records). when defined(windows): - import winlean + import std/winlean when defined(nimPreviewSlimSystem): import std/widestrs elif defined(posix): - import posix + import std/posix else: {.error: "the memfiles module is not supported on your operating system!".} -import streams +import std/streams import std/oserrors when defined(nimPreviewSlimSystem): diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index 346fb39eeddc..e7dd2f8f2b7a 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -26,8 +26,8 @@ runnableExamples: doAssert m.getMimetype("fakext") == "text/fakelang" doAssert m.getMimetype("FaKeXT") == "text/fakelang" -import tables -from strutils import startsWith, toLowerAscii, strip +import std/tables +from std/strutils import startsWith, toLowerAscii, strip when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index b3465ef14b17..6d6b3097a3a6 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -12,7 +12,7 @@ # TODO: Clean up the exports a bit and everything else in general. -import os, options +import std/[os, options] import std/private/since import std/strbasics @@ -27,12 +27,12 @@ const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr defined(nuttx) when useWinVersion: - import winlean + import std/winlean export WSAEWOULDBLOCK, WSAECONNRESET, WSAECONNABORTED, WSAENETRESET, WSANOTINITIALISED, WSAENOTSOCK, WSAEINPROGRESS, WSAEINTR, WSAEDISCON, ERROR_NETNAME_DELETED else: - import posix + import std/posix export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL, EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET, EBADF export Sockaddr_storage, Sockaddr_un, Sockaddr_un_path_length @@ -387,21 +387,37 @@ when not useNimNetLite: proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = ## This function will lookup the hostname of an IP Address. - var myaddr: InAddr - myaddr.s_addr = inet_addr(ip) + var + addrInfo = getAddrInfo(ip, Port(0), AF_UNSPEC) + myAddr: pointer + addrLen = 0 + family = 0 + + defer: freeAddrInfo(addrInfo) + + if addrInfo.ai_addr.sa_family.cint == nativeAfInet: + family = nativeAfInet + myAddr = addr cast[ptr Sockaddr_in](addrInfo.ai_addr).sin_addr + addrLen = 4 + elif addrInfo.ai_addr.sa_family.cint == nativeAfInet6: + family = nativeAfInet6 + myAddr = addr cast[ptr Sockaddr_in6](addrInfo.ai_addr).sin6_addr + addrLen = 16 + else: + raise newException(IOError, "Unknown socket family in `getHostByAddr()`") when useWinVersion: - var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint, - cint(AF_INET)) + var s = winlean.gethostbyaddr(cast[ptr InAddr](myAddr), addrLen.cuint, + cint(family)) if s == nil: raiseOSError(osLastError()) else: var s = when defined(android4): - posix.gethostbyaddr(cast[cstring](addr(myaddr)), sizeof(myaddr).cint, - cint(posix.AF_INET)) + posix.gethostbyaddr(cast[cstring](myAddr), addrLen.cint, + cint(family)) else: - posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).SockLen, - cint(posix.AF_INET)) + posix.gethostbyaddr(myAddr, addrLen.SockLen, + cint(family)) if s == nil: raiseOSError(osLastError(), $hstrerror(h_errno)) @@ -424,7 +440,20 @@ when not useNimNetLite: result.addrList.add($inet_ntoa(inaddrPtr[])) inc(i) else: - result.addrList = cstringArrayToSeq(s.h_addr_list) + let strAddrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN.int + else: 46 + var i = 0 + while not isNil(s.h_addr_list[i]): + var ipStr = newString(strAddrLen) + if inet_ntop(nativeAfInet6, cast[pointer](s.h_addr_list[i]), + cstring(ipStr), len(ipStr).int32) == nil: + raiseOSError(osLastError()) + when not useWinVersion: + if posix.IN6_IS_ADDR_V4MAPPED(cast[ptr In6Addr](s.h_addr_list[i])) != 0: + ipStr.setSlice("::ffff:".len..`_. diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 7ba156c89f94..1fd08e7636bb 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -52,7 +52,7 @@ import std/private/since import std/cmdline export cmdline -import strutils, pathnorm +import std/[strutils, pathnorm] when defined(nimPreviewSlimSystem): import std/[syncio, assertions, widestrs] @@ -76,9 +76,9 @@ since (1, 1): when weirdTarget: discard elif defined(windows): - import winlean, times + import std/[winlean, times] elif defined(posix): - import posix, times + import std/[posix, times] proc toTime(ts: Timespec): times.Time {.inline.} = result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index b8dd153f2402..9284e823af74 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -18,18 +18,18 @@ include "system/inclrtl" import - strutils, os, strtabs, streams, cpuinfo, streamwrapper, - std/private/since + std/[strutils, os, strtabs, streams, cpuinfo, streamwrapper, + private/since] export quoteShell, quoteShellWindows, quoteShellPosix when defined(windows): - import winlean + import std/winlean else: - import posix + import std/posix when defined(linux) and defined(useClone): - import linux + import std/linux when defined(nimPreviewSlimSystem): import std/[syncio, assertions] @@ -1231,7 +1231,7 @@ elif not defined(useNimRtl): when defined(macosx) or defined(freebsd) or defined(netbsd) or defined(openbsd) or defined(dragonfly): - import kqueue + import std/kqueue proc waitForExit(p: Process, timeout: int = -1): int = if p.exitFlag: @@ -1353,7 +1353,7 @@ elif not defined(useNimRtl): result = exitStatusLikeShell(p.exitStatus) else: - import times + import std/times const hasThreadSupport = compileOption("threads") and not defined(nimscript) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 3ba62ebd144b..ea9c18333665 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -170,7 +170,7 @@ runnableExamples: assert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False" assert dict.getSectionValue(section4, "purpose") == "formatting for readability" -import strutils, lexbase, streams, tables +import std/[strutils, lexbase, streams, tables] import std/private/decode_helpers import std/private/since diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index dcd486c089bd..c7bf0c9c118c 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -67,7 +67,7 @@ ## * `parsesql module `_ for a SQL parser ## * `other parsers `_ for other parsers -import lexbase, streams +import std/[lexbase, streams] when defined(nimPreviewSlimSystem): import std/syncio @@ -349,7 +349,7 @@ proc rowEntry*(self: var CsvParser, entry: string): var string = raise newException(KeyError, "Entry `" & entry & "` doesn't exist") when not defined(testing) and isMainModule: - import os + import std/os var s = newFileStream(paramStr(1), fmRead) if s == nil: quit("cannot open the file" & paramStr(1)) var x: CsvParser diff --git a/lib/pure/parsejson.nim b/lib/pure/parsejson.nim index fcbcf8e364fa..9292a859641b 100644 --- a/lib/pure/parsejson.nim +++ b/lib/pure/parsejson.nim @@ -11,7 +11,7 @@ ## and exported by the `json` standard library ## module, but can also be used in its own right. -import strutils, lexbase, streams, unicode +import std/[strutils, lexbase, streams, unicode] import std/private/decode_helpers when defined(nimPreviewSlimSystem): diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index 6674a7272a5c..24c903b584d5 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -176,7 +176,7 @@ include "system/inclrtl" -import os +import std/os type CmdLineKind* = enum ## The detected command line token. diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index 074faf64c01b..a7c938d0181a 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -12,7 +12,7 @@ ## ## Unstable API. -import strutils, lexbase +import std/[strutils, lexbase] import std/private/decode_helpers when defined(nimPreviewSlimSystem): @@ -1491,7 +1491,7 @@ proc treeRepr*(s: SqlNode): string = result = newStringOfCap(128) treeReprAux(s, 0, result) -import streams +import std/streams proc open(L: var SqlLexer, input: Stream, filename: string) = lexbase.open(L, input) diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index 88cb6d9c063d..c760799a20b9 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -41,7 +41,7 @@ document. # This program reads an HTML file and writes its title to stdout. # Errors and whitespace are ignored. - import os, streams, parsexml, strutils + import std/[os, streams, parsexml, strutils] if paramCount() < 1: quit("Usage: htmltitle filename[.html]") @@ -90,7 +90,7 @@ an HTML document contains. # This program reads an HTML file and writes all its used links to stdout. # Errors and whitespace are ignored. - import os, streams, parsexml, strutils + import std/[os, streams, parsexml, strutils] proc `=?=` (a, b: string): bool = # little trick: define our own comparator that ignores case @@ -147,7 +147,7 @@ an HTML document contains. ]## import - strutils, lexbase, streams, unicode + std/[strutils, lexbase, streams, unicode] when defined(nimPreviewSlimSystem): import std/[assertions, syncio] @@ -792,7 +792,7 @@ proc next*(my: var XmlParser) = my.state = stateNormal when not defined(testing) and isMainModule: - import os + import std/os var s = newFileStream(paramStr(1), fmRead) if s == nil: quit("cannot open the file" & paramStr(1)) var x: XmlParser diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 18e26027f589..d0c449bdd97f 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -22,11 +22,11 @@ when defined(nimPreviewSlimSystem): const useUnicode = true ## change this to deactivate proper UTF-8 support -import strutils, macros +import std/[strutils, macros] import std/private/decode_helpers when useUnicode: - import unicode + import std/unicode export unicode.`==` const diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 88616594b14a..74994437629a 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -71,7 +71,7 @@ runnableExamples: ## * `list of cryptographic and hashing modules `_ ## in the standard library -import algorithm, math +import std/[algorithm, math] import std/private/[since, jsutils] when defined(nimPreviewSlimSystem): @@ -670,7 +670,7 @@ when not defined(standalone): import std/[hashes, os, sysrand, monotimes] when compileOption("threads"): - import locks + import std/locks var baseSeedLock: Lock baseSeedLock.initLock diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim index aba0f4ce4bbf..ab05bcc252d9 100644 --- a/lib/pure/rationals.nim +++ b/lib/pure/rationals.nim @@ -21,7 +21,7 @@ runnableExamples: doAssert r1 * r2 == -3 // 8 doAssert r1 / r2 == -2 // 3 -import math, hashes +import std/[math, hashes] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/pure/reservedmem.nim b/lib/pure/reservedmem.nim index 528b0095c99c..ffa0128dc833 100644 --- a/lib/pure/reservedmem.nim +++ b/lib/pure/reservedmem.nim @@ -44,7 +44,7 @@ type mem: ReservedMem when defined(windows): - import winlean + import std/winlean import std/private/win_getsysteminfo proc getAllocationGranularity: uint = @@ -68,7 +68,7 @@ when defined(windows): raiseOSError(osLastError()) else: - import posix + import std/posix let allocationGranularity = sysconf(SC_PAGESIZE) diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index b973fd2226c4..8750aca874f6 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -17,7 +17,7 @@ ## runtime efficiency. include system/inclrtl -import streams +import std/streams when defined(nimPreviewSlimSystem): import std/[syncio, formatfloat, assertions] diff --git a/lib/pure/segfaults.nim b/lib/pure/segfaults.nim index b0eac229939e..65b059e86d81 100644 --- a/lib/pure/segfaults.nim +++ b/lib/pure/segfaults.nim @@ -26,7 +26,7 @@ se.msg = "Could not access value because it is nil." when defined(windows): include "../system/ansi_c" - import winlean + import std/winlean const EXCEPTION_ACCESS_VIOLATION = DWORD(0xc0000005'i32) @@ -65,7 +65,7 @@ when defined(windows): c_signal(SIGSEGV, segfaultHandler) else: - import posix + import std/posix var sa: Sigaction diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 1b4ae992de14..ac180e2bdaea 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -27,7 +27,7 @@ ## ## TODO: `/dev/poll`, `event ports` and filesystem events. -import nativesockets +import std/nativesockets import std/oserrors when defined(nimPreviewSlimSystem): @@ -235,9 +235,9 @@ when defined(nimdoc): ## For *poll* and *select* selectors `-1` is returned. else: - import strutils + import std/strutils when hasThreadSupport: - import locks + import std/locks type SharedArray[T] = UncheckedArray[T] @@ -288,7 +288,7 @@ else: setBlocking(fd.SocketHandle, false) when not defined(windows): - import posix + import std/posix template setKey(s, pident, pevents, pparam, pdata: untyped) = var skey = addr(s.fds[pident]) diff --git a/lib/pure/ssl_certs.nim b/lib/pure/ssl_certs.nim index dd09848beb3b..d60cd22eb676 100644 --- a/lib/pure/ssl_certs.nim +++ b/lib/pure/ssl_certs.nim @@ -10,7 +10,7 @@ ## The default locations can be overridden using the SSL_CERT_FILE and ## SSL_CERT_DIR environment variables. -import os, strutils +import std/[os, strutils] # FWIW look for files before scanning entire dirs. @@ -150,7 +150,7 @@ iterator scanSSLCertificates*(useEnvVars = false): string = # Certificates management on windows # when defined(windows) or defined(nimdoc): # -# import openssl +# import std/openssl # # type # PCCertContext {.final, pure.} = pointer diff --git a/lib/pure/stats.nim b/lib/pure/stats.nim index 7f797529d52f..6a4fd8f0135c 100644 --- a/lib/pure/stats.nim +++ b/lib/pure/stats.nim @@ -53,7 +53,7 @@ runnableExamples: doAssert statistics.kurtosis() ~= -1.0 doAssert statistics.kurtosisS() ~= -0.7000000000000008 -from math import FloatClass, sqrt, pow, round +from std/math import FloatClass, sqrt, pow, round when defined(nimPreviewSlimSystem): import std/[assertions, formatfloat] diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index d3aeacee55ca..8ae7fb3c1d44 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1482,7 +1482,7 @@ when false: # do not import windows as this increases compile times: discard else: - import posix + import std/posix proc hsSetPosition(s: FileHandleStream, pos: int) = discard lseek(s.handle, pos, SEEK_SET) diff --git a/lib/pure/streamwrapper.nim b/lib/pure/streamwrapper.nim index 9f5c0f28ae09..99752a9ab022 100644 --- a/lib/pure/streamwrapper.nim +++ b/lib/pure/streamwrapper.nim @@ -11,7 +11,7 @@ ## ## **Since** version 1.2. -import deques, streams +import std/[deques, streams] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 2668ad66ca8c..930993169bb9 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -316,8 +316,8 @@ help with readability, since there is only so much you can cram into single letter DSLs. ]## -import macros, parseutils, unicode -import strutils except format +import std/[macros, parseutils, unicode] +import std/strutils except format when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 0b23abc28bf5..cf3f3116bf08 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -283,7 +283,7 @@ efficiency and perform different checks. ]## -import macros, parseutils +import std/[macros, parseutils] import std/private/since when defined(nimPreviewSlimSystem): diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 11d5015cbb40..4b07aca5a36c 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -51,7 +51,7 @@ runnableExamples: import std/private/since import - hashes, strutils + std/[hashes, strutils] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 5e41705a724a..6d79259412bc 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -70,12 +70,12 @@ runnableExamples: ## easier substring extraction than regular expressions -import parseutils -from math import pow, floor, log10 -from algorithm import fill, reverse +import std/parseutils +from std/math import pow, floor, log10 +from std/algorithm import fill, reverse import std/enumutils -from unicode import toLower, toUpper +from std/unicode import toLower, toUpper export toLower, toUpper include "system/inclrtl" diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index d8e00d1f850e..cfa04a837620 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -11,7 +11,7 @@ ## macro system. import std/private/since -import macros +import std/macros proc checkPragma(ex, prag: var NimNode) = since (1, 3): diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index da95ac32ae30..53b3d61da26e 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -58,13 +58,13 @@ runnableExamples("-r:off"): stdout.styledWriteLine(fgRed, "red text ", styleBright, "bold red", fgDefault, " bold text") -import macros -import strformat -from strutils import toLowerAscii, `%`, parseInt -import colors +import std/macros +import std/strformat +from std/strutils import toLowerAscii, `%`, parseInt +import std/colors when defined(windows): - import winlean + import std/winlean when defined(nimPreviewSlimSystem): import std/[syncio, assertions] @@ -100,7 +100,7 @@ const stylePrefix = "\e[" when defined(windows): - import winlean, os + import std/[winlean, os] const DUPLICATE_SAME_ACCESS = 2 @@ -257,7 +257,7 @@ when defined(windows): if f == stderr: term.hStderr else: term.hStdout else: - import termios, posix, os, parseutils + import std/[termios, posix, os, parseutils] proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) = var mode: Termios @@ -922,7 +922,7 @@ when defined(windows): stdout.write "\n" else: - import termios + import std/termios proc readPasswordFromStdin*(prompt: string, password: var string): bool {.tags: [ReadIOEffect, WriteIOEffect].} = @@ -978,7 +978,7 @@ proc isTrueColorSupported*(): bool = return getTerminal().trueColorIsSupported when defined(windows): - import os + import std/os proc enableTrueColors*() = ## Enables true color. diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 05a123055fd5..a8e24313ff0b 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -203,7 +203,7 @@ * `monotimes module `_ ]## -import strutils, math, options +import std/[strutils, math, options] import std/private/since include "system/inclrtl" @@ -213,7 +213,7 @@ when defined(nimPreviewSlimSystem): when defined(js): - import jscore + import std/jscore # This is really bad, but overflow checks are broken badly for # ints on the JS backend. See #6752. @@ -237,7 +237,7 @@ when defined(js): {.pop.} elif defined(posix): - import posix + import std/posix type CTime = posix.Time @@ -246,7 +246,7 @@ elif defined(posix): {.importc: "gettimeofday", header: "", sideEffect.} elif defined(windows): - import winlean, std/time_t + import std/winlean, std/time_t type CTime = time_t.Time diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 384c2dbac94a..7c58d1ddc389 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -204,7 +204,7 @@ since (1, 3, 5): typeof(block: (for ai in a: ai)) -import macros +import std/macros macro enumLen*(T: typedesc[enum]): int = ## Returns the number of items in the enum `T`. diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index a6b01d64473c..2f3437ac7cee 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -111,15 +111,15 @@ import std/exitprocs when defined(nimPreviewSlimSystem): import std/assertions -import macros, strutils, streams, times, sets, sequtils +import std/[macros, strutils, streams, times, sets, sequtils] when declared(stdout): - import os + import std/os const useTerminal = not defined(js) when useTerminal: - import terminal + import std/terminal type TestStatus* = enum ## The status of a test when it is done. diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim index 6785fa66ec93..2c1e4e37ca01 100644 --- a/lib/pure/xmlparser.nim +++ b/lib/pure/xmlparser.nim @@ -9,7 +9,7 @@ ## This module parses an XML document and creates its XML tree representation. -import streams, parsexml, strtabs, xmltree +import std/[streams, parsexml, strtabs, xmltree] when defined(nimPreviewSlimSystem): import std/syncio @@ -151,7 +151,7 @@ proc loadXml*(path: string, options: set[XmlParseOption] = {reportComments}): Xm when isMainModule: when not defined(testing): - import os + import std/os var errors: seq[string] = @[] var x = loadXml(paramStr(1), errors) diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index e4cd407e2953..5c0cbc5e4368 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -31,7 +31,7 @@ runnableExamples: ## * `htmlgen module `_ for html code generator import std/private/since -import macros, strtabs, strutils, sequtils +import std/[macros, strtabs, strutils, sequtils] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/std/cmdline.nim b/lib/std/cmdline.nim index e545ac599d52..29c357d9d0d7 100644 --- a/lib/std/cmdline.nim +++ b/lib/std/cmdline.nim @@ -30,9 +30,9 @@ const weirdTarget = defined(nimscript) or defined(js) when weirdTarget: discard elif defined(windows): - import winlean + import std/winlean elif defined(posix): - import posix + import std/posix else: {.error: "The cmdline module has not been implemented for the target platform.".} diff --git a/lib/std/decls.nim b/lib/std/decls.nim index 3f774cd08dd2..bb7ec359310a 100644 --- a/lib/std/decls.nim +++ b/lib/std/decls.nim @@ -1,6 +1,6 @@ ## This module implements syntax sugar for some declarations. -import macros +import std/macros macro byaddr*(sect) = ## Allows a syntax for l-value references, being an exact analog to diff --git a/lib/std/dirs.nim b/lib/std/dirs.nim index 0b0366d441e6..380d6d08f809 100644 --- a/lib/std/dirs.nim +++ b/lib/std/dirs.nim @@ -1,6 +1,6 @@ ## This module implements directory handling. -from paths import Path, ReadDirEffect, WriteDirEffect +from std/paths import Path, ReadDirEffect, WriteDirEffect from std/private/osdirs import dirExists, createDir, existsOrCreateDir, removeDir, moveDir, walkDir, setCurrentDir, diff --git a/lib/std/editdistance.nim b/lib/std/editdistance.nim index 9f29c5c05f7b..6a25ca4b94e0 100644 --- a/lib/std/editdistance.nim +++ b/lib/std/editdistance.nim @@ -10,7 +10,7 @@ ## This module implements an algorithm to compute the ## `edit distance`:idx: between two Unicode strings. -import unicode +import std/unicode proc editDistance*(a, b: string): int {.noSideEffect.} = ## Returns the **unicode-rune** edit distance between `a` and `b`. diff --git a/lib/std/effecttraits.nim b/lib/std/effecttraits.nim index fb057a669640..3d1b4ffd320d 100644 --- a/lib/std/effecttraits.nim +++ b/lib/std/effecttraits.nim @@ -14,7 +14,7 @@ ## One can test for the existence of this standard module ## via `defined(nimHasEffectTraitsModule)`. -import macros +import std/macros proc getRaisesListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim" proc getTagsListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim" diff --git a/lib/std/enumerate.nim b/lib/std/enumerate.nim index 4f0161b7c75c..beb65ed30e23 100644 --- a/lib/std/enumerate.nim +++ b/lib/std/enumerate.nim @@ -11,7 +11,7 @@ ## macro system. import std/private/since -import macros +import std/macros macro enumerate*(x: ForLoopStmt): untyped {.since: (1, 3).} = diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index 1ce82eccf21b..bcfb2d5d7b73 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -7,8 +7,8 @@ # distribution, for details about the copyright. # -import macros -from typetraits import OrdinalEnum, HoleyEnum +import std/macros +from std/typetraits import OrdinalEnum, HoleyEnum when defined(nimPreviewSlimSystem): import std/assertions @@ -82,7 +82,7 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, result.add nnkElse.newTree(default) macro enumFullRange(a: typed): untyped = - newNimNode(nnkCurly).add(a.getType[1][1..^1]) + newNimNode(nnkBracket).add(a.getType[1][1..^1]) macro enumNames(a: typed): untyped = # this could be exported too; in particular this could be useful for enum with holes. diff --git a/lib/std/envvars.nim b/lib/std/envvars.nim index ab5c9f06ed55..a955077ea91c 100644 --- a/lib/std/envvars.nim +++ b/lib/std/envvars.nim @@ -60,7 +60,7 @@ when not defined(nimscript): when defined(windows): proc c_putenv(envstring: cstring): cint {.importc: "_putenv", header: "".} from std/private/win_setenv import setEnvImpl - import winlean + import std/winlean when defined(nimPreviewSlimSystem): import std/widestrs diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim index e42397c4cf7c..52e9653df4f5 100644 --- a/lib/std/exitprocs.nim +++ b/lib/std/exitprocs.nim @@ -9,7 +9,7 @@ ## This module allows adding hooks to program exit. -import locks +import std/locks when defined(js) and not defined(nodejs): import std/assertions diff --git a/lib/std/files.nim b/lib/std/files.nim index b61b7dafdac0..c4e0491c9957 100644 --- a/lib/std/files.nim +++ b/lib/std/files.nim @@ -3,7 +3,7 @@ ## **See also:** ## * `paths module `_ for path manipulation -from paths import Path, ReadDirEffect, WriteDirEffect +from std/paths import Path, ReadDirEffect, WriteDirEffect from std/private/osfiles import fileExists, removeFile, moveFile diff --git a/lib/std/genasts.nim b/lib/std/genasts.nim index 04257533dbab..d0f07c527324 100644 --- a/lib/std/genasts.nim +++ b/lib/std/genasts.nim @@ -1,6 +1,6 @@ ## This module implements AST generation using captured variables for macros. -import macros +import std/macros type GenAstOpt* = enum kDirtyTemplate, diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index b1025d24b308..2d28748ce88b 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -16,7 +16,7 @@ runnableExamples: assert 0.0.toJson.kind == JFloat assert Inf.toJson.kind == JString -import json, strutils, tables, sets, strtabs, options, strformat +import std/[json, strutils, tables, sets, strtabs, options, strformat] #[ Future directions: @@ -30,9 +30,9 @@ add a way to customize serialization, for e.g.: objects. ]# -import macros -from enumutils import symbolName -from typetraits import OrdinalEnum, tupleLen +import std/macros +from std/enumutils import symbolName +from std/typetraits import OrdinalEnum, tupleLen when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim index 5c67a5d4c4bd..bf6dc776b9b1 100644 --- a/lib/std/monotimes.nim +++ b/lib/std/monotimes.nim @@ -36,7 +36,7 @@ See also * `times module `_ ]## -import times +import std/times type MonoTime* = object ## Represents a monotonic timestamp. @@ -74,7 +74,7 @@ when defined(js): {.pop.} elif defined(posix) and not defined(osx): - import posix + import std/posix when defined(zephyr): proc k_uptime_ticks(): int64 {.importc: "k_uptime_ticks", header: "".} diff --git a/lib/std/oserrors.nim b/lib/std/oserrors.nim index a641a7f47f85..7b11c5e8e413 100644 --- a/lib/std/oserrors.nim +++ b/lib/std/oserrors.nim @@ -15,7 +15,7 @@ type when not defined(nimscript): when defined(windows): - import winlean + import std/winlean when defined(nimPreviewSlimSystem): import std/widestrs else: diff --git a/lib/std/outparams.nim b/lib/std/outparams.nim index 8a0e5ae67735..a471fbaa72c2 100644 --- a/lib/std/outparams.nim +++ b/lib/std/outparams.nim @@ -9,7 +9,7 @@ ## `outParamsAt` macro for easy writing code that works with both 2.0 and 1.x. -import macros +import std/macros macro outParamsAt*(positions: static openArray[int]; n: untyped): untyped = ## Use this macro to annotate `out` parameters in a portable way. diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index c6d007c26198..3320558f2aaa 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -17,7 +17,7 @@ ## * `sets module `_ for more general hash sets import std/private/since -import hashes +import std/hashes when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/std/paths.nim b/lib/std/paths.nim index f675e7445a4d..b488d2feadf9 100644 --- a/lib/std/paths.nim +++ b/lib/std/paths.nim @@ -9,7 +9,7 @@ export osseps import std/envvars import std/private/osappdirs -import pathnorm +import std/pathnorm from std/private/ospaths2 import joinPath, splitPath, ReadDirEffect, WriteDirEffect, diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim index 64065aac8136..a6d088558273 100644 --- a/lib/std/private/globs.nim +++ b/lib/std/private/globs.nim @@ -4,9 +4,9 @@ this can eventually be moved to std/os and `walkDirRec` can be implemented in te to avoid duplication ]## -import os +import std/os when defined(windows): - from strutils import replace + from std/strutils import replace when defined(nimPreviewSlimSystem): import std/[assertions, objectdollar] @@ -65,6 +65,6 @@ proc nativeToUnixPath*(path: string): string = result = replace(result, '\\', '/') when isMainModule: - import sugar + import std/sugar for a in walkDirRecFilter(".", follow = a=>a.path.lastPathPart notin ["nimcache", ".git", "csources_v1", "csources", "bin"]): echo a diff --git a/lib/std/private/oscommon.nim b/lib/std/private/oscommon.nim index c24db3f671e1..c49d52ef291c 100644 --- a/lib/std/private/oscommon.nim +++ b/lib/std/private/oscommon.nim @@ -22,9 +22,9 @@ type when weirdTarget: discard elif defined(windows): - import winlean, times + import std/[winlean, times] elif defined(posix): - import posix + import std/posix proc c_rename(oldname, newname: cstring): cint {. importc: "rename", header: "".} else: diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim index a4318367d843..b89a59c8dd43 100644 --- a/lib/std/private/osdirs.nim +++ b/lib/std/private/osdirs.nim @@ -16,9 +16,9 @@ when defined(nimPreviewSlimSystem): when weirdTarget: discard elif defined(windows): - import winlean, times + import std/[winlean, times] elif defined(posix): - import posix, times + import std/[posix, times] else: {.error: "OS module not ported to your operating system!".} diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim index 948df4211fbe..a1d7079c5a6a 100644 --- a/lib/std/private/osfiles.nim +++ b/lib/std/private/osfiles.nim @@ -15,9 +15,9 @@ when defined(nimPreviewSlimSystem): when weirdTarget: discard elif defined(windows): - import winlean + import std/winlean elif defined(posix): - import posix, times + import std/[posix, times] proc toTime(ts: Timespec): times.Time {.inline.} = result = initTime(ts.tv_sec.int64, ts.tv_nsec.int) diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim index 421def62b399..37fae3ccd018 100644 --- a/lib/std/private/ospaths2.nim +++ b/lib/std/private/ospaths2.nim @@ -1,7 +1,7 @@ include system/inclrtl import std/private/since -import strutils, pathnorm +import std/[strutils, pathnorm] import std/oserrors import oscommon @@ -17,9 +17,9 @@ const weirdTarget = defined(nimscript) or defined(js) when weirdTarget: discard elif defined(windows): - import winlean + import std/winlean elif defined(posix): - import posix, system/ansi_c + import std/posix, system/ansi_c else: {.error: "OS module not ported to your operating system!".} diff --git a/lib/std/private/ossymlinks.nim b/lib/std/private/ossymlinks.nim index 18737b8b537c..c0774b5735c1 100644 --- a/lib/std/private/ossymlinks.nim +++ b/lib/std/private/ossymlinks.nim @@ -10,9 +10,9 @@ when defined(nimPreviewSlimSystem): when weirdTarget: discard elif defined(windows): - import winlean, times + import std/[winlean, times] elif defined(posix): - import posix + import std/posix else: {.error: "OS module not ported to your operating system!".} diff --git a/lib/std/private/underscored_calls.nim b/lib/std/private/underscored_calls.nim index 8b03926417db..f853572b5103 100644 --- a/lib/std/private/underscored_calls.nim +++ b/lib/std/private/underscored_calls.nim @@ -10,7 +10,7 @@ ## This is an internal helper module. Do not use. -import macros +import std/macros proc underscoredCalls*(result, calls, arg0: NimNode) diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim index 4664d6dcc774..8e7bc6a92d30 100644 --- a/lib/std/setutils.nim +++ b/lib/std/setutils.nim @@ -14,7 +14,7 @@ ## * `std/packedsets `_ ## * `std/sets `_ -import typetraits, macros +import std/[typetraits, macros] #[ type SetElement* = char|byte|bool|int16|uint16|enum|uint8|int8 diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index a1a8c4782397..213af42296f2 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -29,8 +29,8 @@ runnableExamples("-r:off"): {.deprecated: "use command `nimble install checksums` and import `checksums/sha1` instead".} -import strutils -from endians import bigEndian32, bigEndian64 +import std/strutils +from std/endians import bigEndian32, bigEndian64 when defined(nimPreviewSlimSystem): import std/syncio diff --git a/lib/std/socketstreams.nim b/lib/std/socketstreams.nim index 41d46e58ae7e..45e906795328 100644 --- a/lib/std/socketstreams.nim +++ b/lib/std/socketstreams.nim @@ -64,7 +64,7 @@ ## sendStream.write "I" # Throws an error as we can't write into an already sent buffer ## ``` -import net, streams +import std/[net, streams] type ReadSocketStream* = ref ReadSocketStreamObj diff --git a/lib/std/symlinks.nim b/lib/std/symlinks.nim index 60487740caa6..dbe908612178 100644 --- a/lib/std/symlinks.nim +++ b/lib/std/symlinks.nim @@ -2,7 +2,7 @@ ## .. importdoc:: os.nim -from paths import Path, ReadDirEffect +from std/paths import Path, ReadDirEffect from std/private/ossymlinks import symlinkExists, createSymlink, expandSymlink diff --git a/lib/std/syncio.nim b/lib/std/syncio.nim index 498b2b5a446d..b664c3b609ca 100644 --- a/lib/std/syncio.nim +++ b/lib/std/syncio.nim @@ -151,14 +151,11 @@ proc c_fprintf(f: File, frmt: cstring): cint {. proc c_fputc(c: char, f: File): cint {. importc: "fputc", header: "".} -template sysFatal(exc, msg) = - raise newException(exc, msg) - proc raiseEIO(msg: string) {.noinline, noreturn.} = - sysFatal(IOError, msg) + raise newException(IOError, msg) proc raiseEOF() {.noinline, noreturn.} = - sysFatal(EOFError, "EOF reached") + raise newException(EOFError, "EOF reached") proc strerror(errnum: cint): cstring {.importc, header: "".} @@ -764,7 +761,7 @@ proc open*(filename: string, ## ## The file handle associated with the resulting `File` is not inheritable. if not open(result, filename, mode, bufSize): - sysFatal(IOError, "cannot open: " & filename) + raise newException(IOError, "cannot open: " & filename) proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign.} = ## Sets the position of the file pointer that is used for read/write @@ -852,7 +849,7 @@ proc readFile*(filename: string): string {.tags: [ReadIOEffect], benign.} = finally: close(f) else: - sysFatal(IOError, "cannot open: " & filename) + raise newException(IOError, "cannot open: " & filename) proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} = ## Opens a file named `filename` for writing. Then writes the @@ -865,7 +862,7 @@ proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} = finally: close(f) else: - sysFatal(IOError, "cannot open: " & filename) + raise newException(IOError, "cannot open: " & filename) proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} = ## Opens a file named `filename` for writing. Then writes the @@ -895,7 +892,7 @@ proc readLines*(filename: string, n: Natural): seq[string] = finally: close(f) else: - sysFatal(IOError, "cannot open: " & filename) + raise newException(IOError, "cannot open: " & filename) template readLines*(filename: string): seq[ string] {.deprecated: "use readLines with two arguments".} = diff --git a/lib/std/sysatomics.nim b/lib/std/sysatomics.nim index d2f7f59eb58c..2f203b3eb77d 100644 --- a/lib/std/sysatomics.nim +++ b/lib/std/sysatomics.nim @@ -363,7 +363,7 @@ elif someGcc or defined(tcc): elif defined(icl): proc cpuRelax* {.importc: "_mm_pause", header: "xmmintrin.h".} elif false: - from os import sleep + from std/os import sleep proc cpuRelax* {.inline.} = os.sleep(1) diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index 8526336ad32a..6f2c6b0c1600 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -60,7 +60,7 @@ when not defined(js): import std/oserrors when defined(posix): - import posix + import std/posix when defined(nimPreviewSlimSystem): import std/assertions diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim index 1160aaaad54e..539305bde32a 100644 --- a/lib/std/tempfiles.nim +++ b/lib/std/tempfiles.nim @@ -17,7 +17,7 @@ See also: * `mkstemp` (posix), refs https://man7.org/linux/man-pages/man3/mkstemp.3.html ]# -import os, random +import std / [os, random] when defined(nimPreviewSlimSystem): import std/syncio @@ -29,7 +29,7 @@ const when defined(windows): - import winlean + import std/winlean when defined(nimPreviewSlimSystem): import std/widestrs @@ -46,7 +46,7 @@ when defined(windows): proc close_osfandle(fd: cint): cint {. importc: "_close", header: "".} else: - import posix + import std/posix proc c_fdopen( filehandle: cint, diff --git a/lib/std/time_t.nim b/lib/std/time_t.nim index 7fb6e6d468cb..5fa95fff388a 100644 --- a/lib/std/time_t.nim +++ b/lib/std/time_t.nim @@ -19,5 +19,5 @@ elif defined(windows): # newest version of Visual C++ defines time_t to be of 64 bits type Time* {.importc: "time_t", header: "".} = distinct int64 elif defined(posix): - import posix + import std/posix export posix.Time \ No newline at end of file diff --git a/lib/std/with.nim b/lib/std/with.nim index 8043a0b8af25..c2eaa4befcd4 100644 --- a/lib/std/with.nim +++ b/lib/std/with.nim @@ -14,7 +14,7 @@ ## ## **Since:** version 1.2. -import macros, private / underscored_calls +import std/[macros, private / underscored_calls] macro with*(arg: typed; calls: varargs[untyped]): untyped = ## This macro provides `chaining`:idx: of function calls. diff --git a/lib/std/wordwrap.nim b/lib/std/wordwrap.nim index 7dcfc7f59919..9333f880be91 100644 --- a/lib/std/wordwrap.nim +++ b/lib/std/wordwrap.nim @@ -9,7 +9,7 @@ ## This module contains an algorithm to wordwrap a Unicode string. -import strutils, unicode +import std/[strutils, unicode] proc olen(s: string; start, lastExclusive: int): int = var i = start diff --git a/lib/std/wrapnils.nim b/lib/std/wrapnils.nim index 235638134c60..0b75c270e9b0 100644 --- a/lib/std/wrapnils.nim +++ b/lib/std/wrapnils.nim @@ -13,7 +13,7 @@ consider handling indexing operations, eg: doAssert ?.default(seq[int])[3] == default(int) ]# -import macros +import std/macros runnableExamples: type Foo = ref object @@ -122,7 +122,7 @@ macro `?.`*(a: typed): auto = `lhs` # the code below is not needed for `?.` -from options import Option, isSome, get, option, unsafeGet, UnpackDefect +from std/options import Option, isSome, get, option, unsafeGet, UnpackDefect macro `??.`*(a: typed): Option = ## Same as `?.` but returns an `Option`. diff --git a/lib/system.nim b/lib/system.nim index 8d1cda86815e..4f2a051632d3 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1981,15 +1981,11 @@ when defined(nimAuditDelete): else: {.pragma: auditDelete.} -proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect, auditDelete.} = +proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect, systemRaisesDefect, auditDelete.} = ## Deletes the item at index `i` by moving all `x[i+1..^1]` items by one position. ## ## This is an `O(n)` operation. ## - ## .. note:: With `-d:nimStrictDelete`, an index error is produced when the index passed - ## to it was out of bounds. `-d:nimStrictDelete` will become the default - ## in upcoming versions. - ## ## See also: ## * `del <#del,seq[T],Natural>`_ for O(1) operation ## @@ -1998,7 +1994,7 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect, auditDelete.} = s.delete(2) doAssert s == @[1, 2, 4, 5] - when defined(nimStrictDelete): + when not defined(nimAuditDelete): if i > high(x): # xxx this should call `raiseIndexError2(i, high(x))` after some refactoring raise (ref IndexDefect)(msg: "index out of bounds: '" & $i & "' < '" & $x.len & "' failed") @@ -2836,7 +2832,7 @@ when notJSnotNims: hostOS != "any" proc raiseEIO(msg: string) {.noinline, noreturn.} = - sysFatal(IOError, msg) + raise newException(IOError, msg) proc echoBinSafe(args: openArray[string]) {.compilerproc.} = when defined(androidNDK): diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index be931ed14341..1c8a79fd87ea 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -65,7 +65,7 @@ elif defined(macosx) or defined(linux) or defined(freebsd) or SIGSEGV* = cint(11) SIGTERM* = cint(15) SIGPIPE* = cint(13) - SIG_DFL* = cast[CSighandlerT](0) + SIG_DFL* = CSighandlerT(nil) elif defined(haiku): const SIGABRT* = cint(6) @@ -75,7 +75,7 @@ elif defined(haiku): SIGSEGV* = cint(11) SIGTERM* = cint(15) SIGPIPE* = cint(7) - SIG_DFL* = cast[CSighandlerT](0) + SIG_DFL* = CSighandlerT(nil) else: when defined(nimscript): {.error: "SIGABRT not ported to your platform".} diff --git a/lib/system/channels_builtin.nim b/lib/system/channels_builtin.nim index 088003e4b2eb..02b4d8cbfd4e 100644 --- a/lib/system/channels_builtin.nim +++ b/lib/system/channels_builtin.nim @@ -394,7 +394,7 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) = q.ready = false if typ != q.elemType: releaseSys(q.lock) - sysFatal(ValueError, "cannot receive message of wrong type") + raise newException(ValueError, "cannot receive message of wrong type") rawRecv(q, res, typ) if q.maxItems > 0 and q.count == q.maxItems - 1: # Parent thread is awaiting in send. Wake it up. diff --git a/lib/system/fatal.nim b/lib/system/fatal.nim index f1f94d078236..25c05e52d9cc 100644 --- a/lib/system/fatal.nim +++ b/lib/system/fatal.nim @@ -16,19 +16,19 @@ const when hostOS == "standalone": include "$projectpath/panicoverride" - func sysFatal(exceptn: typedesc, message: string) {.inline.} = + func sysFatal(exceptn: typedesc[Defect], message: string) {.inline.} = panic(message) - func sysFatal(exceptn: typedesc, message, arg: string) {.inline.} = + func sysFatal(exceptn: typedesc[Defect], message, arg: string) {.inline.} = rawoutput(message) panic(arg) -elif (quirkyExceptions or defined(nimPanics)) and not defined(nimscript): +elif quirkyExceptions and not defined(nimscript): import ansi_c func name(t: typedesc): string {.magic: "TypeTrait".} - func sysFatal(exceptn: typedesc, message, arg: string) {.inline, noreturn.} = + func sysFatal(exceptn: typedesc[Defect], message, arg: string) {.inline, noreturn.} = when nimvm: # TODO when doAssertRaises works in CT, add a test for it raise (ref exceptn)(msg: message & arg) @@ -45,14 +45,14 @@ elif (quirkyExceptions or defined(nimPanics)) and not defined(nimscript): cstderr.rawWrite buf rawQuit 1 - func sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = + func sysFatal(exceptn: typedesc[Defect], message: string) {.inline, noreturn.} = sysFatal(exceptn, message, "") else: - func sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} = + func sysFatal(exceptn: typedesc[Defect], message: string) {.inline, noreturn.} = raise (ref exceptn)(msg: message) - func sysFatal(exceptn: typedesc, message, arg: string) {.inline, noreturn.} = + func sysFatal(exceptn: typedesc[Defect], message, arg: string) {.inline, noreturn.} = raise (ref exceptn)(msg: message & arg) {.pop.} diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 35ab2690355d..9289c7f55c0a 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -78,7 +78,7 @@ when defined(memProfiler): proc nimProfile(requestedSize: int) {.benign.} when hasThreadSupport: - import sharedlist + import std/sharedlist const rcIncrement = 0b1000 # so that lowest 3 bits are not touched diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 72d22f08b0a9..c885a6893ebe 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -27,7 +27,7 @@ when defined(memProfiler): proc nimProfile(requestedSize: int) when hasThreadSupport: - import sharedlist + import std/sharedlist type WalkOp = enum diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index d41199de6e2e..21ac3552508e 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -61,7 +61,10 @@ iterator items*[T](a: set[T]): T {.inline.} = ## able to hold). var i = low(T).int while i <= high(T).int: - if T(i) in a: yield T(i) + when T is enum and not defined(js): + if cast[T](i) in a: yield cast[T](i) + else: + if T(i) in a: yield T(i) unCheckedInc(i) iterator items*(a: cstring): char {.inline.} = diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index ee8f2d67eb5c..8b3e9ee88a95 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -8,7 +8,7 @@ # -# import typetraits +# import std/typetraits # strs already imported allocateds for us. @@ -178,7 +178,7 @@ proc newSeq[T](s: var seq[T], len: Natural) = shrink(s, 0) setLen(s, len) -proc sameSeqPayload(x: pointer, y: pointer): bool {.compilerproc, inline.} = +proc sameSeqPayload(x: pointer, y: pointer): bool {.compilerRtl, inl.} = result = cast[ptr NimRawSeq](x)[].p == cast[ptr NimRawSeq](y)[].p diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index 5e4cda186193..dbee107774c3 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -209,6 +209,9 @@ proc nimAddStrV1(s: var NimStringV2; src: NimStringV2) {.compilerRtl, inl.} = proc nimDestroyStrV1(s: NimStringV2) {.compilerRtl, inl.} = frees(s) +proc nimStrAtLe(s: string; idx: int; ch: char): bool {.compilerRtl, inl.} = + result = idx < s.len and s[idx] <= ch + func capacity*(self: string): int {.inline.} = ## Returns the current capacity of the string. # See https://github.com/nim-lang/RFCs/issues/460 diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index f8c6ce021683..79681376b227 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -10,7 +10,7 @@ ## This module implements a small wrapper for some needed Win API procedures, ## so that the Nim compiler does not depend on the huge Windows module. -import dynlib +import std/dynlib when defined(nimHasStyleChecks): {.push styleChecks: off.} diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index b94ddaa217e5..9921b7ffde29 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -28,7 +28,7 @@ # https://www.feistyduck.com/library/openssl-cookbook/online/ch-testing-with-openssl.html # -from strutils import startsWith +from std/strutils import startsWith when defined(nimPreviewSlimSystem): import std/syncio @@ -51,17 +51,17 @@ when sslVersion != "": const DLLSSLName* = "libssl." & sslVersion & ".dylib" DLLUtilName* = "libcrypto." & sslVersion & ".dylib" - from posix import SocketHandle + from std/posix import SocketHandle elif defined(windows): const DLLSSLName* = "libssl-" & sslVersion & ".dll" DLLUtilName* = "libcrypto-" & sslVersion & ".dll" - from winlean import SocketHandle + from std/winlean import SocketHandle else: const DLLSSLName* = "libssl.so." & sslVersion DLLUtilName* = "libcrypto.so." & sslVersion - from posix import SocketHandle + from std/posix import SocketHandle elif useWinVersion: when defined(openssl10) or defined(nimOldDlls): @@ -82,7 +82,7 @@ elif useWinVersion: DLLSSLName* = "(libssl-1_1|ssleay32|libssl32).dll" DLLUtilName* = "(libcrypto-1_1|libeay32).dll" - from winlean import SocketHandle + from std/winlean import SocketHandle else: # same list of versions but ordered differently? when defined(osx): @@ -102,9 +102,9 @@ else: const DLLSSLName* = "libssl.so" & versions DLLUtilName* = "libcrypto.so" & versions - from posix import SocketHandle + from std/posix import SocketHandle -import dynlib +import std/dynlib {.pragma: lcrypto, cdecl, dynlib: DLLUtilName, importc.} {.pragma: lssl, cdecl, dynlib: DLLSSLName, importc.} @@ -779,7 +779,7 @@ proc md5*(d: ptr uint8; n: csize_t; md: ptr uint8): ptr uint8{.importc: "MD5".} proc md5_Transform*(c: var MD5_CTX; b: ptr uint8){.importc: "MD5_Transform".} {.pop.} -from strutils import toHex, toLowerAscii +from std/strutils import toHex, toLowerAscii proc hexStr(buf: cstring): string = # turn md5s output into a nice hex str diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 28faf9e3c39e..3834acb93ca1 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -161,7 +161,7 @@ proc listEpc(): SexpNode = argspecs = sexp("file line column dirtyfile".split(" ").map(newSSymbol)) docstring = sexp("line starts at 1, column at 0, dirtyfile is optional") result = newSList() - for command in ["sug", "con", "def", "use", "dus", "chk", "mod", "globalSymbols", "recompile", "saved", "chkFile", "declaration"]: + for command in ["sug", "con", "def", "use", "dus", "chk", "mod", "globalSymbols", "recompile", "saved", "chkFile", "declaration", "inlayHints"]: let cmd = sexp(command) methodDesc = newSList() @@ -506,6 +506,7 @@ proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) = of "chkfile": conf.ideCmd = ideChkFile of "recompile": conf.ideCmd = ideRecompile of "type": conf.ideCmd = ideType + of "inlayhints": conf.ideCmd = ideInlayHints else: err() var dirtyfile = "" var orig = "" @@ -774,6 +775,18 @@ proc findSymData(graph: ModuleGraph, trackPos: TLineInfo): result[] = s break +func isInRange*(current, startPos, endPos: TLineInfo, tokenLen: int): bool = + result = current.fileIndex == startPos.fileIndex and + (current.line > startPos.line or (current.line == startPos.line and current.col>=startPos.col)) and + (current.line < endPos.line or (current.line == endPos.line and current.col <= endPos.col)) + +proc findSymDataInRange(graph: ModuleGraph, startPos, endPos: TLineInfo): + seq[SymInfoPair] = + result = newSeq[SymInfoPair]() + for s in graph.fileSymbols(startPos.fileIndex).deduplicateSymInfoPair: + if isInRange(s.info, startPos, endPos, s.sym.name.s.len): + result.add(s) + proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int): ref SymInfoPair = let @@ -781,6 +794,14 @@ proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int): trackPos = newLineInfo(fileIdx, line, col) result = findSymData(graph, trackPos) +proc findSymDataInRange(graph: ModuleGraph, file: AbsoluteFile; startLine, startCol, endLine, endCol: int): + seq[SymInfoPair] = + let + fileIdx = fileInfoIdx(graph.config, file) + startPos = newLineInfo(fileIdx, startLine, startCol) + endPos = newLineInfo(fileIdx, endLine, endCol) + result = findSymDataInRange(graph, startPos, endPos) + proc markDirtyIfNeeded(graph: ModuleGraph, file: string, originalFileIdx: FileIndex) = let sha = $sha1.secureHashFile(file) if graph.config.m.fileInfos[originalFileIdx.int32].hash != sha or graph.config.ideCmd == ideSug: @@ -803,6 +824,23 @@ proc suggestResult(graph: ModuleGraph, sym: PSym, info: TLineInfo, endLine = endLine, endCol = endCol) suggestResult(graph.config, suggest) +proc suggestInlayHintResult(graph: ModuleGraph, sym: PSym, info: TLineInfo, + defaultSection = ideNone, endLine: uint16 = 0, endCol = 0) = + let section = if defaultSection != ideNone: + defaultSection + elif sym.info.exactEquals(info): + ideDef + else: + ideUse + var suggestDef = symToSuggest(graph, sym, isLocal=false, section, + info, 100, PrefixMatch.None, false, 0, true, + endLine = endLine, endCol = endCol) + suggestDef.inlayHintInfo = suggestToSuggestInlayHint(suggestDef) + suggestDef.section = ideInlayHints + if sym.kind == skForVar: + suggestDef.inlayHintInfo.allowInsert = false + suggestResult(graph.config, suggestDef) + const # kinds for ideOutline and ideGlobalSymbols searchableSymKinds = {skField, skEnumField, skIterator, skMethod, skFunc, skProc, skConverter, skTemplate} @@ -910,7 +948,7 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile, graph.markDirtyIfNeeded(dirtyFile.string, fileInfoIdx(conf, file)) # these commands require fully compiled project - if cmd in {ideUse, ideDus, ideGlobalSymbols, ideChk} and graph.needsCompilation(): + if cmd in {ideUse, ideDus, ideGlobalSymbols, ideChk, ideInlayHints} and graph.needsCompilation(): graph.recompilePartially() # when doing incremental build for the project root we should make sure that # everything is unmarked as no longer beeing dirty in case there is no @@ -1066,6 +1104,19 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile, graph.markDirty fileIndex graph.markClientsDirty fileIndex + of ideInlayHints: + myLog fmt "Executing inlayHints" + var endLine = 0 + var endCol = -1 + var i = 0 + i += skipWhile(tag, seps, i) + i += parseInt(tag, endLine, i) + i += skipWhile(tag, seps, i) + i += parseInt(tag, endCol, i) + let s = graph.findSymDataInRange(file, line, col, endLine, endCol) + for q in s: + if q.sym.kind in {skLet, skVar, skForVar} and q.isDecl and not q.sym.hasUserSpecifiedType: + graph.suggestInlayHintResult(q.sym, q.info, ideInlayHints) else: myLog fmt "Discarding {cmd}" diff --git a/readme.md b/readme.md index 5ba63550c6d4..cbe902c5235c 100644 --- a/readme.md +++ b/readme.md @@ -35,9 +35,11 @@ the latest release, check out [Nim's website][nim-site] or [bleeding edge docs]( The compiler currently officially supports the following platform and architecture combinations: - * Windows (Windows XP or greater) - x86 and x86_64 - * Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l - * Mac OS X (10.04 or greater) - x86, x86_64, ppc64 and Apple Silicon (based on the ARM64 architecture) +| Operating System | Architectures Supported | +|--------------------------------|----------------------------------------| +| Windows (Windows XP or greater) | x86 and x86_64 | +| Linux (most distributions) | x86, x86_64, ppc64, and armv6l | +| Mac OS X (10.04 or greater) | x86, x86_64, ppc64, and Apple Silicon (ARM64) | More platforms are supported, however, they are not tested regularly and they may not be as stable as the above-listed platforms. diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 525c8c3a64d7..3b60fcd02023 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -635,3 +635,56 @@ block: # bug #22664 calc2.stack = calc.stack # This nulls out the object in the stack doAssert $calc.stack == "@[(kind: Number, num: 200.0)]" doAssert $calc2.stack == "@[(kind: Number, num: 200.0)]" + +block: # bug #19250 + type + Bar[T] = object + err: proc(): string + + Foo[T] = object + run: proc(): Bar[T] + + proc bar[T](err: proc(): string): Bar[T] = + assert not err.isNil + Bar[T](err: err) + + proc foo(): Foo[char] = + result.run = proc(): Bar[char] = + # works + # result = Bar[char](err: proc(): string = "x") + # not work + result = bar[char](proc(): string = "x") + + proc bug[T](fs: Foo[T]): Foo[T] = + result.run = proc(): Bar[T] = + let res = fs.run() + + # works + # var errors = @[res.err] + + # not work + var errors: seq[proc(): string] + errors.add res.err + + return bar[T] do () -> string: + for err in errors: + result.add res.err() + + doAssert bug(foo()).run().err() == "x" + +block: # bug #22259 + type + ProcWrapper = tuple + p: proc() {.closure.} + + + proc f(wrapper: ProcWrapper) = + let s = @[wrapper.p] + let a = [wrapper.p] + + proc main = + # let wrapper: ProcWrapper = ProcWrapper(p: proc {.closure.} = echo 10) + let wrapper: ProcWrapper = (p: proc {.closure.} = echo 10) + f(wrapper) + + main() diff --git a/tests/arc/tcomputedgoto.nim b/tests/arc/tcomputedgoto.nim index 541a748c62bb..07487684a643 100644 --- a/tests/arc/tcomputedgoto.nim +++ b/tests/arc/tcomputedgoto.nim @@ -1,16 +1,19 @@ discard """ - cmd: '''nim c --gc:arc $file''' - output: '''2 -2''' + cmd: '''nim c --mm:arc $file''' + output: ''' +2 +2 +destroyed +''' """ type ObjWithDestructor = object a: int -proc `=destroy`(self: var ObjWithDestructor) = +proc `=destroy`(self: ObjWithDestructor) = echo "destroyed" -proc `=`(self: var ObjWithDestructor, other: ObjWithDestructor) = +proc `=copy`(self: var ObjWithDestructor, other: ObjWithDestructor) = echo "copied" proc test(a: range[0..1], arg: ObjWithDestructor) = @@ -38,4 +41,4 @@ proc test(a: range[0..1], arg: ObjWithDestructor) = if iteration == 2: break -test(1, ObjWithDestructor()) \ No newline at end of file +test(1, ObjWithDestructor()) diff --git a/tests/arc/tcomputedgotocopy.nim b/tests/arc/tcomputedgotocopy.nim index 8337123ba072..07487684a643 100644 --- a/tests/arc/tcomputedgotocopy.nim +++ b/tests/arc/tcomputedgotocopy.nim @@ -1,13 +1,16 @@ discard """ - cmd: '''nim c --gc:arc $file''' - output: '''2 -2''' + cmd: '''nim c --mm:arc $file''' + output: ''' +2 +2 +destroyed +''' """ type ObjWithDestructor = object a: int -proc `=destroy`(self: var ObjWithDestructor) = +proc `=destroy`(self: ObjWithDestructor) = echo "destroyed" proc `=copy`(self: var ObjWithDestructor, other: ObjWithDestructor) = diff --git a/tests/cpp/tvirtual.nim b/tests/cpp/tvirtual.nim index fb792380b309..385d052b8fe8 100644 --- a/tests/cpp/tvirtual.nim +++ b/tests/cpp/tvirtual.nim @@ -115,4 +115,12 @@ proc test(self: Child): Box[Inner] {.virtual, asmnostackframe.} = {.emit:"return res;".} -discard Child().test() \ No newline at end of file +discard Child().test() + +import virtualptr + +#We dont want to pull Loo directly by using it as we are testing that the pointer pulls it. +proc makeMoo(): Moo {.importcpp:"{ new Loo() }".} + +makeMoo().loo.salute() + diff --git a/tests/cpp/virtualptr.nim b/tests/cpp/virtualptr.nim new file mode 100644 index 000000000000..f96264081c3e --- /dev/null +++ b/tests/cpp/virtualptr.nim @@ -0,0 +1,9 @@ +type + Loo* {.exportc.} = object + LooPtr* = ptr Loo + Moo* {.exportc.} = object + loo*: LooPtr + + +proc salute*(foo: LooPtr) {.virtual.} = + discard diff --git a/tests/distinct/typeclassborrow.nim b/tests/distinct/typeclassborrow.nim index ee0b0782902c..5e0c63953478 100644 --- a/tests/distinct/typeclassborrow.nim +++ b/tests/distinct/typeclassborrow.nim @@ -1,3 +1,5 @@ +import std/tables + type Foo = distinct seq[int] Bar[N: static[int]] = distinct seq[int] @@ -46,3 +48,9 @@ proc `==`*(x, y: Fine): bool {.borrow.} = var x = Fine("1234") var y = Fine("1234") doAssert x == y + +block: # bug #22902 + type + DistinctTable = distinct Table[int, int] + + proc `[]`(t: DistinctTable; key: int): lent int {.borrow.} diff --git a/tests/generics/t22826.nim b/tests/generics/t22826.nim new file mode 100644 index 000000000000..914d4243a2de --- /dev/null +++ b/tests/generics/t22826.nim @@ -0,0 +1,8 @@ +import std/tables + +var a: Table[string, float] + +type Value*[T] = object + table: Table[string, Value[T]] + +discard toTable({"a": Value[float]()}) \ No newline at end of file diff --git a/tests/js/tnativeexc.nim b/tests/js/tnativeexc.nim index ea371c1cdb87..8b2b43e8f5ad 100644 --- a/tests/js/tnativeexc.nim +++ b/tests/js/tnativeexc.nim @@ -18,7 +18,7 @@ try: except JsEvalError: doAssert false except JsSyntaxError as se: - doAssert se.message == "Unexpected token ; in JSON at position 0" + doAssert se.message == "Unexpected token ';', \";;\" is not valid JSON" except JsError as e: doAssert false diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim index 5e8eac729f18..e4a99344a882 100644 --- a/tests/misc/tconv.nim +++ b/tests/misc/tconv.nim @@ -2,6 +2,9 @@ discard """ matrix: "--warningAsError:EnumConv --warningAsError:CStringConv" """ +from std/enumutils import items # missing from the example code +from std/sequtils import toSeq + template reject(x) = static: doAssert(not compiles(x)) template accept(x) = @@ -117,4 +120,17 @@ reject: var va = 2 var vb = va.Hole +block: # bug #22844 + type + A = enum + a0 = 2 + a1 = 4 + a2 + B[T] = enum + b0 = 2 + b1 = 4 + + doAssert A.toSeq == [a0, a1, a2] + doAssert B[float].toSeq == [B[float].b0, B[float].b1] + {.pop.} diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim index 5e0c51b2dcba..c22a8608cd3e 100644 --- a/tests/stdlib/tsugar.nim +++ b/tests/stdlib/tsugar.nim @@ -1,4 +1,5 @@ discard """ + targets: "c js" matrix: "--mm:refc; --mm:orc" output: ''' x + y = 30 @@ -270,17 +271,16 @@ template main() = discard collect(newSeq, for i in 1..3: i) foo() -proc mainProc() = block: # dump # symbols in templates are gensym'd let - x = 10 - y = 20 + x {.inject.} = 10 + y {.inject.} = 20 dump(x + y) # x + y = 30 block: # dumpToString template square(x): untyped = x * x - let x = 10 + let x {.inject.} = 10 doAssert dumpToString(square(x)) == "square(x): x * x = 100" let s = dumpToString(doAssert 1+1 == 2) doAssert "failedAssertImpl" in s @@ -299,8 +299,8 @@ proc mainProc() = test() -static: - main() - mainProc() +when not defined(js): # TODO fixme JS VM + static: + main() + main() -mainProc() diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index ce6b83980d32..bd5c4ecbe647 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -154,6 +154,7 @@ lib/posix/posix_openbsd_amd64.nim lib/posix/posix_haiku.nim lib/pure/md5.nim lib/std/sha1.nim +lib/pure/htmlparser.nim """.splitWhitespace() officialPackagesList = """ @@ -170,6 +171,7 @@ pkgs/checksums/src/checksums/sha1.nim pkgs/checksums/src/checksums/sha2.nim pkgs/checksums/src/checksums/sha3.nim pkgs/checksums/src/checksums/bcrypt.nim +pkgs/htmlparser/src/htmlparser.nim """.splitWhitespace() officialPackagesListWithoutIndex = """ @@ -188,6 +190,7 @@ when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo): result = path.len > 0 and not ret.startsWith ".." proc getDocList(): seq[string] = + ## var docIgnore: HashSet[string] for a in withoutIndex: docIgnore.incl a for a in ignoredModules: docIgnore.incl a @@ -344,7 +347,7 @@ proc buildJS(): string = proc buildDocsDir*(args: string, dir: string) = let args = nimArgs & " " & args let docHackJsSource = buildJS() - gitClonePackages(@["asyncftpclient", "punycode", "smtp", "db_connector", "checksums", "atlas"]) + gitClonePackages(@["asyncftpclient", "punycode", "smtp", "db_connector", "checksums", "atlas", "htmlparser"]) createDir(dir) buildDocSamples(args, dir)