/*
* Copyright 2003-2016 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.template;
import jetbrains.mps.generator.impl.GenerationFailureException;
import jetbrains.mps.generator.impl.TemplateQueryException;
import jetbrains.mps.generator.impl.query.CallArgumentQuery;
import jetbrains.mps.generator.impl.query.IfMacroCondition;
import jetbrains.mps.generator.impl.query.InlineSwitchCaseCondition;
import jetbrains.mps.generator.impl.query.InsertMacroQuery;
import jetbrains.mps.generator.impl.query.MapNodeQuery;
import jetbrains.mps.generator.impl.query.MapPostProcessor;
import jetbrains.mps.generator.impl.query.PropertyValueQuery;
import jetbrains.mps.generator.impl.query.ReferenceTargetQuery;
import jetbrains.mps.generator.impl.query.SourceNodeQuery;
import jetbrains.mps.generator.impl.query.SourceNodesQuery;
import jetbrains.mps.generator.impl.query.VariableValueQuery;
import jetbrains.mps.generator.runtime.GenerationException;
import jetbrains.mps.generator.runtime.TemplateContext;
import jetbrains.mps.generator.runtime.TemplateCreateRootRule;
import jetbrains.mps.generator.runtime.TemplateExecutionEnvironment;
import jetbrains.mps.generator.runtime.TemplateMappingScript;
import jetbrains.mps.generator.runtime.TemplateReductionRule;
import jetbrains.mps.generator.runtime.TemplateRootMappingRule;
import jetbrains.mps.generator.runtime.TemplateRuleWithCondition;
import jetbrains.mps.generator.runtime.TemplateWeavingRule;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.model.SNode;
import java.util.Collection;
/**
* Default implementation that executes queries without any further activity.
*
* XXX Note, evaluate methods account for any trouble in user code, and wrap them with {@link TemplateQueryException}.
* However, {@link jetbrains.mps.generator.impl.interpreted.ReflectiveQueryProvider} handles unexpected exceptions itself,
* while generated templates don't use this QEC at all. The only case when these catch() work is non-reflective queries, the one
* that we'd like to make primary (and, perhaps, only). See {@link jetbrains.mps.generator.impl.template.QueryExecutor} for
* considerations whether we shall keep QE/QEC indirection, or get another provider that would wrap non-reflective queries with
* try/catch and unexpected error handling (wrapping could be conditional). I lean towards a distinct provider as it gives
* more flexibility (can mix different wrappers) and fine-grained control for wrappers like performance tracer.
* Evgeny Gryaznov, Feb 10, 2010
*/
public class DefaultQueryExecutionContext implements QueryExecutionContext {
private final ITemplateGenerator myGenerator;
private final boolean myIsMultithread;
public DefaultQueryExecutionContext(@NotNull ITemplateGenerator generator) {
this(generator, true);
}
public DefaultQueryExecutionContext(@NotNull ITemplateGenerator generator, boolean isMultithread) {
myGenerator = generator;
myIsMultithread = isMultithread;
}
@Override
public boolean evaluate(@NotNull InlineSwitchCaseCondition condition, @NotNull InlineSwitchCaseContext context) throws GenerationFailureException {
try {
return condition.check(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("condition of inline switch failed", t);
ex.setQueryContext(context);
throw ex;
}
}
@Override
public boolean evaluate(@NotNull IfMacroCondition condition, @NotNull IfMacroContext context) throws GenerationFailureException {
try {
return condition.check(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("IF macro condition failed", t);
ex.setQueryContext(context);
throw ex;
}
}
@Nullable
@Override
public SNode evaluate(@NotNull MapNodeQuery query, @NotNull MapSrcMacroContext context) throws GenerationFailureException {
try {
return query.evaluate(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("mapping function failed", t);
ex.setQueryContext(context);
throw ex;
}
}
@Override
public void execute(@NotNull MapPostProcessor codeBlock, @NotNull MapSrcMacroPostProcContext context) throws GenerationFailureException {
try {
codeBlock.invoke(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("post-processing query failed", t);
ex.setQueryContext(context);
throw ex;
}
}
@Nullable
@Override
public Object evaluate(@NotNull PropertyValueQuery query, @NotNull PropertyMacroContext context) throws GenerationFailureException {
try {
return query.evaluate(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("failed to evaluate property value", t);
ex.setQueryContext(context);
throw ex;
}
}
@Nullable
@Override
public SNode evaluate(@NotNull SourceNodeQuery query, @NotNull SourceSubstituteMacroNodeContext context) throws GenerationFailureException {
try {
return query.evaluate(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("source node query failed", t);
ex.setQueryContext(context);
throw ex;
}
}
@Nullable
@Override
public Object evaluate(@NotNull CallArgumentQuery query, @NotNull TemplateArgumentContext context) throws GenerationFailureException {
try {
return query.evaluate(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("Query for template call argument failed", t);
ex.setQueryContext(context);
throw ex;
}
}
@Nullable
@Override
public Object evaluate(@NotNull VariableValueQuery query, @NotNull TemplateVarContext context) throws GenerationFailureException {
try {
return query.evaluate(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("VAR macro query failed", t);
ex.setQueryContext(context);
throw ex;
}
}
@NotNull
@Override
public Collection<SNode> evaluate(@NotNull SourceNodesQuery query, @NotNull SourceSubstituteMacroNodesContext context) throws GenerationFailureException {
try {
return query.evaluate(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("source nodes query failed", t);
ex.setQueryContext(context);
throw ex;
}
}
@Nullable
@Override
public SNode evaluate(@NotNull InsertMacroQuery query, @NotNull InsertMacroContext context) throws GenerationFailureException {
try {
return query.evaluate(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("INSERT macro query failed", t);
ex.setQueryContext(context);
throw ex;
}
}
@Nullable
@Override
public Object evaluate(@NotNull ReferenceTargetQuery query, @NotNull ReferenceMacroContext context) throws GenerationFailureException {
try {
return query.evaluate(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("reference macro target query failed", t);
ex.setQueryContext(context);
throw ex;
}
}
@Override
public Collection<SNode> applyRule(TemplateReductionRule rule, TemplateContext context) throws GenerationException {
try {
return rule.apply(context);
} catch (GenerationException ex) {
throw ex;
} catch (Throwable t) {
GenerationFailureException ex = new GenerationFailureException("error applying reduction rule", t);
ex.setTemplateContext(context);
ex.setTemplateModelLocation(rule.getRuleNode());
throw ex;
}
}
@Override
public boolean isApplicable(@NotNull TemplateRuleWithCondition rule, @NotNull TemplateContext context) throws GenerationFailureException {
try {
return rule.isApplicable(context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("error executing rule condition", t);
ex.setTemplateContext(context);
ex.setTemplateModelLocation(rule.getRuleNode());
throw ex;
}
}
@Override
public Collection<SNode> applyRule(TemplateRootMappingRule rule, TemplateContext context) throws GenerationException {
try {
return rule.apply(context);
} catch (GenerationException ex) {
throw ex;
} catch (Throwable t) {
GenerationFailureException ex = new GenerationFailureException("unexpected exception when applying root rule", t);
ex.setTemplateContext(context);
ex.setTemplateModelLocation(rule.getRuleNode());
throw ex;
}
}
@Override
public Collection<SNode> applyRule(TemplateCreateRootRule rule, TemplateExecutionEnvironment environment) throws GenerationException {
try {
return rule.apply(environment);
} catch (GenerationException ex) {
throw ex;
} catch (Throwable t) {
GenerationFailureException ex = new GenerationFailureException("unexpected exception when applying create root rule", t);
ex.setTemplateModelLocation(rule.getRuleNode());
throw ex;
}
}
@Override
public boolean applyRule(TemplateWeavingRule rule, TemplateContext context, SNode outputContextNode) throws GenerationException {
try {
return rule.apply(context.getEnvironment(), context, outputContextNode);
} catch (GenerationException ex) {
throw ex;
} catch (Throwable t) {
GenerationFailureException ex = new GenerationFailureException("unexpected exception when applying weaving rule", t);
ex.setTemplateContext(context);
ex.setTemplateModelLocation(rule.getRuleNode());
throw ex;
}
}
@Override
public SNode getContextNode(TemplateWeavingRule rule, TemplateContext context) throws GenerationFailureException {
try {
return rule.getContextNode(context.getEnvironment(), context);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException("cannot evaluate rule context query", t);
ex.setTemplateContext(context);
ex.setTemplateModelLocation(rule.getRuleNode());
throw ex;
}
}
@Override
public void executeScript(TemplateMappingScript mappingScript, SModel model) throws GenerationFailureException {
try {
mappingScript.apply(model, myGenerator);
} catch (GenerationFailureException ex) {
throw ex;
} catch (Throwable t) {
TemplateQueryException ex = new TemplateQueryException(String.format("error executing script %s", mappingScript.getLongName()), t);
ex.setTemplateModelLocation(mappingScript.getScriptNode());
throw ex;
}
}
@Override
public boolean isMultithreaded() {
return myIsMultithread;
}
}