PageRenderTime 32ms CodeModel.GetById 2ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2-build270707/src/edu/vub/at/objects/natives/NATTable.java

http://ambienttalk.googlecode.com/
Java | 312 lines | 203 code | 41 blank | 68 comment | 34 complexity | 1dd4de0b2c4609975642c58b23e562a2 MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * NATTable.java created on 26-jul-2006 at 16:48:34
  4 * (c) Programming Technology Lab, 2006 - 2007
  5 * Authors: Tom Van Cutsem & Stijn Mostinckx
  6 * 
  7 * Permission is hereby granted, free of charge, to any person
  8 * obtaining a copy of this software and associated documentation
  9 * files (the "Software"), to deal in the Software without
 10 * restriction, including without limitation the rights to use,
 11 * copy, modify, merge, publish, distribute, sublicense, and/or
 12 * sell copies of the Software, and to permit persons to whom the
 13 * Software is furnished to do so, subject to the following
 14 * conditions:
 15 *
 16 * The above copyright notice and this permission notice shall be
 17 * included in all copies or substantial portions of the Software.
 18 *
 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 21 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 23 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 26 * OTHER DEALINGS IN THE SOFTWARE.
 27 */
 28package edu.vub.at.objects.natives;
 29
 30import edu.vub.at.eval.Evaluator;
 31import edu.vub.at.exceptions.InterpreterException;
 32import edu.vub.at.exceptions.XIndexOutOfBounds;
 33import edu.vub.at.objects.ATBoolean;
 34import edu.vub.at.objects.ATClosure;
 35import edu.vub.at.objects.ATContext;
 36import edu.vub.at.objects.ATNil;
 37import edu.vub.at.objects.ATNumber;
 38import edu.vub.at.objects.ATObject;
 39import edu.vub.at.objects.ATTable;
 40import edu.vub.at.objects.ATText;
 41import edu.vub.at.objects.coercion.NativeTypeTags;
 42import edu.vub.at.objects.mirrors.NativeClosure;
 43import edu.vub.at.objects.natives.grammar.AGExpression;
 44
 45import java.util.LinkedList;
 46import java.util.Vector;
 47
 48/**
 49 * The native implementation of an AmbientTalk table.
 50 * A table is implemented by a java array.
 51 * 
 52 * An important distinction between AT tables and Java arrays is that
 53 * ATTable objects are indexed from [1..size] rather than [0..size[
 54 * 
 55 * @author tvcutsem
 56 */
 57public final class NATTable extends AGExpression implements ATTable {
 58
 59	public final static NATTable EMPTY = new NATTable(new ATObject[] {});
 60	
 61	public final ATObject[] elements_;
 62	
 63	/**
 64	 * Table factory method. Used to enforce that only one empty table
 65	 * in the system exists.
 66	 */
 67	public static final NATTable atValue(ATObject[] array) {
 68		if (array.length == 0)
 69			return NATTable.EMPTY;
 70		else
 71			return new NATTable(array);
 72	}
 73	
 74	/**
 75	 * @return a table of the given size, filled with nil
 76	 */
 77	public static final NATTable ofSize(int size) {
 78		ATObject[] array = new ATObject[size];
 79		for (int i = 0; i < size; i++) {
 80			array[i] = OBJNil._INSTANCE_;
 81		}
 82		return atValue(array);
 83	}
 84	
 85	/*
 86	 * Auxiliary methods to create tables more easily.
 87	 */
 88	
 89	public static final NATTable of(ATObject one) {
 90		return new NATTable(new ATObject[] { one });
 91	}
 92	
 93	public static final NATTable of(ATObject one, ATObject two) {
 94		return new NATTable(new ATObject[] { one, two });
 95	}
 96	
 97	public static final NATTable of(ATObject one, ATObject two, ATObject three) {
 98		return new NATTable(new ATObject[] { one, two, three });
 99	}
100	
101	private NATTable(ATObject[] elements) {
102		// assert elements.length > 0
103		elements_ = elements;
104	}
105	
106    public ATTable asTable() { return this; }
107	
108    public boolean isTable() { return true; }
109    
110	public NATTable asNativeTable() { return this; }
111	
112	/**
113	 * To evaluate a table, evaluate all of its constituent expressions, taking
114	 * special care to take into account spliced expressions.
115	 * 
116	 * NATTAB(exps).eval(ctx) = NATTAB(map eval(ctx) over exps)
117	 * 
118	 * @return a table of evaluated arguments
119	 */
120	public ATObject meta_eval(ATContext ctx) throws InterpreterException {
121		if (this == EMPTY) return EMPTY;
122		
123		LinkedList result = new LinkedList();
124		int siz = elements_.length;
125		for (int i = 0; i < elements_.length; i++) {
126			if (elements_[i].isSplice()) {
127				ATObject[] tbl = elements_[i].asSplice().base_expression().meta_eval(ctx).asNativeTable().elements_;
128				for (int j = 0; j < tbl.length; j++) {
129					result.add(tbl[j]);
130				}
131				siz += (tbl.length - 1); // -1 because we replace one element by a table of elements
132			} else {
133				result.add(elements_[i].meta_eval(ctx));
134			}
135		}
136		return atValue((ATObject[]) result.toArray(new ATObject[siz]));
137	}
138	
139	/**
140	 * To quote a table, quote all elements of the table.
141	 * Special care needs to be taken in order to properly deal with unquote-spliced elements.
142	 * When one of the direct elements of the table is an unquote-splice element, the resulting
143	 * unquotation must result in a table whose elements are directly added to this table's elements.
144	 */
145	public ATObject meta_quote(ATContext ctx) throws InterpreterException {
146		if (this == EMPTY) return EMPTY;
147		
148		LinkedList result = new LinkedList();
149		int siz = elements_.length;
150		for (int i = 0; i < elements_.length; i++) {
151			if (elements_[i].isUnquoteSplice()) {
152				ATObject[] tbl = elements_[i].asUnquoteSplice().base_expression().meta_eval(ctx).asNativeTable().elements_;
153				for (int j = 0; j < tbl.length; j++) {
154					result.add(tbl[j]);
155				}
156				siz += (tbl.length - 1); // -1 because we replace one element by a table of elements
157			} else {
158				result.add(elements_[i].meta_quote(ctx));
159			}
160		}
161		return atValue((ATObject[]) result.toArray(new ATObject[siz]));
162	}
163	
164	public NATText meta_print() throws InterpreterException {
165		return Evaluator.printElements(this, "[", ", ","]");
166	}
167	
168    public ATTable meta_typeTags() throws InterpreterException {
169    	return NATTable.of(NativeTypeTags._TABLE_);
170    }
171	
172	public ATNumber base_length() { return NATNumber.atValue(elements_.length); }
173
174	public ATObject base_at(ATNumber index) throws InterpreterException {
175		return elements_[extractIndex(index)];
176	}
177
178	public ATObject base_atPut(ATNumber index, ATObject value) throws InterpreterException {
179		elements_[extractIndex(index)] = value;
180		return value;
181	}
182	
183	public ATBoolean base_isEmpty() {
184		return NATBoolean.atValue(elements_.length == 0);
185	}
186	
187	public ATNil base_each_(ATClosure clo) throws InterpreterException {
188		for (int i = 0; i < elements_.length; i++) {
189			clo.base_apply(atValue(new ATObject[] { elements_[i] }));
190		}
191		return OBJNil._INSTANCE_;
192	}
193
194	public ATTable base_map_(ATClosure clo) throws InterpreterException {
195		if (this == EMPTY) return EMPTY;
196		
197		ATObject[] result = new ATObject[elements_.length];
198		for (int i = 0; i < elements_.length; i++) {
199			result[i] = clo.base_apply(atValue(new ATObject[] { elements_[i] }));
200		}
201		return atValue(result);
202	}
203	
204	public ATObject base_inject_into_(ATObject init, ATClosure clo) throws InterpreterException {
205		ATObject total = init;
206		for (int i = 0; i < elements_.length; i++) {
207			total = clo.base_apply(atValue(new ATObject[] { total, elements_[i] }));
208		}
209		return total;
210	}
211	
212	public ATTable base_filter_(ATClosure clo) throws InterpreterException {
213		Vector matchingElements = new Vector(elements_.length);
214		for (int i = 0; i < elements_.length; i++) {
215			if (clo.base_apply(atValue(new ATObject[] { elements_[i] })).asNativeBoolean().javaValue) {
216				matchingElements.add(elements_[i]);
217			}
218		}
219		return atValue((ATObject[]) matchingElements.toArray(new ATObject[matchingElements.size()]));
220	}
221	
222	public ATObject base_find_(ATClosure clo) throws InterpreterException {
223		for (int i = 0; i < elements_.length; i++) {
224			if (clo.base_apply(atValue(new ATObject[] { elements_[i] })).asNativeBoolean().javaValue) {
225				return NATNumber.atValue(i+1);
226			}
227		}
228		return OBJNil._INSTANCE_;
229	}
230	
231	public ATBoolean base_contains(ATObject obj) throws InterpreterException {
232		for (int i = 0; i < elements_.length; i++) {
233			if (obj.base__opeql__opeql_(elements_[i]).asNativeBoolean().javaValue) {
234				return NATBoolean._TRUE_;
235			}
236		}
237		return NATBoolean._FALSE_;
238	}
239	
240	public ATText base_implode() throws InterpreterException {
241		StringBuffer buff = new StringBuffer("");
242		for (int i = 0; i < elements_.length; i++) {
243			buff.append(elements_[i].asNativeText().javaValue);
244		}
245		return NATText.atValue(buff.toString());
246	}
247
248	public ATText base_join(ATText sep) throws InterpreterException {
249		String separator = sep.asNativeText().javaValue;
250		StringBuffer buff = new StringBuffer("");
251		for (int i = 0; i < elements_.length-1; i++) {
252			buff.append(elements_[i].asNativeText().javaValue);
253			buff.append(separator);
254		}
255		if (elements_.length > 0)
256			buff.append(elements_[elements_.length-1].asNativeText().javaValue);
257		return NATText.atValue(buff.toString());
258	}
259	
260	/**
261	 * tab.select(start, stop) == els = [ ] ; start.to: stop do: { |i| els << tab[i] } ; els
262	 */
263	public ATTable base_select(ATNumber first, ATNumber last) throws InterpreterException {
264		final LinkedList selection = new LinkedList();
265		first.base_to_do_(last, new NativeClosure(this) {
266			public ATObject base_apply(ATTable args) throws InterpreterException {
267			    selection.add(base_at(args.base_at(NATNumber.ONE).asNumber()));
268			    return OBJNil._INSTANCE_;
269			}
270		});
271		return NATTable.atValue((ATObject[]) selection.toArray(new ATObject[selection.size()]));
272	}
273	
274	public ATTable base__oppls_(ATTable other) throws InterpreterException {
275		return NATTable.atValue(collate(elements_, other.asNativeTable().elements_));
276	}
277	
278	protected int extractIndex(ATNumber atIndex) throws InterpreterException {
279		int javaIndex = atIndex.asNativeNumber().javaValue - 1;
280		if ((javaIndex < 0) || (javaIndex >= elements_.length))
281			throw new XIndexOutOfBounds(javaIndex + 1, elements_.length);
282		else
283			return javaIndex;
284	}
285
286	/**
287	 * Auxiliary method to collate two Java arrays
288	 * @return an array containing first the elements of ary1, then the elements of ary2
289	 */
290	public static final ATObject[] collate(ATObject[] ary1, ATObject[] ary2) {
291	    int siz1 = ary1.length;
292	    int siz2 = ary2.length;
293	    ATObject[] union = new ATObject[siz1 + siz2];
294	    System.arraycopy(ary1, 0, union, 0, siz1);
295	    System.arraycopy(ary2, 0, union, siz1, siz2);
296	    return union;
297	}
298	
299	public ATObject meta_clone() throws InterpreterException {
300		ATObject[] clonedArray = new ATObject[elements_.length];
301		System.arraycopy(elements_, 0, clonedArray, 0, elements_.length);
302		return NATTable.atValue(clonedArray);
303	}
304	
305	public ATObject meta_resolve() throws InterpreterException {
306		if (elements_.length == 0)
307			return NATTable.EMPTY;
308		else
309			return this;
310	}
311	
312}