use of org.codehaus.groovy.ast.EnumConstantClassNode in project groovy by apache.
the class AstBuilder method visitMethodDeclaration.
@Override
public MethodNode visitMethodDeclaration(final MethodDeclarationContext ctx) {
ModifierManager modifierManager = createModifierManager(ctx);
if (modifierManager.containsAny(VAR)) {
throw createParsingFailedException("var cannot be used for method declarations", ctx);
}
String methodName = this.visitMethodName(ctx.methodName());
ClassNode returnType = this.visitReturnType(ctx.returnType());
Parameter[] parameters = this.visitFormalParameters(ctx.formalParameters());
ClassNode[] exceptions = this.visitQualifiedClassNameList(ctx.qualifiedClassNameList());
anonymousInnerClassesDefinedInMethodStack.push(new LinkedList<>());
Statement code = this.visitMethodBody(ctx.methodBody());
List<InnerClassNode> anonymousInnerClassList = anonymousInnerClassesDefinedInMethodStack.pop();
MethodNode methodNode;
// if classNode is not null, the method declaration is for class declaration
ClassNode classNode = ctx.getNodeMetaData(CLASS_DECLARATION_CLASS_NODE);
if (asBoolean(classNode)) {
validateParametersOfMethodDeclaration(parameters, classNode);
methodNode = createConstructorOrMethodNodeForClass(ctx, modifierManager, methodName, returnType, parameters, exceptions, code, classNode);
} else {
// script method declaration
methodNode = createScriptMethodNode(modifierManager, methodName, returnType, parameters, exceptions, code);
}
anonymousInnerClassList.forEach(e -> e.setEnclosingMethod(methodNode));
methodNode.setGenericsTypes(this.visitTypeParameters(ctx.typeParameters()));
methodNode.setSyntheticPublic(this.isSyntheticPublic(this.isAnnotationDeclaration(classNode), classNode instanceof EnumConstantClassNode, asBoolean(ctx.returnType()), modifierManager));
if (modifierManager.containsAny(STATIC)) {
for (Parameter parameter : methodNode.getParameters()) {
parameter.setInStaticContext(true);
}
methodNode.getVariableScope().setInStaticContext(true);
}
configureAST(methodNode, ctx);
validateMethodDeclaration(ctx, methodNode, modifierManager, classNode);
groovydocManager.handle(methodNode, ctx);
return methodNode;
}
use of org.codehaus.groovy.ast.EnumConstantClassNode in project groovy by apache.
the class AstBuilder method visitAnonymousInnerClassDeclaration.
@Override
public InnerClassNode visitAnonymousInnerClassDeclaration(final AnonymousInnerClassDeclarationContext ctx) {
ClassNode superClass = Objects.requireNonNull(ctx.getNodeMetaData(ANONYMOUS_INNER_CLASS_SUPER_CLASS), "superClass should not be null");
ClassNode outerClass = Optional.ofNullable(classNodeStack.peek()).orElse(moduleNode.getScriptClassDummy());
String innerClassName = nextAnonymousClassName(outerClass);
InnerClassNode anonymousInnerClass;
if (ctx.t == 1) {
anonymousInnerClass = new EnumConstantClassNode(outerClass, innerClassName, superClass.getPlainNodeReference());
// and remove the final modifier from classNode to allow the sub class
superClass.setModifiers(superClass.getModifiers() & ~Opcodes.ACC_FINAL);
} else {
anonymousInnerClass = new InnerClassNode(outerClass, innerClassName, Opcodes.ACC_PUBLIC, superClass);
}
anonymousInnerClass.setAnonymous(true);
anonymousInnerClass.setUsingGenerics(false);
anonymousInnerClass.putNodeMetaData(CLASS_NAME, innerClassName);
configureAST(anonymousInnerClass, ctx);
classNodeList.add(anonymousInnerClass);
classNodeStack.push(anonymousInnerClass);
ctx.classBody().putNodeMetaData(CLASS_DECLARATION_CLASS_NODE, anonymousInnerClass);
this.visitClassBody(ctx.classBody());
classNodeStack.pop();
return anonymousInnerClass;
}
use of org.codehaus.groovy.ast.EnumConstantClassNode in project groovy by apache.
the class AntlrParserPlugin method anonymousInnerClassDef.
protected Expression anonymousInnerClassDef(AST node) {
ClassNode oldNode = classNode;
ClassNode outerClass = getClassOrScript(oldNode);
String fullName = outerClass.getName() + '$' + innerClassCounter;
innerClassCounter++;
if (enumConstantBeingDef) {
classNode = new EnumConstantClassNode(outerClass, fullName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
} else {
classNode = new InnerClassNode(outerClass, fullName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
}
((InnerClassNode) classNode).setAnonymous(true);
classNode.setEnclosingMethod(methodNode);
assertNodeType(OBJBLOCK, node);
objectBlock(node);
output.addClass(classNode);
AnonymousInnerClassCarrier ret = new AnonymousInnerClassCarrier();
ret.innerClass = classNode;
classNode = oldNode;
return ret;
}
use of org.codehaus.groovy.ast.EnumConstantClassNode in project groovy-core by groovy.
the class EnumVisitor method addInit.
private void addInit(ClassNode enumClass, FieldNode minValue, FieldNode maxValue, FieldNode values, boolean isAic) {
// constructor helper
// This method is used instead of calling the constructor as
// calling the constructor may require a table with MetaClass
// selecting the constructor for each enum value. So instead we
// use this method to have a central point for constructor selection
// and only one table. The whole construction is needed because
// Reflection forbids access to the enum constructor.
// code:
// def $INIT(Object[] para) {
// return this(*para)
// }
ClassNode enumRef = enumClass.getPlainNodeReference();
Parameter[] parameter = new Parameter[] { new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "para") };
MethodNode initMethod = new MethodNode("$INIT", PUBLIC_FS | Opcodes.ACC_SYNTHETIC, enumRef, parameter, ClassNode.EMPTY_ARRAY, null);
initMethod.setSynthetic(true);
ConstructorCallExpression cce = new ConstructorCallExpression(ClassNode.THIS, new ArgumentListExpression(new SpreadExpression(new VariableExpression("para"))));
BlockStatement code = new BlockStatement();
code.addStatement(new ReturnStatement(cce));
initMethod.setCode(code);
enumClass.addMethod(initMethod);
// static init
List<FieldNode> fields = enumClass.getFields();
List<Expression> arrayInit = new ArrayList<Expression>();
int value = -1;
Token assign = Token.newSymbol(Types.ASSIGN, -1, -1);
List<Statement> block = new ArrayList<Statement>();
FieldNode tempMin = null;
FieldNode tempMax = null;
for (FieldNode field : fields) {
if ((field.getModifiers() & Opcodes.ACC_ENUM) == 0)
continue;
value++;
if (tempMin == null)
tempMin = field;
tempMax = field;
ClassNode enumBase = enumClass;
ArgumentListExpression args = new ArgumentListExpression();
args.addExpression(new ConstantExpression(field.getName()));
args.addExpression(new ConstantExpression(value));
if (field.getInitialExpression() == null) {
if ((enumClass.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
addError(field, "The enum constant " + field.getName() + " must override abstract methods from " + enumBase.getName() + ".");
continue;
}
} else {
ListExpression oldArgs = (ListExpression) field.getInitialExpression();
List<MapEntryExpression> savedMapEntries = new ArrayList<MapEntryExpression>();
for (Expression exp : oldArgs.getExpressions()) {
if (exp instanceof MapEntryExpression) {
savedMapEntries.add((MapEntryExpression) exp);
continue;
}
InnerClassNode inner = null;
if (exp instanceof ClassExpression) {
ClassExpression clazzExp = (ClassExpression) exp;
ClassNode ref = clazzExp.getType();
if (ref instanceof EnumConstantClassNode) {
inner = (InnerClassNode) ref;
}
}
if (inner != null) {
List<MethodNode> baseMethods = enumBase.getMethods();
for (MethodNode methodNode : baseMethods) {
if (!methodNode.isAbstract())
continue;
MethodNode enumConstMethod = inner.getMethod(methodNode.getName(), methodNode.getParameters());
if (enumConstMethod == null || (enumConstMethod.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
addError(field, "Can't have an abstract method in enum constant " + field.getName() + ". Implement method '" + methodNode.getTypeDescriptor() + "'.");
}
}
if (inner.getVariableScope() == null) {
enumBase = inner;
/*
* GROOVY-3985: Remove the final modifier from $INIT method in this case
* so that subclasses of enum generated for enum constants (aic) can provide
* their own $INIT method
*/
initMethod.setModifiers(initMethod.getModifiers() & ~Opcodes.ACC_FINAL);
continue;
}
}
args.addExpression(exp);
}
if (savedMapEntries.size() > 0) {
args.getExpressions().add(2, new MapExpression(savedMapEntries));
}
}
field.setInitialValueExpression(null);
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(field), assign, new StaticMethodCallExpression(enumBase, "$INIT", args))));
arrayInit.add(new FieldExpression(field));
}
if (!isAic) {
if (tempMin != null) {
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(minValue), assign, new FieldExpression(tempMin))));
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(maxValue), assign, new FieldExpression(tempMax))));
enumClass.addField(minValue);
enumClass.addField(maxValue);
}
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(values), assign, new ArrayExpression(enumClass, arrayInit))));
enumClass.addField(values);
}
enumClass.addStaticInitializerStatements(block, true);
}
use of org.codehaus.groovy.ast.EnumConstantClassNode in project groovy by apache.
the class EnumVisitor method addInit.
private void addInit(final ClassNode enumClass, final FieldNode minValue, final FieldNode maxValue, final FieldNode values, final boolean isAIC) {
// constructor helper
// This method is used instead of calling the constructor as
// calling the constructor may require a table with MetaClass
// selecting the constructor for each enum value. So instead we
// use this method to have a central point for constructor selection
// and only one table. The whole construction is needed because
// Reflection forbids access to the enum constructor.
// code:
// def $INIT(Object[] para) {
// return this(*para)
// }
ClassNode enumRef = enumClass.getPlainNodeReference();
Parameter[] parameter = new Parameter[] { new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "para") };
MethodNode initMethod = new MethodNode("$INIT", ACC_FINAL | ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, enumRef, parameter, ClassNode.EMPTY_ARRAY, null);
initMethod.setSynthetic(true);
ConstructorCallExpression cce = new ConstructorCallExpression(ClassNode.THIS, new ArgumentListExpression(new SpreadExpression(new VariableExpression("para"))));
BlockStatement code = new BlockStatement();
code.addStatement(new ReturnStatement(cce));
initMethod.setCode(code);
addGeneratedMethod(enumClass, initMethod);
// static init
List<FieldNode> fields = enumClass.getFields();
List<Expression> arrayInit = new ArrayList<>();
int value = -1;
Token assign = Token.newSymbol(Types.ASSIGN, -1, -1);
List<Statement> block = new ArrayList<>();
FieldNode tempMin = null;
FieldNode tempMax = null;
for (FieldNode field : fields) {
if (!field.isEnum())
continue;
value += 1;
if (tempMin == null)
tempMin = field;
tempMax = field;
ClassNode enumBase = enumClass;
ArgumentListExpression args = new ArgumentListExpression();
args.addExpression(new ConstantExpression(field.getName()));
args.addExpression(new ConstantExpression(value));
if (field.getInitialExpression() == null) {
if (enumClass.isAbstract()) {
addError(field, "The enum constant " + field.getName() + " must override abstract methods from " + enumBase.getName() + ".");
continue;
}
} else {
ListExpression oldArgs = (ListExpression) field.getInitialExpression();
List<MapEntryExpression> savedMapEntries = new ArrayList<>();
for (Expression exp : oldArgs.getExpressions()) {
if (exp instanceof MapEntryExpression) {
savedMapEntries.add((MapEntryExpression) exp);
continue;
}
InnerClassNode inner = null;
if (exp instanceof ClassExpression) {
ClassExpression clazzExp = (ClassExpression) exp;
ClassNode ref = clazzExp.getType();
if (ref instanceof EnumConstantClassNode) {
inner = (InnerClassNode) ref;
}
}
if (inner != null) {
List<MethodNode> baseMethods = enumBase.getMethods();
for (MethodNode methodNode : baseMethods) {
if (!methodNode.isAbstract())
continue;
MethodNode enumConstMethod = inner.getMethod(methodNode.getName(), methodNode.getParameters());
if (enumConstMethod == null || enumConstMethod.isAbstract()) {
addError(field, "Can't have an abstract method in enum constant " + field.getName() + ". Implement method '" + methodNode.getTypeDescriptor() + "'.");
}
}
if (inner.getVariableScope() == null) {
enumBase = inner;
/*
* GROOVY-3985: Remove the final modifier from $INIT method in this case
* so that subclasses of enum generated for enum constants (aic) can provide
* their own $INIT method
*/
initMethod.setModifiers(initMethod.getModifiers() & ~ACC_FINAL);
continue;
}
}
args.addExpression(exp);
}
if (!savedMapEntries.isEmpty()) {
args.getExpressions().add(2, new MapExpression(savedMapEntries));
}
}
field.setInitialValueExpression(null);
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(field), assign, new StaticMethodCallExpression(enumBase, "$INIT", args))));
arrayInit.add(new FieldExpression(field));
}
if (!isAIC) {
if (tempMin != null) {
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(minValue), assign, new FieldExpression(tempMin))));
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(maxValue), assign, new FieldExpression(tempMax))));
enumClass.addField(minValue);
enumClass.addField(maxValue);
}
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(values), assign, new ArrayExpression(enumClass, arrayInit))));
enumClass.addField(values);
}
enumClass.addStaticInitializerStatements(block, true);
}
Aggregations