src.main.lombok.ast.Template Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lombok-ast Show documentation
Show all versions of lombok-ast Show documentation
This is a very small fork of lombok.ast as some Android tools needed a few modifications. The normal repository for lombok.ast is here https://github.com/rzwitserloot/lombok.ast and our changes for 0.2.3 are in this pull request: https://github.com/rzwitserloot/lombok.ast/pull/8
The newest version!
package lombok.ast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import lombok.ast.grammar.Source;
public class Template {
private static N process(Source s, String name, Class type) {
if (!s.getProblems().isEmpty()) {
throw new AstException(null, "Can't parse snippet: " + s.getProblems().get(0).getMessage());
}
if (s.getNodes().isEmpty()) return null;
if (s.getNodes().size() > 1) throw new AstException(null, "Can't parse snippet: more than one " + name + " in snippet");
Node n = s.getNodes().get(0);
if (type.isInstance(n)) return type.cast(n);
throw new AstException(null, "Can't parse snippet: Not a " + name);
}
/**
* Parses one construct that is legal as a type member, and returns it.
*
* Legal type members:
* - Constructor Declaration
* - Method Declaration
* - Static or Instance Initializer
* - Any type declaration
* - The empty declaration (lone semi-colon)
* - A variable declaration
*
*
* Note that neither annotation method declarations nor enum constants will be parsed properly by this method.
*/
public static TypeMember parseMember(String source) throws AstException {
Source s = new Source(source, "memberSnippet");
s.parseMember();
return process(s, "type member", TypeMember.class);
}
public static MethodDeclaration parseMethod(String source) throws AstException {
Source s = new Source(source, "methodSnippet");
s.parseMember();
return process(s, "method", MethodDeclaration.class);
}
public static ConstructorDeclaration parseConstructor(String source) throws AstException {
Source s = new Source(source, "constructorSnippet");
s.parseMember();
return process(s, "constructor", ConstructorDeclaration.class);
}
public static VariableDeclaration parseField(String source) throws AstException {
Source s = new Source(source, "fieldSnippet");
s.parseMember();
return process(s, "field", VariableDeclaration.class);
}
public static VariableDefinition parseVariableDefinition(String source) throws AstException {
Source s = new Source(source, "vardefSnippet");
s.parseMember();
return process(s, "vardef", VariableDefinition.class);
}
public static Statement parseStatement(String source) throws AstException {
Source s = new Source(source, "statementSnippet");
s.parseStatement();
return process(s, "statement", Statement.class);
}
public static Expression parseExpression(String source) throws AstException {
Source s = new Source(source, "expressionSnippet");
s.parseExpression();
return process(s, "expression", Expression.class);
}
/**
* NB: Do not simply pass the result of {@code parseX} to this method; parsing is extremely slow. Instead, parse a template once,
* and then pass this one result every time. The template will never modify the original.
*/
@SuppressWarnings("unchecked")
public static Template of(N source) throws AstException {
return new Template((N) source.copy());
}
private final T node;
private int location;
private Node responsible;
private List replacements = new ArrayList();
private int replacementsPointer = 0;
private static class ReplacementOrder {
String identifierToReplace, statementToReplace, expressionToReplace, typeReferenceToReplace;
List extends Node> replacement;
Position position;
static ReplacementOrder forIdentifier(String identifier, String newValue, Position position) {
ReplacementOrder order = new ReplacementOrder();
order.identifierToReplace = identifier;
order.replacement = Collections.singletonList(newValue == null ? null : Identifier.of(newValue));
order.position = position;
return order;
}
static ReplacementOrder forStatement(String label, List extends Node> replacements, Position position) {
ReplacementOrder order = new ReplacementOrder();
order.statementToReplace = label;
order.replacement = replacements == null ? Collections.emptyList() : replacements;
order.position = position;
return order;
}
static ReplacementOrder forExpression(String identifier, Node replacement, Position position) {
ReplacementOrder order = new ReplacementOrder();
order.expressionToReplace = identifier;
order.replacement = Collections.singletonList(replacement);
order.position = position;
return order;
}
static ReplacementOrder forTypeReference(String identifier, Node replacement, Position position) {
ReplacementOrder order = new ReplacementOrder();
order.typeReferenceToReplace = identifier;
order.replacement = Collections.singletonList(replacement);
order.position = position;
return order;
}
}
private final AstVisitor visitor = new ForwardingAstVisitor() {
@Override public boolean visitNode(Node node) {
node.setPosition(new Position(location, location, responsible));
return false;
}
@Override public void endVisit(Node node) {
node.setPosition(new Position(node.getPosition().getStart(), location, responsible));
}
private ReplacementOrder currentOrder() {
return (replacementsPointer < replacements.size()) ? replacements.get(replacementsPointer) : null;
}
@Override public boolean visitIdentifier(Identifier node) {
ReplacementOrder order = currentOrder();
if (order != null && order.identifierToReplace != null) {
if (order.identifierToReplace.equals(node.astValue())) {
Node replacement = order.replacement.get(0);
int startLoc = order.position == null ? location : order.position.getStart();
int endLoc = order.position == null ? location : order.position.getEnd();
replacement.setPosition(new Position(startLoc, endLoc, responsible));
location = endLoc;
node.replace(replacement);
replacementsPointer++;
return true;
}
}
return visitNode(node);
}
@Override public boolean visitLabelledStatement(LabelledStatement node) {
ReplacementOrder order = currentOrder();
if (order != null && order.statementToReplace.equals(node.astLabel().astValue())) {
if (!(node.rawStatement() instanceof EmptyStatement)) {
throw new IllegalStateException("Placeholder statements in templates should be of the form: \"labelName: ;\" - i.e. a labelled empty statement");
}
int startLoc, endLoc;
if (order.position == null) {
if (order.replacement.isEmpty() || order.replacement.get(0).getPosition().getStart() < 0) startLoc = location;
else startLoc = order.replacement.get(0).getPosition().getStart();
if (order.replacement.isEmpty() || order.replacement.get(order.replacement.size() - 1).getPosition().getEnd() < 0) endLoc = location;
else endLoc = order.replacement.get(order.replacement.size() - 1).getPosition().getEnd();
} else {
startLoc = order.position.getStart();
endLoc = order.position.getEnd();
}
switch (order.replacement.size()) {
case 0:
node.unparent();
break;
case 1:
Node replacement = order.replacement.get(0);
if (replacement.getPosition().isUnplaced()) Ast.setAllPositions(replacement, new Position(startLoc, endLoc, responsible));
node.replace(replacement);
break;
default:
// Replacing multiple statements only works in a Block.
Block b = node.upToBlock();
if (b == null) throw new IllegalStateException("Replacing one placeholder statement with multiple statements is legal only if the placeholder is in a block");
b.rawContents().addAfter(node, order.replacement.toArray(new Node[0]));
node.unparent();
for (Node n : order.replacement) {
if (n.getPosition().isUnplaced()) Ast.setAllPositions(n, new Position(startLoc, endLoc, responsible));
}
}
replacementsPointer++;
location = endLoc;
return true;
}
return visitNode(node);
}
@Override public boolean visitVariableReference(VariableReference node) {
ReplacementOrder order = currentOrder();
if (order != null && order.expressionToReplace.equals(node.astIdentifier().astValue())) {
Node replacement = order.replacement.get(0);
int startLoc, endLoc;
if (order.position == null) {
if (order.replacement.isEmpty() || replacement.getPosition().getStart() < 0) startLoc = location;
else startLoc = replacement.getPosition().getStart();
if (order.replacement.isEmpty() || replacement.getPosition().getEnd() < 0) endLoc = location;
else endLoc = replacement.getPosition().getEnd();
} else {
startLoc = order.position.getStart();
endLoc = order.position.getEnd();
}
if (replacement.getPosition().isUnplaced()) Ast.setAllPositions(replacement, new Position(startLoc, endLoc, responsible));
location = endLoc;
node.replace(replacement);
replacementsPointer++;
return true;
}
return visitNode(node);
}
@Override public boolean visitTypeReference(TypeReference node) {
ReplacementOrder order = currentOrder();
if (order != null && node.astParts().size() == 1 && node.astParts().last().rawTypeArguments().isEmpty() &&
node.astParts().last().astIdentifier().astValue().equals(order.typeReferenceToReplace)) {
Node replacement = order.replacement.get(0);
int startLoc, endLoc;
if (order.position == null) {
if (order.replacement.isEmpty() || replacement.getPosition().getStart() < 0) startLoc = location;
else startLoc = replacement.getPosition().getStart();
if (order.replacement.isEmpty() || replacement.getPosition().getEnd() < 0) endLoc = location;
else endLoc = replacement.getPosition().getEnd();
} else {
startLoc = order.position.getStart();
endLoc = order.position.getEnd();
}
if (replacement.getPosition().isUnplaced()) Ast.setAllPositions(replacement, new Position(startLoc, endLoc, responsible));
location = endLoc;
node.replace(replacement);
replacementsPointer++;
return true;
}
return visitNode(node);
}
};
private Template(T node) {
this.node = node;
}
public Template setStartPosition(int location) {
this.location = location;
return this;
}
public Template setResponsibleNode(Node responsible) {
this.responsible = responsible;
return this;
}
public Template replaceIdentifier(String placeholder, String replacement, Position p) {
this.replacements.add(ReplacementOrder.forIdentifier(placeholder, replacement, p));
return this;
}
public Template replaceIdentifier(String placeholder, String replacement) {
return replaceIdentifier(placeholder, replacement, null);
}
public Template replaceStatement(String placeholder, Node replacement, Position p) {
this.replacements.add(ReplacementOrder.forStatement(placeholder, replacement == null ? Collections.emptyList() : Collections.singletonList(replacement), p));
return this;
}
public Template replaceStatement(String placeholder, Node replacement) {
return replaceStatement(placeholder, replacement, null);
}
public Template replaceStatement(String placeholder, List extends Node> replacement, Position p) {
this.replacements.add(ReplacementOrder.forStatement(placeholder, replacement, p));
return this;
}
public Template replaceStatement(String placeholder, List extends Node> replacement) {
return replaceStatement(placeholder, replacement, null);
}
public Template replaceExpression(String placeholder, Node replacement, Position p) {
this.replacements.add(ReplacementOrder.forExpression(placeholder, replacement, p));
return this;
}
public Template replaceExpression(String placeholder, Node replacement) {
return replaceExpression(placeholder, replacement, null);
}
public Template replaceTypeReference(String placeholder, Node replacement, Position p) {
this.replacements.add(ReplacementOrder.forTypeReference(placeholder, replacement, p));
return this;
}
public Template replaceTypeReference(String placeholder, Node replacement) {
return replaceTypeReference(placeholder, replacement, null);
}
public T finish() {
node.accept(visitor);
return node;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy