浏览代码

Merge branch 'newNamingService' into misraNaming

René Beckmann 7 年之前
父节点
当前提交
1d3c0d3849
共有 16 个文件被更改,包括 1219 次插入1219 次删除
  1. 2 1
      plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/CCodeGeneratorModule.java
  2. 145 0
      plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/CTreeNamingService.xtend
  3. 1 0
      plugins/org.yakindu.sct.model.sexec/META-INF/MANIFEST.MF
  4. 2 2
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/ElementNameProvider.xtend
  5. 34 0
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/IStringShortener.java
  6. 0 453
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/StringTreeNode.xtend
  7. 0 651
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/TreeNamingService.xtend
  8. 30 18
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/ShortString.xtend
  9. 48 0
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/tree/ShortStringUtils.xtend
  10. 206 0
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/tree/StringTreeNode.xtend
  11. 365 0
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/tree/TreeNamingService.xtend
  12. 43 0
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/tree/TreeServiceNamesValidator.xtend
  13. 190 0
      plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/tree/TreeStringShortener.xtend
  14. 10 14
      test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/ShortStringTest.java
  15. 140 77
      test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/StringTreeNodeTest.java
  16. 3 3
      test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/TreeNamingServiceTest.java

+ 2 - 1
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/CCodeGeneratorModule.java

@@ -32,6 +32,7 @@ import org.yakindu.sct.model.sgen.GeneratorEntry;
 import org.yakindu.sct.model.sgraph.Statechart;
 import org.yakindu.sct.model.sgraph.Statechart;
 
 
 import com.google.inject.Binder;
 import com.google.inject.Binder;
+import com.google.inject.Singleton;
 import com.google.inject.name.Names;
 import com.google.inject.name.Names;
 /**
 /**
  * 
  * 
@@ -44,7 +45,7 @@ public class CCodeGeneratorModule implements IGeneratorModule {
 	public void configure(GeneratorEntry entry, Binder binder) {
 	public void configure(GeneratorEntry entry, Binder binder) {
 		binder.bind(GeneratorEntry.class).toInstance(entry);
 		binder.bind(GeneratorEntry.class).toInstance(entry);
 		binder.bind(IExecutionFlowGenerator.class).to(CGenerator.class);
 		binder.bind(IExecutionFlowGenerator.class).to(CGenerator.class);
-		binder.bind(INamingService.class).to(CNamingService.class);
+		binder.bind(INamingService.class).to(CTreeNamingService.class).in(Singleton.class);
 		binder.bind(ICodegenTypeSystemAccess.class).to(CTypeSystemAccess.class);
 		binder.bind(ICodegenTypeSystemAccess.class).to(CTypeSystemAccess.class);
 		binder.bind(IncludeProvider.class).to(StandardIncludeProvider.class);
 		binder.bind(IncludeProvider.class).to(StandardIncludeProvider.class);
 		bindIGenArtifactConfigurations(entry, binder);
 		bindIGenArtifactConfigurations(entry, binder);

+ 145 - 0
plugins/org.yakindu.sct.generator.c/src/org/yakindu/sct/generator/c/CTreeNamingService.xtend

@@ -0,0 +1,145 @@
+/**
+  Copyright (c) 2014-2015 committers of YAKINDU Statechart Tools.
+  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:
+  	Markus Mühlbrandt - Initial contribution and API
+*/
+
+package org.yakindu.sct.generator.c
+
+import com.google.inject.Inject
+import java.util.Arrays
+import java.util.Map
+import org.yakindu.base.base.NamedElement
+import org.yakindu.sct.generator.c.extensions.GenmodelEntries
+import org.yakindu.sct.model.sexec.ExecutionFlow
+import org.yakindu.sct.model.sexec.ExecutionState
+import org.yakindu.sct.model.sexec.Step
+import org.yakindu.sct.model.sexec.extensions.SExecExtensions
+import org.yakindu.sct.model.sexec.naming.tree.TreeNamingService
+import org.yakindu.sct.model.sgen.GeneratorEntry
+import org.yakindu.sct.model.sgraph.State
+import org.yakindu.sct.model.sgraph.Statechart
+import org.yakindu.sct.model.stext.stext.TimeEventSpec
+
+import static org.yakindu.sct.generator.c.CKeywords.*
+
+public class CTreeNamingService extends TreeNamingService {
+	
+	@Inject
+	extension GenmodelEntries
+	@Inject
+	extension SExecExtensions
+	@Inject
+	var GeneratorEntry entry
+	
+	override void initializeNamingService(Statechart statechart) {
+		if (entry.identifierLength !== null) {
+			setMaxLength(entry.identifierLength)
+		}
+		
+		if (entry.separator !== null) {
+			setSeparator(entry.separator.charAt(0))
+		}
+		
+		super.initializeNamingService(statechart)
+	}
+	
+	override void initializeNamingService(ExecutionFlow flow) {
+		if (entry.identifierLength !== null) {
+			setMaxLength(entry.identifierLength)
+		}
+		
+		if (entry.separator !== null) {
+			setSeparator(entry.separator.charAt(0))
+		}
+		
+		super.initializeNamingService(flow)
+	}
+	
+	override Map<NamedElement, String> getShortNameMap(ExecutionFlow flow) {
+		if (entry.identifierLength !== null) {
+			setMaxLength(entry.identifierLength)
+		}
+		
+		if (entry.separator !== null) {
+			setSeparator(entry.separator.charAt(0))
+		}
+		
+		return super.getShortNameMap(flow)
+	}
+	
+	override Map<NamedElement, String> getShortNameMap(Statechart statechart) {
+		if (entry.identifierLength !== null) {
+			setMaxLength(entry.identifierLength)
+		}
+		
+		if (entry.separator !== null) {
+			setSeparator(entry.separator.charAt(0))
+		}
+		
+		return super.getShortNameMap(statechart)
+	}
+	
+	override protected prefix(Step it) {
+		val prefix = newArrayList
+		if (entry.statemachinePrefix != null) {
+			prefix.add(entry.statemachinePrefix)
+		} else {
+			prefix.add(flow.name.toFirstLower)
+		}
+		prefix.add(switch (it) {
+			case isCheckFunction:"check"
+			case isEntryAction: "enact"
+			case isExitAction: "exact"
+			case isEffect: "effect"
+			case isEnterSequence: "enseq"
+			case isDeepEnterSequence: "dhenseq"
+			case isShallowEnterSequence: "shenseq"
+			case isExitSequence: "exseq"
+			case isReactSequence: "react"
+			default: ""
+		})
+		return prefix
+	}
+	
+	override protected prefix(ExecutionState it) {
+		if (entry.statemachinePrefix.nullOrEmpty) {
+			super.prefix(it).toFirstUpper		
+		} else {
+			#[entry.statemachinePrefix]
+		}
+	}
+	
+	override protected prefix(State it) {
+		if (entry.statemachinePrefix.nullOrEmpty) {
+			super.prefix(it).toFirstUpper
+		} else {
+			#[entry.statemachinePrefix]
+		}
+	}
+	
+	override protected prefix(TimeEventSpec it, NamedElement element) {
+		if (entry.statemachinePrefix.nullOrEmpty) {
+			super.prefix(it, element).toFirstUpper
+		} else {
+			#[entry.statemachinePrefix]
+		}
+	}
+	
+	override asEscapedIdentifier(String it) {
+		var s = it
+		if (s.isKeyword) {
+			s = s + separator +'ID'
+		}
+		return s.asIdentifier
+	}
+	
+	override boolean isKeyword(String name) {
+		return !Arrays::asList(C_KEYWORDS).findFirst[it.equalsIgnoreCase(name)].nullOrEmpty
+	}
+}

+ 1 - 0
plugins/org.yakindu.sct.model.sexec/META-INF/MANIFEST.MF

@@ -11,6 +11,7 @@ Export-Package: org.yakindu.sct.model.sexec,
  org.yakindu.sct.model.sexec.extensions,
  org.yakindu.sct.model.sexec.extensions,
  org.yakindu.sct.model.sexec.impl,
  org.yakindu.sct.model.sexec.impl,
  org.yakindu.sct.model.sexec.naming,
  org.yakindu.sct.model.sexec.naming,
+ org.yakindu.sct.model.sexec.naming.tree,
  org.yakindu.sct.model.sexec.transformation,
  org.yakindu.sct.model.sexec.transformation,
  org.yakindu.sct.model.sexec.util
  org.yakindu.sct.model.sexec.util
 Require-Bundle: com.google.inject,
 Require-Bundle: com.google.inject,

+ 2 - 2
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/ElementNameProvider.xtend

