Search in sources :

Example 1 with Model

use of org.lflang.lf.Model in project lingua-franca by lf-lang.

the class GeneratorBase method doGenerate.

/**
 * Generate code from the Lingua Franca model contained by the specified resource.
 *
 * This is the main entry point for code generation. This base class finds all
 * reactor class definitions, including any reactors defined in imported .lf files
 * (except any main reactors in those imported files), and adds them to the
 * {@link #GeneratorBase.reactors reactors} list. If errors occur during
 * generation, then a subsequent call to errorsOccurred() will return true.
 * @param resource The resource containing the source code.
 * @param context Context relating to invocation of the code generator.
 * In stand alone mode, this object is also used to relay CLI arguments.
 */
public void doGenerate(Resource resource, LFGeneratorContext context) {
    GeneratorUtils.setTargetConfig(context, GeneratorUtils.findTarget(fileConfig.resource), targetConfig, errorReporter);
    cleanIfNeeded(context);
    printInfo(context.getMode());
    // Markers mark problems in the Eclipse IDE when running in integrated mode.
    if (errorReporter instanceof EclipseErrorReporter) {
        ((EclipseErrorReporter) errorReporter).clearMarkers();
    }
    ASTUtils.setMainName(fileConfig.resource, fileConfig.name);
    createMainInstantiation();
    // Check if there are any conflicting main reactors elsewhere in the package.
    if (Objects.equal(context.getMode(), LFGeneratorContext.Mode.STANDALONE) && mainDef != null) {
        for (String conflict : new MainConflictChecker(fileConfig).conflicts) {
            errorReporter.reportError(this.mainDef.getReactorClass(), "Conflicting main reactor in " + conflict);
        }
    }
    // Configure the command factory
    commandFactory.setVerbose();
    if (Objects.equal(context.getMode(), LFGeneratorContext.Mode.STANDALONE) && context.getArgs().containsKey("quiet")) {
        commandFactory.setQuiet();
    }
    // This must be done before desugaring delays below.
    analyzeFederates(context);
    // Process target files. Copy each of them into the src-gen dir.
    // FIXME: Should we do this here? This doesn't make sense for federates the way it is
    // done here.
    copyUserFiles(this.targetConfig, this.fileConfig);
    // Collect reactors and create an instantiation graph.
    // These are needed to figure out which resources we need
    // to validate, which happens in setResources().
    setReactorsAndInstantiationGraph(context.getMode());
    GeneratorUtils.validate(context, fileConfig, instantiationGraph, errorReporter);
    List<Resource> allResources = GeneratorUtils.getResources(reactors);
    resources.addAll(// FIXME: This filter reproduces the behavior of the method it replaces. But why must it be so complicated? Why are we worried about weird corner cases like this?
    allResources.stream().filter(it -> !Objects.equal(it, fileConfig.resource) || mainDef != null && it == mainDef.getReactorClass().eResource()).map(it -> GeneratorUtils.getLFResource(it, fileConfig.getSrcGenBasePath(), context, errorReporter)).collect(Collectors.toList()));
    GeneratorUtils.accommodatePhysicalActionsIfPresent(allResources, getTarget().setsKeepAliveOptionAutomatically(), targetConfig, errorReporter);
    // FIXME: Should the GeneratorBase pull in `files` from imported
    // resources?
    // Reroute connections that have delays associated with them via
    // generated delay reactors.
    transformDelays();
    // Transform connections that reside in mutually exclusive modes and are otherwise conflicting
    // This should be done before creating the instantiation graph
    transformConflictingConnectionsInModalReactors();
    // Invoke these functions a second time because transformations
    // may have introduced new reactors!
    setReactorsAndInstantiationGraph(context.getMode());
    // Check for existence and support of modes
    hasModalReactors = IterableExtensions.exists(reactors, it -> !it.getModes().isEmpty());
    checkModalReactorSupport(false);
    enableSupportForSerializationIfApplicable(context.getCancelIndicator());
}
Also used : SupportedSerializers(org.lflang.federated.serialization.SupportedSerializers) Delay(org.lflang.lf.Delay) FedASTUtils(org.lflang.federated.FedASTUtils) Action(org.lflang.lf.Action) InferredType(org.lflang.InferredType) Matcher(java.util.regex.Matcher) Map(java.util.Map) Instantiation(org.lflang.lf.Instantiation) Objects(com.google.common.base.Objects) Path(java.nio.file.Path) Connection(org.lflang.lf.Connection) MainConflictChecker(org.lflang.MainConflictChecker) TargetConfig(org.lflang.TargetConfig) Collection(java.util.Collection) Set(java.util.Set) EObject(org.eclipse.emf.ecore.EObject) Collectors(java.util.stream.Collectors) Parameter(org.lflang.lf.Parameter) List(java.util.List) Value(org.lflang.lf.Value) CollectionLiterals(org.eclipse.xtext.xbase.lib.CollectionLiterals) Target(org.lflang.Target) Resource(org.eclipse.emf.ecore.resource.Resource) Pattern(java.util.regex.Pattern) Pair(org.eclipse.xtext.xbase.lib.Pair) FileConfig(org.lflang.FileConfig) ASTUtils(org.lflang.ASTUtils) FederateInstance(org.lflang.federated.FederateInstance) Iterables(com.google.common.collect.Iterables) LfFactory(org.lflang.lf.LfFactory) ErrorReporter(org.lflang.ErrorReporter) AbstractLFValidator(org.lflang.validation.AbstractLFValidator) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) CancelIndicator(org.eclipse.xtext.util.CancelIndicator) Reaction(org.lflang.lf.Reaction) TimeUnit(org.lflang.TimeUnit) TimeValue(org.lflang.TimeValue) LinkedHashSet(java.util.LinkedHashSet) IMarker(org.eclipse.core.resources.IMarker) InstantiationGraph(org.lflang.graph.InstantiationGraph) CoordinationType(org.lflang.TargetProperty.CoordinationType) Model(org.lflang.lf.Model) IOException(java.io.IOException) Time(org.lflang.lf.Time) File(java.io.File) IteratorExtensions(org.eclipse.xtext.xbase.lib.IteratorExtensions) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) Paths(java.nio.file.Paths) Reactor(org.lflang.lf.Reactor) VarRef(org.lflang.lf.VarRef) MainConflictChecker(org.lflang.MainConflictChecker) Resource(org.eclipse.emf.ecore.resource.Resource)

