splittedType = JavaTypeFactory.splitTypeFromArrayDimension(normalizedType);
+ String baseType = splittedType.left();
final int arrayDimension = splittedType.right();
- // if the type is a primitive (e.g. int) or a primitive wrapper (e.g.
- // Integer)
- if (JavaTypeFactory.isPrimitive(type)) {
- Primitive primitive = Primitive.getPrimitive(type);
- if (arrayDimension == 0) {
- final JavaType primitiveType = JavaTypeFactory.getPrimitiveWrapper(primitive);
- primitiveType.setArrayDimension(arrayDimension);
- return primitiveType;
- }
- final JavaType primitiveType = JavaTypeFactory.getPrimitiveType(Primitive.getPrimitive(type));
- primitiveType.setArrayDimension(arrayDimension);
- return primitiveType;
+ // if the type is a primitive (e.g. int) or a primitive wrapper (e.g. Integer)
+ if (JavaTypeFactory.isPrimitive(baseType)) {
+ Primitive primitive = Primitive.getPrimitive(baseType);
+ return strategy.convertPrimitive(primitive, arrayDimension);
}
- if (JavaTypeFactory.isPrimitiveWrapper(type)) {
- final JavaType primitiveWrapper = JavaTypeFactory.getPrimitiveWrapper(type);
+ if (JavaTypeFactory.isPrimitiveWrapper(baseType)) {
+ final JavaType primitiveWrapper = JavaTypeFactory.getPrimitiveWrapper(baseType);
primitiveWrapper.setArrayDimension(arrayDimension);
return primitiveWrapper;
}
- return getConvertedTypeAux(type, generator, arrayDimension);
+ return getConvertedTypeAux(baseType, generator, arrayDimension);
}
private static JavaType getConvertedTypeAux(String type, JavaAbstractsGenerator generator,
@@ -146,15 +184,15 @@ private static JavaType getConvertedTypeAux(String type, JavaAbstractsGenerator
return clone;
}
- // if it is the base joinpoint type
- if (keyType.equals(ConvertUtils.JoinPointClassTypeName)) {
+ // if it is the base joinpoint type (case-insensitive match)
+ if (keyType.equalsIgnoreCase(ConvertUtils.JoinPointClassTypeName)) {
final JavaType clone = generator.getaJoinPointType().clone();
clone.setArrayDimension(arrayDimension);
return clone;
}
- // if it is the joinpoint interface type
- if (keyType.equals(ConvertUtils.JoinPointInterfaceClassTypeName)) {
+ // if it is the joinpoint interface type (case-insensitive match)
+ if (keyType.equalsIgnoreCase(ConvertUtils.JoinPointInterfaceClassTypeName)) {
final JavaType clone = GenConstants.getJoinPointInterfaceType().clone();
clone.setArrayDimension(arrayDimension);
return clone;
@@ -249,4 +287,210 @@ private static String normalizeWrappedReference(String rawType, String trimmed,
public static String ln() {
return Utils.ln();
}
+
+ // ========== IType-aware type conversion ==========
+
+ /**
+ * Converts an IType to a JavaType, resolving ThisType to the current join point
+ * type.
+ * This method handles all IType subtypes including ParameterizedType,
+ * ArrayType, WildcardType, etc.
+ *
+ * @param type the IType to convert (must not be null)
+ * @param generator the generator context for resolving type references
+ * @param currentJpType the JavaType representing the current join point
+ * abstract being generated; ThisType will resolve to this
+ * type. Must not be null if the type contains ThisType
+ * (directly or nested in generic arguments).
+ * @return the converted JavaType
+ * @throws IllegalArgumentException if type is null
+ * @throws IllegalStateException if ThisType is encountered but currentJpType
+ * is null (ThisType is not supported in
+ * contexts like TypeDef fields)
+ */
+ public static JavaType getConvertedType(IType type, JavaAbstractsGenerator generator, JavaType currentJpType) {
+ return getConvertedType(type, generator, currentJpType, PrimitiveConversionStrategy.STANDARD);
+ }
+
+ /**
+ * Converts an IType to a JavaType for use as an attribute return type.
+ * Similar to {@link #getConvertedType(IType, JavaAbstractsGenerator, JavaType)}
+ * but wraps
+ * primitives in their wrapper classes for use as return types.
+ *
+ * @param type the IType to convert (must not be null)
+ * @param generator the generator context for resolving type references
+ * @param currentJpType the JavaType representing the current join point
+ * abstract; ThisType will resolve to this type. Must not
+ * be null if the type contains ThisType (directly or
+ * nested in generic arguments).
+ * @return the converted JavaType with primitives wrapped
+ * @throws IllegalArgumentException if type is null
+ * @throws IllegalStateException if ThisType is encountered but currentJpType
+ * is null (ThisType is not supported in
+ * contexts like TypeDef fields)
+ */
+ public static JavaType getAttributeConvertedType(IType type, JavaAbstractsGenerator generator,
+ JavaType currentJpType) {
+ return getConvertedType(type, generator, currentJpType, PrimitiveConversionStrategy.ATTRIBUTE_RETURN);
+ }
+
+ private static JavaType getConvertedType(IType type, JavaAbstractsGenerator generator, JavaType currentJpType,
+ PrimitiveConversionStrategy strategy) {
+ if (type == null) {
+ throw new IllegalArgumentException("Type cannot be null");
+ }
+
+ // Handle ThisType - resolve to current join point type
+ if (type instanceof ThisType) {
+ if (currentJpType == null) {
+ throw new IllegalStateException(
+ "ThisType found but no currentJpType context provided. " +
+ "ThisType is not supported in this context (e.g., TypeDef fields).");
+ }
+ return currentJpType.clone();
+ }
+
+ // Handle ArrayType - recursively convert base type and set dimension
+ if (type instanceof ArrayType arrayType) {
+ // For arrays, use the base conversion to ensure primitives are wrapped at the
+ // element level
+ JavaType baseJavaType = getConvertedType(arrayType.getBaseType(), generator, currentJpType, strategy);
+ baseJavaType.setArrayDimension(baseJavaType.getArrayDimension() + arrayType.getDimension());
+ return baseJavaType;
+ }
+
+ // Handle ParameterizedType - convert base and type arguments
+ if (type instanceof ParameterizedType paramType) {
+ JavaType baseJavaType = getRawBaseType(paramType.getBaseType(), generator, currentJpType);
+
+ for (IType typeArg : paramType.getTypeArguments()) {
+ JavaType argJavaType = getConvertedType(typeArg, generator, currentJpType, strategy);
+ baseJavaType.addGeneric(new JavaGenericType(argJavaType));
+ }
+
+ return baseJavaType;
+ }
+
+ // Handle WildcardType
+ if (type instanceof WildcardType wildcardType) {
+ return convertWildcardType(wildcardType, generator, currentJpType);
+ }
+
+ // Handle JPType (join point reference)
+ if (type instanceof JPType jpType) {
+ String jpClassName = jpType.getJointPoint().getName();
+ // Check if this is the global join point (named "joinpoint")
+ // If so, use the pre-configured AJoinPoint type from the generator
+ if (jpClassName.equalsIgnoreCase(JoinPointClassTypeName)) {
+ return generator.getaJoinPointType().clone();
+ }
+ // For regular join points, construct the abstract class name
+ String jpName = GenConstants.abstractPrefix() + StringUtils.firstCharToUpper(jpClassName);
+ return new JavaType(jpName, generator.getJoinPointClassPackage());
+ }
+
+ // Handle GenericType - check standard Java types first, then fall back to
+ // string-based conversion
+ if (type instanceof GenericType genericType) {
+ String typeName = genericType.type();
+ // Check standard Java types (List, Set, Optional, etc.)
+ if (StandardJavaTypes.containsKey(typeName)) {
+ JavaType result = StandardJavaTypes.get(typeName).clone();
+ if (genericType.isArray()) {
+ result.setArrayDimension(1);
+ }
+ return result;
+ }
+ }
+
+ // Fall back to string-based conversion for other simple types
+ return getConvertedType(type.type(), generator, strategy);
+ }
+
+ /**
+ * Gets the raw base type for use in ParameterizedType conversion.
+ * This method ensures that when resolving generic container types like Map,
+ * List, etc.,
+ * we get a clean type without any pre-populated generics.
+ *
+ *
+ * The InterpreterTypes map contains some types with pre-populated wildcards for
+ * backward compatibility (e.g., Map, ?>). When we're building a
+ * ParameterizedType with explicit type arguments, we need the raw type without
+ * these wildcards.
+ *
+ *
+ * @param baseType the base type of a ParameterizedType
+ * @param generator the generator context
+ * @param currentJpType the current join point type for ThisType resolution
+ * @return a JavaType representing the raw base type without pre-populated
+ * generics
+ */
+ private static JavaType getRawBaseType(IType baseType, JavaAbstractsGenerator generator, JavaType currentJpType) {
+ // For GenericType, check if it's a standard Java type
+ if (baseType instanceof GenericType genericType) {
+ String typeName = genericType.type();
+ // Use StandardJavaTypes which have clean types without pre-populated generics
+ if (StandardJavaTypes.containsKey(typeName)) {
+ return StandardJavaTypes.get(typeName).clone();
+ }
+ }
+
+ // Handle PrimitiveClasses that are also in StandardJavaTypes (e.g., MAP)
+ // PrimitiveClasses.MAP has pre-populated wildcards in InterpreterTypes,
+ // so we need to use the clean version from StandardJavaTypes
+ if (baseType instanceof PrimitiveClasses primitiveClass) {
+ String typeName = primitiveClass.type(); // e.g., "Map"
+ if (StandardJavaTypes.containsKey(typeName)) {
+ return StandardJavaTypes.get(typeName).clone();
+ }
+ }
+
+ // For other types, convert normally.
+ // Note: Only collection types in InterpreterTypes have pre-populated generics,
+ // and those are handled above via StandardJavaTypes. Other types (String,
+ // Object, etc.) don't have pre-populated generics that would interfere.
+ return getConvertedType(baseType, generator, currentJpType);
+ }
+
+ /**
+ * Converts a WildcardType to a JavaType representing a wildcard.
+ * Note: Wildcards in Java generics are special - they can only appear as type
+ * arguments, not as standalone types. This method returns a JavaType that can
+ * be used with addGeneric().
+ * For unbounded wildcards, returns the wildcard type directly.
+ * For bounded wildcards, we create the bound type and represent the wildcard
+ * accordingly.
+ */
+ private static JavaType convertWildcardType(WildcardType wildcardType, JavaAbstractsGenerator generator,
+ JavaType currentJpType) {
+ switch (wildcardType.getKind()) {
+ case UNBOUNDED:
+ return JavaTypeFactory.getWildCardType();
+
+ case EXTENDS:
+ // For ? extends T, we need to properly represent the bounded wildcard
+ JavaType extendsBound = getConvertedType(wildcardType.getBound(), generator, currentJpType);
+ // Create a type that represents ? extends T
+ // Use the full type representation including package if needed
+ String extendsTypeName = extendsBound.getPackage().isEmpty()
+ ? extendsBound.getSimpleType()
+ : extendsBound.getPackage() + "." + extendsBound.getSimpleType();
+ JavaType extendsWildcard = new JavaType("? extends " + extendsTypeName);
+ return extendsWildcard;
+
+ case SUPER:
+ JavaType superBound = getConvertedType(wildcardType.getBound(), generator, currentJpType);
+ // Create a type that represents ? super T
+ String superTypeName = superBound.getPackage().isEmpty()
+ ? superBound.getSimpleType()
+ : superBound.getPackage() + "." + superBound.getSimpleType();
+ JavaType superWildcard = new JavaType("? super " + superTypeName);
+ return superWildcard;
+
+ default:
+ throw new IllegalArgumentException("Unknown wildcard kind: " + wildcardType.getKind());
+ }
+ }
}
diff --git a/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/CrtpJavaClass.java b/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/CrtpJavaClass.java
new file mode 100644
index 000000000..aca8036bb
--- /dev/null
+++ b/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/CrtpJavaClass.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright 2026 SPeCS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package org.lara.interpreter.weaver.generator.generator.java.utils;
+
+import org.specs.generators.java.classtypes.JavaClass;
+import org.specs.generators.java.enums.Modifier;
+import org.specs.generators.java.types.JavaType;
+import org.specs.generators.java.types.JavaTypeFactory;
+
+/**
+ * A JavaClass that supports the CRTP (Curiously Recurring Template Pattern) for polymorphic "this" types.
+ *
+ *
This class extends JavaClass to add class-level type parameters while keeping the
+ * file name clean. The standard JavaClass uses the name for both the class declaration
+ * and the file name, which prevents using type parameters like {@code ANode>}.
+ *
+ * ALL classes get the CRTP type parameter for consistency and future extensibility:
+ *
+ * CrtpJavaClass javaC = new CrtpJavaClass("ANode", package);
+ * // Generates: public abstract class ANode<Self extends ANode<Self>> extends ASuperClass<Self>
+ *
+ * CrtpJavaClass javaC = new CrtpJavaClass("ALoop", package);
+ * // Generates: public abstract class ALoop<Self extends ALoop<Self>> extends AStmt<Self>
+ *
+ */
+public class CrtpJavaClass extends JavaClass {
+
+ /** The name used for the CRTP type parameter */
+ public static final String SELF_TYPE_PARAMETER = "Self";
+
+ private String superClassTypeArg;
+ private boolean addTypeArgToSuperClass = true;
+
+ /**
+ * Creates a CRTP-enabled JavaClass.
+ *
+ * All classes get the CRTP type parameter {@code >} for
+ * consistency and to allow any class to be extended in the future.
+ *
+ * @param name the base class name (without type parameters, e.g., "ANode")
+ * @param classPackage the class package
+ */
+ public CrtpJavaClass(String name, String classPackage) {
+ super(name, classPackage);
+ this.superClassTypeArg = null;
+ }
+
+ /**
+ * Creates a CRTP-enabled JavaClass with modifier.
+ *
+ * All classes get the CRTP type parameter {@code >} for
+ * consistency and to allow any class to be extended in the future.
+ *
+ * @param name the base class name (without type parameters, e.g., "ANode")
+ * @param classPackage the class package
+ * @param modifier the class modifier
+ */
+ public CrtpJavaClass(String name, String classPackage, Modifier modifier) {
+ super(name, classPackage, modifier);
+ this.superClassTypeArg = null;
+ }
+
+ /**
+ * Sets whether to add a type argument to the superclass.
+ *
+ * Use this when the superclass doesn't support type parameters (e.g., the base JoinPoint class).
+ *
+ * @param addTypeArg true to add type argument, false to omit it
+ */
+ public void setAddTypeArgToSuperClass(boolean addTypeArg) {
+ this.addTypeArgToSuperClass = addTypeArg;
+ }
+
+ /**
+ * Sets the superclass with a type argument for CRTP.
+ *
+ * All classes now use "Self" as the type argument to maintain consistency:
+ * setSuperClassWithTypeArg("AParent") // Uses "Self" as type arg
+ *
+ * @param superClassName the simple name of the superclass (used for documentation, actual superclass set via setSuperClass)
+ */
+ public void setSuperClassWithTypeArg(String superClassName) {
+ this.superClassTypeArg = SELF_TYPE_PARAMETER;
+ }
+
+ /**
+ * Overrides the default setSuperClass to track that we may need type args.
+ *
+ * @param superClass the superclass type
+ */
+ @Override
+ public void setSuperClass(JavaType superClass) {
+ super.setSuperClass(superClass);
+ // If we haven't explicitly set a type arg, always use Self (all classes use CRTP)
+ if (superClassTypeArg == null) {
+ superClassTypeArg = SELF_TYPE_PARAMETER;
+ }
+ }
+
+ /**
+ * Generates the Java class code with CRTP type parameters.
+ *
+ * All classes are generated with the CRTP pattern:
+ * public abstract class ANode<Self extends ANode<Self>> extends AParent<Self>
+ * public abstract class ALoop<Self extends ALoop<Self>> extends AStmt<Self>
+ *
+ * @param indentation the indentation level
+ * @return the generated Java class code
+ */
+ @Override
+ public StringBuilder generateCode(int indentation) {
+ final StringBuilder classGen = generateClassHeader(indentation);
+
+ classGen.append("class ");
+ classGen.append(getName());
+
+ // All classes get the CRTP type parameter
+ classGen.append("<");
+ classGen.append(SELF_TYPE_PARAMETER);
+ classGen.append(" extends ");
+ classGen.append(getName());
+ classGen.append("<");
+ classGen.append(SELF_TYPE_PARAMETER);
+ classGen.append(">>");
+
+ // Add extends clause with type argument
+ JavaType superClass = getSuperClass();
+ if (superClass != null && !superClass.equals(JavaTypeFactory.getObjectType())) {
+ classGen.append(" extends ");
+ classGen.append(superClass.getSimpleType());
+ // Add type argument to superclass (only if enabled and we have a type arg)
+ if (addTypeArgToSuperClass && superClassTypeArg != null) {
+ classGen.append("<");
+ classGen.append(superClassTypeArg);
+ classGen.append(">");
+ }
+ }
+
+ addImplements(classGen);
+ classGen.append(" {" + ln() + ln());
+
+ addFields(indentation, classGen);
+ addConstructors(indentation, classGen);
+
+ addMethods(indentation, classGen);
+
+ classGen.append(generateClassTail(indentation));
+ return classGen;
+ }
+}
diff --git a/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/GeneratorUtils.java b/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/GeneratorUtils.java
index 73e9a719a..48a96de24 100644
--- a/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/GeneratorUtils.java
+++ b/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/GeneratorUtils.java
@@ -13,6 +13,15 @@
package org.lara.interpreter.weaver.generator.generator.java.utils;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
import org.lara.interpreter.exception.ActionException;
import org.lara.interpreter.exception.AttributeException;
import org.lara.interpreter.weaver.generator.generator.java.JavaAbstractsGenerator;
@@ -24,30 +33,85 @@
import org.lara.language.specification.dsl.JoinPointClass;
import org.lara.language.specification.dsl.Parameter;
import org.lara.language.specification.dsl.types.ArrayType;
+import org.lara.language.specification.dsl.types.GenericType;
+import org.lara.language.specification.dsl.types.IType;
import org.lara.language.specification.dsl.types.JPType;
+import org.lara.language.specification.dsl.types.LiteralEnum;
+import org.lara.language.specification.dsl.types.ParameterizedType;
import org.lara.language.specification.dsl.types.PrimitiveClasses;
+import org.lara.language.specification.dsl.types.ThisType;
+import org.lara.language.specification.dsl.types.WildcardType;
import org.specs.generators.java.classtypes.JavaClass;
import org.specs.generators.java.classtypes.JavaEnum;
import org.specs.generators.java.enums.Annotation;
import org.specs.generators.java.enums.JDocTag;
import org.specs.generators.java.enums.Modifier;
import org.specs.generators.java.enums.Privacy;
-import org.specs.generators.java.members.*;
+import org.specs.generators.java.members.Argument;
+import org.specs.generators.java.members.Constructor;
+import org.specs.generators.java.members.EnumItem;
+import org.specs.generators.java.members.Field;
+import org.specs.generators.java.members.JavaDoc;
+import org.specs.generators.java.members.Method;
import org.specs.generators.java.types.JavaType;
import org.specs.generators.java.types.JavaTypeFactory;
import org.specs.generators.java.utils.Utils;
+
import tdrc.utils.Pair;
import tdrc.utils.StringUtils;
-import java.util.*;
-import java.util.function.Function;
-
public class GeneratorUtils {
private static String ln() {
return Utils.ln();
}
+ /**
+ * Checks if the given IType contains ThisType (directly or nested in generic
+ * arguments, arrays, etc.).
+ *
+ * @param type the type to check
+ * @return true if the type contains ThisType anywhere in its structure
+ */
+ public static boolean containsThisType(IType type) {
+ return containsType(type, candidate -> candidate instanceof ThisType);
+ }
+
+ /**
+ * Checks if the given IType contains a join point type (directly or nested in
+ * generic arguments, arrays, etc.).
+ */
+ public static boolean containsJoinPointType(IType type) {
+ return containsType(type, candidate -> candidate instanceof JPType);
+ }
+
+ private static boolean containsType(IType type, Predicate matcher) {
+ if (type == null) {
+ return false;
+ }
+ if (matcher.test(type)) {
+ return true;
+ }
+ if (type instanceof ArrayType arrayType) {
+ return containsType(arrayType.getBaseType(), matcher);
+ }
+ if (type instanceof ParameterizedType paramType) {
+ if (containsType(paramType.getBaseType(), matcher)) {
+ return true;
+ }
+ for (IType typeArg : paramType.getTypeArguments()) {
+ if (containsType(typeArg, matcher)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (type instanceof WildcardType wildcardType) {
+ return containsType(wildcardType.getBound(), matcher);
+ }
+ return false;
+ }
+
/**
* Add methods of the super join point to the java class
*
@@ -64,6 +128,39 @@ public static void addSuperMethods(JavaClass javaC, String fieldName, JavaAbstra
addSuperMethods(javaC, fieldName, generator, parent);
}
+ /**
+ * Add methods of the super join point to the java class, resolving ThisType to
+ * "Self".
+ *
+ *
+ * With CRTP (Curiously Recurring Template Pattern), all classes in the
+ * hierarchy use the same "Self" type parameter. Therefore, inherited methods
+ * that use ThisType should also resolve to "Self" - the override is valid
+ * because both parent and child use "Self".
+ *
+ *
+ * @param javaC the target Java class
+ * @param fieldName the name of the field holding the super join point
+ * @param generator the generator context
+ * @param current the current join point class
+ * @param currentJpType the JavaType representing "Self" - used for ThisType
+ * resolution in all methods
+ */
+ public static void addSuperMethods(JavaClass javaC, String fieldName, JavaAbstractsGenerator generator,
+ JoinPointClass current, JavaType currentJpType) {
+
+ var parent = current.getExtendExplicit().orElse(null);
+ if (parent == null) {
+ return;
+ }
+
+ // With CRTP, all classes use "Self" as their type parameter, so inherited
+ // methods should also use "Self" for ThisType resolution (the override is valid
+ // because both parent and child use the same type parameter "Self")
+ addSuperGetters(javaC, fieldName, generator, parent.getAttributesSelf(), currentJpType);
+ addSuperMethods(javaC, fieldName, generator, parent, currentJpType);
+ }
+
/**
*/
public static void addSuperToString(JavaClass javaC, String fieldName) {
@@ -82,27 +179,70 @@ public static void addSuperGetters(JavaClass javaC, String fieldName, JavaAbstra
public static void addSuperGetters(JavaClass javaC, String fieldName, JavaAbstractsGenerator generator,
List attributes) {
+ addSuperGetters(javaC, fieldName, generator, attributes, null);
+
+ }
+
+ @FunctionalInterface
+ private interface ParameterTypeResolver {
+ JavaType resolve(Parameter parameter);
+ }
+
+ /**
+ * Add getter methods for inherited attributes.
+ *
+ *
+ * With CRTP (Curiously Recurring Template Pattern), all classes use "Self" as
+ * their type parameter. Therefore, inherited attributes that use ThisType
+ * should also resolve to "Self" - the override is valid because both parent and
+ * child use the same type parameter.
+ *
+ *
+ * @param javaC the target Java class
+ * @param fieldName the name of the field holding the super join point
+ * @param generator the generator context
+ * @param attributes the list of inherited attributes
+ * @param currentJpType the JavaType representing "Self" (for ThisType
+ * resolution)
+ */
+ public static void addSuperGetters(JavaClass javaC, String fieldName, JavaAbstractsGenerator generator,
+ List attributes, JavaType currentJpType) {
- // TODO: Remove sort
var mutableAttributes = new ArrayList<>(attributes);
mutableAttributes.sort(Comparator.comparing(Attribute::getName));
+ boolean hasThisTypeContext = currentJpType != null;
for (var attribute : mutableAttributes) {
- // System.out.println("ATTR:" + attribute.getName());
- String attrClassStr = attribute.getReturnType().trim();
+ JavaType type;
+ ParameterTypeResolver parameterTypeResolver;
+ boolean needsCast = false;
- if (attrClassStr.startsWith("{")) { // then it is an enumerator
- attrClassStr = String.class.getSimpleName();
- }
+ if (hasThisTypeContext) {
+ IType attrType = attribute.getType();
+ needsCast = containsThisType(attrType);
- // if (ObjectOfPrimitives.contains(attrClassStr))
- // attrClassStr = ObjectOfPrimitives.getPrimitive(attrClassStr);
+ // Handle literal enums specially
+ if (attrType instanceof LiteralEnum) {
+ attrType = new GenericType("String", false);
+ }
+
+ type = ConvertUtils.getAttributeConvertedType(attrType, generator, currentJpType);
+ parameterTypeResolver = parameter -> ConvertUtils.getConvertedType(parameter.getIType(), generator,
+ currentJpType);
+ } else {
+ String attrClassStr = attribute.getReturnType().trim();
+ if (attrClassStr.startsWith("{")) { // then it is an enumerator
+ attrClassStr = String.class.getSimpleName();
+ }
+
+ type = ConvertUtils.getAttributeConvertedType(attrClassStr, generator);
+ parameterTypeResolver = parameter -> ConvertUtils.getConvertedType(parameter.getType(), generator);
+ }
String sanitizedName = sanitizeAttributeName(attribute.getName());
String methodBase = attributeMethodBaseName(attribute.getName());
- JavaType type = ConvertUtils.getAttributeConvertedType(attrClassStr, generator);
String effectiveMethodBase = methodBase;
if (type.isArray()) {
effectiveMethodBase += GenConstants.getArrayMethodSufix();
@@ -112,10 +252,9 @@ public static void addSuperGetters(JavaClass javaC, String fieldName, JavaAbstra
}
final Method getter = createSuperGetter(sanitizedName, effectiveMethodBase, type, fieldName,
- attribute.getParameters(),
- generator);
+ attribute.getParameters(), parameterTypeResolver, needsCast);
- if (hasMethod(javaC, getter)) {
+ if (hasMethodSignature(javaC, getter)) {
continue;
}
@@ -131,7 +270,8 @@ public static void addSuperGetters(JavaClass javaC, String fieldName, JavaAbstra
*/
public static void addSuperActions(JavaAbstractsGenerator javaGenerator, JavaClass javaC,
JoinPointClass joinPointSuperType,
- String fieldName) {
+ String fieldName,
+ JavaType currentJpType) {
var jps = new ArrayList<>(joinPointSuperType.getActions());
@@ -154,28 +294,29 @@ public static void addSuperActions(JavaAbstractsGenerator javaGenerator, JavaCla
// Sort with the insert actions inside
jps.sort(Comparator.comparing(Action::getName));
- // getJoinPointOwnActions(joinPointSuperType); // These two lines makes
- // the same thing as the code above
- // joinPointOwnActions.addAll(langSpec.getActionModel().getActionsForAll());
for (var action : jps) {
- // for (var action :
- // joinPointSuperType.getActionsSelf().stream().sorted((attribute, t1) ->
- // attribute.getName().compareTo(t1.getName())).toList()) {
-
- final Method m = generateActionMethod(action, javaGenerator);
+ final Method m = generateActionMethod(action, javaGenerator, currentJpType);
m.setName(m.getName() + GenConstants.getImplementationSufix());
m.clearCode();
m.add(Annotation.OVERRIDE);
+
+ // Check if the return type involves ThisType (which resolves to Self)
+ // If so, we need to cast the delegation result since the delegate field has raw
+ // type
+ boolean needsCast = containsThisType(action.getType()) || containsJoinPointType(action.getType());
+
if (!action.getReturnType().equals("void")) {
m.appendCode("return ");
+ if (needsCast) {
+ // Add cast to the method's return type (which has Self resolved)
+ m.appendCode("(" + m.getReturnType().getSimpleType() + ") ");
+ }
}
- m.appendCode("this." + fieldName + "." + m.getName() + "(");
- final String joinedParameters = StringUtils.join(m.getParams(), Argument::getName, ", ");
- m.appendCode(joinedParameters);
+ appendDelegationInvocation(m, fieldName, m.getName());
- m.appendCode(");");
-
- javaC.add(m);
+ if (!hasMethodSignature(javaC, m)) {
+ javaC.add(m);
+ }
}
}
@@ -192,9 +333,6 @@ public static Pair createGetterAndSetter(Field field, String ori
boolean abstractGetters) {
final String attr = field.getName();
final JavaType attrClassType = field.getType();
- // attrClassType = JavaTypeFactory.primitiveUnwrap(attrClassType);
- // if (ObjectOfPrimitives.contains(getAttrType))
- // getAttrType = ObjectOfPrimitives.getPrimitive(getAttrType);
final Method getAttribute = createGetter(attr, originalName, attrClassType, abstractGetters);
final Method setAttribute = createSetter(attr, originalName, attrClassType);
@@ -236,35 +374,34 @@ private static Method createGetter(String attr, String originalName, JavaType ge
private static Method createSuperGetter(String attr, String originalName, JavaType getAttrType, String superField,
List list,
- JavaAbstractsGenerator generator) {
-
- if (!list.isEmpty()) {
- final Method getAttribute = new Method(getAttrType, originalName);
- // getAttribute.addModifier(Modifier.ABSTRACT);
- getAttribute.appendComment("Get value on attribute " + attr);
- getAttribute.addJavaDocTag(JDocTag.RETURN, "the attribute's value");
- getAttribute.appendCode("return this." + superField + "." + originalName + "(");
-
- for (var parameter : list) {
+ ParameterTypeResolver parameterTypeResolver, boolean needsCast) {
- JavaType type = ConvertUtils.getConvertedType(parameter.getType(), generator);
- getAttribute.addArgument(type, parameter.getName());
- getAttribute.appendCode(parameter.getName());
- }
- getAttribute.appendCode(");");
-
- return getAttribute;
- }
- final String getName = "get" + Utils.firstCharToUpper(originalName);
- final Method getAttribute = new Method(getAttrType, getName);
- // getAttribute.addModifier(Modifier.ABSTRACT);
+ final boolean hasParameters = !list.isEmpty();
+ final String methodName = hasParameters ? originalName : "get" + Utils.firstCharToUpper(originalName);
+ final Method getAttribute = new Method(getAttrType, methodName);
getAttribute.appendComment("Get value on attribute " + attr);
getAttribute.addJavaDocTag(JDocTag.RETURN, "the attribute's value");
- getAttribute.appendCode("return this." + superField + "." + getName + "();");
+ getAttribute.appendCode("return ");
+ if (needsCast) {
+ getAttribute.appendCode("(" + getAttrType.getSimpleType() + ") ");
+ }
+
+ for (var parameter : list) {
+ JavaType type = parameterTypeResolver.resolve(parameter);
+ getAttribute.addArgument(type, parameter.getName());
+ }
+
+ appendDelegationInvocation(getAttribute, superField, methodName);
return getAttribute;
}
+ private static void appendDelegationInvocation(Method method, String targetField, String targetMethodName) {
+ method.appendCode("this." + targetField + "." + targetMethodName + "(");
+ method.appendCode(StringUtils.join(method.getParams(), Argument::getName, ", "));
+ method.appendCode(");");
+ }
+
public static void encapsulateArrayAttribute(JavaClass javaC, Method getter) {
final Method newGetter = getter.clone();
newGetter.setName(newGetter.getName() + GenConstants.getArrayMethodSufix());
@@ -282,8 +419,7 @@ public static void encapsulateArrayAttribute(JavaClass javaC, Method getter) {
final String argsList = StringUtils.join(arguments, Argument::getName, ", ");
getter.appendCode(argsList);
getter.appendCode(");" + ln());
- getter.appendCode(encapsulateBasedOnDimension(baseType, valueName, returnType.getArrayDimension(), 0));
- getter.appendCode("return " + GenConstants.getNativeArrayVarName() + "0;");
+ getter.appendCode("return " + valueName + "0;");
getter.remove(Modifier.ABSTRACT);
javaC.add(newGetter);
}
@@ -291,34 +427,11 @@ public static void encapsulateArrayAttribute(JavaClass javaC, Method getter) {
public static String encapsulateBasedOnDimension(String baseType, String valueName, int dimension, int position) {
final String spaceStr = "\t".repeat(position);
final String nativeArrayVarName = GenConstants.getNativeArrayVarName();
- if (dimension == 1) {
- // return spaceStr + "Bindings " + nativeArrayVarName + position + " =
- // Converter.toNativeArray(" + valueName
- // + position + ");\n";
- // return spaceStr + "Bindings " + nativeArrayVarName + position
- return spaceStr + "Object " + nativeArrayVarName + position
- + " = " + valueName + position + ";" + ln();
- }
- String converted = "";
- final int currentNa = position;
- final int nextNa = position + 1;
- // int previousNa = dimension + 1;
- String currentBinding = nativeArrayVarName + currentNa;
- // converted += spaceStr + "Bindings " + currentBinding + " =
- // Converter.newNativeArray();\n";
- converted += spaceStr + "Object " + currentBinding + " = Converter.newNativeArray();" + ln();
- String iNa = "i" + currentNa;
- converted += spaceStr + "for (int " + iNa + " = 0; i < " + valueName + currentNa + ".length; i++) {" + ln();
- converted += spaceStr + "\t" + baseType + "[]".repeat(dimension - 1);
- converted += " " + valueName + nextNa + " = " + valueName + currentNa + "[ " + iNa + "];" + ln();
- converted += encapsulateBasedOnDimension(baseType, valueName, dimension - 1, position + 1);
- converted += spaceStr + "\t" + currentBinding + ".put(\"\"+" + iNa + ", " + nativeArrayVarName + nextNa
- + ");" + ln();
- converted += spaceStr + "}" + ln();
- return converted;
- }
-
- private static boolean hasMethod(JavaClass javaClass, Method candidate) {
+ return spaceStr + "Object " + nativeArrayVarName + position
+ + " = " + valueName + position + ";" + ln();
+ }
+
+ public static boolean hasMethodSignature(JavaClass javaClass, Method candidate) {
return javaClass.getMethods().stream().anyMatch(existing -> sameSignature(existing, candidate));
}
@@ -378,6 +491,38 @@ public static Method generateActionMethod(org.lara.language.specification.dsl.Ac
return m;
}
+ /**
+ * Generates the method with the name and parameters of the action, resolving
+ * ThisType to the current join point type.
+ *
+ * @param action the action used to generate its method
+ * @param generator the generator context
+ * @param currentJpType the JavaType representing the current join point
+ * abstract being generated
+ */
+ public static Method generateActionMethod(org.lara.language.specification.dsl.Action action,
+ JavaAbstractsGenerator generator, JavaType currentJpType) {
+
+ JavaType actionReturn = getJavaType(action.getType(), action.getName(), action, "ActionParam", generator,
+ currentJpType);
+ final Method m = new Method(actionReturn, action.getName());
+ action.getToolTip().ifPresent(m::appendComment);
+ for (var param : action.getParameters()) {
+
+ String paramName = param.getName();
+ paramName = StringUtils.getSanitizedName(paramName);
+ JavaType jType = getJavaType(param.getIType(), paramName, action, "ActionParam", generator, currentJpType);
+
+ paramName = StringUtils.getSanitizedName(paramName);
+ m.addArgument(jType, paramName);
+ m.addJavaDocTag(JDocTag.PARAM, paramName + " ");
+ }
+ m.appendCode("throw new UnsupportedOperationException(" + GenConstants.getClassName() + "()+\": Action "
+ + action.getName() + " not implemented \");");
+
+ return m;
+ }
+
private static JavaType getJavaType(String type, String paramName,
org.lara.language.specification.dsl.Action action, String sufix,
JavaAbstractsGenerator generator) {
@@ -397,6 +542,29 @@ private static JavaType getJavaType(String type, String paramName,
return jType;
}
+ /**
+ * Converts an IType to a JavaType, resolving ThisType to the current join point
+ * type.
+ */
+ private static JavaType getJavaType(IType type, String paramName,
+ org.lara.language.specification.dsl.Action action, String sufix,
+ JavaAbstractsGenerator generator, JavaType currentJpType) {
+
+ // Check for literal enum (inline enum definition like {val1, val2, val3})
+ // A LiteralEnum with only one value is typically a type reference like
+ // {TypeName}, not a true enum. We only generate an enum for multi-value
+ // LiteralEnums.
+ if (type instanceof LiteralEnum literalEnum && literalEnum.getValues().size() > 1) {
+ final String firstCharToUpper = StringUtils.firstCharToUpper(action.getName());
+ final JavaEnum enumerator = generateEnum(type.type(), paramName, firstCharToUpper + sufix, generator);
+ generator.getEnums().add(enumerator);
+ return JavaType.enumType(enumerator.getName(), enumerator.getClassPackage());
+ }
+
+ // Use IType-aware conversion that resolves ThisType
+ return ConvertUtils.getConvertedType(type, generator, currentJpType);
+ }
+
/**
* Processes the arguments. Processing includes:
*
@@ -429,13 +597,15 @@ public static List convertParamArrayToObjArray(List argument
*
*/
public static Method generateActionImplMethod(Method original, org.lara.language.specification.dsl.Action action,
- JavaClass targetClass, JavaAbstractsGenerator generator) {
+ JavaClass targetClass, JavaAbstractsGenerator generator, JavaType currentJpType) {
String actionName = action.getName();
String returnType = action.getReturnType();
boolean hasEvents = generator.hasEvents();
- JavaType actionReturn = getJavaType(action.getReturnType(), action.getName(), action, "ActionParam", generator);
+ // Use IType-aware conversion that properly handles ThisType
+ JavaType actionReturn = getJavaType(action.getType(), action.getName(), action, "ActionParam", generator,
+ currentJpType);
// TODO: This is the abstract method that will be called from JavaScript,
// instead of cloned should have another name. Also, this method is called
@@ -759,12 +929,96 @@ public static Method generateAttribute(org.lara.language.specification.dsl.Attri
}
+ /**
+ * Generate code for a given attribute, resolving ThisType to the current join
+ * point type.
+ *
+ * @param attribute the attribute to generate
+ * @param javaC the target Java class
+ * @param generator the generator context
+ * @param currentJpType the JavaType representing the current join point
+ * abstract being generated
+ */
+ public static Method generateAttribute(org.lara.language.specification.dsl.Attribute attribute, JavaClass javaC,
+ JavaAbstractsGenerator generator, JavaType currentJpType) {
+ IType attrType = attribute.getType();
+ boolean isEnum = false;
+ JavaEnum enumerator = null;
+ JavaType javaType;
+ final String name = attribute.getName();
+ final String fieldName = sanitizeAttributeName(name);
+ final String methodBaseName = attributeMethodBaseName(name);
+
+ // A LiteralEnum with only one value is typically a type reference like
+ // {TypeName}, not a true enum. We only generate an enum for multi-value
+ // LiteralEnums.
+ if (attrType instanceof LiteralEnum literalEnum && literalEnum.getValues().size() > 1) { // then it is an
+ // enumerator
+ isEnum = true;
+ enumerator = generateEnum(attrType.type(), name, javaC.getName(), generator);
+ generator.getEnums().add(enumerator);
+ javaType = new JavaType(enumerator.getName(), enumerator.getClassPackage());
+ } else {
+ // Use IType-aware conversion that resolves ThisType
+ javaType = ConvertUtils.getAttributeConvertedType(attrType, generator, currentJpType);
+ }
+ final Field attributeField = new Field(javaType, fieldName, Privacy.PROTECTED);
+ if (!generator.isAbstractGetters()) {
+ javaC.add(attributeField);
+ }
+
+ var parameters = attribute.getParameters();
+ if (parameters.isEmpty()) {
+
+ final Pair get_set = createGetterAndSetter(attributeField, methodBaseName,
+ generator.isAbstractGetters());
+ final Method getter = get_set.left();
+ if (isEnum) {
+ defineEnumReturnType(getter, enumerator, attributeField, generator.isAbstractGetters());
+ } else if (javaType.isArray()) {
+ encapsulateArrayAttribute(javaC, getter);
+ }
+ attribute.getToolTip().ifPresent(comment -> getter.setJavaDocComment(new JavaDoc(comment)));
+ javaC.add(getter);
+
+ return getter;
+ }
+ final Method methodForAttribute = new Method(javaType, name);
+
+ methodForAttribute.add(Modifier.ABSTRACT);
+ for (var param : parameters) {
+ // Use IType-aware conversion for parameter types as well
+ final Argument arg = newSanitizedArgument(param.getName(), param.getIType(), generator, currentJpType);
+ methodForAttribute.addArgument(arg);
+ methodForAttribute.addJavaDocTag(JDocTag.PARAM, arg.getName());
+ }
+
+ methodForAttribute.addJavaDocTag(JDocTag.RETURN, "");
+ if (javaType.isArray()) {
+ encapsulateArrayAttribute(javaC, methodForAttribute);
+ }
+
+ javaC.add(methodForAttribute);
+ return methodForAttribute;
+ }
+
private static Argument newSanitizedArgument(String name, String type, JavaAbstractsGenerator generator) {
final String sanitizedName = StringUtils.getSanitizedName(name);
final JavaType paramType = ConvertUtils.getConvertedType(type, generator);
return new Argument(paramType, sanitizedName);
}
+ /**
+ * Creates a sanitized argument from an IType, resolving ThisType to the current
+ * join point type.
+ */
+ private static Argument newSanitizedArgument(String name, IType type, JavaAbstractsGenerator generator,
+ JavaType currentJpType) {
+ final String sanitizedName = StringUtils.getSanitizedName(name);
+ final JavaType paramType = ConvertUtils.getConvertedType(type, generator, currentJpType);
+ return new Argument(paramType, sanitizedName);
+ }
+
/**
* Generate the default code that compares the nodes of the join points
*
diff --git a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/AEdgeWeaverJoinPoint.java.txt b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/AEdgeWeaverJoinPoint.java.txt
index 57ff99ae3..97a574b6f 100644
--- a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/AEdgeWeaverJoinPoint.java.txt
+++ b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/AEdgeWeaverJoinPoint.java.txt
@@ -9,7 +9,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class AEdgeWeaverJoinPoint extends AJoinPoint {
+public abstract class AEdgeWeaverJoinPoint> extends AJoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ABase.java.txt b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ABase.java.txt
index 645f304da..f00ac3f44 100644
--- a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ABase.java.txt
+++ b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ABase.java.txt
@@ -15,7 +15,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class ABase extends AEdgeWeaverJoinPoint {
+public abstract class ABase> extends AEdgeWeaverJoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/AJoinPoint.java.txt b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/AJoinPoint.java.txt
index 8a541809e..dff0caafd 100644
--- a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/AJoinPoint.java.txt
+++ b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/AJoinPoint.java.txt
@@ -9,7 +9,7 @@ import org.lara.interpreter.exception.ActionException;
* This class is overwritten when the weaver generator is executed.
* @author Lara Weaver Generator
*/
-public abstract class AJoinPoint extends JoinPoint {
+public abstract class AJoinPoint> extends JoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ALevel1.java.txt b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ALevel1.java.txt
index ee15bb61b..a90fd457d 100644
--- a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ALevel1.java.txt
+++ b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ALevel1.java.txt
@@ -15,7 +15,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class ALevel1 extends ABase {
+public abstract class ALevel1> extends ABase {
protected ABase aBase;
@@ -58,7 +58,7 @@ public abstract class ALevel1 extends ABase {
*/
@Override
public AJoinPoint[] insertImpl(String position, String code) {
- return this.aBase.insertImpl(position, code);
+ return (AJoinPoint[]) this.aBase.insertImpl(position, code);
}
/**
@@ -68,7 +68,7 @@ public abstract class ALevel1 extends ABase {
*/
@Override
public AJoinPoint[] insertImpl(String position, JoinPoint code) {
- return this.aBase.insertImpl(position, code);
+ return (AJoinPoint[]) this.aBase.insertImpl(position, code);
}
/**
diff --git a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ALevel2.java.txt b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ALevel2.java.txt
index fd33d9805..ac6e61d6b 100644
--- a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ALevel2.java.txt
+++ b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/ALevel2.java.txt
@@ -15,7 +15,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class ALevel2 extends ALevel1 {
+public abstract class ALevel2> extends ALevel1 {
protected ALevel1 aLevel1;
@@ -70,7 +70,7 @@ public abstract class ALevel2 extends ALevel1 {
*/
@Override
public AJoinPoint[] insertImpl(String position, String code) {
- return this.aLevel1.insertImpl(position, code);
+ return (AJoinPoint[]) this.aLevel1.insertImpl(position, code);
}
/**
@@ -80,7 +80,7 @@ public abstract class ALevel2 extends ALevel1 {
*/
@Override
public AJoinPoint[] insertImpl(String position, JoinPoint code) {
- return this.aLevel1.insertImpl(position, code);
+ return (AJoinPoint[]) this.aLevel1.insertImpl(position, code);
}
/**
diff --git a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/AReservedKeyword.java.txt b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/AReservedKeyword.java.txt
index e3a2cabbe..58c77ca5a 100644
--- a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/AReservedKeyword.java.txt
+++ b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/joinpoints/AReservedKeyword.java.txt
@@ -15,7 +15,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class AReservedKeyword extends ALevel2 {
+public abstract class AReservedKeyword> extends ALevel2 {
protected ALevel2 aLevel2;
@@ -79,7 +79,7 @@ public abstract class AReservedKeyword extends ALevel2 {
*/
@Override
public AJoinPoint[] insertImpl(String position, String code) {
- return this.aLevel2.insertImpl(position, code);
+ return (AJoinPoint[]) this.aLevel2.insertImpl(position, code);
}
/**
@@ -89,7 +89,7 @@ public abstract class AReservedKeyword extends ALevel2 {
*/
@Override
public AJoinPoint[] insertImpl(String position, JoinPoint code) {
- return this.aLevel2.insertImpl(position, code);
+ return (AJoinPoint[]) this.aLevel2.insertImpl(position, code);
}
/**
diff --git a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/AMediumWeaverJoinPoint.java.txt b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/AMediumWeaverJoinPoint.java.txt
index ee57f90c9..907ab1ad3 100644
--- a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/AMediumWeaverJoinPoint.java.txt
+++ b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/AMediumWeaverJoinPoint.java.txt
@@ -9,7 +9,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class AMediumWeaverJoinPoint extends AJoinPoint {
+public abstract class AMediumWeaverJoinPoint> extends AJoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/ABody.java.txt b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/ABody.java.txt
index fe8cd0bf6..4b28dfd34 100644
--- a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/ABody.java.txt
+++ b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/ABody.java.txt
@@ -14,7 +14,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class ABody extends AMediumWeaverJoinPoint {
+public abstract class ABody> extends AMediumWeaverJoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AFile.java.txt b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AFile.java.txt
index 41db0fb4c..27f2f2ce1 100644
--- a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AFile.java.txt
+++ b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AFile.java.txt
@@ -15,7 +15,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class AFile extends AMediumWeaverJoinPoint {
+public abstract class AFile> extends AMediumWeaverJoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AFunction.java.txt b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AFunction.java.txt
index fd227e4c4..27d7fe2d3 100644
--- a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AFunction.java.txt
+++ b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AFunction.java.txt
@@ -17,7 +17,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class AFunction extends AMediumWeaverJoinPoint {
+public abstract class AFunction> extends AMediumWeaverJoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AJoinPoint.java.txt b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AJoinPoint.java.txt
index 42d2d7032..eafb92029 100644
--- a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AJoinPoint.java.txt
+++ b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AJoinPoint.java.txt
@@ -10,7 +10,7 @@ import org.lara.interpreter.exception.AttributeException;
* This class is overwritten when the weaver generator is executed.
* @author Lara Weaver Generator
*/
-public abstract class AJoinPoint extends JoinPoint {
+public abstract class AJoinPoint> extends JoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AStatement.java.txt b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AStatement.java.txt
index d8a3607f5..a1afe24f1 100644
--- a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AStatement.java.txt
+++ b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AStatement.java.txt
@@ -14,7 +14,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class AStatement extends AMediumWeaverJoinPoint {
+public abstract class AStatement> extends AMediumWeaverJoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AVar.java.txt b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AVar.java.txt
index d25ae9971..f3ce8b248 100644
--- a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AVar.java.txt
+++ b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/joinpoints/AVar.java.txt
@@ -14,7 +14,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class AVar extends AMediumWeaverJoinPoint {
+public abstract class AVar> extends AMediumWeaverJoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/AMinimalWeaverJoinPoint.java.txt b/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/AMinimalWeaverJoinPoint.java.txt
index 9239522ed..7a7070bd8 100644
--- a/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/AMinimalWeaverJoinPoint.java.txt
+++ b/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/AMinimalWeaverJoinPoint.java.txt
@@ -9,7 +9,7 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class AMinimalWeaverJoinPoint extends AJoinPoint {
+public abstract class AMinimalWeaverJoinPoint> extends AJoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/joinpoints/AJoinPoint.java.txt b/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/joinpoints/AJoinPoint.java.txt
index 799a6cae1..68637da87 100644
--- a/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/joinpoints/AJoinPoint.java.txt
+++ b/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/joinpoints/AJoinPoint.java.txt
@@ -8,7 +8,7 @@ import org.lara.interpreter.weaver.interf.WeaverEngine;
* This class is overwritten when the weaver generator is executed.
* @author Lara Weaver Generator
*/
-public abstract class AJoinPoint extends JoinPoint {
+public abstract class AJoinPoint> extends JoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/joinpoints/ARoot.java.txt b/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/joinpoints/ARoot.java.txt
index 1be3ae674..887522080 100644
--- a/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/joinpoints/ARoot.java.txt
+++ b/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/joinpoints/ARoot.java.txt
@@ -10,7 +10,7 @@ import minimal.pkg.abstracts.AMinimalWeaverJoinPoint;
*
* @author Lara Weaver Generator
*/
-public abstract class ARoot extends AMinimalWeaverJoinPoint {
+public abstract class ARoot> extends AMinimalWeaverJoinPoint {
/**
*
diff --git a/WeaverGenerator/test-resources/golden/thistype/pkg/ThistypeWeaver.java.txt b/WeaverGenerator/test-resources/golden/thistype/pkg/ThistypeWeaver.java.txt
new file mode 100644
index 000000000..f1354b95c
--- /dev/null
+++ b/WeaverGenerator/test-resources/golden/thistype/pkg/ThistypeWeaver.java.txt
@@ -0,0 +1,94 @@
+package thistype.pkg;
+
+import thistype.pkg.abstracts.weaver.AThistypeWeaver;
+import java.util.List;
+import java.io.File;
+import org.suikasoft.jOptions.Interfaces.DataStore;
+import org.lara.interpreter.weaver.interf.JoinPoint;
+import org.lara.interpreter.weaver.interf.AGear;
+import org.lara.interpreter.weaver.options.WeaverOption;
+import org.lara.language.specification.dsl.LanguageSpecification;
+
+/**
+ * Weaver Implementation for ThistypeWeaver
+ * Since the generated abstract classes are always overwritten, their implementation should be done by extending those abstract classes with user-defined classes.
+ * The abstract class {@link thistype.pkg.abstracts.AThistypeWeaverJoinPoint} contains attributes and actions common to all join points.
+ * @author Lara Weaver Generator
+ */
+public class ThistypeWeaver extends AThistypeWeaver {
+
+ /**
+ * Setups the weaver with inputs sources, an output folder and the provided options.
+ *
+ * @param sources the sources with the code (files/folders)
+ * @param outputDir output folder for the generated file(s)
+ * @param args options for the weaver
+ * @return true if initialization occurred without problems, false otherwise
+ */
+ @Override
+ public boolean begin(List sources, File outputDir, DataStore args) {
+ //Initialize weaver with the input file/folder
+ throw new UnsupportedOperationException("Method begin for ThistypeWeaver is not yet implemented");
+ }
+
+ /**
+ * Performs operations needed when closing the weaver (e.g., generates new version of source file(s) to the specified output folder).
+ *
+ * @return if close was successful
+ */
+ @Override
+ public boolean close() {
+ //Terminate weaver execution with final steps required and writing output files
+ throw new UnsupportedOperationException("Method close for ThistypeWeaver is not yet implemented");
+ }
+
+ /**
+ * Return a JoinPoint instance of the sources root, i.e., an instance of ANode
+ * @return an instance of the join point root
+ */
+ @Override
+ public JoinPoint getRootJp() {
+ //return new ;
+ throw new UnsupportedOperationException("Method getRootJp for ThistypeWeaver is not yet implemented");
+ }
+
+ /**
+ * Returns a list of Gears associated to this weaver engine
+ *
+ * @return a list of implementations of {@link AGear} or null if no gears are available
+ */
+ public List getGears() {
+ return List.of(); //i.e., no gears currently being used
+ }
+
+ /**
+ * Returns a list of options specific to this weaver engine.
+ *
+ * @return a list of {@link WeaverOption} representing additional options provided by this weaver
+ */
+ @Override
+ public List getOptions() {
+ return List.of(); //i.e., no additional options
+ }
+
+ /**
+ * Builds the language specification, based on the input XML files.
+ *
+ * @return a new {@link LanguageSpecification} instance for this weaver
+ */
+ public static LanguageSpecification buildLanguageSpecification() {
+ return LanguageSpecification.newInstance(() -> "spec/valid/thistype/" + LanguageSpecification.getJoinPointsFilename(),
+ () -> "spec/valid/thistype/" + LanguageSpecification.getAttributesFilename(),
+ () -> "spec/valid/thistype/" + LanguageSpecification.getActionsFilename());
+ }
+
+ /**
+ * Builds the language specification, based on the input XML files.
+ *
+ * @return a new {@link LanguageSpecification} instance for this weaver
+ */
+ @Override
+ protected LanguageSpecification buildLangSpecs() {
+ return buildLanguageSpecification();
+ }
+}
diff --git a/WeaverGenerator/test-resources/golden/thistype/pkg/abstracts/AThistypeWeaverJoinPoint.java.txt b/WeaverGenerator/test-resources/golden/thistype/pkg/abstracts/AThistypeWeaverJoinPoint.java.txt
new file mode 100644
index 000000000..cb250f7a4
--- /dev/null
+++ b/WeaverGenerator/test-resources/golden/thistype/pkg/abstracts/AThistypeWeaverJoinPoint.java.txt
@@ -0,0 +1,38 @@
+package thistype.pkg.abstracts;
+
+import thistype.pkg.abstracts.joinpoints.AJoinPoint;
+import thistype.pkg.ThistypeWeaver;
+import java.util.List;
+
+/**
+ * Abstract class which can be edited by the developer. This class will not be overwritten.
+ *
+ * @author Lara Weaver Generator
+ */
+public abstract class AThistypeWeaverJoinPoint> extends AJoinPoint {
+
+ /**
+ *
+ */
+ public AThistypeWeaverJoinPoint(ThistypeWeaver weaver){
+ super(weaver);
+ }
+ /**
+ * Returns the Weaving Engine this join point pertains to.
+ */
+ @Override
+ public ThistypeWeaver getWeaverEngine() {
+ return (ThistypeWeaver) super.getWeaverEngine();
+ }
+
+ /**
+ * Compares the two join points based on their node reference of the used compiler/parsing tool.
+ * This is the default implementation for comparing two join points.
+ * Note for developers: A weaver may override this implementation in the editable abstract join point, so
+ * the changes are made for all join points, or override this method in specific join points.
+ */
+ @Override
+ public boolean compareNodes(AJoinPoint aJoinPoint) {
+ return this.getNode().equals(aJoinPoint.getNode());
+ }
+}
diff --git a/WeaverGenerator/test-resources/golden/thistype/pkg/abstracts/joinpoints/ABinaryExpr.java.txt b/WeaverGenerator/test-resources/golden/thistype/pkg/abstracts/joinpoints/ABinaryExpr.java.txt
new file mode 100644
index 000000000..1d8e94b9b
--- /dev/null
+++ b/WeaverGenerator/test-resources/golden/thistype/pkg/abstracts/joinpoints/ABinaryExpr.java.txt
@@ -0,0 +1,684 @@
+package thistype.pkg.abstracts.joinpoints;
+
+import org.lara.interpreter.exception.AttributeException;
+import java.util.List;
+import org.lara.interpreter.exception.ActionException;
+import thistype.pkg.ThistypeWeaver;
+import java.util.Map;
+import java.util.Set;
+import org.lara.interpreter.weaver.interf.JoinPoint;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.Arrays;
+
+/**
+ * Auto-Generated class for join point ABinaryExpr
+ * This class is overwritten by the Weaver Generator.
+ *
+ *
+ * @author Lara Weaver Generator
+ */
+public abstract class ABinaryExpr> extends AExpr {
+
+ protected AExpr aExpr;
+
+ /**
+ *
+ */
+ public ABinaryExpr(AExpr aExpr, ThistypeWeaver weaver){
+ super(aExpr, weaver);
+ this.aExpr = aExpr;
+ }
+ /**
+ * Returns left operand with late-bound type
+ */
+ public abstract Self getLeftImpl();
+
+ /**
+ * Returns left operand with late-bound type
+ */
+ public final Object getLeft() {
+ try {
+ Self result = this.getLeftImpl();
+ return result!=null?result:getUndefinedValue();
+ } catch(Exception e) {
+ throw new AttributeException(get_class(), "left", e);
+ }
+ }
+
+ /**
+ * Returns both operands as list
+ */
+ public abstract List getOperandsImpl();
+
+ /**
+ * Returns both operands as list
+ */
+ public final Object getOperands() {
+ try {
+ List result = this.getOperandsImpl();
+ return result!=null?result:getUndefinedValue();
+ } catch(Exception e) {
+ throw new AttributeException(get_class(), "operands", e);
+ }
+ }
+
+ /**
+ * Returns right operand with late-bound type
+ */
+ public abstract Self getRightImpl();
+
+ /**
+ * Returns right operand with late-bound type
+ */
+ public final Object getRight() {
+ try {
+ Self result = this.getRightImpl();
+ return result!=null?result:getUndefinedValue();
+ } catch(Exception e) {
+ throw new AttributeException(get_class(), "right", e);
+ }
+ }
+
+ /**
+ * Sets both operands
+ * @param left
+ * @param right
+ */
+ public void setOperandsImpl(Self left, Self right) {
+ throw new UnsupportedOperationException(get_class()+": Action setOperands not implemented ");
+ }
+
+ /**
+ * Sets both operands
+ * @param left
+ * @param right
+ */
+ public final void setOperands(Self left, Self right) {
+ try {
+ this.setOperandsImpl(left, right);
+ } catch(Exception e) {
+ throw new ActionException(get_class(), "setOperands", e);
+ }
+ }
+
+ /**
+ * Swaps left and right operands
+ */
+ public Self swapOperandsImpl() {
+ throw new UnsupportedOperationException(get_class()+": Action swapOperands not implemented ");
+ }
+
+ /**
+ * Swaps left and right operands
+ */
+ public final Object swapOperands() {
+ try {
+ Self result = this.swapOperandsImpl();
+ return result!=null?result:getUndefinedValue();
+ } catch(Exception e) {
+ throw new ActionException(get_class(), "swapOperands", e);
+ }
+ }
+
+ /**
+ * Get value on attribute normalize
+ * @return the attribute's value
+ */
+ @Override
+ public Self getNormalizeImpl() {
+ return (Self) this.aExpr.getNormalizeImpl();
+ }
+
+ /**
+ * Get value on attribute simplify
+ * @return the attribute's value
+ */
+ @Override
+ public Self getSimplifyImpl() {
+ return (Self) this.aExpr.getSimplifyImpl();
+ }
+
+ /**
+ * Get value on attribute subExpressions
+ * @return the attribute's value
+ */
+ @Override
+ public List getSubExpressionsImpl() {
+ return (List) this.aExpr.getSubExpressionsImpl();
+ }
+
+ /**
+ * Get value on attribute ancestorOfType
+ * @return the attribute's value
+ */
+ @Override
+ public Self ancestorOfTypeImpl(String typeName) {
+ return (Self) this.aExpr.ancestorOfTypeImpl(typeName);
+ }
+
+ /**
+ * Get value on attribute attributes
+ * @return the attribute's value
+ */
+ @Override
+ public Map getAttributesImpl() {
+ return this.aExpr.getAttributesImpl();
+ }
+
+ /**
+ * Get value on attribute categorizedNodes
+ * @return the attribute's value
+ */
+ @Override
+ public Map> getCategorizedNodesImpl() {
+ return (Map>) this.aExpr.getCategorizedNodesImpl();
+ }
+
+ /**
+ * Get value on attribute childGroups
+ * @return the attribute's value
+ */
+ @Override
+ public List> getChildGroupsImpl() {
+ return (List>) this.aExpr.getChildGroupsImpl();
+ }
+
+ /**
+ * Get value on attribute childList
+ * @return the attribute's value
+ */
+ @Override
+ public List getChildListImpl() {
+ return (List) this.aExpr.getChildListImpl();
+ }
+
+ /**
+ * Get value on attribute children
+ * @return the attribute's value
+ */
+ @Override
+ public Self[] getChildrenArrayImpl() {
+ return (Self[]) this.aExpr.getChildrenArrayImpl();
+ }
+
+ /**
+ * Get value on attribute childrenMatrix
+ * @return the attribute's value
+ */
+ @Override
+ public Self[][] getChildrenMatrixArrayImpl() {
+ return (Self[][]) this.aExpr.getChildrenMatrixArrayImpl();
+ }
+
+ /**
+ * Get value on attribute clone
+ * @return the attribute's value
+ */
+ @Override
+ public Self getCloneImpl() {
+ return (Self) this.aExpr.getCloneImpl();
+ }
+
+ /**
+ * Get value on attribute column
+ * @return the attribute's value
+ */
+ @Override
+ public Integer getColumnImpl() {
+ return this.aExpr.getColumnImpl();
+ }
+
+ /**
+ * Get value on attribute descendantSet
+ * @return the attribute's value
+ */
+ @Override
+ public Set getDescendantSetImpl() {
+ return (Set) this.aExpr.getDescendantSetImpl();
+ }
+
+ /**
+ * Get value on attribute descendants
+ * @return the attribute's value
+ */
+ @Override
+ public Self[] getDescendantsArrayImpl() {
+ return (Self[]) this.aExpr.getDescendantsArrayImpl();
+ }
+
+ /**
+ * Get value on attribute findBetween
+ * @return the attribute's value
+ */
+ @Override
+ public List findBetweenImpl(Self start, Self end) {
+ return (List) this.aExpr.findBetweenImpl(start, end);
+ }
+
+ /**
+ * Get value on attribute findSimilar
+ * @return the attribute's value
+ */
+ @Override
+ public List findSimilarImpl(Self target) {
+ return (List) this.aExpr.findSimilarImpl(target);
+ }
+
+ /**
+ * Get value on attribute hierarchy
+ * @return the attribute's value
+ */
+ @Override
+ public Map> getHierarchyImpl() {
+ return (Map>) this.aExpr.getHierarchyImpl();
+ }
+
+ /**
+ * Get value on attribute id
+ * @return the attribute's value
+ */
+ @Override
+ public String getIdImpl() {
+ return this.aExpr.getIdImpl();
+ }
+
+ /**
+ * Get value on attribute indexedNodes
+ * @return the attribute's value
+ */
+ @Override
+ public Map getIndexedNodesImpl() {
+ return (Map) this.aExpr.getIndexedNodesImpl();
+ }
+
+ /**
+ * Get value on attribute line
+ * @return the attribute's value
+ */
+ @Override
+ public Integer getLineImpl() {
+ return this.aExpr.getLineImpl();
+ }
+
+ /**
+ * Get value on attribute namedChildren
+ * @return the attribute's value
+ */
+ @Override
+ public Map getNamedChildrenImpl() {
+ return (Map) this.aExpr.getNamedChildrenImpl();
+ }
+
+ /**
+ * Get value on attribute parent
+ * @return the attribute's value
+ */
+ @Override
+ public Self getParentImpl() {
+ return (Self) this.aExpr.getParentImpl();
+ }
+
+ /**
+ * Get value on attribute properties
+ * @return the attribute's value
+ */
+ @Override
+ public Map getPropertiesImpl() {
+ return this.aExpr.getPropertiesImpl();
+ }
+
+ /**
+ * Get value on attribute tags
+ * @return the attribute's value
+ */
+ @Override
+ public List getTagsImpl() {
+ return this.aExpr.getTagsImpl();
+ }
+
+ /**
+ * Get value on attribute ancestors
+ * @return the attribute's value
+ */
+ @Override
+ public Self[] getAncestorsArrayImpl() {
+ return (Self[]) this.aExpr.getAncestorsArrayImpl();
+ }
+
+ /**
+ * Get value on attribute root
+ * @return the attribute's value
+ */
+ @Override
+ public Self getRootImpl() {
+ return (Self) this.aExpr.getRootImpl();
+ }
+
+ /**
+ * Get value on attribute siblings
+ * @return the attribute's value
+ */
+ @Override
+ public List getSiblingsImpl() {
+ return (List) this.aExpr.getSiblingsImpl();
+ }
+
+ /**
+ * Categorizes nodes by criteria
+ */
+ @Override
+ public Map categorizeImpl() {
+ return (Map) this.aExpr.categorizeImpl();
+ }
+
+ /**
+ * Collects all terms
+ */
+ @Override
+ public List collectTermsImpl() {
+ return (List) this.aExpr.collectTermsImpl();
+ }
+
+ /**
+ * Creates a copy of this node
+ */
+ @Override
+ public Self copyImpl() {
+ return (Self) this.aExpr.copyImpl();
+ }
+
+ /**
+ * Detaches node from parent and returns it
+ */
+ @Override
+ public Self detachImpl() {
+ return (Self) this.aExpr.detachImpl();
+ }
+
+ /**
+ * Evaluates and returns simplified form
+ */
+ @Override
+ public Self evaluateImpl() {
+ return (Self) this.aExpr.evaluateImpl();
+ }
+
+ /**
+ * Finds all matching nodes
+ * @param pattern
+ */
+ @Override
+ public List findAllImpl(String pattern) {
+ return (List) this.aExpr.findAllImpl(pattern);
+ }
+
+ /**
+ * Finds children matching criteria
+ * @param filter
+ */
+ @Override
+ public List findChildrenImpl(String filter) {
+ return (List) this.aExpr.findChildrenImpl(filter);
+ }
+
+ /**
+ * Returns metadata as map
+ */
+ @Override
+ public Map getMetadataImpl() {
+ return this.aExpr.getMetadataImpl();
+ }
+
+ /**
+ * Groups descendants by type
+ */
+ @Override
+ public Map> groupByTypeImpl() {
+ return (Map>) this.aExpr.groupByTypeImpl();
+ }
+
+ /**
+ *
+ * @param position
+ * @param code
+ */
+ @Override
+ public AJoinPoint[] insertImpl(String position, String code) {
+ return (AJoinPoint[]) this.aExpr.insertImpl(position, code);
+ }
+
+ /**
+ *
+ * @param position
+ * @param code
+ */
+ @Override
+ public AJoinPoint[] insertImpl(String position, JoinPoint code) {
+ return (AJoinPoint[]) this.aExpr.insertImpl(position, code);
+ }
+
+ /**
+ * Inserts node after this one
+ * @param node
+ */
+ @Override
+ public void insertAfterImpl(Self node) {
+ this.aExpr.insertAfterImpl(node);
+ }
+
+ /**
+ * Inserts multiple nodes
+ * @param nodes
+ */
+ @Override
+ public void insertAllImpl(List nodes) {
+ this.aExpr.insertAllImpl(nodes);
+ }
+
+ /**
+ * Inserts node at specific position
+ * @param position
+ * @param node
+ */
+ @Override
+ public void insertAtImpl(Integer position, Self node) {
+ this.aExpr.insertAtImpl(position, node);
+ }
+
+ /**
+ * Inserts node before this one
+ * @param node
+ */
+ @Override
+ public void insertBeforeImpl(Self node) {
+ this.aExpr.insertBeforeImpl(node);
+ }
+
+ /**
+ * Merges with another node
+ * @param other
+ */
+ @Override
+ public Self mergeImpl(Self other) {
+ return (Self) this.aExpr.mergeImpl(other);
+ }
+
+ /**
+ * Partitions children
+ * @param criteria
+ */
+ @Override
+ public Map> partitionChildrenImpl(String criteria) {
+ return (Map>) this.aExpr.partitionChildrenImpl(criteria);
+ }
+
+ /**
+ * Replaces multiple nodes by name
+ * @param replacements
+ */
+ @Override
+ public void replaceAllImpl(Map replacements) {
+ this.aExpr.replaceAllImpl(replacements);
+ }
+
+ /**
+ * Replaces nodes between two markers
+ * @param start
+ * @param end
+ * @param replacement
+ */
+ @Override
+ public void replaceBetweenImpl(Self start, Self end, Self replacement) {
+ this.aExpr.replaceBetweenImpl(start, end, replacement);
+ }
+
+ /**
+ * Replaces this node with another
+ * @param replacement
+ */
+ @Override
+ public void replaceWithImpl(Self replacement) {
+ this.aExpr.replaceWithImpl(replacement);
+ }
+
+ /**
+ * Applies transformation returning self
+ * @param transformName
+ */
+ @Override
+ public Self selfTransformImpl(String transformName) {
+ return (Self) this.aExpr.selfTransformImpl(transformName);
+ }
+
+ /**
+ * Substitutes sub-expression
+ * @param target
+ * @param replacement
+ */
+ @Override
+ public Self substituteImpl(Self target, Self replacement) {
+ return (Self) this.aExpr.substituteImpl(target, replacement);
+ }
+
+ /**
+ * Swaps position with another node
+ * @param other
+ * @param preserveComments
+ */
+ @Override
+ public void swapImpl(Self other, Boolean preserveComments) {
+ this.aExpr.swapImpl(other, preserveComments);
+ }
+
+ /**
+ * Converts children to array
+ */
+ @Override
+ public Self[] toArrayImpl() {
+ return (Self[]) this.aExpr.toArrayImpl();
+ }
+
+ /**
+ * Wraps this node with wrapper
+ * @param wrapper
+ * @param position
+ */
+ @Override
+ public Self wrapWithImpl(Self wrapper, String position) {
+ return (Self) this.aExpr.wrapWithImpl(wrapper, position);
+ }
+
+ /**
+ *
+ */
+ @Override
+ public Optional extends AExpr> getSuper() {
+ return Optional.of(this.aExpr);
+ }
+
+ /**
+ * Returns the join point type of this class
+ * @return The join point type
+ */
+ @Override
+ public final String get_class() {
+ return "binaryExpr";
+ }
+
+ /**
+ * Defines if this joinpoint is an instanceof a given joinpoint class
+ * @return True if this join point is an instanceof the given class
+ */
+ @Override
+ public final boolean instanceOf(String joinpointClass) {
+ boolean isInstance = get_class().equals(joinpointClass);
+ if(isInstance) {
+ return true;
+ }
+ return this.aExpr.instanceOf(joinpointClass);
+ }
+ /**
+ *
+ */
+ protected enum BinaryExprAttributes {
+ LEFT("left"),
+ OPERANDS("operands"),
+ RIGHT("right"),
+ NORMALIZE("normalize"),
+ SIMPLIFY("simplify"),
+ SUBEXPRESSIONS("subExpressions"),
+ ANCESTOROFTYPE("ancestorOfType"),
+ ATTRIBUTES("attributes"),
+ CATEGORIZEDNODES("categorizedNodes"),
+ CHILDGROUPS("childGroups"),
+ CHILDLIST("childList"),
+ CHILDREN("children"),
+ CHILDRENMATRIX("childrenMatrix"),
+ CLONE("clone"),
+ COLUMN("column"),
+ DESCENDANTSET("descendantSet"),
+ DESCENDANTS("descendants"),
+ FINDBETWEEN("findBetween"),
+ FINDSIMILAR("findSimilar"),
+ HIERARCHY("hierarchy"),
+ ID("id"),
+ INDEXEDNODES("indexedNodes"),
+ LINE("line"),
+ NAMEDCHILDREN("namedChildren"),
+ PARENT("parent"),
+ PROPERTIES("properties"),
+ TAGS("tags"),
+ ANCESTORS("ancestors"),
+ ROOT("root"),
+ SIBLINGS("siblings");
+ private String name;
+
+ /**
+ *
+ */
+ private BinaryExprAttributes(String name){
+ this.name = name;
+ }
+ /**
+ * Return an attribute enumeration item from a given attribute name
+ */
+ public static Optional fromString(String name) {
+ return Arrays.asList(values()).stream().filter(attr -> attr.name.equals(name)).findAny();
+ }
+
+ /**
+ * Return a list of attributes in String format
+ */
+ public static List getNames() {
+ return Arrays.asList(values()).stream().map(BinaryExprAttributes::name).collect(Collectors.toList());
+ }
+
+ /**
+ * True if the enum contains the given attribute name, false otherwise.
+ */
+ public static boolean contains(String name) {
+ return fromString(name).isPresent();
+ }
+ }
+}
diff --git a/WeaverGenerator/test-resources/golden/thistype/pkg/abstracts/joinpoints/AContainer.java.txt b/WeaverGenerator/test-resources/golden/thistype/pkg/abstracts/joinpoints/AContainer.java.txt
new file mode 100644
index 000000000..6512f5304
--- /dev/null
+++ b/WeaverGenerator/test-resources/golden/thistype/pkg/abstracts/joinpoints/AContainer.java.txt
@@ -0,0 +1,147 @@
+package thistype.pkg.abstracts.joinpoints;
+
+import java.util.List;
+import java.util.Map;
+import org.lara.interpreter.exception.AttributeException;
+import org.lara.interpreter.exception.ActionException;
+import thistype.pkg.ThistypeWeaver;
+import thistype.pkg.abstracts.AThistypeWeaverJoinPoint;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.Arrays;
+
+/**
+ * Auto-Generated class for join point AContainer
+ * This class is overwritten by the Weaver Generator.
+ *
+ *
+ * @author Lara Weaver Generator
+ */
+public abstract class AContainer> extends AThistypeWeaverJoinPoint {
+
+ /**
+ *
+ */
+ public AContainer(ThistypeWeaver weaver){
+ super(weaver);
+ }
+ /**
+ * Deeply nested generic with this
+ */
+ public abstract List