use of org.lflang.FileConfig 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.FileConfig 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.FileConfig in project lingua-franca by lf-lang.
the class IntegratedBuilder method run.
/* ------------------------- PUBLIC METHODS -------------------------- */
/**
* Generates code from the Lingua Franca file {@code f}.
* @param uri The URI of a Lingua Franca file.
* @param mustComplete Whether the build must be taken to completion.
* @return The result of the build.
*/
public GeneratorResult run(URI uri, boolean mustComplete, ReportProgress reportProgress, CancelIndicator cancelIndicator) {
// FIXME: A refactoring of the following line is needed. This refactor will affect FileConfig and
// org.lflang.lfc.Main. The issue is that there is duplicated code.
fileAccess.setOutputPath(FileConfig.findPackageRoot(Path.of(uri.path()), s -> {
}).resolve(FileConfig.DEFAULT_SRC_GEN_DIR).toString());
List<EObject> parseRoots = getResource(uri).getContents();
if (parseRoots.isEmpty())
return GeneratorResult.NOTHING;
ErrorReporter errorReporter = new LanguageServerErrorReporter(parseRoots.get(0));
reportProgress.apply("Validating...", START_PERCENT_PROGRESS);
validate(uri, errorReporter);
reportProgress.apply("Code validation complete.", VALIDATED_PERCENT_PROGRESS);
if (cancelIndicator.isCanceled())
return GeneratorResult.CANCELLED;
if (errorReporter.getErrorsOccurred())
return GeneratorResult.FAILED;
reportProgress.apply("Generating code...", VALIDATED_PERCENT_PROGRESS);
return doGenerate(uri, mustComplete, reportProgress, cancelIndicator);
}
use of org.lflang.FileConfig in project lingua-franca by lf-lang.
the class TestBase method configure.
/**
* Configure a test by applying the given configurator and return a
* generator context. Also, if the given level is less than
* `TestLevel.BUILD`, add a `no-compile` flag to the generator context. If
* the configurator was not applied successfully, throw an AssertionError.
*
* @param test the test to configure.
* @param configurator The configurator to apply to the test.
* @param level The level of testing in which the generator context will be
* used.
* @return a generator context with a fresh resource, unaffected by any AST
* transformation that may have occured in other tests.
* @throws IOException if there is any file access problem
*/
private LFGeneratorContext configure(LFTest test, Configurator configurator, TestLevel level) throws IOException {
var context = new MainContext(LFGeneratorContext.Mode.STANDALONE, CancelIndicator.NullImpl, (m, p) -> {
}, new Properties(), true, fileConfig -> new DefaultErrorReporter());
var r = resourceSetProvider.get().getResource(URI.createFileURI(test.srcFile.toFile().getAbsolutePath()), true);
if (r.getErrors().size() > 0) {
test.result = Result.PARSE_FAIL;
throw new AssertionError("Test did not parse correctly.");
}
fileAccess.setOutputPath(FileConfig.findPackageRoot(test.srcFile, s -> {
}).resolve(FileConfig.DEFAULT_SRC_GEN_DIR).toString());
test.context = context;
test.fileConfig = new FileConfig(r, FileConfig.getSrcGenRoot(fileAccess), context.useHierarchicalBin());
// Set the no-compile flag the test is not supposed to reach the build stage.
if (level.compareTo(TestLevel.BUILD) < 0) {
context.getArgs().setProperty("no-compile", "");
}
addExtraLfcArgs(context.getArgs());
// Update the test by applying the configuration. E.g., to carry out an AST transformation.
if (configurator != null && !configurator.configure(test)) {
test.result = Result.CONFIG_FAIL;
throw new AssertionError("Test configuration unsuccessful.");
}
return context;
}
use of org.lflang.FileConfig in project lingua-franca by lf-lang.
the class GeneratorUtils method getLFResource.
/**
* Return the {@code LFResource} representation of the
* given resource.
* @param resource The {@code Resource} to be
* represented as an {@code LFResource}
* @param srcGenBasePath The root directory for any
* generated sources associated with the resource.
* @param context The generator invocation context.
* @param errorReporter An error message acceptor.
* @return the {@code LFResource} representation of the
* given resource.
*/
public static LFResource getLFResource(Resource resource, Path srcGenBasePath, LFGeneratorContext context, ErrorReporter errorReporter) {
TargetDecl target = GeneratorUtils.findTarget(resource);
KeyValuePairs config = target.getConfig();
var targetConfig = new TargetConfig();
if (config != null) {
List<KeyValuePair> pairs = config.getPairs();
TargetProperty.set(targetConfig, pairs != null ? pairs : List.of(), errorReporter);
}
try {
FileConfig fc = new FileConfig(resource, srcGenBasePath, context.useHierarchicalBin());
return new LFResource(resource, fc, targetConfig);
} catch (IOException e) {
throw new RuntimeException("Failed to instantiate an imported resource because an I/O error " + "occurred.");
}
}
Aggregations