Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0e258b3
use LinkedList instead of ArrayList for temporary candidate lists
jra-se Sep 4, 2025
9cb3ff2
use LinkedList instead of ArrayList for temporary candidate lists
jra-se Sep 4, 2025
f9f63f2
use comments to store parents instead of hashmap
jra-se Sep 4, 2025
57f4426
use FastLookupList to prevent List copies
jra-se Sep 8, 2025
5f4e694
add searchplan optimization
jra-se Sep 8, 2025
4a8f21b
add missing candidate resets
jra-se Sep 8, 2025
431e314
deepClone on move: monticore/monticore#4671
jra-se Sep 8, 2025
9fd4c08
add dirty flag to the search graph to prevent unnecessary traversals …
jra-se Sep 8, 2025
5734b6a
add error code
jra-se Sep 9, 2025
b4b48e7
add option to disable search plan optimization
jra-se Sep 9, 2025
4bc3cc3
add todo
jra-se Sep 12, 2025
c11815a
Merge branch 'dev' into backport-trafo-optimization
jra-se Oct 14, 2025
d20dda5
Merge branch 'refs/heads/dev' into backport-trafo-optimization
jra-se Oct 30, 2025
f847cee
Merge branch 'dev' into backport-trafo-optimization
jra-se Dec 8, 2025
49e9355
generate reset methods for all optionals instead of lists of Runnables
jra-se Dec 15, 2025
e07cbd2
generate reset methods for all optionals instead of lists of Runnables
jra-se Dec 15, 2025
3c25e51
try to add missing optional resets in handles
jra-se Dec 15, 2025
4d177bf
Merge branch 'dev' into backport-trafo-optimization
jra-se Dec 16, 2025
a0ae26c
added todo
jra-se Dec 16, 2025
1947415
made optimizeSearchplan method protected
jra-se Dec 16, 2025
abb94d9
added more comments
jra-se Dec 16, 2025
154de79
minor doc fix
jra-se Dec 17, 2025
3b3cd49
added even more comments
luepges Dec 17, 2025
b7ee83e
Merge branch 'dev' into backport-trafo-optimization
luepges Dec 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.tf.odrulegeneration._ast;

import java.util.HashMap;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

