Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
import org.codehaus.groovy.ast.AnnotationNode
import org.codehaus.groovy.ast.expr.ClassExpression
import org.codehaus.groovy.ast.expr.Expression
import org.codehaus.groovy.ast.expr.ListExpression

currentType(mixins: annotatedBy(Mixin)).accept {
	provider = "Mixin AST Transform"
	for (AnnotationNode mixin in mixins) {
		if (mixin instanceof AnnotationNode) {
			Expression expr = mixin.getMember("value")
			if (expr instanceof ClassExpression) {
				delegatesTo expr
			} else if (expr instanceof ListExpression) {
				for (Expression ex in expr?.expressions) {
					delegatesTo ex
				}
			}
		}
	}
}

Newify

Here is the @Newify DSLD. This matches whenever an enclosing field, method, or class is annotated by groovy.lang.Newify. We add both the Python-style constructors and the Ruby style cosntructors.

Code Block

import org.codehaus.groovy.ast.AnnotationNode
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.ConstructorNode;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.ListExpression;


(enclosingMethod(newify: annotatedBy(Newify)) | enclosingClass(newify: annotatedBy(Newify)) | enclosingField(newify: annotatedBy(Newify))).accept {
	provider = "Newify AST Transform"
	for (AnnotationNode a : newify) {
		def classes = findClasses(a)
		println "CurrentType: " + currentType
		// when there are no classes in the list, then applies to all classes
		if (classes.isEmpty() || classes.contains(currentType)) {
			// no arg constructor
			// Python style
			method name: "new", type: currentType, declaringType: currentType, isStatic: true
			// Ruby style
			method name: currentType.nameWithoutPackage, type: currentType, isStstic: true
			
			for (cons in (currentType.declaredConstructors?: [])) {
				def extractedParams = extractParams(cons)
				// Python style
				method name: "new", type: currentType, declaringType: currentType, params: extractedParams, isStatic: true
				// Ruby style
				method name: currentType.nameWithoutPackage, type: currentType, params: extractedParams, isStatic: true
			}
			
		}
	} 
}

// helpers
// convert to a list of class nodes
List<ClassNode> findClasses(AnnotationNode a) {
  def value = a.getMember("value")
  if (value instanceof ListExpression) {
	  return value.expressions.collect{ it.type } 
  } else if (value instanceof Expression) {
	return [value.type]
  } else {
  	return [] 
  } 
}
 
// Convert Parameters to a map if String -> ClassNode
def extractParams(ConstructorNode cons) {
	def params = [ : ]
	
	for (param in (cons.parameters ?: [] )) {
		params."${param.name}" = param.type
	}  
	params
}

SwingBuilder

Although this next example is quite long, it is fairly straight forward. We are just adding lots and lots and lots of methods to the SwingBuilder class. This script is only partially complete since we don't include documentation for all contributed methods. It might be possible to use BeanInfo to generate this script automatically.

...