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