diff options
45 files changed, 574 insertions, 101 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index f9fa1a0f6..6c96f209e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -670,6 +670,8 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = #if e[0].kind != nkBracketExpr: # message(e.info, warnUser, "CAME HERE " & renderTree(e)) expr(p, e.sons[0], d) + if e.sons[0].typ.skipTypes(abstractInst).kind == tyRef: + d.s = OnHeap else: var a: TLoc let typ = skipTypes(e.sons[0].typ, abstractInst) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index a0b54812f..80bcd2b0e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -8,7 +8,7 @@ # # This is the JavaScript code generator. -# Soon also a PHP code generator. ;-) +# Also a PHP code generator. ;-) discard """ The JS code generator contains only 2 tricks: @@ -1280,14 +1280,15 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = assert(typ.kind == tyProc) genPatternCall(p, n, pat, typ, r) return - gen(p, n.sons[1], r) - if r.typ == etyBaseIndex: - if r.address == nil: - globalError(n.info, "cannot invoke with infix syntax") - r.res = "$1[$2]" % [r.address, r.res] - r.address = nil - r.typ = etyNone - add(r.res, "." | "->") + if n.len != 1: + gen(p, n.sons[1], r) + if r.typ == etyBaseIndex: + if r.address == nil: + globalError(n.info, "cannot invoke with infix syntax") + r.res = "$1[$2]" % [r.address, r.res] + r.address = nil + r.typ = etyNone + add(r.res, "." | "->") var op: TCompRes if p.target == targetPHP: op.kind = resCallee diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 1f93f5317..db5f8e727 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -90,43 +90,38 @@ proc pragmaAsm*(c: PContext, n: PNode): char = else: invalidPragma(it) -proc setExternName(s: PSym, extname: string) = - s.loc.r = rope(extname % s.name.s) +proc setExternName(s: PSym, extname: string, info: TLineInfo) = + # special cases to improve performance: + if extname == "$1": + s.loc.r = rope(s.name.s) + elif '$' notin extname: + s.loc.r = rope(extname) + else: + try: + s.loc.r = rope(extname % s.name.s) + except ValueError: + localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)") if gCmd == cmdPretty and '$' notin extname: # note that '{.importc.}' is transformed into '{.importc: "$1".}' s.loc.flags.incl(lfFullExternalName) -proc makeExternImport(s: PSym, extname: string) = - setExternName(s, extname) +proc makeExternImport(s: PSym, extname: string, info: TLineInfo) = + setExternName(s, extname, info) incl(s.flags, sfImportc) excl(s.flags, sfForward) -proc validateExternCName(s: PSym, info: TLineInfo) = - ## Validates that the symbol name in s.loc.r is a valid C identifier. - ## - ## Valid identifiers are those alphanumeric including the underscore not - ## starting with a number. If the check fails, a generic error will be - ## displayed to the user. - let target = $s.loc.r - if target.len < 1 or target[0] notin IdentStartChars or - not target.allCharsInSet(IdentChars): - localError(info, errGenerated, "invalid exported symbol") - proc makeExternExport(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname) - # XXX to fix make it work with nimrtl. - #if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}: - # validateExternCName(s, info) + setExternName(s, extname, info) incl(s.flags, sfExportc) -proc processImportCompilerProc(s: PSym, extname: string) = - setExternName(s, extname) +proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) = + setExternName(s, extname, info) incl(s.flags, sfImportc) excl(s.flags, sfForward) incl(s.loc.flags, lfImportCompilerProc) -proc processImportCpp(s: PSym, extname: string) = - setExternName(s, extname) +proc processImportCpp(s: PSym, extname: string, info: TLineInfo) = + setExternName(s, extname, info) incl(s.flags, sfImportc) incl(s.flags, sfInfixCall) excl(s.flags, sfForward) @@ -134,8 +129,8 @@ proc processImportCpp(s: PSym, extname: string) = incl(m.flags, sfCompileToCpp) extccomp.gMixedMode = true -proc processImportObjC(s: PSym, extname: string) = - setExternName(s, extname) +proc processImportObjC(s: PSym, extname: string, info: TLineInfo) = + setExternName(s, extname, info) incl(s.flags, sfImportc) incl(s.flags, sfNamedParamCall) excl(s.flags, sfForward) @@ -623,10 +618,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, of wExportc: makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info) incl(sym.flags, sfUsed) # avoid wrong hints - of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1")) + of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"), it.info) of wImportCompilerProc: - processImportCompilerProc(sym, getOptionalStr(c, it, "$1")) - of wExtern: setExternName(sym, expectStrLit(c, it)) + processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info) + of wExtern: setExternName(sym, expectStrLit(c, it), it.info) of wImmediate: if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate) @@ -637,9 +632,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, if sym.kind == skTemplate: incl(sym.flags, sfDirty) else: invalidPragma(it) of wImportCpp: - processImportCpp(sym, getOptionalStr(c, it, "$1")) + processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info) of wImportObjC: - processImportObjC(sym, getOptionalStr(c, it, "$1")) + processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info) of wAlign: if sym.typ == nil: invalidPragma(it) var align = expectIntLit(c, it) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index fc31829ba..e3552f94e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -701,9 +701,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, # error correction, prevents endless for loop elimination in transf. # See bug #2051: result.sons[0] = newSymNode(errorSym(c, n)) - if sfNoSideEffect notin callee.flags: - if {sfImportc, sfSideEffect} * callee.flags != {}: - incl(c.p.owner.flags, sfSideEffect) proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode @@ -804,9 +801,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = else: result = m.call instGenericConvertersSons(c, result, m) - # we assume that a procedure that calls something indirectly - # has side-effects: - if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect) elif t != nil and t.kind == tyTypeDesc: if n.len == 1: return semObjConstr(c, n, flags) return semConv(c, n) @@ -1040,9 +1034,6 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = markUsed(n.info, s) styleCheckUse(n.info, s) - # if a proc accesses a global variable, it is not side effect free: - if sfGlobal in s.flags: - incl(c.p.owner.flags, sfSideEffect) result = newSymNode(s, n.info) # We cannot check for access to outer vars for example because it's still # not sure the symbol really ends up being used: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 9ea3efd0c..b8451865e 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -202,24 +202,25 @@ proc semGenericStmt(c: PContext, n: PNode, if s != nil: incl(s.flags, sfUsed) mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles} - let scOption = if s.name.id in ctx.toMixin: scForceOpen else: scOpen + let sc = symChoice(c, fn, s, + if s.name.id in ctx.toMixin: scForceOpen else: scOpen) case s.kind of skMacro: - if macroToExpand(s): + if macroToExpand(s) and sc.safeLen <= 1: styleCheckUse(fn.info, s) result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, flags, ctx) else: - n.sons[0] = symChoice(c, fn, s, scOption) + n.sons[0] = sc result = n mixinContext = true of skTemplate: - if macroToExpand(s): + if macroToExpand(s) and sc.safeLen <= 1: styleCheckUse(fn.info, s) result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, flags, ctx) else: - n.sons[0] = symChoice(c, fn, s, scOption) + n.sons[0] = sc result = n # BUGFIX: we must not return here, we need to do first phase of # symbol lookup. Also since templates and macros can do scope injections @@ -230,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode, # Leave it as an identifier. discard of skProc, skMethod, skIterator, skConverter, skModule: - result.sons[0] = symChoice(c, fn, s, scOption) + result.sons[0] = sc # do not check of 's.magic==mRoof' here because it might be some # other '^' but after overload resolution the proper one: if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^": diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 460db4f7c..a57b8e520 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -172,9 +172,10 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) = popInfoContext() proc sideEffectsCheck(c: PContext, s: PSym) = - if {sfNoSideEffect, sfSideEffect} * s.flags == - {sfNoSideEffect, sfSideEffect}: - localError(s.info, errXhasSideEffects, s.name.s) + when false: + if {sfNoSideEffect, sfSideEffect} * s.flags == + {sfNoSideEffect, sfSideEffect}: + localError(s.info, errXhasSideEffects, s.name.s) proc instGenericContainer(c: PContext, info: TLineInfo, header: PType, allowMetaTypes = false): PType = diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index b12ab5e96..6d2e82ef0 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -59,7 +59,7 @@ type init: seq[int] # list of initialized variables guards: TModel # nested guards locked: seq[PNode] # locked locations - gcUnsafe, isRecursive, isToplevel: bool + gcUnsafe, isRecursive, isToplevel, hasSideEffect: bool maxLockLevel, currLockLevel: TLockLevel PEffects = var TEffects @@ -192,6 +192,14 @@ proc markGcUnsafe(a: PEffects; reason: PNode) = a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"), a.owner, reason.info) +when true: + template markSideEffect(a: PEffects; reason: typed) = + a.hasSideEffect = true +else: + template markSideEffect(a: PEffects; reason: typed) = + a.hasSideEffect = true + markGcUnsafe(a, reason) + proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) = let u = s.gcUnsafetyReason if u != nil and not cycleCheck.containsOrIncl(u.id): @@ -226,12 +234,16 @@ proc useVar(a: PEffects, n: PNode) = message(n.info, warnUninit, s.name.s) # prevent superfluous warnings about the same variable: a.init.add s.id - if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet}: + if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and + s.magic != mNimVm: if s.guard != nil: guardGlobal(a, n, s.guard) if {sfGlobal, sfThread} * s.flags == {sfGlobal} and (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem): #if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(a, s) + else: + markSideEffect(a, s) + type TIntersection = seq[tuple[id, count: int]] # a simple count table @@ -495,6 +507,8 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = if notGcSafe(s.typ) and sfImportc notin s.flags: if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(tracked, s) + if tfNoSideEffect notin s.typ.flags: + markSideEffect(tracked, s) mergeLockLevels(tracked, n, s.getLockLevel) proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = @@ -550,12 +564,16 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner): if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(tracked, a) + elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner): + markSideEffect(tracked, a) else: mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) if notGcSafe(op): if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(tracked, a) + elif tfNoSideEffect notin op.flags: + markSideEffect(tracked, a) notNilCheck(tracked, n, paramType) proc breaksBlock(n: PNode): bool = @@ -684,6 +702,7 @@ proc track(tracked: PEffects, n: PNode) = if a.sym == tracked.owner: tracked.isRecursive = true # even for recursive calls we need to check the lock levels (!): mergeLockLevels(tracked, n, a.sym.getLockLevel) + if sfSideEffect in a.sym.flags: markSideEffect(tracked, a) else: mergeLockLevels(tracked, n, op.lockLevel) var effectList = op.n.sons[0] @@ -702,6 +721,10 @@ proc track(tracked: PEffects, n: PNode) = if not (a.kind == nkSym and a.sym == tracked.owner): if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) markGcUnsafe(tracked, a) + if tfNoSideEffect notin op.flags and not importedFromC(a): + # and it's not a recursive call: + if not (a.kind == nkSym and a.sym == tracked.owner): + markSideEffect(tracked, a) for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i)) if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}: # may not look like an assignment, but it is: @@ -912,8 +935,15 @@ proc trackProc*(s: PSym, body: PNode) = else: listGcUnsafety(s, onlyWarning=true) #localError(s.info, warnGcUnsafe2, s.name.s) + if sfNoSideEffect in s.flags and t.hasSideEffect: + when false: + listGcUnsafety(s, onlyWarning=false) + else: + localError(s.info, errXhasSideEffects, s.name.s) if not t.gcUnsafe: s.typ.flags.incl tfGcSafe + if not t.hasSideEffect: + s.typ.flags.incl tfNoSideEffect if s.typ.lockLevel == UnspecifiedLockLevel: s.typ.lockLevel = t.maxLockLevel elif t.maxLockLevel > s.typ.lockLevel: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5d1770a32..5f9989ea2 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -304,8 +304,14 @@ proc semTry(c: PContext, n: PNode): PNode = proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = result = fitNode(c, typ, n) if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: - changeType(result.sons[1], typ, check=true) - result = result.sons[1] + let r1 = result.sons[1] + if r1.kind in {nkCharLit..nkUInt64Lit} and typ.skipTypes(abstractRange).kind in {tyFloat..tyFloat128}: + result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal) + result.info = n.info + result.typ = typ + else: + changeType(r1, typ, check=true) + result = r1 elif not sameType(result.typ, typ): changeType(result, typ, check=false) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index ce4f893ea..ec429968c 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -221,13 +221,14 @@ proc cmpCandidates*(a, b: TCandidate): int = if result != 0: return result = a.convMatches - b.convMatches if result != 0: return - result = a.calleeScope - b.calleeScope - if result != 0: return # the other way round because of other semantics: result = b.inheritancePenalty - a.inheritancePenalty if result != 0: return # prefer more specialized generic over more general generic: result = complexDisambiguation(a.callee, b.callee) + # only as a last resort, consider scoping: + if result != 0: return + result = a.calleeScope - b.calleeScope proc writeMatches*(c: TCandidate) = writeLine(stdout, "exact matches: " & $c.exactMatches) diff --git a/compiler/transf.nim b/compiler/transf.nim index d64276cfb..fc400c524 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -474,12 +474,14 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = type TPutArgInto = enum - paDirectMapping, paFastAsgn, paVarAsgn + paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray proc putArgInto(arg: PNode, formal: PType): TPutArgInto = # This analyses how to treat the mapping "formal <-> arg" in an # inline context. if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}: + if arg.kind == nkStmtListExpr: + return paComplexOpenarray return paDirectMapping # XXX really correct? # what if ``arg`` has side-effects? case arg.kind @@ -569,6 +571,14 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = assert(skipTypes(formal.typ, abstractInst).kind == tyVar) idNodeTablePut(newC.mapping, formal, arg) # XXX BUG still not correct if the arg has a side effect! + of paComplexOpenarray: + let typ = newType(tySequence, formal.owner) + addSonSkipIntLit(typ, formal.typ.sons[0]) + var temp = newTemp(c, typ, formal.info) + addVar(v, temp) + add(stmtList, newAsgnStmt(c, temp, arg.PTransNode)) + idNodeTablePut(newC.mapping, formal, temp) + var body = iter.getBody.copyTree pushInfoContext(n.info) # XXX optimize this somehow. But the check "c.inlining" is not correct: diff --git a/compiler/types.nim b/compiler/types.nim index ff60730f0..312e36ae5 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -48,6 +48,8 @@ proc isOrdinalType*(t: PType): bool proc enumHasHoles*(t: PType): bool const + # TODO: Remove tyTypeDesc from each abstractX and (where necessary) + # replace with typedescX abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable, tyTypeDesc} abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal, @@ -61,6 +63,7 @@ const skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable, tyTypeDesc} + # typedescX is used if we're sure tyTypeDesc should be included (or skipped) typedescPtrs* = abstractPtrs + {tyTypeDesc} typedescInst* = abstractInst + {tyTypeDesc} diff --git a/doc/manual/ffi.txt b/doc/manual/ffi.txt index 5055f18af..d7d9596d2 100644 --- a/doc/manual/ffi.txt +++ b/doc/manual/ffi.txt @@ -16,12 +16,20 @@ spelled*: .. code-block:: proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.} -Note that this pragma is somewhat of a misnomer: Other backends will provide +Note that this pragma is somewhat of a misnomer: Other backends do provide the same feature under the same name. Also, if one is interfacing with C++ the `ImportCpp pragma <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and interfacing with Objective-C the `ImportObjC pragma <manual.html#implementation-specific-pragmas-importobjc-pragma>`_ can be used. +The string literal passed to ``importc`` can be a format string: + +.. code-block:: Nim + proc p(s: cstring) {.importc: "prefix$1".} + +In the example the external name of ``p`` is set to ``prefixp``. Only ``$1`` +is available and a literal dollar sign must be written as ``$$``. + Exportc pragma -------------- @@ -33,9 +41,19 @@ name is the Nim identifier *exactly as spelled*: .. code-block:: Nim proc callme(formatstr: cstring) {.exportc: "callMe", varargs.} -Note that this pragma is somewhat of a misnomer: Other backends will provide +Note that this pragma is somewhat of a misnomer: Other backends do provide the same feature under the same name. +The string literal passed to ``exportc`` can be a format string: + +.. code-block:: Nim + proc p(s: string) {.exportc: "prefix$1".} = + echo s + +In the example the external name of ``p`` is set to ``prefixp``. Only ``$1`` +is available and a literal dollar sign must be written as ``$$``. + + Extern pragma ------------- @@ -46,7 +64,9 @@ mangling. The string literal passed to ``extern`` can be a format string: proc p(s: string) {.extern: "prefix$1".} = echo s -In the example the external name of ``p`` is set to ``prefixp``. +In the example the external name of ``p`` is set to ``prefixp``. Only ``$1`` +is available and a literal dollar sign must be written as ``$$``. + Bycopy pragma diff --git a/lib/deprecated/pure/ftpclient.nim b/lib/deprecated/pure/ftpclient.nim index 1188c0795..ed2f14450 100644 --- a/lib/deprecated/pure/ftpclient.nim +++ b/lib/deprecated/pure/ftpclient.nim @@ -129,10 +129,10 @@ proc ftpClient*(address: string, port = Port(21), result.csock = socket() if result.csock == invalidSocket: raiseOSError(osLastError()) -template blockingOperation(sock: Socket, body: stmt) {.immediate.} = +template blockingOperation(sock: Socket, body: untyped) = body -template blockingOperation(sock: asyncio.AsyncSocket, body: stmt) {.immediate.} = +template blockingOperation(sock: asyncio.AsyncSocket, body: untyped) = sock.setBlocking(true) body sock.setBlocking(false) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index eee4fab22..b83daf245 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -231,7 +231,7 @@ template sortedByIt*(seq1, op: untyped): untyped = ## ## echo people.sortedByIt((it.age, it.name)) ## - var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int = + var result = sorted(seq1, proc(x, y: type(seq1[0])): int = var it {.inject.} = x let a = op it = y diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index e277ee9e8..f458b7636 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -371,7 +371,7 @@ template filterIt*(seq1, pred: untyped): untyped = ## notAcceptable = filterIt(temperatures, it > 50 or it < -10) ## assert acceptable == @[-2.0, 24.5, 44.31] ## assert notAcceptable == @[-272.15, 99.9, -113.44] - var result {.gensym.} = newSeq[type(seq1[0])]() + var result = newSeq[type(seq1[0])]() for it {.inject.} in items(seq1): if pred: result.add(it) result @@ -420,7 +420,7 @@ template allIt*(seq1, pred: untyped): bool = ## let numbers = @[1, 4, 5, 8, 9, 7, 4] ## assert allIt(numbers, it < 10) == true ## assert allIt(numbers, it < 9) == false - var result {.gensym.} = true + var result = true for it {.inject.} in items(seq1): if not pred: result = false @@ -451,7 +451,7 @@ template anyIt*(seq1, pred: untyped): bool = ## let numbers = @[1, 4, 5, 8, 9, 7, 4] ## assert anyIt(numbers, it > 8) == true ## assert anyIt(numbers, it > 9) == false - var result {.gensym.} = false + var result = false for it {.inject.} in items(seq1): if pred: result = true @@ -512,7 +512,7 @@ template foldl*(sequence, operation: untyped): untyped = ## assert concatenation == "nimiscool" let s = sequence assert s.len > 0, "Can't fold empty sequences" - var result {.gensym.}: type(s[0]) + var result: type(s[0]) result = s[0] for i in 1..<s.len: let @@ -537,7 +537,7 @@ template foldl*(sequence, operation, first): untyped = ## numbers = @[0, 8, 1, 5] ## digits = foldl(numbers, a & (chr(b + ord('0'))), "") ## assert digits == "0815" - var result {.gensym.}: type(first) + var result: type(first) result = first for x in items(sequence): let @@ -574,7 +574,7 @@ template foldr*(sequence, operation: untyped): untyped = ## assert concatenation == "nimiscool" let s = sequence assert s.len > 0, "Can't fold empty sequences" - var result {.gensym.}: type(s[0]) + var result: type(s[0]) result = sequence[s.len - 1] for i in countdown(s.len - 2, 0): let @@ -598,7 +598,7 @@ template mapIt*(seq1, typ, op: untyped): untyped = ## assert strings == @["4", "8", "12", "16"] ## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)`` ## template instead. - var result {.gensym.}: seq[typ] = @[] + var result: seq[typ] = @[] for it {.inject.} in items(seq1): result.add(op) result @@ -662,7 +662,7 @@ template newSeqWith*(len: int, init: untyped): untyped = ## import random ## var seqRand = newSeqWith(20, random(10)) ## echo seqRand - var result {.gensym.} = newSeq[type(init)](len) + var result = newSeq[type(init)](len) for i in 0 .. <len: result[i] = init result diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 9501f6dc7..bd208761b 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -205,6 +205,10 @@ proc newSocket*(fd: SocketHandle, domain: Domain = AF_INET, if buffered: result.currPos = 0 + # Set SO_NOSIGPIPE on OS X. + when defined(macosx): + setSockOptInt(fd, SOL_SOCKET, SO_NOSIGPIPE, 1) + proc newSocket*(domain, sockType, protocol: cint, buffered = true): Socket = ## Creates a new socket. ## @@ -342,8 +346,6 @@ when defineSsl: result = SSLContext(context: newCTX, extraInternalIndex: 0, referencedData: initSet[int]()) result.extraInternalIndex = getExtraDataIndex(result) - # The PSK callback functions assume the internal index is 0. - assert result.extraInternalIndex == 0 let extraInternal = new(SslContextExtraInternal) result.setExtraData(result.extraInternalIndex, extraInternal) @@ -392,6 +394,8 @@ when defineSsl: ## ## Only used in PSK ciphersuites. ctx.getExtraInternal().clientGetPskFunc = fun + assert ctx.extraInternalIndex == 0, + "The pskClientCallback assumes the extraInternalIndex is 0" ctx.context.SSL_CTX_set_psk_client_callback( if fun == nil: nil else: pskClientCallback) diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index fca10dab6..e4c97b260 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -74,8 +74,7 @@ proc genOid*(): Oid = var t = gettime(nil) - var i = int32(incr) - atomicInc(incr) + var i = int32(atomicInc(incr)) if fuzz == 0: # racy, but fine semantically: diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 92ddc3e75..0fc2e441e 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -77,6 +77,15 @@ checkpoints = @[] proc shouldRun(testName: string): bool = result = true +proc startSuite(name: string) = + template rawPrint() = echo("\n[Suite] ", name) + when not defined(ECMAScript): + if colorOutput: + styledEcho styleBright, fgBlue, "\n[Suite] ", fgWhite, name + else: rawPrint() + else: rawPrint() + + template suite*(name, body) {.dirty.} = ## Declare a test suite identified by `name` with optional ``setup`` ## and/or ``teardown`` section. @@ -103,9 +112,11 @@ template suite*(name, body) {.dirty.} = ## ## .. code-block:: ## - ## [OK] 2 + 2 = 4 - ## [OK] (2 + -2) != 4 + ## [Suite] test suite for addition + ## [OK] 2 + 2 = 4 + ## [OK] (2 + -2) != 4 block: + bind startSuite template setup(setupBody: untyped) {.dirty.} = var testSetupIMPLFlag = true template testSetupIMPL: untyped {.dirty.} = setupBody @@ -114,14 +125,16 @@ template suite*(name, body) {.dirty.} = var testTeardownIMPLFlag = true template testTeardownIMPL: untyped {.dirty.} = teardownBody + let testInSuiteImplFlag = true + startSuite name body -proc testDone(name: string, s: TestStatus) = +proc testDone(name: string, s: TestStatus, indent: bool) = if s == FAILED: programResult += 1 - + let prefix = if indent: " " else: "" if outputLevel != PRINT_NONE and (outputLevel == PRINT_ALL or s == FAILED): - template rawPrint() = echo("[", $s, "] ", name) + template rawPrint() = echo(prefix, "[", $s, "] ", name) when not defined(ECMAScript): if colorOutput and not defined(ECMAScript): var color = case s @@ -129,7 +142,7 @@ proc testDone(name: string, s: TestStatus) = of FAILED: fgRed of SKIPPED: fgYellow else: fgWhite - styledEcho styleBright, color, "[", $s, "] ", fgWhite, name + styledEcho styleBright, color, prefix, "[", $s, "] ", fgWhite, name else: rawPrint() else: @@ -168,7 +181,7 @@ template test*(name, body) {.dirty.} = fail() finally: - testDone name, testStatusIMPL + testDone name, testStatusIMPL, declared(testInSuiteImplFlag) proc checkpoint*(msg: string) = ## Set a checkpoint identified by `msg`. Upon test failure all @@ -198,8 +211,9 @@ template fail* = ## ## outputs "Checkpoint A" before quitting. bind checkpoints + let prefix = if declared(testInSuiteImplFlag): " " else: "" for msg in items(checkpoints): - echo msg + echo prefix, msg when not defined(ECMAScript): if abortOnError: quit(1) diff --git a/lib/system.nim b/lib/system.nim index 82980d9da..356248e6c 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -3232,7 +3232,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] = when low(a) < 0: {.error: "Slicing for arrays with negative indices is unsupported.".} var L = x.b - x.a + 1 - newSeq(result, L) + result = newSeq[T](L) for i in 0.. <L: result[i] = a[i + x.a] proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) = @@ -3681,4 +3681,4 @@ when defined(nimconfig): when defined(windows) and appType == "console" and not defined(nimconfig): proc setConsoleOutputCP(codepage: cint): cint {.stdcall, dynlib: "kernel32", importc: "SetConsoleOutputCP".} - discard setConsoleOutputCP(65001) # 65001 - utf-8 codepage \ No newline at end of file + discard setConsoleOutputCP(65001) # 65001 - utf-8 codepage diff --git a/lib/upcoming/asyncdispatch.nim b/lib/upcoming/asyncdispatch.nim index 162ac5e08..19c9815d2 100644 --- a/lib/upcoming/asyncdispatch.nim +++ b/lib/upcoming/asyncdispatch.nim @@ -1233,7 +1233,7 @@ when defined(windows) or defined(nimdoc): registerWaitableHandle(p, hProcess, flags, pcd, proccb) - proc newEvent*(): AsyncEvent = + proc newAsyncEvent*(): AsyncEvent = ## Creates new ``AsyncEvent`` object. var sa = SECURITY_ATTRIBUTES( nLength: sizeof(SECURITY_ATTRIBUTES).cint, @@ -1314,7 +1314,7 @@ else: readCB: Callback writeCB: Callback - AsyncEvent = SelectEvent + AsyncEvent* = SelectEvent PDispatcher* = ref object of PDispatcherBase selector: Selector[AsyncData] @@ -1419,7 +1419,7 @@ else: if adata.writeCB == cb: adata.writeCB = nil update = true - + when supportedPlatform: if (customSet * events) != {}: let cb = keys[i].data.readCB @@ -1686,11 +1686,11 @@ else: proc setEvent*(ev: AsyncEvent) = ## Sets new ``AsyncEvent`` to signaled state. - setEvent(SelectEvent(ev)) + ioselectors.setEvent(SelectEvent(ev)) proc close*(ev: AsyncEvent) = ## Closes ``AsyncEvent`` - close(SelectEvent(ev)) + ioselectors.close(SelectEvent(ev)) proc addEvent*(ev: AsyncEvent, cb: Callback) = ## Start watching for event ``ev``, and call callback ``cb``, when diff --git a/tests/ccgbugs/twrong_rc_for_refarray.nim b/tests/ccgbugs/twrong_rc_for_refarray.nim new file mode 100644 index 000000000..99bdac5e1 --- /dev/null +++ b/tests/ccgbugs/twrong_rc_for_refarray.nim @@ -0,0 +1,26 @@ +discard """ + output: '''m[0][0] = 1.0 +m[0][0] = 2.0''' +""" +# bug #4653 +type + Vector = ref array[2, float64] + Matrix = ref array[2, Vector] + +proc newVector(): Vector = + new(result) + +proc newMatrix(): Matrix = + new(result) + for ix in 0 .. 1: + result[ix] = newVector() + +let m = newMatrix() + +m[0][0] = 1.0 +echo "m[0][0] = ", m[0][0] + +GC_fullCollect() + +m[0][0] = 2.0 +echo "m[0][0] = ", m[0][0] diff --git a/tests/effects/tsidee4.nim b/tests/effects/tsidee4.nim index 2cb88a23e..ecc79580c 100644 --- a/tests/effects/tsidee4.nim +++ b/tests/effects/tsidee4.nim @@ -1,13 +1,13 @@ discard """ file: "tsidee4.nim" - line: 15 - errormsg: "type mismatch" + line: 12 + errormsg: "'noSideEffect' can have side effects" """ var global: int -proc dontcare(x: int): int = return x +proc dontcare(x: int): int = return global proc noSideEffect(x, y: int, p: proc (a: int): int {.noSideEffect.}): int {.noSideEffect.} = return x + y + dontcare(x) diff --git a/tests/generics/ttempl_in_generic.nim b/tests/generics/ttempl_in_generic.nim new file mode 100644 index 000000000..f04b9d216 --- /dev/null +++ b/tests/generics/ttempl_in_generic.nim @@ -0,0 +1,8 @@ + +# bug #4600 +template foo(x: untyped): untyped = echo 1 +template foo(x,y: untyped): untyped = echo 2 + +proc bar1[T](x: T) = foo(x) +proc bar2(x: float) = foo(x,x) +proc bar3[T](x: T) = foo(x,x) diff --git a/tests/iter/tcomplex_openarray.nim b/tests/iter/tcomplex_openarray.nim new file mode 100644 index 000000000..6fc191e90 --- /dev/null +++ b/tests/iter/tcomplex_openarray.nim @@ -0,0 +1,33 @@ + +# bug #3221 + +import algorithm, math, sequtils + + +iterator permutations[T](ys: openarray[T]): seq[T] = + var + d = 1 + c = newSeq[int](ys.len) + xs = newSeq[T](ys.len) + for i, y in ys: xs[i] = y + yield xs + block outer: + while true: + while d > 1: + dec d + c[d] = 0 + while c[d] >= d: + inc d + if d >= ys.len: break outer + let i = if (d and 1) == 1: c[d] else: 0 + swap xs[i], xs[d] + yield xs + inc c[d] + +proc dig_vectors(): void = + var v_nums: seq[int] + v_nums = newSeq[int](1) + for perm in permutations(toSeq(0 .. 1)): + v_nums[0] = 1 + +dig_vectors() diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim index 4b09c99a9..7c2e70563 100644 --- a/tests/js/tunittests.nim +++ b/tests/js/tunittests.nim @@ -1,5 +1,7 @@ discard """ - output: '''[OK] >:)''' + output: ''' +[Suite] Bacon + [OK] >:)''' """ import unittest diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim index 4d4df7c13..2ac272fd1 100644 --- a/tests/stdlib/tnet_ll.nim +++ b/tests/stdlib/tnet_ll.nim @@ -1,5 +1,8 @@ discard """ action: run + output: ''' +[Suite] inet_ntop tests +''' """ when defined(windows): diff --git a/tests/stdlib/tparseuints.nim b/tests/stdlib/tparseuints.nim index 5be3bcbd0..6b228d933 100644 --- a/tests/stdlib/tparseuints.nim +++ b/tests/stdlib/tparseuints.nim @@ -1,5 +1,7 @@ discard """ action: run + output: ''' +[Suite] parseutils''' """ import unittest, strutils diff --git a/tests/vm/tconst_float_as_int.nim b/tests/vm/tconst_float_as_int.nim new file mode 100644 index 000000000..ed84ec194 --- /dev/null +++ b/tests/vm/tconst_float_as_int.nim @@ -0,0 +1,3 @@ + +# bug #4619 +const x: float = 0 diff --git a/todo.txt b/todo.txt index 86bffcc3d..106f2bb34 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,7 @@ version 1.0 battle plan ======================= +- iters for js - fix "high priority" bugs - try to fix as many compiler crashes as reasonable diff --git a/web/assets/news/images/survey/dev_os.png b/web/assets/news/images/survey/dev_os.png new file mode 100644 index 000000000..088918dc3 --- /dev/null +++ b/web/assets/news/images/survey/dev_os.png Binary files differdiff --git a/web/assets/news/images/survey/do_you_use_nim.png b/web/assets/news/images/survey/do_you_use_nim.png new file mode 100644 index 000000000..257148325 --- /dev/null +++ b/web/assets/news/images/survey/do_you_use_nim.png Binary files differdiff --git a/web/assets/news/images/survey/editors.png b/web/assets/news/images/survey/editors.png new file mode 100644 index 000000000..816ad515f --- /dev/null +++ b/web/assets/news/images/survey/editors.png Binary files differdiff --git a/web/assets/news/images/survey/nim_at_work.png b/web/assets/news/images/survey/nim_at_work.png new file mode 100644 index 000000000..f00ab1a94 --- /dev/null +++ b/web/assets/news/images/survey/nim_at_work.png Binary files differdiff --git a/web/assets/news/images/survey/nim_found.png b/web/assets/news/images/survey/nim_found.png new file mode 100644 index 000000000..a0a65b813 --- /dev/null +++ b/web/assets/news/images/survey/nim_found.png Binary files differdiff --git a/web/assets/news/images/survey/nim_time.png b/web/assets/news/images/survey/nim_time.png new file mode 100644 index 000000000..23bc4a136 --- /dev/null +++ b/web/assets/news/images/survey/nim_time.png Binary files differdiff --git a/web/assets/news/images/survey/nim_time_rust.png b/web/assets/news/images/survey/nim_time_rust.png new file mode 100644 index 000000000..9b861608a --- /dev/null +++ b/web/assets/news/images/survey/nim_time_rust.png Binary files differdiff --git a/web/assets/news/images/survey/nim_versions.png b/web/assets/news/images/survey/nim_versions.png new file mode 100644 index 000000000..ba382c93d --- /dev/null +++ b/web/assets/news/images/survey/nim_versions.png Binary files differdiff --git a/web/assets/news/images/survey/planning_to_use_at_work.png b/web/assets/news/images/survey/planning_to_use_at_work.png new file mode 100644 index 000000000..be3a50467 --- /dev/null +++ b/web/assets/news/images/survey/planning_to_use_at_work.png Binary files differdiff --git a/web/assets/news/images/survey/project_size.png b/web/assets/news/images/survey/project_size.png new file mode 100644 index 000000000..ad1359d0c --- /dev/null +++ b/web/assets/news/images/survey/project_size.png Binary files differdiff --git a/web/assets/news/images/survey/project_size_nim_rust.png b/web/assets/news/images/survey/project_size_nim_rust.png new file mode 100644 index 000000000..41e3ec8b1 --- /dev/null +++ b/web/assets/news/images/survey/project_size_nim_rust.png Binary files differdiff --git a/web/assets/news/images/survey/project_size_work.png b/web/assets/news/images/survey/project_size_work.png new file mode 100644 index 000000000..fab6e52f2 --- /dev/null +++ b/web/assets/news/images/survey/project_size_work.png Binary files differdiff --git a/web/assets/news/images/survey/reliability.png b/web/assets/news/images/survey/reliability.png new file mode 100644 index 000000000..1767e9803 --- /dev/null +++ b/web/assets/news/images/survey/reliability.png Binary files differdiff --git a/web/assets/news/images/survey/target_os.png b/web/assets/news/images/survey/target_os.png new file mode 100644 index 000000000..a36915af1 --- /dev/null +++ b/web/assets/news/images/survey/target_os.png Binary files differdiff --git a/web/assets/news/images/survey/upgrades_broke_things.png b/web/assets/news/images/survey/upgrades_broke_things.png new file mode 100644 index 000000000..28a8ee3f0 --- /dev/null +++ b/web/assets/news/images/survey/upgrades_broke_things.png Binary files differdiff --git a/web/news/nim_community_survey_results.rst b/web/news/nim_community_survey_results.rst new file mode 100644 index 000000000..49656f20a --- /dev/null +++ b/web/news/nim_community_survey_results.rst @@ -0,0 +1,317 @@ +Nim Community Survey Results +============================ + +.. container:: metadata + + Posted by Dominik Picheta on 20/08/2016 + +We have recently closed the 2016 Nim Community Survey. I am happy to +say that we have received exactly 790 responses, huge thanks go to the people +that took the time to respond. We're very thankful for this very valuable +feedback. + +This survey was inspired in part by the +`2016 State of Rust <https://blog.rust-lang.org/2016/06/30/State-of-Rust-Survey-2016.html>`_ +survey. You will note that many of the questions were modelled after +Rust's survey. One of the reasons for doing this was to allow us to easily +compare our results against the results obtained in the Rust survey. In +addition, we of course also liked many of their questions. + +Our survey ran from the 23rd of June 2016 until the 8th of August 2016. The +response numbers are impressive considering Nim's community size; at 790 they +make up just over 25% of the Rust survey's responses. + +The goal of this survey was to primarily determine how our community is using +Nim, in order to better understand how we should be improving it. In particular, +we wanted to know what people feel is missing from Nim in the lead up to +version 1.0. We have also asked our respondents about how well the Nim tools +worked, the challenges of adopting Nim, the resources that they used to learn +Nim and more. + +It is my hope that we will be able to run a similar survey in a years time, +doing so should give us an idea of whether we are improving. +With these general facts in mind, let's begin looking at specific questions. + +How did you find out about Nim? +------------------------------- + +The rationale for the first question was simple, we wanted to know where our +respondents found out about Nim. This is an interesting question for us, as +we do occassionally get users asking us why it took so long for them to hear +about Nim. It allows us to see how effective each website is at spreading the +word about Nim. + +.. raw::html + + <a href="../assets/news/images/survey/nim_found.png"> + <img src="../assets/news/images/survey/nim_found.png" alt="How did you find out about Nim?" style="width:100%"/> + </a> + +The majority of our respondents found Nim via Reddit, HackerNews or a search +engine such as Google. These results are not altogether surprising. There were +also a lot of "Other" responses, some of which were a bit more +interesting. These included multiple mentions of habrahabr.ru, Dr. Dobb's, +and lobste.rs. + +Do you use Nim? +--------------- + +Just like the Rust survey creators, we wanted to ensure that our survey was +open to both Nim users as well people who never used Nim. In addition to +those two groups, we have also included a third group of people: ex-Nim +users. All three are interesting, for many different reasons. +Nim users can tell us how they are using Nim and also how Nim's +tooling can improve. Ex-Nim users give us an +idea of why they stopped using Nim. Finally, respondents who never used Nim +can tell us the reasons for not adopting it. + +.. raw::html + + <a href="../assets/news/images/survey/do_you_use_nim.png"> + <img src="../assets/news/images/survey/do_you_use_nim.png" alt="Do you use Nim?" style="width:100%"/> + </a> + +It's nice to see that we have such a good range of respondents. The Rust survey +had a much larger number of Rust users amongst their respondents, with +no distinction between users that never used Rust and users that stopped using +Rust. + +.. raw::html + + <a href="https://blog.rust-lang.org/images/2016-06-Survey/do_you_use_rust.png"> + <img src="https://blog.rust-lang.org/images/2016-06-Survey/do_you_use_rust.png" alt="Do you use Rust?" style="width:100%"/> + </a> + +Should we consider your answers to be invalid? +---------------------------------------------- + +This was something I thought would be interesting to have, after I saw it +being used in another survey. While it does pinpoint possibly +invalid respondents, I have opted against filtering those out. Mainly because +that would require re-creating each of the charts generated by Google Forms +manually. + +.. raw::html + + <a href="../assets/news/images/survey/reliability.png"> + <img src="../assets/news/images/survey/reliability.png" alt="Should we consider your answers to be invalid?" style="width:100%"/> + </a> + +According to the responses to this question, around 94% of our responses +can be considered reliable. + +Nim users +--------- + +The following questions were answered only by the 38.9% of our respondents +who identified themselves as Nim users. + +How long have you been using Nim? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. raw::html + + <a href="../assets/news/images/survey/nim_time.png"> + <img src="../assets/news/images/survey/nim_time.png" alt="How long have you been using Nim?" style="width:100%"/> + </a> + +A large proportion of our Nim users were new. This is good news as it means that +our community is growing, with a large proportion of new Nim users that could +become long-term Nimians. In total, more than 35% of Nim users can be considered +new having used Nim for less than 3 months. With 18% of Nim users that can +be considered very new having used Nim for less than a month. +This could suggest that 18% of our users have only just found out about Nim in +the last week or so and have not yet got the chance to use it extensively. + +The high percentages of long term Nim users are encouraging. +They suggest +that many users are continuing to use Nim after making it through the first +few months. The sharp drop at 7-9 months is interesting, but may simply be +due to the fact that there were fewer newcomers during that period, or it +could be because our respondents are more likely to estimate that they have +been using Nim for a year or half a year rather than the awkward 7-9 months. + +.. raw::html + + <a href="../assets/news/images/survey/nim_time_rust.png"> + <img src="../assets/news/images/survey/nim_time_rust.png" alt="Time using Nim and Rust" style="width:100%"/> + </a> + +The results for Nim and Rust are actually remarkably similar. They both show a +drop at 7-9 months, although Rust's isn't as dramatic. Nim on the other hand +has a significantly higher percentage of new Nim users. + +Do you use Nim at work? +~~~~~~~~~~~~~~~~~~~~~~~ + +An important aspect of a language's adoption is whether it is being used for +"real" work. We wanted to know how many people are using Nim in their day +jobs and under what circumstances it is used. + +.. raw::html + + <a href="../assets/news/images/survey/nim_at_work.png"> + <img src="../assets/news/images/survey/nim_at_work.png" alt="Do you use Nim at work?" style="width:100%"/> + </a> + +While a vast majority of our users are not using Nim at work, more than 25% +of them are. It's encouraging to see such a high number already, even before +we have released version 1.0. In fact, this percentage is likely close to 30%, +because many of the "Other" responses mention using Nim for the likes of +internal tools or small scripts to help with the respondent's work. + +.. raw::html + + <a href="https://blog.rust-lang.org/images/2016-06-Survey/rust_at_work.png"> + <img src="https://blog.rust-lang.org/images/2016-06-Survey/rust_at_work.png" alt="Do you use Rust at work?" style="width:100%"/> + </a> + +Interestingly, a larger percentage of Nim users are using Nim at work than +Rust users. The sample sizes are of course vastly different, but it's still an +interesting result. Combined, nearly 1/5th of Rust users are using Rust +commercially whereas more than a quarter of Nim users are using Nim +commercially. + +Approximately how large are all the Nim projects that you work on? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Finding out how large the Nim projects worked on by Nim users are is also +very valuable. + +.. raw::html + + <a href="../assets/news/images/survey/project_size.png"> + <img src="../assets/news/images/survey/project_size.png" alt="Nim project size for all users" style="width:100%"/> + </a> + +This shows us that currently Nim is primarily being used for small scripts and +applications, with nearly 60% of the projects consisting of less than 1,000 +lines of code. This makes sense as many of our users are not using Nim +professionally, but are doing so in their spare time. + +.. raw::html + + <a href="../assets/news/images/survey/project_size_work.png"> + <img src="../assets/news/images/survey/project_size_work.png" alt="Nim project size for work users" style="width:100%"/> + </a> + +The numbers for part-time and full-time work users of Nim tell a different +story. Over 70% of the projects written by full-time users are between 10,001 +and 100,000 lines of code. Part-time users show a slightly different trend, +with many more small projects, the majority being between 1,000 and +10,000 lines of code. + +Overall it's good to see that there is a few large projects out there which are +composed of more than 100,000 lines of code. We expect to see the amount of +large projects to grow with time, especially with version 1.0 on the way. + +.. raw::html + + <a href="../assets/news/images/survey/project_size_nim_rust.png"> + <img src="../assets/news/images/survey/project_size_nim_rust.png" alt="Nim project size for work users (Nim vs. Rust)" style="width:100%"/> + </a> + +In comparison to Rust the proportion of project sizes for full-time users is +vastly different. This is likely due to our small sample size. Project sizes for +part-time users between Rust and Nim are somewhat similar, with differences of +around 10% for each project size. + +Do you plan to try to use Nim at work? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. raw::html + + <a href="../assets/news/images/survey/planning_to_use_at_work.png"> + <img src="../assets/news/images/survey/planning_to_use_at_work.png" alt="Planning to use Nim at work?" style="width:100%"/> + </a> + +It's also encouraging to see that over 50% of Nim users are planning to use +Nim at work! This is slightly more than Rust's 40% and should help Nim's +adoption into even more areas. + +Nim and its tools +~~~~~~~~~~~~~~~~~ + +In this section of the survey, we wanted to find out the tools that Nim +users are utilising when developing Nim applications. + +What editor(s) do you use when writing Nim? +___________________________________________ + +Programmers are very specific when it comes to their editor of choice, because +of that it's good to know which editor is most popular among our community. + +.. raw::html + + <a href="../assets/news/images/survey/editors.png"> + <img src="../assets/news/images/survey/editors.png" alt="Editors used by Nim users" style="width:100%"/> + </a> + +Looks like Vim is the winner with almost 30%. Followed by Sublime Text and +Visual Studio Code. Aporia, the Nim IDE, gets a respectable 15.5%. There was +also more than +17% of answers which included "Other" editors, such as: Notepad++, Geany, gedit, +and Kate. + +What operating system(s) do you compile for and run your Nim projects on? +_________________________________________________________________________ + +This question gave us information about the most popular target operating +systems, as well as some of the more obscure ones. We have asked this question +to find out the platforms on which Nim applications run on most frequently. + +.. raw::html + + <a href="../assets/news/images/survey/target_os.png"> + <img src="../assets/news/images/survey/target_os.png" alt="Target operating systems" style="width:100%"/> + </a> + +This question allowed multiple choices, so each percentage is out of the total +number of respondents for this question. For example, 80.7% of the +respondents selected "Linux" but only 26.6% selected OS X. + +This makes Linux by far the most popular target for Nim applications. +Some "Other" targets included: BSD (OpenBSD, FreeBSD), iOS, Android, and +JavaScript. +It's great to see Nim being used on such a wide variety of platforms. + +What operating system(s) do you develop Nim projects on? +________________________________________________________ + +With this question, we wanted to know what operating systems are used for +development. + +.. raw::html + + <a href="../assets/news/images/survey/dev_os.png"> + <img src="../assets/news/images/survey/dev_os.png" alt="Development operating systems" style="width:100%"/> + </a> + +This question also allowed multiple choices and ended up with very similar +results. + +You can see that Linux is also the most popular developmental +platform for Nim. But it's more popular as a target platform. + +Which version(s) of Nim do you use for your applications? +_________________________________________________________ + +.. raw::html + + <a href="../assets/news/images/survey/nim_versions.png"> + <img src="../assets/news/images/survey/nim_versions.png" alt="Version use" style="width:100%"/> + </a> + +At the time of this survey, version 0.14.2 was the latest stable release. +It's no wonder that it is the most commonly used release of Nim. It's good to +see that the older versions are not used as often. The high use of ``Git HEAD (devel)`` +(nightly builds) isn't surprising, Nim is still evolving rapidly and our +release schedule is not regular or frequent. + +Once we go past the 1.0 release, we expect to see much less use of the unstable +``devel`` branch. + + + + + |