Commit 76e3bf2a authored by Martti Käärik's avatar Martti Käärik
Browse files

Implemented usage of un-mapped data in execution. Unmapped data overloads of...

Implemented usage of un-mapped data in execution. Unmapped data overloads of predefined functions + implementation. Runtime helper functions. Code generator.
parent d311a75e
Loading
Loading
Loading
Loading
Loading
+85 −9
Original line number Diff line number Diff line
@@ -1181,8 +1181,14 @@ public class JUnitTestGenerator extends Renderer {
				VariableUse v = ((Assignment) b).getVariable();
				initializeDataUse(((Assignment) b).getExpression(), dataUseVariables);
				write(v, dataUseVariables);
				// Fix? The variable itself (write() would render its value, e.g. as Data)
				//append(COMPONENT_FIELD + "." + getElementName(v.getVariable()));
				append(" = ");
				if (isUnmapped())
					append(COMPONENT_FIELD + "." + RuntimeApi.VALUE + "(");
				write(((Assignment) b).getExpression(), dataUseVariables);
				if (isUnmapped())
					append(")");
				line(";");

			}
@@ -1199,7 +1205,7 @@ public class JUnitTestGenerator extends Renderer {
				// finally block, so also when the assertion error is thrown below)
				String resultVar = getAssertionResultVariable(b);
				append(resultVar + " = (");
				write(condition, dataUseVariables);
				writeCondition(condition, dataUseVariables);
				line(");");
				List<DataUse> operands = getAssertionOperands(condition);
				if (!operands.isEmpty()) {
@@ -1361,7 +1367,7 @@ public class JUnitTestGenerator extends Renderer {
				// XXX counter type
				String counterType = "int";
				append("for (" + counterType + " " + counterName + " = 0; " + counterName + " < ");
				write(d, dataUseVariables);
				writeInteger(d, dataUseVariables);
				append("; " + counterName + "++)");

				blockOpen();
@@ -1416,7 +1422,7 @@ public class JUnitTestGenerator extends Renderer {
						DataUse g = guard.get().getExpression();
						initializeDataUse(g, dataUseVariables);
						append("if (");
						write(g, dataUseVariables);
						writeCondition(g, dataUseVariables);
						append(") ");
					}

@@ -1568,7 +1574,7 @@ public class JUnitTestGenerator extends Renderer {
						// Single tester-input: value assignments + timeout handling
						writeResultHandling(f.b, dataUseVariables);
						if (f.kind.equals("TimeoutResult")) {
							line(COMPONENT_FIELD + "." + RuntimeApi.TERMINATE + "(\"" + escape(f.terminationMessage) + "\");");
							line(COMPONENT_FIELD + "." + RuntimeApi.TERMINATE + "(\"Timeout\");");
							thrownExceptions.add(STOP_EXCEPTION);
						}
					}
@@ -1713,7 +1719,7 @@ public class JUnitTestGenerator extends Renderer {
			initializeDataUse(g, dataUseVariables);

			append("if (");
			write(g, dataUseVariables);
			writeCondition(g, dataUseVariables);
			append(")");
			blockOpen();
		}
@@ -2369,8 +2375,14 @@ public class JUnitTestGenerator extends Renderer {
				append(")");

		} else if (function != null || predefinedFunction != null) {
			if (isUnmapped())
				append(unmappedDataInitializer + ".setValue(");
			// Unmapped functions return Data, taken as the value. Generic predefined
			// functions take Data in both modes and thus return Java primitives, which
			// are wrapped here.
			boolean dataResult = isUnmapped() && (function != null || !isGenericPredefinedFunction(predefinedFunction));
			if (dataResult)
				append(" = " + COMPONENT_FIELD + "." + RuntimeApi.VALUE + "(");
			else if (isUnmapped())
				append(unmappedDataInitializer + "." + RuntimeApi.SET_VALUE + "(");

			if (function != null) {
				// TODO instance function
@@ -2407,13 +2419,19 @@ public class JUnitTestGenerator extends Renderer {

		} else if (formalParameter != null) {
			if (isUnmapped())
				append(unmappedDataInitializer + ".setValue(");
				append(unmappedDataInitializer + "." + RuntimeApi.SET_VALUE + "(");
			append(getElementName(formalParameter));
			if (isUnmapped())
				append(")");

		} else if (d instanceof VariableUse) {
			// Reached for a cast of a variable (plain variable uses need no
			// initialization); unmapped: the cast keeps the Data as it is
			if (isUnmapped())
				append(" = " + COMPONENT_FIELD + "." + RuntimeApi.VALUE + "(");
			write(d, dataUseVariables);
			if (isUnmapped())
				append(")");
//			append(HELPER_FIELD + ".clone(" + getElementName(((VariableUse) d).getVariable()) + ")");

		}
@@ -2729,6 +2747,18 @@ public class JUnitTestGenerator extends Renderer {
			DataUse idx = ref.getCollectionIndex();
			Member prop = ref.getMember();

			if (isUnmapped()) {
				// Navigate the Value tree: each step yields Data again
				if (prop != null)
					append(".getValue().getParameter(\"" + escape(prop.getName()) + "\")");
				if (idx != null) {
					append(".getValue().getItems().get(");
					writeInteger(idx, dataUseVariables);
					append(")");
				}
				continue;
			}

			if (prop != null) {
				ParameterMapping pm = getParameterMapping(prop);

@@ -2779,6 +2809,29 @@ public class JUnitTestGenerator extends Renderer {
		}
	}

	/**
	 * Writes a data use where the engine needs a Java boolean (conditions): in
	 * unmapped mode the Data value is unwrapped.
	 */
	private void writeCondition(DataUse d, Map<DataUse, String> dataUseVariables) {
		writeUnwrapped(RuntimeApi.IS_TRUE, d, dataUseVariables);
	}

	/**
	 * Writes a data use where the engine needs a Java int (counts).
	 */
	private void writeInteger(DataUse d, Map<DataUse, String> dataUseVariables) {
		writeUnwrapped(RuntimeApi.INTEGER, d, dataUseVariables);
	}

	private void writeUnwrapped(String helper, DataUse d, Map<DataUse, String> dataUseVariables) {
		if (isUnmapped())
			append(COMPONENT_FIELD + "." + helper + "(");
		write(d, dataUseVariables);
		if (isUnmapped())
			append(")");
	}

	private void convertToData(DataUse d, Map<DataUse, String> dataUseVariables) {
		String templateRef = getTemplateVariable(d, dataUseVariables);

@@ -2818,6 +2871,22 @@ public class JUnitTestGenerator extends Renderer {
		append(")");
	}

	/**
	 * Whether a predefined function is generic: it operates on {@code Data} in
	 * both mapped and unmapped mode (see {@code PredefinedFunctions}) and returns
	 * a Java primitive, so its result is wrapped in unmapped mode.
	 */
	private boolean isGenericPredefinedFunction(PredefinedFunction f) {
		switch (f.getName()) {
		case "==":
		case "!=":
		case "size":
			return true;
		default:
			return false;
		}
	}

	private String getPredefinedFunction(PredefinedFunction f) {
		switch (f.getName()) {
		case "==":
@@ -2854,10 +2923,17 @@ public class JUnitTestGenerator extends Renderer {
		case "<=":
		case ">=":
			return "boolean";
		case "and":
		case "or":
		case "xor":
		case "not":
			return "boolean";
		case "+":
		case "-":
		case "*":
		case "/":
		case "mod":
		case "size":
			return "integer";
		default:
			throw new RuntimeException("Unknown predefined function in type resolution.");
+105 −0
Original line number Diff line number Diff line
@@ -141,6 +141,111 @@ public class PredefinedFunctionsImpl implements PredefinedFunctions {
		return i0 % i1;
	}

	/**
	 * The primitive held by data: the value of a {@link Value} (unmapped data) or
	 * the value itself (mapped primitive data).
	 */
	private static Object primitive(Data<?, ?> d) {
		Object v = d != null ? d.getValue() : null;
		if (v instanceof Value)
			v = ((Value) v).getValue();
		return v;
	}

	private static long number(Data<?, ?> d) {
		Object v = primitive(d);
		if (v instanceof Number)
			return ((Number) v).longValue();
		throw new IllegalArgumentException("Not a number: " + v);
	}

	private static boolean bool(Data<?, ?> d) {
		Object v = primitive(d);
		if (v instanceof Boolean)
			return (Boolean) v;
		throw new IllegalArgumentException("Not a boolean: " + v);
	}

	/**
	 * Wraps an arithmetic result as data of the operands' type - an int if both
	 * operands were ints, a long otherwise.
	 */
	private static Data<?, ?> result(Data<?, ?> d0, Data<?, ?> d1, long value) {
		boolean ints = primitive(d0) instanceof Integer && primitive(d1) instanceof Integer;
		Object type = d0 != null ? d0.getType() : null;
		ValueImpl v = type instanceof TypeImpl ? new ValueImpl((TypeImpl) type) : new ValueImpl();
		return v.setValue(ints ? (Object) (int) value : (Object) value).asData();
	}

	private static Data<?, ?> result(boolean value) {
		return new ValueImpl().setValue(value).asData();
	}

	@Override
	public Data<?, ?> lt(Data<?, ?> d0, Data<?, ?> d1) {
		return result(number(d0) < number(d1));
	}

	@Override
	public Data<?, ?> gt(Data<?, ?> d0, Data<?, ?> d1) {
		return result(number(d0) > number(d1));
	}

	@Override
	public Data<?, ?> lteq(Data<?, ?> d0, Data<?, ?> d1) {
		return result(number(d0) <= number(d1));
	}

	@Override
	public Data<?, ?> gteq(Data<?, ?> d0, Data<?, ?> d1) {
		return result(number(d0) >= number(d1));
	}

	@Override
	public Data<?, ?> and(Data<?, ?> d0, Data<?, ?> d1) {
		return result(bool(d0) && bool(d1));
	}

	@Override
	public Data<?, ?> or(Data<?, ?> d0, Data<?, ?> d1) {
		return result(bool(d0) || bool(d1));
	}

	@Override
	public Data<?, ?> xor(Data<?, ?> d0, Data<?, ?> d1) {
		return result(bool(d0) ^ bool(d1));
	}

	@Override
	public Data<?, ?> not(Data<?, ?> d) {
		return result(!bool(d));
	}

	@Override
	public Data<?, ?> plus(Data<?, ?> d0, Data<?, ?> d1) {
		return result(d0, d1, number(d0) + number(d1));
	}

	@Override
	public Data<?, ?> minus(Data<?, ?> d0, Data<?, ?> d1) {
		return result(d0, d1, number(d0) - number(d1));
	}

	@Override
	public Data<?, ?> multiply(Data<?, ?> d0, Data<?, ?> d1) {
		return result(d0, d1, number(d0) * number(d1));
	}

	@Override
	public Data<?, ?> divide(Data<?, ?> d0, Data<?, ?> d1) {
		return result(d0, d1, number(d0) / number(d1));
	}

	@Override
	public Data<?, ?> mod(Data<?, ?> d0, Data<?, ?> d1) {
		return result(d0, d1, number(d0) % number(d1));
	}

	@Override
	public int size(Data<?, ?> collection) {
		Object v = collection.getValue();
+44 −1
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ import org.etsi.mts.tdl.execution.java.tri.Argument;
import org.etsi.mts.tdl.execution.java.tri.ComponentInstanceRole;
import org.etsi.mts.tdl.execution.java.tri.Connection;
import org.etsi.mts.tdl.execution.java.tri.Data;
import org.etsi.mts.tdl.execution.java.tri.Element;
import org.etsi.mts.tdl.execution.java.tri.GateReference;
import org.etsi.mts.tdl.execution.java.tri.NamedElement;
import org.etsi.mts.tdl.execution.java.tri.PredefinedFunctions;
@@ -27,6 +26,7 @@ import org.etsi.mts.tdl.execution.java.tri.Reporter;
import org.etsi.mts.tdl.execution.java.tri.StopException;
import org.etsi.mts.tdl.execution.java.tri.SystemAdapter;
import org.etsi.mts.tdl.execution.java.tri.Validator;
import org.etsi.mts.tdl.execution.java.tri.Value;

import com.google.inject.Guice;
import com.google.inject.Injector;
@@ -481,6 +481,49 @@ public class TestControl {
		return sleep(period * 1000);
	}

	// Unmapped data helpers used by generated code

	/**
	 * The primitive held by data (see {@link Value#getValue()}), or the value
	 * itself for mapped primitive data.
	 */
	private static Object primitive(Data<?, ?> d) {
		Object v = d != null ? d.getValue() : null;
		if (v instanceof Value)
			v = ((Value) v).getValue();
		return v;
	}

	@GeneratedCodeApi
	public boolean isTrue(Data<?, ?> condition) {
		Object v = primitive(condition);
		if (v instanceof Boolean)
			return (Boolean) v;
		throw new IllegalArgumentException("Not a boolean value: " + v);
	}

	@GeneratedCodeApi
	public int integer(Data<?, ?> number) {
		Object v = primitive(number);
		if (v instanceof Number)
			return ((Number) v).intValue();
		throw new IllegalArgumentException("Not an integer value: " + v);
	}

	/**
	 * The value of unmapped data as produced by generated code and unmapped
	 * functions (see {@link ValueImpl#asData()}), to store it in a variable.
	 */
	@GeneratedCodeApi
	public ValueImpl value(Data<?, ?> data) {
		if (data == null)
			return null;
		Object v = data.getValue();
		if (v instanceof ValueImpl)
			return (ValueImpl) v;
		throw new IllegalArgumentException("Unmapped data is expected to hold a ValueImpl, got: " + v);
	}

	@GeneratedCodeApi
	public ExecutionCallable receive(Data expected, Connection connection) {
		return receive(expected, connection, false);
+39 −3
Original line number Diff line number Diff line
package org.etsi.mts.tdl.execution.java.tri;

/**
 * The predefined functions, in two families of overloads:
 * <ul>
 * <li><b>Mapped data</b>: operands and results are Java primitives
 * (<code>boolean</code>, <code>int</code>, <code>long</code>).</li>
 * <li><b>Unmapped data</b>: operands and results are {@link Data} holding
 * primitive {@link Value}s. Comparisons and logical operations yield boolean
 * Data, arithmetic Data of the operands' type.</li>
 * </ul>
 * The <i>generic</i> functions <code>equals</code>, <code>notEquals</code> and
 * <code>size</code> take {@link Data} in both modes (they operate on whole
 * values) and return Java primitives.
 */
public interface PredefinedFunctions {

	boolean equals(Data<?, ?> d0, Data<?, ?> d1);
@@ -50,9 +63,32 @@ public interface PredefinedFunctions {

	long mod(long i0, long i1);

	/**
	 * @param collection An object that a CollectionDataInstance is mapped to.
	 */
	int size(Data<?, ?> collection);

	Data<?, ?> lt(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> gt(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> lteq(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> gteq(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> and(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> or(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> xor(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> not(Data<?, ?> d);

	Data<?, ?> plus(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> minus(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> multiply(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> divide(Data<?, ?> d0, Data<?, ?> d1);

	Data<?, ?> mod(Data<?, ?> d0, Data<?, ?> d1);

}
 No newline at end of file