/* * Copyright 2003-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.generator; import jetbrains.mps.generator.impl.RuleManager; import jetbrains.mps.generator.impl.TemplateSwitchGraph; import jetbrains.mps.generator.plan.CheckpointIdentity; import jetbrains.mps.generator.runtime.TemplateMappingConfiguration; import jetbrains.mps.generator.runtime.TemplateModel; import jetbrains.mps.generator.runtime.TemplateModule; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.language.SLanguage; import org.jetbrains.mps.openapi.model.SModel; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; /** * Is it a final breakdown of shall I treat list of TMC as a raw input and re-order them as appropriate? * evgeny, 1/12/12 */ public interface ModelGenerationPlan { List<Step> getSteps(); Collection<TemplateModule> getGenerators(); // PROVISIONAL, for migration purposes here. // Seems to be bad design - if we allow external plans (with partial generation), then // we shall leave it up to caller to decide whether to report errors about unexpected languages in an output model // Besides, even if language is 'covered', nothing tells it is 'yet to get processed' one, not the one 'already processed' // (so/ output nodes in that language still make no sense). Perhaps, could be part of Step, and each Step knows // what languages are to come down the road? // Shall drop, but first need to replace with a mechanism that collects all languages that emerge during generation boolean coversLanguage(SLanguage language); /* * Give a chance for a plan implementation to accommodate to actual input being transformed. Plans are inherently read-only, * so to give an input-specific plan, one need to make a copy of a template and augment it. * <p/> * Invoked once per each processed {@linkplain GeneratorTask generation task} prior to any step. * * @return An instance of the plan modified according to languages present in the task, or {@code this} if this * plan doesn't depend on transformed input. */ // @NotNull // default ModelGenerationPlan prepare(@NotNull GeneratorTask task) { // return this; // } interface Step { // e.g. to print MCs that take part, if Transform step populates objects rather than return list of MC // String describe(); } final class Checkpoint implements Step { private final boolean mySynchOnly; private final CheckpointIdentity myIdentity; public Checkpoint(@NotNull CheckpointIdentity cpIdentity) { this(cpIdentity, false); } public Checkpoint(@NotNull CheckpointIdentity cpIdentity, boolean synchOnly) { mySynchOnly = synchOnly; myIdentity = cpIdentity; } public String getName() { // FIXME I'm not sure I shall keep this method at all. Is it describe(), merely to present GP to user? return myIdentity.getName(); } public CheckpointIdentity getIdentity() { return myIdentity; } /** * @return {@code true} if model state at this checkpoint is to be saved into a storage, {@code false} means this checkpoint is for * synchronization with other models only. */ public boolean isPersisted() { return !mySynchOnly; } } final class Transform implements Step { private final TemplateMappingConfiguration[] myMapCfg; public Transform(@NotNull Collection<TemplateMappingConfiguration> tmc) { myMapCfg = tmc.toArray(new TemplateMappingConfiguration[tmc.size()]); } @NotNull public List<TemplateMappingConfiguration> getTransformations() { return Arrays.asList(myMapCfg); } // Do I need this? public List<TemplateModel> getTemplateModels() { ArrayList<TemplateModel> rv = new ArrayList<TemplateModel>(myMapCfg.length); // generally, there are very few distinct template models per step, don't care about performance here for (TemplateMappingConfiguration mc : myMapCfg) { if (!rv.contains(mc.getModel())) { rv.add(mc.getModel()); } } return rv; } // alternatively, why not to give control over rule/switch manager to the step? // i.e. to avoid extra iface to hold both TMC and nested plan. // XXX need to drop !TMC.isApplicable and report these RuleManager getRuleManager() { return null; } void fill(RuleManager ruleManager) { } TemplateSwitchGraph getSwitchGraph() { return null; } } /** * Marker to indicate source capable to supply ModelGenerationPlan for a model */ interface Provider { /** * @param model what we need plan for. * @return {@code null} if this provider could not give a plan for the model */ @Nullable ModelGenerationPlan getPlan(@NotNull SModel model); } }