diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/AbstractService.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/AbstractService.java index 0075980274..87ef53254a 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/AbstractService.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/AbstractService.java @@ -21,7 +21,6 @@ import de.monticore.symbols.basicsymbols._symboltable.DiagramSymbol; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; -import de.monticore.symbols.basicsymbols._symboltable.TypeSymbolSurrogate; import de.monticore.symboltable.ImportStatement; import de.monticore.types.MCTypeFacade; import de.monticore.types.check.SymTypeExpression; @@ -169,27 +168,35 @@ public List getAllSuperClassesTransitive(ASTCDClass astcdClass) { protected List getAllSuperClassesTransitive(TypeSymbol cdTypeSymbol) { List superSymbolList = new ArrayList<>(); if (cdTypeSymbol.isPresentSuperClass()) { - TypeSymbol superSymbol = cdTypeSymbol.getSuperClass().getTypeInfo(); - if (superSymbol instanceof TypeSymbolSurrogate) { - if (!((TypeSymbolSurrogate) superSymbol).checkLazyLoadDelegate()) { - return superSymbolList; - } - superSymbol = ((TypeSymbolSurrogate) superSymbol).lazyLoadDelegate(); + Optional superSymbol = resolveTypeInfo(cdTypeSymbol.getSuperClass()); + if (superSymbol.isEmpty()) { + return superSymbolList; } - - superSymbolList.add(superSymbol); - superSymbolList.addAll(getAllSuperClassesTransitive(superSymbol)); + superSymbolList.add(superSymbol.get()); + superSymbolList.addAll(getAllSuperClassesTransitive(superSymbol.get())); } return superSymbolList; } + public Optional resolveTypeInfo(SymTypeExpression symType) { + if (!symType.hasTypeInfo()) { + return Optional.empty(); + } + TypeSymbol typeInfo = symType.getTypeInfo(); + if (typeInfo.getEnclosingScope() == null) { + return Optional.of(typeInfo); + } + return typeInfo.getEnclosingScope().resolveType(typeInfo.getName()); + } + public List getAllSuperInterfacesTransitive(TypeSymbol cdTypeSymbol) { List superSymbolList = new ArrayList<>(); List localSuperInterfaces = Lists.newArrayList(); cdTypeSymbol.getSuperTypesList().stream() .filter(s -> !isTFInterface(s)) - .filter(s -> ((TypeSymbolSurrogate)s.getTypeInfo()).checkLazyLoadDelegate()) - .map(s -> ((TypeSymbolSurrogate)s.getTypeInfo()).lazyLoadDelegate()) + .map(this::resolveTypeInfo) + .filter(Optional::isPresent) + .map(Optional::get) .forEach(t -> {if(t instanceof CDTypeSymbol && ((CDTypeSymbol)t).isIsInterface()) localSuperInterfaces.add((CDTypeSymbol) t);}); for (CDTypeSymbol superInterface : localSuperInterfaces) { superSymbolList.add(createASTFullName(superInterface)); diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/DecorationHelper.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/DecorationHelper.java index 69365678d7..b62bd8011a 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/DecorationHelper.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/DecorationHelper.java @@ -9,15 +9,17 @@ import de.monticore.codegen.mc2cd.MC2CDStereotypes; import de.monticore.codegen.mc2cd.TransformationHelper; import de.monticore.generating.templateengine.GlobalExtensionManagement; +import de.monticore.codegen.cd2java.methods.AccessAsSupplierTypes; import de.monticore.generating.templateengine.HookPoint; import de.monticore.generating.templateengine.StringHookPoint; import de.monticore.symboltable.ISymbol; import de.monticore.types.MCBasicTypesHelper; +import de.monticore.types.MCTypeFacade; import de.monticore.types.mcbasictypes._ast.ASTMCPrimitiveType; import de.monticore.types.mcbasictypes._ast.ASTMCType; import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType; -import de.monticore.types.mccollectiontypes._ast.ASTMCOptionalType; import de.monticore.types.mccollectiontypes._ast.ASTMCTypeArgument; +import de.monticore.types.mcsimplegenerictypes.MCSimpleGenericTypesMill; import de.monticore.umlmodifier._ast.ASTModifier; import de.monticore.umlstereotype._ast.ASTStereoValue; import de.monticore.umlstereotype._ast.ASTStereotype; @@ -26,11 +28,14 @@ import de.se_rwth.commons.StringTransformations; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Optional; import static de.monticore.cd.codegen.CD2JavaTemplates.VALUE; import static de.monticore.codegen.cd2java._ast.ast_class.ASTConstants.AST_PREFIX; +import static de.monticore.codegen.cd2java.methods.AccessAsSupplierTypes.STD_SUPPLIER_TYPE; +import static de.monticore.codegen.cd2java.methods.AccessAsSupplierTypes.SUPPLIER_TYPE; public class DecorationHelper extends MCBasicTypesHelper { @@ -67,7 +72,7 @@ public boolean isAstNode(ASTCDAttribute attr) { } public boolean isSimpleAstNode(ASTCDAttribute attr) { - return !isOptional(attr.getMCType()) && !isListType(attr.printType()) && isAstNode(attr); + return !isOptional(attr.getMCType()) && !isList(attr.getMCType()) && isAstNode(attr); } public boolean isOptionalAstNode(ASTCDAttribute attr) { @@ -75,7 +80,7 @@ public boolean isOptionalAstNode(ASTCDAttribute attr) { } public boolean isListAstNode(ASTCDAttribute attribute) { - return isListType(attribute.printType()) && isAstNode(attribute); + return isList(attribute.getMCType()) && isAstNode(attribute); } public boolean isListType(String type) { @@ -100,17 +105,36 @@ public boolean isOptional(String type) { if (index != -1) { type = type.substring(0, index); } - return "Optional".equals(type) || "java.lang.Optional".equals(type); + return "Optional".equals(Names.getSimpleName(type)); } - public boolean isOptional(ASTMCType type) { - if (type instanceof ASTMCOptionalType) { - return true; - } else if (type instanceof ASTMCGenericType) { - String simpleType = ((ASTMCGenericType) type).printWithoutTypeArguments(); - return "Optional".equals(Names.getSimpleName(simpleType)); + /** + * Checks whether the type is wrapped by the internal supplier type. + */ + public boolean isSupplier(String type) { + int index = type.indexOf('<'); + if (index != -1) { + type = type.substring(0, index); } - return false; + return SUPPLIER_TYPE.equals(type); + } + + // The ASTMCType overloads intentionally delegate to the String checks above instead of using + // instanceof: a single implementation, and no reliance on the concrete AST node. + public boolean isOptional(ASTMCType type) { + return isOptional(type.printType()); + } + + public boolean isList(ASTMCType type) { + return isListType(type.printType()); + } + + public boolean isSupplier(ASTMCType type) { + return isSupplier(type.printType()); + } + + public boolean shouldHaveSupplier(ASTCDAttribute attribute) { + return AccessAsSupplierTypes.shouldHaveSupplier(attribute); } public boolean isString(String type) { @@ -159,12 +183,33 @@ public String getSimpleNativeType(String nativeAttributeType) { * important for Optional and List types */ public void addAttributeDefaultValues(ASTCDAttribute attribute, GlobalExtensionManagement glex) { - if (isListType(attribute.printType())) { - glex.replaceTemplate(VALUE, attribute, new StringHookPoint("= new java.util.ArrayList<>()")); + // For a wrapped attribute (Supplier) the default is derived from the unwrapped type X. + boolean isSupplier = isSupplier(attribute.getMCType()); + ASTMCType type = unwrapSupplier(attribute.getMCType()); + + boolean isList = isList(type); + String inner; + if (isList) { + inner = "new java.util.ArrayList<>()"; + } else if (isOptional(type)) { + inner = "Optional.empty()"; + } else if (isSupplier) { + inner = "null"; + } else { + return; + } - } else if (isOptional(attribute.getMCType())) { - glex.replaceTemplate(VALUE, attribute, new StringHookPoint("= Optional.empty()")); + // the initialization expression that is placed after the '=' of the field declaration + String defaultValue; + if (!isSupplier) { + defaultValue = inner; + } else if (isList) { + // A list must expose a stable instance, otherwise we would create a new one every get and entries would be lost. + defaultValue = "com.google.common.base.Suppliers.memoize(() -> " + inner + ")"; + } else { + defaultValue = "() -> " + inner; } + glex.replaceTemplate(VALUE, attribute, new StringHookPoint("= " + defaultValue)); } /** @@ -179,11 +224,38 @@ public String getNativeAttributeName(String attributeName) { return attributeName.substring(JavaNamesHelper.PREFIX_WHEN_WORD_IS_RESERVED.length()); } - public ASTMCTypeArgument getReferenceTypeFromOptional(ASTMCType type) { + public ASTMCTypeArgument getReferenceTypeOfOptional(ASTMCType type) { Preconditions.checkArgument(isOptional(type)); return ((ASTMCGenericType) type).getMCTypeArgumentList().getFirst(); } + public ASTMCTypeArgument getReferenceTypeOfSupplier(ASTMCType type) { + Preconditions.checkArgument(isSupplier(type)); + return ((ASTMCGenericType) type).getMCTypeArgumentList().getFirst(); + } + + /** + * Wraps {@code inner} into the internal supplier type {@code __internal__Supplier} + * + * A copy of this is already in the MCTypeFacade. This can be deleted, and references rerouted to MCTypeFacade after release ... + */ + public ASTMCType createInternalSupplierTypeOf(ASTMCType inner) { + ASTMCTypeArgument arg = MCSimpleGenericTypesMill + .mCCustomTypeArgumentBuilder().setMCType(inner.deepClone()).build(); + return MCTypeFacade.getInstance().createBasicGenericTypeOf(SUPPLIER_TYPE, arg); + } + + /** + * Wraps {@code inner} into the public {@code java.util.function.Supplier} type. + * + * A copy of this is already in the MCTypeFacade. This can be deleted, and references rerouted to MCTypeFacade after release ... + */ + public ASTMCType createStdSupplierTypeOf(ASTMCType inner) { + ASTMCTypeArgument arg = MCSimpleGenericTypesMill + .mCCustomTypeArgumentBuilder().setMCType(inner.deepClone()).build(); + return MCTypeFacade.getInstance().createBasicGenericTypeOf(STD_SUPPLIER_TYPE, arg); + } + /** * methods only used in templates */ @@ -219,12 +291,52 @@ public boolean isAttributeOfTypeEnum(ASTCDAttribute attr) { return ((CDTypeSymbol) type.get()).isIsEnum(); } + /** + * unwraps the internal supplier type (Supplier<X> -> X); returns the type unchanged if it is not wrapped + */ + public ASTMCType unwrapSupplier(ASTMCType type) { + if (isSupplier(type)) { + return getReferenceTypeOfSupplier(type).getMCTypeOpt().get(); + } + return type; + } + + /** + * The type that generated code exposes for a supplied attribute: + * {@code __internal__Supplier} (or an unwrapped X) becomes {@code java.util.function.Supplier}, + * so the internal wrapper never leaks into the public API. + */ + public ASTMCType toPublicSupplierType(ASTMCType type) { + return createStdSupplierTypeOf(unwrapSupplier(type)); + } + + /** + * Replaces the internal marker type of all wrapped attributes by the public {@code java.util.function.Supplier}. + * Must be called after all decorators that rely on {@link #isSupplier} are done with the attributes, because + * afterwards the attributes are no longer recognized as supplied. The generated fields then store the plain supplier. + */ + public void unmarkSuppliers(Collection attributes) { + attributes.stream() + .filter(a -> isSupplier(a.getMCType())) + .forEach(a -> a.setMCType(toPublicSupplierType(a.getMCType()))); + } + + /** + * Wraps the type of every attribute that {@link #shouldHaveSupplier} selects into the internal supplier type. + * The internal type is only a generation-time marker, see {@link #unmarkSuppliers}. + */ + public void wrapAndMarkSuppliers(Collection attributes) { + attributes.stream() + .filter(this::shouldHaveSupplier) + .forEach(a -> a.setMCType(createInternalSupplierTypeOf(a.getMCType()))); + } + /** * methods return correct getters or setters for a special attribut * needed in templates */ public String getPlainGetter(ASTCDAttribute ast) { - String astType = CD4CodeMill.prettyPrint(ast.getMCType(), false); + String astType = CD4CodeMill.prettyPrint(unwrapSupplier(ast.getMCType()), false); StringBuilder sb = new StringBuilder(); // Do not use CDTypes.isBoolean() because only primitive boolean uses GET_PREFIX_BOOLEAN if (astType.equals("boolean")) { @@ -247,7 +359,7 @@ public String getPlainGetter(ASTCDAttribute ast) { public String getPlainSetter(ASTCDAttribute ast) { StringBuilder sb = new StringBuilder(SET_PREFIX).append( StringTransformations.capitalize(getNativeAttributeName(ast.getName()))); - String astType = CD4CodeMill.prettyPrint(ast.getMCType(), false); + String astType = CD4CodeMill.prettyPrint(unwrapSupplier(ast.getMCType()), false); if (isListType(astType)) { if (hasDerivedAttributeName(ast) && ast.getName().endsWith(TransformationHelper.LIST_SUFFIX)) { sb.replace(sb.length() - TransformationHelper.LIST_SUFFIX.length(), diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/ast_class/reference/definition/methoddecorator/ReferencedDefinitionOptAccessorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/ast_class/reference/definition/methoddecorator/ReferencedDefinitionOptAccessorDecorator.java index f59b247c53..077b089df6 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/ast_class/reference/definition/methoddecorator/ReferencedDefinitionOptAccessorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/ast_class/reference/definition/methoddecorator/ReferencedDefinitionOptAccessorDecorator.java @@ -43,7 +43,7 @@ protected String getNaiveAttributeName(ASTCDAttribute astcdAttribute) { @Override protected ASTCDMethod createGetMethod(final ASTCDAttribute ast) { String name = String.format(GET, StringUtils.capitalize(naiveAttributeName)); - ASTMCType type = getDecorationHelper().getReferenceTypeFromOptional(ast.getMCType().deepClone()).getMCTypeOpt().get(); + ASTMCType type = getDecorationHelper().getReferenceTypeOfOptional(ast.getMCType().deepClone()).getMCTypeOpt().get(); ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), type, name); String referencedSymbolType = symbolTableService.getReferencedSymbolTypeName(ast); String attributeName = this.getDecorationHelper().getNativeAttributeName(ast.getName()); diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/BuilderDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/BuilderDecorator.java index b205ab7499..7283fc7652 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/BuilderDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/BuilderDecorator.java @@ -117,6 +117,8 @@ public ASTCDClass decorate(final ASTCDClass domainClass) throws DecorateExceptio .collect(Collectors.toList()); builderAttributes.forEach(this::addAttributeDefaultValues); + // the marker type is not needed anymore: the fields store the plain Supplier + getDecorationHelper().unmarkSuppliers(builderAttributes); return CD4AnalysisMill.cDClassBuilder() .setModifier(modifier) @@ -133,7 +135,11 @@ public ASTCDClass decorate(final ASTCDClass domainClass) throws DecorateExceptio } protected void addAttributeDefaultValues(ASTCDAttribute attribute) { - if (getDecorationHelper().isListType(CD4CodeMill.prettyPrint(attribute.getMCType(), false))) { + if (getDecorationHelper().isSupplier(attribute.getMCType())) { + // a supplier-wrapped attribute must have a non-null default supplier, otherwise build() would + // hand the symbol a null field where a Supplier is expected + getDecorationHelper().addAttributeDefaultValues(attribute, glex); + } else if (getDecorationHelper().isListType(CD4CodeMill.prettyPrint(attribute.getMCType(), false))) { this.replaceTemplate(VALUE, attribute, new StringHookPoint("= new java.util.ArrayList<>()")); } else if (getDecorationHelper().isOptional(CD4CodeMill.prettyPrint(attribute.getMCType(), false))) { diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderListMutatorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderListMutatorDecorator.java index d8098c2f06..1ce899239f 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderListMutatorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderListMutatorDecorator.java @@ -15,6 +15,7 @@ import java.util.stream.Collectors; import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY; +import static de.monticore.cd.facade.CDModifier.PUBLIC; /** * changes return type of builder setters for list attributes @@ -46,8 +47,8 @@ protected List createSetter(ASTCDAttribute attribute) { String parameterCall = m.getCDParameterList().stream() .map(ASTCDParameter::getName) .collect(Collectors.joining(", ")); - this.replaceTemplate(EMPTY_BODY, m, new TemplateHookPoint("_ast.builder.MethodDelegate4ASTBuilder", - attribute, methodName, parameterCall)); + this.replaceTemplate(EMPTY_BODY, m, new TemplateHookPoint("_ast.builder.MethodDelegate4ASTBuilder", + attribute.deepClone(), methodName, parameterCall)); } return methods; } @@ -58,7 +59,24 @@ protected ASTCDMethod createSetListMethod(ASTCDAttribute ast) { ASTCDMethod method = this.getCDMethodFacade().createMethodByDefinition(signature); ASTMCReturnType returnType = MCBasicTypesMill.mCReturnTypeBuilder().setMCType(builderType).build(); method.setMCReturnType(returnType); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.Set4ASTBuilder", ast)); + + String templateName = "_ast.builder.Set4ASTBuilder"; + if (getDecorationHelper().isSupplier(ast.getMCType())) { + templateName = "_ast.builder.SupplierSet4ASTBuilder"; + } + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint(templateName, ast)); + return method; + } + + @Override + protected ASTCDMethod createSetListSupplierMethod(ASTCDAttribute ast) { + String name = "set" + capitalizedAttributeNameWithOutS + "ListSupplier"; + ASTMCType supplierType = getDecorationHelper().toPublicSupplierType(ast.getMCType()); + ASTCDParameter parameter = this.getCDParameterFacade().createParameter(supplierType, ast.getName()); + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, parameter); + ASTMCReturnType returnType = MCBasicTypesMill.mCReturnTypeBuilder().setMCType(builderType).build(); + method.setMCReturnType(returnType); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.SupplierSetRaw4ASTBuilder", ast)); return method; } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderMandatoryMutatorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderMandatoryMutatorDecorator.java index 21bd56009e..f64d186175 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderMandatoryMutatorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderMandatoryMutatorDecorator.java @@ -26,9 +26,28 @@ public BuilderMandatoryMutatorDecorator(final GlobalExtensionManagement glex, @Override protected ASTCDMethod createSetter(final ASTCDAttribute ast) { - String name = String.format(SET, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(ast.getName()))); - ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), builderType, name, this.getCDParameterFacade().createParameters(ast)); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.Set4ASTBuilder", ast)); + ASTCDAttribute attribute = ast; + String templateName = "_ast.builder.Set4ASTBuilder"; + if (getDecorationHelper().isSupplier(ast.getMCType())) { + attribute = ast.deepClone(); + attribute.setMCType(getDecorationHelper().unwrapSupplier(attribute.getMCType())); + templateName = "_ast.builder.SupplierSet4ASTBuilder"; + } + + String name = String.format(SET, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(attribute.getName()))); + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), builderType, name, this.getCDParameterFacade().createParameters(attribute)); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint(templateName, ast)); + return method; + } + + @Override + protected ASTCDMethod createSupplierSetter(final ASTCDAttribute ast) { + ASTCDAttribute attribute = ast.deepClone(); + attribute.setMCType(getDecorationHelper().toPublicSupplierType(ast.getMCType())); + + String name = String.format(SET, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(attribute.getName()))) + "Supplier"; + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), builderType, name, this.getCDParameterFacade().createParameters(attribute)); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.SupplierSetRaw4ASTBuilder", ast)); return method; } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderOptionalMutatorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderOptionalMutatorDecorator.java index 58a7d8592e..2826303fd6 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderOptionalMutatorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/buildermethods/BuilderOptionalMutatorDecorator.java @@ -30,12 +30,32 @@ public BuilderOptionalMutatorDecorator(final GlobalExtensionManagement glex, @Override protected ASTCDMethod createSetMethod(final ASTCDAttribute attribute) { String name = String.format(SET, naiveAttributeName); - ASTMCType parameterType = getDecorationHelper().getReferenceTypeFromOptional(attribute.getMCType()).getMCTypeOpt().get().deepClone(); + + ASTMCType type = attribute.getMCType().deepClone(); + String templateName = "_ast.builder.opt.Set4ASTBuilderOpt"; + if (getDecorationHelper().isSupplier(type)) { + type = getDecorationHelper().unwrapSupplier(type); + templateName = "_ast.builder.opt.SupplierSet4ASTBuilderOpt"; + } + + ASTMCType parameterType = getDecorationHelper().getReferenceTypeOfOptional(type).getMCTypeOpt().get().deepClone(); ASTCDParameter parameter = this.getCDParameterFacade().createParameter(parameterType, attribute.getName()); ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, parameter); ASTMCReturnType returnType = MCBasicTypesMill.mCReturnTypeBuilder().setMCType(builderType).build(); method.setMCReturnType(returnType); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.opt.Set4ASTBuilderOpt", attribute)); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint(templateName, attribute)); + return method; + } + + @Override + protected ASTCDMethod createSupplierSetMethod(final ASTCDAttribute ast) { + String name = String.format(SET, naiveAttributeName) + "Supplier"; + ASTMCType supplierType = getDecorationHelper().toPublicSupplierType(ast.getMCType()); + ASTCDParameter parameter = this.getCDParameterFacade().createParameter(supplierType, ast.getName()); + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, parameter); + ASTMCReturnType returnType = MCBasicTypesMill.mCReturnTypeBuilder().setMCType(builderType).build(); + method.setMCReturnType(returnType); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.SupplierSetRaw4ASTBuilder", ast)); return method; } @@ -45,7 +65,13 @@ protected ASTCDMethod createSetAbsentMethod(final ASTCDAttribute attribute) { ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name); ASTMCReturnType returnType = MCBasicTypesMill.mCReturnTypeBuilder().setMCType(builderType).build(); method.setMCReturnType(returnType); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.opt.SetAbsent4ASTBuilderOpt", attribute)); + + String templateName = "_ast.builder.opt.SetAbsent4ASTBuilderOpt"; + if (getDecorationHelper().isSupplier(attribute.getMCType())) { + templateName = "_ast.builder.opt.SupplierSetAbsent4ASTBuilderOpt"; + } + + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint(templateName, attribute)); return method; } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderListMutatorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderListMutatorDecorator.java index fa591abae8..8c2c9ff321 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderListMutatorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderListMutatorDecorator.java @@ -3,6 +3,7 @@ import de.monticore.cdbasis._ast.ASTCDAttribute; import de.monticore.cd4codebasis._ast.ASTCDMethod; +import de.monticore.cd4codebasis._ast.ASTCDParameter; import de.monticore.codegen.cd2java._ast.builder.buildermethods.BuilderListMutatorDecorator; import de.monticore.generating.templateengine.GlobalExtensionManagement; import de.monticore.generating.templateengine.TemplateHookPoint; @@ -11,6 +12,7 @@ import de.monticore.types.mcbasictypes.MCBasicTypesMill; import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY; +import static de.monticore.cd.facade.CDModifier.PUBLIC; /** * changes return type of builder setters for list attributes @@ -30,4 +32,16 @@ protected ASTCDMethod createSetListMethod(ASTCDAttribute ast) { this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.SetInherited", ast, "set" + capitalizedAttributeNameWithS + "List")); return method; } + + @Override + protected ASTCDMethod createSetListSupplierMethod(ASTCDAttribute ast) { + String name = "set" + capitalizedAttributeNameWithOutS + "ListSupplier"; + ASTMCType supplierType = getDecorationHelper().toPublicSupplierType(ast.getMCType()); + ASTCDParameter parameter = this.getCDParameterFacade().createParameter(supplierType, ast.getName()); + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, parameter); + ASTMCReturnType returnType = MCBasicTypesMill.mCReturnTypeBuilder().setMCType(builderType).build(); + method.setMCReturnType(returnType); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.SetInherited", ast, name)); + return method; + } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderMandatoryMutatorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderMandatoryMutatorDecorator.java index 90aca96882..ac4310baaf 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderMandatoryMutatorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderMandatoryMutatorDecorator.java @@ -24,9 +24,25 @@ public InheritedBuilderMandatoryMutatorDecorator(final GlobalExtensionManagement @Override protected ASTCDMethod createSetter(final ASTCDAttribute ast) { - String name = String.format(SET, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(ast.getName()))); - ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), builderType, name, this.getCDParameterFacade().createParameters(ast)); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.SetInherited", ast, name)); + ASTCDAttribute attribute = ast; + if (getDecorationHelper().isSupplier(ast.getMCType())) { + attribute = ast.deepClone(); + attribute.setMCType(getDecorationHelper().unwrapSupplier(attribute.getMCType())); + } + String name = String.format(SET, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(attribute.getName()))); + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), builderType, name, this.getCDParameterFacade().createParameters(attribute)); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.SetInherited", attribute, name)); + return method; + } + + @Override + protected ASTCDMethod createSupplierSetter(final ASTCDAttribute ast) { + ASTCDAttribute attribute = ast.deepClone(); + attribute.setMCType(getDecorationHelper().toPublicSupplierType(ast.getMCType())); + + String name = String.format(SET, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(attribute.getName()))) + "Supplier"; + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), builderType, name, this.getCDParameterFacade().createParameters(attribute)); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.SetInherited", attribute, name)); return method; } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderOptionalMutatorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderOptionalMutatorDecorator.java index 70d14d4f7e..72bc90788e 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderOptionalMutatorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_ast/builder/inheritedmethods/InheritedBuilderOptionalMutatorDecorator.java @@ -28,7 +28,11 @@ public InheritedBuilderOptionalMutatorDecorator(final GlobalExtensionManagement @Override protected ASTCDMethod createSetMethod(final ASTCDAttribute attribute) { String name = String.format(SET, naiveAttributeName); - ASTMCType parameterType = getDecorationHelper().getReferenceTypeFromOptional(attribute.getMCType()).getMCTypeOpt().get().deepClone(); + ASTMCType type = attribute.getMCType().deepClone(); + if (getDecorationHelper().isSupplier(type)) { + type = getDecorationHelper().unwrapSupplier(type); + } + ASTMCType parameterType = getDecorationHelper().getReferenceTypeOfOptional(type).getMCTypeOpt().get().deepClone(); ASTCDParameter parameter = this.getCDParameterFacade().createParameter(parameterType, attribute.getName()); ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, parameter); ASTMCReturnType returnType = MCBasicTypesMill.mCReturnTypeBuilder().setMCType(builderType).build(); @@ -37,6 +41,18 @@ protected ASTCDMethod createSetMethod(final ASTCDAttribute attribute) { return method; } + @Override + protected ASTCDMethod createSupplierSetMethod(final ASTCDAttribute ast) { + String name = String.format(SET, naiveAttributeName) + "Supplier"; + ASTMCType supplierType = getDecorationHelper().toPublicSupplierType(ast.getMCType()); + ASTCDParameter parameter = this.getCDParameterFacade().createParameter(supplierType, ast.getName()); + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, parameter); + ASTMCReturnType returnType = MCBasicTypesMill.mCReturnTypeBuilder().setMCType(builderType).build(); + method.setMCReturnType(returnType); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("_ast.builder.SetInherited", ast, name)); + return method; + } + @Override protected ASTCDMethod createSetAbsentMethod(final ASTCDAttribute attribute) { String name = String.format(SET_ABSENT, naiveAttributeName); diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeClassDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeClassDecorator.java index 08aed607c6..ca5ed4845d 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeClassDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeClassDecorator.java @@ -95,6 +95,10 @@ public ASTCDClass decorate(ASTCDCompilationUnit scopeInput, ASTCDCompilationUnit .flatMap(List::stream) .map(ASTCDAttribute::deepClone) .collect(Collectors.toList()); + + // Wrap selected scoperule attribute types into Supplier so their (possibly not-yet-resolvable) value can be computed later. + // Als mark them as special case suppliers + getDecorationHelper().wrapAndMarkSuppliers(scopeRuleAttributeList); scopeRuleAttributeList .forEach(a -> getDecorationHelper().addAttributeDefaultValues(a, this.glex)); @@ -116,6 +120,8 @@ public ASTCDClass decorate(ASTCDCompilationUnit scopeInput, ASTCDCompilationUnit .map(methodDecorator::decorate) .flatMap(List::stream) .collect(Collectors.toList()); + // the marker is not needed anymore: the fields store the plain Supplier + getDecorationHelper().unmarkSuppliers(scopeRuleAttributeList); Map symbolAttributes = createSymbolAttributes( symbolInput.getCDDefinition().getCDClassesList(), symbolTableService.getCDSymbol()); diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeInterfaceDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeInterfaceDecorator.java index 8de398a602..447ace65df 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeInterfaceDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeInterfaceDecorator.java @@ -93,7 +93,11 @@ public ASTCDInterface decorate(ASTCDCompilationUnit scopeInput, ASTCDCompilation .map(ASTCDClass::getCDAttributeList) .flatMap(List::stream) .map(ASTCDAttribute::deepClone) - .toList(); + .collect(Collectors.toList()); + + // Wrap selected scoperule attribute types into Supplier so their (possibly not-yet-resolvable) value can be computed later. + // Als mark them as special case suppliers. As Interfaces have no attributes, we don't need to unmark later + getDecorationHelper().wrapAndMarkSuppliers(scopeRuleAttributes); List scopeRuleMethodList = scopeInput.deepClone().getCDDefinition().getCDClassesList() .stream() diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/ScopeDeSerDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/ScopeDeSerDecorator.java index 9d2ea934d1..0afe4714ce 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/ScopeDeSerDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/ScopeDeSerDecorator.java @@ -22,6 +22,7 @@ import de.monticore.symbols.basicsymbols._symboltable.DiagramSymbol; import de.monticore.symboltable.serialization.ISymbolDeSer; import de.monticore.types.mcbasictypes._ast.ASTMCQualifiedType; +import de.monticore.types.mcbasictypes._ast.ASTMCType; import de.se_rwth.commons.StringTransformations; import java.util.*; @@ -264,12 +265,16 @@ protected List createDeserializeAttrMethods( List methodList = new ArrayList<>(); for (ASTCDAttribute attr : attributeList) { String methodName = DESERIALIZE + StringTransformations.capitalize(attr.getName()); + // Deserializers for supplied attributes return a supplier of that type + ASTMCType returnType = getDecorationHelper().shouldHaveSupplier(attr) + ? getDecorationHelper().createStdSupplierTypeOf(attr.getMCType()) + : attr.getMCType(); ASTCDMethod method = getCDMethodFacade() - .createMethod(PROTECTED.build(), attr.getMCType(), methodName, scopeParam, scopeJsonParam); + .createMethod(PROTECTED.build(), returnType, methodName, scopeParam, scopeJsonParam); // create wrapper functions offering the deprecated interface // this one does not take the enclosing scope ASTCDMethod wrapperMethod = getCDMethodFacade() - .createMethod(PROTECTED.build(), attr.getMCType(), methodName, scopeJsonParam); + .createMethod(PROTECTED.build(), returnType, methodName, scopeJsonParam); // Check whether built-in serialization exists. If yes, use it and otherwise make method abstract Optional impl = bitser @@ -295,7 +300,7 @@ protected List createDeserializeAttrMethods( ASTCDParameter iScopeParam = getCDParameterFacade().createParameter(getMCTypeFacade() .createQualifiedType(I_SCOPE), scopeParam.getName()); ASTCDMethod wrapperMethod2 = getCDMethodFacade() - .createMethod(PROTECTED.build(), attr.getMCType(), methodName, iScopeParam, scopeJsonParam); + .createMethod(PROTECTED.build(), returnType, methodName, iScopeParam, scopeJsonParam); String errorCode = symbolTableService.getGeneratedErrorCode(methodName); this.replaceTemplate(EMPTY_BODY, wrapperMethod2, new TemplateHookPoint( DESERIALIZE_IS_TEMPL, methodName, scopeParam.getMCType().printType(), errorCode)); diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/SymTypeExpressionSerStrategy.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/SymTypeExpressionSerStrategy.java index 7768c76f84..f850c0004d 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/SymTypeExpressionSerStrategy.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/SymTypeExpressionSerStrategy.java @@ -30,16 +30,16 @@ public HookPoint getListSerialHook(String attrParam) { @Override public HookPoint getDeserialHook(String jsonParam, String attrParam, String scopeName) { - return new StringHookPoint(String.format("return de.monticore.types.check.SymTypeExpressionDeSer.deserializeMember(\"%s\", %s, %s);", attrParam, jsonParam, scopeName)); + return new StringHookPoint(String.format("return new de.monticore.symboltable.ClearingMemorizer(() -> de.monticore.types.check.SymTypeExpressionDeSer.deserializeMember(\"%s\", %s, %s));", attrParam, jsonParam, scopeName)); } @Override public HookPoint getOptDeserialHook(String jsonParam, String attrParam, String scopeName) { - return new StringHookPoint(String.format("return de.monticore.types.check.SymTypeExpressionDeSer.deserializeOptionalMember(\"%s\", %s, %s);", attrParam, jsonParam, scopeName)); + return new StringHookPoint(String.format("return new de.monticore.symboltable.ClearingMemorizer>(() -> de.monticore.types.check.SymTypeExpressionDeSer.deserializeOptionalMember(\"%s\", %s, %s));", attrParam, jsonParam, scopeName)); } @Override public HookPoint getListDeserialHook(String jsonParam, String attrParam, String scopeName) { - return new StringHookPoint(String.format("return de.monticore.types.check.SymTypeExpressionDeSer.deserializeListMember(\"%s\", %s, %s);", attrParam, jsonParam, scopeName)); + return new StringHookPoint(String.format("return new de.monticore.symboltable.ClearingMemorizer>(() -> de.monticore.types.check.SymTypeExpressionDeSer.deserializeListMember(\"%s\", %s, %s));", attrParam, jsonParam, scopeName)); } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/SymbolDeSerDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/SymbolDeSerDecorator.java index f30037b68e..9567e6c69e 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/SymbolDeSerDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/serialization/SymbolDeSerDecorator.java @@ -211,12 +211,16 @@ protected List createDeserializeAttrMethods( List methodList = new ArrayList<>(); for (ASTCDAttribute attr : attributeList) { String methodName = DESERIALIZE + StringTransformations.capitalize(attr.getName()); + // Deserializers for supplied attributes return a supplier of that type + ASTMCType returnType = getDecorationHelper().shouldHaveSupplier(attr) + ? getDecorationHelper().createStdSupplierTypeOf(attr.getMCType()) + : attr.getMCType(); ASTCDMethod method = getCDMethodFacade() - .createMethod(PROTECTED.build(), attr.getMCType(), methodName, scopeParam, scopeJsonParam); + .createMethod(PROTECTED.build(), returnType, methodName, scopeParam, scopeJsonParam); // create wrapper function offering the deprecated interface // this one does not take the enclosing scope ASTCDMethod wrapperMethod = getCDMethodFacade() - .createMethod(PROTECTED.build(), attr.getMCType(), methodName, scopeJsonParam); + .createMethod(PROTECTED.build(), returnType, methodName, scopeJsonParam); // Check whether built-in serialization exists. If yes, use it and otherwise make method abstract Optional impl = bitser diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecorator.java index 564d447524..085836b045 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecorator.java @@ -74,7 +74,8 @@ public ASTCDClass decorate(final ASTCDClass symbolClass) { defaultAttrs.add(spannedScopeAttr); } } - + // Wrap selected attribute types into Supplier so their (possibly not-yet-resolvable) value can be computed later + getDecorationHelper().wrapAndMarkSuppliers(decoratedSymbolClass.getCDAttributeList()); builderDecorator.setPrintBuildMethodTemplate(false); ASTCDClass symbolBuilder = builderDecorator.decorate(decoratedSymbolClass); builderDecorator.setPrintBuildMethodTemplate(true); diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecorator.java index bbde906e2d..0a3a893573 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecorator.java @@ -90,12 +90,19 @@ public ASTCDClass decorate(ASTCDClass symbolInput) { .filter(attr -> !symbolTableService.isInheritedAttribute(attr)) .map(ASTCDAttribute::deepClone) .collect(Collectors.toList()); + + // Wrap selected symbolrule attribute types into Supplier so their (possibly not-yet-resolvable) value can be computed later + // Als mark them as special case supplier + getDecorationHelper().wrapAndMarkSuppliers(symbolRuleAttributes); + symbolRuleAttributes.forEach(a -> getDecorationHelper().addAttributeDefaultValues(a, this.glex)); List symbolRuleAttributeMethods = symbolRuleAttributes .stream() .map(methodDecorator::decorate) .flatMap(List::stream) .collect(Collectors.toList()); + // the marker type is not needed anymore: the fields store the plain Supplier + getDecorationHelper().unmarkSuppliers(symbolRuleAttributes); List symbolRuleMethods = symbolInput.getCDMethodList().stream() .map(ASTCDMethod::deepClone) .collect(Collectors.toList()); diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/AccessAsSupplierTypes.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/AccessAsSupplierTypes.java new file mode 100644 index 0000000000..d4ab40a942 --- /dev/null +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/AccessAsSupplierTypes.java @@ -0,0 +1,54 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.codegen.cd2java.methods; + +import de.monticore.cdbasis._ast.ASTCDAttribute; + +import java.util.Set; + +/** + * Some attributes in symbolrules must be decorated with a supplier, since they might not be known immediately during the deserialization. + *

+ * This class contains what those types are + */ +public final class AccessAsSupplierTypes { + + /** + * Name of the marker type that tags lazily resolved attributes while the class diagram is decorated. + * There is no implementation. It is only present during decoration. + */ + public static final String SUPPLIER_TYPE = "de.monticore.symboltable.__internal__Supplier"; + + /** + * Fully qualified name of the public supplier type exposed by generated getters and setters. + */ + public static final String STD_SUPPLIER_TYPE = "java.util.function.Supplier"; + + private static final Set SUPPLIED_TYPES = Set.of( + "de.monticore.types.check.SymTypeExpression", + "java.util.List", + "java.util.Optional", + "List", + "Optional", + "SymTypeExpression", + "java.util.List", + "java.util.Optional", + "List", + "Optional" + ); + + private AccessAsSupplierTypes() { + } + + /** + * @param type the printed attribute type + * @return whether an attribute of this type should be wrapped in / accessed via a {@code Supplier} + */ + public static boolean shouldHaveSupplier(String type) { + return SUPPLIED_TYPES.contains(type); + } + + public static boolean shouldHaveSupplier(ASTCDAttribute attribute) { + return shouldHaveSupplier(attribute.printType()); + } + +} diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/ListMethodDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/ListMethodDecorator.java index e193305c0d..4067b939b0 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/ListMethodDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/ListMethodDecorator.java @@ -83,6 +83,12 @@ public String getCapitalizedAttributeNameWithS(ASTCDAttribute attribute) { } public String getAttributeType(ASTCDAttribute attribute) { - return getTypeArgumentFromListType(attribute.getMCType()); + ASTMCType type = attribute.getMCType(); + + if (getDecorationHelper().isSupplier(type)) { + // a wrapped list attribute has the shape Supplier> -> unwrap to List before extracting X + type = getDecorationHelper().unwrapSupplier(type); + } + return getTypeArgumentFromListType(type); } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/SpecificMethodDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/SpecificMethodDecorator.java index a88d4507f7..64e7dcd763 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/SpecificMethodDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/SpecificMethodDecorator.java @@ -5,6 +5,7 @@ import de.monticore.cd4codebasis._ast.ASTCDMethod; import de.monticore.codegen.cd2java.AbstractCreator; import de.monticore.generating.templateengine.GlobalExtensionManagement; +import de.monticore.types.mcbasictypes._ast.ASTMCType; import java.util.List; @@ -47,11 +48,17 @@ public List decorate(final ASTCDAttribute ast) { } protected AbstractCreator> determineMethodDecoratorStrategy(final ASTCDAttribute ast) { - if (getMCTypeFacade().isBooleanType(ast.getMCType())) { + // If the type is wrapped (supplier), unwrap for determination + ASTMCType type = ast.getMCType(); + if (getDecorationHelper().isSupplier(type)) { + type = getDecorationHelper().unwrapSupplier(type); + } + + if (getMCTypeFacade().isBooleanType(type)) { return mandatoryMethodDecorator; - } else if (getDecorationHelper().isListType(ast.printType())) { + } else if (getDecorationHelper().isList(type)) { return listMethodDecorator; - } else if (getDecorationHelper().isOptional(ast.getMCType())) { + } else if (getDecorationHelper().isOptional(type)) { return optionalMethodDecorator; } return mandatoryMethodDecorator; diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/ListAccessorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/ListAccessorDecorator.java index 2c7004272d..6e3ad3f6a0 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/ListAccessorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/ListAccessorDecorator.java @@ -6,11 +6,13 @@ import de.monticore.codegen.cd2java.methods.ListMethodDecorator; import de.monticore.generating.templateengine.GlobalExtensionManagement; import de.monticore.generating.templateengine.TemplateHookPoint; +import de.monticore.types.mcbasictypes._ast.ASTMCType; import java.util.Arrays; import java.util.List; import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY; +import static de.monticore.cd.facade.CDModifier.PUBLIC; public class ListAccessorDecorator extends ListMethodDecorator { @@ -42,6 +44,9 @@ public ListAccessorDecorator(final GlobalExtensionManagement glex) { public List decorate(ASTCDAttribute ast) { List methods = super.decorate(ast); methods.add(createGetListMethod(ast)); + if (getDecorationHelper().isSupplier(ast.getMCType())) { + methods.add(createGetListSupplierMethod(ast)); + } return methods; } @@ -49,10 +54,25 @@ public List decorate(ASTCDAttribute ast) { protected ASTCDMethod createGetListMethod(ASTCDAttribute ast) { String signature = String.format(GET_LIST, attributeType, capitalizedAttributeNameWithOutS); ASTCDMethod getList = this.getCDMethodFacade().createMethodByDefinition(signature); - this.replaceTemplate(EMPTY_BODY, getList, new TemplateHookPoint("methods.Get", ast)); + + String templateName = "methods.Get"; + if (getDecorationHelper().isSupplier(ast.getMCType())) { + templateName = "methods.SupplierGet"; + } + + this.replaceTemplate(EMPTY_BODY, getList, new TemplateHookPoint(templateName, ast)); return getList; } + protected ASTCDMethod createGetListSupplierMethod(ASTCDAttribute ast) { + String name = "get" + capitalizedAttributeNameWithOutS + "ListSupplier"; + ASTMCType supplierType = getDecorationHelper().toPublicSupplierType(ast.getMCType()); + ASTCDMethod method = this.getCDMethodFacade().createMethod( + PUBLIC.build(), supplierType, name); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.SupplierGetRaw", ast)); + return method; + } + @Override protected List getMethodSignatures() { return Arrays.asList( diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/MandatoryAccessorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/MandatoryAccessorDecorator.java index 9c2de169db..98cee06bbc 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/MandatoryAccessorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/MandatoryAccessorDecorator.java @@ -10,7 +10,6 @@ import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import static de.monticore.cd.facade.CDModifier.PUBLIC; @@ -29,7 +28,12 @@ public MandatoryAccessorDecorator(final GlobalExtensionManagement glex) { @Override public List decorate(final ASTCDAttribute ast) { - return new ArrayList<>(Collections.singletonList(createGetter(ast))); + List methods = new ArrayList<>(); + methods.add(createGetter(ast)); + if (getDecorationHelper().isSupplier(ast.getMCType())) { + methods.add(createSupplierGetter(ast)); + } + return methods; } protected ASTCDMethod createGetter(final ASTCDAttribute ast) { @@ -41,8 +45,25 @@ protected ASTCDMethod createGetter(final ASTCDAttribute ast) { } String name = String.format(getterPrefix, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(ast.getName()))); ASTMCType type = ast.getMCType().deepClone(); + + String templateName = "methods.Get"; + if (getDecorationHelper().isSupplier(type)) { + // The Supplier is hidden from the user. The getter has to expose the unwrapped type (Supplier -> X) + type = getDecorationHelper().unwrapSupplier(type); + templateName = "methods.SupplierGet"; + } + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), type, name); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.Get", ast)); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint(templateName, ast)); + return method; + } + + protected ASTCDMethod createSupplierGetter(final ASTCDAttribute ast) { + String name = String.format(GET, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(ast.getName()))) + "Supplier"; + ASTMCType supplierType = getDecorationHelper().toPublicSupplierType(ast.getMCType()); + + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), supplierType, name); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.SupplierGetRaw", ast)); return method; } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/OptionalAccessorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/OptionalAccessorDecorator.java index 508cdd9deb..18e2f5d1fc 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/OptionalAccessorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/accessor/OptionalAccessorDecorator.java @@ -11,7 +11,6 @@ import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import static de.monticore.cd.facade.CDModifier.PUBLIC; @@ -36,9 +35,13 @@ public OptionalAccessorDecorator(final GlobalExtensionManagement glex, @Override public List decorate(final ASTCDAttribute ast) { naiveAttributeName = getNaiveAttributeName(ast); - ASTCDMethod get = createGetMethod(ast); - ASTCDMethod isPresent = createIsPresentMethod(ast); - return new ArrayList<>(Arrays.asList(get, isPresent)); + List methods = new ArrayList<>(); + methods.add(createGetMethod(ast)); + methods.add(createIsPresentMethod(ast)); + if (getDecorationHelper().isSupplier(ast.getMCType())) { + methods.add(createSupplierGetMethod(ast)); + } + return methods; } protected String getNaiveAttributeName(ASTCDAttribute astcdAttribute) { @@ -47,17 +50,39 @@ protected String getNaiveAttributeName(ASTCDAttribute astcdAttribute) { protected ASTCDMethod createGetMethod(final ASTCDAttribute ast) { String name = String.format(GET, naiveAttributeName); - ASTMCType type = getDecorationHelper().getReferenceTypeFromOptional(ast.getMCType().deepClone()).getMCTypeOpt().get(); + + ASTMCType type = ast.getMCType().deepClone(); + String templateName = "methods.opt.Get4Opt"; + if (getDecorationHelper().isSupplier(type)) { + type = getDecorationHelper().unwrapSupplier(type); + templateName = "methods.opt.SupplierGet4Opt"; + } + + type = getDecorationHelper().getReferenceTypeOfOptional(type).getMCTypeOpt().get(); ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), type, name); String generatedErrorCode = service.getGeneratedErrorCode(ast.getName() + ast.printType()); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.opt.Get4Opt", ast, naiveAttributeName, generatedErrorCode)); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint(templateName, ast, naiveAttributeName, generatedErrorCode)); + return method; + } + + protected ASTCDMethod createSupplierGetMethod(final ASTCDAttribute ast) { + String name = String.format(GET, naiveAttributeName) + "Supplier"; + ASTMCType supplierType = getDecorationHelper().toPublicSupplierType(ast.getMCType()); + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), supplierType, name); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.SupplierGetRaw", ast)); return method; } protected ASTCDMethod createIsPresentMethod(final ASTCDAttribute ast) { String name = String.format(IS_PRESENT, naiveAttributeName); ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), getMCTypeFacade().createBooleanType(), name); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.opt.IsPresent4Opt", ast)); + + String templateName = "methods.opt.IsPresent4Opt"; + if (getDecorationHelper().isSupplier(ast.getMCType())) { + templateName = "methods.opt.SupplierIsPresent4Opt"; + } + + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint(templateName, ast)); return method; } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/ListMutatorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/ListMutatorDecorator.java index 603a983390..840048a2ce 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/ListMutatorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/ListMutatorDecorator.java @@ -1,16 +1,19 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.codegen.cd2java.methods.mutator; +import de.monticore.cd4codebasis._ast.ASTCDParameter; import de.monticore.cdbasis._ast.ASTCDAttribute; import de.monticore.cd4codebasis._ast.ASTCDMethod; import de.monticore.codegen.cd2java.methods.ListMethodDecorator; import de.monticore.generating.templateengine.GlobalExtensionManagement; import de.monticore.generating.templateengine.TemplateHookPoint; +import de.monticore.types.mcbasictypes._ast.ASTMCType; import java.util.Arrays; import java.util.List; import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY; +import static de.monticore.cd.facade.CDModifier.PUBLIC; public class ListMutatorDecorator extends ListMethodDecorator { @@ -38,16 +41,35 @@ public ListMutatorDecorator(final GlobalExtensionManagement glex) { public List decorate(ASTCDAttribute ast) { List methods = createSetter(ast); methods.add(createSetListMethod(ast)); + if (getDecorationHelper().isSupplier(ast.getMCType())) { + methods.add(createSetListSupplierMethod(ast)); + } return methods; } protected ASTCDMethod createSetListMethod(ASTCDAttribute ast) { String signature = String.format(SET_LIST, capitalizedAttributeNameWithOutS, attributeType, ast.getName()); ASTCDMethod getList = this.getCDMethodFacade().createMethodByDefinition(signature); - this.replaceTemplate(EMPTY_BODY, getList, new TemplateHookPoint("methods.Set", ast)); + + String templateName = "methods.Set"; + if (getDecorationHelper().isSupplier(ast.getMCType())) { + templateName = "methods.SupplierSet"; + } + + this.replaceTemplate(EMPTY_BODY, getList, new TemplateHookPoint(templateName, ast)); return getList; } + protected ASTCDMethod createSetListSupplierMethod(ASTCDAttribute ast) { + String name = "set" + capitalizedAttributeNameWithOutS + "ListSupplier"; + ASTMCType supplierType = getDecorationHelper().toPublicSupplierType(ast.getMCType()); + ASTCDParameter parameter = + this.getCDParameterFacade().createParameter(supplierType, ast.getName()); + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, parameter); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.SupplierSetRaw", ast)); + return method; + } + protected List createSetter(ASTCDAttribute ast){ return super.decorate(ast); } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/MandatoryMutatorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/MandatoryMutatorDecorator.java index 903fdd5c48..cb10708529 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/MandatoryMutatorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/MandatoryMutatorDecorator.java @@ -25,13 +25,37 @@ public MandatoryMutatorDecorator(final GlobalExtensionManagement glex) { @Override public List decorate(final ASTCDAttribute ast) { - return new ArrayList<>(Collections.singletonList(createSetter(ast))); + List methods = new ArrayList<>(Collections.singletonList(createSetter(ast))); + if (getDecorationHelper().isSupplier(ast.getMCType())) { + methods.add(createSupplierSetter(ast)); + } + return methods; } protected ASTCDMethod createSetter(final ASTCDAttribute ast) { - String name = String.format(SET, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(ast.getName()))); - ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, this.getCDParameterFacade().createParameters(ast)); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.Set", ast)); + ASTCDAttribute attribute = ast; + String templateName = "methods.Set"; + if (getDecorationHelper().isSupplier(ast.getMCType())) { + // expose the unwrapped type (Supplier -> X) in the setter parameter; the Supplier stays hidden + attribute = ast.deepClone(); + attribute.setMCType(getDecorationHelper().unwrapSupplier(attribute.getMCType())); + templateName = "methods.SupplierSet"; + } + + String name = String.format(SET, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(attribute.getName()))); + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, this.getCDParameterFacade().createParameters(attribute)); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint(templateName, ast)); + return method; + } + + + protected ASTCDMethod createSupplierSetter(final ASTCDAttribute ast) { + ASTCDAttribute attribute = ast.deepClone(); + attribute.setMCType(getDecorationHelper().toPublicSupplierType(ast.getMCType())); + + String name = String.format(SET, StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(attribute.getName()))) + "Supplier"; + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, this.getCDParameterFacade().createParameters(attribute)); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.SupplierSetRaw", ast)); return method; } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/OptionalMutatorDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/OptionalMutatorDecorator.java index a11baf943a..12fa4d6d74 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/OptionalMutatorDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/methods/mutator/OptionalMutatorDecorator.java @@ -34,22 +34,48 @@ public List decorate(final ASTCDAttribute ast) { naiveAttributeName = StringUtils.capitalize(getDecorationHelper().getNativeAttributeName(ast.getName())); methodList.add(createSetMethod(ast)); methodList.add(createSetAbsentMethod(ast)); + if (getDecorationHelper().isSupplier(ast.getMCType())) { + methodList.add(createSupplierSetMethod(ast)); + } return methodList; } protected ASTCDMethod createSetMethod(final ASTCDAttribute ast) { String name = String.format(SET, naiveAttributeName); - ASTMCType parameterType = getDecorationHelper().getReferenceTypeFromOptional(ast.getMCType()).getMCTypeOpt().get().deepClone(); - ASTCDParameter parameter = this.getCDParameterFacade().createParameter(parameterType, ast.getName()); + + ASTMCType type = ast.getMCType().deepClone(); + String templateName = "methods.opt.Set4Opt"; + if (getDecorationHelper().isSupplier(type)) { + type = getDecorationHelper().unwrapSupplier(type); + templateName = "methods.opt.SupplierSet4Opt"; + } + + type = getDecorationHelper().getReferenceTypeOfOptional(type).getMCTypeOpt().get().deepClone(); + ASTCDParameter parameter = this.getCDParameterFacade().createParameter(type, ast.getName()); + ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, parameter); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint(templateName, ast, naiveAttributeName)); + return method; + } + + protected ASTCDMethod createSupplierSetMethod(final ASTCDAttribute ast) { + String name = String.format(SET, naiveAttributeName) + "Supplier"; + ASTMCType supplierType = getDecorationHelper().toPublicSupplierType(ast.getMCType()); + ASTCDParameter parameter = this.getCDParameterFacade().createParameter(supplierType, ast.getName()); ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name, parameter); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.opt.Set4Opt", ast, naiveAttributeName)); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.SupplierSetRaw", ast)); return method; } protected ASTCDMethod createSetAbsentMethod(final ASTCDAttribute ast) { String name = String.format(SET_ABSENT, naiveAttributeName); ASTCDMethod method = this.getCDMethodFacade().createMethod(PUBLIC.build(), name); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("methods.opt.SetAbsent", ast)); + + String templateName = "methods.opt.SetAbsent"; + if (getDecorationHelper().isSupplier(ast.getMCType())) { + templateName = "methods.opt.SupplierSetAbsent"; + } + + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint(templateName, ast)); return method; } } diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/typedispatcher/TypeDispatcherDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/typedispatcher/TypeDispatcherDecorator.java index 1d21f6dc02..75b434c285 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/typedispatcher/TypeDispatcherDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/typedispatcher/TypeDispatcherDecorator.java @@ -15,11 +15,11 @@ import de.monticore.generating.templateengine.StringHookPoint; import de.monticore.generating.templateengine.TemplateHookPoint; import de.monticore.symbols.basicsymbols._symboltable.DiagramSymbol; -import de.monticore.symbols.basicsymbols._symboltable.TypeSymbolSurrogate; import de.monticore.types.MCTypeFacade; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY; @@ -254,8 +254,9 @@ protected List createHandleMethods(List attributeNam protected List getSuperTypes(CDTypeSymbol typeSymbol) { return typeSymbol.getSuperTypesList() .stream() - .filter(s -> ((TypeSymbolSurrogate) s.getTypeInfo()).checkLazyLoadDelegate()) - .map(s -> ((TypeSymbolSurrogate) s.getTypeInfo()).lazyLoadDelegate()) + .map(visitorService::resolveTypeInfo) + .filter(Optional::isPresent) + .map(Optional::get) .filter(t -> t instanceof CDTypeSymbol) .map(s -> visitorService.createASTFullName((CDTypeSymbol) s)) .collect(Collectors.toList()); diff --git a/monticore-generator/src/main/resources/_ast/builder/SupplierSet4ASTBuilder.ftl b/monticore-generator/src/main/resources/_ast/builder/SupplierSet4ASTBuilder.ftl new file mode 100644 index 0000000000..6661b8d21b --- /dev/null +++ b/monticore-generator/src/main/resources/_ast/builder/SupplierSet4ASTBuilder.ftl @@ -0,0 +1,6 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute")} +${defineHookPoint("Setter:Before")} +this.${attribute.getName()} = () -> ${attribute.getName()}; +${defineHookPoint("Setter:After")} +return this.realBuilder; diff --git a/monticore-generator/src/main/resources/_ast/builder/SupplierSetRaw4ASTBuilder.ftl b/monticore-generator/src/main/resources/_ast/builder/SupplierSetRaw4ASTBuilder.ftl new file mode 100644 index 0000000000..da71c5ff49 --- /dev/null +++ b/monticore-generator/src/main/resources/_ast/builder/SupplierSetRaw4ASTBuilder.ftl @@ -0,0 +1,6 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute")} +${defineHookPoint("Setter:Before")} +this.${attribute.getName()} = ${attribute.getName()}; +${defineHookPoint("Setter:After")} +return this.realBuilder; diff --git a/monticore-generator/src/main/resources/_ast/builder/opt/SupplierSet4ASTBuilderOpt.ftl b/monticore-generator/src/main/resources/_ast/builder/opt/SupplierSet4ASTBuilderOpt.ftl new file mode 100644 index 0000000000..f0a086e4ce --- /dev/null +++ b/monticore-generator/src/main/resources/_ast/builder/opt/SupplierSet4ASTBuilderOpt.ftl @@ -0,0 +1,4 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute")} +this.${attribute.getName()} = () -> Optional.ofNullable(${attribute.getName()}); +return this.realBuilder; diff --git a/monticore-generator/src/main/resources/_ast/builder/opt/SupplierSetAbsent4ASTBuilderOpt.ftl b/monticore-generator/src/main/resources/_ast/builder/opt/SupplierSetAbsent4ASTBuilderOpt.ftl new file mode 100644 index 0000000000..5e1df9d0ed --- /dev/null +++ b/monticore-generator/src/main/resources/_ast/builder/opt/SupplierSetAbsent4ASTBuilderOpt.ftl @@ -0,0 +1,4 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute")} +this.${attribute.getName()} = () -> Optional.empty(); +return this.realBuilder; diff --git a/monticore-generator/src/main/resources/_symboltable/serialization/scopeDeSer/DeserializeArtifactScope.ftl b/monticore-generator/src/main/resources/_symboltable/serialization/scopeDeSer/DeserializeArtifactScope.ftl index 07ef78215f..70790c07b4 100644 --- a/monticore-generator/src/main/resources/_symboltable/serialization/scopeDeSer/DeserializeArtifactScope.ftl +++ b/monticore-generator/src/main/resources/_symboltable/serialization/scopeDeSer/DeserializeArtifactScope.ftl @@ -9,15 +9,18 @@ ${tc.signature("symTabMill", "artifactScope", "scopeRuleAttrList")} scope.setExportingSymbols(true); <#list scopeRuleAttrList as attr> - <#if genHelper.isOptional(attr.getMCType())> + <#assign setter = genHelper.getPlainSetter(attr)> + <#if genHelper.shouldHaveSupplier(attr)> + scope.${setter}Supplier(deserialize${attr.getName()?cap_first}(scope, scopeJson)); + <#elseif genHelper.isOptional(attr.getMCType())> ${attr.printType()} _${attr.getName()} = deserialize${attr.getName()?cap_first}(scope, scopeJson); if (_${attr.getName()}.isPresent()) { - scope.${genHelper.getPlainSetter(attr)}(_${attr.getName()}.get()); + scope.${setter}(_${attr.getName()}.get()); } else { - scope.${genHelper.getPlainSetter(attr)}Absent(); + scope.${setter}Absent(); } <#else> - scope.${genHelper.getPlainSetter(attr)}(deserialize${attr.getName()?cap_first}(scope, scopeJson)); + scope.${setter}(deserialize${attr.getName()?cap_first}(scope, scopeJson)); diff --git a/monticore-generator/src/main/resources/_symboltable/serialization/scopeDeSer/DeserializeScope.ftl b/monticore-generator/src/main/resources/_symboltable/serialization/scopeDeSer/DeserializeScope.ftl index 2edbddd61f..1d967dd612 100644 --- a/monticore-generator/src/main/resources/_symboltable/serialization/scopeDeSer/DeserializeScope.ftl +++ b/monticore-generator/src/main/resources/_symboltable/serialization/scopeDeSer/DeserializeScope.ftl @@ -9,15 +9,18 @@ ${tc.signature("symTabMill", "scopeClass", "scopeRuleAttrList")} scope.setExportingSymbols(true); <#list scopeRuleAttrList as attr> - <#if genHelper.isOptional(attr.getMCType())> + <#assign setter = genHelper.getPlainSetter(attr)> + <#if genHelper.shouldHaveSupplier(attr)> + scope.${setter}Supplier(deserialize${attr.getName()?cap_first}(scope, scopeJson)); + <#elseif genHelper.isOptional(attr.getMCType())> ${attr.printType()} _${attr.getName()} = deserialize${attr.getName()?cap_first}(scope, scopeJson); if (_${attr.getName()}.isPresent()) { - scope.${genHelper.getPlainSetter(attr)}(_${attr.getName()}.get()); + scope.${setter}(_${attr.getName()}.get()); } else { - scope.${genHelper.getPlainSetter(attr)}Absent(); + scope.${setter}Absent(); } <#else> - scope.${genHelper.getPlainSetter(attr)}(deserialize${attr.getName()?cap_first}(scope, scopeJson)); + scope.${setter}(deserialize${attr.getName()?cap_first}(scope, scopeJson)); diff --git a/monticore-generator/src/main/resources/_symboltable/serialization/symbolDeSer/Deserialize4SymbolDeSer.ftl b/monticore-generator/src/main/resources/_symboltable/serialization/symbolDeSer/Deserialize4SymbolDeSer.ftl index dd739b6960..1a20fa832b 100644 --- a/monticore-generator/src/main/resources/_symboltable/serialization/symbolDeSer/Deserialize4SymbolDeSer.ftl +++ b/monticore-generator/src/main/resources/_symboltable/serialization/symbolDeSer/Deserialize4SymbolDeSer.ftl @@ -21,14 +21,16 @@ ${tc.signature("symTabMill", "symbolFullName", "symbolSimpleName","symbolRuleAtt } <#list symbolRuleAttribute as attr> - <#if genHelper.isOptional(attr.getMCType())> - if (deserialize${attr.getName()?cap_first}(symbolJson).isPresent()) { - builder.${genHelper.getPlainSetter(attr)}(deserialize${attr.getName()?cap_first}(scope, symbolJson).get()); - } else { - builder.${genHelper.getPlainSetter(attr)}Absent(); - } + <#if genHelper.shouldHaveSupplier(attr)> + builder.${genHelper.getPlainSetter(attr)}Supplier(deserialize${attr.getName()?cap_first}(scope, symbolJson)); + <#elseif genHelper.isOptional(attr.getMCType())> + if (deserialize${attr.getName()?cap_first}(symbolJson).isPresent()) { + builder.${genHelper.getPlainSetter(attr)}(deserialize${attr.getName()?cap_first}(scope, symbolJson).get()); + } else { + builder.${genHelper.getPlainSetter(attr)}Absent(); + } <#else> - builder.${genHelper.getPlainSetter(attr)}(deserialize${attr.getName()?cap_first}(scope, symbolJson)); + builder.${genHelper.getPlainSetter(attr)}(deserialize${attr.getName()?cap_first}(scope, symbolJson)); diff --git a/monticore-generator/src/main/resources/_symboltable/symbol/BuildSymbol.ftl b/monticore-generator/src/main/resources/_symboltable/symbol/BuildSymbol.ftl index a874441c5b..a58f3cfff6 100644 --- a/monticore-generator/src/main/resources/_symboltable/symbol/BuildSymbol.ftl +++ b/monticore-generator/src/main/resources/_symboltable/symbol/BuildSymbol.ftl @@ -3,15 +3,18 @@ ${tc.signature("symbolClassName", "attributes")} <#assign genHelper = glex.getGlobalVar("astHelper")> ${symbolClassName} symbol = new ${symbolClassName}(name); <#list attributes as attribute> -<#assign setter = genHelper.getPlainSetter(attribute)> -<#if genHelper.isOptional(attribute.getMCType())> - if (this.${attribute.getName()}.isPresent()) { - symbol.${setter}(this.${attribute.getName()}.get()); - } else { - symbol.${setter}Absent(); - } -<#else> - symbol.${setter}(this.${attribute.getName()}); - + <#assign setter = genHelper.getPlainSetter(attribute)> + <#if genHelper.isSupplier(attribute.getMCType())> + <#assign getter = genHelper.getPlainGetter(attribute)> + symbol.${setter}Supplier(this.${getter}Supplier()); + <#elseif genHelper.isOptional(attribute.getMCType())> + if (this.${attribute.getName()}.isPresent()) { + symbol.${setter}(this.${attribute.getName()}.get()); + } else { + symbol.${setter}Absent(); + } + <#else> + symbol.${setter}(this.${attribute.getName()}); + return symbol; diff --git a/monticore-generator/src/main/resources/data/DeepCloneWithParameters.ftl b/monticore-generator/src/main/resources/data/DeepCloneWithParameters.ftl index 078cad0d68..a63c8fc1a4 100644 --- a/monticore-generator/src/main/resources/data/DeepCloneWithParameters.ftl +++ b/monticore-generator/src/main/resources/data/DeepCloneWithParameters.ftl @@ -27,7 +27,7 @@ ${tc.signature("attributeList", "hasSuperClass")} <#elseif genHelper.isPrimitive(attrType)> result.set${methName}(${genHelper.getPlainGetter(attribute)}()); <#elseif genHelper.isOptional(attribute.getMCType())> - <#assign reference = genHelper.getReferenceTypeFromOptional(attrType)> + <#assign reference = genHelper.getReferenceTypeOfOptional(attrType)> <#assign referenceName = typeName> <#if genHelper.isString(reference) || genHelper.isAttributeOfTypeEnum(attribute)> if (isPresent${methName}()) { diff --git a/monticore-generator/src/main/resources/methods/SupplierGet.ftl b/monticore-generator/src/main/resources/methods/SupplierGet.ftl new file mode 100644 index 0000000000..e09f4bc2d6 --- /dev/null +++ b/monticore-generator/src/main/resources/methods/SupplierGet.ftl @@ -0,0 +1,7 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute")} +var value = this.${attribute.getName()}.get(); +if (value == null) { + Log.info("Value of '${attribute.getName()}' is not available yet.", "get${attribute.getName()}"); +} +return value; diff --git a/monticore-generator/src/main/resources/methods/SupplierGetRaw.ftl b/monticore-generator/src/main/resources/methods/SupplierGetRaw.ftl new file mode 100644 index 0000000000..1f1de2a52a --- /dev/null +++ b/monticore-generator/src/main/resources/methods/SupplierGetRaw.ftl @@ -0,0 +1,3 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute")} +return this.${attribute.getName()}; diff --git a/monticore-generator/src/main/resources/methods/SupplierSet.ftl b/monticore-generator/src/main/resources/methods/SupplierSet.ftl new file mode 100644 index 0000000000..41e8259e86 --- /dev/null +++ b/monticore-generator/src/main/resources/methods/SupplierSet.ftl @@ -0,0 +1,5 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute")} +${defineHookPoint("Setter:Before")} +this.${attribute.getName()} = () -> ${attribute.getName()}; +${defineHookPoint("Setter:After")} diff --git a/monticore-generator/src/main/resources/methods/SupplierSetRaw.ftl b/monticore-generator/src/main/resources/methods/SupplierSetRaw.ftl new file mode 100644 index 0000000000..04c99af220 --- /dev/null +++ b/monticore-generator/src/main/resources/methods/SupplierSetRaw.ftl @@ -0,0 +1,5 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute")} +${defineHookPoint("Setter:Before")} +this.${attribute.getName()} = ${attribute.getName()}; +${defineHookPoint("Setter:After")} diff --git a/monticore-generator/src/main/resources/methods/opt/SupplierGet4Opt.ftl b/monticore-generator/src/main/resources/methods/opt/SupplierGet4Opt.ftl new file mode 100644 index 0000000000..5c78414743 --- /dev/null +++ b/monticore-generator/src/main/resources/methods/opt/SupplierGet4Opt.ftl @@ -0,0 +1,7 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute", "naiveAttributeName", "generatedErrorCode")} + if (isPresent${naiveAttributeName}()) { + return this.${attribute.getName()}.get().get(); + } + Log.info("0xA7003${generatedErrorCode} get for ${naiveAttributeName} can't return a value. Attribute is empty.", "get${attribute.getName()}"); + return null; diff --git a/monticore-generator/src/main/resources/methods/opt/SupplierIsPresent4Opt.ftl b/monticore-generator/src/main/resources/methods/opt/SupplierIsPresent4Opt.ftl new file mode 100644 index 0000000000..2167c5d80d --- /dev/null +++ b/monticore-generator/src/main/resources/methods/opt/SupplierIsPresent4Opt.ftl @@ -0,0 +1,8 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute")} +var optional = this.${attribute.getName()}.get(); +if (optional == null){ + Log.info("supplier for ${attribute.getName()} is null", "isPresent${attribute.getName()}"); + return false; +} +return optional.isPresent(); diff --git a/monticore-generator/src/main/resources/methods/opt/SupplierSet4Opt.ftl b/monticore-generator/src/main/resources/methods/opt/SupplierSet4Opt.ftl new file mode 100644 index 0000000000..69d9a84eed --- /dev/null +++ b/monticore-generator/src/main/resources/methods/opt/SupplierSet4Opt.ftl @@ -0,0 +1,5 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute", "nativeAttributeName")} +${defineHookPoint("Setter:Before")} +this.${attribute.getName()} = () -> Optional.ofNullable(${attribute.getName()}); +${defineHookPoint("Setter:After")} diff --git a/monticore-generator/src/main/resources/methods/opt/SupplierSetAbsent.ftl b/monticore-generator/src/main/resources/methods/opt/SupplierSetAbsent.ftl new file mode 100644 index 0000000000..9a899540ca --- /dev/null +++ b/monticore-generator/src/main/resources/methods/opt/SupplierSetAbsent.ftl @@ -0,0 +1,5 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("attribute")} +${defineHookPoint("Setter:Before")} +this.${attribute.getName()} = () -> Optional.empty(); +${defineHookPoint("Setter:After")} diff --git a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeClassDecoratorTest.java b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeClassDecoratorTest.java index 65751a1315..d74c5c1eea 100644 --- a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeClassDecoratorTest.java +++ b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/scope/ScopeClassDecoratorTest.java @@ -13,12 +13,15 @@ import de.monticore.cdbasis._ast.ASTCDClass; import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.codegen.cd2java.AbstractService; +import de.monticore.codegen.cd2java.DecorationHelper; import de.monticore.codegen.cd2java.DecoratorTestCase; import de.monticore.codegen.cd2java._symboltable.SymbolTableService; import de.monticore.codegen.cd2java._visitor.VisitorService; +import de.monticore.codegen.cd2java.methods.AccessAsSupplierTypes; import de.monticore.codegen.cd2java.methods.MethodDecorator; import de.monticore.generating.GeneratorEngine; import de.monticore.generating.GeneratorSetup; +import de.monticore.types.mcbasictypes._ast.ASTMCType; import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -35,6 +38,7 @@ import static de.monticore.codegen.cd2java.DecoratorAssert.assertOptionalOf; import static de.monticore.codegen.cd2java.DecoratorAssert.assertVoid; import static de.monticore.codegen.cd2java.DecoratorTestUtil.getAttributeBy; +import static de.monticore.codegen.cd2java.DecoratorTestUtil.getClassBy; import static de.monticore.codegen.cd2java.DecoratorTestUtil.getMethodBy; import static de.monticore.codegen.cd2java.DecoratorTestUtil.getMethodsBy; import static org.junit.jupiter.api.Assertions.*; @@ -43,8 +47,12 @@ public class ScopeClassDecoratorTest extends DecoratorTestCase { private ASTCDClass scopeClass; + private ASTCDClass originalScopeRuleClass; + private de.monticore.types.MCTypeFacade mcTypeFacade; + private static final String SYM_TYPE_EXPRESSION = "de.monticore.types.check.SymTypeExpression"; + private ASTCDCompilationUnit decoratedSymbolCompilationUnit; private ASTCDCompilationUnit decoratedScopeCompilationUnit; @@ -87,6 +95,7 @@ public void setUp() { ASTCDCompilationUnit astcdCompilationUnit = this.parse("de", "monticore", "codegen", "symboltable", "Automaton"); decoratedSymbolCompilationUnit = this.parse("de", "monticore", "codegen", "symboltable", "AutomatonSymbolCD"); decoratedScopeCompilationUnit = this.parse("de", "monticore", "codegen", "symboltable", "AutomatonScopeCD"); + originalScopeRuleClass = getClassBy("AutomatonScope", decoratedScopeCompilationUnit); originalCompilationUnit = decoratedSymbolCompilationUnit.deepClone(); this.glex.setGlobalValue("service", new AbstractService(astcdCompilationUnit)); @@ -208,7 +217,7 @@ public void testShadowingAndEnclosingScopeConstructor() { @Test public void testAttributeCount() { - assertEquals(21, scopeClass.getCDAttributeList().size()); + assertEquals(24, scopeClass.getCDAttributeList().size()); } @Test @@ -361,22 +370,163 @@ public void testScopeRuleAttributes() { ASTCDAttribute fooAttribute = getAttributeBy("foo", scopeClass); assertDeepEquals(PROTECTED, fooAttribute.getModifier()); assertListOf(String.class, fooAttribute.getMCType()); + assertFalse(AccessAsSupplierTypes.shouldHaveSupplier(fooAttribute)); ASTCDAttribute blaAttribute = getAttributeBy("bla", scopeClass); assertDeepEquals(PROTECTED, blaAttribute.getModifier()); assertOptionalOf(Integer.class, blaAttribute.getMCType()); + assertFalse(AccessAsSupplierTypes.shouldHaveSupplier(blaAttribute)); ASTCDAttribute extraAtt = getAttributeBy("extraAttribute", scopeClass); assertDeepEquals(PROTECTED, extraAtt.getModifier()); assertBoolean(extraAtt.getMCType()); - + assertFalse(AccessAsSupplierTypes.shouldHaveSupplier(extraAtt)); + + // symType, lSymType and oSymType are of the types listed in AccessAsSupplierTypes, so they are stored as + // plain java.util.function.Supplier. + ASTCDAttribute originalSymTypeAttribute = getAttributeBy("symType", originalScopeRuleClass); + assertTrue(AccessAsSupplierTypes.shouldHaveSupplier(originalSymTypeAttribute)); + ASTCDAttribute symTypeAttribute = getAttributeBy("symType", scopeClass); + assertDeepEquals(PROTECTED, symTypeAttribute.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(originalSymTypeAttribute.getMCType()), + symTypeAttribute.getMCType()); + + ASTCDAttribute originalLSymTypeAttribute = getAttributeBy("lSymType", originalScopeRuleClass); + assertTrue(AccessAsSupplierTypes.shouldHaveSupplier(originalLSymTypeAttribute)); + ASTCDAttribute lSymTypeAttribute = getAttributeBy("lSymType", scopeClass); + assertDeepEquals(PROTECTED, lSymTypeAttribute.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(originalLSymTypeAttribute.getMCType()), + lSymTypeAttribute.getMCType()); + + ASTCDAttribute originalOSymTypeAttribute = getAttributeBy("oSymType", originalScopeRuleClass); + assertTrue(AccessAsSupplierTypes.shouldHaveSupplier(originalOSymTypeAttribute)); + ASTCDAttribute oSymTypeAttribute = getAttributeBy("oSymType", scopeClass); + assertDeepEquals(PROTECTED, oSymTypeAttribute.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(originalOSymTypeAttribute.getMCType()), + oSymTypeAttribute.getMCType()); + + assertTrue(Log.getFindings().isEmpty()); + } + + + // getters/setters that have to be Supplier-wrapped (see AccessAsSupplierTypes) + // get additional fields, allowing to both set/get the Supplier itself and to set/get the value directly + + @Test + public void testSymTypeScopeRuleMethods() { + ASTMCType symTypeType = getAttributeBy("symType", originalScopeRuleClass).getMCType(); + + ASTCDMethod getter = getMethodBy("getSymType", scopeClass); + assertDeepEquals(PUBLIC, getter.getModifier()); + assertDeepEquals(symTypeType, getter.getMCReturnType().getMCType()); + assertTrue(getter.isEmptyCDParameters()); + + ASTCDMethod setter = getMethodBy("setSymType", scopeClass); + assertDeepEquals(PUBLIC, setter.getModifier()); + assertTrue(setter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, setter.sizeCDParameters()); + assertDeepEquals(symTypeType, setter.getCDParameter(0).getMCType()); + assertEquals("symType", setter.getCDParameter(0).getName()); + + ASTCDMethod supplierGetter = getMethodBy("getSymTypeSupplier", scopeClass); + assertDeepEquals(PUBLIC, supplierGetter.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(symTypeType), supplierGetter.getMCReturnType().getMCType()); + assertTrue(supplierGetter.isEmptyCDParameters()); + + ASTCDMethod supplierSetter = getMethodBy("setSymTypeSupplier", scopeClass); + assertDeepEquals(PUBLIC, supplierSetter.getModifier()); + assertTrue(supplierSetter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, supplierSetter.sizeCDParameters()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(symTypeType), supplierSetter.getCDParameter(0).getMCType()); + assertEquals("symType", supplierSetter.getCDParameter(0).getName()); + + assertTrue(Log.getFindings().isEmpty()); + } + + @Test + public void testLSymTypeScopeRuleMethods() { + ASTMCType lSymTypeType = getAttributeBy("lSymType", originalScopeRuleClass).getMCType(); + + ASTCDMethod getter = getMethodBy("getLSymTypeList", scopeClass); + assertDeepEquals(PUBLIC, getter.getModifier()); + assertListOf(SYM_TYPE_EXPRESSION, getter.getMCReturnType().getMCType()); + assertTrue(getter.isEmptyCDParameters()); + + ASTCDMethod setter = getMethodBy("setLSymTypeList", scopeClass); + assertDeepEquals(PUBLIC, setter.getModifier()); + assertTrue(setter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, setter.sizeCDParameters()); + assertListOf(SYM_TYPE_EXPRESSION, setter.getCDParameter(0).getMCType()); + assertEquals("lSymType", setter.getCDParameter(0).getName()); + + ASTCDMethod supplierGetter = getMethodBy("getLSymTypeListSupplier", scopeClass); + assertDeepEquals(PUBLIC, supplierGetter.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(lSymTypeType), supplierGetter.getMCReturnType().getMCType()); + assertTrue(supplierGetter.isEmptyCDParameters()); + + ASTCDMethod supplierSetter = getMethodBy("setLSymTypeListSupplier", scopeClass); + assertDeepEquals(PUBLIC, supplierSetter.getModifier()); + assertTrue(supplierSetter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, supplierSetter.sizeCDParameters()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(lSymTypeType), supplierSetter.getCDParameter(0).getMCType()); + assertEquals("lSymType", supplierSetter.getCDParameter(0).getName()); + + assertTrue(Log.getFindings().isEmpty()); + } + + @Test + public void testOSymTypeScopeRuleMethods() { + ASTCDAttribute originalOSymTypeAttribute = getAttributeBy("oSymType", originalScopeRuleClass); + ASTMCType oSymTypeType = originalOSymTypeAttribute.getMCType(); + ASTMCType innerType = DecorationHelper.getInstance().getReferenceTypeOfOptional(oSymTypeType).getMCTypeOpt().get(); + + ASTCDMethod getter = getMethodBy("getOSymType", scopeClass); + assertDeepEquals(PUBLIC, getter.getModifier()); + assertDeepEquals(innerType, getter.getMCReturnType().getMCType()); + assertTrue(getter.isEmptyCDParameters()); + + ASTCDMethod isPresent = getMethodBy("isPresentOSymType", scopeClass); + assertDeepEquals(PUBLIC, isPresent.getModifier()); + assertBoolean(isPresent.getMCReturnType().getMCType()); + assertTrue(isPresent.isEmptyCDParameters()); + + ASTCDMethod setter = getMethodBy("setOSymType", scopeClass); + assertDeepEquals(PUBLIC, setter.getModifier()); + assertTrue(setter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, setter.sizeCDParameters()); + assertDeepEquals(innerType, setter.getCDParameter(0).getMCType()); + assertEquals("oSymType", setter.getCDParameter(0).getName()); + + ASTCDMethod setAbsent = getMethodBy("setOSymTypeAbsent", scopeClass); + assertDeepEquals(PUBLIC, setAbsent.getModifier()); + assertTrue(setAbsent.getMCReturnType().isPresentMCVoidType()); + assertTrue(setAbsent.isEmptyCDParameters()); + + ASTCDMethod supplierGetter = getMethodBy("getOSymTypeSupplier", scopeClass); + assertDeepEquals(PUBLIC, supplierGetter.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(oSymTypeType), supplierGetter.getMCReturnType().getMCType()); + assertTrue(supplierGetter.isEmptyCDParameters()); + + ASTCDMethod supplierSetter = getMethodBy("setOSymTypeSupplier", scopeClass); + assertDeepEquals(PUBLIC, supplierSetter.getModifier()); + assertTrue(supplierSetter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, supplierSetter.sizeCDParameters()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(oSymTypeType), supplierSetter.getCDParameter(0).getMCType()); + assertEquals("oSymType", supplierSetter.getCDParameter(0).getName()); + assertTrue(Log.getFindings().isEmpty()); } @Test public void testMethodCount() { - assertEquals(104, scopeClass.getCDMethodList().size()); - + // previously here: =104 + // added because of supplied fields + // symType (mandatory): get+getSupplier, set+setSupplier = 4 + // lSymType (list): 18 delegate + getList + getListSupplier = 20 + // 14 delegate + setList + setListSupplier = 16 + // oSymType (optional): get+isPresent+getSupplier, set+setAbsent+setSupplier = 6 + assertEquals(104 + 4 + 20 + 16 + 6, scopeClass.getCDMethodList().size()); + assertTrue(Log.getFindings().isEmpty()); } diff --git a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecoratorTest.java b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecoratorTest.java index 650a4a5302..4fa23c6536 100644 --- a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecoratorTest.java +++ b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolBuilderDecoratorTest.java @@ -13,6 +13,7 @@ import de.monticore.cdbasis._ast.ASTCDClass; import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.codegen.cd2java.AbstractService; +import de.monticore.codegen.cd2java.DecorationHelper; import de.monticore.codegen.cd2java.DecoratorTestCase; import de.monticore.codegen.cd2java._ast.builder.BuilderDecorator; import de.monticore.codegen.cd2java._symboltable.SymbolTableService; @@ -20,6 +21,7 @@ import de.monticore.generating.GeneratorEngine; import de.monticore.generating.GeneratorSetup; import de.monticore.types.MCTypeFacade; +import de.monticore.types.mcbasictypes._ast.ASTMCType; import de.se_rwth.commons.logging.Log; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -27,6 +29,7 @@ import static de.monticore.cd.facade.CDModifier.PUBLIC; import static de.monticore.codegen.cd2java.DecoratorAssert.assertBoolean; import static de.monticore.codegen.cd2java.DecoratorAssert.assertDeepEquals; +import static de.monticore.codegen.cd2java.DecoratorAssert.assertListOf; import static de.monticore.codegen.cd2java.DecoratorTestUtil.getAttributeBy; import static de.monticore.codegen.cd2java.DecoratorTestUtil.getClassBy; import static de.monticore.codegen.cd2java.DecoratorTestUtil.getMethodBy; @@ -34,10 +37,14 @@ public class SymbolBuilderDecoratorTest extends DecoratorTestCase { + private ASTCDClass cdClass; + private ASTCDClass builderClass; private MCTypeFacade mcTypeFacade; + private static final String SYM_TYPE_EXPRESSION = "de.monticore.types.check.SymTypeExpression"; + private static final String ENCLOSING_SCOPE_TYPE = "de.monticore.codegen.symboltable.cdforbuilder.symbol_builder._symboltable.ISymbol_BuilderScope"; private static final String A_NODE_TYPE_OPT = "Optional"; @@ -55,7 +62,7 @@ public void setup() { this.mcTypeFacade = MCTypeFacade.getInstance(); ASTCDCompilationUnit ast = parse("de", "monticore", "codegen", "symboltable","cdForBuilder", "Symbol_Builder"); - ASTCDClass cdClass = getClassBy("A", ast); + cdClass = getClassBy("A", ast); this.glex.setGlobalValue("service", new AbstractService(ast)); AccessorDecorator methodDecorator = new AccessorDecorator(glex, new SymbolTableService(ast)); @@ -106,8 +113,130 @@ public void testDefaultConstructor() { @Test public void testAttributes() { - assertEquals(8, builderClass.getCDAttributeList().size()); - + assertEquals(11, builderClass.getCDAttributeList().size()); + + assertTrue(Log.getFindings().isEmpty()); + } + + // getters/setters that have to be Supplier-wrapped (see AccessAsSupplierTypes) + // get additional fields. allowing to both set/get the Supplier itself and to set/get the value directly + + @Test + public void testSymTypeAttributeAndMethods() { + ASTCDAttribute originalAttribute = getAttributeBy("symType", cdClass); + ASTMCType symTypeType = originalAttribute.getMCType(); + + ASTCDAttribute attribute = getAttributeBy("symType", builderClass); + assertDeepEquals(CDModifier.PROTECTED, attribute.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(symTypeType), attribute.getMCType()); + + ASTCDMethod getter = getMethodBy("getSymType", builderClass); + assertDeepEquals(PUBLIC, getter.getModifier()); + assertDeepEquals(symTypeType, getter.getMCReturnType().getMCType()); + assertTrue(getter.isEmptyCDParameters()); + + ASTCDMethod setter = getMethodBy("setSymType", builderClass); + assertDeepEquals(PUBLIC, setter.getModifier()); + assertDeepEquals(builderClass.getName(), setter.getMCReturnType().getMCType()); + assertEquals(1, setter.sizeCDParameters()); + assertDeepEquals(symTypeType, setter.getCDParameter(0).getMCType()); + assertEquals("symType", setter.getCDParameter(0).getName()); + + ASTCDMethod supplierGetter = getMethodBy("getSymTypeSupplier", builderClass); + assertDeepEquals(PUBLIC, supplierGetter.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(symTypeType), supplierGetter.getMCReturnType().getMCType()); + assertTrue(supplierGetter.isEmptyCDParameters()); + + ASTCDMethod supplierSetter = getMethodBy("setSymTypeSupplier", builderClass); + assertDeepEquals(PUBLIC, supplierSetter.getModifier()); + assertDeepEquals(builderClass.getName(), supplierSetter.getMCReturnType().getMCType()); + assertEquals(1, supplierSetter.sizeCDParameters()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(symTypeType), supplierSetter.getCDParameter(0).getMCType()); + assertEquals("symType", supplierSetter.getCDParameter(0).getName()); + + assertTrue(Log.getFindings().isEmpty()); + } + + @Test + public void testLSymTypeAttributeAndMethods() { + ASTCDAttribute originalAttribute = getAttributeBy("lSymType", cdClass); + ASTMCType lSymTypeType = originalAttribute.getMCType(); + + ASTCDAttribute attribute = getAttributeBy("lSymType", builderClass); + assertDeepEquals(CDModifier.PROTECTED, attribute.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(lSymTypeType), attribute.getMCType()); + + ASTCDMethod getter = getMethodBy("getLSymTypeList", builderClass); + assertDeepEquals(PUBLIC, getter.getModifier()); + assertListOf(SYM_TYPE_EXPRESSION, getter.getMCReturnType().getMCType()); + assertTrue(getter.isEmptyCDParameters()); + + ASTCDMethod setter = getMethodBy("setLSymTypeList", builderClass); + assertDeepEquals(PUBLIC, setter.getModifier()); + assertDeepEquals(builderClass.getName(), setter.getMCReturnType().getMCType()); + assertEquals(1, setter.sizeCDParameters()); + assertListOf(SYM_TYPE_EXPRESSION, setter.getCDParameter(0).getMCType()); + assertEquals("lSymType", setter.getCDParameter(0).getName()); + + ASTCDMethod supplierGetter = getMethodBy("getLSymTypeListSupplier", builderClass); + assertDeepEquals(PUBLIC, supplierGetter.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(lSymTypeType), supplierGetter.getMCReturnType().getMCType()); + assertTrue(supplierGetter.isEmptyCDParameters()); + + ASTCDMethod supplierSetter = getMethodBy("setLSymTypeListSupplier", builderClass); + assertDeepEquals(PUBLIC, supplierSetter.getModifier()); + assertDeepEquals(builderClass.getName(), supplierSetter.getMCReturnType().getMCType()); + assertEquals(1, supplierSetter.sizeCDParameters()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(lSymTypeType), supplierSetter.getCDParameter(0).getMCType()); + assertEquals("lSymType", supplierSetter.getCDParameter(0).getName()); + + assertTrue(Log.getFindings().isEmpty()); + } + + @Test + public void testOSymTypeAttributeAndMethods() { + ASTCDAttribute originalAttribute = getAttributeBy("oSymType", cdClass); + ASTMCType oSymTypeType = originalAttribute.getMCType(); + ASTMCType innerType = DecorationHelper.getInstance().getReferenceTypeOfOptional(oSymTypeType).getMCTypeOpt().get(); + + ASTCDAttribute attribute = getAttributeBy("oSymType", builderClass); + assertDeepEquals(CDModifier.PROTECTED, attribute.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(oSymTypeType), attribute.getMCType()); + + ASTCDMethod getter = getMethodBy("getOSymType", builderClass); + assertDeepEquals(PUBLIC, getter.getModifier()); + assertDeepEquals(innerType, getter.getMCReturnType().getMCType()); + assertTrue(getter.isEmptyCDParameters()); + + ASTCDMethod isPresent = getMethodBy("isPresentOSymType", builderClass); + assertDeepEquals(PUBLIC, isPresent.getModifier()); + assertBoolean(isPresent.getMCReturnType().getMCType()); + assertTrue(isPresent.isEmptyCDParameters()); + + ASTCDMethod setter = getMethodBy("setOSymType", builderClass); + assertDeepEquals(PUBLIC, setter.getModifier()); + assertDeepEquals(builderClass.getName(), setter.getMCReturnType().getMCType()); + assertEquals(1, setter.sizeCDParameters()); + assertDeepEquals(innerType, setter.getCDParameter(0).getMCType()); + assertEquals("oSymType", setter.getCDParameter(0).getName()); + + ASTCDMethod setAbsent = getMethodBy("setOSymTypeAbsent", builderClass); + assertDeepEquals(PUBLIC, setAbsent.getModifier()); + assertDeepEquals(builderClass.getName(), setAbsent.getMCReturnType().getMCType()); + assertTrue(setAbsent.isEmptyCDParameters()); + + ASTCDMethod supplierGetter = getMethodBy("getOSymTypeSupplier", builderClass); + assertDeepEquals(PUBLIC, supplierGetter.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(oSymTypeType), supplierGetter.getMCReturnType().getMCType()); + assertTrue(supplierGetter.isEmptyCDParameters()); + + ASTCDMethod supplierSetter = getMethodBy("setOSymTypeSupplier", builderClass); + assertDeepEquals(PUBLIC, supplierSetter.getModifier()); + assertDeepEquals(builderClass.getName(), supplierSetter.getMCReturnType().getMCType()); + assertEquals(1, supplierSetter.sizeCDParameters()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(oSymTypeType), supplierSetter.getCDParameter(0).getMCType()); + assertEquals("oSymType", supplierSetter.getCDParameter(0).getName()); + assertTrue(Log.getFindings().isEmpty()); } @@ -185,8 +314,14 @@ public void testStereoinfoAttribute() { @Test public void testMethods() { - assertEquals(20, builderClass.getCDMethodList().size()); - + // previously here: 20 + // added because of supplied fields + // symType (mandatory): get+getSupplier, set+setSupplier = 4 + // lSymType (list): 18 delegate + getList + getListSupplier = 20 + // 14 delegate + setList + setListSupplier = 16 + // oSymType (optional): get+isPresent+getSupplier, set+setAbsent+setSupplier = 6 + assertEquals(20 + 4 + 20 + 16 + 6, builderClass.getCDMethodList().size()); + assertTrue(Log.getFindings().isEmpty()); } diff --git a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecoratorTest.java b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecoratorTest.java index 92e55b08f2..06605701e1 100644 --- a/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecoratorTest.java +++ b/monticore-generator/src/test/java/de/monticore/codegen/cd2java/_symboltable/symbol/SymbolDecoratorTest.java @@ -13,9 +13,11 @@ import de.monticore.cdbasis._ast.ASTCDClass; import de.monticore.cdbasis._ast.ASTCDCompilationUnit; import de.monticore.codegen.cd2java.AbstractService; +import de.monticore.codegen.cd2java.DecorationHelper; import de.monticore.codegen.cd2java.DecoratorTestCase; import de.monticore.codegen.cd2java._symboltable.SymbolTableService; import de.monticore.codegen.cd2java._visitor.VisitorService; +import de.monticore.codegen.cd2java.methods.AccessAsSupplierTypes; import de.monticore.codegen.cd2java.methods.MethodDecorator; import de.monticore.generating.GeneratorEngine; import de.monticore.generating.GeneratorSetup; @@ -55,6 +57,10 @@ public class SymbolDecoratorTest extends DecoratorTestCase { private ASTCDCompilationUnit originalCompilationUnit; + private ASTCDClass originalFooClass; + + private static final String SYM_TYPE_EXPRESSION = "de.monticore.types.check.SymTypeExpression"; + private static final String ENCLOSING_SCOPE_TYPE = "de.monticore.codegen.symboltable.automatonsymbolcd._symboltable.IAutomatonSymbolCDScope"; private static final String A_NODE_TYPE_OPT = "Optional"; @@ -77,6 +83,7 @@ public void setUp() { decoratedCompilationUnit = this.parse("de", "monticore", "codegen", "symboltable", "AutomatonSymbolCD"); originalCompilationUnit = decoratedCompilationUnit.deepClone(); + originalFooClass = getClassBy("Foo", originalCompilationUnit); this.glex.setGlobalValue("service", new AbstractService(decoratedCompilationUnit)); @@ -247,15 +254,150 @@ public void testSymbolRuleAttributes() { ASTCDAttribute fooAttribute = getAttributeBy("foo", symbolClassFoo); assertDeepEquals(PROTECTED, fooAttribute.getModifier()); assertListOf(String.class, fooAttribute.getMCType()); + assertFalse(AccessAsSupplierTypes.shouldHaveSupplier(fooAttribute)); ASTCDAttribute blaAttribute = getAttributeBy("bla", symbolClassFoo); assertDeepEquals(PROTECTED, blaAttribute.getModifier()); assertOptionalOf(Integer.class, blaAttribute.getMCType()); + assertFalse(AccessAsSupplierTypes.shouldHaveSupplier(blaAttribute)); ASTCDAttribute extraAtt = getAttributeBy("extraAttribute", symbolClassFoo); assertDeepEquals(PROTECTED, extraAtt.getModifier()); assertBoolean(extraAtt.getMCType()); - + assertFalse(AccessAsSupplierTypes.shouldHaveSupplier(extraAtt)); + + // symType, lSymType and oSymType are of the types listed in AccessAsSupplierTypes, so the + // decorator must store them as a Supplier . + ASTCDAttribute originalSymTypeAttribute = getAttributeBy("symType", originalFooClass); + assertTrue(AccessAsSupplierTypes.shouldHaveSupplier(originalSymTypeAttribute)); + ASTCDAttribute symTypeAttribute = getAttributeBy("symType", symbolClassFoo); + assertDeepEquals(PROTECTED, symTypeAttribute.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(originalSymTypeAttribute.getMCType()), + symTypeAttribute.getMCType()); + + ASTCDAttribute originalLSymTypeAttribute = getAttributeBy("lSymType", originalFooClass); + assertTrue(AccessAsSupplierTypes.shouldHaveSupplier(originalLSymTypeAttribute)); + ASTCDAttribute lSymTypeAttribute = getAttributeBy("lSymType", symbolClassFoo); + assertDeepEquals(PROTECTED, lSymTypeAttribute.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(originalLSymTypeAttribute.getMCType()), + lSymTypeAttribute.getMCType()); + + ASTCDAttribute originalOSymTypeAttribute = getAttributeBy("oSymType", originalFooClass); + assertTrue(AccessAsSupplierTypes.shouldHaveSupplier(originalOSymTypeAttribute)); + ASTCDAttribute oSymTypeAttribute = getAttributeBy("oSymType", symbolClassFoo); + assertDeepEquals(PROTECTED, oSymTypeAttribute.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(originalOSymTypeAttribute.getMCType()), + oSymTypeAttribute.getMCType()); + + assertTrue(Log.getFindings().isEmpty()); + } + + // getters/setters for the Supplier-wrapped symbolrule attributes (see AccessAsSupplierTypes): + // each of them gets a plain getter/setter that hides the Supplier (exposing the unwrapped type), + // plus an additional "...Supplier" getter/setter that exposes the java.util.function.Supplier itself. + + @Test + public void testSymTypeSymbolRuleMethods() { + ASTMCType symTypeType = getAttributeBy("symType", originalFooClass).getMCType(); + + ASTCDMethod getter = getMethodBy("getSymType", symbolClassFoo); + assertDeepEquals(PUBLIC, getter.getModifier()); + assertDeepEquals(symTypeType, getter.getMCReturnType().getMCType()); + assertTrue(getter.isEmptyCDParameters()); + + ASTCDMethod setter = getMethodBy("setSymType", symbolClassFoo); + assertDeepEquals(PUBLIC, setter.getModifier()); + assertTrue(setter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, setter.sizeCDParameters()); + assertDeepEquals(symTypeType, setter.getCDParameter(0).getMCType()); + assertEquals("symType", setter.getCDParameter(0).getName()); + + ASTCDMethod supplierGetter = getMethodBy("getSymTypeSupplier", symbolClassFoo); + assertDeepEquals(PUBLIC, supplierGetter.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(symTypeType), supplierGetter.getMCReturnType().getMCType()); + assertTrue(supplierGetter.isEmptyCDParameters()); + + ASTCDMethod supplierSetter = getMethodBy("setSymTypeSupplier", symbolClassFoo); + assertDeepEquals(PUBLIC, supplierSetter.getModifier()); + assertTrue(supplierSetter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, supplierSetter.sizeCDParameters()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(symTypeType), supplierSetter.getCDParameter(0).getMCType()); + assertEquals("symType", supplierSetter.getCDParameter(0).getName()); + + assertTrue(Log.getFindings().isEmpty()); + } + + @Test + public void testListSymTypeSymbolRuleMethods() { + ASTMCType lSymTypeType = getAttributeBy("lSymType", originalFooClass).getMCType(); + + ASTCDMethod getter = getMethodBy("getLSymTypeList", symbolClassFoo); + assertDeepEquals(PUBLIC, getter.getModifier()); + assertListOf(SYM_TYPE_EXPRESSION, getter.getMCReturnType().getMCType()); + assertTrue(getter.isEmptyCDParameters()); + + ASTCDMethod setter = getMethodBy("setLSymTypeList", symbolClassFoo); + assertDeepEquals(PUBLIC, setter.getModifier()); + assertTrue(setter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, setter.sizeCDParameters()); + assertListOf(SYM_TYPE_EXPRESSION, setter.getCDParameter(0).getMCType()); + assertEquals("lSymType", setter.getCDParameter(0).getName()); + + ASTCDMethod supplierGetter = getMethodBy("getLSymTypeListSupplier", symbolClassFoo); + assertDeepEquals(PUBLIC, supplierGetter.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(lSymTypeType), supplierGetter.getMCReturnType().getMCType()); + assertTrue(supplierGetter.isEmptyCDParameters()); + + ASTCDMethod supplierSetter = getMethodBy("setLSymTypeListSupplier", symbolClassFoo); + assertDeepEquals(PUBLIC, supplierSetter.getModifier()); + assertTrue(supplierSetter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, supplierSetter.sizeCDParameters()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(lSymTypeType), supplierSetter.getCDParameter(0).getMCType()); + assertEquals("lSymType", supplierSetter.getCDParameter(0).getName()); + + assertTrue(Log.getFindings().isEmpty()); + } + + @Test + public void testOptionalSymTypeSymbolRuleMethods() { + ASTCDAttribute originalOSymTypeAttribute = getAttributeBy("oSymType", originalFooClass); + ASTMCType oSymTypeType = originalOSymTypeAttribute.getMCType(); + ASTMCType innerType = DecorationHelper.getInstance().getReferenceTypeOfOptional(oSymTypeType).getMCTypeOpt().get(); + + ASTCDMethod getter = getMethodBy("getOSymType", symbolClassFoo); + assertDeepEquals(PUBLIC, getter.getModifier()); + assertDeepEquals(innerType, getter.getMCReturnType().getMCType()); + assertTrue(getter.isEmptyCDParameters()); + + ASTCDMethod isPresent = getMethodBy("isPresentOSymType", symbolClassFoo); + assertDeepEquals(PUBLIC, isPresent.getModifier()); + assertBoolean(isPresent.getMCReturnType().getMCType()); + assertTrue(isPresent.isEmptyCDParameters()); + + ASTCDMethod setter = getMethodBy("setOSymType", symbolClassFoo); + assertDeepEquals(PUBLIC, setter.getModifier()); + assertTrue(setter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, setter.sizeCDParameters()); + assertDeepEquals(innerType, setter.getCDParameter(0).getMCType()); + assertEquals("oSymType", setter.getCDParameter(0).getName()); + + ASTCDMethod setAbsent = getMethodBy("setOSymTypeAbsent", symbolClassFoo); + assertDeepEquals(PUBLIC, setAbsent.getModifier()); + assertTrue(setAbsent.getMCReturnType().isPresentMCVoidType()); + assertTrue(setAbsent.isEmptyCDParameters()); + + ASTCDMethod supplierGetter = getMethodBy("getOSymTypeSupplier", symbolClassFoo); + assertDeepEquals(PUBLIC, supplierGetter.getModifier()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(oSymTypeType), supplierGetter.getMCReturnType().getMCType()); + assertTrue(supplierGetter.isEmptyCDParameters()); + + ASTCDMethod supplierSetter = getMethodBy("setOSymTypeSupplier", symbolClassFoo); + assertDeepEquals(PUBLIC, supplierSetter.getModifier()); + assertTrue(supplierSetter.getMCReturnType().isPresentMCVoidType()); + assertEquals(1, supplierSetter.sizeCDParameters()); + assertDeepEquals(DecorationHelper.getInstance().createStdSupplierTypeOf(oSymTypeType), supplierSetter.getCDParameter(0).getMCType()); + assertEquals("oSymType", supplierSetter.getCDParameter(0).getName()); + assertTrue(Log.getFindings().isEmpty()); } diff --git a/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/AutomatonScopeCD.cd b/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/AutomatonScopeCD.cd index a7f2f4988e..7d1255519b 100644 --- a/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/AutomatonScopeCD.cd +++ b/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/AutomatonScopeCD.cd @@ -9,6 +9,9 @@ classdiagram AutomatonScopeCD { protected boolean extraAttribute; protected List foo; protected Optional bla; + protected de.monticore.types.check.SymTypeExpression symType; + protected java.util.List lSymType; + protected java.util.Optional oSymType; <>public String toString(); } } diff --git a/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/AutomatonSymbolCD.cd b/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/AutomatonSymbolCD.cd index 8f25f7c269..532ade0272 100644 --- a/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/AutomatonSymbolCD.cd +++ b/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/AutomatonSymbolCD.cd @@ -16,6 +16,9 @@ classdiagram AutomatonSymbolCD { protected boolean extraAttribute; protected List foo; protected Optional bla; + protected de.monticore.types.check.SymTypeExpression symType; + protected java.util.List lSymType; + protected java.util.Optional oSymType; <>public String toString(); } } diff --git a/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/cdForBuilder/Symbol_Builder.cd b/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/cdForBuilder/Symbol_Builder.cd index 542056ee9d..ee97a9649f 100644 --- a/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/cdForBuilder/Symbol_Builder.cd +++ b/monticore-generator/src/test/resources/de/monticore/codegen/symboltable/cdForBuilder/Symbol_Builder.cd @@ -4,6 +4,8 @@ package de.monticore.codegen.symboltable.cdForBuilder; classdiagram Symbol_Builder { class A { - + protected de.monticore.types.check.SymTypeExpression symType; + protected java.util.List lSymType; + protected java.util.Optional oSymType; } } diff --git a/monticore-grammar/src/main/java/de/monticore/javalight/_symboltable/JavaMethodSymbolDeSer.java b/monticore-grammar/src/main/java/de/monticore/javalight/_symboltable/JavaMethodSymbolDeSer.java deleted file mode 100644 index 37d97b76c2..0000000000 --- a/monticore-grammar/src/main/java/de/monticore/javalight/_symboltable/JavaMethodSymbolDeSer.java +++ /dev/null @@ -1,27 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.javalight._symboltable; - -import de.monticore.symboltable.serialization.json.JsonObject; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionDeSer; - -import java.util.List; - -public class JavaMethodSymbolDeSer extends JavaMethodSymbolDeSerTOP { - - @Override - protected List deserializeExceptions(JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeListMember("exceptions", symbolJson); - } - - @Override - protected List deserializeAnnotations(JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeListMember("annotations", symbolJson); - } - - @Override - protected SymTypeExpression deserializeType(JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeMember("type", symbolJson); - } - -} diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/FunctionSymbol.java b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/FunctionSymbol.java index a8c74c9ab3..39e99d5560 100644 --- a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/FunctionSymbol.java +++ b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/FunctionSymbol.java @@ -2,6 +2,7 @@ package de.monticore.symbols.basicsymbols._symboltable; import com.google.common.collect.Lists; +import de.monticore.symboltable.ClearingMemorizer; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionFactory; @@ -21,7 +22,8 @@ public FunctionSymbol(String name){ public FunctionSymbol deepClone(){ FunctionSymbol clone = new FunctionSymbol(name); - clone.setType(this.getType().deepClone()); + // keep the type lazy + clone.setTypeSupplier(ClearingMemorizer.map(getTypeSupplier(), t -> t == null ? null : t.deepClone())); clone.setIsElliptic(this.isIsElliptic()); clone.setEnclosingScope(this.enclosingScope); clone.setFullName(this.fullName); @@ -71,15 +73,9 @@ public List getParameterList(){ public void replaceTypeVariables(Map replaceMap){ //return type SymTypeExpression type = this.getType(); - TypeSymbol realTypeInfo; - TypeSymbol typeInfo = type.isTypeVariable() ? + TypeSymbol realTypeInfo = type.isTypeVariable() ? type.asTypeVariable().getTypeVarSymbol() : type.getTypeInfo(); - if(typeInfo instanceof TypeSymbolSurrogate){ - realTypeInfo = ((TypeSymbolSurrogate) type.getTypeInfo()).lazyLoadDelegate(); - }else{ - realTypeInfo = typeInfo; - } if(type.isTypeVariable() && realTypeInfo instanceof TypeVarSymbol){ Optional typeVar = replaceMap.keySet().stream().filter(t -> t.getName().equals(realTypeInfo.getName())).findAny(); typeVar.ifPresent(typeVarSymbol -> this.setType(replaceMap.get(typeVarSymbol))); diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/FunctionSymbolDeSer.java b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/FunctionSymbolDeSer.java deleted file mode 100644 index a03bd9ed91..0000000000 --- a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/FunctionSymbolDeSer.java +++ /dev/null @@ -1,22 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.symbols.basicsymbols._symboltable; - -import de.monticore.symboltable.serialization.json.JsonObject; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionDeSer; - -public class FunctionSymbolDeSer extends FunctionSymbolDeSerTOP { - - @Override - public SymTypeExpression deserializeType(JsonObject symbolJson) { - // support deprecated behavior - return deserializeType(null, symbolJson); - } - - @Override - public SymTypeExpression deserializeType( - IBasicSymbolsScope scope, JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeMember("type", symbolJson, scope); - } - -} diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbol.java b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbol.java index 78af208b98..92ebd72cb8 100644 --- a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbol.java +++ b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbol.java @@ -21,11 +21,11 @@ public void setFunctionList(List methodList){ } public List getSuperClassesOnly(){ - return superTypes; + return getSuperTypesList(); } public List getInterfaceList(){ - return superTypes; + return getSuperTypesList(); } /** diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbolDeSer.java b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbolDeSer.java deleted file mode 100644 index e8f468780a..0000000000 --- a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/TypeSymbolDeSer.java +++ /dev/null @@ -1,24 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.symbols.basicsymbols._symboltable; - -import de.monticore.symboltable.serialization.json.JsonObject; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionDeSer; - -import java.util.List; - -public class TypeSymbolDeSer extends TypeSymbolDeSerTOP { - - @Override - public List deserializeSuperTypes(JsonObject symbolJson) { - // support deprecated behavior - return deserializeSuperTypes(null, symbolJson); - } - - @Override - public List deserializeSuperTypes( - IBasicSymbolsScope scope, JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeListMember("superTypes", symbolJson, scope); - } - -} diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/TypeVarSymbolDeSer.java b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/TypeVarSymbolDeSer.java deleted file mode 100644 index 2c34a141ae..0000000000 --- a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/TypeVarSymbolDeSer.java +++ /dev/null @@ -1,24 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.symbols.basicsymbols._symboltable; - -import de.monticore.symboltable.serialization.json.JsonObject; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionDeSer; - -import java.util.List; - -public class TypeVarSymbolDeSer extends TypeVarSymbolDeSerTOP { - - @Override - public List deserializeSuperTypes(JsonObject symbolJson) { - // support deprecated behavior - return deserializeSuperTypes(null, symbolJson); - } - - @Override - public List deserializeSuperTypes( - IBasicSymbolsScope scope, JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeListMember("superTypes", symbolJson, scope); - } - -} diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/VariableSymbol.java b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/VariableSymbol.java index 328818c74a..93c8d95ed7 100644 --- a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/VariableSymbol.java +++ b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/VariableSymbol.java @@ -1,6 +1,7 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.symbols.basicsymbols._symboltable; +import de.monticore.symboltable.ClearingMemorizer; import de.monticore.symboltable.modifiers.AccessModifier; import de.monticore.types.check.SymTypeExpression; import de.se_rwth.commons.logging.Log; @@ -22,9 +23,8 @@ public VariableSymbol deepClone(){ if(isPresentAstNode()) { clone.setAstNode(this.getAstNode()); } - if(type!=null){ - clone.setType(type.deepClone()); - } + // keep the type lazy + clone.setTypeSupplier(ClearingMemorizer.map(getTypeSupplier(), t -> t == null ? null : t.deepClone())); return clone; } @@ -35,15 +35,9 @@ public VariableSymbol deepClone(){ public void replaceTypeVariables(Map replaceMap){ //return type SymTypeExpression returnType = this.getType(); - TypeSymbol realTypeInfo; - TypeSymbol typeInfo = returnType.isTypeVariable() ? + TypeSymbol realTypeInfo = returnType.isTypeVariable() ? returnType.asTypeVariable().getTypeVarSymbol() : returnType.getTypeInfo(); - if(typeInfo instanceof TypeSymbolSurrogate){ - realTypeInfo = ((TypeSymbolSurrogate) returnType.getTypeInfo()).lazyLoadDelegate(); - }else{ - realTypeInfo = typeInfo; - } if(returnType.isTypeVariable() && realTypeInfo instanceof TypeVarSymbol){ Optional typeVar = replaceMap.keySet().stream().filter(t -> t.getName().equals(realTypeInfo.getName())).findAny(); typeVar.ifPresent(typeVarSymbol -> this.setType(replaceMap.get(typeVarSymbol))); diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/VariableSymbolDeSer.java b/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/VariableSymbolDeSer.java deleted file mode 100644 index a2069ffc57..0000000000 --- a/monticore-grammar/src/main/java/de/monticore/symbols/basicsymbols/_symboltable/VariableSymbolDeSer.java +++ /dev/null @@ -1,22 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.symbols.basicsymbols._symboltable; - -import de.monticore.symboltable.serialization.json.JsonObject; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionDeSer; - -public class VariableSymbolDeSer extends VariableSymbolDeSerTOP { - - @Override - public SymTypeExpression deserializeType(JsonObject symbolJson) { - // support deprecated behavior - return deserializeType(null, symbolJson); - } - - @Override - public SymTypeExpression deserializeType( - IBasicSymbolsScope scope, JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeMember("type", symbolJson, scope); - } - -} diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/compsymbols/_symboltable/ComponentType2TypeSymbolAdapter.java b/monticore-grammar/src/main/java/de/monticore/symbols/compsymbols/_symboltable/ComponentType2TypeSymbolAdapter.java index 0458e3960b..70578ae6d9 100644 --- a/monticore-grammar/src/main/java/de/monticore/symbols/compsymbols/_symboltable/ComponentType2TypeSymbolAdapter.java +++ b/monticore-grammar/src/main/java/de/monticore/symbols/compsymbols/_symboltable/ComponentType2TypeSymbolAdapter.java @@ -20,7 +20,7 @@ public ComponentType2TypeSymbolAdapter(@NonNull ComponentTypeSymbol adaptee) { this.adaptee = adaptee; this.accessModifier = BasicAccessModifier.PUBLIC; this.spannedScope = adaptee.getSpannedScope(); - this.superTypes = adaptee.getSuperComponentsList().stream().map(c -> { + setSuperTypesList(adaptee.getSuperComponentsList().stream().map(c -> { if (!c.isGenericComponentType()) { return SymTypeExpressionFactory.createTypeObject(new ComponentType2TypeSymbolAdapter(c.getTypeInfo())); } else { @@ -28,7 +28,7 @@ public ComponentType2TypeSymbolAdapter(@NonNull ComponentTypeSymbol adaptee) { new ComponentType2TypeSymbolAdapter(c.getTypeInfo()), c.asGenericComponentType().getTypeBindingsAsList() ); } - }).collect(Collectors.toList()); + }).collect(Collectors.toList())); } public ComponentTypeSymbol getAdaptee() { diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/compsymbols/_symboltable/PortSymbol.java b/monticore-grammar/src/main/java/de/monticore/symbols/compsymbols/_symboltable/PortSymbol.java index f2066aa0dd..dd7e4a4220 100644 --- a/monticore-grammar/src/main/java/de/monticore/symbols/compsymbols/_symboltable/PortSymbol.java +++ b/monticore-grammar/src/main/java/de/monticore/symbols/compsymbols/_symboltable/PortSymbol.java @@ -3,7 +3,6 @@ import com.google.common.base.Preconditions; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; -import de.monticore.symbols.basicsymbols._symboltable.TypeSymbolSurrogate; import de.monticore.types.check.SymTypeExpression; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -27,29 +26,30 @@ protected PortSymbol(String name, SymTypeExpression type, Timing timing) { super(name); - this.type = type; + setType(type); this.timing = timing; this.incoming = incoming; this.outgoing = outgoing; } public boolean isTypePresent() { - return this.type != null; + // type is not an optional, so we resolve it here to check if it is null + return getTypeSupplier().get() != null; } public SymTypeExpression getType() { - Preconditions.checkState(this.type != null); - return this.type; + SymTypeExpression t = super.getType(); + Preconditions.checkState(t != null); + return t; } public void setType(@NonNull SymTypeExpression type) { Preconditions.checkNotNull(type); - this.type = type; + super.setType(type); } public TypeSymbol getTypeInfo() { - return this.getType().getTypeInfo() instanceof TypeSymbolSurrogate ? - ((TypeSymbolSurrogate) this.getType().getTypeInfo()).lazyLoadDelegate() : this.getType().getTypeInfo(); + return this.getType().getTypeInfo(); } @Override diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/FieldSymbol.java b/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/FieldSymbol.java index d29dbee6f2..7634be402a 100644 --- a/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/FieldSymbol.java +++ b/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/FieldSymbol.java @@ -1,7 +1,9 @@ /* (c) https://github.com/MontiCore/monticore */ package de.monticore.symbols.oosymbols._symboltable; +import de.monticore.symboltable.ClearingMemorizer; import de.monticore.symboltable.modifiers.*; +import de.monticore.types.check.SymTypeExpression; import java.util.ArrayList; import java.util.List; @@ -34,9 +36,8 @@ public FieldSymbol deepClone(){ if(isPresentAstNode()) { clone.setAstNode(this.getAstNode()); } - if(getType()!=null){ - clone.setType(this.getType().deepClone()); - } + // keep the type lazy + clone.setTypeSupplier(ClearingMemorizer.map(getTypeSupplier(), t -> t == null ? null : t.deepClone())); return clone; } diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/MethodSymbol.java b/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/MethodSymbol.java index f9809f094b..a0946773ae 100644 --- a/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/MethodSymbol.java +++ b/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/MethodSymbol.java @@ -2,7 +2,9 @@ package de.monticore.symbols.oosymbols._symboltable; import de.monticore.symbols.basicsymbols._symboltable.VariableSymbol; +import de.monticore.symboltable.ClearingMemorizer; import de.monticore.symboltable.modifiers.*; +import de.monticore.types.check.SymTypeExpression; import java.util.ArrayList; import java.util.List; @@ -18,7 +20,8 @@ public MethodSymbol(String name) { */ public MethodSymbol deepClone() { MethodSymbol clone = new MethodSymbol(name); - clone.setType(this.type.deepClone()); + // keep the type lazy + clone.setTypeSupplier(ClearingMemorizer.map(getTypeSupplier(), t -> t == null ? null : t.deepClone())); clone.setEnclosingScope(this.enclosingScope); clone.setFullName(this.fullName); clone.setIsConstructor(this.isConstructor); diff --git a/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/OOTypeSymbol.java b/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/OOTypeSymbol.java index 4aa74d6011..f22e55eb6c 100644 --- a/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/OOTypeSymbol.java +++ b/monticore-grammar/src/main/java/de/monticore/symbols/oosymbols/_symboltable/OOTypeSymbol.java @@ -99,7 +99,7 @@ public SymTypeExpression getSuperClass() { public List getSuperClassesOnly() { List normalSuperTypes = super.getSuperClassesOnly().stream() .filter(type -> !(type.getTypeInfo() instanceof OOTypeSymbol)).collect(Collectors.toList()); - List oOSuperTypes = superTypes.stream() + List oOSuperTypes = getSuperTypesList().stream() .filter(type -> type.getTypeInfo() instanceof OOTypeSymbol) .filter(type -> ((OOTypeSymbol) type.getTypeInfo()).isIsClass()) .toList(); @@ -109,7 +109,7 @@ public List getSuperClassesOnly() { @Override public List getInterfaceList() { - return superTypes.stream() + return getSuperTypesList().stream() .filter(type -> type.getTypeInfo() instanceof OOTypeSymbol) .filter(type -> ((OOTypeSymbol) type.getTypeInfo()).isIsInterface()) .collect(Collectors.toList()); diff --git a/monticore-grammar/src/main/java/de/monticore/types/MCTypeFacade.java b/monticore-grammar/src/main/java/de/monticore/types/MCTypeFacade.java index 23a30417b3..a3a5809049 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/MCTypeFacade.java +++ b/monticore-grammar/src/main/java/de/monticore/types/MCTypeFacade.java @@ -9,6 +9,7 @@ import de.monticore.types.mccollectiontypes._ast.*; import de.monticore.types.mcfullgenerictypes.MCFullGenericTypesMill; import de.monticore.types.mcfullgenerictypes._ast.ASTMCWildcardTypeArgument; +import de.monticore.types.mcsimplegenerictypes.MCSimpleGenericTypesMill; import de.monticore.types.mcsimplegenerictypes._ast.ASTMCBasicGenericType; import java.util.ArrayList; @@ -248,6 +249,27 @@ public ASTMCArrayType createArrayType(final String name, int dimension) { return createArrayType(this.createQualifiedType(name), dimension); } + /** + * {@code java.util.function.Supplier } types. + */ + + public ASTMCBasicGenericType createStdSupplierTypeOf(final ASTMCTypeArgument inner) { + return createBasicGenericTypeOf("java.util.function.Supplier", inner); + } + + public ASTMCBasicGenericType createStdSupplierTypeOf(ASTMCType inner) { + ASTMCTypeArgument arg = MCSimpleGenericTypesMill.mCCustomTypeArgumentBuilder().setMCType(inner.deepClone()).build(); + return createStdSupplierTypeOf(arg); + } + + public ASTMCBasicGenericType createStdSupplierTypeOf(final String name) { + return createStdSupplierTypeOf(createBasicTypeArgumentOf(name)); + } + + public ASTMCBasicGenericType createStdSupplierTypeOf(final Class clazz) { + return createStdSupplierTypeOf(clazz.getName()); + } + /** * primitive types */ diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeArray.java b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeArray.java index 07b874dba0..1a794a671b 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeArray.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeArray.java @@ -3,7 +3,6 @@ import com.google.common.base.Preconditions; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; -import de.monticore.symbols.basicsymbols._symboltable.TypeSymbolSurrogate; import de.monticore.types3.ISymTypeVisitor; import de.se_rwth.commons.logging.Log; @@ -98,11 +97,9 @@ public void setArgument(SymTypeExpression argument) { @Override public SymTypeArray deepClone() { //to support deprecated code: + // (hasTypeInfo() is deliberately false for arrays, check the field) if(typeSymbol != null) { - TypeSymbol typeSymbol = new TypeSymbolSurrogate(this.typeSymbol.getName()); - typeSymbol.setEnclosingScope(this.typeSymbol.getEnclosingScope()); - return new SymTypeArray(typeSymbol, - this.dim, this.argument.deepClone()); + return new SymTypeArray(this.typeSymbol, this.dim, this.argument.deepClone()); } else { return new SymTypeArray(getArgument().deepClone(), getDim()); diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeExpressionDeSer.java b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeExpressionDeSer.java index 3c9fae774e..137eff16cc 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeExpressionDeSer.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeExpressionDeSer.java @@ -3,6 +3,8 @@ import de.monticore.symbols.basicsymbols.BasicSymbolsMill; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; +import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; +import de.monticore.symbols.basicsymbols._symboltable.TypeVarSymbol; import de.monticore.symboltable.serialization.JsonDeSers; import de.monticore.symboltable.serialization.JsonParser; import de.monticore.symboltable.serialization.JsonPrinter; @@ -138,6 +140,34 @@ public static List deserializeListMember( return result; } + public static TypeSymbol resolveTypeSymbolOrLogError( + String name, IBasicSymbolsScope enclosingScope) { + Optional resolved = enclosingScope.resolveType(name); + if (resolved.isPresent()) { + return resolved.get(); + } + Log.error("0x893F63 Internal error: cannot resolve the type \"" + + name + "\" required by a SymTypeExpression!"); + TypeSymbol unresolved = new TypeSymbol(name); + unresolved.setEnclosingScope(enclosingScope); + unresolved.setFullName(name); + return unresolved; + } + + public static TypeVarSymbol resolveTypeVarSymbolOrLogError( + String name, IBasicSymbolsScope enclosingScope) { + Optional resolved = enclosingScope.resolveTypeVar(name); + if (resolved.isPresent()) { + return resolved.get(); + } + Log.error("0x893F64 Internal error: cannot resolve the type variable \"" + + name + "\" required by a SymTypeExpression!"); + TypeVarSymbol unresolved = new TypeVarSymbol(name); + unresolved.setEnclosingScope(enclosingScope); + unresolved.setFullName(name); + return unresolved; + } + public static SymTypeExpressionDeSer getInstance() { if (null == instance) { instance = new SymTypeExpressionDeSer(); diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeExpressionFactory.java b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeExpressionFactory.java index b54e563478..f883f5cf2d 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeExpressionFactory.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeExpressionFactory.java @@ -161,6 +161,7 @@ public static SymTypeOfObject createTypeObjectViaSurrogate(String name, IBasicSy return new SymTypeOfObject(typeSymbol); } + /** * for RegEx-types, e.g. 'R"gr(a|e)y"' */ @@ -210,8 +211,14 @@ public static SymTypeArray createTypeArray(TypeSymbol typeSymbol, int dim, @Deprecated(forRemoval = true) public static SymTypeArray createTypeArray(String name, IBasicSymbolsScope typeSymbolsScope, int dim, SymTypeExpression argument) { - TypeSymbol typeSymbol = new TypeSymbolSurrogate(name); - typeSymbol.setEnclosingScope(typeSymbolsScope); + + TypeSymbol typeSymbol = typeSymbolsScope.resolveType(name) + .orElseGet(() -> { + TypeSymbol unresolved = new TypeSymbol(name); + unresolved.setEnclosingScope(typeSymbolsScope); + unresolved.setFullName(name); + return unresolved; + }); return new SymTypeArray(typeSymbol, dim, argument); } diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfGenerics.java b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfGenerics.java index 7928acf443..47e2f18865 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfGenerics.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfGenerics.java @@ -3,7 +3,6 @@ import com.google.common.base.Preconditions; import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; -import de.monticore.symbols.basicsymbols._symboltable.TypeSymbolSurrogate; import de.monticore.symbols.basicsymbols._symboltable.TypeVarSymbol; import de.monticore.types3.ISymTypeVisitor; import de.se_rwth.commons.logging.Log; @@ -278,13 +277,7 @@ else if (arguments.size() != typeVars.size()) { public void replaceTypeVariables(Map replaceMap) { for(int i = 0; i typeVar = replaceMap.keySet().stream().filter(t -> t.getName().equals(realTypeInfo.getName())).findAny(); if(typeVar.isPresent()){ diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfGenericsDeSer.java b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfGenericsDeSer.java index 55d91d84eb..07fd3072a8 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfGenericsDeSer.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfGenericsDeSer.java @@ -3,7 +3,6 @@ import de.monticore.symbols.basicsymbols.BasicSymbolsMill; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; -import de.monticore.symbols.basicsymbols._symboltable.TypeSymbolSurrogate; import de.monticore.symboltable.serialization.JsonDeSers; import de.monticore.symboltable.serialization.JsonParser; import de.monticore.symboltable.serialization.JsonPrinter; @@ -48,14 +47,11 @@ public SymTypeOfGenerics deserialize(JsonObject serialized, IBasicSymbolsScope e // support deprecated behavior enclosingScope = BasicSymbolsMill.globalScope(); } - TypeSymbolSurrogate typeSym = new TypeSymbolSurrogate(typeConstructorFullName); - typeSym.setEnclosingScope(enclosingScope); - List arguments = SymTypeExpressionDeSer .deserializeListMember(SERIALIZED_ARGUMENTS, serialized, enclosingScope); - return SymTypeExpressionFactory - .createGenerics(typeSym, arguments); + return SymTypeExpressionFactory.createGenerics(SymTypeExpressionDeSer + .resolveTypeSymbolOrLogError(typeConstructorFullName, enclosingScope), arguments); } Log.error( "0x823F6 Internal error: Loading ill-structured SymTab: missing typeConstructorFullName of SymTypeOfGenerics " diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfNull.java b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfNull.java index 4b144e81db..cac344d594 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfNull.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfNull.java @@ -2,7 +2,7 @@ package de.monticore.types.check; import de.monticore.symbols.basicsymbols.BasicSymbolsMill; -import de.monticore.symbols.basicsymbols._symboltable.TypeSymbolSurrogate; +import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; import de.monticore.types3.ISymTypeVisitor; public class SymTypeOfNull extends SymTypeExpression { @@ -20,7 +20,7 @@ public class SymTypeOfNull extends SymTypeExpression { */ @Deprecated public SymTypeOfNull() { - typeSymbol = new TypeSymbolSurrogate(BasicSymbolsMill.NULL); + typeSymbol = new TypeSymbol(BasicSymbolsMill.NULL); typeSymbol.setEnclosingScope(BasicSymbolsMill.scope()); } diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfObject.java b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfObject.java index 23201ff391..107aaa6eb6 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfObject.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfObject.java @@ -14,9 +14,6 @@ public class SymTypeOfObject extends SymTypeExpression { protected TypeSymbol typeSymbol; - /** - * Constructor: with a TypeSymbolSurrogate that contains the name and enclosingScope - */ public SymTypeOfObject(TypeSymbol typeSymbol) { Preconditions.checkNotNull(typeSymbol); diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfObjectDeSer.java b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfObjectDeSer.java index e9b1406717..781b0a2b8e 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfObjectDeSer.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeOfObjectDeSer.java @@ -3,7 +3,6 @@ import de.monticore.symbols.basicsymbols.BasicSymbolsMill; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; -import de.monticore.symbols.basicsymbols._symboltable.TypeSymbolSurrogate; import de.monticore.symboltable.serialization.JsonDeSers; import de.monticore.symboltable.serialization.JsonParser; import de.monticore.symboltable.serialization.JsonPrinter; @@ -43,9 +42,8 @@ public SymTypeOfObject deserialize(JsonObject serialized, IBasicSymbolsScope enc // support deprecated behavior enclosingScope = BasicSymbolsMill.globalScope(); } - TypeSymbolSurrogate typeSym = new TypeSymbolSurrogate(objName); - typeSym.setEnclosingScope(enclosingScope); - return SymTypeExpressionFactory.createTypeObject(typeSym); + return SymTypeExpressionFactory.createTypeObject(SymTypeExpressionDeSer + .resolveTypeSymbolOrLogError(objName, enclosingScope)); } Log.error("0x823F4 Internal error: Cannot load \"" + serialized + "\" as SymTypeOfObject!"); diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeVariableDeSer.java b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeVariableDeSer.java index 276e853dd5..bbfb484aa2 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeVariableDeSer.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeVariableDeSer.java @@ -3,7 +3,6 @@ import de.monticore.symbols.basicsymbols.BasicSymbolsMill; import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope; -import de.monticore.symbols.basicsymbols._symboltable.TypeVarSymbolSurrogate; import de.monticore.symboltable.serialization.JsonDeSers; import de.monticore.symboltable.serialization.JsonParser; import de.monticore.symboltable.serialization.JsonPrinter; @@ -51,9 +50,8 @@ public SymTypeVariable deserialize(JsonObject serialized, IBasicSymbolsScope enc // support deprecated behavior: enclosingScope = BasicSymbolsMill.globalScope(); } - TypeVarSymbolSurrogate typeVarSym = new TypeVarSymbolSurrogate(varName); - typeVarSym.setEnclosingScope(enclosingScope); - return SymTypeExpressionFactory.createTypeVariable(typeVarSym); + return SymTypeExpressionFactory.createTypeVariable(SymTypeExpressionDeSer + .resolveTypeVarSymbolOrLogError(varName, enclosingScope)); } Log.error("0x823F5 Internal error: Cannot load \"" + serialized + "\" as SymTypeVariable!"); return null; diff --git a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeVoid.java b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeVoid.java index a044c0c654..399d85c3c8 100644 --- a/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeVoid.java +++ b/monticore-grammar/src/main/java/de/monticore/types/check/SymTypeVoid.java @@ -3,7 +3,7 @@ import de.monticore.symbols.basicsymbols.BasicSymbolsMill; -import de.monticore.symbols.basicsymbols._symboltable.TypeSymbolSurrogate; +import de.monticore.symbols.basicsymbols._symboltable.TypeSymbol; import de.monticore.types3.ISymTypeVisitor; public class SymTypeVoid extends SymTypeExpression { @@ -14,7 +14,7 @@ public class SymTypeVoid extends SymTypeExpression { */ @Deprecated public SymTypeVoid() { - typeSymbol = new TypeSymbolSurrogate(BasicSymbolsMill.VOID); + typeSymbol = new TypeSymbol(BasicSymbolsMill.VOID); typeSymbol.setEnclosingScope(BasicSymbolsMill.globalScope()); } diff --git a/monticore-grammar/src/test/grammars/de/monticore/suppliedtypes/SuppliedTypes.mc4 b/monticore-grammar/src/test/grammars/de/monticore/suppliedtypes/SuppliedTypes.mc4 new file mode 100644 index 0000000000..172e56d6c5 --- /dev/null +++ b/monticore-grammar/src/test/grammars/de/monticore/suppliedtypes/SuppliedTypes.mc4 @@ -0,0 +1,20 @@ +/* (c) https://github.com/MontiCore/monticore */ + +package de.monticore.suppliedtypes; + + +grammar SuppliedTypes extends de.monticore.symbols.BasicSymbols { + + symbol Holder = "holder" Name; + + symbolrule Holder = + mandatoryType: de.monticore.types.check.SymTypeExpression + listType: de.monticore.types.check.SymTypeExpression* + optType: de.monticore.types.check.SymTypeExpression?; + + scoperule = + mandatoryType: de.monticore.types.check.SymTypeExpression + listType: de.monticore.types.check.SymTypeExpression* + optType: de.monticore.types.check.SymTypeExpression?; + +} diff --git a/monticore-grammar/src/test/java/de/monticore/suppliedtypes/SuppliedTypesTest.java b/monticore-grammar/src/test/java/de/monticore/suppliedtypes/SuppliedTypesTest.java new file mode 100644 index 0000000000..b54a801406 --- /dev/null +++ b/monticore-grammar/src/test/java/de/monticore/suppliedtypes/SuppliedTypesTest.java @@ -0,0 +1,258 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.suppliedtypes; + +import de.monticore.runtime.junit.TestWithMCLanguage; +import de.monticore.suppliedtypes.suppliedtypes.SuppliedTypesMill; +import de.monticore.suppliedtypes.suppliedtypes._symboltable.HolderSymbol; +import de.monticore.suppliedtypes.suppliedtypes._symboltable.HolderSymbolBuilder; +import de.monticore.suppliedtypes.suppliedtypes._symboltable.ISuppliedTypesScope; +import de.monticore.symbols.basicsymbols.BasicSymbolsMill; +import de.monticore.types.check.SymTypeExpression; +import de.monticore.types.check.SymTypeExpressionFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Optional; +import java.util.function.Supplier; + +import static org.junit.jupiter.api.Assertions.*; + +@TestWithMCLanguage(SuppliedTypesMill.class) +public class SuppliedTypesTest { + + private SymTypeExpression intType; + + private SymTypeExpression booleanType; + + @BeforeEach + public void init() { + BasicSymbolsMill.initializePrimitives(); + intType = SymTypeExpressionFactory.createPrimitive("int"); + booleanType = SymTypeExpressionFactory.createPrimitive("boolean"); + } + + @Test + public void symbolMandatoryType() { + HolderSymbol symbol = new HolderSymbol("holder"); + + // default: no value set yet + assertNull(symbol.getMandatoryType()); + + symbol.setMandatoryType(intType); + assertSame(intType, symbol.getMandatoryType()); + assertSame(intType, symbol.getMandatoryTypeSupplier().get()); + + symbol.setMandatoryTypeSupplier(() -> booleanType); + assertSame(booleanType, symbol.getMandatoryType()); + + // getXSupplier() must never leak the internal wrapper: it returns exactly what was set + Supplier plainSupplier = () -> intType; + symbol.setMandatoryTypeSupplier(plainSupplier); + assertSame(plainSupplier, symbol.getMandatoryTypeSupplier()); + } + + @Test + public void symbolListType() { + HolderSymbol symbol = new HolderSymbol("holder"); + + // default: an empty, non-null list + assertNotNull(symbol.getListTypeList()); + assertTrue(symbol.getListTypeList().isEmpty()); + + List values = List.of(intType, booleanType); + symbol.setListTypeList(values); + assertEquals(values, symbol.getListTypeList()); + assertEquals(values, symbol.getListTypeListSupplier().get()); + + symbol.setListTypeListSupplier(() -> values); + assertEquals(values, symbol.getListTypeList()); + + // getXSupplier() it returns exactly what was set + Supplier> plainSupplier = () -> values; + symbol.setListTypeListSupplier(plainSupplier); + assertSame(plainSupplier, symbol.getListTypeListSupplier()); + } + + @Test + public void symbolOptType() { + HolderSymbol symbol = new HolderSymbol("holder"); + + // default: absent + assertFalse(symbol.isPresentOptType()); + assertNull(symbol.getOptType()); + + symbol.setOptType(booleanType); + assertTrue(symbol.isPresentOptType()); + assertSame(booleanType, symbol.getOptType()); + assertEquals(java.util.Optional.of(booleanType), symbol.getOptTypeSupplier().get()); + + // removing value + symbol.setOptTypeAbsent(); + assertFalse(symbol.isPresentOptType()); + assertNull(symbol.getOptType()); + + + symbol.setOptTypeSupplier(() -> Optional.of(intType)); + assertTrue(symbol.isPresentOptType()); + assertSame(intType, symbol.getOptType()); + + // getXSupplier() it returns exactly what was set + Supplier> plainSupplier = () -> Optional.of(booleanType); + symbol.setOptTypeSupplier(plainSupplier); + assertSame(plainSupplier, symbol.getOptTypeSupplier()); + } + + @Test + public void scopeMandatoryType() { + ISuppliedTypesScope scope = SuppliedTypesMill.scope(); + + // default: no value set yet + assertNull(scope.getMandatoryType()); + + scope.setMandatoryType(intType); + assertSame(intType, scope.getMandatoryType()); + assertSame(intType, scope.getMandatoryTypeSupplier().get()); + + scope.setMandatoryTypeSupplier(() -> booleanType); + assertSame(booleanType, scope.getMandatoryType()); + + // getXSupplier() must never leak the internal wrapper: it returns exactly what was set + Supplier plainSupplier = () -> intType; + scope.setMandatoryTypeSupplier(plainSupplier); + assertSame(plainSupplier, scope.getMandatoryTypeSupplier()); + } + + @Test + public void scopeListType() { + ISuppliedTypesScope scope = SuppliedTypesMill.scope(); + + // default: an empty, non-null list + assertNotNull(scope.getListTypeList()); + assertTrue(scope.getListTypeList().isEmpty()); + + List values = List.of(intType, booleanType); + scope.setListTypeList(values); + assertEquals(values, scope.getListTypeList()); + assertEquals(values, scope.getListTypeListSupplier().get()); + + scope.setListTypeListSupplier(() -> values); + assertEquals(values, scope.getListTypeList()); + + // getXSupplier() it returns exactly what was set + Supplier> plainSupplier = () -> values; + scope.setListTypeListSupplier(plainSupplier); + assertSame(plainSupplier, scope.getListTypeListSupplier()); + } + + @Test + public void scopeOptType() { + ISuppliedTypesScope scope = SuppliedTypesMill.scope(); + + // default: absent + assertFalse(scope.isPresentOptType()); + assertNull(scope.getOptType()); + + scope.setOptType(booleanType); + assertTrue(scope.isPresentOptType()); + assertSame(booleanType, scope.getOptType()); + assertEquals(java.util.Optional.of(booleanType), scope.getOptTypeSupplier().get()); + + // removing value + scope.setOptTypeAbsent(); + assertFalse(scope.isPresentOptType()); + assertNull(scope.getOptType()); + + + scope.setOptTypeSupplier(() -> Optional.of(intType)); + assertTrue(scope.isPresentOptType()); + assertSame(intType, scope.getOptType()); + + // getXSupplier() it returns exactly what was set + Supplier> plainSupplier = () -> Optional.of(booleanType); + scope.setOptTypeSupplier(plainSupplier); + assertSame(plainSupplier, scope.getOptTypeSupplier()); + } + + @Test + public void builderMandatoryType() { + HolderSymbolBuilder builder = SuppliedTypesMill.holderSymbolBuilder(); + + // default: no value set yet + assertNull(builder.getMandatoryType()); + + builder.setMandatoryType(intType); + assertSame(intType, builder.getMandatoryType()); + assertSame(intType, builder.getMandatoryTypeSupplier().get()); + + builder.setMandatoryTypeSupplier(() -> booleanType); + assertSame(booleanType, builder.getMandatoryType()); + + // getXSupplier() it returns exactly what was set + Supplier plainSupplier = () -> intType; + builder.setMandatoryTypeSupplier(plainSupplier); + assertSame(plainSupplier, builder.getMandatoryTypeSupplier()); + } + + @Test + public void builderListType() { + HolderSymbolBuilder builder = SuppliedTypesMill.holderSymbolBuilder(); + + // default: an empty, non-null list + assertNotNull(builder.getListTypeList()); + assertTrue(builder.getListTypeList().isEmpty()); + + List values = List.of(intType, booleanType); + builder.setListTypeList(values); + assertEquals(values, builder.getListTypeList()); + assertEquals(values, builder.getListTypeListSupplier().get()); + + builder.setListTypeListSupplier(() -> values); + assertEquals(values, builder.getListTypeList()); + + // getXSupplier() it returns exactly what was set + Supplier> plainSupplier = () -> values; + builder.setListTypeListSupplier(plainSupplier); + assertSame(plainSupplier, builder.getListTypeListSupplier()); + } + + @Test + public void builderOptType() { + HolderSymbolBuilder builder = SuppliedTypesMill.holderSymbolBuilder(); + + // default: absent + assertFalse(builder.isPresentOptType()); + assertNull(builder.getOptType()); + + builder.setOptType(booleanType); + assertTrue(builder.isPresentOptType()); + assertSame(booleanType, builder.getOptType()); + assertEquals(Optional.of(booleanType), builder.getOptTypeSupplier().get()); + + // removing value + builder.setOptTypeAbsent(); + assertFalse(builder.isPresentOptType()); + assertNull(builder.getOptType()); + + builder.setOptTypeSupplier(() -> Optional.of(intType)); + assertTrue(builder.isPresentOptType()); + assertSame(intType, builder.getOptType()); + + // getXSupplier() it returns exactly what was set + Supplier> plainSupplier = () -> Optional.of(booleanType); + builder.setOptTypeSupplier(plainSupplier); + assertSame(plainSupplier, builder.getOptTypeSupplier()); + } + + @Test + public void builderDefaultsPropagateToTheBuiltSymbol() { + HolderSymbol symbol = SuppliedTypesMill.holderSymbolBuilder() + .setName("holder") + .build(); + + assertNull(symbol.getMandatoryType()); + assertNotNull(symbol.getListTypeList()); + assertTrue(symbol.getListTypeList().isEmpty()); + assertFalse(symbol.isPresentOptType()); + } +} diff --git a/monticore-runtime/src/main/java/de/monticore/symboltable/ClearingMemorizer.java b/monticore-runtime/src/main/java/de/monticore/symboltable/ClearingMemorizer.java new file mode 100644 index 0000000000..bb53057a86 --- /dev/null +++ b/monticore-runtime/src/main/java/de/monticore/symboltable/ClearingMemorizer.java @@ -0,0 +1,39 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.symboltable; + +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * Evaluates the wrapped supplier at most once and caches the result. Afterwards the + * supplier is released (and with it everything it captured, e.g. the JSON it deserializes from). + */ +public class ClearingMemorizer implements Supplier { + + private Supplier supplier; + + private T cache; + + public ClearingMemorizer(Supplier supplier) { + this.supplier = supplier; + } + + /** + * Lazily applies the mapper to the value of the source, evaluated at most once. + * Nothing is evaluated until the result is requested, e.g. to copy a not-yet-resolvable + * attribute of a symbol without forcing it. + */ + public static Supplier map(Supplier source, Function mapper) { + return new ClearingMemorizer<>(() -> mapper.apply(source.get())); + } + + @Override + public T get() { + if (supplier != null) { + // a null result is cached as well + cache = supplier.get(); + supplier = null; + } + return cache; + } +} diff --git a/monticore-test/02.experiments/resolving/src/main/java/de/monticore/simplecd/_symboltable/CDClassSymbolDeSer.java b/monticore-test/02.experiments/resolving/src/main/java/de/monticore/simplecd/_symboltable/CDClassSymbolDeSer.java deleted file mode 100644 index 9bb113dc7a..0000000000 --- a/monticore-test/02.experiments/resolving/src/main/java/de/monticore/simplecd/_symboltable/CDClassSymbolDeSer.java +++ /dev/null @@ -1,23 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package de.monticore.simplecd._symboltable; - -import de.monticore.symboltable.serialization.json.JsonObject; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionDeSer; - -import java.util.List; - -public class CDClassSymbolDeSer extends CDClassSymbolDeSerTOP{ - - @Override - protected void serializeSuperTypes(List superTypes, SimpleCDSymbols2Json s2j) { - SymTypeExpressionDeSer.serializeMember(s2j.printer, "superTypes", superTypes); - } - - @Override - protected List deserializeSuperTypes(JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeListMember("superTypes", symbolJson); - } - - -} diff --git a/monticore-test/02.experiments/unknownScopes/src/main/java/foo/_symboltable/FunctionDeclarationSymbolDeSer.java b/monticore-test/02.experiments/unknownScopes/src/main/java/foo/_symboltable/FunctionDeclarationSymbolDeSer.java index 675837fb5d..7fffc96dc6 100644 --- a/monticore-test/02.experiments/unknownScopes/src/main/java/foo/_symboltable/FunctionDeclarationSymbolDeSer.java +++ b/monticore-test/02.experiments/unknownScopes/src/main/java/foo/_symboltable/FunctionDeclarationSymbolDeSer.java @@ -4,14 +4,16 @@ import de.monticore.symboltable.serialization.json.JsonObject; import de.monticore.types.check.SymTypeExpression; +import java.util.function.Supplier; + public class FunctionDeclarationSymbolDeSer extends FunctionDeclarationSymbolDeSerTOP { @Override protected void serializeType(SymTypeExpression type, FooSymbols2Json s2j) {} @Override - protected SymTypeExpression deserializeType(JsonObject symbolJson) { - return null; + protected Supplier deserializeType(JsonObject symbolJson) { + return () -> null; } } diff --git a/monticore-test/it/src/main/grammars/mc/feature/scoperules/ScoperuleTest.mc4 b/monticore-test/it/src/main/grammars/mc/feature/scoperules/ScoperuleTest.mc4 index 8f7173c0d5..4381971431 100644 --- a/monticore-test/it/src/main/grammars/mc/feature/scoperules/ScoperuleTest.mc4 +++ b/monticore-test/it/src/main/grammars/mc/feature/scoperules/ScoperuleTest.mc4 @@ -34,8 +34,8 @@ grammar ScoperuleTest extends de.monticore.MCBasics, de.monticore.symbols.BasicS } symType:de.monticore.types.check.SymTypeExpression? method public void createSymType(){ - if(!symType.isPresent()){ - symType = Optional.of(de.monticore.types.check.SymTypeExpressionFactory.createPrimitive("double")); + if(!isPresentSymType()){ + setSymType(de.monticore.types.check.SymTypeExpressionFactory.createPrimitive("double")); } }; diff --git a/monticore-test/it/src/main/grammars/mc/feature/symbolrules/SymbolruleTest.mc4 b/monticore-test/it/src/main/grammars/mc/feature/symbolrules/SymbolruleTest.mc4 index 6b19ce2ceb..28f593979e 100644 --- a/monticore-test/it/src/main/grammars/mc/feature/symbolrules/SymbolruleTest.mc4 +++ b/monticore-test/it/src/main/grammars/mc/feature/symbolrules/SymbolruleTest.mc4 @@ -22,7 +22,7 @@ grammar SymbolruleTest extends de.monticore.MCBasics, de.monticore.symbols.Basic symbolrule ITest = superTypes:de.monticore.types.check.SymTypeExpression* method public de.monticore.types.check.SymTypeExpression getByName(String name){ java.util.Optional expr = Optional.empty(); - for(de.monticore.types.check.SymTypeExpression symType:superTypes){ + for(de.monticore.types.check.SymTypeExpression symType:getSuperTypesList()){ if(symType.print().equals(name)){ expr = Optional.of(symType); } @@ -70,8 +70,8 @@ grammar SymbolruleTest extends de.monticore.MCBasics, de.monticore.symbols.Basic } symType:de.monticore.types.check.SymTypeExpression? method public void createSymType(){ - if(!symType.isPresent()){ - symType = Optional.of(de.monticore.types.check.SymTypeExpressionFactory.createPrimitive("double")); + if(!isPresentSymType()){ + setSymType(de.monticore.types.check.SymTypeExpressionFactory.createPrimitive("double")); } }; diff --git a/monticore-test/it/src/main/java/mc/feature/scoperules/scoperuletest/_symboltable/ScoperuleTestDeSer.java b/monticore-test/it/src/main/java/mc/feature/scoperules/scoperuletest/_symboltable/ScoperuleTestDeSer.java index c1b9cd9deb..c3f650e0ad 100644 --- a/monticore-test/it/src/main/java/mc/feature/scoperules/scoperuletest/_symboltable/ScoperuleTestDeSer.java +++ b/monticore-test/it/src/main/java/mc/feature/scoperules/scoperuletest/_symboltable/ScoperuleTestDeSer.java @@ -1,16 +1,18 @@ /* (c) https://github.com/MontiCore/monticore */ package mc.feature.scoperules.scoperuletest._symboltable; +import de.monticore.symboltable.serialization.json.JsonObject; import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionDeSer; import java.util.Optional; +import java.util.function.Supplier; public class ScoperuleTestDeSer extends ScoperuleTestDeSerTOP { @Override - public Optional deserializeSymType (de.monticore.symboltable.serialization.json.JsonObject scopeJson) { - return SymTypeExpressionDeSer.deserializeOptionalMember("symType",scopeJson); + public Supplier> deserializeSymType (JsonObject scopeJson) { + return () -> SymTypeExpressionDeSer.deserializeOptionalMember("symType",scopeJson); } @Override diff --git a/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolrulelisttest/_symboltable/SymbolruleListTestDeSer.java b/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolrulelisttest/_symboltable/SymbolruleListTestDeSer.java index b82a8f0572..1199440d19 100644 --- a/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolrulelisttest/_symboltable/SymbolruleListTestDeSer.java +++ b/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolrulelisttest/_symboltable/SymbolruleListTestDeSer.java @@ -1,13 +1,18 @@ /* (c) https://github.com/MontiCore/monticore */ package mc.feature.symbolrules.symbolrulelisttest._symboltable; +import de.monticore.symboltable.serialization.json.JsonObject; +import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionDeSer; +import java.util.List; +import java.util.function.Supplier; + public class SymbolruleListTestDeSer extends SymbolruleListTestDeSerTOP { @Override - public java.util.List deserializeSymTypes (de.monticore.symboltable.serialization.json.JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeListMember("symTypes", symbolJson); + public Supplier> deserializeSymTypes (JsonObject symbolJson) { + return () -> SymTypeExpressionDeSer.deserializeListMember("symTypes", symbolJson); } } diff --git a/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/ITestSymbolDeSer.java b/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/ITestSymbolDeSer.java index ca7f59bf4c..881281cf21 100644 --- a/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/ITestSymbolDeSer.java +++ b/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/ITestSymbolDeSer.java @@ -1,13 +1,18 @@ /* (c) https://github.com/MontiCore/monticore */ package mc.feature.symbolrules.symbolruletest._symboltable; +import de.monticore.symboltable.serialization.json.JsonObject; +import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionDeSer; +import java.util.List; +import java.util.function.Supplier; + public class ITestSymbolDeSer extends ITestSymbolDeSerTOP { @Override - public java.util.List deserializeSuperTypes (de.monticore.symboltable.serialization.json.JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeListMember("superTypes", symbolJson); + public Supplier> deserializeSuperTypes (JsonObject symbolJson) { + return () -> SymTypeExpressionDeSer.deserializeListMember("superTypes", symbolJson); } } diff --git a/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/SymbolruleTestDeSer.java b/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/SymbolruleTestDeSer.java index 41099e0471..ea72025a7a 100644 --- a/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/SymbolruleTestDeSer.java +++ b/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/SymbolruleTestDeSer.java @@ -1,16 +1,18 @@ /* (c) https://github.com/MontiCore/monticore */ package mc.feature.symbolrules.symbolruletest._symboltable; +import de.monticore.symboltable.serialization.json.JsonObject; import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionDeSer; import java.util.Optional; +import java.util.function.Supplier; public class SymbolruleTestDeSer extends SymbolruleTestDeSerTOP { @Override - public java.util.Optional deserializeSymType (de.monticore.symboltable.serialization.json.JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeOptionalMember("symType", symbolJson); + public Supplier> deserializeSymType (JsonObject symbolJson) { + return () -> SymTypeExpressionDeSer.deserializeOptionalMember("symType", symbolJson); } @Override diff --git a/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/Test1SymbolDeSer.java b/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/Test1SymbolDeSer.java index 0b896d35c1..9dba4fe430 100644 --- a/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/Test1SymbolDeSer.java +++ b/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/Test1SymbolDeSer.java @@ -1,12 +1,17 @@ /* (c) https://github.com/MontiCore/monticore */ package mc.feature.symbolrules.symbolruletest._symboltable; +import de.monticore.symboltable.serialization.json.JsonObject; +import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionDeSer; +import java.util.List; +import java.util.function.Supplier; + public class Test1SymbolDeSer extends Test1SymbolDeSerTOP { - + @Override - public java.util.List deserializeSuperTypes (de.monticore.symboltable.serialization.json.JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeListMember("superTypes", symbolJson); + public Supplier> deserializeSuperTypes (JsonObject symbolJson) { + return () -> SymTypeExpressionDeSer.deserializeListMember("superTypes", symbolJson); } } diff --git a/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/Test2SymbolDeSer.java b/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/Test2SymbolDeSer.java index fc2827479d..a1dfd73c8b 100644 --- a/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/Test2SymbolDeSer.java +++ b/monticore-test/it/src/main/java/mc/feature/symbolrules/symbolruletest/_symboltable/Test2SymbolDeSer.java @@ -1,13 +1,18 @@ /* (c) https://github.com/MontiCore/monticore */ package mc.feature.symbolrules.symbolruletest._symboltable; +import de.monticore.symboltable.serialization.json.JsonObject; +import de.monticore.types.check.SymTypeExpression; import de.monticore.types.check.SymTypeExpressionDeSer; +import java.util.List; +import java.util.function.Supplier; + public class Test2SymbolDeSer extends Test2SymbolDeSerTOP { @Override - public java.util.List deserializeSuperTypes (de.monticore.symboltable.serialization.json.JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeListMember("superTypes", symbolJson); + public Supplier> deserializeSuperTypes (JsonObject symbolJson) { + return () -> SymTypeExpressionDeSer.deserializeListMember("superTypes", symbolJson); } } diff --git a/monticore-test/monticore-grammar-it/src/main/java/mc/typechecktest/_symboltable/TCArtifactSymbolDeSer.java b/monticore-test/monticore-grammar-it/src/main/java/mc/typechecktest/_symboltable/TCArtifactSymbolDeSer.java deleted file mode 100644 index 72a8ed7537..0000000000 --- a/monticore-test/monticore-grammar-it/src/main/java/mc/typechecktest/_symboltable/TCArtifactSymbolDeSer.java +++ /dev/null @@ -1,16 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package mc.typechecktest._symboltable; - -import de.monticore.symboltable.serialization.json.JsonObject; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionDeSer; - -import java.util.List; - -public class TCArtifactSymbolDeSer extends TCArtifactSymbolDeSerTOP { - - @Override - protected List deserializeSuperTypes(JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeListMember("superTypes", symbolJson); - } -} diff --git a/monticore-test/monticore-grammar-it/src/main/java/mc/typechecktest/_symboltable/TCMethodSymbolDeSer.java b/monticore-test/monticore-grammar-it/src/main/java/mc/typechecktest/_symboltable/TCMethodSymbolDeSer.java deleted file mode 100644 index 13b29e8223..0000000000 --- a/monticore-test/monticore-grammar-it/src/main/java/mc/typechecktest/_symboltable/TCMethodSymbolDeSer.java +++ /dev/null @@ -1,14 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package mc.typechecktest._symboltable; - -import de.monticore.symboltable.serialization.json.JsonObject; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionDeSer; - -public class TCMethodSymbolDeSer extends TCMethodSymbolDeSerTOP { - - @Override - protected SymTypeExpression deserializeType(JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeMember("type", symbolJson); - } -} diff --git a/monticore-test/monticore-grammar-it/src/main/java/mc/typechecktest/_symboltable/TCVarDeclSymbolDeSer.java b/monticore-test/monticore-grammar-it/src/main/java/mc/typechecktest/_symboltable/TCVarDeclSymbolDeSer.java deleted file mode 100644 index 6b1df014b1..0000000000 --- a/monticore-test/monticore-grammar-it/src/main/java/mc/typechecktest/_symboltable/TCVarDeclSymbolDeSer.java +++ /dev/null @@ -1,14 +0,0 @@ -/* (c) https://github.com/MontiCore/monticore */ -package mc.typechecktest._symboltable; - -import de.monticore.symboltable.serialization.json.JsonObject; -import de.monticore.types.check.SymTypeExpression; -import de.monticore.types.check.SymTypeExpressionDeSer; - -public class TCVarDeclSymbolDeSer extends TCVarDeclSymbolDeSerTOP { - - @Override - protected SymTypeExpression deserializeType(JsonObject symbolJson) { - return SymTypeExpressionDeSer.deserializeMember("type", symbolJson); - } -}