diff --git a/src/main/java/nl/utwente/groove/grammar/rule/DefaultRuleNode.java b/src/main/java/nl/utwente/groove/grammar/rule/DefaultRuleNode.java index 0431ee89b..5cf877b0c 100644 --- a/src/main/java/nl/utwente/groove/grammar/rule/DefaultRuleNode.java +++ b/src/main/java/nl/utwente/groove/grammar/rule/DefaultRuleNode.java @@ -44,15 +44,18 @@ public class DefaultRuleNode extends ANode implements RuleNode, AnchorKey { /** * Constructs a fresh node, with an explicitly given number and node type. * @param nr the number for this node - * @param type the node type; may be {@code null} + * @param type the node type + * @param declared flag indicating if the node type is explicitly declared + * (by a type label) * @param sharp if {@code true}, the node is sharply typed * @param typeGuards collection of named and unnamed type guards for this node */ - protected DefaultRuleNode(int nr, TypeNode type, boolean sharp, + protected DefaultRuleNode(int nr, TypeNode type, boolean declared, boolean sharp, @Nullable List typeGuards) { super(nr); assert type != null : "Can't instantiate untyped rule node"; this.type = type; + this.declared = declared; this.sharp = sharp; if (typeGuards == null) { this.typeGuards = Collections.emptyList(); @@ -155,6 +158,14 @@ public boolean isSharp() { /** Flag indicating if this node is sharply typed. */ private final boolean sharp; + @Override + public boolean isDeclared() { + return this.declared; + } + + /** Flag indicating the node type is explicitly declared. */ + private final boolean declared; + @Override public AnchorKind getAnchorKind() { return AnchorKind.NODE; diff --git a/src/main/java/nl/utwente/groove/grammar/rule/OperatorNode.java b/src/main/java/nl/utwente/groove/grammar/rule/OperatorNode.java index 06b3a03cf..8d6ac78c1 100644 --- a/src/main/java/nl/utwente/groove/grammar/rule/OperatorNode.java +++ b/src/main/java/nl/utwente/groove/grammar/rule/OperatorNode.java @@ -17,11 +17,9 @@ package nl.utwente.groove.grammar.rule; import java.util.List; -import java.util.Set; import nl.utwente.groove.algebra.Operator; import nl.utwente.groove.grammar.AnchorKind; -import nl.utwente.groove.grammar.type.TypeGuard; import nl.utwente.groove.grammar.type.TypeLabel; import nl.utwente.groove.grammar.type.TypeNode; import nl.utwente.groove.graph.ANode; @@ -90,26 +88,6 @@ public TypeNode getType() { return getTarget().getType(); } - @Override - public List getTypeGuards() { - return EMPTY_GUARD_LIST; - } - - @Override - public Set getVars() { - return EMPTY_VAR_SET; - } - - @Override - public boolean isSharp() { - return true; - } - - @Override - public Set getMatchingTypes() { - return EMPTY_MATCH_SET; - } - @Override public AnchorKind getAnchorKind() { return AnchorKind.NODE; diff --git a/src/main/java/nl/utwente/groove/grammar/rule/RuleEdge.java b/src/main/java/nl/utwente/groove/grammar/rule/RuleEdge.java index a9f5d56c5..530ef44ad 100644 --- a/src/main/java/nl/utwente/groove/grammar/rule/RuleEdge.java +++ b/src/main/java/nl/utwente/groove/grammar/rule/RuleEdge.java @@ -46,13 +46,13 @@ public RuleEdge(RuleNode source, RuleLabel label, @Nullable TypeEdge type, RuleN : emptyList(); TypeGraph typeGraph = source.getType().getGraph(); this.matchingTypes = new HashSet<>(); - for (TypeEdge typeEdge : typeGraph.edgeSet()) { - if (typeEdge.source().getSubtypes().contains(source.getType()) - && typeEdge.target().getSubtypes().contains(target.getType()) - && guard.test(typeEdge)) { - this.matchingTypes.add(typeEdge); - } - } + typeGraph + .edgeSet() + .stream() + .filter(e -> source.isTypedBy(e.source())) + .filter(e -> target.isTypedBy(e.target())) + .filter(guard::test) + .forEach(this.matchingTypes::add); } else if (type == null) { this.matchingTypes = emptySet(); this.typeGuards = emptyList(); diff --git a/src/main/java/nl/utwente/groove/grammar/rule/RuleElement.java b/src/main/java/nl/utwente/groove/grammar/rule/RuleElement.java index 17723ef42..55feff928 100644 --- a/src/main/java/nl/utwente/groove/grammar/rule/RuleElement.java +++ b/src/main/java/nl/utwente/groove/grammar/rule/RuleElement.java @@ -39,10 +39,14 @@ public interface RuleElement extends Element, AnchorKey { public @Nullable TypeElement getType(); /** Returns the set of label variables associated with this rule element. */ - public Set getVars(); + default public Set getVars() { + return EMPTY_VAR_SET; + } /** Returns the collection of (named) type guards associated with this rule element. */ - public List getTypeGuards(); + default public List getTypeGuards() { + return EMPTY_GUARD_LIST; + } /** * Returns the set of type elements that are valid matches of this rule element. diff --git a/src/main/java/nl/utwente/groove/grammar/rule/RuleFactory.java b/src/main/java/nl/utwente/groove/grammar/rule/RuleFactory.java index 9db79fc16..763b2bb17 100644 --- a/src/main/java/nl/utwente/groove/grammar/rule/RuleFactory.java +++ b/src/main/java/nl/utwente/groove/grammar/rule/RuleFactory.java @@ -47,27 +47,25 @@ protected RuleNode newNode(int nr) { @Override protected boolean isAllowed(RuleNode node) { - return node.getType() - .isTopType() && !node.isSharp() - && node.getTypeGuards() - .isEmpty(); + return node.getType().isTopType() && !node.isSharp() && node.getTypeGuards().isEmpty(); } /** Returns the fixed node factory for the top type. */ private RuleNodeFactory getTopNodeFactory() { if (this.topNodeFactory == null) { - this.topNodeFactory = - (RuleNodeFactory) nodes(getTypeFactory().getTopNode(), true, null); + this.topNodeFactory + = (RuleNodeFactory) nodes(getTypeFactory().getTopNode(), false, true, null); } return this.topNodeFactory; } private RuleNodeFactory topNodeFactory; - /** Returns a node factory for typed default rule nodes. */ - public NodeFactory nodes(@NonNull TypeNode type, boolean sharp, - List typeGuards) { - return new RuleNodeFactory(type, sharp, typeGuards); + /** Returns a node factory for typed default rule nodes. + * @param declared flag indicating if the node type is explicitly declared (see {@link RuleNode#isDeclared()}). */ + public NodeFactory nodes(@NonNull TypeNode type, boolean declared, boolean sharp, + List typeGuards) { + return new RuleNodeFactory(type, declared, sharp, typeGuards); } /** Creates a variable node for a given algebra term, and with a given node number. */ @@ -80,7 +78,7 @@ public VariableNode createVariableNode(int nr, Expression term) { /** Creates an operator node for a given node number and arity. */ public OperatorNode createOperatorNode(int nr, Operator operator, List arguments, - VariableNode target) { + VariableNode target) { OperatorNode result = new OperatorNode(nr, operator, arguments, target); registerNode(result); return result; @@ -97,7 +95,8 @@ public RuleLabel createLabel(String text) { public RuleEdge createEdge(RuleNode source, Label label, RuleNode target) { RuleLabel ruleLabel = (RuleLabel) label; TypeLabel typeLabel = ruleLabel.getTypeLabel(); - TypeEdge type = typeLabel == null ? null + TypeEdge type = typeLabel == null + ? null : getTypeFactory().createEdge(source.getType(), typeLabel, target.getType(), false); return new RuleEdge(source, ruleLabel, type, target); } @@ -127,10 +126,14 @@ public static RuleFactory newInstance(TypeFactory typeFactory) { /** Factory for (typed) {@link DefaultHostNode}s. */ protected class RuleNodeFactory extends DependentNodeFactory { - /** Constructor for subclassing. */ - protected RuleNodeFactory(@NonNull TypeNode type, boolean sharp, - List typeGuards) { + /** Constructor for subclassing. + * @param declared flag indicating if the generated nodes are explicitly typed; + * see RuleNode#isDeclared() + */ + protected RuleNodeFactory(@NonNull TypeNode type, boolean declared, boolean sharp, + List typeGuards) { this.type = type; + this.declared = declared; this.sharp = sharp; this.typeGuards = typeGuards; } @@ -138,13 +141,12 @@ protected RuleNodeFactory(@NonNull TypeNode type, boolean sharp, @Override protected boolean isAllowed(RuleNode node) { return node.getType() == this.type && node.isSharp() == this.sharp - && node.getTypeGuards() - .equals(this.typeGuards); + && node.getTypeGuards().equals(this.typeGuards); } @Override protected RuleNode newNode(int nr) { - return new DefaultRuleNode(nr, this.type, this.sharp, this.typeGuards); + return new DefaultRuleNode(nr, this.type, this.declared, this.sharp, this.typeGuards); } /** Returns the type wrapped into this factory. */ @@ -154,7 +156,7 @@ protected TypeNode getType() { private final @NonNull TypeNode type; private final boolean sharp; + private final boolean declared; private final List typeGuards; } - } diff --git a/src/main/java/nl/utwente/groove/grammar/rule/RuleNode.java b/src/main/java/nl/utwente/groove/grammar/rule/RuleNode.java index 95e940731..8427b724c 100644 --- a/src/main/java/nl/utwente/groove/grammar/rule/RuleNode.java +++ b/src/main/java/nl/utwente/groove/grammar/rule/RuleNode.java @@ -61,17 +61,39 @@ default public Optional getPar() { * Indicates if the rule node is sharply typed. * Returns {@code false} if the node is untyped. */ - public boolean isSharp(); + default public boolean isSharp() { + return true; + } + + /** Indicates if the node type is declared explicitly, by a type label. + * (If not, it is determined by type variables). + */ + default public boolean isDeclared() { + return true; + } /* Specialises the return type. */ @Override - public Set getMatchingTypes(); + default public Set getMatchingTypes() { + return Collections.singleton(getType()); + } + + /** Indicates if this rule node is correctly typed by a given node type. + * This is the case if this node has a declared type that is a subtype of + * the given node type, or, if this node type is not declared, if any of the + * matching node types is a subtype of the given node type. + */ + default public boolean isTypedBy(TypeNode type) { + var subtypes = type.getSubtypes(); + if (isDeclared()) { + return subtypes.contains(getType()); + } else { + return getMatchingTypes().stream().anyMatch(subtypes::contains); + } + } /** Tests if the matching types and type guards of this node * equal that of another. (This is not covered by #equals). */ public boolean stronglyEquals(RuleNode other); - - /** Fixed global empty set of matching types. */ - final static Set EMPTY_MATCH_SET = Collections.emptySet(); } diff --git a/src/main/java/nl/utwente/groove/grammar/rule/VariableNode.java b/src/main/java/nl/utwente/groove/grammar/rule/VariableNode.java index 9fad5f56d..9f3612c93 100644 --- a/src/main/java/nl/utwente/groove/grammar/rule/VariableNode.java +++ b/src/main/java/nl/utwente/groove/grammar/rule/VariableNode.java @@ -16,12 +16,7 @@ */ package nl.utwente.groove.grammar.rule; -import java.util.Collections; -import java.util.List; import java.util.Optional; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNull; import nl.utwente.groove.algebra.Constant; import nl.utwente.groove.algebra.Sort; @@ -29,7 +24,6 @@ import nl.utwente.groove.algebra.syntax.Variable; import nl.utwente.groove.grammar.AnchorKind; import nl.utwente.groove.grammar.UnitPar.RulePar; -import nl.utwente.groove.grammar.type.TypeGuard; import nl.utwente.groove.grammar.type.TypeNode; import nl.utwente.groove.graph.ANode; @@ -168,26 +162,6 @@ public AnchorKind getAnchorKind() { return AnchorKind.NODE; } - @Override - public List getTypeGuards() { - return EMPTY_GUARD_LIST; - } - - @Override - public Set getVars() { - return EMPTY_VAR_SET; - } - - @Override - public Set getMatchingTypes() { - return EMPTY_NODES_SET; - } - - @Override - public boolean isSharp() { - return true; - } - /** The type of this variable node. */ private final TypeNode type; /** Term (constant or variable) associated with this variable node. */ @@ -195,10 +169,4 @@ public boolean isSharp() { /** returns the string preceding the node number in the default variable node id. */ static public final String TO_STRING_PREFIX = "x"; - /** Predefined empty list of matching types. */ - static private final @NonNull Set EMPTY_NODES_SET = Collections.emptySet(); - /** Predefined empty list of type guards. */ - static private final @NonNull List EMPTY_GUARD_LIST = Collections.emptyList(); - /** Predefined empty list of type guards. */ - static private final @NonNull Set EMPTY_VAR_SET = Collections.emptySet(); } diff --git a/src/main/java/nl/utwente/groove/grammar/type/TypeGraph.java b/src/main/java/nl/utwente/groove/grammar/type/TypeGraph.java index 50b563322..ac8a162a3 100644 --- a/src/main/java/nl/utwente/groove/grammar/type/TypeGraph.java +++ b/src/main/java/nl/utwente/groove/grammar/type/TypeGraph.java @@ -672,7 +672,7 @@ private VariableNode cloneVariableNode(RuleFactory ruleFactory, * @param parentTyping morphism from the untyped rule graph to the typed version * of a parent rule graph; used to get a hint for the node types * @param typing resulting morphism from the untyped to the typed rule graph; - * this is modified the node variables constraints + * this is modified using the node variables constraints * @return mapping from source rule nodes to typed versions * @throws FormatException if any errors were detected while constructing node images */ @@ -685,8 +685,9 @@ private Map computeNodeImages(RuleGraph source, FormatErrorSet errors = new FormatErrorSet(); // mapping from rule nodes to sets of label variables that occur on them Map> nodeVarsMap = new HashMap<>(); + // mapping from rule nodes to their type guards Map> nodeGuardsMap = new HashMap<>(); - // auxiliary map to sets of allowed node types + // mapping from rule nodes to their allowed types, according to the type guards Map> allowedTypesMap = new HashMap<>(); // mapping from nodes to declared node type Map declaredTypeMap = new HashMap<>(); @@ -808,7 +809,8 @@ private Map computeNodeImages(RuleGraph source, } else { RuleNode image = parentTyping .getFactory() - .nodes(type, sharpNodes.contains(node), nodeGuardsMap.get(node)) + .nodes(type, declaredType != null, sharpNodes.contains(node), + nodeGuardsMap.get(node)) .createNode(node.getNumber()); image.getMatchingTypes().retainAll(allowedTypes); result.put(node, image); diff --git a/src/main/java/nl/utwente/groove/match/rete/ReteNetwork.java b/src/main/java/nl/utwente/groove/match/rete/ReteNetwork.java index 9f1f976ca..319bb2d16 100644 --- a/src/main/java/nl/utwente/groove/match/rete/ReteNetwork.java +++ b/src/main/java/nl/utwente/groove/match/rete/ReteNetwork.java @@ -680,7 +680,7 @@ private RuleGraphMorphism createRuleMorphismForCloning(RuleGraph source, .nodeMap() .put(dn, rfact - .nodes(dn.getType(), n.isSharp(), dn.getTypeGuards()) + .nodes(dn.getType(), n.isDeclared(), n.isSharp(), dn.getTypeGuards()) .createNode(maxNodeNr++)); }