All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.xtext.nodemodel.impl.CompositeNode Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2010 itemis AG (http://www.itemis.eu) and others.
 * 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
 *******************************************************************************/
package org.eclipse.xtext.nodemodel.impl;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.nodemodel.BidiIterable;
import org.eclipse.xtext.nodemodel.BidiTreeIterator;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.serialization.DeserializationConversionContext;
import org.eclipse.xtext.nodemodel.serialization.SerializationConversionContext;
import org.eclipse.xtext.nodemodel.serialization.SerializationUtil;
import org.eclipse.xtext.nodemodel.util.EmptyBidiIterable;
import org.eclipse.xtext.nodemodel.util.NodeIterable;
import org.eclipse.xtext.nodemodel.util.SingletonBidiIterable;

/**
 * @author Sebastian Zarnekow - Initial contribution and API
 * @author Mark Christiaens - Serialization support
 * @noextend This class is not intended to be subclassed by clients.
 */
public class CompositeNode extends AbstractNode implements ICompositeNode {

	private AbstractNode firstChild;
	
	private int lookAhead;
	
	public BidiIterable getChildren() {
		if (hasChildren()) {
			INode firstChild = getFirstChild();
			if (firstChild.hasSiblings()) {
				return new NodeIterable(firstChild);
			} else {
				return SingletonBidiIterable.create(firstChild);
			}
		}
		return EmptyBidiIterable.instance();
	}
	
	public BidiIterable basicGetChildren() {
		if (firstChild != null) {
			if (firstChild.hasSiblings()) {
				return new BasicNodeIterable(firstChild);
			} else {
				return SingletonBidiIterable.create(basicGetFirstChild());
			}
		}
		return EmptyBidiIterable.instance();
	}
	
	public boolean hasChildren() {
		return firstChild != null || isFolded();
	}

	public int getLookAhead() {
		return lookAhead;
	}
	
	public int getTotalLength() {
		if (firstChild != null) {
			int offset = firstChild.getTotalOffset();
			AbstractNode lastChild = firstChild.basicGetPreviousSibling();
			return lastChild.getTotalOffset() + lastChild.getTotalLength() - offset;
		}
		return 0;
	}
	
	public int getTotalOffset() {
		if (firstChild != null)
			return firstChild.getTotalOffset();
		AbstractNode compositeWithSiblings = this;
		while(!compositeWithSiblings.basicHasNextSibling() && compositeWithSiblings.basicGetParent() != null) {
			compositeWithSiblings = compositeWithSiblings.basicGetParent();
		}
		if (compositeWithSiblings.basicHasNextSibling()) {
			AbstractNode sibling = compositeWithSiblings.basicGetNextSibling();
			return sibling.getTotalOffset();
		}
		// expensive fallback - should never happen in a valid node model
		BidiTreeIterator iter = getRootNode().getAsTreeIterable().iterator();
		ILeafNode lastSeen = null;
		while(iter.hasNext()) {
			INode next = iter.next();
			if (next == this) {
				if (lastSeen == null)
					return 0;
				else
					return lastSeen.getTotalEndOffset();
			}
			if (next instanceof ILeafNode) {
				lastSeen = (ILeafNode) next;
			}
		}
		return 0;
	}

	protected void basicSetLookAhead(int lookAhead) {
		this.lookAhead = lookAhead;
	}
	
	public INode getFirstChild() {
		if (isFolded()) {
			return new SyntheticCompositeNode(this, 1);
		}
		return firstChild;
	}
	
	protected AbstractNode basicGetFirstChild() {
		return firstChild;
	}
	
	protected void basicSetFirstChild(AbstractNode firstChild) {
		this.firstChild = firstChild;
	}
	
	public INode getLastChild() {
		if (isFolded()) {
			return new SyntheticCompositeNode(this, 1);
		}
		return basicGetLastChild();
	}
	
	protected AbstractNode basicGetLastChild() {
		if (firstChild == null)
			return null;
		return firstChild.basicGetPreviousSibling();
	}
	
	protected boolean isFolded() {
		Object grammarElementOrArray = basicGetGrammarElement();
		return isFolded(grammarElementOrArray);
	}

	protected boolean isFolded(Object grammarElementOrArray) {
		return !(grammarElementOrArray == null || grammarElementOrArray instanceof EObject);
	}
	
	public ICompositeNode resolveAsParent() {
		Object grammarElementOrArray = basicGetGrammarElement();
		if (!isFolded())
			return this;
		EObject[] grammarElements = (EObject[]) grammarElementOrArray;
		return new SyntheticCompositeNode(this, grammarElements.length - 1);
	}	
	
	@Override
	public EObject getGrammarElement() {
		Object grammarElementOrArray = basicGetGrammarElement();
		if (!isFolded())
			return (EObject) grammarElementOrArray;
		EObject[] grammarElements = (EObject[]) grammarElementOrArray;
		return grammarElements[0];
	}

	private static final NodeType[] NODE_TYPE_VALUES = NodeType.values();
	
	@Override 
	void readData(DataInputStream in, DeserializationConversionContext context) throws IOException {
		super.readData(in, context);

		int childNodeCount = SerializationUtil.readInt(in, true);

		if (childNodeCount > 0) {
			AbstractNode child = null;
			AbstractNode prevChild = null;
			for (int i = 0; i < childNodeCount; ++i) {
				int nodeId = SerializationUtil.readInt(in, true);
				NodeType nodeType = NODE_TYPE_VALUES[nodeId];
				child = createChildNode(nodeType);
				child.readData(in, context);

				if (firstChild == null) {
					firstChild = child;
				}

				child.basicSetParent(this);
				child.basicSetPreviousSibling(prevChild);

				prevChild = child;
			}

			firstChild.basicSetPreviousSibling(child);

			// All left links are fine, now the right ones

			child = firstChild.basicGetPreviousSibling();
			prevChild = firstChild;

			while (child != firstChild) {
				child.basicSetNextSibling(prevChild);
				prevChild = child;
				child = child.basicGetPreviousSibling();
			}

			firstChild.basicSetNextSibling(prevChild);
		}

		lookAhead = SerializationUtil.readInt(in, true);
	}
	
	private AbstractNode createChildNode(AbstractNode.NodeType type) {
		switch (type) {
			case CompositeNode:
				return new CompositeNode();
			case CompositeNodeWithSemanticElement:
				return new CompositeNodeWithSemanticElement();
			case CompositeNodeWithSemanticElementAndSyntaxError:
				return new CompositeNodeWithSemanticElementAndSyntaxError();
			case CompositeNodeWithSyntaxError:
				return new CompositeNodeWithSyntaxError();
			case HiddenLeafNode:
				return new HiddenLeafNode();
			case HiddenLeafNodeWithSyntaxError:
				return new HiddenLeafNodeWithSyntaxError();
			case LeafNode:
				return new LeafNode();
			case LeafNodeWithSyntaxError:
				return new LeafNodeWithSyntaxError();
			case RootNode:
				return new RootNode();
			default:
				throw new IllegalArgumentException("Trying to construct a non-existing INode");
		}
	}
	
	@Override
	void write(DataOutputStream out, SerializationConversionContext scc) throws IOException {
		super.write(out, scc);

		int childNodeCount = getChildCount();
		SerializationUtil.writeInt(out, childNodeCount, true);

		AbstractNode it = firstChild;

		for (int i = 0; i < childNodeCount; ++i) {
			SerializationUtil.writeInt(out, it.getNodeId().ordinal(), true);
			it.write(out, scc);
			it = it.basicGetNextSibling();
		}

		SerializationUtil.writeInt(out, lookAhead, true);
	}

	private int getChildCount() {
		if (firstChild == null) {
			return 0;
		}

		AbstractNode it = firstChild;
		int count = 0;

		do {
			++count;
			it = it.basicGetNextSibling();
		} while (it != firstChild);

		return count;
	}

	@Override
	int fillGrammarElementToIdMap(int currentId, Map grammarElementToIdMap,
			List grammarIdToURIMap) {
		currentId = super.fillGrammarElementToIdMap(currentId, grammarElementToIdMap, grammarIdToURIMap);

		if (firstChild != null) {
			AbstractNode it = firstChild;

			do {
				currentId = it.fillGrammarElementToIdMap(currentId, grammarElementToIdMap, grammarIdToURIMap);
				it = it.basicGetNextSibling();
			} while (it != firstChild);
		}

		return currentId;
	}

	@Override
	NodeType getNodeId() {
		return NodeType.CompositeNode;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy