/*******************************************************************************
* Copyright (c) 2015 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.editor.support.yaml.ast;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.SequenceNode;
/**
* A node reference represents a 'pointer' to a location where a Node is stored.
* The concept is useful because when looking for a 'path' inside an Yaml AST a
* NodeRef makes it explicit where the node is with respect to some 'container'.
* For example it allows distinguishing between a reference to Node which is
* obtained from map key versus a map value.
*
* @author Kris De Volder
*/
public abstract class NodeRef<Parent> {
public static enum Kind {
ROOT, SEQ, KEY, VAL
}
private Parent parent;
public NodeRef(Parent parent) {
this.parent = parent;
}
public Parent getParent() {
return parent;
}
public abstract Node get();
public abstract void put(Node value);
public abstract String toString();
public abstract Kind getKind();
/**
* Represents a reference to a root node, contained directly
* inside a {@link YamlFileAST}
*/
public static class RootRef extends NodeRef<YamlFileAST> {
private int index;
public RootRef(YamlFileAST file, int index) {
super(file);
this.index = index;
}
@Override
public Node get() {
return getParent().get(index);
}
@Override
public void put(Node value) {
getParent().put(index, value);
}
@Override
public String toString() {
return "ROOT["+index+"]";
}
@Override
public Kind getKind() {
return Kind.ROOT;
}
public int getIndex() {
return index;
}
}
public static class SeqRef extends NodeRef<SequenceNode> {
private int index;
public SeqRef(SequenceNode seq, int index) {
super(seq);
this.index = index;
}
@Override
public Node get() {
return getParent().getValue().get(index);
}
@Override
public void put(Node value) {
getParent().getValue().set(index, value);
}
@Override
public String toString() {
return "["+index+"]";
}
@Override
public Kind getKind() {
return Kind.SEQ;
}
public int getIndex() {
return index;
}
}
/**
* Abstract, represent reference to either a key or
* value inside a map tuple. Concrete subclasses define whether
* key or value is being accessed.
*/
public static abstract class TupleRef extends NodeRef<MappingNode> {
protected int index;
public TupleRef(MappingNode map, int index) {
super(map);
this.index = index;
}
public NodeTuple getTuple() {
return getParent().getValue().get(index);
}
public void putTuple(NodeTuple value) {
getParent().getValue().set(index, value);
}
}
/**
* References a key of a map entry
*/
public static class TupleKeyRef extends TupleRef {
public TupleKeyRef(MappingNode parent, int index) {
super(parent, index);
}
@Override
public Node get() {
return getTuple().getKeyNode();
}
@Override
public void put(Node newKey) {
NodeTuple tuple = getTuple();
putTuple(new NodeTuple(newKey, tuple.getValueNode()));
}
@Override
public String toString() {
return "@key["+index+"]";
}
@Override
public Kind getKind() {
return Kind.KEY;
}
}
/**
* References a value of a map entry
*/
public static class TupleValueRef extends TupleRef {
public TupleValueRef(MappingNode parent, int index) {
super(parent, index);
}
@Override
public Node get() {
return getTuple().getValueNode();
}
@Override
public void put(Node newValue) {
NodeTuple t = getTuple();
putTuple(new NodeTuple(t.getKeyNode(), newValue));
}
@Override
public String toString() {
String keyString = NodeUtil.asScalar(getTuple().getKeyNode());
if (keyString!=null) {
//more readable to use the key value than the index of the tuple
return "@val['"+keyString+"']";
}
return "@val["+index+"]";
}
@Override
public Kind getKind() {
return Kind.VAL;
}
public Node getKey() {
return getTuple().getKeyNode();
}
}
}