/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.hcl.tree;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.NonFinal;
import org.jspecify.annotations.Nullable;
import org.openrewrite.*;
import org.openrewrite.hcl.HclParser;
import org.openrewrite.hcl.HclVisitor;
import org.openrewrite.hcl.internal.HclPrinter;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.marker.Markers;
import org.openrewrite.template.SourceTemplate;
import java.lang.ref.WeakReference;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;
import java.util.UUID;
import static java.util.Collections.singletonList;
@SuppressWarnings("unused")
public interface Hcl extends Tree {
@SuppressWarnings("unchecked")
@Override
default R accept(TreeVisitor v, P p) {
return (R) acceptHcl(v.adapt(HclVisitor.class), p);
}
default @Nullable Hcl acceptHcl(HclVisitor
v, P p) {
return v.defaultValue(this, p);
}
@Override
default
boolean isAcceptable(TreeVisitor, P> v, P p) {
return v.isAdaptableTo(HclVisitor.class);
}
Space getPrefix();
H withPrefix(Space prefix);
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class Attribute implements BodyContent, Expression {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
/**
* When this is attribute of an object value,
* can be a parenthetical expression or identifier.
*/
@With
@Getter
Expression name;
@JsonIgnore
public String getSimpleName() {
return getSimpleName(name);
}
private String getSimpleName(Expression e) {
return e instanceof Parentheses ? getSimpleName(((Parentheses) e).getExpression()) : ((Identifier) e).getName();
}
HclLeftPadded type;
public Type getType() {
return type.getElement();
}
public Attribute withType(Type type) {
return getPadding().withType(this.type.withElement(type));
}
@With
@Getter
Expression value;
@With
@Getter
@Nullable
Empty comma;
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitAttribute(this, p);
}
@Override
public String toString() {
return "Attribute{" + name + "}";
}
public enum Type {
ObjectElement,
Assignment
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final Attribute t;
public HclLeftPadded getType() {
return t.type;
}
public Attribute withType(HclLeftPadded type) {
return t.type == type ? t : new Attribute(t.id, t.prefix, t.markers, t.name, type, t.value, t.comma);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class AttributeAccess implements Expression, Label {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
@With
@Getter
Expression attribute;
HclLeftPadded name;
public Identifier getType() {
return name.getElement();
}
public AttributeAccess withType(Identifier name) {
return getPadding().withName(this.name.withElement(name));
}
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitAttributeAccess(this, p);
}
@Override
public String toString() {
return "AttributeAccess{" + attribute + "." + name + "}";
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final AttributeAccess t;
public HclLeftPadded getName() {
return t.name;
}
public AttributeAccess withName(HclLeftPadded name) {
return t.name == name ? t : new AttributeAccess(t.id, t.prefix, t.markers, t.attribute, name);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class Binary implements Expression {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
@With
@Getter
Expression left;
HclLeftPadded operator;
public Type getOperator() {
return operator.getElement();
}
public Binary withOperator(Type type) {
return getPadding().withOperator(this.operator.withElement(type));
}
@With
@Getter
Expression right;
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitBinary(this, p);
}
@Override
public String toString() {
return "Binary";
}
public enum Type {
Addition,
Subtraction,
Multiplication,
Division,
Modulo,
LessThan,
GreaterThan,
LessThanOrEqual,
GreaterThanOrEqual,
Equal,
NotEqual,
Or,
And
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final Binary t;
public HclLeftPadded getOperator() {
return t.operator;
}
public Binary withOperator(HclLeftPadded operator) {
return t.operator == operator ? t : new Binary(t.id, t.prefix, t.markers, t.left, operator, t.right);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class Block implements BodyContent, Expression {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
/**
* Nullable for anonymous block expressions
*/
@With
@Nullable
Identifier type;
@With
List labels;
@With
Space open;
@With
List body;
@Incubating(since = "7.27.0")
public @Nullable Attribute getAttribute(String attrName) {
for (BodyContent t : body) {
if (t instanceof Attribute) {
Attribute attribute = (Attribute) t;
if (attribute.getSimpleName().equals(attrName)) {
return attribute;
}
}
}
return null;
}
/**
* Locate an attribute with the given name and set its value.
*
* @param attrName The attribute to locate. This assumes there is one and only one.
* @param value The value to set.
* @return This block.
*/
@Incubating(since = "7.27.0")
public Hcl.Block withAttributeValue(String attrName, Object value) {
Attribute attr = getAttribute(attrName);
if (attr == null || getAttributeValue(attrName).equals(value)) {
return this;
}
return withBody(ListUtils.map(body, b -> {
if (b == attr) {
if (attr.getValue() instanceof Literal) {
Literal l = (Literal) attr.getValue();
return attr.withValue(l.withValue(value.toString()).withValueSource("\"" + value + "\""));
} else if (attr.getValue() instanceof QuotedTemplate) {
QuotedTemplate q = (QuotedTemplate) attr.getValue();
return attr.withValue(q.withExpressions(singletonList(new Literal(Tree.randomId(),
Space.EMPTY, Markers.EMPTY, value, value.toString()))));
}
}
return b;
}));
}
/**
* @param attrName The name of the attribute to look for.
* @return The text value of the attribute matching the provided name, if any.
*/
@Incubating(since = "7.27.0")
public @Nullable T getAttributeValue(String attrName) {
Attribute attr = getAttribute(attrName);
if (attr == null) {
return null;
}
Object value = attr.getValue() instanceof Literal ?
((Literal) attr.getValue()).getValueSource() : null;
if (attr.getValue() instanceof QuotedTemplate) {
Cursor root = new Cursor(null, HclParser.builder().build().parse("")
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Could not parse as HCL")));
StringBuilder valueBuilder = new StringBuilder();
for (Expression expr : ((QuotedTemplate) attr.getValue()).getExpressions()) {
valueBuilder.append(expr.print(root));
}
value = valueBuilder.toString();
}
//noinspection unchecked
return (T) value;
}
@With
Space end;
@Override
public CoordinateBuilder.Block getCoordinates() {
return new CoordinateBuilder.Block(this);
}
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitBlock(this, p);
}
@Override
public String toString() {
return "Block";
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class Conditional implements Expression {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
@With
@Getter
Expression condition;
HclLeftPadded truePart;
public Expression getTruePart() {
return truePart.getElement();
}
public Conditional withTruePart(Expression truePart) {
return getPadding().withTruePart(this.truePart.withElement(truePart));
}
HclLeftPadded falsePart;
public Expression getFalsePart() {
return falsePart.getElement();
}
public Conditional withFalsePart(Expression falsePart) {
return getPadding().withFalsePart(this.falsePart.withElement(falsePart));
}
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitConditional(this, p);
}
@Override
public String toString() {
return "Block";
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final Conditional t;
public HclLeftPadded getTruePart() {
return t.truePart;
}
public Conditional withTruePart(HclLeftPadded truePart) {
return t.truePart == truePart ? t : new Conditional(t.id, t.prefix, t.markers, t.condition, truePart, t.falsePart);
}
public HclLeftPadded getFalsePart() {
return t.falsePart;
}
public Conditional withFalsePart(HclLeftPadded falsePart) {
return t.falsePart == falsePart ? t : new Conditional(t.id, t.prefix, t.markers, t.condition, t.truePart, falsePart);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class ConfigFile implements Hcl, SourceFile {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Path sourcePath;
@With
@Nullable
FileAttributes fileAttributes;
@With
Space prefix;
@With
Markers markers;
@Nullable // for backwards compatibility
@With(AccessLevel.PRIVATE)
String charsetName;
@With
@Getter
boolean charsetBomMarked;
@Override
public Charset getCharset() {
return charsetName == null ? StandardCharsets.UTF_8 : Charset.forName(charsetName);
}
@Override
public SourceFile withCharset(Charset charset) {
return withCharsetName(charset.name());
}
@With
@Getter
@Nullable
Checksum checksum;
@With
List body;
@With
Space eof;
public CoordinateBuilder.ConfigFile getCoordinates() {
return new CoordinateBuilder.ConfigFile(this);
}
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitConfigFile(this, p);
}
@Override
public String toString() {
return "ConfigFile";
}
@Override
public
TreeVisitor, PrintOutputCapture
> printer(Cursor cursor) {
return new HclPrinter<>();
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class Empty implements Expression {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
@Override
public
Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitEmpty(this, p);
}
@Override
public String toString() {
return "Empty";
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class ForIntro implements Hcl {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
HclContainer variables;
public List getVariables() {
return variables.getElements();
}
public ForIntro withVariables(List variables) {
return getPadding().withVariables(HclContainer.withElements(this.variables, variables));
}
@With
@Getter
Expression in;
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitForIntro(this, p);
}
@Override
public String toString() {
return "ForIntro";
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final ForIntro t;
public HclContainer getVariables() {
return t.variables;
}
public ForIntro withVariables(HclContainer variables) {
return t.variables == variables ? t : new ForIntro(t.id, t.prefix, t.markers, variables, t.in);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class ForObject implements Expression {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
@With
@Getter
ForIntro intro;
HclLeftPadded updateName;
public Expression getUpdateName() {
return updateName.getElement();
}
public ForObject withUpdateName(Expression updateName) {
return getPadding().withUpdateName(this.updateName.withElement(updateName));
}
HclLeftPadded updateValue;
public Expression getUpdateValue() {
return updateValue.getElement();
}
public ForObject withUpdateValue(Expression updateValue) {
return getPadding().withUpdateValue(this.updateValue.withElement(updateValue));
}
@With
@Getter
@Nullable
Empty ellipsis;
@Nullable
HclLeftPadded condition;
public @Nullable Expression getCondition() {
return condition == null ? null : condition.getElement();
}
public ForObject withCondition(Expression condition) {
return getPadding().withCondition(HclLeftPadded.withElement(this.condition, condition));
}
@With
@Getter
Space end;
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitForObject(this, p);
}
@Override
public String toString() {
return "ForTuple";
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final ForObject t;
public HclLeftPadded getUpdateName() {
return t.updateName;
}
public ForObject withUpdateName(HclLeftPadded updateName) {
return t.updateName == updateName ? t : new ForObject(t.id, t.prefix, t.markers, t.intro, updateName, t.updateValue, t.ellipsis, t.condition, t.end);
}
public HclLeftPadded getUpdateValue() {
return t.updateValue;
}
public ForObject withUpdateValue(HclLeftPadded updateValue) {
return t.updateValue == updateValue ? t : new ForObject(t.id, t.prefix, t.markers, t.intro, t.updateName, updateValue, t.ellipsis, t.condition, t.end);
}
public @Nullable HclLeftPadded getCondition() {
return t.condition;
}
public ForObject withCondition(@Nullable HclLeftPadded condition) {
return t.condition == condition ? t : new ForObject(t.id, t.prefix, t.markers, t.intro, t.updateName, t.updateValue, t.ellipsis, condition, t.end);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class ForTuple implements Expression {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
@With
@Getter
ForIntro intro;
HclLeftPadded update;
public Expression getUpdateName() {
return update.getElement();
}
public ForTuple withUpdateName(Expression updateName) {
return getPadding().withUpdate(this.update.withElement(updateName));
}
@Nullable
HclLeftPadded condition;
public @Nullable Expression getCondition() {
return condition == null ? null : condition.getElement();
}
public ForTuple withCondition(Expression condition) {
return getPadding().withCondition(HclLeftPadded.withElement(this.condition, condition));
}
@With
@Getter
Space end;
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitForTuple(this, p);
}
@Override
public String toString() {
return "ForTuple";
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final ForTuple t;
public HclLeftPadded getUpdate() {
return t.update;
}
public ForTuple withUpdate(HclLeftPadded update) {
return t.update == update ? t : new ForTuple(t.id, t.prefix, t.markers, t.intro, update, t.condition, t.end);
}
public @Nullable HclLeftPadded getCondition() {
return t.condition;
}
public ForTuple withCondition(@Nullable HclLeftPadded condition) {
return t.condition == condition ? t : new ForTuple(t.id, t.prefix, t.markers, t.intro, t.update, condition, t.end);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class FunctionCall implements Expression {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
@With
@Getter
Identifier name;
HclContainer arguments;
public List getVariables() {
return arguments.getElements();
}
public FunctionCall withArguments(List arguments) {
return getPadding().withArguments(HclContainer.withElements(this.arguments, arguments));
}
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitFunctionCall(this, p);
}
@Override
public String toString() {
return "FunctionCall{" + name + ", argArity=" + arguments.getElements().size() + "}";
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final FunctionCall t;
public HclContainer getArguments() {
return t.arguments;
}
public FunctionCall withArguments(HclContainer arguments) {
return t.arguments == arguments ? t : new FunctionCall(t.id, t.prefix, t.markers, t.name, arguments);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class HeredocTemplate implements Expression {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
String arrow;
public HeredocTemplate withArrow(String arrow) {
if (!"<<".equals(arrow) && !"<<-".equals(arrow)) {
throw new IllegalArgumentException("Heredoc arrow must be one of << or <<-");
}
return this.arrow.equals(arrow) ? this :
new HeredocTemplate(id, prefix, markers, arrow, delimiter, expressions, end);
}
@With
Identifier delimiter;
@With
List expressions;
@With
Space end;
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitHeredocTemplate(this, p);
}
@Override
public String toString() {
return "QuotedTemplate";
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class Identifier implements Expression, Label {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
@With
String name;
@Override
public
Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitIdentifier(this, p);
}
@Override
public String toString() {
return "Identifier{" + name + "}";
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class Index implements Expression {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
@With
Expression indexed;
@With
Position position;
@Override
public
Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitIndex(this, p);
}
@Override
public String toString() {
return "Index";
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public static class Position implements Hcl {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
HclRightPadded position;
public Expression getPosition() {
return position.getElement();
}
public Position withPosition(Expression position) {
return getPadding().withPosition(this.position.withElement(position));
}
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitIndexPosition(this, p);
}
@Override
public String toString() {
return "IndexPosition";
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final Position t;
public HclRightPadded getPosition() {
return t.position;
}
public Position withPosition(HclRightPadded position) {
return t.position == position ? t : new Position(t.id, t.prefix, t.markers, position);
}
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class Literal implements Hcl, Expression, Label {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
@With
Object value;
@With
String valueSource;
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitLiteral(this, p);
}
@Override
public String toString() {
return "Literal{" + valueSource + "}";
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class ObjectValue implements Expression {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
/**
* Can be an {@link Attribute} or {@link Empty}. {@link Empty} is the
* type of a trailing comma at the end of the attribute list.
*/
HclContainer attributes;
public List getAttributes() {
return attributes.getElements();
}
public ObjectValue withArguments(List attributes) {
return getPadding().withAttributes(HclContainer.withElements(this.attributes, attributes));
}
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitObjectValue(this, p);
}
@Override
public String toString() {
return "ObjectValue";
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final ObjectValue t;
public HclContainer getAttributes() {
return t.attributes;
}
public ObjectValue withAttributes(HclContainer attributes) {
return t.attributes == attributes ? t : new ObjectValue(t.id, t.prefix, t.markers, attributes);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class Parentheses implements Expression {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
HclRightPadded expression;
public Expression getExpression() {
return expression.getElement();
}
public Parentheses withExpression(Expression expression) {
return getPadding().withExpression(this.expression.withElement(expression));
}
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitParentheses(this, p);
}
@Override
public String toString() {
return "Parentheses";
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final Parentheses t;
public HclRightPadded getExpression() {
return t.expression;
}
public Parentheses withExpression(HclRightPadded expression) {
return t.expression == expression ? t : new Parentheses(t.id, t.prefix, t.markers, expression);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class QuotedTemplate implements Expression {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
@With
List expressions;
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitQuotedTemplate(this, p);
}
@Override
public String toString() {
return "QuotedTemplate";
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class Splat implements Expression {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
@With
Expression select;
@With
Operator operator;
@Override
public
Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitSplat(this, p);
}
@Override
public String toString() {
return "Splat{" + select + "}";
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
public static class Operator implements Hcl {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
@With
Type type;
/**
* The {@link Empty} here is a placeholder for the fixed '*' token.
*
* Left padding between the '*' and the preceding '.' or '[', depending on whether it
* is an attribute splat or full splat.
*
* Right padding possible for full splats (between the '*' and the ']').
*/
@With
HclRightPadded splat;
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitSplatOperator(this, p);
}
@Override
public String toString() {
return "SplatOperator";
}
public enum Type {
Attribute,
Full
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class TemplateInterpolation implements Hcl, Expression {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
@With
Expression expression;
@Override
public
Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitTemplateInterpolation(this, p);
}
@Override
public String toString() {
return "TemplateInterpolation";
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
class Tuple implements CollectionValue {
@Nullable
@NonFinal
transient WeakReference padding;
@With
@EqualsAndHashCode.Include
@Getter
UUID id;
@With
@Getter
Space prefix;
@With
@Getter
Markers markers;
HclContainer values;
public List getValues() {
return values.getElements();
}
public Tuple withValues(List values) {
return getPadding().withValues(HclContainer.withElements(this.values, values));
}
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitTuple(this, p);
}
@Override
public String toString() {
return "Tuple";
}
public Padding getPadding() {
Padding p;
if (this.padding == null) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
} else {
p = this.padding.get();
if (p == null || p.t != this) {
p = new Padding(this);
this.padding = new WeakReference<>(p);
}
}
return p;
}
@RequiredArgsConstructor
public static class Padding {
private final Tuple t;
public HclContainer getValues() {
return t.values;
}
public Tuple withValues(HclContainer values) {
return t.values == values ? t : new Tuple(t.id, t.prefix, t.markers, values);
}
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class Unary implements Expression {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
@With
Type operator;
@With
Expression expression;
@Override
public Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitUnary(this, p);
}
@Override
public String toString() {
return "Unary";
}
public enum Type {
Negative,
Not
}
}
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
@Data
class VariableExpression implements Expression {
@With
@EqualsAndHashCode.Include
UUID id;
@With
Space prefix;
@With
Markers markers;
@With
Identifier name;
@Override
public
Hcl acceptHcl(HclVisitor
v, P p) {
return v.visitVariableExpression(this, p);
}
@Override
public String toString() {
return "Variable{" + name + "}";
}
}
}