Skip to content

Commit

Permalink
Better treatment of label variables
Browse files Browse the repository at this point in the history
A node only typed by a label variable is now not considered to be typed
by the top node, allowing more flexibility in incident edge types
  • Loading branch information
rensink committed Apr 8, 2024
1 parent 979d5c9 commit b68f1bd
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 93 deletions.
15 changes: 13 additions & 2 deletions src/main/java/nl/utwente/groove/grammar/rule/DefaultRuleNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<TypeGuard> 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();
Expand Down Expand Up @@ -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;
Expand Down
22 changes: 0 additions & 22 deletions src/main/java/nl/utwente/groove/grammar/rule/OperatorNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -90,26 +88,6 @@ public TypeNode getType() {
return getTarget().getType();
}

@Override
public List<TypeGuard> getTypeGuards() {
return EMPTY_GUARD_LIST;
}

@Override
public Set<LabelVar> getVars() {
return EMPTY_VAR_SET;
}

@Override
public boolean isSharp() {
return true;
}

@Override
public Set<TypeNode> getMatchingTypes() {
return EMPTY_MATCH_SET;
}

@Override
public AnchorKind getAnchorKind() {
return AnchorKind.NODE;
Expand Down
14 changes: 7 additions & 7 deletions src/main/java/nl/utwente/groove/grammar/rule/RuleEdge.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/nl/utwente/groove/grammar/rule/RuleElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<LabelVar> getVars();
default public Set<LabelVar> getVars() {
return EMPTY_VAR_SET;
}

/** Returns the collection of (named) type guards associated with this rule element. */
public List<TypeGuard> getTypeGuards();
default public List<TypeGuard> getTypeGuards() {
return EMPTY_GUARD_LIST;
}

/**
* Returns the set of type elements that are valid matches of this rule element.
Expand Down
40 changes: 21 additions & 19 deletions src/main/java/nl/utwente/groove/grammar/rule/RuleFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<RuleNode> nodes(@NonNull TypeNode type, boolean sharp,
List<TypeGuard> 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<RuleNode> nodes(@NonNull TypeNode type, boolean declared, boolean sharp,
List<TypeGuard> typeGuards) {
return new RuleNodeFactory(type, declared, sharp, typeGuards);
}

/** Creates a variable node for a given algebra term, and with a given node number. */
Expand All @@ -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<VariableNode> arguments,
VariableNode target) {
VariableNode target) {
OperatorNode result = new OperatorNode(nr, operator, arguments, target);
registerNode(result);
return result;
Expand All @@ -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);
}
Expand Down Expand Up @@ -127,24 +126,27 @@ 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<TypeGuard> 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<TypeGuard> typeGuards) {
this.type = type;
this.declared = declared;
this.sharp = sharp;
this.typeGuards = typeGuards;
}

@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. */
Expand All @@ -154,7 +156,7 @@ protected TypeNode getType() {

private final @NonNull TypeNode type;
private final boolean sharp;
private final boolean declared;
private final List<TypeGuard> typeGuards;
}

}
32 changes: 27 additions & 5 deletions src/main/java/nl/utwente/groove/grammar/rule/RuleNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,39 @@ default public Optional<RulePar> 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<TypeNode> getMatchingTypes();
default public Set<TypeNode> 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<TypeNode> EMPTY_MATCH_SET = Collections.emptySet();
}
32 changes: 0 additions & 32 deletions src/main/java/nl/utwente/groove/grammar/rule/VariableNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,14 @@
*/
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;
import nl.utwente.groove.algebra.syntax.Expression;
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;

Expand Down Expand Up @@ -168,37 +162,11 @@ public AnchorKind getAnchorKind() {
return AnchorKind.NODE;
}

@Override
public List<TypeGuard> getTypeGuards() {
return EMPTY_GUARD_LIST;
}

@Override
public Set<LabelVar> getVars() {
return EMPTY_VAR_SET;
}

@Override
public Set<TypeNode> 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. */
private final Expression term;

/** 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<TypeNode> EMPTY_NODES_SET = Collections.emptySet();
/** Predefined empty list of type guards. */
static private final @NonNull List<TypeGuard> EMPTY_GUARD_LIST = Collections.emptyList();
/** Predefined empty list of type guards. */
static private final @NonNull Set<LabelVar> EMPTY_VAR_SET = Collections.emptySet();
}
8 changes: 5 additions & 3 deletions src/main/java/nl/utwente/groove/grammar/type/TypeGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -685,8 +685,9 @@ private Map<RuleNode,RuleNode> computeNodeImages(RuleGraph source,
FormatErrorSet errors = new FormatErrorSet();
// mapping from rule nodes to sets of label variables that occur on them
Map<RuleNode,Set<LabelVar>> nodeVarsMap = new HashMap<>();
// mapping from rule nodes to their type guards
Map<RuleNode,List<TypeGuard>> 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<RuleNode,Set<TypeNode>> allowedTypesMap = new HashMap<>();
// mapping from nodes to declared node type
Map<RuleNode,TypeNode> declaredTypeMap = new HashMap<>();
Expand Down Expand Up @@ -808,7 +809,8 @@ private Map<RuleNode,RuleNode> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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++));
}

Expand Down

0 comments on commit b68f1bd

Please sign in to comment.