[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[henshin-dev] Interpreter API draft

Hi,

I created a first draft for the new API -- see the attached interfaces. We should now discuss the details and design decisions. I'm keen to hear your ideas :).

A few comments up-front:

- all classes are meant to be reusable (for multiple executions)
- all objects are supposed to be created using a factory
- the engine has 2 jobs now: (1) find matches, (2) create a model changes
- options are directly stored in the engine (no TransformationOption class)
- the engine internally keeps the reference to the JavaScript engine (the reason for keeping the engine separately)
- matches are computed on-the-fly in an iterator
- for applying a rule either a partial match (e.g. an empty one) or a complete match can be specified. Partial matches are completed automatically if no complete match is defined explicitly.


If you don't understand something, please ask. The API should be powerful, user-friendly, minimal and allow to build efficient implementations.

Please make suggestions for (and *briefly* say why):

- Names of interfaces / methods etc.
- Functionality that you think should be moved, added, deleted,
- Any other ideas you have ;)

Cheers,
Christian

package org.eclipse.emf.henshin.interpreter;

import org.eclipse.emf.henshin.model.Parameter;
import org.eclipse.emf.henshin.model.TransformationUnit;

/**
 * Parameter assignment interface for storing parameter values.
 * @author Christian Krause
 */
public interface Assignment {

	/**
	 * Get the unit that this assignment refers to.
	 * @return The transformation unit.
	 */
	TransformationUnit getUnit();

	/**
	 * Set the unit that this assignment refers to.
	 * @param unit The transformation unit.
	 */
	void setUnit(TransformationUnit unit);

	/**
	 * Get the value assigned to a parameter.
	 * @param param The parameter.
	 * @return The assigned value or <code>null</code>.
	 */
	Object getParameterValue(Parameter param);
	
	/**
	 * Set the assigned value for a parameter.
	 * @param param The parameter.
	 * @param value The value to be assigned with the parameter.
	 */
	void setParameterValue(Parameter param, Object value);
	
	/**
	 * Clear this assignment.
	 */
	void clear();
	
}
package org.eclipse.emf.henshin.interpreter;

import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.change.ChangeDescription;

/**
 * Change descriptions for {@link EGraph}.
 * Created objects are stored in {@link #getObjectsToAttach()}.
 * Deleted objects are stored in {@link #getObjectsToDetach()}.
 * 
 * @author Christian Krause
 *
 */
public interface EChange extends ChangeDescription {
	
	/**
	 * Set the {@link EGraph} this change refers to.
	 * @param graph The {@link EGraph}.
	 */
	void setEGraph(EGraph graph);

	/**
	 * Helper method for adding a reference change.
	 * @param object Object to be changed.
	 * @param reference Reference to be changed.
	 * @param value Object that should be added to or deleted from the reference.
	 * @param delete Flag indicating whether the reference should be deleted.
	 */
	void addReferenceChange(EObject object, EReference reference, EObject value, boolean delete);
	
	/**
	 * Helper method for adding an attribute change.
	 * @param object Object to be changed.
	 * @param attribute Attribute to be changed.
	 * @param value New value for the attribute.
	 * @param delete Flag indicating whether the value should be deleted.
	 */
	void addAttributeChange(EObject object, EAttribute attribute, String value, boolean delete);
	
}
package org.eclipse.emf.henshin.interpreter;

import java.util.Set;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;

/**
 * EGraph interface for storing object graphs.
 * @author Christian Krause
 */
public interface EGraph extends Set<EObject> {
	
	/**
	 * Adds an {@link EObject} and all its children to this graph.
	 * @param root The root object of the tree.
	 * @return <code>true</code> if an object was added.
	 */
	boolean addTree(EObject root);
	
	/**
	 * Removes an {@link EObject} and all its children from this graph.
	 * @param root The root object of the tree.
	 * @return <code>true</code> if any object was removed. 
	 */
	boolean removeTree(EObject root);
	
	/**
	 * Get all {@link EObject}s of this graph which are compatible with the given type.
	 * @param type The type of the objects.
	 * @param strict Whether subtypes are excluded from the result.
	 * @return A set of {@link EObject}s compatible with the type.
	 */
	Set<EObject> getDomain(EClass type, boolean strict);
	
	/**
	 * Check whether the domain for a type is empty. This is the case if and only
	 * if {@link #getDomain(EClass, boolean)} returns an empty list.
	 * @param type The type.
	 * @param strict Whether subtypes are excluded.
	 * @return <code>true</code> if the domain is empty.
	 */
	boolean isDomainEmpty(EClass type, boolean strict);

