diff --git a/compiler/ast.nim b/compiler/ast.nim index 21358ba3e9..5c2349daaa 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -221,7 +221,6 @@ type nkGotoState, # used for the state machine (for iterators) nkState, # give a label to a code section (for iterators) nkBreakState, # special break statement for easier code generation - nkSigSection TNodeKinds* = set[TNodeKind] type diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 8362436d85..69a0fea2aa 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -45,7 +45,7 @@ type tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc, tkPtr, tkRaise, tkRef, tkReturn, - tkShl, tkShr, tkSig, tkStatic, + tkShl, tkShr, tkStatic, tkTemplate, tkTry, tkTuple, tkType, tkUsing, tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor, @@ -82,7 +82,7 @@ const "macro", "method", "mixin", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc", "ptr", "raise", "ref", "return", - "shl", "shr", "sig", "static", + "shl", "shr", "static", "template", "try", "tuple", "type", "using", "var", "when", "while", "with", "without", "xor", diff --git a/compiler/parser.nim b/compiler/parser.nim index e5a381b07e..f22177ac1b 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1908,7 +1908,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode = #| | 'converter' routine #| | 'type' section(typeDef) #| | 'const' section(constant) - #| | ('let' | 'var') section(variable) + #| | ('let' | 'var' | 'using') section(variable) #| | bindStmt | mixinStmt) #| / simpleStmt case p.tok.tokType @@ -1943,10 +1943,9 @@ proc complexOrSimpleStmt(p: var TParser): PNode = of tkLet: result = parseSection(p, nkLetSection, parseVariable) of tkWhen: result = parseIfOrWhen(p, nkWhenStmt) of tkVar: result = parseSection(p, nkVarSection, parseVariable) - of tkSig: result = parseSection(p, nkSigSection, parseVariable) of tkBind: result = parseBind(p, nkBindStmt) of tkMixin: result = parseBind(p, nkMixinStmt) - of tkUsing: result = parseBind(p, nkUsingStmt) + of tkUsing: result = parseSection(p, nkUsingStmt, parseVariable) else: result = simpleStmt(p) proc parseStmt(p: var TParser): PNode = diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 2b552f1305..12852ba3d7 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -460,9 +460,12 @@ proc lsub(n: PNode): int = else: result = len("enum") of nkEnumFieldDef: result = lsons(n) + 3 - of nkVarSection, nkLetSection, nkSigSection: + of nkVarSection, nkLetSection: if sonsLen(n) > 1: result = MaxLineLen + 1 else: result = lsons(n) + len("var_") + of nkUsingStmt: + if sonsLen(n) > 1: result = MaxLineLen + 1 + else: result = lsons(n) + len("using_") of nkReturnStmt: result = lsub(n.sons[0]) + len("return_") of nkRaiseStmt: result = lsub(n.sons[0]) + len("raise_") of nkYieldStmt: result = lsub(n.sons[0]) + len("yield_") @@ -1173,12 +1176,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = initContext(a) incl(a.flags, rfInConstExpr) gsection(g, n, a, tkConst, "const") - of nkVarSection, nkLetSection, nkSigSection: + of nkVarSection, nkLetSection, nkUsingStmt: var L = sonsLen(n) if L == 0: return if n.kind == nkVarSection: putWithSpace(g, tkVar, "var") elif n.kind == nkLetSection: putWithSpace(g, tkLet, "let") - else: putWithSpace(g, tkSig, "sig") + else: putWithSpace(g, tkUsing, "using") if L > 1: gcoms(g) indentNL(g) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a2f1940f74..16b4ee4792 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1556,10 +1556,6 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo, result = newSym(kind, idAnon, owner, info) result.flags = {sfGenSym} -proc semUsing(c: PContext, n: PNode): PNode = - result = newNodeI(nkEmpty, n.info) - localError(n.info, "'using' statement is obsolete") - proc semExpandToAst(c: PContext, n: PNode): PNode = var macroCall = n[1] var expandedSym = expectMacroOrTemplateCall(c, macroCall) @@ -2354,7 +2350,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]): localError(n.info, errGenerated, "'defer' takes a 'void' expression") #localError(n.info, errGenerated, "'defer' not allowed in this context") - of nkSigSection: result = semSigSection(c, n) else: localError(n.info, errInvalidExpressionX, renderTree(n, {renderNoComments})) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 20bca4c906..5d16f2fbaf 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -386,8 +386,11 @@ proc isDiscardUnderscore(v: PSym): bool = v.flags.incl(sfGenSym) result = true -proc semSigSection(c: PContext; n: PNode): PNode = +proc semUsing(c: PContext; n: PNode): PNode = result = ast.emptyNode + if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "using") + if not experimentalMode(c): + localError(n.info, "use the {.experimental.} pragma to enable 'using'") for i in countup(0, sonsLen(n)-1): var a = n.sons[i] if gCmd == cmdIdeTools: suggestStmt(c, a) @@ -402,10 +405,10 @@ proc semSigSection(c: PContext; n: PNode): PNode = v.typ = typ strTableIncl(c.signatures, v) else: - localError(a.info, "'sig' section must have a type") + localError(a.info, "'using' section must have a type") var def: PNode if a.sons[length-1].kind != nkEmpty: - localError(a.info, "'sig' sections cannot contain assignments") + localError(a.info, "'using' sections cannot contain assignments") proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var b: PNode diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 62848c0782..3e0e05a948 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -30,7 +30,7 @@ type wInclude, wInterface, wIs, wIsnot, wIterator, wLet, wMacro, wMethod, wMixin, wMod, wNil, wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn, - wShl, wShr, wSig, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar, + wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar, wWhen, wWhile, wWith, wWithout, wXor, wYield, wColon, wColonColon, wEquals, wDot, wDotDot, @@ -114,7 +114,7 @@ const "macro", "method", "mixin", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc", "ptr", "raise", "ref", "return", - "shl", "shr", "sig", "static", + "shl", "shr", "static", "template", "try", "tuple", "type", "using", "var", "when", "while", "with", "without", "xor", "yield", diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt index 83852b1ff2..4f8d6e9352 100644 --- a/doc/manual/stmts.txt +++ b/doc/manual/stmts.txt @@ -547,55 +547,36 @@ Instead of: Using statement --------------- -**Warning**: The ``using`` statement is highly experimental and has to be +**Warning**: The ``using`` statement is 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 -constant, it will instruct Nim to automatically consider the used symbol as -a hidden leading parameter for any procedure calls, following the using -statement in the current scope. Thus, it behaves much like the hidden `this` -parameter available in some object-oriented programming languages. +The using statement provides syntactic convenience in modules where +the same parameter names and types are used over and over. Instead of: .. code-block:: nim + proc foo(c: Context; n: Node) = ... + proc bar(c: Context; n: Node, counter: int) = ... + proc baz(c: Context; n: Node) = ... - var s = socket() - using s - - connect(host, port) - send(data) - - while true: - let line = readLine(timeout) - ... - - -When applied to a callable symbol, it brings the designated symbol in the -current scope. Thus, it can be used to disambiguate between imported symbols -from different modules having the same name. +One can tell the compiler about the convention that a parameter of +name ``c`` should default to type ``Context``, ``n`` should default to +``Node`` etc.: .. code-block:: nim - import windows, sdl - using sdl.SetTimer + {.experimental.} + using + c: Context + n: Node + counter: int -Note that ``using`` only *adds* to the current context, it doesn't remove or -replace, **neither** does it create a new scope. What this means is that if one -applies this to multiple variables the compiler will find conflicts in what -variable to use: + proc foo(c, n) = ... + proc bar(c, n, counter) = ... + proc baz(c, n) = ... -.. code-block:: nim - var a, b = "kill it" - using a - add(" with fire") - using b - add(" with water") - echo a - echo b -When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could -be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or -is ambiguous)``. To solve this one would need to nest ``using`` with a -``block`` statement so as to control the reach of the ``using`` statement. +The ``using`` section uses the same indentation based grouping syntax as +a ``var`` or ``let``` section. + If expression ------------- diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 7d39812c45..4522e0fc6b 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -75,8 +75,7 @@ type nnkClosure, nnkGotoState, nnkState, - nnkBreakState, - nnkSigSection + nnkBreakState NimNodeKinds* = set[NimNodeKind] NimTypeKind* = enum diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index 6321115c4e..1bc0af1b63 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -56,7 +56,7 @@ const "generic", "if", "import", "in", "include", "interface", "is", "isnot", "iterator", "let", "macro", "method", "mixin", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc", - "ptr", "raise", "ref", "return", "shl", "shr", "sig", "static", + "ptr", "raise", "ref", "return", "shl", "shr", "static", "template", "try", "tuple", "type", "using", "var", "when", "while", "with", "without", "xor", "yield"] diff --git a/tests/casestmt/tcaseexpr1.nim b/tests/casestmt/tcaseexpr1.nim index e5e08e25e5..56acbbc8a5 100644 --- a/tests/casestmt/tcaseexpr1.nim +++ b/tests/casestmt/tcaseexpr1.nim @@ -11,7 +11,7 @@ discard """ type E = enum A, B, C -proc foo(x): auto = +proc foo(x: int): auto = return case x of 1..9: "digit" else: "number" diff --git a/tests/generics/tbadgenericlambda.nim b/tests/generics/tbadgenericlambda.nim index 2ab8e724db..9fac150c13 100644 --- a/tests/generics/tbadgenericlambda.nim +++ b/tests/generics/tbadgenericlambda.nim @@ -3,5 +3,5 @@ discard """ line: 6 """ -let x = proc (x, y): auto = x + y +let x = proc (x, y: auto): auto = x + y diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim index 45450ccca1..a045b32f80 100644 --- a/tests/generics/tgeneric0.nim +++ b/tests/generics/tgeneric0.nim @@ -18,7 +18,7 @@ proc foo[T](p: TType[T, range[0..2]]) = #bug #1366 -proc reversed(x) = +proc reversed(x: auto) = for i in countdown(x.low, x.high): echo i diff --git a/tests/generics/tgenericlambda.nim b/tests/generics/tgenericlambda.nim index eb6ada3e58..41ee74557f 100644 --- a/tests/generics/tgenericlambda.nim +++ b/tests/generics/tgenericlambda.nim @@ -5,15 +5,15 @@ discard """ proc test(x: proc (a, b: int): int) = echo x(5, 5) -test(proc (a, b): auto = a + b) +test(proc (a, b: auto): auto = a + b) -test do (a, b) -> auto: a + b +test do (a, b: auto) -> auto: a + b proc foreach[T](s: seq[T], body: proc(x: T)) = for e in s: body(e) -foreach(@[1,2,3]) do (x): +foreach(@[1,2,3]) do (x: auto): echo x proc foo = diff --git a/tests/macros/tclosuremacro.nim b/tests/macros/tclosuremacro.nim index cf51949edc..c29fbe1c84 100644 --- a/tests/macros/tclosuremacro.nim +++ b/tests/macros/tclosuremacro.nim @@ -26,7 +26,7 @@ proc noReturn(x: () -> void) = proc doWithOneAndTwo(f: (int, int) -> int): int = f(1,2) -echo twoParams(proc (a, b): auto = a + b) +echo twoParams(proc (a, b: auto): auto = a + b) echo twoParams((x, y) => x + y) echo oneParam(x => x+5) diff --git a/tests/misc/tupcomingfeatures.nim b/tests/misc/tupcomingfeatures.nim new file mode 100644 index 0000000000..9a99e769ae --- /dev/null +++ b/tests/misc/tupcomingfeatures.nim @@ -0,0 +1,39 @@ +discard """ + output: '''0 -2 0 + 0 -2''' +""" + +{.this: self.} + +type + Foo {.partial.} = object + a, b: int + +type + tupcomingfeatures.Foo = object + x: int + +proc yay(self: Foo) = + echo a, " ", b, " ", x + +proc footest[T](self: var Foo, a: T) = + b = 1+a + yay() + +proc nongeneric(self: Foo) = + echo a, " ", b + +var ff: Foo +footest(ff, -3) +ff.nongeneric + +{.experimental.} +using + c: Foo + x, y: int + +proc usesSig(c) = + echo "yummy" + +proc foobar(c, y) = + echo "yay" diff --git a/tests/template/tit.nim b/tests/template/tit.nim index 9866711de7..cf50d2f6fb 100644 --- a/tests/template/tit.nim +++ b/tests/template/tit.nim @@ -5,7 +5,7 @@ template someIt(a, pred: expr): expr = var it {.inject.} = 0 pred -proc aProc(n) = +proc aProc(n: auto) = n.someIt(echo(it)) aProc(89) diff --git a/tests/typerel/trettypeinference.nim b/tests/typerel/trettypeinference.nim index 41b4aa5ef4..fa4e89cc8d 100644 --- a/tests/typerel/trettypeinference.nim +++ b/tests/typerel/trettypeinference.nim @@ -5,8 +5,8 @@ discard """ import typetraits -proc plus(a, b): auto = a + b -proc makePair(a, b): auto = (first: a, second: b) +proc plus(a, b: auto): auto = a + b +proc makePair(a, b: auto): auto = (first: a, second: b) proc `+`(a, b: string): seq[string] = @[a, b] @@ -19,7 +19,7 @@ static: assert p[0].type is string echo i.type.name echo s.type.name -proc inst(a): auto = +proc inst(a: auto): auto = static: echo "instantiated for ", a.type.name result = a diff --git a/todo.txt b/todo.txt index 703139c9c0..db3604283b 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,9 @@ nim c --gc:v2 -r -d:useSysAssert -d:useGcAssert -d:smokeCycles -d:useRealtimeGc tests/gc/gcbench +- document ``this`` pragma +- document and stress test ``.partial`` object declarations + essential for 1.0 ================= diff --git a/web/news.txt b/web/news.txt index f27398ee1e..46a1c51629 100644 --- a/web/news.txt +++ b/web/news.txt @@ -16,20 +16,34 @@ Changes affecting backwards compatibility ``table.mpairs`` iterator only the returned values can be modified, no longer the keys. - The deprecated Nim shebang notation ``#!`` was removed from the language. Use ``#?`` instead. +- The ``using`` statement now means something completely different. You can use the + new experimental ``this`` pragma to achieve a similar effect to what the old ``using`` statement tried to achieve. +- Typeless parameters have been removed from the language since it would + clash with ``using``. Library Additions ----------------- - The rlocks module has been added providing reentrant lock synchronization - primitive + primitive. Compiler Additions ------------------ - Added a new ``--noCppExceptions`` switch that allows to use default exception handling (no ``throw`` or ``try``/``catch`` generated) when compiling to C++ - code + code. + +Language Additions +------------------ + +- Nim now supports a ``.this`` pragma for more notational convenience. +- Nim now supports a different ``using`` statement for more convenience. +- Nim now supports ``partial`` object declarations to mitigate the problems + that arise when types are mutually dependent and yet should be kept in + different modules. + 2016-01-27 Nim in Action is now available! ==========================================