This is an automated email from the ASF dual-hosted git repository.

lkishalmi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new b1f2e5b4a0 Made HCL AST on records Use TextBlocks in formatting test, 
minor enhancements
b1f2e5b4a0 is described below

commit b1f2e5b4a0e78b2194d59b7560d369ebb77f59ee
Author: Laszlo Kishalmi <[email protected]>
AuthorDate: Sun Mar 17 07:30:39 2024 -0700

    Made HCL AST on records
    Use TextBlocks in formatting test, minor enhancements
---
 ide/languages.hcl/manifest.mf                      |   2 +-
 ide/languages.hcl/nbproject/project.properties     |   4 +-
 .../modules/languages/hcl/HCLSemanticAnalyzer.java |  71 +++++-----
 .../modules/languages/hcl/HCLStructureItem.java    |  17 ++-
 .../netbeans/modules/languages/hcl/SourceRef.java  |   9 +-
 .../languages/hcl/ast/HCLAddressableElement.java   |  47 -------
 .../languages/hcl/ast/HCLArithmeticOperation.java  |  42 ++----
 .../modules/languages/hcl/ast/HCLAttribute.java    |  35 +----
 .../modules/languages/hcl/ast/HCLBlock.java        |  37 +++--
 .../modules/languages/hcl/ast/HCLBlockFactory.java |  74 ++++------
 .../modules/languages/hcl/ast/HCLCollection.java   |  81 +++--------
 .../languages/hcl/ast/HCLConditionalOperation.java |  14 +-
 .../modules/languages/hcl/ast/HCLContainer.java    |  55 +++-----
 .../modules/languages/hcl/ast/HCLDocument.java     |  23 +++-
 .../modules/languages/hcl/ast/HCLElement.java      |  75 +----------
 .../languages/hcl/ast/HCLElementFactory.java       |  75 +++++++++++
 .../modules/languages/hcl/ast/HCLExpression.java   |  35 +++--
 .../languages/hcl/ast/HCLExpressionFactory.java    | 123 ++++++-----------
 .../languages/hcl/ast/HCLForExpression.java        |  49 ++-----
 .../modules/languages/hcl/ast/HCLFunction.java     |  28 +---
 .../modules/languages/hcl/ast/HCLIdentifier.java   |  45 ++-----
 .../modules/languages/hcl/ast/HCLLiteral.java      |  41 +-----
 .../languages/hcl/ast/HCLResolveOperation.java     |  64 ++-------
 .../modules/languages/hcl/ast/HCLTemplate.java     |  89 +++---------
 .../modules/languages/hcl/ast/HCLTreeWalker.java   |  58 ++++++++
 .../modules/languages/hcl/ast/HCLVariable.java     |  18 +--
 .../hcl/terraform/TerraformParserResult.java       |  79 ++++++-----
 .../hcl/terraform/TerraformSemanticAnalyzer.java   |  41 ++----
 .../languages/hcl/tfvars/TFVarsParserResult.java   |   6 +-
 .../modules/languages/hcl/HCLIndenterTest.java     | 149 +++++++++++++++++++--
 .../modules/languages/hcl/ReferenceTest.java       |   7 +-
 .../modules/languages/hcl/ast/HCLLiteralsTest.java |   8 +-
 .../languages/hcl/ast/HCLOperationsTest.java       |  34 ++---
 33 files changed, 640 insertions(+), 895 deletions(-)

diff --git a/ide/languages.hcl/manifest.mf b/ide/languages.hcl/manifest.mf
index ac658e5249..642080e4ed 100644
--- a/ide/languages.hcl/manifest.mf
+++ b/ide/languages.hcl/manifest.mf
@@ -3,5 +3,5 @@ OpenIDE-Module: org.netbeans.modules.languages.hcl
 OpenIDE-Module-Layer: org/netbeans/modules/languages/hcl/layer.xml
 OpenIDE-Module-Localizing-Bundle: 
org/netbeans/modules/languages/hcl/Bundle.properties
 OpenIDE-Module-Specification-Version: 1.4
-OpenIDE-Module-Java-Dependencies: Java > 11
+OpenIDE-Module-Java-Dependencies: Java > 17
 AutoUpdate-Show-In-Client: true
diff --git a/ide/languages.hcl/nbproject/project.properties 
b/ide/languages.hcl/nbproject/project.properties
index 5163ac1bd4..9d38ead391 100644
--- a/ide/languages.hcl/nbproject/project.properties
+++ b/ide/languages.hcl/nbproject/project.properties
@@ -14,6 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-javac.source=11
-javac.target=11
+javac.source=17
+javac.target=17
 
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/HCLSemanticAnalyzer.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/HCLSemanticAnalyzer.java
index 86581df92b..a320de27f4 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/HCLSemanticAnalyzer.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/HCLSemanticAnalyzer.java
@@ -29,11 +29,10 @@ import org.netbeans.modules.csl.api.SemanticAnalyzer;
 import org.netbeans.modules.languages.hcl.ast.HCLAttribute;
 import org.netbeans.modules.languages.hcl.ast.HCLBlock;
 import org.netbeans.modules.languages.hcl.ast.HCLCollection;
-import org.netbeans.modules.languages.hcl.ast.HCLDocument;
 import org.netbeans.modules.languages.hcl.ast.HCLElement;
-import org.netbeans.modules.languages.hcl.ast.HCLExpression;
 import org.netbeans.modules.languages.hcl.ast.HCLFunction;
 import org.netbeans.modules.languages.hcl.ast.HCLIdentifier;
+import org.netbeans.modules.languages.hcl.ast.HCLTreeWalker;
 import org.netbeans.modules.languages.hcl.ast.HCLVariable;
 import org.netbeans.modules.parsing.spi.Scheduler;
 import org.netbeans.modules.parsing.spi.SchedulerEvent;
