/interpreter/tags/at_build150307/src/edu/vub/at/objects/natives/NATTable.java
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}