From 3e060cfb0ab6b1affe26a7b09e6b4192e0d68a7f Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Sun, 3 May 2020 11:22:49 +0300 Subject: [PATCH] => supports pragmas & names (+ changed behavior) (#14200) * => supports pragmas & names (+ changed behavior) (x, y: int) is now parsed as (x: int, y: int) instead of (x: auto, y: int) inside => and ->. * fix pragma check * fixes, use since & LHS of -> supports pragmas --- changelog.md | 16 ++++++ lib/pure/htmlgen.nim | 8 +-- lib/pure/strutils.nim | 2 +- lib/pure/sugar.nim | 92 ++++++++++++++++++++++------------ lib/pure/typetraits.nim | 2 +- tests/macros/tclosuremacro.nim | 31 ++++++------ 6 files changed, 96 insertions(+), 55 deletions(-) diff --git a/changelog.md b/changelog.md index 4aa22b9d7a4f5..165518bd7cca4 100644 --- a/changelog.md +++ b/changelog.md @@ -61,6 +61,22 @@ - `paramCount` & `paramStr` are now defined in os.nim instead of nimscript.nim for nimscript/nimble. - `dollars.$` now works for unsigned ints with `nim js` +- `sugar.=>` and `sugar.->` changes: Previously `(x, y: int)` was transformed + into `(x: auto, y: int)`, it now becomes `(x: int, y: int)` in consistency + with regular proc definitions (although you cannot use semicolons). + + Pragmas and using a name are now allowed on the lefthand side of `=>`. Here + is an aggregate example of these changes: + ```nim + import sugar + + foo(x, y: int) {.noSideEffect.} => x + y + + # is transformed into + + proc foo(x: int, y: int): auto {.noSideEffect.} = x + y + ``` + ## Language changes - In newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: ```nim diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index e0518f5ee10a9..99af26c993a6a 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -64,7 +64,7 @@ proc getIdent(e: NimNode): string {.compileTime.} = result = getIdent(e[0]) for i in 1 .. e.len-1: result.add getIdent(e[i]) - else: error("cannot extract identifier from node: " & toStrLit(e).strVal) + else: error("cannot extract identifier from node: " & toStrLit(e).strVal, e) proc delete[T](s: var seq[T], attr: T): bool = var idx = find(s, attr) @@ -96,14 +96,14 @@ proc xmlCheckedTag*(argsList: NimNode, tag: string, optAttr = "", reqAttr = "", result.add(argsList[i][1]) result.add(newStrLitNode("\"")) else: - error("invalid attribute for '" & tag & "' element: " & name) + error("invalid attribute for '" & tag & "' element: " & name, argsList[i]) # check each required attribute exists: if req.len > 0: - error(req[0] & " attribute for '" & tag & "' element expected") + error(req[0] & " attribute for '" & tag & "' element expected", argsList) if isLeaf: for i in 0 ..< argsList.len: if argsList[i].kind != nnkExprEqExpr: - error("element " & tag & " cannot be nested") + error("element " & tag & " cannot be nested", argsList[i]) result.add(newStrLitNode(" />")) else: result.add(newStrLitNode(">")) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index a1f80ad7675b5..bb68085aad6bf 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1295,7 +1295,7 @@ macro genEnumStmt(typ: typedesc, argSym: typed, default: typed): untyped = foundFields.add fStr else: error("Ambiguous enums cannot be parsed, field " & $fStr & - " appears multiple times!") + " appears multiple times!", f) inc fNum # finally add else branch to raise or use default if default == nil: diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 062341ccb6627..dbc60b8a9cdda 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -11,16 +11,25 @@ ## macro system. import std/private/since -import macros -import typetraits +import macros, typetraits + +proc checkPragma(ex, prag: var NimNode) = + since (1, 3): + if ex.kind == nnkPragmaExpr: + prag = ex[1] + if ex[0].kind == nnkPar and ex[0].len == 1: + ex = ex[0][0] + else: + ex = ex[0] proc createProcType(p, b: NimNode): NimNode {.compileTime.} = - #echo treeRepr(p) - #echo treeRepr(b) result = newNimNode(nnkProcTy) - var formalParams = newNimNode(nnkFormalParams) + var + formalParams = newNimNode(nnkFormalParams).add(b) + p = p + prag = newEmptyNode() - formalParams.add b + checkPragma(p, prag) case p.kind of nnkPar, nnkTupleConstr: @@ -44,9 +53,7 @@ proc createProcType(p, b: NimNode): NimNode {.compileTime.} = formalParams.add identDefs result.add formalParams - result.add newEmptyNode() - #echo(treeRepr(result)) - #echo(result.toStrLit()) + result.add prag macro `=>`*(p, b: untyped): untyped = ## Syntax sugar for anonymous procedures. @@ -58,56 +65,75 @@ macro `=>`*(p, b: untyped): untyped = ## ## passTwoAndTwo((x, y) => x + y) # 4 - #echo treeRepr(p) - #echo(treeRepr(b)) - var params: seq[NimNode] = @[newIdentNode("auto")] + var + params = @[ident"auto"] + name = newEmptyNode() + kind = nnkLambda + pragma = newEmptyNode() + p = p + + checkPragma(p, pragma) + + if p.kind == nnkInfix and p[0].kind == nnkIdent and p[0].eqIdent"->": + params[0] = p[2] + p = p[1] + + checkPragma(p, pragma) # check again after -> transform + + since (1, 3): + if p.kind == nnkCall: + # foo(x, y) => x + y + kind = nnkProcDef + name = p[0] + let newP = newNimNode(nnkPar) + for i in 1..