Example 2 with Model

use of org.lflang.lf.Model in project lingua-franca by lf-lang.

the class ModelInfo method update.

/**
 * Redo all analysis based on the given model.
 *
 * @param model the model to analyze.
 */
public void update(Model model, ErrorReporter reporter) {
    this.updated = true;
    this.model = model;
    this.instantiationGraph = new InstantiationGraph(model, true);
    if (this.instantiationGraph.getCycles().size() == 0) {
        List<ReactorInstance> topLevelReactorInstances = new LinkedList<>();
        var main = model.getReactors().stream().filter(it -> it.isMain() || it.isFederated()).findFirst();
        if (main.isPresent()) {
            var inst = new ReactorInstance(main.get(), reporter);
            topLevelReactorInstances.add(inst);
        } else {
            model.getReactors().forEach(it -> topLevelReactorInstances.add(new ReactorInstance(it, reporter)));
        }
        // don't store the graph into a field, only the cycles.
        for (ReactorInstance top : topLevelReactorInstances) {
            this.topologyCycles.addAll(top.getCycles());
        }
    }
    // may be null if the target is invalid
    var target = Target.forName(model.getTarget().getName()).orElse(null);
    // Perform C-specific traversals.
    if (target == Target.C) {
        this.collectOverflowingNodes();
    }
}
Also used : Model(org.lflang.lf.Model) Deadline(org.lflang.lf.Deadline) IteratorExtensions.toIterable(org.eclipse.xtext.xbase.lib.IteratorExtensions.toIterable) Set(java.util.Set) IterableExtensions.filter(org.eclipse.xtext.xbase.lib.IterableExtensions.filter) NamedInstance(org.lflang.generator.NamedInstance) STP(org.lflang.lf.STP) HashSet(java.util.HashSet) ReactorInstance(org.lflang.generator.ReactorInstance) Parameter(org.lflang.lf.Parameter) List(java.util.List) Reactor(org.lflang.lf.Reactor) Assignment(org.lflang.lf.Assignment) Instantiation(org.lflang.lf.Instantiation) LinkedList(java.util.LinkedList) LinkedHashSet(java.util.LinkedHashSet) InstantiationGraph(org.lflang.graph.InstantiationGraph) ReactorInstance(org.lflang.generator.ReactorInstance) InstantiationGraph(org.lflang.graph.InstantiationGraph) LinkedList(java.util.LinkedList)

