Browse Source

generalized type inference, to also work with unit inference

Cláudio Gomes 6 years ago
parent
commit
8f2d6b5a31

+ 67 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.tests/input/power_window_case_study/lazy.sa

@@ -0,0 +1,67 @@
+semantic adaptation reactive moore LazySA lazy_sa
+at "./path/to/LazySA.fmu"
+
+	for inner fmu Controller controller
+	at "./path/to/Controller.fmu"
+	with input ports Bool obj_detected, Bool passenger_up, Bool passenger_down, Bool passenger_stop, Bool driver_up, Bool driver_down, Bool driver_stop
+	with output ports Bool up, Bool down, Bool stop
+
+input ports obj_detected -> controller.obj_detected,
+			passenger_up -> controller.passenger_up,
+			passenger_down -> controller.passenger_down,
+			passenger_stop -> controller.passenger_stop,
+			driver_up -> controller.driver_up,
+			driver_down -> controller.driver_down,
+			driver_stop -> controller.driver_stop
+
+param 	INIT_OBJ_DETECTED := false,
+		INIT_PASSENGER_UP := false,
+		INIT_PASSENGER_DOWN := false,
+		INIT_PASSENGER_STOP := false,
+		INIT_DRIVER_UP := false,
+		INIT_DRIVER_DOWN := false,
+		INIT_DRIVER_STOP := false;
+
+control var	tn := -1.0,
+			tl := -1.0,
+			prev_obj_detected := INIT_OBJ_DETECTED,
+			prev_passenger_up := INIT_PASSENGER_UP,
+			prev_passenger_down := INIT_PASSENGER_DOWN,
+			prev_passenger_stop := INIT_PASSENGER_STOP,
+			prev_driver_up := INIT_DRIVER_UP,
+			prev_driver_down := INIT_DRIVER_DOWN,
+			prev_driver_stop := INIT_DRIVER_STOP;
+
+control rules {
+	if (tl < 0.0){
+		tl := t;
+	}
+	
+	var step_size := min(H, tn - t); 
+	if (lazy_sa.obj_detected != prev_obj_detected or
+		lazy_sa.passenger_up != prev_passenger_up or
+		lazy_sa.passenger_down != prev_passenger_down or
+		lazy_sa.passenger_stop != prev_passenger_stop or
+		lazy_sa.driver_up != prev_driver_up or
+		lazy_sa.driver_down != prev_driver_down or
+		lazy_sa.driver_stop != prev_driver_stop or
+		(t+H) >= tn
+	){
+		var Real step_to_be_done := (t+H-tl);
+		var step_done := do_step(controller, t, step_to_be_done); 
+		tn := tl + step_done + get_next_time_step(controller); 
+		step_size := tl + step_done - t; 
+		tl := tl + step_done; 
+	}
+	
+	prev_obj_detected := lazy_sa.obj_detected;
+	prev_passenger_up := lazy_sa.passenger_up;
+	prev_passenger_down := lazy_sa.passenger_down;
+	prev_passenger_stop := lazy_sa.passenger_stop;
+	prev_driver_up := lazy_sa.driver_up;
+	prev_driver_down := lazy_sa.driver_down;
+	prev_driver_stop := lazy_sa.driver_stop;
+	
+	return step_size;
+}
+

+ 74 - 0
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.tests/input/power_window_case_study/loop_canonical.sa

