use of org.lflang.Target 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());
}
use of org.lflang.Target in project lingua-franca by lf-lang.
the class LFGenerator method doGenerate.
@Override
public void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
final LFGeneratorContext lfContext = LFGeneratorContext.lfGeneratorContextOf(context, resource);
// The fastest way to generate code is to not generate any code.
if (lfContext.getMode() == LFGeneratorContext.Mode.LSP_FAST)
return;
final Target target = Target.fromDecl(ASTUtils.targetDecl(resource));
assert target != null;
FileConfig fileConfig;
try {
fileConfig = Objects.requireNonNull(createFileConfig(target, resource, fsa, lfContext));
} catch (IOException e) {
throw new RuntimeIOException("Error during FileConfig instantiation", e);
}
final ErrorReporter errorReporter = lfContext.constructErrorReporter(fileConfig);
final GeneratorBase generator = createGenerator(target, fileConfig, errorReporter);
if (generator != null) {
generator.doGenerate(resource, lfContext);
generatorErrorsOccurred = generator.errorsOccurred();
}
if (errorReporter instanceof LanguageServerErrorReporter) {
((LanguageServerErrorReporter) errorReporter).publishDiagnostics();
}
}
use of org.lflang.Target in project lingua-franca by lf-lang.
the class TestBase method runTestsFor.
/**
* Run tests in the given selection for a subset of given targets.
*
* @param subset The subset of targets to run the selected tests for.
* @param description A string that describes the collection of tests.
* @param selected A predicate that given a test category returns whether
* it should be included in this test run or not.
* @param configurator A procedure for configuring the tests.
* @param level The level of testing to be performed during this run.
* @param copy Whether to work on copies of tests in the test.
* registry.
*/
protected void runTestsFor(List<Target> subset, String description, Predicate<TestCategory> selected, Configurator configurator, TestLevel level, boolean copy) {
for (Target target : subset) {
printTestHeader(target, description);
runTestsAndPrintResults(target, selected, configurator, level, copy);
}
}
use of org.lflang.Target in project lingua-franca by lf-lang.
the class LinguaFrancaValidationTest method testPreambleVisibility.
/**
* Test warnings and errors for the target dependent preamble visibility qualifiers
*/
@Test
public void testPreambleVisibility() throws Exception {
for (Target target : Target.values()) {
for (Visibility visibility : Visibility.values()) {
// Java 17:
// Model model_reactor_scope = """
// target %s;
// reactor Foo {
// %spreamble {==}
// }
// """.formatted(target, visibility != java.beans.Visibility.NONE ? visibility + " " : "");
// Java 11:
Model model_reactor_scope = parseWithoutError(String.join(System.getProperty("line.separator"), String.format("target %s;", target), "reactor Foo {", String.format(" %spreamble {==}", visibility != Visibility.NONE ? visibility + " " : ""), "}"));
// Java 17:
// Model model_file_scope = """
// target %s;
// %spreamble {==}
// reactor Foo {
// }
// """.formatted(target, visibility != java.beans.Visibility.NONE ? visibility + " " : "");
// Java 11:
Model model_file_scope = parseWithoutError(String.join(System.getProperty("line.separator"), String.format("target %s;", target), String.format(" %spreamble {==}", visibility != Visibility.NONE ? visibility + " " : ""), "reactor Foo {", "}"));
// Java 17:
// Model model_no_preamble = """
// target %s;
// reactor Foo {
// }
// """.formatted(target);
// Java 11:
Model model_no_preamble = parseWithoutError(String.join(System.getProperty("line.separator"), String.format("target %s;", target), "reactor Foo {", "}"));
validator.assertNoIssues(model_no_preamble);
if (target == Target.CPP) {
if (visibility == Visibility.NONE) {
validator.assertError(model_file_scope, LfPackage.eINSTANCE.getPreamble(), null, "Preambles for the C++ target need a visibility qualifier (private or public)!");
validator.assertError(model_reactor_scope, LfPackage.eINSTANCE.getPreamble(), null, "Preambles for the C++ target need a visibility qualifier (private or public)!");
} else {
validator.assertNoIssues(model_file_scope);
validator.assertNoIssues(model_reactor_scope);
}
} else {
if (visibility == Visibility.NONE) {
validator.assertNoIssues(model_file_scope);
validator.assertNoIssues(model_reactor_scope);
} else {
validator.assertWarning(model_file_scope, LfPackage.eINSTANCE.getPreamble(), null, String.format("The %s qualifier has no meaning for the %s target. It should be removed.", visibility, target.name()));
validator.assertWarning(model_reactor_scope, LfPackage.eINSTANCE.getPreamble(), null, String.format("The %s qualifier has no meaning for the %s target. It should be removed.", visibility, target.name()));
}
}
}
}
}
use of org.lflang.Target in project lingua-franca by lf-lang.
the class RunSingleTestMain method main.
public static void main(String[] args) throws FileNotFoundException {
if (args.length != 1) {
throw new IllegalArgumentException("Expected 1 path to an LF file");
}
var path = Paths.get(args[0]);
if (!Files.exists(path)) {
throw new FileNotFoundException("No such test file: " + path);
}
Matcher matcher = TEST_FILE_PATTERN.matcher(args[0]);
if (!matcher.matches()) {
throw new FileNotFoundException("Not a test: " + path);
}
Target target = Target.forName(matcher.group(2)).get();
Class<? extends TestBase> testClass = getTestInstance(target);
LFTest testCase = new LFTest(target, path.toAbsolutePath());
TestBase.runSingleTestAndPrintResults(testCase, testClass, TestLevel.EXECUTION);
}
Aggregations