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());
}
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();
}
}
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);
}
}
}
}
}
}
}
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!");
}
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.");
}
}
Aggregations