From 3cce54d7f20cee0cb2ec340b88d825dc04f7be17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Thu, 23 Nov 2023 10:16:41 +0100 Subject: [PATCH] Tagging Repository --- .../cd2java/_tagging/TaggerDecorator.java | 87 +++++++++-- .../tagging/TagDefinitionDerivVisitor.java | 7 +- .../resources/tagging/itagger/GetTags.ftl | 2 +- .../tagging/itagger/GetTagsFromRepo.ftl | 3 + .../resources/tagging/tagger/AddTagSymbol.ftl | 13 ++ .../tagging/tagger/GetArtifactScope.ftl | 4 +- .../main/resources/tagging/tagger/GetTags.ftl | 61 ++++---- .../tagging/tagger/GetTagsSymbol.ftl | 57 ++++--- .../de/monticore/tagging/TagRepository.java | 99 ++++++++++++ .../01.experiments/tagging/build.gradle | 22 +++ .../de/monticore/tagtest/CDBasis4Tags.mc4 | 35 +++++ .../cdbasis4tags/_ast/ASTCDPackage.java | 9 ++ .../_symboltable/CDTypeSymbolDeSer.java | 21 +++ .../tagging/src/test/java/CDTest.java | 146 ++++++++++++++++++ .../src/test/java/FQNInheritedTagTest.java | 39 ++--- .../tagging/src/test/java/FQNTagTest.java | 33 ++-- .../src/test/java/NotQuiteAutomataTest.java | 5 +- .../test/java/TagSchemaSerializationTest.java | 1 - .../tagging/src/test/java/TagTest.java | 55 +++---- .../tagging/src/test/resources/models/Door.cd | 9 ++ .../models/DoorsThatAreOpenable.tags | 5 + 21 files changed, 564 insertions(+), 149 deletions(-) create mode 100644 monticore-generator/src/main/resources/tagging/itagger/GetTagsFromRepo.ftl create mode 100644 monticore-generator/src/main/resources/tagging/tagger/AddTagSymbol.ftl create mode 100644 monticore-grammar/src/main/java/de/monticore/tagging/TagRepository.java create mode 100644 monticore-test/01.experiments/tagging/src/main/grammars/de/monticore/tagtest/CDBasis4Tags.mc4 create mode 100644 monticore-test/01.experiments/tagging/src/main/java/de/monticore/tagtest/cdbasis4tags/_ast/ASTCDPackage.java create mode 100644 monticore-test/01.experiments/tagging/src/main/java/de/monticore/tagtest/cdbasis4tags/_symboltable/CDTypeSymbolDeSer.java create mode 100644 monticore-test/01.experiments/tagging/src/test/java/CDTest.java create mode 100644 monticore-test/01.experiments/tagging/src/test/resources/models/Door.cd create mode 100644 monticore-test/01.experiments/tagging/src/test/resources/models/DoorsThatAreOpenable.tags diff --git a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_tagging/TaggerDecorator.java b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_tagging/TaggerDecorator.java index a42746bbfe..9850ee6a20 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_tagging/TaggerDecorator.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/cd2java/_tagging/TaggerDecorator.java @@ -3,7 +3,6 @@ import de.monticore.cd.methodtemplates.CD4C; import de.monticore.cd4code.CD4CodeMill; -import de.monticore.cd4codebasis._ast.ASTCDConstructor; import de.monticore.cd4codebasis._ast.ASTCDMethod; import de.monticore.cdbasis._ast.ASTCDClass; import de.monticore.cdbasis._ast.ASTCDElement; @@ -19,6 +18,7 @@ import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol; import de.monticore.grammar.grammar._symboltable.MCGrammarSymbolSurrogate; import de.monticore.grammar.grammar._symboltable.ProdSymbol; +import de.monticore.grammar.grammar._symboltable.ProdSymbolSurrogate; import de.monticore.symboltable.IScope; import de.monticore.tagging.tags._ast.*; import de.monticore.types.mcbasictypes._ast.ASTMCObjectType; @@ -27,7 +27,10 @@ import de.se_rwth.commons.StringTransformations; import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; import java.util.List; +import java.util.Set; import java.util.stream.Stream; import static de.monticore.cd.codegen.CD2JavaTemplates.EMPTY_BODY; @@ -73,7 +76,7 @@ public List decorate() { if (!superInterfaces.isEmpty()) { taggerInterface.setCDExtendUsage(CD4CodeMill.cDExtendUsageBuilder().addAllSuperclass(superInterfaces).build()); } - + CD4C.getInstance().addImport(taggerInterface, "de.monticore.tagging.TagRepository"); ASTCDClass taggerClass = CD4CodeMill.cDClassBuilder() .setModifier(PUBLIC.build()) @@ -84,6 +87,7 @@ public List decorate() { CD4C.getInstance().addImport(taggerClass, "de.monticore.tagging.tags.TagsMill"); CD4C.getInstance().addImport(taggerClass, "de.monticore.tagging.tags._ast.ASTContext"); CD4C.getInstance().addImport(taggerClass, "de.monticore.tagging.tags._ast.ASTTag"); + CD4C.getInstance().addImport(taggerClass, "de.monticore.tagging.tags._ast.ASTTagUnit"); CD4C.getInstance().addImport(taggerClass, "java.util.stream.Collectors"); CD4C.getInstance().addImport(taggerClass, "de.se_rwth.commons.Joiners"); elements.add(taggerClass); @@ -94,7 +98,7 @@ public List decorate() { // Skip left recursive productions // DISCUSS: Support for left-recursive if (prodSymbol.isIsDirectLeftRecursive() || prodSymbol.isIsIndirectLeftRecursive()) continue; - boolean isSymbolLike = prodSymbol.isIsSymbolDefinition() || MC2CDTaggingTranslation.hasName(prodSymbol); + boolean isSymbolLike = prodSymbol.isIsSymbolDefinition() || MC2CDTaggingTranslation.hasName(prodSymbol) || isIndirectSymbol(prodSymbol); taggerInterface.addAllCDMembers(createITaggerMethods(prodSymbol, taggerClass.getName())); taggerClass.addAllCDMembers(createTaggerMethods(prodSymbol, isSymbolLike)); @@ -125,18 +129,30 @@ protected List createITaggerMethods(ProdSymbol prodSymbol, String c List methods = new ArrayList<>(); ASTCDMethod m; + // I${Lang}Tagger.getTags(AST${prodSymbol.name} model, Iterable astTagUnits) methods.add((m = cdMethodFacade.createMethod(PACKAGE_PRIVATE.build(), mcTypeFacade.createListTypeOf(ASTTag.class.getName()), "getTags", cdParameterFacade.createParameter(astFQN, "model"), - cdParameterFacade.createParameter(ASTTagUnit.class.getName(), "astTagUnit")))); + cdParameterFacade.createParameter(mcTypeFacade.createBasicGenericTypeOf(Iterable.class.getName(), ASTTagUnit.class.getName()), "astTagUnits")))); this.replaceTemplate(EMPTY_BODY, m, new TemplateHookPoint("tagging.itagger.GetTags", clazzname)); + // I${Lang}Tagger.getTags(AST${prodSymbol.name} model) + methods.add((m = cdMethodFacade.createMethod(PACKAGE_PRIVATE.build(), mcTypeFacade.createListTypeOf(ASTTag.class.getName()), + "getTags", + cdParameterFacade.createParameter(astFQN, "model")))); + this.replaceTemplate(EMPTY_BODY, m, new TemplateHookPoint("tagging.itagger.GetTagsFromRepo", clazzname)); if (prodSymbol.isIsSymbolDefinition()) { + // I${Lang}Tagger.getTags({prodSymbol.name}Symbol symbol, Iterable astTagUnits) methods.add((m = cdMethodFacade.createMethod(PACKAGE_PRIVATE.build(), mcTypeFacade.createListTypeOf(ASTTag.class.getName()), "getTags", cdParameterFacade.createParameter(symbolFQN, "model"), - cdParameterFacade.createParameter(ASTTagUnit.class.getName(), "astTagUnit")))); + cdParameterFacade.createParameter(mcTypeFacade.createBasicGenericTypeOf(Iterable.class.getName(), ASTTagUnit.class.getName()), "astTagUnits")))); this.replaceTemplate(EMPTY_BODY, m, new TemplateHookPoint("tagging.itagger.GetTags", clazzname)); + // I${Lang}Tagger.getTags({prodSymbol.name}Symbol symbol) + methods.add((m = cdMethodFacade.createMethod(PACKAGE_PRIVATE.build(), mcTypeFacade.createListTypeOf(ASTTag.class.getName()), + "getTags", + cdParameterFacade.createParameter(symbolFQN, "model")))); + this.replaceTemplate(EMPTY_BODY, m, new TemplateHookPoint("tagging.itagger.GetTagsFromRepo", clazzname)); } methods.add((m = cdMethodFacade.createMethod(PACKAGE_PRIVATE.build(), mcTypeFacade.createBooleanType(), @@ -166,19 +182,21 @@ protected List createTaggerMethods(ProdSymbol prodSymbol, boolean i List methods = new ArrayList<>(); ASTCDMethod method; + // ${Lang}Tagger.getTags(AST${prodSymbol.name} model, Iterable astTagUnits) methods.add((method = cdMethodFacade.createMethod(PUBLIC.build(), mcTypeFacade.createListTypeOf(ASTTag.class.getName()), "getTags", cdParameterFacade.createParameter(astFQN, "model"), - cdParameterFacade.createParameter(ASTTagUnit.class.getName(), "astTagUnit")))); + cdParameterFacade.createParameter(mcTypeFacade.createBasicGenericTypeOf(Iterable.class.getName(), ASTTagUnit.class.getName()), "astTagUnits")))); this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("tagging.tagger.GetTags", prodSymbol.getName(), isSymbolLike)); if (prodSymbol.isIsSymbolDefinition()) { + // ${Lang}Tagger.getTags(${prodSymbol.name}Symbol symbol, Iterable astTagUnits) methods.add((method = cdMethodFacade.createMethod(PUBLIC.build(), mcTypeFacade.createListTypeOf(ASTTag.class.getName()), "getTags", cdParameterFacade.createParameter(symbolFQN, "symbol"), - cdParameterFacade.createParameter(ASTTagUnit.class.getName(), "astTagUnit")))); + cdParameterFacade.createParameter(mcTypeFacade.createBasicGenericTypeOf(Iterable.class.getName(), ASTTagUnit.class.getName()), "astTagUnits")))); this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("tagging.tagger.GetTagsSymbol", prodSymbol.getName())); } @@ -191,14 +209,26 @@ protected List createTaggerMethods(ProdSymbol prodSymbol, boolean i ))); this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("tagging.tagger.RemoveTag", prodSymbol.getName(), isSymbolLike)); - methods.add((method = cdMethodFacade.createMethod(PUBLIC.build(), - "addTag", - cdParameterFacade.createParameter(astFQN, "model"), - cdParameterFacade.createParameter(ASTTagUnit.class.getName(), "astTagUnit"), - cdParameterFacade.createParameter(ASTTag.class.getName(), "astTag") - ))); - this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("tagging.tagger.AddTag", - prodSymbol.getName(), originalGrammar.getName(), getPackageName(originalGrammar.getSymbol()), prodSymbol.isIsSymbolDefinition())); + if (!prodSymbol.isIsInterface()) { + methods.add((method = cdMethodFacade.createMethod(PUBLIC.build(), + "addTag", + cdParameterFacade.createParameter(astFQN, "model"), + cdParameterFacade.createParameter(ASTTagUnit.class.getName(), "astTagUnit"), + cdParameterFacade.createParameter(ASTTag.class.getName(), "astTag") + ))); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("tagging.tagger.AddTag", + prodSymbol.getName(), originalGrammar.getName(), getPackageName(originalGrammar.getSymbol()), prodSymbol.isIsSymbolDefinition())); + } + if (prodSymbol.isIsSymbolDefinition()) { + methods.add((method = cdMethodFacade.createMethod(PUBLIC.build(), + "addTag", + cdParameterFacade.createParameter(symbolFQN, "symbol"), + cdParameterFacade.createParameter(ASTTagUnit.class.getName(), "astTagUnit"), + cdParameterFacade.createParameter(ASTTag.class.getName(), "astTag") + ))); + this.replaceTemplate(EMPTY_BODY, method, new TemplateHookPoint("tagging.tagger.AddTagSymbol", + prodSymbol.getName(), originalGrammar.getName(), getPackageName(originalGrammar.getSymbol()))); + } methods.add((method = cdMethodFacade.createMethod(PROTECTED.build(), mcTypeFacade.createBasicGenericTypeOf(Stream.class.getName(), ASTTargetElement.class.getName()), @@ -266,4 +296,31 @@ protected String getMillName(MCGrammarSymbol symbol) { protected String getPackageName(MCGrammarSymbol symbol) { return Names.getQualifiedName(symbol.getPackageName(), symbol.getName().toLowerCase()); } + + // Does this production extend a symbol production + protected boolean isIndirectSymbol(ProdSymbol symbol){ + if (symbol.isIsSymbolDefinition()) return true; + LinkedList toCheck = new LinkedList<>(); + Set checked = new HashSet<>(); + toCheck.add(symbol); + while (!toCheck.isEmpty()) { + ProdSymbol symbolToCheck = toCheck.removeFirst(); + if (symbolToCheck.isIsSymbolDefinition()) return true; + for (ProdSymbolSurrogate surg : symbolToCheck.getSuperProds()){ + ProdSymbol sym = surg.lazyLoadDelegate(); + if (sym.isIsSymbolDefinition()) return true; + if (checked.contains(sym)) continue; + toCheck.add(sym); + checked.add(sym); + } + for (ProdSymbolSurrogate surg : symbolToCheck.getSuperInterfaceProds()){ + ProdSymbol sym = surg.lazyLoadDelegate(); + if (sym.isIsSymbolDefinition()) return true; + if (checked.contains(sym)) continue; + toCheck.add(sym); + checked.add(sym); + } + } + return false; + } } diff --git a/monticore-generator/src/main/java/de/monticore/tagging/TagDefinitionDerivVisitor.java b/monticore-generator/src/main/java/de/monticore/tagging/TagDefinitionDerivVisitor.java index 831833945e..c0b77ce745 100644 --- a/monticore-generator/src/main/java/de/monticore/tagging/TagDefinitionDerivVisitor.java +++ b/monticore-generator/src/main/java/de/monticore/tagging/TagDefinitionDerivVisitor.java @@ -65,12 +65,7 @@ public void visit(ASTClassProd node) { @Override public void visit(ASTInterfaceProd node) { - if (node.getSymbol().isIsDirectLeftRecursive() || node.getSymbol().isIsIndirectLeftRecursive()) { - grammar.add_PostComment(new Comment("/* Unable to create a TagDef Identifier for left-recursive interface " + node.getName() + " */")); - Log.warn("0xA5C13 Unable to create a TagDef Identifier for left-recursive interface " + node.getName(), node.get_SourcePositionStart()); - return; - } - createSpecificIdentifier(node); + // We do not generate (specific) identifiers based on the CS for interfaces } protected void createSpecificIdentifier(ASTProd node) { diff --git a/monticore-generator/src/main/resources/tagging/itagger/GetTags.ftl b/monticore-generator/src/main/resources/tagging/itagger/GetTags.ftl index bb6cb0c0eb..9786d12833 100644 --- a/monticore-generator/src/main/resources/tagging/itagger/GetTags.ftl +++ b/monticore-generator/src/main/resources/tagging/itagger/GetTags.ftl @@ -1,3 +1,3 @@ <#-- (c) https://github.com/MontiCore/monticore --> ${tc.signature("clazzname")} -return ${clazzname}.getInstance().getTags(model, astTagUnit); +return ${clazzname}.getInstance().getTags(model, astTagUnits); diff --git a/monticore-generator/src/main/resources/tagging/itagger/GetTagsFromRepo.ftl b/monticore-generator/src/main/resources/tagging/itagger/GetTagsFromRepo.ftl new file mode 100644 index 0000000000..fe1c624668 --- /dev/null +++ b/monticore-generator/src/main/resources/tagging/itagger/GetTagsFromRepo.ftl @@ -0,0 +1,3 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("clazzname")} +return ${clazzname}.getInstance().getTags(model, TagRepository.getLoadedTagUnits()); diff --git a/monticore-generator/src/main/resources/tagging/tagger/AddTagSymbol.ftl b/monticore-generator/src/main/resources/tagging/tagger/AddTagSymbol.ftl new file mode 100644 index 0000000000..1359062f40 --- /dev/null +++ b/monticore-generator/src/main/resources/tagging/tagger/AddTagSymbol.ftl @@ -0,0 +1,13 @@ +<#-- (c) https://github.com/MontiCore/monticore --> +${tc.signature("prodname", "grammarname", "package")} +<#-- isSymbol: true for symbols --> +astTagUnit.addTags( + TagsMill.targetElementBuilder() + .addModelElementIdentifier( + TagsMill.defaultIdentBuilder().setMCQualifiedName( + TagsMill.mCQualifiedNameBuilder().setPartsList(de.se_rwth.commons.Splitters.QUALIFIED_NAME_DELIMITERS.splitToList(symbol.getFullName())).build() + ).build() + ) + .addTag(astTag) + .build() +); \ No newline at end of file diff --git a/monticore-generator/src/main/resources/tagging/tagger/GetArtifactScope.ftl b/monticore-generator/src/main/resources/tagging/tagger/GetArtifactScope.ftl index febb951aba..d022844aba 100644 --- a/monticore-generator/src/main/resources/tagging/tagger/GetArtifactScope.ftl +++ b/monticore-generator/src/main/resources/tagging/tagger/GetArtifactScope.ftl @@ -1,8 +1,6 @@ <#-- (c) https://github.com/MontiCore/monticore --> ${tc.signature("millname")} -// While we could use instanceof, we instead use the semantic knowledge, that artifact scopes are subscopes of a global scope -List globalChildren = ${millname}.globalScope().getSubScopes(); -while (!(globalChildren.contains(s))) { +while (!(s instanceof de.monticore.symboltable.IArtifactScope)) { s = s.getEnclosingScope(); } return s; diff --git a/monticore-generator/src/main/resources/tagging/tagger/GetTags.ftl b/monticore-generator/src/main/resources/tagging/tagger/GetTags.ftl index 1e85ad75cc..a88449f331 100644 --- a/monticore-generator/src/main/resources/tagging/tagger/GetTags.ftl +++ b/monticore-generator/src/main/resources/tagging/tagger/GetTags.ftl @@ -4,43 +4,44 @@ ${tc.signature("prodname", "hasName")} <#-- isSymbol: true for symbols --> List< ASTTag> tags = new ArrayList<>(); -List< String> scopeStack = getScopeDifferences(model.getEnclosingScope(), getArtifactScope(model.getEnclosingScope())); - List< ASTContext> contexts; -if (scopeStack.isEmpty()) { - <#if hasName>findTargetsBy(astTagUnit, model.getName()).forEach(t -> tags.addAll(t.getTagList())); - findTargetsBy(astTagUnit, model).forEach(t -> tags.addAll(t.getTagList())); -} else { - // within/context must always be on scopes, so we can use name matching instead of pattern matching - <#if hasName>scopeStack.add(model.getName()); +for (ASTTagUnit astTagUnit : astTagUnits) { + List< String> scopeStack = getScopeDifferences(model.getEnclosingScope(), getArtifactScope(model.getEnclosingScope())); + if (scopeStack.isEmpty()) { + <#if hasName>findTargetsBy(astTagUnit, model.getName()).forEach(t -> tags.addAll(t.getTagList())); + findTargetsBy(astTagUnit, model).forEach(t -> tags.addAll(t.getTagList())); + } else { + // within/context must always be on scopes, so we can use name matching instead of pattern matching + <#if hasName>scopeStack.add(model.getName()); - contexts = findContextBy(astTagUnit, scopeStack.get(0)).collect(Collectors.toList()); + contexts = findContextBy(astTagUnit, scopeStack.get(0)).collect(Collectors.toList()); - <#if hasName> - String joinedNames = Joiners.DOT.join(scopeStack); - findTargetsBy(astTagUnit, joinedNames).forEach(t -> tags.addAll(t.getTagList())); - + <#if hasName> + String joinedNames = Joiners.DOT.join(scopeStack); + findTargetsBy(astTagUnit, joinedNames).forEach(t -> tags.addAll(t.getTagList())); + - scopeStack.remove(0); + scopeStack.remove(0); - while (scopeStack.size() > 1) { - List< ASTContext> tempContexts = contexts; - contexts = new ArrayList<>(); - <#if hasName>joinedNames = Joiners.DOT.join(scopeStack); - String name = scopeStack.remove(0); + while (scopeStack.size() > 1) { + List< ASTContext> tempContexts = contexts; + contexts = new ArrayList<>(); + <#if hasName>joinedNames = Joiners.DOT.join(scopeStack); + String name = scopeStack.remove(0); - for (ASTContext context : tempContexts) { - findContextBy(context, name).forEach(contexts::add); - <#if hasName>findTargetsBy(context, joinedNames).forEach(t -> tags.addAll(t.getTagList())); + for (ASTContext context : tempContexts) { + findContextBy(context, name).forEach(contexts::add); + <#if hasName>findTargetsBy(context, joinedNames).forEach(t -> tags.addAll(t.getTagList())); + } + } + for (ASTContext context : contexts) { + <#if hasName> + findTargetsBy(context, scopeStack.get(0)).forEach(t -> tags.addAll(t.getTagList())); + <#else> + findTargetsBy(context, model).forEach(t -> tags.addAll(t.getTagList())); + } - } - for (ASTContext context : contexts) { - <#if hasName> - findTargetsBy(context, scopeStack.get(0)).forEach(t -> tags.addAll(t.getTagList())); - <#else> - findTargetsBy(context, model).forEach(t -> tags.addAll(t.getTagList())); - - } + } } return tags; diff --git a/monticore-generator/src/main/resources/tagging/tagger/GetTagsSymbol.ftl b/monticore-generator/src/main/resources/tagging/tagger/GetTagsSymbol.ftl index 5d281d3ece..1b01a95ef8 100644 --- a/monticore-generator/src/main/resources/tagging/tagger/GetTagsSymbol.ftl +++ b/monticore-generator/src/main/resources/tagging/tagger/GetTagsSymbol.ftl @@ -2,37 +2,36 @@ ${tc.signature("prodname")} List< ASTTag> tags = new ArrayList<>(); -List< String> scopeStack = getScopeDifferences(symbol.getEnclosingScope(), getArtifactScope(symbol.getEnclosingScope())); - - List< ASTContext> contexts; -if (scopeStack.isEmpty()) { - findTargetsBy(astTagUnit, symbol.getName()).forEach(t -> tags.addAll(t.getTagList())); -} else { - // within/context must always be on scopes, so we can use name matching instead of pattern matching - scopeStack.add(symbol.getName()); - - contexts = findContextBy(astTagUnit, scopeStack.get(0)).collect(Collectors.toList()); - - String joinedNames = Joiners.DOT.join(scopeStack); - findTargetsBy(astTagUnit, joinedNames).forEach(t -> tags.addAll(t.getTagList())); - - scopeStack.remove(0); - - while (scopeStack.size() > 1) { - List< ASTContext> tempContexts = contexts; - contexts = new ArrayList<>(); - joinedNames = Joiners.DOT.join(scopeStack); - String name = scopeStack.remove(0); - - for (ASTContext context : tempContexts) { - findContextBy(context, name).forEach(contexts::add); - findTargetsBy(context, joinedNames).forEach(t -> tags.addAll(t.getTagList())); +for (ASTTagUnit astTagUnit : astTagUnits) { + List< String> scopeStack = getScopeDifferences(symbol.getEnclosingScope(), getArtifactScope(symbol.getEnclosingScope())); + if (scopeStack.isEmpty()) { + findTargetsBy(astTagUnit, symbol.getName()).forEach(t -> tags.addAll(t.getTagList())); + } else { + // within/context must always be on scopes, so we can use name matching instead of pattern matching + scopeStack.add(symbol.getName()); + + contexts = findContextBy(astTagUnit, scopeStack.get(0)).collect(Collectors.toList()); + + String joinedNames = Joiners.DOT.join(scopeStack); + findTargetsBy(astTagUnit, joinedNames).forEach(t -> tags.addAll(t.getTagList())); + + scopeStack.remove(0); + + while (scopeStack.size() > 1) { + List< ASTContext> tempContexts = contexts; + contexts = new ArrayList<>(); + joinedNames = Joiners.DOT.join(scopeStack); + String name = scopeStack.remove(0); + + for (ASTContext context : tempContexts) { + findContextBy(context, name).forEach(contexts::add); + findTargetsBy(context, joinedNames).forEach(t -> tags.addAll(t.getTagList())); + } + } + for (ASTContext context : contexts) { + findTargetsBy(context, scopeStack.get(0)).forEach(t -> tags.addAll(t.getTagList())); } } - for (ASTContext context : contexts) { - findTargetsBy(context, scopeStack.get(0)).forEach(t -> tags.addAll(t.getTagList())); - } - } return tags; diff --git a/monticore-grammar/src/main/java/de/monticore/tagging/TagRepository.java b/monticore-grammar/src/main/java/de/monticore/tagging/TagRepository.java new file mode 100644 index 0000000000..080f9278b8 --- /dev/null +++ b/monticore-grammar/src/main/java/de/monticore/tagging/TagRepository.java @@ -0,0 +1,99 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.tagging; + +import com.google.common.collect.Iterables; +import de.monticore.tagging.tags.TagsMill; +import de.monticore.tagging.tags._ast.ASTTagUnit; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class TagRepository { + + // A cache for tag models loaded from files + protected static Map loadedFileTags = new HashMap<>(); + + // And a cache for temporary tag models + protected static Map loadedTags = new HashMap<>(); + + /** + * Load a new tag model into this repository + * @param file location of the tag model + * @return an empty optional in case the parsing failed, otherwise the tag model + */ + public static Optional loadTagModel(File file) throws IOException { + Optional tagUnitOpt = TagsMill.parser().parse(file.getAbsolutePath()); + if (tagUnitOpt.isEmpty()) + return tagUnitOpt; + loadedFileTags.put(file, tagUnitOpt.get()); + return tagUnitOpt; + } + + /** + * Create a new (temporary) tag model in this repository. + * In case a tag model of this name is already present, + * this already present model is returned. + * Otherwise, a new tag model with the given name is returned and stored in this repository + * @param name the name of the tag model + * @return a tag model with the given name + */ + public static Optional loadTempTagModel(String name) { + if (loadedTags.containsKey(name)) + return Optional.of(loadedTags.get(name)); + ASTTagUnit unit = TagsMill.tagUnitBuilder() + .setName(name) + .build(); + loadedTags.put(name, unit); + return Optional.of(unit); + } + + /** + * Unload a given tag model + * @param tagUnit the tag model + * @return true iff the tag model was unloaded from this repository + */ + public static boolean unloadTagModel(ASTTagUnit tagUnit) { + return loadedFileTags.values().remove(tagUnit) + | loadedTags.remove(tagUnit.getName()) != null; + } + + /** + * Unload a tag model by its file, + * loaded by {@link #loadTagModel(File)} + * @param file location of the tag model + * @return true if the model was stored in this repository + */ + public static boolean unloadTagModel(File file){ + return loadedFileTags.remove(file) != null; + } + + /** + * Unload a (temporary) tag model by its name, + * loaded by {@link #loadTempTagModel(String)} + * @param name the name given when loading the model + * @return true if the model was stored in this repository + */ + public static boolean unloadTempTagModel(String name){ + return loadedTags.remove(name) != null; + } + + /** + * @return an Iterable over all loaded tag models + */ + public static Iterable getLoadedTagUnits() { + return Iterables.concat(loadedFileTags.values(), loadedTags.values()); + } + + /** + * Unload all tag models + */ + public static void clearTags() { + loadedFileTags.clear(); + loadedTags.clear(); + } +} + diff --git a/monticore-test/01.experiments/tagging/build.gradle b/monticore-test/01.experiments/tagging/build.gradle index 1bf6b7b209..5be0ad01e5 100644 --- a/monticore-test/01.experiments/tagging/build.gradle +++ b/monticore-test/01.experiments/tagging/build.gradle @@ -78,3 +78,25 @@ task generateEnhancedFQNTagSchema (type: MCTask, dependsOn: generateEnhancedFQN) def uptoDate = incCheck("de/monticore/fqn/FQNEnhancedAutomataTagSchema.mc4") outputs.upToDateWhen { uptoDate } } + +// +task generateCDBasis4Tags (type: MCTask) { + grammar = file "$projectDir/$grammarDir/de/monticore/tagtest/CDBasis4Tags.mc4" + outputDir = file outDir + def uptoDate = incCheck("de/monticore/tagtest/CDBasis4Tags.mc4") + outputs.upToDateWhen { uptoDate } +} + +task generateCDBasis4TagsTagDefinition (type: MCTask, dependsOn: generateCDBasis4Tags) { + grammar = file "$grammarOutDir/de/monticore/tagtest/CDBasis4TagsTagDefinition.mc4" + outputDir = file outDir + def uptoDate = incCheck("de/monticore/tagtest/CDBasis4TagsTagDefinition.mc4") + outputs.upToDateWhen { uptoDate } + genTag = true // generate tagging related infrastructure, such as the Taggers +} +task generateCDBasis4TagsTagSchema (type: MCTask, dependsOn: generateCDBasis4Tags) { + grammar = file "$grammarOutDir/de/monticore/tagtest/CDBasis4TagsTagSchema.mc4" + outputDir = file outDir + def uptoDate = incCheck("de/monticore/tagtest/CDBasis4TagsTagSchema.mc4") + outputs.upToDateWhen { uptoDate } +} diff --git a/monticore-test/01.experiments/tagging/src/main/grammars/de/monticore/tagtest/CDBasis4Tags.mc4 b/monticore-test/01.experiments/tagging/src/main/grammars/de/monticore/tagtest/CDBasis4Tags.mc4 new file mode 100644 index 0000000000..59205d4b13 --- /dev/null +++ b/monticore-test/01.experiments/tagging/src/main/grammars/de/monticore/tagtest/CDBasis4Tags.mc4 @@ -0,0 +1,35 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.tagtest; + +grammar CDBasis4Tags extends de.monticore.MCBasics, de.monticore.symbols.OOSymbols, de.monticore.types.MCBasicTypes, + de.monticore.UMLStereotype, de.monticore.UMLModifier { + + CDCompilationUnit = + CDDefinition; + + + interface CDElement; + interface symbol scope CDType extends CDElement, OOType; + + + scope symbol CDPackage implements CDElement = + "package" MCQualifiedName "{" + CDElement* + "}"; + + scope CDClass implements CDType = + Modifier "class" Name + ( "{" + CDMember* + "}" + | ";" ); + + interface CDMember; + + CDAttribute implements CDMember, Field = Modifier MCType Name ";"; + + CDDefinition implements Diagram = + Modifier "classdiagram" Name "{" CDElement* "}"; + + +} diff --git a/monticore-test/01.experiments/tagging/src/main/java/de/monticore/tagtest/cdbasis4tags/_ast/ASTCDPackage.java b/monticore-test/01.experiments/tagging/src/main/java/de/monticore/tagtest/cdbasis4tags/_ast/ASTCDPackage.java new file mode 100644 index 0000000000..b250ca30b6 --- /dev/null +++ b/monticore-test/01.experiments/tagging/src/main/java/de/monticore/tagtest/cdbasis4tags/_ast/ASTCDPackage.java @@ -0,0 +1,9 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.tagtest.cdbasis4tags._ast; + +public class ASTCDPackage extends ASTCDPackageTOP { + @Override + public String getName() { + return getMCQualifiedName().getQName(); + } +} diff --git a/monticore-test/01.experiments/tagging/src/main/java/de/monticore/tagtest/cdbasis4tags/_symboltable/CDTypeSymbolDeSer.java b/monticore-test/01.experiments/tagging/src/main/java/de/monticore/tagtest/cdbasis4tags/_symboltable/CDTypeSymbolDeSer.java new file mode 100644 index 0000000000..16f3d93862 --- /dev/null +++ b/monticore-test/01.experiments/tagging/src/main/java/de/monticore/tagtest/cdbasis4tags/_symboltable/CDTypeSymbolDeSer.java @@ -0,0 +1,21 @@ +/* (c) https://github.com/MontiCore/monticore */ +package de.monticore.tagtest.cdbasis4tags._symboltable; + +import de.monticore.symboltable.serialization.json.JsonObject; +import de.monticore.types.check.SymTypeExpression; + +import java.util.ArrayList; +import java.util.List; + +public class CDTypeSymbolDeSer extends CDTypeSymbolDeSerTOP { + + @Override + protected void serializeSuperTypes(List superTypes, CDBasis4TagsSymbols2Json s2j) { + // stub + } + + @Override + protected List deserializeSuperTypes(JsonObject symbolJson) { + return new ArrayList<>(); // stub + } +} diff --git a/monticore-test/01.experiments/tagging/src/test/java/CDTest.java b/monticore-test/01.experiments/tagging/src/test/java/CDTest.java new file mode 100644 index 0000000000..253f3ff416 --- /dev/null +++ b/monticore-test/01.experiments/tagging/src/test/java/CDTest.java @@ -0,0 +1,146 @@ +/* (c) https://github.com/MontiCore/monticore */ +import de.monticore.ast.ASTNode; +import de.monticore.tagging.tags.TagsMill; +import de.monticore.tagging.tags._ast.ASTSimpleTag; +import de.monticore.tagging.tags._ast.ASTTag; +import de.monticore.tagging.tags._ast.ASTTagUnit; +import de.monticore.tagging.tags._ast.ASTValuedTag; +import de.monticore.tagtest.cdbasis4tags._ast.ASTCDClass; +import de.monticore.tagtest.cdbasis4tags._ast.ASTCDCompilationUnit; +import de.monticore.tagtest.cdbasis4tagstagdefinition.CDBasis4TagsTagDefinitionMill; +import de.monticore.tagtest.cdbasis4tags.CDBasis4TagsMill; +import de.monticore.umlstereotype.UMLStereotypeMill; +import de.monticore.umlstereotype._ast.ASTStereoValue; +import de.monticore.umlstereotype._ast.ASTStereoValueBuilder; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import de.monticore.tagging.TagRepository; +import de.monticore.tagtest.cdbasis4tags._tagging.CDBasis4TagsTagger; + +import de.monticore.tagtest.cdbasis4tags._visitor.CDBasis4TagsVisitor2; +import de.monticore.tagtest.cdbasis4tags._visitor.CDBasis4TagsTraverser; +import java.io.File; +import java.util.*; + +/** + * This test aims to replicate parts of CD4A to test the tagging infrastucture + * in regards to interface usage (such as types) + * + * In addition, we demonstrate the interaction between tags and stereotypes + */ +public class CDTest { + @BeforeClass + public static void init() { + CDBasis4TagsTagDefinitionMill.init(); + } + + @Test + public void test() throws Exception{ + Optional ast = CDBasis4TagsMill.parser().parse(new File("src/test/resources/models/Door.cd").toString()); + Assert.assertTrue(ast.isPresent()); + CDBasis4TagsMill.scopesGenitorDelegator().createFromAST(ast.get()); + + + Optional doorsThatAreOpenableTags = TagRepository.loadTagModel(new File("src/test/resources/models/DoorsThatAreOpenable.tags")); + Assert.assertTrue(doorsThatAreOpenableTags.isPresent()); + + Optional theDoorSymbol = ast.get().getEnclosingScope().resolveCDType("TheDoor"); + Optional aSingleDoorSymbol = ast.get().getEnclosingScope().resolveCDType("ASingleDoor"); + Assert.assertTrue(theDoorSymbol.isPresent()); + Assert.assertTrue(aSingleDoorSymbol.isPresent()); + + List tagsForTheDoor = new ArrayList<>(CDBasis4TagsTagger.getInstance().getTags(theDoorSymbol.get())); + Assert.assertEquals(1, tagsForTheDoor.size()); + + List tagsForASingleDoor = new ArrayList<>(CDBasis4TagsTagger.getInstance().getTags(aSingleDoorSymbol.get())); + Assert.assertEquals(1, tagsForASingleDoor.size()); + + + // Turn stereos into tags + ASTTagUnit tempTagUnit = TagRepository.loadTempTagModel("temp").get(); + tagsFromStereo(ast.get(), tempTagUnit); + + tagsForASingleDoor.addAll(CDBasis4TagsTagger.getInstance().getTags(aSingleDoorSymbol.get())); + Assert.assertEquals(2, tagsForASingleDoor.size()); + + stereoFromTags(ast.get(), Collections.singleton(doorsThatAreOpenableTags.get())); + + String pretty = CDBasis4TagsMill.prettyPrint(ast.get(), false); + } + + // The Stereo<->Tag tooling should be, eventually, generated + protected void tagsFromStereo(ASTNode astNode, ASTTagUnit tagUnit) { + CDBasis4TagsTraverser t = CDBasis4TagsMill.traverser(); + t.add4CDBasis4Tags(new CDBasis4TagsFromStereo(tagUnit)); + + astNode.accept(t); + } + + // The Stereo<->Tag tooling should be, eventually, generated + protected void stereoFromTags(ASTNode astNode, Collection tagUnits) { + CDBasis4TagsTraverser t = CDBasis4TagsMill.traverser(); + t.add4CDBasis4Tags(new CDBasis4TagsToStereo(tagUnits)); + + astNode.accept(t); + } + + // The Stereo<->Tag tooling should be, eventually, generated + class CDBasis4TagsFromStereo implements CDBasis4TagsVisitor2 { + + protected ASTTagUnit tagUnit; + + public CDBasis4TagsFromStereo(ASTTagUnit tagUnit) { + this.tagUnit = tagUnit; + } + + @Override + public void visit(ASTCDClass node) { + if (node.getModifier().isPresentStereotype()) { + for (ASTStereoValue value: node.getModifier().getStereotype().getValuesList()) { + CDBasis4TagsTagger.getInstance().addTag(node, tagUnit, getTagFromStereo(value)); + } + } + } + } + + // The Stereo<->Tag tooling should be, eventually, generated + class CDBasis4TagsToStereo implements CDBasis4TagsVisitor2 { + + protected Collection tagUnits; + + public CDBasis4TagsToStereo(Collection tagUnits) { + this.tagUnits = tagUnits; + } + + @Override + public void visit(ASTCDClass node) { + List tags = CDBasis4TagsTagger.getInstance().getTags(node, this.tagUnits); + for (ASTTag tag : tags) { + if (!node.getModifier().isPresentStereotype()) + node.getModifier().setStereotype(UMLStereotypeMill.stereotypeBuilder().build()); + + ASTStereoValueBuilder builder = UMLStereotypeMill.stereoValueBuilder(); + if (tag instanceof ASTSimpleTag) { + builder.setName(((ASTSimpleTag) tag).getName()); + builder.setContent(""); + } else if (tag instanceof ASTValuedTag) { + builder.setName(((ASTValuedTag) tag).getName()); + builder.setName(((ASTValuedTag) tag).getValue()); + } + node.getModifier().getStereotype().addValues(builder.build()); + } + } + } + + protected ASTTag getTagFromStereo(ASTStereoValue value) { + if (value.getValue().isEmpty()) { + return TagsMill.simpleTagBuilder().setName(value.getName()).build(); + } + return TagsMill.valuedTagBuilder() + .setName(value.getName()) + .setValue(value.getValue()) + .build(); + } + +} diff --git a/monticore-test/01.experiments/tagging/src/test/java/FQNInheritedTagTest.java b/monticore-test/01.experiments/tagging/src/test/java/FQNInheritedTagTest.java index 3a13f00b65..e56574bc7b 100644 --- a/monticore-test/01.experiments/tagging/src/test/java/FQNInheritedTagTest.java +++ b/monticore-test/01.experiments/tagging/src/test/java/FQNInheritedTagTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import util.TestUtil; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -76,55 +77,55 @@ public void visit(ASTRedState node) { @Test public void testAutomaton() { - List tags = fqnAutomataTagger.getTags(model, tagDefinition); + List tags = fqnAutomataTagger.getTags(model, Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "Method", "App.call()"); } @Test public void testStateA() { - List tags = fqnAutomataTagger.getTags(states.get("A"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("A"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "Monitored"); } @Test public void testStateB() { - List tags = fqnAutomataTagger.getTags(states.get("B"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("B"), Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); } @Test public void testStateBA() { - List tags = fqnAutomataTagger.getTags(states.get("BA"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("BA"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag1"); } @Test public void testStateBB() { - List tags = fqnAutomataTagger.getTags(states.get("BB"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("BB"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag2"); } @Test public void testSomeScopeC() { - List tags = fqnAutomataTagger.getTags(model.getEnclosingScope().resolveScopedState("C").get().getAstNode(), tagDefinition); + List tags = fqnAutomataTagger.getTags(model.getEnclosingScope().resolveScopedState("C").get().getAstNode(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "Log", "doLogC"); } @Test public void testStateC_CA() { - List tags = fqnAutomataTagger.getTags(states.get("C.CA"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("C.CA"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag1"); } @Test public void testStateC_CB() { - List tags = fqnAutomataTagger.getTags(states.get("C.CB"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("C.CB"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag2"); } @@ -132,14 +133,14 @@ public void testStateC_CB() { @Test public void testSomeScopeC_Transition() { List tags = fqnAutomataTagger.getTags((ASTTransition) model.getEnclosingScope().resolveScopedState("C").get().getAstNode() - .getScopedStateElement(2), tagDefinition); + .getScopedStateElement(2), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "Log", "timestamp"); } @Test public void testStateD() { - List tags = fqnAutomataTagger.getTags(states.get("D"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("D"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "WildcardedTag"); } @@ -147,47 +148,47 @@ public void testStateD() { @Test public void testAddStateE() { ASTState stateE = states.get("E"); - List tags = fqnAutomataTagger.getTags(stateE, tagDefinition); + List tags = fqnAutomataTagger.getTags(stateE, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); // Add new Tag ASTTag tag = TagsMill.simpleTagBuilder().setName("TestTag").build(); fqnAutomataTagger.addTag(stateE, tagDefinition, tag); - tags = fqnAutomataTagger.getTags(stateE, tagDefinition); + tags = fqnAutomataTagger.getTags(stateE, Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "TestTag"); // Remove tag again fqnAutomataTagger.removeTag(stateE, tagDefinition, tag); - tags = fqnAutomataTagger.getTags(stateE, tagDefinition); + tags = fqnAutomataTagger.getTags(stateE, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); } @Test public void testAddTransition() { ASTTransition transition = TestUtil.getTransition(model).stream().filter(e->e.getFrom().equals("E") && e.getTo().equals("E")).findAny().get(); - List tags = fqnAutomataTagger.getTags(transition, tagDefinition); + List tags = fqnAutomataTagger.getTags(transition, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); // Add new Tag ASTTag tag = TagsMill.simpleTagBuilder().setName("TestTag").build(); fqnAutomataTagger.addTag(transition, tagDefinition, tag); - tags = fqnAutomataTagger.getTags(transition, tagDefinition); + tags = fqnAutomataTagger.getTags(transition, Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "TestTag"); // Remove tag again fqnAutomataTagger.removeTag(transition, tagDefinition, tag); - tags = fqnAutomataTagger.getTags(transition, tagDefinition); + tags = fqnAutomataTagger.getTags(transition, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); } @Test public void testStateRC_CA() { - List tags = fqnAutomataTagger.getTags(states.get("RC.CA"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("RC.CA"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag1"); } @Test public void testStateRC_RCB() { - List tags = fqnAutomataTagger.getTags(red_states.get("RC.RCB"), tagDefinition); + List tags = fqnAutomataTagger.getTags(red_states.get("RC.RCB"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag2"); } @@ -196,7 +197,7 @@ public void testStateRC_RCB() { public void testSomeScopeRC_Transition() { List tags = fqnAutomataTagger.getTags((ASTTransition) ((IFQNEnhancedAutomataScope) model.getEnclosingScope()) .resolveRedScopedState("RC").get().getAstNode() - .getScopedStateElement(2), tagDefinition); + .getScopedStateElement(2), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "Log", "timestamp"); } diff --git a/monticore-test/01.experiments/tagging/src/test/java/FQNTagTest.java b/monticore-test/01.experiments/tagging/src/test/java/FQNTagTest.java index 7d820f181e..7b87b34b5b 100644 --- a/monticore-test/01.experiments/tagging/src/test/java/FQNTagTest.java +++ b/monticore-test/01.experiments/tagging/src/test/java/FQNTagTest.java @@ -21,6 +21,7 @@ import org.junit.Test; import util.TestUtil; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -62,55 +63,55 @@ public void visit(ASTState node) { @Test public void testAutomaton() { - List tags = fqnAutomataTagger.getTags(model, tagDefinition); + List tags = fqnAutomataTagger.getTags(model, Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "Method", "App.call()"); } @Test public void testStateA() { - List tags = fqnAutomataTagger.getTags(states.get("A"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("A"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "Monitored"); } @Test public void testStateB() { - List tags = fqnAutomataTagger.getTags(states.get("B"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("B"), Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); } @Test public void testStateBA() { - List tags = fqnAutomataTagger.getTags(states.get("BA"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("BA"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag1"); } @Test public void testStateBB() { - List tags = fqnAutomataTagger.getTags(states.get("BB"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("BB"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag2"); } @Test public void testSomeScopeC() { - List tags = fqnAutomataTagger.getTags(model.getEnclosingScope().resolveScopedState("C").get().getAstNode(), tagDefinition); + List tags = fqnAutomataTagger.getTags(model.getEnclosingScope().resolveScopedState("C").get().getAstNode(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "VerboseLog", "doLogC"); } @Test public void testStateC_CA() { - List tags = fqnAutomataTagger.getTags(states.get("C.CA"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("C.CA"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag1"); } @Test public void testStateC_CB() { - List tags = fqnAutomataTagger.getTags(states.get("C.CB"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("C.CB"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag2"); } @@ -118,14 +119,14 @@ public void testStateC_CB() { @Test public void testSomeScopeC_Transition() { List tags = fqnAutomataTagger.getTags((ASTTransition) model.getEnclosingScope().resolveScopedState("C").get().getAstNode() - .getScopedStateElement(2), tagDefinition); + .getScopedStateElement(2), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "Log", "timestamp"); } @Test public void testStateD() { - List tags = fqnAutomataTagger.getTags(states.get("D"), tagDefinition); + List tags = fqnAutomataTagger.getTags(states.get("D"), Collections.singleton(tagDefinition)); Assert.assertEquals(2, tags.size()); assertSimpleTag(tags.get(0), "WildcardedTag"); } @@ -133,34 +134,34 @@ public void testStateD() { @Test public void testAddStateE() { ASTState stateE = states.get("E"); - List tags = fqnAutomataTagger.getTags(stateE, tagDefinition); + List tags = fqnAutomataTagger.getTags(stateE, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); // Add new Tag ASTTag tag = TagsMill.simpleTagBuilder().setName("TestTag").build(); fqnAutomataTagger.addTag(stateE, tagDefinition, tag); - tags = fqnAutomataTagger.getTags(stateE, tagDefinition); + tags = fqnAutomataTagger.getTags(stateE, Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "TestTag"); // Remove tag again fqnAutomataTagger.removeTag(stateE, tagDefinition, tag); - tags = fqnAutomataTagger.getTags(stateE, tagDefinition); + tags = fqnAutomataTagger.getTags(stateE, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); } @Test public void testAddTransition() { ASTTransition transition = TestUtil.getTransition(model).stream().filter(e->e.getFrom().equals("E") && e.getTo().equals("E")).findAny().get(); - List tags = fqnAutomataTagger.getTags(transition, tagDefinition); + List tags = fqnAutomataTagger.getTags(transition, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); // Add new Tag ASTTag tag = TagsMill.simpleTagBuilder().setName("TestTag").build(); fqnAutomataTagger.addTag(transition, tagDefinition, tag); - tags = fqnAutomataTagger.getTags(transition, tagDefinition); + tags = fqnAutomataTagger.getTags(transition, Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "TestTag"); // Remove tag again fqnAutomataTagger.removeTag(transition, tagDefinition, tag); - tags = fqnAutomataTagger.getTags(transition, tagDefinition); + tags = fqnAutomataTagger.getTags(transition, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); } diff --git a/monticore-test/01.experiments/tagging/src/test/java/NotQuiteAutomataTest.java b/monticore-test/01.experiments/tagging/src/test/java/NotQuiteAutomataTest.java index cba8cee371..2daf7a06fc 100644 --- a/monticore-test/01.experiments/tagging/src/test/java/NotQuiteAutomataTest.java +++ b/monticore-test/01.experiments/tagging/src/test/java/NotQuiteAutomataTest.java @@ -15,6 +15,7 @@ import org.junit.BeforeClass; import org.junit.Test; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -121,9 +122,9 @@ public void testYetAnotherSymbolProdCS() { doTest((ASTYetAnotherSymbolProd) nodes.get("YetAnotherSymbolProd YASP2"), automataTagger::getTags, "YASPTag"); } - protected void doTest(A ast, BiFunction> getTags, String name) { + protected void doTest(A ast, BiFunction, List> getTags, String name) { Assert.assertNotNull(ast); - List tags = getTags.apply(ast, tagDefinition); + List tags = getTags.apply(ast, Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), name); } diff --git a/monticore-test/01.experiments/tagging/src/test/java/TagSchemaSerializationTest.java b/monticore-test/01.experiments/tagging/src/test/java/TagSchemaSerializationTest.java index 52eaae3c93..aada37f8eb 100644 --- a/monticore-test/01.experiments/tagging/src/test/java/TagSchemaSerializationTest.java +++ b/monticore-test/01.experiments/tagging/src/test/java/TagSchemaSerializationTest.java @@ -69,7 +69,6 @@ public void test() throws IOException { IFQNEnhancedAutomataTagSchemaArtifactScope copy = schemaSymbols2Json.deserialize(serialized); - System.err.println(copy); String serializedCopy = schemaSymbols2Json.serialize(copy); Assert.assertEquals(serialized, serializedCopy); diff --git a/monticore-test/01.experiments/tagging/src/test/java/TagTest.java b/monticore-test/01.experiments/tagging/src/test/java/TagTest.java index 18dbafcd5d..ec52514079 100644 --- a/monticore-test/01.experiments/tagging/src/test/java/TagTest.java +++ b/monticore-test/01.experiments/tagging/src/test/java/TagTest.java @@ -22,6 +22,7 @@ import org.junit.BeforeClass; import org.junit.Test; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -64,28 +65,28 @@ public void visit(ASTState node) { @Test public void testAutomaton() { - List tags = automataTagger.getTags(model, tagDefinition); + List tags = automataTagger.getTags(model, Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "Method", "App.call()"); } @Test public void testAutomatonSymbol() { - List tags = automataTagger.getTags(model.getSymbol(), tagDefinition); + List tags = automataTagger.getTags(model.getSymbol(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "Method", "App.call()"); } @Test public void testStateA() { - List tags = automataTagger.getTags(states.get("A"), tagDefinition); + List tags = automataTagger.getTags(states.get("A"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "Monitored"); } @Test public void testStateASymbol() { - List tags = automataTagger.getTags(states.get("A").getSymbol(), tagDefinition); + List tags = automataTagger.getTags(states.get("A").getSymbol(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "Monitored"); } @@ -93,82 +94,82 @@ public void testStateASymbol() { @Test public void testStateB() { - List tags = automataTagger.getTags(states.get("B"), tagDefinition); + List tags = automataTagger.getTags(states.get("B"), Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); } @Test public void testStateBSymbol() { - List tags = automataTagger.getTags(states.get("B").getSymbol(), tagDefinition); + List tags = automataTagger.getTags(states.get("B").getSymbol(), Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); } @Test public void testStateBA() { - List tags = automataTagger.getTags(states.get("BA"), tagDefinition); + List tags = automataTagger.getTags(states.get("BA"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag1"); } @Test public void testStateBASymbol() { - List tags = automataTagger.getTags(states.get("BA").getSymbol(), tagDefinition); + List tags = automataTagger.getTags(states.get("BA").getSymbol(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag1"); } @Test public void testStateBB() { - List tags = automataTagger.getTags(states.get("BB"), tagDefinition); + List tags = automataTagger.getTags(states.get("BB"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag2"); } @Test public void testStateBBSymbol() { - List tags = automataTagger.getTags(states.get("BB").getSymbol(), tagDefinition); + List tags = automataTagger.getTags(states.get("BB").getSymbol(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag2"); } @Test public void testSomeScopeC() { - List tags = automataTagger.getTags(model.getEnclosingScope().resolveScopedState("C").get().getAstNode(), tagDefinition); + List tags = automataTagger.getTags(model.getEnclosingScope().resolveScopedState("C").get().getAstNode(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "VerboseLog", "doLogC"); } @Test public void testSomeScopeCSymbol() { - List tags = automataTagger.getTags(model.getEnclosingScope().resolveScopedState("C").get(), tagDefinition); + List tags = automataTagger.getTags(model.getEnclosingScope().resolveScopedState("C").get(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "VerboseLog", "doLogC"); } @Test public void testStateC_CA() { - List tags = automataTagger.getTags(states.get("C.CA"), tagDefinition); + List tags = automataTagger.getTags(states.get("C.CA"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag1"); } @Test public void testStateC_CASymbol() { - List tags = automataTagger.getTags(states.get("C.CA").getSymbol(), tagDefinition); + List tags = automataTagger.getTags(states.get("C.CA").getSymbol(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag1"); } @Test public void testStateC_CB() { - List tags = automataTagger.getTags(states.get("C.CB"), tagDefinition); + List tags = automataTagger.getTags(states.get("C.CB"), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag2"); } @Test public void testStateC_CBSymbol() { - List tags = automataTagger.getTags(states.get("C.CB").getSymbol(), tagDefinition); + List tags = automataTagger.getTags(states.get("C.CB").getSymbol(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "StateTag2"); } @@ -176,21 +177,21 @@ public void testStateC_CBSymbol() { @Test public void testSomeScopeC_Transition() { List tags = automataTagger.getTags((ASTTransition) model.getEnclosingScope().resolveScopedState("C").get().getAstNode() - .getScopedStateElement(2), tagDefinition); + .getScopedStateElement(2), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertValuedTag(tags.get(0), "Log", "timestamp"); } @Test public void testStateD() { - List tags = automataTagger.getTags(states.get("D"), tagDefinition); + List tags = automataTagger.getTags(states.get("D"), Collections.singleton(tagDefinition)); Assert.assertEquals(2, tags.size()); assertSimpleTag(tags.get(0), "WildcardedTag"); } @Test public void testStateDSymbol() { - List tags = automataTagger.getTags(states.get("D").getSymbol(), tagDefinition); + List tags = automataTagger.getTags(states.get("D").getSymbol(), Collections.singleton(tagDefinition)); Assert.assertEquals(2, tags.size()); assertSimpleTag(tags.get(0), "WildcardedTag"); } @@ -202,11 +203,11 @@ public void testDupSymbols() { Optional scopedStateSymbolOpt = model.getEnclosingScope().resolveScopedState("Dup"); Assert.assertTrue(scopedStateSymbolOpt.isPresent()); // Discuss if this type-unaware duplication is desired? - List tags = automataTagger.getTags(stateSymbolOpt.get(), tagDefinition); + List tags = automataTagger.getTags(stateSymbolOpt.get(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "WildcardedTag"); - tags = automataTagger.getTags(scopedStateSymbolOpt.get(), tagDefinition); + tags = automataTagger.getTags(scopedStateSymbolOpt.get(), Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "WildcardedTag"); } @@ -214,34 +215,34 @@ public void testDupSymbols() { @Test public void testAddStateE() { ASTState stateE = states.get("E"); - List tags = automataTagger.getTags(stateE, tagDefinition); + List tags = automataTagger.getTags(stateE, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); // Add new Tag ASTTag tag = TagsMill.simpleTagBuilder().setName("TestTag").build(); automataTagger.addTag(stateE, tagDefinition, tag); - tags = automataTagger.getTags(stateE, tagDefinition); + tags = automataTagger.getTags(stateE, Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "TestTag"); // Remove tag again automataTagger.removeTag(stateE, tagDefinition, tag); - tags = automataTagger.getTags(stateE, tagDefinition); + tags = automataTagger.getTags(stateE, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); } @Test public void testAddTransition() { ASTTransition transition = model.getTransitionList().stream().filter(e->e.getFrom().equals("E") && e.getTo().equals("E")).findAny().get(); - List tags = automataTagger.getTags(transition, tagDefinition); + List tags = automataTagger.getTags(transition, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); // Add new Tag ASTTag tag = TagsMill.simpleTagBuilder().setName("TestTag").build(); automataTagger.addTag(transition, tagDefinition, tag); - tags = automataTagger.getTags(transition, tagDefinition); + tags = automataTagger.getTags(transition, Collections.singleton(tagDefinition)); Assert.assertEquals(1, tags.size()); assertSimpleTag(tags.get(0), "TestTag"); // Remove tag again automataTagger.removeTag(transition, tagDefinition, tag); - tags = automataTagger.getTags(transition, tagDefinition); + tags = automataTagger.getTags(transition, Collections.singleton(tagDefinition)); Assert.assertEquals(0, tags.size()); } diff --git a/monticore-test/01.experiments/tagging/src/test/resources/models/Door.cd b/monticore-test/01.experiments/tagging/src/test/resources/models/Door.cd new file mode 100644 index 0000000000..8694354033 --- /dev/null +++ b/monticore-test/01.experiments/tagging/src/test/resources/models/Door.cd @@ -0,0 +1,9 @@ +/* (c) https://github.com/MontiCore/monticore */ +classdiagram Door { + class TheDoor {} + + class FinishPersonOpeningTheDoor { } + + <> class ASingleDoor { } + +} \ No newline at end of file diff --git a/monticore-test/01.experiments/tagging/src/test/resources/models/DoorsThatAreOpenable.tags b/monticore-test/01.experiments/tagging/src/test/resources/models/DoorsThatAreOpenable.tags new file mode 100644 index 0000000000..02a7af5309 --- /dev/null +++ b/monticore-test/01.experiments/tagging/src/test/resources/models/DoorsThatAreOpenable.tags @@ -0,0 +1,5 @@ +/* (c) https://github.com/MontiCore/monticore */ +tags DoorsThatAreOpenable { + tag TheDoor with Openable; + tag ASingleDoor with Openable; +} \ No newline at end of file