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:
jdf
2010-03-16 17:55:26 +00:00
parent b45e466a3e
commit e4d577e6c1
4 changed files with 81 additions and 54 deletions
@@ -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() + ";");
+6 -5
View File
@@ -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";
+5 -23
View File
@@ -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));