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

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