@@ -0,0 +1,74 @@
+semantic adaptation reactive moore LoopSA loop_sa
+at "./path/to/LoopSA.fmu"
+	
+	for inner fmu WindowSA window_sa
+		at "./path/to/WindowSA.fmu"
+		with input ports displacement (rad), speed (rad/s), reaction_force (N)
+		with output ports disp (m), tau (N.m)
+	
+	for inner fmu Obstacle obstacle
+		at "./path/to/Obstacle.fmu"
+		with input ports disp (m)
+		with output ports reaction_force (m)
+	
+	coupled as window_sa.disp -> obstacle.disp, 
+				obstacle.reaction_force -> window_sa.reaction_force
+
+input ports displacement, speed
+
+output ports tau
+
+param 	MAXITER := 10, REL_TOL := 1e-05, ABS_TOL := 1e-05,
+		INIT_LOOP_SA_DISPLACEMENT := 0.0,
+		INIT_LOOP_SA_SPEED := 0.0,
+		INIT_WINDOW_SA_DISP := 0.0,
+		INIT_WINDOW_SA_TAU := 0.0,
+		INIT_OBSTACLE_REACTION_FORCE := 0.0;
+
+control var prev_disp := 0.0;
+control rules {
+	var repeat := false;
+	for (var iter in 0 .. MAXITER) {
+		save_state(obstacle);
+		save_state(window_sa);
+		obstacle.disp := prev_disp;
+		do_step(obstacle,t,H);
+		window_sa.reaction_force := stored_obstacle_reaction_force;
+		do_step(window_sa,t,H);
+		
+		repeat := is_close(prev_disp, stored_window_sa_disp, REL_TOL, ABS_TOL);
+		prev_disp := stored_window_sa_disp;
+		if (repeat) {
+			break;
+		} else {
+			rollback(obstacle);
+			rollback(window_sa);
+		}
+	}
+	return H;
+}
+
+in var 	stored_loop_sa_displacement := INIT_LOOP_SA_DISPLACEMENT,
+		stored_loop_sa_speed := INIT_LOOP_SA_SPEED;
+in rules {
+	true -> {
+		stored_loop_sa_displacement := loop_sa.displacement;
+		stored_loop_sa_speed := loop_sa.speed;
+	} --> {
+		window_sa.displacement := stored_loop_sa_displacement;
+		window_sa.speed := stored_loop_sa_speed;
+	};
+}
+
+out var	stored_window_sa_disp := INIT_WINDOW_SA_DISP,
+		stored_window_sa_tau := INIT_WINDOW_SA_TAU,
+		stored_obstacle_reaction_force := INIT_OBSTACLE_REACTION_FORCE;
+out rules{
+	true -> {
+		stored_window_sa_disp := window_sa.disp;
+		stored_window_sa_tau := window_sa.tau;
+		stored_obstacle_reaction_force := obstacle.tau;
+	} --> {
+		loop_sa.tau := stored_window_sa_tau;
+	};
+}

+ 1 - 1
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.tests/input/power_window_case_study/window_sa.BASE.sa

@@ -6,7 +6,7 @@ at "./path/to/WindowSA.fmu"
 		with input ports displacement(rad), speed (rad/s), reaction_force (N)
 		with input ports displacement(rad), speed (rad/s), reaction_force (N)
 		with output ports height (cm), reaction_torque (N.m)
 		with output ports height (cm), reaction_torque (N.m)
 
 
