Search in sources :

Example 1 with InvalidSourceException

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;
}
Also used : VarRef(org.lflang.lf.VarRef) InvalidSourceException(org.lflang.generator.InvalidSourceException) Port(org.lflang.lf.Port) Instantiation(org.lflang.lf.Instantiation)

Example 2 with InvalidSourceException

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;
}
Also used : VarRef(org.lflang.lf.VarRef) InvalidSourceException(org.lflang.generator.InvalidSourceException) Connection(org.lflang.lf.Connection) Instantiation(org.lflang.lf.Instantiation) ImportedReactor(org.lflang.lf.ImportedReactor) Reactor(org.lflang.lf.Reactor) WidthTerm(org.lflang.lf.WidthTerm)

Aggregations

InvalidSourceException (org.lflang.generator.InvalidSourceException)2 Instantiation (org.lflang.lf.Instantiation)2 VarRef (org.lflang.lf.VarRef)2 Connection (org.lflang.lf.Connection)1 ImportedReactor (org.lflang.lf.ImportedReactor)1 Port (org.lflang.lf.Port)1 Reactor (org.lflang.lf.Reactor)1 WidthTerm (org.lflang.lf.WidthTerm)1