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

http://ambienttalk.googlecode.com/ · Java · 386 lines · 216 code · 45 blank · 125 comment · 50 complexity · 84696fe2f9d3f509fc90106e2389266d MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * NATCallframe.java created on Jul 28, 2006 at 11:26:17 AM
  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.XDuplicateSlot;
  32. import edu.vub.at.exceptions.XIllegalOperation;
  33. import edu.vub.at.exceptions.XSelectorNotFound;
  34. import edu.vub.at.exceptions.XUndefinedSlot;
  35. import edu.vub.at.objects.ATBoolean;
  36. import edu.vub.at.objects.ATField;
  37. import edu.vub.at.objects.ATMethod;
  38. import edu.vub.at.objects.ATNil;
  39. import edu.vub.at.objects.ATObject;
  40. import edu.vub.at.objects.ATTable;
  41. import edu.vub.at.objects.grammar.ATSymbol;
  42. import edu.vub.at.objects.mirrors.NativeClosure;
  43. import java.util.Iterator;
  44. import java.util.LinkedList;
  45. import java.util.Vector;
  46. /**
  47. * NATCallframe is a native implementation of a callframe. A callframe differs from
  48. * an ordinary object in the following regards:
  49. * - it has no dynamic parent
  50. * - it treats method definition as the addition of a closure to its variables.
  51. * - it cannot be extended nor cloned
  52. *
  53. * Callframes can be regarded as 'field-only' objects. Fields are implemented as follows:
  54. * - native fields are implemented efficiently using a 'map': the map datastructure maps
  55. * selectors to indices into a state vector, such that field names can be shared efficiently
  56. * across clones.
  57. * - custom fields are collected in a linked list. Their lookup and assignment is slower,
  58. * and when an object is cloned, the custom field objects are re-instantiated.
  59. * The new clone is passed as the sole argument to 'new'.
  60. *
  61. * @author tvcutsem
  62. * @author smostinc
  63. */
  64. public class NATCallframe extends NATByRef implements ATObject {
  65. protected FieldMap variableMap_;
  66. protected final Vector stateVector_;
  67. /**
  68. * The lexical parent 'scope' of this call frame/object.
  69. */
  70. protected ATObject lexicalParent_;
  71. protected LinkedList customFields_;
  72. /**
  73. * Default constructor: creates a new call frame with a given scope pointer.
  74. */
  75. public NATCallframe(ATObject lexicalParent) {
  76. variableMap_ = new FieldMap();
  77. stateVector_ = new Vector();
  78. lexicalParent_ = lexicalParent;
  79. customFields_ = null;
  80. }
  81. /**
  82. * Used internally for cloning a callframe/object.
  83. */
  84. protected NATCallframe(FieldMap varMap, Vector stateVector, ATObject lexicalParent, LinkedList customFields) {
  85. variableMap_ = varMap;
  86. stateVector_ = stateVector;
  87. lexicalParent_ = lexicalParent;
  88. customFields_ = customFields;
  89. }
  90. /* ------------------------------------------
  91. * -- Slot accessing and mutating protocol --
  92. * ------------------------------------------ */
  93. /**
  94. * A field can be added to either a call frame or an object.
  95. * In both cases, it is checked whether the field does not already exist.
  96. * If it does not, a new field is created and its value set to the given initial value.
  97. * @throws InterpreterException
  98. */
  99. public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException {
  100. if (this.hasLocalField(name) || this.hasLocalMethod(name)) {
  101. // field already exists...
  102. throw new XDuplicateSlot(name);
  103. } else {
  104. boolean fieldAdded = variableMap_.put(name);
  105. if (!fieldAdded) {
  106. throw new RuntimeException("Assertion failed: field not added to map while not duplicate");
  107. }
  108. // field now defined, add its value to the state vector
  109. stateVector_.add(value);
  110. }
  111. return Evaluator.getNil();
  112. }
  113. /* ------------------------------------
  114. * -- Extension and cloning protocol --
  115. * ------------------------------------ */
  116. public ATObject meta_clone() throws InterpreterException {
  117. throw new XIllegalOperation("Cannot clone a call frame, clone its owning object instead.");
  118. }
  119. public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
  120. throw new XIllegalOperation("Cannot create a new instance of a call frame, new its owning object instead.");
  121. }
  122. /* ---------------------------------
  123. * -- Structural Access Protocol --
  124. * --------------------------------- */
  125. public ATNil meta_addField(ATField field) throws InterpreterException {
  126. // when adding a native field, revert to the more optimized implementation using the map
  127. if (field.isNativeField()) {
  128. return this.meta_defineField(field.base_name(), field.base_readField());
  129. }
  130. ATSymbol name = field.base_name();
  131. if (this.hasLocalField(name)) {
  132. // field already exists...
  133. throw new XDuplicateSlot(name);
  134. } else {
  135. // add a clone of the field initialized with its new host
  136. field = field.meta_newInstance(NATTable.of(this)).asField();
  137. // add the field to the list of custom fields, which is created lazily
  138. if (customFields_ == null) {
  139. customFields_ = new LinkedList();
  140. }
  141. // append the custom field object
  142. customFields_.add(field);
  143. }
  144. return Evaluator.getNil();
  145. }
  146. public ATNil meta_addMethod(ATMethod method) throws InterpreterException {
  147. throw new XIllegalOperation("Cannot add method "+
  148. method.base_name().base_text().asNativeText().javaValue +
  149. " to a call frame. Add it as a closure field instead.");
  150. }
  151. public ATField meta_grabField(ATSymbol selector) throws InterpreterException {
  152. if (this.hasLocalNativeField(selector)) {
  153. return new NATField(selector, this);
  154. } else {
  155. ATField fld = this.getLocalCustomField(selector);
  156. if (fld != null) {
  157. return fld;
  158. } else {
  159. throw new XUndefinedSlot("field grabbed", selector.toString());
  160. }
  161. }
  162. }
  163. public ATMethod meta_grabMethod(ATSymbol selector) throws InterpreterException {
  164. throw new XSelectorNotFound(selector, this);
  165. }
  166. public ATObject meta_removeSlot(ATSymbol selector) throws InterpreterException {
  167. return this.removeLocalField(selector);
  168. }
  169. public ATTable meta_listFields() throws InterpreterException {
  170. ATObject[] nativeFields = new ATObject[stateVector_.size()];
  171. ATSymbol[] fieldNames = variableMap_.listFields();
  172. // native fields first
  173. for (int i = 0; i < fieldNames.length; i++) {
  174. nativeFields[i] = new NATField(fieldNames[i], this);
  175. }
  176. if (customFields_ == null) {
  177. // no custom fields
  178. return NATTable.atValue(nativeFields);
  179. } else {
  180. ATObject[] customFields = (ATObject[]) customFields_.toArray(new ATObject[customFields_.size()]);
  181. return NATTable.atValue(NATTable.collate(nativeFields, customFields));
  182. }
  183. }
  184. public ATTable meta_listMethods() throws InterpreterException {
  185. return NATTable.EMPTY;
  186. }
  187. public NATText meta_print() throws InterpreterException {
  188. return NATText.atValue("<callframe>");
  189. }
  190. /* ---------------------
  191. * -- Mirror Fields --
  192. * --------------------- */
  193. /**
  194. * Auxiliary method to dynamically select the 'super' field from this object.
  195. * Note that this method is part of the base-level interface to an object.
  196. *
  197. * Also note that this method performs the behaviour equivalent to evaluating
  198. * 'super' and not 'self.super', which could lead to infinite loops.
  199. */
  200. public ATObject base_super() throws InterpreterException {
  201. return this.impl_call(NATObject._SUPER_NAME_, NATTable.EMPTY);
  202. };
  203. public ATObject impl_lexicalParent() throws InterpreterException {
  204. return lexicalParent_;
  205. }
  206. /* --------------------------
  207. * -- Conversion Protocol --
  208. * -------------------------- */
  209. public boolean isCallFrame() {
  210. return true;
  211. }
  212. public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException {
  213. if( (original instanceof NATCallframe) &
  214. ! (original instanceof NATObject)) {
  215. FieldMap originalVariables = ((NATCallframe)original).variableMap_;
  216. return NATBoolean.atValue(
  217. variableMap_.isDerivedFrom(originalVariables));
  218. } else {
  219. return NATBoolean._FALSE_;
  220. }
  221. }
  222. public ATBoolean meta_isRelatedTo(ATObject object) throws InterpreterException {
  223. return super.meta_isRelatedTo(object);
  224. }
  225. /* -----------------------------
  226. * -- Object Passing protocol --
  227. * ----------------------------- */
  228. // protected methods, only to be used by NATCallframe and NATObject
  229. protected boolean hasLocalField(ATSymbol selector) throws InterpreterException {
  230. return hasLocalNativeField(selector) || hasLocalCustomField(selector);
  231. }
  232. protected boolean hasLocalNativeField(ATSymbol selector) {
  233. return variableMap_.get(selector) != -1;
  234. }
  235. protected boolean hasLocalCustomField(ATSymbol selector) throws InterpreterException {
  236. if (customFields_ == null) {
  237. return false;
  238. } else {
  239. Iterator it = customFields_.iterator();
  240. while (it.hasNext()) {
  241. ATField field = (ATField) it.next();
  242. if (field.base_name().equals(selector)) {
  243. return true;
  244. }
  245. }
  246. return false;
  247. }
  248. }
  249. /**
  250. * Reads out the value of either a native or a custom field.
  251. * @throws XSelectorNotFound if no native or custom field with the given name exists locally.
  252. */
  253. protected ATObject getLocalField(ATSymbol selector) throws InterpreterException {
  254. int index = variableMap_.get(selector);
  255. if(index != -1) {
  256. return (ATObject) (stateVector_.get(index));
  257. } else {
  258. ATField fld = getLocalCustomField(selector);
  259. if (fld != null) {
  260. return fld.base_readField();
  261. } else {
  262. throw new XSelectorNotFound(selector, this);
  263. }
  264. }
  265. }
  266. /**
  267. * @return a custom field matching the given selector or null if such a field does not exist
  268. */
  269. protected ATField getLocalCustomField(ATSymbol selector) throws InterpreterException {
  270. if (customFields_ == null) {
  271. return null;
  272. } else {
  273. Iterator it = customFields_.iterator();
  274. while (it.hasNext()) {
  275. ATField field = (ATField) it.next();
  276. if (field.base_name().equals(selector)) {
  277. return field;
  278. }
  279. }
  280. return null;
  281. }
  282. }
  283. /**
  284. * Set a given field if it exists.
  285. */
  286. protected void setLocalField(ATSymbol selector, ATObject value) throws InterpreterException {
  287. int index = variableMap_.get(selector);
  288. if(index != -1) {
  289. // field exists, modify the state vector
  290. stateVector_.set(index, value);
  291. // ok
  292. } else {
  293. ATField fld = getLocalCustomField(selector);
  294. if (fld != null) {
  295. fld.base_writeField(value);
  296. // ok
  297. } else {
  298. // fail
  299. throw new XSelectorNotFound(selector, this);
  300. }
  301. }
  302. }
  303. /**
  304. * Remove a given field if it exists.
  305. * @param selector the field to be removed
  306. * @return the value to which the field was bound
  307. * @throws XSelectorNotFound if the field could not be found
  308. */
  309. protected ATObject removeLocalField(ATSymbol selector) throws InterpreterException {
  310. int index = variableMap_.remove(selector);
  311. if (index != -1) {
  312. // field exists, remove from state vector as well
  313. ATObject val = (ATObject) stateVector_.get(index);
  314. stateVector_.removeElementAt(index);
  315. // ok
  316. return val;
  317. } else {
  318. ATField fld = getLocalCustomField(selector);
  319. if (fld != null) {
  320. customFields_.remove(fld);
  321. // ok
  322. return fld.base_readField();
  323. } else {
  324. // fail
  325. throw new XSelectorNotFound(selector, this);
  326. }
  327. }
  328. }
  329. /**
  330. * A call frame has no methods.
  331. */
  332. protected boolean hasLocalMethod(ATSymbol atSelector) throws InterpreterException {
  333. return false;
  334. }
  335. /**
  336. * A call frame has no methods.
  337. */
  338. protected ATMethod getLocalMethod(ATSymbol selector) throws InterpreterException {
  339. throw new XSelectorNotFound(selector, this);
  340. }
  341. }