From f5d70e7fa7195658e3200f71a1653e07fe81275a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 14 Oct 2023 03:34:13 +0800 Subject: [PATCH 01/41] fixes #19250; fixes #22259; ORC AssertionDefect not containsManagedMemory(n.typ) (#22823) fixes #19250 fixes #22259 The strings, seqs, refs types all have this flag, why should closures be treated differently? follow up https://github.com/nim-lang/Nim/pull/14336 --- compiler/semtypes.nim | 2 ++ tests/arc/tarcmisc.nim | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) 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/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() From 5f400983d588ec91a688453ce69cec94d310cc70 Mon Sep 17 00:00:00 2001 From: Himaj Patil <78681144+HimajPatil@users.noreply.github.com> Date: Mon, 16 Oct 2023 00:59:16 +0530 Subject: [PATCH 02/41] Update readme.md (#22827) Added table view in Compiling section of documentation --- readme.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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. From 10c3ab626941d9c1ec69a2921696f4b7d0c2a6ac Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 16 Oct 2023 00:01:33 +0200 Subject: [PATCH 03/41] =?UTF-8?q?NIR:=20store=20sizes,=20alignments=20and?= =?UTF-8?q?=20offsets=20in=20the=20type=20graph;=20beginning=E2=80=A6=20(#?= =?UTF-8?q?22822)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …s of a patent-pending new VM --- compiler/ast.nim | 2 +- compiler/commands.nim | 4 +- compiler/extccomp.nim | 2 +- compiler/ic/rodfiles.nim | 7 +- compiler/main.nim | 26 ++ compiler/modulegraphs.nim | 1 + compiler/nim.nim | 2 +- compiler/nir/ast2ir.nim | 592 +++++++++++++++++-------------- compiler/nir/nir.nim | 66 +++- compiler/nir/nirc.nim | 48 +++ compiler/nir/nirinsts.nim | 32 +- compiler/nir/nirlineinfos.nim | 7 +- compiler/nir/nirslots.nim | 2 +- compiler/nir/nirtypes.nim | 143 ++++++-- compiler/nir/nirvm.nim | 467 ++++++++++++++++++++++++ compiler/nir/stringcases.nim | 200 +++++++++++ compiler/nir/types2ir.nim | 139 +++++--- compiler/options.nim | 13 +- compiler/pipelines.nim | 6 + compiler/sizealignoffsetimpl.nim | 12 +- lib/system/seqs_v2.nim | 2 +- lib/system/strs_v2.nim | 3 + 22 files changed, 1389 insertions(+), 387 deletions(-) create mode 100644 compiler/nir/nirc.nim create mode 100644 compiler/nir/nirvm.nim create mode 100644 compiler/nir/stringcases.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 3017aedcf6e8..8d4511436ff3 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -924,7 +924,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/commands.nim b/compiler/commands.nim index f36d82306f3e..0e35cc3e8c27 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -460,6 +460,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 +497,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 +796,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/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/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index 41e85084f156..4968c5924f1b 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -97,6 +97,7 @@ type typeInfoSection # required by the backend backendFlagsSection aliveSymsSection # beware, this is stored in a `.alivesyms` file. + sideChannelSection RodFileError* = enum ok, tooBig, cannotOpen, ioFailure, wrongHeader, wrongSection, configMismatch, @@ -110,7 +111,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 +207,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: @@ -1123,20 +1192,20 @@ proc genInclExcl(c: var ProcCon; n: PNode; m: TMagic) = 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: 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 +1214,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 @@ -1182,7 +1251,7 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = if c.m.types.g[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 +1264,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 +1281,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 +1292,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: @@ -1239,19 +1308,19 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = 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: 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 @@ -1266,19 +1335,19 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = 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: 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) = @@ -1290,14 +1359,14 @@ proc genSetConstr(c: var ProcCon; n: PNode; d: var Value) = if c.m.types.g[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) 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 @@ -1334,7 +1403,7 @@ proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) = var tmpLen = allocTemp(c.sm, 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 + c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, precomputedLen for a in mitems(args): buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmpLen @@ -1441,6 +1510,57 @@ proc genMove(c: var ProcCon; n: PNode; d: var Value) = buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, typeToIr(c.m.types, 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 = seqPayloadPtrType(c.m.types, 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, c.m.nativeIntId).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,16 +1568,110 @@ 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 = nil): 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 + of ForArray: + let x = toInt64 lengthOrd(c.config, arr) + result.addIntVal c.lit.numbers, info, c.m.nativeIntId, x + result.Tree.addLabel info, CheckedGoto, c.exitLabel + 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.types.g, typeToIr(c.m.types, arrType.lastSon)) + case arrType.kind + of tyString, tySequence: + let t = typeToIr(c.m.types, arrType.lastSon) + let checkKind = if arrType.kind == tyString: ForStr else: ForSeq + let pay = if checkKind == ForStr: strPayloadPtrType(c.m.types) + else: seqPayloadPtrType(c.m.types, arrType) + + let y = genIndexCheck(c, n[2], x, checkKind) + let z = genIndexCheck(c, n[3], x, checkKind) + + buildTyped target, info, ObjConstr, typeToIr(c.m.types, n.typ): + target.addImmediateVal info, 0 + buildTyped target, info, AddrOf, elemType: + buildTyped target, info, ArrayAt, t: + buildTyped target, info, FieldAt, pay: + 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, tyOpenArray: + let t = typeToIr(c.m.types, arrType.lastSon) + # XXX This evaluates the index check for `y` twice. + # This check is also still insufficient for non-zero based arrays. + let checkKind = if arrType.kind == tyArray: ForArray else: ForOpenArray + + 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.types, n.typ): + target.addImmediateVal info, 0 + buildTyped target, info, AddrOf, elemType: + buildTyped target, info, ArrayAt, t: + 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 + 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) @@ -1470,7 +1684,7 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) = of mDec: unused(c, n, d) c.genIncDec(n, CheckedSub) - of mOrd, mChr, mArrToSeq, mUnown: + of mOrd, mChr, mUnown: c.gen(n[1], d) of generatedMagics: genCall(c, n, d) @@ -1621,154 +1835,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 +1870,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) @@ -1842,7 +1906,7 @@ proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; buildTyped target, info, FieldAt, strPayloadPtrType(c.m.types): 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: @@ -1857,7 +1921,7 @@ proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; buildTyped target, info, FieldAt, seqPayloadPtrType(c.m.types, typ): 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: @@ -1870,9 +1934,9 @@ proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; 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, typ)) else: raiseAssert "addAddrOfFirstElem: " & typeToString(typ) @@ -1933,10 +1997,32 @@ proc genObjOrTupleConstr(c: var ProcCon; n: PNode, d: var Value) = valueIntoDest c, info, d, n.typ, body +proc genSeqConstr(c: var ProcCon; n: PNode; d: var Value) = + if isEmpty(d): d = getTemp(c, n) + + let info = toLineInfo(c, n.info) + let seqtype = skipTypes(n.typ, abstractVarRange) + let baseType = seqtype.lastSon + + var b = default(Value) + b.addIntVal c.lit.numbers, info, c.m.nativeIntId, n.len + + genNewSeqPayload(c, info, d, b, seqtype) + + for i in 0..= 0, typeToString(s.typ) & (c.config $ n.info) + c.code.addSummon toLineInfo(c, a.info), SymId(s.itemId.item), t, opc if a[2].kind != nkEmpty: genAsgn2(c, vn, a[2]) else: @@ -2002,7 +2090,7 @@ proc genRdVar(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = if ast.originatingModule(s) != c.m.module: 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 @@ -2026,7 +2114,7 @@ proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = 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.types, 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,13 +2122,13 @@ 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.types, 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) = @@ -2068,31 +2156,6 @@ 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 info = toLineInfo(c, n.info) @@ -2189,7 +2252,10 @@ proc genObjAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = proc genParams(c: var ProcCon; params: PNode) = for i in 1..= 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 typ.int >= 0 assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam} let x = prepare(t, info, opc) t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info) @@ -304,10 +317,16 @@ proc addIntVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; 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 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: @@ -370,6 +389,14 @@ proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTabl for i in 0.. 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..; x begins to live + SummonParamM, + + AddrOfM, + ArrayAtM, # addr(a[i]) + FieldAtM, # addr(obj.field) + + LoadM, # a[] + StoreM, # a[] = b + AsgnM, # a = b + SetExcM, + TestExcM, + + CheckedRangeM, + CheckedIndexM, + + CallM, + IndirectCallM, + CheckedCallM, # call that can raise + CheckedIndirectCallM, # call that can raise + 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 and OpcodeMask) +template operand(n: Instr): uint32 = (n 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 + PatchPos = distinct int + CodePos = distinct int + + Unit = ref object ## a NIR module + procs: Table[SymId, CodePos] + globals: Table[SymId, uint32] + integers: BiTable[int64] + strings: BiTable[string] + globalsGen: uint32 + + Universe* = object ## all units: For interpretation we need that + units: Table[string, Unit] + + Bytecode = object + code: seq[Instr] + debug: seq[PackedLineInfo] + u: Unit + +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, uint(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 + +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 + +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) + +type + Preprocessing = object + known: Table[LabelId, CodePos] + toPatch: Table[LabelId, seq[CodePos]] + locals: Table[SymId, uint32] + c: Bytecode # to be moved out + thisModule: LitId + markedWithLabel: IntSet + +proc genGoto(c: var Preprocessing; lab: LabelId; opc: OpcodeM) = + let dest = c.known.getOrDefault(lab, CodePos(-1)) + if dest.int >= 0: + c.bc.add info, opc, uint32 dest + else: + let here = CodePos(c.bc.code.len) + c.toPatch.mgetOrPut(lab, @[]).add here + c.bc.add info, opc, 1u32 # will be patched once we traversed the label + +proc preprocess(c: var Preprocessing; u: var Universe; t: Tree; n: NodePos) = + let info = t[n].info + + template recurse(opc) = + build c.bc, info, opc: + for c in sons(t, n): preprocess(c, u, t, c) + + case t[n].kind + of Nop: + discard "don't use Nop" + of ImmediateVal: + c.bc.add info, ImmediateValM, t[n].rawOperand + of IntVal: + c.bc.add info, IntValM, t[n].rawOperand + of StrVal: + c.bc.add info, StrValM, t[n].rawOperand + of SymDef: + assert false, "SymDef outside of declaration context" + of SymUse: + let s = t[n].symId + if c.locals.hasKey(s): + c.bc.add info, LoadLocalM, c.locals[s] + elif c.bc.u.procs.hasKey(s): + build c.bc, info, LoadProcM: + c.bc.add info, StrValM, thisModule + c.bc.add info, LoadLocalM, uint32 c.bc.u.procs[s] + elif c.bc.u.globals.hasKey(s): + build c.bc, info, LoadGlobalM: + c.bc.add info, StrValM, thisModule + c.bc.add info, LoadLocalM, uint32 s + else: + assert false, "don't understand SymUse ID" + + of ModuleSymUse: + let moduleName {.cursor.} = c.bc.u.strings[t[n.firstSon].litId] + let unit = u.units.getOrDefault(moduleName) + + of Typed: + c.bc.add info, TypedM, t[n].rawOperand + of PragmaId: + c.bc.add info, TypedM, t[n].rawOperand + of NilVal: + c.bc.add info, NilValM, t[n].rawOperand + of LoopLabel, Label: + let lab = t[n].label + let here = CodePos(c.bc.code.len-1) + c.known[lab] = here + var p: seq[CodePos] + if c.toPatch.take(lab, p): + for x in p: c.bc.code[x] = toIns(c.bc.code[x].kind, here) + c.markedWithLabel.incl here.int # for toString() + of Goto, GotoLoop: + c.genGoto(t[n].label, GotoM) + of CheckedGoto: + c.genGoto(t[n].label, CheckedGotoM) + of ArrayConstr: + recurse ArrayConstrM + of ObjConstr: + recurse ObjConstrM + 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 s = + discard "xxx" + of Summon, SummonParam: + # x = Summon Typed ; x begins to live + discard "xxx" + of Kill: + discard "we don't care about Kill instructions" + of AddrOf: + recurse AddrOfM + of ArrayAt: + recurse ArrayAtM + of FieldAt: + recurse FieldAtM + of Load: + recurse LoadM + of Store: + recurse StoreM + of Asgn: + recurse AsgnM + of SetExc: + recurse SetExcM + of TestExc: + recurse TestExcM + of CheckedRange: + recurse CheckedRangeM + of CheckedIndex: + recurse CheckedIndexM + of Call: + recurse CallM + of IndirectCall: + recurse IndirectCallM + of CheckedCall: + recurse CheckedCallM + of CheckedIndirectCall: + recurse CheckedIndirectCallM + 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: + assert false, "cannot interpret: Emit" + of ProcDecl: + recurse ProcDeclM + 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 + +proc newStackFrame(size: int; caller: StackFrame; returnAddr: CodePos): StackFrame = + result = StackFrame(caller: caller, returnAddr: returnAddr) + if size <= PayloadSize: + result.locals = addr(result.payload) + else: + result.locals = alloc0(size) + +proc popStackFrame(s: StackFrame): StackFrame = + if result.locals != addr(result.payload): + dealloc result.locals + result = s.caller + +template `+!`(p: pointer; diff: uint): pointer = cast[pointer](cast[uint](p) + diff) + +proc eval(c: seq[Instr]; pc: CodePos; s: StackFrame; result: pointer) + +proc evalAddr(c: seq[Instr]; pc: CodePos; s: StackFrame): pointer = + case c[pc].kind + of LoadLocalM: + result = s.locals +! c[pc].operand + of FieldAtM: + result = eval(c, pc+1, s) + result = result +! c[pc+2].operand + of ArrayAtM: + let elemSize = c[pc+1].operand + result = eval(c, pc+2, s) + var idx: int + eval(c, pc+3, addr idx) + result = result +! (idx * elemSize) + +proc eval(c: seq[Instr]; pc: CodePos; s: StackFrame; result: pointer) = + case c[pc].kind + of AddM: + # assume `int` here for now: + var x, y: int + eval c, pc+1, s, addr x + eval c, pc+2, s, addr y + cast[ptr int](res)[] = x + y + of StrValM: + cast[ptr StringDesc](res)[] = addr(c.strings[c[pc].litId]) + of ObjConstrM: + for ch in sons(c, pc): + let offset = c[ch] + eval c, ch+2, s, result+!offset + of ArrayConstrM: + let elemSize = c[pc+1].operand + var r = result + for ch in sons(c, pc): + eval c, ch, s, r + r = r+!elemSize # can even do strength reduction here! + else: + assert false, "cannot happen" + +proc exec(c: seq[Instr]; pc: CodePos) = + var pc = pc + var currentFrame: StackFrame = nil + while true: + case c[pc].kind + of GotoM: + pc = CodePos(c[pc].operand) + of Asgn: + let (size, a, b) = sons3(c, pc) + let dest = evalAddr(c, a, s) + eval(c, b, s, dest) + of CallM: + # No support for return values, these are mapped to `var T` parameters! + let prc = evalProc(c, pc+1) + # setup storage for the proc already: + let s2 = newStackFrame(prc.frameSize, currentFrame, pc) + var i = 0 + for a in sons(c, pc): + eval(c, a, s2, paramAddr(s2, i)) + inc i + currentFrame = s2 + pc = pcOf(prc) + of RetM: + pc = currentFrame.returnAddr + currentFrame = popStackFrame(currentFrame) + of SelectM: + var x: bool + eval(c, b, addr x) + # follow the selection instructions... + pc = activeBranch(c, b, x) diff --git a/compiler/nir/stringcases.nim b/compiler/nir/stringcases.nim new file mode 100644 index 000000000000..9417d613d0a9 --- /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 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.. Date: Mon, 16 Oct 2023 12:44:55 +0800 Subject: [PATCH 04/41] closes #16919; followup #16820, test tsugar on all backends (#22829) closes #16919 followup #16820 --- tests/stdlib/tsugar.nim | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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() From a9bc6779e1010572e1def98379cb3693e55b8a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Mon, 16 Oct 2023 14:36:39 +0100 Subject: [PATCH 05/41] the compiler can be compiled with vcc (#22832) --- lib/pure/bitops.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 005c7fa8fa78..e442557ef29c 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -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 From 3c48af7ebe9c8949ce3341bb62eacf0de43e4d11 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 16 Oct 2023 15:47:13 +0200 Subject: [PATCH 06/41] NIR: temporary ID generation bugfix (#22830) --- compiler/nir/ast2ir.nim | 53 ++++++++++++++++++++++++--------------- compiler/nir/nirc.nim | 2 ++ compiler/nir/nirinsts.nim | 6 ++--- compiler/nir/nirslots.nim | 41 +++++++++++++++--------------- compiler/nir/nirtypes.nim | 3 +++ 5 files changed, 61 insertions(+), 44 deletions(-) diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim index fd3a4df09b21..0920f5d8ac2b 100644 --- a/compiler/nir/ast2ir.nim +++ b/compiler/nir/ast2ir.nim @@ -25,12 +25,12 @@ type man*: LineInfoManager lit*: Literals types*: TypesCon - slotGenerator: ref int module*: PSym graph*: ModuleGraph nativeIntId, nativeUIntId: TypeId idgen: IdGenerator - pendingProcs: Table[ItemId, PSym] # procs we still need to generate code for + processedProcs: HashSet[ItemId] + pendingProcs: seq[PSym] # procs we still need to generate code for ProcCon* = object config*: ConfigRef @@ -42,16 +42,14 @@ type code*: Tree blocks: seq[(PSym, LabelId)] sm: SlotManager - locGen: int + idgen: IdGenerator m: ModuleCon prc: PSym options: TOptions proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym): ModuleCon = let lit = Literals() # must be shared - var g = new(int) - g[] = idgen.symId + 1 - result = ModuleCon(graph: graph, types: initTypesCon(config, lit), slotGenerator: g, + result = ModuleCon(graph: graph, types: initTypesCon(config, lit), idgen: idgen, module: module, lit: lit) case config.target.intSize of 2: @@ -65,8 +63,8 @@ proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; m result.nativeUIntId = UInt16Id proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon = - ProcCon(m: m, sm: initSlotManager({}, m.slotGenerator), prc: prc, config: config, - lit: m.lit, + ProcCon(m: m, sm: initSlotManager({}), prc: prc, config: config, + lit: m.lit, idgen: m.idgen, options: if prc != nil: prc.options else: config.options) @@ -117,12 +115,12 @@ proc freeTemp(c: var ProcCon; tmp: Value) = proc getTemp(c: var ProcCon; n: PNode): Value = let info = toLineInfo(c, n.info) let t = typeToIr(c.m.types, n.typ) - let tmp = allocTemp(c.sm, t) + let tmp = allocTemp(c.sm, t, c.idgen.symId) c.code.addSummon info, tmp, t result = localToValue(info, tmp) proc getTemp(c: var ProcCon; t: TypeId; info: PackedLineInfo): Value = - let tmp = allocTemp(c.sm, t) + let tmp = allocTemp(c.sm, t, c.idgen.symId) c.code.addSummon info, tmp, t result = localToValue(info, tmp) @@ -322,7 +320,6 @@ proc addUseCodegenProc(c: var ProcCon; dest: var Tree; name: string; info: Packe template buildCond(useNegation: bool; cond: typed; body: untyped) = let lab = newLabel(c.labelGen) - #let info = toLineInfo(c, n.info) buildTyped c.code, info, Select, Bool8Id: c.code.copyTree cond build c.code, info, SelectPair: @@ -998,7 +995,7 @@ proc genEqSet(c: var ProcCon; n: PNode; d: var Value) = freeTemp c, a proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: int): (SymId, LabelId, LabelId) = - let tmp = allocTemp(c.sm, c.m.nativeIntId) + let tmp = allocTemp(c.sm, c.m.nativeIntId, c.idgen.symId) c.code.addSummon info, tmp, c.m.nativeIntId buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmp @@ -1016,7 +1013,7 @@ proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: int): (Sy c.code.gotoLabel info, Goto, result[2] proc beginCountLoop(c: var ProcCon; info: PackedLineInfo; first, last: Value): (SymId, LabelId, LabelId) = - let tmp = allocTemp(c.sm, c.m.nativeIntId) + let tmp = allocTemp(c.sm, c.m.nativeIntId, c.idgen.symId) c.code.addSummon info, tmp, c.m.nativeIntId buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmp @@ -1400,7 +1397,7 @@ proc genStrConcat(c: var ProcCon; n: PNode; d: var Value) = args.add genx(c, it) # generate length computation: - var tmpLen = allocTemp(c.sm, c.m.nativeIntId) + var tmpLen = allocTemp(c.sm, c.m.nativeIntId, c.idgen.symId) buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmpLen c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, precomputedLen @@ -2108,8 +2105,8 @@ proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = if ast.originatingModule(s) == c.m.module: # 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.containsOrIncl(s.itemId): + c.m.pendingProcs.add s genRdVar(c, n, d, flags) of skEnumField: let info = toLineInfo(c, n.info) @@ -2270,10 +2267,9 @@ proc addCallConv(c: var ProcCon; info: PackedLineInfo; callConv: TCallingConvent of ccThisCall: ann ThisCall of ccNoConvention: ann NoCall -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): return +proc genProc(cOuter: var ProcCon; prc: PSym) = + if cOuter.m.processedProcs.containsOrIncl(prc.itemId): + return var c = initProcCon(cOuter.m, prc, cOuter.m.graph.config) @@ -2312,6 +2308,12 @@ proc genProc(cOuter: var ProcCon; n: PNode) = copyTree cOuter.code, c.code +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): return + genProc cOuter, prc + proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = when defined(nimCompilerStacktraceHints): setFrameMsg c.config$n.info & " " & $n.kind & " " & $flags @@ -2405,19 +2407,30 @@ proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = 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 genPendingProcs(c: var ProcCon) = + while c.m.pendingProcs.len > 0: + let procs = move(c.m.pendingProcs) + for v in procs: + genProc(c, v) + proc genStmt*(c: var ProcCon; n: PNode): int = result = 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/nirc.nim b/compiler/nir/nirc.nim index da8d7d7786b3..3d8c8e6ffa12 100644 --- a/compiler/nir/nirc.nim +++ b/compiler/nir/nirc.nim @@ -41,6 +41,8 @@ proc view(filename: string) = var res = "" allTreesToString code, lit.strings, lit.numbers, res + res.add "\n# TYPES\n" + nirtypes.toString res, types echo res import std / os diff --git a/compiler/nir/nirinsts.nim b/compiler/nir/nirinsts.nim index 741733d48ef6..d95cd061d169 100644 --- a/compiler/nir/nirinsts.nim +++ b/compiler/nir/nirinsts.nim @@ -368,8 +368,9 @@ proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTabl 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: @@ -377,7 +378,7 @@ proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTabl 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 @@ -391,7 +392,6 @@ proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTabl proc allTreesToString*(t: Tree; strings: BiTable[string]; integers: BiTable[int64]; r: var string) = - var i = 0 while i < t.len: toString t, NodePos(i), strings, integers, r diff --git a/compiler/nir/nirslots.nim b/compiler/nir/nirslots.nim index d983fdea2cf2..a01e7a6339e7 100644 --- a/compiler/nir/nirslots.nim +++ b/compiler/nir/nirslots.nim @@ -24,25 +24,25 @@ type dead: Table[TypeId, seq[SymId]] flags: set[SlotManagerFlag] inScope: seq[SymId] - locGen: ref int -proc initSlotManager*(flags: set[SlotManagerFlag]; generator: ref int): SlotManager {.inline.} = - SlotManager(flags: flags, locGen: generator) +proc initSlotManager*(flags: set[SlotManagerFlag]): SlotManager {.inline.} = + SlotManager(flags: flags) -proc allocRaw(m: var SlotManager; t: TypeId; f: SlotManagerFlag; k: SlotKind): SymId {.inline.} = +proc allocRaw(m: var SlotManager; t: TypeId; f: SlotManagerFlag; k: SlotKind; + symIdgen: var int32): SymId {.inline.} = if f in m.flags and m.dead.hasKey(t) and m.dead[t].len > 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(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 288f3063d383..e07f1395dac8 100644 --- a/compiler/nir/nirtypes.nim +++ b/compiler/nir/nirtypes.nim @@ -392,6 +392,9 @@ proc toString*(dest: var string; g: TypeGraph; i: TypeId) = proc toString*(dest: var string; g: TypeGraph) = var i = 0 while i < g.len: + dest.add "T<" + dest.addInt i + dest.add "> " toString(dest, g, TypeId i) dest.add '\n' nextChild g, i From 0d4b3ed18edff5ae098be842a986cb32de651fbf Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:44:13 +0800 Subject: [PATCH 07/41] =?UTF-8?q?fixes=20#22836;=20Unnecessary=20warning?= =?UTF-8?q?=20on=20'options.none'=20with=20'strictDefs'=E2=80=A6=20(#22837?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … enabled fixes #22836 --- lib/pure/options.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/options.nim b/lib/pure/options.nim index ec384ceb4ba3..815eaab8967d 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -152,7 +152,7 @@ proc none*(T: typedesc): Option[T] {.inline.} = assert none(int).isNone # the default is the none type - discard + result = Option[T]() proc none*[T]: Option[T] {.inline.} = ## Alias for `none(T) <#none,typedesc>`_. From 05a7c0fdd098b1971041f742ebf9e1871e4ad2b4 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 18 Oct 2023 21:12:50 -0300 Subject: [PATCH 08/41] Bisect default Linux (#22840) - Bisect default to Linux only. Tiny diff, YAML only. | OS | How to? | |----|---------| | Linux | `-d:linux` | | Windows | `-d:windows` | | OS X | `-d:osx` | If no `-d:linux` nor `-d:windows` nor `-d:osx` is used then defaults to Linux. --- .github/workflows/bisects.yml | 5 +++++ 1 file changed, 5 insertions(+) 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 }} From 27deacecaadd711cbb5a615abba3237925250616 Mon Sep 17 00:00:00 2001 From: rockcavera Date: Fri, 20 Oct 2023 04:43:53 -0300 Subject: [PATCH 09/41] fix #22834 (#22843) fix #22834 Edit: also fixes `result.addrList` when IPv6, which previously only performed a `result.addrList = cstringArrayToSeq(s.h_addr_list)` which does not provide the textual representation of an IPv6 --- lib/pure/nativesockets.nim | 47 ++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index b3465ef14b17..e1784491b620 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -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 + + 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()`") + + freeAddrInfo(addrInfo) 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.. Date: Sat, 21 Oct 2023 00:38:42 +0800 Subject: [PATCH 10/41] fixes #22844; uses arrays to store holeyenums for iterations; much more efficient than sets and reasonable for holeyenums (#22845) fixes #22844 --- lib/std/enumutils.nim | 2 +- tests/misc/tconv.nim | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index 1ce82eccf21b..ca62a504c5fe 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -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/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.} From 2b1a671f1cbe4d3443537435ef0f0cddf928abbf Mon Sep 17 00:00:00 2001 From: Vindaar Date: Fri, 20 Oct 2023 19:04:01 +0200 Subject: [PATCH 11/41] explicitly import using `std/` in `tempfiles.nim` (#22851) At least on modern Nim `tempfiles` is not usable if the user has https://github.com/oprypin/nim-random installed, because the compiler picks the nimble path over the stdlib path (apparently). --- lib/std/tempfiles.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim index 1160aaaad54e..582cf531eae4 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 From c13c48500b527cb483480702390b1f230ac896a4 Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Sat, 21 Oct 2023 22:00:16 +0200 Subject: [PATCH 12/41] Fix #22826: Don't skip generic instances in type comparison (#22828) Close #22826 I am not sure why this code skips generic insts, so letting CI tell me. Update: It has told me nothing. Maybe someone knows during review. Issue itself seems to be that the generic instance is skipped thus it ends up being just `float` which makes it use the wrong generic instance of the proc because it matches the one in cache --------- Co-authored-by: SirOlaf <> --- compiler/types.nim | 8 ++++---- tests/generics/t22826.nim | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 tests/generics/t22826.nim diff --git a/compiler/types.nim b/compiler/types.nim index f5e965df98ff..cdb3067c307f 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1202,12 +1202,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: 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 From ca577dbab12cb7a9a73ca8d39ce03f568bade2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Mon, 23 Oct 2023 07:59:14 +0100 Subject: [PATCH 13/41] C++: ptr fields now pulls the whole type if it's a member in nkDotExpr (#22855) --- compiler/ccgexprs.nim | 6 ++++++ tests/cpp/tvirtual.nim | 10 +++++++++- tests/cpp/virtualptr.nim | 9 +++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/cpp/virtualptr.nim 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/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 From 562a5fb8f9df8985be2543e5581252e449d6ae09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8F=A1=E7=8C=AB=E7=8C=AB?= <164346864@qq.com> Date: Mon, 23 Oct 2023 15:11:13 +0800 Subject: [PATCH 14/41] fix use after free (#22854) 1. `freeAddrInfo` is called prematurely, the variable `myAddr` is still in use 2. Use defer syntax to ensure that `freeAddrInfo` is also called on exceptions --- lib/pure/nativesockets.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index e1784491b620..593bd2d56f39 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -392,6 +392,8 @@ when not useNimNetLite: myAddr: pointer addrLen = 0 family = 0 + + defer: freeAddrInfo(addrInfo) if addrInfo.ai_addr.sa_family.cint == nativeAfInet: family = nativeAfInet @@ -404,8 +406,6 @@ when not useNimNetLite: else: raise newException(IOError, "Unknown socket family in `getHostByAddr()`") - freeAddrInfo(addrInfo) - when useWinVersion: var s = winlean.gethostbyaddr(cast[ptr InAddr](myAddr), addrLen.cuint, cint(family)) From 3095048d674b0cc17dfbf221f81e13a1dc1eb6c0 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 23 Oct 2023 22:56:52 +0800 Subject: [PATCH 15/41] fixes `system.delete` that raises defects (#22857) --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 8d1cda86815e..1d81c3f22a4b 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1981,7 +1981,7 @@ 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. From 3fd4e684331a22be84e940833faee111226945ea Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 24 Oct 2023 11:13:14 +0800 Subject: [PATCH 16/41] fixes #22856; enables `-d:nimStrictDelete` (#22858) fixes #22856 `-d:nimStrictDelete` is introduced in 1.6.0, which promised to be enabled in the coming versions. To keep backwards incompatibilities, it also extends the feature of `-d:nimAuditDelete`, which now mimics the old behaviors. --- changelog.md | 1 + lib/system.nim | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 72d0a2a2dd7a..58efde163f1e 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,7 @@ ## 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. ## Standard library additions and changes diff --git a/lib/system.nim b/lib/system.nim index 1d81c3f22a4b..41c9e96ea2ac 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1986,10 +1986,6 @@ proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect, systemRaisesDefect, a ## ## 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, systemRaisesDefect, a 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") From 7c3917d1dd3faa12fa1cc079d6fcf22f3da630c5 Mon Sep 17 00:00:00 2001 From: shuoer86 <129674997+shuoer86@users.noreply.github.com> Date: Wed, 25 Oct 2023 20:53:15 +0800 Subject: [PATCH 17/41] doc: fix typos (#22869) doc: fix typos --- doc/docgen.md | 4 ++-- doc/manual_experimental.md | 2 +- doc/markdown_rst.md | 2 +- doc/nimc.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) 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/manual_experimental.md b/doc/manual_experimental.md index 4bafd408ff0b..4ba56205acd0 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -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 From cef5e57eb59f0ef2633c298aa2c8a5b049b32d5c Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 26 Oct 2023 16:06:44 +0800 Subject: [PATCH 18/41] fixes #22867; fixes cstring modification example on Nim Manual (#22871) fixes #22867 --- doc/manual.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual.md b/doc/manual.md index 8f419705efd3..0e447fd123d3 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -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 ``` From 0e45b01b210bbf1bc535cc73fcb3fe649a343168 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 26 Oct 2023 19:07:50 +0800 Subject: [PATCH 19/41] deprecate htmlparser (#22870) ref https://github.com/nim-lang/Nim/pull/22848 see also https://github.com/nim-lang/htmlparser will build the documentation later when everything else is settled --------- Co-authored-by: Andreas Rumpf --- changelog.md | 1 + lib/pure/htmlparser.nim | 2 ++ 2 files changed, 3 insertions(+) diff --git a/changelog.md b/changelog.md index 58efde163f1e..b094dd0ebeb8 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,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:" diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index 0de384a8e645..8bf149721419 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -47,6 +47,8 @@ ## writeFile("output.html", $html) ## ``` +{.deprecated: "use `nimble install htmlparser` and import `pkg/htmlparser` instead".} + import strutils, streams, parsexml, xmltree, unicode, strtabs when defined(nimPreviewSlimSystem): From d66f3febd120a6e888250dd9fa80b1533591d68f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:32:10 +0800 Subject: [PATCH 20/41] fixes #22868; fixes `std/nre` leaks under ARC/ORC (#22872) fixes #22868 --- lib/impure/nre.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 2c1b1deaeee0..422b1b68c792 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -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) From fbc801d1d15aa2c5f12a3f3bc1e35aad185dafb1 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 28 Oct 2023 06:34:53 +0800 Subject: [PATCH 21/41] build documentation for `htmlparser` (#22879) I have added a note for installment https://github.com/nim-lang/htmlparser/pull/5 > In order to use this module, run `nimble install htmlparser`. --- tools/kochdocs.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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) From 94ffc183323c859fc5a395404ac6035ae29cbc5a Mon Sep 17 00:00:00 2001 From: Yardanico Date: Sun, 29 Oct 2023 08:21:32 +0300 Subject: [PATCH 22/41] Fix #22862 - change the httpclient user-agent to be valid spec-wise (#22882) Per https://datatracker.ietf.org/doc/html/rfc9110#name-user-agent a User-Agent is defined as follows: ``` User-Agent = product *( RWS ( product / comment ) ) ``` Where ``` product = token ["/" product-version] product-version = token ``` In this case, `token` is defined in RFC 7230 - https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6: ``` token = 1*tchar tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA ; any VCHAR, except delimiters ``` or, in the original RFC 2616 - https://datatracker.ietf.org/doc/html/rfc2616#section-2.2 (next page): ``` token = 1* separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT ``` which means that a `token` cannot have whitespace. Not sure if this should be in the breaking changelog section - theoretically, some clients might've relied on the old Nim user-agent? For some extra info, some other languages seem to have adopted the same hyphen user agent to specify the language + module, e.g.: - https://github.com/python/cpython/blob/main/Lib/urllib/request.py#L1679 (`Python-urllib/`) Fixes #22862. --- changelog.md | 1 + lib/pure/httpclient.nim | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index b094dd0ebeb8..454b613f074b 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,7 @@ ## 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 diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 9444618db652..d2bf925bab3c 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 From 0c26d19e228e831393cb5d2c1f43660362d349c9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Oct 2023 14:47:22 +0100 Subject: [PATCH 23/41] NIR: VM + refactorings (#22835) --- compiler/ccgcalls.nim | 14 +- compiler/ic/rodfiles.nim | 1 + compiler/nir/ast2ir.nim | 509 ++++++++++++++--------- compiler/nir/nir.nim | 55 +-- compiler/nir/nirc.nim | 69 +-- compiler/nir/nirfiles.nim | 73 ++++ compiler/nir/nirinsts.nim | 97 ++++- compiler/nir/nirtypes.nim | 28 +- compiler/nir/nirvm.nim | 856 ++++++++++++++++++++++++++++++++------ compiler/nir/types2ir.nim | 481 ++++++++++----------- lib/system/ansi_c.nim | 4 +- 11 files changed, 1538 insertions(+), 649 deletions(-) create mode 100644 compiler/nir/nirfiles.nim 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/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index 4968c5924f1b..3505bfdfb861 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -98,6 +98,7 @@ type backendFlagsSection aliveSymsSection # beware, this is stored in a `.alivesyms` file. sideChannelSection + symnamesSection RodFileError* = enum ok, tooBig, cannotOpen, ioFailure, wrongHeader, wrongSection, configMismatch, diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim index 0920f5d8ac2b..b1a90e9bf25d 100644 --- a/compiler/nir/ast2ir.nim +++ b/compiler/nir/ast2ir.nim @@ -15,22 +15,27 @@ from ".." / lowerings import lowerSwap, lowerTupleUnpacking from ".." / pathutils import customPath import .. / ic / bitabs -import nirtypes, nirinsts, nirlineinfos, nirslots, types2ir +import nirtypes, nirinsts, nirlineinfos, nirslots, types2ir, nirfiles when defined(nimCompilerStacktraceHints): import std/stackframes type ModuleCon* = ref object - man*: LineInfoManager - lit*: Literals - types*: TypesCon + nirm*: ref NirModule + types: TypesCon module*: PSym graph*: ModuleGraph + symnames*: SymNames nativeIntId, nativeUIntId: TypeId + strPayloadId: (TypeId, TypeId) idgen: IdGenerator - processedProcs: HashSet[ItemId] + processedProcs, pendingProcsAsSet: HashSet[ItemId] pendingProcs: seq[PSym] # procs we still need to generate code for + noModularity*: bool + inProc: int + toSymId: Table[ItemId, SymId] + symIdCounter: int32 ProcCon* = object config*: ConfigRef @@ -39,7 +44,7 @@ type lastFileVal: LitId labelGen: int exitLabel: LabelId - code*: Tree + #code*: Tree blocks: seq[(PSym, LabelId)] sm: SlotManager idgen: IdGenerator @@ -47,10 +52,13 @@ type prc: PSym options: TOptions -proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym): ModuleCon = - let lit = Literals() # must be shared - result = ModuleCon(graph: graph, types: initTypesCon(config, lit), - idgen: idgen, module: module, lit: lit) +template code(c: ProcCon): Tree = c.m.nirm.code + +proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym; + nirm: ref NirModule): ModuleCon = + #let lit = Literals() # must be shared + result = ModuleCon(graph: graph, types: initTypesCon(config), nirm: nirm, + idgen: idgen, module: module) case config.target.intSize of 2: result.nativeIntId = Int16Id @@ -61,10 +69,11 @@ proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; m else: result.nativeIntId = Int64Id result.nativeUIntId = UInt16Id + result.strPayloadId = strPayloadPtrType(result.types, result.nirm.types) proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon = ProcCon(m: m, sm: initSlotManager({}), prc: prc, config: config, - lit: m.lit, idgen: m.idgen, + lit: m.nirm.lit, idgen: m.idgen, options: if prc != nil: prc.options else: config.options) @@ -77,7 +86,7 @@ proc toLineInfo(c: var ProcCon; i: TLineInfo): PackedLineInfo = # remember the entry: c.lastFileKey = i.fileIndex c.lastFileVal = val - result = pack(c.m.man, val, int32 i.line, int32 i.col) + result = pack(c.m.nirm.man, val, int32 i.line, int32 i.col) proc bestEffort(c: ProcCon): TLineInfo = if c.prc != nil: @@ -112,15 +121,41 @@ proc freeTemp(c: var ProcCon; tmp: Value) = if s != SymId(-1): freeTemp(c.sm, s) +proc typeToIr(m: ModuleCon; t: PType): TypeId = + typeToIr(m.types, m.nirm.types, t) + +proc allocTemp(c: var ProcCon; t: TypeId): SymId = + if c.m.noModularity: + result = allocTemp(c.sm, t, c.m.symIdCounter) + else: + result = allocTemp(c.sm, t, c.idgen.symId) + +const + ListSymId = -1 + +proc toSymId(c: var ProcCon; s: PSym): SymId = + if c.m.noModularity: + result = c.m.toSymId.getOrDefault(s.itemId, SymId(-1)) + if result.int < 0: + inc c.m.symIdCounter + result = SymId(c.m.symIdCounter) + c.m.toSymId[s.itemId] = result + when ListSymId != -1: + if result.int == ListSymId or s.name.s == "echoBinSafe": + echo result.int, " is ", s.name.s, " ", c.m.graph.config $ s.info, " ", s.flags + writeStackTrace() + else: + result = SymId(s.itemId.item) + proc getTemp(c: var ProcCon; n: PNode): Value = let info = toLineInfo(c, n.info) - let t = typeToIr(c.m.types, n.typ) - let tmp = allocTemp(c.sm, t, c.idgen.symId) + let t = typeToIr(c.m, n.typ) + let tmp = allocTemp(c, t) c.code.addSummon info, tmp, t result = localToValue(info, tmp) proc getTemp(c: var ProcCon; t: TypeId; info: PackedLineInfo): Value = - let tmp = allocTemp(c.sm, t, c.idgen.symId) + let tmp = allocTemp(c, t) c.code.addSummon info, tmp, t result = localToValue(info, tmp) @@ -274,7 +309,7 @@ proc tempToDest(c: var ProcCon; n: PNode; d: var Value; tmp: Value) = else: let info = toLineInfo(c, n.info) build c.code, info, Asgn: - c.code.addTyped info, typeToIr(c.m.types, n.typ) + c.code.addTyped info, typeToIr(c.m, n.typ) c.code.copyTree d c.code.copyTree tmp freeTemp(c, tmp) @@ -369,7 +404,7 @@ proc genCase(c: var ProcCon; n: PNode; d: var Value) = let info = toLineInfo(c, n.info) withTemp(tmp, n[0]): build c.code, info, Select: - c.code.addTyped info, typeToIr(c.m.types, n[0].typ) + c.code.addTyped info, typeToIr(c.m, n[0].typ) c.gen(n[0], tmp) for i in 1..>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.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: @@ -1184,14 +1223,14 @@ proc genInclExcl(c: var ProcCon; n: PNode; m: TMagic) = 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.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: @@ -1234,9 +1273,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 @@ -1245,7 +1284,7 @@ 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.lit.numbers, info, t, 0 @@ -1300,14 +1339,14 @@ 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.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: @@ -1327,14 +1366,14 @@ 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.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: @@ -1350,16 +1389,16 @@ proc genSetConstrDyn(c: var ProcCon; n: PNode; d: var Value) = 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.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): @@ -1387,32 +1426,36 @@ 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, c.idgen.symId) + var tmpLen = allocTemp(c, c.m.nativeIntId) buildTyped c.code, info, Asgn, c.m.nativeIntId: c.code.addSymUse info, tmpLen c.code.addIntVal c.lit.numbers, info, c.m.nativeIntId, precomputedLen - for a in mitems(args): + 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.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: @@ -1432,7 +1475,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] @@ -1469,13 +1512,14 @@ 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 @@ -1487,13 +1531,13 @@ proc genMove(c: var ProcCon; n: PNode; d: var Value) = 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) @@ -1502,9 +1546,9 @@ 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 = @@ -1542,13 +1586,13 @@ proc genDestroySeq(c: var ProcCon; n: PNode; t: PType) = let x = c.genx(n[1]) let baseType = t.lastSon - let seqType = seqPayloadPtrType(c.m.types, t) + 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, c.m.nativeIntId).bitOp(BitAnd, 0).eqZero(): + 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) @@ -1572,7 +1616,7 @@ type IndexFor = enum ForSeq, ForStr, ForOpenArray, ForArray -proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PType = nil): Value = +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) @@ -1581,11 +1625,11 @@ proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PTyp copyTree result.Tree, idx case kind of ForSeq, ForStr: - buildTyped result, info, FieldAt, c.m.nativeIntId: + 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, c.m.nativeIntId: + buildTyped result, info, FieldAt, typeToIr(c.m, arr): copyTree result.Tree, a result.addImmediateVal info, 1 # (p, len)-pair of ForArray: @@ -1598,22 +1642,21 @@ proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor; arr: PTyp proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo; x: Value; n: PNode; arrType: PType) = - 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, tySequence: - let t = typeToIr(c.m.types, arrType.lastSon) let checkKind = if arrType.kind == tyString: ForStr else: ForSeq - let pay = if checkKind == ForStr: strPayloadPtrType(c.m.types) - else: seqPayloadPtrType(c.m.types, arrType) + 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) - let z = genIndexCheck(c, n[3], x, checkKind) + 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.types, n.typ): + buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ): target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: - buildTyped target, info, ArrayAt, t: - buildTyped target, info, FieldAt, pay: + buildTyped target, info, ArrayAt, pay[1]: + buildTyped target, info, FieldAt, typeToIr(c.m, arrType): copyTree target, x target.addImmediateVal info, 1 # (len, p)-pair copyTree target, y @@ -1628,19 +1671,16 @@ proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo; freeTemp c, z freeTemp c, y - of tyArray, tyOpenArray: - let t = typeToIr(c.m.types, arrType.lastSon) + of tyArray: # XXX This evaluates the index check for `y` twice. # This check is also still insufficient for non-zero based arrays. - let checkKind = if arrType.kind == tyArray: ForArray else: ForOpenArray - - let y = genIndexCheck(c, n[2], x, checkKind, arrType) - let z = genIndexCheck(c, n[3], x, checkKind, arrType) + 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.types, n.typ): + buildTyped target, info, ObjConstr, typeToIr(c.m, n.typ): target.addImmediateVal info, 0 buildTyped target, info, AddrOf, elemType: - buildTyped target, info, ArrayAt, t: + buildTyped target, info, ArrayAt, typeToIr(c.m, arrType): copyTree target, x copyTree target, y @@ -1651,6 +1691,30 @@ proc addSliceFields(c: var ProcCon; target: var Tree; info: PackedLineInfo; 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, ArrayAt, 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: @@ -1875,7 +1939,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 @@ -1885,7 +1949,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 @@ -1893,47 +1957,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, ArrayAt, 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.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, ArrayAt, 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.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.lit.numbers, info, c.m.nativeIntId, 0 target.addImmediateVal info, 1 - target.addIntVal(c.lit.numbers, 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) @@ -1942,7 +2006,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 @@ -1966,7 +2030,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 @@ -1974,11 +2038,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) - c.code.addSummon toLineInfo(c, a.info), SymId(s.itemId.item), t, opc + let symId = toSymId(c, s) + c.code.addSummon toLineInfo(c, a.info), symId, t, opc + c.m.symnames[symId] = c.lit.strings.getOrIncl(s.name.s) if a[2].kind != nkEmpty: genAsgn2(c, vn, a[2]) else: @@ -2081,10 +2163,13 @@ proc irModule(c: var ProcCon; owner: PSym): string = #if owner == c.m.module: "" else: customPath(toFullPath(c.config, owner.info)) +proc fromForeignModule(c: ProcCon; s: PSym): bool {.inline.} = + result = ast.originatingModule(s) != c.m.module and not c.m.noModularity + 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): template body(target) = build target, info, ModuleSymUse: target.addStrVal c.lit.strings, info, irModule(c, ast.originatingModule(s)) @@ -2093,7 +2178,7 @@ proc genRdVar(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = 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 = {}) = @@ -2102,16 +2187,17 @@ proc genSym(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = of skVar, skForVar, skTemp, skLet, skResult, skParam, skConst: genRdVar(c, n, d, flags) of skProc, skFunc, skConverter, skMethod, skIterator: - if ast.originatingModule(s) == c.m.module: + if not fromForeignModule(c, s): # anon and generic procs have no AST so we need to remember not to forget # to emit these: - if not c.m.processedProcs.containsOrIncl(s.itemId): - c.m.pendingProcs.add 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.lit.numbers, 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) @@ -2119,7 +2205,7 @@ 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.lit.numbers, 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) = @@ -2131,7 +2217,7 @@ proc genStringLit(c: var ProcCon; n: PNode; d: var Value) = 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) = @@ -2141,7 +2227,7 @@ 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): copyTree target, tmp copyTree target, a copyTree target, b @@ -2154,16 +2240,17 @@ proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) = gen c, n[0], d 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, ArrayAt, 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 @@ -2175,7 +2262,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, ArrayAt, typeToIr(c.m, arrayType): copyTree target, a copyTree target, b valueIntoDest c, info, d, n.typ, body @@ -2186,7 +2273,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 @@ -2194,11 +2281,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, ArrayAt, 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 @@ -2212,7 +2299,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 @@ -2220,11 +2307,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, ArrayAt, 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 @@ -2239,20 +2326,28 @@ proc genObjAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) = let a = genx(c, n[0], flags) template body(target) = - buildTyped target, info, FieldAt, typeToIr(c.m.types, n.typ): + buildTyped target, info, FieldAt, typeToIr(c.m, n[0].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) = + if params.len > 0 and resultPos < prc.ast.len: + let resNode = prc.ast[resultPos] + let res = resNode.sym # get result symbol + c.code.addSummon toLineInfo(c, res.info), toSymId(c, res), + typeToIr(c.m, res.typ), 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) @@ -2277,8 +2378,14 @@ proc genProc(cOuter: var ProcCon; prc: PSym) = let info = toLineInfo(c, body.info) build c.code, info, ProcDecl: - addSymDef c.code, info, SymId(prc.itemId.item) + let symId = toSymId(c, prc) + addSymDef c.code, info, symId + c.m.symnames[symId] = c.lit.strings.getOrIncl(prc.name.s) 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 @@ -2302,18 +2409,35 @@ proc genProc(cOuter: var ProcCon; prc: PSym) = else: c.code.addPragmaId info, ObjExport - genParams(c, prc.typ.n) + genParams(c, prc.typ.n, prc) gen(c, body) patch c, body, c.exitLabel - copyTree cOuter.code, c.code + #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): return + if isGenericRoutineStrict(prc) or isCompileTimeProc(prc) or sfForward in prc.flags: return genProc cOuter, prc +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): setFrameMsg c.config$n.info & " " & $n.kind & " " & $flags @@ -2328,11 +2452,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: @@ -2401,8 +2523,13 @@ 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: @@ -2419,8 +2546,8 @@ proc genPendingProcs(c: var ProcCon) = for v in procs: genProc(c, v) -proc genStmt*(c: var ProcCon; n: PNode): int = - result = c.code.len +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 diff --git a/compiler/nir/nir.nim b/compiler/nir/nir.nim index 0669bc222590..c4fb5322d5a0 100644 --- a/compiler/nir/nir.nim +++ b/compiler/nir/nir.nim @@ -12,8 +12,9 @@ from os import addFileExt, `/`, createDir +import std / assertions import ".." / [ast, modulegraphs, renderer, transf, options, msgs, lineinfos] -import nirtypes, nirinsts, ast2ir, nirlineinfos +import nirtypes, nirinsts, ast2ir, nirlineinfos, nirfiles, nirvm import ".." / ic / [rodfiles, bitabs] @@ -22,13 +23,18 @@ type 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 @@ -46,14 +52,13 @@ 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.lit.strings, c.m.lit.numbers, res + #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: + execCode c.bytecode, c.m.nirm.code, pc + #echo res proc runCode*(c: PPassContext; n: PNode): PNode = let c = PCtx(c) @@ -71,7 +76,9 @@ type c: ProcCon proc openNirBackend*(g: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = - let m = initModuleCon(g, g.config, idgen, module) + 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) = @@ -89,27 +96,9 @@ proc closeNirBackend*(c: PPassContext; finalNode: PNode) = let nimcache = getNimcacheDir(c.c.config).string createDir nimcache let outp = nimcache / c.m.module.name.s.addFileExt("nir") - var r = rodfiles.create(outp) + #c.m.nirm.code = move c.c.code try: - r.storeHeader(nirCookie) - r.storeSection stringsSection - r.store c.m.lit.strings - - r.storeSection numbersSection - r.store c.m.lit.numbers - - r.storeSection bodiesSection - r.store c.c.code - - r.storeSection typesSection - r.store c.m.types.g - - r.storeSection sideChannelSection - r.store c.m.man - - finally: - r.close() - if r.err != ok: - rawMessage(c.c.config, errFatal, "serialization failed: " & outp) - else: + 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 index 3d8c8e6ffa12..363507ca6537 100644 --- a/compiler/nir/nirc.nim +++ b/compiler/nir/nirc.nim @@ -10,41 +10,46 @@ ## Nir Compiler. Currently only supports a "view" command. import ".." / ic / [bitabs, rodfiles] -import nirinsts, nirtypes, nirlineinfos +import nirinsts, nirtypes, nirlineinfos, nirfiles #, nir2gcc proc view(filename: string) = - var lit = Literals() - - var r = rodfiles.open(filename) - var code = default Tree - var man = default LineInfoManager - var types = initTypeGraph(lit) - try: - r.loadHeader(nirCookie) - r.loadSection stringsSection - r.load lit.strings - - r.loadSection numbersSection - r.load lit.numbers - - r.loadSection bodiesSection - r.load code - - r.loadSection typesSection - r.load types - - r.loadSection sideChannelSection - r.load man - - finally: - r.close() - + let m = load(filename) var res = "" - allTreesToString code, lit.strings, lit.numbers, res + allTreesToString m.code, m.lit.strings, m.lit.numbers, m.symnames, res res.add "\n# TYPES\n" - nirtypes.toString res, types + nirtypes.toString res, m.types echo res -import std / os - -view paramStr(1) +proc libgcc(filename: string) = + let m = load(filename) + #gcc m, filename + +import std / [syncio, parseopt] + +proc writeHelp = + echo """Usage: nirc view|gcc """ + 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 "gcc": + libgcc inp + +main() diff --git a/compiler/nir/nirfiles.nim b/compiler/nir/nirfiles.nim new file mode 100644 index 000000000000..f6c73178b0ba --- /dev/null +++ b/compiler/nir/nirfiles.nim @@ -0,0 +1,73 @@ +# +# +# 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 + 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 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 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 d95cd061d169..7b281e876884 100644 --- a/compiler/nir/nirinsts.nim +++ b/compiler/nir/nirinsts.nim @@ -57,6 +57,7 @@ type SummonGlobal, SummonThreadLocal, Summon, # x = Summon Typed ; x begins to live + SummonResult, SummonParam, SummonConst, Kill, # `Kill x`: scope end for `x` @@ -110,6 +111,7 @@ type type PragmaKey* = enum FastCall, StdCall, CDeclCall, SafeCall, SysCall, InlineCall, NoinlineCall, ThisCall, NoCall, + CoreName, ExternName, HeaderImport, DllImport, @@ -167,7 +169,7 @@ const 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) @@ -234,6 +236,10 @@ 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) + iterator sons*(tree: Tree; n: NodePos): NodePos = var pos = n.int assert tree.nodes[pos].kind > LastAtomicValue @@ -243,6 +249,16 @@ 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 + template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int] proc span(tree: Tree; pos: int): int {.inline.} = @@ -257,9 +273,46 @@ proc copyTree*(dest: var Tree; src: Tree) = for i in 0..= 0 - assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam} + 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) @@ -345,7 +398,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 ' ' @@ -361,10 +439,10 @@ 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: @@ -374,7 +452,11 @@ proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTabl 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 @@ -385,16 +467,17 @@ proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTabl 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..; x begins to live + AllocLocals, SummonParamM, AddrOfM, - ArrayAtM, # addr(a[i]) + ArrayAtM, # (elemSize, addr(a), i) FieldAtM, # addr(obj.field) LoadM, # a[] - StoreM, # a[] = b AsgnM, # a = b + StoreM, # a[] = b SetExcM, TestExcM, @@ -63,9 +60,7 @@ type CheckedIndexM, CallM, - IndirectCallM, CheckedCallM, # call that can raise - CheckedIndirectCallM, # call that can raise CheckedAddM, # with overflow checking etc. CheckedSubM, CheckedMulM, @@ -103,8 +98,8 @@ const type Instr = distinct uint32 -template kind(n: Instr): OpcodeM = OpcodeM(n and OpcodeMask) -template operand(n: Instr): uint32 = (n shr OpcodeBits) +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)) @@ -112,24 +107,108 @@ template toIns(k: OpcodeM; operand: uint32): Instr = template toIns(k: OpcodeM; operand: LitId): Instr = Instr(uint32(k) or (operand.uint32 shl OpcodeBits)) +const + GlobalsSize = 1024*24 + type PatchPos = distinct int CodePos = distinct int - Unit = ref object ## a NIR module + Bytecode* = object + code: seq[Instr] + debug: seq[PackedLineInfo] + m: ref NirModule procs: Table[SymId, CodePos] globals: Table[SymId, uint32] - integers: BiTable[int64] - strings: BiTable[string] - globalsGen: uint32 + 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]] Universe* = object ## all units: For interpretation we need that - units: Table[string, Unit] + units: seq[Bytecode] + unitNames: Table[string, int] + current: int - Bytecode = object - code: seq[Instr] - debug: seq[PackedLineInfo] - u: Unit +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 + +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 = b.m.lit.numbers[b.m.types[y].litId] + break + b.offsets.mgetOrPut(offsetKey, @[]).add (offset, x.firstSon) + of SizeVal: + size = b.m.lit.numbers[b.m.types[x].litId] + of AlignVal: + align = 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) @@ -146,7 +225,7 @@ proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; raw: uint32) = bc.debug.add info proc add(bc: var Bytecode; info: PackedLineInfo; kind: OpcodeM; lit: LitId) = - add bc, info, kind, uint(lit) + 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 @@ -175,6 +254,8 @@ proc nextChild(bc: Bytecode; pos: var int) {.inline.} = 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 @@ -184,88 +265,175 @@ iterator sons(bc: Bytecode; n: CodePos): CodePos = yield CodePos pos nextChild bc, pos -template `[]`*(t: Bytecode; n: CodePos): Instr = t.code[n.int] +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 + type Preprocessing = object + u: ref Universe known: Table[LabelId, CodePos] toPatch: Table[LabelId, seq[CodePos]] locals: Table[SymId, uint32] - c: Bytecode # to be moved out - thisModule: LitId + thisModule: uint32 + localsAddr: uint32 markedWithLabel: IntSet -proc genGoto(c: var Preprocessing; lab: LabelId; opc: OpcodeM) = +proc align(address, alignment: uint32): uint32 = + result = (address + (alignment - 1'u32)) and not (alignment - 1'u32) + +proc genGoto(c: var Preprocessing; bc: var Bytecode; info: PackedLineInfo; lab: LabelId; opc: OpcodeM) = let dest = c.known.getOrDefault(lab, CodePos(-1)) if dest.int >= 0: - c.bc.add info, opc, uint32 dest + bc.add info, opc, uint32 dest else: - let here = CodePos(c.bc.code.len) + let here = CodePos(bc.code.len) c.toPatch.mgetOrPut(lab, @[]).add here - c.bc.add info, opc, 1u32 # will be patched once we traversed the label + bc.add info, opc, 1u32 # will be patched once we traversed the label + +type + AddrMode = enum + InDotExpr, WantAddr + +template maybeDeref(doDeref: bool; body: untyped) = + var pos = PatchPos(-1) + if doDeref: + pos = prepare(bc, info, LoadM) + bc.add info, TypedM, 0'u32 + body + if doDeref: + patch(bc, pos) + +const + ForwardedProc = 10_000_000'u32 -proc preprocess(c: var Preprocessing; u: var Universe; t: Tree; n: NodePos) = +proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; flags: set[AddrMode]) = let info = t[n].info template recurse(opc) = - build c.bc, info, opc: - for c in sons(t, n): preprocess(c, u, t, c) + build bc, info, opc: + for ch in sons(t, n): preprocess(c, bc, t, ch, {WantAddr}) case t[n].kind of Nop: discard "don't use Nop" of ImmediateVal: - c.bc.add info, ImmediateValM, t[n].rawOperand + bc.add info, ImmediateValM, t[n].rawOperand of IntVal: - c.bc.add info, IntValM, t[n].rawOperand + bc.add info, IntValM, t[n].rawOperand of StrVal: - c.bc.add info, StrValM, t[n].rawOperand + bc.add info, StrValM, t[n].rawOperand of SymDef: - assert false, "SymDef outside of declaration context" + 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): - c.bc.add info, LoadLocalM, c.locals[s] - elif c.bc.u.procs.hasKey(s): - build c.bc, info, LoadProcM: - c.bc.add info, StrValM, thisModule - c.bc.add info, LoadLocalM, uint32 c.bc.u.procs[s] - elif c.bc.u.globals.hasKey(s): - build c.bc, info, LoadGlobalM: - c.bc.add info, StrValM, thisModule - c.bc.add info, LoadLocalM, uint32 s + maybeDeref(WantAddr notin flags): + bc.add info, LoadLocalM, c.locals[s] + elif bc.procs.hasKey(s): + bc.add info, LoadProcM, uint32 bc.procs[s] + elif bc.globals.hasKey(s): + maybeDeref(WantAddr notin flags): + bc.add info, LoadGlobalM, uint32 s else: - assert false, "don't understand SymUse ID" + 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: - let moduleName {.cursor.} = c.bc.u.strings[t[n.firstSon].litId] - let unit = u.units.getOrDefault(moduleName) + 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: - c.bc.add info, TypedM, t[n].rawOperand + bc.add info, TypedM, t[n].rawOperand of PragmaId: - c.bc.add info, TypedM, t[n].rawOperand + bc.add info, PragmaIdM, t[n].rawOperand of NilVal: - c.bc.add info, NilValM, t[n].rawOperand + bc.add info, NilValM, t[n].rawOperand of LoopLabel, Label: let lab = t[n].label - let here = CodePos(c.bc.code.len-1) + let here = CodePos(bc.code.len-1) c.known[lab] = here - var p: seq[CodePos] + var p: seq[CodePos] = @[] if c.toPatch.take(lab, p): - for x in p: c.bc.code[x] = toIns(c.bc.code[x].kind, here) + 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(t[n].label, GotoM) + c.genGoto(bc, info, t[n].label, GotoM) of CheckedGoto: - c.genGoto(t[n].label, CheckedGotoM) + c.genGoto(bc, info, t[n].label, CheckedGotoM) of ArrayConstr: - recurse ArrayConstrM + 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: - recurse ObjConstrM + 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: @@ -281,25 +449,120 @@ proc preprocess(c: var Preprocessing; u: var Universe; t: Tree; n: NodePos) = of SelectRange: recurse SelectRangeM of SummonGlobal, SummonThreadLocal, SummonConst: - #let s = - discard "xxx" - of Summon, SummonParam: - # x = Summon Typed ; x begins to live - discard "xxx" + 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 + 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 + 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 + 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: - recurse AddrOfM + 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: - recurse ArrayAtM + let (arrayType, a, i) = sons3(t, n) + let tid = t[arrayType].typeId + let size = uint32 computeElemSize(bc, tid) + if t[a].kind == Load: + let (_, arg) = sons2(t, a) + build bc, info, LoadM: + bc.add info, ImmediateValM, size + build bc, info, ArrayAtM: + bc.add info, ImmediateValM, size + preprocess(c, bc, t, arg, {WantAddr}) + preprocess(c, bc, t, i, {WantAddr}) + else: + build bc, info, ArrayAtM: + bc.add info, ImmediateValM, size + preprocess(c, bc, t, a, {WantAddr}) + preprocess(c, bc, t, i, {WantAddr}) of FieldAt: - recurse FieldAtM + # a[] conceptually loads a block of size of T. But when applied to an object selector + # only a subset of the data is really requested so `(a[] : T).field` + # becomes `(a+offset(field))[] : T_Field` + # And now if this is paired with `addr` the deref disappears, as usual: `addr x.field[]` + # is `(x+offset(field))`. + let (typ, a, b) = sons3(t, n) + if t[a].kind == Load: + let (_, arg) = sons2(t, a) + build bc, info, LoadM: + bc.add info, ImmediateValM, uint32 computeSize(bc, t[typ].typeId)[0] + let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0] + build bc, info, FieldAtM: + preprocess(c, bc, t, arg, flags+{WantAddr}) + bc.add info, ImmediateValM, uint32(offset) + else: + 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 Load: - recurse LoadM + 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: - recurse StoreM + raiseAssert "Assumption was that Store is unused!" of Asgn: - recurse AsgnM + 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, dest, {WantAddr}) + for ch in sons(t, src): preprocess(c, bc, t, ch, {WantAddr}) + elif t[src].kind in {CheckedCall, CheckedIndirectCall}: + build bc, info, CheckedCallM: + preprocess(c, bc, t, src.firstSon, {WantAddr}) + preprocess(c, bc, t, dest, {WantAddr}) + for ch in sonsFrom1(t, src): preprocess(c, bc, t, ch, {WantAddr}) + 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: @@ -308,14 +571,14 @@ proc preprocess(c: var Preprocessing; u: var Universe; t: Tree; n: NodePos) = recurse CheckedRangeM of CheckedIndex: recurse CheckedIndexM - of Call: - recurse CallM - of IndirectCall: - recurse IndirectCallM - of CheckedCall: - recurse CheckedCallM - of CheckedIndirectCall: - recurse CheckedIndirectCallM + 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: + build bc, info, CheckedCallM: + for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr}) of CheckedAdd: recurse CheckedAddM of CheckedSub: @@ -367,9 +630,20 @@ proc preprocess(c: var Preprocessing; u: var Universe; t: Tree; n: NodePos) = of TestOf: recurse TestOfM of Emit: - assert false, "cannot interpret: Emit" + raiseAssert "cannot interpret: Emit" of ProcDecl: - recurse ProcDeclM + 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) of PragmaPair: recurse PragmaPairM @@ -381,87 +655,399 @@ type 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) + 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 result.locals != addr(result.payload): - dealloc result.locals + 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 eval(c: seq[Instr]; pc: CodePos; s: StackFrame; result: pointer) +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 evalAddr(c: seq[Instr]; pc: CodePos; s: StackFrame): pointer = - case c[pc].kind +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[pc].operand + result = s.locals +! c.code[pc].operand of FieldAtM: - result = eval(c, pc+1, s) - result = result +! c[pc+2].operand + let (x, offset) = sons2(c.code, pc) + result = evalAddr(c, x, s) + result = result +! c.code[offset].operand of ArrayAtM: - let elemSize = c[pc+1].operand - result = eval(c, pc+2, s) - var idx: int - eval(c, pc+3, addr idx) - result = result +! (idx * elemSize) - -proc eval(c: seq[Instr]; pc: CodePos; s: StackFrame; result: pointer) = - case c[pc].kind - of AddM: - # assume `int` here for now: - var x, y: int - eval c, pc+1, s, addr x - eval c, pc+2, s, addr y - cast[ptr int](res)[] = x + y + 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 LoadM: + let (_, arg) = sons2(c.code, pc) + let p = evalAddr(c, arg, s) + result = cast[ptr pointer](p)[] + 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 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) + assert c.code[values].kind == SelectListM + 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 dest = s.locals +! c.code[pc].operand + copyMem dest, result, size + of FieldAtM, ArrayAtM, LoadM: + let dest = evalAddr(c, pc, s) + copyMem dest, result, 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: - cast[ptr StringDesc](res)[] = addr(c.strings[c[pc].litId]) + # binary compatible and no deep copy required: + copyMem(cast[ptr string](result), addr(c.m.lit.strings[c[pc].litId]), sizeof(string)) + # XXX not correct! of ObjConstrM: - for ch in sons(c, pc): - let offset = c[ch] - eval c, ch+2, s, result+!offset + for offset, size, val in triples(c, pc): + eval c, val, s, result+!offset, size of ArrayConstrM: - let elemSize = c[pc+1].operand + let elemSize = c.code[pc.firstSon].operand var r = result - for ch in sons(c, pc): - eval c, ch, s, r + 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 + 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" else: - assert false, "cannot happen" + #debug c, c.debug[pc.int] + raiseAssert "cannot happen: " & $c.code[pc].kind -proc exec(c: seq[Instr]; pc: CodePos) = - var pc = pc - var currentFrame: StackFrame = nil +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; s: StackFrame) = + type StringArray = object + len: int + data: ptr UncheckedArray[string] + var sa = default(StringArray) + for a in sonsFrom1(c, pc): + eval(c, a, s, addr(sa), sizeof(sa)) + for i in 0..= 0: + pc = pc2 + else: + next c, pc + of ProcDeclM: + next c, pc + else: + raiseAssert "unreachable" + +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: + preprocess c, bc, t, pc, {} + next t, pc + exec bc, start, nil diff --git a/compiler/nir/types2ir.nim b/compiler/nir/types2ir.nim index 76907d587000..4c3ce7001f87 100644 --- a/compiler/nir/types2ir.nim +++ b/compiler/nir/types2ir.nim @@ -15,11 +15,11 @@ type TypesCon* = object processed: Table[ItemId, TypeId] recursionCheck: HashSet[ItemId] - g*: TypeGraph conf: ConfigRef + stringType: TypeId -proc initTypesCon*(conf: ConfigRef; lit: Literals): TypesCon = - TypesCon(g: initTypeGraph(lit), conf: conf) +proc initTypesCon*(conf: ConfigRef): TypesCon = + TypesCon(conf: conf, stringType: TypeId(-1)) proc mangle(c: var TypesCon; t: PType): string = result = $sighashes.hashType(t, c.conf) @@ -30,131 +30,131 @@ template cached(c: var TypesCon; t: PType; body: untyped) = body c.processed[t.itemId] = result -proc typeToIr*(c: var TypesCon; t: PType): TypeId +proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId -proc collectFieldTypes(c: var TypesCon; n: PNode; dest: var Table[ItemId, TypeId]) = +proc collectFieldTypes(c: var TypesCon; g: var TypeGraph; n: PNode; dest: var Table[ItemId, TypeId]) = case n.kind of nkRecList: for i in 0..= 0, typeToString(t) - let p = openType(c.g, ObjectDecl) - c.g.addName typeName - c.g.addSize c.conf.target.ptrSize*2 - c.g.addAlign c.conf.target.ptrSize - - let f = c.g.openType FieldDecl - let arr = c.g.openType AArrayPtrTy - c.g.addType elementType - sealType(c.g, arr) # LastArrayTy - c.g.addOffset 0 - c.g.addName "data" - sealType(c.g, f) # FieldDecl - - c.g.addField "len", c.nativeInt, c.conf.target.ptrSize - - result = finishType(c.g, p) # ObjectDecl - -proc strPayloadType(c: var TypesCon): string = - result = "NimStrPayload" - let p = openType(c.g, ObjectDecl) - c.g.addName result - c.g.addSize c.conf.target.ptrSize*2 - c.g.addAlign c.conf.target.ptrSize - - c.g.addField "cap", c.nativeInt, 0 - - let f = c.g.openType FieldDecl - let arr = c.g.openType LastArrayTy - c.g.addBuiltinType Char8Id - sealType(c.g, arr) # LastArrayTy - c.g.addOffset c.conf.target.ptrSize # comes after the len field - c.g.addName "data" - sealType(c.g, f) # FieldDecl - - 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 = finishType(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 @@ -232,86 +232,86 @@ 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.addSize c.conf.target.ptrSize*2 - c.g.addAlign c.conf.target.ptrSize + let str = openType(g, ObjectDecl) + g.addName "NimStringV2" + g.addSize c.conf.target.ptrSize*2 + g.addAlign c.conf.target.ptrSize - c.g.addField "len", c.nativeInt, 0 + g.addField "len", c.nativeInt, 0 - let fp = c.g.openType FieldDecl - let ffp = c.g.openType APtrTy - c.g.addNominalType ObjectTy, "NimStrPayload" - sealType(c.g, ffp) # APtrTy - c.g.addOffset c.conf.target.ptrSize # comes after 'len' field - c.g.addName "p" - sealType(c.g, fp) # FieldDecl + 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 - result = finishType(c.g, str) # ObjectDecl + result = finishType(g, str) # ObjectDecl -proc seqPayloadType(c: var TypesCon; t: PType): string = +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.addSize c.conf.target.intSize - c.g.addAlign c.conf.target.intSize - - c.g.addField "cap", c.nativeInt, 0 - - let f = c.g.openType FieldDecl - let arr = c.g.openType LastArrayTy - c.g.addType elementType - sealType(c.g, arr) # LastArrayTy - c.g.addOffset c.conf.target.ptrSize - c.g.addName "data" - sealType(c.g, f) # FieldDecl - 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 = finishType(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 + result[1] = finishType(g, arr) # LastArrayTy + 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.addSize c.conf.getSize(t) - c.g.addAlign c.conf.getAlign(t) + let sq = openType(g, ObjectDecl) + g.addName "NimSeqV2" & mangledBase + g.addSize c.conf.getSize(t) + g.addAlign c.conf.getAlign(t) - c.g.addField "len", c.nativeInt, 0 + g.addField "len", c.nativeInt, 0 - let fp = c.g.openType FieldDecl - let ffp = c.g.openType APtrTy - c.g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase - sealType(c.g, ffp) # APtrTy - c.g.addOffset c.conf.target.ptrSize - c.g.addName "p" - sealType(c.g, fp) # FieldDecl + 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(c.g, sq) # ObjectDecl + 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" & @@ -319,31 +319,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 - c.g.addSize c.conf.getSize(t) - c.g.addAlign c.conf.getAlign(t) + 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.addOffset 0 - c.g.addName "ClP_0" - 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) - sealType(c.g, voidPtr) + let f2 = g.openType FieldDecl + let voidPtr = openType(g, APtrTy) + g.addBuiltinType(VoidId) + sealType(g, voidPtr) - c.g.addOffset c.conf.target.ptrSize - c.g.addName "ClE_0" - sealType(c.g, f2) # FieldDecl + g.addOffset c.conf.target.ptrSize + g.addName "ClE_0" + sealType(g, f2) # FieldDecl - result = finishType(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 @@ -352,7 +352,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: @@ -370,7 +370,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 @@ -384,7 +384,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 @@ -397,47 +397,47 @@ 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 n - result = finishType(c.g, a) + let elemType = typeToIr(c, g, t[1]) + let a = openType(g, ArrayTy) + g.addType(elemType) + g.addArrayLen n + 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 = finishType(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 = finishType(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 = finishType(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 @@ -448,54 +448,57 @@ 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 s - result = finishType(c.g, a) + let a = openType(g, ArrayTy) + g.addType(UInt8Id) + g.addArrayLen s + 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(c.g, APtrTy) - c.g.addBuiltinType(VoidId) - result = finishType(c.g, a) + 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) + 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) + result = seqToIr(c, g, t) of tyCstring: cached(c, t): - let a = openType(c.g, AArrayPtrTy) - c.g.addBuiltinType Char8Id - result = finishType(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 = finishType(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]`: 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".} From e17237ce9dbf5410623e9d510217e7817bf4fd89 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 29 Oct 2023 21:48:11 +0800 Subject: [PATCH 24/41] prepare for the enforcement of `std` prefix (#22873) follow up https://github.com/nim-lang/Nim/pull/22851 --- compiler/aliases.nim | 4 +++- compiler/ast.nim | 6 ++++-- compiler/astalgo.nim | 7 ++++--- compiler/ccgtypes.nim | 2 +- compiler/ccgutils.nim | 4 +++- compiler/cgen.nim | 12 ++++++------ compiler/cgendata.nim | 6 ++++-- compiler/cgmeth.nim | 5 ++++- compiler/closureiters.nim | 4 +++- compiler/cmdlinehelper.nim | 4 +++- compiler/commands.nim | 4 +++- compiler/concepts.nim | 4 +++- compiler/condsyms.nim | 3 ++- compiler/depends.nim | 2 +- compiler/dfa.nim | 3 ++- compiler/docgen.nim | 11 ++++++----- compiler/errorhandling.nim | 3 ++- compiler/evalffi.nim | 6 ++++-- compiler/evaltempl.nim | 4 ++-- compiler/filter_tmpl.nim | 4 +++- compiler/filters.nim | 4 +++- compiler/gorgeimpl.nim | 5 +++-- compiler/guards.nim | 2 +- compiler/ic/bitabs.nim | 3 ++- compiler/ic/cbackend.nim | 2 +- compiler/ic/ic.nim | 4 ++-- compiler/ic/integrity.nim | 2 +- compiler/ic/navigator.nim | 4 ++-- compiler/ic/packed_ast.nim | 2 +- compiler/ic/replayer.nim | 2 +- compiler/ic/rodfiles.nim | 2 +- compiler/idents.nim | 4 ++-- compiler/importer.nim | 15 ++++++++++----- compiler/injectdestructors.nim | 6 ++++-- compiler/int128.nim | 4 ++-- compiler/isolation_check.nim | 4 +++- compiler/jsgen.nim | 4 ++-- compiler/lambdalifting.nim | 6 ++++-- compiler/lexer.nim | 6 ++++-- compiler/liftdestructors.nim | 3 ++- compiler/liftlocals.nim | 4 +++- compiler/lineinfos.nim | 7 +++++-- compiler/lookups.nim | 8 +++++--- compiler/modulegraphs.nim | 2 +- compiler/modulepaths.nim | 4 +++- compiler/nilcheck.nim | 4 ++-- compiler/nim.cfg | 5 +++++ compiler/nim.nim | 2 +- compiler/nimblecmd.nim | 5 +++-- compiler/nimconf.nim | 6 ++++-- compiler/nimlexbase.nim | 5 +++-- compiler/nimpaths.nim | 2 +- compiler/nir/nir.nim | 2 +- compiler/nir/stringcases.nim | 2 +- compiler/nodejs.nim | 2 +- compiler/optimizer.nim | 4 ++-- compiler/options.nim | 11 ++++++----- compiler/parampatterns.nim | 4 +++- compiler/parser.nim | 4 +++- compiler/pathutils.nim | 2 +- compiler/platform.nim | 2 +- compiler/pragmas.nim | 6 ++++-- compiler/prefixmatches.nim | 2 +- compiler/procfind.nim | 4 +++- compiler/renderer.nim | 4 +++- compiler/renderverbatim.nim | 2 +- compiler/reorder.nim | 4 +++- compiler/rodutils.nim | 2 +- compiler/scriptconfig.nim | 6 ++++-- compiler/sem.nim | 11 +++++------ compiler/semdata.nim | 6 +++--- compiler/semfold.nim | 7 ++++--- compiler/semobjconstr.nim | 2 +- compiler/semparallel.nim | 2 +- compiler/sempass2.nim | 8 +++++--- compiler/sighashes.nim | 5 +++-- compiler/sigmatch.nim | 6 ++++-- compiler/suggest.nim | 6 ++++-- compiler/syntaxes.nim | 3 ++- compiler/treetab.nim | 5 +++-- compiler/typeallowed.nim | 4 ++-- compiler/types.nim | 4 +++- compiler/typesrenderer.nim | 3 ++- compiler/vmdeps.nim | 4 +++- compiler/vmgen.nim | 6 +++--- compiler/vmmarshal.nim | 4 +++- compiler/vmprofiler.nim | 6 +++--- compiler/wordrecg.nim | 2 +- 88 files changed, 244 insertions(+), 149 deletions(-) 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 8d4511436ff3..5ee9afa024de 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 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/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 0e35cc3e8c27..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 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/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..65b1e5a0ed07 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 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 3505bfdfb861..db520527bce6 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] diff --git a/compiler/idents.nim b/compiler/idents.nim index f36ce09f3c48..34177e76defd 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -11,8 +11,8 @@ # An identifier is a shared immutable string that can be compared by its # id. This module is essential for the compiler's performance. -import - hashes, wordrecg +import wordrecg +import std/hashes when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/importer.nim b/compiler/importer.nim index dcdd0bb49e43..ff1f9f63ef04 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -10,11 +10,12 @@ ## This module implements the symbol importing mechanism. import - intsets, ast, astalgo, msgs, options, idents, lookups, - semdata, modulepaths, sigmatch, lineinfos, sets, - modulegraphs, wordrecg, tables -from strutils import `%` -from sequtils import addUnique + ast, astalgo, msgs, options, idents, lookups, + semdata, modulepaths, sigmatch, lineinfos, + modulegraphs, wordrecg +from std/strutils import `%`, startsWith +from std/sequtils import addUnique +import std/[sets, tables, intsets] when defined(nimPreviewSlimSystem): import std/assertions @@ -301,6 +302,10 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym = var prefix = "" if realModule.constraint != nil: prefix = realModule.constraint.strVal & "; " message(c.config, n.info, warnDeprecated, prefix & realModule.name.s & " is deprecated") + let moduleName = getModuleName(c.config, n) + if belongsToStdlib(c.graph, result) and not startsWith(moduleName, stdPrefix) and + not startsWith(moduleName, "system/") and not startsWith(moduleName, "packages/"): + message(c.config, n.info, warnStdPrefix, realModule.name.s) suggestSym(c.graph, n.info, result, c.graph.usageSym, false) importStmtResult.add newSymNode(result, n.info) #newStrNode(toFullPath(c.config, f), n.info) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index a5ec6c21a691..6b3fdeca5aac 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -14,11 +14,13 @@ ## See doc/destructors.rst for a spec of the implemented rewrite rules import - intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents, - strutils, options, lowerings, tables, modulegraphs, + ast, astalgo, msgs, renderer, magicsys, types, idents, + options, lowerings, modulegraphs, lineinfos, parampatterns, sighashes, liftdestructors, optimizer, varpartitions, aliasanalysis, dfa, wordrecg +import std/[strtabs, tables, strutils, intsets] + when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/int128.nim b/compiler/int128.nim index 18e751f98964..ca06a3a9743b 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -3,7 +3,7 @@ ## hold all from `low(BiggestInt)` to `high(BiggestUInt)`, This ## type is for that purpose. -from math import trunc +from std/math import trunc when defined(nimPreviewSlimSystem): import std/assertions @@ -358,7 +358,7 @@ proc `*`*(lhs, rhs: Int128): Int128 = proc `*=`*(a: var Int128, b: Int128) = a = a * b -import bitops +import std/bitops proc fastLog2*(a: Int128): int = result = 0 diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 5fd1b8d51b5c..b11d64a6b9dd 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -11,7 +11,9 @@ ## https://github.com/nim-lang/RFCs/issues/244 for more details. import - ast, types, renderer, intsets + ast, types, renderer + +import std/intsets when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 6b57c097f3b7..74edb469485f 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -37,8 +37,8 @@ import import pipelineutils -import json, sets, math, tables, intsets -import strutils except addf +import std/[json, sets, math, tables, intsets] +import std/strutils except addf when defined(nimPreviewSlimSystem): import std/[assertions, syncio] diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index fdba7ba3d147..248effcaf8ff 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -10,10 +10,12 @@ # This file implements lambda lifting for the transformator. import - intsets, strutils, options, ast, astalgo, msgs, - idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos, + options, ast, astalgo, msgs, + idents, renderer, types, magicsys, lowerings, modulegraphs, lineinfos, transf, liftdestructors, typeallowed +import std/[strutils, tables, intsets] + when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 93a5f80406f9..5aed19636247 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -16,8 +16,10 @@ # DOS or Macintosh text files, even when it is not the native format. import - hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream, - wordrecg, lineinfos, pathutils, parseutils + options, msgs, platform, idents, nimlexbase, llstream, + wordrecg, lineinfos, pathutils + +import std/[hashes, parseutils, strutils] when defined(nimPreviewSlimSystem): import std/[assertions, formatfloat] diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index a73df046ef8d..ea0d6e6f8b01 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -11,8 +11,9 @@ ## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`). import modulegraphs, lineinfos, idents, ast, renderer, semdata, - sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils + sighashes, lowerings, options, types, msgs, magicsys, ccgutils +import std/tables from trees import isCaseObj when defined(nimPreviewSlimSystem): diff --git a/compiler/liftlocals.nim b/compiler/liftlocals.nim index 58c6189d4098..aaa0707e053d 100644 --- a/compiler/liftlocals.nim +++ b/compiler/liftlocals.nim @@ -10,9 +10,11 @@ ## This module implements the '.liftLocals' pragma. import - strutils, options, ast, msgs, + options, ast, msgs, idents, renderer, types, lowerings, lineinfos +import std/strutils + from pragmas import getPragmaVal from wordrecg import wLiftLocals diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 544c5295c7bc..ef3222288a22 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -10,7 +10,8 @@ ## This module contains the `TMsgKind` enum as well as the ## `TLineInfo` object. -import ropes, tables, pathutils, hashes +import ropes, pathutils +import std/[hashes, tables] const explanationsBaseUrl* = "https://nim-lang.github.io/Nim" @@ -91,6 +92,7 @@ type warnStmtListLambda = "StmtListLambda", warnBareExcept = "BareExcept", warnImplicitDefaultValue = "ImplicitDefaultValue", + warnStdPrefix = "StdPrefix" warnUser = "User", # hints hintSuccess = "Success", hintSuccessX = "SuccessX", @@ -194,6 +196,7 @@ const warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead", warnBareExcept: "$1", warnImplicitDefaultValue: "$1", + warnStdPrefix: "$1 needs the 'std' prefix", warnUser: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` @@ -249,7 +252,7 @@ type proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result = default(array[0..3, TNoteKinds]) - result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept} + result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept, warnStdPrefix} result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 2bdf3a1e0725..1a60de7e532b 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -14,8 +14,10 @@ when defined(nimPreviewSlimSystem): import std/assertions import - intsets, ast, astalgo, idents, semdata, types, msgs, options, - renderer, lineinfos, modulegraphs, astmsgs, sets, wordrecg + ast, astalgo, idents, semdata, types, msgs, options, + renderer, lineinfos, modulegraphs, astmsgs, wordrecg + +import std/[intsets, sets] proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) @@ -464,7 +466,7 @@ proc mergeShadowScope*(c: PContext) = c.addInterfaceDecl(sym) -import std/editdistance, heapqueue +import std/[editdistance, heapqueue] type SpellCandidate = object dist: int diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index c450af50f325..325c0adb1d5f 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -11,7 +11,7 @@ ## represents a complete Nim project. Single modules can either be kept in RAM ## or stored in a rod-file. -import intsets, tables, hashes +import std/[intsets, tables, hashes] import ../dist/checksums/src/checksums/md5 import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages import ic / [packed_ast, ic] diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index e80ea3fa6632..c29ed6793c2e 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -7,9 +7,11 @@ # distribution, for details about the copyright. # -import ast, renderer, strutils, msgs, options, idents, os, lineinfos, +import ast, renderer, msgs, options, idents, lineinfos, pathutils +import std/[strutils, os] + proc getModuleName*(conf: ConfigRef; n: PNode): string = # This returns a short relative module name without the nim extension # e.g. like "system", "importer" or "somepath/module" diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index 96e0967702cb..1713a888f80f 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -7,8 +7,8 @@ # distribution, for details about the copyright. # -import ast, renderer, intsets, tables, msgs, options, lineinfos, strformat, idents, treetab, hashes -import sequtils, strutils, sets +import ast, renderer, msgs, options, lineinfos, idents, treetab +import std/[intsets, tables, sequtils, strutils, sets, strformat, hashes] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 04005368512c..e4425065e704 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -41,6 +41,7 @@ define:useStdoutAsStdmsg @end @if nimHasWarnBareExcept: + warning[BareExcept]:on warningAserror[BareExcept]:on @end @@ -51,3 +52,7 @@ define:useStdoutAsStdmsg warningAsError[ProveInit]:on @end +@if nimHasWarnStdPrefix: + warning[StdPrefix]:on + warningAsError[StdPrefix]:on +@end diff --git a/compiler/nim.nim b/compiler/nim.nim index 7ec6f3e77d4f..184303f8eab7 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -28,7 +28,7 @@ import commands, options, msgs, extccomp, main, idents, lineinfos, cmdlinehelper, pathutils, modulegraphs -from browsers import openDefaultBrowser +from std/browsers import openDefaultBrowser from nodejs import findNodeJs when hasTinyCBackend: diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 97a66f1cd99f..4b6e22bc9d77 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -9,8 +9,9 @@ ## Implements some helper procs for Nimble (Nim's package manager) support. -import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils, - tables +import options, msgs, lineinfos, pathutils + +import std/[parseutils, strutils, os, tables, sequtils] when defined(nimPreviewSlimSystem): import std/[syncio, assertions] diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 78215d281a66..3a811a106168 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -10,8 +10,10 @@ # This module handles the reading of the config file. import - llstream, commands, os, strutils, msgs, lexer, ast, - options, idents, wordrecg, strtabs, lineinfos, pathutils, scriptconfig + llstream, commands, msgs, lexer, ast, + options, idents, wordrecg, lineinfos, pathutils, scriptconfig + +import std/[os, strutils, strtabs] when defined(nimPreviewSlimSystem): import std/syncio diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim index 3bc9af9c905a..6708b57f805d 100644 --- a/compiler/nimlexbase.nim +++ b/compiler/nimlexbase.nim @@ -12,8 +12,9 @@ # handling that exists! Only at line endings checks are necessary # if the buffer needs refilling. -import - llstream, strutils +import llstream + +import std/strutils when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/nimpaths.nim b/compiler/nimpaths.nim index 3756f956b57c..0a66c3c1fdfb 100644 --- a/compiler/nimpaths.nim +++ b/compiler/nimpaths.nim @@ -17,7 +17,7 @@ interpolation variables: Unstable API ]## -import os, strutils +import std/[os, strutils] when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/nir/nir.nim b/compiler/nir/nir.nim index c4fb5322d5a0..1efa6719a11a 100644 --- a/compiler/nir/nir.nim +++ b/compiler/nir/nir.nim @@ -10,7 +10,7 @@ ## 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. -from os import addFileExt, `/`, createDir +from std/os import addFileExt, `/`, createDir import std / assertions import ".." / [ast, modulegraphs, renderer, transf, options, msgs, lineinfos] diff --git a/compiler/nir/stringcases.nim b/compiler/nir/stringcases.nim index 9417d613d0a9..afdf8fda4f4a 100644 --- a/compiler/nir/stringcases.nim +++ b/compiler/nir/stringcases.nim @@ -49,7 +49,7 @@ afterCase: ... # Every string of length > position for which s[position] <= char is in one # set else it is in the other set. -from sequtils import addUnique +from std/sequtils import addUnique type Key = (LitId, LabelId) 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 b36f72693adf..f2d93a9b3a09 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): @@ -890,7 +891,7 @@ const stdlibDirs* = [ const pkgPrefix = "pkg/" - stdPrefix = "std/" + stdPrefix* = "std/" proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile, isTitle = false): RelativeFile = result = RelativeFile("") 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/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/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/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/suggest.nim b/compiler/suggest.nim index 5554991bd736..5714c6d21102 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' 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 cdb3067c307f..31563b71f7e4 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] 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) From 403e0118ae8d099384e9bd6a046c2114538503b8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 29 Oct 2023 21:53:28 +0100 Subject: [PATCH 25/41] NIR: progress (#22884) --- compiler/nir/ast2ir.nim | 32 ++++++++++++---- compiler/nir/nirinsts.nim | 2 +- compiler/nir/nirvm.nim | 81 ++++++++++++++++++++++++++++++++++----- 3 files changed, 96 insertions(+), 19 deletions(-) diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim index b1a90e9bf25d..f3b68474b00b 100644 --- a/compiler/nir/ast2ir.nim +++ b/compiler/nir/ast2ir.nim @@ -26,7 +26,6 @@ type types: TypesCon module*: PSym graph*: ModuleGraph - symnames*: SymNames nativeIntId, nativeUIntId: TypeId strPayloadId: (TypeId, TypeId) idgen: IdGenerator @@ -72,10 +71,11 @@ proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; m result.strPayloadId = strPayloadPtrType(result.types, result.nirm.types) proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon = - ProcCon(m: m, sm: initSlotManager({}), prc: prc, config: config, + result = ProcCon(m: m, sm: initSlotManager({}), prc: prc, config: config, lit: m.nirm.lit, idgen: m.idgen, options: if prc != nil: prc.options else: config.options) + result.exitLabel = newLabel(result.labelGen) proc toLineInfo(c: var ProcCon; i: TLineInfo): PackedLineInfo = var val: LitId @@ -121,6 +121,9 @@ proc freeTemp(c: var ProcCon; tmp: Value) = if s != SymId(-1): freeTemp(c.sm, s) +proc freeTemps(c: var ProcCon; tmps: openArray[Value]) = + for t in tmps: freeTemp(c, t) + proc typeToIr(m: ModuleCon; t: PType): TypeId = typeToIr(m.types, m.nirm.types, t) @@ -482,6 +485,7 @@ proc genCall(c: var ProcCon; n: PNode; d: var Value) = rawCall c, info, opc, tb, args else: rawCall c, info, opc, tb, args + freeTemps c, args proc genRaise(c: var ProcCon; n: PNode) = let info = toLineInfo(c, n.info) @@ -694,6 +698,16 @@ template valueIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: copyTree c.code, d body(c.code) +template constrIntoDest(c: var ProcCon; info: PackedLineInfo; d: var Value; typ: PType; body: untyped) = + var tmp = default(Value) + body(Tree tmp) + if isEmpty(d): + d = tmp + else: + buildTyped c.code, info, Asgn, typeToIr(c.m, typ): + copyTree c.code, d + copyTree c.code, tmp + proc genBinaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) = let info = toLineInfo(c, n.info) let tmp = c.genx(n[1]) @@ -702,7 +716,7 @@ proc genBinaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) = template body(target) = buildTyped target, info, opc, t: if optOverflowCheck in c.options and opc in {CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedMod}: - c.code.addLabel info, CheckedGoto, c.exitLabel + target.addLabel info, CheckedGoto, c.exitLabel copyTree target, tmp copyTree target, tmp2 intoDest d, info, t, body @@ -2060,7 +2074,7 @@ proc genObjOrTupleConstr(c: var ProcCon; n: PNode; d: var Value; t: PType) = target.addImmediateVal info, 1 # "name" field is at position after the "parent". See system.nim target.addStrVal c.lit.strings, info, t.skipTypes(abstractInst).sym.name.s - valueIntoDest c, info, d, t, body + constrIntoDest c, info, d, t, body proc genRefObjConstr(c: var ProcCon; n: PNode; d: var Value) = if isEmpty(d): d = getTemp(c, n) @@ -2110,7 +2124,7 @@ proc genArrayConstr(c: var ProcCon; n: PNode, d: var Value) = copyTree target, tmp c.freeTemp(tmp) - valueIntoDest c, info, d, n.typ, body + constrIntoDest c, info, d, n.typ, body proc genAsgn2(c: var ProcCon; a, b: PNode) = assert a != nil @@ -2140,7 +2154,7 @@ proc genVarSection(c: var ProcCon; n: PNode) = #assert t.int >= 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.symnames[symId] = c.lit.strings.getOrIncl(s.name.s) + c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s) if a[2].kind != nkEmpty: genAsgn2(c, vn, a[2]) else: @@ -2347,7 +2361,7 @@ proc genParams(c: var ProcCon; params: PNode; prc: PSym) = assert t.int != -1, typeToString(s.typ) let symId = toSymId(c, s) c.code.addSummon toLineInfo(c, params[i].info), symId, t, SummonParam - c.m.symnames[symId] = c.lit.strings.getOrIncl(s.name.s) + c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(s.name.s) proc addCallConv(c: var ProcCon; info: PackedLineInfo; callConv: TCallingConvention) = template ann(s: untyped) = c.code.addPragmaId info, s @@ -2380,7 +2394,7 @@ proc genProc(cOuter: var ProcCon; prc: PSym) = build c.code, info, ProcDecl: let symId = toSymId(c, prc) addSymDef c.code, info, symId - c.m.symnames[symId] = c.lit.strings.getOrIncl(prc.name.s) + c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(prc.name.s) addCallConv c, info, prc.typ.callConv if sfCompilerProc in prc.flags: build c.code, info, PragmaPair: @@ -2412,6 +2426,8 @@ proc genProc(cOuter: var ProcCon; prc: PSym) = genParams(c, prc.typ.n, prc) gen(c, body) patch c, body, c.exitLabel + build c.code, info, Ret: + discard #copyTree cOuter.code, c.code dec cOuter.m.inProc diff --git a/compiler/nir/nirinsts.nim b/compiler/nir/nirinsts.nim index 7b281e876884..87300440829b 100644 --- a/compiler/nir/nirinsts.nim +++ b/compiler/nir/nirinsts.nim @@ -380,7 +380,7 @@ proc addNilVal*(t: var Tree; info: PackedLineInfo; typ: TypeId) = 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) = +proc escapeToNimLit*(s: string; result: var string) = result.add '"' for c in items s: if c < ' ' or int(c) >= 128: diff --git a/compiler/nir/nirvm.nim b/compiler/nir/nirvm.nim index b58f482724f9..1f2f4e326cd4 100644 --- a/compiler/nir/nirvm.nim +++ b/compiler/nir/nirvm.nim @@ -30,6 +30,8 @@ type TypedM, # with type ID PragmaIdM, # with Pragma ID, possible values: see PragmaKey enum NilValM, + AllocLocals, + SummonParamM, GotoM, CheckedGotoM, # last atom @@ -43,8 +45,6 @@ type SelectListM, # (values...) SelectValueM, # (value) SelectRangeM, # (valueA..valueB) - AllocLocals, - SummonParamM, AddrOfM, ArrayAtM, # (elemSize, addr(a), i) @@ -144,6 +144,11 @@ 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) = @@ -307,6 +312,50 @@ iterator triples*(bc: Bytecode; n: CodePos): (uint32, int, CodePos) = 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: + 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.. Date: Tue, 31 Oct 2023 00:03:04 +0800 Subject: [PATCH 26/41] complete std prefixes for stdlib (#22887) follow up https://github.com/nim-lang/Nim/pull/22851 follow up https://github.com/nim-lang/Nim/pull/22873 --- doc/astspec.txt | 12 ++++++------ doc/docgen_sample.nim | 2 +- doc/estp.md | 2 +- doc/manual.md | 6 +++--- doc/manual_experimental.md | 2 +- lib/core/hotcodereloading.nim | 2 +- lib/deprecated/pure/future.nim | 2 +- lib/deprecated/pure/ospaths.nim | 2 +- lib/deprecated/pure/oswalkdir.nim | 6 +++--- lib/experimental/diff.nim | 2 +- lib/impure/nre.nim | 10 +++++----- lib/impure/nre/private/util.nim | 2 +- lib/impure/rdstdin.nim | 2 +- lib/impure/re.nim | 2 +- lib/nimhcr.nim | 2 +- lib/nimrtl.nim | 4 ++-- lib/packages/docutils/dochelpers.nim | 3 ++- lib/packages/docutils/highlite.nim | 4 ++-- lib/packages/docutils/rst.nim | 6 ++++-- lib/packages/docutils/rstast.nim | 2 +- lib/packages/docutils/rstgen.nim | 6 +++--- lib/packages/docutils/rstidx.nim | 4 ++-- lib/posix/epoll.nim | 2 +- lib/posix/kqueue.nim | 2 +- lib/posix/linux.nim | 2 +- lib/posix/posix_utils.nim | 2 +- lib/posix/termios.nim | 2 +- lib/pure/async.nim | 4 ++-- lib/pure/asyncdispatch.nim | 20 ++++++++++---------- lib/pure/asyncfile.nim | 6 +++--- lib/pure/asyncfutures.nim | 4 ++-- lib/pure/asynchttpserver.nim | 6 +++--- lib/pure/asyncmacro.nim | 2 +- lib/pure/asyncnet.nim | 4 ++-- lib/pure/asyncstreams.nim | 4 ++-- lib/pure/bitops.nim | 2 +- lib/pure/browsers.nim | 10 +++++----- lib/pure/cgi.nim | 2 +- lib/pure/collections/deques.nim | 2 +- lib/pure/collections/sequtils.nim | 4 ++-- lib/pure/collections/sets.nim | 2 +- lib/pure/collections/sharedlist.nim | 2 +- lib/pure/collections/sharedtables.nim | 2 +- lib/pure/collections/tables.nim | 2 +- lib/pure/colors.nim | 4 ++-- lib/pure/complex.nim | 2 +- lib/pure/concurrency/cpuinfo.nim | 2 +- lib/pure/concurrency/cpuload.nim | 6 +++--- lib/pure/concurrency/threadpool.nim | 2 +- lib/pure/cookies.nim | 2 +- lib/pure/coro.nim | 5 ++--- lib/pure/dynlib.nim | 2 +- lib/pure/encodings.nim | 4 ++-- lib/pure/htmlgen.nim | 4 ++-- lib/pure/htmlparser.nim | 4 ++-- lib/pure/httpcore.nim | 2 +- lib/pure/ioselects/ioselectors_epoll.nim | 2 +- lib/pure/ioselects/ioselectors_kqueue.nim | 2 +- lib/pure/ioselects/ioselectors_poll.nim | 2 +- lib/pure/ioselects/ioselectors_select.nim | 4 ++-- lib/pure/json.nim | 10 +++++----- lib/pure/lexbase.nim | 2 +- lib/pure/logging.nim | 4 ++-- lib/pure/marshal.nim | 2 +- lib/pure/math.nim | 2 +- lib/pure/memfiles.nim | 6 +++--- lib/pure/mimetypes.nim | 4 ++-- lib/pure/nativesockets.nim | 6 +++--- lib/pure/net.nim | 20 ++++++++++---------- lib/pure/nimprof.nim | 4 ++-- lib/pure/oids.nim | 2 +- lib/pure/options.nim | 2 +- lib/pure/os.nim | 6 +++--- lib/pure/osproc.nim | 14 +++++++------- lib/pure/parsecfg.nim | 2 +- lib/pure/parsecsv.nim | 4 ++-- lib/pure/parsejson.nim | 2 +- lib/pure/parseopt.nim | 2 +- lib/pure/parsesql.nim | 4 ++-- lib/pure/parsexml.nim | 8 ++++---- lib/pure/pegs.nim | 4 ++-- lib/pure/random.nim | 4 ++-- lib/pure/rationals.nim | 2 +- lib/pure/reservedmem.nim | 4 ++-- lib/pure/ropes.nim | 2 +- lib/pure/segfaults.nim | 4 ++-- lib/pure/selectors.nim | 8 ++++---- lib/pure/ssl_certs.nim | 4 ++-- lib/pure/stats.nim | 2 +- lib/pure/streams.nim | 2 +- lib/pure/streamwrapper.nim | 2 +- lib/pure/strformat.nim | 4 ++-- lib/pure/strscans.nim | 2 +- lib/pure/strtabs.nim | 2 +- lib/pure/strutils.nim | 8 ++++---- lib/pure/sugar.nim | 2 +- lib/pure/terminal.nim | 18 +++++++++--------- lib/pure/times.nim | 8 ++++---- lib/pure/typetraits.nim | 2 +- lib/pure/unittest.nim | 6 +++--- lib/pure/xmlparser.nim | 4 ++-- lib/pure/xmltree.nim | 2 +- lib/std/cmdline.nim | 4 ++-- lib/std/decls.nim | 2 +- lib/std/dirs.nim | 2 +- lib/std/editdistance.nim | 2 +- lib/std/effecttraits.nim | 2 +- lib/std/enumerate.nim | 2 +- lib/std/enumutils.nim | 4 ++-- lib/std/envvars.nim | 2 +- lib/std/exitprocs.nim | 2 +- lib/std/files.nim | 2 +- lib/std/genasts.nim | 2 +- lib/std/jsonutils.nim | 8 ++++---- lib/std/monotimes.nim | 4 ++-- lib/std/oserrors.nim | 2 +- lib/std/outparams.nim | 2 +- lib/std/packedsets.nim | 2 +- lib/std/paths.nim | 2 +- lib/std/private/globs.nim | 6 +++--- lib/std/private/oscommon.nim | 4 ++-- lib/std/private/osdirs.nim | 4 ++-- lib/std/private/osfiles.nim | 4 ++-- lib/std/private/ospaths2.nim | 6 +++--- lib/std/private/ossymlinks.nim | 4 ++-- lib/std/private/underscored_calls.nim | 2 +- lib/std/setutils.nim | 2 +- lib/std/sha1.nim | 4 ++-- lib/std/socketstreams.nim | 2 +- lib/std/symlinks.nim | 2 +- lib/std/sysatomics.nim | 2 +- lib/std/sysrand.nim | 2 +- lib/std/tempfiles.nim | 4 ++-- lib/std/time_t.nim | 2 +- lib/std/with.nim | 2 +- lib/std/wordwrap.nim | 2 +- lib/std/wrapnils.nim | 4 ++-- lib/system/gc.nim | 2 +- lib/system/gc_ms.nim | 2 +- lib/system/seqs_v2.nim | 2 +- lib/windows/winlean.nim | 2 +- lib/wrappers/openssl.nim | 16 ++++++++-------- 142 files changed, 277 insertions(+), 275 deletions(-) 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_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 0e447fd123d3..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 @@ -5231,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 4ba56205acd0..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) 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 422b1b68c792..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 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 e442557ef29c..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 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/sets.nim b/lib/pure/collections/sets.nim index 62abd68d4442..220ef3bb63cc 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.} 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/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 8bf149721419..62919546f2b2 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -49,7 +49,7 @@ {.deprecated: "use `nimble install htmlparser` and import `pkg/htmlparser` instead".} -import strutils, streams, parsexml, xmltree, unicode, strtabs +import std/[strutils, streams, parsexml, xmltree, unicode, strtabs] when defined(nimPreviewSlimSystem): import std/syncio @@ -2064,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/httpcore.nim b/lib/pure/httpcore.nim index 3b5cbc3cfc9e..5b3d7b45b131 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 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 593bd2d56f39..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 diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 129c15fbf777..d77ab5db1681 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -93,9 +93,9 @@ import std/private/since when defined(nimPreviewSlimSystem): import std/assertions -import nativesockets -import os, strutils, times, sets, options, std/monotimes -import ssl_config +import std/nativesockets +import std/[os, strutils, times, sets, options, monotimes] +import std/ssl_config export nativesockets.Port, nativesockets.`$`, nativesockets.`==` export Domain, SockType, Protocol @@ -105,12 +105,12 @@ const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr const defineSsl = defined(ssl) or defined(nimdoc) when useWinVersion: - from winlean import WSAESHUTDOWN + from std/winlean import WSAESHUTDOWN when defineSsl: - import openssl + import std/openssl when not defined(nimDisableCertificateValidation): - from ssl_certs import scanSSLCertificates + from std/ssl_certs import scanSSLCertificates # Note: The enumerations are mapped to Window's constants. @@ -209,7 +209,7 @@ when defined(nimHasStyleChecks): when defined(posix) and not defined(lwip): - from posix import TPollfd, POLLIN, POLLPRI, POLLOUT, POLLWRBAND, Tnfds + from std/posix import TPollfd, POLLIN, POLLPRI, POLLOUT, POLLWRBAND, Tnfds template monitorPollEvent(x: var SocketHandle, y: cint, timeout: int): int = var tpollfd: TPollfd @@ -1154,7 +1154,7 @@ proc accept*(server: Socket, client: var owned(Socket), acceptAddr(server, client, addrDummy, flags) when defined(posix) and not defined(lwip): - from posix import Sigset, sigwait, sigismember, sigemptyset, sigaddset, + from std/posix import Sigset, sigwait, sigismember, sigemptyset, sigaddset, sigprocmask, pthread_sigmask, SIGPIPE, SIG_BLOCK, SIG_UNBLOCK template blockSigpipe(body: untyped): untyped = @@ -1268,9 +1268,9 @@ proc close*(socket: Socket, flags = {SocketFlag.SafeDisconn}) = socket.fd = osInvalidSocket when defined(posix): - from posix import TCP_NODELAY + from std/posix import TCP_NODELAY else: - from winlean import TCP_NODELAY + from std/winlean import TCP_NODELAY proc toCInt*(opt: SOBool): cint = ## Converts a `SOBool` into its Socket Option cint representation. diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index 9849e42db77a..bf8367d1de62 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -20,7 +20,7 @@ when not defined(profiler) and not defined(memProfiler): # We don't want to profile the profiling code ... {.push profiler: off.} -import hashes, algorithm, strutils, tables, sets +import std/[hashes, algorithm, strutils, tables, sets] when defined(nimPreviewSlimSystem): import std/[syncio, sysatomics] @@ -69,7 +69,7 @@ when not defined(memProfiler): else: interval = intervalInUs * 1000 - tickCountCorrection when withThreads: - import locks + import std/locks var profilingLock: Lock diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index ad8eeefd7071..4d6ceefd7994 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -14,7 +14,7 @@ ## This implementation calls `initRand()` for the first call of ## `genOid`. -import hashes, times, endians, random +import std/[hashes, times, endians, random] from std/private/decode_helpers import handleHexChar when defined(nimPreviewSlimSystem): diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 815eaab8967d..10a46cc94fd7 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -74,7 +74,7 @@ when defined(nimHasEffectsOf): else: {.pragma: effectsOf.} -import typetraits +import std/typetraits when defined(nimPreviewSlimSystem): import std/assertions 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 ca62a504c5fe..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 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/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 582cf531eae4..539305bde32a 100644 --- a/lib/std/tempfiles.nim +++ b/lib/std/tempfiles.nim @@ -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/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/seqs_v2.nim b/lib/system/seqs_v2.nim index d6b26493cb7a..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. 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 From afa2f2ebf6bbceeae2846546afb78d316bca7d5f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 31 Oct 2023 00:03:19 +0800 Subject: [PATCH 27/41] fixes nightlies; fixes incompatible types with csource_v2 (#22889) ref https://github.com/nim-lang/nightlies/actions/runs/6686795512/job/18166625042#logs > /home/runner/work/nightlies/nightlies/nim/compiler/nir/nirvm.nim(163, 35) Error: type mismatch: got 'BiggestInt' for 'b.m.lit.numbers[litId(b.m.types.nodes[int(y)])]' but expected 'int' Or unifies the type in one way or another --- compiler/nir/nirvm.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/nir/nirvm.nim b/compiler/nir/nirvm.nim index 1f2f4e326cd4..4b2c7e548b08 100644 --- a/compiler/nir/nirvm.nim +++ b/compiler/nir/nirvm.nim @@ -160,13 +160,13 @@ proc traverseObject(b: var Bytecode; t, offsetKey: TypeId) = var offset = -1 for y in sons(b.m.types, x): if b.m.types[y].kind == OffsetVal: - offset = b.m.lit.numbers[b.m.types[y].litId] + offset = int(b.m.lit.numbers[b.m.types[y].litId]) break b.offsets.mgetOrPut(offsetKey, @[]).add (offset, x.firstSon) of SizeVal: - size = b.m.lit.numbers[b.m.types[x].litId] + size = int(b.m.lit.numbers[b.m.types[x].litId]) of AlignVal: - align = b.m.lit.numbers[b.m.types[x].litId] + 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]) From f61311f7a0f1a4c2fab1eeaa747654d4281bc56b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 31 Oct 2023 00:05:03 +0800 Subject: [PATCH 28/41] bump node to 20.x; since 16.x is End-of-Life (#22892) --- .github/workflows/ci_bench.yml | 6 +++--- .github/workflows/ci_packages.yml | 6 +++--- .github/workflows/ci_publish.yml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) 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' From 2ae344f1c204f92a944afeb70fe6b1ca1c419f62 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 1 Nov 2023 01:49:23 +0800 Subject: [PATCH 29/41] minor fixes for node20 (#22894) --- azure-pipelines.yml | 4 ++-- tests/js/tnativeexc.nim | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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/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 From 801c02bf48b1612c8bf58ed113f944c9d6e32ead Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 31 Oct 2023 21:32:09 +0100 Subject: [PATCH 30/41] so close... (#22885) --- compiler/main.nim | 4 +- compiler/modulegraphs.nim | 1 + compiler/nir/ast2ir.nim | 94 +++++++------ compiler/nir/nir.nim | 1 + compiler/nir/nirinsts.nim | 28 +++- compiler/nir/nirvm.nim | 283 +++++++++++++++++++++++--------------- compiler/pipelines.nim | 3 +- 7 files changed, 255 insertions(+), 159 deletions(-) diff --git a/compiler/main.nim b/compiler/main.nim index 0627a61bb49c..6651128ebf73 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -201,7 +201,9 @@ proc commandCompileToJS(graph: ModuleGraph) = proc commandInteractive(graph: ModuleGraph; useNir: bool) = graph.config.setErrorMaxHighMaybe initDefines(graph.config.symbols) - if not useNir: + if useNir: + defineSymbol(graph.config.symbols, "noSignalHandler") + else: defineSymbol(graph.config.symbols, "nimscript") # note: seems redundant with -d:nimHasLibFFI when hasFFI: defineSymbol(graph.config.symbols, "nimffi") diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 325c0adb1d5f..ba636eb5a16d 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -92,6 +92,7 @@ type importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies suggestMode*: bool # whether we are in nimsuggest mode or not. invalidTransitiveClosure: bool + interactive*: bool inclToMod*: Table[FileIndex, FileIndex] # mapping of include file to the # first module that included it importStack*: seq[FileIndex] # The current import stack. Used for detecting recursive diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim index f3b68474b00b..ad04dc103d21 100644 --- a/compiler/nir/ast2ir.nim +++ b/compiler/nir/ast2ir.nim @@ -205,7 +205,7 @@ proc xjmp(c: var ProcCon; n: PNode; jk: JmpKind; v: Value): LabelId = c.code.copyTree Tree(v) build c.code, info, SelectPair: build c.code, info, SelectValue: - c.code.boolVal(info, jk == opcTJmp) + c.code.boolVal(c.lit.numbers, info, jk == opcTJmp) c.code.gotoLabel info, Goto, result proc patch(c: var ProcCon; n: PNode; L: LabelId) = @@ -311,8 +311,7 @@ proc tempToDest(c: var ProcCon; n: PNode; d: var Value; tmp: Value) = d = tmp else: let info = toLineInfo(c, n.info) - build c.code, info, Asgn: - c.code.addTyped info, typeToIr(c.m, n.typ) + buildTyped c.code, info, Asgn, typeToIr(c.m, n.typ): c.code.copyTree d c.code.copyTree tmp freeTemp(c, tmp) @@ -362,7 +361,7 @@ template buildCond(useNegation: bool; cond: typed; body: untyped) = c.code.copyTree cond build c.code, info, SelectPair: build c.code, info, SelectValue: - c.code.boolVal(info, useNegation) + c.code.boolVal(c.lit.numbers, info, useNegation) c.code.gotoLabel info, Goto, lab body @@ -381,7 +380,7 @@ template buildIfThenElse(cond: typed; then, otherwise: untyped) = c.code.copyTree cond build c.code, info, SelectPair: build c.code, info, SelectValue: - c.code.boolVal(info, false) + c.code.boolVal(c.lit.numbers, info, false) c.code.gotoLabel info, Goto, lelse then() @@ -406,8 +405,7 @@ proc genCase(c: var ProcCon; n: PNode; d: var Value) = let ending = newLabel(c.labelGen) let info = toLineInfo(c, n.info) withTemp(tmp, n[0]): - build c.code, info, Select: - c.code.addTyped info, typeToIr(c.m, n[0].typ) + buildTyped c.code, info, Select, typeToIr(c.m, n[0].typ): c.gen(n[0], tmp) for i in 1.. 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, n[0].typ): + buildTyped target, info, opc, typeToIr(c.m, n0.typ): copyTree target, a genField c, n[1], Value(target) @@ -2353,6 +2360,11 @@ proc genParams(c: var ProcCon; params: PNode; prc: PSym) = let res = resNode.sym # get result symbol c.code.addSummon toLineInfo(c, res.info), toSymId(c, res), typeToIr(c.m, res.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.. LastAtomicValue @@ -259,6 +265,17 @@ iterator sonsFrom1*(tree: Tree; n: NodePos): NodePos = 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] proc span(tree: Tree; pos: int): int {.inline.} = @@ -327,9 +344,6 @@ proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcod t.nodes.add Instr(x: toX(k, uint32(result)), info: info) inc labelGen -proc boolVal*(t: var Tree; info: PackedLineInfo; b: bool) = - t.nodes.add Instr(x: toX(ImmediateVal, uint32(b)), info: info) - proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) = assert k in {Goto, GotoLoop, CheckedGoto} t.nodes.add Instr(x: toX(k, uint32(L)), info: info) @@ -367,6 +381,10 @@ 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) diff --git a/compiler/nir/nirvm.nim b/compiler/nir/nirvm.nim index 4b2c7e548b08..a3d69a2962d3 100644 --- a/compiler/nir/nirvm.nim +++ b/compiler/nir/nirvm.nim @@ -48,7 +48,9 @@ type AddrOfM, ArrayAtM, # (elemSize, addr(a), i) + DerefArrayAtM, FieldAtM, # addr(obj.field) + DerefFieldAtM, LoadM, # a[] AsgnM, # a = b @@ -60,7 +62,6 @@ type CheckedIndexM, CallM, - CheckedCallM, # call that can raise CheckedAddM, # with overflow checking etc. CheckedSubM, CheckedMulM, @@ -107,6 +108,14 @@ template toIns(k: OpcodeM; operand: uint32): Instr = 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 @@ -119,7 +128,8 @@ type debug: seq[PackedLineInfo] m: ref NirModule procs: Table[SymId, CodePos] - globals: Table[SymId, uint32] + globals: Table[SymId, (uint32, int)] + strings: Table[LitId, NimStringVM] globalData: pointer globalsAddr: uint32 typeImpls: Table[string, TypeId] @@ -127,6 +137,7 @@ type 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] @@ -325,7 +336,7 @@ proc toString*(t: Bytecode; pos: CodePos; 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: + of LoadLocalM, LoadGlobalM, LoadProcM, AllocLocals, SummonParamM: r.add $t[pos].kind r.add ' ' r.add $t[pos].operand @@ -361,7 +372,7 @@ type u: ref Universe known: Table[LabelId, CodePos] toPatch: Table[LabelId, seq[CodePos]] - locals: Table[SymId, uint32] + locals: Table[SymId, (uint32, int)] # address, size thisModule: uint32 localsAddr: uint32 markedWithLabel: IntSet @@ -382,15 +393,23 @@ type AddrMode = enum InDotExpr, WantAddr -template maybeDeref(doDeref: bool; body: untyped) = +template maybeDeref(doDeref: bool; size: int; body: untyped) = var pos = PatchPos(-1) if doDeref: pos = prepare(bc, info, LoadM) - bc.add info, TypedM, 0'u32 + 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 @@ -409,19 +428,24 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla 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): - maybeDeref(WantAddr notin flags): - bc.add info, LoadLocalM, c.locals[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): - maybeDeref(WantAddr notin flags): - bc.add info, LoadGlobalM, uint32 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) @@ -452,7 +476,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla bc.add info, NilValM, t[n].rawOperand of LoopLabel, Label: let lab = t[n].label - let here = CodePos(bc.code.len-1) + let here = CodePos(bc.code.len) c.known[lab] = here var p: seq[CodePos] = @[] if c.toPatch.take(lab, p): @@ -506,7 +530,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla let (size, alignment) = computeSize(bc, tid) let global = align(bc.globalsAddr, uint32 alignment) - bc.globals[s] = global + bc.globals[s] = (global, size) bc.globalsAddr += uint32 size assert bc.globalsAddr < GlobalsSize @@ -518,7 +542,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla let (size, alignment) = computeSize(bc, tid) let local = align(c.localsAddr, uint32 alignment) - c.locals[s] = local + c.locals[s] = (local, size) c.localsAddr += uint32 size # allocation is combined into the frame allocation so there is no # instruction to emit @@ -530,7 +554,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla let (size, alignment) = computeSize(bc, tid) let local = align(c.localsAddr, uint32 alignment) - c.locals[s] = local + c.locals[s] = (local, size) c.localsAddr += uint32 size bc.add info, SummonParamM, local bc.add info, ImmediateValM, uint32 size @@ -545,39 +569,30 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla let (arrayType, a, i) = sons3(t, n) let tid = t[arrayType].typeId let size = uint32 computeElemSize(bc, tid) - if t[a].kind == Load: - let (_, arg) = sons2(t, a) - build bc, info, LoadM: - bc.add info, ImmediateValM, size - build bc, info, ArrayAtM: - bc.add info, ImmediateValM, size - preprocess(c, bc, t, arg, {WantAddr}) - preprocess(c, bc, t, i, {WantAddr}) - else: - build bc, info, ArrayAtM: - bc.add info, ImmediateValM, size - preprocess(c, bc, t, a, {WantAddr}) - preprocess(c, bc, t, i, {WantAddr}) + 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: - # a[] conceptually loads a block of size of T. But when applied to an object selector - # only a subset of the data is really requested so `(a[] : T).field` - # becomes `(a+offset(field))[] : T_Field` - # And now if this is paired with `addr` the deref disappears, as usual: `addr x.field[]` - # is `(x+offset(field))`. let (typ, a, b) = sons3(t, n) - if t[a].kind == Load: - let (_, arg) = sons2(t, a) - build bc, info, LoadM: - bc.add info, ImmediateValM, uint32 computeSize(bc, t[typ].typeId)[0] - let offset = bc.offsets[t[typ].typeId][t[b].immediateVal][0] - build bc, info, FieldAtM: - preprocess(c, bc, t, arg, flags+{WantAddr}) - bc.add info, ImmediateValM, uint32(offset) - else: - 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) + 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 @@ -593,14 +608,16 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla 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.firstSon, {WantAddr}) + preprocess(c, bc, t, src.skipTyped, {WantAddr}) preprocess(c, bc, t, dest, {WantAddr}) - for ch in sonsFrom1(t, src): preprocess(c, bc, t, ch, {WantAddr}) + for ch in sonsFromN(t, src, 2): preprocess(c, bc, t, ch, {WantAddr}) elif t[src].kind in {CheckedCall, CheckedIndirectCall}: - build bc, info, CheckedCallM: - preprocess(c, bc, t, src.firstSon, {WantAddr}) + 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 sonsFrom1(t, src): preprocess(c, bc, t, ch, {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] @@ -628,8 +645,11 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr}) of CheckedCall, CheckedIndirectCall: # avoid the Typed thing at position 0: - build bc, info, CheckedCallM: - for ch in sonsFrom1(t, n): preprocess(c, bc, t, ch, {WantAddr}) + 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: @@ -696,7 +716,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla for ch in sons(t, n): preprocess(c2, bc, t, ch, {}) bc.code[toPatch] = toIns(AllocLocals, c2.localsAddr) when false: - if here.int == 40192: + if here.int == 39850: debug bc, t, n debug bc, here @@ -776,6 +796,10 @@ proc evalAddr(c: Bytecode; pc: CodePos; s: StackFrame): pointer = 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 @@ -783,10 +807,13 @@ proc evalAddr(c: Bytecode; pc: CodePos; s: StackFrame): pointer = var idx: int = 0 eval(c, i, s, addr idx, sizeof(int)) result = result +! (uint32(idx) * elemSize) - of LoadM: - let (_, arg) = sons2(c.code, pc) - let p = evalAddr(c, arg, s) - result = cast[ptr pointer](p)[] + 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: @@ -897,23 +924,29 @@ proc evalSelect(c: Bytecode; pc: CodePos; s: StackFrame): CodePos = for pair in sonsFrom2(c, pc): assert c.code[pair].kind == SelectPairM let (values, action) = sons2(c.code, pair) - assert c.code[values].kind == SelectListM - 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" + 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) @@ -932,11 +965,18 @@ proc evalSelect(c: Bytecode; pc: CodePos; s: StackFrame): CodePos = proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) = case c.code[pc].kind of LoadLocalM: - let dest = s.locals +! c.code[pc].operand - copyMem dest, result, size - of FieldAtM, ArrayAtM, LoadM: - let dest = evalAddr(c, pc, s) - copyMem dest, result, size + 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 `*` @@ -958,8 +998,7 @@ proc eval(c: Bytecode; pc: CodePos; s: StackFrame; result: pointer; size: int) = of StrValM: # binary compatible and no deep copy required: - copyMem(cast[ptr string](result), addr(c.m.lit.strings[c[pc].litId]), sizeof(string)) - # XXX not correct! + 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 @@ -1013,31 +1052,41 @@ proc evalProc(c: Bytecode; pc: CodePos; s: StackFrame): CodePos = assert procSym < ForwardedProc result = CodePos(procSym) -proc echoImpl(c: Bytecode; pc: CodePos; s: StackFrame) = - type StringArray = object - len: int - data: ptr UncheckedArray[string] - var sa = default(StringArray) +proc echoImpl(c: Bytecode; pc: CodePos; frame: StackFrame) = + var s = default(NimStringVM) for a in sonsFrom1(c, pc): - eval(c, a, s, addr(sa), sizeof(sa)) - for i in 0.. 0: + discard stdout.writeBuffer(addr(s.p.data[0]), s.len) stdout.write "\n" stdout.flushFile() -proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; didEval: var bool): CodePos = +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) - if cast[PragmaKey](c[x]) == CoreName: + 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: discard - echo "running compilerproc: ", c.m.lit.strings[lit] - didEval = true + 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 @@ -1045,52 +1094,63 @@ proc evalBuiltin(c: Bytecode; pc: CodePos; s: StackFrame; prc: CodePos; didEval: proc exec(c: Bytecode; pc: CodePos; u: ref Universe) = var pc = pc - var s = StackFrame(u: u) + 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, s) - eval(c, b, s, dest, c.code[sz].operand.int) + 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, s) + let destPtr = evalAddr(c, a, frame) let dest = cast[ptr pointer](destPtr)[] - eval(c, b, s, dest, c.code[sz].operand.int) + 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, s) + 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 didEval = false - prc = evalBuiltin(c, pc, s, prc.firstSon, didEval) - if didEval: + 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, s, 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 - eval(c, a, s2, s2.locals +! paramAddr, paramSize) next c, prc - s = s2 + eval(c, a, s2, s2.locals +! paramAddr, paramSize) + frame = s2 pc = prc of RetM: - pc = s.returnAddr - s = popStackFrame(s) + pc = frame.returnAddr + if c.code[pc].kind == CheckedGotoM: + pc = frame.jumpTo + frame = popStackFrame(frame) of SelectM: - let pc2 = evalSelect(c, pc, s) + let pc2 = evalSelect(c, pc, frame) if pc2.int >= 0: pc = pc2 else: @@ -1107,8 +1167,9 @@ proc execCode*(bc: var Bytecode; t: Tree; n: NodePos) = let start = CodePos(bc.code.len) var pc = n while pc.int < t.len: - #echo "RUnning: " - #debug bc, t, pc + #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/pipelines.nim b/compiler/pipelines.nim index e4c484e1f328..8f40ac031da7 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -148,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) From 92141e82ede93028be5781d6f4e906cefa3b03eb Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 1 Nov 2023 14:54:47 +0800 Subject: [PATCH 31/41] =?UTF-8?q?fixes=20#22883;=20replace=20`default(type?= =?UTF-8?q?of(`=20with=20`reset`;=20suppress=20`Unsaf=E2=80=A6=20(#22895)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes #22883 …eDefault` warnings avoid issues mentioned by https://forum.nim-lang.org namely, it allocated unnecessary stack objects in the loop ```c while (1) { tyObject_N__8DSNqSGSHBKOhI8CqSgAow T5_; nimZeroMem((void *)(&T5_), sizeof(tyObject_N__8DSNqSGSHBKOhI8CqSgAow)); eqsink___test4954_u450((&(*t_p0).data.p->data[i].Field1), T5_); } ``` It might be more efficient in some cases follow up https://github.com/nim-lang/Nim/pull/21821 --- lib/pure/collections/setimpl.nim | 2 +- lib/pure/collections/sets.nim | 4 ++-- lib/pure/collections/tableimpl.nim | 8 ++++---- lib/system.nim | 4 ++++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index dbd4ce1d5e12..cff953b108c6 100644 --- a/lib/pure/collections/setimpl.nim +++ b/lib/pure/collections/setimpl.nim @@ -87,7 +87,7 @@ 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)) + reset(s.data[i].key) 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 220ef3bb63cc..99bb299d5bab 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -382,7 +382,7 @@ 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)) + reset(s.data[i].key) proc union*[A](s1, s2: HashSet[A]): HashSet[A] = @@ -816,7 +816,7 @@ 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)) + reset(s.data[i].key) proc len*[A](s: OrderedSet[A]): int {.inline.} = ## Returns the number of elements in `s`. diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index 112aaa7d0697..9bccc8d9662e 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -119,8 +119,8 @@ 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)) + reset(t.data[i].key) + reset(t.data[i].val) while true: i = (i + 1) and msk # increment mod table size if cellEmpty(i): # end of collision cluster; So all done @@ -151,8 +151,8 @@ 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)) + reset(t.data[i].key) + reset(t.data[i].val) t.counter = 0 template ctAnd(a, b): bool = diff --git a/lib/system.nim b/lib/system.nim index 41c9e96ea2ac..d8a61f9fa941 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -911,14 +911,18 @@ proc default*[T](_: typedesc[T]): T {.magic: "Default", noSideEffect.} = proc reset*[T](obj: var T) {.noSideEffect.} = ## Resets an object `obj` to its default value. when nimvm: + {.push warning[UnsafeDefault]:off.} obj = default(typeof(obj)) + {.pop.} else: when defined(gcDestructors): {.cast(noSideEffect), cast(raises: []), cast(tags: []).}: `=destroy`(obj) `=wasMoved`(obj) else: + {.push warning[UnsafeDefault]:off.} obj = default(typeof(obj)) + {.pop.} proc setLen*[T](s: var seq[T], newlen: Natural) {. magic: "SetLengthSeq", noSideEffect, nodestroy.} From 40e33dec45b98e1c5385f844e241011a8351d364 Mon Sep 17 00:00:00 2001 From: Yardanico Date: Wed, 1 Nov 2023 10:01:31 +0300 Subject: [PATCH 32/41] Fix `IndexDefect` errors in httpclient on invalid/weird headers (#22886) Continuation of https://github.com/nim-lang/Nim/pull/19262 Fixes https://github.com/nim-lang/Nim/issues/19261 The parsing code is still too lenient (e.g. it will happily parse header names with spaces in them, which is outright invalid by the spec), but I didn't want to touch it beyond the simple changes to make sure that `std/httpclient` won't throw `IndexDefect`s like it does now on those cases: - Multiline header values - No colon after the header name - No value after the header name + colon One question remains - should I keep `toCaseInsensitive` exported in `httpcore` or just copy-paste the implementation? --------- Co-authored-by: Andreas Rumpf --- lib/pure/httpclient.nim | 34 ++++++++++++++++++++++++---------- lib/pure/httpcore.nim | 3 ++- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index d2bf925bab3c..fc66b96f522f 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -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 5b3d7b45b131..ab0c030a5c73 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -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 = From b68e0aab4c9c7db5df996ba1a4eb91ce7c82b8c6 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:14:50 +0800 Subject: [PATCH 33/41] fixes #22866; fixes #19998; ensure destruction for Object construction with custom destructors (#22901) fixes #22866; fixes #19998 --- compiler/injectdestructors.nim | 4 +++- tests/arc/tcomputedgoto.nim | 15 +++++++++------ tests/arc/tcomputedgotocopy.nim | 11 +++++++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 6b3fdeca5aac..a278f7c49a3f 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -857,7 +857,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing result[i][1] = p(n[i][1], c, s, m) else: result[i] = p(n[i], c, s, m) - if mode == normal and isRefConstr: + if mode == normal and (isRefConstr or (hasDestructor(c, t) and + getAttachedOp(c.graph, t, attachedDestructor) != nil and + sfOverridden in getAttachedOp(c.graph, t, attachedDestructor).flags)): result = ensureDestruction(result, n, c, s) of nkCallKinds: if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove: 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) = From d70a9957e21a60b1756f8ea7c8cdaa9fb89fb2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Fri, 3 Nov 2023 17:54:35 +0000 Subject: [PATCH 34/41] adds C++ features to change log (#22906) Co-authored-by: Andreas Rumpf Co-authored-by: Juan Carlos --- changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.md b/changelog.md index 454b613f074b..3351a6f7a052 100644 --- a/changelog.md +++ b/changelog.md @@ -32,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 From 95e5ad6927af309552857686bf2c74bfac36cbb7 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 4 Nov 2023 15:50:30 +0800 Subject: [PATCH 35/41] fixes #22902; borrow from proc return type mismatch (#22908) fixes #22902 --- compiler/semcall.nim | 2 +- compiler/types.nim | 3 ++- tests/distinct/typeclassborrow.nim | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) 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/types.nim b/compiler/types.nim index 31563b71f7e4..46433a2306dd 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -972,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] @@ -1306,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/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.} From 3f2b9c8bcf9faf30b6844e5222ffe6ec501064e8 Mon Sep 17 00:00:00 2001 From: Nikolay Nikolov Date: Sat, 4 Nov 2023 09:51:09 +0200 Subject: [PATCH 36/41] Inlay hints support (#22896) This adds inlay hints support to nimsuggest. It adds a new command to nimsuggest, called 'inlayHints'. Currently, it provides type information to 'var' and 'let' variables. In the future, inlay hints can also be added for 'const' and for function parameters. The protocol also reserves space for a tooltip field, which is not used, yet, but support for it can be added in the future, without further changing the protocol. The change includes refactoring to allow the 'inlayHints' command to return a completely different structure, compared to the other nimsuggest commands. This will allow other future commands to have custom return types as well. All the previous commands return the same structure as before, so perfect backwards compatibility is maintained. To use this feature, an update to the nim language server, as well as the VS code extension is needed. Related PRs: nimlangserver: https://github.com/nim-lang/langserver/pull/53 VS code extension: https://github.com/saem/vscode-nim/pull/134 --------- Co-authored-by: Andreas Rumpf --- compiler/ast.nim | 1 + compiler/modulegraphs.nim | 1 + compiler/options.nim | 18 +++++- compiler/semstmts.nim | 4 ++ compiler/suggest.nim | 114 ++++++++++++++++++++++++-------------- nimsuggest/nimsuggest.nim | 55 +++++++++++++++++- 6 files changed, 149 insertions(+), 44 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 5ee9afa024de..661a82703c5d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -903,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.: diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index ba636eb5a16d..5c23325e82dd 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -57,6 +57,7 @@ type SymInfoPair* = object sym*: PSym info*: TLineInfo + isDecl*: bool PipelinePass* = enum NonePass diff --git a/compiler/options.nim b/compiler/options.nim index f2d93a9b3a09..704248d78936 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -199,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, @@ -288,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 @@ -1071,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/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/suggest.nim b/compiler/suggest.nim index 5714c6d21102..1d84fada52ff 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -107,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 = "" @@ -177,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) @@ -185,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): @@ -537,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/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}" From af556841ac57655f5b2ffe34de401a981b6eaf94 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 4 Nov 2023 15:52:30 +0800 Subject: [PATCH 37/41] fixes #22860; suppress `AnyEnumConv` warning when iterating over set (#22904) fixes #22860 --- lib/system/iterators.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index e511f25087d6..125bee98ff52 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.} = From ec37b59a6552ed4a989e4c3cb1970fb970152e04 Mon Sep 17 00:00:00 2001 From: Solitude Date: Sat, 4 Nov 2023 11:46:59 +0200 Subject: [PATCH 38/41] Add missing std prefix (#22910) without it, devels fails to build with `-d:useLinenoise` --- compiler/llstream.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 84fe7dcdb9b5..fa223b373913 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -19,7 +19,7 @@ when defined(nimPreviewSlimSystem): const hasRstdin = (defined(nimUseLinenoise) or defined(useLinenoise) or defined(useGnuReadline)) and not defined(windows) -when hasRstdin: import rdstdin +when hasRstdin: import std/rdstdin type TLLRepl* = proc (s: PLLStream, buf: pointer, bufLen: int): int From f0e5bdd7d8575d6456a7fc489e203e979d0926b3 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 5 Nov 2023 16:12:53 +0800 Subject: [PATCH 39/41] fixes #22898; fix #22883 differently (#22900) fixes #22898 In these cases, the tables/sets are clears or elements are deleted from them. It's reasonable to suppress warnings because the value is not accessed anymore, which means it's safe to ignore the warnings. --- lib/pure/collections/setimpl.nim | 2 ++ lib/pure/collections/sets.nim | 4 ++++ lib/pure/collections/tableimpl.nim | 4 ++++ lib/system.nim | 4 ---- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index cff953b108c6..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 + {.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 99bb299d5bab..af13135aabbf 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -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 + {.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 + {.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/tableimpl.nim b/lib/pure/collections/tableimpl.nim index 9bccc8d9662e..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 + {.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 + {.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/system.nim b/lib/system.nim index d8a61f9fa941..41c9e96ea2ac 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -911,18 +911,14 @@ proc default*[T](_: typedesc[T]): T {.magic: "Default", noSideEffect.} = proc reset*[T](obj: var T) {.noSideEffect.} = ## Resets an object `obj` to its default value. when nimvm: - {.push warning[UnsafeDefault]:off.} obj = default(typeof(obj)) - {.pop.} else: when defined(gcDestructors): {.cast(noSideEffect), cast(raises: []), cast(tags: []).}: `=destroy`(obj) `=wasMoved`(obj) else: - {.push warning[UnsafeDefault]:off.} obj = default(typeof(obj)) - {.pop.} proc setLen*[T](s: var seq[T], newlen: Natural) {. magic: "SetLengthSeq", noSideEffect, nodestroy.} From eb8824d71cb36be8a9558bf572606a24825bb33b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 5 Nov 2023 20:25:25 +0100 Subject: [PATCH 40/41] NIR: C codegen, WIP (#22903) --- compiler/ic/bitabs.nim | 4 +- compiler/ic/rodfiles.nim | 1 + compiler/nir/ast2ir.nim | 161 ++++--- compiler/nir/cir.nim | 881 +++++++++++++++++++++++++++++++++++++- compiler/nir/nirc.nim | 15 +- compiler/nir/nirfiles.nim | 10 + compiler/nir/nirinsts.nim | 34 +- compiler/nir/nirtypes.nim | 35 +- compiler/nir/nirvm.nim | 2 +- compiler/nir/types2ir.nim | 21 +- 10 files changed, 1072 insertions(+), 92 deletions(-) diff --git a/compiler/ic/bitabs.nim b/compiler/ic/bitabs.nim index 65b1e5a0ed07..c8798e0ca4bf 100644 --- a/compiler/ic/bitabs.nim +++ b/compiler/ic/bitabs.nim @@ -36,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/rodfiles.nim b/compiler/ic/rodfiles.nim index db520527bce6..be5095fbb70a 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -98,6 +98,7 @@ type backendFlagsSection aliveSymsSection # beware, this is stored in a `.alivesyms` file. sideChannelSection + namespaceSection symnamesSection RodFileError* = enum diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim index ad04dc103d21..2dc28e87bcaf 100644 --- a/compiler/nir/ast2ir.nim +++ b/compiler/nir/ast2ir.nim @@ -31,6 +31,8 @@ type idgen: IdGenerator processedProcs, pendingProcsAsSet: HashSet[ItemId] pendingProcs: seq[PSym] # procs we still need to generate code for + pendingVarsAsSet: HashSet[ItemId] + pendingVars: seq[PSym] noModularity*: bool inProc: int toSymId: Table[ItemId, SymId] @@ -69,6 +71,8 @@ proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; m result.nativeIntId = Int64Id result.nativeUIntId = UInt16Id result.strPayloadId = strPayloadPtrType(result.types, result.nirm.types) + nirm.namespace = nirm.lit.strings.getOrIncl(customPath(toFullPath(config, module.info))) + nirm.intbits = uint32(config.target.intSize * 8) proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon = result = ProcCon(m: m, sm: initSlotManager({}), prc: prc, config: config, @@ -162,11 +166,6 @@ proc getTemp(c: var ProcCon; t: TypeId; info: PackedLineInfo): Value = c.code.addSummon info, tmp, t result = localToValue(info, tmp) -template withTemp(tmp, n, body: untyped) {.dirty.} = - var tmp = getTemp(c, n) - body - c.freeTemp(tmp) - proc gen(c: var ProcCon; n: PNode; flags: GenFlags = {}) = var tmp = default(Value) gen(c, n, tmp, flags) @@ -281,14 +280,15 @@ proc genIf(c: var ProcCon; n: PNode; d: var Value) = var it = n[i] if it.len == 2: let info = toLineInfo(c, it[0].info) - withTemp(tmp, it[0]): - var elsePos: LabelId - if isNotOpr(it[0]): - c.gen(it[0][1], tmp) - elsePos = c.xjmp(it[0][1], opcTJmp, tmp) # if true - else: - c.gen(it[0], tmp) - elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false + var elsePos: LabelId + if isNotOpr(it[0]): + let tmp = c.genx(it[0][1]) + elsePos = c.xjmp(it[0][1], opcTJmp, tmp) # if true + c.freeTemp tmp + else: + let tmp = c.genx(it[0]) + elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false + c.freeTemp tmp c.clearDest(n, d) if isEmptyType(it[1].typ): # maybe noreturn call, don't touch `d` c.genScope(it[1]) @@ -404,22 +404,23 @@ proc genCase(c: var ProcCon; n: PNode; d: var Value) = var sections = newSeqOfCap[LabelId](n.len-1) let ending = newLabel(c.labelGen) let info = toLineInfo(c, n.info) - withTemp(tmp, n[0]): - buildTyped c.code, info, Select, typeToIr(c.m, n[0].typ): - c.gen(n[0], tmp) - for i in 1.. 0 and resultPos < prc.ast.len: let resNode = prc.ast[resultPos] - let res = resNode.sym # get result symbol - c.code.addSummon toLineInfo(c, res.info), toSymId(c, res), - typeToIr(c.m, res.typ), SummonResult + 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]) @@ -2389,6 +2419,7 @@ proc addCallConv(c: var ProcCon; info: PackedLineInfo; callConv: TCallingConvent of ccNoConvention: ann NoCall proc genProc(cOuter: var ProcCon; prc: PSym) = + if prc.magic notin generatedMagics: return if cOuter.m.processedProcs.containsOrIncl(prc.itemId): return #assert cOuter.m.inProc == 0, " in nested proc! " & prc.name.s @@ -2399,14 +2430,22 @@ proc genProc(cOuter: var ProcCon; prc: PSym) = inc cOuter.m.inProc var c = initProcCon(cOuter.m, prc, cOuter.m.graph.config) - - let body = transformBody(c.m.graph, c.m.idgen, prc, {useCache, keepOpenArrayConversions}) - - let info = toLineInfo(c, body.info) - build c.code, info, ProcDecl: - let symId = toSymId(c, prc) - addSymDef c.code, info, symId - c.m.nirm.symnames[symId] = c.lit.strings.getOrIncl(prc.name.s) + 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: @@ -2435,11 +2474,16 @@ proc genProc(cOuter: var ProcCon; prc: PSym) = else: c.code.addPragmaId info, ObjExport - genParams(c, prc.typ.n, prc) - gen(c, body) - patch c, body, c.exitLabel - build c.code, info, Ret: - discard + 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 @@ -2569,10 +2613,13 @@ proc gen(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags = {}) = localError(c.config, n.info, "cannot generate IR code for " & $n) proc genPendingProcs(c: var ProcCon) = - while c.m.pendingProcs.len > 0: + 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 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/nirc.nim b/compiler/nir/nirc.nim index 363507ca6537..a2cf69988abe 100644 --- a/compiler/nir/nirc.nim +++ b/compiler/nir/nirc.nim @@ -7,10 +7,10 @@ # distribution, for details about the copyright. # -## Nir Compiler. Currently only supports a "view" command. +## Nir Compiler. import ".." / ic / [bitabs, rodfiles] -import nirinsts, nirtypes, nirlineinfos, nirfiles #, nir2gcc +import nirinsts, nirtypes, nirlineinfos, nirfiles, cir proc view(filename: string) = let m = load(filename) @@ -20,14 +20,10 @@ proc view(filename: string) = nirtypes.toString res, m.types echo res -proc libgcc(filename: string) = - let m = load(filename) - #gcc m, filename - import std / [syncio, parseopt] proc writeHelp = - echo """Usage: nirc view|gcc """ + echo """Usage: nirc view|c """ quit 0 proc main = @@ -49,7 +45,8 @@ proc main = case cmd of "", "view": view inp - of "gcc": - libgcc inp + of "c": + let outp = inp & ".c" + cir.generateCode inp, outp main() diff --git a/compiler/nir/nirfiles.nim b/compiler/nir/nirfiles.nim index f6c73178b0ba..cd5a79f06e44 100644 --- a/compiler/nir/nirfiles.nim +++ b/compiler/nir/nirfiles.nim @@ -16,6 +16,8 @@ type man*: LineInfoManager types*: TypeGraph lit*: Literals + namespace*: LitId + intbits*: uint32 symnames*: SymNames proc load*(filename: string): NirModule = @@ -39,6 +41,10 @@ proc load*(filename: string): NirModule = 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 @@ -64,6 +70,10 @@ proc store*(m: NirModule; outp: string) = 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 diff --git a/compiler/nir/nirinsts.nim b/compiler/nir/nirinsts.nim index 5c2901540396..6cffc1a8938d 100644 --- a/compiler/nir/nirinsts.nim +++ b/compiler/nir/nirinsts.nim @@ -54,6 +54,7 @@ type SelectList, # (values...) SelectValue, # (value) SelectRange, # (valueA..valueB) + ForeignDecl, # Can wrap SummonGlobal, SummonThreadLocal, SummonConst SummonGlobal, SummonThreadLocal, Summon, # x = Summon Typed ; x begins to live @@ -108,6 +109,7 @@ type TestOf, Emit, ProcDecl, + ForeignProcDecl, PragmaPair type @@ -278,6 +280,14 @@ iterator sonsFromN*(tree: Tree; n: NodePos; toSkip = 2): NodePos = 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) @@ -290,19 +300,36 @@ proc copyTree*(dest: var Tree; src: Tree) = for i in 0..= 0 t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info) diff --git a/compiler/nir/nirtypes.nim b/compiler/nir/nirtypes.nim index d1c7c6084139..a79bf6d012a3 100644 --- a/compiler/nir/nirtypes.nim +++ b/compiler/nir/nirtypes.nim @@ -177,11 +177,35 @@ proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) = let c = b + span(tree, b) result = (TypeId a, TypeId b, TypeId c) +proc arrayName*(tree: TypeGraph; n: TypeId): TypeId {.inline.} = + assert tree[n].kind == ArrayTy + 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, ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl, @@ -356,10 +380,12 @@ proc toString*(dest: var string; g: TypeGraph; i: TypeId) = dest.add "]" of ArrayTy: dest.add "Array[" - let (elems, len) = g.sons2(i) + let (elems, len, name) = g.sons3(i) toString(dest, g, elems) dest.add ", " toString(dest, g, len) + dest.add ", " + toString(dest, g, name) dest.add "]" of LastArrayTy: # array of unspecified size as a last field inside an object @@ -421,6 +447,12 @@ iterator allTypes*(g: TypeGraph; start = 0): TypeId = 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) @@ -431,6 +463,7 @@ when isMainModule: let a = g.openType ArrayTy g.addBuiltinType Int8Id g.addArrayLen 5 + g.addName "SomeArray" let finalArrayType = finishType(g, a) let obj = g.openType ObjectDecl diff --git a/compiler/nir/nirvm.nim b/compiler/nir/nirvm.nim index a3d69a2962d3..faa7a1fb7eb3 100644 --- a/compiler/nir/nirvm.nim +++ b/compiler/nir/nirvm.nim @@ -421,7 +421,7 @@ proc preprocess(c: var Preprocessing; bc: var Bytecode; t: Tree; n: NodePos; fla for ch in sons(t, n): preprocess(c, bc, t, ch, {WantAddr}) case t[n].kind - of Nop: + of Nop, ForeignDecl, ForeignProcDecl: discard "don't use Nop" of ImmediateVal: bc.add info, ImmediateValM, t[n].rawOperand diff --git a/compiler/nir/types2ir.nim b/compiler/nir/types2ir.nim index 4c3ce7001f87..9c951328451c 100644 --- a/compiler/nir/types2ir.nim +++ b/compiler/nir/types2ir.nim @@ -14,6 +14,7 @@ import nirtypes type TypesCon* = object processed: Table[ItemId, TypeId] + processedByName: Table[string, TypeId] recursionCheck: HashSet[ItemId] conf: ConfigRef stringType: TypeId @@ -30,6 +31,13 @@ template cached(c: var TypesCon; t: PType; body: untyped) = body c.processed[t.itemId] = result +template cachedByName(c: var TypesCon; t: PType; body: untyped) = + let key = mangle(c, t) + result = c.processedByName.getOrDefault(key) + if result.int == 0: + body + c.processedByName[key] = result + proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId proc collectFieldTypes(c: var TypesCon; g: var TypeGraph; n: PNode; dest: var Table[ItemId, TypeId]) = @@ -273,10 +281,15 @@ proc seqPayloadType(c: var TypesCon; g: var TypeGraph; t: PType): (string, TypeI let f = g.openType FieldDecl let arr = g.openType LastArrayTy g.addType elementType - result[1] = finishType(g, arr) # LastArrayTy + # 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) = @@ -413,6 +426,7 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = 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): @@ -451,6 +465,7 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = 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 @@ -467,7 +482,7 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = else: result = objectHeaderToIr(c, g, t) of tyTuple: - cached(c, t): + cachedByName(c, t): result = tupleToIr(c, g, t) of tyProc: cached(c, t): @@ -485,7 +500,7 @@ proc typeToIr*(c: var TypesCon; g: var TypeGraph; t: PType): TypeId = else: result = c.stringType of tySequence: - cached(c, t): + cachedByName(c, t): result = seqToIr(c, g, t) of tyCstring: cached(c, t): From 58c44312afba755f73ba2ec7ab73daea7768e41d Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Mon, 6 Nov 2023 07:57:29 +0100 Subject: [PATCH 41/41] reserve `sysFatal` for `Defect` (#22158) Per manual, `panics:on` affects _only_ `Defect`:s - thus `sysFatal` should not redirect any other exceptions. Also, when `sysFatal` is used in `nimPanics` mode, it should use regular exception handling pipeline to ensure exception hooks are called consistently for all raised defects. --- lib/std/syncio.nim | 15 ++++++--------- lib/system.nim | 2 +- lib/system/channels_builtin.nim | 2 +- lib/system/fatal.nim | 14 +++++++------- 4 files changed, 15 insertions(+), 18 deletions(-) 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/system.nim b/lib/system.nim index 41c9e96ea2ac..4f2a051632d3 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2832,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/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.}