PageRenderTime 48ms CodeModel.GetById 28ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2dist091109/src/edu/vub/at/objects/natives/NATTable.java

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