	/**
	 * Get the cross reference adapter of this graph.
	 * @return The cross reference adapter.
	 */
	ECrossReferenceAdapter getCrossReferenceAdapter();

}
/*******************************************************************************
 * Copyright (c) 2010 CWI Amsterdam, Technical University Berlin, 
 * Philipps-University Marburg and others. All rights reserved. 
 * This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Technical University Berlin - initial API and implementation
 *******************************************************************************/
package org.eclipse.emf.henshin.interpreter;

import java.util.Map;

import org.eclipse.emf.henshin.model.Rule;

/**
 * Engine interface for the Henshin interpreter.
 */
public interface Engine {
	
	/**
	 * Option for general injective rule matching. 
	 */
	String OPTION_INJECTIVE_MATCHING = "INJECTIVE_MATCHING";
	
	/**
	 * Option for general checks for dangling edges.
	 */
	String OPTION_CHECK_DANGLING = "CHECK_DANGLING";
	
	/**
	 * Option for general deterministic engine behavior.
	 */
	String OPTION_DETERMINISTIC = "DETERMINISTIC";

	/**
	 * Find matches for a {@link Rule} in an {@link EGraph}.
	 * @param rule Rule to be matched.
	 * @param graph Graph where the match should be found.
	 * @param partialMatch Partial match (can be empty or <code>null</code>).
	 * @return An iterable list of matches.
	 */
	Iterable<Match> findMatches(Rule rule, EGraph graph, Match partialMatch);

	/**
	 * Create an {@link EChange} for applying a rule
	 * @param rule Rule to be applied.
	 * @param graph Graph where the rule should be applied.
	 * @param completeMatch A <b>complete</b> match for the rule in the graph.
	 * @return An {@link EChange} object that can be used to apply the rule
	 */
	EChange createChange(Rule rule, EGraph graph, Match completeMatch);
	
	/**
	 * Get or set the options for this engine.
	 * @return Options map.
	 */
	Map<?,?> getOptions();
		
}
package org.eclipse.emf.henshin.interpreter;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.henshin.interpreter.impl.InterpreterFactoryImpl;
import org.eclipse.emf.henshin.model.Rule;
import org.eclipse.emf.henshin.model.TransformationUnit;

/**
 * Factory interface for the Henshin interpreter.
 * @author Christian Krause
 */
public interface InterpreterFactory {
	
	/**
	 * Static factory instance.
	 */
	final static InterpreterFactory INSTANCE = new InterpreterFactoryImpl();
	
	/**
	 * Create a new {@link EGraph} object.
	 * @return A new {@link EGraph}.
	 */
	EGraph createEGraph();

	/**
	 * Create a new {@link EGraph} object.
	 * @param root A root object to be used in the graph.
	 * @return A new {@link EGraph}.
	 */
	EGraph createEGraph(EObject root);
	
	/**
	 * Create a new {@link EGraph} object.
	 * @param resource A resource whose content shall be used in the graph.
	 * @return A new {@link EGraph}.
	 */
	EGraph createEGraph(Resource resource);
	
	/**
	 * Create an {@link Assignment} object.
	 * @param unit Target {@link TransformationUnit}.
	 * @return A new {@link Assignment}.
	 */
	Assignment createAssignment(TransformationUnit unit);
	
	/**
	 * Create a {@link Match} object.
	 * @param Rule to be matched.
	 * @return A new {@link Match}.
	 */
	Match createMatch(Rule rule);

	/**
	 * Create an {@link Engine} object. For engines create with this
	 * factory method, it is always ensured that fresh {@link Match}s
	 * and {@link EChange}s are created.
	 * @return A new {@link Engine}.
	 */
	Engine createEngine();
	
	/**
	 * Create a new minimal {@link Engine} object. Minimal engines
	 * save memory by reusing {@link Match}s and {@link EChange}s.
	 * @return A new minimal {@link Engine}.
	 */
	Engine createMinimalEngine();

	/**
	 * Create a new {@link UnitApplication}.
	 * @param unit {@link TransformationUnit} to be applied.
	 * @param graph {@link EGraph} the unit should be applied to.
	 * @param engine {@link Engine} to be used.
	 * @return A new {@link UnitApplication}.
	 */
	UnitApplication createUnitApplication(TransformationUnit unit, EGraph graph, Engine engine);

	/**
	 * Create a new {@link RuleApplication}.
	 * @param unit {@link Rule} to be applied.
	 * @param graph {@link EGraph} the rule should be applied to.
	 * @param engine {@link Engine} to be used.
	 * @return A new {@link RuleApplication}.
	 */
	RuleApplication createRuleApplication(Rule rule, EGraph graph, Engine engine);
	
}
package org.eclipse.emf.henshin.interpreter;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.henshin.model.Node;
import org.eclipse.emf.henshin.model.Rule;

