Merged supporting classes into PdeParseTreeListener.

An explicit goal of @benfry is to reduce class count and this PR cleans up edits made within preproc to merge supporting classes and utility functions of PdeParseTreeListener into PdeParseTreeListener itself. This includes removal of ImportUtil per https://github.com/processing/processing4/issues/10.
This commit is contained in:
A Pottinger
2019-10-11 08:38:38 -07:00
parent d08048eca9
commit 96e4f0a203
8 changed files with 775 additions and 873 deletions

View File

@@ -34,7 +34,6 @@ 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;
@@ -281,6 +280,52 @@ public class PdePreprocessor {
private Optional<List<String>> defaultImports;
private Optional<List<String>> coreImports;
/**
* 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();
@@ -368,11 +413,11 @@ public class PdePreprocessor {
);
List<String> effectiveDefaultImports = defaultImports.orElseGet(
() -> Arrays.asList(ImportUtil.getDefaultImports())
() -> Arrays.asList(BASE_DEFAULT_IMPORTS)
);
List<String> effectiveCoreImports = coreImports.orElseGet(
() -> Arrays.asList(ImportUtil.getCoreImports())
() -> Arrays.asList(BASE_CORE_IMPORTS)
);
return new PdePreprocessor(

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

@@ -34,326 +34,4 @@ public class RewriterCodeGenerator {
indent3 = indent2 + indent1;
}
/**
* Prepare 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 prepareHeader(TokenStreamRewriter headerWriter, RewriteParams params) {
RewriteResultBuilder resultBuilder = new RewriteResultBuilder();
PrintWriterWithEditGen decoratedWriter = new PrintWriterWithEditGen(
headerWriter,
resultBuilder,
0,
true
);
writeHeaderContents(decoratedWriter, params, resultBuilder);
decoratedWriter.finish();
return resultBuilder.build();
}
/**
* Prepare 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 prepareFooter(TokenStreamRewriter footerWriter, RewriteParams params,
int insertPoint) {
RewriteResultBuilder resultBuilder = new RewriteResultBuilder();
PrintWriterWithEditGen decoratedWriter = new PrintWriterWithEditGen(
footerWriter,
resultBuilder,
insertPoint,
false
);
writeFooterContents(decoratedWriter, params, resultBuilder);
decoratedWriter.finish();
return resultBuilder.build();
}
/**
* Write the contents of the header using a prebuilt print writer.
*
* @param decoratedWriter he 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.
*/
protected void writeHeaderContents(PrintWriterWithEditGen decoratedWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
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);
}
}
/**
* Write the contents of the footer using a prebuilt print writer.
*
* @param decoratedWriter he 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.
*/
protected void writeFooterContents(PrintWriterWithEditGen decoratedWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
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);
}
}
/**
* 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.
*/
protected 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.
*/
protected 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.
*/
protected 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.
*/
protected 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.
*/
protected 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.
*/
protected 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.
*/
protected void writeStaticSketchFooter(PrintWriterWithEditGen footerWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
footerWriter.addCodeLine(indent2 + "noLoop();");
footerWriter.addCodeLine(indent1 + "}");
}
/**
* Write code supporting special 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.
*/
protected 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.
*/
protected 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.
*/
protected void writeClassFooter(PrintWriterWithEditGen footerWriter, RewriteParams params,
RewriteResultBuilder resultBuilder) {
footerWriter.addCodeLine("}");
}
}