From 9acfc43119d42d7265497fd6ae60eda3903d9938 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 11 Sep 2011 21:43:12 +0300 Subject: using statement (ala C#) implemented as macro (added as test). simplified the usage of the interpolatedFragments iterator. --- tests/accept/run/tusingstatement.nim | 102 +++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 tests/accept/run/tusingstatement.nim (limited to 'tests/accept/run/tusingstatement.nim') diff --git a/tests/accept/run/tusingstatement.nim b/tests/accept/run/tusingstatement.nim new file mode 100644 index 000000000..0017af556 --- /dev/null +++ b/tests/accept/run/tusingstatement.nim @@ -0,0 +1,102 @@ +discard """ + file: "tusingstatement.nim" + output: "Using test.Closing test." +""" + +import + macros + +# This macro mimics the using statement from C# +# +# XXX: +# It doen't match the C# version exactly yet. +# In particular, it's not recursive, which prevents it from dealing +# with exceptions thrown from the variable initializers when multiple. +# variables are used. +# +# Also, since nimrod relies less on exceptions in general, a more +# idiomatic definition could be: +# var x = init() +# if opened(x): +# try: +# body +# finally: +# close(x) +# +# `opened` here could be an overloaded proc which any type can define. +# A common practice can be returing an Optional[Resource] obj for which +# `opened` is defined to `optional.hasValue` +macro using(e: expr) : stmt = + if e.len != 2: + error "Using statement: unexpected number of arguments. Got " & + $e.len & ", expected: 1 or more variable assignments and a block" + + var args = e[0] + var body = e[1] + + var + variables : seq[PNimrodNode] + closingCalls : seq[PNimrodNode] + + newSeq(variables, 0) + newSeq(closingCalls, 0) + + for i in countup(1, args.len-1): + 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(!"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) + + # XXX: Use a template here once getAst is working properly + var targetAst = parseStmt"""block: + var + x = foo() + y = bar() + + try: + body() + + finally: + close x + close y + """ + + targetAst[0][1][0] = varSection + targetAst[0][1][1][0] = body + targetAst[0][1][1][1][0] = finallyBlock + + return targetAst + +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 & ".") + +using(r = openResource("test")): + use r + + -- cgit 1.4.1-2-gfad0