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