public class ASTTransformationStructure extends ASTTransformationStructureTOP {

Expand Down Expand Up @@ -70,5 +70,36 @@ public HashMap<String, List<String>> getFoldingHash () {
public void setFoldingHash (HashMap<String, List<String>> foldingHash) {
this.foldingHash = foldingHash;
}


public List<String> getCompositionDependencyNames(ASTMatchingObject object) {
return this.getPattern().getLinkConditionsList().stream().filter(
l -> l.getLinktype().equals("composition") && l.getDependency().getContent()
.equals(object.getObjectName())).map(ASTCondition::getObjectName)
.collect(Collectors.toList());
}

public Map<String, String> getReplacementChangeMapping() {
Map<String, String> replacementChangeMapping = new HashMap<>();
this.getReplacement().getChangesList().stream().filter(ASTChange::isPresentValue)
.filter(x -> x.getValue().charAt(0) == '_').forEach(change -> {
String truncValueName =
change.getValue().substring(1, change.getValue().lastIndexOf("_"));
replacementChangeMapping.put(change.getObjectName(), truncValueName);
});
return replacementChangeMapping;
}

public Set<String> getAllInnerNonOptionalNames(List<ASTMatchingObject> allObjects,
ASTMatchingObject matchObject) {
Set<String> result = new HashSet<>();
for (String innerLinkObjectName : matchObject.getInnerLinkObjectNamesList()) {
ASTMatchingObject innerLinkObject = this.getPattern().getMatchingObjectsList().stream()
.filter(f -> f.getObjectName().equals(innerLinkObjectName)).findFirst().get();
if (!innerLinkObject.isOptObject()) {
result.add(innerLinkObjectName);
}
result.addAll(getAllInnerNonOptionalNames(allObjects, innerLinkObject));
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.tf.runtime;

import java.util.AbstractList;
import java.util.ConcurrentModificationException;
import java.util.List;

/**
* A sliding range, read-only window of list.
* Alternative to myList = new ArrayList(list);
* myList.remove(0);
* Calling {@link #remove(int)} of this class instead moves the read-window ahead.
* Does not support updates to the underlying list.
*
* @param <T> type of the list
*/

public class FastLookupList<T> extends AbstractList<T> {

protected List<T> list;

public FastLookupList(List<T> list) {
this.list = list;
this.size = list.size();
}

public FastLookupList(List<T> list, int removalCounter) {
this(list);
this.removalCounter = removalCounter;
}

protected int removalCounter = 0;
protected int size;

public void reset() {
removalCounter = 0;
}

@Override
public T get(int index) {
if (list.size() != size) {
throw new ConcurrentModificationException("FastLookupList size changed");
}
return this.list.get(index + removalCounter);
}

@Override
public T remove(int index) {
if (index != 0) {
throw new IllegalArgumentException("You may only remove index 0");
}
removalCounter++;
return null;
}

@Override
public int size() {
return size - removalCounter;
}

@Override
public boolean isEmpty() {
if (list.size() != size) {
throw new ConcurrentModificationException("FastLookupList size changed");
}
return removalCounter == size;
}

public FastLookupList<T> matchCopy() {
return new FastLookupList<>(this.list, this.removalCounter);
}

@Override
public String toString() {
return "FastLookupList{" + removalCounter + "/ " + size + ": " + list.subList(removalCounter,
size) + "}";
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/*
* (c) https://github.com/MontiCore/monticore
*/

/* (c) https://github.com/MontiCore/monticore */
package de.monticore.tf.runtime;

import de.monticore.ast.ASTNode;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
/* (c) https://github.com/MontiCore/monticore */
/*
* (c) https://github.com/MontiCore/monticore
*/


package de.monticore.tf.runtime;

import de.monticore.ast.ASTNode;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.tf.runtime.matching;

import de.monticore.ast.ASTNode;
import de.monticore.ast.Comment;
import de.monticore.visitor.ITraverser;

import java.util.*;

/**
* This CommentBasedModelTraversal is a more efficient implementation of the default
* ModelTraversal. Instead of using a HashMap to store node parents, which showed unexpected
* performance issues due to the suboptimal hash function of ASTNodes, this Traversal stores
* node parents as Comment objects in the respective child nodes.
* Thereby map lookups are prevented and replaced by efficient direct lookups.
*
* @param <E> a language traverser type
*/
public class CommentBasedModelTraversal<E extends ITraverser> extends ModelTraversal<E> {

protected CommentBasedModelTraversal(E traverser) {
super(traverser);
}

@Override
public ASTNode getParent(ASTNode node) {
return ((WComment) node.get_PostCommentList().get(0)).getParent();
}

public void init() {
for (Map.Entry<ASTNode, ASTNode> node : this.getParents().entrySet()) {
if (node.getKey().get_PostCommentList().isEmpty()) {
node.getKey().get_PostCommentList().add(new WComment("", node.getValue()));
}
else {
node.getKey().get_PostCommentList()
.set(0, new WComment(node.getKey().get_PostCommentList().get(0), node.getValue()));
}
}
}

static class WComment extends Comment {

protected ASTNode parent;

public WComment(String text, ASTNode parent) {
super(text);
this.parent = parent;
}

public WComment(Comment c, ASTNode parent) {
this(c.getText(), parent);
this.set_SourcePositionStart(c.get_SourcePositionStart());
this.set_SourcePositionEnd(c.get_SourcePositionEnd());
}

public ASTNode getParent() {
return parent;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.tf.runtime.matching;

import de.monticore.visitor.ITraverser;

public class CommentBasedModelTraversalFactory extends ModelTraversalFactory {

private static CommentBasedModelTraversalFactory instance;

public static CommentBasedModelTraversalFactory getInstance() {
if (instance == null) {
instance = new CommentBasedModelTraversalFactory();
}
return instance;
}

/**
* @return a {@link ModelTraversal} for the given model
*/
public ModelTraversalVisitor createVisitor(ModelTraversal<?> modelTraversal) {
return new CommentBasedModelTraversalVisitor(modelTraversal);
}

public <E extends ITraverser> ModelTraversal<E> create(java.util.function.Supplier<E> traverserSupplier){
return this.create(traverserSupplier.get());
}

public <E extends ITraverser> ModelTraversal<E> create(E traverser){
ModelTraversal<E> modelTraversal = new CommentBasedModelTraversal<>(traverser);
traverser.add4IVisitor(createVisitor(modelTraversal));
return modelTraversal;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* (c) https://github.com/MontiCore/monticore */
package de.monticore.tf.runtime.matching;

import de.monticore.visitor.IVisitor;

public class CommentBasedModelTraversalVisitor extends ModelTraversalVisitor implements IVisitor {

protected CommentBasedModelTraversalVisitor(ModelTraversal<?> modelTraversal) {
super(modelTraversal);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
<#assign matchObjects = hierarchyHelper.getMandatoryMatchObjects(ast.getPattern().getMatchingObjectsList())>
<#assign optionalMatchObjects = hierarchyHelper.getOptionalMatchObjects(ast.getPattern().getLHSObjectsList())>

public static boolean optimizeSP = true;

private List<ASTNode> hostGraph;
private GlobalExtensionManagement glex = new GlobalExtensionManagement();
private List<Match> allMatches;
private boolean doReplacementExecuted = false;
private boolean isHostGraphDirty = true;
<#-- for each object creates a _candidates, _candidates_temp nodelist and an _cand object-->

// Matches
Expand All @@ -19,7 +22,7 @@
protected boolean ${variable.getName()}_is_fix = false;
private ${variable.getType()} ${variable.getName()};
</#list>
private ModelTraversal <?> t = ModelTraversalFactory.getInstance().create((java.util.function.Supplier)${grammarName}Mill::inheritanceTraverser);
private ModelTraversal <?> t = CommentBasedModelTraversalFactory.getInstance().create((java.util.function.Supplier)${grammarName}Mill::inheritanceTraverser);
<#list ast.getPattern().getAssocList() as association>
private mc.ast.MCAssociation ${association.getName()};
</#list>
Expand Down Expand Up @@ -67,3 +70,22 @@
doPatternMatching();
doReplacement();
}

protected void loadIntoModelTraverser() {
for (ASTNode astNode : Log.errorIfNull(hostGraph,
"0xE1200: Hostgraph is null, check constructor arguments!")) {
astNode.accept(t.getTraverser());
}

if (t instanceof CommentBasedModelTraversal) {
((CommentBasedModelTraversal<?>) t).init();
}
}

/**
* Marks the original model as dirty, same as if {@link #doReplacement} was called.
* @see ${ast.getClassname()}#doReplacement()
*/
public void markDirty() {
this.isHostGraphDirty = true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,23 @@ public boolean doPatternMatching() {
// (this will skip all attempts to match negative nodes)
boolean isBacktracking = true;
boolean isBacktrackingNegative = false;
for(ASTNode a: hostGraph){
a.accept(t.getTraverser());

<#list hierarchyHelper.getOptionalMatchObjects(ast.getPattern().getLHSObjectsList()) as optional>
reset_${optional.getObjectName()}();
</#list>

if (isHostGraphDirty || searchPlan == null) {
this.loadIntoModelTraverser();
isHostGraphDirty= false;
}

if (searchPlan == null) {
searchPlan = findSearchPlan();

if(optimizeSP) {
optimizeSearchplan();
}
initializeFastLookupList();
splitSearchplan(); // for OptList structures
isBacktracking = false;
}
Expand All @@ -29,13 +41,13 @@ public boolean doPatternMatching() {
<#--creates an if statement for each object for matching the object-->
<#list hierarchyHelper.getMandatoryObjectsWithoutListChilds(ast.getPattern().getLHSObjectsList()) as object>
<#if object.isListObject()>
${tc.includeArgs("de.monticore.tf.odrules.dopatternmatching.HandleListObject", object, [false])}
${tc.includeArgs("de.monticore.tf.odrules.dopatternmatching.HandleListObject", object, [false, ""])}
<#elseif object.isOptObject()>
${tc.includeArgs("de.monticore.tf.odrules.dopatternmatching.HandleOptObject", object, [false])}
${tc.includeArgs("de.monticore.tf.odrules.dopatternmatching.HandleOptObject", object, [false, ""])}
<#elseif object.isNotObject()>
${tc.includeArgs("de.monticore.tf.odrules.dopatternmatching.HandleNotObject", object, [false])}
${tc.includeArgs("de.monticore.tf.odrules.dopatternmatching.HandleNotObject", object, [false, ""])}
<#else>
${tc.includeArgs("de.monticore.tf.odrules.dopatternmatching.HandleNormalObject", object, [false])}
${tc.includeArgs("de.monticore.tf.odrules.dopatternmatching.HandleNormalObject", object, [false, ""])}
</#if>
<#if object_has_next>else</#if>
</#list>
Expand Down
Loading
Loading