PageRenderTime 39ms CodeModel.GetById 18ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://ambienttalk.googlecode.com/
Java | 295 lines | 189 code | 38 blank | 68 comment | 32 complexity | 1d7e6069b0df0c2bc7a9d4af6da114fb 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.NativeStripes;
 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 tvc
 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] = NATNil._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 NATTable asNativeTable() { return this; }
109	
110	/**
111	 * To evaluate a table, evaluate all of its constituent expressions, taking
112	 * special care to take into account spliced expressions.
113	 * 
114	 * NATTAB(exps).eval(ctx) = NATTAB(map eval(ctx) over exps)
115	 * 
116	 * @return a table of evaluated arguments
117	 */
118	public ATObject meta_eval(ATContext ctx) throws InterpreterException {
119		if (this == EMPTY) return EMPTY;
120		
121		LinkedList result = new LinkedList();
122		int siz = elements_.length;
123		for (int i = 0; i < elements_.length; i++) {
124			if (elements_[i].isSplice()) {
125				ATObject[] tbl = elements_[i].asSplice().base_getExpression().meta_eval(ctx).asNativeTable().elements_;
126				for (int j = 0; j < tbl.length; j++) {
127					result.add(tbl[j]);
128				}
129				siz += (tbl.length - 1); // -1 because we replace one element by a table of elements
130			} else {
131				result.add(elements_[i].meta_eval(ctx));
132			}
133		}
134		return atValue((ATObject[]) result.toArray(new ATObject[siz]));
135	}
136	
137	/**
138	 * To quote a table, quote all elements of the table.
139	 * Special care needs to be taken in order to properly deal with unquote-spliced elements.
140	 * When one of the direct elements of the table is an unquote-splice element, the resulting
141	 * unquotation must result in a table whose elements are directly added to this table's elements.
142	 */
143	public ATObject meta_quote(ATContext ctx) throws InterpreterException {
144		if (this == EMPTY) return EMPTY;
145		
146		LinkedList result = new LinkedList();
147		int siz = elements_.length;
148		for (int i = 0; i < elements_.length; i++) {
149			if (elements_[i].isUnquoteSplice()) {
150				ATObject[] tbl = elements_[i].asUnquoteSplice().base_getExpression().meta_eval(ctx).asNativeTable().elements_;
151				for (int j = 0; j < tbl.length; j++) {
152					result.add(tbl[j]);
153				}
154				siz += (tbl.length - 1); // -1 because we replace one element by a table of elements
155			} else {
156				result.add(elements_[i].meta_quote(ctx));
157			}
158		}
159		return atValue((ATObject[]) result.toArray(new ATObject[siz]));
160	}
161	
162	public NATText meta_print() throws InterpreterException {
163		return Evaluator.printElements(this, "[", ", ","]");
164	}
165	
166    public ATTable meta_getStripes() throws InterpreterException {
167    	return NATTable.of(NativeStripes._TABLE_);
168    }
169	
170	public ATNumber base_getLength() { return NATNumber.atValue(elements_.length); }
171
172	public ATObject base_at(ATNumber index) throws InterpreterException {
173		return elements_[extractIndex(index)];
174	}
175
176	public ATObject base_atPut(ATNumber index, ATObject value) throws InterpreterException {
177		elements_[extractIndex(index)] = value;
178		return value;
179	}
180	
181	public ATBoolean base_isEmpty() {
182		return NATBoolean.atValue(elements_.length == 0);
183	}
184	
185	public ATNil base_each_(ATClosure clo) throws InterpreterException {
186		for (int i = 0; i < elements_.length; i++) {
187			clo.base_apply(atValue(new ATObject[] { elements_[i] }));
188		}
189		return NATNil._INSTANCE_;
190	}
191
192	public ATTable base_map_(ATClosure clo) throws InterpreterException {
193		if (this == EMPTY) return EMPTY;
194		
195		ATObject[] result = new ATObject[elements_.length];
196		for (int i = 0; i < elements_.length; i++) {
197			result[i] = clo.base_apply(atValue(new ATObject[] { elements_[i] }));
198		}
199		return atValue(result);
200	}
201	
202	public ATObject base_with_collect_(ATObject init, ATClosure clo) throws InterpreterException {
203		ATObject total = init;
204		for (int i = 0; i < elements_.length; i++) {
205			total = clo.base_apply(atValue(new ATObject[] { total, elements_[i] }));
206		}
207		return total;
208	}
209	
210	public ATTable base_filter_(ATClosure clo) throws InterpreterException {
211		Vector matchingElements = new Vector(elements_.length);
212		for (int i = 0; i < elements_.length; i++) {
213			if (clo.base_apply(atValue(new ATObject[] { elements_[i] })).asNativeBoolean().javaValue) {
214				matchingElements.add(elements_[i]);
215			}
216		}
217		return atValue((ATObject[]) matchingElements.toArray(new ATObject[matchingElements.size()]));
218	}
219	
220	public ATObject base_find_(ATClosure clo) throws InterpreterException {
221		for (int i = 0; i < elements_.length; i++) {
222			if (clo.base_apply(atValue(new ATObject[] { elements_[i] })).asNativeBoolean().javaValue) {
223				return NATNumber.atValue(i+1);
224			}
225		}
226		return NATNil._INSTANCE_;
227	}
228	
229	public ATText base_implode() throws InterpreterException {
230		StringBuffer buff = new StringBuffer("");
231		for (int i = 0; i < elements_.length; i++) {
232			buff.append(elements_[i].asNativeText().javaValue);
233		}
234		return NATText.atValue(buff.toString());
235	}
236
237	public ATText base_join(ATText sep) throws InterpreterException {
238		String separator = sep.asNativeText().javaValue;
239		StringBuffer buff = new StringBuffer("");
240		for (int i = 0; i < elements_.length-1; i++) {
241			buff.append(elements_[i].asNativeText().javaValue);
242			buff.append(separator);
243		}
244		if (elements_.length > 0)
245			buff.append(elements_[elements_.length-1].asNativeText().javaValue);
246		return NATText.atValue(buff.toString());
247	}
248	
249	/**
250	 * tab.select(start, stop) == els = [ ] ; start.to: stop do: { |i| els << tab[i] } ; els
251	 */
252	public ATTable base_select(ATNumber first, ATNumber last) throws InterpreterException {
253		final LinkedList selection = new LinkedList();
254		first.base_to_do_(last, new NativeClosure(this) {
255			public ATObject base_apply(ATTable args) throws InterpreterException {
256			    selection.add(base_at(args.base_at(NATNumber.ONE).asNumber()));
257			    return NATNil._INSTANCE_;
258			}
259		});
260		return NATTable.atValue((ATObject[]) selection.toArray(new ATObject[selection.size()]));
261	}
262	
263	public ATTable base__oppls_(ATTable other) throws InterpreterException {
264		return NATTable.atValue(collate(elements_, other.asNativeTable().elements_));
265	}
266	
267	protected int extractIndex(ATNumber atIndex) throws InterpreterException {
268		int javaIndex = atIndex.asNativeNumber().javaValue - 1;
269		if ((javaIndex < 0) || (javaIndex >= elements_.length))
270			throw new XIndexOutOfBounds(javaIndex + 1, elements_.length);
271		else
272			return javaIndex;
273	}
274
275	/**
276	 * Auxiliary method to collate two Java arrays
277	 * @return an array containing first the elements of ary1, then the elements of ary2
278	 */
279	public static final ATObject[] collate(ATObject[] ary1, ATObject[] ary2) {
280	    int siz1 = ary1.length;
281	    int siz2 = ary2.length;
282	    ATObject[] union = new ATObject[siz1 + siz2];
283	    System.arraycopy(ary1, 0, union, 0, siz1);
284	    System.arraycopy(ary2, 0, union, siz1, siz2);
285	    return union;
286	}
287	
288	public ATObject meta_resolve() throws InterpreterException {
289		if (elements_.length == 0)
290			return NATTable.EMPTY;
291		else
292			return this;
293	}
294	
295}