tusingstatement.nim 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. discard """
  2. output: "Using test.Closing test."
  3. """
  4. import
  5. macros
  6. # This macro mimics the using statement from C#
  7. #
  8. # It's kept only as a test for the macro system
  9. # Nim's destructors offer a mechanism for automatic
  10. # disposal of resources.
  11. #
  12. macro autoClose(args: varargs[untyped]): untyped =
  13. let e = callsite()
  14. if e.len != 3:
  15. error "Using statement: unexpected number of arguments. Got " &
  16. $e.len & ", expected: 1 or more variable assignments and a block"
  17. var args = e
  18. var body = e[2]
  19. var
  20. variables : seq[NimNode]
  21. closingCalls : seq[NimNode]
  22. newSeq(variables, 0)
  23. newSeq(closingCalls, 0)
  24. for i in countup(1, args.len-2):
  25. if args[i].kind == nnkExprEqExpr:
  26. var varName = args[i][0]
  27. var varValue = args[i][1]
  28. var varAssignment = newNimNode(nnkIdentDefs)
  29. varAssignment.add(varName)
  30. varAssignment.add(newNimNode(nnkEmpty)) # empty means no type
  31. varAssignment.add(varValue)
  32. variables.add(varAssignment)
  33. closingCalls.add(newCall(!"close", varName))
  34. else:
  35. error "Using statement: Unexpected expression. Got " &
  36. $args[i].kind & " instead of assignment."
  37. var varSection = newNimNode(nnkVarSection)
  38. varSection.add(variables)
  39. var finallyBlock = newNimNode(nnkStmtList)
  40. finallyBlock.add(closingCalls)
  41. # XXX: Use a template here once getAst is working properly
  42. var targetAst = parseStmt"""block:
  43. var
  44. x = foo()
  45. y = bar()
  46. try:
  47. body()
  48. finally:
  49. close x
  50. close y
  51. """
  52. targetAst[0][1][0] = varSection
  53. targetAst[0][1][1][0] = body
  54. targetAst[0][1][1][1][0] = finallyBlock
  55. result = targetAst
  56. type
  57. TResource* = object
  58. field*: string
  59. proc openResource(param: string): TResource =
  60. result.field = param
  61. proc close(r: var TResource) =
  62. write(stdout, "Closing " & r.field & ".")
  63. proc use(r: var TResource) =
  64. write(stdout, "Using " & r.field & ".")
  65. autoClose(r = openResource("test")):
  66. use r
  67. write stdout, "\n"