/interpreter/tags/at2dist091109/src/edu/vub/at/objects/natives/NativeATObject.java
Java | 1037 lines | 591 code | 135 blank | 311 comment | 67 complexity | 0c424b575d2ec74347d2fc8fe373ac03 MD5 | raw file
1/** 2 * AmbientTalk/2 Project 3 * NATNil.java created on Jul 13, 2006 at 9:38:51 PM 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.actors.ATActorMirror; 31import edu.vub.at.actors.ATAsyncMessage; 32import edu.vub.at.actors.ATFarReference; 33import edu.vub.at.actors.ATLetter; 34import edu.vub.at.actors.natives.ELActor; 35import edu.vub.at.actors.natives.NATFarReference; 36import edu.vub.at.actors.net.SerializationException; 37import edu.vub.at.eval.Evaluator; 38import edu.vub.at.eval.Import.DelegateMethod; 39import edu.vub.at.exceptions.InterpreterException; 40import edu.vub.at.exceptions.XIllegalOperation; 41import edu.vub.at.exceptions.XSelectorNotFound; 42import edu.vub.at.exceptions.XTypeMismatch; 43import edu.vub.at.objects.ATAbstractGrammar; 44import edu.vub.at.objects.ATBoolean; 45import edu.vub.at.objects.ATClosure; 46import edu.vub.at.objects.ATContext; 47import edu.vub.at.objects.ATField; 48import edu.vub.at.objects.ATHandler; 49import edu.vub.at.objects.ATMessage; 50import edu.vub.at.objects.ATMethod; 51import edu.vub.at.objects.ATMethodInvocation; 52import edu.vub.at.objects.ATNil; 53import edu.vub.at.objects.ATNumber; 54import edu.vub.at.objects.ATObject; 55import edu.vub.at.objects.ATTable; 56import edu.vub.at.objects.ATTypeTag; 57import edu.vub.at.objects.coercion.NativeTypeTags; 58import edu.vub.at.objects.grammar.ATAssignVariable; 59import edu.vub.at.objects.grammar.ATAssignmentSymbol; 60import edu.vub.at.objects.grammar.ATBegin; 61import edu.vub.at.objects.grammar.ATDefinition; 62import edu.vub.at.objects.grammar.ATExpression; 63import edu.vub.at.objects.grammar.ATMessageCreation; 64import edu.vub.at.objects.grammar.ATQuote; 65import edu.vub.at.objects.grammar.ATSplice; 66import edu.vub.at.objects.grammar.ATStatement; 67import edu.vub.at.objects.grammar.ATSymbol; 68import edu.vub.at.objects.grammar.ATUnquoteSplice; 69import edu.vub.at.objects.mirrors.NATIntrospectiveMirror; 70import edu.vub.at.objects.mirrors.NATMirage; 71import edu.vub.at.objects.mirrors.NativeClosure; 72import edu.vub.at.objects.mirrors.Reflection; 73import edu.vub.at.objects.symbiosis.JavaClass; 74import edu.vub.at.objects.symbiosis.JavaMethod; 75import edu.vub.at.objects.symbiosis.JavaObject; 76import edu.vub.at.util.logging.Logging; 77 78import java.io.InvalidObjectException; 79import java.io.ObjectStreamException; 80import java.io.Serializable; 81import java.util.HashSet; 82import java.util.Set; 83 84/** 85 * This class implements default semantics for all test and conversion methods. 86 * It also implements the default metaobject protocol semantics for native 87 * AmbientTalk objects. 88 * <p> 89 * More specifically, this class encapsulates the behavior for: 90 * <ul> 91 * <li>The behavior of all native objects. 92 * <li>The default behavior of all non-native objects. 93 * </ul> 94 * Native AmbientTalk objects contain no fields, only methods. Fields are represented 95 * using accessor methods. Mutable fields also have a mutator method. 96 * <p> 97 * To allow for AmbientTalk language values to be unquoted into parsetrees, 98 * a native object is considered to be a valid ambienttalk expression. 99 * 100 * @author tvcutsem, smostinc 101 */ 102public abstract class NativeATObject implements ATObject, ATExpression, Serializable { 103 104 protected NativeATObject() {}; 105 106 /** 107 * Asynchronous messages ( <tt>o<-m( args )</tt> ) sent in the context of an object o (i.e. 108 * sent in a method or closure where the self pseudovariable is bound to o) are 109 * delegated to the base-level send method of the actor in which the object o is 110 * contained. 111 */ 112 public ATObject meta_send(ATObject receiver, ATAsyncMessage message) throws InterpreterException { 113 return OBJLexicalRoot._INSTANCE_.base_reflectOnActor().base_send(receiver, message); 114 } 115 116 /** 117 * When a local object reference is used as an eventual reference by sending it an 118 * asynchronous message, the object simply schedules the message in its owner's 119 * message queue and returns <tt>nil</tt> immediately. The message is later transformed 120 * into a method invocation (in a later actor execution "turn"). 121 * 122 * Note: in pre-2.9 versions of AmbientTalk, this method was invoked in the later 123 * execution turn and immediately performed the message processing. Now, this method 124 * is invoked by the sender of an async message and allows custom eventual references 125 * to return a value other than <tt>nil</tt> for an async message send. 126 */ 127 public ATObject meta_receive(ATAsyncMessage message) throws InterpreterException { 128 ELActor.currentActor().acceptSelfSend(this, message); 129 return Evaluator.getNil(); 130 } 131 132 /** 133 * An ambienttalk object can respond to a message if a corresponding field or method exists 134 * either in the receiver object locally, or in one of its dynamic parents. 135 * Fields also implicitly define a mutator whose name has the form <tt>field:=</tt>. 136 */ 137 public ATBoolean meta_respondsTo(ATSymbol selector) throws InterpreterException { 138 if (this.hasLocalField(selector) || this.hasLocalMethod(selector)) { 139 return NATBoolean._TRUE_; 140 } else { 141 if (selector.isAssignmentSymbol()) { 142 if (this.hasLocalField(selector.asAssignmentSymbol().base_fieldName())) { 143 return NATBoolean._TRUE_; 144 } 145 } 146 } 147 return base_super().meta_respondsTo(selector); 148 } 149 150 /** 151 * By default, when a selection is not understood by a primitive object, an error is raised. 152 */ 153 public ATClosure meta_doesNotUnderstand(ATSymbol selector) throws InterpreterException { 154 throw new XSelectorNotFound(selector, this); 155 } 156 157 /* ------------------------------------------ 158 * -- Slot accessing and mutating protocol -- 159 * ------------------------------------------ */ 160 161 public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException { 162 throw new XIllegalOperation("Cannot add fields to " + Evaluator.valueNameOf(this.getClass())); 163 } 164 165 /* ------------------------------------ 166 * -- Extension and cloning protocol -- 167 * ------------------------------------ */ 168 169 public ATObject meta_clone() throws InterpreterException { 170 throw new XIllegalOperation("Cannot clone a native object of type " + this.getClass().getName()); 171 } 172 173 public ATObject meta_newInstance(ATTable initargs) throws InterpreterException { 174 return Reflection.upInstanceCreation(this, initargs); 175 } 176 177 /* --------------------------------- 178 * -- Structural Access Protocol -- 179 * --------------------------------- */ 180 181 public ATNil meta_addField(ATField field) throws InterpreterException { 182 throw new XIllegalOperation("Cannot add fields to " + Evaluator.valueNameOf(this.getClass())); 183 } 184 185 public ATNil meta_addMethod(ATMethod method) throws InterpreterException { 186 throw new XIllegalOperation("Cannot add methods to " + Evaluator.valueNameOf(this.getClass())); 187 } 188 189 public ATField meta_grabField(ATSymbol fieldName) throws InterpreterException { 190 throw new XSelectorNotFound(fieldName, this); 191 } 192 193 public ATMethod meta_grabMethod(ATSymbol methodName) throws InterpreterException { 194 return Reflection.downBaseLevelMethod(this, methodName); 195 } 196 197 public ATObject meta_removeSlot(ATSymbol selector) throws InterpreterException { 198 throw new XIllegalOperation("Cannot remove slot "+selector+" from native object "+this); 199 } 200 201 public ATTable meta_listFields() throws InterpreterException { 202 return NATTable.EMPTY; 203 } 204 205 public ATTable meta_listMethods() throws InterpreterException { 206 return NATTable.atValue(Reflection.downBaseLevelMethods(this)); 207 } 208 209 public ATNil meta_addSlot(ATMethod method) throws InterpreterException { 210 return this.meta_addMethod(method); 211 } 212 213 public ATMethod meta_grabSlot(ATSymbol methodName) throws InterpreterException { 214 try { 215 return this.meta_grabMethod(methodName); 216 } catch(XSelectorNotFound e) { 217 e.catchOnlyIfSelectorEquals(methodName); 218 if (methodName.isAssignmentSymbol()) { 219 ATField mutator = this.meta_grabField(methodName.asAssignmentSymbol().base_fieldName()); 220 return mutator.base_mutator(); 221 } else { 222 ATField accessor = this.meta_grabField(methodName); 223 return accessor.base_accessor(); 224 } 225 } 226 } 227 228 public ATTable meta_listSlots() throws InterpreterException { 229 ATObject[] fields = this.meta_listFields().asNativeTable().elements_; 230 ATObject[] methods = this.meta_listMethods().asNativeTable().elements_; 231 232 int fieldLength = fields.length * 2; 233 ATObject[] slots = new ATObject[fieldLength + methods.length]; 234 int i = 0; 235 // add field accessors and mutators 236 for (; i < fieldLength ; i+=2) { 237 ATField field = (ATField) fields[i/2]; 238 slots[i] = field.base_accessor(); 239 slots[i+1] = field.base_mutator(); 240 } 241 // add regular methods 242 for (; i < fieldLength + methods.length ; i++) { 243 slots[i] = methods[i - fieldLength]; 244 } 245 246 return NATTable.atValue(slots); 247 } 248 249 /* --------------------------------- 250 * -- Abstract Grammar Protocol -- 251 * --------------------------------- */ 252 253 /** 254 * All NATObjects which are not Abstract Grammar elements are self-evaluating. 255 */ 256 public ATObject meta_eval(ATContext ctx) throws InterpreterException { 257 return this; 258 } 259 260 /** 261 * Quoting a native object returns itself, except for pure AG elements. 262 */ 263 public ATObject meta_quote(ATContext ctx) throws InterpreterException { 264 return this; 265 } 266 267 public abstract NATText meta_print() throws InterpreterException; 268 269 /* ------------------------------ 270 * -- ATObject Mirror Fields -- 271 * ------------------------------ */ 272 273 /** 274 * Native objects have a SHARES-A parent link to 'nil', by default. 275 */ 276 public ATBoolean meta_isExtensionOfParent() throws InterpreterException { 277 return NATBoolean.atValue((NATObject._SHARES_A_)); 278 }; 279 280 /** 281 * By default numbers, tables and so on have root as their lexical parent. 282 */ 283 public ATObject impl_lexicalParent() throws InterpreterException { 284 return Evaluator.getGlobalLexicalScope(); 285 } 286 287 public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException { 288 return NATBoolean.atValue( 289 this.getClass() == original.getClass()); 290 } 291 292 public ATBoolean meta_isRelatedTo(ATObject object) throws InterpreterException { 293 return this.meta_isCloneOf(object); 294 } 295 296 /* --------------------------------- 297 * -- Type Testing and Querying -- 298 * --------------------------------- */ 299 300 /** 301 * Native objects implement the type test non-recursively: only the type tags 302 * returned by {@link this#meta_getTypeTags()} are tested against. 303 */ 304 public ATBoolean meta_isTaggedAs(ATTypeTag type) throws InterpreterException { 305 ATObject[] types = this.meta_typeTags().asNativeTable().elements_; 306 for (int i = 0; i < types.length; i++) { 307 if (types[i].asTypeTag().base_isSubtypeOf(type).asNativeBoolean().javaValue) { 308 return NATBoolean._TRUE_; 309 } 310 } 311 return NATBoolean._FALSE_; 312 } 313 314 /** 315 * By default, a native object (and also nil) has no type tags. 316 */ 317 public ATTable meta_typeTags() throws InterpreterException { 318 return NATTable.EMPTY; 319 } 320 321 /* ----------------------------- 322 * -- Object Passing protocol -- 323 * ----------------------------- */ 324 325 /** 326 * This method allows objects to decide which object should be serialized in their 327 * stead when they are passed as argument in an asynchronous message send that 328 * crosses actor boundaries. 329 */ 330 public abstract ATObject meta_pass() throws InterpreterException; 331 332 /** 333 * Delegate the responsibility of serialization to the AT/2 meta-level 334 */ 335 public Object writeReplace() throws ObjectStreamException { 336 try { 337 return this.meta_pass(); 338 } catch(InterpreterException e) { 339 throw new InvalidObjectException("Failed to pass object " + this + ": " + e.getMessage()); 340 } 341 } 342 343 public abstract ATObject meta_resolve() throws InterpreterException; 344 345 /** 346 * Delegate the responsibility of deserialization to the AT/2 meta-level 347 */ 348 public Object readResolve() throws ObjectStreamException { 349 try { 350 return this.meta_resolve(); 351 } catch(InterpreterException e) { 352 throw new SerializationException(e); 353 } 354 } 355 356 /* --------------------------------- 357 * -- Value Conversion Protocol -- 358 * --------------------------------- */ 359 360 public boolean isSymbol() throws InterpreterException { 361 return false; 362 } 363 364 public boolean isTable() throws InterpreterException { 365 return false; 366 } 367 368 public boolean isCallFrame() throws InterpreterException { 369 return false; 370 } 371 372 public boolean isUnquoteSplice() throws InterpreterException { 373 return false; 374 } 375 376 public boolean isVariableAssignment() throws InterpreterException { 377 return false; 378 } 379 380 public boolean isSplice() throws InterpreterException { 381 return false; 382 } 383 384 public boolean isDefinition() throws InterpreterException { 385 return false; 386 } 387 388 public boolean isMessageCreation() throws InterpreterException { 389 return false; 390 } 391 392 public boolean isAmbientTalkObject() { 393 return false; 394 } 395 396 public boolean isMirage() { 397 return false; 398 } 399 400 public boolean isJavaObjectUnderSymbiosis() { 401 return false; 402 } 403 404 public boolean isNativeBoolean() { 405 return false; 406 } 407 408 public boolean isNativeText() { 409 return false; 410 } 411 412 public boolean isNativeNumber() { 413 return false; 414 } 415 416 public boolean isNativeField() { 417 return false; 418 } 419 420 public boolean isTypeTag() throws InterpreterException { 421 return false; 422 } 423 424 public boolean isNativeFarReference() { 425 return false; 426 } 427 428 // Conversions for concurrency and distribution related object 429 public boolean isFarReference() throws InterpreterException { 430 return false; 431 } 432 433 public boolean isNativeFraction() { return false; } 434 public boolean isNativeIntrospectiveMirror() { return false; } 435 public boolean isJavaClassUnderSymbiosis() { return false; } 436 public boolean isJavaMethodUnderSymbiosis() { return false; } 437 public boolean isNativeDelegateMethod() { return false; } 438 439 public ATClosure asClosure() throws InterpreterException { 440 throw new XTypeMismatch(ATClosure.class, this); 441 } 442 443 public ATSymbol asSymbol() throws InterpreterException { 444 throw new XTypeMismatch(ATSymbol.class, this); 445 } 446 447 public ATTable asTable() throws InterpreterException { 448 throw new XTypeMismatch(ATTable.class, this); 449 } 450 451 public ATBoolean asBoolean() throws InterpreterException { 452 throw new XTypeMismatch(ATBoolean.class, this); 453 } 454 455 public ATNumber asNumber() throws InterpreterException { 456 throw new XTypeMismatch(ATNumber.class, this); 457 } 458 459 public ATMessage asMessage() throws InterpreterException { 460 throw new XTypeMismatch(ATMessage.class, this); 461 } 462 463 public ATMethodInvocation asMethodInvocation() throws InterpreterException { 464 throw new XTypeMismatch(ATMethodInvocation.class, this); 465 } 466 467 public ATField asField() throws InterpreterException { 468 throw new XTypeMismatch(ATField.class, this); 469 } 470 471 public ATMethod asMethod() throws InterpreterException { 472 throw new XTypeMismatch(ATMethod.class, this); 473 } 474 475 public ATHandler asHandler() throws InterpreterException { 476 throw new XTypeMismatch(ATHandler.class, this); 477 } 478 479 public ATTypeTag asTypeTag() throws InterpreterException { 480 throw new XTypeMismatch(ATTypeTag.class, this); 481 } 482 483 public ATFarReference asFarReference() throws InterpreterException { 484 throw new XTypeMismatch(ATFarReference.class, this); 485 } 486 487 public ATAsyncMessage asAsyncMessage() throws InterpreterException { 488 throw new XTypeMismatch(ATAsyncMessage.class, this); 489 } 490 491 public ATActorMirror asActorMirror() throws InterpreterException { 492 throw new XTypeMismatch(ATActorMirror.class, this); 493 } 494 495 // Conversions for abstract grammar elements 496 497 public ATAbstractGrammar asAbstractGrammar() throws InterpreterException { 498 return this; 499 } 500 501 public ATDefinition asDefinition() throws InterpreterException { 502 throw new XTypeMismatch(ATDefinition.class, this); 503 } 504 505 public ATExpression asExpression() throws InterpreterException { 506 return this; 507 } 508 509 public ATBegin asBegin() throws InterpreterException { 510 throw new XTypeMismatch(ATBegin.class, this); 511 } 512 513 public ATMessageCreation asMessageCreation() throws InterpreterException { 514 throw new XTypeMismatch(ATMessageCreation.class, this); 515 } 516 517 public ATQuote asQuote() throws InterpreterException { 518 throw new XTypeMismatch(ATQuote.class, this); 519 } 520 521 public ATUnquoteSplice asUnquoteSplice() throws InterpreterException { 522 throw new XTypeMismatch(ATUnquoteSplice.class, this); 523 } 524 525 public ATAssignVariable asVariableAssignment() throws InterpreterException { 526 throw new XTypeMismatch(ATAssignVariable.class, this); 527 } 528 529 public ATSplice asSplice() throws InterpreterException { 530 throw new XTypeMismatch(ATSplice.class, this); 531 } 532 533 public ATLetter asLetter() throws InterpreterException { 534 throw new XTypeMismatch(ATLetter.class, this); 535 } 536 537 // Conversions for native values 538 public NATObject asAmbientTalkObject() throws XTypeMismatch { 539 throw new XTypeMismatch(NATObject.class, this); 540 } 541 542 public NATMirage asMirage() throws XTypeMismatch { 543 throw new XTypeMismatch(NATMirage.class, this); 544 } 545 546 public NATNumber asNativeNumber() throws XTypeMismatch { 547 throw new XTypeMismatch(NATNumber.class, this); 548 } 549 550 public NATFraction asNativeFraction() throws XTypeMismatch { 551 throw new XTypeMismatch(NATFraction.class, this); 552 } 553 554 public NATText asNativeText() throws XTypeMismatch { 555 throw new XTypeMismatch(NATText.class, this); 556 } 557 558 public NATTable asNativeTable() throws XTypeMismatch { 559 throw new XTypeMismatch(NATTable.class, this); 560 } 561 562 public NATBoolean asNativeBoolean() throws XTypeMismatch { 563 throw new XTypeMismatch(NATBoolean.class, this); 564 } 565 566 public NATNumeric asNativeNumeric() throws XTypeMismatch { 567 throw new XTypeMismatch(NATNumeric.class, this); 568 } 569 570 public NATFarReference asNativeFarReference() throws XTypeMismatch { 571 throw new XTypeMismatch(NATFarReference.class, this); 572 } 573 574 public JavaObject asJavaObjectUnderSymbiosis() throws XTypeMismatch { 575 throw new XTypeMismatch(JavaObject.class, this); 576 } 577 578 public JavaClass asJavaClassUnderSymbiosis() throws XTypeMismatch { 579 throw new XTypeMismatch(JavaClass.class, this); 580 } 581 582 public JavaMethod asJavaMethodUnderSymbiosis() throws XTypeMismatch { 583 throw new XTypeMismatch(JavaMethod.class, this); 584 } 585 586 public DelegateMethod asNativeDelegateMethod() throws XTypeMismatch { 587 throw new XTypeMismatch(DelegateMethod.class, this); 588 } 589 590 public NATIntrospectiveMirror asNativeIntrospectiveMirror() throws XTypeMismatch { 591 throw new XTypeMismatch(NATIntrospectiveMirror.class, this); 592 } 593 594 /** 595 * Only true objects have a dynamic pointer, native objects denote 'nil' to 596 * be their dynamic parent when asked for it. Note that, for native objects, 597 * 'super' is a read-only field (i.e. only an accessor for the virtual field exists). 598 */ 599 public ATObject base_super() throws InterpreterException { 600 return Evaluator.getNil(); 601 }; 602 603 public String toString() { 604 return Evaluator.toString(this); 605 } 606 607 /** 608 * Java method invocations of equals are transformed into 609 * AmbientTalk '==' method invocations. 610 */ 611 public boolean equals(Object other) { 612 try { 613 if (other instanceof ATObject) { 614 return this.base__opeql__opeql_((ATObject) other).asNativeBoolean().javaValue; 615 } 616 } catch (InterpreterException e) { 617 Logging.Actor_LOG.warn("Error during equality testing:", e); 618 } 619 return false; 620 } 621 622 public ATBoolean impl_identityEquals(ATObject other) throws InterpreterException { 623 return NATBoolean.atValue(other == this); 624 } 625 626 /** 627 * By default, two AmbientTalk objects are equal if they are the 628 * same object, or one is a proxy for the same object. 629 */ 630 public ATBoolean base__opeql__opeql_(ATObject other) throws InterpreterException { 631 // by default, ATObjects use pointer equality 632 return NATBoolean.atValue(this == other); 633 } 634 635 /*public ATObject base_new(ATObject[] initargs) throws InterpreterException { 636 return this.meta_newInstance(NATTable.atValue(initargs)); 637 }*/ 638 639 /*public ATObject base_init(ATObject[] initargs) throws InterpreterException { 640 return Evaluator.getNil(); 641 }*/ 642 643 /** 644 * This method is used to evaluate code of the form <tt>selector(args)</tt> 645 * or <tt>selector := arg</tt> within the scope of this object. 646 * 647 * It dispatches to other implementation-level methods based on the selector. 648 */ 649 public ATObject impl_call(ATSymbol selector, ATTable arguments) throws InterpreterException { 650 if (selector.isAssignmentSymbol()) { 651 return this.impl_callMutator(selector.asAssignmentSymbol(), arguments); 652 } else { 653 return this.impl_callAccessor(selector, arguments); 654 } 655 } 656 657 /** 658 * Implements the interpretation of <tt>f(arg)</tt> inside the scope of a 659 * particular object. 660 * 661 * - if f is bound to a local method, the method is applied 662 * - if f is bound to a field: 663 * - if the field contains a closure, the closure is applied 664 * - otherwise, the field is treated as a nullary closure and 'applied' 665 * - otherwise, the search for the selector continues in the lexical parent 666 */ 667 public ATObject impl_callAccessor(ATSymbol selector, ATTable arguments) throws InterpreterException { 668 if(this.hasLocalMethod(selector)) { 669 // apply the method with a context ctx where 670 // ctx.scope = the implementing scope, being this object 671 // ctx.self = the receiver, being in this case again the implementor 672 return this.getLocalMethod(selector).base_apply(arguments, new NATContext(this, this)); 673 } else { 674 if (this.hasLocalField(selector)) { 675 ATObject fieldValue = this.getLocalField(selector); 676 677 if (fieldValue.meta_isTaggedAs(NativeTypeTags._CLOSURE_).asNativeBoolean().javaValue) { 678 return fieldValue.asClosure().base_apply(arguments); 679 } else { 680 NativeClosure.checkNullaryArguments(selector, arguments); 681 return fieldValue; 682 } 683 } else { 684 return this.impl_lexicalParent().impl_callAccessor(selector, arguments); 685 } 686 } 687 } 688 689 /** 690 * Implements the interpretation of <tt>x := arg</tt> inside the scope of a 691 * particular object. 692 * 693 * - if x:= is bound to a local method, the method is applied 694 * - if x is bound to a field, the field is assigned if exactly one argument is given 695 * - otherwise, the search for the selector continues in the lexical parent 696 */ 697 public ATObject impl_callMutator(ATAssignmentSymbol selector, ATTable arguments) throws InterpreterException { 698 if(this.hasLocalMethod(selector)) { 699 // apply the method with a context ctx where 700 // ctx.scope = the implementing scope, being this object 701 // ctx.self = the receiver, being in this case again the implementor 702 return this.getLocalMethod(selector).base_apply(arguments, new NATContext(this, this)); 703 } else { 704 ATSymbol fieldSelector = selector.base_fieldName(); 705 if (this.hasLocalField(fieldSelector)) { 706 ATObject value = NativeClosure.checkUnaryArguments(selector, arguments); 707 this.setLocalField(fieldSelector, value); 708 return value; 709 } else { 710 return this.impl_lexicalParent().impl_callMutator(selector, arguments); 711 } 712 } 713 } 714 715 /** 716 * Implements the interpretation of <tt>x</tt> inside the scope of a 717 * particular object. 718 * 719 * - if x is bound to a local method, the method is applied to <tt>[]</tt> 720 * - if x is bound to a field, the field's value is returned (even if it 721 * contains a closure) 722 * - otherwise, the search for the selector continues in the lexical parent 723 */ 724 public ATObject impl_callField(ATSymbol selector) throws InterpreterException { 725 // if selector is bound to a method, treat 'm' as 'm()' 726 if(this.hasLocalMethod(selector)) { 727 // apply the method with a context ctx where 728 // ctx.scope = the implementing scope, being this object 729 // ctx.self = the receiver, being in this case again the implementor 730 return this.getLocalMethod(selector).base_apply(NATTable.EMPTY, new NATContext(this, this)); 731 } else { 732 if (this.hasLocalField(selector)) { 733 // simply return the field's value, regardless of whether it is bound to a 734 // closure or not 735 return this.getLocalField(selector); 736 } else { 737 return this.impl_lexicalParent().impl_callField(selector); 738 } 739 } 740 } 741 742 /** 743 * This method simply deconstructs the method invocation object and passes it on to 744 * the native implementation. 745 */ 746 public ATObject meta_invoke(ATObject delegate, ATMethodInvocation invocation) throws InterpreterException { 747 return this.impl_invoke(delegate, invocation.base_selector(), invocation.base_arguments()); 748 } 749 750 /** 751 * This method dispatches to specific invocation primitives 752 * depending on whether or not the given selector denotes an assignment. 753 */ 754 public ATObject impl_invoke(ATObject delegate, ATSymbol selector, ATTable arguments) throws InterpreterException { 755 // If the selector is an assignment symbol (i.e. `field:=) try to assign the corresponding field 756 if (selector.isAssignmentSymbol()) { 757 return this.impl_invokeMutator(delegate, selector.asAssignmentSymbol(), arguments); 758 } else { 759 return this.impl_invokeAccessor(delegate, selector, arguments); 760 } 761 } 762 763 /** 764 * Implements the interpretation of <tt>o.m(arg)</tt>. 765 * 766 * - if m is bound to a local method of o, the method is applied 767 * - if m is bound to a field of o: 768 * - if the field contains a closure, the closure is applied 769 * - otherwise, the field is treated as a nullary closure and 'applied' 770 * - otherwise, the search for the selector continues in the dynamic parent 771 */ 772 public ATObject impl_invokeAccessor(ATObject receiver, ATSymbol selector, ATTable arguments) throws InterpreterException { 773 if (this.hasLocalMethod(selector)) { 774 // immediately execute the method in the context ctx where 775 // ctx.scope = the implementing scope, being this object, under which an additional callframe will be inserted 776 // ctx.self = the late bound receiver, being the passed receiver 777 return this.getLocalMethod(selector).base_apply(arguments, new NATContext(this, receiver)); 778 } else { 779 if (this.hasLocalField(selector)) { 780 ATObject fieldValue = this.getLocalField(selector); 781 782 if (fieldValue.meta_isTaggedAs(NativeTypeTags._CLOSURE_).asNativeBoolean().javaValue) { 783 return fieldValue.asClosure().base_apply(arguments); 784 } else { 785 NativeClosure.checkNullaryArguments(selector, arguments); 786 return fieldValue; 787 } 788 } else { 789 return base_super().impl_invokeAccessor(receiver, selector, arguments); 790 } 791 } 792 } 793 794 /** 795 * Implements the interpretation of <tt>o.x := arg</tt>. 796 * 797 * - if x:= is bound to a local method of o, the method is applied to the arguments. 798 * - if x is bound to a field of o, the field is treated as a unary mutator method 799 * that assigns the field and 'applied' to the given arguments. 800 * - otherwise, the search for the selector continues in the dynamic parent 801 */ 802 public ATObject impl_invokeMutator(ATObject receiver, ATAssignmentSymbol selector, ATTable arguments) throws InterpreterException { 803 if (this.hasLocalMethod(selector)) { 804 // immediately execute the method in the context ctx where 805 // ctx.scope = the implementing scope, being this object, under which an additional callframe will be inserted 806 // ctx.self = the late bound receiver, being the passed receiver 807 return this.getLocalMethod(selector).base_apply(arguments, new NATContext(this, receiver)); 808 } else { 809 // try to treat a local field as a mutator 810 ATSymbol fieldSelector = selector.base_fieldName(); 811 if (this.hasLocalField(fieldSelector)) { 812 ATObject value = NativeClosure.checkUnaryArguments(selector, arguments); 813 this.setLocalField(fieldSelector, value); 814 return value; 815 } else { 816 // if no field matching the selector exists, delegate to the parent 817 return base_super().impl_invokeMutator(receiver, selector, arguments); 818 } 819 } 820 } 821 822 /** 823 * Implements the interpretation of <tt>o.x</tt>. 824 * 825 * - if x is bound to a local method of o, the method is applied to <tt>[]</tt> 826 * - if x is bound to a field of o, the field's value is returned (even if it 827 * contains a closure). 828 * - otherwise, the search for the selector continues in the dynamic parent 829 */ 830 public ATObject meta_invokeField(ATObject receiver, ATSymbol selector) throws InterpreterException { 831 // if selector is bound to a method, treat 'o.m' as 'o.m()' 832 if (this.hasLocalMethod(selector)) { 833 // immediately execute the method in the context ctx where 834 // ctx.scope = the implementing scope, being this object, under which an additional callframe will be inserted 835 // ctx.self = the late bound receiver, being the passed receiver 836 return this.getLocalMethod(selector).base_apply(NATTable.EMPTY, new NATContext(this, receiver)); 837 } else { 838 if (this.hasLocalField(selector)) { 839 // return the field's value, regardless of whether it is a closure or not 840 return this.getLocalField(selector); 841 } else { 842 return base_super().meta_invokeField(receiver, selector); 843 } 844 } 845 } 846 847 /** 848 * This operation dispatches to more specific implementation-level methods depending 849 * on the type of the selector. 850 */ 851 public ATClosure impl_lookup(ATSymbol selector) throws InterpreterException { 852 if (selector.isAssignmentSymbol()) { 853 return this.impl_lookupMutator(selector.asAssignmentSymbol()); 854 } else { 855 return this.impl_lookupAccessor(selector); 856 } 857 } 858 859 /** 860 * Implements the interpretation of <tt>&f</tt> in the scope of this object. 861 * 862 * - if f is bound to a local method, a closure wrapping the method is returned 863 * - if f is bound to a field of o, an accessor closure is returned which yields 864 * the field's value upon application. 865 * - otherwise, the search for the selector continues in the lexical parent 866 */ 867 public ATClosure impl_lookupAccessor(final ATSymbol selector) throws InterpreterException { 868 if (this.hasLocalMethod(selector)) { 869 // return a new closure (mth, ctx) where 870 // mth = the method found in this object 871 // ctx.scope = the implementing scope, being this object 872 // ctx.self = the late bound receiver, being the passed receiver 873 // ctx.super = the parent of the implementor 874 return this.getLocalMethod(selector).base_wrap(this, this); 875 } else { 876 // try to wrap a local field in an accessor 877 if(this.hasLocalField(selector)) { 878 final NativeATObject scope = this; 879 return new NativeClosure.Accessor(selector, this) { 880 protected ATObject access() throws InterpreterException { 881 return scope.getLocalField(selector); 882 } 883 }; 884 } else { 885 return this.impl_lexicalParent().impl_lookupAccessor(selector); 886 } 887 } 888 } 889 890 /** 891 * Implements the interpretation of <tt>&f:=</tt> in the scope of this object. 892 * 893 * - if f:= is bound to a local method, a closure wrapping the method is returned 894 * - if f is bound to a field of o, a mutator closure is returned which assigns 895 * the field upon application. 896 * - otherwise, the search for the selector continues in the lexical parent 897 */ 898 public ATClosure impl_lookupMutator(ATAssignmentSymbol selector) throws InterpreterException { 899 if (this.hasLocalMethod(selector)) { 900 // return a new closure (mth, ctx) where 901 // mth = the method found in this object 902 // ctx.scope = the implementing scope, being this object 903 // ctx.self = the late bound receiver, being the passed receiver 904 // ctx.super = the parent of the implementor 905 return this.getLocalMethod(selector).base_wrap(this, this); 906 } else { 907 final ATSymbol fieldSelector = selector.base_fieldName(); 908 // try to wrap a local field in a mutator 909 if(this.hasLocalField(fieldSelector)) { 910 final NativeATObject scope = this; 911 return new NativeClosure.Mutator(selector, this) { 912 protected ATObject mutate(ATObject arg) throws InterpreterException { 913 scope.setLocalField(fieldSelector, arg); 914 return arg; 915 } 916 }; 917 } else { 918 return this.impl_lexicalParent().impl_lookupMutator(selector); 919 } 920 } 921 } 922 923 /** 924 * select should dispatch to specific selection primitives 925 * depending on whether or not the given selector denotes an assignment. 926 */ 927 public ATClosure meta_select(ATObject receiver, final ATSymbol selector) throws InterpreterException { 928 if (selector.isAssignmentSymbol()) { 929 return this.impl_selectMutator(receiver, selector.asAssignmentSymbol()); 930 } else { 931 return this.impl_selectAccessor(receiver, selector); 932 } 933 } 934 935 /** 936 * Implements the interpretation of <tt>o.&m</tt>. 937 * 938 * - if m is bound to a local method, a closure wrapping the method is returned 939 * - if m is bound to a field of o, an accessor closure is returned which yields 940 * the field's value upon application. 941 * - otherwise, the search for the selector continues in the dynamic parent 942 */ 943 public ATClosure impl_selectAccessor(ATObject receiver, final ATSymbol selector) throws InterpreterException { 944 if (this.hasLocalMethod(selector)) { 945 // return a new closure (mth, ctx) where 946 // mth = the method found in this object 947 // ctx.scope = the implementing scope, being this object 948 // ctx.self = the late bound receiver, being the passed receiver 949 // ctx.super = the parent of the implementor 950 return this.getLocalMethod(selector).base_wrap(this, receiver); 951 } else { 952 if (this.hasLocalField(selector)) { 953 final NativeATObject scope = this; 954 return new NativeClosure.Accessor(selector, this) { 955 protected ATObject access() throws InterpreterException { 956 return scope.getLocalField(selector); 957 } 958 }; 959 } else { 960 return base_super().impl_selectAccessor(receiver, selector); 961 } 962 } 963 } 964 965 /** 966 * Implements the interpretation of <tt>o.&m:=</tt>. 967 * 968 * - if m:= is bound to a local method, a closure wrapping the method is returned 969 * - if m is bound to a field of o, a mutator closure is returned which assigns 970 * the field upon application. 971 * - otherwise, the search for the selector continues in the dynamic parent 972 */ 973 public ATClosure impl_selectMutator(ATObject receiver, final ATAssignmentSymbol selector) throws InterpreterException { 974 if (this.hasLocalMethod(selector)) { 975 // return a new closure (mth, ctx) where 976 // mth = the method found in this object 977 // ctx.scope = the implementing scope, being this object 978 // ctx.self = the late bound receiver, being the passed receiver 979 // ctx.super = the parent of the implementor 980 return this.getLocalMethod(selector).base_wrap(this, receiver); 981 } else { 982 // try to wrap a local field in a mutator 983 final ATSymbol fieldSelector = selector.base_fieldName(); 984 if (this.hasLocalField(fieldSelector)) { 985 final NativeATObject scope = this; 986 return new NativeClosure.Mutator(selector, this) { 987 protected ATObject mutate(ATObject arg) throws InterpreterException { 988 scope.setLocalField(fieldSelector, arg); 989 return arg; 990 } 991 }; 992 } else { 993 // if no field matching the selector exists, delegate to the parent 994 return base_super().impl_selectMutator(receiver, selector); 995 } 996 } 997 } 998 999 public ATTable base_freeVariables() throws InterpreterException { 1000 Set freeVars = this.impl_freeVariables(); 1001 ATSymbol[] tbl = (ATSymbol[]) freeVars.toArray(new ATSymbol[freeVars.size()]); 1002 return NATTable.atValue(tbl); 1003 } 1004 1005 /** FV(nativeObj) = { } */ 1006 public Set impl_freeVariables() throws InterpreterException { return new HashSet(); } 1007 1008 public Set impl_quotedFreeVariables() throws InterpreterException { return new HashSet(); } 1009 1010 /** native objects have no fields */ 1011 protected boolean hasLocalField(ATSymbol sym) throws InterpreterException { 1012 return false; 1013 } 1014 1015 /** 1016 * A native Java object has a local method if it implements a 1017 * native Java method corresponding to the selector prefixed by 'base_'. 1018 */ 1019 protected boolean hasLocalMethod(ATSymbol atSelector) throws InterpreterException { 1020 String jSelector = Reflection.upBaseLevelSelector(atSelector); 1021 return Reflection.upRespondsTo(this, jSelector); 1022 } 1023 1024 protected ATObject getLocalField(ATSymbol selector) throws InterpreterException { 1025 throw new XSelectorNotFound(selector, this); 1026 } 1027 1028 protected ATMethod getLocalMethod(ATSymbol selector) throws InterpreterException { 1029 String methSelector = Reflection.upBaseLevelSelector(selector); 1030 return Reflection.upMethodSelection(this, methSelector, selector); 1031 } 1032 1033 protected void setLocalField(ATSymbol selector, ATObject value) throws InterpreterException { 1034 throw new XSelectorNotFound(selector, this); 1035 } 1036 1037}