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