-output ports disp (m)  <- window.height, tau
+output ports disp (m)  <- window.height, tau (N)
 
 
 out rules {
 out rules {
 	true -> {} --> {
 	true -> {} --> {

+ 6 - 1
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation.tests/src/be/uantwerpen/ansymo/semanticadaptation/tests/SemanticAdaptationGeneratorTest.xtend

@@ -18,13 +18,18 @@ class SemanticAdaptationGeneratorTest extends AbstractSemanticAdaptationTest{
 	
 	
 	@Inject extension CompilationTestHelper
 	@Inject extension CompilationTestHelper
 	
 	
+	@Test def window_SA() { __generate('input/power_window_case_study/window_sa.BASE.sa') }
+	
 	@Test def lazy_SA() { __generate('input/power_window_case_study/lazy.sa') }
 	@Test def lazy_SA() { __generate('input/power_window_case_study/lazy.sa') }
 	
 	
+	
 	def void __generate(String filename) {
 	def void __generate(String filename) {
 		//readFile(filename).assertCompilesTo('oracles/power_window_case_study/lazy.BASE.sa')
 		//readFile(filename).assertCompilesTo('oracles/power_window_case_study/lazy.BASE.sa')
 		
 		
 		readFile(filename).compile(new IAcceptor<CompilationTestHelper.Result>(){
 		readFile(filename).compile(new IAcceptor<CompilationTestHelper.Result>(){
-			override accept(Result t) { }
+			override accept(Result t) {
+				// TODO: What kind of acceptance for generated text files? File comparison is very very brittle.
+			}
 		})
 		})
 		
 		
 	}
 	}

+ 370 - 26
DSL_SemanticAdaptation/be.uantwerpen.ansymo.semanticadaptation/src/be/uantwerpen/ansymo/semanticadaptation/generator/SemanticAdaptationCanonicalGenerator.xtend

@@ -23,6 +23,7 @@ import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.StringLiteral
 import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Variable
 import be.uantwerpen.ansymo.semanticadaptation.semanticAdaptation.Variable
 import java.io.ByteArrayOutputStream
 import java.io.ByteArrayOutputStream
 import java.util.HashMap
 import java.util.HashMap
+import org.eclipse.emf.ecore.EObject
 import org.eclipse.emf.ecore.resource.Resource
 import org.eclipse.emf.ecore.resource.Resource
 import org.eclipse.xtext.EcoreUtil2
 import org.eclipse.xtext.EcoreUtil2
 import org.eclipse.xtext.generator.AbstractGenerator
 import org.eclipse.xtext.generator.AbstractGenerator
@@ -95,8 +96,51 @@ class SemanticAdaptationCanonicalGenerator extends AbstractGenerator {
 	
 	
 	def canonicalize(Adaptation sa){
 	def canonicalize(Adaptation sa){
 		
 		
+		//inferUnits(sa)
+		
+		
 		// Type inference
 		// Type inference
-		inferTypes(sa)
+		genericDeclarationInferenceAlgorithm(sa , 
+			[// getField
+				element | {
+					if (element instanceof SingleParamDeclaration) {
+						return element.type
+					} else if (element instanceof Port){
+						return element.type
+					} else if (element instanceof SingleVarDeclaration){
+						return element.type
+					} else {
+						throw new Exception("Unexpected element type: " + element)
+					}
+				}
+			],
+			[// setField
+				element, value | {
+					if (element instanceof SingleParamDeclaration) {
+						element.type = value as String
+					} else if (element instanceof Port){
+						element.type = value as String
+					} else if (element instanceof SingleVarDeclaration){
+						element.type = value as String
+					} else {
+						throw new Exception("Unexpected element type: " + element)
+					}
+				}
+			],
+			[// inferField
+				element | {
+					if (element instanceof SingleParamDeclaration) {
+						return extractTypeFromExpression(element.expr, element.name)
+					} else if (element instanceof Port){
+						return getPortType(element)
+					} else if (element instanceof SingleVarDeclaration){
+						return extractTypeFromExpression(element.expr, element.name)
+					} else {
+						throw new Exception("Unexpected element type: " + element)
+					}
+				}
+			]
+		)
 		
 		
 		// TODO Add input ports
 		// TODO Add input ports
 		
 		
@@ -105,6 +149,184 @@ class SemanticAdaptationCanonicalGenerator extends AbstractGenerator {
 		
 		
 	}
 	}
 	
 	
+	def genericDeclarationInferenceAlgorithm(Adaptation sa, 
+												(EObject)=>Object getField, 
+												(EObject, Object)=>void setField,
+												(EObject)=>Object inferField
+	){
+		println("Running generic inference algorithm...")
+		
+		/*
+		 * Dumbest (and simplest) algorithm for this is a fixed point computation:
+		 * 1. Look for every var/port declaration
+		 * 2. If that var has a XXX already, nothing else to be done.
+		 * 3. If that var has no XXX declared, then
+		 * 3.1 If var/port has an initial value or connection, then
+		 * 3.1.1 If the initial_value/connection has a XXX declared, then var gets that XXX.
+		 * 3.1.2 Otherwise, nothing else to be done.
+		 * 3.2 If var/port has no initial value or connection then this either is a missing feature, or an error.
+		 * 3.3 If something has changed, go to 1. Otherwise, end.
+		 */
+		var fixedPoint = false
+		var untypedElementsCounter = 0
+		while (! fixedPoint){
+			fixedPoint = true
+			untypedElementsCounter = 0
+			
+			println("Inferring parameter fields...")
+			
+			for (paramDeclarations : sa.params) {
+				for (paramDeclaration : paramDeclarations.declarations) {
+					println("Computing field for param " + paramDeclaration.name)
+					if(getField.apply(paramDeclaration) !== null){
+						println("Already has been inferred: " + getField.apply(paramDeclaration))
+					} else {
+						println("Has not been inferred yet.")
+						//var inferredTypeAttempt = extractTypeFromExpression(paramDeclaration.expr, paramDeclaration.name)
+						var inferredTypeAttempt = inferField.apply(paramDeclaration)
+						if (inferredTypeAttempt !== null){
+							//paramDeclaration.type = inferredTypeAttempt
+							setField.apply(paramDeclaration, inferredTypeAttempt)
+							fixedPoint = false
+							println("Got new field: " + inferredTypeAttempt)
+						} else {
+							untypedElementsCounter++
+							println("Cannot infer field now.")
+						}
+					}
+				}
+			}
+			
+			if(sa.inner !== null){
+				if(sa.inner instanceof InnerFMUDeclarationFull){
+					var innerFMUFull = sa.inner as InnerFMUDeclarationFull
+					for(fmu : innerFMUFull.fmus){
+						println("Inferring port fields of FMU " + fmu.name)
+						for (port : EcoreUtil2.getAllContentsOfType(fmu, Port)) {
+							if(getField.apply(port) !== null){
+								println("Already has a type: " + port.type)
+							//} else if(inferPortType(port)) {
+							} else {
+								// TODO Refactor this with the above code, to check and infer field of generic type.
+								var inferredTypeAttempt = inferField.apply(port)
+								if (inferredTypeAttempt !== null){
+									setField.apply(port, inferredTypeAttempt)
+									fixedPoint = false
+									println("Got new field: " + inferredTypeAttempt)
+								} else {
+									untypedElementsCounter++
+									println("Cannot infer field now.")
+								}
+							}
+						}
+					}
+					
+					if (innerFMUFull.connection.size > 0){
+						println("Inferring port fields using internal scenario bindings.")
+						for (binding : innerFMUFull.connection){
+							if (getField.apply(binding.src.port) !== null && getField.apply(binding.tgt.port) !== null){
+								println("Both ports have fields already.")
+							//} else if (inferPortTypeViaConnection(binding)){
+							} else {
+								var inferredTypeAttempt = inferPortFieldViaConnection(binding, getField, setField, inferField)
+								if (inferredTypeAttempt !== null){
+									setField.apply(binding, inferredTypeAttempt)
+									fixedPoint = false
+									untypedElementsCounter--
+									println("Got new field: " + inferredTypeAttempt)
+								} else {
+									println("Cannot infer field from binding now.")
+								}
+							}
+						}
+					}
+				} else {
+					throw new Exception("Field inference only supported for InnerFMUDeclarationFull.")
+				}
+			}
+			
+			println("Inferring external port fields...")
+			
+			for (port : sa.inports) {
+				//if (port.type !== null){
+				if (getField.apply(port) !== null){
+					println("Already has a field: " + getField.apply(port))
+					//if (pushPortType(port)){
+					if (pushPortField(port, getField, setField, inferField)){
+						fixedPoint = false
+						untypedElementsCounter--
+					} 
+				//} else if (inferPortType(port)){
+				} else {
+					// TODO Refactor this with the above code, to check and infer field of generic type.
+					var inferredTypeAttempt = inferField.apply(port)
+					if (inferredTypeAttempt !== null){
+						setField.apply(port, inferredTypeAttempt)
+						fixedPoint = false
+						println("Got new field: " + inferredTypeAttempt)
+					} else {
+						untypedElementsCounter++
+						println("Cannot infer field now.")
+					}
+				}
+			}
+			for (port : sa.outports) {
+				//if (port.type !== null){
+				// TODO Refactor this with the above code, the treatment to external output ports is the exact same as for external input ports.
+				if (getField.apply(port) !== null){
+					println("Already has a field: " + getField.apply(port))
+					//if (pushPortType(port)){
+					if (pushPortField(port, getField, setField, inferField)){
+						fixedPoint = false
+						untypedElementsCounter--
+					} 
+				//} else if (inferPortType(port)){
+				} else {
+					// TODO Refactor this with the above code, to check and infer field of generic type.
+					var inferredTypeAttempt = inferField.apply(port)
+					if (inferredTypeAttempt !== null){
+						setField.apply(port, inferredTypeAttempt)
+						fixedPoint = false
+						println("Got new field: " + inferredTypeAttempt)
+					} else {
+						untypedElementsCounter++
+						println("Cannot infer field now.")
+					}	
+				}
+			}
+			
+			println("Inferring all other declaration fields...")
+			
+			for (varDeclaration : EcoreUtil2.getAllContentsOfType(sa, SingleVarDeclaration)) {
+				println("Computing type for declaration " + varDeclaration.name)
+				//if(varDeclaration.type !== null){
+				if(getField.apply(varDeclaration) !== null){
+					println("Already has a field: " + getField.apply(varDeclaration))
+				} else {
+					//var inferredTypeAttempt = extractTypeFromExpression(varDeclaration.expr, varDeclaration.name)
+					var inferredTypeAttempt = inferField.apply(varDeclaration)
+					if (inferredTypeAttempt !== null){
+						//varDeclaration.type = inferredTypeAttempt
+						setField.apply(varDeclaration, inferredTypeAttempt)
+						fixedPoint = false
+						println("Got new type: " + inferredTypeAttempt)
+					} else {
+						untypedElementsCounter++
+						println("Cannot infer field now.")
+					}
+				}
+			}
+			
+			println("Ended iteration with unfielded elements remaining: " + untypedElementsCounter)
+		} // while (! fixedPoint)
+		
+		if (untypedElementsCounter > 0){
+			throw new Exception("Could not infer all fields. There are " + untypedElementsCounter + " unfielded elements.")
+		}
+		
+		println("Running generic inference algorithm... DONE")
+	}
+	
 	def inferTypes(Adaptation sa){
 	def inferTypes(Adaptation sa){
 		println("Inferring types...")
 		println("Inferring types...")
 		
 		
@@ -280,11 +502,31 @@ class SemanticAdaptationCanonicalGenerator extends AbstractGenerator {
 		return null
 		return null
 	}
 	}
 	
 	
+	def inferPortFieldViaConnection(Connection binding, 
+										(EObject)=>Object getField, 
+										(EObject, Object)=>void setField,
+										(EObject)=>Object inferField
+	){
+		var Object resultField = null
+		if (getField.apply(binding.src.port) !== null && getField.apply(binding.tgt.port) !== null){
+			throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.")
+		} else if (getField.apply(binding.src.port) !== null){
+			//binding.tgt.port.type = binding.src.port.type
+			resultField = getField.apply(binding.src.port)
+			println("Target port "+ binding.tgt.port.name +" got new type: " + resultField)
+		} else if (getField.apply(binding.tgt.port) !== null){
+			//binding.src.port.type = binding.tgt.port.type
+			resultField = getField.apply(binding.tgt.port)
+			println("Target port "+ binding.src.port.name +" got new type: " + resultField)
+		}
+		
+		return resultField
+	}
+	
 	def inferPortTypeViaConnection(Connection binding){
 	def inferPortTypeViaConnection(Connection binding){
 		var typeInferred = false
 		var typeInferred = false
 		
 		
 		if (binding.src.port.type !== null && binding.tgt.port.type !== null){
 		if (binding.src.port.type !== null && binding.tgt.port.type !== null){
-			println("Both ports have types already.")
 			throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.")
 			throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.")
 		} else if (binding.src.port.type !== null){
 		} else if (binding.src.port.type !== null){
 			binding.tgt.port.type = binding.src.port.type
 			binding.tgt.port.type = binding.src.port.type
@@ -297,34 +539,48 @@ class SemanticAdaptationCanonicalGenerator extends AbstractGenerator {
 		return typeInferred
 		return typeInferred
 	}
 	}
 	
 	
-	def inferPortTypeFromBindings(Port port){
+	def pushPortField(Port port, 
+							(EObject)=>Object getField, 
+							(EObject, Object)=>void setField,
+							(EObject)=>Object inferField){
 		var typeInferred = false
 		var typeInferred = false
-		if(port.sourcedependency !== null){
-			println("Has a source dependency: " + port.sourcedependency.port.name)
-			if(port.sourcedependency.port.type === null){
-				println("Dependency has no type yet.")
+		println("Pushing field of port " + port.name + " to its bindings.")
+		
+		if(getField.apply(port) === null){
+			println("Has no field to be pushed.")
+			// TODO Throw exception wrong usage
+		} else {
+			println("Pushing field: " + getField.apply(port))
+			if(port.sourcedependency !== null){
+				println("Has a source dependency: " + port.sourcedependency.port.name)
+				if(getField.apply(port.sourcedependency.port) === null){
+					//port.sourcedependency.port.type = port.type
+					setField.apply(port.sourcedependency.port, getField.apply(port))
+					println("Port " + port.sourcedependency.port.name + " got new type: " + getField.apply(port.sourcedependency.port))
+					typeInferred = true
+				} else {
+					println("Source port already has field.")
+				}
 			} else {
 			} else {
-				port.type = port.sourcedependency.port.type
-				println("Got new type: " + port.type)
-				typeInferred = true
+				println("Has no source dependency.")
 			}
 			}
-		} else {
-			println("Has no source dependency.")
-		}
-		
-		if (port.targetdependency !== null && !typeInferred) {
-			println("Has a target dependency: " + port.targetdependency.owner.name + "." + port.targetdependency.port.name)
-			if(port.targetdependency.port.type === null){
-				//println("Port object: " + port.targetdependency.port)
-				println("Dependency has no type yet.")
+			
+			if (port.targetdependency !== null) {
+				println("Has a target dependency: " + port.targetdependency.port.name)
+				if(getField.apply(port.targetdependency.port) === null){
+					println("Dependency has no field yet.")
+					//port.targetdependency.port.type = port.type
+					setField.apply(port.targetdependency.port, getField.apply(port))
+					println("Port " + port.targetdependency.port.name + " got new type: " + getField.apply(port.targetdependency.port))
+					typeInferred = true
+				} else {
+					println("Target port already has field.")
+				}
 			} else {
 			} else {
-				port.type = port.targetdependency.port.type
-				println("Got new type: " + port.type)
-				typeInferred = true
+				println("Has no target dependency.")
 			}
 			}
-		} else {
-			println("Has no target dependency, or type has already been inferred from source dependency.")
 		}
 		}
+		
 		return typeInferred
 		return typeInferred
 	}
 	}
 	
 	
@@ -367,17 +623,105 @@ class SemanticAdaptationCanonicalGenerator extends AbstractGenerator {
 		return typeInferred
 		return typeInferred
 	}
 	}
 	
 	
+	def getPortType(Port port){
+		var typeInferred = false
+		
+		println("Computing type for port " + port.name)
+		//println("Object: " + port)
+		
+		var String returnType = null
+		
+		if(port.type !== null){
+			throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.")
+		} else {
+			println("Has no type.")
+			
+			println("Attempting to infer type from units.")
+			if (port.unity !== null){
+				returnType = "Real"
+				println("Got new type: " + returnType)
+				typeInferred = true
+			} else {
+				println("Attempting to infer type from bindings.")
+
+				if(port.sourcedependency !== null){
+					println("Has a source dependency: " + port.sourcedependency.port.name)
+					if(port.sourcedependency.port.type === null){
+						println("Dependency has no type yet.")
+					} else {
+						returnType = port.sourcedependency.port.type
+						println("Got new type: " + returnType)
+						typeInferred = true
+					}
+				} else {
+					println("Has no source dependency.")
+				}
+				
+				if (port.targetdependency !== null && !typeInferred) {
+					println("Has a target dependency: " + port.targetdependency.owner.name + "." + port.targetdependency.port.name)
+					if(port.targetdependency.port.type === null){
+						//println("Port object: " + port.targetdependency.port)
+						println("Dependency has no type yet.")
+					} else {
+						returnType = port.targetdependency.port.type
+						println("Got new type: " + port.type)
+						typeInferred = true
+					}
+				} else {
+					println("Has no target dependency, or type has already been inferred from source dependency.")
+				}
+			}
+		}
+		
+		return returnType
+	}
+	
 	def inferPortType(Port port){
 	def inferPortType(Port port){
 		var typeInferred = false
 		var typeInferred = false
 		println("Computing type for port " + port.name)
 		println("Computing type for port " + port.name)
 		//println("Object: " + port)
 		//println("Object: " + port)
 			
 			
 		if(port.type !== null){
 		if(port.type !== null){
-			println("Already has a type: " + port.type)
 			throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.")
 			throw new Exception("Wrong way of using this function. It assumes type is not inferred yet.")
 		} else {
 		} else {
 			println("Has no type.")
 			println("Has no type.")
-			typeInferred = inferPortTypeFromBindings(port)
+			
+			println("Attempting to infer type from units.")
+			if (port.unity !== null){
+				port.type = "Real"
+				println("Got new type: " + port.type)
+				typeInferred = true
+			} else {
+				println("Attempting to infer type from bindings.")
+
+				if(port.sourcedependency !== null){
+					println("Has a source dependency: " + port.sourcedependency.port.name)
+					if(port.sourcedependency.port.type === null){
+						println("Dependency has no type yet.")
+					} else {
+						port.type = port.sourcedependency.port.type
+						println("Got new type: " + port.type)
+						typeInferred = true
+					}
+				} else {
+					println("Has no source dependency.")
+				}
+				
+				if (port.targetdependency !== null && !typeInferred) {
+					println("Has a target dependency: " + port.targetdependency.owner.name + "." + port.targetdependency.port.name)
+					if(port.targetdependency.port.type === null){
+						//println("Port object: " + port.targetdependency.port)
+						println("Dependency has no type yet.")
+					} else {
+						port.type = port.targetdependency.port.type
+						println("Got new type: " + port.type)
+						typeInferred = true
+					}
+				} else {
+					println("Has no target dependency, or type has already been inferred from source dependency.")
+				}
+				
+			}
 		}
 		}
 		
 		
 		return typeInferred
 		return typeInferred