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