use of org.codehaus.groovy.ast.expr.ClosureExpression in project groovy by apache.
the class MacroInvocationTrap method handleTargetMethodCallExpression.
@Override
protected boolean handleTargetMethodCallExpression(MethodCallExpression macroCall) {
final ClosureExpression closureExpression = getClosureArgument(macroCall);
if (closureExpression == null) {
return true;
}
if (closureExpression.getParameters() != null && closureExpression.getParameters().length > 0) {
addError("Macro closure arguments are not allowed", closureExpression);
return true;
}
final MapExpression mapExpression = buildSubstitutionMap(closureExpression);
String source = convertClosureToSource(closureExpression);
BlockStatement closureBlock = (BlockStatement) closureExpression.getCode();
Boolean asIs = false;
TupleExpression macroArguments = getMacroArguments(macroCall);
if (macroArguments == null) {
return true;
}
List<Expression> macroArgumentsExpressions = macroArguments.getExpressions();
if (macroArgumentsExpressions.size() == 2 || macroArgumentsExpressions.size() == 3) {
Expression asIsArgumentExpression = macroArgumentsExpressions.get(macroArgumentsExpressions.size() - 2);
if ((asIsArgumentExpression instanceof ConstantExpression)) {
ConstantExpression asIsConstantExpression = (ConstantExpression) asIsArgumentExpression;
if (!(asIsConstantExpression.getValue() instanceof Boolean)) {
addError("AsIs argument value should be boolean", asIsConstantExpression);
return true;
}
asIs = (Boolean) asIsConstantExpression.getValue();
}
}
macroArgumentsExpressions.remove(macroArgumentsExpressions.size() - 1);
macroArgumentsExpressions.add(new ConstantExpression(source));
macroArgumentsExpressions.add(mapExpression);
macroArgumentsExpressions.add(new ClassExpression(ClassHelper.makeWithoutCaching(MacroBuilder.getMacroValue(closureBlock, asIs).getClass(), false)));
macroCall.setObjectExpression(new PropertyExpression(new ClassExpression(ClassHelper.makeWithoutCaching(MacroBuilder.class, false)), "INSTANCE"));
macroCall.setSpreadSafe(false);
macroCall.setSafe(false);
macroCall.setImplicitThis(false);
return true;
}
use of org.codehaus.groovy.ast.expr.ClosureExpression in project groovy by apache.
the class MacroInvocationTrap method getClosureArgument.
protected ClosureExpression getClosureArgument(MethodCallExpression call) {
TupleExpression tupleArguments = getMacroArguments(call);
if (tupleArguments.getExpressions().size() < 1) {
addError("Call arguments should have at least one argument", tupleArguments);
return null;
}
Expression result = tupleArguments.getExpression(tupleArguments.getExpressions().size() - 1);
if (!(result instanceof ClosureExpression)) {
addError("Last call argument should be a closure", result);
return null;
}
return (ClosureExpression) result;
}
use of org.codehaus.groovy.ast.expr.ClosureExpression in project groovy by apache.
the class MacroInvocationTrap method buildSubstitutionMap.
private MapExpression buildSubstitutionMap(final ASTNode expr) {
final Map<MacroSubstitutionKey, ClosureExpression> map = new HashMap<MacroSubstitutionKey, ClosureExpression>();
final MapExpression mapExpression = new MapExpression();
ClassCodeVisitorSupport visitor = new ClassCodeVisitorSupport() {
@Override
protected SourceUnit getSourceUnit() {
return null;
}
@Override
public void visitClass(final ClassNode node) {
super.visitClass(node);
Iterator<InnerClassNode> it = node.getInnerClasses();
while (it.hasNext()) {
InnerClassNode next = it.next();
visitClass(next);
}
}
@Override
public void visitMethodCallExpression(MethodCallExpression call) {
super.visitMethodCallExpression(call);
if (isBuildInvocation(call, MacroTransformation.DOLLAR_VALUE)) {
ClosureExpression substitutionClosureExpression = getClosureArgument(call);
if (substitutionClosureExpression == null) {
return;
}
Statement code = substitutionClosureExpression.getCode();
if (code instanceof BlockStatement) {
((BlockStatement) code).setVariableScope(null);
}
MacroSubstitutionKey key = new MacroSubstitutionKey(call, expr.getLineNumber(), expr.getColumnNumber());
map.put(key, substitutionClosureExpression);
}
}
};
if (expr instanceof ClassNode) {
visitor.visitClass((ClassNode) expr);
} else {
expr.visit(visitor);
}
for (Map.Entry<MacroSubstitutionKey, ClosureExpression> entry : map.entrySet()) {
mapExpression.addMapEntryExpression(entry.getKey().toConstructorCallExpression(), entry.getValue());
}
return mapExpression;
}
use of org.codehaus.groovy.ast.expr.ClosureExpression in project groovy by apache.
the class Verifier method addDefaultParameterMethods.
/**
* Creates a new helper method for each combination of default parameter expressions
*/
protected void addDefaultParameterMethods(final ClassNode node) {
List methods = new ArrayList(node.getMethods());
addDefaultParameters(methods, new DefaultArgsAction() {
public void call(ArgumentListExpression arguments, Parameter[] newParams, MethodNode method) {
final BlockStatement code = new BlockStatement();
MethodNode newMethod = new MethodNode(method.getName(), method.getModifiers(), method.getReturnType(), newParams, method.getExceptions(), code);
// GROOVY-5681 and GROOVY-5632
for (Expression argument : arguments.getExpressions()) {
if (argument instanceof CastExpression) {
argument = ((CastExpression) argument).getExpression();
}
if (argument instanceof ConstructorCallExpression) {
ClassNode type = argument.getType();
if (type instanceof InnerClassNode && ((InnerClassNode) type).isAnonymous()) {
type.setEnclosingMethod(newMethod);
}
}
// check whether closure shared variables refer to params with default values (GROOVY-5632)
if (argument instanceof ClosureExpression) {
final List<Parameter> newMethodNodeParameters = Arrays.asList(newParams);
CodeVisitorSupport visitor = new CodeVisitorSupport() {
@Override
public void visitVariableExpression(VariableExpression expression) {
Variable v = expression.getAccessedVariable();
if (!(v instanceof Parameter))
return;
Parameter param = (Parameter) v;
if (param.hasInitialExpression() && code.getVariableScope().getDeclaredVariable(param.getName()) == null && !newMethodNodeParameters.contains(param)) {
VariableExpression localVariable = new VariableExpression(param.getName(), ClassHelper.makeReference());
DeclarationExpression declarationExpression = new DeclarationExpression(localVariable, Token.newSymbol(Types.EQUAL, -1, -1), new ConstructorCallExpression(ClassHelper.makeReference(), param.getInitialExpression()));
code.addStatement(new ExpressionStatement(declarationExpression));
code.getVariableScope().putDeclaredVariable(localVariable);
}
}
};
visitor.visitClosureExpression((ClosureExpression) argument);
}
}
MethodCallExpression expression = new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
expression.setMethodTarget(method);
expression.setImplicitThis(true);
if (method.isVoidMethod()) {
code.addStatement(new ExpressionStatement(expression));
} else {
code.addStatement(new ReturnStatement(expression));
}
List<AnnotationNode> annotations = method.getAnnotations();
if (annotations != null) {
newMethod.addAnnotations(annotations);
}
MethodNode oldMethod = node.getDeclaredMethod(method.getName(), newParams);
if (oldMethod != null) {
throw new RuntimeParserException("The method with default parameters \"" + method.getTypeDescriptor() + "\" defines a method \"" + newMethod.getTypeDescriptor() + "\" that is already defined.", method);
}
addPropertyMethod(newMethod);
newMethod.setGenericsTypes(method.getGenericsTypes());
newMethod.putNodeMetaData(DEFAULT_PARAMETER_GENERATED, true);
}
});
}
use of org.codehaus.groovy.ast.expr.ClosureExpression in project groovy by apache.
the class AnnotationVisitor method visitExpression.
protected void visitExpression(String attrName, Expression attrExp, ClassNode attrType) {
if (attrType.isArray()) {
// check needed as @Test(attr = {"elem"}) passes through the parser
if (attrExp instanceof ListExpression) {
ListExpression le = (ListExpression) attrExp;
visitListExpression(attrName, le, attrType.getComponentType());
} else if (attrExp instanceof ClosureExpression) {
addError("Annotation list attributes must use Groovy notation [el1, el2]", attrExp);
} else {
// treat like a singleton list as per Java
ListExpression listExp = new ListExpression();
listExp.addExpression(attrExp);
if (annotation != null) {
annotation.setMember(attrName, listExp);
}
visitExpression(attrName, listExp, attrType);
}
} else if (ClassHelper.isPrimitiveType(attrType)) {
visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), ClassHelper.getWrapper(attrType));
} else if (ClassHelper.STRING_TYPE.equals(attrType)) {
visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), ClassHelper.STRING_TYPE);
} else if (ClassHelper.CLASS_Type.equals(attrType)) {
if (!(attrExp instanceof ClassExpression || attrExp instanceof ClosureExpression)) {
addError("Only classes and closures can be used for attribute '" + attrName + "'", attrExp);
}
} else if (attrType.isDerivedFrom(ClassHelper.Enum_Type)) {
if (attrExp instanceof PropertyExpression) {
visitEnumExpression(attrName, (PropertyExpression) attrExp, attrType);
} else {
addError("Expected enum value for attribute " + attrName, attrExp);
}
} else if (isValidAnnotationClass(attrType)) {
if (attrExp instanceof AnnotationConstantExpression) {
visitAnnotationExpression(attrName, (AnnotationConstantExpression) attrExp, attrType);
} else {
addError("Expected annotation of type '" + attrType.getName() + "' for attribute " + attrName, attrExp);
}
} else {
addError("Unexpected type " + attrType.getName(), attrExp);
}
}
Aggregations