Newer
Older
AlgebraicDataflowArchitectureModel / AlgebraicDataflowArchitectureModel / src / generators / CodeGenerationContext.java
package generators;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import code.ast.TypeDeclaration;
import models.algebra.Type;
import models.dataConstraintModel.DataConstraintModel;
import models.dataConstraintModel.ListType;
import models.dataConstraintModel.MapType;
import models.dataConstraintModel.ResourceHierarchy;
import models.dataFlowModel.DataTransferChannel;

public class CodeGenerationContext {
	protected HashMap<String, HashMap<ResourceHierarchy, String>> componentNames = new HashMap<>();
	protected Map<ResourceHierarchy, TypeDeclaration> resourceHierarchyToComponent;
	protected Map<String, Type> componentNameToType;
	protected Map<ResourceHierarchy, Map<ResourceHierarchy, Map<DataTransferChannel, String>>> updateMethods;
	protected ILanguageSpecific langSpec = null;
	protected IPlatformSpecific platformSpec = null;
	
	public CodeGenerationContext(ILanguageSpecific langSpec, IPlatformSpecific platformSpec) {
		this.resourceHierarchyToComponent = new HashMap<>();
		this.componentNameToType = new HashMap<>();
		this.updateMethods = new HashMap<>();
		this.langSpec = langSpec;
		this.platformSpec = platformSpec;
	}

	public String getComponentName(ResourceHierarchy res, ILanguageSpecific langSpec) {
		String name = res.getResourceName();
		if (res.getNumParameters() > 0) {
			if (name.length() > 3 && name.endsWith("ies")) {
				name = name.substring(0, name.length() - 3) + "y";
			} else if (name.length() > 1 && name.endsWith("s")) {
				name = name.substring(0, name.length() - 1);
			} else {
				name += "Element";
			}
		}
		String componentName = langSpec.toComponentName(name);
		if (!generatesComponent(res)) return componentName;
		// To avoid generating multiple components with the same name.
		HashMap<ResourceHierarchy, String> resToName = componentNames.get(componentName);
		if (resToName == null) {
			resToName = new HashMap<>();
			resToName.put(res, componentName);
			componentNames.put(componentName, resToName);
			return componentName;
		}
		if (resToName.get(res) == null) {
			componentName += resToName.size();
			resToName.put(res, componentName);
			return componentName;
		}
		return resToName.get(res);
	}
	
	public Type getOrCreateComponentType(ResourceHierarchy res) {
		return getOrCreateComponentType(getComponentName(res, langSpec));
	}
	
	public Type getOrCreateComponentType(String componentName) {
		Type componentType = componentNameToType.get(componentName);
		if (componentType != null) return componentType;
		componentType = new Type(componentName, new code.ast.SimpleType(componentName));
		componentNameToType.put(componentName, componentType);
		return componentType;
	}
	
	public Type getImplStateType(ResourceHierarchy res, ILanguageSpecific langSpec) {
		Set<ResourceHierarchy> children = res.getChildren();
		if (children == null || children.size() == 0) {
			// leaf resource.
			return res.getResourceStateType();
		} else {
			ResourceHierarchy child = children.iterator().next();
			if (children.size() == 1 && child.getNumParameters() > 0) {
				// map or list.
				if (DataConstraintModel.typeList.isAncestorOf(res.getResourceStateType()) || res.getResourceStateType() instanceof ListType) {
					// list.
					if (generatesComponent(child)) {
						return langSpec.newListType(getOrCreateComponentType(child));
					} else {
						return langSpec.newListType(getImplStateType(child, langSpec));
					}
				} else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType()) || res.getResourceStateType() instanceof MapType) {
					// map.
					if (generatesComponent(child)) {
						return langSpec.newMapType(DataConstraintModel.typeString, getOrCreateComponentType(child).getInterfaceTypeName());
					} else {
						return langSpec.newMapType(DataConstraintModel.typeString, getImplStateType(child, langSpec).getInterfaceTypeName());
					}
				}
				return null;
			} else {
				// class
				return res.getResourceStateType();
			}
		}
	}
	
	public boolean generatesComponent(ResourceHierarchy res) {
		if (res.getParent() == null) return true;
		if (res.getChildren() == null || res.getChildren().size() == 0) return false;
		if (res.getNumParameters() > 0 && res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0) return false;
		if (res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0 
				&& (res.getChildren().iterator().next().getChildren() == null || res.getChildren().iterator().next().getChildren().size() == 0)) return false;
		return true;
//		return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0);
	}
	
	public void putComponent(ResourceHierarchy res, TypeDeclaration component) {
		resourceHierarchyToComponent.put(res, component);
	}
	
	public TypeDeclaration getComponent(ResourceHierarchy res) {
		return resourceHierarchyToComponent.get(res);
	}
	

	public String getOrPutUpdateMethodName(ResourceHierarchy srcRes, DataTransferChannel ch, ResourceHierarchy dstRes) {
		Map<ResourceHierarchy, Map<DataTransferChannel, String>> dstResUpdatesMethods = updateMethods.getOrDefault(dstRes, new HashMap<>());
		updateMethods.put(dstRes, dstResUpdatesMethods);
		Map<DataTransferChannel, String> dstResFromSrcResUpdatesMethods = dstResUpdatesMethods.getOrDefault(srcRes, new HashMap<>());
		dstResUpdatesMethods.put(srcRes, dstResFromSrcResUpdatesMethods);
		String updateMethodName = dstResFromSrcResUpdatesMethods.get(ch);
		if (updateMethodName == null) {
			String srcResComponentName = getComponentName(srcRes, langSpec);
			String dstResComponentName = getComponentName(dstRes, langSpec);
			if (generatesComponent(dstRes)) {
				updateMethodName = CodeGenerator.updateMethodPrefix + CodeGenerator.from + srcResComponentName;
			} else if (dstRes.getParent() != null) {
				updateMethodName = CodeGenerator.updateMethodPrefix + dstResComponentName + CodeGenerator.from + srcResComponentName;
			}
			if (dstResFromSrcResUpdatesMethods.size() > 0) {
				updateMethodName += dstResFromSrcResUpdatesMethods.size() + 1;		// To avoid declaring the method multiply.
			}
			dstResFromSrcResUpdatesMethods.put(ch, updateMethodName);
		}
		return updateMethodName;
	}
}