# # # Nim's Runtime Library # (c) Copyright 2015 Dominik Picheta # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This module implements nice syntactic sugar based on Nim's ## macro system. import std/private/since import std/macros proc checkPragma(ex, prag: var NimNode) = since (1, 3): if ex.kind == nnkPragmaExpr: prag = ex[1] ex = ex[0] proc createProcType(p, b: NimNode): NimNode {.compileTime.} = result = newNimNode(nnkProcTy) var formalParams = newNimNode(nnkFormalParams).add(b) p = p prag = newEmptyNode() checkPragma(p, prag) case p.kind of nnkPar, nnkTupleConstr: for i in 0 ..< p.len: let ident = p[i] var identDefs = newNimNode(nnkIdentDefs) case ident.kind of nnkExprColonExpr: identDefs.add ident[0] identDefs.add ident[1] else: identDefs.add newIdentNode("i" & $i) identDefs.add(ident) identDefs.add newEmptyNode() formalParams.add identDefs else: var identDefs = newNimNode(nnkIdentDefs) identDefs.add newIdentNode("i0") identDefs.add(p) identDefs.add newEmptyNode() formalParams.add identDefs result.add formalParams result.add prag macro `=>`*(p, b: untyped): untyped = ## Syntax sugar for anonymous procedures. It also supports pragmas. # TODO: xxx pending #13491: uncomment in runnableExamples runnableExamples: proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2) doAssert passTwoAndTwo((x, y) => x + y) == 4 type Bot = object call: (string {.noSideEffect.} -> string) var myBot = Bot() myBot.call = (name: string) {.noSideEffect.} => "Hello " & name & ", I'm a bot." doAssert myBot.call("John") == "Hello John, I'm a bot." # let f = () => (discard) # simplest proc that returns void # f() 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 in {nnkCall, nnkObjConstr}: # foo(x, y) => x + y kind = nnkProcDef name = p[0] let newP = newNimNode(nnkPar) for i in 1..": var procTy = createProcType(c[1], c[2]) params[0] = procTy[0][0] for i in 1 ..< procTy[0].len: params.add(procTy[0][i]) else: error("Expected proc type (->) got (" & c[0].strVal & ").", c) break else: error("Incorrect procedure parameter.", c) params.add(identDefs) of nnkIdent: var identDefs = newNimNode(nnkIdentDefs) identDefs.add(p) identDefs.add(ident"auto") identDefs.add(newEmptyNode()) params.add(identDefs) else: error("Incorrect procedure parameter list.", p) result = newProc(body = b, params = params, pragmas = pragma, name = name, procType = kind) macro `->`*(p, b: untyped): untyped = ## Syntax sugar for procedure types. It also supports pragmas. runnableExamples: proc passTwoAndTwo(f: (int, int) -> int): int = f(2, 2) # is the same as: # proc passTwoAndTwo(f: proc (x, y: int): int): int = f(2, 2) doAssert passTwoAndTwo((x, y) => x + y) == 4 proc passOne(f: (int {.noSideEffect.} -> int)): int = f(1) # is the same as: # proc passOne(f: proc (x: int): int {.noSideEffect.}): int = f(1) doAssert passOne(x {.noSideEffect.} => x + 1) == 2 result = createProcType(p, b) macro dump*(x: untyped): untyped = ## Dumps the content of an expression, useful for debugging. ## It accepts any expression and prints a textual representation ## of the tree representing the expression - as it would appear in ## source code - together with the value of the expression. ## ## See also: `dumpToString` which is more convenient and useful since ## it expands intermediate templates/macros, returns a string instead of ## calling `echo`, and works with statements and expressions. runnableExamples: let x = 10 y = 20 if false: dump(x + y) # if true would print `x + y = 30` let s = x.toStrLit result = quote do: debugEcho `s`, " = ", `x` macro dumpToStringImpl(s: static string, x: typed): string = let s2 = x.toStrLit if x.typeKind == ntyVoid: result = quote do: `s` & ": " & `s2` else: result = quote do: `s` & ": " & `s2` & " = " & $`x` macro dumpToString*(x: untyped): string = ## Returns the content of a statement or expression `x` after semantic analysis, ## useful for debugging. runnableExamples: const a = 1 let x = 10 doAssert dumpToString(a + 2) == "a + 2: 3 = 3" doAssert dumpToString(a + x) == "a + x: 1 + x = 11" template square(x): untyped = x * x doAsse
discard """
  output: '''1
2
3
4
20
21
22
23'''
"""

proc toIter*[T](s: Slice[T]): iterator: T =
  iterator it: T {.closure.} =
    for x in s.a..s.b:
      yield x
  return it

iterator concat*[T](its: