diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/ReplModule.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/ReplModule.java index af5154ad..4e8ac4ed 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/ReplModule.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/ReplModule.java @@ -19,13 +19,12 @@ import org.metaborg.spoofax.shell.core.DynSemEvaluationStrategy; import org.metaborg.spoofax.shell.core.IEvaluationStrategy; import org.metaborg.spoofax.shell.core.IInterpreterLoader; -import org.metaborg.spoofax.shell.functions.AEvalFunction; import org.metaborg.spoofax.shell.functions.ATransformFunction; import org.metaborg.spoofax.shell.functions.AnalyzeFunction; +import org.metaborg.spoofax.shell.functions.EvaluateFunction; import org.metaborg.spoofax.shell.functions.FailableFunction; import org.metaborg.spoofax.shell.functions.IFunctionFactory; import org.metaborg.spoofax.shell.functions.InputFunction; -import org.metaborg.spoofax.shell.functions.PEvalFunction; import org.metaborg.spoofax.shell.functions.PTransformFunction; import org.metaborg.spoofax.shell.functions.ParseFunction; import org.metaborg.spoofax.shell.invoker.ICommandInvoker; @@ -35,6 +34,7 @@ import org.metaborg.spoofax.shell.output.IResult; import org.metaborg.spoofax.shell.output.IResultFactory; import org.metaborg.spoofax.shell.output.IResultVisitor; +import org.metaborg.spoofax.shell.output.ISpoofaxTermResult; import org.metaborg.spoofax.shell.output.InputResult; import org.metaborg.spoofax.shell.output.ParseResult; import org.metaborg.spoofax.shell.output.TransformResult; @@ -94,8 +94,6 @@ protected void bindFactories() { .implement(TransformResult.class, Names.named("parsed"), TransformResult.Parsed.class) .implement(TransformResult.class, Names.named("analyzed"), TransformResult.Analyzed.class) - .implement(EvaluateResult.class, Names.named("parsed"), EvaluateResult.Parsed.class) - .implement(EvaluateResult.class, Names.named("analyzed"), EvaluateResult.Analyzed.class) .build(IResultFactory.class)); install(new FactoryModuleBuilder() @@ -109,10 +107,9 @@ protected void bindFactories() { PTransformFunction.class) .implement(new TypeLiteral>() { }, ATransformFunction.class) - .implement(new TypeLiteral>() { }, - PEvalFunction.class) - .implement(new TypeLiteral>() { }, - AEvalFunction.class) + .implement(new TypeLiteral, + EvaluateResult, IResult>>() { }, + EvaluateFunction.class) .build(IFunctionFactory.class)); } diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/commands/CommandBuilder.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/commands/CommandBuilder.java index d1683378..89762c7e 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/commands/CommandBuilder.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/commands/CommandBuilder.java @@ -118,11 +118,13 @@ private FailableFunction analyzeFunction() { } private FailableFunction pEvaluateFunction() { - return parseFunction().kleisliCompose(functionFactory.createPEvalFunction(project, lang)); + return parseFunction() + .kleisliCompose(functionFactory.createEvaluateFunction(project, lang)); } private FailableFunction aEvaluateFunction() { - return analyzeFunction().kleisliCompose(functionFactory.createAEvalFunction(project, lang)); + return analyzeFunction() + .kleisliCompose(functionFactory.createEvaluateFunction(project, lang)); } /** diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/core/DynSemEvaluationStrategy.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/core/DynSemEvaluationStrategy.java index 8968db2e..173b778a 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/core/DynSemEvaluationStrategy.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/core/DynSemEvaluationStrategy.java @@ -15,8 +15,6 @@ import org.metaborg.meta.lang.dynsem.interpreter.terms.ITerm; import org.metaborg.spoofax.core.terms.ITermFactoryService; import org.metaborg.spoofax.shell.core.IInterpreterLoader.InterpreterLoadException; -import org.metaborg.spoofax.shell.output.AnalyzeResult; -import org.metaborg.spoofax.shell.output.ParseResult; import org.metaborg.spoofax.shell.util.StrategoUtil; import org.spoofax.interpreter.core.Tools; import org.spoofax.interpreter.terms.IStrategoAppl; @@ -42,8 +40,8 @@ public class DynSemEvaluationStrategy implements IEvaluationStrategy { /** * Construct a new {@link DynSemEvaluationStrategy}. This does not yet load the interpreter for - * the language. Rather, this is done when first invoking - * {@link #evaluate(AnalyzeResult, IContext)} or {@link #evaluate(ParseResult, IContext)}. + * the language. Rather, this is done when invoking {@link #evaluate(IStrategoTerm, IContext)} + * for the first time. * * @param interpLoader * The loader for a generated DynSem interpreter. @@ -63,14 +61,8 @@ public String name() { } @Override - public IStrategoTerm evaluate(ParseResult parsed, IContext context) throws MetaborgException { - return evaluate(parsed.ast().get(), context.language()); - } - - @Override - public IStrategoTerm evaluate(AnalyzeResult analyzed, IContext context) - throws MetaborgException { - return evaluate(analyzed.ast().get(), context.language()); + public IStrategoTerm evaluate(IStrategoTerm term, IContext context) throws MetaborgException { + return evaluate(term, context.language()); } private IStrategoTerm evaluate(IStrategoTerm input, ILanguageImpl langImpl) @@ -168,8 +160,7 @@ private void initialize(ILanguageImpl langImpl) throws InterpreterLoadException initializeExecutionEnvironment(); } - private void initializeExecutionEnvironment() - throws InterpreterLoadException { + private void initializeExecutionEnvironment() throws InterpreterLoadException { ITermFactory termFactory = termFactService.getGeneric(); IStrategoConstructor termConstr = termFactory.makeConstructor("ShellInit", 0); IStrategoAppl shellInitAppl = termFactory.makeAppl(termConstr); diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/core/IEvaluationStrategy.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/core/IEvaluationStrategy.java index b68edd32..23012bca 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/core/IEvaluationStrategy.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/core/IEvaluationStrategy.java @@ -2,8 +2,6 @@ import org.metaborg.core.MetaborgException; import org.metaborg.core.context.IContext; -import org.metaborg.spoofax.shell.output.AnalyzeResult; -import org.metaborg.spoofax.shell.output.ParseResult; import org.spoofax.interpreter.terms.IStrategoTerm; /** @@ -18,19 +16,11 @@ public interface IEvaluationStrategy { /** * Evaluate the given Stratego term using this strategy. - * @param parsed The parsed input. + * @param term The input term. * @param context The {@link IContext}. * @return The output Stratego term. * @throws MetaborgException When evaluation fails for one reason or another. */ - IStrategoTerm evaluate(ParseResult parsed, IContext context) throws MetaborgException; + IStrategoTerm evaluate(IStrategoTerm term, IContext context) throws MetaborgException; - /** - * Evaluate the given Stratego term using this strategy. - * @param analyzed The analyzed input. - * @param context The {@link IContext}. - * @return The output Stratego term. - * @throws MetaborgException When evaluation fails for one reason or another. - */ - IStrategoTerm evaluate(AnalyzeResult analyzed, IContext context) throws MetaborgException; } diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/AEvalFunction.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/EvaluateFunction.java similarity index 77% rename from org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/AEvalFunction.java rename to org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/EvaluateFunction.java index cc1c2a92..1322f115 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/AEvalFunction.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/EvaluateFunction.java @@ -9,11 +9,12 @@ import org.metaborg.core.project.IProject; import org.metaborg.spoofax.core.shell.ShellFacet; import org.metaborg.spoofax.shell.core.IEvaluationStrategy; -import org.metaborg.spoofax.shell.output.AnalyzeResult; import org.metaborg.spoofax.shell.output.EvaluateResult; import org.metaborg.spoofax.shell.output.FailOrSuccessResult; +import org.metaborg.spoofax.shell.output.FailResult; import org.metaborg.spoofax.shell.output.IResult; import org.metaborg.spoofax.shell.output.IResultFactory; +import org.metaborg.spoofax.shell.output.ISpoofaxTermResult; import org.spoofax.interpreter.terms.IStrategoTerm; import com.google.inject.Inject; @@ -22,7 +23,8 @@ /** * Creates an {@link EvaluateResult} from a given {@link AnalyzeResult}. */ -public class AEvalFunction extends ContextualSpoofaxFunction { +public class EvaluateFunction extends ContextualSpoofaxFunction, + EvaluateResult> { private final Map evaluationStrategies; /** @@ -40,7 +42,7 @@ public class AEvalFunction extends ContextualSpoofaxFunction evaluationStrategies, + public EvaluateFunction(Map evaluationStrategies, IContextService contextService, IResultFactory resultFactory, @Assisted IProject project, @Assisted ILanguageImpl lang) { super(contextService, resultFactory, project, lang); @@ -49,14 +51,18 @@ public AEvalFunction(Map evaluationStrategies, @Override protected FailOrSuccessResult - applyThrowing(IContext context, AnalyzeResult a) throws Exception { + applyThrowing(IContext context, ISpoofaxTermResult a) throws Exception { + if (!a.ast().isPresent()) { + return FailOrSuccessResult.failed(new FailResult(a)); + } ShellFacet facet = context.language().facet(ShellFacet.class); if (facet == null) { throw new MetaborgException("Cannot find the shell facet."); } IEvaluationStrategy evalStrategy = evaluationStrategies.get(facet.getEvaluationMethod()); - IStrategoTerm result = evalStrategy.evaluate(a, context); + IStrategoTerm result = evalStrategy.evaluate(a.ast().get(), context); + return FailOrSuccessResult.ofSpoofaxResult(resultFactory.createEvaluateResult(a, result)); } } diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/FailableFunction.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/FailableFunction.java index 3d1e987d..9edcd592 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/FailableFunction.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/FailableFunction.java @@ -43,7 +43,7 @@ public interface FailableFunction FailableFunction - kleisliCompose(FailableFunction other) { + kleisliCompose(FailableFunction other) { Objects.requireNonNull(other); return a -> this.apply(a).flatMap(other); } diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/IFunctionFactory.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/IFunctionFactory.java index cddcada0..7e4bdf73 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/IFunctionFactory.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/IFunctionFactory.java @@ -8,6 +8,7 @@ import org.metaborg.spoofax.shell.output.AnalyzeResult; import org.metaborg.spoofax.shell.output.EvaluateResult; import org.metaborg.spoofax.shell.output.IResult; +import org.metaborg.spoofax.shell.output.ISpoofaxTermResult; import org.metaborg.spoofax.shell.output.InputResult; import org.metaborg.spoofax.shell.output.ParseResult; import org.metaborg.spoofax.shell.output.TransformResult; @@ -69,22 +70,13 @@ public interface IFunctionFactory { ITransformAction action); /** - * Factory method for creating a {@link PEvalFunction} from a {@link ParseFunction}. + * Factory method for creating a {@link EvaluateFunction}. * @param project The associated {@link IProject} * @param lang The associated {@link ILanguageImpl} * @return an {@link PEvalFunction} */ - FailableFunction - createPEvalFunction(IProject project, ILanguageImpl lang); - - /** - * Factory method for creating an {@link AEvalFunction} from an {@link AnalyzeFunction}. - * @param project The associated {@link IProject} - * @param lang The associated {@link ILanguageImpl} - * @return an {@link AEvalFunction} - */ - FailableFunction - createAEvalFunction(IProject project, ILanguageImpl lang); + FailableFunction, EvaluateResult, IResult> + createEvaluateFunction(IProject project, ILanguageImpl lang); /** * Factory method for creating a {@link CommandBuilder}. diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/PEvalFunction.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/PEvalFunction.java deleted file mode 100644 index 1e2a2cfa..00000000 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/functions/PEvalFunction.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.metaborg.spoofax.shell.functions; - -import java.util.Map; - -import org.metaborg.core.MetaborgException; -import org.metaborg.core.context.IContext; -import org.metaborg.core.context.IContextService; -import org.metaborg.core.language.ILanguageImpl; -import org.metaborg.core.project.IProject; -import org.metaborg.spoofax.core.shell.ShellFacet; -import org.metaborg.spoofax.shell.core.IEvaluationStrategy; -import org.metaborg.spoofax.shell.output.EvaluateResult; -import org.metaborg.spoofax.shell.output.FailOrSuccessResult; -import org.metaborg.spoofax.shell.output.IResult; -import org.metaborg.spoofax.shell.output.IResultFactory; -import org.metaborg.spoofax.shell.output.ParseResult; -import org.spoofax.interpreter.terms.IStrategoTerm; - -import com.google.inject.Inject; -import com.google.inject.assistedinject.Assisted; - -/** - * Creates an {@link EvaluateResult} from a given {@link ParseResult}. - */ -public class PEvalFunction extends ContextualSpoofaxFunction { - private final Map evaluationStrategies; - - /** - * Instantiate a {@link PEvalFunction}. - * - * @param evaluationStrategies - * The {@link IEvaluationStrategy} implementations, grouped by their names as keys. - * @param contextService - * The {@link IContextService}. - * @param resultFactory - * The {@link IResultFactory} for creating delegate commands. - * @param project - * The {@link IProject} in which this command should operate. - * @param lang - * The {@link ILanguageImpl} to which this command applies. - */ - @Inject - public PEvalFunction(Map evaluationStrategies, - IContextService contextService, IResultFactory resultFactory, - @Assisted IProject project, @Assisted ILanguageImpl lang) { - super(contextService, resultFactory, project, lang); - this.evaluationStrategies = evaluationStrategies; - } - - @Override - protected FailOrSuccessResult - applyThrowing(IContext context, ParseResult a) throws Exception { - ShellFacet facet = context.language().facet(ShellFacet.class); - if (facet == null) { - throw new MetaborgException("Cannot find the shell facet."); - } - - IEvaluationStrategy evalStrategy = evaluationStrategies.get(facet.getEvaluationMethod()); - IStrategoTerm result = evalStrategy.evaluate(a, context); - return FailOrSuccessResult.ofSpoofaxResult(resultFactory.createEvaluateResult(a, result)); - } -} diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AbstractSpoofaxResult.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AbstractSpoofaxResult.java index c9d212b6..846554f4 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AbstractSpoofaxResult.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AbstractSpoofaxResult.java @@ -2,26 +2,20 @@ import org.apache.commons.vfs2.FileObject; import org.metaborg.core.unit.IUnit; -import org.metaborg.spoofax.core.stratego.IStrategoCommon; -import org.metaborg.spoofax.shell.commands.IReplCommand; -import org.spoofax.interpreter.terms.IStrategoTerm; /** * Represents an {@link AbstractSpoofaxResult} as returned by the {@link IReplCommand}. * Wraps Spoofax {@link IUnit} of various types. * @param the wrapped subtype of {@link IUnit} */ -public abstract class AbstractSpoofaxResult implements ISpoofaxResult { - private final IStrategoCommon common; +public abstract class AbstractSpoofaxResult implements ISpoofaxResult { private final T unit; /** - * Constructor for an {@link AbstractSpoofaxResult}. - * @param common the {@link IStrategoCommon} service + * Constructor for an {@link AbstractResult}. * @param unit the wrapped {@link IUnit} */ - public AbstractSpoofaxResult(IStrategoCommon common, T unit) { - this.common = common; + public AbstractSpoofaxResult(T unit) { this.unit = unit; } @@ -34,21 +28,4 @@ public FileObject source() { public T unit() { return unit; } - - /** - * Returns a textual representation of a term. - * @param term the term - * @return a string - */ - public StyledText toString(IStrategoTerm term) { - return new StyledText(common.toString(term)); - } - - @Override - public StyledText styled() { - if (!valid() || !ast().isPresent()) { - return new StyledText(messages().toString()); - } - return toString(ast().get()); - } } diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AbstractSpoofaxTermResult.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AbstractSpoofaxTermResult.java new file mode 100644 index 00000000..90a36f85 --- /dev/null +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AbstractSpoofaxTermResult.java @@ -0,0 +1,45 @@ +package org.metaborg.spoofax.shell.output; + +import org.metaborg.core.unit.IUnit; +import org.metaborg.spoofax.core.stratego.IStrategoCommon; +import org.spoofax.interpreter.terms.IStrategoTerm; + +/** + * Represents an {@link AbstractResult} as returned by the {@link SpoofaxCommand}. + * Wraps Spoofax {@link IUnit} of various types. Additionally, stores an AST. + * @param the wrapped subtype of {@link IUnit} + */ +//@formatter:off +public abstract class AbstractSpoofaxTermResult + extends AbstractSpoofaxResult implements ISpoofaxTermResult { +//@formatter:on + private final IStrategoCommon common; + + /** + * Constructor for an {@link AbstractResult}. + * @param common the {@link IStrategoCommon} service. + * @param unit the wrapped {@link IUnit}. + */ + public AbstractSpoofaxTermResult(IStrategoCommon common, T unit) { + super(unit); + this.common = common; + } + + /** + * Returns a textual representation of a term. + * @param term the term + * @return a string + */ + public StyledText toString(IStrategoTerm term) { + return new StyledText(common.toString(term)); + } + + @Override + public StyledText styled() { + if (!valid() || !ast().isPresent()) { + return new StyledText(messages().toString()); + } + return toString(ast().get()); + } + +} diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AnalyzeResult.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AnalyzeResult.java index d55e7e1c..88bdcb05 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AnalyzeResult.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/AnalyzeResult.java @@ -19,7 +19,7 @@ * Represents an {@link AnalyzeResult} as returned by the {@link IReplCommand}. * Wraps a {@link ISpoofaxAnalyzeUnit}. */ -public class AnalyzeResult extends AbstractSpoofaxResult { +public class AnalyzeResult extends AbstractSpoofaxTermResult { /** * Create a {@link AnalyzeResult}. diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/EvaluateResult.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/EvaluateResult.java index b71a93fb..bf2980c7 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/EvaluateResult.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/EvaluateResult.java @@ -7,8 +7,6 @@ import org.metaborg.core.messages.IMessage; import org.metaborg.core.unit.IUnit; import org.metaborg.spoofax.core.stratego.IStrategoCommon; -import org.metaborg.spoofax.shell.functions.AEvalFunction; -import org.metaborg.spoofax.shell.functions.PEvalFunction; import org.spoofax.interpreter.terms.IStrategoTerm; import com.google.inject.Inject; @@ -17,57 +15,24 @@ /** * The result of the execution of an {@link AEvalFunction} or a {@link PEvalFunction}. */ -public abstract class EvaluateResult extends AbstractSpoofaxResult { - private final AbstractSpoofaxResult wrappedDelegate; +public class EvaluateResult extends AbstractSpoofaxTermResult { + private final ISpoofaxTermResult wrappedDelegate; private final IStrategoTerm result; /** - * The result of the evaluation of an analyzed AST. + * Create a {@link EvaluateResult}. + * + * @param common + * the {@link IStrategoCommon} service. + * @param wrappedResult + * the wrapped {@link ISpoofaxTermResult}. + * @param result + * the result of the evaluation. */ - public static class Analyzed extends EvaluateResult { - - /** - * Create a {@link EvaluateResult}. - * - * @param common - * the {@link IStrategoCommon} service - * @param analyzed - * the wrapped {@link AnalyzeResult}. - * @param result - * the result of the evaluation. - */ - @Inject - public Analyzed(IStrategoCommon common, @Assisted AnalyzeResult analyzed, - @Assisted IStrategoTerm result) { - super(common, analyzed, result); - } - } - - /** - * The result of the evaluation of a parsed, but not analyzed, AST. - */ - public static class Parsed extends EvaluateResult { - - /** - * Create a {@link EvaluateResult}. - * - * @param common - * the {@link IStrategoCommon} service - * @param parsed - * the wrapped {@link ParseResult}. - * @param result - * the result of the evaluation. - */ - @Inject - public Parsed(IStrategoCommon common, @Assisted ParseResult parsed, - @Assisted IStrategoTerm result) { - super(common, parsed, result); - } - } - - private EvaluateResult(IStrategoCommon common, - AbstractSpoofaxResult wrappedResult, - IStrategoTerm result) { + @Inject + public EvaluateResult(IStrategoCommon common, + @Assisted ISpoofaxTermResult wrappedResult, + @Assisted IStrategoTerm result) { super(common, wrappedResult.unit()); this.wrappedDelegate = wrappedResult; this.result = result; diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/FailOrSuccessResult.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/FailOrSuccessResult.java index 543b1824..766c90e7 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/FailOrSuccessResult.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/FailOrSuccessResult.java @@ -38,7 +38,7 @@ public void accept(IResultVisitor visitor) { @Override public FailOrSuccessResult - flatMap(FailableFunction failable) { + flatMap(FailableFunction failable) { Objects.requireNonNull(failable); return failable.apply(result); } @@ -65,7 +65,7 @@ public void accept(IResultVisitor visitor) { @Override public FailOrSuccessResult - flatMap(FailableFunction failable) { + flatMap(FailableFunction failable) { Objects.requireNonNull(failable); return failed(result); } @@ -133,12 +133,12 @@ public void accept(IResultVisitor visitor) { * success, otherwise just returns the same cause of the failure. The result of the mapping can * in turn be a success or a failure. * - * @param failable + * @param other * The {@link FailableFunction} to apply when this was a success. * @return The result, either a success or a failure. * @param * the new type of a successful result. */ public abstract FailOrSuccessResult - flatMap(FailableFunction failable); + flatMap(FailableFunction other); } diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/IResultFactory.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/IResultFactory.java index c13ce28f..6de00b5f 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/IResultFactory.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/IResultFactory.java @@ -76,20 +76,12 @@ InputResult createInputResult(ILanguageImpl lang, FileObject file, String source /** * Create an {@link EvaluateResult} that can be passed to the Repl. - * @param parsed the wrapped {@link ParseResult} - * @param result the result of the evaluation. + * @param inputTermResult the wrapped {@link ISpoofaxTermResult} that was the input + * of the evaluation. + * @param result the result of the evaluation. * @return a {@link EvaluateResult} */ - @Named("parsed") - EvaluateResult createEvaluateResult(ParseResult parsed, IStrategoTerm result); - - /** - * Create an {@link EvaluateResult} that can be passed to the Repl. - * @param analyzed the wrapped {@link AnalyzeResult} - * @param result the result of the evaluation. - * @return a {@link EvaluateResult} - */ - @Named("analyzed") - EvaluateResult createEvaluateResult(AnalyzeResult analyzed, IStrategoTerm result); + EvaluateResult createEvaluateResult(ISpoofaxTermResult inputTermResult, + IStrategoTerm result); } diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/IResultVisitor.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/IResultVisitor.java index 519f56f4..f4fbe307 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/IResultVisitor.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/IResultVisitor.java @@ -6,6 +6,16 @@ */ public interface IResultVisitor { + /** + * Visit an {@link ISpoofaxTermResult}. + * + * @param result + * The result to be visited. + */ + default void visitTermResult(ISpoofaxTermResult result) { + visitResult(result); + } + /** * Visit an {@link ISpoofaxResult}. * diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ISpoofaxResult.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ISpoofaxResult.java index b27a76a8..7605c3c0 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ISpoofaxResult.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ISpoofaxResult.java @@ -7,8 +7,6 @@ import org.metaborg.core.context.IContext; import org.metaborg.core.messages.IMessage; import org.metaborg.core.unit.IUnit; -import org.metaborg.spoofax.shell.commands.IReplCommand; -import org.spoofax.interpreter.terms.IStrategoTerm; /** * Represents an {@link ISpoofaxResult} as returned by the {@link IReplCommand}. @@ -16,11 +14,6 @@ * @param the wrapped subtype of {@link IUnit} */ public interface ISpoofaxResult extends IResult { - /** - * Returns the ast of this unit as a {@link IStrategoTerm} if present. - * @return a {@link IStrategoTerm} or null - */ - Optional ast(); /** * Returns the context of this unit if present. diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ISpoofaxTermResult.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ISpoofaxTermResult.java new file mode 100644 index 00000000..d4174ee4 --- /dev/null +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ISpoofaxTermResult.java @@ -0,0 +1,19 @@ +package org.metaborg.spoofax.shell.output; + +import java.util.Optional; + +import org.metaborg.core.unit.IUnit; +import org.spoofax.interpreter.terms.IStrategoTerm; + +/** + * Interface for {@link ISpoofaxResult}s that also have an optional AST. + * @param The type of the wrapped {@link IUnit}. + */ +public interface ISpoofaxTermResult extends ISpoofaxResult { + + /** + * Returns the ast of this unit as a {@link IStrategoTerm} if present. + * @return a {@link IStrategoTerm} or null + */ + Optional ast(); +} diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/InputResult.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/InputResult.java index 1fb1c5e2..fbedafb3 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/InputResult.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/InputResult.java @@ -7,12 +7,9 @@ import org.metaborg.core.context.IContext; import org.metaborg.core.language.ILanguageImpl; import org.metaborg.core.messages.IMessage; -import org.metaborg.spoofax.core.stratego.IStrategoCommon; import org.metaborg.spoofax.core.syntax.JSGLRParserConfiguration; import org.metaborg.spoofax.core.unit.ISpoofaxInputUnit; import org.metaborg.spoofax.core.unit.ISpoofaxUnitService; -import org.metaborg.spoofax.shell.commands.IReplCommand; -import org.spoofax.interpreter.terms.IStrategoTerm; import com.google.common.collect.Lists; import com.google.inject.assistedinject.Assisted; @@ -27,21 +24,17 @@ public class InputResult extends AbstractSpoofaxResult { /** * Create a {@link InputResult}. * - * @param common - * the {@link IStrategoCommon} service * @param unit * the wrapped {@link ISpoofaxInputUnit} */ @AssistedInject - public InputResult(IStrategoCommon common, @Assisted ISpoofaxInputUnit unit) { - super(common, unit); + public InputResult(@Assisted ISpoofaxInputUnit unit) { + super(unit); } /** * Create a {@link InputResult} from source. * - * @param common - * the {@link IStrategoCommon} service * @param unitService * the {@link ISpoofaxUnitService} * @param lang @@ -54,17 +47,15 @@ public InputResult(IStrategoCommon common, @Assisted ISpoofaxInputUnit unit) { * the parser configuration */ @AssistedInject - public InputResult(IStrategoCommon common, ISpoofaxUnitService unitService, + public InputResult(ISpoofaxUnitService unitService, @Assisted ILanguageImpl lang, @Assisted FileObject file, @Assisted String source, @Assisted JSGLRParserConfiguration parserConfig) { - super(common, unitService.inputUnit(file, source, lang, null, parserConfig)); + super(unitService.inputUnit(file, source, lang, null, parserConfig)); } /** * Create a {@link InputResult} from source. * - * @param common - * the {@link IStrategoCommon} service * @param unitService * the {@link ISpoofaxUnitService} * @param lang @@ -75,15 +66,10 @@ public InputResult(IStrategoCommon common, ISpoofaxUnitService unitService, * the source string */ @AssistedInject - public InputResult(IStrategoCommon common, ISpoofaxUnitService unitService, + public InputResult(ISpoofaxUnitService unitService, @Assisted ILanguageImpl lang, @Assisted FileObject file, @Assisted String source) { - this(common, unitService, lang, file, source, null); - } - - @Override - public Optional ast() { - return Optional.empty(); + this(unitService, lang, file, source, null); } @Override diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ParseResult.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ParseResult.java index bc2b25c4..e0eb6fc5 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ParseResult.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/ParseResult.java @@ -19,7 +19,7 @@ * Represents a {@link ParseResult} as returned by the {@link IReplCommand}. * Wraps a {@link ISpoofaxParseUnit}. */ -public class ParseResult extends AbstractSpoofaxResult { +public class ParseResult extends AbstractSpoofaxTermResult { /** * Create a {@link ParseResult}. diff --git a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/TransformResult.java b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/TransformResult.java index ef698187..e796551d 100644 --- a/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/TransformResult.java +++ b/org.metaborg.spoofax.shell.core/src/main/java/org/metaborg/spoofax/shell/output/TransformResult.java @@ -24,7 +24,7 @@ * {@link ISpoofaxTransformUnit}. */ public abstract class TransformResult - extends AbstractSpoofaxResult> { + extends AbstractSpoofaxTermResult> { /** * The result of the transformation of an analyzed AST. diff --git a/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/core/DynSemEvaluationStrategyTest.java b/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/core/DynSemEvaluationStrategyTest.java index 53f7d7cb..b089f25d 100644 --- a/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/core/DynSemEvaluationStrategyTest.java +++ b/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/core/DynSemEvaluationStrategyTest.java @@ -13,7 +13,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; @@ -28,7 +27,6 @@ import org.metaborg.meta.lang.dynsem.interpreter.terms.ITermTransformer; import org.metaborg.spoofax.core.SpoofaxModule; import org.metaborg.spoofax.core.terms.ITermFactoryService; -import org.metaborg.spoofax.shell.output.AnalyzeResult; import org.metaborg.spoofax.shell.util.StrategoUtil; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; @@ -111,17 +109,15 @@ public static Collection inputAndRuleParameters() { */ @Test public void testEnvironmentPropagation() { - AnalyzeResult analyzeResultMock = - when(mock(AnalyzeResult.class).ast()).thenReturn(Optional.of(input)).getMock(); try { // First invocation causes an update in the environment. IStrategoTerm firstResult = evalStrategy - .evaluate(analyzeResultMock, mock(IContext.class, Mockito.RETURNS_MOCKS)); + .evaluate(input, mock(IContext.class, Mockito.RETURNS_MOCKS)); assertTrue(firstResult.toString().contains("0")); // Second invocation has a different result due to a different environment. IStrategoTerm secondResult = evalStrategy - .evaluate(analyzeResultMock, mock(IContext.class, Mockito.RETURNS_MOCKS)); + .evaluate(input, mock(IContext.class, Mockito.RETURNS_MOCKS)); assertTrue(secondResult.toString().contains(String.valueOf(DEFAULT_SHELL_RULE_ANSWER))); } catch (MetaborgException e) { assertEquals(expectedExceptionMessage, e.getMessage()); diff --git a/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/functions/EvaluateFunctionTest.java b/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/functions/EvaluateFunctionTest.java index cfe1dffc..37e3e827 100644 --- a/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/functions/EvaluateFunctionTest.java +++ b/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/functions/EvaluateFunctionTest.java @@ -1,8 +1,10 @@ package org.metaborg.spoofax.shell.functions; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -48,6 +50,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; +import org.spoofax.interpreter.terms.IStrategoTerm; /** * Test creating and using a {@link IReplCommand} created from the {@link AEvalFunction} and @@ -164,8 +167,12 @@ private void mockContext() { private void mockServices() throws FileSystemException, MetaborgException { FileObject sourceFile = VFS.getManager().resolveFile("ram://junit-temp"); when(project.location()).thenReturn(sourceFile); + when(parseResult.ast()).thenReturn(Optional.of(mock(IStrategoTerm.class))); + when(analyzeResult.ast()).thenReturn(Optional.of(mock(IStrategoTerm.class))); when(parseResult.context()).thenReturn(Optional.empty()); when(analyzeResult.context()).thenReturn(Optional.empty()); + doCallRealMethod().when(parseResult).accept(any(IResultVisitor.class)); + doCallRealMethod().when(analyzeResult).accept(any(IResultVisitor.class)); when(contextService.get(any(), any(), any())).thenReturn(context); when(resultFactory.createEvaluateResult(any(ParseResult.class), any())).thenReturn(result); @@ -176,10 +183,8 @@ private void mockServices() throws FileSystemException, MetaborgException { private void mockFunctions() { Map evalStrategies = new HashMap<>(1); evalStrategies.put("mock", evalStrategy); - PEvalFunction pEvalFunction = - new PEvalFunction(evalStrategies, contextService, resultFactory, project, lang); - AEvalFunction aEvalFunction = - new AEvalFunction(evalStrategies, contextService, resultFactory, project, lang); + EvaluateFunction pEvalFunction = + new EvaluateFunction(evalStrategies, contextService, resultFactory, project, lang); when(functionFactory.createInputFunction(any(), any())) .thenReturn((input) -> FailOrSuccessResult.successful(inputResult)); @@ -188,8 +193,7 @@ private void mockFunctions() { when(functionFactory.createAnalyzeFunction(any(), any())) .thenReturn((input) -> FailOrSuccessResult.successful(analyzeResult)); - when(functionFactory.createPEvalFunction(any(), any())).thenReturn(pEvalFunction); - when(functionFactory.createAEvalFunction(any(), any())).thenReturn(aEvalFunction); + when(functionFactory.createEvaluateFunction(any(), any())).thenReturn(pEvalFunction); } /** @@ -200,6 +204,26 @@ public void testDescription() { assertEquals(description, command.description()); } + /** + * Test failing of command when input has no AST present. + * + * @throws MetaborgException + * on unexpected Spoofax exceptions + */ + @Test + public void testEvaluateNoAST() throws MetaborgException { + when(parseResult.ast()).thenReturn(Optional.empty()); + when(analyzeResult.ast()).thenReturn(Optional.empty()); + + IResult execute = command.execute("test"); + assertTrue(execute instanceof FailOrSuccessResult); + + execute.accept(visitor); + verify(visitor, times(1)).visitFailure(failCaptor.capture()); + ISpoofaxResult failureCause = failCaptor.getValue().getCause(); + assertTrue(parseResult == failureCause || analyzeResult == failureCause); + } + /** * Test creating a valid {@link EvaluateResult}. * @@ -259,17 +283,16 @@ public void testEvaluateInvalid() throws MetaborgException { } /** - * Test creating a {@link EvaluateResult} resulting in an exception. + * Test evaluation strategy invocation resulting in an exception. * * @throws MetaborgException * on unexpected Spoofax exceptions */ @Test - public void testEvaluateException() throws MetaborgException { + public void testEvaluationStrategyException() throws MetaborgException { MetaborgException evalException = new MetaborgException("error"); - when(evalStrategy.evaluate(any(ParseResult.class), eq(context))).thenThrow(evalException); - when(evalStrategy.evaluate(any(AnalyzeResult.class), eq(context))).thenThrow(evalException); + when(evalStrategy.evaluate(any(IStrategoTerm.class), eq(context))).thenThrow(evalException); IResult execute = command.execute("test"); verify(visitor, never()).visitException(any()); @@ -279,4 +302,24 @@ public void testEvaluateException() throws MetaborgException { assertEquals(evalException, exceptionCaptor.getValue()); } + /** + * Test throwing an exception when there is no {@link ShellFacet}. + * + * @throws MetaborgException + * on unexpected Spoofax exceptions + */ + @Test + public void testAbsentShellFacetException() throws MetaborgException { + ILanguageImpl langMock = + when(mock(ILanguageImpl.class).facet(ShellFacet.class)).thenReturn(null).getMock(); + when(context.language()).thenReturn(langMock); + + IResult execute = command.execute("test"); + verify(visitor, never()).visitException(any()); + + execute.accept(visitor); + verify(visitor, times(1)).visitException(exceptionCaptor.capture()); + assertEquals("Cannot find the shell facet.", exceptionCaptor.getValue().getMessage()); + } + } diff --git a/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/output/SpoofaxResultsTest.java b/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/output/SpoofaxResultsTest.java index 29b1a411..443483c5 100644 --- a/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/output/SpoofaxResultsTest.java +++ b/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/output/SpoofaxResultsTest.java @@ -1,17 +1,14 @@ package org.metaborg.spoofax.shell.output; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.function.BiFunction; import javax.annotation.Nullable; @@ -23,30 +20,24 @@ import org.metaborg.core.context.IContext; import org.metaborg.core.messages.IMessage; import org.metaborg.core.unit.IUnit; -import org.metaborg.spoofax.core.stratego.IStrategoCommon; -import org.metaborg.spoofax.core.unit.ISpoofaxAnalyzeUnit; import org.metaborg.spoofax.core.unit.ISpoofaxInputUnit; -import org.metaborg.spoofax.core.unit.ISpoofaxParseUnit; -import org.metaborg.spoofax.core.unit.ISpoofaxTransformUnit; import org.spoofax.interpreter.terms.IStrategoTerm; /** - * Tests all subclasses of {@link AbstractSpoofaxResult} using a {@link Parameterized parameterized - * test}. + * Tests all subclasses of {@link AbstractSpoofaxResult} using a {@link Parameterized + * parameterized test}. */ @RunWith(Parameterized.class) public class SpoofaxResultsTest { - private static final String ACTUAL_TO_STRING = "actual"; - private static final String ACTUAL_SOURCE = "actual source"; - - private final AbstractSpoofaxResult abstractResult; - private final List expectedMessages; - private final Optional expectedAst; - private final Optional expectedContext; - private final FileObject expectedSource; - private final boolean expectedValid; - private final String expectedString; + protected static final String ACTUAL_TO_STRING = "actual"; + protected static final String ACTUAL_SOURCE = "actual source"; + protected final AbstractSpoofaxResult abstractResult; + protected final List expectedMessages; + protected final Optional expectedContext; + protected final FileObject expectedSource; + protected final boolean expectedValid; + protected final String expectedString; /** * Instantiate parameters. @@ -55,8 +46,6 @@ public class SpoofaxResultsTest { * The result class being tested. * @param messages * Expected messages. - * @param ast - * Expected AST. * @param context * Expected context. * @param source @@ -68,12 +57,11 @@ public class SpoofaxResultsTest { */ // CHECKSTYLE.OFF: ParameterNumber public SpoofaxResultsTest(AbstractSpoofaxResult abstractResult, List messages, - @Nullable IStrategoTerm ast, @Nullable IContext context, - FileObject source, boolean isValid, String expectedString) { + @Nullable IContext context, FileObject source, boolean isValid, + String expectedString) { this.abstractResult = abstractResult; this.expectedMessages = messages; this.expectedString = expectedString; - this.expectedAst = Optional.ofNullable(ast); this.expectedContext = Optional.ofNullable(context); this.expectedSource = source; this.expectedValid = isValid; @@ -83,11 +71,8 @@ public SpoofaxResultsTest(AbstractSpoofaxResult abstractResult, List resultParameters() { - IStrategoCommon common = mock(IStrategoCommon.class); IMessage message1 = mock(IMessage.class), message2 = mock(IMessage.class); List messages = Arrays.asList(message1, message2); String messagesString = messages.toString(); @@ -95,196 +80,53 @@ public static List resultParameters() { IContext context = mock(IContext.class); FileObject source = mock(FileObject.class); - when(common.toString(any())).thenReturn(ACTUAL_TO_STRING); + return addParams(messages, messagesString, ast, context, source); + } + /** + * Return list parameters. + * @param messages messages + * @param messagesString messagesString + * @param ast ast + * @param context context + * @param source source + * @return parameters + */ + protected static List addParams(List messages, + String messagesString, IStrategoTerm ast, + IContext context, FileObject source) { List params = new ArrayList<>(); ISpoofaxInputUnit mockInput = mockInput(source); - InputResult inputResult = new InputResult(null, mockInput); - params.add(new Object[] { inputResult, Collections.emptyList(), null, null, source, true, + InputResult inputResult = new InputResult(mockInput); + params.add(new Object[] { inputResult, Collections.emptyList(), null, source, true, ACTUAL_SOURCE }); - - BiFunction> makeParseMock = - (valid, success) -> new ParseResult(common, mockParse(source, ast, messages, mockInput, - valid, success)); - BiFunction> makeNoASTParseMock = - (valid, success) -> new ParseResult(common, mockParse(source, null, messages, mockInput, - valid, success)); - ISpoofaxParseUnit mockParse = (ISpoofaxParseUnit) makeParseMock.apply(true, true).unit(); - params.addAll(makeParams(makeParseMock, makeNoASTParseMock, messages, ast, null, source, - messagesString)); - - BiFunction> makeAnalyzeMock = - (valid, success) -> new AnalyzeResult(common, - mockAnalyze(source, ast, context, messages, - mockParse, valid, success)); - BiFunction> makeNoASTAnalyzeMock = - (valid, success) -> new AnalyzeResult(common, - mockAnalyze(source, null, context, messages, - mockParse, valid, success)); - ISpoofaxAnalyzeUnit mockAnalyze = (ISpoofaxAnalyzeUnit) makeAnalyzeMock.apply(true, true) - .unit(); - params.addAll(makeParams(makeAnalyzeMock, makeNoASTAnalyzeMock, messages, ast, context, - source, messagesString)); - - BiFunction> makeTransPMock = - (valid, success) -> new TransformResult.Parsed(common, - mockPTransform(source, ast, context, - messages, mockParse, - valid, success)); - BiFunction> makeNoASTTransPMock = - (valid, success) -> new TransformResult.Parsed(common, - mockPTransform(source, null, context, - messages, mockParse, - valid, success)); - params.addAll(makeParams(makeTransPMock, makeNoASTTransPMock, messages, ast, context, - source, messagesString)); - - BiFunction> makeTransAMock = - (valid, success) -> new TransformResult.Analyzed(common, - mockATransform(source, ast, context, - messages, mockAnalyze, - valid, success)); - BiFunction> makeNoASTTransAMock = - (valid, success) -> new TransformResult.Analyzed(common, - mockATransform(source, null, context, - messages, mockAnalyze, - valid, success)); - params.addAll(makeParams(makeTransAMock, makeNoASTTransAMock, messages, ast, context, - source, messagesString)); - - BiFunction> makeEvalAMock = - (valid, success) -> new EvaluateResult.Analyzed(common, (AnalyzeResult) makeAnalyzeMock - .apply(valid, success), ast); - BiFunction> makeNoASTEvalAMock = - (valid, success) -> new EvaluateResult.Analyzed(common, - (AnalyzeResult) makeNoASTAnalyzeMock - .apply(valid, success), null); - params.addAll(makeParams(makeEvalAMock, makeNoASTEvalAMock, messages, ast, context, - source, messagesString)); - - BiFunction> makeEvalPMock = - (valid, success) -> new EvaluateResult.Parsed(common, (ParseResult) makeParseMock - .apply(valid, success), ast); - BiFunction> makeNoASTEvalPMock = - (valid, success) -> new EvaluateResult.Parsed(common, (ParseResult) makeNoASTParseMock - .apply(valid, success), null); - params.addAll(makeParams(makeEvalPMock, makeNoASTEvalPMock, messages, ast, null, - source, messagesString)); - return params; } - //@formatter:on - - private static Collection - makeParams(BiFunction> makeMock, - BiFunction> makeNoASTMock, - List messages, IStrategoTerm ast, IContext context, - FileObject source, String messagesString) { - return Arrays - .asList((Object[]) new Object[][] { { makeMock.apply(true, true), messages, ast, - context, source, true, ACTUAL_TO_STRING }, - { makeMock.apply(false, false), messages, ast, - context, source, false, messagesString }, - { makeMock.apply(false, true), messages, ast, - context, source, false, messagesString }, - { makeMock.apply(true, false), messages, ast, - context, source, false, messagesString }, - { makeNoASTMock.apply(true, true), messages, null, - context, source, true, messagesString }, - { makeNoASTMock.apply(false, false), messages, null, - context, source, false, messagesString }, - { makeNoASTMock.apply(false, true), messages, null, - context, source, false, messagesString }, - { makeNoASTMock.apply(true, false), messages, null, - context, source, false, messagesString } }); - } - // CHECKSTYLE.ON: MethodLength - private static ISpoofaxInputUnit mockInput(FileObject source) { + /** + * mock input unit. + * @param source source. + * @return the input unit. + */ + protected static ISpoofaxInputUnit mockInput(FileObject source) { ISpoofaxInputUnit unit = (ISpoofaxInputUnit) mockUnit(ISpoofaxInputUnit.class, source); when(unit.text()).thenReturn(ACTUAL_SOURCE); return unit; } - private static ISpoofaxParseUnit mockParse(FileObject source, IStrategoTerm ast, - List messages, ISpoofaxInputUnit mockInput, - boolean valid, boolean success) { - ISpoofaxParseUnit unit = (ISpoofaxParseUnit) mockUnit(ISpoofaxParseUnit.class, source); - when(unit.ast()).thenReturn(ast); - when(unit.messages()).thenReturn(messages); - when(unit.input()).thenReturn(mockInput); - when(unit.valid()).thenReturn(valid); - when(unit.success()).thenReturn(success); - return unit; - } - - private static ISpoofaxAnalyzeUnit mockAnalyze(FileObject source, IStrategoTerm ast, - IContext context, List messages, - ISpoofaxParseUnit mockParse, boolean valid, - boolean success) { - ISpoofaxAnalyzeUnit unit = - (ISpoofaxAnalyzeUnit) mockUnit(ISpoofaxAnalyzeUnit.class, source); - when(unit.ast()).thenReturn(ast); - when(unit.context()).thenReturn(context); - when(unit.messages()).thenReturn(messages); - when(unit.input()).thenReturn(mockParse); - when(unit.valid()).thenReturn(valid); - when(unit.success()).thenReturn(success); - return unit; - } - - @SuppressWarnings("unchecked") - private static ISpoofaxTransformUnit - mockPTransform(FileObject source, IStrategoTerm ast, IContext context, - List messages, ISpoofaxParseUnit mockParse, boolean valid, - boolean success) { - ISpoofaxTransformUnit unit = - (ISpoofaxTransformUnit) mockTransform(source, ast, context, messages, - valid, success); - when(unit.input()).thenReturn(mockParse); - return unit; - } - - @SuppressWarnings("unchecked") - private static ISpoofaxTransformUnit - mockATransform(FileObject source, IStrategoTerm ast, IContext context, - List messages, ISpoofaxAnalyzeUnit mockAnalyze, boolean valid, - boolean success) { - ISpoofaxTransformUnit unit = - (ISpoofaxTransformUnit) mockTransform(source, ast, context, - messages, valid, success); - when(unit.input()).thenReturn(mockAnalyze); - return unit; - } - - private static ISpoofaxTransformUnit mockTransform(FileObject source, IStrategoTerm ast, - IContext context, List messages, - boolean valid, boolean success) { - ISpoofaxTransformUnit unit = - (ISpoofaxTransformUnit) mockUnit(ISpoofaxTransformUnit.class, source); - when(unit.ast()).thenReturn(ast); - when(unit.context()).thenReturn(context); - when(unit.messages()).thenReturn(messages); - when(unit.valid()).thenReturn(valid); - when(unit.success()).thenReturn(success); - return unit; - } - - private static IUnit mockUnit(Class clazz, FileObject source) { + /** + * Mock any unit. + * @param clazz unit class + * @param source source + * @return mock unit. + */ + protected static IUnit mockUnit(Class clazz, FileObject source) { IUnit unit = mock(clazz); when(unit.source()).thenReturn(source); return unit; } - /** - * Test returning the ast. - */ - @Test - public void testAst() { - assertEquals(expectedAst, abstractResult.ast()); - } - /** * Test returning the {@link IContext}. */ @@ -332,4 +174,5 @@ public void testSourceText() { public void testValidOrInvalid() { assertEquals(expectedValid, abstractResult.valid()); } -} + +} \ No newline at end of file diff --git a/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/output/SpoofaxTermResultsTest.java b/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/output/SpoofaxTermResultsTest.java new file mode 100644 index 00000000..dee3ab1f --- /dev/null +++ b/org.metaborg.spoofax.shell.core/src/test/java/org/metaborg/spoofax/shell/output/SpoofaxTermResultsTest.java @@ -0,0 +1,288 @@ +package org.metaborg.spoofax.shell.output; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.function.BiFunction; + +import javax.annotation.Nullable; + +import org.apache.commons.vfs2.FileObject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.metaborg.core.context.IContext; +import org.metaborg.core.messages.IMessage; +import org.metaborg.spoofax.core.stratego.IStrategoCommon; +import org.metaborg.spoofax.core.unit.ISpoofaxAnalyzeUnit; +import org.metaborg.spoofax.core.unit.ISpoofaxInputUnit; +import org.metaborg.spoofax.core.unit.ISpoofaxParseUnit; +import org.metaborg.spoofax.core.unit.ISpoofaxTransformUnit; +import org.spoofax.interpreter.terms.IStrategoTerm; + +/** + * Tests all subclasses of {@link AbstractSpoofaxTermResult} using a {@link Parameterized + * parameterized test}. + */ +@RunWith(Parameterized.class) +public class SpoofaxTermResultsTest extends SpoofaxResultsTest { + + private final Optional expectedAst; + private final AbstractSpoofaxTermResult abstractResult; + + /** + * Instantiate parameters. + * + * @param abstractResult + * The result class being tested. + * @param messages + * Expected messages. + * @param ast + * Expected AST. + * @param context + * Expected context. + * @param source + * Expected source. + * @param isValid + * Whether we should expect the result to be valid. + * @param expectedString + * The expected string when calling the styled() method. + */ + // CHECKSTYLE.OFF: ParameterNumber + public SpoofaxTermResultsTest(AbstractSpoofaxTermResult abstractResult, + List messages, @Nullable IStrategoTerm ast, + @Nullable IContext context, FileObject source, boolean isValid, + String expectedString) { + super(abstractResult, messages, context, source, isValid, expectedString); + this.abstractResult = abstractResult; + this.expectedAst = Optional.ofNullable(ast); + } + // CHECKSTYLE.ON: ParameterNumber + + /** + * @return All of the parameters to run each test against. + */ + @Parameters(name = "{index}: {0}") + public static List resultParameters() { + IStrategoCommon common = mock(IStrategoCommon.class); + IMessage message1 = mock(IMessage.class), message2 = mock(IMessage.class); + List messages = Arrays.asList(message1, message2); + String messagesString = messages.toString(); + IStrategoTerm ast = mock(IStrategoTerm.class); + IContext context = mock(IContext.class); + FileObject source = mock(FileObject.class); + + when(common.toString(any())).thenReturn(ACTUAL_TO_STRING); + + return addParams(common, messages, messagesString, ast, context, source); + } + //@formatter:on + + /** + * Return list parameters. + * + * @param common + * common + * @param messages + * messages + * @param messagesString + * messagesString + * @param ast + * ast + * @param context + * context + * @param source + * source + * @return parameters + */ + // CHECKSTYLE.OFF: MethodLength + protected static List addParams(IStrategoCommon common, List messages, + String messagesString, IStrategoTerm ast, + IContext context, FileObject source) { + List params = new ArrayList<>(); + + ISpoofaxInputUnit mockInput = mockInput(source); + + BiFunction> makeParseMock = + (valid, success) -> new ParseResult(common, mockParse(source, ast, messages, mockInput, + valid, success)); + BiFunction> makeNoASTParseMock = + (valid, success) -> new ParseResult(common, mockParse(source, null, messages, mockInput, + valid, success)); + ISpoofaxParseUnit mockParse = (ISpoofaxParseUnit) makeParseMock.apply(true, true).unit(); + params.addAll(makeParams(makeParseMock, makeNoASTParseMock, messages, ast, null, source, + messagesString)); + + BiFunction> makeAnalyzeMock = + (valid, success) -> new AnalyzeResult(common, + mockAnalyze(source, ast, context, messages, + mockParse, valid, success)); + BiFunction> makeNoASTAnalyzeMock = + (valid, success) -> new AnalyzeResult(common, + mockAnalyze(source, null, context, messages, + mockParse, valid, success)); + ISpoofaxAnalyzeUnit mockAnalyze = + (ISpoofaxAnalyzeUnit) makeAnalyzeMock.apply(true, true).unit(); + params.addAll(makeParams(makeAnalyzeMock, makeNoASTAnalyzeMock, messages, ast, context, + source, messagesString)); + + BiFunction> makeTransPMock = + (valid, success) -> new TransformResult.Parsed(common, + mockPTransform(source, ast, context, + messages, mockParse, + valid, success)); + BiFunction> makeNoASTTransPMock = + (valid, success) -> new TransformResult.Parsed(common, + mockPTransform(source, null, context, + messages, mockParse, + valid, success)); + params.addAll(makeParams(makeTransPMock, makeNoASTTransPMock, messages, ast, context, + source, messagesString)); + + BiFunction> makeTransAMock = + (valid, success) -> new TransformResult.Analyzed(common, + mockATransform(source, ast, context, + messages, mockAnalyze, + valid, success)); + BiFunction> makeNoASTTransAMock = + (valid, success) -> new TransformResult.Analyzed(common, + mockATransform(source, null, context, + messages, mockAnalyze, + valid, success)); + params.addAll(makeParams(makeTransAMock, makeNoASTTransAMock, messages, ast, context, + source, messagesString)); + + BiFunction> makeEvalAMock = + (valid, + success) -> new EvaluateResult(common, + (AnalyzeResult) makeAnalyzeMock.apply(valid, + success), + ast); + BiFunction> makeNoASTEvalAMock = + (valid, success) -> new EvaluateResult(common, (AnalyzeResult) makeNoASTAnalyzeMock + .apply(valid, success), null); + params.addAll(makeParams(makeEvalAMock, makeNoASTEvalAMock, messages, ast, context, source, + messagesString)); + + BiFunction> makeEvalPMock = + (valid, + success) -> new EvaluateResult(common, + (ParseResult) makeParseMock.apply(valid, success), ast); + BiFunction> makeNoASTEvalPMock = + (valid, + success) -> new EvaluateResult(common, + (ParseResult) makeNoASTParseMock.apply(valid, + success), + null); + params.addAll(makeParams(makeEvalPMock, makeNoASTEvalPMock, messages, ast, null, source, + messagesString)); + + return params; + } + // CHECKSTYLE.ON: MethodLength + + private static Collection + makeParams(BiFunction> makeMock, + BiFunction> makeNoASTMock, + List messages, IStrategoTerm ast, IContext context, + FileObject source, String messagesString) { + return Arrays + .asList((Object[]) new Object[][] { { makeMock.apply(true, true), messages, ast, + context, source, true, ACTUAL_TO_STRING }, + { makeMock.apply(false, false), messages, ast, + context, source, false, messagesString }, + { makeMock.apply(false, true), messages, ast, + context, source, false, messagesString }, + { makeMock.apply(true, false), messages, ast, + context, source, false, messagesString }, + { makeNoASTMock.apply(true, true), messages, null, + context, source, true, messagesString }, + { makeNoASTMock.apply(false, false), messages, null, + context, source, false, messagesString }, + { makeNoASTMock.apply(false, true), messages, null, + context, source, false, messagesString }, + { makeNoASTMock.apply(true, false), messages, null, + context, source, false, messagesString } }); + } + // CHECKSTYLE.ON: MethodLength + + private static ISpoofaxParseUnit mockParse(FileObject source, IStrategoTerm ast, + List messages, ISpoofaxInputUnit mockInput, + boolean valid, boolean success) { + ISpoofaxParseUnit unit = (ISpoofaxParseUnit) mockUnit(ISpoofaxParseUnit.class, source); + when(unit.ast()).thenReturn(ast); + when(unit.messages()).thenReturn(messages); + when(unit.input()).thenReturn(mockInput); + when(unit.valid()).thenReturn(valid); + when(unit.success()).thenReturn(success); + return unit; + } + + private static ISpoofaxAnalyzeUnit mockAnalyze(FileObject source, IStrategoTerm ast, + IContext context, List messages, + ISpoofaxParseUnit mockParse, boolean valid, + boolean success) { + ISpoofaxAnalyzeUnit unit = + (ISpoofaxAnalyzeUnit) mockUnit(ISpoofaxAnalyzeUnit.class, source); + when(unit.ast()).thenReturn(ast); + when(unit.context()).thenReturn(context); + when(unit.messages()).thenReturn(messages); + when(unit.input()).thenReturn(mockParse); + when(unit.valid()).thenReturn(valid); + when(unit.success()).thenReturn(success); + return unit; + } + + @SuppressWarnings("unchecked") + private static ISpoofaxTransformUnit + mockPTransform(FileObject source, IStrategoTerm ast, IContext context, + List messages, ISpoofaxParseUnit mockParse, boolean valid, + boolean success) { + ISpoofaxTransformUnit unit = + (ISpoofaxTransformUnit) mockTransform(source, ast, context, messages, + valid, success); + when(unit.input()).thenReturn(mockParse); + return unit; + } + + @SuppressWarnings("unchecked") + private static ISpoofaxTransformUnit + mockATransform(FileObject source, IStrategoTerm ast, IContext context, + List messages, ISpoofaxAnalyzeUnit mockAnalyze, boolean valid, + boolean success) { + ISpoofaxTransformUnit unit = + (ISpoofaxTransformUnit) mockTransform(source, ast, context, + messages, valid, success); + when(unit.input()).thenReturn(mockAnalyze); + return unit; + } + + private static ISpoofaxTransformUnit mockTransform(FileObject source, IStrategoTerm ast, + IContext context, List messages, + boolean valid, boolean success) { + ISpoofaxTransformUnit unit = + (ISpoofaxTransformUnit) mockUnit(ISpoofaxTransformUnit.class, source); + when(unit.ast()).thenReturn(ast); + when(unit.context()).thenReturn(context); + when(unit.messages()).thenReturn(messages); + when(unit.valid()).thenReturn(valid); + when(unit.success()).thenReturn(success); + return unit; + } + + /** + * Test returning the ast. + */ + @Test + public void testAst() { + assertEquals(expectedAst, abstractResult.ast()); + } +}