use of org.lflang.lf.Time 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.Time in project lingua-franca by lf-lang.
the class ASTUtils method getDelayClass.
/**
* Return a synthesized AST node that represents the definition of a delay
* reactor. Depending on whether the target supports generics, either this
* method will synthesize a generic definition and keep returning it upon
* subsequent calls, or otherwise, it will synthesize a new definition for
* each new type it hasn't yet created a compatible delay reactor for.
* @param type The type the delay class must be compatible with.
* @param generator A code generator.
*/
private static Reactor getDelayClass(Type type, GeneratorBase generator) {
String className;
if (generator.getTargetTypes().supportsGenerics()) {
className = GeneratorBase.GEN_DELAY_CLASS_NAME;
} else {
String id = Integer.toHexString(InferredType.fromAST(type).toText().hashCode());
className = String.format("%s_%s", GeneratorBase.GEN_DELAY_CLASS_NAME, id);
}
// Only add class definition if it is not already there.
Reactor classDef = generator.findDelayClass(className);
if ((classDef != null)) {
return classDef;
}
Reactor delayClass = factory.createReactor();
Parameter delayParameter = factory.createParameter();
Action action = factory.createAction();
VarRef triggerRef = factory.createVarRef();
VarRef effectRef = factory.createVarRef();
Input input = factory.createInput();
Output output = factory.createOutput();
VarRef inRef = factory.createVarRef();
VarRef outRef = factory.createVarRef();
Reaction r1 = factory.createReaction();
Reaction r2 = factory.createReaction();
delayParameter.setName("delay");
delayParameter.setType(factory.createType());
delayParameter.getType().setId("time");
delayParameter.getType().setTime(true);
Time defaultTime = factory.createTime();
defaultTime.setUnit(null);
defaultTime.setInterval(0);
Value defaultValue = factory.createValue();
defaultValue.setTime(defaultTime);
delayParameter.getInit().add(defaultValue);
// Name the newly created action; set its delay and type.
action.setName("act");
action.setMinDelay(factory.createValue());
action.getMinDelay().setParameter(delayParameter);
action.setOrigin(ActionOrigin.LOGICAL);
if (generator.getTargetTypes().supportsGenerics()) {
action.setType(factory.createType());
action.getType().setId("T");
} else {
action.setType(EcoreUtil.copy(type));
}
input.setName("inp");
input.setType(EcoreUtil.copy(action.getType()));
output.setName("out");
output.setType(EcoreUtil.copy(action.getType()));
// Establish references to the involved ports.
inRef.setVariable(input);
outRef.setVariable(output);
// Establish references to the action.
triggerRef.setVariable(action);
effectRef.setVariable(action);
// Add the action to the reactor.
delayClass.setName(className);
delayClass.getActions().add(action);
// Configure the second reaction, which reads the input.
r1.getTriggers().add(inRef);
r1.getEffects().add(effectRef);
r1.setCode(factory.createCode());
r1.getCode().setBody(generator.generateDelayBody(action, inRef));
// Configure the first reaction, which produces the output.
r2.getTriggers().add(triggerRef);
r2.getEffects().add(outRef);
r2.setCode(factory.createCode());
r2.getCode().setBody(generator.generateForwardBody(action, outRef));
// Add the reactions to the newly created reactor class.
// These need to go in the opposite order in case
// a new input arrives at the same time the delayed
// output is delivered!
delayClass.getReactions().add(r2);
delayClass.getReactions().add(r1);
// Add a type parameter if the target supports it.
if (generator.getTargetTypes().supportsGenerics()) {
TypeParm parm = factory.createTypeParm();
parm.setLiteral(generator.generateDelayGeneric());
delayClass.getTypeParms().add(parm);
}
delayClass.getInputs().add(input);
delayClass.getOutputs().add(output);
delayClass.getParameters().add(delayParameter);
generator.addDelayClass(delayClass);
return delayClass;
}
Aggregations