Merge pull request #13 from sampottinger/tree_listener_parameter

[Fork] Refactor within PdePreprocessor to allow for override of edits.
This commit is contained in:
A Samuel Pottinger
2019-10-20 16:13:47 -07:00
committed by GitHub
21 changed files with 1149 additions and 1510 deletions
+2 -1
View File
@@ -138,7 +138,8 @@ public class JavaBuild {
* @return null if compilation failed, main class name if not
*/
public String preprocess(File srcFolder, boolean sizeWarning) throws SketchException {
return preprocess(srcFolder, null, new PdePreprocessor(sketch.getName()), sizeWarning);
PdePreprocessor preprocessor = PdePreprocessor.builderFor(sketch.getName()).build();
return preprocess(srcFolder, null, preprocessor, sizeWarning);
}
@@ -148,7 +148,7 @@ public class JavaEditor extends Editor {
public PdePreprocessor createPreprocessor(final String sketchName) {
return new PdePreprocessor(sketchName);
return PdePreprocessor.builderFor(sketchName).build();
}
@@ -52,7 +52,6 @@ import processing.mode.java.pdex.util.ProblemFactory;
import processing.mode.java.pdex.util.RuntimePathBuilder;
import processing.mode.java.preproc.PdePreprocessor;
import processing.mode.java.preproc.PreprocessorResult;
import processing.mode.java.preproc.code.ImportUtil;
import processing.mode.java.preproc.code.SyntaxUtil;
@@ -522,16 +521,16 @@ public class PreprocessingService {
/**
* Determine which imports need to be available for core processing services.
*
* @param p The preprocessor to operate on.
* @param preprocessor The preprocessor to operate on.
* @return The import statements that need to be present.
*/
private static List<ImportStatement> buildCoreAndDefaultImports(PdePreprocessor p) {
private static List<ImportStatement> buildCoreAndDefaultImports(PdePreprocessor preprocessor) {
List<ImportStatement> result = new ArrayList<>();
for (String imp : ImportUtil.getCoreImports()) {
for (String imp : preprocessor.getCoreImports()) {
result.add(ImportStatement.parse(imp));
}
for (String imp : ImportUtil.getDefaultImports()) {
for (String imp : preprocessor.getDefaultImports()) {
result.add(ImportStatement.parse(imp));
}
@@ -1,39 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-19 The Processing Foundation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.mode.java.preproc;
import processing.mode.java.preproc.issue.PdePreprocessIssue;
/**
* Listener for issues encountered while processing a valid pde parse tree.
*/
interface PdeParseTreeErrorListener {
/**
* Callback to invoke when an issue is encountered while processing a valid PDE parse tree.
*
* @param issue The issue reported.
*/
void onError(PdePreprocessIssue issue);
}
File diff suppressed because it is too large Load Diff
@@ -24,7 +24,9 @@ package processing.mode.java.preproc;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree;
@@ -32,58 +34,92 @@ import org.antlr.v4.runtime.tree.ParseTreeWalker;
import processing.app.Preferences;
import processing.app.SketchException;
import processing.mode.java.preproc.code.ImportUtil;
import processing.mode.java.preproc.issue.PdeIssueEmitter;
import processing.mode.java.preproc.issue.PdePreprocessIssue;
/**
* Utility to preprocess sketches prior to comilation.
* Utility to preprocess sketches prior to compilation.
*
* <p>
* This preprocessor assists with
* </p>
*/
public class PdePreprocessor {
/**
* The mode that the sketch uses to run.
*/
public static enum Mode {
STATIC, ACTIVE, JAVA
/**
* Sketch without draw, setup, or settings functions where code is run as if the body of a
* method without any enclosing types. This code will not define its enclosing class or method.
*/
STATIC,
/**
* Sketch using draw, setup, and / or settings where the code is run as if defining the body
* of a class. This code will not define its enclosing class but it will define its enclosing
* method.
*/
ACTIVE,
/**
* Sketch written like typical Java where the code is run such that it defines the enclosing
* classes itself.
*/
JAVA
}
private String sketchName;
private int tabSize;
private boolean hasMain;
private final String sketchName;
private final int tabSize;
private final boolean isTesting;
private final ParseTreeListenerFactory listenerFactory;
private final List<String> defaultImports;
private final List<String> coreImports;
private final Optional<String> destinationPackage;
private boolean foundMain;
/**
* Create a new preprocessor.
* Create a new PdePreprocessorBuilder for a sketch of the given name.
*
* @param sketchName The name of the sketch.
* Create a new builder to help instantiate a preprocessor for a sketch of the given name. Use
* this builder to configure settings of the preprocessor before building.
*
* @param sketchName The name of the sketch for which a preprocessor will be built.
* @return Builder to create a preprocessor for the sketch of the given name.
*/
public PdePreprocessor(final String sketchName) {
this(sketchName, Preferences.getInteger("editor.tabs.size"), false);
public static PdePreprocessorBuilder builderFor(String sketchName) {
return new PdePreprocessorBuilder(sketchName);
}
/**
* Create a new preprocessor.
*
* @param sketchName The name of the sketch.
* @param tabSize The number of tabs.
*/
public PdePreprocessor(final String sketchName, final int tabSize) {
this(sketchName, tabSize, false);
}
/**
* Create a new preprocessor.
* Create a new preprocessor that will use the following set of configuration values to process
* a parse tree. This object can be instantiated by calling {builderFor}.
*
* @param sketchName The name of the sketch.
* @param tabSize The number of tabs.
* @param isTesting Flag indicating if this is running in unit tests (true) or in production
* @param newSketchName The name of the sketch.
* @param newTabSize The number of spaces within a tab.
* @param newIsTesting Flag indicating if this is running in unit tests (true) or in production
* (false).
* @param newFactory The factory to use for building the ANTLR tree traversal listener where
* preprocessing edits should be made.
* @param newDefaultImports Imports provided for user convenience.
* @param newCoreImports Imports required for core or processing itself.
*/
public PdePreprocessor(final String sketchName, final int tabSize, boolean isTesting) {
this.sketchName = sketchName;
this.tabSize = tabSize;
this.isTesting = isTesting;
public PdePreprocessor(final String newSketchName, final int newTabSize, boolean newIsTesting,
final ParseTreeListenerFactory newFactory, List<String> newDefaultImports,
List<String> newCoreImports, Optional<String> newDestinationPackage) {
sketchName = newSketchName;
tabSize = newTabSize;
isTesting = newIsTesting;
listenerFactory = newFactory;
defaultImports = newDefaultImports;
coreImports = newCoreImports;
destinationPackage = newDestinationPackage;
}
/**
@@ -151,10 +187,15 @@ public class PdePreprocessor {
// Parser
final List<PdePreprocessIssue> preprocessIssues = new ArrayList<>();
final List<PdePreprocessIssue> treeIssues = new ArrayList<>();
PdeParseTreeListener listener = createListener(tokens, sketchName);
PdeParseTreeListener listener = listenerFactory.build(
tokens,
sketchName,
tabSize,
destinationPackage
);
listener.setTesting(isTesting);
listener.setCoreImports(ImportUtil.getCoreImports());
listener.setDefaultImports(ImportUtil.getDefaultImports());
listener.setCoreImports(coreImports);
listener.setDefaultImports(defaultImports);
listener.setCodeFolderImports(codeFolderImports);
listener.setTreeErrorListener((x) -> { treeIssues.add(x); });
@@ -188,7 +229,7 @@ public class PdePreprocessor {
PrintWriter outPrintWriter = new PrintWriter(outWriter);
outPrintWriter.print(outputProgram);
hasMain = listener.foundMain();
foundMain = listener.foundMain();
return listener.getResult();
}
@@ -199,20 +240,249 @@ public class PdePreprocessor {
* @return True if a main method was found. False otherwise.
*/
public boolean hasMain() {
return hasMain;
return foundMain;
}
/**
* Factory function to create a {PdeParseTreeListener} for use in preprocessing
* Get the more or processing-required imports that this preprocessor is using.
*
* @param tokens The token stream for which the listener needs to be created.
* @param sketchName The name of the sketch being preprocessed.
* @return Newly created listener suitable for use in this {PdePreprocessor}.
* @return List of imports required by processing or this mode.
*/
private PdeParseTreeListener createListener(CommonTokenStream tokens, String sketchName) {
return new PdeParseTreeListener(tokens, sketchName, tabSize);
public List<String> getCoreImports() {
return coreImports;
}
/**
* Get convenience imports provided on the user's behalf.
*
* @return Imports included by default but not required by processing or the mode.
*/
public List<String> getDefaultImports() {
return defaultImports;
}
/* ========================
* === Type Definitions ===
* ========================
*
* The preprocessor has a sizable number of parameters, including those that can modify its
* internal behavior. These supporting types help initialize this object and provide hooks for
* behavior modifications.
*/
/**
* Builder to help instantiate a PdePreprocessor.
*
* The PdePreprocessor includes a number of parameters, including some behavioral parameters that
* change how the parse tree is processed. This builder helps instantiate this object by providing
* reasonable defaults for most values but allowing client to (especially modes) to override those
* defaults.
*/
public static class PdePreprocessorBuilder {
private final String sketchName;
private Optional<Integer> tabSize;
private Optional<Boolean> isTesting;
private Optional<ParseTreeListenerFactory> parseTreeFactory;
private Optional<List<String>> defaultImports;
private Optional<List<String>> coreImports;
private Optional<String> destinationPackage;
/**
* The imports required for the Java processing mode.
*
* <p>
* The set of imports required by processing itself (in java mode) that are made public so that
* client code (like in modes) can modify and re-use this list.
* </p>
*/
public static final String[] BASE_CORE_IMPORTS = {
"processing.core.*",
"processing.data.*",
"processing.event.*",
"processing.opengl.*"
};
/**
* The imports provided as a convenience for the user.
*
* <p>
* The imports that are not strictly required by processing sketches but that are included on
* behalf of the user that are made public so that client code (like in modes) can modify and
* re-use this list.
* </p>
*/
public static final String[] BASE_DEFAULT_IMPORTS = {
"java.util.HashMap",
"java.util.ArrayList",
"java.io.File",
"java.io.BufferedReader",
"java.io.PrintWriter",
"java.io.InputStream",
"java.io.OutputStream",
"java.io.IOException"
};
/**
* Create a new preprocessor builder.
*
* <p>
* Create a new preprocessor builder which will use default values unless overridden prior to
* calling build. Note that client code should use {PdePreprocessor.builderFor} instead of
* this constructor.
* </p>
*
* @param newSketchName The name of the sketch.
*/
private PdePreprocessorBuilder(String newSketchName) {
sketchName = newSketchName;
tabSize = Optional.empty();
isTesting = Optional.empty();
parseTreeFactory = Optional.empty();
defaultImports = Optional.empty();
coreImports = Optional.empty();
destinationPackage = Optional.empty();
}
/**
* Set how large the tabs should be.
*
* @param newTabSize The number of spaces in a tab.
* @return This builder for method chaining.
*/
public PdePreprocessorBuilder setTabSize(int newTabSize) {
tabSize = Optional.of(newTabSize);
return this;
}
/**
* Indicate if this preprocessor is running within unittests.
*
* @param newIsTesting Flag that, if true, will configure the preprocessor to run safely within
* a unit testing environment.
* @return This builder for method chaining.
*/
public PdePreprocessorBuilder setIsTesting(boolean newIsTesting) {
isTesting = Optional.of(newIsTesting);
return this;
}
/**
* Specify how the parse tree listener should be built.
*
* The ANTLR parse tree listener is where the preprocessing edits are generated and some client
* code (like modes) may need to override some of the preprocessing edit behavior. Specifying
* this factory allows client code to replace the default PdeParseTreeListener that is used
* during preprocessing.
*
* @param newFactory The factory to use in building a parse tree listener.
* @return This builder for method chaining.
*/
public PdePreprocessorBuilder setParseTreeListenerFactory(ParseTreeListenerFactory newFactory) {
parseTreeFactory = Optional.of(newFactory);
return this;
}
/**
* Indicate which imports are provided on behalf of the user for convenience.
*
* @param newDefaultImports The new set of default imports.
* @return This builder for method chaining.
*/
public PdePreprocessorBuilder setDefaultImports(List<String> newDefaultImports) {
defaultImports = Optional.of(newDefaultImports);
return this;
}
/**
* Indicate which imports are required by processing or the mode itself.
*
* @param newCoreImports The new set of core imports.
* @return This builder for method chaining.
*/
public PdePreprocessorBuilder setCoreImports(List<String> newCoreImports) {
coreImports = Optional.of(newCoreImports);
return this;
}
/**
* Specify to which package generated code should be assigned.
*
* @param newDestinationPackage The package to which output code should be assigned.
* @return This builder for method chaining.
*/
public PdePreprocessorBuilder setDestinationPackage(String newDestinationPackage) {
destinationPackage = Optional.of(newDestinationPackage);
return this;
}
/**
* Build the preprocessor.
*
* @return Newly built preproceesor.
*/
public PdePreprocessor build() {
final int effectiveTabSize = tabSize.orElseGet(
() -> Preferences.getInteger("editor.tabs.size")
);
final boolean effectiveIsTesting = isTesting.orElse(false);
ParseTreeListenerFactory effectiveFactory = parseTreeFactory.orElse(
PdeParseTreeListener::new
);
List<String> effectiveDefaultImports = defaultImports.orElseGet(
() -> Arrays.asList(BASE_DEFAULT_IMPORTS)
);
List<String> effectiveCoreImports = coreImports.orElseGet(
() -> Arrays.asList(BASE_CORE_IMPORTS)
);
return new PdePreprocessor(
sketchName,
effectiveTabSize,
effectiveIsTesting,
effectiveFactory,
effectiveDefaultImports,
effectiveCoreImports,
destinationPackage
);
}
}
/**
* Factory which creates parse tree traversal listeners.
*
* The ANTLR parse tree listener is where the preprocessing edits are generated and some client
* code (like modes) may need to override some of the preprocessing edit behavior. Specifying
* this factory allows client code to replace the default PdeParseTreeListener that is used
* during preprocessing.
*/
public static interface ParseTreeListenerFactory {
/**
* Create a new processing listener.
*
* @param tokens The token stream with sketch code contents.
* @param sketchName The name of the sketch that will be preprocessed.
* @param tabSize The size (number of spaces) of the tabs.
* @param packageName The optional package name for generated code.
* @return The newly created listener.
*/
PdeParseTreeListener build(CommonTokenStream tokens, String sketchName, int tabSize,
Optional<String> packageName);
}
/* ==================================
* === Internal Utility Functions ===
* ==================================
*/
/**
* Utility function to substitute non ascii characters for escaped unicode character sequences.
*
@@ -1,37 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-19 The Processing Foundation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.mode.java.preproc;
/**
* Simple interface for strategy which can emit the full body of a processing sketch.
*/
public interface SourceEmitter {
/**
* Get the full body of the processing sketch.
*
* @return String processing sketch source code across all tabs.
*/
String getSource();
}
@@ -1,129 +0,0 @@
package processing.mode.java.preproc.code;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStreamRewriter;
import processing.mode.java.pdex.TextTransform;
/**
* Utility which generates and performs code edit operations.
*
* <p>
* Utility which generates and performs code edit operations, performing the edit immediately
* within a ANTLR rewriter but also generating a {TextTransform.Edit} for use with the JDT.
* </p>
*/
public class CodeEditOperationUtil {
/**
* Delete a single token.
*
* @param start The token to be deleted.
* @param rewriter The rewriter in which to immediately edit.
* @return The {TextTransform.Edit} corresponding to this change.
*/
public static TextTransform.Edit createDelete(Token start, TokenStreamRewriter rewriter) {
rewriter.delete(start);
return TextTransform.Edit.delete(start.getStartIndex(), start.getText().length());
}
/**
* Delete tokens between a start end end token inclusive.
*
* @param start The token to be deleted.
* @param stop The final token to be deleted.
* @param rewriter The rewriter in which to immediately edit.
* @return The {TextTransform.Edit} corresponding to this change.
*/
public static TextTransform.Edit createDelete(Token start, Token stop,
TokenStreamRewriter rewriter) {
rewriter.delete(start, stop);
int startIndex = start.getStartIndex();
int length = stop.getStopIndex() - startIndex + 1;
return TextTransform.Edit.delete(
startIndex,
length
);
}
/**
* Insert text after a token.
*
* @param start The position after which the text should be inserted.
* @param text The text to insert.
* @param rewriter The rewriter in which to immediately edit.
* @return The {TextTransform.Edit} corresponding to this change.
*/
public static TextTransform.Edit createInsertAfter(int start, String text,
TokenStreamRewriter rewriter) {
rewriter.insertAfter(start, text);
return TextTransform.Edit.insert(
start + 1,
text
);
}
/**
* Insert text after a token.
*
* @param start The token after which the text should be inserted.
* @param text The text to insert.
* @param rewriter The rewriter in which to immediately edit.
* @return The {TextTransform.Edit} corresponding to this change.
*/
public static TextTransform.Edit createInsertAfter(Token start, String text,
TokenStreamRewriter rewriter) {
rewriter.insertAfter(start, text);
return TextTransform.Edit.insert(
start.getStopIndex() + 1,
text
);
}
/**
* Insert text before a token.
*
* @param before Token before which the text should be inserted.
* @param text The text to insert.
* @param rewriter The rewriter in which to immediately edit.
* @return The {TextTransform.Edit} corresponding to this change.
*/
public static TextTransform.Edit createInsertBefore(Token before, String text,
TokenStreamRewriter rewriter) {
rewriter.insertBefore(before, text);
return TextTransform.Edit.insert(
before.getStartIndex(),
text
);
}
/**
* Insert text before a position in code.
*
* @param before The location before which to insert the text in tokens.
* @param beforeOffset THe location before which to insert the text in chars.
* @param text The text to insert.
* @param rewriter The rewriter in which to immediately edit.
* @return The {TextTransform.Edit} corresponding to this change.
*/
public static TextTransform.Edit createInsertBefore(int before, int beforeOffset, String text,
TokenStreamRewriter rewriter) {
rewriter.insertBefore(before, text);
return TextTransform.Edit.insert(
beforeOffset,
text
);
}
}
@@ -1,45 +0,0 @@
package processing.mode.java.preproc.code;
/**
* Utility to assist with preprocessing imports.
*/
public class ImportUtil {
/**
* Get the imports required by processing itself.
*
* @return List of imports required by processing itself.
*/
public static String[] getCoreImports() {
return new String[] {
"processing.core.*",
"processing.data.*",
"processing.event.*",
"processing.opengl.*"
};
}
/**
* Get the list of imports included by default on behalf of the user.
*
* @return List of "default" imports not required for processing but included for user
* convenience.
*/
public static String[] getDefaultImports() {
// These may change in-between (if the prefs panel adds this option)
//String prefsLine = Preferences.get("preproc.imports");
//return PApplet.splitTokens(prefsLine, ", ");
return new String[] {
"java.util.HashMap",
"java.util.ArrayList",
"java.io.File",
"java.io.BufferedReader",
"java.io.PrintWriter",
"java.io.InputStream",
"java.io.OutputStream",
"java.io.IOException"
};
}
}
@@ -1,91 +1,7 @@
package processing.mode.java.preproc.code;
import org.antlr.v4.runtime.TokenStreamRewriter;
import processing.mode.java.preproc.PdeParseTreeListener;
/**
* Decorator around a {TokenStreamRewriter}.
*
* <p>
* Decorator around a {TokenStreamRewriter} which converts input commands into something that the
* rewriter can understand but also generates edits saved to an input RewriteResultBuilder.
* Requires a call to finish() after completion of preprocessing.
* </p>
*/
public class PrintWriterWithEditGen {
private final TokenStreamRewriter writer;
private final RewriteResultBuilder rewriteResultBuilder;
private final int insertPoint;
private final StringBuilder editBuilder;
private final boolean before;
/**
* Create a new edit generator decorator.
*
* @param writer The writer to which edits should be immediately made.
* @param newRewriteResultBuilder The builder to which edits should be saved.
* @param newInsertPoint The point at which new values should be inserted.
* @param newBefore If true, the values will be inserted before the given insert point. If false,
* will, insert after the insertion point.
*/
public PrintWriterWithEditGen(TokenStreamRewriter writer,
RewriteResultBuilder newRewriteResultBuilder, int newInsertPoint, boolean newBefore) {
this.writer = writer;
rewriteResultBuilder = newRewriteResultBuilder;
insertPoint = newInsertPoint;
editBuilder = new StringBuilder();
before = newBefore;
}
/**
* Add an empty line into the code.
*/
public void addEmptyLine() {
addCode("\n");
}
/**
* Add code with a newline automatically appended.
*
* @param newCode The code to add.
*/
public void addCodeLine(String newCode) {
addCode(newCode + "\n");
}
/**
* Add code without a new line.
*
* @param newCode The code to add.
*/
public void addCode(String newCode) {
editBuilder.append(newCode);
}
/**
* Finalize edits made through this decorator.
*/
public void finish() {
String newCode = editBuilder.toString();
if (before) {
rewriteResultBuilder.addEdit(CodeEditOperationUtil.createInsertBefore(
insertPoint,
insertPoint,
newCode,
writer
));
} else {
rewriteResultBuilder.addEdit(CodeEditOperationUtil.createInsertAfter(
insertPoint,
newCode,
writer
));
}
rewriteResultBuilder.addOffset(SyntaxUtil.getCount(newCode, "\n"));
}
}
@@ -1,228 +0,0 @@
package processing.mode.java.preproc.code;
import org.antlr.v4.runtime.TokenStreamRewriter;
import processing.mode.java.preproc.PdePreprocessor;
import java.util.List;
import java.util.Optional;
/**
* Set of parameters required for re-writing as part of sketch preprocessing.
*/
public class RewriteParams {
private final String version;
private final String sketchName;
private final boolean isTesting;
private final TokenStreamRewriter rewriter;
private final PdePreprocessor.Mode mode;
private final boolean foundMain;
private final int lineOffset;
private final List<String> coreImports;
private final List<String> defaultImports;
private final List<String> codeFolderImports;
private final List<String> foundImports;
private final Optional<String> sketchWidth;
private final Optional<String> sketchHeight;
private final Optional<String> sketchRenderer;
private final boolean isSizeValidInGlobal;
private final boolean isSizeFullscreen;
/**
* Create a new set of parameters.
*
* @param newVersion The version of the preprocessor.
* @param newSketchName The name of the sketch.
* @param newisTesting Flag indicating if this is being run as part of automated testing.
* @param newRewriter The rewriter into which edits should be made.
* @param newMode The mode (like STATIC) in which processing is being run.
* @param newFoundMain Flag indicating if a user-provided main method was found in preprocessing.
* @param newLineOffset The line offset of the preprocessor prior to rewrite.
* @param newCoreImports The set of imports to include that are required for processing.
* @param newDefaultImports The set of imports included for user convenience.
* @param newCodeFolderImports The imports required to include other code in the code folder.
* @param newFoundImports The imports included by the user.
* @param newSketchWidth The width of the sketch or code used to generate it. If not included,
* call to size will not be made.
* @param newSketchHeight The height of the sketch or code used to generate it. If not included,
* call to size will not be made.
* @param newSketchRenderer The renderer like P2D.
* @param newIsSizeValidInGlobal Flag indicating if a call to size is valid when that call to size
* is made from sketch global context.
* @param newSizeIsFullscreen Indicate if in fullscreen mode.
*/
public RewriteParams(String newVersion, String newSketchName, boolean newisTesting,
TokenStreamRewriter newRewriter, PdePreprocessor.Mode newMode,
boolean newFoundMain, int newLineOffset, List<String> newCoreImports,
List<String> newDefaultImports, List<String> newCodeFolderImports,
List<String> newFoundImports, Optional<String> newSketchWidth,
Optional<String> newSketchHeight, Optional<String> newSketchRenderer,
boolean newIsSizeValidInGlobal, boolean newSizeIsFullscreen) {
version = newVersion;
sketchName = newSketchName;
isTesting = newisTesting;
rewriter = newRewriter;
mode = newMode;
foundMain = newFoundMain;
lineOffset = newLineOffset;
coreImports = newCoreImports;
defaultImports = newDefaultImports;
codeFolderImports = newCodeFolderImports;
foundImports = newFoundImports;
sketchWidth = newSketchWidth;
sketchHeight = newSketchHeight;
sketchRenderer = newSketchRenderer;
isSizeValidInGlobal = newIsSizeValidInGlobal;
isSizeFullscreen = newSizeIsFullscreen;
}
/**
* Get the version of the preprocessor.
*
* @return The version of the preprocessor.
*/
public String getVersion() {
return version;
}
/**
* The user provided or automated name of the sketch.
*
* @return The name of the sketch.
*/
public String getSketchName() {
return sketchName;
}
/**
* Determine if this code is being exercised in automated test.
*
* @return Flag indicating if this is being run as part of automated testing.
*/
public boolean getisTesting() {
return isTesting;
}
/**
* Get the rewriter to be used in rewriting.
*
* @return The rewriter into which edits should be made.
*/
public TokenStreamRewriter getRewriter() {
return rewriter;
}
/**
* Get the mode in which processing is being run.
*
* @return The mode (like STATIC) in which processing is being run.
*/
public PdePreprocessor.Mode getMode() {
return mode;
}
/**
* Determine if the user provided their own main method.
*
* @return Flag indicating if a user-provided main method was found in preprocessing.
*/
public boolean getFoundMain() {
return foundMain;
}
/**
* Determine the line offset of the preprocessor prior to rewrite.
*
* @return The line offset of the preprocessor prior to rewrite.
*/
public int getLineOffset() {
return lineOffset;
}
/**
* Get imports required for processing.
*
* @return The set of imports to include that are required for processing.
*/
public List<String> getCoreImports() {
return coreImports;
}
/**
* Get the imports added for user convenience.
*
* @return The set of imports included for user convenience.
*/
public List<String> getDefaultImports() {
return defaultImports;
}
/**
* The imports required to access other code in the code folder.
*
* @return The imports required to include other code in the code folder.
*/
public List<String> getCodeFolderImports() {
return codeFolderImports;
}
/**
* Get the users included by the user.
*
* @return The imports included by the user.
*/
public List<String> getFoundImports() {
return foundImports;
}
/**
* Get the code used to determine sketch width if given.
*
* @return The width of the sketch or code used to generate it. If not included, call to size will
* not be made. Not included means it is an empty optional.
*/
public Optional<String> getSketchWidth() {
return sketchWidth;
}
/**
* Get the code used to determine sketch height if given.
*
* @return The height of the sketch or code used to generate it. If not included, call to size
* will not be made. Not included means it is an empty optional.
*/
public Optional<String> getSketchHeight() {
return sketchHeight;
}
/**
* Get the user provided renderer or an empty optional if user has not provided renderer.
*
* @return The renderer like P2D if given.
*/
public Optional<String> getSketchRenderer() {
return sketchRenderer;
}
/**
* Determine if a call to size has been made in sketch global context.
*
* @return Flag indicating if a call to size is valid when that call to size is made from sketch
* global context.
*/
public boolean getIsSizeValidInGlobal() {
return isSizeValidInGlobal;
}
/**
* Determine if running in fullscreen.
*
* @return Flag indicating if in running in fullscreen.
*/
public boolean getIsSizeFullscreen() {
return isSizeFullscreen;
}
}
@@ -1,256 +0,0 @@
package processing.mode.java.preproc.code;
import org.antlr.v4.runtime.TokenStreamRewriter;
import processing.mode.java.preproc.PdePreprocessor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;
/**
* Builder to help generate a {RewriteParams}.
*/
public class RewriteParamsBuilder {
private final String version;
private Optional<String> sketchName;
private Optional<Boolean> isTesting;
private Optional<TokenStreamRewriter> rewriter;
private Optional<PdePreprocessor.Mode> mode;
private Optional<Boolean> foundMain;
private Optional<Integer> lineOffset;
private Optional<String> sketchWidth;
private Optional<String> sketchHeight;
private Optional<String> sketchRenderer;
private Optional<Boolean> isSizeValidInGlobal;
private Optional<Boolean> isSizeFullscreen;
private ArrayList<String> coreImports;
private ArrayList<String> defaultImports;
private ArrayList<String> codeFolderImports;
private ArrayList<String> foundImports;
/**
* Create a new params build.
*
* @param newVersion The version to include in generated RewriteParams.
*/
public RewriteParamsBuilder(String newVersion) {
version = newVersion;
coreImports = new ArrayList<>();
defaultImports = new ArrayList<>();
codeFolderImports = new ArrayList<>();
foundImports = new ArrayList<>();
sketchName = Optional.empty();
isTesting = Optional.empty();
rewriter = Optional.empty();
mode = Optional.empty();
foundMain = Optional.empty();
lineOffset = Optional.empty();
sketchWidth = Optional.empty();
sketchHeight = Optional.empty();
sketchRenderer = Optional.empty();
isSizeValidInGlobal = Optional.empty();
isSizeFullscreen = Optional.empty();
}
/**
* Specify the name of the sketch.
*
* @param newSketchName The name of the sketch.
*/
public void setSketchName(String newSketchName) {
sketchName = Optional.ofNullable(newSketchName);
}
/**
* Specify if this is being run as part of automated testing.
*
* @param newisTesting Flag indicating if this is being run as part of automated testing.
*/
public void setisTesting(boolean newisTesting) {
isTesting = Optional.of(newisTesting);
}
/**
* Specify rewriter into which edits should be made.
*
* @param newRewriter The rewriter into which edits should be made.
*/
public void setRewriter(TokenStreamRewriter newRewriter) {
rewriter = Optional.ofNullable(newRewriter);
}
/**
* Specify mode (like STATIC) in which processing is being run.
*
* @param newMode The mode (like STATIC) in which processing is being run.
*/
public void setMode(PdePreprocessor.Mode newMode) {
mode = Optional.ofNullable(newMode);
}
/**
* Specify if a user-provided main method was found in preprocessing.
*
* @param newFoundMain Flag indicating if a user-provided main method was found in preprocessing.
*/
public void setFoundMain(boolean newFoundMain) {
foundMain = Optional.of(newFoundMain);
}
/**
* Specify line offset of the preprocessor prior to rewrite.
*
* @param newLineOffset The line offset of the preprocessor prior to rewrite.
*/
public void setLineOffset(int newLineOffset) {
lineOffset = Optional.of(newLineOffset);
}
/**
* Specify width of the sketch.
*
* @param newSketchWidth The width of the sketch or code used to generate it. If not included,
* call to size will not be made.
*/
public void setSketchWidth(String newSketchWidth) {
sketchWidth = Optional.ofNullable(newSketchWidth);
}
/**
* Specify height of the sketch.
*
* @param newSketchHeight The height of the sketch or code used to generate it. If not included,
* call to size will not be made.
*/
public void setSketchHeight(String newSketchHeight) {
sketchHeight = Optional.ofNullable(newSketchHeight);
}
/**
* Specify renderer like P2D.
*
* @param newSketchRenderer The renderer like P2D.
*/
public void setSketchRenderer(String newSketchRenderer) {
sketchRenderer = Optional.ofNullable(newSketchRenderer);
}
/**
* Specify if the user made a valid call to size in sketch global context.
*
* @param newIsSizeValidInGlobal Flag indicating if a call to size is valid when that call to size
* is made from sketch global context.
*/
public void setIsSizeValidInGlobal(boolean newIsSizeValidInGlobal) {
isSizeValidInGlobal = Optional.of(newIsSizeValidInGlobal);
}
/**
* Specify if running in fullscreen.
*
* @param newIsSizeFullscreen Flag indicating if running in fullscreen.
*/
public void setIsSizeFullscreen(boolean newIsSizeFullscreen) {
isSizeFullscreen = Optional.of(newIsSizeFullscreen);
}
/**
* Add imports required for processing to function.
*
* @param newImports The set of imports to include that are required for processing.
*/
public void addCoreImports(Collection<String> newImports) {
coreImports.addAll(newImports);
}
/**
* Add imports that are included ahead of time for the user.
*
* @param newImports The set of imports included for user convenience.
*/
public void addDefaultImports(Collection<String> newImports) {
defaultImports.addAll(newImports);
}
/**
* Add imports required for the sketch to reach code in its own code folder.
*
* @param newImports The imports required to include other code in the code folder.
*/
public void addCodeFolderImports(Collection<String> newImports) {
codeFolderImports.addAll(newImports);
}
/**
* Add imports included manually by the user.
*
* @param newImports The imports included by the user.
*/
public void addFoundImports(Collection<String> newImports) {
foundImports.addAll(newImports);
}
/**
* Build a new set of rewrite parameters.
*
* @return Parameters required to execute {RewriterCodeGenerator};
*/
public RewriteParams build() {
if (sketchName.isEmpty()) {
throw new RuntimeException("Expected sketchName to be set");
}
if (isTesting.isEmpty()) {
throw new RuntimeException("Expected isTesting to be set");
}
if (rewriter.isEmpty()) {
throw new RuntimeException("Expected rewriter to be set");
}
if (mode.isEmpty()) {
throw new RuntimeException("Expected mode to be set");
}
if (foundMain.isEmpty()) {
throw new RuntimeException("Expected foundMain to be set");
}
if (lineOffset.isEmpty()) {
throw new RuntimeException("Expected lineOffset to be set");
}
if (isSizeValidInGlobal.isEmpty()) {
throw new RuntimeException("Expected isSizeValidInGlobal to be set");
}
if (isSizeFullscreen.isEmpty()) {
throw new RuntimeException("Expected isSizeFullscreen to be set");
}
return new RewriteParams(
version,
sketchName.get(),
isTesting.get(),
rewriter.get(),
mode.get(),
foundMain.get(),
lineOffset.get(),
coreImports,
defaultImports,
codeFolderImports,
foundImports,
sketchWidth,
sketchHeight,
sketchRenderer,
isSizeValidInGlobal.get(),
isSizeFullscreen.get()
);
}
}
@@ -1,332 +0,0 @@
package processing.mode.java.preproc.code;
import org.antlr.v4.runtime.TokenStreamRewriter;
import processing.app.Preferences;
import processing.core.PApplet;
import processing.mode.java.preproc.PdePreprocessor;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.StringJoiner;
/**
* Utility to rewrite code as part of preprocessing.
*/
public class RewriterCodeGenerator {
private final String indent1;
private final String indent2;
private final String indent3;
/**
* Create a new rewriter.
*
* @param indentSize Number of spaces in the indent.
*/
public RewriterCodeGenerator(int indentSize) {
final char[] indentChars = new char[indentSize];
Arrays.fill(indentChars, ' ');
indent1 = new String(indentChars);
indent2 = indent1 + indent1;
indent3 = indent2 + indent1;
}
/**
* Write preface code to wrap sketch code so that it is contained within a proper Java definition.
*
* @param headerWriter The writer into which the header should be written.
* @param params The parameters for the rewrite.
* @return Information about the completed rewrite.
*/
public RewriteResult writeHeader(TokenStreamRewriter headerWriter, RewriteParams params) {
RewriteResultBuilder resultBuilder = new RewriteResultBuilder();
PrintWriterWithEditGen decoratedWriter = new PrintWriterWithEditGen(
headerWriter,
resultBuilder,
0,
true
);
if (!params.getisTesting()) writePreprocessorComment(decoratedWriter, params, resultBuilder);
writeImports(decoratedWriter, params, resultBuilder);
PdePreprocessor.Mode mode = params.getMode();
boolean requiresClassHeader = mode == PdePreprocessor.Mode.STATIC;
requiresClassHeader = requiresClassHeader || mode == PdePreprocessor.Mode.ACTIVE;
boolean requiresStaticSketchHeader = mode == PdePreprocessor.Mode.STATIC;
if (requiresClassHeader) {
writeClassHeader(decoratedWriter, params, resultBuilder);
}
if (requiresStaticSketchHeader) {
writeStaticSketchHeader(decoratedWriter, params, resultBuilder);
}
decoratedWriter.finish();
return resultBuilder.build();
}
/**
* Write the footer for a sketch (finishes the constructs introduced in header like class def).
*
* @param footerWriter The writer through which the footer should be introduced.
* @param params The parameters for the rewrite.
* @param insertPoint The loction at which the footer should be written.
* @return Information about the completed rewrite.
*/
public RewriteResult writeFooter(TokenStreamRewriter footerWriter, RewriteParams params,
int insertPoint) {
RewriteResultBuilder resultBuilder = new RewriteResultBuilder();
PrintWriterWithEditGen decoratedWriter = new PrintWriterWithEditGen(
footerWriter,
resultBuilder,
insertPoint,
false
);
decoratedWriter.addEmptyLine();
PdePreprocessor.Mode mode = params.getMode();
boolean requiresStaticSketchFooter = mode == PdePreprocessor.Mode.STATIC;
boolean requiresClassWrap = mode == PdePreprocessor.Mode.STATIC;
requiresClassWrap = requiresClassWrap || mode == PdePreprocessor.Mode.ACTIVE;
if (requiresStaticSketchFooter) {
writeStaticSketchFooter(decoratedWriter, params, resultBuilder);
}
if (requiresClassWrap) {
writeExtraFieldsAndMethods(decoratedWriter, params, resultBuilder);
if (!params.getFoundMain()) writeMain(decoratedWriter, params, resultBuilder);
writeClassFooter(decoratedWriter, params, resultBuilder);
}
decoratedWriter.finish();
return resultBuilder.build();
}
/**
* Comment out sketch code before it is moved elsewhere in resulting Java.
*
* @param headerWriter The writer though which the comment should be introduced.
* @param params The parameters for the rewrite.
* @param resultBuilder Builder for reporting out results to the caller.
*/
private void writePreprocessorComment(PrintWriterWithEditGen headerWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
String dateStr = new SimpleDateFormat("YYYY-MM-dd").format(new Date());
String newCode = String.format(
"/* autogenerated by Processing preprocessor v%s on %s */",
params.getVersion(),
dateStr
);
headerWriter.addCodeLine(newCode);
}
/**
* Add imports as part of conversion from processing sketch to Java code.
*
* @param headerWriter The writer though which the imports should be introduced.
* @param params The parameters for the rewrite.
* @param resultBuilder Builder for reporting out results to the caller.
*/
private void writeImports(PrintWriterWithEditGen headerWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
writeImportList(headerWriter, params.getCoreImports(), params, resultBuilder);
writeImportList(headerWriter, params.getCodeFolderImports(), params, resultBuilder);
writeImportList(headerWriter, params.getFoundImports(), params, resultBuilder);
writeImportList(headerWriter, params.getDefaultImports(), params, resultBuilder);
}
/**
* Write a list of imports.
*
* @param headerWriter The writer though which the imports should be introduced.
* @param imports Collection of imports to introduce.
* @param params The parameters for the rewrite.
* @param resultBuilder Builder for reporting out results to the caller.
*/
private void writeImportList(PrintWriterWithEditGen headerWriter, List<String> imports, RewriteParams params,
RewriteResultBuilder resultBuilder) {
writeImportList(headerWriter, imports.toArray(new String[0]), params, resultBuilder);
}
/**
* Write a list of imports.
*
* @param headerWriter The writer though which the imports should be introduced.
* @param imports Collection of imports to introduce.
* @param params The parameters for the rewrite.
* @param resultBuilder Builder for reporting out results to the caller.
*/
private void writeImportList(PrintWriterWithEditGen headerWriter, String[] imports, RewriteParams params,
RewriteResultBuilder resultBuilder) {
for (String importDecl : imports) {
headerWriter.addCodeLine("import " + importDecl + ";");
}
if (imports.length > 0) {
headerWriter.addEmptyLine();
}
}
/**
* Write the prefix which defines the enclosing class for the sketch.
*
* @param headerWriter The writer through which the header should be introduced.
* @param params The parameters for the rewrite.
* @param resultBuilder Builder for reporting out results to the caller.
*/
private void writeClassHeader(PrintWriterWithEditGen headerWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
headerWriter.addCodeLine("public class " + params.getSketchName() + " extends PApplet {");
headerWriter.addEmptyLine();
}
/**
* Write the header for a static sketch (no methods).
*
* @param headerWriter The writer through which the header should be introduced.
* @param params The parameters for the rewrite.
* @param resultBuilder Builder for reporting out results to the caller.
*/
private void writeStaticSketchHeader(PrintWriterWithEditGen headerWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
headerWriter.addCodeLine(indent1 + "public void setup() {");
}
/**
* Write the bottom of the sketch code for static mode.
*
* @param footerWriter The footer into which the text should be written.
* @param params The parameters for the rewrite.
* @param resultBuilder Builder for reporting out results to the caller.
*/
private void writeStaticSketchFooter(PrintWriterWithEditGen footerWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
footerWriter.addCodeLine(indent2 + "noLoop();");
footerWriter.addCodeLine(indent1 + "}");
}
/**
* Write code supporting speical functions like size.
*
* @param classBodyWriter The writer into which the code should be written. Should be for class
* body.
* @param params The parameters for the rewrite.
* @param resultBuilder Builder for reporting out results to the caller.
*/
private void writeExtraFieldsAndMethods(PrintWriterWithEditGen classBodyWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
if (!params.getIsSizeValidInGlobal()) {
return;
}
String settingsOuterTemplate = indent1 + "public void settings() { %s }";
String settingsInner;
if (params.getIsSizeFullscreen()) {
String fullscreenInner = params.getSketchRenderer().orElse("");
settingsInner = String.format("fullScreen(%s);", fullscreenInner);
} else {
if (params.getSketchWidth().isEmpty() || params.getSketchHeight().isEmpty()) {
return;
}
StringJoiner argJoiner = new StringJoiner(",");
argJoiner.add(params.getSketchWidth().get());
argJoiner.add(params.getSketchHeight().get());
if (params.getSketchRenderer().isPresent()) {
argJoiner.add(params.getSketchRenderer().get());
}
settingsInner = String.format("size(%s);", argJoiner.toString());
}
String newCode = String.format(settingsOuterTemplate, settingsInner);
classBodyWriter.addEmptyLine();
classBodyWriter.addCodeLine(newCode);
}
/**
* Write the main method.
*
* @param footerWriter The writer into which the footer should be written.
* @param params The parameters for the rewrite.
* @param resultBuilder Builder for reporting out results to the caller.
*/
private void writeMain(PrintWriterWithEditGen footerWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
footerWriter.addEmptyLine();
footerWriter.addCodeLine(indent1 + "static public void main(String[] passedArgs) {");
footerWriter.addCode(indent2 + "String[] appletArgs = new String[] { ");
{ // assemble line with applet args
if (Preferences.getBoolean("export.application.fullscreen")) {
footerWriter.addCode("\"" + PApplet.ARGS_FULL_SCREEN + "\", ");
String bgColor = Preferences.get("run.present.bgcolor");
footerWriter.addCode("\"" + PApplet.ARGS_BGCOLOR + "=" + bgColor + "\", ");
if (Preferences.getBoolean("export.application.stop")) {
String stopColor = Preferences.get("run.present.stop.color");
footerWriter.addCode("\"" + PApplet.ARGS_STOP_COLOR + "=" + stopColor + "\", ");
} else {
footerWriter.addCode("\"" + PApplet.ARGS_HIDE_STOP + "\", ");
}
}
footerWriter.addCode("\"" + params.getSketchName() + "\"");
}
footerWriter.addCodeLine(" };");
footerWriter.addCodeLine(indent2 + "if (passedArgs != null) {");
footerWriter.addCodeLine(indent3 + "PApplet.main(concat(appletArgs, passedArgs));");
footerWriter.addCodeLine(indent2 + "} else {");
footerWriter.addCodeLine(indent3 + "PApplet.main(appletArgs);");
footerWriter.addCodeLine(indent2 + "}");
footerWriter.addCodeLine(indent1 + "}");
}
/**
* Write the end of the class body for the footer.
*
* @param footerWriter The writer into which the footer should be written.
* @param params The parameters for the rewrite.
* @param resultBuilder Builder for reporting out results to the caller.
*/
private void writeClassFooter(PrintWriterWithEditGen footerWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
footerWriter.addCodeLine("}");
}
}
@@ -25,8 +25,6 @@ import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import processing.mode.java.preproc.SourceEmitter;
import java.util.Optional;
@@ -100,4 +98,31 @@ public class PdeIssueEmitter extends BaseErrorListener {
));
}
/**
* Simple interface for strategy which can emit the full body of a processing sketch.
*/
public static interface SourceEmitter {
/**
* Get the full body of the processing sketch.
*
* @return String processing sketch source code across all tabs.
*/
String getSource();
}
/**
* Interface for listener that responds to issues reported by the preprocessor.
*/
public static interface PdePreprocessIssueListener {
/**
* Callback to invoke when an issue is encountered in preprocesing.
*
* @param issue Description of the issue.
*/
void onIssue(PdePreprocessIssue issue);
}
}
@@ -1,9 +0,0 @@
package processing.mode.java.preproc.issue;
import processing.mode.java.preproc.issue.PdePreprocessIssue;
public interface PdePreprocessIssueListener {
void onIssue(PdePreprocessIssue issue);
}
@@ -88,8 +88,12 @@ public class ParserTests {
}
static void expectGood(final String id, boolean ignoreWhitespace) {
expectGood(id, ignoreWhitespace, Optional.empty());
}
static void expectGood(final String id, boolean ignoreWhitespace, Optional<String> packageName) {
try {
final String program = preprocess(id, res(id + ".pde"));
final String program = preprocess(id, res(id + ".pde"), packageName);
boolean successful = compile(id, program);
if (successful) {
System.err.println("----------------------------");
@@ -368,6 +372,11 @@ public class ParserTests {
expectGood("typeinference");
}
@Test
public void testPackage() {
expectGood("packageTest", true, Optional.of("test.subtest"));
}
private static boolean compile(String id, String program) {
// Create compilable AST to get syntax problems
CompilationUnit compilableCU = JdtCompilerUtil.makeAST(
@@ -5,6 +5,8 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.Optional;
import processing.app.Preferences;
import processing.app.SketchException;
import processing.mode.java.preproc.PdePreprocessor;
@@ -37,9 +39,25 @@ public class ProcessingTestUtil {
static String preprocess(final String name, final File resource)
throws SketchException {
return preprocess(name, resource, Optional.empty());
}
static String preprocess(final String name, final File resource, Optional<String> optionalPackage)
throws SketchException {
final String program = read(resource);
final StringWriter out = new StringWriter();
PreprocessorResult result = new PdePreprocessor(name, 4, true).write(out, program);
PdePreprocessor.PdePreprocessorBuilder builder = PdePreprocessor.builderFor(name);
builder.setTabSize(4);
builder.setIsTesting(true);
if (optionalPackage.isPresent()) {
builder.setDestinationPackage(optionalPackage.get());
}
PdePreprocessor preprocessor = builder.build();
PreprocessorResult result = preprocessor.write(out, program);
if (result.getPreprocessIssues().size() > 0) {
throw new PdePreprocessIssueException(result.getPreprocessIssues().get(0));
@@ -1,103 +0,0 @@
package processing.mode.java.preproc.code;
import org.antlr.v4.runtime.BufferedTokenStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.TokenStreamRewriter;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import processing.mode.java.pdex.TextTransform;
import static org.junit.Assert.*;
public class CodeEditOperationUtilTest {
private TokenStreamRewriter tokenStreamRewriter;
private Token sampleStart;
private Token sampleEnd;
@Before
public void setUp() {
tokenStreamRewriter = Mockito.mock(TokenStreamRewriter.class);
sampleStart = Mockito.mock(Token.class);
Mockito.when(sampleStart.getStartIndex()).thenReturn(5);
Mockito.when(sampleStart.getText()).thenReturn("test");
sampleEnd = Mockito.mock(Token.class);
Mockito.when(sampleEnd.getStartIndex()).thenReturn(10);
Mockito.when(sampleEnd.getText()).thenReturn("testing");
}
@Test
public void createDeleteSingle() {
TextTransform.Edit edit = CodeEditOperationUtil.createDelete(sampleStart, tokenStreamRewriter);
Assert.assertNotNull(edit);
Mockito.verify(tokenStreamRewriter).delete(sampleStart);
}
@Test
public void createDeleteRange() {
TextTransform.Edit edit = CodeEditOperationUtil.createDelete(
sampleStart,
sampleEnd,
tokenStreamRewriter
);
Assert.assertNotNull(edit);
Mockito.verify(tokenStreamRewriter).delete(sampleStart, sampleEnd);
}
@Test
public void createInsertAfterLocation() {
TextTransform.Edit edit = CodeEditOperationUtil.createInsertAfter(
5,
"text",
tokenStreamRewriter
);
Assert.assertNotNull(edit);
Mockito.verify(tokenStreamRewriter).insertAfter(5, "text");
}
@Test
public void createInsertAfterToken() {
TextTransform.Edit edit = CodeEditOperationUtil.createInsertAfter(
sampleStart,
"text",
tokenStreamRewriter
);
Assert.assertNotNull(edit);
Mockito.verify(tokenStreamRewriter).insertAfter(sampleStart, "text");
}
@Test
public void createInsertBeforeToken() {
TextTransform.Edit edit = CodeEditOperationUtil.createInsertBefore(
sampleStart,
"text",
tokenStreamRewriter
);
Assert.assertNotNull(edit);
Mockito.verify(tokenStreamRewriter).insertBefore(sampleStart, "text");
}
@Test
public void createInsertBeforeLocation() {
TextTransform.Edit edit = CodeEditOperationUtil.createInsertBefore(
5,
5,
"text",
tokenStreamRewriter
);
Assert.assertNotNull(edit);
Mockito.verify(tokenStreamRewriter).insertBefore(5, "text");
}
}
@@ -6,6 +6,7 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import processing.mode.java.pdex.TextTransform;
import processing.mode.java.preproc.PdeParseTreeListener;
import java.util.List;
@@ -24,7 +25,7 @@ public class PrintWriterWithEditGenTest {
@Test
public void addEmptyLineBefore() {
PrintWriterWithEditGen editGen = createGen(true);
PdeParseTreeListener.PrintWriterWithEditGen editGen = createGen(true);
editGen.addEmptyLine();
editGen.finish();
@@ -36,7 +37,7 @@ public class PrintWriterWithEditGenTest {
@Test
public void addCodeLineBefore() {
PrintWriterWithEditGen editGen = createGen(true);
PdeParseTreeListener.PrintWriterWithEditGen editGen = createGen(true);
editGen.addCodeLine("test");
editGen.finish();
@@ -48,7 +49,7 @@ public class PrintWriterWithEditGenTest {
@Test
public void addCodeBefore() {
PrintWriterWithEditGen editGen = createGen(true);
PdeParseTreeListener.PrintWriterWithEditGen editGen = createGen(true);
editGen.addCode("test");
editGen.finish();
@@ -60,7 +61,7 @@ public class PrintWriterWithEditGenTest {
@Test
public void addEmptyLineAfter() {
PrintWriterWithEditGen editGen = createGen(false);
PdeParseTreeListener.PrintWriterWithEditGen editGen = createGen(false);
editGen.addEmptyLine();
editGen.finish();
@@ -72,7 +73,7 @@ public class PrintWriterWithEditGenTest {
@Test
public void addCodeLineAfter() {
PrintWriterWithEditGen editGen = createGen(false);
PdeParseTreeListener.PrintWriterWithEditGen editGen = createGen(false);
editGen.addCodeLine("test");
editGen.finish();
@@ -84,7 +85,7 @@ public class PrintWriterWithEditGenTest {
@Test
public void addCodeAfter() {
PrintWriterWithEditGen editGen = createGen(false);
PdeParseTreeListener.PrintWriterWithEditGen editGen = createGen(false);
editGen.addCode("test");
editGen.finish();
@@ -94,8 +95,8 @@ public class PrintWriterWithEditGenTest {
Mockito.verify(tokenStreamRewriter).insertAfter(5, "test");
}
private PrintWriterWithEditGen createGen(boolean before) {
return new PrintWriterWithEditGen(
private PdeParseTreeListener.PrintWriterWithEditGen createGen(boolean before) {
return new PdeParseTreeListener.PrintWriterWithEditGen(
tokenStreamRewriter,
rewriteResultBuilder,
5,
+33
View File
@@ -0,0 +1,33 @@
package test.subtest;
import processing.core.*;
import processing.data.*;
import processing.event.*;
import processing.opengl.*;
import java.util.*;
import java.util.HashMap;
import java.util.ArrayList;
import java.io.File;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
public class packageTest extends PApplet {
public void setup() {
List<String> test = new ArrayList<>();
noLoop();
}
static public void main(String[] passedArgs) {
String[] appletArgs = new String[] { "packageTest" };
if (passedArgs != null) {
PApplet.main(concat(appletArgs, passedArgs));
} else {
PApplet.main(appletArgs);
}
}
}
+3
View File
@@ -0,0 +1,3 @@
import java.util.*;
List<String> test = new ArrayList<>();