/* * 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.impl.plan; import jetbrains.mps.generator.ModelGenerationPlan; import jetbrains.mps.generator.impl.plan.PriorityConflicts.Kind; import jetbrains.mps.generator.runtime.TemplateMappingConfiguration; import jetbrains.mps.generator.runtime.TemplateModel; import jetbrains.mps.generator.runtime.TemplateModule; import jetbrains.mps.util.NameUtil; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; 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.Collections; import java.util.LinkedList; import java.util.List; /** * Default/regular/legacy plan to generate a model based solely on a languaes * * To get extra information about picked generators, update bin/log.xml like that: * <pre> * <category name="jetbrains.mps.generator.impl.plan" additivity="false"> * <priority value="DEBUG"/> * <appender-ref ref="CONSOLE-DEBUG"/> * </category> * </pre> * @author Evgeny Gryaznov, Jan 18, 2010 * @author Artem Tikhomirov */ public class GenerationPlan implements ModelGenerationPlan { private static final Logger LOG = LogManager.getLogger(GenerationPlan.class); private final Collection<TemplateModule> myGenerators; private final Collection<TemplateModel> myTemplateModels; private final List<List<TemplateMappingConfiguration>> myPlan; private List<Step> mySteps; private final PriorityConflicts myConflictingPriorityRules; public GenerationPlan(@NotNull SModel inputModel) { this(inputModel, null); } public GenerationPlan(@NotNull SModel inputModel, @Nullable Collection<SLanguage> additionalLanguages) { try { EngagedGeneratorCollector c = new EngagedGeneratorCollector(inputModel, additionalLanguages); myGenerators = c.getGenerators(); if (LOG.isDebugEnabled()) { LOG.debug(">>>"); c.dump(LOG::debug); LOG.debug("<<<"); } GenerationPartitioner partitioner = new GenerationPartitioner(c.getGenerators()); myPlan = partitioner.createMappingSets(); if (myPlan.isEmpty()) { myPlan.add(Collections.<TemplateMappingConfiguration>emptyList()); } myConflictingPriorityRules = partitioner.getConflictingPriorityRules(); myTemplateModels = new ArrayList<TemplateModel>(); for (TemplateModule module : myGenerators) { myTemplateModels.addAll(module.getModels()); } } catch (Throwable t) { String msg = String.format("Couldn't compute generation steps for model '%s;", NameUtil.getModelLongName(inputModel)); LOG.error(msg, t); throw new RuntimeException(msg, t); } } @Override public List<Step> getSteps() { if (mySteps == null) { LinkedList<Step> steps = new LinkedList<Step>(); for (List<TemplateMappingConfiguration> p : myPlan) { steps.add(new Transform(p)); } // debug // steps.add(myPlan.size() / 3, new Checkpoint("first")); // steps.add(myPlan.size() / 3 * 2, new Checkpoint("second")); mySteps = Arrays.asList(steps.toArray(new Step[steps.size()])); } return mySteps; } public Collection<TemplateModule> getGenerators() { return myGenerators; } @Override public boolean coversLanguage(SLanguage language) { // return myLanguages.contains(language); // // disable checking temporarily: // when generating model jetbrains.mps.baseLanguage.closures.dataFlow, // type SetType (from collections lang) appears at some moment inside InternalStaticMethodCall node. // While language 'jetbrains.mps.baseLanguage.collections' wasn't detected when computing generation steps, // this is harmless for generation (because no text is generated for that node) // but it sets off the alarms in generator. // // todo: postpone the error reporting till text generation phase? // or // todo: in a very base text_gen class catch nodes which was not reduced (and has no text_gen) ? return true; } public boolean hasIgnoredPriorityRules() { return !myConflictingPriorityRules.get(Kind.Invalid).isEmpty(); } public List<Conflict> getIgnoredPriorityRules() { return new ArrayList<Conflict>(myConflictingPriorityRules.get(Kind.Invalid)); } public boolean hasConflictingPriorityRules() { return myConflictingPriorityRules.hasConflicts(deemedConflict()); } public List<Conflict> getConflicts() { return myConflictingPriorityRules.getConflicts(deemedConflict()); } private static Collection<Kind> deemedConflict() { ArrayList<Kind> deemedConflict = new ArrayList<Kind>(Arrays.asList(Kind.values())); deemedConflict.remove(Kind.Invalid); return deemedConflict; } }