package bluej.stride.framedjava.convert;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import bluej.parser.lexer.JavaTokenTypes;
import bluej.parser.lexer.LocatableToken;
import bluej.stride.framedjava.ast.FilledExpressionSlotFragment;
import bluej.stride.framedjava.ast.OptionalExpressionSlotFragment;
import bluej.stride.framedjava.ast.SuperThisParamsExpressionFragment;
import bluej.stride.framedjava.convert.ConversionWarning.UnsupportedFeature;
import bluej.stride.framedjava.elements.AssignElement;
import bluej.stride.framedjava.elements.CodeElement;
import threadchecker.OnThread;
import threadchecker.Tag;
| Class in charge of building expressions.
|
| Because expressions can nest, beginExpression/endExpression will likely be called
| multiple times on the same handler. We pair them off, and only finish when
| the outermost expression is completed.
|
class ExpressionBuilder
{
private LocatableToken start;
private int outstanding = 0;
private final Consumer<Expression> handler;
private final TriFunction<LocatableToken, LocatableToken, List<Mask>, String> getText;
private LocatableToken assignOp;
private List<Integer> incDec = new ArrayList<>();
private final Consumer<ConversionWarning> addWarning;
private final Stack<Mask> curMasks = new Stack<>();
private final List<Mask> completeMasks = new ArrayList<>();
ExpressionBuilder(Consumer<Expression> handler, TriFunction<LocatableToken, LocatableToken, List<Mask>, String> getText, Consumer<ConversionWarning> addWarning)
{
this.handler = handler;
this.getText = getText;
this.addWarning = addWarning;
}
p.public void expressionBegun(LocatableToken start)
{
if (outstanding == 0)
this.start = start;
outstanding += 1;
}
p.public boolean expressionEnd(LocatableToken end)
{
outstanding -= 1;
if (outstanding == 0)
{
if (assignOp == null)
{
String java = getText.apply(start, end, completeMasks);
handler.accept(new Expression(java, incDec, addWarning));
}
else
{
String wholeJava = getText.apply(start, end, completeMasks);
String lhs = getText.apply(start, assignOp, completeMasks).trim();
String rhs = assignOp.getText().equals("=")
? getText.apply(assignOp, end, completeMasks).substring(assignOp.getText().length())
: lhs + " " + assignOp.getText().substring(0, assignOp.getText().length() - 1) + " " + getText.apply(assignOp, end, completeMasks).substring(assignOp.getText().length());
handler.accept(new Expression(wholeJava, incDec, addWarning) {
@Override
FilledExpressionSlotFragment toFilled()
{
addWarning.accept(new UnsupportedFeature(assignOp.getText() + " in expression"));
return super.toFilled();
}
@Override
OptionalExpressionSlotFragment toOptional()
{
addWarning.accept(new UnsupportedFeature(assignOp.getText() + " in expression"));
return super.toOptional();
}
@Override
SuperThisParamsExpressionFragment toSuperThis()
{
addWarning.accept(new UnsupportedFeature(assignOp.getText() + " in expression"));
return super.toSuperThis();
}
@Override
public CodeElement toStatement()
{
return new AssignElement(null, new Expression(lhs, incDec, addWarning).toFilled(), new Expression(rhs, Collections.emptyList(), addWarning).toFilled(), true);
}
});
}
return true;
}
else{
return false;
}
}
public void binaryOperator(LocatableToken opToken)
{
switch (opToken.getType())
{
case JavaTokenTypes.BAND_ASSIGN:
case JavaTokenTypes.BOR_ASSIGN:
case JavaTokenTypes.BSR_ASSIGN:
case JavaTokenTypes.BXOR_ASSIGN:
case JavaTokenTypes.DIV_ASSIGN:
case JavaTokenTypes.MINUS_ASSIGN:
case JavaTokenTypes.MOD_ASSIGN:
case JavaTokenTypes.PLUS_ASSIGN:
case JavaTokenTypes.SL_ASSIGN:
case JavaTokenTypes.SR_ASSIGN:
case JavaTokenTypes.STAR_ASSIGN:
case JavaTokenTypes.ASSIGN:
if (outstanding == 1)
assignOp = opToken;
else{ addWarning.accept(new UnsupportedFeature(opToken.getText() + " in expression"));
}
break;
default:
return;
}
}
public void unaryOperator(LocatableToken token)
{
if (token.getType() == JavaTokenTypes.INC || token.getType() == JavaTokenTypes.DEC)
incDec.add(token.getType());
}
public void postOperator(LocatableToken token)
{
unaryOperator(token);
}
public void beginMask(LocatableToken from)
{
curMasks.push(new Mask(from));
}
public void endMask(LocatableToken to)
{
Mask mask = curMasks.pop();
if (curMasks.isEmpty())
{
mask.setEnd(to);
completeMasks.add(mask);
}
}
public static interface TriFunction<T1, T2, T3, R>
{
public R apply(T1 t1, T2 t2, T3 t3);
}
}
. - ExpressionBuilder
. expressionBegun
. expressionEnd
. toStatement
. binaryOperator
. unaryOperator
. postOperator
. beginMask
. endMask
. apply
228 neLoCode
+ 4 LoComm