/******************************************************************************* * Copyright (c) 2007-2013 IBM Corporation & CWI * 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: * * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package org.rascalmpl.value.impl.reference; import java.util.Iterator; import java.util.Map; import org.rascalmpl.value.INode; import org.rascalmpl.value.IValue; import org.rascalmpl.value.IValueFactory; import org.rascalmpl.value.impl.AbstractNode; import org.rascalmpl.value.impl.func.NodeFunctions; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; import org.rascalmpl.value.visitors.IValueVisitor; import io.usethesource.capsule.ArrayIterator; /** * Naive implementation of an untyped tree node, using array of children. */ /*package*/ class Node extends AbstractNode implements INode { protected final static Type VALUE_TYPE = TypeFactory.getInstance().valueType(); @Override public Type getType() { return fType; } protected final Type fType; protected final IValue[] fChildren; protected final String fName; protected int fHash = 0; protected final String[] keyArgNames; /*package*/ Node(String name, IValue[] children) { super(); fType = TypeFactory.getInstance().nodeType(); fName = name; fChildren = children.clone(); keyArgNames = null; } protected Node(String name, Type type, IValue[] children) { super(); fType = type; fName = name; fChildren = children.clone(); keyArgNames = null; } /*package*/ Node(String name, IValue[] children, Map<String, IValue> keyArgValues){ super(); fType = TypeFactory.getInstance().nodeType(); fName = (name != null ? name.intern() : null); // Handle (weird) special case. if(keyArgValues != null){ int nkw = keyArgValues.size(); IValue[] extendedChildren = new IValue[children.length + nkw]; for(int i = 0; i < children.length;i++){ extendedChildren[i] = children[i]; } String keyArgNames[]= new String[nkw]; int k = 0; for(String kw : keyArgValues.keySet()){ keyArgNames[k++] = kw; } for(int i = 0; i < nkw; i++){ extendedChildren[children.length + i] = keyArgValues.get(keyArgNames[i]); } this.fChildren = extendedChildren; this.keyArgNames = keyArgNames; } else { this.fChildren = children; this.keyArgNames = null; } } /*package*/ Node(String name) { this(name, new IValue[0]); } /** * Replaces a child * @param other * @param index * @param newChild */ protected Node(Node other, int index, IValue newChild) { super(); fType = other.fType; fName = other.fName; fChildren = other.fChildren.clone(); fChildren[index] = newChild; keyArgNames = null; } @Override public <T, E extends Throwable> T accept(IValueVisitor<T,E> v) throws E { return v.visitNode(this); } @Override public int arity() { return fChildren.length; } @Override protected IValueFactory getValueFactory() { return ValueFactory.getInstance(); } @Override public IValue get(int i) throws IndexOutOfBoundsException { try { return fChildren[i]; } catch (ArrayIndexOutOfBoundsException e) { throw new IndexOutOfBoundsException("Node node does not have child at pos " + i); } } @Override public Iterable<IValue> getChildren() { return this; } @Override public String getName() { return fName; } @Override public INode set(int i, IValue newChild) throws IndexOutOfBoundsException { try { return new Node(this, i, newChild); } catch (ArrayIndexOutOfBoundsException e) { throw new IndexOutOfBoundsException("Node node does not have child at pos " + i); } } @Override public Iterator<IValue> iterator() { return ArrayIterator.of(fChildren); } @Override public boolean equals(Object obj) { if(this == obj) { return true; } else if(obj == null) { return false; } else if (getClass() == obj.getClass()) { Node other = (Node) obj; if (!fType.comparable(other.fType)) { return false; } if (fChildren.length != other.fChildren.length) { return false; } if (fName == other.fName || (fName != null && fName.equals(other.fName))) { for (int i = 0; i < fChildren.length; i++) { if (!fChildren[i].equals(other.fChildren[i])) { return false; } } return true; } } return false; } @Override public boolean isEqual(IValue value){ return NodeFunctions.isEqual(getValueFactory(), this, value); } public int computeHashCode() { int hash = fName != null ? fName.hashCode() : 0; for (int i = 0; i < fChildren.length; i++) { hash = (hash << 1) ^ (hash >> 1) ^ fChildren[i].hashCode(); } return hash; } @Override public int hashCode() { if (fHash == 0) { fHash = computeHashCode(); } return fHash; } }