|
|
@@ -0,0 +1,133 @@
|
|
|
+package net.ranides.assira.g4.antlr;
|
|
|
+
|
|
|
+import net.ranides.assira.collection.iterators.IteratorUtils;
|
|
|
+import net.ranides.assira.collection.lists.ListUtils;
|
|
|
+import net.ranides.assira.collection.lists.ReversedList;
|
|
|
+import net.ranides.assira.collection.lists.VirtualList;
|
|
|
+import net.ranides.assira.collection.query.CQuery;
|
|
|
+import net.ranides.assira.g4.G4Node;
|
|
|
+import net.ranides.assira.text.StringUtils;
|
|
|
+import org.antlr.v4.runtime.tree.ParseTree;
|
|
|
+import org.antlr.v4.runtime.tree.RuleNode;
|
|
|
+import org.antlr.v4.runtime.tree.TerminalNode;
|
|
|
+
|
|
|
+import java.util.Deque;
|
|
|
+import java.util.LinkedList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.Optional;
|
|
|
+import java.util.OptionalInt;
|
|
|
+
|
|
|
+abstract class NodeAbstract<N extends ParseTree> implements G4Node {
|
|
|
+
|
|
|
+ protected final BasicParser.Shared shared;
|
|
|
+
|
|
|
+ protected final NodeAbstract<?> parent;
|
|
|
+
|
|
|
+ protected final N node;
|
|
|
+
|
|
|
+ public NodeAbstract(BasicParser.Shared shared, NodeAbstract<?> parent, N node) {
|
|
|
+ this.shared = shared;
|
|
|
+ this.parent = parent;
|
|
|
+ this.node = node;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final G4Node root() {
|
|
|
+ return shared.root;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final List<G4Node> children() {
|
|
|
+ return VirtualList.of(node.getChildCount(), i -> wrap(node.getChild(i)));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String name() {
|
|
|
+ return qualifier().map(q -> shortname() + "<" + q + ">").orElseGet(this::shortname);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final Optional<NodeAbstract<?>> parent() {
|
|
|
+ return Optional.ofNullable(parent);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected G4Node wrap(ParseTree tree) {
|
|
|
+ if(tree instanceof RuleNode) {
|
|
|
+ return new NodeForRule(shared, this, (RuleNode) tree);
|
|
|
+ } else {
|
|
|
+ return new NodeForTerm(shared, this, (TerminalNode) tree);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String path() {
|
|
|
+ List<String> path = new LinkedList<>();
|
|
|
+
|
|
|
+ Optional<NodeAbstract<?>> current = Optional.of(this);
|
|
|
+
|
|
|
+ while (current.isPresent()) {
|
|
|
+ path.add(current.get().getPathComponent());
|
|
|
+ current = current.get().parent();
|
|
|
+ }
|
|
|
+
|
|
|
+// IteratorUtils.finite()
|
|
|
+
|
|
|
+ return StringUtils.join(new ReversedList<>(path), "/");
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getPathComponent() {
|
|
|
+ Optional<Integer> index = getPathComponentIndex();
|
|
|
+ if(index.isPresent()) {
|
|
|
+ return shortname() + "[" + index.get() + "]";
|
|
|
+ } else {
|
|
|
+ return shortname();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Optional<Integer> getPathComponentIndex() {
|
|
|
+ if (parent == null || parent.children().size() == 1) {
|
|
|
+ return Optional.empty();
|
|
|
+ }
|
|
|
+
|
|
|
+ int found = 0;
|
|
|
+ Optional<Integer> index = Optional.empty();
|
|
|
+
|
|
|
+ for (G4Node child : parent.children()) {
|
|
|
+ if (child.equals(this)) {
|
|
|
+ index = Optional.of(found);
|
|
|
+
|
|
|
+ // break unnecessary looping, indexes greater that zero are always displayed
|
|
|
+ if (found > 0) {
|
|
|
+ return index;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (child.type() == this.type()) {
|
|
|
+ found++;
|
|
|
+
|
|
|
+ // break unnecessary looping, zero index should be displayed if there is more than one similar element
|
|
|
+ if (found > 1 && index.isPresent()) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // do not return zero index, if there is only one (i.e. this) child
|
|
|
+ return found > 1 ? index : Optional.empty();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean equals(Object o) {
|
|
|
+ if(o instanceof NodeAbstract<?>) {
|
|
|
+ NodeAbstract<?> that = (NodeAbstract<?>)o;
|
|
|
+ return this.node.equals(that.node);
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int hashCode() {
|
|
|
+ return Objects.hash(node);
|
|
|
+ }
|
|
|
+}
|