@@ -64,8 +63,7 @@ public class HCLSemanticAnalyzer extends 
SemanticAnalyzer<HCLParserResult> {
         resume();
 
         Highlighter h = createHighlighter(result);
-        result.getDocument().accept(h);
-        highlights = h.work;
+        highlights = h.process(result.getDocument());
     }
 
     protected Highlighter createHighlighter(HCLParserResult result) {
@@ -74,7 +72,7 @@ public class HCLSemanticAnalyzer extends 
SemanticAnalyzer<HCLParserResult> {
     
     @Override
     public int getPriority() {
-        return 0;
+        return 100;
     }
 
     @Override
@@ -87,7 +85,7 @@ public class HCLSemanticAnalyzer extends 
SemanticAnalyzer<HCLParserResult> {
         cancelled = true;
     }
     
-    protected abstract class Highlighter extends HCLElement.BAEVisitor {
+    protected abstract class Highlighter {
         protected final Map<OffsetRange, Set<ColoringAttributes>> work = new 
HashMap<>();
 
         protected final SourceRef refs;
@@ -95,17 +93,25 @@ public class HCLSemanticAnalyzer extends 
SemanticAnalyzer<HCLParserResult> {
             this.refs = refs;
         }
 
-        @Override
-        public final boolean visit(HCLElement e) {
+        protected abstract void highlight(HCLTreeWalker.Step step);
+
+        private boolean cancellableHighlight(HCLTreeWalker.Step step) {
             if (isCancelled()) {
-                return true;
+                return false;
             }
-            return super.visit(e);
+            highlight(step);
+            return true;
+        }
+
+        public Map<OffsetRange, Set<ColoringAttributes>> process(HCLElement 
element) {
+            HCLTreeWalker.depthFirst(element, this::cancellableHighlight);
+            return work;
         }
         
         protected final void mark(HCLElement e, Set<ColoringAttributes> attrs) 
{
             refs.getOffsetRange(e).ifPresent((range) -> work.put(range, 
attrs));
         }
+
     }
     
     protected class DefaultHighlighter extends Highlighter {
@@ -115,9 +121,12 @@ public class HCLSemanticAnalyzer extends 
SemanticAnalyzer<HCLParserResult> {
         }
         
         @Override
-        protected boolean visitBlock(HCLBlock block) {
-            if (block.getParent() instanceof HCLDocument) {
-                List<HCLIdentifier> decl = block.getDeclaration();
+        protected void highlight(HCLTreeWalker.Step step) {
+
+            // TODO: Can use record patterns from Java 21
+            HCLElement e = step.node();
+            if (e instanceof HCLBlock block && step.depth() == 1) {
+                List<HCLIdentifier> decl = block.declaration();
                 HCLIdentifier type = decl.get(0);
 
                 mark(type, ColoringAttributes.CLASS_SET);
@@ -127,35 +136,17 @@ public class HCLSemanticAnalyzer extends 
SemanticAnalyzer<HCLParserResult> {
                         mark(id, ColoringAttributes.CONSTRUCTOR_SET);
                     }
                 }
-            } else {
-                //TODO: Handle nested Blocks...
-            }
-            return false;
-        }
-
-        @Override
-        protected boolean visitAttribute(HCLAttribute attr) {
-            mark(attr.getName(), ColoringAttributes.FIELD_SET);
-            return false;
-        }
-
-        @Override
-        protected boolean visitExpression(HCLExpression expr) {
-            if (expr instanceof HCLFunction) {
-                HCLFunction func =  (HCLFunction) expr;
-                mark(func.getName(), ColoringAttributes.CONSTRUCTOR_SET);
-            }
-
-            if (expr instanceof HCLCollection.Object) {
-                HCLCollection.Object obj = (HCLCollection.Object) expr;
-                for (HCLExpression key : obj.getKeys()) {
-                    if (key instanceof HCLVariable) {
-                        mark(key, ColoringAttributes.FIELD_SET);
+            } else if (e instanceof HCLAttribute attr) {
+                mark(attr.name(), ColoringAttributes.FIELD_SET);
+            } else if (e instanceof HCLFunction func) {
+                mark(func.name(), ColoringAttributes.CONSTRUCTOR_SET);
+            } else if (e instanceof HCLCollection.Object obj) {
+                for (HCLCollection.ObjectElement oe : obj.elements()) {
+                    if (oe.key() instanceof HCLVariable) {
+                        mark(oe.key(), ColoringAttributes.FIELD_SET);
                     }
                 }
             }
-            return false;
-        }
-        
+        }        
     }
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/HCLStructureItem.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/HCLStructureItem.java
index 6c8b845fef..f269863e74 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/HCLStructureItem.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/HCLStructureItem.java
@@ -30,10 +30,10 @@ import org.netbeans.modules.csl.api.Modifier;
 import org.netbeans.modules.csl.api.OffsetRange;
 import org.netbeans.modules.csl.api.StructureItem;
 import org.netbeans.modules.csl.spi.ParserResult;
-import org.netbeans.modules.languages.hcl.ast.HCLAddressableElement;
 import org.netbeans.modules.languages.hcl.ast.HCLAttribute;
 import org.netbeans.modules.languages.hcl.ast.HCLBlock;
 import org.netbeans.modules.languages.hcl.ast.HCLContainer;
+import org.netbeans.modules.languages.hcl.ast.HCLElement;
 import org.openide.filesystems.FileObject;
 
 /**
@@ -42,11 +42,11 @@ import org.openide.filesystems.FileObject;
  */
 public class HCLStructureItem implements ElementHandle, StructureItem {
 
-    final HCLAddressableElement element;
+    final HCLElement element;
     final SourceRef references;
     private List<? extends StructureItem> nestedCache;
 
-    public HCLStructureItem(HCLAddressableElement element, SourceRef 
references) {
+    public HCLStructureItem(HCLElement element, SourceRef references) {
         this.element = element;
         this.references = references;
     }
@@ -63,7 +63,12 @@ public class HCLStructureItem implements ElementHandle, 
StructureItem {
 
     @Override
     public String getName() {
-        return element.id();
+        if (element instanceof HCLAttribute a) {
+            return a.id();
+        } else if (element instanceof HCLBlock b) {
+            return b.id();
+        }
+        return  "<" + element.getClass().getSimpleName() + ">";
     }
 
     @Override
@@ -113,10 +118,10 @@ public class HCLStructureItem implements ElementHandle, 
StructureItem {
             if (element instanceof HCLContainer) {
                 HCLContainer c = (HCLContainer) element;
                 List<HCLStructureItem> nested = new ArrayList<>();
-                for (HCLBlock block : c.getBlocks()) {
+                for (HCLBlock block : c.blocks()) {
                     nested.add(new HCLStructureItem(block, references));
                 }
-                for (HCLAttribute attribute : c.getAttributes()) {
+                for (HCLAttribute attribute : c.attributes()) {
                     nested.add(new HCLStructureItem(attribute, references));
                 }
                 nestedCache = nested;
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/SourceRef.java 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/SourceRef.java
index e83ba786e5..0e34fd9fcd 100644
--- a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/SourceRef.java
+++ b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/SourceRef.java
@@ -19,7 +19,7 @@
 package org.netbeans.modules.languages.hcl;
 
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -28,6 +28,7 @@ import java.util.Optional;
 import java.util.TreeMap;
 import org.netbeans.modules.csl.api.OffsetRange;
 import org.netbeans.modules.languages.hcl.ast.HCLElement;
+import org.netbeans.modules.languages.hcl.ast.HCLElementFactory;
 import org.netbeans.modules.parsing.api.Snapshot;
 import org.openide.filesystems.FileObject;
 
@@ -37,7 +38,7 @@ import org.openide.filesystems.FileObject;
  */
 public class SourceRef {
     public final Snapshot source;
-    private Map<HCLElement, OffsetRange> elementOffsets = new HashMap<>();
+    private Map<HCLElement, OffsetRange> elementOffsets = new 
IdentityHashMap<>();
 
     private TreeMap<OffsetRange, HCLElement> elementAt = new TreeMap<>((o1, 
o2) -> o1.getStart() != o2.getStart() ? o1.getStart() - o2.getStart() : 
o2.getEnd() - o1.getEnd());
     
@@ -53,8 +54,8 @@ public class SourceRef {
         }
     }
 
-    void elementCreated(HCLElement.CreateContext ctx) {
-        add(ctx.element, new OffsetRange(ctx.start.getStartIndex(), 
ctx.stop.getStopIndex() + 1));
+    void elementCreated(HCLElementFactory.CreateContext ctx) {
+        add(ctx.element(), new OffsetRange(ctx.start().getStartIndex(), 
ctx.stop().getStopIndex() + 1));
     }
 
     public FileObject getFileObject() {
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLAddressableElement.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLAddressableElement.java
deleted file mode 100644
index 407648d3d4..0000000000
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLAddressableElement.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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
- *
- *   http://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.netbeans.modules.languages.hcl.ast;
-
-/**
- *
- * @author lkishalmi
- */
-public abstract class HCLAddressableElement extends HCLElement {
-    
-    final HCLAddressableElement parent;
-
-    public HCLAddressableElement(HCLAddressableElement parent) {
-        this.parent = parent;
-    }
-
-    public final HCLAddressableElement getParent() {
-        return parent;
-    }
-
-    public HCLContainer getContainer() {
-        HCLAddressableElement e = parent;
-        while (e != null && !(e instanceof HCLContainer)) {
-            e = e.parent;
-        }
-        return (HCLContainer) e;
-    }
-
-    public abstract String id();
-
-}
\ No newline at end of file
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLArithmeticOperation.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLArithmeticOperation.java
index 3386a8fd79..c8b5468bea 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLArithmeticOperation.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLArithmeticOperation.java
@@ -18,15 +18,15 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 
 /**
  *
  * @author lkishalmi
  */
-public abstract class HCLArithmeticOperation extends HCLExpression {
+public sealed interface HCLArithmeticOperation extends HCLExpression {
+
+    Operator op();
 
     public enum Operator {
         NOT("!"),
@@ -61,51 +61,27 @@ public abstract class HCLArithmeticOperation extends 
HCLExpression {
         }
     }
 
-    public final Operator op;
-
-    public HCLArithmeticOperation(Operator op) {
-        this.op = op;
-    }
-
-    public final static class Binary extends HCLArithmeticOperation {
-        public final HCLExpression left;
-        public final HCLExpression right;
-
-        public Binary(Operator op, HCLExpression left, HCLExpression right) {
-            super(op);
-            this.left = left;
-            this.right = right;
-        }
-
+    public record Binary(Operator op, HCLExpression left, HCLExpression right) 
implements HCLArithmeticOperation {
         @Override
         public String asString() {
             return left.toString() + op.toString() + right.toString();
         }
 
         @Override
-        public List<? extends HCLExpression> getChildren() {
-            return Arrays.asList(left, right);
+        public List<? extends HCLExpression> elements() {
+            return List.of(left, right);
         }
-                
     } 
 
-    public final static class Unary extends HCLArithmeticOperation {
-        public final HCLExpression operand;
-
-        public Unary(Operator op, HCLExpression operand) {
-            super(op);
-            this.operand = operand;
-        }
-        
+    public record Unary(Operator op, HCLExpression operand) implements 
HCLArithmeticOperation {
         @Override
         public String asString() {
             return op.toString() + operand.toString();
         }
 
         @Override
-        public List<? extends HCLExpression> getChildren() {
-            return Collections.singletonList(operand);
+        public List<? extends HCLExpression> elements() {
+            return List.of(operand);
         }
-        
     } 
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLAttribute.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLAttribute.java
index 64ea0a16e9..0ad41a869a 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLAttribute.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLAttribute.java
@@ -18,46 +18,21 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
+import java.util.List;
+
 
 /**
  *
  * @author Laszlo Kishalmi
  */
-public final class HCLAttribute extends HCLAddressableElement {
-
-    final HCLIdentifier name;
-    final HCLExpression value;
-    final int group;
+public record HCLAttribute(HCLIdentifier name, HCLExpression value) implements 
HCLElement {
 
-    public HCLAttribute(HCLContainer parent, HCLIdentifier name, HCLExpression 
value, int group) {
-        super(parent);
-        this.name = name;
-        this.value = value;
-        this.group = group;
-    }
- 
-    @Override
     public String id() {
         return name.id();
     }
 
-    public HCLIdentifier getName() {
-        return name;
-    }
-
-    public HCLExpression getValue() {
-        return value;
-    }
-
-    public int getGroup() {
-        return group;
-    }
-
     @Override
-    public void accept(Visitor v) {
-        if (!v.visit(this) && (value != null)) {
-            value.accept(v);
-        }
+    public List<? extends HCLElement> elements() {
+        return  value != null ? List.of(name, value) : List.of(name);
     }
-    
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLBlock.java 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLBlock.java
index 7967d9af61..e6478044ac 100644
--- a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLBlock.java
+++ b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLBlock.java
@@ -18,35 +18,46 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 /**
  *
  * @author Laszlo Kishalmi
  */
-public class HCLBlock extends HCLContainer {
+public final class HCLBlock extends HCLContainer  {
 
-    private List<HCLIdentifier> declaration;
-    private String id;
+    private final String id;
 
-    public HCLBlock(HCLContainer parent) {
-        super(parent);
+    private final List<HCLIdentifier> declaration;
+
+    public HCLBlock(List<HCLIdentifier> declaration, List<HCLElement> 
elements) {
+        super(elements);
+        this.declaration = List.copyOf(declaration);
+        this.id = declaration.stream().map(d -> 
d.id()).collect(Collectors.joining("."));
     }
 
-    void setDeclaration(List<HCLIdentifier> declaration) {
-        this.declaration = Collections.unmodifiableList(declaration);
-        id = declaration.stream().map(d -> 
d.id()).collect(Collectors.joining("."));
+    public List<HCLIdentifier> declaration() {
+        return declaration;
     }
 
-    
-    @Override
     public String id() {
         return id;
     }
+    @Override
+    public String toString() {
+        return "HCLBlock[declaration=" + declaration + ", elements=" + 
elements + "]";
+    }
 
-    public List<HCLIdentifier> getDeclaration() {
-        return declaration;
+
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof HCLBlock that ? Objects.equals(this.declaration, 
that.declaration) && Objects.equals(this.elements, that.elements) : false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(declaration, elements);
     }
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLBlockFactory.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLBlockFactory.java
index 3f3bed8773..b2474fc929 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLBlockFactory.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLBlockFactory.java
@@ -19,6 +19,7 @@
 package org.netbeans.modules.languages.hcl.ast;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Consumer;
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.Token;
@@ -32,16 +33,14 @@ import org.netbeans.modules.languages.hcl.grammar.HCLParser;
  *
  * @author lkishalmi
  */
-public class HCLBlockFactory {
-
-    private final Consumer<HCLElement.CreateContext> createAction;
+public final class HCLBlockFactory extends HCLElementFactory {
     private final HCLExpressionFactory exprFactory;
 
     private int group = 0;
     private ParserRuleContext prev = null;
 
-    public HCLBlockFactory(Consumer<HCLElement.CreateContext> createAction) {
-        this.createAction = createAction;
+    public HCLBlockFactory(Consumer<CreateContext> createAction) {
+        super(createAction);
         this.exprFactory = new HCLExpressionFactory(createAction);
     }
     
@@ -50,27 +49,23 @@ public class HCLBlockFactory {
     }
     
     public final HCLDocument process(HCLParser.ConfigFileContext ctx) {
-        var ret = new HCLDocument();
-        if (ctx.body() != null) {
-            body(ret, ctx.body());
-        }
-        return ret;
+        return new HCLDocument(ctx.body() != null ? body(ctx.body()) : 
List.of());
     }
     
-    protected HCLBlock block(HCLContainer parent, HCLParser.BlockContext ctx) {
-        HCLBlock ret = created(new HCLBlock(parent), ctx);
+    protected HCLBlock block(HCLParser.BlockContext ctx) {
         
+       ArrayList<HCLElement> elements = new ArrayList<>();
         
         if (ctx.body() != null) {
-            body(ret, ctx.body());
+            elements.addAll(body(ctx.body()));
         }
         
-        ArrayList<HCLIdentifier> decl = new ArrayList<>(4);
+        List<HCLIdentifier> decl = new ArrayList<>(4);
         
         if (ctx.children != null) {
             for (ParseTree pt : ctx.children) {
-                if (pt instanceof TerminalNode) {
-                    Token token = ((TerminalNode) pt).getSymbol();
+                if (pt instanceof TerminalNode tn) {
+                    Token token = tn.getSymbol();
                     if (token.getType() == HCLLexer.IDENTIFIER) {
                         HCLIdentifier attrName = created(new 
HCLIdentifier.SimpleId( token.getText()), token);
                         if (pt instanceof ErrorNode) {
@@ -78,15 +73,14 @@ public class HCLBlockFactory {
                             if (prev != null) {
                                 group += prev.stop.getLine() + 1 < 
token.getLine() ? 1 : 0;
                             }
-                            HCLAttribute attr = created(new HCLAttribute(ret, 
attrName, null, group), token);
-                            ret.add(attr);
+                            HCLAttribute attr = created(new 
HCLAttribute(attrName, null), token, token, group);
+                            elements.add(attr);
                         } else {
                             decl.add(attrName);
                         }
                     }
                 }
-                if (pt instanceof HCLParser.StringLitContext) {
-                    HCLParser.StringLitContext slit = 
(HCLParser.StringLitContext) pt;
+                if (pt instanceof HCLParser.StringLitContext slit) {
                     String sid = slit.getText();
                     if (sid.length() > 1) { // Do not process the '"' string 
literal
                         sid = sid.substring(1, sid.length() - 
(sid.endsWith("\"") ? 1 : 0));
@@ -97,59 +91,41 @@ public class HCLBlockFactory {
             }
         }
         
-        ret.setDeclaration(decl);
-        
-        return ret;
+        return created(new HCLBlock(decl, elements), ctx);
     }
 
-    protected void body(HCLContainer c, HCLParser.BodyContext ctx) {
+    protected List<HCLElement> body(HCLParser.BodyContext ctx) {
+        List<HCLElement> c = new ArrayList<>();
         if (ctx.children != null) {
             for (ParseTree pt : ctx.children) {
-                if (pt instanceof HCLParser.AttributeContext) {
-                    HCLParser.AttributeContext actx = 
(HCLParser.AttributeContext) pt;
+                if (pt instanceof HCLParser.AttributeContext actx) {
                     if (prev != null) {
                         group += prev.stop.getLine() + 1 < 
actx.start.getLine() ? 1 : 0;
                     }
                     HCLIdentifier attrName = created(new 
HCLIdentifier.SimpleId(actx.IDENTIFIER().getText()), 
actx.IDENTIFIER().getSymbol());
                     HCLExpression attrValue = 
exprFactory.process(actx.expression());
-                    HCLAttribute attr = created(new HCLAttribute(c, attrName, 
attrValue, group), actx);
+                    HCLAttribute attr = created(new HCLAttribute(attrName, 
attrValue), actx, group);
                     c.add(attr);
                     prev = actx;
                     continue;
                 }
-                if (pt instanceof HCLParser.BlockContext) {
-                    c.add(block(c, (HCLParser.BlockContext) pt));
+                if (pt instanceof HCLParser.BlockContext bct) {
+                    c.add(block(bct));
                     continue;
                 }
-                if (pt instanceof ErrorNode) {
-                    Token token = ((ErrorNode) pt).getSymbol();
+                if (pt instanceof ErrorNode en) {
+                    Token token = en.getSymbol();
                     if (token.getType() == HCLLexer.IDENTIFIER) {
                         if (prev != null) {
                             group += prev.stop.getLine() + 1 < token.getLine() 
? 1 : 0;
                         }
                         HCLIdentifier attrName = created(new 
HCLIdentifier.SimpleId(token.getText()), token);
-                        HCLAttribute attr = new HCLAttribute(c, attrName, 
null, group);
+                        HCLAttribute attr = new HCLAttribute(attrName, null); 
//TODO: created?
                         c.add(attr);
                     }
                 }
             }
         }
+        return c;
     }
-    
-    private <E extends HCLElement> E created(E element, Token token) {
-        elementCreated(element, token, token);
-        return element;
-    }
-
-    private <E extends HCLElement> E created(E element, ParserRuleContext ctx) 
{
-        elementCreated(element, ctx.start, ctx.stop);
-        return element;
-    }
-
-    private void elementCreated(HCLElement element, Token start, Token stop) {
-        if (createAction != null) {
-            createAction.accept(new HCLElement.CreateContext(element, start, 
stop));
-        }
-    }
-
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLCollection.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLCollection.java
index bbb740b8ff..02acecad40 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLCollection.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLCollection.java
@@ -18,8 +18,6 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.StringJoiner;
 
@@ -27,21 +25,14 @@ import java.util.StringJoiner;
  *
  * @author lkishalmi
  */
-public abstract class HCLCollection<T> extends HCLExpression {
+public sealed interface HCLCollection<T> extends HCLExpression {
 
-    public final List<T> elements;
+    public record Tuple(List<HCLExpression> elements) implements  
HCLCollection<HCLExpression> {
 
-    public HCLCollection(List<T> elements) {
-        this.elements = Collections.unmodifiableList(elements);
-    }
-    
-    public static final class Tuple extends HCLCollection<HCLExpression> {
-
-
-        public Tuple(List<HCLExpression> elements) {
-            super(elements);
+        public Tuple {
+            elements = List.copyOf(elements);
         }
-        
+
         @Override
         public String asString() {
             StringJoiner sj = new StringJoiner(",", "[", "]");
@@ -51,52 +42,24 @@ public abstract class HCLCollection<T> extends 
HCLExpression {
             return sj.toString();
         }
 
-        @Override
-        public List<? extends HCLExpression> getChildren() {
-            return elements;
-        }
-        
     }
-    
-    public static final class ObjectElement {
-        public final HCLExpression key;
-        public final HCLExpression value;
-        public final int group;
 
-        public ObjectElement(HCLExpression key, HCLExpression value, int 
group) {
-            this.key = key;
-            this.value = value;
-            this.group = group;
+    public record ObjectElement(HCLExpression key, HCLExpression value) 
implements HCLExpression {
+        @Override
+        public String asString() {
+            return key.asString() + "=" + value.asString();
         }
 
         @Override
-        public String toString() {
-            return key.asString() + "=" + value.asString();
+        public List<? extends HCLExpression> elements() {
+            return List.of(key, value);
         }
-        
-        
     }
     
-    public static final class Object extends HCLCollection<ObjectElement> {
+    public record Object(List<ObjectElement> elements) implements 
HCLCollection<ObjectElement> {
 
-        private final List<? extends HCLExpression> parts;
-        private final List<? extends HCLExpression> keys;
-        private final List<? extends HCLExpression> values;
-        
-        public Object(List<ObjectElement> elements) {
-            super(elements);
-            List<HCLExpression> p = new ArrayList<>(elements.size() * 2);
-            List<HCLExpression> k = new ArrayList<>(elements.size());
-            List<HCLExpression> v = new ArrayList<>(elements.size());
-            for (ObjectElement e : elements) {
-                k.add(e.key);
-                v.add(e.value);
-                p.add(e.key);
-                p.add(e.value);
-            }
-            parts = Collections.unmodifiableList(p);
-            keys = Collections.unmodifiableList(k);
-            values = Collections.unmodifiableList(v);
+        public Object {
+            elements = List.copyOf(elements);
         }
 
         @Override
@@ -106,20 +69,6 @@ public abstract class HCLCollection<T> extends 
HCLExpression {
                 sj.add(element.toString());
             }
             return sj.toString();
-        }
-
-        public List<? extends HCLExpression> getKeys() {
-            return keys;
-        }
-        
-        public List<? extends HCLExpression> getValues() {
-            return values;
-        }
-        
-        @Override
-        public List<? extends HCLExpression> getChildren() {
-            return parts;
-        }
-        
+        }        
     }
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLConditionalOperation.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLConditionalOperation.java
index 1980d5b51e..1072ff65ec 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLConditionalOperation.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLConditionalOperation.java
@@ -25,17 +25,7 @@ import java.util.List;
  *
  * @author lkishalmi
  */
-public final class HCLConditionalOperation extends HCLExpression {
-
-    final HCLExpression condition;
-    final HCLExpression trueValue;
-    final HCLExpression falseValue;
-
-    public HCLConditionalOperation(HCLExpression condition, HCLExpression 
trueValue, HCLExpression falseValue) {
-        this.condition = condition;
-        this.trueValue = trueValue;
-        this.falseValue = falseValue;
-    }
+public record HCLConditionalOperation(HCLExpression condition, HCLExpression 
trueValue, HCLExpression falseValue) implements HCLExpression {
 
     @Override
     public String asString() {
@@ -43,7 +33,7 @@ public final class HCLConditionalOperation extends 
HCLExpression {
     }
 
     @Override
-    public List<? extends HCLExpression> getChildren() {
+    public List<? extends HCLExpression> elements() {
         return Arrays.asList(condition, trueValue, falseValue);
     }
         
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLContainer.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLContainer.java
index 87e6559aa7..9b0ca868f5 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLContainer.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLContainer.java
@@ -18,59 +18,42 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
 
 /**
  *
  * @author Laszlo Kishalmi
  */
-public abstract class HCLContainer extends HCLAddressableElement {
-    final List<HCLElement> elements = new LinkedList<>();
+public sealed abstract class HCLContainer implements HCLElement permits 
HCLBlock, HCLDocument {
 
-    final List<HCLBlock> blocks = new LinkedList<>();
-    final List<HCLAttribute> attributes = new LinkedList<>();
+    protected final List<HCLElement> elements;
+    private final List<HCLBlock> blocks;
+    private final List<HCLAttribute> attributes;
 
-    public HCLContainer(HCLContainer parent) {
-        super(parent);
+    protected HCLContainer(List<HCLElement> elements) {
+        this.elements = List.copyOf(elements);
+        this.blocks = 
elements.stream().filter(HCLBlock.class::isInstance).map(HCLBlock.class::cast).toList();
+        this.attributes = 
elements.stream().filter(HCLAttribute.class::isInstance).map(HCLAttribute.class::cast).toList();
     }
 
-    public void add(HCLBlock block) {
-        elements.add(block);
-        blocks.add(block);
+    public boolean hasBlock() {
+        return !blocks.isEmpty();
     }
 
-    public void add(HCLAttribute attr) {
-        elements.add(attr);
-        attributes.add(attr);
-    }
-
-    @Override
-    public HCLContainer getContainer() {
-        return (HCLContainer) parent;
-    }
-
-    public Collection<? extends HCLBlock> getBlocks() {
-        return Collections.unmodifiableCollection(blocks);
+    public boolean hasAttribute() {
+        return !attributes.isEmpty();
     }
 
-    public Collection<? extends HCLAttribute> getAttributes() {
-        return Collections.unmodifiableCollection(attributes);
+    public List<HCLBlock> blocks() {
+        return blocks;
     }
 
-    public boolean hasAttributes() {
-        return !attributes.isEmpty();
+    public List<HCLAttribute> attributes() {
+        return attributes;
     }
-
+    
     @Override
-    public final void accept(Visitor v) {
-        if (!v.visit(this)) {
-            for (HCLElement element : elements) {
-                element.accept(v);
-            }
-        }
+    public List<? extends HCLElement> elements() {
+        return elements;
     }
-
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLDocument.java 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLDocument.java
index dfe65d93b1..41f41eff84 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLDocument.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLDocument.java
@@ -18,19 +18,32 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
+import java.util.List;
+import java.util.Objects;
+
 /**
  *
  * @author Laszlo Kishalmi
  */
 public final class HCLDocument extends HCLContainer {
 
-    public HCLDocument() {
-        super(null);
+    public HCLDocument(List<HCLElement> elements) {
+        super(elements);
+    }
+
+    @Override
+    public String toString() {
+        return "HCLDocument[elements=" + elements + "]";
+    }
+
+
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof HCLDocument that ? Objects.equals(this.elements, 
that.elements) : false;
     }
 
     @Override
-    public String id() {
-        return "<hcl>";
+    public int hashCode() {
+        return Objects.hashCode(elements);
     }
-    
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLElement.java 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLElement.java
index 3c4b54f5fd..017efae28b 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLElement.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLElement.java
@@ -18,81 +18,12 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import org.antlr.v4.runtime.Token;
+import java.util.List;
 
 /**
  *
  * @author Laszlo Kishalmi
  */
-public abstract class HCLElement {
-
-    public abstract void accept(Visitor v);
-    
-    public interface Visitor {
-        /**
-         * Visit the given element. Shall return {@code true} if the visit
-         * shall be finished at this level in the element tree.
-         * 
-         * @param e the element to visit.
-         * @return {@code false} if the visit shall continue on the subtree of
-         *         the given element.
-         */
-        boolean visit(HCLElement e);
-    }
-    
-    /**
-     * Convenience Visitor implementation, where the HCLElements are split to
-     * Block, Attribute, and Expression types. 
-     */
-    public abstract static class BAEVisitor implements Visitor {
-        @Override
-        public boolean visit(HCLElement e) {
-            if (e instanceof HCLBlock) {
-                return visitBlock((HCLBlock)e);
-            } else if (e instanceof HCLAttribute) {
-                return visitAttribute((HCLAttribute) e);
-            } else if (e instanceof HCLExpression) {
-                return visitExpression((HCLExpression) e);
-            }
-            return false;
-        }
-        
-        protected abstract boolean visitBlock(HCLBlock block);
-        
-        protected abstract boolean visitAttribute(HCLAttribute attr);
-        
-        protected abstract boolean visitExpression(HCLExpression expr);
-    }
-
-    public static class BAEVisitorAdapter extends BAEVisitor {
-
-        @Override
-        protected boolean visitBlock(HCLBlock block) {
-            return false;
-        }
-
-        @Override
-        protected boolean visitAttribute(HCLAttribute attr) {
-            return false;
-        }
-
-        @Override
-        protected boolean visitExpression(HCLExpression expr) {
-            return false;
-        }
-        
-    }
-
-    public static final class CreateContext {
-        public final HCLElement element;
-        public final Token start;
-        public final Token stop;
-
-        public CreateContext(HCLElement element, Token start, Token stop) {
-            this.element = element;
-            this.start = start;
-            this.stop = stop;
-        }
-        
-    }
+public sealed interface HCLElement permits HCLExpression, HCLIdentifier, 
HCLContainer, HCLAttribute {
+    List<? extends HCLElement> elements();
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLElementFactory.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLElementFactory.java
new file mode 100644
index 0000000000..3b84857a1f
--- /dev/null
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLElementFactory.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   http://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.netbeans.modules.languages.hcl.ast;
+
+import java.util.function.Consumer;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.netbeans.modules.languages.hcl.grammar.HCLLexer;
+
+/**
+ *
+ * @author lkishalmi
+ */
+public sealed abstract class HCLElementFactory permits HCLBlockFactory, 
HCLExpressionFactory {
+    public record CreateContext(HCLElement element, Token start, Token stop, 
int group) {}
+
+    private final Consumer<CreateContext> createAction;
+
+    public HCLElementFactory(Consumer<CreateContext> createAction) {
+        this.createAction = createAction;
+    }
+
+    protected final HCLIdentifier id(TerminalNode tn) {
+        return tn != null ? id(tn.getSymbol()) : null;
+    }
+
+    protected final HCLIdentifier id(Token t) {
+        return (t != null) && (t.getType() == HCLLexer.IDENTIFIER) ? 
created(new HCLIdentifier.SimpleId(t.getText()), t) : null;
+    }
+
+    protected final <E extends HCLElement> E created(E element, Token token) {
+        return created(element, token, token);
+    }
+
+    protected final <E extends HCLElement> E created(E element, 
ParserRuleContext ctx) {
+        return created(element, ctx.start, ctx.stop);
+    }
+
+    protected final <E extends HCLElement> E created(E element, 
ParserRuleContext ctx, int group) {
+        return created(element, ctx.start, ctx.stop, group);
+    }
+
+    protected final <E extends HCLElement> E created(E element, Token start, 
Token stop) {
+        elementCreated(element, start, stop, -1);
+        return element;
+    }
+
+    protected final <E extends HCLElement> E created(E element, Token start, 
Token stop, int group) {
+        elementCreated(element, start, stop, group);
+        return element;
+    }
+
+    protected final void elementCreated(HCLElement element, Token start, Token 
stop, int group) {
+        if (createAction != null) {
+            createAction.accept(new CreateContext(element, start, stop, 
group));
+        }
+    }
+}
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLExpression.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLExpression.java
index 15ed91a722..344f029dba 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLExpression.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLExpression.java
@@ -18,6 +18,7 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
+import java.util.Collections;
 import java.util.List;
 import org.antlr.v4.runtime.CharStreams;
 import org.antlr.v4.runtime.CommonTokenStream;
@@ -28,30 +29,28 @@ import org.netbeans.modules.languages.hcl.grammar.HCLParser;
  *
  * @author lkishalmi
  */
-public abstract class HCLExpression extends HCLElement {
+public sealed interface HCLExpression extends HCLElement permits
+        HCLArithmeticOperation,
+        HCLCollection,
+        HCLCollection.ObjectElement,
+        HCLConditionalOperation,
+        HCLForExpression,
+        HCLFunction,
+        HCLLiteral,
+        HCLResolveOperation,
+        HCLTemplate,
+        HCLVariable {
 
     public static HCLExpression parse(String expr) {
         HCLLexer lexer = new HCLLexer(CharStreams.fromString(expr));
         HCLParser parser = new HCLParser(new CommonTokenStream(lexer));
         return new HCLExpressionFactory().process(parser.expression());
     }
-    
-    public String toString() {
-        return getClass().getSimpleName() + ": " + asString();
+
+    default List<? extends HCLExpression> elements() {
+        return Collections.emptyList();
     }
-    
-    public abstract List<? extends HCLExpression> getChildren();
-    
+
     public abstract String asString();
-    
-    @Override
-    public final void accept(Visitor v) {
-        if (!v.visit(this)) {
-            for (HCLExpression c : getChildren()) {
-                if (c != null) {
-                    c.accept(v);
-                }
-            }
-        }
-    }
+
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLExpressionFactory.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLExpressionFactory.java
index 3ca0ef8665..455ae4806b 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLExpressionFactory.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLExpressionFactory.java
@@ -26,9 +26,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 import org.antlr.v4.runtime.NoViableAltException;
 import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.tree.ParseTree;
-import org.antlr.v4.runtime.tree.TerminalNode;
 import org.netbeans.modules.languages.hcl.grammar.HCLLexer;
 import static org.netbeans.modules.languages.hcl.grammar.HCLLexer.*;
 import org.netbeans.modules.languages.hcl.grammar.HCLParser;
@@ -37,12 +35,10 @@ import org.netbeans.modules.languages.hcl.grammar.HCLParser;
  *
  * @author lkishalmi
  */
-public class HCLExpressionFactory {
+public final class HCLExpressionFactory extends HCLElementFactory {
 
-    private final Consumer<HCLElement.CreateContext> createAction;
-
-    public HCLExpressionFactory(Consumer<HCLElement.CreateContext> 
createAction) {
-        this.createAction = createAction;
+    public HCLExpressionFactory(Consumer<CreateContext> createAction) {
+        super(createAction);
     }
 
     public HCLExpressionFactory() {
@@ -65,12 +61,11 @@ public class HCLExpressionFactory {
                 return created(new HCLArithmeticOperation.Binary(op, 
expr(ctx.left), expr(ctx.right)), ctx);
             }
             if (ctx.right != null) {
-                switch (ctx.op.getType()) {
-                    case NOT:
-                        return created(new 
HCLArithmeticOperation.Unary(HCLArithmeticOperation.Operator.NOT, 
expr(ctx.right)), ctx);
-                    case MINUS:
-                        return created(new 
HCLArithmeticOperation.Unary(HCLArithmeticOperation.Operator.MINUS, 
expr(ctx.right)), ctx);
-                }
+                return switch (ctx.op.getType()) {
+                    case NOT ->  created(new 
HCLArithmeticOperation.Unary(HCLArithmeticOperation.Operator.NOT, 
expr(ctx.right)), ctx);
+                    case MINUS -> created(new 
HCLArithmeticOperation.Unary(HCLArithmeticOperation.Operator.MINUS, 
expr(ctx.right)), ctx);
+                    default -> throw new 
UnsupportedOperationException("Unsupported expression: " + ctx.getText());
+                };
             }
             if (ctx.exprCond != null && ctx.exprTrue != null && ctx.exprFalse 
!= null) {
                 return created(new HCLConditionalOperation(expr(ctx.exprCond), 
expr(ctx.exprTrue), expr(ctx.exprFalse)), ctx);
@@ -109,8 +104,7 @@ public class HCLExpressionFactory {
             ret = expr(ctx.exprTerm(), splat);
         }
         if (ctx.exception != null) {
-            if (ctx.exception instanceof NoViableAltException) {
-                NoViableAltException nva = (NoViableAltException) 
ctx.exception;
+            if (ctx.exception instanceof NoViableAltException nva) {
                 if (nva.getStartToken().getType() == HCLLexer.DOT) {
                     //Most probably a single DOT would mean a started 
attribute resolve expression
                     //Let's create an empty one on the fly
@@ -168,7 +162,8 @@ public class HCLExpressionFactory {
                 if ((prev != null) && (ec.key != null)) {
                     group += prev.stop.getLine() + 1 < ec.key.start.getLine() 
? 1 : 0;
                 }
-                elements.add(new HCLCollection.ObjectElement(expr(ec.key), 
expr(ec.value), group));
+                HCLCollection.ObjectElement oe = new 
HCLCollection.ObjectElement(expr(ec.key), expr(ec.value));
+                elements.add(created(oe, ec, group));
                 prev = ec;
             }
             return new HCLCollection.Object(elements);
@@ -193,36 +188,22 @@ public class HCLExpressionFactory {
     }
 
     private static HCLArithmeticOperation.Operator binOp(int tokenType) {
-        switch (tokenType) {
-            case STAR:
-                return HCLArithmeticOperation.Operator.MUL;
-            case SLASH:
-                return HCLArithmeticOperation.Operator.DIV;
-            case PERCENT:
-                return HCLArithmeticOperation.Operator.MOD;
-            case PLUS:
-                return HCLArithmeticOperation.Operator.ADD;
-            case MINUS:
-                return HCLArithmeticOperation.Operator.SUB;
-            case OR:
-                return HCLArithmeticOperation.Operator.OR;
-            case AND:
-                return HCLArithmeticOperation.Operator.AND;
-            case LT:
-                return HCLArithmeticOperation.Operator.LT;
-            case LTE:
-                return HCLArithmeticOperation.Operator.LTE;
-            case GT:
-                return HCLArithmeticOperation.Operator.GT;
-            case GTE:
-                return HCLArithmeticOperation.Operator.GTE;
-            case EQUALS:
-                return HCLArithmeticOperation.Operator.EQUALS;
-            case NOT_EQUALS:
-                return HCLArithmeticOperation.Operator.NOT_EQUALS;
-            default:
-                return null;
-        }
+        return switch (tokenType) {
+            case STAR -> HCLArithmeticOperation.Operator.MUL;
+            case SLASH -> HCLArithmeticOperation.Operator.DIV;
+            case PERCENT -> HCLArithmeticOperation.Operator.MOD;
+            case PLUS -> HCLArithmeticOperation.Operator.ADD;
+            case MINUS -> HCLArithmeticOperation.Operator.SUB;
+            case OR -> HCLArithmeticOperation.Operator.OR;
+            case AND -> HCLArithmeticOperation.Operator.AND;
+            case LT -> HCLArithmeticOperation.Operator.LT;
+            case LTE -> HCLArithmeticOperation.Operator.LTE;
+            case GT -> HCLArithmeticOperation.Operator.GT;
+            case GTE -> HCLArithmeticOperation.Operator.GTE;
+            case EQUALS -> HCLArithmeticOperation.Operator.EQUALS;
+            case NOT_EQUALS -> HCLArithmeticOperation.Operator.NOT_EQUALS;
+            default -> null;
+        };
     }
 
     protected HCLExpression expr(HCLParser.TemplateExprContext ctx) {
@@ -267,13 +248,13 @@ public class HCLExpressionFactory {
         if (ctx.heredocTemplate() != null && ctx.heredocTemplate().children != 
null) {
             for (ParseTree pt : ctx.heredocTemplate().children) {
                 if (pt instanceof HCLParser.HeredocContentContext) {
-                    parts.add(new HCLTemplate.StringPart(pt.getText()));
+                    parts.add(new HCLTemplate.Part.StringPart(pt.getText()));
                 }
                 if (pt instanceof HCLParser.InterpolationContext) {
-                    parts.add(new HCLTemplate.InterpolationPart(pt.getText()));
+                    parts.add(new 
HCLTemplate.Part.InterpolationPart(pt.getText()));
                 }
                 if (pt instanceof HCLParser.TemplateContext) {
-                    parts.add(new HCLTemplate.TemplatePart(pt.getText()));
+                    parts.add(new HCLTemplate.Part.TemplatePart(pt.getText()));
                 }
             }
         }
@@ -287,13 +268,13 @@ public class HCLExpressionFactory {
         LinkedList<HCLTemplate.Part> parts = new LinkedList<>();
         for (ParseTree pt : ctx.children) {
             if (pt instanceof HCLParser.StringContentContext) {
-                parts.add(new HCLTemplate.StringPart(pt.getText()));
+                parts.add(new HCLTemplate.Part.StringPart(pt.getText()));
             }
             if (pt instanceof HCLParser.InterpolationContext) {
-                parts.add(new HCLTemplate.InterpolationPart(pt.getText()));
+                parts.add(new 
HCLTemplate.Part.InterpolationPart(pt.getText()));
             }
             if (pt instanceof HCLParser.TemplateContext) {
-                parts.add(new HCLTemplate.TemplatePart(pt.getText()));
+                parts.add(new HCLTemplate.Part.TemplatePart(pt.getText()));
             }
         }
         return new HCLTemplate.StringTemplate(parts);
@@ -308,7 +289,7 @@ public class HCLExpressionFactory {
         HCLParser.ForIntroContext intro = isTuple ? 
ctx.forTupleExpr().forIntro() : ctx.forObjectExpr().forIntro();
 
         HCLIdentifier keyVar = null;
-        HCLIdentifier valueVar = null;
+        HCLIdentifier valueVar;
         if (intro.second != null) {
             keyVar = id(intro.first);
             valueVar = id(intro.second);
@@ -342,12 +323,11 @@ public class HCLExpressionFactory {
         if (splat.fullSplat() != null) {
             base = expr(base, splat);
             for (ParseTree pt : splat.fullSplat().children) {
-                if (pt instanceof HCLParser.GetAttrContext) {
-                    HCLParser.GetAttrContext ac = (HCLParser.GetAttrContext) 
pt;
-                    base = expr(base, ac);
+                if (pt instanceof HCLParser.GetAttrContext gac) {
+                    base = expr(base, gac);
                 }
-                if (pt instanceof HCLParser.IndexContext) {
-                    base = expr(base, (HCLParser.IndexContext) pt);
+                if (pt instanceof HCLParser.IndexContext ic) {
+                    base = expr(base, ic);
                 }
             }
         }
@@ -377,31 +357,4 @@ public class HCLExpressionFactory {
         return created(new HCLResolveOperation.Index(base, index, 
idx.LEGACY_INDEX() != null), idx);
 
     }
-
-    private HCLIdentifier id(TerminalNode tn) {
-        return tn != null ? id(tn.getSymbol()) : null;
-    }
-    
-    protected HCLIdentifier id(Token t) {
-        return (t != null) && (t.getType() == HCLLexer.IDENTIFIER) ? 
created(new HCLIdentifier.SimpleId(t.getText()), t) : null;
-    }
-    
-    private <E extends HCLElement> E created(E element, Token token) {
-        return created(element, token, token);
-    }
-
-    private <E extends HCLElement> E created(E element, ParserRuleContext ctx) 
{
-        return created(element, ctx.start, ctx.stop);
-    }
-
-    private <E extends HCLElement> E created(E element, Token start, Token 
stop) {
-        elementCreated(element, start, stop);
-        return element;
-    }
-
-    private void elementCreated(HCLElement element, Token start, Token stop) {
-        if (createAction != null) {
-            createAction.accept(new HCLElement.CreateContext(element, start, 
stop));
-        }
-    }
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLForExpression.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLForExpression.java
index 6b499026c7..4326685488 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLForExpression.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLForExpression.java
@@ -18,36 +18,21 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import java.util.Arrays;
 import java.util.List;
 
 /**
  *
  * @author lkishalmi
  */
-public abstract class HCLForExpression extends HCLExpression {
+public sealed interface HCLForExpression extends HCLExpression {
     
-    public final HCLIdentifier keyVar;
-    public final HCLIdentifier valueVar;
+    HCLIdentifier keyVar();
+    HCLIdentifier valueVar();
 
-    public final HCLExpression iterable;
-    public final HCLExpression condition;
+    HCLExpression iterable();
+    HCLExpression condition();
     
-    public HCLForExpression(HCLIdentifier keyVar, HCLIdentifier valueVar, 
HCLExpression iterable, HCLExpression condition) {
-        this.keyVar = keyVar;
-        this.valueVar = valueVar;
-        this.iterable = iterable;
-        this.condition = condition;
-    }
-
-    public final static class Tuple extends HCLForExpression {
-
-        public final HCLExpression result;
-        
-        public Tuple(HCLIdentifier keyVar, HCLIdentifier valueVar, 
HCLExpression iterable, HCLExpression condition, HCLExpression result) {
-            super(keyVar, valueVar, iterable, condition);
-            this.result = result;
-        }
+    public record Tuple(HCLIdentifier keyVar, HCLIdentifier valueVar, 
HCLExpression iterable, HCLExpression condition, HCLExpression result) 
implements HCLForExpression {
 
         @Override
         public String asString() {
@@ -66,24 +51,12 @@ public abstract class HCLForExpression extends 
HCLExpression {
         }
         
         @Override
-        public List<? extends HCLExpression> getChildren() {
-            return Arrays.asList(iterable, result, condition);
+        public List<? extends HCLExpression> elements() {
+            return List.of(iterable, result, condition);
         }
     }
     
-    public final static class Object extends HCLForExpression {
-        public final HCLExpression resultKey;
-        public final HCLExpression resultValue;
-        
-        public final boolean grouping;
-
-        public Object(HCLIdentifier keyVar, HCLIdentifier valueVar, 
HCLExpression iterable, HCLExpression condition, HCLExpression resultKey, 
HCLExpression resultValue, boolean grouping) {
-            super(keyVar, valueVar, iterable, condition);
-            this.resultKey = resultKey;
-            this.resultValue = resultValue;
-            this.grouping = grouping;
-        }
-
+    public record Object(HCLIdentifier keyVar, HCLIdentifier valueVar, 
HCLExpression iterable, HCLExpression condition, HCLExpression resultKey, 
HCLExpression resultValue, boolean grouping) implements HCLForExpression {
         @Override
         public String asString() {
             StringBuilder sb = new StringBuilder();
@@ -104,8 +77,8 @@ public abstract class HCLForExpression extends HCLExpression 
{
         }
 
         @Override
-        public List<? extends HCLExpression> getChildren() {
-            return Arrays.asList(iterable, resultKey, resultValue, condition);
+        public List<? extends HCLExpression> elements() {
+            return List.of(iterable, resultKey, resultValue, condition);
         }
         
     }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLFunction.java 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLFunction.java
index 2900359f9e..f2556a5384 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLFunction.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLFunction.java
@@ -25,24 +25,10 @@ import java.util.StringJoiner;
  *
  * @author lkishalmi
  */
-public class HCLFunction extends HCLExpression {
+public record HCLFunction(HCLIdentifier name, List<HCLExpression> args, 
boolean expand) implements HCLExpression {
 
-    final HCLIdentifier name;
-    final List<HCLExpression> args;
-    final boolean expand;
-
-    public HCLFunction(HCLIdentifier name, List<HCLExpression> args, boolean 
expand) {
-        this.name = name;
-        this.args = args;
-        this.expand = expand;
-    }
-
-    public HCLIdentifier getName() {
-        return name;
-    }
-
-    public List<HCLExpression> getArgs() {
-        return args;
+    public HCLFunction {
+        args = List.copyOf(args);
     }
 
     @Override
@@ -53,9 +39,7 @@ public class HCLFunction extends HCLExpression {
     }
 
     @Override
-    public List<? extends HCLExpression> getChildren() {
-        return args;
-    }
-
-    
+    public List<? extends HCLExpression> elements() {
+        return args();
+    }    
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLIdentifier.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLIdentifier.java
index 32270c80c4..1dd48e8ad5 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLIdentifier.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLIdentifier.java
@@ -18,49 +18,22 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
+import java.util.List;
+
 /**
  *
  * @author Laszlo Kishalmi
  */
-public abstract class HCLIdentifier extends HCLElement {
+public sealed interface HCLIdentifier extends HCLElement {
 
-    public final String id;
+    String id();
     
-    public HCLIdentifier(String id) {
-        this.id = id;
-    }
-
-    public String id() {
-        return id;
-    }
-
     @Override
-    public final void accept(Visitor v) {
-        v.visit(this);
-    }
-
-    public final static class SimpleId extends HCLIdentifier {
-
-        public SimpleId(String id) {
-            super(id);
-        }
-
-        @Override
-        public String toString() {
-            return id;
-        }
+    default List<? extends HCLElement> elements() {
+        return List.of();
     }
+    
+    public record SimpleId(String id) implements HCLIdentifier {}
 
-    public final static class StringId extends HCLIdentifier {
-
-        public StringId(String id) {
-            super(id);
-        }
-
-        @Override
-        public String toString() {
-            return "\"" + id + "\"";
-        }
-
-    }
+    public record StringId(String id) implements HCLIdentifier {}
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLLiteral.java 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLLiteral.java
index 7ecd99d2dc..6ebd069f99 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLLiteral.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLLiteral.java
@@ -18,45 +18,25 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import java.util.Collections;
-import java.util.List;
-
 /**
  *
  * @author lkishalmi
  */
-public abstract class HCLLiteral extends HCLExpression {
+public sealed interface HCLLiteral extends HCLExpression {
 
     public static final Bool TRUE = new Bool(true);
     public static final Bool FALSE = new Bool(false);
     public static final Null NULL = new Null();
 
-    @Override
-    public final List<? extends HCLExpression> getChildren() {
-        return Collections.emptyList();
-    }
     
-    public static final class Bool extends HCLLiteral {
-
-        final boolean value;
-
-        private Bool(boolean value) {
-            this.value = value;
-        }
-
+    public record Bool(boolean value) implements HCLLiteral {
         @Override
         public String asString() {
             return value ? "true" : "false";
         }
     }
 
-    public static final class StringLit extends HCLLiteral {
-
-        final String value;
-
-        public StringLit(String value) {
-            this.value = value;
-        }
+    public record StringLit(String value) implements HCLLiteral {
 
         @Override
         public String asString() {
@@ -64,25 +44,14 @@ public abstract class HCLLiteral extends HCLExpression {
         }
     }
 
-    public static final class Null extends HCLLiteral {
-
-
-        private Null() {
-        }
-
+    public record Null() implements HCLLiteral {
         @Override
         public String asString() {
             return "null"; //NOI18N
         }
     }
 
-    public static final class NumericLit extends HCLLiteral {
-
-        final String value;
-
-        public NumericLit(String value) {
-            this.value = value;
-        }
+    public record NumericLit(String value) implements HCLLiteral {
 
         @Override
         public String asString() {
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLResolveOperation.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLResolveOperation.java
index 6586b61fec..4e721f89b3 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLResolveOperation.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLResolveOperation.java
@@ -18,92 +18,50 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 
 /**
  *
  * @author lkishalmi
  */
-public abstract class HCLResolveOperation extends HCLExpression {
+public sealed interface HCLResolveOperation extends HCLExpression {
 
-    public final HCLExpression base;
 
-    public HCLResolveOperation(HCLExpression base) {
-        this.base = base;
+    HCLExpression base();
+    default List<? extends HCLExpression> elements() {
+            return List.of(base());
     }
 
-    @Override
-    public List<? extends HCLExpression> getChildren() {
-        return Collections.singletonList(base);
-    }
-
-    public final static class Attribute extends HCLResolveOperation {
-        public final HCLIdentifier attr;
-
-        public Attribute(HCLExpression base, HCLIdentifier attr) {
-            super(base);
-            this.attr = attr;
-        }
-
-        @Override
-        public String toString() {
-            return getClass().getSimpleName() + ": ." + attr;
-        }
-
-        
+    public record Attribute(HCLExpression base, HCLIdentifier attr) implements 
HCLResolveOperation {
         @Override
         public String asString() {
             return base.asString() + "." + attr;
         }
-        
-    }
-
-    public final static class Index extends HCLResolveOperation {
-        public final HCLExpression index;
-        public final boolean legacy;
 
-        public Index(HCLExpression base, HCLExpression index, boolean legacy) {
-            super(base);
-            this.index = index;
-            this.legacy = legacy;
-        }
+    }
 
+    public record Index(HCLExpression base, HCLExpression index, boolean 
legacy) implements HCLResolveOperation {
         @Override
         public String asString() {
             return base.asString() + (legacy ? "." + index : "[" + index + 
"]");
         }
-
         @Override
-        public List<? extends HCLExpression> getChildren() {
-            return Arrays.asList(base, index);
+        public List<? extends HCLExpression> elements() {
+            return List.of(base, index);
         }
     }
     
-    public final static class AttrSplat extends HCLResolveOperation {
-
-        public AttrSplat(HCLExpression base) {
-            super(base);
-        }
-
+    public record AttrSplat(HCLExpression base) implements HCLResolveOperation 
{
         @Override
         public String asString() {
             return base.asString() + ".*";
         }
-        
     }
 
-    public final static class FullSplat extends HCLResolveOperation {
-
-        public FullSplat(HCLExpression base) {
-            super(base);
-        }
-
+    public record FullSplat(HCLExpression base) implements HCLResolveOperation 
{
         @Override
         public String asString() {
             return base.asString() + "[*]";
         }
-        
     }
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLTemplate.java 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLTemplate.java
index 785b97a95a..4592bbeb44 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLTemplate.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLTemplate.java
@@ -18,85 +18,40 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import java.util.Collections;
 import java.util.List;
 
 /**
  *
  * @author lkishalmi
  */
-public abstract class HCLTemplate extends HCLExpression {
+public sealed interface HCLTemplate extends HCLExpression {
     
-    public final List<Part> parts;
+    List<? extends Part> parts();
 
-    public HCLTemplate(List<Part> parts) {
-        this.parts = Collections.unmodifiableList(parts);
-    }
-    
-    @Override
-    public List<? extends HCLExpression> getChildren() {
-        return Collections.emptyList();
-    }
-    
-    public abstract static class Part {
-        public final String value;
-
-        public Part(String value) {
-            this.value = value;
-        }        
-    }
-    
-    public final static class StringPart extends Part {
-        
+    public sealed interface Part {
         public static final StringPart NL = new StringPart("\n");
 
-        public StringPart(String value) {
-            super(value);
-        }
-
-        @Override
-        public String toString() {
-            return value;
-        }
-    }
-    
-    public final static class InterpolationPart extends Part {
-
-        public InterpolationPart(String value) {
-            super(value);
+        String value();
+        default String asString() {
+            if (this instanceof StringPart) return value();
+            if (this instanceof InterpolationPart) return "${" + value() + "}";
+            if (this instanceof TemplatePart) return "%{" + value() + "}";
+            return null;
         }
 
-        @Override
-        public String toString() {
-            return "${" + value + "}";
-        }
-    }
-
-    /**
-     * This is just a temporal implementation as the template expression
-     * should really form a tree.
-     */
-    public final static class TemplatePart extends Part {
-        
-        public TemplatePart(String value) {
-            super(value);
-        }
-
-        @Override
-        public String toString() {
-            return "%{" + value + "}";
-        }
-        
+        public record StringPart(String value) implements Part {}
+        /**
+         * This is just a temporal implementation as the template expression
+         * should really form a tree.
+         */
+        public record InterpolationPart(String value) implements Part {}
+        public record TemplatePart(String value) implements Part {}
     }
     
-    public final static class HereDoc extends HCLTemplate {
-        public final String marker;
-        public final int indent;
+    public record HereDoc(String marker, int indent, List<Part> parts) 
implements HCLTemplate {
 
-        public HereDoc(String marker, int indent, List<Part> parts) {
-            super(parts);
-            this.marker = marker;
-            this.indent = indent;
+        public HereDoc {
+            parts = List.copyOf(parts);
         }
 
         public boolean isIndented() {
@@ -115,10 +70,10 @@ public abstract class HCLTemplate extends HCLExpression {
         }
     }
     
-    public final static class StringTemplate extends HCLTemplate {
+    public record StringTemplate(List<Part> parts) implements HCLTemplate {
 
-        public StringTemplate(List<Part> parts) {
-            super(parts);
+        public StringTemplate {
+            parts = List.copyOf(parts);
         }
 
         @Override
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLTreeWalker.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLTreeWalker.java
new file mode 100644
index 0000000000..b6378cd41d
--- /dev/null
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLTreeWalker.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   http://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.netbeans.modules.languages.hcl.ast;
+
+import java.util.LinkedList;
+import java.util.function.Predicate;
+
+/**
+ *
+ * @author lkishalmi
+ */
+public final class HCLTreeWalker {
+    public record Step(HCLElement parent, HCLElement node, int depth) {}
+
+    private HCLTreeWalker() {}
+
+    public static void depthFirst(HCLElement root, Predicate<Step> t) {
+        LinkedList<Step> process = new LinkedList<>();
+        process.push(new Step(null, root, 0));
+        while (!process.isEmpty()) {
+            Step current = process.pop();
+            if (t.test(current)) {
+                for (HCLElement e : current.node.elements()) {
+                    process.push(new Step(current.node, e, current.depth + 1));
+                }
+            }
+        }
+    }
+
+    public static void breadthFirst(HCLElement root, Predicate<Step> t) {
+        LinkedList<Step> process = new LinkedList<>();
+        process.add(new Step(null, root, 0));
+        while (!process.isEmpty()) {
+            var current = process.pop();
+            if (t.test(current)) {
+                for (HCLElement e : current.node.elements()) {
+                    process.add(new Step(current.node, e, current.depth + 1));
+                }
+            }
+        }
+    }
+}
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLVariable.java 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLVariable.java
index 306b825fc7..84f2779ec6 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLVariable.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/ast/HCLVariable.java
@@ -18,28 +18,14 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import java.util.Collections;
-import java.util.List;
-
 /**
  *
  * @author lkishalmi
  */
-public final class HCLVariable extends HCLExpression {
-
-    public final HCLIdentifier name;
-
-    public HCLVariable(HCLIdentifier name) {
-        this.name = name;
-    }
+public record HCLVariable(HCLIdentifier name) implements HCLExpression {
 
     @Override
     public String asString() {
-        return name.id;
-    }
-
-    @Override
-    public List<? extends HCLExpression> getChildren() {
-        return Collections.emptyList();
+        return name.id();
     }
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/terraform/TerraformParserResult.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/terraform/TerraformParserResult.java
index 929d467d62..075981e069 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/terraform/TerraformParserResult.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/terraform/TerraformParserResult.java
@@ -30,8 +30,7 @@ import org.netbeans.modules.languages.hcl.ast.HCLContainer;
 import org.netbeans.modules.languages.hcl.ast.HCLDocument;
 import org.netbeans.modules.languages.hcl.ast.HCLIdentifier;
 import org.netbeans.modules.languages.hcl.SourceRef;
-import org.netbeans.modules.languages.hcl.ast.HCLElement;
-import org.netbeans.modules.languages.hcl.ast.HCLElement.Visitor;
+import org.netbeans.modules.languages.hcl.ast.HCLTreeWalker;
 import org.netbeans.modules.parsing.api.Snapshot;
 import org.openide.util.NbBundle.Messages;
 
@@ -41,18 +40,21 @@ import org.openide.util.NbBundle.Messages;
  */
 public class TerraformParserResult extends HCLParserResult {
 
-    private Map<String, HCLBlock> definedBlocks = new HashMap<>();
+    private final Map<String, HCLBlock> definedBlocks = new HashMap<>();
     
     public enum BlockType {
 
         CHECK("check", 2),
         DATA("data", 3),
+        IMPORT("import", 1),
         LOCALS("locals", 1),
         MODULE("module", 2),
         MOVED("moved", 1),
         OUTPUT("output", 2),
         PROVIDER("provider", 2),
+        REMOVED("removed", 1),
         RESOURCE("resource", 3),
+        RUN("run", 2),
         TERRAFORM("terraform", 1),
         VARIABLE("variable", 2);
 
@@ -97,59 +99,54 @@ public class TerraformParserResult extends HCLParserResult {
 
     })
     protected void processDocument(HCLDocument doc, SourceRef references) {
-        doc.accept(this::duplicateAttributeVisitor);
-        doc.accept(this::checkBlockDeclarationVisitor);
+        HCLTreeWalker.breadthFirst(doc, this::duplicateAttributeVisitor);
+        HCLTreeWalker.breadthFirst(doc, this::checkBlockDeclarationVisitor);
     }
 
+    private boolean checkBlockDeclarationVisitor(HCLTreeWalker.Step step) {
+        if (step.node() instanceof HCLBlock block) {
+            List<HCLIdentifier> decl = block.declaration();
+            HCLIdentifier type = decl.get(0);
 
-    private boolean checkBlockDeclarationVisitor(HCLElement e) {
-        if (e instanceof HCLBlock) {
-            HCLBlock block = (HCLBlock) e;
-            if (block.getParent() instanceof HCLDocument) {
-                List<HCLIdentifier> decl = block.getDeclaration();
-                HCLIdentifier type = decl.get(0);
-
-                BlockType bt = BlockType.get(type.id());
-                if (bt != null) {
-                    if (decl.size() != bt.definitionLength) {
-                        addError(type, 
Bundle.INVALID_BLOCK_DECLARATION(bt.type, bt.definitionLength - 1));
-                    } else {
-                        if (definedBlocks.put(block.id(), block) != null) {
-                            switch (bt) {
-                                case CHECK:
-                                case DATA:
-                                case MODULE:
-                                case OUTPUT:
-                                case RESOURCE:
-                                case VARIABLE:
-                                    addError(decl.get(bt.definitionLength - 
1), Bundle.DUPLICATE_BLOCK(block.id()));
-                            }
+            BlockType bt = BlockType.get(type.id());
+            if (bt != null) {
+                if (decl.size() != bt.definitionLength) {
+                    addError(type, Bundle.INVALID_BLOCK_DECLARATION(bt.type, 
bt.definitionLength - 1));
+                } else {
+                    if (definedBlocks.put(block.id(), block) != null) {
+                        switch (bt) {
+                            case CHECK:
+                            case DATA:
+                            case MODULE:
+                            case OUTPUT:
+                            case RESOURCE:
+                            case RUN:
+                            case VARIABLE:
+                                addError(decl.get(bt.definitionLength - 1), 
Bundle.DUPLICATE_BLOCK(block.id()));
                         }
                     }
-                } else {
-                    addError(type, Bundle.UNKNOWN_BLOCK(type.id()));
                 }
+            } else {
+                addError(type, Bundle.UNKNOWN_BLOCK(type.id()));
             }
-            return true;
         }
-        return !(e instanceof HCLDocument);
+        // Here we just check the first level of blocks, won't go deeper int 
the tree
+        return false;
     }
     
-    private boolean duplicateAttributeVisitor(HCLElement e) {
-        if (e instanceof HCLDocument) {
-            HCLDocument doc = (HCLDocument) e;
-            for (HCLAttribute attr : doc.getAttributes()) {
+    private boolean duplicateAttributeVisitor(HCLTreeWalker.Step step) {
+        if (step.node() instanceof HCLDocument doc) {
+            for (HCLAttribute attr : doc.attributes()) {
                 addError(attr, 
Bundle.UNEXPECTED_DOCUMENT_ATTRIBUTE(attr.id()));
             }
-            return false;
+            return true;
         }
-        if (e instanceof HCLContainer) {
-            HCLContainer c = (HCLContainer) e;
-            if (c.hasAttributes()) {
+        if (step.node() instanceof HCLContainer c) {
+            if (c.hasAttribute()) {
                 Set<String> defined = new HashSet<>();
-                for (HCLAttribute attr : c.getAttributes()) {
+                for (HCLAttribute attr : c.attributes()) {
                     if (!defined.add(attr.id())) {
-                        addError(attr.getName(), 
Bundle.DUPLICATE_ATTRIBUTE(attr.id()));
+                        addError(attr.name(), 
Bundle.DUPLICATE_ATTRIBUTE(attr.id()));
                     }                        
                 }
             }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/terraform/TerraformSemanticAnalyzer.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/terraform/TerraformSemanticAnalyzer.java
index beb209b693..fa16880a04 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/terraform/TerraformSemanticAnalyzer.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/terraform/TerraformSemanticAnalyzer.java
@@ -24,12 +24,11 @@ import org.netbeans.modules.csl.api.ColoringAttributes;
 import org.netbeans.modules.languages.hcl.HCLSemanticAnalyzer;
 import org.netbeans.modules.languages.hcl.HCLParserResult;
 import org.netbeans.modules.languages.hcl.ast.HCLBlock;
-import org.netbeans.modules.languages.hcl.ast.HCLDocument;
-import org.netbeans.modules.languages.hcl.ast.HCLExpression;
 import org.netbeans.modules.languages.hcl.ast.HCLIdentifier;
 import org.netbeans.modules.languages.hcl.ast.HCLResolveOperation;
 import org.netbeans.modules.languages.hcl.ast.HCLVariable;
 import org.netbeans.modules.languages.hcl.SourceRef;
+import org.netbeans.modules.languages.hcl.ast.HCLTreeWalker;
 import 
org.netbeans.modules.languages.hcl.terraform.TerraformParserResult.BlockType;
 import static 
org.netbeans.modules.languages.hcl.terraform.TerraformParserResult.BlockType.CHECK;
 import static 
org.netbeans.modules.languages.hcl.terraform.TerraformParserResult.BlockType.DATA;
@@ -61,7 +60,6 @@ public final class TerraformSemanticAnalyzer extends 
HCLSemanticAnalyzer {
             "string"
     );
 
-    
     @Override
     protected Highlighter createHighlighter(HCLParserResult result) {
         return new TerraformHighlighter(result.getReferences());
@@ -75,23 +73,18 @@ public final class TerraformSemanticAnalyzer extends 
HCLSemanticAnalyzer {
         }
 
         @Override
-        protected boolean visitBlock(HCLBlock block) {
-            if (block.getParent() instanceof HCLDocument) {
-                List<HCLIdentifier> dcl = block.getDeclaration();
+        protected void highlight(HCLTreeWalker.Step step) {
+            super.highlight(step);
+
+            // TODO: Can use record patterns from Java 21
+            if (step.depth() == 1 && step.node() instanceof HCLBlock block) {
+                List<HCLIdentifier> dcl = block.declaration();
                 if (!dcl.isEmpty()) {
                     rootBlockType = 
TerraformParserResult.BlockType.get(dcl.get(0).id());
                 }
-            }
-            return super.visitBlock(block);
-        }
-        
-        
-        @Override
-        protected boolean visitExpression(HCLExpression expr) {
-            if (expr instanceof HCLResolveOperation.Attribute) {
-                HCLResolveOperation.Attribute attr = 
(HCLResolveOperation.Attribute) expr;
-                if ((rootBlockType != null) && (attr.base instanceof 
HCLVariable)) {
-                    String name = ((HCLVariable)attr.base).name.id;
+            } else if (step.node() instanceof HCLResolveOperation.Attribute 
attr) {
+                if ((rootBlockType != null) && (attr.base() instanceof 
HCLVariable var)) {
+                    String name = var.name().id();
                     switch (rootBlockType) {
                         case CHECK:
                         case DATA:
@@ -101,24 +94,18 @@ public final class TerraformSemanticAnalyzer extends 
HCLSemanticAnalyzer {
                         case PROVIDER:
                         case RESOURCE:
                             if (RESOLVE_BASES.contains(name)) {
-                                mark(attr.base, ColoringAttributes.FIELD_SET);
+                                mark(attr.base(), 
ColoringAttributes.FIELD_SET);
                             }
                             break;
                     }
-                    return false;
                 }
-            }
-
-            if (rootBlockType == BlockType.VARIABLE && (expr instanceof 
HCLVariable)) {
-                String name = ((HCLVariable) expr).name.id;
+            } else if (rootBlockType == BlockType.VARIABLE && (step.node() 
instanceof HCLVariable var)) {
+                String name = var.name().id();
                 if (LITERAL_TYPES.contains(name)) {
-                    mark(expr, ColoringAttributes.FIELD_SET);
+                    mark(var, ColoringAttributes.FIELD_SET);
                 }
-                return false;
             }
-            return super.visitExpression(expr);
         }
 
     }
-    
 }
diff --git 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/tfvars/TFVarsParserResult.java
 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/tfvars/TFVarsParserResult.java
index 63e5f41d9b..e4768b9466 100644
--- 
a/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/tfvars/TFVarsParserResult.java
+++ 
b/ide/languages.hcl/src/org/netbeans/modules/languages/hcl/tfvars/TFVarsParserResult.java
@@ -45,13 +45,13 @@ public class TFVarsParserResult extends HCLParserResult {
         "DUPLICATE_VARIABLE=Variable {0} is already defined."
     })
     protected void processDocument(HCLDocument doc, SourceRef references) {
-        for (HCLBlock block : doc.getBlocks()) {
+        for (HCLBlock block : doc.blocks()) {
             addError(block, Bundle.INVALID_BLOCK());
         }
         Set<String> usedAttributes = new HashSet<>();
-        for (HCLAttribute attr : doc.getAttributes()) {
+        for (HCLAttribute attr : doc.attributes()) {
             if (!usedAttributes.add(attr.id())) {
-                addError(attr.getName(), Bundle.DUPLICATE_VARIABLE(attr.id()));
+                addError(attr.name(), Bundle.DUPLICATE_VARIABLE(attr.id()));
             }
         }
     }
diff --git 
a/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/HCLIndenterTest.java
 
b/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/HCLIndenterTest.java
index e3e055f544..26667fe46c 100644
--- 
a/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/HCLIndenterTest.java
+++ 
b/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/HCLIndenterTest.java
@@ -67,32 +67,98 @@ public class HCLIndenterTest extends NbTestCase {
 
     @Test
     public void testIndentedNL1() throws Exception {
-        performNewLineIndentationTest("  a = 1\n|", "  a = 1\n\n  ");
+        performNewLineIndentationTest(
+              """
+                a = 1
+              |\
+              """,
+              """
+                a = 1
+
+               \s\
+              """);
     }
     
     @Test
     public void testIndentedNL2() throws Exception {
-        performNewLineIndentationTest("  a = 1\n \n|", "  a = 1\n \n\n  ");
+        performNewLineIndentationTest(
+                """
+                  a = 1
+                \s
+                |\
+                """,
+                """
+                  a = 1
+                \s
+                
+                \s\s\
+                """
+        );
     }
 
     @Test
     public void testIndentedBlockNL1() throws Exception {
-        performNewLineIndentationTest("locals {|}", "locals {\n}");
+        performNewLineIndentationTest(
+                """
+                locals {|}\
+                """,
+                """
+                locals {
+                }\
+                """
+        );
     }
 
     @Test
     public void testIndentedBlockNL2() throws Exception {
-        performNewLineIndentationTest("locals {\n  a = [|]}", "locals {\n  a = 
[\n]}");
+        performNewLineIndentationTest(
+                """
+                locals {
+                  a = [|]}\
+                """,
+                """
+                locals {
+                  a = [
+                ]}\
+                """
+        );
     }
 
     @Test
     public void testIndentedBlockNL3() throws Exception {
-        performNewLineIndentationTest("locals {\n  a = [|\n  ]\n}", "locals 
{\n  a = [\n    \n  ]\n}");
+        performNewLineIndentationTest(
+                """
+                locals {
+                  a = [|
+                  ]
+                }\
+                """,
+                """
+                locals {
+                  a = [
+                   \s
+                  ]
+                }\
+                """
+        );
     }
 
     @Test
     public void testIndentedBlockNL4() throws Exception {
-        performNewLineIndentationTest("locals {\n\n|\n}", "locals {\n\n\n  
\n}");
+        performNewLineIndentationTest(
+                """
+                locals {
+                
+                |
+                }\
+                """,
+                """
+                locals {
+                
+                
+                 \s
+                }\
+                """);
     }
 
     
@@ -118,19 +184,78 @@ public class HCLIndenterTest extends NbTestCase {
 
     @Test
     public void testEmptyLine() throws Exception {
-        performLineIndentationTest("locals {\n  |\n}\n", "locals {\n\n}\n");
+        performLineIndentationTest(
+                """
+                locals {
+                  |
+                }
+                """,
+                """
+                locals {
+
+                }
+                """
+        );
     }
 
     public void testReindent1() throws Exception {
-        performSpanIndentationTest("|   locals {\n a = 1\n   \nb = 2\n}|\n", 
"locals {\n  a = 1\n\n  b = 2\n}\n");
+        performSpanIndentationTest(
+                """
+                |   locals {
+                 a = 1
+                  \s
+                b = 2
+                }|
+                """,
+                """
+                locals {
+                  a = 1
+                
+                  b = 2
+                }
+                """);
     }
     
     public void testReindent2() throws Exception {
-        performSpanIndentationTest("|a = {\nb = [[\n\"one\"\n], 
[\n\"two\"\n]]\n}|\n", "a = {\n  b = [[\n      \"one\"\n    ], [\n      
\"two\"\n  ]]\n}\n");
+        performSpanIndentationTest(
+                """
+                |a = {
+                b = [[
+                "one"
+                ], [
+                "two"
+                ]]
+                }|
+                """,
+                """
+                a = {
+                  b = [[
+                      "one"
+                    ], [
+                      "two"
+                  ]]
+                }
+                """
+        );
     }
     
     public void testReindentHeredoc() throws Exception {
-        performSpanIndentationTest("|a = <<-EOT\n    This\n    multi\n    
line\nEOT|\n", "a = <<-EOT\n    This\n    multi\n    line\nEOT\n");
+        performSpanIndentationTest(
+                """
+                |a = <<-EOT
+                    This
+                    multi
+                    line
+                EOT|
+                """,
+                """
+                a = <<-EOT
+                    This
+                    multi
+                    line
+                EOT
+                """
+        );
     }
     
     private void performNewLineIndentationTest(String code, String golden) 
throws Exception {
@@ -138,7 +263,7 @@ public class HCLIndenterTest extends NbTestCase {
 
         assertNotSame(-1, pos);
 
-        code = code.replaceAll(Pattern.quote("|"), "");
+        code = code.replace("|", "");
 
         doc.insertString(0, code, null);
         Indent indent = Indent.get(doc);
@@ -153,7 +278,7 @@ public class HCLIndenterTest extends NbTestCase {
 
         assertNotSame(-1, pos);
 
-        code = code.replaceAll(Pattern.quote("|"), "");
+        code = code.replace("|", "");
 
         doc.insertString(0, code, null);
         Indent indent = Indent.get(doc);
diff --git 
a/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ReferenceTest.java
 
b/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ReferenceTest.java
index a5c6d9a752..5d9c319583 100644
--- 
a/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ReferenceTest.java
+++ 
b/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ReferenceTest.java
@@ -54,7 +54,12 @@ public class ReferenceTest {
     
     @Test
     public void testReferences3() throws Exception {
-        var at = elementAt("a^{\nb=true\n}");
+        var at = elementAt( """
+                            a^{
+                                b = true
+                            }
+                            """
+                     );
         assertEquals(2, at.size());
         var it = at.iterator();
         assertTrue(it.next() instanceof HCLBlock);
diff --git 
a/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ast/HCLLiteralsTest.java
 
b/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ast/HCLLiteralsTest.java
index 2b168cda5a..d25afd1a87 100644
--- 
a/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ast/HCLLiteralsTest.java
+++ 
b/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ast/HCLLiteralsTest.java
@@ -44,7 +44,7 @@ public class HCLLiteralsTest {
         HCLExpression exp = parse("3.14");
         assertTrue(exp instanceof HCLLiteral.NumericLit);
         HCLLiteral.NumericLit num = (HCLLiteral.NumericLit) exp;
-        assertEquals("3.14", num.value);
+        assertEquals("3.14", num.value());
     }
 
     @Test
@@ -52,7 +52,7 @@ public class HCLLiteralsTest {
         HCLExpression exp = parse("\"Hello\"");
         assertTrue(exp instanceof HCLLiteral.StringLit);
         HCLLiteral.StringLit str = (HCLLiteral.StringLit) exp;
-        assertEquals("Hello", str.value);
+        assertEquals("Hello", str.value());
     }
 
     @Test
@@ -60,7 +60,7 @@ public class HCLLiteralsTest {
         HCLExpression exp = parse("\"\"");
         assertTrue(exp instanceof HCLLiteral.StringLit);
         HCLLiteral.StringLit str = (HCLLiteral.StringLit) exp;
-        assertEquals("", str.value);
+        assertEquals("", str.value());
     }
 
     @Test
@@ -68,7 +68,7 @@ public class HCLLiteralsTest {
         HCLExpression exp = parse("<<EOT\nEOT");
         assertTrue(exp instanceof HCLTemplate.HereDoc);
         HCLTemplate.HereDoc heredoc = (HCLTemplate.HereDoc) exp;
-        assertTrue(heredoc.parts.isEmpty());
+        assertTrue(heredoc.parts().isEmpty());
     }
 
 }
diff --git 
a/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ast/HCLOperationsTest.java
 
b/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ast/HCLOperationsTest.java
index e4cb2c8bea..95d794667f 100644
--- 
a/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ast/HCLOperationsTest.java
+++ 
b/ide/languages.hcl/test/unit/src/org/netbeans/modules/languages/hcl/ast/HCLOperationsTest.java
@@ -18,12 +18,6 @@
  */
 package org.netbeans.modules.languages.hcl.ast;
 
-import org.netbeans.modules.languages.hcl.ast.HCLResolveOperation;
-import org.netbeans.modules.languages.hcl.ast.HCLArithmeticOperation;
-import org.netbeans.modules.languages.hcl.ast.HCLLiteral;
-import org.netbeans.modules.languages.hcl.ast.HCLVariable;
-import org.netbeans.modules.languages.hcl.ast.HCLExpression;
-import org.netbeans.modules.languages.hcl.ast.HCLConditionalOperation;
 import org.junit.Test;
 import static org.junit.Assert.*;
 
@@ -40,9 +34,9 @@ public class HCLOperationsTest {
         HCLExpression exp = parse("var.key");
         assertTrue(exp instanceof HCLResolveOperation.Attribute);
         HCLResolveOperation.Attribute  resolve = 
(HCLResolveOperation.Attribute) exp;
-        assertEquals("key", resolve.attr.id);
-        assertTrue(resolve.base instanceof HCLVariable);
-        assertEquals("var", ((HCLVariable)resolve.base).name.id);
+        assertEquals("key", resolve.attr().id());
+        assertTrue(resolve.base() instanceof HCLVariable);
+        assertEquals("var", ((HCLVariable)resolve.base()).name().id());
     }
 
     @Test
@@ -50,9 +44,9 @@ public class HCLOperationsTest {
         HCLExpression exp = parse("a[0]");
         assertTrue(exp instanceof HCLResolveOperation.Index);
         HCLResolveOperation.Index  resolve = (HCLResolveOperation.Index) exp;
-        assertEquals("0", ((HCLLiteral.NumericLit)resolve.index).value);
-        assertTrue(resolve.base instanceof HCLVariable);
-        assertEquals("a", ((HCLVariable)resolve.base).name.id);
+        assertEquals("0", ((HCLLiteral.NumericLit)resolve.index()).value());
+        assertTrue(resolve.base() instanceof HCLVariable);
+        assertEquals("a", ((HCLVariable)resolve.base()).name().id());
     }
     
     @Test
@@ -61,11 +55,11 @@ public class HCLOperationsTest {
         assertTrue(exp instanceof HCLResolveOperation.Attribute);
         HCLResolveOperation.Attribute  resolve = 
(HCLResolveOperation.Attribute) exp;
 
-        assertTrue(resolve.base instanceof HCLResolveOperation.Index);
-        HCLResolveOperation.Index  resolve2 = (HCLResolveOperation.Index) 
resolve.base;
-        assertEquals("1", ((HCLLiteral.NumericLit)resolve2.index).value);
-        assertTrue(resolve2.base instanceof HCLVariable);
-        assertEquals("a", ((HCLVariable)resolve2.base).name.id);
+        assertTrue(resolve.base() instanceof HCLResolveOperation.Index);
+        HCLResolveOperation.Index  resolve2 = (HCLResolveOperation.Index) 
resolve.base();
+        assertEquals("1", ((HCLLiteral.NumericLit)resolve2.index()).value());
+        assertTrue(resolve2.base() instanceof HCLVariable);
+        assertEquals("a", ((HCLVariable)resolve2.base()).name().id());
     }
     
     @Test
@@ -73,9 +67,9 @@ public class HCLOperationsTest {
         HCLExpression exp = parse("a == b ? 1 : var");
         assertTrue(exp instanceof HCLConditionalOperation);
         HCLConditionalOperation cond = (HCLConditionalOperation) exp;
-        assertTrue(cond.condition instanceof HCLArithmeticOperation.Binary);
-        assertTrue(cond.trueValue instanceof HCLLiteral.NumericLit);
-        assertTrue(cond.falseValue instanceof HCLVariable);
+        assertTrue(cond.condition() instanceof HCLArithmeticOperation.Binary);
+        assertTrue(cond.trueValue() instanceof HCLLiteral.NumericLit);
+        assertTrue(cond.falseValue() instanceof HCLVariable);
         
         
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to