Merge branch 'master' into static_imports

This commit is contained in:
Sam Pottinger
2019-11-04 17:06:32 -08:00
69 changed files with 1489 additions and 2187 deletions

View File

@@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-15 The Processing Foundation
Copyright (c) 2012-19 The Processing Foundation
Copyright (c) 2008-12 Ben Fry and Casey Reas
This program is free software; you can redistribute it and/or modify
@@ -42,8 +42,6 @@ import processing.mode.java.runner.Runner;
/**
* Class to handle running Processing from the command line.
*
* @author fry
*/
public class Commander implements RunnerListener {
static final String helpArg = "--help";
@@ -65,7 +63,6 @@ public class Commander implements RunnerListener {
static final int BUILD = 1;
static final int RUN = 2;
static final int PRESENT = 3;
// static final int EXPORT_APPLET = 4;
static final int EXPORT = 4;
Sketch sketch;
@@ -74,19 +71,6 @@ public class Commander implements RunnerListener {
PrintStream systemErr;
static public void main(String[] args) {
// Do this early so that error messages go to the console
Base.setCommandLine();
// init the platform so that prefs and other native code is ready to go
Platform.init();
// make sure a full JDK is installed
//Base.initRequirements();
// launch command line handler
new Commander(args);
}
public Commander(String[] args) {
String sketchPath = null;
File sketchFolder = null;
@@ -152,7 +136,6 @@ public class Commander implements RunnerListener {
embedJava = false;
} else if (arg.startsWith(platformArg)) {
// complainAndQuit("The --platform option has been removed from Processing 2.1.", false);
String platformStr = arg.substring(platformArg.length());
platform = Platform.getIndex(platformStr);
if (platform == -1) {
@@ -160,17 +143,6 @@ public class Commander implements RunnerListener {
"'windows', 'macosx', or 'linux'.", true);
}
} else if (arg.startsWith(bitsArg)) {
complainAndQuit("The --bits option has been removed.", false);
// String bitsStr = arg.substring(bitsArg.length());
// if (bitsStr.equals("32")) {
// platformBits = 32;
// } else if (bitsStr.equals("64")) {
// platformBits = 64;
// } else {
// complainAndQuit("Bits should be either 32 or 64, not " + bitsStr, true);
// }
} else if (arg.startsWith(sketchArg)) {
sketchPath = arg.substring(sketchArg.length());
sketchFolder = new File(sketchPath);
@@ -199,13 +171,6 @@ public class Commander implements RunnerListener {
}
String[] sketchArgs = PApplet.subset(args, argOffset);
// if ((outputPath == null) &&
// (task == PREPROCESS || task == BUILD ||
// task == RUN || task == PRESENT)) {
// complainAndQuit("An output path must be specified when using " +
// preprocArg + ", " + buildArg + ", " +
// runArg + ", or " + presentArg + ".");
// }
if (task == HELP) {
printCommandLine(systemOut);
System.exit(0);
@@ -256,8 +221,6 @@ public class Commander implements RunnerListener {
boolean success = false;
// JavaMode javaMode =
// new JavaMode(null, Base.getContentFile("modes/java"));
JavaMode javaMode = (JavaMode)
ModeContribution.load(null, Platform.getContentFile("modes/java"),
"processing.mode.java.JavaMode").getMode();
@@ -389,9 +352,6 @@ public class Commander implements RunnerListener {
out.println("--no-java Do not embed Java. Use at your own risk!");
out.println("--platform Specify the platform (export to application only).");
out.println(" Should be one of 'windows', 'macosx', or 'linux'.");
// out.println("--bits Must be specified if libraries are used that are");
// out.println(" 32- or 64-bit specific such as the OpenGL library.");
// out.println(" Otherwise specify 0 or leave it out.");
out.println();
out.println("The --build, --run, --present, or --export must be the final parameter");
@@ -406,22 +366,31 @@ public class Commander implements RunnerListener {
@Override
public void startIndeterminate() {
}
public void startIndeterminate() { }
@Override
public void stopIndeterminate() {
}
public void stopIndeterminate() { }
@Override
public void statusHalt() {
}
public void statusHalt() { }
@Override
public boolean isHalted() {
return false;
}
static public void main(String[] args) {
// Do this early so that error messages go to the console
Base.setCommandLine();
// init the platform so that prefs and other native code is ready to go
Platform.init();
// launch command line handler
new Commander(args);
}
}

View File

@@ -31,9 +31,6 @@ import java.io.*;
import java.lang.reflect.Method;
import java.util.HashMap;
//import org.eclipse.jdt.core.compiler.batch.BatchCompiler;
//import org.eclipse.jdt.core.compiler.CompilationProgress;
public class Compiler {

View File

@@ -139,7 +139,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);
}

View File

@@ -1,3 +1,26 @@
/* -*- 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
Copyright (c) 2004-12 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
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;
import java.awt.*;
@@ -125,7 +148,7 @@ public class JavaEditor extends Editor {
public PdePreprocessor createPreprocessor(final String sketchName) {
return new PdePreprocessor(sketchName);
return PdePreprocessor.builderFor(sketchName).build();
}

View File

@@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-15 The Processing Foundation
Copyright (c) 2012-19 The Processing Foundation
Copyright (c) 2004-12 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
@@ -24,15 +24,15 @@
package processing.mode.java;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import processing.app.Preferences;
import processing.app.Sketch;
import processing.app.syntax.*;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.PdeInputHandler;
import processing.app.ui.Editor;
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
/**
* Filters key events for tab expansion/indent/etc. This is very old code
@@ -41,9 +41,9 @@ import java.util.Arrays;
*/
public class JavaInputHandler extends PdeInputHandler {
/** ctrl-alt on windows and linux, cmd-alt on mac os x */
static final int CTRL_ALT = ActionEvent.ALT_MASK |
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
// /** ctrl-alt on windows and linux, cmd-alt on mac os x */
// static final int CTRL_ALT = ActionEvent.ALT_MASK |
// Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
public JavaInputHandler(Editor editor) {
@@ -66,7 +66,8 @@ public class JavaInputHandler extends PdeInputHandler {
Sketch sketch = editor.getSketch();
JEditTextArea textarea = editor.getTextArea();
if ((event.getModifiers() & InputEvent.META_MASK) != 0) {
if (event.isMetaDown()) {
//if ((event.getModifiers() & InputEvent.META_MASK) != 0) {
//event.consume(); // does nothing
return false;
}
@@ -76,8 +77,8 @@ public class JavaInputHandler extends PdeInputHandler {
sketch.setModified(true);
}
if ((code == KeyEvent.VK_UP) &&
((event.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
if ((code == KeyEvent.VK_UP) && event.isControlDown()) {
//((event.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
// back up to the last empty line
char contents[] = textarea.getText().toCharArray();
//int origIndex = textarea.getCaretPosition() - 1;
@@ -104,7 +105,8 @@ public class JavaInputHandler extends PdeInputHandler {
// if the first char, index will be -2
if (index < 0) index = 0;
if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
//if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
if (event.isShiftDown()) {
textarea.setSelectionStart(caretIndex);
textarea.setSelectionEnd(index);
} else {
@@ -113,8 +115,8 @@ public class JavaInputHandler extends PdeInputHandler {
event.consume();
// return true;
} else if ((code == KeyEvent.VK_DOWN) &&
((event.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
} else if ((code == KeyEvent.VK_DOWN) && event.isControlDown()) {
//((event.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
char contents[] = textarea.getText().toCharArray();
int caretIndex = textarea.getCaretPosition();
@@ -136,7 +138,8 @@ public class JavaInputHandler extends PdeInputHandler {
index++;
}
if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
//if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
if (event.isShiftDown()) {
textarea.setSelectionStart(caretIndex);
textarea.setSelectionEnd(index);
} else {
@@ -146,7 +149,8 @@ public class JavaInputHandler extends PdeInputHandler {
// return true;
} else if (c == 9) {
if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
//if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
if (event.isShiftDown()) {
// if shift is down, the user always expects an outdent
// http://code.google.com/p/processing/issues/detail?id=458
editor.handleOutdent();
@@ -317,7 +321,8 @@ public class JavaInputHandler extends PdeInputHandler {
public boolean handleTyped(KeyEvent event) {
char c = event.getKeyChar();
if ((event.getModifiers() & InputEvent.CTRL_MASK) != 0) {
//if ((event.getModifiers() & InputEvent.CTRL_MASK) != 0) {
if (event.isControlDown()) { // TODO true on typed? [fry 191007]
// on linux, ctrl-comma (prefs) being passed through to the editor
if (c == KeyEvent.VK_COMMA) {
event.consume();

View File

@@ -4,7 +4,7 @@
Part of the Processing project - http://processing.org
Copyright (c) 2010-11 Ben Fry and Casey Reas
Copyright (c) 2012-15 The Processing Foundation
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
@@ -37,6 +37,7 @@ import processing.app.*;
import processing.app.ui.Editor;
import processing.app.ui.EditorException;
import processing.app.ui.EditorState;
import processing.mode.java.runner.Runner;
import processing.mode.java.tweak.SketchParser;

View File

@@ -21,7 +21,6 @@
package processing.mode.java;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.util.ArrayList;
import java.util.List;
@@ -131,7 +130,7 @@ public class JavaToolbar extends EditorToolbar {
@Override
public void handleRun(int modifiers) {
boolean shift = (modifiers & InputEvent.SHIFT_MASK) != 0;
boolean shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
if (shift) {
jeditor.handlePresent();
} else {

View File

@@ -1790,7 +1790,7 @@ public class CompletionGenerator {
// Now parse the expression into an ASTNode object
ASTNode nearestNode;
ASTParser parser = ASTParser.newParser(AST.JLS8);
ASTParser parser = ASTParser.newParser(AST.JLS11);
parser.setKind(ASTParser.K_EXPRESSION);
parser.setSource(phrase.toCharArray());
ASTNode testnode = parser.createAST(null);

View File

@@ -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));
}

View File

@@ -20,22 +20,31 @@ along with this program; if not, write to the Free Software Foundation, Inc.
package processing.mode.java.pdex.util;
import com.google.classpath.ClassPathFactory;
import processing.app.*;
import processing.mode.java.JavaMode;
import processing.mode.java.pdex.ImportStatement;
import processing.mode.java.pdex.PreprocessedSketch;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Paths;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.classpath.ClassPathFactory;
import processing.app.Library;
import processing.app.Messages;
import processing.app.Sketch;
import processing.app.SketchException;
import processing.app.Util;
import processing.mode.java.JavaMode;
import processing.mode.java.pdex.ImportStatement;
import processing.mode.java.pdex.PreprocessedSketch;
/**
* Builder which generates runtime paths using a series of caches.

View File

@@ -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);
}

View File

@@ -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.
*

View File

@@ -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();
}

View File

@@ -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
);
}
}

View File

@@ -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"
};
}
}

View File

@@ -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"));
}
}

View File

@@ -1,229 +0,0 @@
package processing.mode.java.preproc.code;
import org.antlr.v4.runtime.TokenStreamRewriter;
import processing.mode.java.pdex.ImportStatement;
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<ImportStatement> coreImports;
private final List<ImportStatement> defaultImports;
private final List<ImportStatement> codeFolderImports;
private final List<ImportStatement> 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<ImportStatement> newCoreImports,
List<ImportStatement> newDefaultImports, List<ImportStatement> newCodeFolderImports,
List<ImportStatement> 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<ImportStatement> getCoreImports() {
return coreImports;
}
/**
* Get the imports added for user convenience.
*
* @return The set of imports included for user convenience.
*/
public List<ImportStatement> 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<ImportStatement> getCodeFolderImports() {
return codeFolderImports;
}
/**
* Get the users included by the user.
*
* @return The imports included by the user.
*/
public List<ImportStatement> 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;
}
}

View File

@@ -1,257 +0,0 @@
package processing.mode.java.preproc.code;
import org.antlr.v4.runtime.TokenStreamRewriter;
import processing.mode.java.pdex.ImportStatement;
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<ImportStatement> coreImports;
private ArrayList<ImportStatement> defaultImports;
private ArrayList<ImportStatement> codeFolderImports;
private ArrayList<ImportStatement> 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<ImportStatement> 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<ImportStatement> 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<ImportStatement> newImports) {
codeFolderImports.addAll(newImports);
}
/**
* Add imports included manually by the user.
*
* @param newImports The imports included by the user.
*/
public void addFoundImports(Collection<ImportStatement> 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()
);
}
}

View File

@@ -1,333 +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.pdex.ImportStatement;
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<ImportStatement> imports, RewriteParams params,
RewriteResultBuilder resultBuilder) {
writeImportList(headerWriter, imports.toArray(new ImportStatement[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, ImportStatement[] imports, RewriteParams params,
RewriteResultBuilder resultBuilder) {
for (ImportStatement importDecl : imports) {
headerWriter.addCodeLine(importDecl.getFullSourceLine());
}
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("}");
}
}

View File

@@ -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);
}
}

View File

@@ -1,9 +0,0 @@
package processing.mode.java.preproc.issue;
import processing.mode.java.preproc.issue.PdePreprocessIssue;
public interface PdePreprocessIssueListener {
void onIssue(PdePreprocessIssue issue);
}

View File

@@ -662,10 +662,8 @@ public class Runner implements MessageConsumer {
protected Connector findConnector(String connectorName) {
// List connectors =
// com.sun.jdi.Bootstrap.virtualMachineManager().allConnectors();
List<Connector> connectors =
org.eclipse.jdi.Bootstrap.virtualMachineManager().allConnectors();
com.sun.jdi.Bootstrap.virtualMachineManager().allConnectors();
// // debug: code to list available connectors
// Iterator iter2 = connectors.iterator();

View File

@@ -23,6 +23,7 @@ package processing.mode.java.tweak;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Comparator;
import java.util.Locale;
@@ -171,7 +172,7 @@ public class Handle {
} else if ("float".equals(type)) {
BigDecimal bd = new BigDecimal(value.floatValue());
bd = bd.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP);
bd = bd.setScale(decimalPlaces, RoundingMode.HALF_UP);
newValue = bd.floatValue();
strNewValue = String.format(Locale.US, textFormat, newValue.floatValue());
}