diff options
46 files changed, 1791 insertions, 354 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 862776740..55fa7564c 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -504,6 +504,11 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = "$# = #mulInt($#, $#);$n", "$# = #divInt($#, $#);$n", "$# = #modInt($#, $#);$n", "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n"] + prc64: array[mAddI..mPred, string] = [ + "$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n", + "$# = #mulInt64($#, $#);$n", "$# = #divInt64($#, $#);$n", + "$# = #modInt64($#, $#);$n", + "$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n"] opr: array[mAddI..mPred, string] = [ "($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)", "($#)($# / $#)", "($#)($# % $#)", @@ -520,7 +525,8 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = let res = opr[m] % [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)] putIntoDest(p, d, e.typ, res) else: - let res = binaryArithOverflowRaw(p, t, a, b, prc[m]) + let res = binaryArithOverflowRaw(p, t, a, b, + if t.kind == tyInt64: prc64[m] else: prc[m]) putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, t), res]) proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = diff --git a/compiler/commands.nim b/compiler/commands.nim index 285d73e7a..7c8abd9b8 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -22,6 +22,7 @@ bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas") bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm") bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep") bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational") +bootSwitch(usedGoGC, defined(gogc), "--gc:go") bootSwitch(usedNoGC, defined(nogc), "--gc:none") import @@ -86,7 +87,7 @@ proc writeVersionInfo(pass: TCmdLinePass) = msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine & usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas & - usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedNoGC) + usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC) msgQuit(0) var @@ -181,6 +182,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool = of "v2": result = gSelectedGC == gcV2 of "markandsweep": result = gSelectedGC == gcMarkAndSweep of "generational": result = gSelectedGC == gcGenerational + of "go": result = gSelectedGC == gcGo of "none": result = gSelectedGC == gcNone else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) of "opt": @@ -365,6 +367,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "generational": gSelectedGC = gcGenerational defineSymbol("gcgenerational") + of "go": + gSelectedGC = gcGo + defineSymbol("gogc") of "none": gSelectedGC = gcNone defineSymbol("nogc") diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index ad7d80c85..34322471f 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -88,3 +88,4 @@ proc initDefines*() = defineSymbol("nimalias") defineSymbol("nimlocks") defineSymbol("nimnode") + defineSymbol("nimnomagic64") diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index f6ec256d2..ede759426 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -505,12 +505,12 @@ proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) = proc genTry(p: PProc, n: PNode, r: var TCompRes) = # code to generate: # - # var sp = {prev: excHandler, exc: null}; - # excHandler = sp; + # ++excHandler; # try { # stmts; - # TMP = e - # } catch (e) { + # } catch (EXC) { + # var prevJSError = lastJSError; lastJSError = EXC; + # --excHandler; # if (e.typ && e.typ == NTI433 || e.typ == NTI2321) { # stmts; # } else if (e.typ && e.typ == NTI32342) { @@ -518,35 +518,41 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = # } else { # stmts; # } + # lastJSError = prevJSError; # } finally { # stmts; - # excHandler = excHandler.prev; # } genLineDir(p, n) if not isEmptyType(n.typ): r.kind = resVal r.res = getTemp(p) inc(p.unique) + var i = 1 + var length = sonsLen(n) + var catchBranchesExist = length > 1 and n.sons[i].kind == nkExceptBranch + if catchBranchesExist: + add(p.body, "++excHandler;" & tnl) var safePoint = "Tmp$1" % [rope(p.unique)] addf(p.body, - "var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" | + "" | "local $1 = pcall(", [safePoint]) if optStackTrace in p.options: add(p.body, "framePtr = F;" & tnl) addf(p.body, "try {$n" | "function()$n", []) - var length = sonsLen(n) var a: TCompRes gen(p, n.sons[0], a) moveInto(p, a, r) - var i = 1 - if p.target == targetJS and length > 1 and n.sons[i].kind == nkExceptBranch: - addf(p.body, "} catch (EXC) {$n lastJSError = EXC;$n", []) + var generalCatchBranchExists = false + if p.target == targetJS and catchBranchesExist: + addf(p.body, "} catch (EXC) {$n var prevJSError = lastJSError;$n" & + " lastJSError = EXC;$n --excHandler;$n", []) elif p.target == targetLua: addf(p.body, "end)$n", []) while i < length and n.sons[i].kind == nkExceptBranch: let blen = sonsLen(n.sons[i]) if blen == 1: # general except section: + generalCatchBranchExists = true if i > 1: addf(p.body, "else {$n" | "else$n", []) gen(p, n.sons[i].sons[0], a) moveInto(p, a, r) @@ -558,17 +564,22 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = if n.sons[i].sons[j].kind != nkType: internalError(n.info, "genTryStmt") if orExpr != nil: add(orExpr, "||" | " or ") - addf(orExpr, "isObj($1.exc.m_type, $2)", - [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)]) + addf(orExpr, "isObj(lastJSError.m_type, $1)", + [genTypeInfo(p, n.sons[i].sons[j].typ)]) if i > 1: add(p.body, "else ") - addf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n", + addf(p.body, "if (lastJSError && ($2)) {$n" | "if $1.exc and ($2) then$n", [safePoint, orExpr]) gen(p, n.sons[i].sons[blen - 1], a) moveInto(p, a, r) addf(p.body, "}$n" | "end$n", []) inc(i) if p.target == targetJS: - add(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl) + if catchBranchesExist: + if not generalCatchBranchExists: + useMagic(p, "reraiseException") + add(p.body, "else {" & tnl & "reraiseException();" & tnl & "}" & tnl) + add(p.body, "lastJSError = prevJSError;" & tnl) + add(p.body, "} finally {" & tnl) if i < length and n.sons[i].kind == nkFinally: genStmt(p, n.sons[i].sons[0]) if p.target == targetJS: @@ -957,7 +968,9 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) = of tyTuple: genFieldAddr(p, n.sons[0], r) else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')') - else: internalError(n.sons[0].info, "genAddr") + of nkObjDownConv: + gen(p, n.sons[0], r) + else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind) proc genProcForSymIfNeeded(p: PProc, s: PSym) = if not p.g.generatedSyms.containsOrIncl(s.id): @@ -1067,6 +1080,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = r.kind = resExpr proc genEcho(p: PProc, n: PNode, r: var TCompRes) = + useMagic(p, "toJSStr") # Used in rawEcho useMagic(p, "rawEcho") add(r.res, "rawEcho(") let n = n[1].skipConv @@ -1084,24 +1098,32 @@ proc putToSeq(s: string, indirect: bool): Rope = if indirect: result = "[$1]" % [result] proc createVar(p: PProc, typ: PType, indirect: bool): Rope -proc createRecordVarAux(p: PProc, rec: PNode, c: var int): Rope = - result = nil +proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output: var Rope) = case rec.kind of nkRecList: for i in countup(0, sonsLen(rec) - 1): - add(result, createRecordVarAux(p, rec.sons[i], c)) + createRecordVarAux(p, rec.sons[i], excludedFieldIDs, output) of nkRecCase: - add(result, createRecordVarAux(p, rec.sons[0], c)) + createRecordVarAux(p, rec.sons[0], excludedFieldIDs, output) for i in countup(1, sonsLen(rec) - 1): - add(result, createRecordVarAux(p, lastSon(rec.sons[i]), c)) + createRecordVarAux(p, lastSon(rec.sons[i]), excludedFieldIDs, output) of nkSym: - if c > 0: add(result, ", ") - add(result, mangleName(rec.sym)) - add(result, ": ") - add(result, createVar(p, rec.sym.typ, false)) - inc(c) + if rec.sym.id notin excludedFieldIDs: + if output.len > 0: output.add(", ") + output.add(mangleName(rec.sym)) + output.add(": ") + output.add(createVar(p, rec.sym.typ, false)) else: internalError(rec.info, "createRecordVarAux") +proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: var Rope) = + var t = typ + if tfFinal notin t.flags or t.sons[0] != nil: + if output.len > 0: output.add(", ") + addf(output, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)]) + while t != nil: + createRecordVarAux(p, t.n, excludedFieldIDs, output) + t = t.sons[0] + proc createVar(p: PProc, typ: PType, indirect: bool): Rope = var t = skipTypes(typ, abstractInst) case t.kind @@ -1142,15 +1164,9 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope = add(result, "}") if indirect: result = "[$1]" % [result] of tyObject: - result = rope("{") - var c = 0 - if tfFinal notin t.flags or t.sons[0] != nil: - inc(c) - addf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)]) - while t != nil: - add(result, createRecordVarAux(p, t.n, c)) - t = t.sons[0] - add(result, "}") + var initList : Rope + createObjInitList(p, t, initIntSet(), initList) + result = "{$1}" % [initList] if indirect: result = "[$1]" % [result] of tyVar, tyPtr, tyRef: if mapType(t) == etyBaseIndex: @@ -1423,6 +1439,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes r.res = rope("{") r.kind = resExpr + var fieldIDs = initIntSet() for i in countup(1, sonsLen(n) - 1): if i > 1: add(r.res, ", ") var it = n.sons[i] @@ -1430,7 +1447,10 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) = gen(p, it.sons[1], a) var f = it.sons[0].sym if f.loc.r == nil: f.loc.r = mangleName(f) + fieldIDs.incl(f.id) addf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res]) + let t = skipTypes(n.typ, abstractInst + skipPtrs) + createObjInitList(p, t, fieldIDs, r.res) r.res.add("}") proc genConv(p: PProc, n: PNode, r: var TCompRes) = @@ -1676,7 +1696,7 @@ proc genHeader(): Rope = result = ("/* Generated by the Nim Compiler v$1 */$n" & "/* (c) 2015 Andreas Rumpf */$n$n" & "var framePtr = null;$n" & - "var excHandler = null;$n" & + "var excHandler = 0;$n" & "var lastJSError = null;$n") % [rope(VersionAsString)] diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 5c7baf7d3..cea42ad1e 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -262,10 +262,6 @@ template eatChar(L: var TLexer, t: var TToken) = add(t.literal, L.buf[L.bufpos]) inc(L.bufpos) - - - - proc getNumber(L: var TLexer): TToken = proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) = var pos = L.bufpos # use registers for pos, buf @@ -483,7 +479,7 @@ proc getNumber(L: var TLexer): TToken = else: internalError(getLineInfo(L), "getNumber") # Bounds checks. Non decimal literals are allowed to overflow the range of - # the datatype as long as their pattern don't overflow _bitwise_, hence + # the datatype as long as their pattern don't overflow _bitwise_, hence # below checks of signed sizes against uint*.high is deliberate: # (0x80'u8 = 128, 0x80'i8 = -128, etc == OK) if result.tokType notin floatTypes: @@ -495,7 +491,7 @@ proc getNumber(L: var TLexer): TToken = else: false if outOfRange: - echo "out of range num: ", result.iNumber, " vs ", xi + #echo "out of range num: ", result.iNumber, " vs ", xi lexMessageLitNum(L, errNumberOutOfRange, startpos) else: @@ -528,8 +524,8 @@ proc getNumber(L: var TLexer): TToken = # Promote int literal to int64? Not always necessary, but more consistent if result.tokType == tkIntLit: - if (result.iNumber < low(int32)) or (result.iNumber > high(int32)): - result.tokType = tkInt64Lit + if (result.iNumber < low(int32)) or (result.iNumber > high(int32)): + result.tokType = tkInt64Lit except ValueError: lexMessageLitNum(L, errInvalidNumber, startpos) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index b6b01d558..b4319b246 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -63,6 +63,26 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode = if n.sons[i].kind == nkSym: v.addVar(n.sons[i]) result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i)) +proc lowerSwap*(n: PNode; owner: PSym): PNode = + result = newNodeI(nkStmtList, n.info) + # note: cannot use 'skTemp' here cause we really need the copy for the VM :-( + var temp = newSym(skVar, getIdent(genPrefix), owner, n.info) + temp.typ = n.sons[1].typ + incl(temp.flags, sfFromGeneric) + + var v = newNodeI(nkVarSection, n.info) + let tempAsNode = newSymNode(temp) + + var vpart = newNodeI(nkIdentDefs, v.info, 3) + vpart.sons[0] = tempAsNode + vpart.sons[1] = ast.emptyNode + vpart.sons[2] = n[1] + addSon(v, vpart) + + result.add(v) + result.add newFastAsgnStmt(n[1], n[2]) + result.add newFastAsgnStmt(n[2], tempAsNode) + proc createObj*(owner: PSym, info: TLineInfo): PType = result = newType(tyObject, owner) rawAddSon(result, nil) diff --git a/compiler/modules.nim b/compiler/modules.nim index 6cb14c091..dcba5cf3d 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -51,19 +51,19 @@ proc crcChanged(fileIdx: int32): bool = of crcNotChanged: result = false of crcCached: - let newCrc = secureHashFile(fileIdx.toFilename) + let newCrc = secureHashFile(fileIdx.toFullPath) result = newCrc != gMemCacheData[fileIdx].crc gMemCacheData[fileIdx].crc = newCrc updateStatus() of crcNotTaken: - gMemCacheData[fileIdx].crc = secureHashFile(fileIdx.toFilename) + gMemCacheData[fileIdx].crc = secureHashFile(fileIdx.toFullPath) result = true updateStatus() proc doCRC(fileIdx: int32) = if gMemCacheData[fileIdx].crcStatus == crcNotTaken: # echo "FIRST CRC: ", fileIdx.ToFilename - gMemCacheData[fileIdx].crc = secureHashFile(fileIdx.toFilename) + gMemCacheData[fileIdx].crc = secureHashFile(fileIdx.toFullPath) proc addDep(x: PSym, dep: int32) = growCache gMemCacheData, dep diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 4df4430d7..6b71b7159 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -8,7 +8,7 @@ # import - options, strutils, os, tables, ropes, platform, terminal + options, strutils, os, tables, ropes, platform, terminal, macros type TMsgKind* = enum @@ -367,54 +367,54 @@ const "of the generic paramers can be inferred from the expected signature.", errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target", errUser: "$1", - warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]", - warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]", - warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]", - warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]", - warnDeprecated: "$1 is deprecated [Deprecated]", - warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]", - warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]", - warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]", - warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]", - warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]", - warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]", - warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]", - warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]", - warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]", - warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template' [TypelessParam]", - warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]", - warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]", - warnUnsafeCode: "unsafe code: '$1' [UnsafeCode]", - warnEachIdentIsTuple: "each identifier is a tuple [EachIdentIsTuple]", - warnShadowIdent: "shadowed identifier: '$1' [ShadowIdent]", - warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future. [ProveInit]", - warnProveField: "cannot prove that field '$1' is accessible [ProveField]", - warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]", - warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]", + warnCannotOpenFile: "cannot open \'$1\'", + warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored", + warnXIsNeverRead: "\'$1\' is never read", + warnXmightNotBeenInit: "\'$1\' might not have been initialized", + warnDeprecated: "$1 is deprecated", + warnConfigDeprecated: "config file '$1' is deprecated", + warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one)", + warnUnknownMagic: "unknown magic \'$1\' might crash the compiler", + warnRedefinitionOfLabel: "redefinition of label \'$1\'", + warnUnknownSubstitutionX: "unknown substitution \'$1\'", + warnLanguageXNotSupported: "language \'$1\' not supported", + warnFieldXNotSupported: "field \'$1\' not supported", + warnCommentXIgnored: "comment \'$1\' ignored", + warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead", + warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'", + warnDifferentHeaps: "possible inconsistency of thread local heaps", + warnWriteToForeignHeap: "write to foreign heap", + warnUnsafeCode: "unsafe code: '$1'", + warnEachIdentIsTuple: "each identifier is a tuple", + warnShadowIdent: "shadowed identifier: '$1'", + warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.", + warnProveField: "cannot prove that field '$1' is accessible", + warnProveIndex: "cannot prove index '$1' is valid", + warnGcUnsafe: "not GC-safe: '$1'", warnGcUnsafe2: "$1", - warnUninit: "'$1' might not have been initialized [Uninit]", - warnGcMem: "'$1' uses GC'ed memory [GcMem]", - warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]", - warnLockLevel: "$1 [LockLevel]", - warnResultShadowed: "Special variable 'result' is shadowed. [ResultShadowed]", - warnUser: "$1 [User]", - hintSuccess: "operation successful [Success]", - hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#) [SuccessX]", - hintLineTooLong: "line too long [LineTooLong]", - hintXDeclaredButNotUsed: "\'$1\' is declared but not used [XDeclaredButNotUsed]", - hintConvToBaseNotNeeded: "conversion to base object is not needed [ConvToBaseNotNeeded]", - hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless [ConvFromXtoItselfNotNeeded]", - hintExprAlwaysX: "expression evaluates always to \'$1\' [ExprAlwaysX]", - hintQuitCalled: "quit() called [QuitCalled]", - hintProcessing: "$1 [Processing]", - hintCodeBegin: "generated code listing: [CodeBegin]", - hintCodeEnd: "end of listing [CodeEnd]", - hintConf: "used config file \'$1\' [Conf]", - hintPath: "added path: '$1' [Path]", - hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]", - hintName: "name should be: '$1' [Name]", - hintPattern: "$1 [Pattern]", - hintUser: "$1 [User]"] + warnUninit: "'$1' might not have been initialized", + warnGcMem: "'$1' uses GC'ed memory", + warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.", + warnLockLevel: "$1", + warnResultShadowed: "Special variable 'result' is shadowed.", + warnUser: "$1", + hintSuccess: "operation successful", + hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)", + hintLineTooLong: "line too long", + hintXDeclaredButNotUsed: "\'$1\' is declared but not used", + hintConvToBaseNotNeeded: "conversion to base object is not needed", + hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless", + hintExprAlwaysX: "expression evaluates always to \'$1\'", + hintQuitCalled: "quit() called", + hintProcessing: "$1", + hintCodeBegin: "generated code listing:", + hintCodeEnd: "end of listing", + hintConf: "used config file \'$1\'", + hintPath: "added path: '$1'", + hintConditionAlwaysTrue: "condition is always true: '$1'", + hintName: "name should be: '$1'", + hintPattern: "$1", + hintUser: "$1"] const WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape", @@ -605,13 +605,17 @@ proc suggestQuit*() = # this format is understood by many text editors: it is the same that # Borland and Freepascal use const - PosErrorFormat* = "$1($2, $3) Error: " - PosWarningFormat* = "$1($2, $3) Warning: " - PosHintFormat* = "$1($2, $3) Hint: " - PosContextFormat = "$1($2, $3) Info: " - RawError* = "Error: " - RawWarning* = "Warning: " - RawHint* = "Hint: " + PosFormat = "$1($2, $3) " + KindFormat = " [$1]" + KindColor = fgCyan + ErrorTitle = "Error: " + ErrorColor = fgRed + WarningTitle = "Warning: " + WarningColor = fgYellow + HintTitle = "Hint: " + HintColor = fgGreen + InfoTitle = "Info: " + InfoColor = fgCyan proc getInfoContextLen*(): int = return msgContext.len proc setInfoContextLen*(L: int) = setLen(msgContext, L) @@ -686,27 +690,58 @@ proc outWriteln*(s: string) = ## Writes to stdout. Always. if eStdOut in errorOutputs: writeln(stdout, s) -proc msgWriteln*(s: string, color: ForegroundColor = fgWhite, coloredText: string = "") = - ## Writes to stdout. If --stderr option is given, writes to stderr instead. +proc msgWriteln*(s: string) = + ## Writes to stdout. If --stdout option is given, writes to stderr instead. #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return - var hasColor = optUseColors in gGlobalOptions if not isNil(writelnHook): - writelnHook(coloredText & s) + writelnHook(s) + elif optStdout in gGlobalOptions: + if eStdErr in errorOutputs: writeln(stderr, s) else: - if optStdout in gGlobalOptions: - if eStdErr in errorOutputs: - if hasColor: setForegroundColor(color) - write(stderr, coloredText) - if hasColor: resetAttributes() - writeln(stderr, s) - else: - if eStdOut in errorOutputs: - if hasColor: setForegroundColor(color) - write(stdout, coloredText) - if hasColor: resetAttributes() - writeln(stdout, s) + if eStdOut in errorOutputs: writeln(stdout, s) + +macro callIgnoringStyle(theProc: typed, first: typed, + args: varargs[expr]): stmt = + let typForegroundColor = bindSym"ForegroundColor".getType + let typBackgroundColor = bindSym"BackgroundColor".getType + let typStyle = bindSym"Style".getType + let typTerminalCmd = bindSym"TerminalCmd".getType + result = newCall(theProc) + if first.kind != nnkNilLit: result.add(first) + for arg in children(args[0][1]): + if arg.kind == nnkNilLit: continue + let typ = arg.getType + if typ.kind != nnkEnumTy or + typ != typForegroundColor and + typ != typBackgroundColor and + typ != typStyle and + typ != typTerminalCmd: + result.add(arg) + +macro callStyledEcho(args: varargs[expr]): stmt = + result = newCall(bindSym"styledEcho") + for arg in children(args[0][1]): + result.add(arg) + +template callWritelnHook(args: varargs[string, `$`]) = + var s = "" + for arg in args: + s.add arg + writelnHook s + +template styledMsgWriteln*(args: varargs[expr]) = + if not isNil(writelnHook): + callIgnoringStyle(callWritelnHook, nil, args) + elif optStdout in gGlobalOptions: + if eStdErr in errorOutputs: callIgnoringStyle(writeln, stderr, args) + else: + if eStdOut in errorOutputs: + if optUseColors in gGlobalOptions: + callStyledEcho(args) + else: + callIgnoringStyle(writeln, stdout, args) proc coordToStr(coord: int): string = if coord == -1: result = "???" @@ -728,7 +763,7 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = if stackTraceAvailable() and isNil(writelnHook): writeStackTrace() else: - msgWriteln("", fgRed, "No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>") + styledMsgWriteln(fgRed, "No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>") quit 1 if msg >= fatalMin and msg <= fatalMax: @@ -750,10 +785,12 @@ proc writeContext(lastinfo: TLineInfo) = var info = lastinfo for i in countup(0, len(msgContext) - 1): if msgContext[i] != lastinfo and msgContext[i] != info: - msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]), - coordToStr(msgContext[i].line), - coordToStr(msgContext[i].col+1), - getMessageStr(errInstantiationFrom, "")]) + styledMsgWriteln(styleBright, + PosFormat % [toMsgFilename(msgContext[i]), + coordToStr(msgContext[i].line), + coordToStr(msgContext[i].col+1)], + styleDim, + getMessageStr(errInstantiationFrom, "")) info = msgContext[i] proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool = @@ -761,29 +798,36 @@ proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool = proc rawMessage*(msg: TMsgKind, args: openArray[string]) = var - frmt: string + title: string color: ForegroundColor + kind: string case msg of errMin..errMax: writeContext(unknownLineInfo()) - frmt = RawError - color = fgRed + title = ErrorTitle + color = ErrorColor of warnMin..warnMax: if optWarns notin gOptions: return if msg notin gNotes: return writeContext(unknownLineInfo()) - frmt = RawWarning + title = WarningTitle + color = WarningColor + kind = WarningsToStr[ord(msg) - ord(warnMin)] inc(gWarnCounter) - color = fgYellow of hintMin..hintMax: if optHints notin gOptions: return if msg notin gNotes: return - frmt = RawHint + title = HintTitle + color = HintColor + kind = HintsToStr[ord(msg) - ord(hintMin)] inc(gHintCounter) - color = fgGreen let s = `%`(msgKindToString(msg), args) if not ignoreMsgBecauseOfIdeTools(msg): - msgWriteln(s, color, frmt) + if kind != nil: + styledMsgWriteln(color, title, resetStyle, s, + KindColor, `%`(KindFormat, kind)) + else: + styledMsgWriteln(color, title, resetStyle, s) handleError(msg, doAbort, s) proc rawMessage*(msg: TMsgKind, arg: string) = @@ -795,47 +839,56 @@ proc writeSurroundingSrc(info: TLineInfo) = msgWriteln(indent & spaces(info.col) & '^') proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string = - let frmt = case msg - of warnMin..warnMax: PosWarningFormat - of hintMin..hintMax: PosHintFormat - else: PosErrorFormat - result = frmt % [toMsgFilename(info), coordToStr(info.line), - coordToStr(info.col+1), getMessageStr(msg, arg)] + let title = case msg + of warnMin..warnMax: WarningTitle + of hintMin..hintMax: HintTitle + else: ErrorTitle + result = PosFormat % [toMsgFilename(info), coordToStr(info.line), + coordToStr(info.col+1)] & + title & + getMessageStr(msg, arg) proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, eh: TErrorHandling) = var - frmt: string - ignoreMsg = false + title: string color: ForegroundColor + kind: string + ignoreMsg = false case msg of errMin..errMax: writeContext(info) - frmt = PosErrorFormat + title = ErrorTitle + color = ErrorColor # we try to filter error messages so that not two error message # in the same file and line are produced: #ignoreMsg = lastError == info and eh != doAbort lastError = info - color = fgRed of warnMin..warnMax: ignoreMsg = optWarns notin gOptions or msg notin gNotes if not ignoreMsg: writeContext(info) - frmt = PosWarningFormat + title = WarningTitle + color = WarningColor + kind = WarningsToStr[ord(msg) - ord(warnMin)] inc(gWarnCounter) - color = fgYellow of hintMin..hintMax: ignoreMsg = optHints notin gOptions or msg notin gNotes - frmt = PosHintFormat + title = HintTitle + color = HintColor + kind = HintsToStr[ord(msg) - ord(hintMin)] inc(gHintCounter) - color = fgGreen # NOTE: currently line info line numbers start with 1, # but column numbers start with 0, however most editors expect # first column to be 1, so we need to +1 here - let x = frmt % [toMsgFilename(info), coordToStr(info.line), - coordToStr(info.col+1)] + let x = PosFormat % [toMsgFilename(info), coordToStr(info.line), + coordToStr(info.col+1)] let s = getMessageStr(msg, arg) if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg): - msgWriteln(s, color, x) + if kind != nil: + styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s, + KindColor, `%`(KindFormat, kind)) + else: + styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s) if optPrintSurroundingSrc and msg in errMin..errMax: info.writeSurroundingSrc handleError(msg, eh, s) @@ -907,3 +960,6 @@ ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) = of rCannotOpenFile: rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg) +# enable colors by default on terminals +if terminal.isatty(stdout): + incl(gGlobalOptions, optUseColors) diff --git a/compiler/options.nim b/compiler/options.nim index 42a13f8e8..f3277f855 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -82,7 +82,7 @@ type # please make sure we have under 32 options cmdRun # run the project via TCC backend TStringSeq* = seq[string] TGCMode* = enum # the selected GC - gcNone, gcBoehm, gcMarkAndSweep, gcRefc, gcV2, gcGenerational + gcNone, gcBoehm, gcGo, gcMarkAndSweep, gcRefc, gcV2, gcGenerational IdeCmd* = enum ideNone, ideSug, ideCon, ideDef, ideUse diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7ea2c3d6f..f506e3ff5 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -748,6 +748,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = isConvertible elif typeRel(c, base(f), a.sons[0]) >= isGeneric: result = isConvertible + of tyString: + if f.kind == tyOpenArray: + if f.sons[0].kind == tyChar: + result = isConvertible + elif f.sons[0].kind == tyGenericParam and typeRel(c, base(f), base(a)) >= isGeneric: + result = isConvertible else: discard of tySequence: case a.kind diff --git a/compiler/vm.nim b/compiler/vm.nim index 9f0d0bfce..826356c68 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1051,18 +1051,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # set to default value: for i in oldLen .. <newLen: regs[ra].node.sons[i] = newNodeI(nkEmpty, c.debug[pc]) - of opcSwap: - let rb = instr.regB - if regs[ra].kind == regs[rb].kind: - case regs[ra].kind - of rkNone: discard - of rkInt: swap regs[ra].intVal, regs[rb].intVal - of rkFloat: swap regs[ra].floatVal, regs[rb].floatVal - of rkNode: swap regs[ra].node, regs[rb].node - of rkRegisterAddr: swap regs[ra].regAddr, regs[rb].regAddr - of rkNodeAddr: swap regs[ra].nodeAddr, regs[rb].nodeAddr - else: - internalError(c.debug[pc], "cannot swap operands") of opcReset: internalError(c.debug[pc], "too implement") of opcNarrowS: diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 047009f01..2d0272cd7 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -65,7 +65,7 @@ type opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet, opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr, opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq, - opcSwap, opcIsNil, opcOf, opcIs, + opcIsNil, opcOf, opcIs, opcSubStr, opcParseFloat, opcConv, opcCast, opcQuit, opcReset, opcNarrowS, opcNarrowU, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index c68282fde..dc3188c66 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -831,12 +831,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.freeTemp(tmp) of mSwap: unused(n, dest) - var - d1 = c.genx(n.sons[1]) - d2 = c.genx(n.sons[2]) - c.gABC(n, opcSwap, d1, d2) - c.genAsgnPatch(n.sons[1], d1) - c.genAsgnPatch(n.sons[2], d2) + c.gen(lowerSwap(n, if c.prc == nil: c.module else: c.prc.sym)) of mIsNil: genUnaryABC(c, n, dest, opcIsNil) of mCopyStr: if dest < 0: dest = c.getTemp(n.typ) diff --git a/doc/advopt.txt b/doc/advopt.txt index 195122cc7..a4f72e2d8 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -58,7 +58,7 @@ Advanced options: --skipUserCfg do not read the user's configuration file --skipParentCfg do not read the parent dirs' configuration files --skipProjCfg do not read the project's configuration file - --gc:refc|v2|markAndSweep|boehm|none + --gc:refc|v2|markAndSweep|boehm|go|none select the GC to use; default is 'refc' --index:on|off turn index file generation on|off --putenv:key=value set an environment variable diff --git a/doc/astspec.txt b/doc/astspec.txt index 68bb9f1cd..d3ca7755e 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -1,5 +1,6 @@ The AST in Nim -================= +============== + This section describes how the AST is modelled with Nim's type system. The AST consists of nodes (``NimNode``) with a variable number of children. Each node has a field named ``kind`` which describes what the node @@ -24,9 +25,9 @@ contains: of nnkNone, nnkEmpty, nnkNilLit: discard ## node contains no additional fields of nnkCharLit..nnkUInt64Lit: - intVal: biggestInt ## the int literal + intVal: BiggestInt ## the int literal of nnkFloatLit..nnkFloat64Lit: - floatVal: biggestFloat ## the float literal + floatVal: BiggestFloat ## the float literal of nnkStrLit..nnkTripleStrLit: strVal: string ## the string literal of nnkIdent: @@ -40,26 +41,30 @@ For the ``NimNode`` type, the ``[]`` operator has been overloaded: ``n[i]`` is ``n``'s ``i``-th child. To specify the AST for the different Nim constructs, the notation -``nodekind(son1, son2, ...)`` or ``nodekind(value)`` or +``nodekind(son1, son2, ...)`` or ``nodekind(value)`` or ``nodekind(field=value)`` is used. -Some child may be missing. A missing child is a node of kind ``nnkEmpty``; +Some child may be missing. A missing child is a node of kind ``nnkEmpty``; a child can never be nil. Leaf nodes/Atoms ================ -A leaf of the AST often corresponds to a terminal symbol in the concrete +A leaf of the AST often corresponds to a terminal symbol in the concrete syntax. ----------------- --------------------------------------------- -Nim expression corresponding AST +Nim expression Corresponding AST ----------------- --------------------------------------------- ``42`` ``nnkIntLit(intVal = 42)`` ``42'i8`` ``nnkInt8Lit(intVal = 42)`` ``42'i16`` ``nnkInt16Lit(intVal = 42)`` ``42'i32`` ``nnkInt32Lit(intVal = 42)`` ``42'i64`` ``nnkInt64Lit(intVal = 42)`` +``42'u8`` ``nnkUInt8Lit(intVal = 42)`` +``42'u16`` ``nnkUInt16Lit(intVal = 42)`` +``42'u32`` ``nnkUInt32Lit(intVal = 42)`` +``42'u64`` ``nnkUInt64Lit(intVal = 42)`` ``42.0`` ``nnkFloatLit(floatVal = 42.0)`` ``42.0'f32`` ``nnkFloat32Lit(floatVal = 42.0)`` ``42.0'f64`` ``nnkFloat64Lit(floatVal = 42.0)`` @@ -90,7 +95,11 @@ Concrete syntax: AST: .. code-block:: nim - nnkCommand(nnkIdent(!"echo"), nnkStrLit("abc"), nnkStrLit("xyz")) + nnkCommand( + nnkIdent(!"echo"), + nnkStrLit("abc"), + nnkStrLit("xyz") + ) Call with ``()`` @@ -104,7 +113,11 @@ Concrete syntax: AST: .. code-block:: nim - nnkCall(nnkIdent(!"echo"), nnkStrLit("abc"), nnkStrLit("xyz")) + nnkCall( + nnkIdent(!"echo"), + nnkStrLit("abc"), + nnkStrLit("xyz") + ) Infix operator call @@ -118,8 +131,53 @@ Concrete syntax: AST: .. code-block:: nim - nnkInfix(nnkIdent(!"&"), nnkStrLit("abc"), nnkStrLit("xyz")) + nnkInfix( + nnkIdent(!"&"), + nnkStrLit("abc"), + nnkStrLit("xyz") + ) + +Note that with multiple infix operators, the command is parsed by operator +precedence. +Concrete syntax: + +.. code-block:: nim + 5 + 3 * 4 + +AST: + +.. code-block:: nim + nnkInfix( + nnkIdent(!"+"), + nnkIntLit(5), + nnkInfix( + nnkIdent(!"*"), + nnkIntLit(3), + nnkIntLit(4) + ) + ) + +As a side note, if you choose to use infix operators in a prefix form, the AST +behaves as a +[parenthetical function call](./macros.html#calls-expressions-call-with) with +``nnkAccQuoted``, as follows: + +Concrete syntax: + +.. code-block:: nim + `+`(3, 4) + +AST: + +.. code-block:: nim + nnkCall( + nnkAccQuoted( + nnkIdent(!"+") + ), + nnkIntLit(3), + nnkIntLit(4) + ) Prefix operator call -------------------- @@ -132,13 +190,16 @@ Concrete syntax: AST: .. code-block:: nim - nnkPrefix(nnkIdent(!"?"), nnkStrLit("abc")) + nnkPrefix( + nnkIdent(!"?"), + nnkStrLit("abc") + ) Postfix operator call --------------------- -**Note:** There are no postfix operators in Nim. However, the +**Note:** There are no postfix operators in Nim. However, the ``nnkPostfix`` node is used for the *asterisk export marker* ``*``: Concrete syntax: @@ -149,7 +210,10 @@ Concrete syntax: AST: .. code-block:: nim - nnkPostfix(nnkIdent(!"*"), nnkIdent(!"identifier")) + nnkPostfix( + nnkIdent(!"*"), + nnkIdent(!"identifier") + ) Call with named arguments @@ -163,10 +227,34 @@ Concrete syntax: AST: .. code-block:: nim - nnkCall(nnkIdent(!"writeln"), - nnkExprEqExpr(nnkIdent(!"file"), nnkIdent(!"stdout")), - nnkStrLit("hallo")) + nnkCall( + nnkIdent(!"writeln"), + nnkExprEqExpr( + nnkIdent(!"file"), + nnkIdent(!"stdout") + ), + nnkStrLit("hallo") + ) + +Call with raw string literal +---------------------------- + +This is used, for example, in the ``bindSym`` examples +[here](http://nim-lang.org/docs/manual.html#macros-bindsym) and with +``re"some regexp"`` in the regular expression module. + +Concrete syntax: +.. code-block:: nim + echo"abc" + +AST: + +.. code-block:: nim + nnkCallStrLit( + nnkIdent(!"echo"), + nnkRStrLit("hello") + ) Dereference operator ``[]`` --------------------------- @@ -223,6 +311,9 @@ AST: .. code-block:: nim nnkDotExpr(nnkIdent(!"x"), nnkIdent(!"y")) +If you use Nim's flexible calling syntax (as in ``x.len()``), the result is the +same as above but wrapped in an ``nnkCall``. + Array access operator ``[]`` ---------------------------- @@ -241,7 +332,7 @@ AST: Parentheses ----------- -Parentheses for affecting operator precedence or tuple construction +Parentheses for affecting operator precedence or tuple construction are built with the ``nnkPar`` node. Concrete syntax: @@ -253,12 +344,12 @@ AST: .. code-block:: nim nnkPar(nnkIntLit(1), nnkIntLit(2), nnkPar(nnkIntLit(3))) - - + + Curly braces ------------ -Curly braces are used as the set constructor. +Curly braces are used as the set constructor. Concrete syntax: @@ -270,11 +361,26 @@ AST: .. code-block:: nim nnkCurly(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3)) +When used as a table constructor, the syntax is different. + +Concrete syntax: + +.. code-block:: nim + {a: 3, b: 5} + +AST: + +.. code-block:: nim + nnkTableConstr( + nnkExprColonExpr(nnkIdent(!"a"), nnkIntLit(3)), + nnkExprColonExpr(nnkIdent(!"b"), nnkIntLit(5)) + ) + Brackets -------- -Brackets are used as the array constructor. +Brackets are used as the array constructor. Concrete syntax: @@ -290,7 +396,7 @@ AST: Ranges ------ -Ranges occur in set constructors, case statement branches or array slices. +Ranges occur in set constructors, case statement branches, or array slices. Concrete syntax: @@ -306,7 +412,7 @@ AST: If expression ------------- -The representation of the if expression is subtle, but easy to traverse. +The representation of the ``if`` expression is subtle, but easy to traverse. Concrete syntax: @@ -322,6 +428,69 @@ AST: nnkElseExpr(expr3) ) +Documentation Comments +---------------------- + +Double-hash (``##``) comments in the code actually have their own format, +but the comments do not yet show up in the AST, which will only show that +a comment exists, not what it contains. Single-hash (``#``) comments are ignored. + +Concrete syntax: + +.. code-block:: nim + ## This is a comment + ## This is part of the first comment + stmt1 + ## Yet another + +AST: + +.. code-block:: nim + nnkCommentStmt() # only appears once for the first two lines! + stmt1 + nnkCommentStmt() # another nnkCommentStmt because there is another comment + # (separate from the first) + +Pragmas +------- + +One of Nim's cool features is pragmas, which allow fine-tuning of various +aspects of the language. They come in all types, such as adorning procs and +objects, but the standalone ``emit`` pragma shows the basics with the AST. + +Concrete syntax: + +.. code-block:: nim + {.emit: "#include <stdio.h>".} + +AST: + +.. code-block:: nim + nnkPragma( + nnkExprColonExpr( + nnkIdent(!"emit"), + nnkStrLit("#include <stdio.h>") # the "argument" + ) + ) + +As many ``nnkIdent`` appear as there are pragmas between ``{..}``. Note that +the declaration of new pragmas is essentially the same: + +Concrete syntax: + +.. code-block:: nim + {.pragma: cdeclRename, cdecl.} + +AST: + +.. code-block:: nim + nnkPragma( + nnkExprColonExpr( + nnkIdent(!"pragma"), # this is always first when declaring a new pragma + nnkIdent(!"cdeclRename") # the name of the pragma + ), + nnkIdent(!"cdecl") + ) Statements ========== @@ -335,7 +504,7 @@ there is no ``else`` branch, no ``nnkElse`` child exists. Concrete syntax: .. code-block:: nim - if cond1: + if cond1: stmt1 elif cond2: stmt2 @@ -374,6 +543,8 @@ AST: .. code-block:: nim nnkAsgn(nnkIdent(!"x"), nnkIntLit(42)) +This is not the syntax for assignment when combined with ``var``, ``let``, +or ``const``. Statement list -------------- @@ -390,7 +561,7 @@ AST: .. code-block:: nim nnkStmtList(stmt1, stmt2, stmt3) - + Case statement -------------- @@ -398,7 +569,7 @@ Concrete syntax: .. code-block:: nim case expr1 - of expr2, expr3..expr4: + of expr2, expr3..expr4: stmt1 of expr5: stmt2 @@ -459,11 +630,11 @@ Concrete syntax: .. code-block:: nim try: stmt1 - except e1, e2: + except e1, e2: stmt2 except e3: stmt3 - except: + except: stmt4 finally: stmt5 @@ -472,9 +643,9 @@ AST: .. code-block:: nim nnkTryStmt( - stmt1, - nnkExceptBranch(e1, e2, stmt2), - nnkExceptBranch(e3, stmt3), + stmt1, + nnkExceptBranch(e1, e2, stmt2), + nnkExceptBranch(e3, stmt3), nnkExceptBranch(stmt4), nnkFinally(stmt5) ) @@ -499,12 +670,18 @@ Yield statement Like ``return``, but with ``nnkYieldStmt`` kind. +.. code-block:: nim + nnkYieldStmt(expr1) + Discard statement ----------------- Like ``return``, but with ``nnkDiscardStmt`` kind. +.. code-block:: nim + nnkDiscardStmt(expr1) + Continue statement ------------------ @@ -519,54 +696,679 @@ AST: .. code-block:: nim nnkContinueStmt() +Break statement +--------------- + +Concrete syntax: + +.. code-block:: nim + break otherLocation + +AST: + +.. code-block:: nim + nnkBreakStmt(nnkIdent(!"otherLocation")) + +If ``break`` is used without a jump-to location, ``nnkEmpty`` replaces ``nnkIdent``. + +Block statement +--------------- + +Concrete syntax: + +.. code-block:: nim + block name: + +AST: + +.. code-block:: nim + nnkBlockStmt(nnkIdent(!"name"), nnkStmtList(...)) + +A ``block`` doesn't need an name, in which case ``nnkEmpty`` is used. + +Asm statement +------------- + +Concrete syntax: + +.. code-block:: nim + asm """ + some asm + """ + +AST: + +.. code-block:: nim + nnkAsmStmt( + nnkEmpty(), # for pragmas + nnkTripleStrLit("some asm"), + ) + +Import section +-------------- + +Nim's ``import`` statement actually takes different variations depending +on what keywords are present. Let's start with the simplest form. + +Concrete syntax: + +.. code-block:: nim + import math + +AST: + +.. code-block:: nim + nnkImportStmt(nnkIdent(!"math")) + +With ``except``, we get ``nnkImportExceptStmt``. + +Concrete syntax: + +.. code-block:: nim + import math except pow + +AST: + +.. code-block:: nim + nnkImportExceptStmt(nnkIdent(!"math"),nnkIdent(!"pow")) + +Note that ``import math as m`` does not use a different node; rather, +we use ``nnkImportStmt`` with ``as`` as an infix operator. + +Concrete syntax: + +.. code-block:: nim + import strutils as su + +AST: + +.. code-block:: nim + nnkImportStmt( + nnkInfix( + nnkIdent(!"as"), + nnkIdent(!"strutils"), + nnkIdent(!"su") + ) + ) + +From statement +-------------- + +If we use ``from ... import``, the result is different, too. + +Concrete syntax: + +.. code-block:: nim + from math import pow + +AST: + +.. code-block:: nim + nnkFromStmt(nnkIdent(!"math"), nnkIdent(!"pow")) + +Using ``from math as m import pow`` works identically to the ``as`` modifier +with the ``import`` statement, but wrapped in ``nnkFromStmt``. + +Export statement +---------------- + +When you are making an imported module accessible by modules that import yours, +the ``export`` syntax is pretty straightforward. + +Concrete syntax: + +.. code-block:: nim + export unsigned + +AST: + +.. code-block:: nim + nnkExportStmt(nnkIdent(!"unsigned")) + +Similar to the ``import`` statement, the AST is different for +``export ... except``. + +Concrete syntax: + +.. code-block:: nim + export math except pow # we're going to implement our own exponentiation + +AST: + +.. code-block:: nim + nnkExportExceptStmt(nnkIdent(!"math"),nnkIdent(!"pow")) + +Include statement +----------------- + +Like a plain ``import`` statement but with ``nnkIncludeStmt``. + +Concrete syntax: + +.. code-block:: nim + include blocks + +AST: + +.. code-block:: nim + nnkIncludeStmt(nnkIdent(!"blocks")) + Var section ----------- -To be written. +Concrete syntax: +.. code-block:: nim + var a = 3 + +AST: + +.. code-block:: nim + nnkVarSection( + nnkIdentDefs( + nnkIdent(!"a"), + nnkEmpty(), # or nnkIdent(...) if the variable declares the type + nnkIntLit(3), + ) + ) + +Note that either the second or third (or both) parameters above must exist, +as the compiler needs to know the type somehow (which it can infer from +the given assignment). + +This is not the same AST for all uses of ``var``. See +[Procedure declaration](http://nim-lang.org/docs/macros.html#statements-procedure-declaration) +for details. + +Let section +----------- + +This is equivalent to ``var``, but with ``nnkLetSection`` rather than +``nnkVarSection``. + +Concrete syntax: + +.. code-block:: nim + let v = 3 + +AST: + +.. code-block:: nim + nnkLetSection( + nnkIdentDefs(!"v"), + nnkEmpty(), # for the type + nnkIntLit(3) + ) Const section ------------- -To be written. +Concrete syntax: + +.. code-block:: nim + const a = 3 +AST: + +.. code-block:: nim + nnkConstSection( + nnkConstDef( # not nnkConstDefs! + nnkIdent(!"a"), + nnkEmpty(), # or nnkIdent(...) if the variable declares the type + nnkIntLit(3), # required in a const declaration! + ) + ) Type section ------------ -To be written. +Starting with the simplest case, a ``type`` section appears much like ``var`` +and ``const``. + +Concrete syntax: + +.. code-block:: nim + type A = int + +AST: + +.. code-block:: nim + nnkTypeSection( + nnkTypeDef( + nnkIdent(!"A"), + nnkEmpty(), + nnkIdent(!"int") + ) + ) + +Declaring ``distinct`` types is similar, with the last ``nnkIdent`` wrapped +in ``nnkDistinctTy``. + +Concrete syntax: + +.. code-block:: nim + type MyInt = distinct int + +AST: + +.. code-block:: nim + # ... + nnkTypeDef( + nnkIdent(!"MyInt"), + nnkEmpty(), + nnkDistinctTy( + nnkIdent(!"int") + ) + ) + +If a type section uses generic parameters, they are treated here: + +Concrete syntax: + +.. code-block:: nim + type A[T] = expr1 + +AST: + +.. code-block:: nim + nnkTypeSection( + nnkTypeDef( + nnkIdent(!"A"), + nnkGenericParams( + nnkIdentDefs( + nnkIdent(!"T"), + nnkEmpty(), # if the type is declared with options, like + # ``[T: SomeInteger]``, they are given here + nnkEmpty(), + ) + ) + expr1, + ) + ) + +Note that not all ``nnkTypeDef`` utilize ``nnkIdent`` as their +their parameter. One of the most common uses of type declarations +is to work with objects. + +Concrete syntax: + +.. code-block:: nim + type IO = object of RootObj + +AST: + +.. code-block:: nim + # ... + nnkTypeDef( + nnkIdent(!"IO"), + nnkEmpty(), + nnkObjectTy( + nnkEmpty(), # no pragmas here + nnkOfInherit( + nnkIdent(!"RootObj") # inherits from RootObj + ) + nnkEmpty() + ) + ) + +Nim's object syntax is rich. Let's take a look at an involved example in +its entirety to see some of the complexities. + +Concrete syntax: + +.. code-block:: nim + type Obj[T] = object {.inheritable.} + name: string + case isFat: bool + of true: + m: array[100_000, T] + of false: + m: array[10, T] + +AST: + +.. code-block:: nim + # ... + nnkObjectTy( + nnkPragma( + nnkIdent(!"inheritable") + ), + nnkEmpty(), + nnkRecList( # list of object parameters + nnkIdentDefs( + nnkIdent(!"name"), + nnkIdent(!"string"), + nnkEmpty() + ), + nnkRecCase( # case statement within object (not nnkCaseStmt) + nnkIdentDefs( + nnkIdent(!"isFat"), + nnkIdent(!"bool"), + nnkEmpty() + ), + nnkOfBranch( + nnkIdent(!"true"), + nnkRecList( # again, a list of object parameters + nnkIdentDefs( + nnkIdent(!"m"), + nnkBracketExpr( + nnkIdent(!"array"), + nnkIntLit(100000), + nnkIdent(!"T") + ), + nnkEmpty() + ) + ), + nnkOfBranch( + nnkIdent(!"false"), + nnkRecList( + nnkIdentDefs( + nnkIdent(!"m"), + nnkBracketExpr( + nnkIdent(!"array"), + nnkIntLit(10), + nnkIdent(!"T") + ), + nnkEmpty() + ) + ) + ) + ) + ) + ) + + +Using an ``enum`` is similar to using an ``object``. + +Concrete syntax: + +.. code-block:: nim + type X = enum + First + +AST: + +.. code-block:: nim + # ... + nnkEnumTy( + nnkEmpty(), + nnkIdent(!"First") # you need at least one nnkIdent or the compiler complains + ) + +The usage of ``concept`` (experimental) is similar to objects. + +Concrete syntax: + +.. code-block:: nim + type Con = concept x,y,z + (x & y & z) is string + +AST: + +.. code-block:: nim + # ... + nnkTypeClassTy( # note this isn't nnkConceptTy! + nnkArglist( + # ... idents for x, y, z + ) + # ... + ) +Static types, like ``static[int]``, use ``nnkIdent`` wrapped in +``nnkStaticTy``. + +Concrete syntax: + +.. code-block:: nim + type A[T: static[int]] = object + +AST: + +.. code-block:: nim + # ... within nnkGenericParams + nnkIdentDefs( + nnkIdent(!"T"), + nnkStaticTy( + nnkIdent(!"int") + ), + nnkEmpty() + ) + # ... + +In general, declaring types mirrors this syntax (i.e., ``nnkStaticTy`` for +``static``, etc.). Examples follow (exceptions marked by ``*``): + +------------- --------------------------------------------- +Nim type Corresponding AST +------------- --------------------------------------------- +``static`` ``nnkStaticTy`` +``tuple`` ``nnkTupleTy`` +``var`` ``nnkVarTy`` +``ptr`` ``nnkPtrTy`` +``ref`` ``nnkRefTy`` +``distinct`` ``nnkDistinctTy`` +``enum`` ``nnkEnumTy`` +``concept`` ``nnkTypeClassTy``\* +``array`` ``nnkBracketExpr(nnkIdent(!"array"),...``\* +``proc`` ``nnkProcTy`` +``iterator`` ``nnkIteratorTy`` +``object`` ``nnkObjectTy`` + +Take special care when declaring types as ``proc``. The behavior is similar +to ``Procedure declaration``, below, but does not treat ``nnkGenericParams``. +Generic parameters are treated in the type, not the ``proc`` itself. + +Concrete syntax: + +.. code-block:: nim + type MyProc[T] = proc(x: T) + +AST: + +.. code-block:: nim + # ... + nnkTypeDef( + nnkIdent(!"MyProc"), + nnkGenericParams( # here, not with the proc + # ... + ) + nnkProcTy( # behaves like a procedure declaration from here on + nnkFormalParams( + # ... + ) + ) + ) + +The same syntax applies to ``iterator`` (with ``nnkIteratorTy``), but +*does not* apply to ``converter`` or ``template``. + +Mixin statement +--------------- + +Concrete syntax: + +.. code-block:: nim + mixin x + +AST: + +.. code-block:: nim + nnkMixinStmt(nnkIdent(!"x")) + +Bind statement +-------------- + +Concrete syntax: + +.. code-block:: nim + bind x + +AST: + +.. code-block:: nim + nnkBindStmt(nnkIdent(!"x")) Procedure declaration --------------------- -To be written. +Let's take a look at a procedure with a lot of interesting aspects to get +a feel for how procedure calls are broken down. + +Concrete syntax: + +.. code-block:: nim + proc hello*[T: SomeInteger](x: int = 3, y: float32): int {.inline.} = discard + +AST: + +.. code-block:: nim + nnkProcDef( + nnkPostfix(nnkIdent(!"*"), nnkIdent(!"hello")), # the exported proc name + nnkEmpty(), # patterns for term rewriting in templates and macros (not procs) + nnkGenericParams( # generic type parameters, like with type declaration + nnkIdentDefs( + nnkIdent(!"T"), nnkIdent(!"SomeInteger") + ) + ), + nnkFormalParams( + nnkIdent(!"int"), # the first FormalParam is the return type. nnkEmpty() if there is none + nnkIdentDefs( + nnkIdent(!"x"), + nnkIdent(!"int"), # type type (required for procs, not for templates) + nnkIntLit(3) # a default value + ), + nnkIdentDefs( + nnkIdent(!"y"), + nnkIdent(!"float32"), + nnkEmpty() + ) + nnkPragma(nnkIdent(!"inline")), + nnkEmpty(), # reserved slot for future use + nnkStmtList(nnkDiscardStmt(nnkEmpty())) # the meat of the proc + ) + ) +There is another consideration. Nim has flexible type identification for +its procs. Even though ``proc(a: int, b: int)`` and ``proc(a, b: int)`` +are equivalent in the code, the AST is a little different for the latter. + +Concrete syntax: + +.. code-block:: nim + proc(a, b: int) + +AST: + +.. code-block:: nim + # ...AST as above... + nnkFormalParams( + nnkEmpty(), # no return here + nnkIdentDefs( + nnkIdent(!"a"), # the first parameter + nnkIdent(!"b"), # directly to the second parameter + nnkIdent(!"int"), # their shared type identifier + nnkEmpty(), # default value would go here + ) + ), + # ... + +When a procedure uses the special ``var`` type return variable, the result +is different from that of a var section. + +Concrete syntax: + +.. code-block:: nim + proc hello(): var int + +AST: + +.. code-block:: nim + # ... + nnkFormalParams( + nnkVarTy( + nnkIdent(!"int") + ) + ) Iterator declaration -------------------- -To be written. +The syntax for iterators is similar to procs, but with ``nnkIteratorDef`` +replacing ``nnkProcDef``. + +Concrete syntax: + +.. code-block:: nim + iterator nonsense[T](x: seq[T]): float {.closure.} = ... +AST: + +.. code-block:: nim + nnkIteratorDef( + nnkIdent(!"nonsense"), + nnkEmpty(), + ... + ) + +Converter declaration +--------------------- + +A converter is similar to a proc. + +Concrete syntax: + +.. code-block:: nim + converter toBool(x: float): bool + +AST: + +.. code-block:: nim + nnkConverterDef( + nnkIdent(!"toBool"), + # ... + ) Template declaration -------------------- -To be written. +Templates (as well as macros, as we'll see) have a slightly expanded AST when +compared to procs and iterators. The reason for this is [term-rewriting +macros](http://nim-lang.org/docs/manual.html#term-rewriting-macros). Notice +the ``nnkEmpty()`` as the second argument to ``nnkProcDef`` and +``nnkIteratorDef`` above? That's where the term-rewriting macros go. + +Concrete syntax: + +.. code-block:: nim + template optOpt{expr1}(a: int): int +AST: + +.. code-block:: nim + nnkTemplateDef( + nnkIdent(!"optOpt"), + nnkStmtList( # instead of nnkEmpty() + expr1 + ), + # follows like a proc or iterator + ) + +If the template does not have types for its parameters, the type identifiers +inside ``nnkFormalParams`` just becomes ``nnkEmpty``. Macro declaration ----------------- -To be written. +Macros behave like templates, but ``nnkTemplateDef`` is replaced with +``nnkMacroDef``. Special node kinds ================== -There are several node kinds that are used for semantic checking or code +There are several node kinds that are used for semantic checking or code generation. These are accessible from this module, but should not be used. Other node kinds are especially designed to make AST manipulations easier. -These are explained here. +These are explained here. To be written. diff --git a/doc/koch.txt b/doc/koch.txt index 7da137458..a58d386ea 100644 --- a/doc/koch.txt +++ b/doc/koch.txt @@ -71,7 +71,7 @@ options: are limited to pure Nim code at compilation time. Enabling this switch will allow macros to execute non-nim code at compilation time (eg. open a file and write to it). ---gc:refc|v2|markAndSweep|boehm|none +--gc:refc|v2|markAndSweep|boehm|go|none Selects which garbage collection strategy to use for the compiler and generated code. See the `Nim's Garbage Collector <gc.html>`_ documentation for more information. diff --git a/doc/manual/lexing.txt b/doc/manual/lexing.txt index fab6da416..9419f8453 100644 --- a/doc/manual/lexing.txt +++ b/doc/manual/lexing.txt @@ -101,25 +101,28 @@ Two identifiers are considered equal if the following algorithm returns true: .. code-block:: nim proc sameIdentifier(a, b: string): bool = - a[0] == b[0] and a.replace("_", "").toLower == b.replace("_", "").toLower + a[0] == b[0] and + a.replace(re"_|–", "").toLower == b.replace(re"_|–", "").toLower That means only the first letters are compared in a case sensitive manner. Other -letters are compared case insensitively and underscores are ignored. +letters are compared case insensitively and underscores and en-dash (Unicode +point U+2013) are ignored. -This rather strange way to do identifier comparisons is called +This rather unorthodox way to do identifier comparisons is called `partial case insensitivity`:idx: and has some advantages over the conventional case sensitivity: It allows programmers to mostly use their own preferred -spelling style and libraries written by different programmers cannot use -incompatible conventions. A Nim-aware editor or IDE can show the identifiers as -preferred. Another advantage is that it frees the programmer from remembering +spelling style, be it humpStyle, snake_style or dash–style and libraries written +by different programmers cannot use incompatible conventions. +A Nim-aware editor or IDE can show the identifiers as preferred. +Another advantage is that it frees the programmer from remembering the exact spelling of an identifier. The exception with respect to the first letter allows common code like ``var foo: Foo`` to be parsed unambiguously. -Historically, Nim was a `style-insensitive`:idx: language. This means that it -was not case-sensitive and underscores were ignored and there was no distinction -between ``foo`` and ``Foo``. +Historically, Nim was a fully `style-insensitive`:idx: language. This meant that +it was not case-sensitive and underscores were ignored and there was no even a +distinction between ``foo`` and ``Foo``. String literals @@ -345,6 +348,12 @@ notation: ``0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64`` is approximately 1.72826e35 according to the IEEE floating point standard. +Literals are bounds checked so that they fit the datatype. Non base-10 +literals are used mainly for flags and bit pattern representations, therefore +bounds checking is done on bit width, not value range. If the literal fits in +the bit width of the datatype, it is accepted. +Hence: 0b10000000'u8 == 0x80'u8 == 128, but, 0b10000000'i8 == 0x80'i8 == -1 +instead of causing an overflow error. Operators --------- diff --git a/doc/manual/modules.txt b/doc/manual/modules.txt index fe3360773..813505769 100644 --- a/doc/manual/modules.txt +++ b/doc/manual/modules.txt @@ -146,6 +146,14 @@ modules don't need to import a module's dependencies: var x: MyObject echo($x) +Note on paths +----------- +In module related statements, if any part of the module name / +path begins with a number, you may have to quote it in double quotes. +In the following example, it would be seen as a literal number '3.0' of type +'float64' if not quoted, if uncertain - quote it: +.. code-block:: nim + import "gfx/3d/somemodule" Scope rules ----------- diff --git a/doc/tut1.txt b/doc/tut1.txt index 1fa495054..500480cf0 100644 --- a/doc/tut1.txt +++ b/doc/tut1.txt @@ -757,16 +757,25 @@ However, this cannot be done for mutually recursive procedures: # forward declaration: proc even(n: int): bool - proc odd(n: int): bool = +proc even(n: int): bool + +proc odd(n: int): bool = + assert(n >= 0) # makes sure we don't run into negative recursion + if n == 0: false + else: n == 1 or even(n-1) - proc even(n: int): bool = +proc even(n: int): bool = + assert(n >= 0) # makes sure we don't run into negative recursion + if n == 1: false + else: n == 0 or odd(n-1) Here ``odd`` depends on ``even`` and vice versa. Thus ``even`` needs to be introduced to the compiler before it is completely defined. The syntax for such a forward declaration is simple: just omit the ``=`` and the -procedure's body. +procedure's body. The ``assert`` just adds border conditions, and will be +covered later in `Modules`_ section. Later versions of the language will weaken the requirements for forward declarations. diff --git a/doc/tut2.txt b/doc/tut2.txt index e1ac20074..966423844 100644 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -233,17 +233,15 @@ is needed: type Socket* = ref object of RootObj - FHost: int # cannot be accessed from the outside of the module - # the `F` prefix is a convention to avoid clashes since - # the accessors are named `host` + host: int # cannot be accessed from the outside of the module due to missing star proc `host=`*(s: var Socket, value: int) {.inline.} = - ## setter of hostAddr - s.FHost = value + ## setter of host address + s.host = value proc host*(s: Socket): int {.inline.} = - ## getter of hostAddr - s.FHost + ## getter of host address + s.host var s: Socket new s diff --git a/install.txt b/install.txt index deca55599..efd60f9aa 100644 --- a/install.txt +++ b/install.txt @@ -9,10 +9,10 @@ should be in your ``$PATH`` (most likely the case). Note that some few Linux distributions do not ship with a GCC compiler preinstalled - then you have to install it. -Install Nim by downloading the appropriate ``.zip`` file and extracting it +Install Nim by downloading the appropriate ``.zip`` file and extracting it to a directory of your choice. The Nim Compiler will stay in this -directory (unless you copy it somewhere else). The compiler does not need -write access to its directory, so copying the nim folder to ``/opt`` +directory (unless you copy it somewhere else). The compiler does not need +write access to its directory, so copying the nim folder to ``/opt`` works. Then run the following command:: @@ -26,7 +26,7 @@ manually. An alternative is to create a symbolic link in ``/usr/bin``:: [sudo] ln -s $your_install_dir/bin/nim /usr/bin/nim -There are also ``install.sh`` and ``deinstall.sh`` scripts for distributing +There are also ``install.sh`` and ``deinstall.sh`` scripts for distributing the files over the UNIX hierarchy. However, updating your Nim installation is more cumbersome then. @@ -35,8 +35,8 @@ Installation on the Macintosh ----------------------------- Only MacOS X is supported. -Since MacOS X is UNIX based too, it works like the installation on Linux. -However, for unknown reasons the symbolic link method does not work on MacOS X. +Since MacOS X is UNIX based too, it works like the installation on Linux. +However, for unknown reasons the symbolic link method does not work on MacOS X. You need to install Apple's developer's tools for the GNU Compiler Collection. @@ -64,5 +64,5 @@ However, most testing is done with GCC. Bootstrapping from Github ------------------------- -Take a look at the readme file on github `here <https://github.com/Araq/Nim#readme>`_ +Take a look at the readme file on github `here <https://github.com/nim-lang/Nim#readme>`_ for instructions. diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index ab150b2a4..dc97784c3 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -68,11 +68,15 @@ type TGenericSeq {.importc.} = object len, space: int + when defined(gogc): + elemSize: int PGenSeq = ptr TGenericSeq {.deprecated: [TAny: Any, TAnyKind: AnyKind].} -const - GenericSeqSize = (2 * sizeof(int)) +when defined(gogc): + const GenericSeqSize = (3 * sizeof(int)) +else: + const GenericSeqSize = (2 * sizeof(int)) proc genericAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.} proc genericShallowAssign(dest, src: pointer, mt: PNimType) {. diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 6f92b0d71..973f1f2ee 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -586,9 +586,12 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string] result = @[] var lastIdx = start var splits = 0 - var bounds = 0 .. 0 + var bounds = 0 .. -1 + var never_ran = true for match in str.findIter(pattern, start = start): + never_ran = false + # bounds are inclusive: # # 0123456 @@ -615,7 +618,8 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string] # "12".split("\b") would be @["1", "2", ""], but # if we skip an empty last match, it's the correct # @["1", "2"] - if bounds.a <= bounds.b or bounds.b < str.high: + # If matches were never found, then the input string is the result + if bounds.a <= bounds.b or bounds.b < str.high or never_ran: # last match: Each match takes the previous substring, # but "1 2".split(/ /) needs to return @["1", "2"]. # This handles "2" diff --git a/lib/pure/math.nim b/lib/pure/math.nim index a9e9010f6..494dfc4c8 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -161,6 +161,8 @@ proc randomize*(seed: int) {.benign.} when not defined(JS): proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".} ## computes the square root of `x`. + proc cbrt*(x: float): float {.importc: "cbrt", header: "<math.h>".} + ## computes the cubic root of `x` proc ln*(x: float): float {.importc: "log", header: "<math.h>".} ## computes ln(x). @@ -200,30 +202,64 @@ when not defined(JS): proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".} proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".} ## computes x to power raised of y. + + proc erf*(x: float): float {.importc: "erf", header: "<math.h>".} + ## The error function + proc erfc*(x: float): float {.importc: "erfc", header: "<math.h>".} + ## The complementary error function + + proc lgamma*(x: float): float {.importc: "lgamma", header: "<math.h>".} + ## Natural log of the gamma function + proc tgamma*(x: float): float {.importc: "tgamma", header: "<math.h>".} + ## The gamma function # C procs: - proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>".} - proc rand(): cint {.importc: "rand", header: "<stdlib.h>".} + when defined(vcc): + # The "secure" random, available from Windows XP + # https://msdn.microsoft.com/en-us/library/sxtz2fa8.aspx + # Present in some variants of MinGW but not enough to justify + # `when defined(windows)` yet + proc rand_s(val: var cuint) {.importc: "rand_s", header: "<stdlib.h>".} + # To behave like the normal version + proc rand(): cuint = rand_s(result) + else: + proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>".} + proc rand(): cint {.importc: "rand", header: "<stdlib.h>".} when not defined(windows): proc srand48(seed: clong) {.importc: "srand48", header: "<stdlib.h>".} proc drand48(): float {.importc: "drand48", header: "<stdlib.h>".} proc random(max: float): float = result = drand48() * max - when defined(windows): - proc random(max: float): float = - # we are hardcodeing this because - # importcing macros is extremely problematic - # and because the value is publicly documented - # on MSDN and very unlikely to change - const rand_max = 32767 - result = (float(rand()) / float(rand_max)) * max - proc randomize() = - randomize(cast[int](epochTime())) - - proc randomize(seed: int) = - srand(cint(seed)) - when declared(srand48): srand48(seed) + else: + when defined(vcc): # Windows with Visual C + proc random(max: float): float = + # we are hardcoding this because + # importc-ing macros is extremely problematic + # and because the value is publicly documented + # on MSDN and very unlikely to change + # See https://msdn.microsoft.com/en-us/library/296az74e.aspx + const rand_max = 4294967295 # UINT_MAX + result = (float(rand()) / float(rand_max)) * max + proc randomize() = discard + proc randomize(seed: int) = discard + else: # Windows with another compiler + proc random(max: float): float = + # we are hardcoding this because + # importc-ing macros is extremely problematic + # and because the value is publicly documented + # on MSDN and very unlikely to change + const rand_max = 32767 + result = (float(rand()) / float(rand_max)) * max + + when not defined(vcc): # the above code for vcc uses `discard` instead + # this is either not Windows or is Windows without vcc + proc randomize() = + randomize(cast[int](epochTime())) + proc randomize(seed: int) = + srand(cint(seed)) # rand_s doesn't use srand + when declared(srand48): srand48(seed) + proc random(max: int): int = result = int(rand()) mod max @@ -387,3 +423,9 @@ when isMainModule and not defined(JS): # Check for no side effect annotation proc mySqrt(num: float): float {.noSideEffect.} = return sqrt(num) + + # check gamma function + assert(tgamma(5.0) == 24.0) # 4! + assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0 + assert(erf(6.0) > erf(5.0)) + assert(erfc(6.0) < erfc(5.0)) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 4deb79f86..f29505590 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1304,7 +1304,9 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {. when defined(linux) or defined(macosx) or defined(bsd): if x.d_type != DT_UNKNOWN: if x.d_type == DT_DIR: k = pcDir - if x.d_type == DT_LNK: k = succ(k) + if x.d_type == DT_LNK: + if dirExists(y): k = pcLinkToDir + else: k = succ(k) yield (k, y) continue diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index c07b713de..b3708838a 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -26,7 +26,7 @@ proc toLower(c: char): char {.inline.} = result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c proc parseHex*(s: string, number: var int, start = 0): int {. - rtl, extern: "npuParseHex", noSideEffect.} = + rtl, extern: "npuParseHex", noSideEffect.} = ## Parses a hexadecimal number and stores its value in ``number``. ## ## Returns the number of the parsed characters or 0 in case of an error. This @@ -49,7 +49,7 @@ proc parseHex*(s: string, number: var int, start = 0): int {. var foundDigit = false if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2) elif s[i] == '#': inc(i) - while true: + while true: case s[i] of '_': discard of '0'..'9': @@ -66,13 +66,13 @@ proc parseHex*(s: string, number: var int, start = 0): int {. if foundDigit: result = i-start proc parseOct*(s: string, number: var int, start = 0): int {. - rtl, extern: "npuParseOct", noSideEffect.} = + rtl, extern: "npuParseOct", noSideEffect.} = ## parses an octal number and stores its value in ``number``. Returns ## the number of the parsed characters or 0 in case of an error. var i = start var foundDigit = false if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2) - while true: + while true: case s[i] of '_': discard of '0'..'7': @@ -93,7 +93,7 @@ proc parseIdent*(s: string, ident: var string, start = 0): int = result = i-start proc parseIdent*(s: string, start = 0): string = - ## parses an identifier and stores it in ``ident``. + ## parses an identifier and stores it in ``ident``. ## Returns the parsed identifier or an empty string in case of an error. result = "" var i = start @@ -101,14 +101,14 @@ proc parseIdent*(s: string, start = 0): string = if s[i] in IdentStartChars: inc(i) while s[i] in IdentChars: inc(i) - + result = substr(s, start, i-1) proc parseToken*(s: string, token: var string, validChars: set[char], start = 0): int {.inline, deprecated.} = ## parses a token and stores it in ``token``. Returns ## the number of the parsed characters or 0 in case of an error. A token - ## consists of the characters in `validChars`. + ## consists of the characters in `validChars`. ## ## **Deprecated since version 0.8.12**: Use ``parseWhile`` instead. var i = start @@ -126,13 +126,13 @@ proc skip*(s, token: string, start = 0): int {.inline.} = ## or 0 if there was no `token` at ``s[start]``. while result < token.len and s[result+start] == token[result]: inc(result) if result != token.len: result = 0 - + proc skipIgnoreCase*(s, token: string, start = 0): int = ## same as `skip` but case is ignored for token matching. while result < token.len and toLower(s[result+start]) == toLower(token[result]): inc(result) if result != token.len: result = 0 - + proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} = ## Skips all characters until one char from the set `until` is found ## or the end is reached. @@ -154,7 +154,7 @@ proc parseUntil*(s: string, token: var string, until: set[char], start = 0): int {.inline.} = ## parses a token and stores it in ``token``. Returns ## the number of the parsed characters or 0 in case of an error. A token - ## consists of the characters notin `until`. + ## consists of the characters notin `until`. var i = start while i < s.len and s[i] notin until: inc(i) result = i-start @@ -174,7 +174,7 @@ proc parseWhile*(s: string, token: var string, validChars: set[char], start = 0): int {.inline.} = ## parses a token and stores it in ``token``. Returns ## the number of the parsed characters or 0 in case of an error. A token - ## consists of the characters in `validChars`. + ## consists of the characters in `validChars`. var i = start while s[i] in validChars: inc(i) result = i-start @@ -214,7 +214,7 @@ proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {. ## `EOverflow` is raised if an overflow occurs. var res: BiggestInt # use 'res' for exception safety (don't write to 'number' in case of an - # overflow exception: + # overflow exception): result = rawParseInt(s, res, start) number = res @@ -246,7 +246,7 @@ proc parseFloat*(s: string, number: var float, start = 0): int {. result = parseBiggestFloat(s, bf, start) if result != 0: number = bf - + type InterpolatedKind* = enum ## describes for `interpolatedFragments` ## which part of the interpolated string is @@ -289,12 +289,12 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind, case s[j] of '{': inc nesting of '}': - if nesting == 0: + if nesting == 0: inc j break dec nesting of '\0': - raise newException(ValueError, + raise newException(ValueError, "Expected closing '}': " & substr(s, i, s.high)) else: discard inc j @@ -310,7 +310,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind, inc i # skip $ kind = ikDollar else: - raise newException(ValueError, + raise newException(ValueError, "Unable to parse a varible name at " & substr(s, i, s.high)) else: while j < s.len and s[j] != '$': inc j diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 15e2eefec..2efdf72d5 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -406,22 +406,43 @@ proc isatty*(f: File): bool = result = isatty(getFileHandle(f)) != 0'i32 -proc styledEchoProcessArg(s: string) = write stdout, s -proc styledEchoProcessArg(style: Style) = setStyle({style}) -proc styledEchoProcessArg(style: set[Style]) = setStyle style -proc styledEchoProcessArg(color: ForegroundColor) = setForegroundColor color -proc styledEchoProcessArg(color: BackgroundColor) = setBackgroundColor color +type + TerminalCmd* = enum ## commands that can be expressed as arguments + resetStyle ## reset attributes + +template styledEchoProcessArg(s: string) = write stdout, s +template styledEchoProcessArg(style: Style) = setStyle({style}) +template styledEchoProcessArg(style: set[Style]) = setStyle style +template styledEchoProcessArg(color: ForegroundColor) = setForegroundColor color +template styledEchoProcessArg(color: BackgroundColor) = setBackgroundColor color +template styledEchoProcessArg(cmd: TerminalCmd) = + when cmd == resetStyle: + resetAttributes() macro styledEcho*(m: varargs[expr]): stmt = ## to be documented. let m = callsite() + var reset = false result = newNimNode(nnkStmtList) for i in countup(1, m.len - 1): - result.add(newCall(bindSym"styledEchoProcessArg", m[i])) + let item = m[i] + case item.kind + of nnkStrLit..nnkTripleStrLit: + if i == m.len - 1: + # optimize if string literal is last, just call writeln + result.add(newCall(bindSym"writeln", bindSym"stdout", item)) + if reset: result.add(newCall(bindSym"resetAttributes")) + return + else: + # if it is string literal just call write, do not enable reset + result.add(newCall(bindSym"write", bindSym"stdout", item)) + else: + result.add(newCall(bindSym"styledEchoProcessArg", item)) + reset = true result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n"))) - result.add(newCall(bindSym"resetAttributes")) + if reset: result.add(newCall(bindSym"resetAttributes")) when defined(nimdoc): proc getch*(): char = diff --git a/lib/system.nim b/lib/system.nim index 2204a5436..2beb5b88d 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -305,6 +305,8 @@ when not defined(JS): type TGenericSeq {.compilerproc, pure, inheritable.} = object len, reserved: int + when defined(gogc): + elemSize: int PGenericSeq {.exportc.} = ptr TGenericSeq UncheckedCharArray {.unchecked.} = array[0..ArrayDummySize, char] # len and space without counting the terminating zero: @@ -677,35 +679,50 @@ proc `not` *(x: int): int {.magic: "BitnotI", noSideEffect.} proc `not` *(x: int8): int8 {.magic: "BitnotI", noSideEffect.} proc `not` *(x: int16): int16 {.magic: "BitnotI", noSideEffect.} proc `not` *(x: int32): int32 {.magic: "BitnotI", noSideEffect.} -proc `not` *(x: int64): int64 {.magic: "BitnotI", noSideEffect.} ## computes the `bitwise complement` of the integer `x`. +when defined(nimnomagic64): + proc `not` *(x: int64): int64 {.magic: "BitnotI", noSideEffect.} +else: + proc `not` *(x: int64): int64 {.magic: "BitnotI64", noSideEffect.} + proc `+` *(x, y: int): int {.magic: "AddI", noSideEffect.} proc `+` *(x, y: int8): int8 {.magic: "AddI", noSideEffect.} proc `+` *(x, y: int16): int16 {.magic: "AddI", noSideEffect.} proc `+` *(x, y: int32): int32 {.magic: "AddI", noSideEffect.} -proc `+` *(x, y: int64): int64 {.magic: "AddI", noSideEffect.} ## Binary `+` operator for an integer. +when defined(nimnomagic64): + proc `+` *(x, y: int64): int64 {.magic: "AddI", noSideEffect.} +else: + proc `+` *(x, y: int64): int64 {.magic: "AddI64", noSideEffect.} + proc `-` *(x, y: int): int {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int8): int8 {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int16): int16 {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int32): int32 {.magic: "SubI", noSideEffect.} -proc `-` *(x, y: int64): int64 {.magic: "SubI", noSideEffect.} ## Binary `-` operator for an integer. +when defined(nimnomagic64): + proc `-` *(x, y: int64): int64 {.magic: "SubI", noSideEffect.} +else: + proc `-` *(x, y: int64): int64 {.magic: "SubI64", noSideEffect.} + proc `*` *(x, y: int): int {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int8): int8 {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int16): int16 {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int32): int32 {.magic: "MulI", noSideEffect.} -proc `*` *(x, y: int64): int64 {.magic: "MulI", noSideEffect.} ## Binary `*` operator for an integer. +when defined(nimnomagic64): + proc `*` *(x, y: int64): int64 {.magic: "MulI", noSideEffect.} +else: + proc `*` *(x, y: int64): int64 {.magic: "MulI64", noSideEffect.} + proc `div` *(x, y: int): int {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int8): int8 {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int16): int16 {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int32): int32 {.magic: "DivI", noSideEffect.} -proc `div` *(x, y: int64): int64 {.magic: "DivI", noSideEffect.} ## computes the integer division. This is roughly the same as ## ``floor(x/y)``. ## @@ -714,14 +731,23 @@ proc `div` *(x, y: int64): int64 {.magic: "DivI", noSideEffect.} ## 2 div 2 == 1 ## 3 div 2 == 1 +when defined(nimnomagic64): + proc `div` *(x, y: int64): int64 {.magic: "DivI", noSideEffect.} +else: + proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.} + proc `mod` *(x, y: int): int {.magic: "ModI", noSideEffect.} proc `mod` *(x, y: int8): int8 {.magic: "ModI", noSideEffect.} proc `mod` *(x, y: int16): int16 {.magic: "ModI", noSideEffect.} proc `mod` *(x, y: int32): int32 {.magic: "ModI", noSideEffect.} -proc `mod` *(x, y: int64): int64 {.magic: "ModI", noSideEffect.} ## computes the integer modulo operation. This is the same as ## ``x - (x div y) * y``. +when defined(nimnomagic64): + proc `mod` *(x, y: int64): int64 {.magic: "ModI", noSideEffect.} +else: + proc `mod` *(x, y: int64): int64 {.magic: "ModI64", noSideEffect.} + proc `shr` *(x, y: int): int {.magic: "ShrI", noSideEffect.} proc `shr` *(x, y: int8): int8 {.magic: "ShrI", noSideEffect.} proc `shr` *(x, y: int16): int16 {.magic: "ShrI", noSideEffect.} @@ -1068,7 +1094,7 @@ proc compileOption*(option, arg: string): bool {. const hasThreadSupport = compileOption("threads") - hasSharedHeap = defined(boehmgc) # don't share heaps; every thread has its own + hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own taintMode = compileOption("taintmode") when taintMode: @@ -2304,11 +2330,18 @@ proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} = if x < 0: -x else: x proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} = if x < 0: -x else: x -proc abs*(x: int64): int64 {.magic: "AbsI", noSideEffect.} = - ## returns the absolute value of `x`. If `x` is ``low(x)`` (that - ## is -MININT for its type), an overflow exception is thrown (if overflow - ## checking is turned on). - if x < 0: -x else: x +when defined(nimnomagic64): + proc abs*(x: int64): int64 {.magic: "AbsI", noSideEffect.} = + ## returns the absolute value of `x`. If `x` is ``low(x)`` (that + ## is -MININT for its type), an overflow exception is thrown (if overflow + ## checking is turned on). + if x < 0: -x else: x +else: + proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} = + ## returns the absolute value of `x`. If `x` is ``low(x)`` (that + ## is -MININT for its type), an overflow exception is thrown (if overflow + ## checking is turned on). + if x < 0: -x else: x {.pop.} when not defined(JS): #and not defined(NimrodVM): @@ -2316,7 +2349,7 @@ when not defined(JS): #and not defined(NimrodVM): when not defined(NimrodVM) and hostOS != "standalone": proc initGC() - when not defined(boehmgc) and not defined(useMalloc): + when not defined(boehmgc) and not defined(useMalloc) and not defined(gogc): proc initAllocator() {.inline.} proc initStackBottom() {.inline, compilerproc.} = @@ -2651,8 +2684,10 @@ when not defined(JS): #and not defined(NimrodVM): when not defined(NimrodVM): include "system/sets" - const - GenericSeqSize = (2 * sizeof(int)) + when defined(gogc): + const GenericSeqSize = (3 * sizeof(int)) + else: + const GenericSeqSize = (2 * sizeof(int)) proc getDiscriminant(aa: pointer, n: ptr TNimNode): int = sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim index 907907e24..69c558799 100644 --- a/lib/system/arithm.nim +++ b/lib/system/arithm.nim @@ -18,7 +18,7 @@ proc raiseDivByZero {.compilerproc, noinline.} = sysFatal(DivByZeroError, "division by zero") when defined(builtinOverflow): -# Builtin compiler functions for improved performance + # Builtin compiler functions for improved performance when sizeof(clong) == 8: proc addInt64Overflow[T: int64|int](a, b: T, c: var T): bool {. importc: "__builtin_saddl_overflow", nodecl, nosideeffect.} diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index f082023ee..242f42c16 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -37,9 +37,7 @@ type var framePtr {.importc, nodecl, volatile.}: PCallFrame - excHandler {.importc, nodecl, volatile.}: PSafePoint = nil - # list of exception handlers - # a global variable for the root of all try blocks + excHandler {.importc, nodecl, volatile.}: int = 0 lastJSError {.importc, nodecl, volatile.}: PJSError = nil {.push stacktrace: off, profiler:off.} @@ -52,9 +50,7 @@ proc nimCharToStr(x: char): string {.compilerproc.} = result[0] = x proc getCurrentExceptionMsg*(): string = - if excHandler != nil and excHandler.exc != nil: - return $excHandler.exc.msg - elif lastJSError != nil: + if lastJSError != nil: return $lastJSError.message else: return "" @@ -99,32 +95,41 @@ proc rawWriteStackTrace(): string = else: result = "No stack traceback available\n" -proc raiseException(e: ref Exception, ename: cstring) {. +proc unhandledException(e: ref Exception) {. compilerproc, asmNoStackFrame.} = - e.name = ename - if excHandler != nil: - excHandler.exc = e + when NimStackTrace: + var buf = rawWriteStackTrace() else: - when NimStackTrace: - var buf = rawWriteStackTrace() - else: - var buf = "" + var buf = "" if e.msg != nil and e.msg[0] != '\0': add(buf, "Error: unhandled exception: ") add(buf, e.msg) else: add(buf, "Error: unhandled exception") add(buf, " [") - add(buf, ename) + add(buf, e.name) add(buf, "]\n") alert(buf) - asm """throw `e`;""" + +proc raiseException(e: ref Exception, ename: cstring) {. + compilerproc, asmNoStackFrame.} = + e.name = ename + when not defined(noUnhandledHandler): + if excHandler == 0: + unhandledException(e) + asm "throw `e`;" proc reraiseException() {.compilerproc, asmNoStackFrame.} = - if excHandler == nil: + if lastJSError == nil: raise newException(ReraiseError, "no exception to reraise") else: - asm """throw excHandler.exc;""" + when not defined(noUnhandledHandler): + if excHandler == 0: + var isNimException : bool + asm "`isNimException` = lastJSError.m_type;" + if isNimException: + unhandledException(cast[ref Exception](lastJSError)) + asm "throw lastJSError;" proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} = raise newException(OverflowError, "over- or underflow") @@ -170,12 +175,28 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} = proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = asm """ var len = `s`.length-1; - var result = new Array(len); + var asciiPart = new Array(len); var fcc = String.fromCharCode; + var nonAsciiPart = null; + var nonAsciiOffset = 0; for (var i = 0; i < len; ++i) { - result[i] = fcc(`s`[i]); + if (nonAsciiPart !== null) { + var offset = (i - nonAsciiOffset) * 2; + nonAsciiPart[offset] = "%"; + nonAsciiPart[offset + 1] = `s`[i].toString(16); + } + else if (`s`[i] < 128) + asciiPart[i] = fcc(`s`[i]); + else { + asciiPart.length = i; + nonAsciiOffset = i; + nonAsciiPart = new Array((len - i) * 2); + --i; + } } - return result.join(""); + asciiPart = asciiPart.join(""); + return (nonAsciiPart === null) ? + asciiPart : asciiPart + decodeURIComponent(nonAsciiPart.join("")); """ proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} = diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 86d834ceb..50f4cb4dc 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -# Nim high-level memory manager: It supports Boehm's GC, no GC and the +# Nim high-level memory manager: It supports Boehm's GC, Go's GC, no GC and the # native Nim GC. The native Nim GC is the default. #{.push checks:on, assertions:on.} @@ -195,6 +195,201 @@ when defined(boehmgc): proc deallocOsPages() {.inline.} = discard include "system/cellsets" + +elif defined(gogc): + when defined(windows): + const goLib = "libgo.dll" + elif defined(macosx): + const goLib = "libgo.dylib" + else: + const goLib = "libgo.so" + + proc `div`[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.} + proc `-`[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.} + + proc roundup(x, v: int): int {.inline.} = + result = (x + (v-1)) and not (v-1) + + proc initGC() = discard + # runtime_setgcpercent is only available in GCC 5 + proc GC_disable() = discard + proc GC_enable() = discard + proc goRuntimeGC(force: int32) {.importc: "runtime_gc", dynlib: goLib.} + proc GC_fullCollect() = goRuntimeGC(2) + proc GC_setStrategy(strategy: GC_Strategy) = discard + proc GC_enableMarkAndSweep() = discard + proc GC_disableMarkAndSweep() = discard + + const + goNumSizeClasses = 67 + + type + cbool {.importc: "_Bool", nodecl.} = bool + + goMStats_inner_struct = object + size: uint32 + nmalloc: uint64 + nfree: uint64 + + goMStats = object + # General statistics. + alloc: uint64 # bytes allocated and still in use + total_alloc: uint64 # bytes allocated (even if freed) + sys: uint64 # bytes obtained from system (should be sum of xxx_sys below, no locking, approximate) + nlookup: uint64 # number of pointer lookups + nmalloc: uint64 # number of mallocs + nfree: uint64 # number of frees + # Statistics about malloc heap. + # protected by mheap.Lock + heap_alloc: uint64 # bytes allocated and still in use + heap_sys: uint64 # bytes obtained from system + heap_idle: uint64 # bytes in idle spans + heap_inuse: uint64 # bytes in non-idle spans + heap_released: uint64 # bytes released to the OS + heap_objects: uint64 # total number of allocated objects + # Statistics about allocation of low-level fixed-size structures. + # Protected by FixAlloc locks. + stacks_inuse: uint64 # bootstrap stacks + stacks_sys: uint64 + mspan_inuse: uint64 # MSpan structures + mspan_sys: uint64 + mcache_inuse: uint64 # MCache structures + mcache_sys: uint64 + buckhash_sys: uint64 # profiling bucket hash table + gc_sys: uint64 + other_sys: uint64 + # Statistics about garbage collector. + # Protected by mheap or stopping the world during GC. + next_gc: uint64 # next GC (in heap_alloc time) + last_gc: uint64 # last GC (in absolute time) + pause_total_ns: uint64 + pause_ns: array[256, uint64] + numgc: uint32 + enablegc: cbool + debuggc: cbool + # Statistics about allocation size classes. + by_size: array[goNumSizeClasses, goMStats_inner_struct] + + proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl, importc: "runtime_ReadMemStats", codegenDecl: "$1 $2$3 __asm__ (\"runtime.ReadMemStats\");\n$1 $2$3", dynlib: goLib.} + + proc GC_getStatistics(): string = + var mstats: goMStats + goRuntime_ReadMemStats(addr mstats) + result = "[GC] total allocated memory: " & $(mstats.total_alloc) & "\n" & + "[GC] total memory obtained from system: " & $(mstats.sys) & "\n" & + "[GC] occupied memory: " & $(mstats.alloc) & "\n" & + "[GC] number of pointer lookups: " & $(mstats.nlookup) & "\n" & + "[GC] number of mallocs: " & $(mstats.nmalloc) & "\n" & + "[GC] number of frees: " & $(mstats.nfree) & "\n" & + "[GC] heap objects: " & $(mstats.heap_objects) & "\n" & + "[GC] numgc: " & $(mstats.numgc) & "\n" & + "[GC] enablegc: " & $(mstats.enablegc) & "\n" & + "[GC] debuggc: " & $(mstats.debuggc) & "\n" & + "[GC] total pause time [ms]: " & $(mstats.pause_total_ns div 1000_000) + + proc getOccupiedMem(): int = + var mstats: goMStats + goRuntime_ReadMemStats(addr mstats) + result = int(mstats.alloc) + + proc getFreeMem(): int = + var mstats: goMStats + goRuntime_ReadMemStats(addr mstats) + result = int(mstats.sys - mstats.alloc) + + proc getTotalMem(): int = + var mstats: goMStats + goRuntime_ReadMemStats(addr mstats) + result = int(mstats.sys) + + proc setStackBottom(theStackBottom: pointer) = discard + + proc alloc(size: Natural): pointer = + result = cmalloc(size) + if result == nil: raiseOutOfMem() + + proc alloc0(size: Natural): pointer = + result = alloc(size) + zeroMem(result, size) + + proc realloc(p: pointer, newsize: Natural): pointer = + result = crealloc(p, newsize) + if result == nil: raiseOutOfMem() + + proc dealloc(p: pointer) = cfree(p) + + proc allocShared(size: Natural): pointer = + result = cmalloc(size) + if result == nil: raiseOutOfMem() + + proc allocShared0(size: Natural): pointer = + result = alloc(size) + zeroMem(result, size) + + proc reallocShared(p: pointer, newsize: Natural): pointer = + result = crealloc(p, newsize) + if result == nil: raiseOutOfMem() + + proc deallocShared(p: pointer) = cfree(p) + + when hasThreadSupport: + proc getFreeSharedMem(): int = discard + proc getTotalSharedMem(): int = discard + proc getOccupiedSharedMem(): int = discard + + const goFlagNoZero: uint32 = 1 shl 3 + proc goRuntimeMallocGC(size: uint, typ: uint, flag: uint32): pointer {.importc: "runtime_mallocgc", dynlib: goLib.} + proc goFree(v: pointer) {.importc: "__go_free", dynlib: goLib.} + + proc goSetFinalizer(obj: pointer, f: pointer) {.importc: "set_finalizer", codegenDecl:"$1 $2$3 __asm__ (\"main.Set_finalizer\");\n$1 $2$3", dynlib: goLib.} + + proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = + result = goRuntimeMallocGC(roundup(size, sizeof(pointer)).uint, 0.uint, 0.uint32) + if typ.finalizer != nil: + goSetFinalizer(result, typ.finalizer) + + proc newObjNoInit(typ: PNimType, size: int): pointer = + result = goRuntimeMallocGC(roundup(size, sizeof(pointer)).uint, 0.uint, goFlagNoZero) + if typ.finalizer != nil: + goSetFinalizer(result, typ.finalizer) + + proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = + result = newObj(typ, len * typ.base.size + GenericSeqSize) + cast[PGenericSeq](result).len = len + cast[PGenericSeq](result).reserved = len + cast[PGenericSeq](result).elemSize = typ.base.size + + proc growObj(old: pointer, newsize: int): pointer = + # the Go GC doesn't have a realloc + var + oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize + result = goRuntimeMallocGC(roundup(newsize, sizeof(pointer)).uint, 0.uint, goFlagNoZero) + copyMem(result, old, oldsize) + zeroMem(cast[pointer](cast[ByteAddress](result) +% oldsize), newsize - oldsize) + goFree(old) + + proc nimGCref(p: pointer) {.compilerproc, inline.} = discard + proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard + + proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} = + dest[] = src + proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} = + dest[] = src + proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} = + dest[] = src + + type + MemRegion = object {.final, pure.} + {.deprecated: [TMemRegion: MemRegion].} + + proc alloc(r: var MemRegion, size: int): pointer = + result = alloc(size) + proc alloc0(r: var MemRegion, size: int): pointer = + result = alloc0(size) + proc dealloc(r: var MemRegion, p: pointer) = dealloc(p) + proc deallocOsPages(r: var MemRegion) {.inline.} = discard + proc deallocOsPages() {.inline.} = discard + elif defined(nogc) and defined(useMalloc): when not defined(useNimRtl): @@ -291,7 +486,6 @@ elif defined(nogc): proc GC_disableMarkAndSweep() = discard proc GC_getStatistics(): string = return "" - proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = result = alloc0(size) diff --git a/lib/system/repr.nim b/lib/system/repr.nim index f3b69954a..37056af3a 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -194,18 +194,24 @@ when not defined(useNimRtl): proc reprRecord(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure) = add result, "[" - let oldLen = result.len - reprRecordAux(result, p, typ.node, cl) - if typ.base != nil: - if oldLen != result.len: add result, ",\n" - reprRecordAux(result, p, typ.base.node, cl) + var curTyp = typ + var first = true + while curTyp.base != nil: + var part = "" + reprRecordAux(part, p, curTyp.node, cl) + if part.len > 0: + if not first: + add result, ",\n" + add result, part + first = false + curTyp = curTyp.base add result, "]" proc reprRef(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure) = # we know that p is not nil here: when declared(CellSet): - when defined(boehmGC) or defined(nogc): + when defined(boehmGC) or defined(gogc) or defined(nogc): var cell = cast[PCell](p) else: var cell = usrToCell(p) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 5b4020c8c..33629016f 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -50,12 +50,16 @@ proc rawNewStringNoInit(space: int): NimString {.compilerProc.} = if s < 7: s = 7 result = allocStrNoInit(sizeof(TGenericSeq) + s + 1) result.reserved = s + when defined(gogc): + result.elemSize = 1 proc rawNewString(space: int): NimString {.compilerProc.} = var s = space if s < 7: s = 7 result = allocStr(sizeof(TGenericSeq) + s + 1) result.reserved = s + when defined(gogc): + result.elemSize = 1 proc mnewString(len: int): NimString {.compilerProc.} = result = rawNewString(len) @@ -216,7 +220,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. elif newLen < result.len: # we need to decref here, otherwise the GC leaks! when not defined(boehmGC) and not defined(nogc) and - not defined(gcMarkAndSweep): + not defined(gcMarkAndSweep) and not defined(gogc): when compileOption("gc", "v2"): for i in newLen..result.len-1: let len0 = gch.tempStack.len diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 865271a50..d77059f68 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -237,7 +237,7 @@ when not defined(useNimRtl): echo "too large thread local storage size requested" quit 1 - when hasSharedHeap and not defined(boehmgc) and not defined(nogc): + when hasSharedHeap and not defined(boehmgc) and not defined(gogc) and not defined(nogc): var threadList: PGcThread @@ -287,7 +287,7 @@ type ## a pointer as a thread ID. {.deprecated: [TThread: Thread, TThreadId: ThreadId].} -when not defined(boehmgc) and not hasSharedHeap: +when not defined(boehmgc) and not hasSharedHeap and not defined(gogc): proc deallocOsPages() template threadProcWrapperBody(closure: expr) {.immediate.} = @@ -295,7 +295,7 @@ template threadProcWrapperBody(closure: expr) {.immediate.} = var t = cast[ptr Thread[TArg]](closure) when useStackMaskHack: var tls: ThreadLocalStorage - when not defined(boehmgc) and not defined(nogc) and not hasSharedHeap: + when not defined(boehmgc) and not defined(gogc) and not defined(nogc) and not hasSharedHeap: # init the GC for this thread: setStackBottom(addr(t)) initGC() diff --git a/readme.txt b/readme.txt index e3119f83d..595c70bf2 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -This package contains the Nim compiler, Nim's stdlib, tools and +This package contains the Nim compiler, Nim's stdlib, tools and documentation. Nim is a compiled, garbage-collected systems programming language which has @@ -7,12 +7,12 @@ efficiency, expressiveness, elegance (in the order of priority). Read install.txt for instructions of how to build and install it. -The compiler and the standard library are licensed under the MIT license, -except for some modules where the documentation suggests otherwise. This means -that you can use any license for your own programs developed with Nim, +The compiler and the standard library are licensed under the MIT license, +except for some modules where the documentation suggests otherwise. This means +that you can use any license for your own programs developed with Nim, allowing you to create commercial applications. Read copying.txt for more details. -Copyright (c) 2006-2014 Andreas Rumpf. +Copyright (c) 2006-2015 Andreas Rumpf. All rights reserved. diff --git a/tests/parallel/tptr_to_ref.nim b/tests/parallel/tptr_to_ref.nim index 66d618481..229c247ce 100644 --- a/tests/parallel/tptr_to_ref.nim +++ b/tests/parallel/tptr_to_ref.nim @@ -1,21 +1,26 @@ # bug #2854 +# Test case for the compiler correctly detecting if a type used by a shared +# global is gcsafe. + import locks, threadpool, osproc -const MAX_WORKERS = 10 +const MAX_WORKERS = 50 type - Killer = object - lock: Lock - bailed {.guard: lock.}: bool + Killer* = object + lock: Lock + bailed {.guard: lock.}: bool processes {.guard: lock.}: array[0..MAX_WORKERS-1, foreign ptr Process] +# Hold a lock for a statement. template hold(lock: Lock, body: stmt) = lock.acquire defer: lock.release {.locks: [lock].}: body +# Return an initialized Killer. proc initKiller*(): Killer = initLock(result.lock) result.lock.hold: @@ -23,4 +28,44 @@ proc initKiller*(): Killer = for i, _ in result.processes: result.processes[i] = nil +# Global Killer instance. var killer = initKiller() + +# remember that a process has been launched, killing it if we have bailed. +proc launched*(process: foreign ptr Process): int {.gcsafe.} = + result = killer.processes.high + 1 + killer.lock.hold: + if killer.bailed: + process[].terminate() + else: + for i, _ in killer.processes: + if killer.processes[i] == nil: + killer.processes[i] = process + result = i + assert(result <= killer.processes.high) + + +# A process has been finished with - remove the process from death row. +# Return true if the process was still present, which will be the +# case unless we have bailed. +proc completed*(index: int): bool {.gcsafe.} = + result = true + if index <= killer.processes.high: + killer.lock.hold: + result = false + if killer.processes[index] != nil: + result = true + killer.processes[index] = nil + + +# Terminate all the processes killer knows about, doing nothing if +# already bailed. +proc bail(): bool {.gcsafe.} = + killer.lock.hold: + result = not killer.bailed + if not killer.bailed: + killer.bailed = true + for i, process in killer.processes: + if process != nil: + process[].terminate + killer.processes[i] = nil diff --git a/tests/stdlib/nre/split.nim b/tests/stdlib/nre/split.nim index 8064e40b7..9d57ea7d8 100644 --- a/tests/stdlib/nre/split.nim +++ b/tests/stdlib/nre/split.nim @@ -8,6 +8,7 @@ suite "string splitting": check("1 2".split(re(" ")) == @["1", "2"]) check("foo".split(re("foo")) == @["", ""]) check("".split(re"foo") == @[""]) + check("9".split(re"\son\s") == @["9"]) test "captured patterns": check("12".split(re"(\d)") == @["", "1", "", "2", ""]) diff --git a/tests/typerel/tstr_as_openarray.nim b/tests/typerel/tstr_as_openarray.nim new file mode 100644 index 000000000..fc28d6c93 --- /dev/null +++ b/tests/typerel/tstr_as_openarray.nim @@ -0,0 +1,22 @@ +discard """ + output: '''success''' +""" +var s = "HI" + +proc x (zz: openarray[char]) = + discard + +x s + +proc z [T] (zz: openarray[T]) = + discard + +z s +z([s,s,s]) + +proc y [T] (arg: var openarray[T]) = + arg[0] = 'X' +y s +doAssert s == "XI" + +echo "success" diff --git a/tests/vm/tconsttable2.nim b/tests/vm/tconsttable2.nim new file mode 100644 index 000000000..e07734eb5 --- /dev/null +++ b/tests/vm/tconsttable2.nim @@ -0,0 +1,81 @@ +discard """ + msg: '''61''' +""" + +# bug #2297 + +import tables + +proc html5tags*(): TableRef[string, string] = + var html5tagsCache: Table[string,string] + if true: + new(result) + html5tagsCache = initTable[string, string]() + html5tagsCache["a"] = "a" + html5tagsCache["abbr"] = "abbr" + html5tagsCache["b"] = "b" + html5tagsCache["element"] = "element" + html5tagsCache["embed"] = "embed" + html5tagsCache["fieldset"] = "fieldset" + html5tagsCache["figcaption"] = "figcaption" + html5tagsCache["figure"] = "figure" + html5tagsCache["footer"] = "footer" + html5tagsCache["header"] = "header" + html5tagsCache["form"] = "form" + html5tagsCache["head"] = "head" + html5tagsCache["hr"] = "hr" + html5tagsCache["html"] = "html" + html5tagsCache["iframe"] = "iframe" + html5tagsCache["img"] = "img" + html5tagsCache["input"] = "input" + html5tagsCache["keygen"] = "keygen" + html5tagsCache["label"] = "label" + html5tagsCache["legend"] = "legend" + html5tagsCache["li"] = "li" + html5tagsCache["link"] = "link" + html5tagsCache["main"] = "main" + html5tagsCache["map"] = "map" + html5tagsCache["menu"] = "menu" + html5tagsCache["menuitem"] = "menuitem" + html5tagsCache["meta"] = "meta" + html5tagsCache["meter"] = "master" + html5tagsCache["noscript"] = "noscript" + html5tagsCache["object"] = "object" + html5tagsCache["ol"] = "ol" + html5tagsCache["optgroup"] = "optgroup" + html5tagsCache["option"] = "option" + html5tagsCache["output"] = "output" + html5tagsCache["p"] = "p" + html5tagsCache["pre"] = "pre" + html5tagsCache["param"] = "param" + html5tagsCache["progress"] = "progress" + html5tagsCache["q"] = "q" + html5tagsCache["rp"] = "rp" + html5tagsCache["rt"] = "rt" + html5tagsCache["ruby"] = "ruby" + html5tagsCache["s"] = "s" + html5tagsCache["script"] = "script" + html5tagsCache["select"] = "select" + html5tagsCache["source"] = "source" + html5tagsCache["style"] = "style" + html5tagsCache["summary"] = "summary" + html5tagsCache["table"] = "table" + html5tagsCache["tbody"] = "tbody" + html5tagsCache["thead"] = "thead" + html5tagsCache["td"] = "td" + html5tagsCache["th"] = "th" + html5tagsCache["template"] = "template" + html5tagsCache["textarea"] = "textarea" + html5tagsCache["time"] = "time" + html5tagsCache["title"] = "title" + html5tagsCache["tr"] = "tr" + html5tagsCache["track"] = "track" + html5tagsCache["ul"] = "ul" + html5tagsCache["video"] = "video" + result[] = html5tagsCache + +static: + var i = 0 + for key, value in html5tags().pairs(): + inc i + echo i diff --git a/tests/vm/tswap.nim b/tests/vm/tswap.nim new file mode 100644 index 000000000..2219be9ca --- /dev/null +++ b/tests/vm/tswap.nim @@ -0,0 +1,24 @@ +discard """ +msg: ''' +x.data = @[10] +y = @[11] +x.data = @[11] +y = @[10]''' +""" + +# bug #2946 + +proc testSwap(): int {.compiletime.} = + type T = object + data: seq[int] + var x: T + x.data = @[10] + var y = @[11] + echo "x.data = ", x.data + echo "y = ", y + swap(y, x.data) + echo "x.data = ", x.data + echo "y = ", y + result = 99 + +const something = testSwap() diff --git a/tools/niminst/buildbat.tmpl b/tools/niminst/buildbat.tmpl index 3a11715bf..2c6a2b5a8 100644 --- a/tools/niminst/buildbat.tmpl +++ b/tools/niminst/buildbat.tmpl @@ -18,13 +18,13 @@ REM call the compiler: # for ff in items(c.cfiles[winIndex][cpuIndex]): # let f = ff.toWin ECHO %CC% %COMP_FLAGS% -Ic_code -c ?{f} -o ?{changeFileExt(f, "o")} -%CC% %COMP_FLAGS% -Ic_code -c ?{f} -o ?{changeFileExt(f, "o")} +CALL %CC% %COMP_FLAGS% -Ic_code -c ?{f} -o ?{changeFileExt(f, "o")} # linkCmd.add(" " & changeFileExt(f, "o")) IF ERRORLEVEL 1 (GOTO:END) # end for ECHO %LINKER% -o ?{"%BIN_DIR%"\toLower(c.name)}.exe ?linkCmd %LINK_FLAGS% -%LINKER% -o ?{"%BIN_DIR%"\toLower(c.name)}.exe ?linkCmd %LINK_FLAGS% +CALL %LINKER% -o ?{"%BIN_DIR%"\toLower(c.name)}.exe ?linkCmd %LINK_FLAGS% # end block diff --git a/web/community.txt b/web/community.txt index 5d9343c98..1348f7bec 100644 --- a/web/community.txt +++ b/web/community.txt @@ -6,7 +6,7 @@ Nim's Community Forum ----- - The `Nim forum <http://forum.nim-lang.org/>`_ is the place where most + The `Nim forum <http://forum.nim-lang.org/>`_ is the place where most discussions related to the language happen. It not only includes discussions relating to the design of Nim but also allows for beginners to ask questions relating to Nim. @@ -44,14 +44,14 @@ Nim's Community Github ------ - Nim's `source code <http://github.com/Araq/Nim>`_ is hosted on Github. - Together with the `wiki <http://github.com/Araq/Nim/wiki>`_ and - `issue tracker <http://github.com/Araq/Nim/issues>`_. + Nim's `source code <http://github.com/nim-lang/Nim>`_ is hosted on Github. + Together with the `wiki <http://github.com/nim-lang/Nim/wiki>`_ and + `issue tracker <http://github.com/nim-lang/Nim/issues>`_. Github also hosts other projects relating to Nim. These projects are a part of the `nim-lang organisation <http://github.com/nim-lang>`_. This includes the `Nimble package manager <https://github.com/nim-lang/nimble>`_ - and its `package repository <http://github.com/nim-lang/packages>`_. + and its `package repository <http://github.com/nim-lang/packages>`_. .. container:: standout @@ -76,8 +76,15 @@ Nim's Community ------------- When asking a question relating to Nim, be sure to use the - `Nim <http://stackoverflow.com/questions/tagged/nim>`_ tag in your + `Nim <http://stackoverflow.com/questions/tagged/nim>`_ tag in your question. + +.. container:: standout + + Google+ + ------- + + The `G+ Nim community <https://plus.google.com/u/0/communities/106921341535068810587>`_ is another place where discussions related to the language happen. Read and follow various articles, posts and interesting links about Nim. .. container:: standout @@ -85,8 +92,8 @@ Nim's Community ----------- There are always many things to be done in the main - `Nim repository <https://github.com/Araq/Nim>`_, check out the - `issues <https://github.com/Araq/Nim/issues>`_ for + `Nim repository <https://github.com/nim-lang/Nim>`_, check out the + `issues <https://github.com/nim-lang/Nim/issues>`_ for things to do; pull requests are always welcome. You can also contribute to the many other projects hosted by the `nim-lang <https://github.com/nim-lang>`_ organisation on github. If you @@ -107,7 +114,7 @@ Nim's Community .. raw:: html <iframe style="border: 0; margin: 0; padding: 0;" - src="https://www.gittip.com/Araq/widget.html" + src="https://www.gittip.com/nim-lang/widget.html" width="64pt" height="22pt"></iframe> Paypal diff --git a/web/download.txt b/web/download.txt index 6acc80b53..c193637b7 100644 --- a/web/download.txt +++ b/web/download.txt @@ -44,7 +44,7 @@ Installation from github Use the following commands to build the compiler from source. Change the branch to suit your needs:: - git clone -b master git://github.com/Araq/Nim.git + git clone -b master git://github.com/nim-lang/Nim.git cd Nim git clone -b master --depth 1 git://github.com/nim-lang/csources cd csources && sh build.sh diff --git a/web/index.txt b/web/index.txt index 95cac9316..506453423 100644 --- a/web/index.txt +++ b/web/index.txt @@ -85,5 +85,5 @@ Roadmap to 1.0 ============== Please have a look at -this `wiki page <https://github.com/Araq/Nim/wiki/Roadmap>`_ for +this `wiki page <https://github.com/nim-lang/Nim/wiki/Roadmap>`_ for an up-to-date overview. diff --git a/web/learn.txt b/web/learn.txt index bf0cc43ef..e1a3f1c8c 100644 --- a/web/learn.txt +++ b/web/learn.txt @@ -28,7 +28,7 @@ Learning Nim - | `Nim on Rosetta Code <http://rosettacode.org/wiki/Category:Nimrod>`_ | Many different Nim code examples comparable to other languages for reference. - - | `Nim for C/C++ Programmers <https://github.com/Araq/Nim/wiki/Nim-for-C-programmers>`_ + - | `Nim for C/C++ Programmers <https://github.com/nim-lang/Nim/wiki/Nim-for-C-programmers>`_ | A useful cheat-sheet for those most familiar with C/C++ languages. diff --git a/web/news.txt b/web/news.txt index 49b49a9f1..bf21dff8d 100644 --- a/web/news.txt +++ b/web/news.txt @@ -3,7 +3,7 @@ News ==== .. - 2015-05-05 Version 0.11.2 released + 2015-05-05 Version 0.11.4 released ================================== Changes affecting backwards compatibility @@ -17,6 +17,11 @@ News their arguments just like ``echo`` does. Affected functions: ``log``, ``debug``, ``info``, ``warn``, ``error``, ``fatal``. Custom subtypes of ``Logger`` also need to be adjusted accordingly. + - Floating point numbers can now look like ``2d`` (float64) + and ``2f`` (float32) which means imports like ``import scene/2d/sprite`` + do not work anymore. Instead quotes have to be + used: ``import "scene/2d/sprite"``. The former code never was valid Nim. + Library additions ----------------- |