Example 3 with Model

use of org.lflang.lf.Model in project lingua-franca by lf-lang.

the class LFSemanticHighlightingCalculator method provideHighlightingFor.

/**
 * {@inheritDoc}
 */
@Override
public void provideHighlightingFor(XtextResource resource, IHighlightedPositionAcceptor acceptor, CancelIndicator cancelIndicator) {
    if (resource == null || locator == null) {
        return;
    }
    IParseResult parseResult = resource.getParseResult();
    if (parseResult == null || parseResult.getRootASTElement() == null) {
        return;
    }
    Model model = (Model) parseResult.getRootASTElement();
    // Provide keyword highlighting for special mode transitions
    for (var reactor : model.getReactors()) {
        for (var reaction : ASTUtils.allReactions(reactor)) {
            for (var effect : reaction.getEffects()) {
                if (effect.getModifier() != null) {
                    if (ModeTransitionType.KEYWORDS.contains(effect.getModifier())) {
                        var pos = locator.getSignificantTextRegion(effect, LfPackage.eINSTANCE.getVarRef_Modifier(), 0);
                        if (pos != null) {
                            acceptor.addPosition(pos.getOffset(), pos.getLength(), HighlightingStyles.KEYWORD_ID);
                        }
                    }
                }
            }
        }
    }
}
Also used : Model(org.lflang.lf.Model) IParseResult(org.eclipse.xtext.parser.IParseResult)

Example 4 with Model

use of org.lflang.lf.Model in project lingua-franca by lf-lang.

the class LinguaFrancaValidationTest method checkTargetProperties.

/**
 * Perform checks on target properties.
 */
@Test
public void checkTargetProperties() throws Exception {
    for (TargetProperty prop : TargetProperty.getOptions()) {
        if (prop == TargetProperty.CARGO_DEPENDENCIES) {
            // we test that separately as it has better error messages
            return;
        }
        System.out.println(String.format("Testing target property %s which is %s", prop, prop.type));
        System.out.println("====");
        System.out.println("Known good assignments:");
        List<String> knownCorrect = synthesizeExamples(prop.type, true);
        for (String it : knownCorrect) {
            Model model = createModel(prop, it);
            validator.assertNoErrors(model);
            // Also make sure warnings are produced when files are not present.
            if (prop.type == PrimitiveType.FILE) {
                validator.assertWarning(model, LfPackage.eINSTANCE.getKeyValuePair(), null, String.format("Could not find file: '%s'.", withoutQuotes(it)));
            }
        }
        // Extra checks for filenames. (This piece of code was commented out in the original xtend file)
        // Temporarily disabled because we need a more sophisticated check that looks for files in different places.
        // if (prop.type == prop.type == ArrayType.FILE_ARRAY ||
        // prop.type == UnionType.FILE_OR_FILE_ARRAY) {
        // val model = prop.createModel(
        // synthesizeExamples(ArrayType.FILE_ARRAY, true).get(0))
        // primitiveTypeToKnownGood.get(PrimitiveType.FILE).forEach [
        // model.assertWarning(
        // LfPackage.eINSTANCE.keyValuePair,
        // null, '''Could not find file: '«it.withoutQuotes»'.''')
        // ]
        // }
        System.out.println("Known bad assignments:");
        List<String> knownIncorrect = synthesizeExamples(prop.type, false);
        if (!(knownIncorrect == null || knownIncorrect.isEmpty())) {
            for (String it : knownIncorrect) {
                validator.assertError(createModel(prop, it), LfPackage.eINSTANCE.getKeyValuePair(), null, String.format("Target property '%s' is required to be %s.", prop.toString(), prop.type));
            }
        } else {
            // No type was synthesized. It must be a composite type.
            List<List<Object>> list = compositeTypeToKnownBad.get(prop.type);
            if (list == null) {
                System.out.println(String.format("No known incorrect values provided for target property '%s'. Aborting test.", prop));
                Assertions.assertTrue(false);
            } else {
                for (List<Object> it : list) {
                    validator.assertError(createModel(prop, it.get(0).toString()), LfPackage.eINSTANCE.getKeyValuePair(), null, String.format("Target property '%s%s' is required to be %s.", prop.toString(), it.get(1), it.get(2)));
                }
            }
        }
        System.out.println("====");
    }
    System.out.println("Done!");
}
Also used : Model(org.lflang.lf.Model) TargetProperty(org.lflang.TargetProperty) LinkedList(java.util.LinkedList) List(java.util.List) Test(org.junit.jupiter.api.Test)

