/interpreter/tags/at2dist170907/src/edu/vub/at/objects/natives/NATCallframe.java
Java | 356 lines | 195 code | 43 blank | 118 comment | 43 complexity | 31455611c32f7be5d6f102f82808ce76 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.XUndefinedSlot; 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 /** 81 * Default constructor: creates a new call frame with a given scope pointer. 82 */ 83 public NATCallframe(ATObject lexicalParent) { 84 variableMap_ = new FieldMap(); 85 stateVector_ = new Vector(); 86 lexicalParent_ = lexicalParent; 87 customFields_ = null; 88 } 89 90 /** 91 * Used internally for cloning a callframe/object. 92 */ 93 protected NATCallframe(FieldMap varMap, Vector stateVector, ATObject lexicalParent, LinkedList customFields) { 94 variableMap_ = varMap; 95 stateVector_ = stateVector; 96 lexicalParent_ = lexicalParent; 97 customFields_ = customFields; 98 } 99 100 /* ------------------------------------------ 101 * -- Slot accessing and mutating protocol -- 102 * ------------------------------------------ */ 103 104 /** 105 * A field can be added to either a call frame or an object. 106 * In both cases, it is checked whether the field does not already exist. 107 * If it does not, a new field is created and its value set to the given initial value. 108 * @throws InterpreterException 109 */ 110 public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException { 111 if (this.hasLocalField(name)) { 112 // field already exists... 113 throw new XDuplicateSlot(name); 114 } else { 115 boolean fieldAdded = variableMap_.put(name); 116 if (!fieldAdded) { 117 throw new RuntimeException("Assertion failed: field not added to map while not duplicate"); 118 } 119 // field now defined, add its value to the state vector 120 stateVector_.add(value); 121 } 122 return OBJNil._INSTANCE_; 123 } 124 125 /* ------------------------------------ 126 * -- Extension and cloning protocol -- 127 * ------------------------------------ */ 128 129 public ATObject meta_clone() throws InterpreterException { 130 throw new XIllegalOperation("Cannot clone a call frame, clone its owning object instead."); 131 } 132 133 public ATObject meta_newInstance(ATTable initargs) throws InterpreterException { 134 throw new XIllegalOperation("Cannot create a new instance of a call frame, new its owning object instead."); 135 } 136 137 /* --------------------------------- 138 * -- Structural Access Protocol -- 139 * --------------------------------- */ 140 141 public ATNil meta_addField(ATField field) throws InterpreterException { 142 // when adding a native field, revert to the more optimized implementation using the map 143 if (field.isNativeField()) { 144 return this.meta_defineField(field.base_name(), field.base_readField()); 145 } 146 147 ATSymbol name = field.base_name(); 148 if (this.hasLocalField(name)) { 149 // field already exists... 150 throw new XDuplicateSlot(name); 151 } else { 152 // add a clone of the field initialized with its new host 153 field = field.base_new(new ATObject[] { this }).asField(); 154 155 // add the field to the list of custom fields, which is created lazily 156 if (customFields_ == null) { 157 customFields_ = new LinkedList(); 158 } 159 // append the custom field object 160 customFields_.add(field); 161 } 162 return OBJNil._INSTANCE_; 163 } 164 165 public ATNil meta_addMethod(ATMethod method) throws InterpreterException { 166 throw new XIllegalOperation("Cannot add method "+ 167 method.base_name().base_text().asNativeText().javaValue + 168 " to a call frame. Add it as a closure field instead."); 169 } 170 171 public ATField meta_grabField(ATSymbol selector) throws InterpreterException { 172 if (this.hasLocalNativeField(selector)) { 173 return new NATField(selector, this); 174 } else { 175 ATField fld = this.getLocalCustomField(selector); 176 if (fld != null) { 177 return fld; 178 } else { 179 throw new XUndefinedSlot("field grabbed", selector.toString()); 180 } 181 } 182 } 183 184 public ATMethod meta_grabMethod(ATSymbol selector) throws InterpreterException { 185 throw new XSelectorNotFound(selector, this); 186 } 187 188 public ATTable meta_listFields() throws InterpreterException { 189 ATObject[] nativeFields = new ATObject[stateVector_.size()]; 190 ATSymbol[] fieldNames = variableMap_.listFields(); 191 // native fields first 192 for (int i = 0; i < fieldNames.length; i++) { 193 nativeFields[i] = new NATField(fieldNames[i], this); 194 } 195 if (customFields_ == null) { 196 // no custom fields 197 return NATTable.atValue(nativeFields); 198 } else { 199 ATObject[] customFields = (ATObject[]) customFields_.toArray(new ATObject[customFields_.size()]); 200 return NATTable.atValue(NATTable.collate(nativeFields, customFields)); 201 } 202 } 203 204 public ATTable meta_listMethods() throws InterpreterException { 205 return NATTable.EMPTY; 206 } 207 208 public NATText meta_print() throws InterpreterException { 209 return NATText.atValue("<callframe>"); 210 } 211 212 /* --------------------- 213 * -- Mirror Fields -- 214 * --------------------- */ 215 216 /** 217 * Auxiliary method to dynamically select the 'super' field from this object. 218 * Note that this method is part of the base-level interface to an object. 219 * 220 * Also note that this method performs the behaviour equivalent to evaluating 221 * 'super' and not 'self.super', which could lead to infinite loops. 222 */ 223 public ATObject base_super() throws InterpreterException { 224 return this.impl_call(NATObject._SUPER_NAME_, NATTable.EMPTY); 225 }; 226 227 public ATObject impl_lexicalParent() throws InterpreterException { 228 return lexicalParent_; 229 } 230 231 /* -------------------------- 232 * -- Conversion Protocol -- 233 * -------------------------- */ 234 235 public boolean isCallFrame() { 236 return true; 237 } 238 239 public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException { 240 if( (original instanceof NATCallframe) & 241 ! (original instanceof NATObject)) { 242 FieldMap originalVariables = ((NATCallframe)original).variableMap_; 243 244 return NATBoolean.atValue( 245 variableMap_.isDerivedFrom(originalVariables)); 246 } else { 247 return NATBoolean._FALSE_; 248 } 249 } 250 251 public ATBoolean meta_isRelatedTo(ATObject object) throws InterpreterException { 252 return super.meta_isRelatedTo(object); 253 } 254 255 /* ----------------------------- 256 * -- Object Passing protocol -- 257 * ----------------------------- */ 258 259 // protected methods, only to be used by NATCallframe and NATObject 260 261 protected boolean hasLocalField(ATSymbol selector) throws InterpreterException { 262 return hasLocalNativeField(selector) || hasLocalCustomField(selector); 263 } 264 265 protected boolean hasLocalNativeField(ATSymbol selector) { 266 return variableMap_.get(selector) != -1; 267 } 268 269 protected boolean hasLocalCustomField(ATSymbol selector) throws InterpreterException { 270 if (customFields_ == null) { 271 return false; 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 true; 278 } 279 } 280 return false; 281 } 282 } 283 284 /** 285 * Reads out the value of either a native or a custom field. 286 * @throws XSelectorNotFound if no native or custom field with the given name exists locally. 287 */ 288 protected ATObject getLocalField(ATSymbol selector) throws InterpreterException { 289 int index = variableMap_.get(selector); 290 if(index != -1) { 291 return (ATObject) (stateVector_.get(index)); 292 } else { 293 ATField fld = getLocalCustomField(selector); 294 if (fld != null) { 295 return fld.base_readField(); 296 } else { 297 throw new XSelectorNotFound(selector, this); 298 } 299 } 300 } 301 302 /** 303 * @return a custom field matching the given selector or null if such a field does not exist 304 */ 305 protected ATField getLocalCustomField(ATSymbol selector) throws InterpreterException { 306 if (customFields_ == null) { 307 return null; 308 } else { 309 Iterator it = customFields_.iterator(); 310 while (it.hasNext()) { 311 ATField field = (ATField) it.next(); 312 if (field.base_name().equals(selector)) { 313 return field; 314 } 315 } 316 return null; 317 } 318 } 319 320 /** 321 * Set a given field if it exists. 322 */ 323 protected void setLocalField(ATSymbol selector, ATObject value) throws InterpreterException { 324 int index = variableMap_.get(selector); 325 if(index != -1) { 326 // field exists, modify the state vector 327 stateVector_.set(index, value); 328 // ok 329 } else { 330 ATField fld = getLocalCustomField(selector); 331 if (fld != null) { 332 fld.base_writeField(value); 333 // ok 334 } else { 335 // fail 336 throw new XSelectorNotFound(selector, this); 337 } 338 } 339 } 340 341 /** 342 * A call frame has no methods. 343 */ 344 protected boolean hasLocalMethod(ATSymbol atSelector) throws InterpreterException { 345 return false; 346 } 347 348 /** 349 * A call frame has no methods. 350 */ 351 protected ATMethod getLocalMethod(ATSymbol selector) throws InterpreterException { 352 throw new XSelectorNotFound(selector, this); 353 } 354 355 356}