001: /*
002: ***** BEGIN LICENSE BLOCK *****
003: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
004: *
005: * The contents of this file are subject to the Common Public
006: * License Version 1.0 (the "License"); you may not use this file
007: * except in compliance with the License. You may obtain a copy of
008: * the License at http://www.eclipse.org/legal/cpl-v10.html
009: *
010: * Software distributed under the License is distributed on an "AS
011: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
012: * implied. See the License for the specific language governing
013: * rights and limitations under the License.
014: *
015: * Copyright (C) 2004-2005 Thomas E Enebo <enebo@acm.org>
016: * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
017: *
018: * Alternatively, the contents of this file may be used under the terms of
019: * either of the GNU General Public License Version 2 or later (the "GPL"),
020: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
021: * in which case the provisions of the GPL or the LGPL are applicable instead
022: * of those above. If you wish to allow use of your version of this file only
023: * under the terms of either the GPL or the LGPL, and not to allow others to
024: * use your version of this file under the terms of the CPL, indicate your
025: * decision by deleting the provisions above and replace them with the notice
026: * and other provisions required by the GPL or the LGPL. If you do not delete
027: * the provisions above, a recipient may use your version of this file under
028: * the terms of any one of the CPL, the GPL or the LGPL.
029: ***** END LICENSE BLOCK *****/
030: package org.jruby.ast;
031:
032: import java.util.Arrays;
033: import java.util.List;
034: import org.jruby.ast.visitor.NodeVisitor;
035: import org.jruby.evaluator.Instruction;
036: import org.jruby.lexer.yacc.ISourcePosition;
037:
038: /**
039: * All Nodes which have a list representation inherit this. This is also used
040: * as generic container for additional information that is not directly evaluated.
041: * In particular, f_arg production rule uses this to capture arg information for
042: * the editor projects who want position info saved.
043: */
044: public class ListNode extends Node {
045: private static Node[] EMPTY_NODE_ARRAY = new Node[0];
046:
047: private Node[] list;
048:
049: /**
050: * Create a new ListNode.
051: *
052: * @param id type of listnode
053: * @param firstNode first element of the list
054: */
055: public ListNode(ISourcePosition position, int id, Node firstNode) {
056: this (position, id);
057:
058: list = new Node[] { firstNode };
059: }
060:
061: public ListNode(ISourcePosition position, int id) {
062: super (position, id);
063:
064: list = EMPTY_NODE_ARRAY;
065: }
066:
067: public ListNode(ISourcePosition position) {
068: this (position, NodeTypes.LISTNODE);
069: }
070:
071: public ListNode add(Node node) {
072: // Ruby Grammar productions return plenty of nulls.
073: if (node == null)
074: return this ;
075: Node[] newList = new Node[list.length + 1];
076: if (list.length > 0)
077: System.arraycopy(list, 0, newList, 0, list.length);
078: list = newList;
079:
080: list[list.length - 1] = node;
081:
082: if (getPosition() == null) {
083: setPosition(node.getPosition());
084: } else {
085: setPosition(getPosition().union(node.getPosition()));
086: }
087:
088: return this ;
089: }
090:
091: public ListNode prepend(Node node) {
092: // Ruby Grammar productions return plenty of nulls.
093: if (node == null)
094: return this ;
095: Node[] newList = new Node[list.length + 1];
096: if (list.length > 0)
097: System.arraycopy(list, 0, newList, 1, list.length);
098: list = newList;
099:
100: list[0] = node;
101: setPosition(getPosition().union(node.getPosition()));
102: return this ;
103: }
104:
105: public int size() {
106: return list.length;
107: }
108:
109: /**
110: * Add all elements in other list to this list node.
111: *
112: * @param other list which has elements
113: * @return this instance for method chaining
114: */
115: public ListNode addAll(ListNode other) {
116: if (other != null && other.size() > 0) {
117: Node[] newList = new Node[list.length + other.size()];
118: if (list.length > 0)
119: System.arraycopy(list, 0, newList, 0, list.length);
120: System.arraycopy(other.list, 0, newList, list.length,
121: other.list.length);
122: list = newList;
123:
124: setPosition(getPosition().union(getLast().getPosition()));
125: }
126: return this ;
127: }
128:
129: /**
130: * Add other element to this list
131: *
132: * @param other list which has elements
133: * @return this instance for method chaining
134: */
135: public ListNode addAll(Node other) {
136: return add(other);
137: }
138:
139: public Node getLast() {
140: return list.length == 0 ? null : list[list.length - 1];
141: }
142:
143: public String toString() {
144: String string = super .toString();
145: StringBuffer b = new StringBuffer();
146: for (int i = 0; i < list.length; i++) {
147: b.append(list[i]);
148: if (i + 1 < list.length) {
149: b.append(", ");
150: }
151: }
152: return string + ": {" + b.toString() + "}";
153: }
154:
155: public List childNodes() {
156: return Arrays.asList(list);
157: }
158:
159: public Instruction accept(NodeVisitor visitor) {
160: throw new RuntimeException(
161: "Base class ListNode should never be evaluated");
162: }
163:
164: public Node get(int idx) {
165: return list[idx];
166: }
167: }
|