SpecialContractExpressionFinder.java
package dev.civl.mc.transform.common.contracts;
import java.util.LinkedList;
import java.util.List;
import dev.civl.abc.ast.node.IF.ASTNode;
import dev.civl.abc.ast.node.IF.ASTNode.NodeKind;
import dev.civl.abc.ast.node.IF.expression.ExpressionNode;
import dev.civl.abc.ast.node.IF.expression.ExpressionNode.ExpressionKind;
import dev.civl.abc.ast.node.IF.expression.OperatorNode;
import dev.civl.abc.ast.node.IF.expression.OperatorNode.Operator;
/**
* <p>
* This class scans an expression in a contract and returns an instance of
* {@link SpecialContractHub}, which is a collection of all references to
* special constructs in the given expression. A special construct is a contract
* construct that needs special handling during code transformation.
* </p>
* <p>
* This class only contains static methods hence no runtime instance of this
* class is needed.
* </p>
*
* @author ziqingluo
*
*/
public class SpecialContractExpressionFinder {
/**
* This class is a collection of all references to special constructs in some
* contract expressions
*
* @author ziqingluo
*/
static class SpecialContractHub {
List<ExpressionNode> nonderefPointers;
List<ExpressionNode> acslOldExpressions;
List<ExpressionNode> acslValidExpressions;
List<ExpressionNode> acslResults;
SpecialContractHub() {
nonderefPointers = new LinkedList<>();
acslOldExpressions = new LinkedList<>();
acslValidExpressions = new LinkedList<>();
acslResults = new LinkedList<>();
}
}
/**
* finds and returns all references to special constructs in the given
* expression.
*
* @param expression
* @return a {@link SpecialContractHub} which is a collection of all references
* to special constructs in the given expression.
*/
static SpecialContractHub findSpecialExpressions(ExpressionNode expression) {
SpecialContractHub specials = new SpecialContractHub();
return findSpecialExpressions(expression, specials);
}
static SpecialContractHub findSpecialExpressions(ExpressionNode expression, SpecialContractHub specials) {
specials.acslOldExpressions.addAll(findOldExpressions(expression));
specials.acslValidExpressions.addAll(findAcslValid(expression));
specials.acslResults.addAll(findAcslResult(expression));
return specials;
}
private static List<ExpressionNode> findOldExpressions(ExpressionNode expr) {
List<ExpressionNode> results = new LinkedList<>();
if (expr.expressionKind() == ExpressionKind.OPERATOR)
if (((OperatorNode) expr).getOperator() == Operator.OLD) {
results.add(expr);
// nested old ? I think it should not happen
return results;
}
int numChildren = expr.numChildren();
for (int i = 0; i < numChildren;) {
ASTNode child = expr.child(i++);
if (child != null && child.nodeKind() == NodeKind.EXPRESSION)
results.addAll(findOldExpressions((ExpressionNode) child));
}
return results;
}
private static List<ExpressionNode> findAcslValid(ExpressionNode expr) {
List<ExpressionNode> results = new LinkedList<>();
if (expr.expressionKind() == ExpressionKind.OPERATOR)
if (((OperatorNode) expr).getOperator() == Operator.VALID) {
results.add(expr);
return results;
}
int numChildren = expr.numChildren();
for (int i = 0; i < numChildren;) {
ASTNode child = expr.child(i++);
if (child != null && child.nodeKind() == NodeKind.EXPRESSION)
results.addAll(findAcslValid((ExpressionNode) child));
}
return results;
}
private static List<ExpressionNode> findAcslResult(ExpressionNode expr) {
List<ExpressionNode> results = new LinkedList<>();
if (expr.expressionKind() == ExpressionKind.RESULT) {
results.add(expr);
return results;
}
int numChildren = expr.numChildren();
for (int i = 0; i < numChildren;) {
ASTNode child = expr.child(i++);
if (child != null && child.nodeKind() == NodeKind.EXPRESSION)
results.addAll(findAcslResult((ExpressionNode) child));
}
return results;
}
}