diff options
-rw-r--r-- | compiler/ast.nim | 4 | ||||
-rw-r--r-- | compiler/commands.nim | 4 | ||||
-rw-r--r-- | compiler/lexer.nim | 6 | ||||
-rw-r--r-- | compiler/options.nim | 1 | ||||
-rw-r--r-- | compiler/parser.nim | 55 | ||||
-rw-r--r-- | compiler/pragmas.nim | 8 | ||||
-rw-r--r-- | compiler/sem.nim | 3 | ||||
-rw-r--r-- | compiler/semdata.nim | 5 | ||||
-rw-r--r-- | compiler/semexprs.nim | 2 | ||||
-rw-r--r-- | compiler/semstmts.nim | 21 | ||||
-rw-r--r-- | compiler/wordrecg.nim | 9 | ||||
-rw-r--r-- | doc/advopt.txt | 1 | ||||
-rw-r--r-- | doc/gc.txt | 3 | ||||
-rw-r--r-- | doc/grammar.txt | 26 | ||||
-rw-r--r-- | doc/keywords.txt | 2 | ||||
-rw-r--r-- | doc/manual/pragmas.txt | 18 | ||||
-rw-r--r-- | doc/manual/stmts.txt | 3 | ||||
-rw-r--r-- | doc/manual/syntax.txt | 50 | ||||
-rw-r--r-- | lib/core/locks.nim | 21 | ||||
-rw-r--r-- | lib/core/macros.nim | 2 | ||||
-rw-r--r-- | lib/core/typeinfo.nim | 9 | ||||
-rw-r--r-- | lib/impure/db_mysql.nim | 7 | ||||
-rw-r--r-- | lib/packages/docutils/highlite.nim | 5 | ||||
-rw-r--r-- | lib/pure/parseutils.nim | 95 | ||||
-rw-r--r-- | lib/system.nim | 16 | ||||
-rw-r--r-- | lib/system/platforms.nim | 74 | ||||
-rw-r--r-- | lib/system/sysstr.nim | 4 | ||||
-rw-r--r-- | lib/windows/windows.nim | 10 | ||||
-rw-r--r-- | todo.txt | 5 | ||||
-rw-r--r-- | web/news.txt | 6 |
30 files changed, 267 insertions, 208 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 62f2d105f..8ebe5afa6 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -160,6 +160,7 @@ type nkConstDef, # a const definition nkTypeDef, # a type definition nkYieldStmt, # the yield statement as a tree + nkDefer, # the 'defer' statement nkTryStmt, # a try statement nkFinally, # a finally section nkRaiseStmt, # a raise statement @@ -293,6 +294,7 @@ const # require RC ops sfCompileToCpp* = sfInfixCall # compile the module as C++ code sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code + sfExperimental* = sfOverriden # module uses the .experimental switch const # getting ready for the future expr/stmt merge @@ -566,7 +568,7 @@ type mBool, mChar, mString, mCstring, mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy, - mIsMainModule, mCompileDate, mCompileTime, mProcCall, + mIsMainModule, mCompileDate, mCompileTime, mProcCall, mCpuEndian, mHostOS, mHostCPU, mAppType, mNaN, mInf, mNegInf, mCompileOption, mCompileOptionArg, diff --git a/compiler/commands.nim b/compiler/commands.nim index f26d1d6c7..a5b0b40d7 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -226,6 +226,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool = of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation) of "implicitstatic": result = contains(gOptions, optImplicitStatic) of "patterns": result = contains(gOptions, optPatterns) + of "experimental": result = gExperimentalMode else: invalidCmdLineOption(passCmd1, switch, info) proc processPath(path: string, notRelativeToProj = false): string = @@ -568,6 +569,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "none": idents.firstCharIsCS = false else: localError(info, errGenerated, "'partial' or 'none' expected, but found " & arg) + of "experimental": + expectNoArg(switch, arg, pass, info) + gExperimentalMode = true else: if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) else: invalidCmdLineOption(pass, switch, info) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index dbeec8acf..fb74f27d6 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -35,7 +35,8 @@ type tkSymbol, # keywords: tkAddr, tkAnd, tkAs, tkAsm, tkAtomic, tkBind, tkBlock, tkBreak, tkCase, tkCast, - tkConst, tkContinue, tkConverter, tkDiscard, tkDistinct, tkDiv, tkDo, + tkConst, tkContinue, tkConverter, + tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo, tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface, @@ -71,7 +72,8 @@ const "tkSymbol", "addr", "and", "as", "asm", "atomic", "bind", "block", "break", "case", "cast", - "const", "continue", "converter", "discard", "distinct", "div", "do", + "const", "continue", "converter", + "defer", "discard", "distinct", "div", "do", "elif", "else", "end", "enum", "except", "export", "finally", "for", "from", "generic", "if", "import", "in", "include", "interface", "is", "isnot", "iterator", diff --git a/compiler/options.nim b/compiler/options.nim index 838f99f8e..415ac8430 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -115,6 +115,7 @@ var # the tracked source X, saved by the CAAS client. gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer. gNoNimblePath* = false + gExperimentalMode*: bool proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools} proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc diff --git a/compiler/parser.nim b/compiler/parser.nim index e4de75a07..a91760e15 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -188,18 +188,13 @@ proc parseTypeDesc(p: var TParser): PNode proc parseDoBlocks(p: var TParser, call: PNode) proc parseParamList(p: var TParser, retColon = true): PNode -proc relevantOprChar(ident: PIdent): char {.inline.} = - result = ident.s[0] - var L = ident.s.len - if result == '\\' and L > 1: - result = ident.s[1] - proc isSigilLike(tok: TToken): bool {.inline.} = - result = tok.tokType == tkOpr and relevantOprChar(tok.ident) == '@' + result = tok.tokType == tkOpr and tok.ident.s[0] == '@' -proc isLeftAssociative(tok: TToken): bool {.inline.} = - ## Determines whether the token is left assocative. - result = tok.tokType != tkOpr or relevantOprChar(tok.ident) != '^' +proc isRightAssociative(tok: TToken): bool {.inline.} = + ## Determines whether the token is right assocative. + result = tok.tokType == tkOpr and (tok.ident.s[0] == '^' or + (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>')) proc getPrecedence(tok: TToken, strongSpaces: bool): int = ## Calculates the precedence of the given token. @@ -209,7 +204,10 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int = case tok.tokType of tkOpr: let L = tok.ident.s.len - let relevantChar = relevantOprChar(tok.ident) + let relevantChar = tok.ident.s[0] + + # arrow like? + if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1) template considerAsgn(value: expr) = result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value) @@ -269,17 +267,18 @@ proc checkBinary(p: TParser) {.inline.} = #| #| optInd = COMMENT? #| optPar = (IND{>} | IND{=})? -#| -#| simpleExpr = assignExpr (OP0 optInd assignExpr)* -#| assignExpr = orExpr (OP1 optInd orExpr)* -#| orExpr = andExpr (OP2 optInd andExpr)* -#| andExpr = cmpExpr (OP3 optInd cmpExpr)* -#| cmpExpr = sliceExpr (OP4 optInd sliceExpr)* -#| sliceExpr = ampExpr (OP5 optInd ampExpr)* -#| ampExpr = plusExpr (OP6 optInd plusExpr)* -#| plusExpr = mulExpr (OP7 optInd mulExpr)* -#| mulExpr = dollarExpr (OP8 optInd dollarExpr)* -#| dollarExpr = primary (OP9 optInd primary)* +#| +#| simpleExpr = arrowExpr (OP0 optInd arrowExpr)* +#| arrowExpr = assignExpr (OP1 optInd assignExpr)* +#| assignExpr = orExpr (OP2 optInd orExpr)* +#| orExpr = andExpr (OP3 optInd andExpr)* +#| andExpr = cmpExpr (OP4 optInd cmpExpr)* +#| cmpExpr = sliceExpr (OP5 optInd sliceExpr)* +#| sliceExpr = ampExpr (OP6 optInd ampExpr)* +#| ampExpr = plusExpr (OP7 optInd plusExpr)* +#| plusExpr = mulExpr (OP8 optInd mulExpr)* +#| mulExpr = dollarExpr (OP9 optInd dollarExpr)* +#| dollarExpr = primary (OP10 optInd primary)* proc colcom(p: var TParser, n: PNode) = eat(p, tkColon) @@ -734,7 +733,7 @@ proc parseOperators(p: var TParser, headNode: PNode, # the operator itself must not start on a new line: while opPrec >= limit and p.tok.indent < 0 and not isUnary(p): checkBinary(p) - var leftAssoc = ord(isLeftAssociative(p.tok)) + var leftAssoc = 1-ord(isRightAssociative(p.tok)) var a = newNodeP(nkInfix, p) var opNode = newIdentNodeP(p.tok.ident, p) # skip operator: getTok(p) @@ -1423,9 +1422,10 @@ proc parseBlock(p: var TParser): PNode = colcom(p, result) addSon(result, parseStmt(p)) -proc parseStatic(p: var TParser): PNode = +proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode = #| staticStmt = 'static' colcom stmt - result = newNodeP(nkStaticStmt, p) + #| deferStmt = 'defer' colcom stmt + result = newNodeP(k, p) getTokNoInd(p) colcom(p, result) addSon(result, parseStmt(p)) @@ -1863,7 +1863,7 @@ proc simpleStmt(p: var TParser): PNode = proc complexOrSimpleStmt(p: var TParser): PNode = #| complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt #| | tryStmt | finallyStmt | exceptStmt | forStmt - #| | blockStmt | staticStmt | asmStmt + #| | blockStmt | staticStmt | deferStmt | asmStmt #| | 'proc' routine #| | 'method' routine #| | 'iterator' routine @@ -1884,7 +1884,8 @@ proc complexOrSimpleStmt(p: var TParser): PNode = of tkExcept: result = parseExceptBlock(p, nkExceptBranch) of tkFor: result = parseFor(p) of tkBlock: result = parseBlock(p) - of tkStatic: result = parseStatic(p) + of tkStatic: result = parseStaticOrDefer(p, nkStaticStmt) + of tkDefer: result = parseStaticOrDefer(p, nkDefer) of tkAsm: result = parseAsm(p) of tkProc: result = parseRoutine(p, nkProcDef) of tkMethod: result = parseRoutine(p, nkMethodDef) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index b548837fe..879950e79 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -45,7 +45,7 @@ const wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated, wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto, - wInjectStmt, wDeprecated} + wInjectStmt, wDeprecated, wExperimental} lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader, wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame, @@ -850,6 +850,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, localError(it.info, errExprExpected) else: it.sons[1] = c.semExpr(c, it.sons[1]) + of wExperimental: + noVal(it) + if isTopLevel(c): + c.module.flags.incl sfExperimental + else: + localError(it.info, "'experimental' pragma only valid as toplevel statement") else: invalidPragma(it) else: invalidPragma(it) else: processNote(c, it) diff --git a/compiler/sem.nim b/compiler/sem.nim index 5b31129a5..5160af20a 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -133,9 +133,6 @@ proc commonType*(x, y: PType): PType = result = newType(k, r.owner) result.addSonSkipIntLit(r) -proc isTopLevel(c: PContext): bool {.inline.} = - result = c.currentScope.depthLevel <= 2 - proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 921e87d30..f876770c0 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -312,3 +312,8 @@ proc checkSonsLen*(n: PNode, length: int) = proc checkMinSonsLen*(n: PNode, length: int) = if sonsLen(n) < length: illFormedAst(n) +proc isTopLevel*(c: PContext): bool {.inline.} = + result = c.currentScope.depthLevel <= 2 + +proc experimentalMode*(c: PContext): bool {.inline.} = + result = gExperimentalMode or sfExperimental in c.module.flags diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 108e21369..ac82e9fed 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1433,6 +1433,8 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo, proc semUsing(c: PContext, n: PNode): PNode = result = newNodeI(nkEmpty, n.info) + if not experimentalMode(c): + localError(n.info, "use the {.experimental.} pragma to enable 'using'") for e in n.sons: let usedSym = semExpr(c, e) if usedSym.kind == nkSym: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c6906d98e..933ac7daf 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1362,8 +1362,9 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = # nkNilLit, nkEmpty}: # dec last for i in countup(0, length - 1): - case n.sons[i].kind - of nkFinally, nkExceptBranch: + let k = n.sons[i].kind + case k + of nkFinally, nkExceptBranch, nkDefer: # stand-alone finally and except blocks are # transformed into regular try blocks: # @@ -1372,12 +1373,24 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = # ... | ... # | finally: # | fclose(f) + var deferPart: PNode + if k == nkDefer: + deferPart = newNodeI(nkFinally, n.sons[i].info) + deferPart.add n.sons[i].sons[0] + elif k == nkFinally: + message(n.info, warnDeprecated, + "use 'defer'; standalone 'finally'") + deferPart = n.sons[i] + else: + message(n.info, warnDeprecated, + "use an explicit 'try'; standalone 'except'") + deferPart = n.sons[i] var tryStmt = newNodeI(nkTryStmt, n.sons[i].info) var body = newNodeI(nkStmtList, n.sons[i].info) if i < n.sonsLen - 1: body.sons = n.sons[(i+1)..(-1)] tryStmt.addSon(body) - tryStmt.addSon(n.sons[i]) + tryStmt.addSon(deferPart) n.sons[i] = semTry(c, tryStmt) n.sons.setLen(i+1) return @@ -1424,7 +1437,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = # a statement list (s; e) has the type 'e': if result.kind == nkStmtList and result.len > 0: var lastStmt = lastSon(result) - if lastStmt.kind != nkNilLit and not ImplicitlyDiscardable(lastStmt): + if lastStmt.kind != nkNilLit and not implicitlyDiscardable(lastStmt): result.typ = lastStmt.typ #localError(lastStmt.info, errGenerated, # "Last expression must be explicitly returned if it " & diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 068f59c71..f08ab0ad9 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -24,7 +24,7 @@ type wAddr, wAnd, wAs, wAsm, wAtomic, wBind, wBlock, wBreak, wCase, wCast, wConst, - wContinue, wConverter, wDiscard, wDistinct, wDiv, wDo, + wContinue, wConverter, wDefer, wDiscard, wDistinct, wDiv, wDo, wElif, wElse, wEnd, wEnum, wExcept, wExport, wFinally, wFor, wFrom, wGeneric, wIf, wImport, wIn, wInclude, wInterface, wIs, wIsnot, wIterator, wLet, @@ -61,7 +61,8 @@ type wPassc, wPassl, wBorrow, wDiscardable, wFieldChecks, wWatchPoint, wSubsChar, - wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt, + wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, + wInjectStmt, wExperimental, wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit, wAsmNoStackFrame, wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks, @@ -103,7 +104,7 @@ const "addr", "and", "as", "asm", "atomic", "bind", "block", "break", "case", "cast", "const", "continue", "converter", - "discard", "distinct", "div", "do", + "defer", "discard", "distinct", "div", "do", "elif", "else", "end", "enum", "except", "export", "finally", "for", "from", "generic", "if", "import", "in", "include", "interface", "is", "isnot", "iterator", @@ -144,7 +145,7 @@ const "passc", "passl", "borrow", "discardable", "fieldchecks", "watchpoint", "subschar", "acyclic", "shallow", "unroll", "linearscanend", - "computedgoto", "injectstmt", + "computedgoto", "injectstmt", "experimental", "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit", "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked", "guard", "locks", diff --git a/doc/advopt.txt b/doc/advopt.txt index 2ddba12e8..78c3d571a 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -91,4 +91,5 @@ Advanced options: --verbosity:0|1|2|3 set Nim's verbosity level (1 is default) --cs:none|partial set case sensitivity level (default: none); do not use! this setting affects the whole language + --experimental enable experimental language features -v, --version show detailed version information diff --git a/doc/gc.txt b/doc/gc.txt index fdb1d1b6c..9398262d9 100644 --- a/doc/gc.txt +++ b/doc/gc.txt @@ -47,7 +47,8 @@ Realtime support ================ To enable realtime support, the symbol `useRealtimeGC`:idx: needs to be -defined. With this switch the GC supports the following operations: +defined via ``--define:useRealtimeGC`` (you can put this into your config +file as well). With this switch the GC supports the following operations: .. code-block:: nim proc GC_setMaxPause*(MaxPauseInUs: int) diff --git a/doc/grammar.txt b/doc/grammar.txt index a54428678..e751c2d8d 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -4,7 +4,7 @@ semicolon = ';' COMMENT? colon = ':' COMMENT? colcom = ':' COMMENT? -operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 +operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 | OP10 | 'or' | 'xor' | 'and' | 'is' | 'isnot' | 'in' | 'notin' | 'of' | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'addr' | 'static' | '..' @@ -14,16 +14,17 @@ prefixOperator = operator optInd = COMMENT? optPar = (IND{>} | IND{=})? -simpleExpr = assignExpr (OP0 optInd assignExpr)* -assignExpr = orExpr (OP1 optInd orExpr)* -orExpr = andExpr (OP2 optInd andExpr)* -andExpr = cmpExpr (OP3 optInd cmpExpr)* -cmpExpr = sliceExpr (OP4 optInd sliceExpr)* -sliceExpr = ampExpr (OP5 optInd ampExpr)* -ampExpr = plusExpr (OP6 optInd plusExpr)* -plusExpr = mulExpr (OP7 optInd mulExpr)* -mulExpr = dollarExpr (OP8 optInd dollarExpr)* -dollarExpr = primary (OP9 optInd primary)* +simpleExpr = arrowExpr (OP0 optInd arrowExpr)* +arrowExpr = assignExpr (OP1 optInd assignExpr)* +assignExpr = orExpr (OP2 optInd orExpr)* +orExpr = andExpr (OP3 optInd andExpr)* +andExpr = cmpExpr (OP4 optInd cmpExpr)* +cmpExpr = sliceExpr (OP5 optInd sliceExpr)* +sliceExpr = ampExpr (OP6 optInd ampExpr)* +ampExpr = plusExpr (OP7 optInd plusExpr)* +plusExpr = mulExpr (OP8 optInd mulExpr)* +mulExpr = dollarExpr (OP9 optInd dollarExpr)* +dollarExpr = primary (OP10 optInd primary)* symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' | IDENT indexExpr = expr @@ -142,6 +143,7 @@ exceptBlock = 'except' colcom stmt forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt blockStmt = 'block' symbol? colcom stmt staticStmt = 'static' colcom stmt +deferStmt = 'defer' colcom stmt asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT) genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)? genericParamList = '[' optInd @@ -182,7 +184,7 @@ simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt | includeStmt | commentStmt) / exprStmt) COMMENT? complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt | tryStmt | finallyStmt | exceptStmt | forStmt - | blockStmt | staticStmt | asmStmt + | blockStmt | staticStmt | deferStmt | asmStmt | 'proc' routine | 'method' routine | 'iterator' routine diff --git a/doc/keywords.txt b/doc/keywords.txt index a43b35475..67ff0ab7f 100644 --- a/doc/keywords.txt +++ b/doc/keywords.txt @@ -1,7 +1,7 @@ addr and as asm atomic bind block break case cast const continue converter -discard distinct div do +defer discard distinct div do elif else end enum except export finally for from generic diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt index 6181b3e1b..6bb1314cd 100644 --- a/doc/manual/pragmas.txt +++ b/doc/manual/pragmas.txt @@ -495,3 +495,21 @@ identifier that can be used to enable or disable it: This is often better than disabling all warnings at once. +experimental pragma +------------------- + +The ``experimental`` pragma enables experimental language features. Depending +on the concrete feature this means that the feature is either considered +too unstable for an otherwise stable release or that the future of the feature +is uncertain (it may be removed any time). + +Example: + +.. code-block:: nim + {.experimental.} + + proc useUsing(dest: var string) = + using dest + add "foo" + add "bar" + diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt index 8d958733d..e31be7121 100644 --- a/doc/manual/stmts.txt +++ b/doc/manual/stmts.txt @@ -488,7 +488,8 @@ Instead of: Using statement --------------- -**Warning**: The ``using`` statement is highly experimental! +**Warning**: The ``using`` statement is highly experimental and has to be +explicitly enabled with the `experimental`:idx: pragma or command line option! The using statement provides syntactic convenience for procs that heavily use a single contextual parameter. When applied to a variable or a diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt index 0ae353edd..c975e7f48 100644 --- a/doc/manual/syntax.txt +++ b/doc/manual/syntax.txt @@ -5,24 +5,21 @@ This section lists Nim's standard syntax. How the parser handles the indentation is already described in the `Lexical Analysis`_ section. Nim allows user-definable operators. -Binary operators have 10 different levels of precedence. +Binary operators have 11 different levels of precedence. -Relevant character ------------------- - -An operator symbol's *relevant character* is its first -character unless the first character is ``\`` and its length is greater than 1 -then it is the second character. - -This rule allows to escape operator symbols with ``\`` and keeps the operator's -precedence and associativity; this is useful for meta programming. Associativity ------------- -Binary operators whose relevant character is ``^`` are right-associative, all -other binary operators are left-associative. +Binary operators whose first character is ``^`` or its last character +is ``>`` are right-associative, all other binary operators are left-associative. + +Exception: The single "greater than" ``>`` operator is left-associative too. + +Operators ending in ``>`` but longer than a single character are +called `arrow like`:idx:. + Precedence ---------- @@ -30,7 +27,7 @@ Precedence Unary operators always bind stronger than any binary operator: ``$a + b`` is ``($a) + b`` and not ``$(a + b)``. -If an unary operator's relevant character is ``@`` it is a `sigil-like`:idx: +If an unary operator's first character is ``@`` it is a `sigil-like`:idx: operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``. @@ -38,25 +35,26 @@ as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``. For binary operators that are not keywords the precedence is determined by the following rules: -If the operator ends with ``=`` and its relevant character is none of +If the operator ends with ``=`` and its first character is none of ``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which has the lowest precedence. -Otherwise precedence is determined by the relevant character. +Otherwise precedence is determined by the first character. ================ =============================================== ================== =============== -Precedence level Operators Relevant character Terminal symbol +Precedence level Operators First character Terminal symbol ================ =============================================== ================== =============== - 9 (highest) ``$ ^`` OP9 - 8 ``* / div mod shl shr %`` ``* % \ /`` OP8 - 7 ``+ -`` ``+ ~ |`` OP7 - 6 ``&`` ``&`` OP6 - 5 ``..`` ``.`` OP5 - 4 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP4 - 3 ``and`` OP3 - 2 ``or xor`` OP2 - 1 ``@ : ?`` OP1 - 0 (lowest) *assignment operator* (like ``+=``, ``*=``) OP0 + 10 (highest) ``$ ^`` OP10 + 9 ``* / div mod shl shr %`` ``* % \ /`` OP9 + 8 ``+ -`` ``+ ~ |`` OP8 + 7 ``&`` ``&`` OP7 + 6 ``..`` ``.`` OP6 + 5 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP5 + 4 ``and`` OP4 + 3 ``or xor`` OP3 + 2 ``@ : ?`` OP2 + 1 *assignment operator* (like ``+=``, ``*=``) OP1 + 0 (lowest) *arrow like operator* (like ``->``, ``=>``) OP0 ================ =============================================== ================== =============== diff --git a/lib/core/locks.nim b/lib/core/locks.nim index 4e85474fb..766b7b536 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -16,12 +16,15 @@ type ## or not is unspecified! TCond* = TSysCond ## Nim condition variable - LockEffect* = object of RootEffect ## effect that denotes that some lock operation - ## is performed - AquireEffect* = object of LockEffect ## effect that denotes that some lock is - ## aquired - ReleaseEffect* = object of LockEffect ## effect that denotes that some lock is - ## released + LockEffect* {.deprecated.} = object of RootEffect ## \ + ## effect that denotes that some lock operation + ## is performed. Deprecated, do not use anymore! + AquireEffect* {.deprecated.} = object of LockEffect ## \ + ## effect that denotes that some lock is + ## aquired. Deprecated, do not use anymore! + ReleaseEffect* {.deprecated.} = object of LockEffect ## \ + ## effect that denotes that some lock is + ## released. Deprecated, do not use anymore! {.deprecated: [FLock: LockEffect, FAquireLock: AquireEffect, FReleaseLock: ReleaseEffect].} @@ -33,15 +36,15 @@ proc deinitLock*(lock: var TLock) {.inline.} = ## Frees the resources associated with the lock. deinitSys(lock) -proc tryAcquire*(lock: var TLock): bool {.tags: [AquireEffect].} = +proc tryAcquire*(lock: var TLock): bool = ## Tries to acquire the given lock. Returns `true` on success. result = tryAcquireSys(lock) -proc acquire*(lock: var TLock) {.tags: [AquireEffect].} = +proc acquire*(lock: var TLock) = ## Acquires the given lock. acquireSys(lock) -proc release*(lock: var TLock) {.tags: [ReleaseEffect].} = +proc release*(lock: var TLock) = ## Releases the given lock. releaseSys(lock) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index b61fe1d17..ed5d3c50c 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -46,7 +46,7 @@ type nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt, nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection, nnkConstDef, nnkTypeDef, - nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt, + nnkYieldStmt, nnkDefer, nnkTryStmt, nnkFinally, nnkRaiseStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt, nnkDiscardStmt, nnkStmtList, nnkImportStmt, diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 84281485f..f3f00f9f5 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -7,9 +7,12 @@ # distribution, for details about the copyright. # -## This module implements an interface to Nimrod's runtime type information. +## This module implements an interface to Nim's runtime type information. ## Note that even though ``TAny`` and its operations hide the nasty low level ## details from its clients, it remains inherently unsafe! +## +## See the `marshal <marshal.html>`_ module for what this module allows you +## to do. {.push hints: off.} @@ -51,7 +54,7 @@ type akUInt32 = 43, ## any represents an unsigned int32 akUInt64 = 44, ## any represents an unsigned int64 - TAny* = object {.pure.} ## can represent any nim value; NOTE: the wrapped + TAny* = object ## can represent any nim value; NOTE: the wrapped ## value can be modified with its wrapper! This means ## that ``TAny`` keeps a non-traced pointer to its ## wrapped value and **must not** live longer than @@ -62,7 +65,7 @@ type ppointer = ptr pointer pbyteArray = ptr array[0.. 0xffff, int8] - TGenSeq {.pure.} = object + TGenSeq = object len, space: int PGenSeq = ptr TGenSeq diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index 37bea45b4..968a2923a 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -220,13 +220,12 @@ proc open*(connection, user, password, database: string): TDbConn {. if result == nil: dbError("could not open database connection") let colonPos = connection.find(':') - host = if colonPos < 0: connection - else: substr(connection, 0, colonPos-1) + host = if colonPos < 0: connection + else: substr(connection, 0, colonPos-1) port: int32 = if colonPos < 0: 0'i32 - else: substr(connection, colonPos+1).parseInt.int32 + else: substr(connection, colonPos+1).parseInt.int32 if mysql.realConnect(result, host, user, password, database, port, nil, 0) == nil: var errmsg = $mysql.error(result) db_mysql.close(result) dbError(errmsg) - diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index d4bd94e5e..9c482575a 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -47,8 +47,9 @@ const # The following list comes from doc/keywords.txt, make sure it is # synchronized with this array by running the module itself as a test case. nimKeywords = ["addr", "and", "as", "asm", "atomic", "bind", "block", - "break", "case", "cast", "const", "continue", "converter", "discard", - "distinct", "div", "do", "elif", "else", "end", "enum", "except", "export", + "break", "case", "cast", "const", "continue", "converter", + "defer", "discard", "distinct", "div", "do", + "elif", "else", "end", "enum", "except", "export", "finally", "for", "from", "generic", "if", "import", "in", "include", "interface", "is", "isnot", "iterator", "let", "macro", "method", "mixin", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc", diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 8f8ca6ab3..1efb141fc 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -231,96 +231,11 @@ proc parseInt*(s: string, number: var int, start = 0): int {. else: number = int(res) -when defined(nimParseBiggestFloatMagic): - proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {. - magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.} - ## parses a float starting at `start` and stores the value into `number`. - ## Result is the number of processed chars or 0 if a parsing error - ## occurred. -else: - proc tenToThePowerOf(b: int): BiggestFloat = - var b = b - var a = 10.0 - result = 1.0 - while true: - if (b and 1) == 1: - result *= a - b = b shr 1 - if b == 0: break - a *= a - - proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {. - rtl, extern: "npuParseBiggestFloat", noSideEffect.} = - ## parses a float starting at `start` and stores the value into `number`. - ## Result is the number of processed chars or 0 if there occured a parsing - ## error. - var - esign = 1.0 - sign = 1.0 - i = start - exponent: int - flags: int - number = 0.0 - if s[i] == '+': inc(i) - elif s[i] == '-': - sign = -1.0 - inc(i) - if s[i] == 'N' or s[i] == 'n': - if s[i+1] == 'A' or s[i+1] == 'a': - if s[i+2] == 'N' or s[i+2] == 'n': - if s[i+3] notin IdentChars: - number = NaN - return i+3 - start - return 0 - if s[i] == 'I' or s[i] == 'i': - if s[i+1] == 'N' or s[i+1] == 'n': - if s[i+2] == 'F' or s[i+2] == 'f': - if s[i+3] notin IdentChars: - number = Inf*sign - return i+3 - start - return 0 - while s[i] in {'0'..'9'}: - # Read integer part - flags = flags or 1 - number = number * 10.0 + toFloat(ord(s[i]) - ord('0')) - inc(i) - while s[i] == '_': inc(i) - # Decimal? - if s[i] == '.': - var hd = 1.0 - inc(i) - while s[i] in {'0'..'9'}: - # Read fractional part - flags = flags or 2 - number = number * 10.0 + toFloat(ord(s[i]) - ord('0')) - hd = hd * 10.0 - inc(i) - while s[i] == '_': inc(i) - number = number / hd # this complicated way preserves precision - # Again, read integer and fractional part - if flags == 0: return 0 - # Exponent? - if s[i] in {'e', 'E'}: - inc(i) - if s[i] == '+': - inc(i) - elif s[i] == '-': - esign = -1.0 - inc(i) - if s[i] notin {'0'..'9'}: - return 0 - while s[i] in {'0'..'9'}: - exponent = exponent * 10 + ord(s[i]) - ord('0') - inc(i) - while s[i] == '_': inc(i) - # Calculate Exponent - let hd = tenToThePowerOf(exponent) - if esign > 0.0: number = number * hd - else: number = number / hd - # evaluate sign - number = number * sign - result = i - start - +proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {. + magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.} + ## parses a float starting at `start` and stores the value into `number`. + ## Result is the number of processed chars or 0 if a parsing error + ## occurred. proc parseFloat*(s: string, number: var float, start = 0): int {. rtl, extern: "npuParseFloat", noSideEffect.} = diff --git a/lib/system.nim b/lib/system.nim index 269dbb1e0..0cd4b84e2 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1020,16 +1020,16 @@ const ## is the endianness of the target CPU. This is a valuable piece of ## information for low-level code only. This works thanks to compiler ## magic. - - hostOS* {.magic: "HostOS"}: string = "" + + hostOS* {.magic: "HostOS".}: string = "" ## a string that describes the host operating system. Possible values: ## "windows", "macosx", "linux", "netbsd", "freebsd", "openbsd", "solaris", ## "aix", "standalone". - - hostCPU* {.magic: "HostCPU"}: string = "" + + hostCPU* {.magic: "HostCPU".}: string = "" ## a string that describes the host CPU. Possible values: - ## "i386", "alpha", "powerpc", "sparc", "amd64", "mips", "arm". - + ## "i386", "alpha", "powerpc", "powerpc64", "sparc", "amd64", "mips", "arm". + seqShallowFlag = low(int) proc compileOption*(option: string): bool {. @@ -2120,7 +2120,7 @@ elif hostOS != "standalone": inc(i) {.pop.} -proc echo*(x: varargs[string, `$`]) {.magic: "Echo", tags: [WriteIOEffect], benign.} +proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect], benign.} ## Writes and flushes the parameters to the standard output. ## ## Special built-in that takes a variable number of arguments. Each argument @@ -2135,7 +2135,7 @@ proc echo*(x: varargs[string, `$`]) {.magic: "Echo", tags: [WriteIOEffect], beni ## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_ ## instead. -proc debugEcho*(x: varargs[string, `$`]) {.magic: "Echo", noSideEffect, +proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect, tags: [], raises: [].} ## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho`` ## pretends to be free of side effects, so that it can be used for debugging diff --git a/lib/system/platforms.nim b/lib/system/platforms.nim new file mode 100644 index 000000000..3ec6a270e --- /dev/null +++ b/lib/system/platforms.nim @@ -0,0 +1,74 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Platform detection for Nim. This module is included by the system module! +## Do not import it directly! + +type + CpuPlatform* {.pure.} = enum ## the CPU this program will run on. + none, ## unknown CPU + i386, ## 32 bit x86 compatible CPU + m68k, ## M68k based processor + alpha, ## Alpha processor + powerpc, ## 32 bit PowerPC + powerpc64, ## 64 bit PowerPC + sparc, ## Sparc based processor + ia64, ## Intel Itanium + amd64, ## x86_64 (AMD64); 64 bit x86 compatible CPU + mips, ## Mips based processor + arm, ## ARM based processor + vm, ## Some Virtual machine: Nim's VM or JavaScript + avr ## AVR based processor + + OsPlatform* {.pure.} = enum ## the OS this program will run on. + none, dos, windows, os2, linux, morphos, skyos, solaris, + irix, netbsd, freebsd, openbsd, aix, palmos, qnx, amiga, + atari, netware, macos, macosx, haiku, js, nimVM, standalone + +const + targetOS* = when defined(windows): OsPlatform.windows + elif defined(dos): OsPlatform.dos + elif defined(os2): OsPlatform.os2 + elif defined(linux): OsPlatform.linux + elif defined(morphos): OsPlatform.morphos + elif defined(skyos): OsPlatform.skyos + elif defined(solaris): OsPlatform.solaris + elif defined(irix): OsPlatform.irix + elif defined(netbsd): OsPlatform.netbsd + elif defined(freebsd): OsPlatform.freebsd + elif defined(openbsd): OsPlatform.openbsd + elif defined(aix): OsPlatform.aix + elif defined(palmos): OsPlatform.palmos + elif defined(qnx): OsPlatform.qnx + elif defined(amiga): OsPlatform.amiga + elif defined(atari): OsPlatform.atari + elif defined(netware): OsPlatform.netware + elif defined(macosx): OsPlatform.macosx + elif defined(macos): OsPlatform.macos + elif defined(haiku): OsPlatform.haiku + elif defined(js): OsPlatform.js + elif defined(nimrodVM): OsPlatform.nimVM + elif defined(standalone): OsPlatform.standalone + else: OsPlatform.none + ## the OS this program will run on. + + targetCPU* = when defined(i386): CpuPlatform.i386 + elif defined(m68k): CpuPlatform.m68k + elif defined(alpha): CpuPlatform.alpha + elif defined(powerpc): CpuPlatform.powerpc + elif defined(powerpc64): CpuPlatform.powerpc64 + elif defined(sparc): CpuPlatform.sparc + elif defined(ia64): CpuPlatform.ia64 + elif defined(amd64): CpuPlatform.amd64 + elif defined(mips): CpuPlatform.mips + elif defined(arm): CpuPlatform.arm + elif defined(vm): CpuPlatform.vm + elif defined(avr): CpuPlatform.avr + else: CpuPlatform.none + ## the CPU this program will run on. diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index ba973e9b5..440d040a5 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -251,7 +251,7 @@ proc nimIntToStr(x: int): string {.compilerRtl.} = swap(result[j], result[i-j-1]) proc nimFloatToStr(f: float): string {.compilerproc.} = - var buf: array [0..64, char] + var buf: array[0..64, char] var n: int = c_sprintf(buf, "%.16g", f) var hasDot = false for i in 0..n-1: @@ -292,7 +292,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, var i = start sign = 1.0 - t: array[128, char] + t: array[500, char] # flaviu says: 325 is the longest reasonable literal ti = 0 hasdigits = false diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim index 9008d63e3..f0895217b 100644 --- a/lib/windows/windows.nim +++ b/lib/windows/windows.nim @@ -6743,13 +6743,13 @@ const EXCEPTION_READ_FAULT* = 0 # Access violation was caused by a read EXCEPTION_WRITE_FAULT* = 1 # Access violation was caused by a write -when defined(cpuia64): +when hostCPU == "ia64": const EXCEPTION_EXECUTE_FAULT* = 2 # Access violation was caused by an instruction fetch else: const EXCEPTION_EXECUTE_FAULT* = 8 -when defined(cpupowerpc32): +when hostCPU == "powerpc": # ppc const CONTEXT_CONTROL* = 1 @@ -6758,7 +6758,7 @@ when defined(cpupowerpc32): CONTEXT_DEBUG_REGISTERS* = 8 CONTEXT_FULL* = CONTEXT_CONTROL or CONTEXT_FLOATING_POINT or CONTEXT_INTEGER CONTEXT_DEBUGGER* = CONTEXT_FULL -when defined(cpui386): +when hostCPU == "i386": # x86 # The doc refered me to winnt.h, so I had to look... const @@ -6776,7 +6776,7 @@ when defined(cpui386): CONTEXT_DEBUG_REGISTERS or CONTEXT_EXTENDED_REGISTERS # our own invention FLAG_TRACE_BIT* = 0x00000100 CONTEXT_DEBUGGER* = CONTEXT_FULL or CONTEXT_FLOATING_POINT -when defined(cpux86_64): +when hostCPU == "amd64": const INITIAL_MXCSR* = 0x00001F80 # initial MXCSR value INITIAL_FPCSR* = 0x0000027F # initial FPCSR value @@ -7778,7 +7778,7 @@ elif defined(x86_64): LastExceptionToRip*: DWORD64 LastExceptionFromRip*: DWORD64 -elif defined(powerpc32): +elif hostCPU == "powerpc": # ppc # Floating point registers returned when CONTEXT_FLOATING_POINT is set # Integer registers returned when CONTEXT_INTEGER is set. diff --git a/todo.txt b/todo.txt index 077f5c9cb..6068c049b 100644 --- a/todo.txt +++ b/todo.txt @@ -1,12 +1,16 @@ version 0.10 ============ + Repetition renders the ridiculous reasonable. + - introduce ``--experimental`` switch +- c2nim depends on the compiler - make nimble part of the distribution - split idetools into separate tool - split docgen into separate tool + Concurrency ----------- @@ -33,7 +37,6 @@ Misc Bugs ==== -- fix the bug that keeps 'defer' template from working - VM: Pegs do not work at compile-time - VM: ptr/ref T cannot work in general - scopes are still broken for generic instantiation! diff --git a/web/news.txt b/web/news.txt index fd9ac77c2..76541560c 100644 --- a/web/news.txt +++ b/web/news.txt @@ -28,6 +28,9 @@ News fails to match. - The "symmetric set difference" operator (``-+-``) never worked and has been removed. + - ``defer`` is a keyword now. + - The ``using`` language feature now needs to be activated via the new + ``{.experimental.}`` pragma that enables experimental language features. Language Additions ------------------ @@ -38,6 +41,9 @@ News - ``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 |