/* * 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; import jetbrains.mps.generator.impl.RoleValidation.RoleValidator; import jetbrains.mps.generator.impl.RoleValidation.Status; import jetbrains.mps.generator.runtime.GenerationException; import jetbrains.mps.generator.runtime.NodeWeaveFacility; import jetbrains.mps.generator.runtime.TemplateContext; import jetbrains.mps.generator.runtime.TemplateDeclaration; import jetbrains.mps.textgen.trace.TracingUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.mps.openapi.language.SContainmentLink; import org.jetbrains.mps.openapi.model.SNode; import org.jetbrains.mps.openapi.model.SNodeReference; import java.util.Collection; import java.util.Collections; import java.util.Iterator; /** * Weave support implementation * @author Artem Tikhomirov * @since 3.3 */ public final class NodeWeaveSupport implements NodeWeaveFacility { private final TemplateContext myTemplateContext; private final SNodeReference myTemplateNode; private final TemplateExecutionEnvironmentImpl myEnv; private final TemplateGenerator myGenerator; @NotNull private final WeaveContext myWeaveContext; public NodeWeaveSupport(@NotNull WeaveContext weaveContext, @NotNull SNodeReference templateNodeReference, @NotNull TemplateExecutionEnvironmentImpl env) { myWeaveContext = weaveContext; myTemplateContext = weaveContext.getTemplateContext(); myTemplateNode = templateNodeReference; myEnv = env; myGenerator = env.getGenerator(); } @NotNull @Override public TemplateContext getTemplateContext() { return myTemplateContext; } @Override public void weaveNode(@NotNull SContainmentLink childRole, @NotNull SNode outputNodeToWeave) throws GenerationFailureException { SNode contextParentNode = myWeaveContext.getContextNode(); SNode anchor = myWeaveContext.getAnchorNode(contextParentNode, outputNodeToWeave); assert anchor == null || anchor.getParent() == contextParentNode; TracingUtil.fillOriginalNode(myTemplateContext.getInput(), outputNodeToWeave, false); // check child RoleValidator v = myGenerator.getChildRoleValidator(contextParentNode, childRole); Status status = v.validate(outputNodeToWeave); if (status != null) { myGenerator.getLogger().warning(myTemplateNode, status.getMessage("weave node"), status.describe( GeneratorUtil.describeInput(myTemplateContext), GeneratorUtil.describe(contextParentNode, "context parent node"))); // spit out the warning, but try to add anyway // fall-through } else { if (!childRole.isMultiple()) { final Iterator<? extends SNode> children = contextParentNode.getChildren(childRole).iterator(); if (children.hasNext()) { // if singular child then don't add more that 1 child SNode singleChild = children.next(); contextParentNode.removeChild(singleChild); String msg = String.format("Attempt to weave a child into the role '%s' that doesn't accept multiple children and has child already set", childRole.getName()); myGenerator.getLogger().warning(myTemplateNode, msg, GeneratorUtil.describeInput(myTemplateContext), GeneratorUtil.describe(contextParentNode, "context parent node"), GeneratorUtil.describe(singleChild, "removed child"), GeneratorUtil.describeIfExists(outputNodeToWeave, "weaved node"), GeneratorUtil.describeIfExists(anchor, "anchor node")); } } } contextParentNode.insertChildBefore(childRole, outputNodeToWeave, anchor); } @Override public Collection<SNode> weaveTemplate(@NotNull SNodeReference templateDeclaration, Object... args) throws GenerationException { TemplateDeclaration templateDeclarationInstance = myEnv.loadTemplateDeclaration(templateDeclaration, myTemplateNode, myTemplateContext, args); if (templateDeclarationInstance != null /*templateDeclarationInstance instanceof TemplateDeclarationWeavingAware2*/) { return templateDeclarationInstance.weave(myWeaveContext, this); } return Collections.emptyList(); } @Override public Collection<SNode> weaveTemplate(@NotNull TemplateDeclaration templateDeclaration) throws GenerationException { return templateDeclaration.weave(myWeaveContext, this); } }