use of org.lflang.generator.InvalidSourceException in project lingua-franca by lf-lang.
the class ASTUtils method inferPortWidth.
/**
* Infer the width of a port reference in a connection.
* The port reference one or two parts, a port and an (optional) container
* which is an Instantiation that may refer to a bank of reactors.
* The width will be the product of the bank width and the port width.
* The returned value will be 1 if the port is not in a bank and is not a multiport.
*
* If the width cannot be determined, this will return -1.
* The width cannot be determined if the list of instantiations is
* missing or incomplete.
*
* The instantiations list is as in
* {@link initialValue(Parameter, List<Instantiation>}.
* The first element on this list should be the instantiation
* that contains the specified connection.
*
* @param reference A port reference.
* @param connection A connection, or null if not in the context of a connection.
* @param instantiations The (optional) list of instantiations.
*
* @return The width or -1 if it could not be determined.
*
* @throws IllegalArgumentException If an instantiation provided is not as
* given above or if the chain of instantiations is not nested.
*/
public static int inferPortWidth(VarRef reference, Connection connection, List<Instantiation> instantiations) {
if (reference.getVariable() instanceof Port) {
// If the port is given as a.b, then we want to prepend a to
// the list of instantiations to determine the width of this port.
List<Instantiation> extended = instantiations;
if (reference.getContainer() != null) {
extended = new ArrayList<>();
extended.add(reference.getContainer());
if (instantiations != null) {
extended.addAll(instantiations);
}
}
int portWidth = width(((Port) reference.getVariable()).getWidthSpec(), extended);
if (portWidth < 0) {
// Could not determine port width.
return -1;
}
// Next determine the bank width. This may be unspecified, in which
// case it has to be inferred using the connection.
int bankWidth = 1;
if (reference.getContainer() != null) {
bankWidth = width(reference.getContainer().getWidthSpec(), instantiations);
if (bankWidth < 0 && connection != null) {
// Try to infer the bank width from the connection.
if (reference.getContainer().getWidthSpec().isOfVariableLength()) {
// This occurs for a bank of delays.
int leftWidth = 0;
int rightWidth = 0;
int leftOrRight = 0;
for (VarRef leftPort : connection.getLeftPorts()) {
if (leftPort == reference) {
if (leftOrRight != 0) {
throw new InvalidSourceException("Multiple ports with variable width on a connection.");
}
// Indicate that this port is on the left.
leftOrRight = -1;
} else {
// The left port is not the same as this reference.
int otherWidth = inferPortWidth(leftPort, connection, instantiations);
if (otherWidth < 0) {
// Cannot determine width.
return -1;
}
leftWidth += otherWidth;
}
}
for (VarRef rightPort : connection.getRightPorts()) {
if (rightPort == reference) {
if (leftOrRight != 0) {
throw new InvalidSourceException("Multiple ports with variable width on a connection.");
}
// Indicate that this port is on the right.
leftOrRight = 1;
} else {
int otherWidth = inferPortWidth(rightPort, connection, instantiations);
if (otherWidth < 0) {
// Cannot determine width.
return -1;
}
rightWidth += otherWidth;
}
}
int discrepancy = 0;
if (leftOrRight < 0) {
// This port is on the left.
discrepancy = rightWidth - leftWidth;
} else if (leftOrRight > 0) {
// This port is on the right.
discrepancy = leftWidth - rightWidth;
}
// Check that portWidth divides the discrepancy.
if (discrepancy % portWidth != 0) {
// This is an error.
return -1;
}
bankWidth = discrepancy / portWidth;
} else {
// Could not determine the bank width.
return -1;
}
}
}
return portWidth * bankWidth;
}
// Argument is not a port.
return -1;
}
use of org.lflang.generator.InvalidSourceException in project lingua-franca by lf-lang.
the class ASTUtils method width.
/**
* Given the width specification of port or instantiation
* and an (optional) list of nested instantiations, return
* the width if it can be determined and -1 if not.
* It will not be able to be determined if either the
* width is variable (in which case you should use
* {@link inferPortWidth(VarRef, Connection, List<Instantiation>})
* or the list of instantiations is incomplete or missing.
* If there are parameter references in the width, they are
* evaluated to the extent possible given the instantiations list.
*
* The instantiations list is as in
* {@link initialValue(Parameter, List<Instantiation>)}.
* If the spec belongs to an instantiation (for a bank of reactors),
* then the first element on this list should be the instantiation
* that contains this instantiation. If the spec belongs to a port,
* then the first element on the list should be the instantiation
* of the reactor that contains the port.
*
* @param spec The width specification or null (to return 1).
* @param instantiations The (optional) list of instantiations.
*
* @return The width, or -1 if the width could not be determined.
*
* @throws IllegalArgumentException If an instantiation provided is not as
* given above or if the chain of instantiations is not nested.
*/
public static int width(WidthSpec spec, List<Instantiation> instantiations) {
if (spec == null) {
return 1;
}
if (spec.isOfVariableLength() && spec.eContainer() instanceof Instantiation) {
// Attempt to infer the width.
for (Connection c : ((Reactor) spec.eContainer().eContainer()).getConnections()) {
int leftWidth = 0;
int rightWidth = 0;
int leftOrRight = 0;
for (VarRef leftPort : c.getLeftPorts()) {
if (leftPort.getContainer() == spec.eContainer()) {
if (leftOrRight != 0) {
throw new InvalidSourceException("Multiple ports with variable width on a connection.");
}
// Indicate that the port is on the left.
leftOrRight = -1;
} else {
leftWidth += inferPortWidth(leftPort, c, instantiations);
}
}
for (VarRef rightPort : c.getRightPorts()) {
if (rightPort.getContainer() == spec.eContainer()) {
if (leftOrRight != 0) {
throw new InvalidSourceException("Multiple ports with variable width on a connection.");
}
// Indicate that the port is on the right.
leftOrRight = 1;
} else {
rightWidth += inferPortWidth(rightPort, c, instantiations);
}
}
if (leftOrRight < 0) {
return rightWidth - leftWidth;
} else if (leftOrRight > 0) {
return leftWidth - rightWidth;
}
}
// A connection was not found with the instantiation.
return -1;
}
var result = 0;
for (WidthTerm term : spec.getTerms()) {
if (term.getParameter() != null) {
Integer termWidth = initialValueInt(term.getParameter(), instantiations);
if (termWidth != null) {
result += termWidth;
} else {
return -1;
}
} else if (term.getWidth() > 0) {
result += term.getWidth();
} else {
return -1;
}
}
return result;
}
Aggregations