package bluej.stride.framedjava.convert;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import bluej.parser.lexer.JavaLexer;
import bluej.parser.lexer.JavaTokenTypes;
import bluej.parser.lexer.LocatableToken;
import bluej.stride.framedjava.ast.CallExpressionSlotFragment;
import bluej.stride.framedjava.ast.FilledExpressionSlotFragment;
import bluej.stride.framedjava.ast.OptionalExpressionSlotFragment;
import bluej.stride.framedjava.ast.Parser;
import bluej.stride.framedjava.ast.SuperThisParamsExpressionFragment;
import bluej.stride.framedjava.convert.ConversionWarning.UnsupportedFeature;
import bluej.stride.framedjava.elements.AssignElement;
import bluej.stride.framedjava.elements.CallElement;
import bluej.stride.framedjava.elements.CodeElement;
| An expression. Because expressions have different text in Stride versus Java
| (because of instanceof), we must keep track of them seperately.
|
class Expression
{
private final String stride;
private final String java;
| A list of JavaTokenTypes.{}NC,DEC} found in the expression. A warning
| should be generated if any turn out to be unsupported.
|
private final List<Integer> incDec;
| A callback to add a warning.
|
private final Consumer<ConversionWarning> addWarning;
| @param src A java expression
|
Expression(String src, List<Integer> incDec, Consumer<ConversionWarning> addWarning)
{
this.stride = uniformSpacing(src, true);
this.java = uniformSpacing(src, false);
this.incDec = new ArrayList<>(incDec);
this.addWarning = addWarning;
}
| @param expressions A list of expressions to join
| @param join The string to put between each pair of adjacent expressions
|
Expression(List<Expression> expressions, String join, Consumer<ConversionWarning> addWarning)
{
this.stride = expressions.stream().map(e -> e.stride).collect(Collectors.joining(join));
this.java = expressions.stream().map(e -> e.java).collect(Collectors.joining(join));
this.incDec = new ArrayList<>();
expressions.forEach(e -> this.incDec.addAll(e.incDec));
this.addWarning = addWarning;
}
| Package-visible for testing
|
| @param src Java source code
| @param replaceInstanceof True to replace instanceof with <:
| @return A version of src with a space between each consecutive token
|
p.public static String uniformSpacing(String src, boolean replaceInstanceof)
{
JavaLexer lexer = new JavaLexer(new StringReader(src));
StringBuilder r = new StringBuilder();
while (true)
{
LocatableToken token = lexer.nextToken();
if (token.getType() == JavaTokenTypes.EOF)
return r.toString();
if (r.length() != 0)
r.append(" ");
if (replaceInstanceof && token.getType() == JavaTokenTypes.LITERAL_instanceof)
r.append("<:");
else{ r.append(token.getText());
}
}
}
FilledExpressionSlotFragment toFilled()
{
warnIncDec();
return new FilledExpressionSlotFragment(stride, java);
}
OptionalExpressionSlotFragment toOptional()
{
warnIncDec();
return new OptionalExpressionSlotFragment(stride, java);
}
SuperThisParamsExpressionFragment toSuperThis()
{
warnIncDec();
return new SuperThisParamsExpressionFragment(stride, java);
}
public CodeElement toStatement()
{
boolean startInc = java.startsWith("++ ");
boolean startDec = java.startsWith("-- ");
boolean endInc = java.endsWith(" ++");
boolean endDec = java.endsWith(" --");
if (startInc || startDec)
{
incDec.remove((Integer)(startInc ? JavaTokenTypes.INC : JavaTokenTypes.DEC));
warnIncDec();
return new AssignElement(null, new FilledExpressionSlotFragment(stride.substring(3), java.substring(3)), new FilledExpressionSlotFragment(stride.substring(3) + " " + stride.substring(0, 1) + " 1", java.substring(3) + " " + java.substring(0, 1) + " 1"), true);
}
else if (endInc || endDec)
{
incDec.remove((Integer)(endInc ? JavaTokenTypes.INC : JavaTokenTypes.DEC));
warnIncDec();
String choppedStride = stride.substring(0, stride.length() - 3);
String choppedJava = java.substring(0, java.length() - 3);
return new AssignElement(null, new FilledExpressionSlotFragment(choppedStride, choppedJava), new FilledExpressionSlotFragment(choppedStride + " " + stride.substring(stride.length() - 1, stride.length()) + " 1", choppedJava + " " + java.substring(java.length() - 1, java.length()) + " 1"), true);
}
else
{
warnIncDec();
return new CallElement(null, new CallExpressionSlotFragment(stride, java), true);
}
}
private void warnIncDec()
{
if (!incDec.isEmpty())
addWarning.accept(new UnsupportedFeature("++/-- in expression"));
}
@Override
public String toString()
{
return java;
}
public String getJava()
{
return java;
}
| Is the expression an integer literal? (Long literal will give false)
|
public boolean isIntegerLiteral()
{
JavaLexer lexer = new JavaLexer(new StringReader(java));
if (lexer.nextToken().getType() != JavaTokenTypes.NUM_INT)
return false;
return lexer.nextToken().getType() == JavaTokenTypes.EOF;
}
| Given varName, is the expression of the exact form "varName < integer_literal"
|* or "varName <= integer_literal" ?
*/
public boolean lessThanIntegerLiteral(String varName)
{
JavaLexer lexer = new JavaLexer(new StringReader(java));
LocatableToken token = lexer.nextToken();
if (token.getType() != JavaTokenTypes.IDENT || !token.getText().equals(varName))
|
|return false;
|
|token = lexer.nextToken();
|
|if (token.getType() != JavaTokenTypes.LT && token.getType() != JavaTokenTypes.LE)
|
|return false;
|
|if (lexer.nextToken().getType() != JavaTokenTypes.NUM_INT)
|
|return false;
|
|return lexer.nextToken().getType() == JavaTokenTypes.EOF;
|
|}
|
|/**
| Assuming lessThanIntegerLiteral has already returned true,
| what is the inclusive upper bound on the condition?
|
public String getUpperBound()
{
JavaLexer lexer = new JavaLexer(new StringReader(java));
LocatableToken token = lexer.nextToken();
if (token.getType() != JavaTokenTypes.IDENT)
return "";
LocatableToken comparisonToken = lexer.nextToken();
if (comparisonToken.getType() != JavaTokenTypes.LT && comparisonToken.getType() != JavaTokenTypes.LE)
return "";
token = lexer.nextToken();
if (token.getType() != JavaTokenTypes.NUM_INT)
return "";
return Integer.toString(Integer.decode(token.getText()) + (comparisonToken.getType() == JavaTokenTypes.LT ? -1 : 0));
}
public boolean isIncrementByOne(String varName)
{
JavaLexer lexer = new JavaLexer(new StringReader(java));
LocatableToken token = lexer.nextToken();
if (token.getType() == JavaTokenTypes.INC)
{
token = lexer.nextToken();
if (token.getType() != JavaTokenTypes.IDENT || !token.getText().equals(varName))
return false;
}
else if (token.getType() == JavaTokenTypes.IDENT && token.getText().equals(varName))
{
token = lexer.nextToken();
if (token.getType() == JavaTokenTypes.INC)
{
}
else if (token.getType() == JavaTokenTypes.PLUS_ASSIGN)
{
token = lexer.nextToken();
if (token.getType() != JavaTokenTypes.NUM_INT || !token.getText().equals("1"))
return false;
}
else if (token.getType() == JavaTokenTypes.ASSIGN)
{
token = lexer.nextToken();
if (token.getType() != JavaTokenTypes.IDENT || !token.getText().equals(varName))
return false;
token = lexer.nextToken();
if (token.getType() != JavaTokenTypes.PLUS)
return false;
token = lexer.nextToken();
if (token.getType() != JavaTokenTypes.NUM_INT || !token.getText().equals("1"))
return false;
}
else{ return false;
}
}
else{ return false;
}
return lexer.nextToken().getType() == JavaTokenTypes.EOF;
}
}
. - Expression
. uniformSpacing
. toStatement
. warnIncDec
. toString
. getJava
. isIntegerLiteral
. getUpperBound
. isIncrementByOne
275 neLoCode
+ 25 LoComm