/interpreter/tags/at2-build270707/src/edu/vub/at/objects/natives/NATTable.java

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