StandardJavaTypes;
static {
InterpreterTypes = new HashMap<>();
@@ -50,85 +96,26 @@ public class ConvertUtils {
ConvertUtils.InterpreterTypes.put("Map", mapType);
ConvertUtils.InterpreterTypes.put("Template", JavaTypeFactory.getStringType());
- }
-
- /**
- * Get the correct type for the given string, according to:
- *
- * 1st the primitives, 2nd the declared objects and 3rd the declared join points
- *
- * @throws RuntimeException if the type cannot be found.
- */
- public static JavaType getConvertedType(String type, JavaAbstractsGenerator generator) {
- type = normalizeReferenceType(type);
-
- // First remove array dimension
- final Pair splittedType = JavaTypeFactory.splitTypeFromArrayDimension(type);
- type = 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)) {
-
- final JavaType primitiveType = JavaTypeFactory.getPrimitiveType(Primitive.getPrimitive(type));
- primitiveType.setArrayDimension(arrayDimension);
- return primitiveType;
- }
- if (JavaTypeFactory.isPrimitiveWrapper(type)) {
-
- final JavaType primitiveWrapper = JavaTypeFactory.getPrimitiveWrapper(type);
- primitiveWrapper.setArrayDimension(arrayDimension);
- return primitiveWrapper;
- }
+ // Standard Java types that can be used in generic contexts
+ StandardJavaTypes = new HashMap<>();
+ StandardJavaTypes.put("List", new JavaType(List.class));
+ StandardJavaTypes.put("Set", new JavaType(Set.class));
+ StandardJavaTypes.put("Collection", new JavaType(Collection.class));
+ StandardJavaTypes.put("Optional", new JavaType(Optional.class));
+ StandardJavaTypes.put("Map", new JavaType(Map.class));
- return getConvertedTypeAux(type, generator, arrayDimension);
}
- /**
- * Get the correct type for the return of an attribute. This method converts a
- * primitive type into its wrapper
- *
- *
- * 1st the primitives, 2nd the declared objects and 3rd the declared join points
- *
- * @throws RuntimeException if the type cannot be found.
- */
- public static JavaType getAttributeConvertedType(String type, JavaAbstractsGenerator generator) {
-
- // Check if enum in the format [name1| name2| ...]
- // In this case, the type is String
- if (type.contains("[") && type.contains("|") && type.contains("]")) {
- type = String.class.getSimpleName();
- }
-
- type = normalizeReferenceType(type);
-
- // First remove array dimension
- final Pair splittedType = JavaTypeFactory.splitTypeFromArrayDimension(type);
- type = 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 (JavaTypeFactory.isPrimitiveWrapper(type)) {
-
- final JavaType primitiveWrapper = JavaTypeFactory.getPrimitiveWrapper(type);
- primitiveWrapper.setArrayDimension(arrayDimension);
- return primitiveWrapper;
- }
+ public static JavaType withJoinPointWildcard(JavaType joinPointType) {
+ JavaType clone = joinPointType.clone();
+ clone.addGeneric(new JavaGenericType(JavaTypeFactory.getWildCardType()));
+ return clone;
+ }
- return getConvertedTypeAux(type, generator, arrayDimension);
+ public static JavaType withJoinPointTypeArgument(JavaType joinPointType, JavaType typeArgument) {
+ JavaType clone = joinPointType.clone();
+ clone.addGeneric(new JavaGenericType(typeArgument.clone()));
+ return clone;
}
private static JavaType getConvertedTypeAux(String type, JavaAbstractsGenerator generator,
@@ -146,15 +133,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;
+ return withJoinPointWildcard(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;
@@ -167,7 +154,7 @@ private static JavaType getConvertedTypeAux(String type, JavaAbstractsGenerator
// if it is a join point class
if (generator.getLanguageSpecification().hasJoinPoint(type)) {
final String jpName = GenConstants.abstractPrefix() + StringUtils.firstCharToUpper(type);
- return new JavaType(jpName, generator.getJoinPointClassPackage(), arrayDimension);
+ return withJoinPointWildcard(new JavaType(jpName, generator.getJoinPointClassPackage(), arrayDimension));
}
// If it does not exist, throw an exception with the error message and
@@ -249,4 +236,260 @@ 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). String-based
+ * conversion is no longer supported.
+ * @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) {
+ ensureThisTypeContext(type, currentJpType);
+ return convert(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). String-based
+ * conversion is no longer supported.
+ * @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) {
+ ensureThisTypeContext(type, currentJpType);
+ return convert(type, generator, currentJpType, PrimitiveConversionStrategy.ATTRIBUTE_RETURN);
+ }
+
+ private static void ensureThisTypeContext(IType type, JavaType currentJpType) {
+ if (type == null) {
+ return;
+ }
+
+ if (currentJpType != null) {
+ return;
+ }
+
+ if (TypeTraversalUtils.containsThisType(type)) {
+ throw new IllegalStateException(
+ "ThisType found but no currentJpType context provided. ThisType is not supported in this context (e.g., TypeDef fields).");
+ }
+ }
+
+ private static JavaType convert(IType type, JavaAbstractsGenerator generator, JavaType currentJpType,
+ PrimitiveConversionStrategy strategy) {
+ if (type == null) {
+ throw new IllegalArgumentException("Type cannot be null");
+ }
+
+ if (type instanceof org.lara.language.specification.dsl.types.Primitive primitiveType) {
+ Primitive primitive = Primitive.getPrimitive(primitiveType.type());
+ return strategy.convertPrimitive(primitive, 0);
+ }
+
+ // Handle ThisType - resolve to current join point type
+ if (type instanceof ThisType) {
+ 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 = convert(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 = convert(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 withJoinPointWildcard(generator.getaJoinPointType().clone());
+ }
+ // For regular join points, construct the abstract class name
+ String jpName = GenConstants.abstractPrefix() + StringUtils.firstCharToUpper(jpClassName);
+ return withJoinPointWildcard(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;
+ }
+
+ // GenericType carries array information separately from its name.
+ // Preserve it for non-standard types by appending the suffix before
+ // simple-name conversion.
+ if (genericType.isArray()) {
+ return convertSimpleTypeName(typeName + "[]", generator, strategy);
+ }
+ }
+
+ // Fall back to string-based conversion for other simple types
+ return convertSimpleTypeName(type.type(), generator, strategy);
+ }
+
+ private static JavaType convertSimpleTypeName(String typeName, JavaAbstractsGenerator generator,
+ PrimitiveConversionStrategy strategy) {
+ String normalizedType = normalizeReferenceType(typeName);
+
+ final Pair splitType = JavaTypeFactory.splitTypeFromArrayDimension(normalizedType);
+ final String baseType = splitType.left();
+ final int arrayDimension = splitType.right();
+
+ if (JavaTypeFactory.isPrimitive(baseType)) {
+ Primitive primitive = Primitive.getPrimitive(baseType);
+ return strategy.convertPrimitive(primitive, arrayDimension);
+ }
+
+ if (JavaTypeFactory.isPrimitiveWrapper(baseType)) {
+ final JavaType primitiveWrapper = JavaTypeFactory.getPrimitiveWrapper(baseType);
+ primitiveWrapper.setArrayDimension(arrayDimension);
+ return primitiveWrapper;
+ }
+
+ return getConvertedTypeAux(baseType, generator, arrayDimension);
+ }
+
+ /**
+ * 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 convert(baseType, generator, currentJpType, PrimitiveConversionStrategy.STANDARD);
+ }
+
+ /**
+ * 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 = convert(wildcardType.getBound(), generator, currentJpType,
+ PrimitiveConversionStrategy.STANDARD);
+ // 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 = convert(wildcardType.getBound(), generator, currentJpType,
+ PrimitiveConversionStrategy.STANDARD);
+ // 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..54fc8c031
--- /dev/null
+++ b/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/CrtpJavaClass.java
@@ -0,0 +1,159 @@
+/**
+ * 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 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);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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 unless explicitly disabled.
+ if (addTypeArgToSuperClass) {
+ classGen.append("<");
+ classGen.append(SELF_TYPE_PARAMETER);
+ 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..6c0ff1c5c 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.Arrays;
+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 org.lara.interpreter.exception.ActionException;
import org.lara.interpreter.exception.AttributeException;
import org.lara.interpreter.weaver.generator.generator.java.JavaAbstractsGenerator;
@@ -23,25 +32,29 @@
import org.lara.language.specification.dsl.Attribute;
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.JPType;
-import org.lara.language.specification.dsl.types.PrimitiveClasses;
+import org.lara.language.specification.dsl.types.GenericType;
+import org.lara.language.specification.dsl.types.IType;
+import org.lara.language.specification.dsl.types.LiteralEnum;
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 pt.up.fe.specs.util.SpecsLogs;
import tdrc.utils.Pair;
import tdrc.utils.StringUtils;
-import java.util.*;
-import java.util.function.Function;
-
public class GeneratorUtils {
private static String ln() {
@@ -49,60 +62,72 @@ private static String ln() {
}
/**
- * Add methods of the super join point to the java class
+ * 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) {
+ JoinPointClass current, JavaType currentJpType) {
var parent = current.getExtendExplicit().orElse(null);
if (parent == null) {
return;
}
- addSuperGetters(javaC, fieldName, generator, parent);
- addSuperMethods(javaC, fieldName, generator, parent);
+ // 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);
}
/**
+ * 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 addSuperToString(JavaClass javaC, String fieldName) {
-
- final Method toStringMethod = new Method(JavaTypeFactory.getStringType(), "toString");
- toStringMethod.add(Annotation.OVERRIDE);
- toStringMethod.appendCode("return this." + fieldName + "." + toStringMethod.getName() + "();");
- javaC.add(toStringMethod);
- }
-
public static void addSuperGetters(JavaClass javaC, String fieldName, JavaAbstractsGenerator generator,
- JoinPointClass parent) {
-
- addSuperGetters(javaC, fieldName, generator, parent.getAttributesSelf());
- }
+ List attributes, JavaType currentJpType) {
- public static void addSuperGetters(JavaClass javaC, String fieldName, JavaAbstractsGenerator generator,
- List attributes) {
-
- // TODO: Remove sort
var mutableAttributes = new ArrayList<>(attributes);
mutableAttributes.sort(Comparator.comparing(Attribute::getName));
for (var attribute : mutableAttributes) {
- // System.out.println("ATTR:" + attribute.getName());
- String attrClassStr = attribute.getReturnType().trim();
-
- if (attrClassStr.startsWith("{")) { // then it is an enumerator
- attrClassStr = String.class.getSimpleName();
- }
-
- // if (ObjectOfPrimitives.contains(attrClassStr))
- // attrClassStr = ObjectOfPrimitives.getPrimitive(attrClassStr);
+ IType attrType = normalizeAttributeTypeForGetter(attribute);
+ JavaType type = ConvertUtils.getConvertedType(attrType, generator, currentJpType);
+ Function parameterTypeResolver = parameter -> ConvertUtils.getConvertedType(
+ parameter.getIType(), generator, currentJpType);
+ boolean needsCast = currentJpType != null && TypeTraversalUtils.containsThisType(attrType);
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 +137,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;
}
@@ -125,57 +149,62 @@ public static void addSuperGetters(JavaClass javaC, String fieldName, JavaAbstra
}
+ private static IType normalizeAttributeTypeForGetter(Attribute attribute) {
+ IType attrType = attribute.getType();
+ if (!(attrType instanceof LiteralEnum)) {
+ return attrType;
+ }
+
+ return new GenericType("String", false);
+ }
+
/**
* Create the action methods calling the super class method
*
*/
public static void addSuperActions(JavaAbstractsGenerator javaGenerator, JavaClass javaC,
JoinPointClass joinPointSuperType,
- String fieldName) {
+ String fieldName,
+ JavaType currentJpType) {
var jps = new ArrayList<>(joinPointSuperType.getActions());
- // TODO: HACK - Two insert methods are missing from the actions/generation,
- // adding them manually
-
- var returnType = new ArrayType(new JPType(JoinPointClass.globalJoinPoint()));
- // var globalJpType = new GenericType("JoinpointInterface", false);
- var globalJpType = PrimitiveClasses.JOINPOINT_INTERFACE;
- var paramsJp = List.of(new Parameter(PrimitiveClasses.STRING, "position"), new Parameter(globalJpType, "code"));
- var paramsString = List.of(new Parameter(PrimitiveClasses.STRING, "position"),
- new Parameter(PrimitiveClasses.STRING, "code"));
-
- var insertActionWithJp = new org.lara.language.specification.dsl.Action(returnType, "insert", paramsJp);
- var insertActionWithString = new org.lara.language.specification.dsl.Action(returnType, "insert", paramsString);
-
- jps.add(insertActionWithString);
- jps.add(insertActionWithJp);
-
- // Sort with the insert actions inside
+ // Insert overloads now come from the shared LaraJoinPoint contract through the
+ // inherited action hierarchy.
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()) {
+ if (isRuntimeBackedAction(action)) {
+ continue;
+ }
+
+ normalizeJoinPointBaseAction(
+ action,
+ javaGenerator,
+ "Inherited action '%s' redeclares inherited action with different return type. Using return type '%s'.");
- 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);
+
+ // Cast is only needed when ThisType is involved.
+ // JPType by itself does not require a cast and may trigger unnecessary-cast
+ // warnings.
+ boolean needsCast = TypeTraversalUtils.containsThisType(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);
-
- m.appendCode(");");
+ appendDelegationInvocation(m, fieldName, m.getName());
- javaC.add(m);
+ if (!hasMethodSignature(javaC, m)) {
+ javaC.add(m);
+ }
}
}
@@ -192,9 +221,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);
@@ -235,90 +261,50 @@ 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) {
-
- JavaType type = ConvertUtils.getConvertedType(parameter.getType(), generator);
- getAttribute.addArgument(type, parameter.getName());
- getAttribute.appendCode(parameter.getName());
- }
- getAttribute.appendCode(");");
+ List list,
+ Function parameterTypeResolver, boolean needsCast) {
- 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.apply(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());
- final JavaType returnType = newGetter.getReturnType();
- final String baseType = returnType.getName();
- // getter.setReturnType(new JavaType(Bindings.class));
getter.setReturnType(new JavaType(Object.class));
- // javaC.addImport(Converter.class); // No longer needed?
getter.clearCode();
- getter.appendCode(returnType.getSimpleType());
- final String valueName = StringUtils.firstCharToLower(baseType) + GenConstants.getArrayMethodSufix();
- getter.appendCode(" " + valueName + "0 = ");
- getter.appendCode(newGetter.getName() + "(");
+ getter.appendCode("return " + newGetter.getName() + "(");
final List arguments = getter.getParams();
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(");");
getter.remove(Modifier.ABSTRACT);
javaC.add(newGetter);
}
- 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) {
+ public static boolean hasMethodSignature(JavaClass javaClass, Method candidate) {
return javaClass.getMethods().stream().anyMatch(existing -> sameSignature(existing, candidate));
}
@@ -351,22 +337,187 @@ private static String attributeMethodBaseName(String attributeName) {
return withoutPrefix.isEmpty() ? sanitized : withoutPrefix;
}
+ public static boolean hasSameSignature(Action left, Action right) {
+ return hasSameParameterTypes(left, right)
+ && normalizeType(left.getReturnType()).equals(normalizeType(right.getReturnType()));
+ }
+
+ public static boolean hasSameParameterTypes(Action left, Action right) {
+ List leftParams = left.getParameters();
+ List rightParams = right.getParameters();
+ if (leftParams.size() != rightParams.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < leftParams.size(); i++) {
+ String leftType = normalizeType(leftParams.get(i).getType());
+ String rightType = normalizeType(rightParams.get(i).getType());
+ if (!leftType.equals(rightType)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static Optional findJoinPointBaseMethod(Action action) {
+ return Arrays.stream(org.lara.interpreter.weaver.interf.JoinPoint.class.getMethods())
+ .filter(method -> method.getName().equals(action.getName()))
+ .filter(method -> parametersMatch(method, action))
+ .findFirst();
+ }
+
+ public static String toSpecTypeName(Class> type) {
+ if (type.isArray()) {
+ return toSpecTypeName(type.getComponentType()) + "[]";
+ }
+
+ if (org.lara.interpreter.weaver.interf.JoinPoint.class.equals(type)) {
+ return "joinpoint";
+ }
+
+ return type.getSimpleName();
+ }
+
+ public static String normalizeType(String type) {
+ return type.replace("java.lang.", "").trim();
+ }
+
+ public static boolean isRuntimeBackedAction(Action action) {
+ return findJoinPointBaseMethod(action).isPresent();
+ }
+
+ public static boolean isRuntimeBackedAttribute(Attribute attribute) {
+ String methodName = attribute.getParameters().isEmpty()
+ ? "get" + Utils.firstCharToUpper(attributeMethodBaseName(attribute.getName()))
+ : attribute.getName();
+
+ Optional baseMethod = Arrays
+ .stream(org.lara.interpreter.weaver.interf.JoinPoint.class.getMethods())
+ .filter(method -> method.getName().equals(methodName))
+ .filter(method -> parametersMatch(method, attribute.getParameters()))
+ .findFirst();
+
+ // Keep generation for Object-returning methods (e.g., children/descendants),
+ // so we can still emit the JP-specific impl hook and wrapper. For methods with
+ // non-Object returns (e.g., getJoinPointType/getSuper/getDump) generation would
+ // produce an invalid override because generated wrappers return Object.
+ return baseMethod
+ .map(method -> java.lang.reflect.Modifier.isFinal(method.getModifiers())
+ || !Object.class.equals(method.getReturnType()))
+ .orElse(false);
+ }
+
+ public static JoinPointBaseActionInfo analyzeJoinPointBaseAction(Action action) {
+ var baseMethod = findJoinPointBaseMethod(action);
+ if (baseMethod.isEmpty()) {
+ return new JoinPointBaseActionInfo(Optional.empty(), false);
+ }
+
+ java.lang.reflect.Method method = baseMethod.get();
+ boolean skipWrapper = java.lang.reflect.Modifier.isFinal(method.getModifiers());
+ String expectedReturnType = toSpecTypeName(method.getReturnType());
+ String actualReturnType = action.getReturnType();
+ Optional correctedReturnType = normalizeType(expectedReturnType).equals(normalizeType(actualReturnType))
+ ? Optional.empty()
+ : Optional.of(expectedReturnType);
+
+ return new JoinPointBaseActionInfo(correctedReturnType, skipWrapper);
+ }
+
/**
- * Generates the method with the name and parameters of the action
+ * Aligns an action with the base JoinPoint contract (if one exists), applying a
+ * corrected return type when needed.
*
- * @param action the action used to generate its method
+ * @param action action to normalize
+ * @param generator generator used to resolve corrected type names
+ * @param warningMessageFmt message format with placeholders: action name,
+ * corrected type name
+ * @return true when wrapper generation should be skipped because the base
+ * method is final
*/
- public static Method generateActionMethod(org.lara.language.specification.dsl.Action action,
- JavaAbstractsGenerator generator) {
+ public static boolean normalizeJoinPointBaseAction(Action action, JavaAbstractsGenerator generator,
+ String warningMessageFmt) {
+ var baseInfo = analyzeJoinPointBaseAction(action);
+ baseInfo.correctedReturnType().ifPresent(specTypeName -> {
+ action.setType(generator.getLanguageSpecification().getType(specTypeName));
+ SpecsLogs.warn(warningMessageFmt.formatted(action.getName(), specTypeName));
+ });
+
+ return baseInfo.skipWrapper();
+ }
+
+ public static void addActionAndWrapper(JavaClass targetClass, Action action, JavaAbstractsGenerator generator,
+ JavaType currentJpType, boolean skipWrapper, String duplicateActionMessage,
+ String duplicateWrapperMessage) {
+ final Method method = generateActionMethod(action, generator, currentJpType);
+ if (hasMethodSignature(targetClass, method)) {
+ SpecsLogs.warn(duplicateActionMessage.formatted(action.getName(), method.getName()));
+ return;
+ }
+ targetClass.add(method);
+
+ Method wrapper = generateActionImplMethod(method, action, targetClass, generator, currentJpType);
+ if (skipWrapper) {
+ return;
+ }
+
+ if (hasMethodSignature(targetClass, wrapper)) {
+ SpecsLogs.warn(duplicateWrapperMessage.formatted(wrapper.getName()));
+ return;
+ }
+
+ targetClass.add(wrapper);
+ }
+
+ public record JoinPointBaseActionInfo(Optional correctedReturnType, boolean skipWrapper) {
+ }
- JavaType actionReturn = getJavaType(action.getReturnType(), action.getName(), action, "ActionParam", generator);
+ private static boolean parametersMatch(java.lang.reflect.Method method, Action action) {
+ return parametersMatch(method, action.getParameters());
+ }
+
+ private static boolean parametersMatch(java.lang.reflect.Method method, List params) {
+ Class>[] parameterTypes = method.getParameterTypes();
+ if (parameterTypes.length != params.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < parameterTypes.length; i++) {
+ String expected = normalizeType(toSpecTypeName(parameterTypes[i]));
+ String actual = normalizeType(params.get(i).getType());
+ if (params.get(i).getIType() instanceof LiteralEnum && expected.equals("String")) {
+ continue;
+ }
+ if (!expected.equals(actual)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * 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.getType(), paramName, action, "ActionParam", generator);
+ JavaType jType = getJavaType(param.getIType(), paramName, action, "ActionParam", generator,
+ currentJpType);
paramName = StringUtils.getSanitizedName(paramName);
m.addArgument(jType, paramName);
@@ -378,23 +529,18 @@ public static Method generateActionMethod(org.lara.language.specification.dsl.Ac
return m;
}
- private static JavaType getJavaType(String type, String paramName,
+ private static JavaType getJavaType(IType type, String paramName,
org.lara.language.specification.dsl.Action action, String sufix,
- JavaAbstractsGenerator generator) {
+ JavaAbstractsGenerator generator, JavaType currentJpType) {
- JavaType jType;
- if (type.startsWith("{")) { // then it is an enumerator
+ if (type instanceof LiteralEnum literalEnum && literalEnum.getValues().size() > 1) {
final String firstCharToUpper = StringUtils.firstCharToUpper(action.getName());
- final JavaEnum enumerator = generateEnum(type, paramName, firstCharToUpper + sufix, generator);
+ final JavaEnum enumerator = generateEnum(literalEnum.getValues(), paramName, firstCharToUpper + sufix,
+ generator);
generator.getEnums().add(enumerator);
- // if (!generator.isAbstractGetters())
- // javaC.addImport(enumerator.getClassPackage() + "." +
- // enumerator.getName());
- jType = JavaType.enumType(enumerator.getName(), enumerator.getClassPackage());
- } else {
- jType = ConvertUtils.getConvertedType(type, generator);
+ return JavaType.enumType(enumerator.getName(), enumerator.getClassPackage());
}
- return jType;
+ return ConvertUtils.getConvertedType(type, generator, currentJpType);
}
/**
@@ -411,9 +557,11 @@ public static List convertParamArrayToObjArray(List argument
for (var arg : arguments) {
if (arg.getClassType().isArray()) {
+ int arrayDimension = arg.getClassType().getArrayDimension();
arg = arg.clone();
- arg.getClassType().setName("Object");
- arg.getClassType().setPackage("java.lang");
+ JavaType objectArrayType = JavaTypeFactory.getObjectType();
+ objectArrayType.setArrayDimension(arrayDimension);
+ arg.setClassType(objectArrayType);
}
newArgs.add(arg);
@@ -429,13 +577,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
@@ -565,17 +715,17 @@ public static JavaType generateJoinPointBaseType(String _package, String type) {
* @param attributeName the name of the attribute
* @param baseName the base for the name
*/
- public static JavaEnum generateEnum(String itemsCollection, String attributeName, String baseName,
+ public static JavaEnum generateEnum(List items, String attributeName, String baseName,
JavaAbstractsGenerator generator) {
- final String[] items = itemsCollection.substring(1, itemsCollection.length() - 1).split(",");
- // System.out.println(itemsCollection);
final String javaEnumName = extractEnumName(baseName, attributeName);
final JavaEnum enumerator = new JavaEnum(javaEnumName, generator.getLiteralEnumsPackage());
for (String itemName : items) {
itemName = itemName.trim();
- String enumName = itemName.toUpperCase();
- enumName = enumName.replace("-", "_");
+ String enumName = itemName.toUpperCase().replaceAll("[^A-Z0-9_]", "_");
+ if (!enumName.isEmpty() && Character.isDigit(enumName.charAt(0))) {
+ enumName = "_" + enumName;
+ }
final EnumItem item = new EnumItem(enumName);
item.addParameter('"' + itemName + '"');
@@ -668,7 +818,11 @@ public static Method generateAttributeImpl(Method original, org.lara.language.sp
cloned.appendCodeln("\t}");
}
- cloned.appendCodeln("\treturn result!=null?result:getUndefinedValue();");
+ if (original.getReturnType().isPrimitive()) {
+ cloned.appendCodeln("\treturn result;");
+ } else {
+ cloned.appendCodeln("\treturn result!=null?result:getUndefinedValue();");
+ }
cloned.appendCodeln("} catch(Exception e) {");
cloned.appendCode("\tthrow new " + AttributeException.class.getSimpleName());
@@ -679,10 +833,19 @@ public static Method generateAttributeImpl(Method original, org.lara.language.sp
return cloned;
}
+ /**
+ * 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) {
- String attrClassStr = attribute.getReturnType().trim();
- // String originalType = attrClassStr;
+ JavaAbstractsGenerator generator, JavaType currentJpType) {
+ IType attrType = attribute.getType();
boolean isEnum = false;
JavaEnum enumerator = null;
JavaType javaType;
@@ -690,26 +853,25 @@ public static Method generateAttribute(org.lara.language.specification.dsl.Attri
final String fieldName = sanitizeAttributeName(name);
final String methodBaseName = attributeMethodBaseName(name);
- if (attrClassStr.startsWith("{")) { // then it is an enumerator
+ // 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) {
isEnum = true;
- enumerator = generateEnum(attrClassStr, name, javaC.getName(), generator);
+ enumerator = generateEnum(literalEnum.getValues(), name, javaC.getName(), generator);
generator.getEnums().add(enumerator);
- // if (!generator.isAbstractGetters())
- // javaC.addImport(enumerator.getClassPackage() + "." +
- // enumerator.getName());
javaType = new JavaType(enumerator.getName(), enumerator.getClassPackage());
} else {
- // Any primitive type for attributes are now converted into their wrapper
- javaType = ConvertUtils.getAttributeConvertedType(attrClassStr, generator);
+ // Use IType-aware conversion that resolves ThisType while preserving
+ // primitive signatures in generated impl methods.
+ javaType = ConvertUtils.getConvertedType(attrType, generator, currentJpType);
}
final Field attributeField = new Field(javaType, fieldName, Privacy.PROTECTED);
- // attributeField.setPrivacy(Privacy.PUBLIC);
if (!generator.isAbstractGetters()) {
javaC.add(attributeField);
}
- var parameters = attribute
- .getParameters();
+ var parameters = attribute.getParameters();
if (parameters.isEmpty()) {
final Pair get_set = createGetterAndSetter(attributeField, methodBaseName,
@@ -718,28 +880,19 @@ public static Method generateAttribute(org.lara.language.specification.dsl.Attri
if (isEnum) {
defineEnumReturnType(getter, enumerator, attributeField, generator.isAbstractGetters());
} else if (javaType.isArray()) {
- // TODO - see if this is really necessary, and if so correct the
- // implementations
encapsulateArrayAttribute(javaC, getter);
}
- // Old code
- // } else if (originalType.equals("Array")) { // if the attribute is
- // an array then it should return a
- // // NativeArray!
- // encapsulateArrayAttribute(javaC, getter);
- // }
attribute.getToolTip().ifPresent(comment -> getter.setJavaDocComment(new JavaDoc(comment)));
javaC.add(getter);
return getter;
- // javaC.add(get_set.getRight());
}
final Method methodForAttribute = new Method(javaType, name);
methodForAttribute.add(Modifier.ABSTRACT);
for (var param : parameters) {
-
- final Argument arg = newSanitizedArgument(param.getName(), param.getType(), generator);
+ // 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());
}
@@ -748,20 +901,19 @@ public static Method generateAttribute(org.lara.language.specification.dsl.Attri
if (javaType.isArray()) {
encapsulateArrayAttribute(javaC, methodForAttribute);
}
- // if (originalType.equals("Array")) { // if the attribute is an array
- // then it should return a
- // NativeArray!
- // encapsulateArrayAttribute(javaC, methodForAttribute);
- // }
javaC.add(methodForAttribute);
return methodForAttribute;
-
}
- private static Argument newSanitizedArgument(String name, String type, JavaAbstractsGenerator generator) {
+ /**
+ * 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);
+ final JavaType paramType = ConvertUtils.getConvertedType(type, generator, currentJpType);
return new Argument(paramType, sanitizedName);
}
@@ -771,9 +923,8 @@ private static Argument newSanitizedArgument(String name, String type, JavaAbstr
*/
public static Method generateCompareNodes(JavaType superClass) {
final Method method = new Method(JavaTypeFactory.getBooleanType(), "compareNodes");
- method.addArgument(superClass, "aJoinPoint");
- // abstJPClass.addImport(javaGenerator.getJoinPointClassPackage()); //
- // JoinPoint.class.getCanonicalName()
+ method.addArgument(
+ ConvertUtils.withJoinPointWildcard(superClass), "aJoinPoint");
method.appendCode("return this.getNode().equals(aJoinPoint.getNode());");
method.appendComment(
"Compares the two join points based on their node reference of the used compiler/parsing tool.
"
diff --git a/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/TypeTraversalUtils.java b/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/TypeTraversalUtils.java
new file mode 100644
index 000000000..c2ab98737
--- /dev/null
+++ b/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/java/utils/TypeTraversalUtils.java
@@ -0,0 +1,58 @@
+/**
+ * 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 java.util.function.Predicate;
+
+import org.lara.language.specification.dsl.types.ArrayType;
+import org.lara.language.specification.dsl.types.IType;
+import org.lara.language.specification.dsl.types.ParameterizedType;
+import org.lara.language.specification.dsl.types.ThisType;
+import org.lara.language.specification.dsl.types.WildcardType;
+
+public final class TypeTraversalUtils {
+
+ private TypeTraversalUtils() {
+ }
+
+ public 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;
+ }
+
+ public static boolean containsThisType(IType type) {
+ return containsType(type, candidate -> candidate instanceof ThisType);
+ }
+}
diff --git a/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/utils/GenConstants.java b/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/utils/GenConstants.java
index cb90a6846..67957bd5b 100644
--- a/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/utils/GenConstants.java
+++ b/WeaverGenerator/src/org/lara/interpreter/weaver/generator/generator/utils/GenConstants.java
@@ -13,11 +13,11 @@
package org.lara.interpreter.weaver.generator.generator.utils;
+import java.io.File;
+
import org.lara.interpreter.weaver.interf.JoinPoint;
import org.specs.generators.java.types.JavaType;
-import java.io.File;
-
public class GenConstants {
private static final String IMPLEMENTATION_SUFIX = "Impl";
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..09b9d7e9b 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 {
/**
*
@@ -32,7 +32,7 @@ public abstract class AEdgeWeaverJoinPoint extends AJoinPoint {
* the changes are made for all join points, or override this method in specific join points.
*/
@Override
- public boolean compareNodes(AJoinPoint aJoinPoint) {
+ public boolean compareNodes(AJoinPoint> aJoinPoint) {
return this.getNode().equals(aJoinPoint.getNode());
}
}
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..b388d58cb 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 {
/**
*
@@ -54,7 +54,15 @@ public abstract class ABase extends AEdgeWeaverJoinPoint {
*
*/
protected enum BaseAttributes {
- A("a");
+ A("a"),
+ DUMP("dump"),
+ JOINPOINTTYPE("joinPointType"),
+ NODE("node"),
+ SELF("self"),
+ SUPER("super"),
+ CHILDREN("children"),
+ DESCENDANTS("descendants"),
+ SCOPENODES("scopeNodes");
private String name;
/**
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..77983b4f3 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 {
/**
*
@@ -23,8 +23,7 @@ public abstract class AJoinPoint extends JoinPoint {
@Override
public boolean same(JoinPoint iJoinPoint) {
if (this.get_class().equals(iJoinPoint.get_class())) {
-
- return this.compareNodes((AJoinPoint) iJoinPoint);
+ return this.compareNodes((AJoinPoint>) iJoinPoint);
}
return false;
}
@@ -35,7 +34,7 @@ public abstract class AJoinPoint extends JoinPoint {
* 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.
*/
- public boolean compareNodes(AJoinPoint aJoinPoint) {
+ public boolean compareNodes(AJoinPoint> aJoinPoint) {
return this.getNode().equals(aJoinPoint.getNode());
}
@@ -45,34 +44,55 @@ public abstract class AJoinPoint extends JoinPoint {
*/
public abstract Object getNode();
+ /**
+ * 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 boolean instanceOf(String joinpointClass) {
+ boolean isInstance = get_class().equals(joinpointClass);
+ if(isInstance) {
+ return true;
+ }
+ return super.instanceOf(joinpointClass);
+ }
+
/**
*
+ * @param jp
*/
- public void noopImpl() {
- throw new UnsupportedOperationException(get_class()+": Action noop not implemented ");
+ public boolean equalsImpl(AJoinPoint> jp) {
+ throw new UnsupportedOperationException(get_class()+": Action equals not implemented ");
}
/**
*
+ * @param jp
*/
- public final void noop() {
+ public final Object equals(AJoinPoint> jp) {
try {
- this.noopImpl();
+ boolean result = this.equalsImpl(jp);
+ return result;
} catch(Exception e) {
- throw new ActionException(get_class(), "noop", e);
+ throw new ActionException(get_class(), "equals", e);
}
}
/**
- * 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 boolean instanceOf(String joinpointClass) {
- boolean isInstance = get_class().equals(joinpointClass);
- if(isInstance) {
- return true;
+ public void noopImpl() {
+ throw new UnsupportedOperationException(get_class()+": Action noop not implemented ");
+ }
+
+ /**
+ *
+ */
+ public final void noop() {
+ try {
+ this.noopImpl();
+ } catch(Exception e) {
+ throw new ActionException(get_class(), "noop", e);
}
- return super.instanceOf(joinpointClass);
}
}
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..48fe2d687 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
@@ -2,7 +2,6 @@ package edge.pkg.abstracts.joinpoints;
import org.lara.interpreter.exception.AttributeException;
import edge.pkg.EdgeWeaver;
-import org.lara.interpreter.weaver.interf.JoinPoint;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.Arrays;
@@ -15,14 +14,14 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class ALevel1 extends ABase {
+public abstract class ALevel1> extends ABase {
- protected ABase aBase;
+ protected ABase aBase;
/**
*
*/
- public ALevel1(ABase aBase, EdgeWeaver weaver){
+ public ALevel1(ABase aBase, EdgeWeaver weaver){
super(weaver);
this.aBase = aBase;
}
@@ -53,22 +52,11 @@ public abstract class ALevel1 extends ABase {
/**
*
- * @param position
- * @param code
+ * @param jp
*/
@Override
- public AJoinPoint[] insertImpl(String position, String code) {
- return this.aBase.insertImpl(position, code);
- }
-
- /**
- *
- * @param position
- * @param code
- */
- @Override
- public AJoinPoint[] insertImpl(String position, JoinPoint code) {
- return this.aBase.insertImpl(position, code);
+ public boolean equalsImpl(AJoinPoint> jp) {
+ return this.aBase.equalsImpl(jp);
}
/**
@@ -83,7 +71,7 @@ public abstract class ALevel1 extends ABase {
*
*/
@Override
- public Optional extends ABase> getSuper() {
+ public Optional extends ABase> getSuper() {
return Optional.of(this.aBase);
}
@@ -113,7 +101,15 @@ public abstract class ALevel1 extends ABase {
*/
protected enum Level1Attributes {
A("a"),
- B("b");
+ B("b"),
+ DUMP("dump"),
+ JOINPOINTTYPE("joinPointType"),
+ NODE("node"),
+ SELF("self"),
+ SUPER("super"),
+ CHILDREN("children"),
+ DESCENDANTS("descendants"),
+ SCOPENODES("scopeNodes");
private String name;
/**
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..0ce14e3aa 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
@@ -2,7 +2,6 @@ package edge.pkg.abstracts.joinpoints;
import org.lara.interpreter.exception.AttributeException;
import edge.pkg.EdgeWeaver;
-import org.lara.interpreter.weaver.interf.JoinPoint;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.Arrays;
@@ -15,14 +14,14 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class ALevel2 extends ALevel1 {
+public abstract class ALevel2> extends ALevel1 {
- protected ALevel1 aLevel1;
+ protected ALevel1 aLevel1;
/**
*
*/
- public ALevel2(ALevel1 aLevel1, EdgeWeaver weaver){
+ public ALevel2(ALevel1 aLevel1, EdgeWeaver weaver){
super(aLevel1, weaver);
this.aLevel1 = aLevel1;
}
@@ -65,22 +64,11 @@ public abstract class ALevel2 extends ALevel1 {
/**
*
- * @param position
- * @param code
+ * @param jp
*/
@Override
- public AJoinPoint[] insertImpl(String position, String code) {
- return this.aLevel1.insertImpl(position, code);
- }
-
- /**
- *
- * @param position
- * @param code
- */
- @Override
- public AJoinPoint[] insertImpl(String position, JoinPoint code) {
- return this.aLevel1.insertImpl(position, code);
+ public boolean equalsImpl(AJoinPoint> jp) {
+ return this.aLevel1.equalsImpl(jp);
}
/**
@@ -95,7 +83,7 @@ public abstract class ALevel2 extends ALevel1 {
*
*/
@Override
- public Optional extends ALevel1> getSuper() {
+ public Optional extends ALevel1> getSuper() {
return Optional.of(this.aLevel1);
}
@@ -126,7 +114,15 @@ public abstract class ALevel2 extends ALevel1 {
protected enum Level2Attributes {
C("c"),
A("a"),
- B("b");
+ B("b"),
+ DUMP("dump"),
+ JOINPOINTTYPE("joinPointType"),
+ NODE("node"),
+ SELF("self"),
+ SUPER("super"),
+ CHILDREN("children"),
+ DESCENDANTS("descendants"),
+ SCOPENODES("scopeNodes");
private String name;
/**
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..6996d8d83 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
@@ -2,7 +2,6 @@ package edge.pkg.abstracts.joinpoints;
import org.lara.interpreter.exception.AttributeException;
import edge.pkg.EdgeWeaver;
-import org.lara.interpreter.weaver.interf.JoinPoint;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.Arrays;
@@ -15,14 +14,14 @@ import java.util.List;
*
* @author Lara Weaver Generator
*/
-public abstract class AReservedKeyword extends ALevel2 {
+public abstract class AReservedKeyword> extends ALevel2 {
- protected ALevel2 aLevel2;
+ protected ALevel2 aLevel2;
/**
*
*/
- public AReservedKeyword(ALevel2 aLevel2, EdgeWeaver weaver){
+ public AReservedKeyword(ALevel2 aLevel2, EdgeWeaver weaver){
super(aLevel2, weaver);
this.aLevel2 = aLevel2;
}
@@ -74,22 +73,11 @@ public abstract class AReservedKeyword extends ALevel2 {
/**
*
- * @param position
- * @param code
+ * @param jp
*/
@Override
- public AJoinPoint[] insertImpl(String position, String code) {
- return this.aLevel2.insertImpl(position, code);
- }
-
- /**
- *
- * @param position
- * @param code
- */
- @Override
- public AJoinPoint[] insertImpl(String position, JoinPoint code) {
- return this.aLevel2.insertImpl(position, code);
+ public boolean equalsImpl(AJoinPoint> jp) {
+ return this.aLevel2.equalsImpl(jp);
}
/**
@@ -104,7 +92,7 @@ public abstract class AReservedKeyword extends ALevel2 {
*
*/
@Override
- public Optional extends ALevel2> getSuper() {
+ public Optional extends ALevel2> getSuper() {
return Optional.of(this.aLevel2);
}
@@ -136,7 +124,15 @@ public abstract class AReservedKeyword extends ALevel2 {
CLASS("class"),
C("c"),
A("a"),
- B("b");
+ B("b"),
+ DUMP("dump"),
+ JOINPOINTTYPE("joinPointType"),
+ NODE("node"),
+ SELF("self"),
+ SUPER("super"),
+ CHILDREN("children"),
+ DESCENDANTS("descendants"),
+ SCOPENODES("scopeNodes");
private String name;
/**
diff --git a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/weaver/AEdgeWeaver.java.txt b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/weaver/AEdgeWeaver.java.txt
index cf17c8a16..4d9b4e4c3 100644
--- a/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/weaver/AEdgeWeaver.java.txt
+++ b/WeaverGenerator/test-resources/golden/edge/pkg/abstracts/weaver/AEdgeWeaver.java.txt
@@ -21,7 +21,7 @@ public abstract class AEdgeWeaver extends LaraWeaverEngine {
*/
@Override
public final List getActions() {
- String[] weaverActions= {"noop"};
+ String[] weaverActions= {"insert", "insert", "toString", "equals", "instanceOf", "instanceOf", "noop"};
return Arrays.asList(weaverActions);
}
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..5ef1ada2d 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 {
/**
*
@@ -32,7 +32,7 @@ public abstract class AMediumWeaverJoinPoint extends AJoinPoint {
* the changes are made for all join points, or override this method in specific join points.
*/
@Override
- public boolean compareNodes(AJoinPoint aJoinPoint) {
+ public boolean compareNodes(AJoinPoint> aJoinPoint) {
return this.getNode().equals(aJoinPoint.getNode());
}
}
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..382b60dd8 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 {
/**
*
@@ -34,6 +34,14 @@ public abstract class ABody extends AMediumWeaverJoinPoint {
*
*/
protected enum BodyAttributes {
+ DUMP("dump"),
+ JOINPOINTTYPE("joinPointType"),
+ NODE("node"),
+ SELF("self"),
+ SUPER("super"),
+ CHILDREN("children"),
+ DESCENDANTS("descendants"),
+ SCOPENODES("scopeNodes"),
LANGUAGE("language");
private String name;
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..7b2a84588 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 {
/**
*
@@ -55,6 +55,14 @@ public abstract class AFile extends AMediumWeaverJoinPoint {
*/
protected enum FileAttributes {
PATH("path"),
+ DUMP("dump"),
+ JOINPOINTTYPE("joinPointType"),
+ NODE("node"),
+ SELF("self"),
+ SUPER("super"),
+ CHILDREN("children"),
+ DESCENDANTS("descendants"),
+ SCOPENODES("scopeNodes"),
LANGUAGE("language");
private String name;
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..aed0a2c84 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 {
/**
*
@@ -67,7 +67,7 @@ public abstract class AFunction extends AMediumWeaverJoinPoint {
*
* @param node
*/
- public AJoinPoint replaceWithImpl(AJoinPoint node) {
+ public AJoinPoint> replaceWithImpl(AJoinPoint> node) {
throw new UnsupportedOperationException(get_class()+": Action replaceWith not implemented ");
}
@@ -75,9 +75,9 @@ public abstract class AFunction extends AMediumWeaverJoinPoint {
*
* @param node
*/
- public final Object replaceWith(AJoinPoint node) {
+ public final Object replaceWith(AJoinPoint> node) {
try {
- AJoinPoint result = this.replaceWithImpl(node);
+ AJoinPoint> result = this.replaceWithImpl(node);
return result!=null?result:getUndefinedValue();
} catch(Exception e) {
throw new ActionException(get_class(), "replaceWith", e);
@@ -98,6 +98,14 @@ public abstract class AFunction extends AMediumWeaverJoinPoint {
protected enum FunctionAttributes {
NAME("name"),
PARAMS("params"),
+ DUMP("dump"),
+ JOINPOINTTYPE("joinPointType"),
+ NODE("node"),
+ SELF("self"),
+ SUPER("super"),
+ CHILDREN("children"),
+ DESCENDANTS("descendants"),
+ SCOPENODES("scopeNodes"),
LANGUAGE("language");
private String name;
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..80c470dea 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 {
/**
*
@@ -24,8 +24,7 @@ public abstract class AJoinPoint extends JoinPoint {
@Override
public boolean same(JoinPoint iJoinPoint) {
if (this.get_class().equals(iJoinPoint.get_class())) {
-
- return this.compareNodes((AJoinPoint) iJoinPoint);
+ return this.compareNodes((AJoinPoint>) iJoinPoint);
}
return false;
}
@@ -36,7 +35,7 @@ public abstract class AJoinPoint extends JoinPoint {
* 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.
*/
- public boolean compareNodes(AJoinPoint aJoinPoint) {
+ public boolean compareNodes(AJoinPoint> aJoinPoint) {
return this.getNode().equals(aJoinPoint.getNode());
}
@@ -46,13 +45,38 @@ public abstract class AJoinPoint extends JoinPoint {
*/
public abstract Object getNode();
+ /**
+ * 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 boolean instanceOf(String joinpointClass) {
+ boolean isInstance = get_class().equals(joinpointClass);
+ if(isInstance) {
+ return true;
+ }
+ return super.instanceOf(joinpointClass);
+ }
+
+ /**
+ *
+ * @param jp
+ */
+ public boolean equalsImpl(AJoinPoint> jp) {
+ throw new UnsupportedOperationException(get_class()+": Action equals not implemented ");
+ }
+
/**
*
- * @param position
- * @param code
+ * @param jp
*/
- public AJoinPoint[] insertImpl(String position, String code) {
- throw new UnsupportedOperationException(get_class()+": Action insert not implemented ");
+ public final Object equals(AJoinPoint> jp) {
+ try {
+ boolean result = this.equalsImpl(jp);
+ return result;
+ } catch(Exception e) {
+ throw new ActionException(get_class(), "equals", e);
+ }
}
/**
@@ -73,17 +97,4 @@ public abstract class AJoinPoint extends JoinPoint {
throw new AttributeException(get_class(), "language", e);
}
}
-
- /**
- * 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 boolean instanceOf(String joinpointClass) {
- boolean isInstance = get_class().equals(joinpointClass);
- if(isInstance) {
- return true;
- }
- return super.instanceOf(joinpointClass);
- }
}
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..f4bb3f2cd 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 {
/**
*
@@ -34,6 +34,14 @@ public abstract class AStatement extends AMediumWeaverJoinPoint {
*
*/
protected enum StatementAttributes {
+ DUMP("dump"),
+ JOINPOINTTYPE("joinPointType"),
+ NODE("node"),
+ SELF("self"),
+ SUPER("super"),
+ CHILDREN("children"),
+ DESCENDANTS("descendants"),
+ SCOPENODES("scopeNodes"),
LANGUAGE("language");
private String name;
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..4eccf67a3 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 {
/**
*
@@ -34,6 +34,14 @@ public abstract class AVar extends AMediumWeaverJoinPoint {
*
*/
protected enum VarAttributes {
+ DUMP("dump"),
+ JOINPOINTTYPE("joinPointType"),
+ NODE("node"),
+ SELF("self"),
+ SUPER("super"),
+ CHILDREN("children"),
+ DESCENDANTS("descendants"),
+ SCOPENODES("scopeNodes"),
LANGUAGE("language");
private String name;
diff --git a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/weaver/AMediumWeaver.java.txt b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/weaver/AMediumWeaver.java.txt
index 7bc88d429..1e79b83b1 100644
--- a/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/weaver/AMediumWeaver.java.txt
+++ b/WeaverGenerator/test-resources/golden/medium/pkg/abstracts/weaver/AMediumWeaver.java.txt
@@ -22,7 +22,7 @@ public abstract class AMediumWeaver extends LaraWeaverEngine {
*/
@Override
public final List getActions() {
- String[] weaverActions= {"insert", "replaceWith"};
+ String[] weaverActions= {"insert", "insert", "toString", "equals", "instanceOf", "instanceOf", "insert", "replaceWith"};
return Arrays.asList(weaverActions);
}
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..cd4ed66d5 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 {
/**
*
@@ -32,7 +32,7 @@ public abstract class AMinimalWeaverJoinPoint extends AJoinPoint {
* the changes are made for all join points, or override this method in specific join points.
*/
@Override
- public boolean compareNodes(AJoinPoint aJoinPoint) {
+ public boolean compareNodes(AJoinPoint> aJoinPoint) {
return this.getNode().equals(aJoinPoint.getNode());
}
}
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..3c84d2a5c 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
@@ -2,13 +2,14 @@ package minimal.pkg.abstracts.joinpoints;
import org.lara.interpreter.weaver.interf.JoinPoint;
import org.lara.interpreter.weaver.interf.WeaverEngine;
+import org.lara.interpreter.exception.ActionException;
/**
* Abstract class containing the global attributes and default action exception.
* 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 {
/**
*
@@ -22,8 +23,7 @@ public abstract class AJoinPoint extends JoinPoint {
@Override
public boolean same(JoinPoint iJoinPoint) {
if (this.get_class().equals(iJoinPoint.get_class())) {
-
- return this.compareNodes((AJoinPoint) iJoinPoint);
+ return this.compareNodes((AJoinPoint>) iJoinPoint);
}
return false;
}
@@ -34,7 +34,7 @@ public abstract class AJoinPoint extends JoinPoint {
* 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.
*/
- public boolean compareNodes(AJoinPoint aJoinPoint) {
+ public boolean compareNodes(AJoinPoint> aJoinPoint) {
return this.getNode().equals(aJoinPoint.getNode());
}
@@ -56,4 +56,25 @@ public abstract class AJoinPoint extends JoinPoint {
}
return super.instanceOf(joinpointClass);
}
+
+ /**
+ *
+ * @param jp
+ */
+ public boolean equalsImpl(AJoinPoint> jp) {
+ throw new UnsupportedOperationException(get_class()+": Action equals not implemented ");
+ }
+
+ /**
+ *
+ * @param jp
+ */
+ public final Object equals(AJoinPoint> jp) {
+ try {
+ boolean result = this.equalsImpl(jp);
+ return result;
+ } catch(Exception e) {
+ throw new ActionException(get_class(), "equals", e);
+ }
+ }
}
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..bf46f42f4 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
@@ -2,6 +2,10 @@ package minimal.pkg.abstracts.joinpoints;
import minimal.pkg.MinimalWeaver;
import minimal.pkg.abstracts.AMinimalWeaverJoinPoint;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.Arrays;
+import java.util.List;
/**
* Auto-Generated class for join point ARoot
@@ -10,7 +14,7 @@ import minimal.pkg.abstracts.AMinimalWeaverJoinPoint;
*
* @author Lara Weaver Generator
*/
-public abstract class ARoot extends AMinimalWeaverJoinPoint {
+public abstract class ARoot> extends AMinimalWeaverJoinPoint {
/**
*
@@ -26,4 +30,45 @@ public abstract class ARoot extends AMinimalWeaverJoinPoint {
public final String get_class() {
return "root";
}
+ /**
+ *
+ */
+ protected enum RootAttributes {
+ DUMP("dump"),
+ JOINPOINTTYPE("joinPointType"),
+ NODE("node"),
+ SELF("self"),
+ SUPER("super"),
+ CHILDREN("children"),
+ DESCENDANTS("descendants"),
+ SCOPENODES("scopeNodes");
+ private String name;
+
+ /**
+ *
+ */
+ private RootAttributes(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(RootAttributes::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/minimal/pkg/abstracts/weaver/AMinimalWeaver.java.txt b/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/weaver/AMinimalWeaver.java.txt
index 9a7e405c4..b5cc52740 100644
--- a/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/weaver/AMinimalWeaver.java.txt
+++ b/WeaverGenerator/test-resources/golden/minimal/pkg/abstracts/weaver/AMinimalWeaver.java.txt
@@ -21,7 +21,7 @@ public abstract class AMinimalWeaver extends LaraWeaverEngine {
*/
@Override
public final List getActions() {
- String[] weaverActions= {};
+ String[] weaverActions= {"insert", "insert", "toString", "equals", "instanceOf", "instanceOf"};
return Arrays.asList(weaverActions);
}
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..15d576488
--- /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..d76810ec9
--- /dev/null
+++ b/WeaverGenerator/test-resources/golden/thistype/pkg/abstracts/joinpoints/ABinaryExpr.java.txt
@@ -0,0 +1,678 @@
+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 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