/interpreter/tags/at2-build190607/src/edu/vub/at/objects/natives/NATCallframe.java

http://ambienttalk.googlecode.com/ · Java · 436 lines · 224 code · 50 blank · 162 comment · 49 complexity · 35d697560f7c4fba24d0ddd758da5d03 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.exceptions.InterpreterException;
  30. import edu.vub.at.exceptions.XDuplicateSlot;
  31. import edu.vub.at.exceptions.XIllegalOperation;
  32. import edu.vub.at.exceptions.XSelectorNotFound;
  33. import edu.vub.at.exceptions.XUndefinedSlot;
  34. import edu.vub.at.objects.ATBoolean;
  35. import edu.vub.at.objects.ATField;
  36. import edu.vub.at.objects.ATMethod;
  37. import edu.vub.at.objects.ATNil;
  38. import edu.vub.at.objects.ATObject;
  39. import edu.vub.at.objects.ATTable;
  40. import edu.vub.at.objects.grammar.ATSymbol;
  41. import java.util.Iterator;
  42. import java.util.LinkedList;
  43. import java.util.Vector;
  44. /**
  45. * NATCallframe is a native implementation of a callframe. A callframe differs from
  46. * an ordinary object in the following regards:
  47. * - it has no dynamic parent
  48. * - it treats method definition as the addition of a closure to its variables.
  49. * - it cannot be extended nor cloned
  50. *
  51. * Callframes can be regarded as 'field-only' objects. Fields are implemented as follows:
  52. * - native fields are implemented efficiently using a 'map': the map datastructure maps
  53. * selectors to indices into a state vector, such that field names can be shared efficiently
  54. * across clones.
  55. * - custom fields are collected in a linked list. Their lookup and assignment is slower,
  56. * and when an object is cloned, the custom field objects are re-instantiated.
  57. * The new clone is passed as the sole argument to 'new'.
  58. *
  59. * @author tvcutsem
  60. * @author smostinc
  61. */
  62. public class NATCallframe extends NATByRef implements ATObject {
  63. protected FieldMap variableMap_;
  64. protected final Vector stateVector_;
  65. /**
  66. * The lexical parent 'scope' of this call frame/object.
  67. * A lexical scope should never travel along with an object when it is serialized,
  68. * hence it is declared transient. Serializable isolate objects will have to reset
  69. * this field upon deserialization.
  70. */
  71. protected transient ATObject lexicalParent_;
  72. protected LinkedList customFields_;
  73. public NATCallframe(ATObject lexicalParent) {
  74. variableMap_ = new FieldMap();
  75. stateVector_ = new Vector();
  76. lexicalParent_ = lexicalParent;
  77. customFields_ = null;
  78. }
  79. /**
  80. * Used internally for cloning a callframe/object.
  81. */
  82. protected NATCallframe(FieldMap varMap, Vector stateVector, ATObject lexicalParent, LinkedList customFields) {
  83. variableMap_ = varMap;
  84. stateVector_ = stateVector;
  85. lexicalParent_ = lexicalParent;
  86. customFields_ = customFields;
  87. }
  88. /* ------------------------------
  89. * -- Message Sending Protocol --
  90. * ------------------------------ */
  91. /**
  92. * Normally, call frames are not used in receiverful method invocation expressions.
  93. * That is, normally, the content of call frames is accessed via the meta_lookup operation.
  94. *
  95. * A meta_invoke operation on call frames is much more ad hoc than on real objects.
  96. * A call frame responds to an invocation by looking up the selector in its own fields (without delegating!)
  97. * and by applying the closure bound to that field.
  98. *
  99. * The 'receiver' argument should always equal 'this' because call frames do not delegate!
  100. */
  101. public ATObject meta_invoke(ATObject receiver, ATSymbol selector, ATTable arguments) throws InterpreterException {
  102. // assert(this == receiver)
  103. return this.getLocalField(selector).asClosure().base_apply(arguments);
  104. }
  105. /**
  106. * respondsTo is a mechanism to ask any object o whether it would respond to the
  107. * selection o.selector. A call frame implements respondsTo by checking whether
  108. * it contains a public field corresponding to the selector.
  109. *
  110. * A call frame does not delegate to other objects to check
  111. * whether it can respond to a certain selector.
  112. */
  113. public ATBoolean meta_respondsTo(ATSymbol selector) throws InterpreterException {
  114. return NATBoolean.atValue(this.hasLocalField(selector));
  115. }
  116. /**
  117. * By default, when a selection is not understood by an AmbientTalk object or call frame, an error is raised.
  118. *
  119. * Warning: this method overrides its parent method which has the exact same implementation.
  120. * This is done for purposes of clarity, by making NATCallframe implement all ATObject methods directly,
  121. * even if NATNil already provides a suitable implementation for these.
  122. */
  123. public ATObject meta_doesNotUnderstand(ATSymbol selector) throws InterpreterException {
  124. throw new XSelectorNotFound(selector, this);
  125. }
  126. /* ------------------------------------------
  127. * -- Slot accessing and mutating protocol --
  128. * ------------------------------------------ */
  129. /**
  130. * This method is used in the evaluation of the code <tt>o.m</tt>.
  131. * When o is a call frame, the call frame is searched for a field 'm'.
  132. * If it is not found, a call frame does not delegate to any dynamic parent, and yields an error.
  133. */
  134. public ATObject meta_select(ATObject receiver, ATSymbol selector) throws InterpreterException {
  135. if (this.hasLocalField(selector)) {
  136. return this.getLocalField(selector);
  137. } else {
  138. throw new XSelectorNotFound(selector, this);
  139. }
  140. }
  141. /**
  142. * This method is used to evaluate code of the form <tt>selector</tt> within the scope
  143. * of this call frame. A call frame resolves such a lookup request by checking whether
  144. * a field corresponding to the selector exists locally. If it does, the result is
  145. * returned. If it does not, the search continues recursively in the call frame's
  146. * lexical parent.
  147. */
  148. public ATObject meta_lookup(ATSymbol selector) throws InterpreterException {
  149. if (this.hasLocalField(selector)) {
  150. return this.getLocalField(selector);
  151. } else {
  152. return lexicalParent_.meta_lookup(selector);
  153. }
  154. }
  155. /**
  156. * A field can be added to either a call frame or an object.
  157. * In both cases, it is checked whether the field does not already exist.
  158. * If it does not, a new field is created and its value set to the given initial value.
  159. * @throws InterpreterException
  160. */
  161. public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException {
  162. if (this.hasLocalField(name)) {
  163. // field already exists...
  164. throw new XDuplicateSlot(name);
  165. } else {
  166. boolean fieldAdded = variableMap_.put(name);
  167. if (!fieldAdded) {
  168. throw new RuntimeException("Assertion failed: field not added to map while not duplicate");
  169. }
  170. // field now defined, add its value to the state vector
  171. stateVector_.add(value);
  172. }
  173. return NATNil._INSTANCE_;
  174. }
  175. /**
  176. * A field can be assigned in either a call frame or an object.
  177. * In both cases, if the field exists locally, it is set to the new value.
  178. * If it does not exist locally, the assignment is performed on the lexical parent.
  179. */
  180. public ATNil meta_assignVariable(ATSymbol name, ATObject value) throws InterpreterException {
  181. if (this.setLocalField(name, value)) {
  182. // field found and set locally
  183. return NATNil._INSTANCE_;
  184. } else {
  185. // The lexical parent chain is followed for assignments. This implies
  186. // that assignments on dynamic parents are disallowed.
  187. return lexicalParent_.meta_assignVariable(name, value);
  188. }
  189. }
  190. /**
  191. * Assigning a call frame's field externally is possible and is treated
  192. * as if it were a variable assignment. Hence, if <tt>o</tt> is a call frame,
  193. * then <tt>o.m := x</tt> follows the same evaluation semantics as those of
  194. * <tt>m := x</tt> when performed in the scope of <tt>o</tt>.
  195. */
  196. public ATNil meta_assignField(ATObject receiver, ATSymbol name, ATObject value) throws InterpreterException {
  197. return this.meta_assignVariable(name, value);
  198. }
  199. /* ------------------------------------
  200. * -- Extension and cloning protocol --
  201. * ------------------------------------ */
  202. public ATObject meta_clone() throws InterpreterException {
  203. throw new XIllegalOperation("Cannot clone a call frame, clone its owning object instead.");
  204. }
  205. public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
  206. throw new XIllegalOperation("Cannot create a new instance of a call frame, new its owning object instead.");
  207. }
  208. /* ---------------------------------
  209. * -- Structural Access Protocol --
  210. * --------------------------------- */
  211. public ATNil meta_addField(ATField field) throws InterpreterException {
  212. // when adding a native field, revert to the more optimized implementation using the map
  213. if (field.isNativeField()) {
  214. return this.meta_defineField(field.base_getName(), field.base_readField());
  215. }
  216. ATSymbol name = field.base_getName();
  217. if (this.hasLocalField(name)) {
  218. // field already exists...
  219. throw new XDuplicateSlot(name);
  220. } else {
  221. // add a clone of the field initialized with its new host
  222. field = field.base_new(new ATObject[] { this }).asField();
  223. // add the field to the list of custom fields, which is created lazily
  224. if (customFields_ == null) {
  225. customFields_ = new LinkedList();
  226. }
  227. // append the custom field object
  228. customFields_.add(field);
  229. }
  230. return NATNil._INSTANCE_;
  231. }
  232. public ATNil meta_addMethod(ATMethod method) throws InterpreterException {
  233. throw new XIllegalOperation("Cannot add method "+
  234. method.base_getName().base_getText().asNativeText().javaValue +
  235. " to a call frame. Add it as a closure field instead.");
  236. }
  237. public ATField meta_grabField(ATSymbol selector) throws InterpreterException {
  238. if (this.hasLocalNativeField(selector)) {
  239. return new NATField(selector, this);
  240. } else {
  241. ATField fld = this.getLocalCustomField(selector);
  242. if (fld != null) {
  243. return fld;
  244. } else {
  245. throw new XUndefinedSlot("field grabbed", selector.toString());
  246. }
  247. }
  248. }
  249. public ATMethod meta_grabMethod(ATSymbol selector) throws InterpreterException {
  250. throw new XSelectorNotFound(selector, this);
  251. }
  252. public ATTable meta_listFields() throws InterpreterException {
  253. ATObject[] nativeFields = new ATObject[stateVector_.size()];
  254. ATSymbol[] fieldNames = variableMap_.listFields();
  255. // native fields first
  256. for (int i = 0; i < fieldNames.length; i++) {
  257. nativeFields[i] = new NATField(fieldNames[i], this);
  258. }
  259. if (customFields_ == null) {
  260. // no custom fields
  261. return NATTable.atValue(nativeFields);
  262. } else {
  263. ATObject[] customFields = (ATObject[]) customFields_.toArray(new ATObject[customFields_.size()]);
  264. return NATTable.atValue(NATTable.collate(nativeFields, customFields));
  265. }
  266. }
  267. public ATTable meta_listMethods() throws InterpreterException {
  268. return NATTable.EMPTY;
  269. }
  270. public NATText meta_print() throws InterpreterException {
  271. return NATText.atValue("<callframe>");
  272. }
  273. /* ---------------------
  274. * -- Mirror Fields --
  275. * --------------------- */
  276. /**
  277. * Auxiliary method to dynamically select the 'super' field from this object.
  278. * Note that this method is part of the base-level interface to an object.
  279. *
  280. * Also note that this method performs the behaviour equivalent to evaluating
  281. * 'super' and not 'self.super', which could lead to infinite loops.
  282. */
  283. public ATObject base_getSuper() throws InterpreterException {
  284. return this.meta_lookup(NATObject._SUPER_NAME_);
  285. };
  286. public ATObject meta_getLexicalParent() throws InterpreterException {
  287. return lexicalParent_;
  288. }
  289. /* --------------------------
  290. * -- Conversion Protocol --
  291. * -------------------------- */
  292. public boolean isCallFrame() {
  293. return true;
  294. }
  295. public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException {
  296. if( (original instanceof NATCallframe) &
  297. ! (original instanceof NATObject)) {
  298. FieldMap originalVariables = ((NATCallframe)original).variableMap_;
  299. return NATBoolean.atValue(
  300. variableMap_.isDerivedFrom(originalVariables));
  301. } else {
  302. return NATBoolean._FALSE_;
  303. }
  304. }
  305. public ATBoolean meta_isRelatedTo(ATObject object) throws InterpreterException {
  306. return super.meta_isRelatedTo(object);
  307. }
  308. /* -----------------------------
  309. * -- Object Passing protocol --
  310. * ----------------------------- */
  311. // protected methods, only to be used by NATCallframe and NATObject
  312. protected boolean hasLocalField(ATSymbol selector) throws InterpreterException {
  313. return hasLocalNativeField(selector) || hasLocalCustomField(selector);
  314. }
  315. protected boolean hasLocalNativeField(ATSymbol selector) {
  316. return variableMap_.get(selector) != -1;
  317. }
  318. protected boolean hasLocalCustomField(ATSymbol selector) throws InterpreterException {
  319. if (customFields_ == null) {
  320. return false;
  321. } else {
  322. Iterator it = customFields_.iterator();
  323. while (it.hasNext()) {
  324. ATField field = (ATField) it.next();
  325. if (field.base_getName().equals(selector)) {
  326. return true;
  327. }
  328. }
  329. return false;
  330. }
  331. }
  332. /**
  333. * Reads out the value of either a native or a custom field.
  334. * @throws XSelectorNotFound if no native or custom field with the given name exists locally.
  335. */
  336. protected ATObject getLocalField(ATSymbol selector) throws InterpreterException {
  337. int index = variableMap_.get(selector);
  338. if(index != -1) {
  339. return (ATObject) (stateVector_.get(index));
  340. } else {
  341. ATField fld = getLocalCustomField(selector);
  342. if (fld != null) {
  343. return fld.base_readField();
  344. } else {
  345. throw new XSelectorNotFound(selector, this);
  346. }
  347. }
  348. }
  349. /**
  350. * @return a custom field matching the given selector or null if such a field does not exist
  351. */
  352. protected ATField getLocalCustomField(ATSymbol selector) throws InterpreterException {
  353. if (customFields_ == null) {
  354. return null;
  355. } else {
  356. Iterator it = customFields_.iterator();
  357. while (it.hasNext()) {
  358. ATField field = (ATField) it.next();
  359. if (field.base_getName().equals(selector)) {
  360. return field;
  361. }
  362. }
  363. return null;
  364. }
  365. }
  366. /**
  367. * Set a given field if it exists.
  368. * @return whether the field existed (and the assignment has been performed)
  369. */
  370. protected boolean setLocalField(ATSymbol selector, ATObject value) throws InterpreterException {
  371. int index = variableMap_.get(selector);
  372. if(index != -1) {
  373. // field exists, modify the state vector
  374. stateVector_.set(index, value);
  375. return true;
  376. } else {
  377. ATField fld = getLocalCustomField(selector);
  378. if (fld != null) {
  379. fld.base_writeField(value);
  380. return true;
  381. } else {
  382. return false;
  383. }
  384. }
  385. }
  386. }