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