diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d034e3b9ba..5809084f03 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -23,11 +23,11 @@ jobs: vmImage: 'ubuntu-20.04' CPU: amd64 # regularly breaks, refs bug #17325 - Linux_i386: - # on 'ubuntu-16.04' (not supported anymore anyways) it errored with: - # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed - vmImage: 'ubuntu-18.04' - CPU: i386 +# Linux_i386: +# # on 'ubuntu-16.04' (not supported anymore anyways) it errored with: +# # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed +# vmImage: 'ubuntu-18.04' +# CPU: i386 OSX_amd64: vmImage: 'macOS-11' CPU: amd64 diff --git a/changelog.md b/changelog.md index 2db577d0bf..100d12fd72 100644 --- a/changelog.md +++ b/changelog.md @@ -10,7 +10,6 @@ [//]: # "Additions:" -- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes. [//]: # "Deprecations:" diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index cbe7554785..02310eea3d 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -135,30 +135,90 @@ - The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection. -- Underscores (`_`) as routine parameters are now ignored and cannot be used in the routine body. - The following code now does not compile: +- The underscore identifier (`_`) is now generally not added to scope when + used as the name of a definition. While this was already the case for + variables, it is now also the case for routine parameters, generic + parameters, routine declarations, type declarations, etc. This means that the following code now does not compile: ```nim proc foo(_: int): int = _ + 1 echo foo(1) + + proc foo[_](t: typedesc[_]): seq[_] = @[default(_)] + echo foo[int]() + + proc _() = echo "_" + _() + + type _ = int + let x: _ = 3 ``` - Instead, the following code now compiles: + Whereas the following code now compiles: ```nim proc foo(_, _: int): int = 123 echo foo(1, 2) - ``` -- Underscores (`_`) as generic parameters are not supported and cannot be used. - Generics that use `_` as parameters will no longer compile requires you to replace `_` with something else: - - ```nim - proc foo[_](t: typedesc[_]): string = "BAR" # Can not compile - proc foo[T](t: typedesc[T]): string = "BAR" # Can compile + + proc foo[_, _](): int = 123 + echo foo[int, bool]() + + proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U)) + echo foo(int, bool) + + proc _() = echo "one" + proc _() = echo "two" + + type _ = int + type _ = float ``` - - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages. +- The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) + for 64-bit integer types (`int64` and `uint64`) by default. As this affects + JS code generation, code using these types to interface with the JS backend + may need to be updated. Note that `int` and `uint` are not affected. + + For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint) + and in the case of potential bugs with the new implementation, the + old behavior is currently still supported with the command line option + `--jsbigint64:off`. + +- The `proc` and `iterator` type classes now respectively only match + procs and iterators. Previously both type classes matched any of + procs or iterators. + + ```nim + proc prc(): int = + 123 + + iterator iter(): int = + yield 123 + + proc takesProc[T: proc](x: T) = discard + proc takesIter[T: iterator](x: T) = discard + + # always compiled: + takesProc(prc) + takesIter(iter) + # no longer compiles: + takesProc(iter) + takesIter(prc) + ``` + +- The `proc` and `iterator` type classes now accept a calling convention pragma + (i.e. `proc {.closure.}`) that must be shared by matching proc or iterator + types. Previously pragmas were parsed but discarded if no parameter list + was given. + + This is represented in the AST by an `nnkProcTy`/`nnkIteratorTy` node with + an `nnkEmpty` node in the place of the `nnkFormalParams` node, and the pragma + node in the same place as in a concrete `proc` or `iterator` type node. This + state of the AST may be unexpected to existing code, both due to the + replacement of the `nnkFormalParams` node as well as having child nodes + unlike other type class AST. + ## Standard library additions and changes [//]: # "Changes:" @@ -231,6 +291,7 @@ - Added `openArray[char]` overloads for `std/parseutils` allowing more code reuse. - Added `openArray[char]` overloads for `std/unicode` allowing more code reuse. - Added `safe` parameter to `base64.encodeMime`. +- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes. [//]: # "Deprecations:" - Deprecated `selfExe` for Nimscript. @@ -343,6 +404,26 @@ - `=wasMoved` can be overridden by users. +- Tuple unpacking for variables is now treated as syntax sugar that directly + expands into multiple assignments. Along with this, tuple unpacking for + variables can now be nested. + + ```nim + proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3) + + let (x, (_, y), _, z) = returnsNestedTuple() + # roughly becomes + let + tmpTup1 = returnsNestedTuple() + x = tmpTup1[0] + tmpTup2 = tmpTup1[1] + y = tmpTup2[1] + z = tmpTup1[3] + ``` + + As a result `nnkVarTuple` nodes in variable sections will no longer be + reflected in `typed` AST. + ## Compiler changes - The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the @@ -364,4 +445,4 @@ ## Tool changes -- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`). +- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop. diff --git a/compiler/ast.nim b/compiler/ast.nim index f93c8d9101..b5306c423c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -510,7 +510,7 @@ type nfLastRead # this node is a last read nfFirstWrite # this node is a first write nfHasComment # node has a comment - nfUseDefaultField # node has a default value (object constructor) + nfSkipFieldChecking # node skips field visable checking TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46) @@ -1081,7 +1081,7 @@ const nfIsRef, nfIsPtr, nfPreventCg, nfLL, nfFromTemplate, nfDefaultRefsParam, nfExecuteOnReload, nfLastRead, - nfFirstWrite, nfUseDefaultField} + nfFirstWrite, nfSkipFieldChecking} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a64a42219c..44466fb571 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1947,7 +1947,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = initLoc(call, locCall, e, OnHeap) if not p.module.compileToCpp: - const setLenPattern = "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)" + const setLenPattern = "($3) #setLengthSeqV2(($1)?&($1)->Sup:NIM_NIL, $4, $2)" call.r = ropecg(p.module, setLenPattern, [ rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)]) @@ -2339,7 +2339,7 @@ proc genWasMoved(p: BProc; n: PNode) = if p.withinBlockLeaveActions > 0 and notYetAlive(n1): discard else: - initLocExpr(p, n1, a) + initLocExpr(p, n1, a, {lfEnforceDeref}) resetLoc(p, a) #linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", # [addrLoc(p.config, a), getTypeDesc(p.module, a.t)]) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 98c1fc55fe..6cc009bb96 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -200,6 +200,9 @@ proc isImportedCppType(t: PType): bool = result = (t.sym != nil and sfInfixCall in t.sym.flags) or (x.sym != nil and sfInfixCall in x.sym.flags) +proc isOrHasImportedCppType(typ: PType): bool = + searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType) + proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope proc isObjLackingTypeField(typ: PType): bool {.inline.} = @@ -553,7 +556,10 @@ proc genRecordFieldsAux(m: BModule, n: PNode, else: # don't use fieldType here because we need the # tyGenericInst for C++ template support - result.addf("$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) + if fieldType.isOrHasImportedCppType(): + result.addf("$1$3 $2{};$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) + else: + result.addf("$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) else: internalError(m.config, n.info, "genRecordFieldsAux()") proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 5ba68580da..960805e8d7 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -61,12 +61,12 @@ proc findPendingModule(m: BModule, s: PSym): BModule = var ms = getModule(s) result = m.g.modules[ms.position] -proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) = +proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}) = result.k = k result.storage = s result.lode = lode result.r = "" - result.flags = {} + result.flags = flags proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} = # fills the loc if it is not already initialized @@ -487,9 +487,6 @@ proc resetLoc(p: BProc, loc: var TLoc) = # on the bytes following the m_type field? genObjectInit(p, cpsStmts, loc.t, loc, constructObj) -proc isOrHasImportedCppType(typ: PType): bool = - searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType) - proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = let typ = loc.t if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}: @@ -644,7 +641,23 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = if sfVolatile in s.flags: decl.add(" volatile") if sfNoalias in s.flags: decl.add(" NIM_NOALIAS") if value != "": - decl.addf(" $1 = $2;$n", [s.loc.r, value]) + if p.module.compileToCpp and value.startsWith "{{}": + # TODO: taking this branch, re"\{\{\}(,\s\{\})*\}" might be emitted, resulting in + # either warnings (GCC 12.2+) or errors (Clang 15, MSVC 19.3+) of C++11+ compilers **when + # explicit constructors are around** due to overload resolution rules in place [^0][^1][^2] + # *Workaround* here: have C++'s static initialization mechanism do the default init work, + # for us lacking a deeper knowledge of an imported object's constructors' ex-/implicitness + # (so far) *and yet* trying to achieve default initialization. + # Still, generating {}s in genConstObjConstr() just to omit them here is faaaar from ideal; + # need to figure out a better way, possibly by keeping around more data about the + # imported objects' contructors? + # + # [^0]: https://en.cppreference.com/w/cpp/language/aggregate_initialization + # [^1]: https://cplusplus.github.io/CWG/issues/1518.html + # [^2]: https://eel.is/c++draft/over.match.ctor + decl.addf(" $1;$n", [s.loc.r]) + else: + decl.addf(" $1 = $2;$n", [s.loc.r, value]) else: decl.addf(" $1;$n", [s.loc.r]) else: @@ -685,8 +698,8 @@ proc genLiteral(p: BProc, n: PNode; result: var Rope) proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int) proc raiseExit(p: BProc) -proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = - initLoc(result, locNone, e, OnUnknown) +proc initLocExpr(p: BProc, e: PNode, result: var TLoc, flags: TLocFlags = {}) = + initLoc(result, locNone, e, OnUnknown, flags) expr(p, e, result) proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) = @@ -1086,7 +1099,7 @@ proc genProcBody(p: BProc; procBody: PNode) = proc isNoReturn(m: BModule; s: PSym): bool {.inline.} = sfNoReturn in s.flags and m.config.exc != excGoto -proc genProcAux(m: BModule, prc: PSym) = +proc genProcAux*(m: BModule, prc: PSym) = var p = newProc(prc, m) var header = newRopeAppender() genProcHeader(m, prc, header) @@ -2094,7 +2107,7 @@ proc updateCachedModule(m: BModule) = cf.flags = {CfileFlag.Cached} addFileToCompile(m.config, cf) -proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = +proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode = ## Also called from IC. if sfMainModule in m.module.flags: # phase ordering problem here: We need to announce this @@ -2140,8 +2153,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) = if m.g.forwardedProcs.len == 0: incl m.flags, objHasKidsValid - let disp = generateMethodDispatchers(graph) - for x in disp: genProcAux(m, x.sym) + result = generateMethodDispatchers(graph, m.idgen) let mm = m m.g.modulesClosed.add mm diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 4940a9093a..1711c5f9a4 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -213,7 +213,7 @@ proc sortBucket(a: var seq[PSym], relevantCols: IntSet) = a[j] = v if h == 1: break -proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PSym = +proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym = var base = methods[0].ast[dispatcherPos].sym result = base var paramLen = base.typ.len @@ -272,7 +272,7 @@ proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PS nilchecks.flags.incl nfTransf # should not be further transformed result.ast[bodyPos] = nilchecks -proc generateMethodDispatchers*(g: ModuleGraph): PNode = +proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode = result = newNode(nkStmtList) for bucket in 0..> $2)", "($1 >> $2)") + let typ = n[1].typ.skipTypes(abstractVarRange) + if typ.size == 8: + if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + applyFormat("BigInt.asIntN(64, $1 >> BigInt($2))") + elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: + applyFormat("BigInt.asUintN(64, $1 >> BigInt($2))") + else: + applyFormat("Math.floor($1 / Math.pow(2, $2))") else: - applyFormat("Math.floor($1 / Math.pow(2, $2))", "Math.floor($1 / Math.pow(2, $2))") + applyFormat("($1 >> $2)", "($1 >> $2)") of mBitandI: applyFormat("($1 & $2)", "($1 & $2)") of mBitorI: applyFormat("($1 | $2)", "($1 | $2)") of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)") @@ -697,7 +751,9 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mMulU: binaryUintExpr(p, n, r, "*") of mDivU: binaryUintExpr(p, n, r, "/") - if n[1].typ.skipTypes(abstractRange).size == 8: + if optJsBigInt64 notin p.config.globalOptions and + n[1].typ.skipTypes(abstractRange).size == 8: + # bigint / already truncates r.res = "Math.trunc($1)" % [r.res] of mDivI: arithAux(p, n, r, op) @@ -707,7 +763,13 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = var x, y: TCompRes gen(p, n[1], x) gen(p, n[2], y) - r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc] + let typ = n[1].typ.skipTypes(abstractVarRange) + if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + r.res = "BigInt.asIntN(64, BigInt.asUintN(64, $1) >> BigInt($2))" % [x.rdLoc, y.rdLoc] + elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: + r.res = "($1 >> BigInt($2))" % [x.rdLoc, y.rdLoc] + else: + r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc] of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr: arithAux(p, n, r, op) of mEqRef: @@ -1764,15 +1826,25 @@ proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: v createRecordVarAux(p, t.n, excludedFieldIDs, output) t = t[0] -proc arrayTypeForElemType(typ: PType): string = +proc arrayTypeForElemType(conf: ConfigRef; typ: PType): string = let typ = typ.skipTypes(abstractRange) case typ.kind of tyInt, tyInt32: "Int32Array" of tyInt16: "Int16Array" of tyInt8: "Int8Array" + of tyInt64: + if optJsBigInt64 in conf.globalOptions: + "BigInt64Array" + else: + "" of tyUInt, tyUInt32: "Uint32Array" of tyUInt16: "Uint16Array" of tyUInt8, tyChar, tyBool: "Uint8Array" + of tyUInt64: + if optJsBigInt64 in conf.globalOptions: + "BigUint64Array" + else: + "" of tyFloat32: "Float32Array" of tyFloat64, tyFloat: "Float64Array" of tyEnum: @@ -1786,11 +1858,18 @@ proc arrayTypeForElemType(typ: PType): string = proc createVar(p: PProc, typ: PType, indirect: bool): Rope = var t = skipTypes(typ, abstractInst) case t.kind - of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: + of tyInt8..tyInt32, tyUInt8..tyUInt32, tyEnum, tyChar: + result = putToSeq("0", indirect) + of tyInt, tyUInt: if $t.sym.loc.r == "bigint": result = putToSeq("0n", indirect) else: result = putToSeq("0", indirect) + of tyInt64, tyUInt64: + if optJsBigInt64 in p.config.globalOptions: + result = putToSeq("0n", indirect) + else: + result = putToSeq("0", indirect) of tyFloat..tyFloat128: result = putToSeq("0.0", indirect) of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent: @@ -1804,7 +1883,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = of tyArray: let length = toInt(lengthOrd(p.config, t)) let e = elemType(t) - let jsTyp = arrayTypeForElemType(e) + let jsTyp = arrayTypeForElemType(p.config, e) if jsTyp.len > 0: result = "new $1($2)" % [rope(jsTyp), rope(length)] elif length > 32: @@ -1979,7 +2058,11 @@ proc genNewSeq(p: PProc, n: PNode) = proc genOrd(p: PProc, n: PNode, r: var TCompRes) = case skipTypes(n[1].typ, abstractVar + abstractRange).kind - of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n[1], r) + of tyEnum, tyInt..tyInt32, tyUInt..tyUInt32, tyChar: gen(p, n[1], r) + of tyInt64, tyUInt64: + if optJsBigInt64 in p.config.globalOptions: + unaryExpr(p, n, r, "", "Number($1)") + else: gen(p, n[1], r) of tyBool: unaryExpr(p, n, r, "", "($1 ? 1 : 0)") else: internalError(p.config, n.info, "genOrd") @@ -2202,14 +2285,34 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = r.res = "($1).length - 1" % [x.rdLoc] r.kind = resExpr of mInc: - if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}: + let typ = n[1].typ.skipTypes(abstractVarRange) + case typ.kind + of tyUInt..tyUInt32: binaryUintExpr(p, n, r, "+", true) + of tyUInt64: + if optJsBigInt64 in p.config.globalOptions: + binaryExpr(p, n, r, "", "$1 = BigInt.asUintN(64, $3 + BigInt($2))", true) + else: binaryUintExpr(p, n, r, "+", true) + elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + if optOverflowCheck notin p.options: + binaryExpr(p, n, r, "", "$1 = BigInt.asIntN(64, $3 + BigInt($2))", true) + else: binaryExpr(p, n, r, "addInt64", "$1 = addInt64($3, BigInt($2))", true) else: if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2") else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)", true) of ast.mDec: - if n[1].typ.skipTypes(abstractRange).kind in {tyUInt..tyUInt64}: + let typ = n[1].typ.skipTypes(abstractVarRange) + case typ.kind + of tyUInt..tyUInt32: binaryUintExpr(p, n, r, "-", true) + of tyUInt64: + if optJsBigInt64 in p.config.globalOptions: + binaryExpr(p, n, r, "", "$1 = BigInt.asUintN(64, $3 - BigInt($2))", true) + else: binaryUintExpr(p, n, r, "+", true) + elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + if optOverflowCheck notin p.options: + binaryExpr(p, n, r, "", "$1 = BigInt.asIntN(64, $3 - BigInt($2))", true) + else: binaryExpr(p, n, r, "subInt64", "$1 = subInt64($3, BigInt($2))", true) else: if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2") else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)", true) @@ -2303,7 +2406,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = ## Nim sequence maps to JS array. var t = skipTypes(n.typ, abstractInst) let e = elemType(t) - let jsTyp = arrayTypeForElemType(e) + let jsTyp = arrayTypeForElemType(p.config, e) if skipTypes(n.typ, abstractVarRange).kind != tySequence and jsTyp.len > 0: # generate typed array # for example Nim generates `new Uint8Array([1, 2, 3])` for `[byte(1), 2, 3]` @@ -2384,7 +2487,27 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) = r.res = "(!!($1))" % [r.res] r.kind = resExpr elif toInt: - r.res = "(($1) | 0)" % [r.res] + if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number($1)" % [r.res] + else: + r.res = "(($1) | 0)" % [r.res] + elif dest.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + if fromInt or fromUint or src.kind in {tyBool, tyChar, tyEnum}: + r.res = "BigInt($1)" % [r.res] + elif src.kind in {tyFloat..tyFloat64}: + r.res = "BigInt(Math.trunc($1))" % [r.res] + elif src.kind == tyUInt64: + r.res = "BigInt.asIntN(64, $1)" % [r.res] + elif dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: + if fromInt or fromUint: + r.res = "BigInt($1)" % [r.res] + elif src.kind in {tyFloat..tyFloat64}: + r.res = "BigInt(Math.trunc($1))" % [r.res] + elif src.kind == tyInt64: + r.res = "BigInt.asUintN(64, $1)" % [r.res] + elif toUint or dest.kind in tyFloat..tyFloat64: + if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number($1)" % [r.res] else: # TODO: What types must we handle here? discard @@ -2395,7 +2518,11 @@ proc upConv(p: PProc, n: PNode, r: var TCompRes) = proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) = var a, b: TCompRes gen(p, n[0], r) - if optRangeCheck notin p.options or (skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64} and + let src = skipTypes(n[0].typ, abstractVarRange) + let dest = skipTypes(n.typ, abstractVarRange) + if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number($1)" % [r.res] + if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and checkUnsignedConversions notin p.config.legacyFeatures): discard "XXX maybe emit masking instructions here" else: @@ -2587,6 +2714,8 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) = if toUint and (fromInt or fromUint): let trimmer = unsignedTrimmer(dest.size) r.res = "($1 $2)" % [r.res, trimmer] + elif toUint and src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number(BigInt.asUintN($1, $2))" % [$(dest.size * 8), r.res] elif toInt: if fromInt: return @@ -2602,6 +2731,25 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) = of 4: "0xfffffffe" else: "" r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer] + elif src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number(BigInt.asIntN($1, $2))" % [$(dest.size * 8), r.res] + elif dest.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + if fromInt or fromUint or src.kind in {tyBool, tyChar, tyEnum}: + r.res = "BigInt($1)" % [r.res] + elif src.kind in {tyFloat..tyFloat64}: + r.res = "BigInt(Math.trunc($1))" % [r.res] + elif src.kind == tyUInt64: + r.res = "BigInt.asIntN(64, $1)" % [r.res] + elif dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: + if fromInt or fromUint: + r.res = "BigInt($1)" % [r.res] + elif src.kind in {tyFloat..tyFloat64}: + r.res = "BigInt(Math.trunc($1))" % [r.res] + elif src.kind == tyInt64: + r.res = "BigInt.asUintN(64, $1)" % [r.res] + elif dest.kind in tyFloat..tyFloat64: + if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number($1)" % [r.res] elif (src.kind == tyPtr and mapType(p, src) == etyObject) and dest.kind == tyPointer: r.address = r.res r.res = "null" @@ -2620,8 +2768,17 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkSym: genSym(p, n, r) of nkCharLit..nkUInt64Lit: - if n.typ.kind == tyBool: + case n.typ.skipTypes(abstractVarRange).kind + of tyBool: r.res = if n.intVal == 0: rope"false" else: rope"true" + of tyUInt64: + r.res = rope($cast[BiggestUInt](n.intVal)) + if optJsBigInt64 in p.config.globalOptions: + r.res.add('n') + of tyInt64: + r.res = rope(n.intVal) + if optJsBigInt64 in p.config.globalOptions: + r.res.add('n') else: r.res = rope(n.intVal) r.kind = resExpr @@ -2855,7 +3012,7 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope = var p = newInitProc(globals, m) attachProc(p, prc) - var disp = generateMethodDispatchers(graph) + var disp = generateMethodDispatchers(graph, m.idgen) for i in 0.. 0: - err.add "\nThis might be caused by a recursive module dependency:\n" - err.add c.recursiveDep - # prevent excessive errors for 'nim check' - c.recursiveDep = "" + var err: string + if name == "_": + err = "the special identifier '_' is ignored in declarations and cannot be used" + else: + err = "undeclared identifier: '" & name & "'" & extra + if c.recursiveDep.len > 0: + err.add "\nThis might be caused by a recursive module dependency:\n" + err.add c.recursiveDep + # prevent excessive errors for 'nim check' + c.recursiveDep = "" localError(c.config, info, errGenerated, err) proc errorUndeclaredIdentifierHint*(c: PContext; n: PNode, ident: PIdent): PSym = diff --git a/compiler/options.nim b/compiler/options.nim index 51a8ff6f02..da9c9cbbb9 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -102,13 +102,11 @@ type # please make sure we have under 32 options optBenchmarkVM # Enables cpuTime() in the VM optProduceAsm # produce assembler code optPanics # turn panics (sysFatal) into a process termination - optNimV1Emulation # emulate Nim v1.0 - optNimV12Emulation # emulate Nim v1.2 - optNimV16Emulation # emulate Nim v1.6 optSourcemap optProfileVM # enable VM profiler optEnableDeepCopy # ORC specific: enable 'deepcopy' for all types. optShowNonExportedFields # for documentation: show fields that are not exported + optJsBigInt64 # use bigints for 64-bit integers in JS TGlobalOptions* = set[TGlobalOption] @@ -479,7 +477,8 @@ const optBoundsCheck, optOverflowCheck, optAssert, optWarns, optRefCheck, optHints, optStackTrace, optLineTrace, # consider adding `optStackTraceMsgs` optTrMacros, optStyleCheck, optCursorInference} - DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace} + DefaultGlobalOptions* = {optThreadAnalysis, optExcessiveStackTrace, + optJsBigInt64} proc getSrcTimestamp(): DateTime = try: diff --git a/compiler/parser.nim b/compiler/parser.nim index abfc7b3239..c62cb0d8e5 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1197,14 +1197,18 @@ proc parseProcExpr(p: var Parser; isExpr: bool; kind: TNodeKind): PNode = let pragmas = optPragmas(p) if p.tok.tokType == tkEquals and isExpr: getTok(p) - skipComment(p, result) - result = newProcNode(kind, info, body = parseStmt(p), + result = newProcNode(kind, info, body = p.emptyNode, params = params, name = p.emptyNode, pattern = p.emptyNode, genericParams = p.emptyNode, pragmas = pragmas, exceptions = p.emptyNode) + skipComment(p, result) + result[bodyPos] = parseStmt(p) else: result = newNodeI(if kind == nkIteratorDef: nkIteratorTy else: nkProcTy, info) - if hasSignature: - result.add(params) + if hasSignature or pragmas.kind != nkEmpty: + if hasSignature: + result.add(params) + else: # pragmas but no param list, implies typeclass with pragmas + result.add(p.emptyNode) if kind == nkFuncDef: parMessage(p, "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead") result.add(pragmas) @@ -2277,13 +2281,19 @@ proc parseTypeDef(p: var Parser): PNode = setEndInfo() proc parseVarTuple(p: var Parser): PNode = - #| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr + #| varTupleLhs = '(' optInd (identWithPragma / varTupleLhs) ^+ comma optPar ')' + #| varTuple = varTupleLhs '=' optInd expr result = newNodeP(nkVarTuple, p) getTok(p) # skip '(' optInd(p, result) # progress guaranteed - while p.tok.tokType in {tkSymbol, tkAccent}: - var a = identWithPragma(p, allowDot=true) + while p.tok.tokType in {tkSymbol, tkAccent, tkParLe}: + var a: PNode + if p.tok.tokType == tkParLe: + a = parseVarTuple(p) + a.add(p.emptyNode) + else: + a = identWithPragma(p, allowDot=true) result.add(a) if p.tok.tokType != tkComma: break getTok(p) diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index 2bb0bc2473..4e574e56b7 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -1,6 +1,7 @@ import sem, cgen, modulegraphs, ast, llstream, parser, msgs, lineinfos, reorder, options, semdata, cgendata, modules, pathutils, - packages, syntaxes, depends, vm, pragmas, idents, lookups + packages, syntaxes, depends, vm, pragmas, idents, lookups, wordrecg, + liftdestructors import pipelineutils @@ -176,7 +177,16 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator case graph.pipelinePass of CgenPass: if bModule != nil: - finalCodegenActions(graph, BModule(bModule), finalNode) + let disps = finalCodegenActions(graph, BModule(bModule), finalNode) + if disps != nil: + let ctx = preparePContext(graph, module, idgen) + for disp in disps: + let retTyp = disp.sym.typ[0] + if retTyp != nil: + # todo properly semcheck the code of dispatcher? + createTypeBoundOps(graph, ctx, retTyp, disp.info, idgen) + genProcAux(BModule(bModule), disp.sym) + discard closePContext(graph, ctx, nil) of JSgenPass: when not defined(leanCompiler): discard finalJSCodeGen(graph, bModule, finalNode) diff --git a/compiler/sem.nim b/compiler/sem.nim index 48a7d56c8a..1c15f905e3 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -572,7 +572,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s let asgnExpr = defaultNodeField(c, recNode, recNode.typ) if asgnExpr != nil: hasDefault = true - asgnExpr.flags.incl nfUseDefaultField + asgnExpr.flags.incl nfSkipFieldChecking result.add newTree(nkExprColonExpr, recNode, asgnExpr) return @@ -582,7 +582,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)), newNodeIT(nkType, recNode.info, asgnType) ) - asgnExpr.flags.incl nfUseDefaultField + asgnExpr.flags.incl nfSkipFieldChecking asgnExpr.typ = recType result.add newTree(nkExprColonExpr, recNode, asgnExpr) else: @@ -604,7 +604,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = defaultValue = newIntNode(nkIntLit#[c.graph]#, 0) defaultValue.typ = discriminator.typ selectedBranch = recNode.pickCaseBranchIndex defaultValue - defaultValue.flags.incl nfUseDefaultField + defaultValue.flags.incl nfSkipFieldChecking result.add newTree(nkExprColonExpr, discriminator, defaultValue) result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1]) of nkSym: @@ -616,7 +616,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = let asgnExpr = defaultNodeField(c, recNode, recType) if asgnExpr != nil: asgnExpr.typ = recType - asgnExpr.flags.incl nfUseDefaultField + asgnExpr.flags.incl nfSkipFieldChecking result.add newTree(nkExprColonExpr, recNode, asgnExpr) else: doAssert false diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 54f03026f8..8445b25e71 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -132,7 +132,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, # just in case, should be impossible though if syms.len == 0: break - + if nextSymIndex > high(syms): # we have reached the end break @@ -293,7 +293,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors): const errTypeMismatch = "type mismatch: got <" errButExpected = "but expected one of:" - errExpectedPosition = "Expected one of (first mismatch at position [#]):" + errExpectedPosition = "Expected one of (first mismatch at [position]):" errUndeclaredField = "undeclared field: '$1'" errUndeclaredRoutine = "attempting to call undeclared routine: '$1'" errBadRoutine = "attempting to call routine: '$1'$2" @@ -338,7 +338,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = if n[0].kind in nkIdentKinds: let ident = considerQuotedIdent(c, n[0], n).s localError(c.config, n.info, errUndeclaredRoutine % ident) - else: + else: localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree) return @@ -630,7 +630,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, if efExplain notin flags: # repeat the overload resolution, # this time enabling all the diagnostic output (this should fail again) - discard semOverloadedCall(c, n, nOrig, filter, flags + {efExplain}) + result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain}) elif efNoUndeclared notin flags: notFoundError(c, n, errors) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index cfa34fcdc2..7e7499e458 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -302,7 +302,7 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode = result = newNodeI(nkConv, n.info) var targetType = semTypeNode(c, n[0], nil) - case targetType.kind + case targetType.skipTypes({tyDistinct}).kind of tyTypeDesc: internalAssert c.config, targetType.len > 0 if targetType.base.kind == tyNone: @@ -469,6 +469,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = res = t.kind == tyProc and t.callConv == ccClosure of "iterator": + # holdover from when `is iterator` didn't work let t = skipTypes(t1, abstractRange) res = t.kind == tyProc and t.callConv == ccClosure and @@ -787,7 +788,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode = else: result = newHiddenAddrTaken(c, n, isOutParam) -proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = +proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) = checkMinSonsLen(n, 1, c.config) const FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, @@ -795,10 +796,15 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove, mWasMoved} + template checkIfConverterCalled(c: PContext, n: PNode) = + ## Checks if there is a converter call which wouldn't be checked otherwise + # Call can sometimes be wrapped in a deref + let node = if n.kind == nkHiddenDeref: n[0] else: n + if node.kind == nkHiddenCallConv: + analyseIfAddressTakenInCall(c, node, true) # get the real type of the callee # it may be a proc var with a generic alias type, so we skip over them var t = n[0].typ.skipTypes({tyGenericInst, tyAlias, tySink}) - if n[0].kind == nkSym and n[0].sym.magic in FakeVarParams: # BUGFIX: check for L-Value still needs to be done for the arguments! # note sometimes this is eval'ed twice so we check for nkHiddenAddr here: @@ -813,6 +819,8 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = discard "allow access within a cast(unsafeAssign) section" else: localError(c.config, it.info, errVarForOutParamNeededX % $it) + # Make sure to still check arguments for converters + c.checkIfConverterCalled(n[i]) # bug #5113: disallow newSeq(result) where result is a 'var T': if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}: var arg = n[1] #.skipAddr @@ -824,15 +832,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = return for i in 1..= 2: + if a.len >= 2 or a.kind == nkTupleConstr: # unfortunately we need to rewrite ``(x, y) = foo()`` already here so # that overloading of the assignment operator still works. Usually we # prefer to do these rewritings in transf.nim: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 0827e68456..fa37af850a 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -78,14 +78,18 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, if macroToExpandSym(s): onUse(n.info, s) result = semTemplateExpr(c, n, s, {efNoSemCheck}) + c.friendModules.add(s.owner.getModule) result = semGenericStmt(c, result, {}, ctx) + discard c.friendModules.pop() else: result = symChoice(c, n, s, scOpen) of skMacro: if macroToExpandSym(s): onUse(n.info, s) result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + c.friendModules.add(s.owner.getModule) result = semGenericStmt(c, result, {}, ctx) + discard c.friendModules.pop() else: result = symChoice(c, n, s, scOpen) of skGenericParam: @@ -245,7 +249,9 @@ proc semGenericStmt(c: PContext, n: PNode, if macroToExpand(s) and sc.safeLen <= 1: onUse(fn.info, s) result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + c.friendModules.add(s.owner.getModule) result = semGenericStmt(c, result, flags, ctx) + discard c.friendModules.pop() else: n[0] = sc result = n @@ -254,7 +260,9 @@ proc semGenericStmt(c: PContext, n: PNode, if macroToExpand(s) and sc.safeLen <= 1: onUse(fn.info, s) result = semTemplateExpr(c, n, s, {efNoSemCheck}) + c.friendModules.add(s.owner.getModule) result = semGenericStmt(c, result, flags, ctx) + discard c.friendModules.pop() else: n[0] = sc result = n @@ -493,6 +501,20 @@ proc semGenericStmt(c: PContext, n: PNode, of nkExprColonExpr, nkExprEqExpr: checkMinSonsLen(n, 2, c.config) result[1] = semGenericStmt(c, n[1], flags, ctx) + of nkObjConstr: + for i in 0.. 3: - message(c.config, a.info, warnEachIdentIsTuple) + # generate new section from tuple unpacking and embed it into this one + let assignments = makeVarTupleSection(c, n, a, def, tup, symkind, result) + let resSection = semVarOrLet(c, assignments, symkind) + for resDef in resSection: + addToVarSection(c, result, n, resDef) + else: + if tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and + a.len > 3: + # var a, b = (1, 2) + message(c.config, a.info, warnEachIdentIsTuple) - for j in 0.. 0: v.flags.incl(sfShadowed) + for j in 0.. 0: v.flags.incl(sfShadowed) + else: + let shadowed = findShadowedVar(c, v) + if shadowed != nil: + shadowed.flags.incl(sfShadowed) + if shadowed.kind == skResult and sfGenSym notin v.flags: + message(c.config, a.info, warnResultShadowed) if def.kind != nkEmpty: if sfThread in v.flags: localError(c.config, def.info, errThreadvarCannotInit) setVarType(c, v, typ) @@ -708,35 +754,26 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = b.add copyTree(def) addToVarSection(c, result, n, b) v.ast = b - else: - if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j] - # bug #7663, for 'nim check' this can be a non-tuple: - if tup.kind == tyTuple: setVarType(c, v, tup[j]) - else: v.typ = tup - b[j] = newSymNode(v) - if def.kind == nkEmpty: - let actualType = v.typ.skipTypes({tyGenericInst, tyAlias, - tyUserTypeClassInst}) - if actualType.kind in {tyObject, tyDistinct} and - actualType.requiresInit: - defaultConstructionError(c, v.typ, v.info) - else: - checkNilable(c, v) - # allow let to not be initialised if imported from C: - if v.kind == skLet and sfImportc notin v.flags and (strictDefs notin c.features or not isLocalSym(v)): - localError(c.config, a.info, errLetNeedsInit) - if sfCompileTime in v.flags: - if a.kind != nkVarTuple: + if def.kind == nkEmpty: + let actualType = v.typ.skipTypes({tyGenericInst, tyAlias, + tyUserTypeClassInst}) + if actualType.kind in {tyObject, tyDistinct} and + actualType.requiresInit: + defaultConstructionError(c, v.typ, v.info) + else: + checkNilable(c, v) + # allow let to not be initialised if imported from C: + if v.kind == skLet and sfImportc notin v.flags and (strictDefs notin c.features or not isLocalSym(v)): + localError(c.config, a.info, errLetNeedsInit) + if sfCompileTime in v.flags: var x = newNodeI(result.kind, v.info) x.add result[i] vm.setupCompileTimeVar(c.module, c.idgen, c.graph, x) - else: - localError(c.config, a.info, "cannot destructure to compile time variable") - if v.flags * {sfGlobal, sfThread} == {sfGlobal}: - message(c.config, v.info, hintGlobalVar) - if {sfGlobal, sfPure} <= v.flags: - globalVarInitCheck(c, def) - suggestSym(c.graph, v.info, v, c.graph.usageSym) + if v.flags * {sfGlobal, sfThread} == {sfGlobal}: + message(c.config, v.info, hintGlobalVar) + if {sfGlobal, sfPure} <= v.flags: + globalVarInitCheck(c, def) + suggestSym(c.graph, v.info, v, c.graph.usageSym) proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) @@ -789,23 +826,19 @@ proc semConst(c: PContext, n: PNode): PNode = typeAllowedCheck(c, a.info, typ, skConst, typFlags) if a.kind == nkVarTuple: - if typ.kind != tyTuple: - localError(c.config, a.info, errXExpected, "tuple") - elif a.len-2 != typ.len: - localError(c.config, a.info, errWrongNumberOfVariables) - b = newNodeI(nkVarTuple, a.info) - newSons(b, a.len) - b[^2] = a[^2] - b[^1] = def + # generate new section from tuple unpacking and embed it into this one + let assignments = makeVarTupleSection(c, n, a, def, typ, skConst, result) + let resSection = semConst(c, assignments) + for resDef in resSection: + addToVarSection(c, result, n, resDef) + else: + for j in 0..= result.safeLen: return result @@ -2292,7 +2320,6 @@ proc semConverterDef(c: PContext, n: PNode): PNode = addConverterDef(c, LazySym(sym: s)) proc semMacroDef(c: PContext, n: PNode): PNode = - checkSonsLen(n, bodyPos + 1, c.config) result = semProcAux(c, n, skMacro, macroPragmas) # macros can transform macros to nothing: if namePos >= result.safeLen: return result diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 26493703dc..d86f5ddb2c 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -130,8 +130,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = e.typ = result e.position = int(counter) let symNode = newSymNode(e) - if optNimV1Emulation notin c.config.globalOptions and identToReplace != nil and - c.config.cmd notin cmdDocLike: # A hack to produce documentation for enum fields. + if identToReplace != nil and c.config.cmd notin cmdDocLike: + # A hack to produce documentation for enum fields. identToReplace[] = symNode if e.position == 0: hasNull = true if result.sym != nil and sfExported in result.sym.flags: @@ -519,7 +519,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = let fSym = newSymNode(field) if hasDefaultField: fSym.sym.ast = a[^1] - fSym.sym.ast.flags.incl nfUseDefaultField + fSym.sym.ast.flags.incl nfSkipFieldChecking result.n.add fSym addSonSkipIntLit(result, typ, c.idgen) styleCheckDef(c, a[j].info, field) @@ -803,8 +803,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, else: illFormedAst(n, c.config) if c.inGenericContext > 0: # use a new check intset here for each branch: - var newCheck: IntSet - assign(newCheck, check) + var newCheck: IntSet = check var newPos = pos var newf = newNodeI(nkRecList, n.info) semRecordNodeAux(c, it[idx], newCheck, newPos, newf, rectype, hasCaseFields) @@ -868,7 +867,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, let fSym = newSymNode(f) if hasDefaultField: fSym.sym.ast = n[^1] - fSym.sym.ast.flags.incl nfUseDefaultField + fSym.sym.ast.flags.incl nfSkipFieldChecking if a.kind == nkEmpty: father.add fSym else: a.add fSym styleCheckDef(c, f) @@ -1311,6 +1310,16 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if hasDefault: def = a[^1] + if a.len > 3: + var msg = "" + for j in 0 ..< a.len - 2: + if msg.len != 0: msg.add(", ") + msg.add($a[j]) + msg.add(" all have default value '") + msg.add(def.renderTree) + msg.add("', this may be unintentional, " & + "either use ';' (semicolon) or explicitly write each default value") + message(c.config, a.info, warnImplicitDefaultValue, msg) block determineType: var defTyp = typ if genericParams != nil and genericParams.len > 0: @@ -1359,6 +1368,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, for j in 0.. 0: pragma(c, s, n[1], procTypePragmas) when useEffectSystem: setEffectsForProcType(c.graph, result, n[1]) - elif c.optionStack.len > 0 and optNimV1Emulation notin c.config.globalOptions: + elif c.optionStack.len > 0: # we construct a fake 'nkProcDef' for the 'mergePragmas' inside 'implicitPragmas'... s.ast = newTree(nkProcDef, newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info), newNodeI(nkEmpty, n.info)) @@ -2043,25 +2054,27 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkOutTy: result = semVarOutType(c, n, prev, {tfIsOutParam}) of nkDistinctTy: result = semDistinct(c, n, prev) of nkStaticTy: result = semStaticType(c, n[0], prev) - of nkIteratorTy: - if n.len == 0: + of nkProcTy, nkIteratorTy: + if n.len == 0 or n[0].kind == nkEmpty: + # 0 length or empty param list with possible pragmas imply typeclass result = newTypeS(tyBuiltInTypeClass, c) let child = newTypeS(tyProc, c) - child.flags.incl tfIterator + var symKind: TSymKind + if n.kind == nkIteratorTy: + child.flags.incl tfIterator + if n.len > 0 and n[1].kind != nkEmpty and n[1].len > 0: + # typeclass with pragma + let symKind = if n.kind == nkIteratorTy: skIterator else: skProc + # dummy symbol for `pragma`: + var s = newSymS(symKind, newIdentNode(getIdent(c.cache, "dummy"), n.info), c) + s.typ = child + # for now only call convention pragmas supported in proc typeclass + pragma(c, s, n[1], {FirstCallConv..LastCallConv}) result.addSonSkipIntLit(child, c.idgen) - else: - result = semProcTypeWithScope(c, n, prev, skIterator) - if result.kind == tyProc: - result.flags.incl(tfIterator) - if n.lastSon.kind == nkPragma and hasPragma(n.lastSon, wInline): - result.callConv = ccInline - else: - result.callConv = ccClosure - of nkProcTy: - if n.len == 0: - result = newConstraint(c, tyProc) else: result = semProcTypeWithScope(c, n, prev, skProc) + if n.kind == nkIteratorTy and result.kind == tyProc: + result.flags.incl(tfIterator) of nkEnumTy: result = semEnum(c, n, prev) of nkType: result = n.typ of nkStmtListType: result = semStmtListType(c, n, prev) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 0ef1d0898f..2fe8c55e41 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -204,7 +204,7 @@ proc hasValuelessStatics(n: PNode): bool = proc doThing(_: MyThing) ]# if n.safeLen == 0: - n.typ.kind == tyStatic + n.typ == nil or n.typ.kind == tyStatic else: for x in n: if hasValuelessStatics(x): diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 7e2a0b660e..e46508cf2c 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -9,11 +9,10 @@ ## Computes hash values for routine (proc, method etc) signatures. -import ast, tables, ropes, md5, modulegraphs, options, msgs, packages, pathutils +import ast, tables, ropes, md5, modulegraphs, options, msgs, pathutils from hashes import Hash import types -import std/os when defined(nimPreviewSlimSystem): import std/assertions diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 87a4fdf1c7..92971b072a 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -624,6 +624,9 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = if f.len != a.len: return result = isEqual # start with maximum; also correct for no # params at all + + if f.flags * {tfIterator} != a.flags * {tfIterator}: + return isNone template checkParam(f, a) = result = minRel(result, procParamTypeRel(c, f, a)) @@ -1295,7 +1298,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyNil: result = isNone else: discard of tyOrdinal: - if isOrdinalType(a, allowEnumWithHoles = optNimV1Emulation in c.c.config.globalOptions): + if isOrdinalType(a): var x = if a.kind == tyOrdinal: a[0] else: a if f[0].kind == tyNone: result = isGeneric @@ -1636,13 +1639,19 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyBuiltInTypeClass: considerPreviousT: - let targetKind = f[0].kind + let target = f[0] + let targetKind = target.kind let effectiveArgType = a.skipTypes({tyRange, tyGenericInst, tyBuiltInTypeClass, tyAlias, tySink, tyOwned}) - let typeClassMatches = targetKind == effectiveArgType.kind and - not effectiveArgType.isEmptyContainer - if typeClassMatches or - (targetKind in {tyProc, tyPointer} and effectiveArgType.kind == tyNil): + if targetKind == effectiveArgType.kind: + if effectiveArgType.isEmptyContainer: + return isNone + if targetKind == tyProc: + if target.flags * {tfIterator} != effectiveArgType.flags * {tfIterator}: + return isNone + if tfExplicitCallConv in target.flags and + target.callConv != effectiveArgType.callConv: + return isNone put(c, f, a) return isGeneric else: @@ -1979,8 +1988,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, if srca == isSubtype: param = implicitConv(nkHiddenSubConv, src, copyTree(arg), m, c) elif src.kind in {tyVar}: - # Analyse the converter return type - arg.sym.flags.incl sfAddrTaken + # Analyse the converter return type. param = newNodeIT(nkHiddenAddr, arg.info, s.typ[1]) param.add copyTree(arg) else: diff --git a/compiler/types.nim b/compiler/types.nim index 457568e327..3874295675 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1686,7 +1686,7 @@ proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = of tyTuple: var cycleDetectorCopy: IntSet for i in 0.. 1: + if n.len > 1 and n[0].kind == nkFormalParams: let params = n[0] - assert params.kind == nkFormalParams assert params.len > 0 result = "proc(" for i in 1..} stmt typeDef = identVisDot genericParamList? pragma '=' optInd typeDefValue indAndComment? -varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr +varTupleLhs = '(' optInd (identWithPragma / varTupleLhs) ^+ comma optPar ')' +varTuple = varTupleLhs '=' optInd expr colonBody = colcom stmt postExprBlocks? variable = (varTuple / identColonEquals) colonBody? indAndComment constant = (varTuple / identWithPragma) (colon typeDesc)? '=' optInd expr indAndComment diff --git a/doc/lib.md b/doc/lib.md index d6ec408ec7..a76b29151f 100644 --- a/doc/lib.md +++ b/doc/lib.md @@ -47,17 +47,17 @@ Core Provides a series of low-level methods for bit manipulation. * [compilesettings](compilesettings.html) - This module allows querying the compiler about diverse configuration settings. + Querying the compiler about diverse configuration settings from code. * [cpuinfo](cpuinfo.html) - This module implements procs to determine the number of CPUs / cores. + Procs to determine the number of CPUs / cores. * [effecttraits](effecttraits.html) - This module provides access to the inferred .raises effects + Access to the inferred .raises effects for Nim's macro system. * [endians](endians.html) - This module contains helpers that deal with different byte orders. + Helpers that deal with different byte orders. * [locks](locks.html) Locks and condition variables for Nim. @@ -75,10 +75,10 @@ Core Provides (unsafe) access to Nim's run-time type information. * [typetraits](typetraits.html) - This module defines compile-time reflection procs for working with types. + Compile-time reflection procs for working with types. * [volatile](volatile.html) - This module contains code for generating volatile loads and stores, + Code for generating volatile loads and stores, which are useful in embedded and systems programming. @@ -86,24 +86,24 @@ Algorithms ---------- * [algorithm](algorithm.html) - This module implements some common generic algorithms like sort or binary search. + Some common generic algorithms like sort or binary search. * [enumutils](enumutils.html) - This module adds functionality for the built-in `enum` type. + Additional functionality for the built-in `enum` type. * [sequtils](sequtils.html) - This module implements operations for the built-in `seq` type + Operations for the built-in `seq` type which were inspired by functional programming languages. * [setutils](setutils.html) - This module adds functionality for the built-in `set` type. + Additional functionality for the built-in `set` type. Collections ----------- * [critbits](critbits.html) - This module implements a *crit bit tree* which is an efficient + A *crit bit tree* which is an efficient container for a sorted set of strings, or a sorted mapping of strings. * [deques](deques.html) @@ -127,7 +127,7 @@ Collections Efficient implementation of a set of ordinals as a sparse bit set. * [ropes](ropes.html) - This module contains support for a *rope* data type. + A *rope* data type. Ropes can represent very long strings efficiently; in particular, concatenation is done in O(1) instead of O(n). @@ -150,7 +150,7 @@ String handling Utilities for `cstring` handling. * [editdistance](editdistance.html) - This module contains an algorithm to compute the edit distance between two + An algorithm to compute the edit distance between two Unicode strings. * [encodings](encodings.html) @@ -158,35 +158,37 @@ String handling the `iconv` library, on Windows the Windows API. * [formatfloat](formatfloat.html) - This module implements formatting floats as strings. + Formatting floats as strings. * [objectdollar](objectdollar.html) - This module implements a generic `$` operator to convert objects to strings. + A generic `$` operator to convert objects to strings. * [punycode](punycode.html) Implements a representation of Unicode with the limited ASCII character subset. * [strbasics](strbasics.html) - This module provides some high performance string operations. + Some high performance string operations. * [strformat](strformat.html) Macro based standard string interpolation/formatting. Inspired by - Python's f-strings. + Python's f-strings.\ + **Note:** if you need templating, consider using Nim + [Source Code Filters (SCF)](filters.html). * [strmisc](strmisc.html) - This module contains uncommon string handling operations that do not - fit with the commonly used operations in strutils. + Uncommon string handling operations that do not + fit with the commonly used operations in [strutils](strutils.html). * [strscans](strscans.html) - This module contains a `scanf` macro for convenient parsing of mini languages. + A `scanf` macro for convenient parsing of mini languages. * [strutils](strutils.html) - This module contains common string handling operations like changing + Common string handling operations like changing case of a string, splitting a string into substrings, searching for substrings, replacing substrings. * [unicode](unicode.html) - This module provides support to handle the Unicode UTF-8 encoding. + Support for handling the Unicode UTF-8 encoding. * [unidecode](unidecode.html) It provides a single proc that does Unicode to ASCII transliterations. @@ -196,7 +198,7 @@ String handling Nim support for C/C++'s wide strings. * [wordwrap](wordwrap.html) - This module contains an algorithm to wordwrap a Unicode string. + An algorithm for word-wrapping Unicode strings. Time handling @@ -213,17 +215,16 @@ Generic Operating System Services --------------------------------- * [appdirs](appdirs.html) - This module implements helpers for determining special directories used by apps. + Helpers for determining special directories used by apps. * [cmdline](cmdline.html) - This module contains system facilities for reading command - line parameters. + System facilities for reading command line parameters. * [dirs](dirs.html) - This module implements directory handling. + Directory handling. * [distros](distros.html) - This module implements the basics for OS distribution ("distro") detection + Basics for OS distribution ("distro") detection and the OS's native package manager. Its primary purpose is to produce output for Nimble packages, but it also contains the widely used **Distribution** enum @@ -231,19 +232,19 @@ Generic Operating System Services See [packaging](packaging.html) for hints on distributing Nim using OS packages. * [dynlib](dynlib.html) - This module implements the ability to access symbols from shared libraries. + Accessing symbols from shared libraries. * [envvars](envvars.html) - This module implements environment variable handling. + Environment variable handling. * [exitprocs](exitprocs.html) - This module allows adding hooks to program exit. + Adding hooks to program exit. * [files](files.html) - This module implements file handling. + File handling. * [memfiles](memfiles.html) - This module provides support for memory-mapped files (Posix's `mmap`) + Support for memory-mapped files (Posix's `mmap`) on the different operating systems. * [os](os.html) @@ -252,52 +253,50 @@ Generic Operating System Services commands, etc. * [oserrors](oserrors.html) - This module implements OS error reporting. + OS error reporting. * [osproc](osproc.html) Module for process communication beyond `os.execShellCmd`. * [paths](paths.html) - This module implements path handling. + Path handling. * [reservedmem](reservedmem.html) - This module provides utilities for reserving portions of the + Utilities for reserving portions of the address space of a program without consuming physical memory. * [streams](streams.html) - This module provides a stream interface and two implementations thereof: + A stream interface and two implementations thereof: the `FileStream` and the `StringStream` which implement the stream interface for Nim file objects (`File`) and strings. Other modules may provide other implementations for this standard stream interface. * [symlinks](symlinks.html) - This module implements symlink handling. + Symlink handling. * [syncio](syncio.html) - This module implements various synchronized I/O operations. + Various synchronized I/O operations. * [terminal](terminal.html) - This module contains a few procedures to control the *terminal* - (also called *console*). The implementation simply uses ANSI escape - sequences and does not depend on any other module. + A module to control the terminal output (also called *console*). * [tempfiles](tempfiles.html) - This module provides some utils to generate temporary path names and - create temporary files and directories. + Some utilities for generating temporary path names and + creating temporary files and directories. Math libraries -------------- * [complex](complex.html) - This module implements complex numbers and relevant mathematical operations. + Complex numbers and relevant mathematical operations. * [fenv](fenv.html) Floating-point environment. Handling of floating-point rounding and exceptions (overflow, zero-divide, etc.). * [lenientops](lenientops.html) - Provides binary operators for mixed integer/float expressions for convenience. + Binary operators for mixed integer/float expressions for convenience. * [math](math.html) Mathematical operations like cosine, square root. @@ -306,7 +305,7 @@ Math libraries Fast and tiny random number generator. * [rationals](rationals.html) - This module implements rational numbers and relevant mathematical operations. + Rational numbers and relevant mathematical operations. * [stats](stats.html) Statistical analysis. @@ -322,75 +321,69 @@ Internet Protocols and Support Exports `asyncmacro` and `asyncfutures` for native backends, and `asyncjs` on the JS backend. * [asyncdispatch](asyncdispatch.html) - This module implements an asynchronous dispatcher for IO operations. + An asynchronous dispatcher for IO operations. * [asyncfile](asyncfile.html) - This module implements asynchronous file reading and writing using - `asyncdispatch`. + An asynchronous file reading and writing using `asyncdispatch`. * [asyncftpclient](asyncftpclient.html) - This module implements an asynchronous FTP client using the `asyncnet` - module. + An asynchronous FTP client using the `asyncnet` module. * [asynchttpserver](asynchttpserver.html) - This module implements an asynchronous HTTP server using the `asyncnet` - module. + An asynchronous HTTP server using the `asyncnet` module. * [asyncmacro](asyncmacro.html) - Implements the `async` and `multisync` macros for `asyncdispatch`. + `async` and `multisync` macros for `asyncdispatch`. * [asyncnet](asyncnet.html) - This module implements asynchronous sockets based on the `asyncdispatch` - module. + Asynchronous sockets based on the `asyncdispatch` module. * [asyncstreams](asyncstreams.html) - This module provides `FutureStream` - a future that acts as a queue. + `FutureStream` - a future that acts as a queue. * [cgi](cgi.html) - This module implements helpers for CGI applications. + Helpers for CGI applications. * [cookies](cookies.html) - This module contains helper procs for parsing and generating cookies. + Helper procs for parsing and generating cookies. * [httpclient](httpclient.html) - This module implements a simple HTTP client which supports both synchronous + A simple HTTP client with support for both synchronous and asynchronous retrieval of web pages. * [mimetypes](mimetypes.html) - This module implements a mimetypes database. + A mimetypes database. * [nativesockets](nativesockets.html) - This module implements a low-level sockets API. + A low-level sockets API. * [net](net.html) - This module implements a high-level sockets API. It replaces the - `sockets` module. + A high-level sockets API. * [selectors](selectors.html) - This module implements a selector API with backends specific to each OS. - Currently, epoll on Linux and select on other operating systems. + A selector API with backends specific to each OS. + Supported OS primitives: `epoll`, `kqueue`, `poll`, and `select` on Windows. * [smtp](smtp.html) - This module implements a simple SMTP client. + A simple SMTP client with support for both synchronous and asynchronous operation. * [socketstreams](socketstreams.html) - This module provides an implementation of the streams interface for sockets. - + An implementation of the streams interface for sockets. * [uri](uri.html) - This module provides functions for working with URIs. + Functions for working with URIs and URLs. Threading --------- * [isolation](isolation.html) - This module implements the `Isolated[T]` type for + The `Isolated[T]` type for safe construction of isolated subgraphs that can be passed efficiently to different channels and threads. * [tasks](tasks.html) - This module provides basic primitives for creating parallel programs. + Basic primitives for creating parallel programs. * [threadpool](threadpool.html) Implements Nim's [spawn](manual_experimental.html#parallel-amp-spawn). @@ -403,13 +396,13 @@ Parsers ------- * [htmlparser](htmlparser.html) - This module parses an HTML document and creates its XML tree representation. + HTML document parser that creates a XML tree representation. * [json](json.html) High-performance JSON parser. * [lexbase](lexbase.html) - This is a low-level module that implements an extremely efficient buffering + A low-level module that implements an extremely efficient buffering scheme for lexers and parsers. This is used by the diverse parsing modules. * [parsecfg](parsecfg.html) @@ -423,7 +416,7 @@ Parsers The `parsecsv` module implements a simple high-performance CSV parser. * [parsejson](parsejson.html) - This module implements a JSON parser. It is used and exported by the [json](json.html) module, but can also be used in its own right. + A JSON parser. It is used and exported by the [json](json.html) module, but can also be used in its own right. * [parseopt](parseopt.html) The `parseopt` module implements a command line option parser. @@ -432,7 +425,7 @@ Parsers The `parsesql` module implements a simple high-performance SQL parser. * [parseutils](parseutils.html) - This module contains helpers for parsing tokens, numbers, identifiers, etc. + Helpers for parsing tokens, numbers, identifiers, etc. * [parsexml](parsexml.html) The `parsexml` module implements a simple high performance XML/HTML parser. @@ -441,7 +434,7 @@ Parsers web can be parsed with it. * [pegs](pegs.html) - This module contains procedures and operators for handling PEGs. + Procedures and operators for handling PEGs. Docutils @@ -453,14 +446,14 @@ Docutils The interface supports one language nested in another. * [packages/docutils/rst](rst.html) - This module implements a reStructuredText parser. A large subset + A reStructuredText parser. A large subset is implemented. Some features of the markdown wiki syntax are also supported. * [packages/docutils/rstast](rstast.html) - This module implements an AST for the reStructuredText parser. + An AST for the reStructuredText parser. * [packages/docutils/rstgen](rstgen.html) - This module implements a generator of HTML/Latex from reStructuredText. + A generator of HTML/Latex from reStructuredText. XML Processing @@ -471,17 +464,17 @@ XML Processing contains a macro for XML/HTML code generation. * [xmlparser](xmlparser.html) - This module parses an XML document and creates its XML tree representation. + XML document parser that creates a XML tree representation. Generators ---------- * [genasts](genasts.html) - This module implements AST generation using captured variables for macros. + AST generation using captured variables for macros. * [htmlgen](htmlgen.html) - This module implements a simple XML and HTML code + A simple XML and HTML code generator. Each commonly used HTML tag has a corresponding macro that generates a string with its HTML representation. @@ -490,14 +483,13 @@ Hashing ------- * [base64](base64.html) - This module implements a Base64 encoder and decoder. + A Base64 encoder and decoder. * [hashes](hashes.html) - This module implements efficient computations of hash values for diverse - Nim types. + Efficient computations of hash values for diverse Nim types. * [md5](md5.html) - This module implements the MD5 checksum algorithm. + The MD5 checksum algorithm. * [oids](oids.html) An OID is a global ID that consists of a timestamp, @@ -505,14 +497,14 @@ Hashing produce a globally distributed unique ID. * [sha1](sha1.html) - This module implements the SHA-1 checksum algorithm. + The SHA-1 checksum algorithm. Serialization ------------- * [jsonutils](jsonutils.html) - This module implements a hookable (de)serialization for arbitrary types + Hookable (de)serialization for arbitrary types using JSON. * [marshal](marshal.html) @@ -524,35 +516,35 @@ Miscellaneous ------------- * [assertions](assertions.html) - This module implements assertion handling. + Assertion handling. * [browsers](browsers.html) - This module implements procs for opening URLs with the user's default + Procs for opening URLs with the user's default browser. * [colors](colors.html) - This module implements color handling for Nim. + Color handling. * [coro](coro.html) - This module implements experimental coroutines in Nim. + Experimental coroutines in Nim. * [decls](decls.html) - This module implements syntax sugar for some declarations. + Syntax sugar for some declarations. * [enumerate](enumerate.html) - This module implements `enumerate` syntactic sugar based on Nim's macro system. + `enumerate` syntactic sugar based on Nim's macro system. * [importutils](importutils.html) Utilities related to import and symbol resolution. * [logging](logging.html) - This module implements a simple logger. + A simple logger. * [segfaults](segfaults.html) Turns access violations or segfaults into a `NilAccessDefect` exception. * [sugar](sugar.html) - This module implements nice syntactic sugar based on Nim's macro system. + Nice syntactic sugar based on Nim's macro system. * [unittest](unittest.html) Implements a Unit testing DSL. @@ -561,10 +553,10 @@ Miscellaneous Decode variable-length integers that are compatible with SQLite. * [with](with.html) - This module implements the `with` macro for easy function chaining. + The `with` macro for easy function chaining. * [wrapnils](wrapnils.html) - This module allows evaluating expressions safely against nil dereferences. + Allows evaluating expressions safely against nil dereferences. Modules for the JavaScript backend @@ -603,12 +595,12 @@ Regular expressions ------------------- * [re](re.html) - This module contains procedures and operators for handling regular + Procedures and operators for handling regular expressions. The current implementation uses PCRE. * [nre](nre.html) - This module contains many help functions for handling regular expressions. + Many help functions for handling regular expressions. The current implementation uses PCRE. Database support @@ -635,7 +627,7 @@ Generic Operating System Services --------------------------------- * [rdstdin](rdstdin.html) - This module contains code for reading from stdin. + Code for reading user input from stdin. Wrappers @@ -649,7 +641,7 @@ Windows-specific ---------------- * [winlean](winlean.html) - Contains a wrapper for a small subset of the Win32 API. + Wrapper for a small subset of the Win32 API. * [registry](registry.html) Windows registry support. @@ -658,7 +650,7 @@ UNIX specific ------------- * [posix](posix.html) - Contains a wrapper for the POSIX standard. + Wrapper for the POSIX standard. * [posix_utils](posix_utils.html) Contains helpers for the POSIX standard or specialized for Linux and BSDs. @@ -674,13 +666,13 @@ Database support ---------------- * [mysql](mysql.html) - Contains a wrapper for the mySQL API. + Wrapper for the mySQL API. * [odbcsql](odbcsql.html) interface to the ODBC driver. * [postgres](postgres.html) - Contains a wrapper for the PostgreSQL API. + Wrapper for the PostgreSQL API. * [sqlite3](sqlite3.html) - Contains a wrapper for the SQLite 3 API. + Wrapper for the SQLite 3 API. Network Programming and Internet Protocols diff --git a/doc/manual.md b/doc/manual.md index 31c620ca73..f5ee10fda3 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -3076,12 +3076,25 @@ when they are declared. The only exception to this is if the `{.importc.}` pragma (or any of the other `importX` pragmas) is applied, in this case the value is expected to come from native code, typically a C/C++ `const`. +Special identifier `_` (underscore) +----------------------------------- + +The identifier `_` has a special meaning in declarations. +Any definition with the name `_` will not be added to scope, meaning the +definition is evaluated, but cannot be used. As a result the name `_` can be +indefinitely redefined. + + ```nim + let _ = 123 + echo _ # error + let _ = 456 # compiles + ``` Tuple unpacking --------------- -In a `var` or `let` statement tuple unpacking can be performed. The special -identifier `_` can be used to ignore some parts of the tuple: +In a `var`, `let` or `const` statement tuple unpacking can be performed. +The special identifier `_` can be used to ignore some parts of the tuple: ```nim proc returnsTuple(): (int, int, int) = (4, 2, 3) @@ -3089,6 +3102,35 @@ identifier `_` can be used to ignore some parts of the tuple: let (x, _, z) = returnsTuple() ``` +This is treated as syntax sugar for roughly the following: + + ```nim + let + tmpTuple = returnsTuple() + x = tmpTuple[0] + z = tmpTuple[2] + ``` + +For `var` or `let` statements, if the value expression is a tuple literal, +each expression is directly expanded into an assignment without the use of +a temporary variable. + + ```nim + let (x, y, z) = (1, 2, 3) + # becomes + let + x = 1 + y = 2 + z = 3 + ``` + +Tuple unpacking can also be nested: + + ```nim + proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3) + + let (x, (_, y), _, z) = returnsNestedTuple() + ``` Const section @@ -3774,15 +3816,6 @@ every time the function is called. proc foo(a: int, b: int = 47): int ``` -Just as the comma propagates the types from right to left until the -first parameter or until a semicolon is hit, it also propagates the -default value starting from the parameter declared with it. - - ```nim - # Both a and b are optional with 47 as their default values. - proc foo(a, b: int = 47): int - ``` - Parameters can be declared mutable and so allow the proc to modify those arguments, by using the type modifier `var`. @@ -5434,9 +5467,9 @@ type class matches ================== =================================================== `object` any object type `tuple` any tuple type - `enum` any enumeration `proc` any proc type +`iterator` any iterator type `ref` any `ref` type `ptr` any `ptr` type `var` any `var` type @@ -5455,7 +5488,7 @@ more complex type classes: ```nim # create a type class that will match all tuple and object types - type RecordType = tuple or object + type RecordType = (tuple or object) proc printFields[T: RecordType](rec: T) = for key, value in fieldPairs(rec): @@ -5496,6 +5529,17 @@ as `type constraints`:idx: of the generic type parameter: onlyIntOrString("xy", 50) # invalid as 'T' cannot be both at the same time ``` +`proc` and `iterator` type classes also accept a calling convention pragma +to restrict the calling convention of the matching `proc` or `iterator` type. + + ```nim + proc onlyClosure[T: proc {.closure.}](x: T) = discard + + onlyClosure(proc() = echo "hello") # valid + proc foo() {.nimcall.} = discard + onlyClosure(foo) # type mismatch + ``` + Implicit generics ----------------- @@ -5504,7 +5548,7 @@ A type class can be used directly as the parameter's type. ```nim # create a type class that will match all tuple and object types - type RecordType = tuple or object + type RecordType = (tuple or object) proc printFields(rec: RecordType) = for key, value in fieldPairs(rec): diff --git a/koch.nim b/koch.nim index 52378e43fb..d89d9fc931 100644 --- a/koch.nim +++ b/koch.nim @@ -229,6 +229,14 @@ proc buildTools(args: string = "") = nimCompileFold("Compile atlas", "tools/atlas/atlas.nim", options = "-d:release " & args, outputName = "atlas") +proc testTools(args: string = "") = + nimCompileFold("Compile nimgrep", "tools/nimgrep.nim", + options = "-d:release " & args) + when defined(windows): buildVccTool(args) + bundleNimpretty(args) + nimCompileFold("Compile testament", "testament/testament.nim", options = "-d:release " & args) + nimCompileFold("Compile atlas", "tools/atlas/atlas.nim", options = "-d:release " & args, + outputName = "atlas") proc nsis(latest: bool; args: string) = bundleNimbleExe(latest, args) @@ -546,7 +554,7 @@ proc runCI(cmd: string) = nimCompileFold("Compile testament", "testament/testament.nim", options = "-d:release") execFold("Test selected Nimble packages", "testament $# pcat nimble-packages" % batchParam) else: - buildTools() + testTools() for a in "zip opengl sdl1 jester@#head".split: let buildDeps = "build"/"deps" # xxx factor pending https://github.com/timotheecour/Nim/issues/616 diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 9cb694bd85..28f52f0a93 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -947,6 +947,8 @@ proc treeTraverse(n: NimNode; res: var string; level = 0; isLisp = false, indent discard # same as nil node in this representation of nnkCharLit .. nnkInt64Lit: res.add(" " & $n.intVal) + of nnkUIntLit .. nnkUInt64Lit: + res.add(" " & $cast[uint64](n.intVal)) of nnkFloatLit .. nnkFloat64Lit: res.add(" " & $n.floatVal) of nnkStrLit .. nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym: diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim index 781e8fd57f..5147b550d8 100644 --- a/lib/js/jscore.nim +++ b/lib/js/jscore.nim @@ -13,7 +13,7 @@ ## specific requirements and solely targets JavaScript, you should be using ## the relevant functions in the `math`, `json`, and `times` stdlib ## modules instead. -import std/private/since +import std/private/[since, jsutils] when not defined(js): {.error: "This module only works on the JavaScript platform".} @@ -74,9 +74,16 @@ proc parse*(d: DateLib, s: cstring): int {.importcpp.} proc newDate*(): DateTime {. importcpp: "new Date()".} -proc newDate*(date: int|int64|string): DateTime {. +proc newDate*(date: int|string): DateTime {. importcpp: "new Date(#)".} +whenJsNoBigInt64: + proc newDate*(date: int64): DateTime {. + importcpp: "new Date(#)".} +do: + proc newDate*(date: int64): DateTime {. + importcpp: "new Date(Number(#))".} + proc newDate*(year, month, day, hours, minutes, seconds, milliseconds: int): DateTime {. importcpp: "new Date(#,#,#,#,#,#,#)".} diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index b3b1fb9c08..4bb623d20e 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -350,7 +350,7 @@ type footnoteAnchor = "footnote anchor", headlineAnchor = "implicitly-generated headline anchor" AnchorSubst = object - info: TLineInfo # where the anchor was defined + info: TLineInfo # the file where the anchor was defined priority: int case kind: range[arInternalRst .. arNim] of arInternalRst: @@ -360,6 +360,7 @@ type anchorTypeExt: RstAnchorKind refnameExt: string of arNim: + module: FileIndex # anchor's module (generally not the same as file) tooltip: string # displayed tooltip for Nim-generated anchors langSym: LangSymbol refname: string # A reference name that will be inserted directly @@ -520,6 +521,9 @@ proc getFilename(filenames: RstFileTable, fid: FileIndex): string = proc getFilename(s: PRstSharedState, subst: AnchorSubst): string = getFilename(s.filenames, subst.info.fileIndex) +proc getModule(s: PRstSharedState, subst: AnchorSubst): string = + result = getFilename(s.filenames, subst.module) + proc currFilename(s: PRstSharedState): string = getFilename(s.filenames, s.currFileIdx) @@ -830,7 +834,7 @@ proc addAnchorExtRst(s: var PRstSharedState, key: string, refn: string, proc addAnchorNim*(s: var PRstSharedState, external: bool, refn: string, tooltip: string, langSym: LangSymbol, priority: int, - info: TLineInfo) = + info: TLineInfo, module: FileIndex) = ## Adds an anchor `refn`, which follows ## the rule `arNim` (i.e. a symbol in ``*.nim`` file) s.anchors.mgetOrPut(langSym.name, newSeq[AnchorSubst]()).add( @@ -859,7 +863,7 @@ proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode, for subst in substitutions: if subst.kind == arNim: if match(subst.langSym, langSym): - let key: GroupKey = (subst.langSym.symKind, getFilename(s, subst)) + let key: GroupKey = (subst.langSym.symKind, getModule(s, subst)) found.mgetOrPut(key, newSeq[AnchorSubst]()).add subst for key, sList in found: if sList.len == 1: @@ -880,7 +884,7 @@ proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode, break doAssert(foundGroup, "docgen has not generated the group for $1 (file $2)" % [ - langSym.name, getFilename(s, sList[0]) ]) + langSym.name, getModule(s, sList[0]) ]) proc findMainAnchorRst(s: PRstSharedState, linkText: string, info: TLineInfo): seq[AnchorSubst] = @@ -2443,7 +2447,9 @@ proc parseParagraph(p: var RstParser, result: PRstNode) = result.addIfNotNil(parseLineBlock(p)) of rnMarkdownBlockQuote: result.addIfNotNil(parseMarkdownBlockQuote(p)) - else: break + else: + dec p.idx # allow subsequent block to be parsed as another section + break else: break of tkPunct: @@ -3552,7 +3558,7 @@ proc loadIdxFile(s: var PRstSharedState, origFilename: string) = langSym = langSymbolGroup(kind=entry.linkTitle, name=entry.keyword) addAnchorNim(s, external = true, refn = refn, tooltip = entry.linkDesc, langSym = langSym, priority = -4, # lowest - info=info) + info = info, module = info.fileIndex) doAssert s.idxImports[origFilename].title != "" proc preparePass2*(s: var PRstSharedState, mainNode: PRstNode, importdoc = true) = diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 12fc8fd571..fbe945df33 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -958,7 +958,7 @@ proc `==`*(x, y: SocketHandle): bool {.borrow.} proc accept*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen): SocketHandle {. importc, header: "", sideEffect.} -when defined(linux) or defined(bsd): +when defined(linux) or defined(bsd) or defined(nuttx): proc accept4*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen, flags: cint): SocketHandle {.importc, header: "".} diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 1b6734b518..ea8731405d 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -10,7 +10,7 @@ when defined(nimHasStyleChecks): {.push styleChecks: off.} -when defined(freertos) or defined(zephyr) or defined(nuttx): +when defined(freertos) or defined(zephyr): const hasSpawnH = false # should exist for every Posix system nowadays hasAioH = false @@ -646,7 +646,7 @@ elif defined(nuttx): else: var SO_REUSEPORT* {.importc, header: "".}: cint -when defined(linux) or defined(bsd): +when defined(linux) or defined(bsd) or defined(nuttx): var SOCK_CLOEXEC* {.importc, header: "".}: cint when defined(macosx): @@ -675,14 +675,14 @@ when defined(haiku): when hasSpawnH: when defined(linux): - # better be safe than sorry; Linux has this flag, macosx doesn't, don't - # know about the other OSes + # better be safe than sorry; Linux has this flag, macosx and NuttX don't, + # don't know about the other OSes - # Non-GNU systems like TCC and musl-libc don't define __USE_GNU, so we + # Non-GNU systems like TCC and musl-libc don't define __USE_GNU, so we # can't get the magic number from spawn.h const POSIX_SPAWN_USEVFORK* = cint(0x40) else: - # macosx lacks this, so we define the constant to be 0 to not affect + # macosx and NuttX lack this, so we define the constant to be 0 to not affect # OR'ing of flags: const POSIX_SPAWN_USEVFORK* = cint(0) diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index a518c25d27..d19c3d248b 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -63,6 +63,12 @@ macro bitxor*[T: SomeInteger](x, y: T; z: varargs[T]): T = type BitsRange*[T] = range[0..sizeof(T)*8-1] ## A range with all bit positions for type `T`. +template typeMasked[T: SomeInteger](x: T): T = + when defined(js): + x and ((0xffffffff_ffffffff'u shr (64 - sizeof(T) * 8))) + else: + x + func bitsliced*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, 3).} = ## Returns an extracted (and shifted) slice of bits from `v`. runnableExamples: @@ -73,7 +79,7 @@ func bitsliced*[T: SomeInteger](v: T; slice: Slice[int]): T {.inline, since: (1, let upmost = sizeof(T) * 8 - 1 uv = v.castToUnsigned - (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T + ((uv shl (upmost - slice.b)).typeMasked shr (upmost - slice.b + slice.a)).T proc bitslice*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, 3).} = ## Mutates `v` into an extracted (and shifted) slice of bits from `v`. @@ -85,7 +91,7 @@ proc bitslice*[T: SomeInteger](v: var T; slice: Slice[int]) {.inline, since: (1, let upmost = sizeof(T) * 8 - 1 uv = v.castToUnsigned - v = (uv shl (upmost - slice.b) shr (upmost - slice.b + slice.a)).T + v = ((uv shl (upmost - slice.b)).typeMasked shr (upmost - slice.b + slice.a)).T func toMask*[T: SomeInteger](slice: Slice[int]): T {.inline, since: (1, 3).} = ## Creates a bitmask based on a slice of bits. @@ -96,7 +102,7 @@ func toMask*[T: SomeInteger](slice: Slice[int]): T {.inline, since: (1, 3).} = let upmost = sizeof(T) * 8 - 1 bitmask = bitnot(0.T).castToUnsigned - (bitmask shl (upmost - slice.b + slice.a) shr (upmost - slice.b)).T + ((bitmask shl (upmost - slice.b + slice.a)).typeMasked shr (upmost - slice.b)).T proc masked*[T: SomeInteger](v, mask :T): T {.inline, since: (1, 3).} = ## Returns `v`, with only the `1` bits from `mask` matching those of diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 1773e827b1..bcdd0879d6 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -1077,9 +1077,9 @@ template newSeqWith*(len: int, init: untyped): untyped = import std/random var seqRand = newSeqWith(20, rand(1.0)) assert seqRand[0] != seqRand[1] - - var result = newSeq[typeof(init)](len) - for i in 0 ..< len: + let newLen = len + var result = newSeq[typeof(init)](newLen) + for i in 0 ..< newLen: result[i] = init move(result) # refs bug #7295 diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 4ae4938c6c..56c3601380 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -501,7 +501,7 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash = h = h !& ord(c) result = !$h -proc hash*[T: tuple | object | proc](x: T): Hash = +proc hash*[T: tuple | object | proc | iterator {.closure.}](x: T): Hash = ## Efficient `hash` overload. runnableExamples: # for `tuple|object`, `hash` must be defined for each component of `x`. diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index d2cf64149f..fd0ef38564 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -10,6 +10,8 @@ ## This module implements a simple HTTP client that can be used to retrieve ## webpages and other data. ## +## .. warning:: Validate untrusted inputs: URI parsers and getters are not detecting malicious URIs. +## ## Retrieving a website ## ==================== ## diff --git a/lib/pure/json.nim b/lib/pure/json.nim index d91da35451..45b22cea51 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1110,7 +1110,7 @@ proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string) = dst = jsonNode.copy proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) = - when T is uint|uint64 or (not defined(js) and int.sizeof == 4): + when T is uint|uint64 or int.sizeof == 4: verifyJsonKind(jsonNode, {JInt, JString}, jsonPath) case jsonNode.kind of JString: diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 915337f122..e30f1da737 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1053,13 +1053,15 @@ elif not defined(useNimRtl): var mask: Sigset chck sigemptyset(mask) chck posix_spawnattr_setsigmask(attr, mask) - if poDaemon in data.options: - chck posix_spawnattr_setpgroup(attr, 0'i32) + when not defined(nuttx): + if poDaemon in data.options: + chck posix_spawnattr_setpgroup(attr, 0'i32) var flags = POSIX_SPAWN_USEVFORK or POSIX_SPAWN_SETSIGMASK - if poDaemon in data.options: - flags = flags or POSIX_SPAWN_SETPGROUP + when not defined(nuttx): + if poDaemon in data.options: + flags = flags or POSIX_SPAWN_SETPGROUP chck posix_spawnattr_setflags(attr, flags) if not (poParentStreams in data.options): diff --git a/lib/pure/random.nim b/lib/pure/random.nim index c36ab445b9..422f42a8b8 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -72,7 +72,7 @@ runnableExamples: ## in the standard library import algorithm, math -import std/private/since +import std/private/[since, jsutils] when defined(nimPreviewSlimSystem): import std/[assertions] @@ -231,11 +231,14 @@ proc rand[T: uint | uint64](r: var Rand; max: T): T = let max = uint64(max) when T.high.uint64 == uint64.high: if max == uint64.high: return T(next(r)) + var iters = 0 while true: let x = next(r) # avoid `mod` bias - if x <= randMax - (randMax mod max): + if x <= randMax - (randMax mod max) or iters > 20: return T(x mod (max + 1)) + else: + inc iters proc rand*(r: var Rand; max: Natural): int {.benign.} = ## Returns a random integer in the range `0..max` using the given state. @@ -337,9 +340,9 @@ proc rand*[T: Ordinal or SomeFloat](r: var Rand; x: HSlice[T, T]): T = when T is SomeFloat: result = rand(r, x.b - x.a) + x.a else: # Integers and Enum types - when defined(js): + whenJsNoBigInt64: result = cast[T](rand(r, cast[uint](x.b) - cast[uint](x.a)) + cast[uint](x.a)) - else: + do: result = cast[T](rand(r, cast[uint64](x.b) - cast[uint64](x.a)) + cast[uint64](x.a)) proc rand*[T: Ordinal or SomeFloat](x: HSlice[T, T]): T = @@ -378,14 +381,14 @@ proc rand*[T: Ordinal](r: var Rand; t: typedesc[T]): T {.since: (1, 7, 1).} = when T is range or T is enum: result = rand(r, low(T)..high(T)) elif T is bool: - when defined(js): + whenJsNoBigInt64: result = (r.next or 0) < 0 - else: + do: result = cast[int64](r.next) < 0 else: - when defined(js): + whenJsNoBigInt64: result = cast[T](r.next shr (sizeof(uint)*8 - sizeof(T)*8)) - else: + do: result = cast[T](r.next shr (sizeof(uint64)*8 - sizeof(T)*8)) proc rand*[T: Ordinal](t: typedesc[T]): T = diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index c458d605e4..0a77e8bf6f 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -79,7 +79,7 @@ from unicode import toLower, toUpper export toLower, toUpper include "system/inclrtl" -import std/private/since +import std/private/[since, jsutils] from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl, startsWithImpl, endsWithImpl @@ -944,9 +944,9 @@ func toHex*[T: SomeInteger](x: T, len: Positive): string = doAssert b.toHex(4) == "1001" doAssert toHex(62, 3) == "03E" doAssert toHex(-8, 6) == "FFFFF8" - when defined(js): + whenJsNoBigInt64: toHexImpl(cast[BiggestUInt](x), len, x < 0) - else: + do: when T is SomeSignedInt: toHexImpl(cast[BiggestUInt](BiggestInt(x)), len, x < 0) else: @@ -957,9 +957,9 @@ func toHex*[T: SomeInteger](x: T): string = runnableExamples: doAssert toHex(1984'i64) == "00000000000007C0" doAssert toHex(1984'i16) == "07C0" - when defined(js): + whenJsNoBigInt64: toHexImpl(cast[BiggestUInt](x), 2*sizeof(T), x < 0) - else: + do: when T is SomeSignedInt: toHexImpl(cast[BiggestUInt](BiggestInt(x)), 2*sizeof(T), x < 0) else: diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index daf470b090..de96293f8a 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -291,25 +291,57 @@ else: ## Returns some reasonable terminal width from either standard file ## descriptors, controlling terminal, environment variables or tradition. - var w = terminalWidthIoctl([0, 1, 2]) #Try standard file descriptors + # POSIX environment variable takes precendence. + # _COLUMNS_: This variable shall represent a decimal integer >0 used + # to indicate the user's preferred width in column positions for + # the terminal screen or window. If this variable is unset or null, + # the implementation determines the number of columns, appropriate + # for the terminal or window, in an unspecified manner. + # When COLUMNS is set, any terminal-width information implied by TERM + # is overridden. Users and conforming applications should not set COLUMNS + # unless they wish to override the system selection and produce output + # unrelated to the terminal characteristics. + # See POSIX Base Definitions Section 8.1 Environment Variable Definition + + var w: int + var s = getEnv("COLUMNS") # Try standard env var + if len(s) > 0 and parseInt(s, w) > 0 and w > 0: + return w + w = terminalWidthIoctl([0, 1, 2]) # Try standard file descriptors if w > 0: return w - var cterm = newString(L_ctermid) #Try controlling tty + var cterm = newString(L_ctermid) # Try controlling tty var fd = open(ctermid(cstring(cterm)), O_RDONLY) if fd != -1: w = terminalWidthIoctl([int(fd)]) discard close(fd) if w > 0: return w - var s = getEnv("COLUMNS") #Try standard env var - if len(s) > 0 and parseInt(s, w) > 0 and w > 0: - return w - return 80 #Finally default to venerable value + return 80 # Finally default to venerable value proc terminalHeight*(): int = ## Returns some reasonable terminal height from either standard file ## descriptors, controlling terminal, environment variables or tradition. ## Zero is returned if the height could not be determined. - var h = terminalHeightIoctl([0, 1, 2]) # Try standard file descriptors + # POSIX environment variable takes precendence. + # _LINES_: This variable shall represent a decimal integer >0 used + # to indicate the user's preferred number of lines on a page or + # the vertical screen or window size in lines. A line in this case + # is a vertical measure large enough to hold the tallest character + # in the character set being displayed. If this variable is unset or null, + # the implementation determines the number of lines, appropriate + # for the terminal or window (size, terminal baud rate, and so on), + # in an unspecified manner. + # When LINES is set, any terminal-height information implied by TERM + # is overridden. Users and conforming applications should not set LINES + # unless they wish to override the system selection and produce output + # unrelated to the terminal characteristics. + # See POSIX Base Definitions Section 8.1 Environment Variable Definition + + var h: int + var s = getEnv("LINES") # Try standard env var + if len(s) > 0 and parseInt(s, h) > 0 and h > 0: + return h + h = terminalHeightIoctl([0, 1, 2]) # Try standard file descriptors if h > 0: return h var cterm = newString(L_ctermid) # Try controlling tty var fd = open(ctermid(cstring(cterm)), O_RDONLY) @@ -317,9 +349,6 @@ else: h = terminalHeightIoctl([int(fd)]) discard close(fd) if h > 0: return h - var s = getEnv("LINES") # Try standard env var - if len(s) > 0 and parseInt(s, h) > 0 and h > 0: - return h return 0 # Could not determine height proc terminalSize*(): tuple[w, h: int] = diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 138f2d9ecf..3d644d3611 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -537,7 +537,7 @@ proc getDayOfWeek*(monthday: MonthdayRange, month: Month, year: int): WeekDay assertValidDate monthday, month, year # 1970-01-01 is a Thursday, we adjust to the previous Monday let days = toEpochDay(monthday, month, year) - 3 - let weeks = floorDiv(days, 7) + let weeks = floorDiv(days, 7'i64) let wd = days - weeks * 7 # The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. # so we must correct for the WeekDay type. diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index ebc8b90efb..725d5bbd95 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -14,6 +14,8 @@ ## as a locator, a name, or both. The term "Uniform Resource Locator" ## (URL) refers to the subset of URIs. ## +## .. warning:: URI parsers in this module do not perform security validation. +## ## # Basic usage diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 82513bc984..186da4df81 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -190,7 +190,7 @@ proc text*(n: XmlNode): lent string {.inline.} = assert $c == "" assert c.text == "my comment" - n.expect {xnText, xnComment, xnCData, xnEntity} + n.expect {xnText, xnVerbatimText, xnComment, xnCData, xnEntity} result = n.fText proc `text=`*(n: XmlNode, text: sink string) {.inline.} = @@ -208,7 +208,7 @@ proc `text=`*(n: XmlNode, text: sink string) {.inline.} = e.text = "a new entity text" assert $e == "&a new entity text;" - n.expect {xnText, xnComment, xnCData, xnEntity} + n.expect {xnText, xnVerbatimText, xnComment, xnCData, xnEntity} n.fText = text proc tag*(n: XmlNode): lent string {.inline.} = @@ -735,7 +735,7 @@ proc addImpl(result: var string, n: XmlNode, indent = 0, indWidth = 2, addNewLines = true, lastNodeIsText = false) = proc noWhitespace(n: XmlNode): bool = for i in 0 ..< n.len: - if n[i].kind in {xnText, xnEntity}: return true + if n[i].kind in {xnText, xnVerbatimText, xnEntity}: return true proc addEscapedAttr(result: var string, s: string) = # `addEscaped` alternative with less escaped characters. @@ -784,7 +784,7 @@ proc addImpl(result: var string, n: XmlNode, indent = 0, indWidth = 2, var lastNodeIsText = false for i in 0 ..< n.len: result.addImpl(n[i], indentNext, indWidth, addNewLines, lastNodeIsText) - lastNodeIsText = n[i].kind == xnText + lastNodeIsText = (n[i].kind == xnText) or (n[i].kind == xnVerbatimText) if not n.noWhitespace(): result.addIndent(indent, addNewLines) diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim index 48b4fca7fb..36f22a5d1a 100644 --- a/lib/std/exitprocs.nim +++ b/lib/std/exitprocs.nim @@ -10,6 +10,8 @@ ## This module allows adding hooks to program exit. import locks +when defined(js) and not defined(nodejs): + import std/assertions type FunKind = enum kClosure, kNoconv # extend as needed diff --git a/lib/std/jsbigints.nim b/lib/std/jsbigints.nim index 04578fc87a..fda299e7b3 100644 --- a/lib/std/jsbigints.nim +++ b/lib/std/jsbigints.nim @@ -64,10 +64,10 @@ func wrapToUint*(this: JsBigInt; bits: Natural): JsBigInt {.importjs: runnableExamples: doAssert (big("3") + big("2") ** big("66")).wrapToUint(66) == big("3") -func toNumber*(this: JsBigInt): BiggestInt {.importjs: "Number(#)".} = +func toNumber*(this: JsBigInt): int {.importjs: "Number(#)".} = ## Does not do any bounds check and may or may not return an inexact representation. runnableExamples: - doAssert toNumber(big"2147483647") == 2147483647.BiggestInt + doAssert toNumber(big"2147483647") == 2147483647.int func `+`*(x, y: JsBigInt): JsBigInt {.importjs: "(# $1 #)".} = runnableExamples: diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 17d08e02e3..71f4389054 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -78,19 +78,24 @@ macro getDiscriminants(a: typedesc): seq[string] = let sym = a[1] let t = sym.getTypeImpl let t2 = t[2] - doAssert t2.kind == nnkRecList - result = newTree(nnkBracket) - for ti in t2: - if ti.kind == nnkRecCase: - let key = ti[0][0] - let typ = ti[0][1] - result.add newLit key.strVal - if result.len > 0: + case t2.kind + of nnkEmpty: # allow empty objects result = quote do: - @`result` + seq[string].default + of nnkRecList: + result = newTree(nnkBracket) + for ti in t2: + if ti.kind == nnkRecCase: + let key = ti[0][0] + result.add newLit key.strVal + if result.len > 0: + result = quote do: + @`result` + else: + result = quote do: + seq[string].default else: - result = quote do: - seq[string].default + doAssert false, "unexpected kind: " & $t2.kind macro initCaseObject(T: typedesc, fun: untyped): untyped = ## does the minimum to construct a valid case object, only initializing diff --git a/lib/std/private/jsutils.nim b/lib/std/private/jsutils.nim index 836b3512a3..fd1f395f38 100644 --- a/lib/std/private/jsutils.nim +++ b/lib/std/private/jsutils.nim @@ -79,5 +79,18 @@ when defined(js): assert not "123".toJs.isSafeInteger assert 123.isSafeInteger assert 123.toJs.isSafeInteger - assert 9007199254740991.toJs.isSafeInteger - assert not 9007199254740992.toJs.isSafeInteger + when false: + assert 9007199254740991.toJs.isSafeInteger + assert not 9007199254740992.toJs.isSafeInteger + +template whenJsNoBigInt64*(no64, yes64): untyped = + when defined(js): + when compiles(compileOption("jsbigint64")): + when compileOption("jsbigint64"): + yes64 + else: + no64 + else: + no64 + else: + no64 diff --git a/lib/std/private/since.nim b/lib/std/private/since.nim index 5b22b63917..1a6dd02cb4 100644 --- a/lib/std/private/since.nim +++ b/lib/std/private/since.nim @@ -1,5 +1,5 @@ ##[ -`since` is used to emulate older versions of nim stdlib with `--useVersion`, +`since` is used to emulate older versions of nim stdlib, see `tuse_version.nim`. If a symbol `foo` is added in version `(1,3,5)`, use `{.since: (1.3.5).}`, not diff --git a/lib/system.nim b/lib/system.nim index af7e0e4c8d..dcf09d6044 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -62,11 +62,11 @@ proc typeof*(x: untyped; mode = typeOfIter): typedesc {. doAssert type(myFoo()) is string doAssert typeof(myFoo()) is string doAssert typeof(myFoo(), typeOfIter) is string - doAssert typeof(myFoo3) is "iterator" + doAssert typeof(myFoo3) is iterator doAssert typeof(myFoo(), typeOfProc) is float doAssert typeof(0.0, typeOfProc) is float - doAssert typeof(myFoo3, typeOfProc) is "iterator" + doAssert typeof(myFoo3, typeOfProc) is iterator doAssert not compiles(typeof(myFoo2(), typeOfProc)) # this would give: Error: attempting to call routine: 'myFoo2' # since `typeOfProc` expects a typed expression and `myFoo2()` can @@ -1108,6 +1108,11 @@ when defined(nimscript) or not defined(nimSeqsV2): ## containers should also call their adding proc `add` for consistency. ## Generic code becomes much easier to write if the Nim naming scheme is ## respected. + ## ``` + ## var s: seq[string] = @["test2","test2"] + ## s.add("test") + ## assert s == @["test2", "test2", "test"] + ## ``` when false: # defined(gcDestructors): proc add*[T](x: var seq[T], y: sink openArray[T]) {.noSideEffect.} = @@ -1142,13 +1147,17 @@ else: ## containers should also call their adding proc `add` for consistency. ## Generic code becomes much easier to write if the Nim naming scheme is ## respected. - ## ``` - ## var s: seq[string] = @["test2","test2"] - ## s.add("test") # s <- @[test2, test2, test] - ## ``` ## ## See also: ## * `& proc <#&,seq[T],seq[T]>`_ + runnableExamples: + var a = @["a1", "a2"] + a.add(["b1", "b2"]) + assert a == @["a1", "a2", "b1", "b2"] + var c = @["c0", "c1", "c2", "c3"] + a.add(c.toOpenArray(1, 2)) + assert a == @["a1", "a2", "b1", "b2", "c1", "c2"] + {.noSideEffect.}: let xl = x.len setLen(x, xl + y.len) @@ -2179,39 +2188,30 @@ when notJSnotNims: include "system/profiler" {.pop.} - proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} = + proc rawProc*[T: proc {.closure.} | iterator {.closure.}](x: T): pointer {.noSideEffect, inline.} = ## Retrieves the raw proc pointer of the closure `x`. This is ## useful for interfacing closures with C/C++, hash compuations, etc. - when T is "closure": - #[ - The conversion from function pointer to `void*` is a tricky topic, but this - should work at least for c++ >= c++11, e.g. for `dlsym` support. - refs: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869, - https://stackoverflow.com/questions/14125474/casts-between-pointer-to-function-and-pointer-to-object-in-c-and-c - ]# - {.emit: """ - `result` = (void*)`x`.ClP_0; - """.} - else: - {.error: "Only closure function and iterator are allowed!".} + #[ + The conversion from function pointer to `void*` is a tricky topic, but this + should work at least for c++ >= c++11, e.g. for `dlsym` support. + refs: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869, + https://stackoverflow.com/questions/14125474/casts-between-pointer-to-function-and-pointer-to-object-in-c-and-c + ]# + {.emit: """ + `result` = (void*)`x`.ClP_0; + """.} - proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} = + proc rawEnv*[T: proc {.closure.} | iterator {.closure.}](x: T): pointer {.noSideEffect, inline.} = ## Retrieves the raw environment pointer of the closure `x`. See also `rawProc`. - when T is "closure": - {.emit: """ - `result` = `x`.ClE_0; - """.} - else: - {.error: "Only closure function and iterator are allowed!".} + {.emit: """ + `result` = `x`.ClE_0; + """.} - proc finished*[T: proc](x: T): bool {.noSideEffect, inline, magic: "Finished".} = + proc finished*[T: iterator {.closure.}](x: T): bool {.noSideEffect, inline, magic: "Finished".} = ## It can be used to determine if a first class iterator has finished. - when T is "iterator": - {.emit: """ - `result` = ((NI*) `x`.ClE_0)[1] < 0; - """.} - else: - {.error: "Only closure iterator is allowed!".} + {.emit: """ + `result` = ((NI*) `x`.ClE_0)[1] < 0; + """.} from std/private/digitsutils import addInt export addInt diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index cee70f6774..ac1741ceb5 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -268,6 +268,20 @@ proc getMaxMem(a: var MemRegion): int = # maximum of these both values here: result = max(a.currMem, a.maxMem) +const nimMaxHeap {.intdefine.} = 0 + +proc allocPages(a: var MemRegion, size: int): pointer = + when nimMaxHeap != 0: + if a.occ + size > nimMaxHeap * 1024 * 1024: + raiseOutOfMem() + osAllocPages(size) + +proc tryAllocPages(a: var MemRegion, size: int): pointer = + when nimMaxHeap != 0: + if a.occ + size > nimMaxHeap * 1024 * 1024: + raiseOutOfMem() + osTryAllocPages(size) + proc llAlloc(a: var MemRegion, size: int): pointer = # *low-level* alloc for the memory managers data structures. Deallocation # is done at the end of the allocator's life time. @@ -277,7 +291,7 @@ proc llAlloc(a: var MemRegion, size: int): pointer = # is one page: sysAssert roundup(size+sizeof(LLChunk), PageSize) == PageSize, "roundup 6" var old = a.llmem # can be nil and is correct with nil - a.llmem = cast[PLLChunk](osAllocPages(PageSize)) + a.llmem = cast[PLLChunk](allocPages(a, PageSize)) when defined(nimAvlcorruption): trackLocation(a.llmem, PageSize) incCurrMem(a, PageSize) @@ -453,15 +467,10 @@ when false: it, it.next, it.prev, it.size) it = it.next -const nimMaxHeap {.intdefine.} = 0 - proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = when not defined(emscripten): if not a.blockChunkSizeIncrease: let usedMem = a.occ #a.currMem # - a.freeMem - when nimMaxHeap != 0: - if usedMem > nimMaxHeap * 1024 * 1024: - raiseOutOfMem() if usedMem < 64 * 1024: a.nextChunkSize = PageSize*4 else: @@ -470,11 +479,11 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = var size = size if size > a.nextChunkSize: - result = cast[PBigChunk](osAllocPages(size)) + result = cast[PBigChunk](allocPages(a, size)) else: - result = cast[PBigChunk](osTryAllocPages(a.nextChunkSize)) + result = cast[PBigChunk](tryAllocPages(a, a.nextChunkSize)) if result == nil: - result = cast[PBigChunk](osAllocPages(size)) + result = cast[PBigChunk](allocPages(a, size)) a.blockChunkSizeIncrease = true else: size = a.nextChunkSize @@ -654,7 +663,7 @@ proc getBigChunk(a: var MemRegion, size: int): PBigChunk = releaseSys a.lock proc getHugeChunk(a: var MemRegion; size: int): PBigChunk = - result = cast[PBigChunk](osAllocPages(size)) + result = cast[PBigChunk](allocPages(a, size)) when RegionHasLock: if not a.lockActive: a.lockActive = true @@ -811,9 +820,9 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer = sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken") var size = roundup(requestedSize, MemAlign) sysAssert(size >= sizeof(FreeCell), "rawAlloc: requested size too small") - sysAssert(size >= requestedSize, "insufficient allocated size!") #c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size) + if size <= SmallChunkSize-smallChunkOverhead(): # allocate a small block: for small chunks, we use only its next pointer let s = size div MemAlign diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 42587929c7..9f4cbc0feb 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -275,10 +275,12 @@ proc genericReset(dest: pointer, mt: PNimType) = proc selectBranch(discVal, L: int, a: ptr array[0x7fff, ptr TNimNode]): ptr TNimNode = - result = a[L] # a[L] contains the ``else`` part (but may be nil) if discVal <% L: - let x = a[discVal] - if x != nil: result = x + result = a[discVal] + if result == nil: + result = a[L] + else: + result = a[L] # a[L] contains the ``else`` part (but may be nil) proc FieldDiscriminantCheck(oldDiscVal, newDiscVal: int, a: ptr array[0x7fff, ptr TNimNode], diff --git a/lib/system/compilation.nim b/lib/system/compilation.nim index c049902774..48521024ef 100644 --- a/lib/system/compilation.nim +++ b/lib/system/compilation.nim @@ -10,7 +10,7 @@ const ## is the minor number of Nim's version. ## Odd for devel, even for releases. - NimPatch* {.intdefine.}: int = 1 + NimPatch* {.intdefine.}: int = 3 ## is the patch number of Nim's version. ## Odd for devel, even for releases. diff --git a/lib/system/ctypes.nim b/lib/system/ctypes.nim index f6a341477f..b788274bd7 100644 --- a/lib/system/ctypes.nim +++ b/lib/system/ctypes.nim @@ -12,16 +12,10 @@ type ## compiler supports. Currently this is `float64`, but it is ## platform-dependent in general. -when defined(js): - type BiggestUInt* = uint32 + BiggestUInt* = uint64 ## is an alias for the biggest unsigned integer type the Nim compiler - ## supports. Currently this is `uint32` for JS and `uint64` for other - ## targets. -else: - type BiggestUInt* = uint64 - ## is an alias for the biggest unsigned integer type the Nim compiler - ## supports. Currently this is `uint32` for JS and `uint64` for other - ## targets. + ## supports. Currently this is `uint64`, but it is platform-dependent + ## in general. when defined(windows): type diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 86cfff9cd3..6b40ca3919 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -448,7 +448,7 @@ proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} = else: pushCurrentException(e) {.emit: "throw `e`;".} - elif defined(nimQuirky) or gotoBasedExceptions: + elif quirkyExceptions or gotoBasedExceptions: pushCurrentException(e) when gotoBasedExceptions: inc nimInErrorMode @@ -560,7 +560,7 @@ proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = when defined(cpp) and appType != "lib" and not gotoBasedExceptions and not defined(js) and not defined(nimscript) and hostOS != "standalone" and hostOS != "any" and not defined(noCppExceptions) and - not defined(nimQuirky): + not quirkyExceptions: type StdException {.importcpp: "std::exception", header: "".} = object diff --git a/lib/system/fatal.nim b/lib/system/fatal.nim index 6073ee7795..f1f94d0782 100644 --- a/lib/system/fatal.nim +++ b/lib/system/fatal.nim @@ -9,7 +9,9 @@ {.push profiler: off.} -const gotoBasedExceptions = compileOption("exceptions", "goto") +const + gotoBasedExceptions = compileOption("exceptions", "goto") + quirkyExceptions = compileOption("exceptions", "quirky") when hostOS == "standalone": include "$projectpath/panicoverride" @@ -21,7 +23,7 @@ when hostOS == "standalone": rawoutput(message) panic(arg) -elif (defined(nimQuirky) or defined(nimPanics)) and not defined(nimscript): +elif (quirkyExceptions or defined(nimPanics)) and not defined(nimscript): import ansi_c func name(t: typedesc): string {.magic: "TypeTrait".} diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 54c51e7838..eb08845603 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -391,7 +391,6 @@ else: let regEnd = sp +% sizeof(registers) while sp <% regEnd: gcMark(gch, cast[PPointer](sp)[]) - gcMark(gch, cast[PPointer](sp +% sizeof(pointer) div 2)[]) sp = sp +% sizeof(pointer) # Make sure sp is word-aligned sp = sp and not (sizeof(pointer) - 1) diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 4f64403fe4..3bf506e1e8 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -451,44 +451,44 @@ proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = return Math.trunc(`a` % `b`); """ -proc checkOverflowInt64(a: int) {.asmNoStackFrame, compilerproc.} = +proc checkOverflowInt64(a: int64) {.asmNoStackFrame, compilerproc.} = asm """ - if (`a` > 9223372036854775807 || `a` < -9223372036854775808) `raiseOverflow`(); + if (`a` > 9223372036854775807n || `a` < -9223372036854775808n) `raiseOverflow`(); """ -proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = +proc addInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` + `b`; `checkOverflowInt64`(result); return result; """ -proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = +proc subInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` - `b`; `checkOverflowInt64`(result); return result; """ -proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = +proc mulInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = asm """ var result = `a` * `b`; `checkOverflowInt64`(result); return result; """ -proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = +proc divInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); - return Math.trunc(`a` / `b`); + if (`b` == 0n) `raiseDivByZero`(); + if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`(); + return `a` / `b`; """ -proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = +proc modInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); - return Math.trunc(`a` % `b`); + if (`b` == 0n) `raiseDivByZero`(); + if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`(); + return `a` % `b`; """ proc negInt(a: int): int {.compilerproc.} = diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index 0818f9cc97..30e84ebeeb 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -12,6 +12,8 @@ when defined(nimPreviewSlimSystem): import std/formatfloat proc reprInt(x: int64): string {.compilerproc.} = $x +proc reprInt(x: uint64): string {.compilerproc.} = $x +proc reprInt(x: int): string {.compilerproc.} = $x proc reprFloat(x: float): string {.compilerproc.} = $x proc reprPointer(p: pointer): string {.compilerproc.} = @@ -192,8 +194,12 @@ proc reprAux(result: var string, p: pointer, typ: PNimType, return dec(cl.recDepth) case typ.kind - of tyInt..tyInt64, tyUInt..tyUInt64: + of tyInt..tyInt32, tyUInt..tyUInt32: add(result, reprInt(cast[int](p))) + of tyInt64: + add(result, reprInt(cast[int64](p))) + of tyUInt64: + add(result, reprInt(cast[uint64](p))) of tyChar: add(result, reprChar(cast[char](p))) of tyBool: diff --git a/nim.nimble b/nim.nimble index 380ffbce8f..b0253f66d5 100644 --- a/nim.nimble +++ b/nim.nimble @@ -10,6 +10,8 @@ skipDirs = @["build" , "changelogs" , "ci" , "csources_v2" , "drnim" , "nimdoc", before install: when defined(windows): - exec "build_all.bat" + if not "bin\nim.exe".fileExists: + exec "build_all.bat" else: - exec "./build_all.sh" + if not "bin/nim".fileExists: + exec "./build_all.sh" diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index ee2618ab3c..cfdac53107 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -106,6 +106,7 @@
  • fn2()
  • fn2(x: int)
  • fn2(x: int; y: float)
  • +
  • fn2(x: int; y: float; z: float)
    • fn3 @@ -215,7 +216,7 @@
      1. Other case value
      2. Second case.
      -

      Ref group fn2 or specific function like fn2() or fn2( int ) or fn2(int, float).

      +

      Ref group fn2 or specific function like fn2() or fn2( int ) or fn2(int, float).

      Ref generics like this: binarySearch or binarySearch(openArray[T], K, proc (T, K)) or fN11 or fn11

      Ref. [] is the same as proc `[]`(G[T]) because there are no overloads. The full form: proc `[]`*[T](x: G[T]): TRef. []= aka `[]=`(G[T], int, T).Ref. $ aka proc $ or proc `$`.Ref. $(a: ref SomeType).Ref. foo_bar aka iterator foo_bar_.Ref. fn[T; U,V: SomeFloat]().Ref. 'big or func `'big` or `'big`(string).

      Pandoc Markdown

      Now repeat all the auto links of above in Pandoc Markdown Syntax.

      -

      Ref group fn2 or specific function like fn2() or fn2( int ) or fn2(int, float).

      +

      Ref group fn2 or specific function like fn2() or fn2( int ) or fn2(int, float).

      Ref generics like this: binarySearch or binarySearch(openArray[T], K, proc (T, K)) or + +

      +
      proc fn2(x: int; y: float; z: float) {....raises: [], tags: [], forbids: [].}
      +
      + + +
      diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx index 81c2103e4b..81b27bcb9f 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx @@ -1,5 +1,6 @@ nimTitle utils subdir/subdir_b/utils.html module subdir/subdir_b/utils 0 nim funWithGenerics subdir/subdir_b/utils.html#funWithGenerics,T,U proc funWithGenerics[T, U: SomeFloat](a: T; b: U) 1 +nim fn2 subdir/subdir_b/utils.html#fn2,int,float,float proc fn2(x: int; y: float; z: float) 5 nim enumValueA subdir/subdir_b/utils.html#enumValueA SomeType.enumValueA 45 nim enumValueB subdir/subdir_b/utils.html#enumValueB SomeType.enumValueB 45 nim enumValueC subdir/subdir_b/utils.html#enumValueC SomeType.enumValueC 45 @@ -34,7 +35,7 @@ nim fn subdir/subdir_b/utils.html#fn proc fn[T; U, V: SomeFloat]() 160 nim `'big` subdir/subdir_b/utils.html#'big,string proc `'big`(a: string): SomeType 164 nimgrp $ subdir/subdir_b/utils.html#$-procs-all proc 148 nimgrp fn11 subdir/subdir_b/utils.html#fN11-procs-all proc 85 -nimgrp fn2 subdir/subdir_b/utils.html#fn2-procs-all proc 57 +nimgrp fn2 subdir/subdir_b/utils.html#fn2-procs-all proc 5 nimgrp f subdir/subdir_b/utils.html#f-procs-all proc 130 heading This is now a header subdir/subdir_b/utils.html#this-is-now-a-header This is now a header 0 heading Next header subdir/subdir_b/utils.html#this-is-now-a-header-next-header Next header 0 diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index f9488eb2dd..fd4666bf9a 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -175,6 +175,8 @@ data-doc-search-tag="utils: proc fn2(x: int)" href="subdir/subdir_b/utils.html#fn2%2Cint">utils: proc fn2(x: int)
    • utils: proc fn2(x: int; y: float)
    • +
    • utils: proc fn2(x: int; y: float; z: float)
    fn3: