> since you seemed to say in the beginning that you did not want to create > objects (if I read this correctly), why creating AutoCloseable instances here > would not pose a problem ?)
Best case scenario is that I get the same performance and memory footprint of the original code (included below). So an AST transform is what I look to in order to type less code but get the same runtime outcome. A macro method must replace an expression with another expression, so writing out a try statement is not possible AFAIK (unless it is embedded in a ClosureExpression or something like that). However an AIC is a ConstructorCallExpression so that is possible with a macro method. And I think the one extra plus going for the AIC AutoCloseable is it could be reused anywhere an AutoCloseable is accepted. If there is something simpler/groovier I am interested to hear about it. The suggestion of converting Foo into an AutoCloseable significantly changes the design/structure. I'm more looking to rewrite the contents of the bar() method only. class Foo { private state def bar() { def temp = state state = newState try { baz() } finally { state = temp } } def baz() { // make use of state; does not require previous values } } In any case, I did manage to prototype it out and it works. Here it is in case anyone wanted to have a look. class Foo { def bar() { println field try (def x = auto(field, 'new')) { // needed to provide "def x =" because parser validates for this and macro transform runs after that baz() } println field } def baz() { println field } private field = 'old' } new Foo().bar() // should print "old", "new", "old" import static org.codehaus.groovy.ast.ClassHelper.* import static org.codehaus.groovy.ast.tools.GeneralUtils.* import org.codehaus.groovy.ast.* import org.codehaus.groovy.ast.expr.* import org.codehaus.groovy.macro.runtime.Macro import org.codehaus.groovy.macro.runtime.MacroContext import groovy.transform.AutoFinal @AutoFinal class MoreMacroMethods { @Macro static Expression auto(MacroContext context, VariableExpression oldValue, Expression newValue = oldValue) { if (isImplicitThis(context)) { ClassNode type = newAutoCloseable(context) FieldNode field = type.addField('temp', 0x12, OBJECT_TYPE, oldValue) type.addObjectInitializerStatements(block(assignS(varX(oldValue.name), newValue))) type.addMethod('close', 0x11, VOID_TYPE, Parameter.EMPTY_ARRAY, new ClassNode[] {make(Exception.class)}, null).tap { addAnnotation(new AnnotationNode(make(Override.class))) setCode(assignS(varX(oldValue.name), fieldX(field))) setSourcePosition(context.call) } return new ConstructorCallExpression(type, ArgumentListExpression.EMPTY_ARGUMENTS).tap { usingAnonymousInnerClass = true } } } private static ClassNode newAutoCloseable(MacroContext context) { def (ClassNode enclosingClass, MethodNode enclosingMethod) = findEnclosing(context) def name = enclosingClass.name + '$' + (anonymousClassCount(enclosingClass) + 1) def type = new InnerClassNode(enclosingClass, name, 1, AUTOCLOSEABLE_TYPE) type.anonymous = true; type.enclosingMethod = enclosingMethod context.compilationUnit.addNewPhaseOperation({ org.codehaus.groovy.control.SourceUnit unit -> if (unit.is(context.sourceUnit)) { unit.AST.addClass(type) } } as org.codehaus.groovy.control.CompilationUnit.ISourceUnitOperation, 3) return type } private static int anonymousClassCount(ClassNode node) { int count = 0 for (Iterator<InnerClassNode> it = node.getInnerClasses(); it.hasNext();) { InnerClassNode innerClass = it.next() if (innerClass.isAnonymous()) { count += 1 } } return count } private static Tuple2<ClassNode, MethodNode> findEnclosing(MacroContext context) { Tuple.tuple(context.sourceUnit.AST.classes[1], context.sourceUnit.AST.classes[1].methods[0]) // TODO: search context.sourceUnit.AST for enclosing type and method of context.call } private static boolean isImplicitThis(MacroContext context) { context.call.with { objectExpression instanceof VariableExpression && objectExpression.isThisExpression() && isImplicitThis() } } }