Skip to content

Commit

Permalink
Merge branch 'tagging-repos' into 'dev'
Browse files Browse the repository at this point in the history
Tagging Repository

Closes #3665

See merge request monticore/monticore!908
  • Loading branch information
MisterErwin committed Nov 23, 2023
2 parents a25cf62 + 3cce54d commit ab3dfcb
Show file tree
Hide file tree
Showing 21 changed files with 564 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -73,7 +76,7 @@ public List<ASTCDElement> 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())
Expand All @@ -84,6 +87,7 @@ public List<ASTCDElement> 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);
Expand All @@ -94,7 +98,7 @@ public List<ASTCDElement> 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));
Expand Down Expand Up @@ -125,18 +129,30 @@ protected List<ASTCDMethod> createITaggerMethods(ProdSymbol prodSymbol, String c
List<ASTCDMethod> methods = new ArrayList<>();

ASTCDMethod m;
// I${Lang}Tagger.getTags(AST${prodSymbol.name} model, Iterable<ASTTagUnit> 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<ASTTagUnit> 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(),
Expand Down Expand Up @@ -166,19 +182,21 @@ protected List<ASTCDMethod> createTaggerMethods(ProdSymbol prodSymbol, boolean i
List<ASTCDMethod> methods = new ArrayList<>();
ASTCDMethod method;

// ${Lang}Tagger.getTags(AST${prodSymbol.name} model, Iterable<ASTTagUnit> 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<ASTTagUnit> 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()));
}

Expand All @@ -191,14 +209,26 @@ protected List<ASTCDMethod> 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()),
Expand Down Expand Up @@ -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<ProdSymbol> toCheck = new LinkedList<>();
Set<ProdSymbol> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<#-- (c) https://github.com/MontiCore/monticore -->
${tc.signature("clazzname")}
return ${clazzname}.getInstance().getTags(model, TagRepository.getLoadedTagUnits());
Original file line number Diff line number Diff line change
@@ -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()
);
Original file line number Diff line number Diff line change
@@ -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;
61 changes: 31 additions & 30 deletions monticore-generator/src/main/resources/tagging/tagger/GetTags.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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()));</#if>
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());</#if>
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()));</#if>
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());</#if>

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>
<#if hasName>
String joinedNames = Joiners.DOT.join(scopeStack);
findTargetsBy(astTagUnit, joinedNames).forEach(t -> tags.addAll(t.getTagList()));
</#if>

scopeStack.remove(0);
scopeStack.remove(0);

while (scopeStack.size() > 1) {
List< ASTContext> tempContexts = contexts;
contexts = new ArrayList<>();
<#if hasName>joinedNames = Joiners.DOT.join(scopeStack);</#if>
String name = scopeStack.remove(0);
while (scopeStack.size() > 1) {
List< ASTContext> tempContexts = contexts;
contexts = new ArrayList<>();
<#if hasName>joinedNames = Joiners.DOT.join(scopeStack);</#if>
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()));</#if>
for (ASTContext context : tempContexts) {
findContextBy(context, name).forEach(contexts::add);
<#if hasName>findTargetsBy(context, joinedNames).forEach(t -> tags.addAll(t.getTagList()));</#if>
}
}
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()));
</#if>
}
}
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()));
</#if>
}

}
}
return tags;
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Loading

0 comments on commit ab3dfcb

Please sign in to comment.