Example 5 with Model

use of org.lflang.lf.Model in project lingua-franca by lf-lang.

the class LinguaFrancaValidationTest method recognizeHostNames.

/**
 * Recognize valid host names and fully qualified names, report invalid ones.
 */
@Test
public void recognizeHostNames() throws Exception {
    // FIXME: add more
    List<String> correct = List.of("localhost");
    // FIXME: add more
    List<String> validationError = List.of("x.y.z");
    // FIXME: add more
    List<String> parseError = List.of("..xyz");
    // Correct names.
    for (String addr : correct) {
        // Java 17:
        // String testCase = """
        // target C;
        // reactor Y {}
        // federated reactor X at foo@%s:4242 {
        // y = new Y() at %s:2424;
        // }
        // """.formatted(addr, addr);
        // Java 11:
        parseWithoutError(String.join(System.getProperty("line.separator"), "target C;", "reactor Y {}", String.format("federated reactor X at foo@%s:4242 {", addr), String.format("    y = new Y() at %s:2424; ", addr), "}"));
    }
    // Names that don't parse.
    for (String addr : parseError) {
        // Java 17:
        // String testCase = """
        // target C;
        // reactor Y {}
        // federated reactor X at foo@%s:4242 {
        // y = new Y() at %s:2424;
        // }
        // """.formatted(addr, addr);
        // Java 11:
        parseWithError(String.join(System.getProperty("line.separator"), "target C;", "reactor Y {}", String.format("federated reactor X at foo@%s:4242 {", addr), String.format("    y = new Y() at %s:2424; ", addr), "}"));
    }
    // Names that parse but are invalid.
    for (String addr : validationError) {
        // Java 17:
        // String testCase = """
        // target C;
        // reactor Y {}
        // federated reactor X at foo@%s:4242 {
        // y = new Y() at %s:2424;
        // }
        // """.formatted(addr, addr);
        // Java 11:
        Model model = parseWithoutError(String.join(System.getProperty("line.separator"), "target C;", "reactor Y {}", String.format("federated reactor X at foo@%s:4242 {", addr), String.format("    y = new Y() at %s:2424; ", addr), "}"));
        validator.assertWarning(model, LfPackage.eINSTANCE.getHost(), null, "Invalid host name or fully qualified domain name.");
    }
}
Also used : Model(org.lflang.lf.Model) Test(org.junit.jupiter.api.Test)

Aggregations

Model (org.lflang.lf.Model)30 Test (org.junit.jupiter.api.Test)20 Reactor (org.lflang.lf.Reactor)5 EObject (org.eclipse.emf.ecore.EObject)4 HashSet (java.util.HashSet)3 LinkedHashSet (java.util.LinkedHashSet)3 List (java.util.List)3 Instantiation (org.lflang.lf.Instantiation)3 Parameter (org.lflang.lf.Parameter)3 IOException (java.io.IOException)2 Path (java.nio.file.Path)2 ArrayList (java.util.ArrayList)2 LinkedList (java.util.LinkedList)2 Set (java.util.Set)2 Resource (org.eclipse.emf.ecore.resource.Resource)2 DefaultErrorReporter (org.lflang.DefaultErrorReporter)2 InstantiationGraph (org.lflang.graph.InstantiationGraph)2 Import (org.lflang.lf.Import)2 Objects (com.google.common.base.Objects)1 Iterables (com.google.common.collect.Iterables)1