PageRenderTime 49ms CodeModel.GetById 26ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/reactive-pattern-matching/src/edu/vub/at/objects/natives/NATTable.java

http://ambienttalk.googlecode.com/
Java | 313 lines | 204 code | 41 blank | 68 comment | 34 complexity | fb183d0835de333bc853e129b7e989b8 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.ATMutable;
 37import edu.vub.at.objects.ATNil;
 38import edu.vub.at.objects.ATNumber;
 39import edu.vub.at.objects.ATObject;
 40import edu.vub.at.objects.ATTable;
 41import edu.vub.at.objects.ATText;
 42import edu.vub.at.objects.coercion.NativeTypeTags;
 43import edu.vub.at.objects.mirrors.NativeClosure;
 44import edu.vub.at.objects.natives.grammar.AGExpression;
 45
 46import java.util.LinkedList;
 47import java.util.Vector;
 48
 49/**
 50 * The native implementation of an AmbientTalk table.
 51 * A table is implemented by a java array.
 52 * 
 53 * An important distinction between AT tables and Java arrays is that
 54 * ATTable objects are indexed from [1..size] rather than [0..size[
 55 * 
 56 * @author tvcutsem
 57 */
 58public final class NATTable extends AGExpression implements ATTable, ATMutable {
 59
 60	public final static NATTable EMPTY = new NATTable(new ATObject[] {});
 61	
 62	public final ATObject[] elements_;
 63	
 64	/**
 65	 * Table factory method. Used to enforce that only one empty table
 66	 * in the system exists.
 67	 */
 68	public static final NATTable atValue(ATObject[] array) {
 69		if (array.length == 0)
 70			return NATTable.EMPTY;
 71		else
 72			return new NATTable(array);
 73	}
 74	
 75	/**
 76	 * @return a table of the given size, filled with nil
 77	 */
 78	public static final NATTable ofSize(int size) {
 79		ATObject[] array = new ATObject[size];
 80		for (int i = 0; i < size; i++) {
 81			array[i] = Evaluator.getNil();
 82		}
 83		return atValue(array);
 84	}
 85	
 86	/*
 87	 * Auxiliary methods to create tables more easily.
 88	 */
 89	
 90	public static final NATTable of(ATObject one) {
 91		return new NATTable(new ATObject[] { one });
 92	}
 93	
 94	public static final NATTable of(ATObject one, ATObject two) {
 95		return new NATTable(new ATObject[] { one, two });
 96	}
 97	
 98	public static final NATTable of(ATObject one, ATObject two, ATObject three) {
 99		return new NATTable(new ATObject[] { one, two, three });
100	}
101	
102	private NATTable(ATObject[] elements) {
103		// assert elements.length > 0
104		elements_ = elements;
105	}
106	
107    public ATTable asTable() { return this; }
108	
109    public boolean isTable() { return true; }
110    
111	public NATTable asNativeTable() { return this; }
112	
113	/**
114	 * To evaluate a table, evaluate all of its constituent expressions, taking
115	 * special care to take into account spliced expressions.
116	 * 
117	 * NATTAB(exps).eval(ctx) = NATTAB(map eval(ctx) over exps)
118	 * 
119	 * @return a table of evaluated arguments
120	 */
121	public ATObject meta_eval(ATContext ctx) throws InterpreterException {
122		if (this == EMPTY) return EMPTY;
123		
124		LinkedList result = new LinkedList();
125		int siz = elements_.length;
126		for (int i = 0; i < elements_.length; i++) {
127			if (elements_[i].isSplice()) {
128				ATObject[] tbl = elements_[i].asSplice().base_expression().meta_eval(ctx).asNativeTable().elements_;
129				for (int j = 0; j < tbl.length; j++) {
130					result.add(tbl[j]);
131				}
132				siz += (tbl.length - 1); // -1 because we replace one element by a table of elements
133			} else {
134				result.add(elements_[i].meta_eval(ctx));
135			}
136		}
137		return atValue((ATObject[]) result.toArray(new ATObject[siz]));
138	}
139	
140	/**
141	 * To quote a table, quote all elements of the table.
142	 * Special care needs to be taken in order to properly deal with unquote-spliced elements.
143	 * When one of the direct elements of the table is an unquote-splice element, the resulting
144	 * unquotation must result in a table whose elements are directly added to this table's elements.
145	 */
146	public ATObject meta_quote(ATContext ctx) throws InterpreterException {
147		if (this == EMPTY) return EMPTY;
148		
149		LinkedList result = new LinkedList();
150		int siz = elements_.length;
151		for (int i = 0; i < elements_.length; i++) {
152			if (elements_[i].isUnquoteSplice()) {
153				ATObject[] tbl = elements_[i].asUnquoteSplice().base_expression().meta_eval(ctx).asNativeTable().elements_;
154				for (int j = 0; j < tbl.length; j++) {
155					result.add(tbl[j]);
156				}
157				siz += (tbl.length - 1); // -1 because we replace one element by a table of elements
158			} else {
159				result.add(elements_[i].meta_quote(ctx));
160			}
161		}
162		return atValue((ATObject[]) result.toArray(new ATObject[siz]));
163	}
164	
165	public NATText meta_print() throws InterpreterException {
166		return Evaluator.printElements(this, "[", ", ","]");
167	}
168	
169    public ATTable meta_typeTags() throws InterpreterException {
170    	return NATTable.of(NativeTypeTags._TABLE_);
171    }
172	
173	public ATNumber base_length() { return NATNumber.atValue(elements_.length); }
174
175	public ATObject base_at(ATNumber index) throws InterpreterException {
176		return elements_[extractIndex(index)];
177	}
178
179	public ATObject base_atPut(ATNumber index, ATObject value) throws InterpreterException {
180		elements_[extractIndex(index)] = value;
181		return value;
182	}
183	
184	public ATBoolean base_isEmpty() {
185		return NATBoolean.atValue(elements_.length == 0);
186	}
187	
188	public ATNil base_each_(ATClosure clo) throws InterpreterException {
189		for (int i = 0; i < elements_.length; i++) {
190			clo.base_apply(atValue(new ATObject[] { elements_[i] }));
191		}
192		return Evaluator.getNil();
193	}
194
195	public ATTable base_map_(ATClosure clo) throws InterpreterException {
196		if (this == EMPTY) return EMPTY;
197		
198		ATObject[] result = new ATObject[elements_.length];
199		for (int i = 0; i < elements_.length; i++) {
200			result[i] = clo.base_apply(atValue(new ATObject[] { elements_[i] }));
201		}
202		return atValue(result);
203	}
204	
205	public ATObject base_inject_into_(ATObject init, ATClosure clo) throws InterpreterException {
206		ATObject total = init;
207		for (int i = 0; i < elements_.length; i++) {
208			total = clo.base_apply(atValue(new ATObject[] { total, elements_[i] }));
209		}
210		return total;
211	}
212	
213	public ATTable base_filter_(ATClosure clo) throws InterpreterException {
214		Vector matchingElements = new Vector(elements_.length);
215		for (int i = 0; i < elements_.length; i++) {
216			if (clo.base_apply(atValue(new ATObject[] { elements_[i] })).asNativeBoolean().javaValue) {
217				matchingElements.add(elements_[i]);
218			}
219		}
220		return atValue((ATObject[]) matchingElements.toArray(new ATObject[matchingElements.size()]));
221	}
222	
223	public ATObject base_find_(ATClosure clo) throws InterpreterException {
224		for (int i = 0; i < elements_.length; i++) {
225			if (clo.base_apply(atValue(new ATObject[] { elements_[i] })).asNativeBoolean().javaValue) {
226				return NATNumber.atValue(i+1);
227			}
228		}
229		return Evaluator.getNil();
230	}
231	
232	public ATBoolean base_contains(ATObject obj) throws InterpreterException {
233		for (int i = 0; i < elements_.length; i++) {
234			if (obj.base__opeql__opeql_(elements_[i]).asNativeBoolean().javaValue) {
235				return NATBoolean._TRUE_;
236			}
237		}
238		return NATBoolean._FALSE_;
239	}
240	
241	public ATText base_implode() throws InterpreterException {
242		StringBuffer buff = new StringBuffer("");
243		for (int i = 0; i < elements_.length; i++) {
244			buff.append(elements_[i].asNativeText().javaValue);
245		}
246		return NATText.atValue(buff.toString());
247	}
248
249	public ATText base_join(ATText sep) throws InterpreterException {
250		String separator = sep.asNativeText().javaValue;
251		StringBuffer buff = new StringBuffer("");
252		for (int i = 0; i < elements_.length-1; i++) {
253			buff.append(elements_[i].asNativeText().javaValue);
254			buff.append(separator);
255		}
256		if (elements_.length > 0)
257			buff.append(elements_[elements_.length-1].asNativeText().javaValue);
258		return NATText.atValue(buff.toString());
259	}
260	
261	/**
262	 * tab.select(start, stop) == els = [ ] ; start.to: stop do: { |i| els << tab[i] } ; els
263	 */
264	public ATTable base_select(ATNumber first, ATNumber last) throws InterpreterException {
265		final LinkedList selection = new LinkedList();
266		first.base_to_do_(last, new NativeClosure(this) {
267			public ATObject base_apply(ATTable args) throws InterpreterException {
268			    selection.add(base_at(args.base_at(NATNumber.ONE).asNumber()));
269			    return Evaluator.getNil();
270			}
271		});
272		return NATTable.atValue((ATObject[]) selection.toArray(new ATObject[selection.size()]));
273	}
274	
275	public ATTable base__oppls_(ATTable other) throws InterpreterException {
276		return NATTable.atValue(collate(elements_, other.asNativeTable().elements_));
277	}
278	
279	protected int extractIndex(ATNumber atIndex) throws InterpreterException {
280		int javaIndex = atIndex.asNativeNumber().javaValue - 1;
281		if ((javaIndex < 0) || (javaIndex >= elements_.length))
282			throw new XIndexOutOfBounds(javaIndex + 1, elements_.length);
283		else
284			return javaIndex;
285	}
286
287	/**
288	 * Auxiliary method to collate two Java arrays
289	 * @return an array containing first the elements of ary1, then the elements of ary2
290	 */
291	public static final ATObject[] collate(ATObject[] ary1, ATObject[] ary2) {
292	    int siz1 = ary1.length;
293	    int siz2 = ary2.length;
294	    ATObject[] union = new ATObject[siz1 + siz2];
295	    System.arraycopy(ary1, 0, union, 0, siz1);
296	    System.arraycopy(ary2, 0, union, siz1, siz2);
297	    return union;
298	}
299	
300	public ATObject meta_clone() throws InterpreterException {
301		ATObject[] clonedArray = new ATObject[elements_.length];
302		System.arraycopy(elements_, 0, clonedArray, 0, elements_.length);
303		return NATTable.atValue(clonedArray);
304	}
305	
306	public ATObject meta_resolve() throws InterpreterException {
307		if (elements_.length == 0)
308			return NATTable.EMPTY;
309		else
310			return this;
311	}
312	
313}