mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
While changing PdePreprocessor to make it more amenable to unit tests, I discovered a bug in my last fix. This fixes the bug while changing the construction of PdePreprocessor. Now instead of emitting the literal text "public" while walking the tree, I modify the tree to contain the "public" modifier on methods that lack explicit access.
This commit is contained in:
@@ -107,7 +107,8 @@ class Build {
|
||||
|
||||
// grab code from current editing window
|
||||
sketch.prepare();
|
||||
className = sketch.preprocess(buildPath, new Preproc());
|
||||
className = sketch.preprocess(buildPath, new Preproc(buildPath, sketch
|
||||
.getName()));
|
||||
if (className != null) {
|
||||
final File androidXML = new File(androidFolder, "AndroidManifest.xml");
|
||||
writeAndroidManifest(androidXML, sketch.getName(), className);
|
||||
@@ -143,6 +144,9 @@ class Build {
|
||||
} catch (final RunnerException e) {
|
||||
editor.statusError(e);
|
||||
return false;
|
||||
} catch (final IOException e) {
|
||||
editor.statusError(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -320,6 +324,12 @@ class Build {
|
||||
}
|
||||
|
||||
class Preproc extends PdePreprocessor {
|
||||
|
||||
public Preproc(final String buildPath, final String sketchName)
|
||||
throws IOException {
|
||||
super(buildPath, sketchName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeImports(final PrintStream out) {
|
||||
out.println("package " + getPackageName() + ";");
|
||||
|
||||
@@ -1202,7 +1202,11 @@ public class Sketch {
|
||||
* @return null if compilation failed, main class name if not
|
||||
*/
|
||||
public String preprocess(String buildPath) throws RunnerException {
|
||||
return preprocess(buildPath, new PdePreprocessor());
|
||||
try {
|
||||
return preprocess(buildPath, new PdePreprocessor(buildPath, name));
|
||||
} catch (IOException e) {
|
||||
throw new RunnerException("Error while preprocessing", true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1250,10 +1254,7 @@ public class Sketch {
|
||||
// it only applies to the code after it's been written to the .java file.
|
||||
int headerOffset = 0;
|
||||
try {
|
||||
headerOffset = preprocessor.writePrefix(bigCode.toString(),
|
||||
buildPath,
|
||||
name,
|
||||
codeFolderPackages);
|
||||
headerOffset = preprocessor.writePrefix(bigCode.toString(), codeFolderPackages);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
fnfe.printStackTrace();
|
||||
String msg = "Build folder disappeared or could not be written";
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.util.Stack;
|
||||
import processing.app.Preferences;
|
||||
import processing.app.antlr.PdeTokenTypes;
|
||||
import processing.app.debug.RunnerException;
|
||||
import antlr.CommonASTWithHiddenTokens;
|
||||
import antlr.CommonHiddenStreamToken;
|
||||
import antlr.collections.AST;
|
||||
|
||||
@@ -62,7 +63,7 @@ public class PdeEmitter implements PdeTokenTypes {
|
||||
* Most hidden tokens are dumped from this function.
|
||||
*/
|
||||
private void dumpHiddenAfter(final AST ast) {
|
||||
dumpHiddenTokens(((antlr.CommonASTWithHiddenTokens) ast).getHiddenAfter());
|
||||
dumpHiddenTokens(((CommonASTWithHiddenTokens) ast).getHiddenAfter());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +76,7 @@ public class PdeEmitter implements PdeTokenTypes {
|
||||
*/
|
||||
private void dumpHiddenBefore(final AST ast) {
|
||||
|
||||
antlr.CommonHiddenStreamToken child = null, parent = ((antlr.CommonASTWithHiddenTokens) ast)
|
||||
antlr.CommonHiddenStreamToken child = null, parent = ((CommonASTWithHiddenTokens) ast)
|
||||
.getHiddenBefore();
|
||||
|
||||
// if there aren't any hidden tokens here, quietly return
|
||||
@@ -228,7 +229,7 @@ public class PdeEmitter implements PdeTokenTypes {
|
||||
private void printMethodDef(final AST ast) throws RunnerException {
|
||||
final AST modifiers = ast.getFirstChild();
|
||||
final AST typeParameters, type;
|
||||
if (modifiers.getFirstChild().getType() == TYPE_PARAMETERS) {
|
||||
if (modifiers.getNextSibling().getType() == TYPE_PARAMETERS) {
|
||||
typeParameters = modifiers.getNextSibling();
|
||||
type = typeParameters.getNextSibling();
|
||||
} else {
|
||||
@@ -239,26 +240,7 @@ public class PdeEmitter implements PdeTokenTypes {
|
||||
if (methodName.getText().equals("main")) {
|
||||
pdePreprocessor.setFoundMain(true);
|
||||
}
|
||||
|
||||
// if this method doesn't have a specifier, make it public
|
||||
// (useful for setup/keyPressed/etc)
|
||||
boolean foundSpecifier = false;
|
||||
AST child = modifiers.getFirstChild();
|
||||
while (child != null) {
|
||||
final String childText = child.getText();
|
||||
if (childText.equals("public") || childText.equals("protected")
|
||||
|| childText.equals("private")) {
|
||||
foundSpecifier = true;
|
||||
child = null;
|
||||
} else {
|
||||
//out.print("." + child.getText() + ".");
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
}
|
||||
if (!foundSpecifier) {
|
||||
out.print("public ");
|
||||
}
|
||||
printChildren(ast); // everything is fine
|
||||
printChildren(ast);
|
||||
}
|
||||
|
||||
private void printIfThenElse(final AST literalIf) throws RunnerException {
|
||||
|
||||
@@ -125,11 +125,14 @@ import antlr.collections.*;
|
||||
* what each type of file is for.
|
||||
* <P/>
|
||||
*/
|
||||
public class PdePreprocessor {
|
||||
public class PdePreprocessor implements PdeTokenTypes {
|
||||
|
||||
// used for calling the ASTFactory to get the root node
|
||||
private static final int ROOT_ID = 0;
|
||||
|
||||
private final PrintStream stream;
|
||||
private final String indent;
|
||||
|
||||
// these ones have the .* at the end, since a class name might be at the end
|
||||
// instead of .* which would make trouble other classes using this can lop
|
||||
// off the . and anything after it to produce a package name consistently.
|
||||
@@ -143,8 +146,6 @@ public class PdePreprocessor {
|
||||
STATIC, ACTIVE, JAVA
|
||||
}
|
||||
|
||||
private String indent;
|
||||
private PrintStream stream;
|
||||
private Reader programReader;
|
||||
// starts as sketch name, ends as main class name
|
||||
private String name;
|
||||
@@ -174,8 +175,14 @@ public class PdePreprocessor {
|
||||
this.programType = programType;
|
||||
}
|
||||
|
||||
public PdePreprocessor() {
|
||||
char[] indentChars = new char[Preferences.getInteger("editor.tabs.size")];
|
||||
public PdePreprocessor(final String buildPath, final String sketchName)
|
||||
throws IOException {
|
||||
this.name = sketchName;
|
||||
final File streamFile = new File(buildPath, sketchName + ".java");
|
||||
stream = new PrintStream(new FileOutputStream(streamFile));
|
||||
|
||||
final char[] indentChars = new char[Preferences
|
||||
.getInteger("editor.tabs.size")];
|
||||
Arrays.fill(indentChars, ' ');
|
||||
indent = new String(indentChars);
|
||||
}
|
||||
@@ -253,20 +260,14 @@ public class PdePreprocessor {
|
||||
}
|
||||
}
|
||||
|
||||
public int writePrefix(String program, String buildPath, String sketchName,
|
||||
String codeFolderPackages[])
|
||||
public int writePrefix(String program, final String codeFolderPackages[])
|
||||
throws FileNotFoundException, RunnerException {
|
||||
this.name = sketchName;
|
||||
|
||||
// need to reset whether or not this has a main()
|
||||
foundMain = false;
|
||||
|
||||
checkForUnterminatedMultilineComment(program);
|
||||
|
||||
// This has to happen BEFORE the scrub, or else the character count is off,
|
||||
// and you get a missing character in the prologue. If you're "lucky",
|
||||
// that missing character is the terminating slash of a multiline comment.
|
||||
// This is behind http://dev.processing.org/bugs/show_bug.cgi?id=1511
|
||||
if (Preferences.getBoolean("preproc.substitute_unicode")) {
|
||||
program = substituteUnicode(program);
|
||||
}
|
||||
@@ -292,9 +293,6 @@ public class PdePreprocessor {
|
||||
|
||||
// Remove the comment from the main program
|
||||
program = program.substring(0, idx) + program.substring(idx + len);
|
||||
// Remove from the scrubbed version as well, to keep offsets identical.
|
||||
//scrubbed = scrubbed.substring(0, idx) + scrubbed.substring(idx + len);
|
||||
|
||||
} while (true);
|
||||
|
||||
codeFolderImports = new ArrayList<String>();
|
||||
@@ -306,9 +304,6 @@ public class PdePreprocessor {
|
||||
// do this after the program gets re-combobulated
|
||||
this.programReader = new StringReader(program);
|
||||
|
||||
//File streamFile = new File(buildPath, getJavaFileName());
|
||||
File streamFile = new File(buildPath, sketchName + ".java");
|
||||
stream = new PrintStream(new FileOutputStream(streamFile));
|
||||
int importsLength = writeImports(stream);
|
||||
|
||||
// return the length of the imports plus the extra lines
|
||||
@@ -367,8 +362,6 @@ public class PdePreprocessor {
|
||||
* preprocesses a pde file and writes out a java file
|
||||
* @return the class name of the exported Java
|
||||
*/
|
||||
//public String write(String program, String buildPath, String name,
|
||||
// String extraImports[]) throws java.lang.Exception {
|
||||
public String write() throws java.lang.Exception {
|
||||
// create a lexer with the stream reader, and tell it to handle
|
||||
// hidden tokens (eg whitespace, comments) since we want to pass these
|
||||
@@ -425,6 +418,8 @@ public class PdePreprocessor {
|
||||
AST rootNode = factory.create(ROOT_ID, "AST ROOT");
|
||||
rootNode.setFirstChild(parserAST);
|
||||
|
||||
makeSimpleMethodsPublic(rootNode);
|
||||
|
||||
// unclear if this actually works, but it's worth a shot
|
||||
//
|
||||
//((CommonAST)parserAST).setVerboseStringConversion(
|
||||
@@ -444,11 +439,7 @@ public class PdePreprocessor {
|
||||
if (name == null)
|
||||
return null;
|
||||
|
||||
writeDeclaration(stream, name);
|
||||
new PdeEmitter(this, stream).print(rootNode);
|
||||
writeFooter(stream, name);
|
||||
stream.close();
|
||||
|
||||
// debug
|
||||
if (false) {
|
||||
final ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||
final PrintStream bufout = new PrintStream(buf);
|
||||
@@ -459,6 +450,11 @@ public class PdePreprocessor {
|
||||
System.err.println(new String(buf.toByteArray()));
|
||||
}
|
||||
|
||||
writeDeclaration(stream, name);
|
||||
new PdeEmitter(this, stream).print(rootNode);
|
||||
writeFooter(stream, name);
|
||||
stream.close();
|
||||
|
||||
// if desired, serialize the parse tree to an XML file. can
|
||||
// be viewed usefully with Mozilla or IE
|
||||
if (Preferences.getBoolean("preproc.output_parse_tree")) {
|
||||
@@ -468,6 +464,44 @@ public class PdePreprocessor {
|
||||
return name;
|
||||
}
|
||||
|
||||
private static class BogusPublicToken extends CommonHiddenStreamToken {
|
||||
public BogusPublicToken() {
|
||||
super(LITERAL_public, "public");
|
||||
setHiddenAfter(new CommonHiddenStreamToken(WS, " "));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk the tree looking for METHOD_DEFs. Any simple METHOD_DEF (one
|
||||
* without TYPE_PARAMETERS) lacking an
|
||||
* access specifier is given public access.
|
||||
* @param node
|
||||
*/
|
||||
private void makeSimpleMethodsPublic(final AST node) {
|
||||
if (node.getType() == METHOD_DEF) {
|
||||
final AST mods = node.getFirstChild();
|
||||
final AST oldFirstMod = mods.getFirstChild();
|
||||
for (AST mod = oldFirstMod; mod != null; mod = mod.getNextSibling()) {
|
||||
final int t = mod.getType();
|
||||
if (t == LITERAL_private || t == LITERAL_protected
|
||||
|| t == LITERAL_public) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mods.getNextSibling().getType() == TYPE_PARAMETERS) {
|
||||
return;
|
||||
}
|
||||
final AST publicNode = new CommonASTWithHiddenTokens(
|
||||
new BogusPublicToken());
|
||||
publicNode.setNextSibling(oldFirstMod);
|
||||
mods.setFirstChild(publicNode);
|
||||
} else {
|
||||
for (AST kid = node.getFirstChild(); kid != null; kid = kid
|
||||
.getNextSibling())
|
||||
makeSimpleMethodsPublic(kid);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeParseTree(String filename, AST ast) {
|
||||
try {
|
||||
PrintStream stream = new PrintStream(new FileOutputStream(filename));
|
||||
|
||||
Reference in New Issue
Block a user