/interpreter/tags/reactive-pattern-matching/src/edu/vub/at/objects/natives/NATTable.java

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