diff options
64 files changed, 1091 insertions, 398 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 64b59a283..d85dbf42c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1517,8 +1517,8 @@ proc getStr*(a: PNode): string = proc getStrOrChar*(a: PNode): string = case a.kind of nkStrLit..nkTripleStrLit: result = a.strVal - of nkCharLit: result = $chr(int(a.intVal)) - else: + of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal)) + else: internalError(a.info, "getStrOrChar") result = "" @@ -1560,3 +1560,9 @@ proc isEmptyType*(t: PType): bool {.inline.} = ## 'void' and 'stmt' types are often equivalent to 'nil' these days: result = t == nil or t.kind in {tyEmpty, tyStmt} +proc makeStmtList*(n: PNode): PNode = + if n.kind == nkStmtList: + result = n + else: + result = newNodeI(nkStmtList, n.info) + result.add n diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index e5848f558..6c7d40d1c 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -798,7 +798,9 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = startBlock(p) var finallyBlock = t.lastSon if finallyBlock.kind == nkFinally: - expr(p, finallyBlock.sons[0], d) + #expr(p, finallyBlock.sons[0], d) + genStmts(p, finallyBlock.sons[0]) + line(p, cpsStmts, ~"throw;$n") endBlock(p) @@ -807,7 +809,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = discard pop(p.nestedTryStmts) if (i < length) and (t.sons[i].kind == nkFinally): - exprBlock(p, t.sons[i].sons[0], d) + genSimpleBlock(p, t.sons[i].sons[0]) proc genTry(p: BProc, t: PNode, d: var TLoc) = # code to generate: @@ -899,7 +901,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = endBlock(p) # end of else block if i < length and t.sons[i].kind == nkFinally: p.finallySafePoints.add(safePoint) - exprBlock(p, t.sons[i].sons[0], d) + genSimpleBlock(p, t.sons[i].sons[0]) discard pop(p.finallySafePoints) linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index c838aa90b..a3423b1d5 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -601,15 +601,13 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = if p.target == targetJS: app(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl) if i < length and n.sons[i].kind == nkFinally: - gen(p, n.sons[i].sons[0], a) - moveInto(p, a, r) + genStmt(p, n.sons[i].sons[0]) if p.target == targetJS: app(p.body, "}" & tnl) if p.target == targetLua: # we need to repeat the finally block for Lua ... if i < length and n.sons[i].kind == nkFinally: - gen(p, n.sons[i].sons[0], a) - moveInto(p, a, r) + genStmt(p, n.sons[i].sons[0]) proc genRaiseStmt(p: PProc, n: PNode) = genLineDir(p, n) diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim index 7b42537c4..918f58e3d 100644 --- a/compiler/nimfix/nimfix.nim +++ b/compiler/nimfix/nimfix.nim @@ -26,12 +26,13 @@ Options: --styleCheck:on|off|auto performs style checking for identifiers and suggests an alternative spelling; 'auto' corrects the spelling. + --bestEffort try to fix the code even when there + are errors. In addition, all command line options of Nim are supported. """ proc mainCommand = - #msgs.gErrorMax = high(int) # do not stop after first error registerPass verbosePass registerPass semPass gCmd = cmdPretty @@ -63,13 +64,14 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = of "on": gCheckExtern = true of "off": gCheckExtern = false else: localError(gCmdLineInfo, errOnOrOffExpected) - of "stylecheck": + of "stylecheck": case p.val.normalize of "off": gStyleCheck = StyleCheck.None of "on": gStyleCheck = StyleCheck.Warn of "auto": gStyleCheck = StyleCheck.Auto else: localError(gCmdLineInfo, errOnOrOffExpected) of "wholeproject": gOnlyMainfile = false + of "besteffort": msgs.gErrorMax = high(int) # dont stop after first error else: processSwitch(pass, p) of cmdArgument: diff --git a/compiler/parser.nim b/compiler/parser.nim index a91760e15..fab3c453b 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -505,7 +505,7 @@ proc parsePar(p: var TParser): PNode = getTok(p) optInd(p, result) if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase, - tkTry, tkFinally, tkExcept, tkFor, tkBlock, + tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock, tkConst, tkLet, tkWhen, tkVar, tkMixin}: # XXX 'bind' used to be an expression, so we exclude it here; @@ -894,7 +894,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode = var a: PNode result = newNodeP(nkFormalParams, p) addSon(result, ast.emptyNode) # return type - if p.tok.tokType == tkParLe and p.tok.indent < 0: + let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0 + if hasParLe: getTok(p) optInd(p, result) while true: @@ -918,6 +919,9 @@ proc parseParamList(p: var TParser, retColon = true): PNode = getTok(p) optInd(p, result) result.sons[0] = parseTypeDesc(p) + elif not retColon and not hasParle: + # Mark as "not there" in order to mark for deprecation in the semantic pass: + result = ast.emptyNode proc optPragmas(p: var TParser): PNode = if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)): @@ -1130,7 +1134,7 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode = skipComment(p, result) if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}: let body = parseStmt(p) - addSon(result, newProcNode(nkDo, body.info, body)) + addSon(result, makeStmtList(body)) while sameInd(p): var b: PNode case p.tok.tokType @@ -1980,15 +1984,17 @@ proc parseTopLevelStmt(p: var TParser): PNode = ## top-level statement or emptyNode if end of stream. result = ast.emptyNode while true: - if p.tok.indent != 0: + if p.tok.indent != 0: if p.firstTok and p.tok.indent < 0: discard - else: parMessage(p, errInvalidIndentation) + elif p.tok.tokType != tkSemiColon: + parMessage(p, errInvalidIndentation) p.firstTok = false case p.tok.tokType of tkSemiColon: getTok(p) if p.tok.indent <= 0: discard else: parMessage(p, errInvalidIndentation) + p.firstTok = true of tkEof: break else: result = complexOrSimpleStmt(p) diff --git a/compiler/sem.nim b/compiler/sem.nim index 5160af20a..9ac7ad139 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -41,7 +41,6 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind) proc maybeAddResult(c: PContext, s: PSym, n: PNode) proc instGenericContainer(c: PContext, n: PNode, header: PType): PType proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode -proc fixImmediateParams(n: PNode): PNode proc activate(c: PContext, n: PNode) proc semQuoteAst(c: PContext, n: PNode): PNode proc finishMethod(c: PContext, s: PSym) @@ -68,12 +67,25 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode = # error correction: result = copyTree(arg) result.typ = formal + else: + let x = result.skipConv + if x.kind == nkPar and formal.kind != tyExpr: + changeType(x, formal, check=true) proc inferWithMetatype(c: PContext, formal: PType, arg: PNode, coerceDistincts = false): PNode var commonTypeBegin = PType(kind: tyExpr) +proc isEmptyContainer(t: PType): bool = + case t.kind + of tyExpr, tyNil: result = true + of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty + of tySet, tySequence, tyOpenArray, tyVarargs: + result = t.sons[0].kind == tyEmpty + of tyGenericInst: result = isEmptyContainer(t.lastSon) + else: result = false + proc commonType*(x, y: PType): PType = # new type relation that is used for array constructors, # if expressions, etc.: @@ -97,6 +109,13 @@ proc commonType*(x, y: PType): PType = # check for seq[empty] vs. seq[int] let idx = ord(b.kind in {tyArray, tyArrayConstr}) if a.sons[idx].kind == tyEmpty: return y + elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len: + var nt: PType + for i in 0.. <a.len: + if isEmptyContainer(a.sons[i]) and not isEmptyContainer(b.sons[i]): + if nt.isNil: nt = copyType(a, a.owner, false) + nt.sons[i] = b.sons[i] + if not nt.isNil: result = nt #elif b.sons[idx].kind == tyEmpty: return x elif a.kind == tyRange and b.kind == tyRange: # consider: (range[0..3], range[0..4]) here. We should make that diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index fc217262e..ee3391e3e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -429,7 +429,8 @@ proc changeType(n: PNode, newType: PType, check: bool) = for i in countup(0, sonsLen(n) - 1): changeType(n.sons[i], elemType(newType), check) of nkPar: - if newType.kind != tyTuple: + let tup = newType.skipTypes({tyGenericInst}) + if tup.kind != tyTuple: internalError(n.info, "changeType: no tuple type for constructor") else: for i in countup(0, sonsLen(n) - 1): @@ -437,7 +438,7 @@ proc changeType(n: PNode, newType: PType, check: bool) = if m.kind == nkExprColonExpr: m = m.sons[1] n.sons[i] = m - changeType(m, newType.sons[i], check) + changeType(m, tup.sons[i], check) of nkCharLit..nkUInt64Lit: if check: let value = n.intVal @@ -926,17 +927,18 @@ proc readTypeParameter(c: PContext, typ: PType, paramName: PIdent, info: TLineInfo): PNode = let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias else: (internalAssert(typ.kind == tyCompositeTypeClass); typ.sons[1]) - + #debug ty let tbody = ty.sons[0] for s in countup(0, tbody.len-2): let tParam = tbody.sons[s] - if tParam.sym.name == paramName: + if tParam.sym.name.id == paramName.id: let rawTyp = ty.sons[s + 1] if rawTyp.kind == tyStatic: return rawTyp.n else: let foundTyp = makeTypeDesc(c, rawTyp) return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) + #echo "came here: returned nil" proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if it's not a built-in field access @@ -971,7 +973,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # look up if the identifier belongs to the enum: while ty != nil: f = getSymFromList(ty.n, i) - if f != nil: break + if f != nil: break ty = ty.sons[0] # enum inheritance if f != nil: result = newSymNode(f) @@ -1505,11 +1507,11 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode if ids.len > 0: - doBlk[paramsPos].sons.setLen(2) - doBlk[paramsPos].sons[0] = getSysSym("stmt").newSymNode # return type + doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info) + doBlk[paramsPos].add getSysSym("stmt").newSymNode # return type ids.add getSysSym("expr").newSymNode # params type ids.add emptyNode # no default value - doBlk[paramsPos].sons[1] = newNode(nkIdentDefs, n.info, ids) + doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids) var tmpl = semTemplateDef(c, doBlk) quotes[0] = tmpl[namePos] @@ -1892,19 +1894,6 @@ proc semBlock(c: PContext, n: PNode): PNode = closeScope(c) dec(c.p.nestedBlockCounter) -proc doBlockIsStmtList(n: PNode): bool = - result = n.kind == nkDo and - n[paramsPos].sonsLen == 1 and - n[paramsPos][0].kind == nkEmpty - -proc fixImmediateParams(n: PNode): PNode = - # XXX: Temporary work-around until we carry out - # the planned overload resolution reforms - for i in 1 .. <safeLen(n): - if doBlockIsStmtList(n[i]): - n.sons[i] = n[i][bodyPos] - result = n - proc semExport(c: PContext, n: PNode): PNode = var x = newNodeI(n.kind, n.info) #let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len @@ -2022,14 +2011,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if sfImmediate notin s.flags: result = semDirectOp(c, n, flags) else: - var p = fixImmediateParams(n) - result = semMacroExpr(c, p, p, s, flags) + result = semMacroExpr(c, n, n, s, flags) of skTemplate: if sfImmediate notin s.flags: result = semDirectOp(c, n, flags) else: - var p = fixImmediateParams(n) - result = semTemplateExpr(c, p, s, flags) + result = semTemplateExpr(c, n, s, flags) of skType: # XXX think about this more (``set`` procs) if n.len == 2: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 723789a31..7c32b0051 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -48,7 +48,6 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, of skTemplate: if macroToExpand(s): styleCheckUse(n.info, s) - let n = fixImmediateParams(n) result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) else: @@ -185,7 +184,6 @@ proc semGenericStmt(c: PContext, n: PNode, of skTemplate: if macroToExpand(s): styleCheckUse(fn.info, s) - let n = fixImmediateParams(n) result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) else: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 646775aae..a7603147c 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -263,7 +263,8 @@ proc semTry(c: PContext, n: PNode): PNode = n.sons[0] = semExprBranchScope(c, n.sons[0]) typ = commonType(typ, n.sons[0].typ) var check = initIntSet() - for i in countup(1, sonsLen(n) - 1): + var last = sonsLen(n) - 1 + for i in countup(1, last): var a = n.sons[i] checkMinSonsLen(a, 1) var length = sonsLen(a) @@ -282,11 +283,12 @@ proc semTry(c: PContext, n: PNode): PNode = a.sons[j].typ = typ if containsOrIncl(check, typ.id): localError(a.sons[j].info, errExceptionAlreadyHandled) - elif a.kind != nkFinally: + elif a.kind != nkFinally: illFormedAst(n) # last child of an nkExcept/nkFinally branch is a statement: a.sons[length-1] = semExprBranchScope(c, a.sons[length-1]) - typ = commonType(typ, a.sons[length-1].typ) + if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ) + else: dec last dec c.p.inTryStmt if isEmptyType(typ) or typ.kind == tyNil: discardCheck(c, n.sons[0]) @@ -294,13 +296,14 @@ proc semTry(c: PContext, n: PNode): PNode = if typ == enforceVoidContext: result.typ = enforceVoidContext else: + if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon) n.sons[0] = fitNode(c, typ, n.sons[0]) - for i in 1..n.len-1: + for i in 1..last: var it = n.sons[i] let j = it.len-1 it.sons[j] = fitNode(c, typ, it.sons[j]) result.typ = typ - + proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = result = fitNode(c, typ, n) if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: @@ -773,7 +776,7 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode = if it.kind == nkExprColonExpr: # pass pragma argument to the macro too: x.add(it.sons[1]) - x.add(newProcNode(nkDo, prc.info, prc)) + x.add(prc) # recursion assures that this works for multiple macro annotations too: return semStmt(c, x) @@ -801,6 +804,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = gp = newNodeI(nkGenericParams, n.info) if n.sons[paramsPos].kind != nkEmpty: + #if n.kind == nkDo and not experimentalMode(c): + # localError(n.sons[paramsPos].info, + # "use the {.experimental.} pragma to enable 'do' with parameters") semParamList(c, n.sons[paramsPos], gp, s) # paramsTypeCheck(c, s.typ) if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty: @@ -1251,6 +1257,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = tryStmt.addSon(deferPart) n.sons[i] = semTry(c, tryStmt) n.sons.setLen(i+1) + n.typ = n.sons[i].typ return else: n.sons[i] = semExpr(c, n.sons[i]) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index ba493bdfa..06f9d58b7 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1083,6 +1083,11 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, arg: PNode): PNode = # arg.typ can be nil in 'suggest': if isNil(arg.typ): return nil + + # sem'checking for 'echo' needs to be re-entrant: + # XXX we will revisit this issue after 0.10.2 is released + if f == arg.typ and arg.kind == nkHiddenStdConv: return arg + var call = newNodeI(nkCall, arg.info) call.add(f.n.copyTree) call.add(arg.copyTree) @@ -1153,8 +1158,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, of isEqual: inc(m.exactMatches) of isNone: discard - if f.kind == tyStmt and argOrig.kind == nkDo: - return argOrig[bodyPos] + if f.kind == tyStmt: + return arg elif f.kind == tyTypeDesc: return arg elif f.kind == tyStatic: diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index c06606318..3d49cb130 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -164,7 +164,8 @@ type slotTempInt, # some temporary int slotTempFloat, # some temporary float slotTempStr, # some temporary string - slotTempComplex # some complex temporary (s.node field is used) + slotTempComplex, # some complex temporary (s.node field is used) + slotTempPerm # slot is temporary but permanent (hack) PProc* = ref object blocks*: seq[TBlock] # blocks; temp data structure diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 7397a562c..9a3fc260a 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -16,7 +16,7 @@ # types that use the 'node' field; the reason is that slots are # re-used in a register based VM. Example: # -# .. code-block:: nimrod +# .. code-block:: nim # let s = a & b # no matter what, create fresh node # s = a & b # no matter what, keep the node # @@ -28,7 +28,7 @@ # this copy depends on the involved types. import - unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef, + unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef, trees, intsets, rodread, magicsys, options, lowerings from os import splitFile @@ -58,6 +58,7 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) = if i in jumpTargets: result.addf("L$1:\n", i) let x = c.code[i] + result.add($i) let opc = opcode(x) if opc in {opcConv, opcCast}: let y = c.code[i+1] @@ -188,7 +189,7 @@ proc getTemp(c: PCtx; typ: PType): TRegister = proc freeTemp(c: PCtx; r: TRegister) = let c = c.prc - if c.slots[r].kind >= slotSomeTemp: c.slots[r].inUse = false + if c.slots[r].kind in {slotSomeTemp..slotTempComplex}: c.slots[r].inUse = false proc getTempRange(c: PCtx; n: int; kind: TSlotKind): TRegister = # if register pressure is high, we re-use more aggressively: @@ -463,7 +464,7 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) = # from the stack c.gABx(fin, opcFinally, 0, 0) if fin.kind == nkFinally: - c.gen(fin.sons[0], dest) + c.gen(fin.sons[0]) c.clearDest(n, dest) c.gABx(fin, opcFinallyEnd, 0, 0) @@ -1074,8 +1075,10 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; c.gABC(n, opcNodeToReg, dest, dest) elif c.prc.slots[tmp].kind >= slotTempUnknown: gABC(c, n, opcAddrNode, dest, tmp) - # XXX this can still be wrong sometimes; hopefully it's only generated - # in call contexts, where it is safe + # hack ahead; in order to fix bug #1781 we mark the temporary as + # permanent, so that it's not used for anything else: + c.prc.slots[tmp].kind = slotTempPerm + # XXX this is still a hack #message(n.info, warnUser, "suspicious opcode used") else: gABC(c, n, opcAddrReg, dest, tmp) diff --git a/copying.txt b/copying.txt index 254b91c77..908625e18 100644 --- a/copying.txt +++ b/copying.txt @@ -1,5 +1,5 @@ ===================================================== -Nimrod -- a Compiler for Nimrod. http://nimrod-lang.org/ +Nim -- a Compiler for Nim. http://nim-lang.org/ Copyright (C) 2006-2014 Andreas Rumpf. All rights reserved. diff --git a/doc/lib.txt b/doc/lib.txt index aba05c2ba..45d9dfd2a 100644 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -18,7 +18,7 @@ low-level interface to a C library. Read this `document <apis.html>`_ for a quick overview of the API design. -The `bottom <#babel>`_ of this page includes a list of 3rd party packages +The `bottom <#nimble>`_ of this page includes a list of 3rd party packages created by the Nim community. These packages are a useful addition to the modules in the standard library. @@ -154,8 +154,8 @@ Generic Operating System Services * `streams <streams.html>`_ This module provides a stream interface and two implementations thereof: - the `PFileStream` and the `PStringStream` which implement the stream - interface for Nim file objects (`TFile`) and strings. Other modules + the `FileStream` and the `StringStream` which implement the stream + interface for Nim file objects (`File`) and strings. Other modules may provide other implementations for this standard stream interface. * `marshal <marshal.html>`_ @@ -581,12 +581,12 @@ Scientific computing * `libsvm <libsvm.html>`_ Low level wrapper for `lib svm <http://www.csie.ntu.edu.tw/~cjlin/libsvm/>`_. -Babel +Nimble ==================== -Babel is a package manager for the Nim programming language. -For instructions on how to install Babel packages see -`its README <https://github.com/nim-code/babel#readme>`_. +Nimble is a package manager for the Nim programming language. +For instructions on how to install Nimble packages see +`its README <https://github.com/nim-lang/babel#readme>`_. Official packages ----------------- @@ -598,7 +598,7 @@ compiler. .. raw:: html <div id="officialPkgList"><b>If you are reading this you are missing - babelpkglist.js or have javascript disabled in your browser.</b></div> + nimblepkglist.js or have javascript disabled in your browser.</b></div> Unofficial packages ------------------- @@ -610,7 +610,7 @@ Nim programming language. .. raw:: html <div id="unofficialPkgList"><b>If you are reading this you are missing - babelpkglist.js or have javascript disabled in your browser.</b></div> + nimblepkglist.js or have javascript disabled in your browser.</b></div> - <script type="text/javascript" src="babelpkglist.js"></script> - <script type="text/javascript" src="http://build.nim-lang.org/packages?callback=gotPackageList"></script> + <script type="text/javascript" src="nimblepkglist.js"></script> + <script type="text/javascript" src="http://irclogs.nim-lang.org/packages?callback=gotPackageList"></script> diff --git a/doc/manual/exceptions.txt b/doc/manual/exceptions.txt index 7cad1c2b4..e40742e0a 100644 --- a/doc/manual/exceptions.txt +++ b/doc/manual/exceptions.txt @@ -47,36 +47,52 @@ the rest of the procedure - that is not within a ``finally`` clause - is not executed (if an exception occurs). -Standalone except and finally statements ----------------------------------------- +Try expression +-------------- -``except`` and ``finally`` can also be used as a stand-alone statements. -Any statements following them in the current block will be considered to be -in an implicit try block: +Try can also be used as an expression; the type of the ``try`` branch then +needs to fit the types of ``except`` branches, but the type of the ``finally`` +branch always has to be ``void``: + +.. code-block:: nim + let x = try: parseInt("133a") + except: -1 + finally: echo "hi" + + +To prevent confusing code there is a parsing limitation; if the ``try`` +follows a ``(`` it has to be written as a one liner: + +.. code-block:: nim + let x = (try: parseInt("133a") except: -1) + + + +Defer statement +--------------- + +Instead of a ``try finally`` statement a ``defer`` statement can be used. + +Any statements following the ``defer`` in the current block will be considered +to be in an implicit try block: .. code-block:: nim var f = open("numbers.txt") - finally: close(f) - ... + defer: close(f) + f.write "abc" + f.write "def" -The ``except`` statement has a limitation in this form: one can't specify the -type of the exception, one has to catch everything. Also, if one wants to use -both ``finally`` and ``except`` one needs to reverse the usual sequence of the -statements. Example: +Is rewritten to: .. code-block:: nim - proc test() = - raise newException(Exception, "Hey ho") - - proc tester() = - finally: echo "3. Finally block" - except: echo "2. Except block" - echo "1. Pre exception" - test() - echo "4. Post exception" - # --> 1, 2, 3 is printed, 4 is never reached - -Top level standalone ``finally`` or ``except`` statements are not supported + var f = open("numbers.txt") + try: + f.write "abc" + f.write "def" + finally: + close(f) + +Top level ``defer`` statements are not supported since it's unclear what such a statement should refer to. diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt index 156e96f1b..2ebbe494d 100644 --- a/doc/manual/procs.txt +++ b/doc/manual/procs.txt @@ -200,6 +200,8 @@ executable code. Do notation ----------- +**Note:** The future of the ``do`` notation is uncertain. + As a special more convenient notation, proc expressions involved in procedure calls can use the ``do`` keyword: @@ -224,11 +226,6 @@ More than one ``do`` block can appear in a single call: do: # code to undo it -For compatibility with ``stmt`` templates and macros, the ``do`` keyword can be -omitted if the supplied proc doesn't have any parameters and return value. -The compatibility works in the other direction too as the ``do`` syntax can be -used with macros and templates expecting ``stmt`` blocks. - Nonoverloadable builtins ------------------------ diff --git a/lib/core/macros.nim b/lib/core/macros.nim index ed5d3c50c..353254d49 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -649,6 +649,8 @@ proc `$`*(node: PNimrodNode): string {.compileTime.} = result = $node.basename.ident & "*" of nnkStrLit..nnkTripleStrLit: result = node.strVal + of nnkSym: + result = $node.symbol else: badNodeKind node.kind, "$" diff --git a/lib/impure/osinfo_posix.nim b/lib/impure/osinfo_posix.nim index 1baff8c55..0ed4289c4 100644 --- a/lib/impure/osinfo_posix.nim +++ b/lib/impure/osinfo_posix.nim @@ -35,7 +35,15 @@ proc getSystemVersion*(): string = elif $unix_info.sysname == "Darwin": # Darwin result.add("Mac OS X ") - if "10" in $unix_info.release: + if "14" in $unix_info.release: + result.add("v10.10 Yosemite") + elif "13" in $unix_info.release: + result.add("v10.9 Mavericks") + elif "12" in $unix_info.release: + result.add("v10.8 Mountian Lion") + elif "11" in $unix_info.release: + result.add("v10.7 Lion") + elif "10" in $unix_info.release: result.add("v10.6 Snow Leopard") elif "9" in $unix_info.release: result.add("v10.5 Leopard") diff --git a/lib/impure/osinfo_win.nim b/lib/impure/osinfo_win.nim index f423a34a3..becec928e 100644 --- a/lib/impure/osinfo_win.nim +++ b/lib/impure/osinfo_win.nim @@ -245,6 +245,14 @@ proc `$`*(osvi: TVersionInfo): string = if osvi.ProductType == VER_NT_WORKSTATION: result.add("Windows 7 ") else: result.add("Windows Server 2008 R2 ") + elif osvi.minorVersion == 2: + if osvi.ProductType == VER_NT_WORKSTATION: + result.add("Windows 8 ") + else: result.add("Windows Server 2012 ") + elif osvi.minorVersion == 3: + if osvi.ProductType == VER_NT_WORKSTATION: + result.add("Windows 8.1 ") + else: result.add("Windows Server 2012 R2 ") var dwType = getProductInfo(osvi.majorVersion, osvi.minorVersion, 0, 0) case dwType diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index a9a0b0fbe..4bdce9cfb 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -436,12 +436,12 @@ when defined(windows) or defined(nimdoc): if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS): raiseOSError(osLastError()) - proc connectEx(s: SocketHandle, name: ptr TSockAddr, namelen: cint, + proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint, lpSendBuffer: pointer, dwSendDataLength: Dword, lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool = if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().") let fun = - cast[proc (s: SocketHandle, name: ptr TSockAddr, namelen: cint, + cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint, lpSendBuffer: pointer, dwSendDataLength: Dword, lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr) @@ -464,16 +464,16 @@ when defined(windows) or defined(nimdoc): proc getAcceptExSockaddrs(lpOutputBuffer: pointer, dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: Dword, - LocalSockaddr: ptr ptr TSockAddr, LocalSockaddrLength: LPInt, - RemoteSockaddr: ptr ptr TSockAddr, RemoteSockaddrLength: LPInt) = + LocalSockaddr: ptr ptr SockAddr, LocalSockaddrLength: LPInt, + RemoteSockaddr: ptr ptr SockAddr, RemoteSockaddrLength: LPInt) = if getAcceptExSockAddrsPtr.isNil: raise newException(ValueError, "Need to initialise getAcceptExSockAddrs().") let fun = cast[proc (lpOutputBuffer: pointer, dwReceiveDataLength, dwLocalAddressLength, - dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr TSockAddr, - LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr TSockAddr, + dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr, + LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr, RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr) fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, @@ -489,12 +489,12 @@ when defined(windows) or defined(nimdoc): verifyPresence(socket) var retFuture = newFuture[void]("connect") # Apparently ``ConnectEx`` expects the socket to be initially bound: - var saddr: Tsockaddr_in + var saddr: Sockaddr_in saddr.sin_family = int16(toInt(af)) saddr.sin_port = 0 saddr.sin_addr.s_addr = INADDR_ANY - if bindAddr(socket.SocketHandle, cast[ptr TSockAddr](addr(saddr)), - sizeof(saddr).TSockLen) < 0'i32: + if bindAddr(socket.SocketHandle, cast[ptr SockAddr](addr(saddr)), + sizeof(saddr).SockLen) < 0'i32: raiseOSError(osLastError()) var aiList = getAddrInfo(address, port, af) @@ -516,7 +516,7 @@ when defined(windows) or defined(nimdoc): ) var ret = connectEx(socket.SocketHandle, it.ai_addr, - sizeof(Tsockaddr_in).cint, nil, 0, nil, + sizeof(Sockaddr_in).cint, nil, 0, nil, cast[POVERLAPPED](ol)) if ret: # Request to connect completed immediately. @@ -700,17 +700,17 @@ when defined(windows) or defined(nimdoc): var lpOutputBuf = newString(lpOutputLen) var dwBytesReceived: Dword let dwReceiveDataLength = 0.Dword # We don't want any data to be read. - let dwLocalAddressLength = Dword(sizeof (Tsockaddr_in) + 16) - let dwRemoteAddressLength = Dword(sizeof(Tsockaddr_in) + 16) + let dwLocalAddressLength = Dword(sizeof (Sockaddr_in) + 16) + let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16) template completeAccept(): stmt {.immediate, dirty.} = var listenSock = socket let setoptRet = setsockopt(clientSock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, addr listenSock, - sizeof(listenSock).TSockLen) + sizeof(listenSock).SockLen) if setoptRet != 0: raiseOSError(osLastError()) - var localSockaddr, remoteSockaddr: ptr TSockAddr + var localSockaddr, remoteSockaddr: ptr SockAddr var localLen, remoteLen: int32 getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, @@ -719,7 +719,7 @@ when defined(windows) or defined(nimdoc): register(clientSock.TAsyncFD) # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186 retFuture.complete( - (address: $inet_ntoa(cast[ptr Tsockaddr_in](remoteSockAddr).sin_addr), + (address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr), client: clientSock.TAsyncFD) ) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index e0f3b6fc2..0b18e6bcc 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -18,7 +18,7 @@ ## ## .. code-block::nim ## var server = newAsyncHttpServer() -## proc cb(req: TRequest) {.async.} = +## proc cb(req: Request) {.async.} = ## await req.respond(Http200, "Hello World") ## ## asyncCheck server.serve(Port(8080), cb) @@ -27,25 +27,52 @@ import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils type Request* = object - client*: PAsyncSocket # TODO: Separate this into a Response object? + client*: AsyncSocket # TODO: Separate this into a Response object? reqMethod*: string - headers*: PStringTable + headers*: StringTableRef protocol*: tuple[orig: string, major, minor: int] - url*: TUri + url*: Uri hostname*: string ## The hostname of the client that made the request. body*: string AsyncHttpServer* = ref object - socket: PAsyncSocket + socket: AsyncSocket reuseAddr: bool HttpCode* = enum + Http100 = "100 Continue", + Http101 = "101 Switching Protocols", Http200 = "200 OK", - Http303 = "303 Moved", + Http201 = "201 Created", + Http202 = "202 Accepted", + Http204 = "204 No Content", + Http205 = "205 Reset Content", + Http206 = "206 Partial Content", + Http300 = "300 Multiple Choices", + Http301 = "301 Moved Permanently", + Http302 = "302 Found", + Http303 = "303 See Other", + Http304 = "304 Not Modified", + Http305 = "305 Use Proxy", + Http307 = "307 Temporary Redirect", Http400 = "400 Bad Request", + Http401 = "401 Unauthorized", + Http403 = "403 Forbidden", Http404 = "404 Not Found", + Http405 = "405 Method Not Allowed", + Http406 = "406 Not Acceptable", + Http407 = "407 Proxy Authentication Required", + Http408 = "408 Request Timeout", + Http409 = "409 Conflict", + Http410 = "410 Gone", + Http411 = "411 Length Required", + Http418 = "418 I'm a teapot", Http500 = "500 Internal Server Error", - Http502 = "502 Bad Gateway" + Http501 = "501 Not Implemented", + Http502 = "502 Bad Gateway", + Http503 = "503 Service Unavailable", + Http504 = "504 Gateway Timeout", + Http505 = "505 HTTP Version Not Supported" HttpVersion* = enum HttpVer11, @@ -55,7 +82,7 @@ type THttpCode: HttpCode, THttpVersion: HttpVersion].} proc `==`*(protocol: tuple[orig: string, major, minor: int], - ver: THttpVersion): bool = + ver: HttpVersion): bool = let major = case ver of HttpVer11, HttpVer10: 1 @@ -65,23 +92,23 @@ proc `==`*(protocol: tuple[orig: string, major, minor: int], of HttpVer10: 0 result = protocol.major == major and protocol.minor == minor -proc newAsyncHttpServer*(reuseAddr = true): PAsyncHttpServer = +proc newAsyncHttpServer*(reuseAddr = true): AsyncHttpServer = ## Creates a new ``AsyncHttpServer`` instance. new result result.reuseAddr = reuseAddr -proc addHeaders(msg: var string, headers: PStringTable) = +proc addHeaders(msg: var string, headers: StringTableRef) = for k, v in headers: msg.add(k & ": " & v & "\c\L") -proc sendHeaders*(req: TRequest, headers: PStringTable): Future[void] = +proc sendHeaders*(req: Request, headers: StringTableRef): Future[void] = ## Sends the specified headers to the requesting client. var msg = "" addHeaders(msg, headers) return req.client.send(msg) -proc respond*(req: TRequest, code: THttpCode, - content: string, headers: PStringTable = newStringTable()) {.async.} = +proc respond*(req: Request, code: HttpCode, + content: string, headers = newStringTable()) {.async.} = ## Responds to the request with the specified ``HttpCode``, headers and ## content. ## @@ -92,7 +119,7 @@ proc respond*(req: TRequest, code: THttpCode, msg.addHeaders(customHeaders) await req.client.send(msg & "\c\L" & content) -proc newRequest(): TRequest = +proc newRequest(): Request = result.headers = newStringTable(modeCaseInsensitive) result.hostname = "" result.body = "" @@ -107,20 +134,20 @@ proc parseHeader(line: string): tuple[key, value: string] = proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] = var i = protocol.skipIgnoreCase("HTTP/") if i != 5: - raise newException(EInvalidValue, "Invalid request protocol. Got: " & + raise newException(ValueError, "Invalid request protocol. Got: " & protocol) result.orig = protocol i.inc protocol.parseInt(result.major, i) i.inc # Skip . i.inc protocol.parseInt(result.minor, i) -proc sendStatus(client: PAsyncSocket, status: string): Future[void] = +proc sendStatus(client: AsyncSocket, status: string): Future[void] = client.send("HTTP/1.1 " & status & "\c\L") -proc processClient(client: PAsyncSocket, address: string, - callback: proc (request: TRequest): +proc processClient(client: AsyncSocket, address: string, + callback: proc (request: Request): Future[void] {.closure, gcsafe.}) {.async.} = - while not client.closed: + while not client.isClosed: # GET /path HTTP/1.1 # Header: val # \n @@ -160,7 +187,7 @@ proc processClient(client: PAsyncSocket, address: string, request.url = parseUri(path) try: request.protocol = protocol.parseProtocol() - except EInvalidValue: + except ValueError: asyncCheck request.respond(Http400, "Invalid request protocol. Got: " & protocol) continue @@ -206,8 +233,8 @@ proc processClient(client: PAsyncSocket, address: string, request.client.close() break -proc serve*(server: PAsyncHttpServer, port: Port, - callback: proc (request: TRequest): Future[void] {.closure,gcsafe.}, +proc serve*(server: AsyncHttpServer, port: Port, + callback: proc (request: Request): Future[void] {.closure,gcsafe.}, address = "") {.async.} = ## Starts the process of listening for incoming HTTP connections on the ## specified address and port. @@ -227,14 +254,14 @@ proc serve*(server: PAsyncHttpServer, port: Port, #echo(f.isNil) #echo(f.repr) -proc close*(server: PAsyncHttpServer) = +proc close*(server: AsyncHttpServer) = ## Terminates the async http server instance. server.socket.close() when isMainModule: proc main = var server = newAsyncHttpServer() - proc cb(req: TRequest) {.async.} = + proc cb(req: Request) {.async.} = #echo(req.reqMethod, " ", req.url) #echo(req.headers) let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT", diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim index 4c25952a8..d40c3849e 100644 --- a/lib/pure/asyncio.nim +++ b/lib/pure/asyncio.nim @@ -10,6 +10,11 @@ include "system/inclrtl" import sockets, os +## +## **Warning:** This module is deprecated since version 0.10.2. +## Use the brand new `asyncdispatch <asyncdispatch.html>`_ module together +## with the `asyncnet <asyncnet.html>`_ module. + ## This module implements an asynchronous event loop together with asynchronous ## sockets which use this event loop. ## It is akin to Python's asyncore module. Many modules that use sockets @@ -90,6 +95,8 @@ import sockets, os ## var client: Socket ## getSocket(s).accept(client) +{.deprecated.} + when defined(windows): from winlean import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet, FD_ISSET, select diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index fd29e0a22..76b2bc46c 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -69,13 +69,13 @@ type # TODO: I would prefer to just do: # AsyncSocket* {.borrow: `.`.} = distinct Socket. But that doesn't work. AsyncSocketDesc = object - fd*: SocketHandle - closed*: bool ## determines whether this socket has been closed - case isBuffered*: bool ## determines whether this socket is buffered. + fd: SocketHandle + closed: bool ## determines whether this socket has been closed + case isBuffered: bool ## determines whether this socket is buffered. of true: - buffer*: array[0..BufferSize, char] - currPos*: int # current index in buffer - bufLen*: int # current length of buffer + buffer: array[0..BufferSize, char] + currPos: int # current index in buffer + bufLen: int # current length of buffer of false: nil case isSsl: bool of true: @@ -91,7 +91,8 @@ type # TODO: Save AF, domain etc info and reuse it in procs which need it like connect. -proc newSocket(fd: TAsyncFD, isBuff: bool): AsyncSocket = +proc newAsyncSocket*(fd: TAsyncFD, isBuff: bool): AsyncSocket = + ## Creates a new ``AsyncSocket`` based on the supplied params. assert fd != osInvalidSocket.TAsyncFD new(result) result.fd = fd.SocketHandle @@ -102,11 +103,17 @@ proc newSocket(fd: TAsyncFD, isBuff: bool): AsyncSocket = proc newAsyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket = ## Creates a new asynchronous socket. - result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered) + ## + ## This procedure will also create a brand new file descriptor for + ## this socket. + result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered) proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): AsyncSocket = ## Creates a new asynchronous socket. - result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered) + ## + ## This procedure will also create a brand new file descriptor for + ## this socket. + result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered) when defined(ssl): proc getSslError(handle: SslPtr, err: cint): cint = @@ -275,7 +282,7 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}): retFuture.fail(future.readError) else: let resultTup = (future.read.address, - newSocket(future.read.client, socket.isBuffered)) + newAsyncSocket(future.read.client, socket.isBuffered)) retFuture.complete(resultTup) return retFuture @@ -399,13 +406,13 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {. proc close*(socket: AsyncSocket) = ## Closes the socket. - socket.fd.TAsyncFD.closeSocket() + defer: + socket.fd.TAsyncFD.closeSocket() when defined(ssl): if socket.isSSL: let res = SslShutdown(socket.sslHandle) if res == 0: - if SslShutdown(socket.sslHandle) != 1: - raiseSslError() + discard elif res != 1: raiseSslError() socket.closed = true # TODO: Add extra debugging checks for this. @@ -439,6 +446,18 @@ proc setSockOpt*(socket: AsyncSocket, opt: SOBool, value: bool, var valuei = cint(if value: 1 else: 0) setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei) +proc isSsl*(socket: AsyncSocket): bool = + ## Determines whether ``socket`` is a SSL socket. + socket.isSsl + +proc getFd*(socket: AsyncSocket): SocketHandle = + ## Returns the socket's file descriptor. + return socket.fd + +proc isClosed*(socket: AsyncSocket): bool = + ## Determines whether the socket has been closed. + return socket.closed + when isMainModule: type TestCases = enum diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index a8709e098..0c5704f69 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -19,10 +19,7 @@ import math const - EPS = 5.0e-6 ## Epsilon used for float comparisons (should be smaller - ## if float is really float64, but w/ the current version - ## it seems to be float32?) - + EPS = 1.0e-7 ## Epsilon used for float comparisons. type Complex* = tuple[re, im: float] diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index a1440b6f4..4852ed50d 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -264,7 +264,7 @@ macro html*(e: expr): expr {.immediate.} = let e = callsite() result = xmlCheckedTag(e, "html", "xmlns", "") -macro hr*(e: expr): expr {.immediate.} = +macro hr*(): expr {.immediate.} = ## generates the HTML ``hr`` element. let e = callsite() result = xmlCheckedTag(e, "hr", commonAttr, "", true) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 28b84eb39..e6fe79740 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -44,21 +44,21 @@ const type SocketImpl* = object ## socket type - fd*: SocketHandle - case isBuffered*: bool # determines whether this socket is buffered. + fd: SocketHandle + case isBuffered: bool # determines whether this socket is buffered. of true: - buffer*: array[0..BufferSize, char] - currPos*: int # current index in buffer - bufLen*: int # current length of buffer + buffer: array[0..BufferSize, char] + currPos: int # current index in buffer + bufLen: int # current length of buffer of false: nil when defined(ssl): - case isSsl*: bool + case isSsl: bool of true: - sslHandle*: SSLPtr - sslContext*: SSLContext - sslNoHandshake*: bool # True if needs handshake. - sslHasPeekChar*: bool - sslPeekChar*: char + sslHandle: SSLPtr + sslContext: SSLContext + sslNoHandshake: bool # True if needs handshake. + sslHasPeekChar: bool + sslPeekChar: char of false: nil Socket* = ref SocketImpl @@ -100,7 +100,8 @@ proc toOSFlags*(socketFlags: set[SocketFlag]): cint = result = result or MSG_PEEK of SocketFlag.SafeDisconn: continue -proc createSocket(fd: SocketHandle, isBuff: bool): Socket = +proc newSocket(fd: SocketHandle, isBuff: bool): Socket = + ## Creates a new socket as specified by the params. assert fd != osInvalidSocket new(result) result.fd = fd @@ -115,7 +116,7 @@ proc newSocket*(domain, typ, protocol: cint, buffered = true): Socket = let fd = newRawSocket(domain, typ, protocol) if fd == osInvalidSocket: raiseOSError(osLastError()) - result = createSocket(fd, buffered) + result = newSocket(fd, buffered) proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, protocol: Protocol = IPPROTO_TCP, buffered = true): Socket = @@ -125,7 +126,7 @@ proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, let fd = newRawSocket(domain, typ, protocol) if fd == osInvalidSocket: raiseOSError(osLastError()) - result = createSocket(fd, buffered) + result = newSocket(fd, buffered) when defined(ssl): CRYPTO_malloc_init() @@ -937,10 +938,10 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int, doAssert socket.handshake() socket.fd.setBlocking(true) -proc isSSL*(socket: Socket): bool = return socket.isSSL +proc isSsl*(socket: Socket): bool = return socket.isSSL ## Determines whether ``socket`` is a SSL socket. -proc getFD*(socket: Socket): SocketHandle = return socket.fd +proc getFd*(socket: Socket): SocketHandle = return socket.fd ## Returns the socket's file descriptor type diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 004287d39..ad82dc682 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -575,7 +575,7 @@ proc `/` * (head, tail: string): string {.noSideEffect.} = proc splitPath*(path: string): tuple[head, tail: string] {. noSideEffect, rtl, extern: "nos$1".} = ## Splits a directory into (head, tail), so that - ## ``joinPath(head, tail) == path``. + ## ``head / tail == path`` (except for edge cases like "/usr"). ## ## Examples: ## diff --git a/lib/pure/parseurl.nim b/lib/pure/parseurl.nim index 32e69b89a..f27cd8c12 100644 --- a/lib/pure/parseurl.nim +++ b/lib/pure/parseurl.nim @@ -7,10 +7,12 @@ # distribution, for details about the copyright. # -## Parses & constructs URLs. +## **Warnings:** This module is deprecated since version 0.10.2. +## Use the `uri <uri.html>`_ module instead. ## -## **Note**: This module will be deprecated in the future and merged into a -## new ``url`` module. +## Parses & constructs URLs. + +{.deprecated.} import strutils diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 8b7554661..7cef0a00d 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -1433,7 +1433,7 @@ proc eat(p: var PegParser, kind: TTokKind) = if p.tok.kind == kind: getTok(p) else: pegError(p, tokKindToStr[kind] & " expected") -proc parseExpr(p: var PegParser): Peg +proc parseExpr(p: var PegParser): Peg {.gcsafe.} proc getNonTerminal(p: var PegParser, name: string): NonTerminal = for i in 0..high(p.nonterms): diff --git a/lib/pure/rawsockets.pretty.nim b/lib/pure/rawsockets.pretty.nim new file mode 100644 index 000000000..46bfba9e7 --- /dev/null +++ b/lib/pure/rawsockets.pretty.nim @@ -0,0 +1,426 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2014 Dominik Picheta +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a low-level cross-platform sockets interface. Look +## at the ``net`` module for the higher-level version. + +# TODO: Clean up the exports a bit and everything else in general. + +import unsigned, os + +when hostOS == "solaris": + {.passl: "-lsocket -lnsl".} + +const useWinVersion = defined(Windows) or defined(nimdoc) + +when useWinVersion: + import winlean + export WSAEWOULDBLOCK, WSAECONNRESET, WSAECONNABORTED, WSAENETRESET, + WSAEDISCON, ERROR_NETNAME_DELETED +else: + import posix + export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL, + EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET + +export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen, + inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto + +export + SO_ERROR, + SOL_SOCKET, + SOMAXCONN, + SO_ACCEPTCONN, SO_BROADCAST, SO_DEBUG, SO_DONTROUTE, + SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR, + MSG_PEEK + +type + Port* = distinct uint16 ## port type + + Domain* = enum ## domain, which specifies the protocol family of the + ## created socket. Other domains than those that are listed + ## here are unsupported. + AF_UNIX, ## for local socket (using a file). Unsupported on Windows. + AF_INET = 2, ## for network protocol IPv4 or + AF_INET6 = 23 ## for network protocol IPv6. + + SockType* = enum ## second argument to `socket` proc + SOCK_STREAM = 1, ## reliable stream-oriented service or Stream Sockets + SOCK_DGRAM = 2, ## datagram service or Datagram Sockets + SOCK_RAW = 3, ## raw protocols atop the network layer. + SOCK_SEQPACKET = 5 ## reliable sequenced packet service + + Protocol* = enum ## third argument to `socket` proc + IPPROTO_TCP = 6, ## Transmission control protocol. + IPPROTO_UDP = 17, ## User datagram protocol. + IPPROTO_IP, ## Internet protocol. Unsupported on Windows. + IPPROTO_IPV6, ## Internet Protocol Version 6. Unsupported on Windows. + IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows. + IPPROTO_ICMP ## Control message protocol. Unsupported on Windows. + + Servent* = object ## information about a service + name*: string + aliases*: seq[string] + port*: Port + proto*: string + + Hostent* = object ## information about a given host + name*: string + aliases*: seq[string] + addrtype*: Domain + length*: int + addrList*: seq[string] + +{.deprecated: [TPort: Port, TDomain: Domain, TType: SockType, + TProtocol: Protocol, TServent: Servent, THostent: Hostent].} + +when useWinVersion: + let + osInvalidSocket* = winlean.INVALID_SOCKET + + const + IOCPARM_MASK* = 127 + IOC_IN* = int(-2147483648) + FIONBIO* = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or + (102 shl 8) or 126 + + proc ioctlsocket*(s: SocketHandle, cmd: clong, + argptr: ptr clong): cint {. + stdcall, importc: "ioctlsocket", dynlib: "ws2_32.dll".} +else: + let + osInvalidSocket* = posix.INVALID_SOCKET + +proc `==`*(a, b: Port): bool {.borrow.} + ## ``==`` for ports. + +proc `$`*(p: Port): string {.borrow.} + ## returns the port number as a string + +proc toInt*(domain: Domain): cint + ## Converts the TDomain enum to a platform-dependent ``cint``. + +proc toInt*(typ: SockType): cint + ## Converts the TType enum to a platform-dependent ``cint``. + +proc toInt*(p: Protocol): cint + ## Converts the TProtocol enum to a platform-dependent ``cint``. + +when not useWinVersion: + proc toInt(domain: Domain): cint = + case domain + of AF_UNIX: result = posix.AF_UNIX + of AF_INET: result = posix.AF_INET + of AF_INET6: result = posix.AF_INET6 + else: discard + + proc toInt(typ: SockType): cint = + case typ + of SOCK_STREAM: result = posix.SOCK_STREAM + of SOCK_DGRAM: result = posix.SOCK_DGRAM + of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET + of SOCK_RAW: result = posix.SOCK_RAW + else: discard + + proc toInt(p: Protocol): cint = + case p + of IPPROTO_TCP: result = posix.IPPROTO_TCP + of IPPROTO_UDP: result = posix.IPPROTO_UDP + of IPPROTO_IP: result = posix.IPPROTO_IP + of IPPROTO_IPV6: result = posix.IPPROTO_IPV6 + of IPPROTO_RAW: result = posix.IPPROTO_RAW + of IPPROTO_ICMP: result = posix.IPPROTO_ICMP + else: discard + +else: + proc toInt(domain: Domain): cint = + result = toU16(ord(domain)) + + proc toInt(typ: SockType): cint = + result = cint(ord(typ)) + + proc toInt(p: Protocol): cint = + result = cint(ord(p)) + + +proc newRawSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP): SocketHandle = + ## Creates a new socket; returns `InvalidSocket` if an error occurs. + socket(toInt(domain), toInt(typ), toInt(protocol)) + +proc close*(socket: SocketHandle) = + ## closes a socket. + when useWinVersion: + discard winlean.closesocket(socket) + else: + discard posix.close(socket) + # TODO: These values should not be discarded. An EOS should be raised. + # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times + +proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint = + result = bindSocket(socket, name, namelen) + +proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [ReadIOEffect].} = + ## Marks ``socket`` as accepting connections. + ## ``Backlog`` specifies the maximum length of the + ## queue of pending connections. + when useWinVersion: + result = winlean.listen(socket, cint(backlog)) + else: + result = posix.listen(socket, cint(backlog)) + +proc getAddrInfo*(address: string, port: Port, af: Domain = AF_INET, typ: SockType = SOCK_STREAM, + prot: Protocol = IPPROTO_TCP): ptr AddrInfo = + ## + ## + ## **Warning**: The resulting ``ptr TAddrInfo`` must be freed using ``dealloc``! + var hints: AddrInfo + result = nil + hints.ai_family = toInt(af) + hints.ai_socktype = toInt(typ) + hints.ai_protocol = toInt(prot) + var gaiResult = getaddrinfo(address, $port, addr(hints), result) + if gaiResult != 0'i32: + when useWinVersion: + raiseOSError(osLastError()) + else: + raise newException(OSError, $gai_strerror(gaiResult)) + +proc dealloc*(ai: ptr AddrInfo) = + freeaddrinfo(ai) + +proc ntohl*(x: int32): int32 = + ## Converts 32-bit integers from network to host byte order. + ## On machines where the host byte order is the same as network byte order, + ## this is a no-op; otherwise, it performs a 4-byte swap operation. + when cpuEndian == bigEndian: result = x + else: result = (x shr 24'i32) or + (x shr 8'i32 and 0xff00'i32) or + (x shl 8'i32 and 0xff0000'i32) or + (x shl 24'i32) + +proc ntohs*(x: int16): int16 = + ## Converts 16-bit integers from network to host byte order. On machines + ## where the host byte order is the same as network byte order, this is + ## a no-op; otherwise, it performs a 2-byte swap operation. + when cpuEndian == bigEndian: result = x + else: result = (x shr 8'i16) or (x shl 8'i16) + +proc htonl*(x: int32): int32 = + ## Converts 32-bit integers from host to network byte order. On machines + ## where the host byte order is the same as network byte order, this is + ## a no-op; otherwise, it performs a 4-byte swap operation. + result = rawsockets.ntohl(x) + +proc htons*(x: int16): int16 = + ## Converts 16-bit positive integers from host to network byte order. + ## On machines where the host byte order is the same as network byte + ## order, this is a no-op; otherwise, it performs a 2-byte swap operation. + result = rawsockets.ntohs(x) + +proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = + ## Searches the database from the beginning and finds the first entry for + ## which the service name specified by ``name`` matches the s_name member + ## and the protocol name specified by ``proto`` matches the s_proto member. + ## + ## On posix this will search through the ``/etc/services`` file. + when useWinVersion: + var s = winlean.getservbyname(name, proto) + else: + var s = posix.getservbyname(name, proto) + if s == nil: raise newException(OSError, "Service not found.") + result.name = $s.s_name + result.aliases = cstringArrayToSeq(s.s_aliases) + result.port = Port(s.s_port) + result.proto = $s.s_proto + +proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} = + ## Searches the database from the beginning and finds the first entry for + ## which the port specified by ``port`` matches the s_port member and the + ## protocol name specified by ``proto`` matches the s_proto member. + ## + ## On posix this will search through the ``/etc/services`` file. + when useWinVersion: + var s = winlean.getservbyport(ze(int16(port)).cint, proto) + else: + var s = posix.getservbyport(ze(int16(port)).cint, proto) + if s == nil: raise newException(OSError, "Service not found.") + result.name = $s.s_name + result.aliases = cstringArrayToSeq(s.s_aliases) + result.port = Port(s.s_port) + result.proto = $s.s_proto + +proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = + ## This function will lookup the hostname of an IP Address. + var myaddr: InAddr + myaddr.s_addr = inet_addr(ip) + + when useWinVersion: + var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint, + cint(rawsockets.AF_INET)) + if s == nil: raiseOSError(osLastError()) + else: + var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, + cint(posix.AF_INET)) + if s == nil: + raise newException(OSError, $hstrerror(h_errno)) + + result.name = $s.h_name + result.aliases = cstringArrayToSeq(s.h_aliases) + when useWinVersion: + result.addrtype = Domain(s.h_addrtype) + else: + if s.h_addrtype == posix.AF_INET: + result.addrtype = AF_INET + elif s.h_addrtype == posix.AF_INET6: + result.addrtype = AF_INET6 + else: + raise newException(OSError, "unknown h_addrtype") + result.addrList = cstringArrayToSeq(s.h_addr_list) + result.length = int(s.h_length) + +proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = + ## This function will lookup the IP address of a hostname. + when useWinVersion: + var s = winlean.gethostbyname(name) + else: + var s = posix.gethostbyname(name) + if s == nil: raiseOSError(osLastError()) + result.name = $s.h_name + result.aliases = cstringArrayToSeq(s.h_aliases) + when useWinVersion: + result.addrtype = Domain(s.h_addrtype) + else: + if s.h_addrtype == posix.AF_INET: + result.addrtype = AF_INET + elif s.h_addrtype == posix.AF_INET6: + result.addrtype = AF_INET6 + else: + raise newException(OSError, "unknown h_addrtype") + result.addrList = cstringArrayToSeq(s.h_addr_list) + result.length = int(s.h_length) + +proc getSockName*(socket: SocketHandle): Port = + ## returns the socket's associated port number. + var name: Sockaddr_in + when useWinVersion: + name.sin_family = int16(ord(AF_INET)) + else: + name.sin_family = posix.AF_INET + #name.sin_port = htons(cint16(port)) + #name.sin_addr.s_addr = htonl(INADDR_ANY) + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), + addr(namelen)) == -1'i32: + raiseOSError(osLastError()) + result = Port(rawsockets.ntohs(name.sin_port)) + +proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {. + tags: [ReadIOEffect].} = + ## getsockopt for integer options. + var res: cint + var size = sizeof(res).SockLen + if getsockopt(socket, cint(level), cint(optname), + addr(res), addr(size)) < 0'i32: + raiseOSError(osLastError()) + result = int(res) + +proc setSockOptInt*(socket: SocketHandle, level, optname, optval: int) {. + tags: [WriteIOEffect].} = + ## setsockopt for integer options. + var value = cint(optval) + if setsockopt(socket, cint(level), cint(optname), addr(value), + sizeof(value).SockLen) < 0'i32: + raiseOSError(osLastError()) + +proc setBlocking*(s: SocketHandle, blocking: bool) = + ## Sets blocking mode on socket. + ## + ## Raises EOS on error. + when useWinVersion: + var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking + if ioctlsocket(s, FIONBIO, addr(mode)) == -1: + raiseOSError(osLastError()) + else: # BSD sockets + var x: int = fcntl(s, F_GETFL, 0) + if x == -1: + raiseOSError(osLastError()) + else: + var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK + if fcntl(s, F_SETFL, mode) == -1: + raiseOSError(osLastError()) + +proc timeValFromMilliseconds(timeout = 500): Timeval = + if timeout != -1: + var seconds = timeout div 1000 + result.tv_sec = seconds.int32 + result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 + +proc createFdSet(fd: var FdSet, s: seq[SocketHandle], m: var int) = + FD_ZERO(fd) + for i in items(s): + m = max(m, int(i)) + fdSet(i, fd) + +proc pruneSocketSet(s: var seq[SocketHandle], fd: var FdSet) = + var i = 0 + var L = s.len + while i < L: + if FD_ISSET(s[i], fd) == 0'i32: + s[i] = s[L-1] + dec(L) + else: + inc(i) + setLen(s, L) + +proc select*(readfds: var seq[SocketHandle], timeout = 500): int = + ## Traditional select function. This function will return the number of + ## sockets that are ready to be read from, written to, or which have errors. + ## If there are none; 0 is returned. + ## ``Timeout`` is in miliseconds and -1 can be specified for no timeout. + ## + ## A socket is removed from the specific ``seq`` when it has data waiting to + ## be read/written to or has errors (``exceptfds``). + var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) + + var rd: FdSet + var m = 0 + createFdSet((rd), readfds, m) + + if timeout != -1: + result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv))) + else: + result = int(select(cint(m+1), addr(rd), nil, nil, nil)) + + pruneSocketSet(readfds, (rd)) + +proc selectWrite*(writefds: var seq[SocketHandle], + timeout = 500): int {.tags: [ReadIOEffect].} = + ## When a socket in ``writefds`` is ready to be written to then a non-zero + ## value will be returned specifying the count of the sockets which can be + ## written to. The sockets which can be written to will also be removed + ## from ``writefds``. + ## + ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for + ## an unlimited time. + var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) + + var wr: FdSet + var m = 0 + createFdSet((wr), writefds, m) + + if timeout != -1: + result = int(select(cint(m+1), nil, addr(wr), nil, addr(tv))) + else: + result = int(select(cint(m+1), nil, addr(wr), nil, nil)) + + pruneSocketSet(writefds, (wr)) + +when defined(Windows): + var wsa: WSAData + if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError()) diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim index 58b37833a..f3e2b583c 100644 --- a/lib/pure/scgi.nim +++ b/lib/pure/scgi.nim @@ -25,6 +25,10 @@ ## ## **Warning:** The API of this module is unstable, and therefore is subject ## to change. +## +## **Warning:** This module only supports the old asynchronous interface. +## You may wish to use the `asynchttpserver <asynchttpserver.html>`_ +## instead for web applications. include "system/inclrtl" diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index 79f409179..11eeefcb9 100644 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -7,6 +7,10 @@ # distribution, for details about the copyright. # +## **Warning:** Since version 0.10.2 this module is deprecated. +## Use the `net <net.html>`_ or the +## `rawsockets <rawsockets.html>`_ module instead. +## ## This module implements portable sockets, it supports a mix of different types ## of sockets. Sockets are buffered by default meaning that data will be ## received in ``BufferSize`` (4000) sized chunks, buffering @@ -23,9 +27,6 @@ ## ## Asynchronous sockets are supported, however a better alternative is to use ## the `asyncio <asyncio.html>`_ module. -## -## Since version 0.10.2 this module is deprecated. Use the `net <net.html>`_ -## or the `rawsockets <rawsockets.html>`_ module instead. {.deprecated.} diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 6c0246f8b..21efea3bc 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -97,7 +97,9 @@ proc checkpoint*(msg: string) = template fail* = bind checkpoints for msg in items(checkpoints): - echo msg + # this used to be 'echo' which now breaks due to a bug. XXX will revisit + # this issue later. + stdout.writeln msg when not defined(ECMAScript): if abortOnError: quit(1) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 2c65d071e..368802dc2 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -19,14 +19,14 @@ type {.deprecated: [TUrl: Url, TUri: Uri].} -proc `$`*(url: TUrl): string {.deprecated.} = - ## **Deprecated since 0.9.6**: Use ``TUri`` instead. +proc `$`*(url: Url): string {.deprecated.} = + ## **Deprecated since 0.9.6**: Use ``Uri`` instead. return string(url) -proc `/`*(a, b: TUrl): TUrl {.deprecated.} = +proc `/`*(a, b: Url): Url {.deprecated.} = ## Joins two URLs together, separating them with / if needed. ## - ## **Deprecated since 0.9.6**: Use ``TUri`` instead. + ## **Deprecated since 0.9.6**: Use ``Uri`` instead. var urlS = $a var bS = $b if urlS == "": return b @@ -36,15 +36,15 @@ proc `/`*(a, b: TUrl): TUrl {.deprecated.} = urlS.add(bS.substr(1)) else: urlS.add(bs) - result = TUrl(urlS) + result = Url(urlS) -proc add*(url: var TUrl, a: TUrl) {.deprecated.} = +proc add*(url: var Url, a: Url) {.deprecated.} = ## Appends url to url. ## - ## **Deprecated since 0.9.6**: Use ``TUri`` instead. + ## **Deprecated since 0.9.6**: Use ``Uri`` instead. url = url / a -proc parseAuthority(authority: string, result: var TUri) = +proc parseAuthority(authority: string, result: var Uri) = var i = 0 var inPort = false while true: @@ -65,7 +65,7 @@ proc parseAuthority(authority: string, result: var TUri) = result.hostname.add(authority[i]) i.inc -proc parsePath(uri: string, i: var int, result: var TUri) = +proc parsePath(uri: string, i: var int, result: var Uri) = i.inc parseUntil(uri, result.path, {'?', '#'}, i) @@ -82,11 +82,11 @@ proc parsePath(uri: string, i: var int, result: var TUri) = i.inc # Skip '#' i.inc parseUntil(uri, result.anchor, {}, i) -proc initUri(): TUri = - result = TUri(scheme: "", username: "", password: "", hostname: "", port: "", +proc initUri(): Uri = + result = Uri(scheme: "", username: "", password: "", hostname: "", port: "", path: "", query: "", anchor: "") -proc parseUri*(uri: string): TUri = +proc parseUri*(uri: string): Uri = ## Parses a URI. result = initUri() @@ -113,7 +113,7 @@ proc parseUri*(uri: string): TUri = var authority = "" i.inc parseUntil(uri, authority, {'/', '?', '#'}, i) if authority == "": - raise newException(EInvalidValue, "Expected authority got nothing.") + raise newException(ValueError, "Expected authority got nothing.") parseAuthority(authority, result) # Path @@ -150,7 +150,7 @@ proc removeDotSegments(path: string): string = result = collection.join("/") if endsWithSlash: result.add '/' -proc merge(base, reference: TUri): string = +proc merge(base, reference: Uri): string = # http://tools.ietf.org/html/rfc3986#section-5.2.3 if base.hostname != "" and base.path == "": '/' & reference.path @@ -161,7 +161,7 @@ proc merge(base, reference: TUri): string = else: base.path[0 .. lastSegment] & reference.path -proc combine*(base: TUri, reference: TUri): TUri = +proc combine*(base: Uri, reference: Uri): Uri = ## Combines a base URI with a reference URI. ## ## This uses the algorithm specified in @@ -216,13 +216,13 @@ proc combine*(base: TUri, reference: TUri): TUri = result.scheme = base.scheme result.anchor = reference.anchor -proc combine*(uris: varargs[TUri]): TUri = +proc combine*(uris: varargs[Uri]): Uri = ## Combines multiple URIs together. result = uris[0] for i in 1 .. <uris.len: result = combine(result, uris[i]) -proc `/`*(x: TUri, path: string): TUri = +proc `/`*(x: Uri, path: string): Uri = ## Concatenates the path specified to the specified URI's path. ## ## Contrary to the ``combine`` procedure you do not have to worry about @@ -251,7 +251,7 @@ proc `/`*(x: TUri, path: string): TUri = result.path.add '/' result.path.add(path) -proc `$`*(u: TUri): string = +proc `$`*(u: Uri): string = ## Returns the string representation of the specified URI object. result = "" if u.scheme.len > 0: diff --git a/lib/system.nim b/lib/system.nim index 0cd4b84e2..b7c77e276 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1516,7 +1516,7 @@ const NimMinor*: int = 10 ## is the minor number of Nim's version. - NimPatch*: int = 1 + NimPatch*: int = 3 ## is the patch number of Nim's version. NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index e21eeca6a..237b42482 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -296,15 +296,15 @@ when not defined(noSignalHandler): template processSignal(s, action: expr) {.immediate, dirty.} = if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n") elif s == SIGSEGV: - action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n") + action("SIGSEGV: Illegal storage access. (Try to compile with -d:useSysAssert -d:useGcAssert for details.)\n") elif s == SIGABRT: when defined(endb): if dbgAborting: return # the debugger wants to abort action("SIGABRT: Abnormal termination.\n") elif s == SIGFPE: action("SIGFPE: Arithmetic error.\n") elif s == SIGILL: action("SIGILL: Illegal operation.\n") - elif s == SIGBUS: - action("SIGBUS: Illegal storage access. (Attempt to read from nil?)\n") + elif s == SIGBUS: + action("SIGBUS: Illegal storage access. (Try to compile with -d:useSysAssert -d:useGcAssert for details.)\n") else: block platformSpecificSignal: when declared(SIGPIPE): diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index ba25fbf1a..f091d8f46 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -280,9 +280,18 @@ when not useWinVersion: proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, dynlib: DLLUtilName, importc.} + proc allocWrapper(size: int): pointer {.cdecl.} = alloc(size) + proc reallocWrapper(p: pointer; newsize: int): pointer {.cdecl.} = + if p == nil: + if newSize > 0: result = alloc(newsize) + elif newsize == 0: dealloc(p) + else: result = realloc(p, newsize) + proc deallocWrapper(p: pointer) {.cdecl.} = + if p != nil: dealloc(p) + proc CRYPTO_malloc_init*() = when not useWinVersion: - CRYPTO_set_mem_functions(alloc, realloc, dealloc) + CRYPTO_set_mem_functions(allocWrapper, reallocWrapper, deallocWrapper) proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cInt, larg: int, parg: pointer): int{. cdecl, dynlib: DLLSSLName, importc.} diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index 5165b0f06..13d531387 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -53,9 +53,7 @@ proc createServer(port: TPort) {.async.} = discard server.SocketHandle.listen() while true: - var client = await accept(server) - asyncCheck readMessages(client) - # TODO: Test: readMessages(disp, await disp.accept(server)) + asyncCheck readMessages(await accept(server)) asyncCheck createServer(TPort(10335)) asyncCheck launchSwarm(TPort(10335)) diff --git a/tests/async/tasynciossl.nim b/tests/async/tasynciossl.nim index b0222e4ff..118b9e74d 100644 --- a/tests/async/tasynciossl.nim +++ b/tests/async/tasynciossl.nim @@ -47,7 +47,7 @@ proc serverAccept(s: PAsyncSocket) = proc launchSwarm(disp: var PDispatcher, port: TPort, count: int, buffered = true, useSSL = false) = for i in 1..count: - var client = AsyncSocket() + var client = asyncSocket() when defined(ssl): if useSSL: ctx1.wrapSocket(client) @@ -56,7 +56,7 @@ proc launchSwarm(disp: var PDispatcher, port: TPort, count: int, client.connect("localhost", port) proc createSwarm(port: TPort, buffered = true, useSSL = false) = - var server = AsyncSocket() + var server = asyncSocket() when defined(ssl): if useSSL: ctx.wrapSocket(server) diff --git a/tests/async/tasyncudp.nim b/tests/async/tasyncudp.nim index fd7f3d568..2a7ed40bf 100644 --- a/tests/async/tasyncudp.nim +++ b/tests/async/tasyncudp.nim @@ -42,14 +42,14 @@ proc swarmConnect(s: PAsyncSocket) = proc createClient(disp: var PDispatcher, port: TPort, buffered = true) = currentClient.inc() - var client = AsyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, + var client = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = buffered) client.handleConnect = swarmConnect disp.register(client) client.connect("localhost", port) proc createServer(port: TPort, buffered = true) = - var server = AsyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, + var server = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = buffered) server.handleRead = serverRead disp.register(server) @@ -75,4 +75,4 @@ while true: break assert msgCount == messagesToSend * serverCount * swarmSize -echo(msgCount) \ No newline at end of file +echo(msgCount) diff --git a/tests/macros/tvtable.nim b/tests/macros/tvtable.nim index 51894618c..3e3b9c0e6 100644 --- a/tests/macros/tvtable.nim +++ b/tests/macros/tvtable.nim @@ -11,8 +11,8 @@ OBJ 2 bar type # these are the signatures of the virtual procs for each type - fooProc[T] = proc (o: var T): int - barProc[T] = proc (o: var T) + fooProc[T] = proc (o: var T): int {.nimcall.} + barProc[T] = proc (o: var T) {.nimcall.} # an untyped table to store the proc pointers # it's also possible to use a strongly typed tuple here diff --git a/tests/metatype/tusertypeclasses.nim b/tests/metatype/tusertypeclasses.nim index a5d575dbf..6e9e4934b 100644 --- a/tests/metatype/tusertypeclasses.nim +++ b/tests/metatype/tusertypeclasses.nim @@ -12,7 +12,7 @@ type (x < y) is bool ObjectContainer = generic C - C.len is ordinal + C.len is Ordinal for v in items(C): v.type is tuple|object diff --git a/tests/misc/tcolonisproc.nim b/tests/misc/tcolonisproc.nim index e55587dfc..af4077284 100644 --- a/tests/misc/tcolonisproc.nim +++ b/tests/misc/tcolonisproc.nim @@ -2,10 +2,11 @@ proc p(a, b: int, c: proc ()) = c() - -p(1, 3): - echo 1 - echo 3 +when false: + # language spec changed: + p(1, 3): + echo 1 + echo 3 p(1, 1, proc() = echo 1 diff --git a/tests/misc/tnoinst.nim b/tests/misc/tnoinst.nim index db1058d09..4c8d9d1aa 100644 --- a/tests/misc/tnoinst.nim +++ b/tests/misc/tnoinst.nim @@ -1,6 +1,7 @@ discard """ line: 12 errormsg: "instantiate 'notConcrete' explicitly" + disabled: "true" """ proc wrap[T]() = diff --git a/tests/misc/tvarious.nim b/tests/misc/tvarious.nim index ed2964cf9..434d25e48 100644 --- a/tests/misc/tvarious.nim +++ b/tests/misc/tvarious.nim @@ -62,3 +62,7 @@ when false: block: var a, b: Bar[int, 0..2] discard foo(a, b) + +# bug #1788 + +echo "hello" & char(ord(' ')) & "world" diff --git a/tests/parser/tprecedence.nim b/tests/parser/tprecedence.nim index 6b1b250a2..d2c6d0b30 100644 --- a/tests/parser/tprecedence.nim +++ b/tests/parser/tprecedence.nim @@ -1,11 +1,15 @@ discard """ - output: "true" + output: '''holla +true''' """ +# Test top level semicolon works properly: +import os; echo "holla" + # Test the new predence rules proc `\+` (x, y: int): int = result = x + y proc `\*` (x, y: int): int = result = x * y -echo 5 \+ 1 \* 9 == 14 +echo 5 \+ 1 \* 9 == 6*9 diff --git a/tests/stdlib/tmath2.nim b/tests/stdlib/tmath2.nim index 935b08634..88d96c80a 100644 --- a/tests/stdlib/tmath2.nim +++ b/tests/stdlib/tmath2.nim @@ -58,7 +58,7 @@ proc TestLoops() = break break - while True: + while true: break @@ -73,7 +73,7 @@ proc main() = res: int s: string #write(stdout, mymax(23, 45)) - write(stdout, "Hallo! Wie heißt du? ") + write(stdout, "Hallo! Wie heisst du? ") s = readLine(stdin) # test the case statement case s diff --git a/tests/stdlib/tparsefloat.nim b/tests/stdlib/tparsefloat.nim deleted file mode 100644 index 38ed2db6d..000000000 --- a/tests/stdlib/tparsefloat.nim +++ /dev/null @@ -1,3 +0,0 @@ -import strutils - -echo ParseFloat("5000") / ParseFloat("10") diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim index e5353e4ff..1bc2669c3 100644 --- a/tests/stdlib/tpegs.nim +++ b/tests/stdlib/tpegs.nim @@ -397,7 +397,7 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string = elif c in reserved: result = '\\' & c else: result = $c -proc singleQuoteEsc(c: Char): string = return "'" & esc(c, {'\''}) & "'" +proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'" proc singleQuoteEsc(str: string): string = result = "'" @@ -421,11 +421,11 @@ proc charSetEscAux(cc: set[char]): string = c1 = c2 inc(c1) -proc CharSetEsc(cc: set[char]): string = +proc charSetEsc(cc: set[char]): string = if card(cc) >= 128+64: - result = "[^" & CharSetEscAux({'\1'..'\xFF'} - cc) & ']' + result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']' else: - result = '[' & CharSetEscAux(cc) & ']' + result = '[' & charSetEscAux(cc) & ']' proc toStrAux(r: TPeg, res: var string) = case r.kind @@ -522,12 +522,12 @@ proc `$` *(r: TPeg): string {.rtl, extern: "npegsToString".} = type TCaptures* {.final.} = object ## contains the captured substrings. - matches: array[0..maxSubpatterns-1, tuple[first, last: int]] + matches: array[0..MaxSubpatterns-1, tuple[first, last: int]] ml: int origStart: int proc bounds*(c: TCaptures, - i: range[0..maxSubpatterns-1]): tuple[first, last: int] = + i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = ## returns the bounds ``[first..last]`` of the `i`'th capture. result = c.matches[i] @@ -695,7 +695,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. while start+result < s.len: var x = rawMatch(s, p.sons[0], start+result, c) if x >= 0: - if idx < maxSubpatterns: + if idx < MaxSubpatterns: c.matches[idx] = (start, start+result-1) #else: silently ignore the capture inc(result, x) @@ -739,7 +739,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. inc(c.ml) result = rawMatch(s, p.sons[0], start, c) if result >= 0: - if idx < maxSubpatterns: + if idx < MaxSubpatterns: c.matches[idx] = (start, start+result-1) #else: silently ignore the capture else: @@ -836,7 +836,7 @@ iterator findAll*(s: string, pattern: TPeg, start = 0): string = while i < s.len: var L = matchLen(s, pattern, matches, i) if L < 0: break - for k in 0..maxSubPatterns-1: + for k in 0..MaxSubPatterns-1: if isNil(matches[k]): break yield matches[k] inc(i, L) @@ -866,7 +866,7 @@ template `=~`*(s: string, pattern: TPeg): expr = ## echo("syntax error") ## when not definedInScope(matches): - var matches {.inject.}: array[0..maxSubpatterns-1, string] + var matches {.inject.}: array[0..MaxSubpatterns-1, string] match(s, pattern, matches) # ------------------------- more string handling ------------------------------ @@ -907,7 +907,7 @@ proc replacef*(s: string, sub: TPeg, by: string): string {. ## "var1<-keykey; val2<-key2key2" result = "" var i = 0 - var caps: array[0..maxSubpatterns-1, string] + var caps: array[0..MaxSubpatterns-1, string] while i < s.len: var x = matchLen(s, sub, caps, i) if x <= 0: @@ -924,7 +924,7 @@ proc replace*(s: string, sub: TPeg, by = ""): string {. ## in `by`. result = "" var i = 0 - var caps: array[0..maxSubpatterns-1, string] + var caps: array[0..MaxSubpatterns-1, string] while i < s.len: var x = matchLen(s, sub, caps, i) if x <= 0: @@ -942,7 +942,7 @@ proc parallelReplace*(s: string, subs: varargs[ ## applied in parallel. result = "" var i = 0 - var caps: array[0..maxSubpatterns-1, string] + var caps: array[0..MaxSubpatterns-1, string] while i < s.len: block searchSubs: for j in 0..high(subs): @@ -1055,7 +1055,7 @@ type TPegLexer {.inheritable.} = object ## the lexer object. bufpos: int ## the current position within the buffer buf: cstring ## the buffer itself - LineNumber: int ## the current line number + lineNumber: int ## the current line number lineStart: int ## index of last line start in buffer colOffset: int ## column to add filename: string @@ -1118,38 +1118,38 @@ proc getEscapedChar(c: var TPegLexer, tok: var TToken) = case c.buf[c.bufpos] of 'r', 'R', 'c', 'C': add(tok.literal, '\c') - Inc(c.bufpos) + inc(c.bufpos) of 'l', 'L': add(tok.literal, '\L') - Inc(c.bufpos) + inc(c.bufpos) of 'f', 'F': add(tok.literal, '\f') inc(c.bufpos) of 'e', 'E': add(tok.literal, '\e') - Inc(c.bufpos) + inc(c.bufpos) of 'a', 'A': add(tok.literal, '\a') - Inc(c.bufpos) + inc(c.bufpos) of 'b', 'B': add(tok.literal, '\b') - Inc(c.bufpos) + inc(c.bufpos) of 'v', 'V': add(tok.literal, '\v') - Inc(c.bufpos) + inc(c.bufpos) of 't', 'T': add(tok.literal, '\t') - Inc(c.bufpos) + inc(c.bufpos) of 'x', 'X': inc(c.bufpos) var xi = 0 handleHexChar(c, xi) handleHexChar(c, xi) if xi == 0: tok.kind = tkInvalid - else: add(tok.literal, Chr(xi)) + else: add(tok.literal, chr(xi)) of '0'..'9': var val = ord(c.buf[c.bufpos]) - ord('0') - Inc(c.bufpos) + inc(c.bufpos) var i = 1 while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): val = val * 10 + ord(c.buf[c.bufpos]) - ord('0') @@ -1159,11 +1159,11 @@ proc getEscapedChar(c: var TPegLexer, tok: var TToken) = else: tok.kind = tkInvalid of '\0'..'\31': tok.kind = tkInvalid - elif c.buf[c.bufpos] in strutils.letters: + elif c.buf[c.bufpos] in strutils.Letters: tok.kind = tkInvalid else: add(tok.literal, c.buf[c.bufpos]) - Inc(c.bufpos) + inc(c.bufpos) proc skip(c: var TPegLexer) = var pos = c.bufpos @@ -1171,7 +1171,7 @@ proc skip(c: var TPegLexer) = while true: case buf[pos] of ' ', '\t': - Inc(pos) + inc(pos) of '#': while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos) of '\c': @@ -1203,7 +1203,7 @@ proc getString(c: var TPegLexer, tok: var TToken) = break else: add(tok.literal, buf[pos]) - Inc(pos) + inc(pos) c.bufpos = pos proc getDollar(c: var TPegLexer, tok: var TToken) = @@ -1244,7 +1244,7 @@ proc getCharSet(c: var TPegLexer, tok: var TToken) = break else: ch = buf[pos] - Inc(pos) + inc(pos) incl(tok.charset, ch) if buf[pos] == '-': if buf[pos+1] == ']': @@ -1264,7 +1264,7 @@ proc getCharSet(c: var TPegLexer, tok: var TToken) = break else: ch2 = buf[pos] - Inc(pos) + inc(pos) for i in ord(ch)+1 .. ord(ch2): incl(tok.charset, chr(i)) c.bufpos = pos @@ -1275,7 +1275,7 @@ proc getSymbol(c: var TPegLexer, tok: var TToken) = var buf = c.buf while true: add(tok.literal, buf[pos]) - Inc(pos) + inc(pos) if buf[pos] notin strutils.IdentChars: break c.bufpos = pos tok.kind = tkIdentifier @@ -1312,11 +1312,11 @@ proc getTok(c: var TPegLexer, tok: var TToken) = getCharset(c, tok) of '(': tok.kind = tkParLe - Inc(c.bufpos) + inc(c.bufpos) add(tok.literal, '(') of ')': tok.kind = tkParRi - Inc(c.bufpos) + inc(c.bufpos) add(tok.literal, ')') of '.': tok.kind = tkAny diff --git a/tests/stdlib/tsockets.nim b/tests/stdlib/tsockets.nim deleted file mode 100644 index ff566df74..000000000 --- a/tests/stdlib/tsockets.nim +++ /dev/null @@ -1,12 +0,0 @@ -import sockets, os -var s: TSocket -s = socket() -if s == InvalidSocket: osError(osLastError()) - -s.connect("www.google.com", TPort(80)) - -var data: string = "" -s.readLine(data) -echo(data) - - diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim new file mode 100644 index 000000000..f8d22bdb8 --- /dev/null +++ b/tests/types/temptyseqs.nim @@ -0,0 +1,26 @@ +discard """ + output: "1" +""" + +# bug #1708 +let foo = { + "1" : (bar: @["1"]), + "2" : (baz: @[]) +} + +# bug #871 + +when true: + import os + + type + In_out = tuple[src, dest, options: string] + + let + nil_var: In_out = ("hey"/"there", "something", nil) + #nil_var2 = ("hey"/"there", "something", nil) + +# bug #1721 +const foo2: seq[string] = @[] + +echo foo[0][0][0] diff --git a/tests/vm/triangle_array.nim b/tests/vm/triangle_array.nim new file mode 100644 index 000000000..054c66f22 --- /dev/null +++ b/tests/vm/triangle_array.nim @@ -0,0 +1,17 @@ +discard """ + output: "56" +""" + +# bug #1781 + +proc initCombinations: array[11, array[11, int]] = + result[0] = [1,2,3,4,5,6,7,8,9,10,11] + result[1][1 .. 10] = [12,13,14,15,16,17,18,19,20,21] + result[2][2 .. 10] = [22,23,24,25,26,27,28,29,30] + result[3][3 .. 10] = [31,32,33,34,35,36,37,38] + result[4][4 .. 10] = [39,40,41,42,43,44,45] + result[5][5 .. 10] = [46,47,48,49,50,51] + result[6][6 .. 10] = [52,53,54,55,56] + +const combinations = initCombinations() +echo combinations[6][10] diff --git a/tests/vm/tstringnil.nim b/tests/vm/tstringnil.nim index 5070dd6b7..61ce60ee5 100644 --- a/tests/vm/tstringnil.nim +++ b/tests/vm/tstringnil.nim @@ -32,7 +32,7 @@ proc buildSuiteContents(suiteName, suiteDesc, suiteBloc: PNimrodNode): tuple[tes testObj.testDesc = nil else: testObj.testDesc = child[2].strVal - testObj.testBlock = child[3][6] + testObj.testBlock = child[1] tests.add(testObj) diff --git a/todo.txt b/todo.txt index 6b1ec569f..b2d8b034e 100644 --- a/todo.txt +++ b/todo.txt @@ -3,8 +3,6 @@ version 0.10 - The bitwise 'not' operator will be renamed to 'bnot' to prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs! -- The 'do' notation might be trimmed so that its only purpose is to pass - multiple multi line constructs to a macro. - c2nim depends on the compiler - make nimble part of the distribution @@ -23,6 +21,7 @@ Low priority: - support for exception propagation? (hard to implement) - the copying of the 'ref Promise' into the thead local storage only happens to work due to the write barrier's implementation +- clean up the C code generator. Full of cruft. Misc @@ -62,6 +61,8 @@ version 0.9.x - we need a magic thisModule symbol - ensure (ref T)(a, b) works as a type conversion and type constructor - optimize 'genericReset'; 'newException' leads to code bloat +- The 'do' notation might be trimmed so that its only purpose is to pass + multiple multi line constructs to a macro. version 0.9.X diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index 9ee3eb9b9..fe1b9a192 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -522,8 +522,8 @@ proc setupDist2(c: var TConfigData) = # ------------------ generate ZIP file --------------------------------------- when haveZipLib: proc zipDist(c: var TConfigData) = - var proj = toLower(c.name) - var n = "$#_$#.zip" % [proj, c.version] + var proj = toLower(c.name) & "-" & c.version + var n = "$#.zip" % proj if c.outdir.len == 0: n = "build" / n else: n = c.outdir / n var z: TZipArchive diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 74f561b52..bbd3776d7 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -396,8 +396,8 @@ proc buildNewsRss(c: var TConfigData, destPath: string) = generateRss(destFilename, parseNewsTitles(srcFilename)) proc buildJS(destPath: string) = - exec("nim js -d:release --out:$1 web/babelpkglist.nim" % - [destPath / "babelpkglist.js"]) + exec("nim js -d:release --out:$1 web/nimblepkglist.nim" % + [destPath / "nimblepkglist.js"]) proc buildWebsite(c: var TConfigData) = const diff --git a/web/assets/style.css b/web/assets/style.css index f12afa838..da4cff05c 100644 --- a/web/assets/style.css +++ b/web/assets/style.css @@ -100,8 +100,9 @@ pre .end { background:url("images/tabEnd.png") no-repeat left bottom; } height:844px; background:url("images/glow-line-vert.png") no-repeat; } - #slideshow { position:absolute; top:10px; left:10px; width:700px; } - #slideshow > div { visibility:hidden; opacity:0; position:absolute; transition:visibility 0s linear 1s, opacity 1s ease-in-out; } + #slideshow { position:absolute; top:10px; left:10px; width:700px; height: 1000px; } + #slideshow > div { + visibility:hidden; opacity:0; position:absolute; transition:visibility 0s linear 1s, opacity 1s ease-in-out; } #slideshow > div.active { visibility:visible; opacity:1; transition-delay:0s; } #slideshow > div.init { transition-delay:0s; } #slideshow-nav { z-index:3; position:absolute; top:110px;; right:-12px; } diff --git a/web/community.txt b/web/community.txt index fc496ca82..f5d6db0e7 100644 --- a/web/community.txt +++ b/web/community.txt @@ -34,9 +34,9 @@ Nim's Community Github ------ - Nim's `source code <http://github.com/Araq/Nimrod>`_ is hosted on Github. - Together with the `wiki <http://github.com/Araq/Nimrod/wiki>`_ and - `issue tracker <http://github.com/Araq/Nimrod/issues>`_. + 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>`_. Github also hosts other projects relating to Nim. These projects are a part of the `nim-lang organisation <http://github.com/nim-lang>`_. diff --git a/web/download.txt b/web/download.txt index 0d3d75756..1ba1ad5f7 100644 --- a/web/download.txt +++ b/web/download.txt @@ -1,6 +1,6 @@ -You can download the latest version of the Nimrod compiler here. +You can download the latest version of the Nim compiler here. -**Note:** The Nimrod compiler requires a C compiler to compile software. On +**Note:** The Nim compiler requires a C compiler to compile software. On Windows we recommend that you use `Mingw-w64 <http://mingw-w64.sourceforge.net/>`_. GCC is recommended on Linux and clang on Mac OS X. @@ -9,10 +9,12 @@ and clang on Mac OS X. Binaries ======== -Unfortunately for now we only provide builds for Windows. +Unfortunately for now we provide no binary builds. -* 32 bit: `nimrod_0.9.6.exe <download/nimrod_0.9.6.exe>`_ -* 64 bit: `nimrod_0.9.6_x64.exe <download/nimrod_0.9.6_x64.exe>`_ +.. + Unfortunately for now we only provide builds for Windows. + * 32 bit: `nim_0.10.2.exe <download/nim-0.10.2.exe>`_ + * 64 bit: `nim_0.10.2_x64.exe <download/nim-0.10.2_x64.exe>`_ Installation based on generated C code @@ -22,13 +24,13 @@ This installation method is the preferred way for Linux, Mac OS X, and other Uni like systems. Binary packages may be provided later. -Download `nimrod_0.9.6.zip <download/nimrod_0.9.6.zip>`_, extract it and follow +Download `nim-0.10.2.zip <download/nim-0.10.2.zip>`_, extract it and follow these instructions: * sh build.sh * Add ``$your_install_dir/bin`` to your PATH. -There are other ways to install Nimrod (like using the ``install.sh`` script), +There are other ways to install Nim (like using the ``install.sh`` script), but these tend to cause more problems. @@ -38,8 +40,8 @@ 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/Nimrod.git - cd Nimrod + git clone -b master git://github.com/Araq/Nim.git + cd Nim git clone -b master --depth 1 git://github.com/nim-lang/csources cd csources && sh build.sh cd .. diff --git a/web/index.txt b/web/index.txt index 1d76c1cda..b6d4f8e8f 100644 --- a/web/index.txt +++ b/web/index.txt @@ -76,7 +76,7 @@ Nim plays nice with others the POSIX API, OpenGL, SDL, Cairo, Python, Lua, TCL, X11, libzip, PCRE, libcurl, mySQL and SQLite are included in the standard distribution or can easily be obtained via the - `Nimble package manager <https://github.com/nimrod-code/nimble>`_. + `Nimble package manager <https://github.com/nim-lang/nimble>`_. * A C to Nim conversion utility: New bindings to C libraries are easily generated by ``c2nim``. @@ -85,5 +85,5 @@ Roadmap to 1.0 ============== Please have a look at -this `wiki page <https://github.com/Araq/Nimrod/wiki/Roadmap>`_ for +this `wiki page <https://github.com/Araq/Nim/wiki/Roadmap>`_ for an up-to-date overview. diff --git a/web/learn.txt b/web/learn.txt index 25db150a4..854b31668 100644 --- a/web/learn.txt +++ b/web/learn.txt @@ -24,7 +24,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/Nimrod/wiki/Nimrod-for-C-programmers>`_ + - | `Nim for C/C++ Programmers <https://github.com/Araq/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 c55620431..75c574405 100644 --- a/web/news.txt +++ b/web/news.txt @@ -2,105 +2,197 @@ News ==== -.. - 2014-10-21 Version 0.10.2 released - ================================== - - This release is the latest release before the release canditates for version - 1.0 roll in. Starting with version 0.10.2 the rename of the language to Nim - is officially complete. As the list of language changes is quite long it's - much more work to update the average Nim project than used to be the case. - However there is a new tool, `nimfix <nimfix.html>`_ to help you - in updating your code from Nimrod to Nim. This tool is unfortunately not - perfect but has been used to update thousands of lines of code successfully. - - - Changes affecting backwards compatibility - ----------------------------------------- - - - **The language has been renamed from Nimrod to Nim.** The name of the - compiler changed from ``nimrod`` to ``nim`` too. - - ``system.fileHandle`` has been renamed to ``system.getFileHandle`` to - prevent name conflicts with the new type ``FileHandle``. - - Comments are now not part of the AST, as such you cannot use them in place - of ``discard``. - - Large parts of the stdlib got rid of the T/P type prefixes. Instead most - types now simply start with an uppercased letter. The - so called "partial case sensitivity" rule is now active allowing for code - like ``var foo: Foo`` in more contexts. - - String case (or any non-ordinal case) statements - without 'else' are deprecated. - - Recursive tuple types are not allowed anymore. Use ``object`` instead. - - The PEGS module returns ``nil`` instead of ``""`` when an optional capture - fails to match. - - The re module returns ``nil`` instead of ``""`` when an optional capture - fails to match. - - The "symmetric set difference" operator (``-+-``) never worked and has been - removed. - - ``defer`` is a keyword now. - - ``func`` is a keyword now. - - The ``using`` language feature now needs to be activated via the new - ``{.experimental.}`` pragma that enables experimental language features. - - Destructors are now officially *experimental*. - - Standalone ``except`` and ``finally`` statements are deprecated now. - The standalone ``finally`` can be replaced with ``defer``, - standalone ``except`` requires an explicit ``try``. - - Operators ending in ``>`` are considered as "arrow like" and have their - own priority level and are right associative. This means that - the ``=>`` and ``->`` operators from the `future <future.html>`_ module - work better. - - Field names in tuples are now ignored for type comparisons. This allows - for greater interoperability between different modules. - - - Language Additions - ------------------ - - - The new concurrency model has been implemented including ``locks`` sections, - lock levels and object field ``guards``. - - The ``parallel`` statement has been implemented. - - ``deepCopy`` has been added to the language. - - The builtin ``procCall`` can be used to get ``super``-like functionality - for multi methods. - - There is a new pragma ``{.experimental.}`` that enables experimental - language features per module, or you can enable this features on a global - level with the ``--experimental`` command line option. - - - Compiler Additions - ------------------ - - - The compiler now supports *mixed* Objective C / C++ / C code generation: - The modules that use ``importCpp`` or ``importObjc`` are compiled to C++ - or Objective C code, any other module is compiled to C code. This - improves interoperability. - - There is a new ``parallel`` statement for safe fork&join parallel computing. - - ``guard`` and ``lock`` pragmas have been implemented to support safer - concurrent programming. - - The following procs are now available at compile-time:: - - math.sqrt, math.ln, math.log10, math.log2, math.exp, math.round, - math.arccos, math.arcsin, math.arctan, math.arctan2, math.cos, math.cosh, - math.hypot, math.sinh, math.sin, math.tan, math.tanh, math.pow, - math.trunc, math.floor, math.ceil, math.fmod, - os.getEnv, os.existsEnv, os.dirExists, os.fileExists, - system.writeFile - - - Two backticks now produce a single backtick within an ``emit`` or ``asm`` - statement. - - There is a new tool, `nimfix <nimfix.html>`_ to help you in updating your - code from Nimrod to Nim. - +2014-12-29 Version 0.10.2 released +================================== + +This release marks the completion of a very important change to the project: +the official renaming from Nimrod to Nim. Version 0.10.2 contains many language +changes, some of which may break your existing code. For your convenience, we +added a new tool called `nimfix <nimfix.html>`_ that will help you convert your +existing projects so that it works with the latest version of the compiler. + +Progress towards version 1.0 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Although Nim is still pre-1.0, we were able to keep the number of breaking +changes to a minimum so far. Starting with version 1.0, we will not introduce +any breaking changes between major release versions. +One of Nim's goals is to ensure that the compiler is as efficient as possible. +Take a look at the +`latest benchmarks <https://github.com/logicchains/LPATHBench/blob/master/writeup.md>`_, +which show that Nim is consistently near +the top and already nearly as fast as C and C++. Recent developments, such as +the new ``asyncdispatch`` module will allow you to write efficient web server +applications using non-blocking code. Nim now also has a built-in thread pool +for lightweight threading through the use of ``spawn``. + +The unpopular "T" and "P" prefixes on types have been deprecated. Nim also +became more expressive by weakening the distinction between statements and +expressions. We also added a new and searchable forum, a new website, and our +documentation generator ``docgen`` has seen major improvements. + +What's left to be done +~~~~~~~~~~~~~~~~~~~~~~ + +The 1.0 release is actually very close. Apart from bug fixes, there are +two major features missing or incomplete: + +* ``static[T]`` needs to be defined precisely and the bugs in the + implementation need to be fixed. +* Overloading of the assignment operator is required for some generic + containers and needs to be implemented. + +This means that fancy matrix libraries will finally start to work, which used +to be a major point of pain in the language. + + +Nimble and other Nim tools +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Outside of the language and the compiler itself many Nim tools have seen +considerable improvements. + +Babel the Nim package manager has been renamed to Nimble. Nimble's purpose +is the installation of packages containing libraries and/or applications +written in Nim. +Even though Nimble is still very young it already is very +functional. It can install packages by name, it does so by accessing a +packages repository which is hosted on a Github repo. Packages can also be +installed via a Git repo URL or Mercurial repo URL. The package repository +is searchable through Nimble. Anyone is free to add their own packages to +the package repository by forking the +`nim-lang/packages <https://github.com/nim-lang/packages>`_ repo and creating +a pull request. Nimble is fully cross-platform and should be fully functional +on all major operating systems. +It is of course completely written in Nim. + +Changelog +~~~~~~~~~ + +Changes affecting backwards compatibility +----------------------------------------- + +- **The language has been renamed from Nimrod to Nim.** The name of the + compiler changed from ``nimrod`` to ``nim`` too. +- ``system.fileHandle`` has been renamed to ``system.getFileHandle`` to + prevent name conflicts with the new type ``FileHandle``. +- Comments are now not part of the AST anymore, as such you cannot use them + in place of ``discard``. +- Large parts of the stdlib got rid of the T/P type prefixes. Instead most + types now simply start with an uppercased letter. The + so called "partial case sensitivity" rule is now active allowing for code + like ``var foo: Foo`` in more contexts. +- String case (or any non-ordinal case) statements + without 'else' are deprecated. +- Recursive tuple types are not allowed anymore. Use ``object`` instead. +- The PEGS module returns ``nil`` instead of ``""`` when an optional capture + fails to match. +- The re module returns ``nil`` instead of ``""`` when an optional capture + fails to match. +- The "symmetric set difference" operator (``-+-``) never worked and has been + removed. +- ``defer`` is a keyword now. +- ``func`` is a keyword now. +- The ``using`` language feature now needs to be activated via the new + ``{.experimental.}`` pragma that enables experimental language features. +- Destructors are now officially *experimental*. +- Standalone ``except`` and ``finally`` statements are deprecated now. + The standalone ``finally`` can be replaced with ``defer``, + standalone ``except`` requires an explicit ``try``. +- Operators ending in ``>`` are considered as "arrow like" and have their + own priority level and are right associative. This means that + the ``=>`` and ``->`` operators from the `future <future.html>`_ module + work better. +- Field names in tuples are now ignored for type comparisons. This allows + for greater interoperability between different modules. +- Statement lists are not converted to an implicit ``do`` block anymore. This + means the confusing ``nnkDo`` nodes when working with macros are gone for + good. + + +Language Additions +------------------ + +- The new concurrency model has been implemented including ``locks`` sections, + lock levels and object field ``guards``. +- The ``parallel`` statement has been implemented. +- ``deepCopy`` has been added to the language. +- The builtin ``procCall`` can be used to get ``super``-like functionality + for multi methods. +- There is a new pragma ``{.experimental.}`` that enables experimental + language features per module, or you can enable this features on a global + level with the ``--experimental`` command line option. - Library Additions - ----------------- - - Added module ``fenv`` to control the handling of floating-point rounding and - exceptions (overflow, division by zero, etc.). - - ``system.setupForeignThreadGc`` can be used for better interaction with - foreign libraries that create threads and run a Nim callback from these - foreign threads. +Compiler Additions +------------------ + +- The compiler now supports *mixed* Objective C / C++ / C code generation: + The modules that use ``importCpp`` or ``importObjc`` are compiled to C++ + or Objective C code, any other module is compiled to C code. This + improves interoperability. +- There is a new ``parallel`` statement for safe fork&join parallel computing. +- ``guard`` and ``lock`` pragmas have been implemented to support safer + concurrent programming. +- The following procs are now available at compile-time:: + + math.sqrt, math.ln, math.log10, math.log2, math.exp, math.round, + math.arccos, math.arcsin, math.arctan, math.arctan2, math.cos, + math.cosh, math.hypot, math.sinh, math.sin, math.tan, math.tanh, + math.pow, math.trunc, math.floor, math.ceil, math.fmod, + os.getEnv, os.existsEnv, os.dirExists, os.fileExists, + system.writeFile + +- Two backticks now produce a single backtick within an ``emit`` or ``asm`` + statement. +- There is a new tool, `nimfix <nimfix.html>`_ to help you in updating your + code from Nimrod to Nim. +- The compiler's output has been prettified. + +Library Additions +----------------- + +- Added module ``fenv`` to control the handling of floating-point rounding and + exceptions (overflow, division by zero, etc.). +- ``system.setupForeignThreadGc`` can be used for better interaction with + foreign libraries that create threads and run a Nim callback from these + foreign threads. +- List comprehensions have been implemented as a macro in the ``future`` + module. +- The new Async module (``asyncnet``) now supports SSL. +- The ``smtp`` module now has an async implementation. +- Added module ``asyncfile`` which implements asynchronous file reading + and writing. +- ``osproc.kill`` has been added. +- ``asyncnet`` and ``asynchttpserver`` now support ``SO_REUSEADDR``. + +Bugfixes +-------- +- ``nil`` and ``NULL`` are now preserved between Nim and databases in the + ``db_*`` modules. +- Fixed issue with OS module in non-unicode mode on Windows. +- Fixed issue with ``x.low`` + (`#1366 <https://github.com/Araq/Nim/issues/1366>`_). +- Fixed tuple unpacking issue inside closure iterators + (`#1067 <https://github.com/Araq/Nim/issues/1067>`_). +- Fixed ENDB compilation issues. +- Many ``asynchttpserver`` fixes. +- Macros can now keep global state across macro calls + (`#903 <https://github.com/Araq/Nim/issues/903>`_). +- ``osproc`` fixes on Windows. +- ``osproc.terminate`` fixed. +- Improvements to exception handling in async procedures. + (`#1487 <https://github.com/Araq/Nim/issues/1487>`_). +- ``try`` now works at compile-time. +- Fixes ``T = ref T`` to be an illegal recursive type. +- Self imports are now disallowed. +- Improved effect inference. +- Fixes for the ``math`` module on Windows. +- User defined pragmas will now work for generics that have + been instantiated in different modules. +- Fixed queue exhaustion bug. +- Many, many more. 2014-12-09 New website design! ============================== diff --git a/web/babelpkglist.nim b/web/nimblepkglist.nim index aeea57a0d..7070f281b 100644 --- a/web/babelpkglist.nim +++ b/web/nimblepkglist.nim @@ -41,6 +41,7 @@ proc processContent(content: string) = dot = if desc.high > 0 and desc[desc.high] in endings: "" else: "." listItem = li(a(href=pkgWeb, pkg["name"].str), " ", desc & dot) if pkg["url"].str.startsWith("git://github.com/nimrod-code") or + pkg["url"].str.startsWith("git://github.com/nim-lang") or "official" in pkg["tags"].elems: officialCount.inc officialList.add listItem & "\n" @@ -52,14 +53,14 @@ proc processContent(content: string) = officialPkgListDiv.innerHTML = p("There are currently " & $officialCount & - " official packages in the Babel package repository.") & + " official packages in the Nimble package repository.") & ul(officialList) var unofficialPkgListDiv = document.getElementById("unofficialPkgList") unofficialPkgListDiv.innerHTML = p("There are currently " & $unofficialCount & - " unofficial packages in the Babel package repository.") & + " unofficial packages in the Nimble package repository.") & ul(unofficialList) proc gotPackageList(apiReply: TData) {.exportc.} = diff --git a/web/ticker.txt b/web/ticker.txt index a0d2f0a78..64218084e 100644 --- a/web/ticker.txt +++ b/web/ticker.txt @@ -1,13 +1,13 @@ +<a class="news" href="news.html#Z2014-12-29-version-0-10-2-released"> + <h4>Dec 29, 2014</h4> + <p>Nim version 0.10.2 has been released!</p> +</a> + <a class="news" href="news.html#Z2014-12-09-new-website-design"> <h4>Dec 9, 2014</h4> <p>The new website design and forum are now online!</p> </a> -<a class="news" href="news.html#Z2014-10-19-version-0-9-6-released"> - <h4>Oct 19, 2014</h4> - <p>Nimrod version 0.9.6 has been released!</p> -</a> - <a class="news" href="news.html#Z2014-02-11-nimrod-featured-in-dr-dobb-s-journal"> <h4>Feb 11, 2014</h4> <p>Nimrod featured in Dr. Dobb's Journal</p> |