package jetbrains.mps.lang.test.matcher; /*Generated by MPS */ import java.util.Map; import org.jetbrains.mps.openapi.model.SNode; import java.util.HashMap; import java.util.List; import java.util.Collections; import java.util.ArrayList; import java.util.Iterator; import java.util.HashSet; import org.jetbrains.mps.openapi.language.SContainmentLink; import org.jetbrains.mps.openapi.language.SReferenceLink; import org.jetbrains.mps.openapi.model.SReference; import org.jetbrains.mps.openapi.language.SProperty; public final class NodesMatcher { private final Map<SNode, SNode> map; public NodesMatcher() { map = new HashMap<SNode, SNode>(); // FIXME refactor to use instances instead of static method } public NodesMatcher(Map<SNode, SNode> map) { this.map = map; } public Map<SNode, SNode> getMap() { // I don't quite understand what's the map we either populate and use, or just use. // why matchNodes(node,node) goes through matchNodes(list,list), creates and populates map, // while matchNodes(node,node,map) does not populate the map // Once I understand what map is, I can give method better name return map; } /** * * @deprecated use instance method */ @Deprecated public static NodeDifference matchNodes(SNode a, SNode b) { List<SNode> aList = Collections.singletonList(a); List<SNode> bList = Collections.singletonList(b); // for whatever reason match(SNode,SNode) just reads map, while match(list<node>, list<node>) populates map first List<NodeDifference> diffs = new NodesMatcher().match(aList, bList); if (diffs != null) { return diffs.get(0); } else { return null; } } /** * * @deprecated use instance method */ @Deprecated public static ArrayList<NodeDifference> matchNodes(List<SNode> a, List<SNode> b) { return NodesMatcher.matchNodes(a, b, new HashMap<SNode, SNode>()); } public List<NodeDifference> match(List<SNode> a, List<SNode> b) { Iterator<SNode> iteratorA = a.iterator(); Iterator<SNode> iteratorB = b.iterator(); while (iteratorA.hasNext() && iteratorB.hasNext()) { populateMap(iteratorA.next(), iteratorB.next()); } ArrayList<NodeDifference> ret = new ArrayList<NodeDifference>(); iteratorA = a.iterator(); iteratorB = b.iterator(); while (iteratorA.hasNext() && iteratorB.hasNext()) { NodeDifference diff = match(iteratorA.next(), iteratorB.next()); if (diff != null) { ret.add(diff); } } return (ret.isEmpty() ? null : ret); } /** * * @deprecated use instance method instead */ @Deprecated public static ArrayList<NodeDifference> matchNodes(List<SNode> a, List<SNode> b, Map<SNode, SNode> map) { NodesMatcher nm = new NodesMatcher(map); List<NodeDifference> rv = nm.match(a, b); return (rv == null ? null : new ArrayList<NodeDifference>(rv)); } private void populateMap(SNode a, SNode b) { if (!(a.getConcept().equals(b.getConcept()))) { return; } HashSet<SContainmentLink> roles = new HashSet<SContainmentLink>(); for (SNode child : a.getChildren()) { roles.add(child.getContainmentLink()); } for (SNode child : b.getChildren()) { roles.add(child.getContainmentLink()); } for (SContainmentLink role : roles) { Iterator<? extends SNode> iterator1 = a.getChildren(role).iterator(); Iterator<? extends SNode> iterator2 = b.getChildren(role).iterator(); while (iterator1.hasNext() && iterator2.hasNext()) { populateMap(iterator1.next(), iterator2.next()); } } map.put(a, b); } public NodeDifference match(SNode a, SNode b) { ArrayList<DifferenceItem> difference = new ArrayList<DifferenceItem>(); if (matchConcepts(a, b, difference)) { return new NodeDifference(a.getPresentation(), difference); } matchProperties(a, b, difference); matchChildren(a, b, difference); matchReferences(a, b, difference); if (difference.size() != 0) { return new NodeDifference(a.getPresentation(), difference); } return null; } /** * * @deprecated use instance method instead */ @Deprecated public static NodeDifference matchNodes(SNode a, SNode b, Map<SNode, SNode> map) { return new NodesMatcher(map).match(a, b); } private boolean matchConcepts(SNode a, SNode b, ArrayList<DifferenceItem> difference) { if (!(a.getConcept().equals(b.getConcept()))) { difference.add(new ConceptDifference(a.getConcept(), b.getConcept())); return true; } return false; } private void matchReferences(SNode a, SNode b, ArrayList<DifferenceItem> difference) { HashSet<SReferenceLink> roles = new HashSet<SReferenceLink>(); for (SReference nextReference : a.getReferences()) { roles.add(nextReference.getLink()); } for (SReference nextReference : b.getReferences()) { roles.add(nextReference.getLink()); } for (SReferenceLink role : roles) { SReference reference1 = a.getReference(role); SNode referenceTarget1 = null; if (reference1 != null) { referenceTarget1 = reference1.getTargetNode(); } SReference reference2 = b.getReference(role); SNode referenceTarget2 = null; if (reference2 != null) { referenceTarget2 = reference2.getTargetNode(); } if (map.containsKey(referenceTarget1)) { if (map.get(referenceTarget1) != referenceTarget2) { difference.add(new ReferenceDifference(role, true, map.get(referenceTarget1), referenceTarget2)); } } else { if (referenceTarget1 != referenceTarget2) { difference.add(new ReferenceDifference(role, false, referenceTarget1, referenceTarget2)); } } } } private static int countElements(Iterator<?> it) { int counter = 0; while (it.hasNext()) { it.next(); counter++; } return counter; } private void matchChildren(SNode a, SNode b, ArrayList<DifferenceItem> difference) { HashSet<SContainmentLink> roles = new HashSet<SContainmentLink>(); for (SNode child : a.getChildren()) { roles.add(child.getContainmentLink()); } for (SNode child : b.getChildren()) { roles.add(child.getContainmentLink()); } for (SContainmentLink role : roles) { Iterable<? extends SNode> children1 = a.getChildren(role); Iterable<? extends SNode> children2 = b.getChildren(role); int size1 = countElements(children1.iterator()); int size2 = countElements(children2.iterator()); if (size1 != size2) { difference.add(new ChildrenCountDifference(role, size1, size2)); continue; } Iterator<? extends SNode> iterator1 = children1.iterator(); Iterator<? extends SNode> iterator2 = children2.iterator(); while (iterator1.hasNext() && iterator2.hasNext()) { NodeDifference d = match(iterator1.next(), iterator2.next()); if (d != null) { difference.add(d); } } } } private void matchProperties(SNode a, SNode b, ArrayList<DifferenceItem> difference) { HashSet<SProperty> properties = new HashSet<SProperty>(); for (SProperty p : a.getProperties()) { properties.add(p); } for (SProperty p : b.getProperties()) { properties.add(p); } for (SProperty key : properties) { String p1 = a.getProperty(key); String p2 = b.getProperty(key); if (p1 == null && "false".equals(p2)) { continue; } if (p2 == null && "false".equals(p1)) { continue; } if (p1 == null || p2 == null || !(p1.equals(p2))) { difference.add(new PropertyDifference(key, p1, p2)); } } } }