/**
 * Match interface for mapping {@link Node}s to {@link EObject} and 
 * assigning parameter values by extending {@link Assignment}.
 * @author Christian Krause
 */
public interface Match extends Assignment {
	
	/**
	 * Get the rule that this match is used for.
	 * @return The rule.
	 */
	Rule getRule();

	/**
	 * Set the rule that this match is used for.
	 * @param rule The rule.
	 */
	void setRule(Rule rule);

	/**
	 * Get the match target for a node.
	 * @param node The node.
	 * @return The matched target object.
	 */
	EObject getNodeTarget(Node node);
	
	/**
	 * Set the match target for a node.
	 * @param node The node.
	 * @param target The match target.
	 */
	void setNodeTarget(Node node, EObject target);
	
	/**
	 * Get the nested matches for a multi-rule.
	 * @param multiRule The multi-rule.
	 * @return List of matches.
	 */
	EList<Match> getNestedMatches(Rule multiRule);

	/**
	 * Checks whether this match overlaps with another match. 
	 * The second match can be from a different rule.
	 * @param match A second match to check against.
	 * @return <code>true</code> if both matches have common targets.
	 */
	boolean overlapsWith(Match match);

	/**
	 * Checks if all nodes have a target and all nested matches are also complete.
	 * @return <code>true</code> if all nodes are matched.
	 */
	boolean isComplete();
	
	/**
	 * Checks whether this match is complete, whether the typing of the matched
	 * objects is correct with respect to the node types, and whether all edges
	 * are present.
	 * @return <code>true</code> if the match is valid.
	 */
	boolean isValid();

	/**
	 * Checks whether this is a comatch. 
	 * @return <code>true</code> if it is a comatch.
	 */
	boolean isCoMatch();
	
	/**
	 * Decide whether this is a comatch. 
	 * @param isCoMatch <code>true</code> if it is a comatch.
	 */
	void setIsCoMatch(boolean isCoMatch);

}
package org.eclipse.emf.henshin.interpreter;

import org.eclipse.emf.henshin.model.Rule;

/**
 * Rule application interface for executing a {@link Rule}.
 * 
 * @author Christian Krause
 */
public interface RuleApplication extends UnitApplication {

	/**
	 * Get the rule to be applied.
	 * @return The rule to be applied.
	 */
	Rule getRule();

	/**
	 * Set the rule to be applied.
	 * @param rule The rule to be applied.
	 */
	void setRule(Rule rule);

	/**
	 * Get the partial match to be used.
	 * @return The partial match.
	 */
	Match getPartialMatch();

	/**
	 * Set the partial match to be used.
	 * @param partialMatch The partial match.
	 */
	void setPartialMatch(Match partialMatch);

	/**
	 * Get the complete match to be used.
	 * @return The complete match.
	 */
	Match getCompleteMatch();

	/**
	 * Set the complete match to be used.
	 * @param completeMatch The complete match.
	 */
	void setCompleteMatch(Match completeMatch);

	/**
	 * Get the used comatch.
	 * @return The comatch.
	 */
	Match getCoMatch();

}
package org.eclipse.emf.henshin.interpreter;

import org.eclipse.emf.henshin.model.TransformationUnit;

/**
 * Unit application interface for executing a {@link TransformationUnit}.
 * If you want to execute a transformation rule, use {@link RuleApplication}
 * instead.
 * 
 * @author Christian Krause
 */
public interface UnitApplication {

	/**
	 * Get the unit to be applied.
	 * @return The transformation unit.
	 */
	TransformationUnit getUnit();

	/**
	 * Set the unit to be applied.
	 * @param unit The transformation unit.
	 */
	void setUnit(TransformationUnit unit);
	
	/**
	 * Get the parameter assignment to be used.
	 * @return The parameter assignment.
	 */
	Assignment getAssignment();

	/**
	 * Set the parameter assignment to be used.
	 * @param assignment The parameter assignment.
	 */
	void setAssignment(Assignment assignment);

	/**
	 * Execute this unit application.
	 * @return <code>true</code> if the unit was successfully applied.
	 */
	boolean execute();
	
	/**
	 * Undo this unit application. This restores the original model as
	 * it was before calling {@link #execute()}.
	 */
	void undo();
	
	/**
	 * Redo this unit application. This method can be invoked after
	 * {@link #undo()} has been invoked. The effect is that the
	 * unit is executed again.
	 */
	void redo();
	
}