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