/interpreter/tags/at2dist091109/src/edu/vub/at/objects/natives/NATTable.java

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