@@ -30,10 +30,10 @@ import java.util.ArrayList
 class ElementNameProvider {
 class ElementNameProvider {
 	@Inject private StextNameProvider provider
 	@Inject private StextNameProvider provider
 
 
-	def protected List<String> elementNameSegments(NamedElement e) {
+	def public List<String> elementNameSegments(NamedElement e) {
 		val name = elementName(e);
 		val name = elementName(e);
 		var ArrayList<String> l;
 		var ArrayList<String> l;
-		if (name != null) {
+		if (name !== null) {
 			l = new ArrayList<String>(name.getSegments());
 			l = new ArrayList<String>(name.getSegments());
 		} else {
 		} else {
 			l = new ArrayList<String>();
 			l = new ArrayList<String>();

+ 34 - 0
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/IStringShortener.java

@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2018 committers of YAKINDU 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:
+ * 	rbeckmann - initial API and implementation
+ * 
+ */
+package org.yakindu.sct.model.sexec.naming;
+
+import java.util.List;
+
+import org.yakindu.sct.model.sexec.naming.tree.TreeStringShortener;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * @author rbeckmann
+ *
+ */
+@ImplementedBy(TreeStringShortener.class)
+public interface IStringShortener {
+	public void setMaxLength(int length);
+	
+	/** Adds a string to the shortener. Can be retreived later in shortened form via getString using the token. */
+	public void addString(List<String> s, Object token);
+	
+	/** Retrieves a shortened String from the shortener, using the token that was specified on depositing the original String. */
+	public String getString(Object token);
+	
+	public void reset();
+}

+ 0 - 453
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/StringTreeNode.xtend

@@ -1,453 +0,0 @@
-/**
- *   Copyright (c) 2016 committers of YAKINDU Statechart Tools.
- *   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:
- * 		@author René Beckmann (beckmann@itemis.de)
- */
-
-package org.yakindu.sct.model.sexec.naming
-
-import java.util.ArrayList
-import java.util.List
-import java.util.Comparator
-
-class StringTreeNodeDepthComparator implements Comparator<StringTreeNode> {
-	override compare(StringTreeNode o1, StringTreeNode o2) {
-		return o1.getDepth() - o2.getDepth();
-	}
-}
-
-class StringTreeNode {
-	/*
-	 * implements a data tree to hold the various statechart elements' names
-	 */
-	private String data;
-	private ArrayList<StringTreeNode> children;
-	private StringTreeNode parent;
-
-	/*
-	 * Constructors
-	 */
-	new(String data) {
-		this.data = data;
-		this.parent = null;
-		this.children = new ArrayList();
-	}
-
-	new() {
-		this.data = null;
-		this.parent = null;
-		this.children = new ArrayList();
-	}
-
-	/*
-	 * getters & setters
-	 */
-	def public ArrayList<StringTreeNode> getChildren() {
-		/*
-		 * getter for this.children
-		 */
-		return children;
-	}
-
-	def public String getData() {
-		/*
-		 * getter for this.data
-		 */
-		return data;
-	}
-
-	/*
-	 * Tree construction functions
-	 */
-	def public void addChild(StringTreeNode node) {
-		/*
-		 * Function to add a child to this node.
-		 */
-		node.parent = this;
-		children.add(node);
-	}
-
-	def public StringTreeNode addString(String s) {
-		/*
-		 * Cut the string into an ArrayList containing the single chars in the string,
-		 * and call addStringList afterwards.
-		 */
-		var sList = new ArrayList<String>();
-
-		for (var i = 0; i < s.length(); i++) {
-			sList.add(Character.toString(s.charAt(i)));
-		}
-		return this.addStringList(sList);
-	}
-
-	def public StringTreeNode addStringList(List<String> sList) {
-		/*
-		 * Adds an array of strings.
-		 * If the first element is found within own children's data,
-		 * cut the first element and call that child with this function recursively.
-		 * Else, create new child with that element, and proceed the same.
-		 */
-		if (sList.size() == 0) {
-			for (child : children) {
-				if (child.isEnd()) {
-					return child; // only add one end per node - don't allow double strings
-				}
-			}
-			val newNode = new StringTreeNode("");
-			addChild(newNode); // mark End
-			return newNode;
-		}
-
-		var firstString = sList.get(0); // first element to search in own children. If not found, create new one.
-		var rest = sList.subList(1, sList.size()); // the rest of the array that the child's addStringList function is called with
-		var newChild = true;
-
-		for (child : children) // search for child that fits
-		{
-			if (child.getData().equals(firstString)) {
-				newChild = false;
-				return child.addStringList(rest);
-			}
-		}
-		if (newChild) {
-			var newNode = new StringTreeNode(firstString);
-			addChild(newNode);
-			return newNode.addStringList(rest);
-		}
-
-	}
-
-	/*
-	 * Tree reading functions
-	 */
-	def public List<StringTreeNode> getNodes() {
-		var List<StringTreeNode> nodelist = new ArrayList<StringTreeNode>();
-
-		nodelist.add(this);
-
-		for (child : children) {
-			nodelist.addAll(child.getNodes())
-		}
-
-		return nodelist;
-	}
-
-	def public int getWeight() {
-		var weight = 0;
-
-		for (c : children) {
-			weight += c.getWeight() + 1; // + 1: count children as well
-		}
-
-		return weight;
-	}
-
-	def public int getDepth() {
-		// Upwards recursion to get distance from root
-		if (parent == null) {
-			return 0;
-		} else {
-			return parent.getDepth() + 1;
-		}
-	}
-
-	def public ArrayList<String> getSiblings(String fullName) {
-
-		val nodeChain = getNodeChain(fullName)
-		val lastNode = (nodeChain).get(nodeChain.size() - 1);
-
-		val siblings = lastNode.getSiblings();
-
-		val siblingsContents = new ArrayList<String>();
-
-		for (node : siblings) {
-			siblingsContents.add(node.getData());
-		}
-		return siblingsContents
-	}
-
-	def public ArrayList<StringTreeNode> getSiblings() {
-		// returns a list of the parent's children without this - can be empty.
-		if (isRoot()) {
-			return new ArrayList<StringTreeNode>();
-		} else {
-			var list = new ArrayList<StringTreeNode>(this.parent.getChildren()); // copy
-			list.removeAll(this);
-			return list;
-		}
-
-	}
-
-	def public ArrayList<String> getContents() {
-		/*
-		 * Returns a list of all strings contained in the tree
-		 */
-		var contents = new ArrayList<String>();
-		var endNodes = getEndNodes();
-
-		for (end : endNodes) {
-			contents.add(end.getContentUpwards());
-		}
-
-		return contents;
-	}
-
-	def public ArrayList<StringTreeNode> getEndNodes() {
-		/*
-		 * returns a list of nodes that are string ending nodes (node.isEnd() == true)
-		 */
-		var endNodes = new ArrayList<StringTreeNode>();
-
-		for (child : children) {
-			if (child.isEnd()) {
-				endNodes.add(child);
-			}
-			endNodes.addAll(child.getEndNodes());
-		}
-		return endNodes;
-	}
-
-	def public String getContentUpwards() {
-		/*
-		 * Traverse tree upwards and return the string ended by this node up to root
-		 */
-		var s = "";
-
-		if (!isRoot()) {
-			s = this.parent.getContentUpwards() + this.data;
-		}
-
-		return s;
-	}
-
-	def public String getShortName(String longname, int maxLen) {
-		var nodeChain = getNodeChain(longname);
-
-		var ret = "";
-
-		for (node : nodeChain) {
-			ret += node.getData();
-		}
-
-		return ret;
-	}
-
-	def public void delete() {
-		/*
-		 * All nodes have a reference to their parent (except the root node, where it's null) and their children.
-		 * Thus, when we want to delete a node, we need to cut it from its parent's children and
-		 * delete the reference to the parent. The rest of the tree is then 'floating' and will be garbage collected.
-		 */
-		if (!isRoot()) {
-			this.parent.deleteChild(this);
-			this.parent = null;
-		}
-	}
-
-	def public deleteChild(StringTreeNode child) {
-		this.children.removeAll(child);
-	}
-
-	def public ArrayList<StringTreeNode> getNodeChain(String name) {
-		/*
-		 * produces an ArrayList containing the Nodes that form the given string.
-		 */
-		var nodeChain = new ArrayList<StringTreeNode>();
-
-		if (children.size() == 0 || (children.size() == 1 && children.get(0).isEnd())) {
-			return nodeChain;
-		}
-
-		var maxEquality = 0;
-		var StringTreeNode maxEqualNode = null;
-
-		for (child : children) // find maximum equality in tree to select the correct branch
-		{
-			var childS = child.getData();
-			if (name.startsWith(childS) && childS.length() > maxEquality) {
-				maxEquality = childS.length();
-				maxEqualNode = child;
-			}
-		}
-
-		if (maxEqualNode == null) {
-			return null;
-		}
-
-		var rest = name.substring(maxEquality);
-
-		nodeChain.add(maxEqualNode);
-
-		val childrenNodeChain = maxEqualNode.getNodeChain(rest);
-
-		if (childrenNodeChain == null) {
-			return null;
-		}
-
-		nodeChain.addAll(childrenNodeChain);
-
-		return nodeChain;
-	}
-
-	def public StringTreeNode navigate(String content) {
-		for (child : children) {
-			if (content.equals(child.getData())) {
-				return child;
-			}
-		}
-
-		return null;
-	}
-
-	def public StringTreeNode getParent() {
-		return parent;
-	}
-
-	def public List<String> getChildrenContents() {
-		var returnList = new ArrayList<String>();
-
-		for (child : children) {
-			returnList.add(child.getData());
-		}
-
-		return returnList;
-	}
-
-	/*
-	 * Tree manipulating functions
-	 */
-	def public void compress() {
-		/*
-		 * Compresses branches.
-		 * All nodes 'X' that have only one child 'A' append 'A's data to their own, delete  'A' and
-		 * make 'A's children their ('X's) own.
-		 * Only exception: endNodes, according to node.isEnd() == true, are not consumed.
-		 * 
-		 * Example:
-		 * A, B, C... denote states, - denotes an edge, # denotes an end node, O the root node
-		 * 
-		 * O-A-B-C-D-E-#
-		 *        \
-		 *         F-G-#
-		 * 
-		 * becomes
-		 * 
-		 * O-ABC-DE-#
-		 *      \
-		 *       FG-#
-		 */
-		if (!isRoot()) // don't do for root, no data should be saved in root
-		{
-			while (this.children.length() == 1 && !children.get(0).isEnd()) {
-				var myChild = children.get(0); // reference to only child
-				this.children.removeAll(myChild); // delete from list
-				this.data += myChild.getData(); // append myChilds data to own
-				for (child : myChild.getChildren()) // adopt myChilds children as own
-				{
-					this.addChild(child);
-				}
-			}
-		}
-
-		for (child : this.children) // recursion
-		{
-			child.compress();
-		}
-
-	}
-
-	/*
-	 * Helper functions
-	 */
-	def public boolean isAncestor(StringTreeNode descendantNode) {
-		/*
-		 * Traverses the tree upwards and checks if the node this function is called on is an ancestor of the given node.
-		 * 
-		 * Example:
-		 * 
-		 * O-A-B-C-D
-		 *      \
-		 *       E
-		 * 
-		 * When called on 'B', given 'D', this should return true, but not the other way round:
-		 * 'D' is not root, and 'D's parent is not 'B', so the function is called again with 'C'. 'B' is 'C's parent, returns true.
-		 * 
-		 * When called on 'E', given 'C', this should return false, and has the same behaviour when called on 'C' given 'E'.
-		 * 1st. call: 'C' is not root, and 'C's parent is not 'E', so the function is called again with 'B'.
-		 * 2nd. call: 'B' is not root, and 'B's parent is not 'E', so the function is called again with 'A'.
-		 * 3rd. call: 'A' is not root, and 'A's parent is not 'E', so the function is called again with 'O', the root node.
-		 * 4th. call: 'O' is the root node, false is returned. E is not an ancestor of C.
-		 * 
-		 * ATTENTION: This function does NOT return true if this is a root node. This would not test if descendantNode
-		 * belongs to this tree.
-		 * 
-		 */
-		if (descendantNode.isRoot()) // obviously, this node can't be the ancestor when descendantNode is root
-		{
-			return false;
-		} else if (descendantNode.parent == this) {
-			return true;
-		} else {
-			return this.isAncestor(descendantNode.parent)
-		}
-	}
-
-	def public int getDistance(StringTreeNode otherNode) {
-		if (this == otherNode) {
-			return 0;
-		} else if (this.isRoot()) {
-			return otherNode.getDepth();
-		} else if (otherNode.isRoot()) {
-			return this.getDepth();
-		} else if (this.isAncestor(otherNode)) {
-			return otherNode.getDepth() - this.getDepth();
-		} else if (otherNode.isAncestor(this)) {
-			return this.getDepth() - otherNode.getDepth();
-		} else {
-			val commonAncestor = this.getCommonAncestor(otherNode);
-			val distance = this.getDepth() + otherNode.getDepth() - 2 * commonAncestor.getDepth();
-			return distance;
-		}
-	}
-
-	def public StringTreeNode getCommonAncestor(StringTreeNode otherNode) {
-		if (this == otherNode) {
-			return this;
-		} else if (this.isAncestor(otherNode)) {
-			return this;
-		} else if (otherNode.isAncestor(this)) {
-			return otherNode;
-		} else {
-			// find node next to root, climb upwards until ancestor of other node is found
-			var StringTreeNode upperNode;
-			var StringTreeNode underNode;
-			val thisDepth = this.getDepth();
-			val otherDepth = otherNode.getDepth();
-			if (thisDepth > otherDepth) {
-				upperNode = otherNode;
-				underNode = this;
-			} else {
-				upperNode = this;
-				underNode = otherNode;
-			}
-			while (!upperNode.isAncestor(underNode)) {
-				upperNode = upperNode.parent;
-			}
-			return upperNode;
-		}
-	}
-
-	def public boolean isRoot() {
-		return this.parent == null;
-	}
-
-	def public boolean isEnd() {
-		var ret = (this.children.size() == 0 && this.data.equals(""));
-		return ret;
-	}
-}

+ 0 - 651
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/TreeNamingService.xtend

@@ -1,651 +0,0 @@
-/**
- *   Copyright (c) 2016 committers of YAKINDU Statechart Tools.
- *   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:
- * 		@author René Beckmann (beckmann@itemis.de)
- */
-
-package org.yakindu.sct.model.sexec.naming
-
-import java.util.ArrayList
-import java.util.HashMap
-import java.util.List
-import java.util.Map
-import javax.inject.Inject
-import org.eclipse.xtext.naming.IQualifiedNameProvider
-import org.yakindu.base.base.NamedElement
-import org.yakindu.sct.model.sexec.ExecutionFlow
-import org.yakindu.sct.model.sexec.ExecutionScope
-import org.yakindu.sct.model.sexec.ExecutionState
-import org.yakindu.sct.model.sexec.Step
-import org.yakindu.sct.model.sexec.extensions.SExecExtensions
-import org.yakindu.sct.model.sexec.transformation.StatechartExtensions
-import org.yakindu.sct.model.sgraph.CompositeElement
-import org.yakindu.sct.model.sgraph.Region
-import org.yakindu.sct.model.sgraph.State
-import org.yakindu.sct.model.sgraph.Statechart
-import org.yakindu.sct.model.sgraph.Vertex
-import org.yakindu.sct.model.stext.stext.TimeEventSpec
-import com.google.common.collect.Maps
-
-/** New implementation of the naming service for various identifiers used in the generated code. 
- * It is responsible for identifier construction depending on the thing to be named including different strategies 
- * which also include name shortening.
- */
-class TreeNamingService implements INamingService {
-
-	@Inject extension SExecExtensions
-	@Inject extension StatechartExtensions
-	@Inject extension IQualifiedNameProvider
-
-	@Inject extension ElementNameProvider
-
-	@Inject private StringTreeNodeDepthComparator stringTreeNodeDepthComparator
-
-	// from public class org.yakindu.sct.generator.c.features.CDefaultFeatureValueProvider extends		
-	private static final String VALID_IDENTIFIER_REGEX = "[_a-zA-Z][_a-zA-Z0-9]*";
-
-	var protected int maxLength = 0;
-
-	var protected char separator = '_';
-
-	/*
-	 * Holds the name of each element whose name was requested.
-	 */
-	var protected Map<NamedElement, String> map;
-
-	/*
-	 * Holds the end node in the tree for each NamedElement that was added.
-	 */
-	var protected Map<NamedElement, StringTreeNode> treeMap;
-
-	/*
-	 * For each node in the tree, there is a mapping to a short string managing the shortening of the name.
-	 */
-	var protected Map<StringTreeNode, ShortString> node_shortString_map;
-
-	/*
-	 * For each end node, individualMap holds a List of Nodes which make this name individual. (a subset of the tree basically)
-	 */
-	var protected Map<StringTreeNode, ArrayList<StringTreeNode>> individualMap;
-
-	var protected boolean shortNamesValid; // marker to remember if the names are currently correctly shortened
-	var protected StringTreeNode tree; // the tree which holds the added names
-	// if the naming service is initialized with a flow, activeStatechart is null, and vice versa.
-	var protected ExecutionFlow activeFlow;
-
-	var protected Statechart activeStatechart;
-
-	new(int maxLength, char separator) {
-		this.maxLength = maxLength
-		this.separator = separator
-	}
-
-	new() {
-		this.maxLength = 0
-		this.separator = '_'
-	}
-
-	override initializeNamingService(Statechart statechart) {
-		if (tree == null || activeStatechart != statechart) {
-			map = Maps.newHashMap
-			treeMap = Maps.newHashMap
-			shortNamesValid = false;
-
-			activeFlow = null;
-			activeStatechart = statechart;
-			createNameTree(statechart);
-
-			individualMap = constructIndividualNames();
-			node_shortString_map = createShortStringMapping();
-
-			shortenNames();
-		}
-	}
-
-	def private void createNameTree(Statechart statechart) {
-		tree = new StringTreeNode();
-
-		addShortVertexNames(statechart);
-	}
-
-	def protected void addShortVertexNames(CompositeElement element) {
-		for (region : element.regions) {
-			addElement(region, new ArrayList<String>(), new ArrayList<String>());
-			for (vertex : region.vertices) {
-				switch vertex {
-					State:
-						addElement(vertex, new ArrayList<String>(), new ArrayList<String>())
-					default:
-						addElement(vertex, new ArrayList<String>(), new ArrayList<String>())
-				}
-			}
-		}
-		for (region : element.regions) {
-			for (vertex : region.vertices) {
-				if (vertex instanceof CompositeElement) {
-					addShortVertexNames(vertex as CompositeElement)
-				}
-			}
-		}
-	}
-
-	override initializeNamingService(ExecutionFlow flow) {
-		if (tree == null || activeFlow != flow) {
-			map = Maps.newHashMap
-			treeMap = Maps.newHashMap
-			shortNamesValid = false;
-
-			activeFlow = flow;
-			activeStatechart = null;
-
-			createNameTree(flow);
-			individualMap = constructIndividualNames();
-			node_shortString_map = createShortStringMapping();
-
-			shortenNames();
-		}
-	}
-
-	def private void createNameTree(ExecutionFlow flow) {
-		// Initialize tree
-		tree = new StringTreeNode();
-
-		for (region : flow.regions) {
-			addElement(region, new ArrayList<String>(), new ArrayList<String>());
-			for (node : region.nodes) {
-				addElement(node, new ArrayList<String>(), new ArrayList<String>());
-			}
-		}
-
-		for (state : flow.states) {
-			addElement(state, state.prefix, state.suffix);
-		}
-		for (func : flow.allFunctions) {
-			addElement(func, func.prefix, func.suffix);
-		}
-
-		// Create short name for time events of statechart
-		if (flow.sourceElement instanceof Statechart) {
-			val statechart = flow.sourceElement as Statechart
-			addShortTimeEventName(flow, statechart)
-		}
-
-		// Create short name for time events of states
-		for (executionState : flow.states) {
-			if (executionState.sourceElement instanceof State) {
-				val state = executionState.sourceElement as State
-				addShortTimeEventName(executionState, state)
-			}
-		}
-	}
-
-	def public test_printTreeContents() {
-		for (s : tree.getContents()) {
-			System.out.println(s);
-		}
-
-		System.out.println();
-	}
-
-	def protected addShortTimeEventName(NamedElement executionFlowElement, NamedElement sgraphElement) {
-		var timeEventSpecs = sgraphElement.timeEventSpecs;
-		for (tes : timeEventSpecs) {
-			val timeEvent = executionFlowElement.flow.getTimeEvent(sgraphElement.fullyQualifiedName + "_time_event_" +
-				timeEventSpecs.indexOf(tes))
-			if (timeEvent != null) {
-				addElement(executionFlowElement, prefix(tes, sgraphElement), suffix(tes, sgraphElement));
-			}
-		}
-	}
-
-	def private void addElement(NamedElement elem, List<String> prefix, List<String> suffix) {
-		val name = new ArrayList<String>(elem.elementNameSegments());
-		val segments = new ArrayList<String>();
-		segments.addAll(prefix);
-		segments.addAll(name);
-		segments.addAll(suffix);
-		if (!segments.isEmpty()) {
-			val addedNode = tree.addStringList(segments);
-
-			treeMap.put(elem, addedNode); // remember for later access
-			shortNamesValid = false;
-		}
-	// System.out.println(name);
-	}
-
-	def protected asIndexPosition(ExecutionScope it) {
-		superScope.subScopes.indexOf(it).toString;
-	}
-
-	def protected dispatch asSGraphIndexPosition(Region it) {
-		composite.regions.toList.indexOf(it).toString
-	}
-
-	def protected dispatch asSGraphIndexPosition(State it) {
-		parentRegion.vertices.filter(typeof(State)).toList.indexOf(it).toString
-	}
-
-	def protected dispatch asSGraphIndexPosition(Vertex it) {
-		parentRegion.vertices.toList.indexOf(it).toString
-	}
-
-	override public setMaxLength(int length) {
-		maxLength = length
-	}
-
-	override public setSeparator(char sep) {
-		// Check if Prefix is ok		
-		var String sepString = sep + ""
-		if (!(sepString.matches(VALID_IDENTIFIER_REGEX))) {
-			throw new IllegalArgumentException
-		}
-		separator = sep
-	}
-
-	override public getMaxLength() {
-		return maxLength
-	}
-
-	override public getSeparator() {
-		return separator
-	}
-
-	override getShortName(NamedElement element) {
-		// check if element was named before
-		if (map.containsKey(element)) {
-			return map.get(element);
-		}
-		// if not, check if element is located in the tree
-		if (!treeMap.containsKey(element)) {
-			addElement(element, new ArrayList<String>(), new ArrayList<String>());
-		}
-		// check if names are shortened already
-		if (!shortNamesValid) {
-			shortenNames();
-		}
-
-		val name = getShortenedName(element);
-
-		map.put(element, name);
-		return name;
-	}
-
-	def private Map<StringTreeNode, ArrayList<StringTreeNode>> constructIndividualNames() {
-		/*
-		 * The map doublets is a three dimensional construct.
-		 * For each end-node-name in the tree, it holds a list of lists describing that name.
-		 * The outer list contains instances representing the same name, and the inner lists hold 
-		 * the current set of nodes that is needed to make the name individual.
-		 * 
-		 * Consider the following simple tree:
-		 * main_region-StateA
-		 * main_region-StateB
-		 * second_region-StateA
-		 * 
-		 * After the initial phase, the map then contains the following:
-		 * {"StateA": [[node(StateA)], [node(StateA)]], "StateB": [[node(StateB)]]}
-		 * 
-		 * The iteration consists of two phases then.
-		 * In Phase 1, all inner lists are extended with the first element's parent - as long as there is more than one list.
-		 * This leads to the following:
-		 * {"StateA": [[node(main_region), node(StateA)], [node(second_region), node(StateA)]], "StateB": [[node(StateB)]]}
-		 * in Phase 2, the map is then resorted with the new names:
-		 * {
-		 * 	"main_region_StateA": [[node(main_region), node(StateA)]],
-		 * 	"second_region_StateA": [[node(second_region), node(StateA)]],
-		 * 	"StateB": [[node(StateB)]] 
-		 * }
-		 * 
-		 * As we can see, all outer lists now have exactly length 1, which is the abortion criterion.
-		 * 
-		 * In the finalization phase, we check if there are any weird things happening like randomly created double names.
-		 * For example, someone could create a state named "region_StateA" and two other elements named "region" and "StateA" could
-		 * be clumped together to form an individual name.
-		 * 
-		 */
-		 
-		// get all end-nodes, that is "ends of strings" added to the tree.
-		val nodes = tree.getEndNodes().sortWith(stringTreeNodeDepthComparator);
-		var doublets = new HashMap<String, ArrayList<ArrayList<StringTreeNode>>>();
-		val mapping = new HashMap<StringTreeNode, ArrayList<StringTreeNode>>();
-
-		// Initialization
-		for (node : nodes) {
-			if (!doublets.containsKey(node.data)) {
-				doublets.put(node.data, new ArrayList<ArrayList<StringTreeNode>>());
-			}
-			val list = new ArrayList<StringTreeNode>();
-			// add new inner list that will hold the nodes going to the end node forming the individual name
-			doublets.get(node.data).add(list);
-			// map this list to the end node. We'll return this map later, but we need to fill the lists first
-			mapping.put(node, list);
-			list.add(node);
-		}
-
-		var abort = false;
-		// Iteration
-		while (!abort) {
-			// Phase 1
-			for (name : doublets.keySet) {
-				// check outer list. If it contains more than one list, there is more than one element with the same name.
-				if (doublets.get(name).length > 1) {
-					// if that is the case, add one parent node to all inner node lists.
-					for (nodelist : doublets.get(name)) {
-						nodelist.add(0, nodelist.get(0).parent);
-					}
-				}
-			}
-
-			// Phase 2
-			val newDoublets = new HashMap<String, ArrayList<ArrayList<StringTreeNode>>>();
-
-			for (name : doublets.keySet) // for all keys
-			{
-				for (nodelist : doublets.get(name)) // for inner lists in outer lists - returned by doublets.get(name)
-				{
-					// construct names formed by inner lists, now possibly extended by one node
-					val sb = new StringBuilder();
-
-					for (var i = 0; i < nodelist.length; i++) {
-						if (i != 0) {
-							sb.append(separator)
-						}
-						sb.append(nodelist.get(i).getData())
-					}
-					// add string to new map if it doesn't exist already
-					if (!newDoublets.containsKey(sb.toString)) {
-						newDoublets.put(sb.toString, new ArrayList<ArrayList<StringTreeNode>>());
-					}
-
-					newDoublets.get(sb.toString).add(nodelist);
-				}
-			}
-
-			doublets = newDoublets;
-
-			// Abort criterion. If there is any name with more than one element, repeat.
-			abort = true;
-			for (name : doublets.keySet) {
-				if(doublets.get(name).length > 1) abort = false;
-			}
-		}
-
-		return mapping;
-	}
-
-	def private shortenNames() {
-		if (individualMap == null || individualMap.isEmpty()) {
-			constructIndividualNames();
-		}
-		if (this.maxLength == 0) {
-			return;
-		}
-		
-		val max_weight = tree.getWeight();
-
-		while (shortenOneCharacter(tree.getEndNodes(), max_weight)) {
-		}
-
-		shortNamesValid = true;
-	}
-
-	def private boolean shortenOneCharacter(ArrayList<StringTreeNode> endnodes, int max_weight) {
-		/*
-		 * takes all end-nodes of the tree, finds their attached individual chain of nodes, their shortstring and shortens the
-		 * longest chain's cheapest shortstring.
-		 */
-		var max_length = 0;
-		var StringTreeNode max_length_node;
-
-		var names = new ArrayList<String>();
-
-		for (node : endnodes) {
-			// iterates over all endnodes and returns the maximum length of all names.
-			var newname = node.getIndividualName.joinShortStrings();
-			names.add(newname);
-			var length = newname.length();
-			if (length > max_length) {
-				max_length = length;
-				max_length_node = node;
-			}
-		}
-
-		if (max_length < this.maxLength) {
-			return false;
-		}
-
-		var min_cost = Integer.MAX_VALUE;
-		var ShortString best_cut;
-
-		for (node : max_length_node.getIndividualName) // all nodes describing the individual name of this end node
-		{
-			val shortstr = node.shortStringForNode;
-			val current_cost = shortstr.getCutCost();
-
-			var noDoubles = false;
-
-			val node_cost_factor = max_weight - node.getWeight() + 1;
-
-			shortstr.removeCheapestChar();
-
-			val cut_cost = (shortstr.getCutCost() - current_cost) * node_cost_factor;
-
-			val current_name = max_length_node.getIndividualName.joinShortStrings;
-
-			if (!names.contains(current_name)) {
-				noDoubles = true;
-				// do further check to avoid double names only when quick check is okay
-				var doubleCheckArray = new ArrayList<String>();
-				for (n : endnodes) {
-					var newname = n.getIndividualName.joinShortStrings();
-					if (doubleCheckArray.contains(newname)) {
-						noDoubles = false;
-					}
-					doubleCheckArray.add(newname);
-				}
-			}
-
-			if (noDoubles && cut_cost > 0 && cut_cost < min_cost) {
-				min_cost = cut_cost;
-				best_cut = shortstr;
-			}
-
-			shortstr.rollback(); // revert changes
-		}
-
-		if (best_cut == null) {
-			return false;
-		}
-		best_cut.removeCheapestChar(); // reapply best change
-		return true;
-	}
-
-	def private Map<StringTreeNode, ShortString> createShortStringMapping() {
-		val HashMap<StringTreeNode, ShortString> mapping = newHashMap;
-		for (node : tree.getNodes()) {
-			mapping.put(
-				node,
-				new ShortString(node.getData())
-			);
-		}
-
-		return mapping;
-	}
-
-	def private StringTreeNode getNodeForElement(NamedElement elem) {
-		return treeMap.get(elem);
-	}
-
-	def private ShortString getShortStringForNode(StringTreeNode node) {
-		if (node_shortString_map == null || node_shortString_map.isEmpty()) {
-			createShortStringMapping();
-		}
-		return node_shortString_map.get(node);
-	}
-
-	def private ArrayList<StringTreeNode> getIndividualName(StringTreeNode node) {
-		if (individualMap.isEmpty()) {
-			constructIndividualNames();
-		}
-		return individualMap.get(node);
-	}
-
-	def private getShortenedName(StringTreeNode node) {
-		return joinShortStrings(getIndividualName(node));
-	}
-
-	def private getShortenedName(NamedElement elem) {
-		return getShortenedName(getNodeForElement(elem));
-	}
-
-	override asEscapedIdentifier(String string) {
-		asIdentifier(string);
-	}
-
-	override asIdentifier(String string) {
-		string.replaceAll('[^a-z&&[^A-Z&&[^0-9]]]', separator.toString)
-	}
-
-	override isKeyword(String string) {
-		return false;
-	}
-
-	override getShortNameMap(Statechart statechart) {
-		throw new UnsupportedOperationException("TODO: auto-generated method stub")
-	}
-
-	override getShortNameMap(ExecutionFlow flow) {
-		throw new UnsupportedOperationException("TODO: auto-generated method stub")
-	}
-
-	def public getTreeContents() {
-		return tree.getContents();
-	}
-
-	def private List<NamedElement> getNodeElements(StringTreeNode node) {
-		val ArrayList<NamedElement> list = new ArrayList<NamedElement>();
-
-		for (elem : treeMap.keySet()) {
-			if (treeMap.get(elem) == node) {
-				list.add(elem);
-			}
-		}
-
-		return list;
-	}
-
-	def private String joinShortStrings(ArrayList list) {
-		val sb = new StringBuilder();
-		var first = true;
-
-		for (s : list) {
-			var String shortened;
-			if (s instanceof ShortString) {
-				shortened = s.getShortenedString();
-			} else if (s instanceof StringTreeNode) {
-				shortened = s.getShortStringForNode.getShortenedString();
-			}
-			if (shortened.length > 0) {
-				if (first) {
-					sb.append(shortened);
-					first = false;
-				} else {
-					sb.append(separator);
-					sb.append(shortened);
-				}
-			}
-		}
-
-		return sb.toString();
-	}
-
-	def protected suffix(Step it) {
-		var l = new ArrayList<String>();
-
-		switch (it) {
-			case isCheckFunction: {
-				l.add("check");
-			}
-			case isEntryAction: {
-				l.add("enact");
-			}
-			case isExitAction: {
-				l.add("exact");
-			}
-			case isEffect: {
-				l.add("effect");
-			}
-			case isEnterSequence: {
-				l.add("enseq");
-			}
-			case isDeepEnterSequence: {
-				l.add("dhenseq");
-			}
-			case isShallowEnterSequence: {
-				l.add("shenseq");
-			}
-			case isExitSequence: {
-				l.add("exseq");
-			}
-			case isReactSequence: {
-				l.add("react");
-			}
-			default: {
-			}
-		}
-
-		return l;
-	}
-
-	def protected prefix(Step it) {
-		return new ArrayList<String>();
-	}
-
-	def protected prefix(ExecutionState it) {
-		var l = new ArrayList<String>();
-		// l.add(flow.name);
-		return l;
-	}
-
-	def protected suffix(ExecutionState it) {
-		return new ArrayList<String>();
-	}
-
-	def protected prefix(TimeEventSpec it, NamedElement element) {
-		var l = new ArrayList<String>();
-		// l.add(activeFlow.name);
-		return l;
-	}
-
-	def protected suffix(TimeEventSpec it, NamedElement element) {
-		var l = new ArrayList<String>();
-		switch (element) {
-			Statechart: {
-				l.add("tev" + element.timeEventSpecs.indexOf(it));
-			}
-			State: {
-				l.add("tev" + element.timeEventSpecs.indexOf(it));
-			}
-		}
-		return l;
-	}
-
-	def protected prefix(State it) {
-		var l = new ArrayList<String>();
-		// l.add(activeStatechart.name);
-		return l;
-	}
-
-	def protected prefix(Vertex it) {
-		return new ArrayList<String>();
-	}
-
-	def protected suffix(Vertex it) {
-		return new ArrayList<String>();
-	}
-}

+ 30 - 18
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/ShortString.xtend

@@ -9,18 +9,21 @@
  * 		@author René Beckmann (beckmann@itemis.de)
  * 		@author René Beckmann (beckmann@itemis.de)
  */
  */
 
 
-package org.yakindu.sct.model.sexec.naming
+package org.yakindu.sct.model.sexec.naming.tree
 
 
-import java.lang.String
+import org.eclipse.xtend.lib.annotations.Accessors
 
 
 class ShortString {
 class ShortString {
 	/*
 	/*
 	 * Class that manages a string and shortened versions of it.
 	 * Class that manages a string and shortened versions of it.
 	 */
 	 */
-	private String originalString;
+	protected String originalString;
+	
+	/** Custom factor for the cut cost */
+	@Accessors int costFactor = 1; 
 
 
-	private int[] cutArray; // holds information if char is cut or not
-	private int[] previous_cutArray; // holds previous state for rollback / undo possibility
+	protected int[] cutArray; // holds information if char is cut or not
+	protected int[] previous_cutArray; // holds previous state for rollback / undo possibility
 	// cost of cutting operations
 	// cost of cutting operations
 	final static public int COST_LOWERCASE_VOCALS = 1;
 	final static public int COST_LOWERCASE_VOCALS = 1;
 	final static public int COST_UNDERSCORE = 1;
 	final static public int COST_UNDERSCORE = 1;
@@ -30,7 +33,11 @@ class ShortString {
 	final static public int COST_FIRSTLETTER = 10;
 	final static public int COST_FIRSTLETTER = 10;
 
 
 	new(String s) {
 	new(String s) {
-		if (s == null) {
+		this(s, 1)
+	}
+	
+	new(String s, int factor) {
+		if (s === null) {
 			originalString = "";
 			originalString = "";
 		} else {
 		} else {
 			originalString = s;
 			originalString = s;
@@ -39,13 +46,14 @@ class ShortString {
 		previous_cutArray = newIntArrayOfSize(size);
 		previous_cutArray = newIntArrayOfSize(size);
 		reset();
 		reset();
 		saveCurrentToPrevious();
 		saveCurrentToPrevious();
+		costFactor = factor
 	}
 	}
 
 
 	def public getOriginalString() {
 	def public getOriginalString() {
 		originalString
 		originalString
 	}
 	}
 
 
-	def private int size() {
+	def protected int size() {
 		// instead of saving originalString.length as an own member
 		// instead of saving originalString.length as an own member
 		originalString.length
 		originalString.length
 	}
 	}
@@ -58,7 +66,7 @@ class ShortString {
 		}
 		}
 	}
 	}
 
 
-	def private saveCurrentToPrevious() {
+	def protected saveCurrentToPrevious() {
 		// save current cut-state to previous_cutArray.
 		// save current cut-state to previous_cutArray.
 		for (var i = 0; i < size; i++) {
 		for (var i = 0; i < size; i++) {
 			previous_cutArray.set(i, cutArray.get(i));
 			previous_cutArray.set(i, cutArray.get(i));
@@ -71,6 +79,10 @@ class ShortString {
 			cutArray.set(i, previous_cutArray.get(i));
 			cutArray.set(i, previous_cutArray.get(i));
 		}
 		}
 	}
 	}
+	
+	override toString() {
+		shortenedString
+	}
 
 
 	def public String getShortenedString() {
 	def public String getShortenedString() {
 		// return the current version of the shortened string according to cutArray
 		// return the current version of the shortened string according to cutArray
@@ -96,7 +108,7 @@ class ShortString {
 		return length;
 		return length;
 	}
 	}
 
 
-	def public int getCutCostFactor() {
+	def public int getCutRatioFactor() {
 		// factor that takes into account how much of the string is already cut, so that cutting away more characters get's more expensive
 		// factor that takes into account how much of the string is already cut, so that cutting away more characters get's more expensive
 		return 10 + (getCutRatio() * 10) as int;
 		return 10 + (getCutRatio() * 10) as int;
 	}
 	}
@@ -114,7 +126,7 @@ class ShortString {
 			}
 			}
 		}
 		}
 
 
-		return cost * getCutCostFactor;
+		return cost * getCutRatioFactor * costFactor;
 	}
 	}
 
 
 	def public int getBaseCutCost(int index) {
 	def public int getBaseCutCost(int index) {
@@ -124,18 +136,18 @@ class ShortString {
 		var c = originalString.charAt(index);
 		var c = originalString.charAt(index);
 
 
 		if (index == 0) {
 		if (index == 0) {
-			cost += org.yakindu.sct.model.sexec.naming.ShortString.COST_FIRSTLETTER;
+			cost += ShortString.COST_FIRSTLETTER;
 		}
 		}
 		if (Character.isDigit(c)) {
 		if (Character.isDigit(c)) {
-			cost += org.yakindu.sct.model.sexec.naming.ShortString.COST_DIGIT;
+			cost += ShortString.COST_DIGIT;
 		} else if (Character.isUpperCase(c)) {
 		} else if (Character.isUpperCase(c)) {
-			cost += org.yakindu.sct.model.sexec.naming.ShortString.COST_UPPERCASE;
+			cost += ShortString.COST_UPPERCASE;
 		} else if (isLowercaseVocal(c)) {
 		} else if (isLowercaseVocal(c)) {
-			cost += org.yakindu.sct.model.sexec.naming.ShortString.COST_LOWERCASE_VOCALS;
+			cost += ShortString.COST_LOWERCASE_VOCALS;
 		} else if (c.toString().equals("_")) {
 		} else if (c.toString().equals("_")) {
-			cost += org.yakindu.sct.model.sexec.naming.ShortString.COST_UNDERSCORE;
+			cost += ShortString.COST_UNDERSCORE;
 		} else {
 		} else {
-			cost += org.yakindu.sct.model.sexec.naming.ShortString.COST_LOWERCASE_CONSONANTS;
+			cost += ShortString.COST_LOWERCASE_CONSONANTS;
 		}
 		}
 
 
 		return cost;
 		return cost;
@@ -171,12 +183,12 @@ class ShortString {
 		}
 		}
 	}
 	}
 
 
-	def private boolean isLowercaseVocal(int i) {
+	def protected boolean isLowercaseVocal(int i) {
 		var c = originalString.charAt(i);
 		var c = originalString.charAt(i);
 		return isLowercaseVocal(c);
 		return isLowercaseVocal(c);
 	}
 	}
 
 
-	def private boolean isLowercaseVocal(char c) {
+	def protected boolean isLowercaseVocal(char c) {
 		val s = c.toString();
 		val s = c.toString();
 		return (s == "a" || s == "e" || s == "i" || s == "o" || s == "u");
 		return (s == "a" || s == "e" || s == "i" || s == "o" || s == "u");
 	}
 	}

+ 48 - 0
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/tree/ShortStringUtils.xtend

@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2018 committers of YAKINDU 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:
+ * 	rbeckmann - initial API and implementation
+ * 
+ */
+package org.yakindu.sct.model.sexec.naming.tree
+
+import java.util.List
+import java.util.Map
+
+/**
+ * @author rbeckmann
+ *
+ */
+class ShortStringUtils {
+	def public List<ShortString> getLongestElement(List<List<ShortString>> names) {
+		names.sortBy[getLength].last
+	}
+	
+	def public getLength(List<ShortString> list) {
+		list.map[shortenedSize].reduce[a, b | a + b]
+	}
+	
+	def public int getMaxLength(List<List<ShortString>> names) {
+		return names.map[getLength].max
+	}
+	
+	def public String join(List<ShortString> name) {
+		val sb = new StringBuilder
+		
+		name.forEach[sb.append(toString)]
+		
+		sb.toString
+	}
+	
+	def public ShortString toShortString(StringTreeNode node, Map<StringTreeNode, ShortString> map) {
+		if(!map.containsKey(node)) {
+			map.put(node, new ShortString(node.data, node.getRoot.weight - node.weight + 1))
+		}
+		map.get(node)
+		
+	}
+}

+ 206 - 0
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/tree/StringTreeNode.xtend

@@ -0,0 +1,206 @@
+/**
+ *   Copyright (c) 2016 committers of YAKINDU Statechart Tools.
+ *   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:
+ * 		@author René Beckmann (beckmann@itemis.de)
+ */
+
+package org.yakindu.sct.model.sexec.naming.tree
+
+import java.util.ArrayList
+import java.util.Comparator
+import java.util.List
+import org.eclipse.xtend.lib.annotations.Accessors
+
+/**
+ * @author rbeckmann
+ */
+class StringTreeNodeDepthComparator implements Comparator<StringTreeNode> {
+	override compare(StringTreeNode o1, StringTreeNode o2) {
+		return o1.getDepth() - o2.getDepth();
+	}
+	
+	def protected int getDepth(StringTreeNode node) {
+		if (node.isRoot) {
+			return 0;
+		} else {
+			return getDepth(node.parent) + 1;
+		}
+	}
+}
+
+/**
+ * @author rbeckmann
+ * 
+ * Implements a data tree for strings, used in the TreeNamingService.
+ */
+class StringTreeNode {
+
+	@Accessors(PUBLIC_GETTER) protected String data;
+	@Accessors(PUBLIC_GETTER) protected ArrayList<StringTreeNode> children;
+	@Accessors(PUBLIC_GETTER) protected StringTreeNode parent;
+
+	new(String data) {
+		this.data = data;
+		this.parent = null;
+		this.children = new ArrayList();
+	}
+
+	new() {
+		this.data = null;
+		this.parent = null;
+		this.children = new ArrayList();
+	}
+
+	def protected void addChild(StringTreeNode node) {
+		node.parent = this;
+		children.add(node);
+	}
+	
+	def protected List<String> getContents() {
+		/*
+		 * Returns a list of all strings contained in the tree
+		 */
+		val List<String> contents = newArrayList
+		val List<StringTreeNode> endNodes = getEndNodes
+
+		for (StringTreeNode end : endNodes) {
+			contents.add(end.contentUpwards);
+		}
+
+		return contents;
+	}
+	
+	def protected String getContentUpwards() {
+		/*
+		 * Traverse tree upwards and return the string ended by this node up to root
+		 */
+		var s = "";
+
+		if (!isRoot()) {
+			s = parent.getContentUpwards() + getData();
+		}
+
+		return s;
+	}
+
+	def public StringTreeNode addStringList(List<String> sList) {
+		/*
+		 * Adds an array of strings.
+		 * If the first element is found within own children's data,
+		 * cut the first element and call that child with this function recursively.
+		 * Else, create new child with that element, and proceed the same.
+		 */
+		if (sList.size() == 0) {
+			for (child : children) {
+				if (child.isEnd()) {
+					return child; // only add one end per node - don't allow double strings
+				}
+			}
+			val newNode = new StringTreeNode("");
+			addChild(newNode); // mark End
+			return newNode;
+		}
+
+		var firstString = sList.get(0) ?: ""; // first element to search in own children. If not found, create new one.
+		var rest = sList.subList(1, sList.size()); // the rest of the array that the child's addStringList function is called with
+
+		for (child : children) // search for child that fits
+		{
+			if (child.getData().equals(firstString)) {
+				return child.addStringList(rest);
+			}
+		}
+		var newNode = new StringTreeNode(firstString);
+		addChild(newNode);
+		return newNode.addStringList(rest);
+	}
+
+	/*
+	 * Tree reading functions
+	 */
+	/** The weight is the number of children, plus their weight recursively.
+	 * 	The tree's root has the maximum weight, while a leaf node's weight is zero.
+	 */
+	def public int getWeight() {
+		var weight = children.size()
+
+		for (c : children) {
+			weight += c.getWeight()
+		}
+
+		return weight;
+	}
+
+	def public List<StringTreeNode> getEndNodes() {
+		/*
+		 * returns a list of nodes that are string ending nodes (node.isEnd() == true)
+		 */
+		var endNodes = new ArrayList<StringTreeNode>();
+
+		for (child : children) {
+			if (child.isEnd()) {
+				endNodes.add(child);
+			}
+			endNodes.addAll(child.getEndNodes());
+		}
+		return endNodes;
+	}
+
+	def public StringTreeNode getRoot() {
+		if(isRoot) {
+			this
+		} else {
+			parent.getRoot()
+		}
+	}
+
+	def public void compress() {
+		/*
+		 * Compresses branches.
+		 * All nodes 'X' that have only one child 'A' append 'A's data to their own, delete  'A' and
+		 * make 'A's children their ('X's) own.
+		 * Only exception: endNodes, according to node.isEnd() == true, are not consumed.
+		 * 
+		 * Example:
+		 * A, B, C... denote states, - denotes an edge, # denotes an end node, O the root node
+		 * 
+		 * O-A-B-C-D-E-#
+		 *        \
+		 *         F-G-#
+		 * 
+		 * becomes
+		 * 
+		 * O-ABC-DE-#
+		 *      \
+		 *       FG-#
+		 */
+		if (!isRoot()) {
+			while (this.children.size() == 1 && !children.get(0).isEnd()) {
+				var myChild = children.head;
+				this.data += myChild.getData();
+				for (child : myChild.getChildren()) {
+					this.addChild(child);
+				}
+				this.children.removeAll(myChild);
+			}
+		}
+
+		for (child : this.children) {
+			child.compress();
+		}
+
+	}
+
+	def public boolean isRoot() {
+		this.parent === null;
+	}
+
+	def public boolean isEnd() {
+		this.children.size() == 0 && this.data.equals("")
+	}
+}

+ 365 - 0
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/tree/TreeNamingService.xtend

@@ -0,0 +1,365 @@
+/**
+ *   Copyright (c) 2016 committers of YAKINDU Statechart Tools.
+ *   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:
+ * 		@author René Beckmann (beckmann@itemis.de)
+ */
+
+package org.yakindu.sct.model.sexec.naming.tree
+
+import java.util.ArrayList
+import java.util.List
+import java.util.Map
+import javax.inject.Inject
+import org.eclipse.xtend.lib.annotations.Accessors
+import org.eclipse.xtext.naming.IQualifiedNameProvider
+import org.yakindu.base.base.NamedElement
+import org.yakindu.sct.model.sexec.ExecutionFlow
+import org.yakindu.sct.model.sexec.ExecutionScope
+import org.yakindu.sct.model.sexec.ExecutionState
+import org.yakindu.sct.model.sexec.Step
+import org.yakindu.sct.model.sexec.extensions.SExecExtensions
+import org.yakindu.sct.model.sexec.naming.ElementNameProvider
+import org.yakindu.sct.model.sexec.naming.INamingService
+import org.yakindu.sct.model.sexec.naming.IStringShortener
+import org.yakindu.sct.model.sexec.transformation.StatechartExtensions
+import org.yakindu.sct.model.sgraph.CompositeElement
+import org.yakindu.sct.model.sgraph.Region
+import org.yakindu.sct.model.sgraph.State
+import org.yakindu.sct.model.sgraph.Statechart
+import org.yakindu.sct.model.sgraph.Vertex
+import org.yakindu.sct.model.stext.stext.TimeEventSpec
+
+/** New implementation of the naming service for various identifiers used in the generated code. 
+ * It is responsible for identifier construction depending on the thing to be named including different strategies 
+ * which also include name shortening.
+ */
+class TreeNamingService implements INamingService {
+	@Accessors protected int maxLength = 0;
+	@Accessors protected char separator = '_';
+
+	@Inject extension SExecExtensions
+	@Inject extension StatechartExtensions
+	@Inject extension IQualifiedNameProvider
+
+	@Inject extension ElementNameProvider
+
+	@Inject protected StringTreeNodeDepthComparator stringTreeNodeDepthComparator
+	
+	@Inject protected IStringShortener shortener
+
+	// from public class org.yakindu.sct.generator.c.features.CDefaultFeatureValueProvider extends		
+	protected static final String VALID_IDENTIFIER_REGEX = "[_a-zA-Z][_a-zA-Z0-9]*";
+
+
+
+	/*
+	 * Holds the name of each element whose name was requested.
+	 */
+	protected Map<NamedElement, String> map
+	
+	// if the naming service is initialized with a flow, activeStatechart is null, and vice versa.
+	protected ExecutionFlow activeFlow;
+	protected Statechart activeStatechart;
+
+	new(int maxLength, char separator) {
+		this.maxLength = maxLength
+		this.separator = separator
+	}
+
+	new() {
+		this.maxLength = 0
+		this.separator = '_'
+	}
+	
+	def protected void reset() {
+		map = newHashMap
+		activeFlow = null
+		activeStatechart = null
+		
+		shortener.reset()
+	}
+
+	override initializeNamingService(Statechart statechart) {
+		if (activeStatechart != statechart) {
+			reset()
+			activeStatechart = statechart;
+			
+			collectNames(statechart)
+		}
+	}
+
+	def protected void collectNames(CompositeElement element) {
+		for (region : element.regions) {
+			addElement(region, new ArrayList<String>(), new ArrayList<String>());
+			for (vertex : region.vertices) {
+				switch vertex {
+					State:
+						addElement(vertex, new ArrayList<String>(), new ArrayList<String>())
+					default:
+						addElement(vertex, new ArrayList<String>(), new ArrayList<String>())
+				}
+			}
+		}
+		for (region : element.regions) {
+			for (vertex : region.vertices) {
+				if (vertex instanceof CompositeElement) {
+					collectNames(vertex as CompositeElement)
+				}
+			}
+		}
+	}
+
+	override initializeNamingService(ExecutionFlow flow) {
+		if (activeFlow != flow) {
+			reset()
+			activeFlow = flow;
+
+			collectNames(flow);
+		}
+	}
+
+	def protected void collectNames(ExecutionFlow flow) {
+
+		for (region : flow.regions) {
+			addElement(region, new ArrayList<String>(), new ArrayList<String>());
+			for (node : region.nodes) {
+				addElement(node, new ArrayList<String>(), new ArrayList<String>());
+			}
+		}
+
+		for (state : flow.states) {
+			addElement(state, state.prefix, state.suffix);
+		}
+		for (func : flow.allFunctions) {
+			addElement(func, func.prefix, func.suffix);
+		}
+
+		// Create short name for time events of statechart
+		if (flow.sourceElement instanceof Statechart) {
+			val statechart = flow.sourceElement as Statechart
+			addShortTimeEventName(flow, statechart)
+		}
+
+		// Create short name for time events of states
+		for (executionState : flow.states) {
+			if (executionState.sourceElement instanceof State) {
+				val state = executionState.sourceElement as State
+				addShortTimeEventName(executionState, state)
+			}
+		}
+	}
+
+	def protected addShortTimeEventName(NamedElement executionFlowElement, NamedElement sgraphElement) {
+		var timeEventSpecs = sgraphElement.timeEventSpecs;
+		for (tes : timeEventSpecs) {
+			val timeEvent = executionFlowElement.flow.getTimeEvent(sgraphElement.fullyQualifiedName + "_time_event_" +
+				timeEventSpecs.indexOf(tes))
+			if (timeEvent !== null) {
+				addElement(executionFlowElement, prefix(tes, sgraphElement), suffix(tes, sgraphElement), timeEvent);
+			}
+		}
+	}
+
+	def protected void addElement(NamedElement elem, List<String> prefix, List<String> suffix) {
+		addElement(elem, prefix, suffix, elem)
+	}
+	
+	def protected void addElement(NamedElement elem, List<String> prefix, List<String> suffix, Object token) {
+		val name = new ArrayList<String>(elem.elementNameSegments());
+		val segments = new ArrayList<String>();
+		segments.addAll(prefix);
+		segments.addAll(name);
+		segments.addAll(suffix);
+		shortener.addString(addSeparator(segments), token)
+	}
+
+	def protected asIndexPosition(ExecutionScope it) {
+		superScope.subScopes.indexOf(it).toString;
+	}
+
+	def protected dispatch asSGraphIndexPosition(Region it) {
+		composite.regions.toList.indexOf(it).toString
+	}
+
+	def protected dispatch asSGraphIndexPosition(State it) {
+		parentRegion.vertices.filter(typeof(State)).toList.indexOf(it).toString
+	}
+
+	def protected dispatch asSGraphIndexPosition(Vertex it) {
+		parentRegion.vertices.toList.indexOf(it).toString
+	}
+
+	override public setMaxLength(int length) {
+		maxLength = length
+		shortener.maxLength = length
+	}
+
+	override public setSeparator(char sep) {
+		// Check if Prefix is ok		
+		var String sepString = sep + ""
+		if (!(sepString.matches(VALID_IDENTIFIER_REGEX))) {
+			throw new IllegalArgumentException
+		}
+		separator = sep
+	}
+
+	override getShortName(NamedElement element) {
+		// check if element was named before
+		if (map.containsKey(element)) {
+			return map.get(element);
+		}
+
+		var name = shortener.getString(element)
+		
+		if (name === null) {
+			addElement(element, new ArrayList<String>(), new ArrayList<String>());
+			name = shortener.getString(element)
+		}
+
+		map.put(element, name);
+		return name;
+	}
+
+	override asEscapedIdentifier(String string) {
+		asIdentifier(string);
+	}
+
+	override asIdentifier(String string) {
+		string.replaceAll('[^a-z&&[^A-Z&&[^0-9]]]', separator.toString)
+	}
+
+	override isKeyword(String string) {
+		return false;
+	}
+
+	override getShortNameMap(Statechart statechart) {
+		initializeNamingService(statechart)
+		return map
+	}
+
+	override getShortNameMap(ExecutionFlow flow) {
+		initializeNamingService(flow)
+		return map
+	}
+
+	def protected List<String> suffix(Step it) {
+		var l = new ArrayList<String>();
+
+		switch (it) {
+			case isCheckFunction: {
+				l.add("check");
+			}
+			case isEntryAction: {
+				l.add("enact");
+			}
+			case isExitAction: {
+				l.add("exact");
+			}
+			case isEffect: {
+				l.add("effect");
+			}
+			case isEnterSequence: {
+				l.add("enseq");
+			}
+			case isDeepEnterSequence: {
+				l.add("dhenseq");
+			}
+			case isShallowEnterSequence: {
+				l.add("shenseq");
+			}
+			case isExitSequence: {
+				l.add("exseq");
+			}
+			case isReactSequence: {
+				l.add("react");
+			}
+			default: {
+			}
+		}
+
+		return l;
+	}
+
+	def protected List<String> prefix(Step it) {
+		return new ArrayList<String>();
+	}
+
+	def protected List<String> prefix(ExecutionState it) {
+		var l = new ArrayList<String>();
+		// l.add(flow.name);
+		return l;
+	}
+
+	def protected List<String> suffix(ExecutionState it) {
+		return new ArrayList<String>();
+	}
+
+	def protected List<String> prefix(TimeEventSpec it, NamedElement element) {
+		var l = new ArrayList<String>();
+		// l.add(activeFlow.name);
+		return l;
+	}
+
+	def protected List<String> suffix(TimeEventSpec it, NamedElement element) {
+		var l = new ArrayList<String>();
+		switch (element) {
+			Statechart: {
+				l.add("tev" + element.timeEventSpecs.indexOf(it));
+			}
+			State: {
+				l.add("tev" + element.timeEventSpecs.indexOf(it));
+			}
+		}
+		return l;
+	}
+
+	def protected List<String> prefix(State it) {
+		var l = new ArrayList<String>();
+		// l.add(activeStatechart.name);
+		return l;
+	}
+
+	def protected List<String> prefix(Vertex it) {
+		return new ArrayList<String>();
+	}
+
+	def protected List<String> suffix(Vertex it) {
+		return new ArrayList<String>();
+	}
+	
+	def protected List<String> addSeparator(List<String> segments) {
+		val List<String> result = newArrayList
+		for(var i = 0; i < segments.size(); i++) {
+			result.add(segments.get(i)) {
+				if(i < segments.size() - 1) {
+					result.add(separator.toString)
+				}
+			}
+			
+		}
+		result
+	}
+	
+	def protected List<String> toFirstUpper(List<String> segments) {
+		val result = newArrayList
+		if(segments.nullOrEmpty) {
+			return result
+		}
+		else {
+			for(var i = 0; i < segments.size(); i++) {
+				if(i == 0) {
+					result.add(segments.get(i).toFirstUpper)
+				} else {
+					result.add(segments.get(i))
+				}
+			}
+		}
+		
+		return result
+	}
+}

+ 43 - 0
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/tree/TreeServiceNamesValidator.xtend

@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2018 committers of YAKINDU 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:
+ * 	rbeckmann - initial API and implementation
+ * 
+ */
+package org.yakindu.sct.model.sexec.naming.tree
+
+import com.google.inject.Inject
+import java.util.List
+import java.util.Set
+import org.eclipse.xtend.lib.annotations.Accessors
+
+/**
+ * @author rbeckmann
+ *
+ */
+class TreeServiceNamesValidator {
+	@Accessors protected List<List<ShortString>> names
+	
+	@Inject protected extension ShortStringUtils
+	
+	def public boolean validate() {
+		val Set<String> set = newHashSet
+		
+		if(names === null) {
+			return false
+		} else {
+			for(name : names) {
+				val s = name.join
+				
+				if(!set.add(s)) {
+					return false
+				}
+			}
+			return true
+		}
+	}
+}

+ 190 - 0
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/naming/tree/TreeStringShortener.xtend

@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) 2018 committers of YAKINDU 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:
+ * 	rbeckmann - initial API and implementation
+ * 
+ */
+package org.yakindu.sct.model.sexec.naming.tree
+
+import com.google.inject.Inject
+import java.util.List
+import java.util.Map
+import org.eclipse.xtend.lib.annotations.Accessors
+import org.yakindu.sct.model.sexec.naming.IStringShortener
+
+/**
+ * @author rbeckmann
+ *
+ */
+class TreeStringShortener implements IStringShortener {
+	@Accessors(PUBLIC_SETTER) protected int maxLength = 0
+	
+	@Inject protected extension ShortStringUtils
+	@Inject protected TreeServiceNamesValidator validator
+	
+	protected StringTreeNode tree
+	
+	protected boolean validState = false
+	
+	protected Map<Object, String> result
+	protected Map<Object, StringTreeNode> storage
+	protected Map<Object, List<String>> originalStrings = newHashMap
+	
+	override reset() {
+		originalStrings = newHashMap
+		validState = false
+	}
+
+	override addString(List<String> s, Object token) {
+		validState = false
+		originalStrings.put(token, s)
+	}
+	
+	override getString(Object token) {
+		if(!originalStrings.containsKey(token)) {
+			return null
+		}
+		
+		assertValidState()
+		
+		return result.get(token)
+	}
+	
+	def protected void assertValidState() {
+		if(!validState) {
+			result = newHashMap
+			storage = newHashMap
+			if(maxLength == 0) {
+				originalStrings.keySet.forEach[token |
+					result.put(token, originalStrings.get(token).join)
+				]
+			} else {
+				buildTree()
+				shortenNames()
+			}
+			validState = true
+		}
+	}
+	
+	def protected buildTree() {
+		tree = new StringTreeNode
+		storage = newHashMap
+		
+		originalStrings.keySet.forEach [ token |
+			storage.put(token, tree.addStringList(originalStrings.get(token)))
+		]
+		
+		tree.compress()
+	}
+	
+	def protected shortenNames() {
+		val List<List<StringTreeNode>> nodes = newArrayList
+		val Map<StringTreeNode, List<StringTreeNode>> map = newHashMap
+		val Map<StringTreeNode, List<ShortString>> endNodeShortStrings = newHashMap
+		val Map<StringTreeNode, ShortString> shortStrings = newHashMap
+		
+		for(node : tree.endNodes) {
+			val List<StringTreeNode> list = newArrayList
+			list.add(node)
+			nodes.add(list)
+			map.put(node, list)
+			endNodeShortStrings.put(node, newArrayList)
+		}
+		
+		buildIndividualNames(nodes)
+		
+		
+		map.keySet.forEach[node |
+			endNodeShortStrings.get(node).addAll(map.get(node).map[toShortString(shortStrings)])
+		]
+		
+		val List<List<ShortString>> shortStringLists = newArrayList(endNodeShortStrings.values)
+		calculateShortNames(shortStringLists)
+		
+		storage.keySet.forEach[token |
+			result.put(
+				token,
+				endNodeShortStrings.get(storage.get(token)).join
+			)
+		]
+		
+	}
+	
+	def calculateShortNames(List<List<ShortString>> names) {
+		validator.names = names
+		var longest = names.longestElement
+		while(longest.getLength > maxLength && cutOneCharacter(longest)) {
+			longest = names.longestElement
+		}
+	}
+	
+	def boolean cutOneCharacter(List<ShortString> strings) {
+		var ShortString toCut
+		var int cheapestCut = Integer.MAX_VALUE
+		
+		for(part : strings) {
+			val oldCost = part.cutCost
+			
+			part.removeCheapestChar()
+		
+			val costDifference = part.cutCost - oldCost
+			if(validator.validate() && costDifference > 0 && costDifference < cheapestCut) {
+				toCut = part
+				cheapestCut = costDifference
+			}
+			part.rollback
+		}
+		toCut?.removeCheapestChar
+		
+		return toCut !== null
+	}
+	
+	/** Expand lists until all names are unambiguous. */
+	def protected void buildIndividualNames(List<List<StringTreeNode>> nodes) {
+		val Map<String, List<List<StringTreeNode>>> map = newHashMap
+		
+		for(list : nodes) {
+			val name = toString(list)
+			
+			if(!map.containsKey(name)) {
+				map.put(name, newArrayList)
+			}
+			
+			map.get(name).add(list)
+		}
+		
+		var abort = true
+		for(outer : map.values) {
+			if(outer.size > 1) {
+				abort = false
+				for(inner : outer) {
+					val parent = inner.get(0).parent
+					if(parent !== null) {
+						inner.add(0, parent)
+					}
+				}
+			}
+		}
+		
+		if(abort) {
+			return
+		}
+		
+		buildIndividualNames(nodes)
+		
+	}
+	
+	def protected String toString(List<StringTreeNode> list) {
+		val sb = new StringBuilder
+		
+		for(node : list) {
+			sb.append(node.data)
+		}
+		
+		sb.toString
+	}
+}

+ 10 - 14
test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/ShortStringTest.java

@@ -12,13 +12,9 @@
 package org.yakindu.sct.model.sexec.transformation.test;
 package org.yakindu.sct.model.sexec.transformation.test;
 
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
 
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.Test;
-import org.yakindu.sct.model.sexec.naming.ShortString;
-
-import com.google.common.primitives.Shorts;
+import org.yakindu.sct.model.sexec.naming.tree.ShortString;
 
 
 public class ShortStringTest {
 public class ShortStringTest {
 	private ShortString shortstr;
 	private ShortString shortstr;
@@ -83,22 +79,22 @@ public class ShortStringTest {
 		shortstr = new ShortString("012345");
 		shortstr = new ShortString("012345");
 		
 		
 		shortstr.removeIndex(0);
 		shortstr.removeIndex(0);
-		assertEquals(11, shortstr.getCutCostFactor());
+		assertEquals(11, shortstr.getCutRatioFactor());
 		
 		
 		shortstr.removeIndex(1);
 		shortstr.removeIndex(1);
-		assertEquals(13, shortstr.getCutCostFactor());
+		assertEquals(13, shortstr.getCutRatioFactor());
 		
 		
 		shortstr.removeIndex(2);
 		shortstr.removeIndex(2);
-		assertEquals(15, shortstr.getCutCostFactor());
+		assertEquals(15, shortstr.getCutRatioFactor());
 		
 		
 		shortstr.removeIndex(3);
 		shortstr.removeIndex(3);
-		assertEquals(16, shortstr.getCutCostFactor());
+		assertEquals(16, shortstr.getCutRatioFactor());
 		
 		
 		shortstr.removeIndex(4);
 		shortstr.removeIndex(4);
-		assertEquals(18, shortstr.getCutCostFactor());
+		assertEquals(18, shortstr.getCutRatioFactor());
 		
 		
 		shortstr.removeIndex(5);
 		shortstr.removeIndex(5);
-		assertEquals(20, shortstr.getCutCostFactor());
+		assertEquals(20, shortstr.getCutRatioFactor());
 	}
 	}
 	
 	
 	@Test
 	@Test
@@ -128,7 +124,7 @@ public class ShortStringTest {
 		shortstr.removeIndex(18); // o
 		shortstr.removeIndex(18); // o
 		shortstr.removeIndex(19); // o
 		shortstr.removeIndex(19); // o
 		
 		
-		int expectedCost = 8 * ShortString.COST_LOWERCASE_VOCALS * shortstr.getCutCostFactor();
+		int expectedCost = 8 * ShortString.COST_LOWERCASE_VOCALS * shortstr.getCutRatioFactor();
 		
 		
 		assertEquals(expectedCost, shortstr.getCutCost());
 		assertEquals(expectedCost, shortstr.getCutCost());
 	}
 	}
@@ -143,7 +139,7 @@ public class ShortStringTest {
 		int expectedCost = (
 		int expectedCost = (
 				1 * ShortString.COST_FIRSTLETTER +
 				1 * ShortString.COST_FIRSTLETTER +
 				1 * ShortString.COST_LOWERCASE_VOCALS
 				1 * ShortString.COST_LOWERCASE_VOCALS
-				) * shortstr.getCutCostFactor();
+				) * shortstr.getCutRatioFactor();
 		
 		
 		assertEquals(expectedCost, shortstr.getCutCost());
 		assertEquals(expectedCost, shortstr.getCutCost());
 	}
 	}
@@ -158,7 +154,7 @@ public class ShortStringTest {
 		int expectedCost = (
 		int expectedCost = (
 				1 * ShortString.COST_FIRSTLETTER + 
 				1 * ShortString.COST_FIRSTLETTER + 
 				1 * ShortString.COST_UPPERCASE
 				1 * ShortString.COST_UPPERCASE
-				) * shortstr.getCutCostFactor();
+				) * shortstr.getCutRatioFactor();
 		
 		
 		assertEquals(expectedCost, shortstr.getCutCost());
 		assertEquals(expectedCost, shortstr.getCutCost());
 	}
 	}

+ 140 - 77
test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/StringTreeNodeTest.java

@@ -11,18 +11,16 @@
 package org.yakindu.sct.model.sexec.transformation.test;
 package org.yakindu.sct.model.sexec.transformation.test;
 
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import org.yakindu.sct.model.sexec.naming.StringTreeNode;
 
 
 import java.text.Collator;
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Arrays;
 import java.util.List;
 import java.util.List;
 
 
+import org.junit.Before;
+import org.junit.Test;
+import org.yakindu.sct.model.sexec.naming.tree.StringTreeNode;
+
 public class StringTreeNodeTest {
 public class StringTreeNodeTest {
 	private StringTreeNode tree;
 	private StringTreeNode tree;
 
 
@@ -48,10 +46,10 @@ public class StringTreeNodeTest {
 		testStrings.add("Statechart1.Region2.StateA");
 		testStrings.add("Statechart1.Region2.StateA");
 
 
 		for (String s : testStrings) {
 		for (String s : testStrings) {
-			tree.addString(s);
+			addString(tree, s);
 		}
 		}
 
 
-		List<String> treeContents = tree.getContents();
+		List<String> treeContents = getContents(tree);
 
 
 		stringListsEqual(testStrings, treeContents);
 		stringListsEqual(testStrings, treeContents);
 	}
 	}
@@ -59,24 +57,24 @@ public class StringTreeNodeTest {
 	@Test
 	@Test
 	public void noDoublesTest() {
 	public void noDoublesTest() {
 		// Add the same string twice, expect it to be in the tree only once.
 		// Add the same string twice, expect it to be in the tree only once.
-		tree.addString("DoubleString");
-		tree.addString("DoubleString");
+		addString(tree, "DoubleString");
+		addString(tree, "DoubleString");
 
 
-		assertEquals(1, tree.getContents().size());
+		assertEquals(1, getContents(tree).size());
 	}
 	}
 
 
 	@Test
 	@Test
 	public void compressTest() {
 	public void compressTest() {
 		// Add data to the tree, compress it, and compare contents before and
 		// Add data to the tree, compress it, and compare contents before and
 		// after compressing.
 		// after compressing.
-		tree.addString("PartOne");
-		tree.addString("PartTwo");
+		addString(tree, "PartOne");
+		addString(tree, "PartTwo");
 
 
-		List<String> beforeContents = tree.getContents();
+		List<String> beforeContents = getContents(tree);
 
 
 		tree.compress();
 		tree.compress();
 
 
-		List<String> afterContents = tree.getContents();
+		List<String> afterContents = getContents(tree);
 
 
 		stringListsEqual(beforeContents, afterContents);
 		stringListsEqual(beforeContents, afterContents);
 	}
 	}
@@ -85,12 +83,12 @@ public class StringTreeNodeTest {
 	public void compressNodeTest() {
 	public void compressNodeTest() {
 		// Add data to the tree, compress it, and check if the nodes match the
 		// Add data to the tree, compress it, and check if the nodes match the
 		// expectation.
 		// expectation.
-		tree.addString("PartOne");
-		tree.addString("PartTwo");
+		addString(tree, "PartOne");
+		addString(tree, "PartTwo");
 
 
 		tree.compress();
 		tree.compress();
 
 
-		List<StringTreeNode> nodelist = tree.getNodes();
+		List<StringTreeNode> nodelist = getNodes(tree);
 		List<String> nodecontents = new ArrayList<String>();
 		List<String> nodecontents = new ArrayList<String>();
 		List<String> expectednodecontents = new ArrayList<String>();
 		List<String> expectednodecontents = new ArrayList<String>();
 
 
@@ -109,21 +107,11 @@ public class StringTreeNodeTest {
 		stringListsEqual(nodecontents, expectednodecontents);
 		stringListsEqual(nodecontents, expectednodecontents);
 	}
 	}
 
 
-	@Test
-	public void hasSiblingsTest() {
-		testSiblings("Sc1Reg1StateA", new ArrayList<String>(Arrays.asList("StateB", "StateC")));
-	}
-
-	@Test
-	public void hasNoSiblingsTest() {
-		testSiblings("Sc1Reg2StateA", new ArrayList<String>());
-	}
-
 	@Test
 	@Test
 	public void nodeChainContainedTest() {
 	public void nodeChainContainedTest() {
 		buildStandardTestTree();
 		buildStandardTestTree();
 		String testString = new String("Sc1Reg1StateA");
 		String testString = new String("Sc1Reg1StateA");
-		List<StringTreeNode> nodes = tree.getNodeChain(testString);
+		List<StringTreeNode> nodes = getNodeChain(tree, testString);
 
 
 		StringBuilder builder = new StringBuilder();
 		StringBuilder builder = new StringBuilder();
 
 
@@ -138,7 +126,7 @@ public class StringTreeNodeTest {
 	public void nodeChainNotContainedTest() {
 	public void nodeChainNotContainedTest() {
 		buildStandardTestTree();
 		buildStandardTestTree();
 		String testString = new String("Sc1Reg3StateA");
 		String testString = new String("Sc1Reg3StateA");
-		List<StringTreeNode> nodes = tree.getNodeChain(testString);
+		List<StringTreeNode> nodes = getNodeChain(tree, testString);
 
 
 		assertEquals(nodes, null);
 		assertEquals(nodes, null);
 	}
 	}
@@ -151,42 +139,21 @@ public class StringTreeNodeTest {
 		assertEquals(6, tree.getEndNodes().size());
 		assertEquals(6, tree.getEndNodes().size());
 	}
 	}
 
 
-	@Test
-	public void distanceTest() {
-		buildStandardTestTree();
-		List<StringTreeNode> nodes1, nodes2, nodes3, nodes4;
-		StringTreeNode testNode1, testNode2, testNode3, testNode4;
-
-		nodes1 = tree.getNodeChain("Sc1Reg1StateA");
-		nodes2 = tree.getNodeChain("Sc1Reg1StateB");
-		nodes3 = tree.getNodeChain("Sc1Reg2StateA");
-		nodes4 = tree.getNodeChain("Sc2Reg1StateA");
-
-		testNode1 = nodes1.get(nodes1.size() - 1); // (Sc1Reg1)State A
-		testNode2 = nodes2.get(nodes2.size() - 1); // (Sc1Reg1)State B
-		testNode3 = nodes3.get(nodes3.size() - 1); // (Sc1Reg2)State A
-		testNode4 = nodes4.get(nodes4.size() - 1); // (Sc2Reg1)State A
-
-		assertEquals(2, testNode1.getDistance(testNode2));
-		assertEquals(4, testNode1.getDistance(testNode3));
-		assertEquals(6, testNode1.getDistance(testNode4));
-	}
-
 	@Test
 	@Test
 	public void navigateTest() {
 	public void navigateTest() {
 		buildStandardTestTree();
 		buildStandardTestTree();
 
 
-		StringTreeNode nextnode = tree.navigate("Sc1");
+		StringTreeNode nextnode = navigate(tree, "Sc1");
 
 
 		assertEquals(true, nextnode != null);
 		assertEquals(true, nextnode != null);
 		assertEquals("Sc1", nextnode.getData());
 		assertEquals("Sc1", nextnode.getData());
 
 
-		nextnode = nextnode.navigate("Reg2");
+		nextnode = navigate(nextnode, "Reg2");
 
 
 		assertEquals(true, nextnode != null);
 		assertEquals(true, nextnode != null);
 		assertEquals("Reg2", nextnode.getData());
 		assertEquals("Reg2", nextnode.getData());
 
 
-		nextnode = nextnode.navigate("StateA");
+		nextnode = navigate(nextnode, "StateA");
 
 
 		assertEquals(true, nextnode != null);
 		assertEquals(true, nextnode != null);
 		assertEquals("StateA", nextnode.getData());
 		assertEquals("StateA", nextnode.getData());
@@ -201,23 +168,11 @@ public class StringTreeNodeTest {
 	public void childrenContentTest() {
 	public void childrenContentTest() {
 		buildStandardTestTree();
 		buildStandardTestTree();
 
 
-		StringTreeNode nextnode = tree.navigate("Sc1");
+		StringTreeNode nextnode = navigate(tree, "Sc1");
 
 
 		ArrayList<String> expectedChildren = new ArrayList<String>(Arrays.asList("Reg1", "Reg2"));
 		ArrayList<String> expectedChildren = new ArrayList<String>(Arrays.asList("Reg1", "Reg2"));
 
 
-		stringListsEqual(expectedChildren, nextnode.getChildrenContents());
-	}
-
-	@Test
-	public void deletionTest() {
-		buildStandardTestTree();
-
-		tree.navigate("Sc1").navigate("Reg2").delete();
-
-		ArrayList<String> expectedContents = new ArrayList<String>(
-				Arrays.asList("Sc1Reg1StateA", "Sc1Reg1StateB", "Sc1Reg1StateC", "Sc2Reg1StateA"));
-
-		stringListsEqual(expectedContents, tree.getContents());
+		stringListsEqual(expectedChildren, getChildrenContents(nextnode));
 	}
 	}
 
 
 	@Test
 	@Test
@@ -225,7 +180,7 @@ public class StringTreeNodeTest {
 		List<String> list = new ArrayList<String>(Arrays.asList("Un", "Deux", "Trois", "Quatre"));
 		List<String> list = new ArrayList<String>(Arrays.asList("Un", "Deux", "Trois", "Quatre"));
 		StringTreeNode testNode = tree.addStringList(list);
 		StringTreeNode testNode = tree.addStringList(list);
 
 
-		assertEquals("UnDeuxTroisQuatre", testNode.getContentUpwards());
+		assertEquals("UnDeuxTroisQuatre", getContentUpwards(testNode));
 	}
 	}
 
 
 	@Test
 	@Test
@@ -238,7 +193,7 @@ public class StringTreeNodeTest {
 
 
 		StringTreeNode testNode = tree.addStringList(list1);
 		StringTreeNode testNode = tree.addStringList(list1);
 
 
-		assertEquals("UnDeuxTroisQuatre", testNode.getContentUpwards());
+		assertEquals("UnDeuxTroisQuatre", getContentUpwards(testNode));
 	}
 	}
 
 
 	@Test
 	@Test
@@ -248,12 +203,7 @@ public class StringTreeNodeTest {
 		assertEquals(15, tree.getWeight());
 		assertEquals(15, tree.getWeight());
 	}
 	}
 
 
-	private void testSiblings(String testString, List<String> expectedSiblings) {
-		buildStandardTestTree();
-		stringListsEqual(tree.getSiblings(testString), expectedSiblings);
-	}
-
-	private void buildStandardTestTree() {
+	protected void buildStandardTestTree() {
 		/*
 		/*
 		 * StateA / root-Sc1-Reg1-StateB \ \ \ \ \ StateC \ \ \ Reg2-StateA \
 		 * StateA / root-Sc1-Reg1-StateB \ \ \ \ \ StateC \ \ \ Reg2-StateA \
 		 * Sc2-Reg1-StateA
 		 * Sc2-Reg1-StateA
@@ -265,9 +215,122 @@ public class StringTreeNodeTest {
 		tree.addStringList(new ArrayList<String>(Arrays.asList("Sc2", "Reg1", "StateA")));
 		tree.addStringList(new ArrayList<String>(Arrays.asList("Sc2", "Reg1", "StateA")));
 	}
 	}
 
 
-	private void stringListsEqual(List<String> onelist, List<String> otherlist) {
+	protected void stringListsEqual(List<String> onelist, List<String> otherlist) {
 		java.util.Collections.sort(onelist, Collator.getInstance());
 		java.util.Collections.sort(onelist, Collator.getInstance());
 		java.util.Collections.sort(otherlist, Collator.getInstance());
 		java.util.Collections.sort(otherlist, Collator.getInstance());
 		assertEquals(onelist, otherlist);
 		assertEquals(onelist, otherlist);
 	}
 	}
+	
+	protected StringTreeNode navigate(StringTreeNode node, String content) {
+		for (StringTreeNode child : node.getChildren()) {
+			if (content.equals(child.getData())) {
+				return child;
+			}
+		}
+
+		return null;
+	}
+	
+	protected List<String> getContents(StringTreeNode tree) {
+		/*
+		 * Returns a list of all strings contained in the tree
+		 */
+		List<String> contents = new ArrayList<>();
+		List<StringTreeNode> endNodes = tree.getEndNodes();
+
+		for (StringTreeNode end : endNodes) {
+			contents.add(getContentUpwards(end));
+		}
+
+		return contents;
+	}
+
+	protected String getContentUpwards(StringTreeNode node) {
+		/*
+		 * Traverse tree upwards and return the string ended by this node up to root
+		 */
+		String s = "";
+
+		if (!node.isRoot()) {
+			s = getContentUpwards(node.getParent()) + node.getData();
+		}
+
+		return s;
+	}
+	
+	protected List<String> getChildrenContents(StringTreeNode node) {
+		List<String> returnList = new ArrayList<>();
+
+		for (StringTreeNode child : node.getChildren()) {
+			returnList.add(child.getData());
+		}
+
+		return returnList;
+	}
+	
+	protected List<StringTreeNode> getNodeChain(StringTreeNode tree, String name) {
+		/*
+		 * produces an ArrayList containing the Nodes that form the given string.
+		 */
+		List<StringTreeNode> nodeChain = new ArrayList<>();
+
+		if (tree.getChildren().size() == 0 || (tree.getChildren().size() == 1 && tree.getChildren().get(0).isEnd())) {
+			return nodeChain;
+		}
+
+		int maxEquality = 0;
+		StringTreeNode maxEqualNode = null;
+
+		for (StringTreeNode child : tree.getChildren()) // find maximum equality in tree to select the correct branch
+		{
+			String childS = child.getData();
+			if (name.startsWith(childS) && childS.length() > maxEquality) {
+				maxEquality = childS.length();
+				maxEqualNode = child;
+			}
+		}
+
+		if (maxEqualNode == null) {
+			return null;
+		}
+
+		String rest = name.substring(maxEquality);
+
+		nodeChain.add(maxEqualNode);
+
+		List<StringTreeNode> childrenNodeChain = getNodeChain(maxEqualNode, rest);
+
+		if (childrenNodeChain == null) {
+			return null;
+		}
+
+		nodeChain.addAll(childrenNodeChain);
+
+		return nodeChain;
+	}
+	
+	protected StringTreeNode addString(StringTreeNode node, String s) {
+		/*
+		 * Cut the string into an ArrayList containing the single chars in the string,
+		 * and call addStringList afterwards.
+		 */
+		List<String> sList = new ArrayList<>();
+
+		for (int i = 0; i < s.length(); i++) {
+			sList.add(Character.toString(s.charAt(i)));
+		}
+		return node.addStringList(sList);
+	}
+	
+	protected List<StringTreeNode> getNodes(StringTreeNode node) {
+		List<StringTreeNode> nodelist = new ArrayList<>();
+
+		nodelist.add(node);
+
+		for (StringTreeNode child : node.getChildren()) {
+			nodelist.addAll(getNodes(child));
+		}
+
+		return nodelist;
+	}
 }
 }

+ 3 - 3
test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/TreeNamingServiceTest.java

@@ -23,7 +23,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.Test;
 import org.yakindu.sct.model.sexec.ExecutionFlow;
 import org.yakindu.sct.model.sexec.ExecutionFlow;
 import org.yakindu.sct.model.sexec.ExecutionState;
 import org.yakindu.sct.model.sexec.ExecutionState;
-import org.yakindu.sct.model.sexec.naming.TreeNamingService;
+import org.yakindu.sct.model.sexec.naming.tree.TreeNamingService;
 import org.yakindu.sct.model.sexec.transformation.FlowOptimizer;
 import org.yakindu.sct.model.sexec.transformation.FlowOptimizer;
 import org.yakindu.sct.model.sgraph.Statechart;
 import org.yakindu.sct.model.sgraph.Statechart;
 import org.yakindu.sct.test.models.SCTUnitTestModels;
 import org.yakindu.sct.test.models.SCTUnitTestModels;
@@ -204,8 +204,8 @@ public class TreeNamingServiceTest extends ModelSequencerTest {
 
 
 		// these names are shorter than 15 characters because there are more
 		// these names are shorter than 15 characters because there are more
 		// elements containing these names, e.g. state actions
 		// elements containing these names, e.g. state actions
-		List<String> expectedNames = new ArrayList<String>(Arrays.asList("mgn_SA", "mgn_StteB", "s_S", "t_S",
-				"t_S_AR_SA", "t_S_AR_StB", "s_S_AR_SA", "s_S_AR_StB"));
+		List<String> expectedNames = new ArrayList<String>(Arrays.asList("mrgn_StA", "mrgn_StteB", "s_SA", "t_SA",
+				"t_SA_AR_SA", "t_SA_AR_StB", "s_SA_AR_SA", "s_SA_AR_StB"));
 
 
 		ExecutionFlow flow = optimizer.transform(sequencer.transform(toTest));
 		ExecutionFlow flow = optimizer.transform(sequencer.transform(toTest));