/interpreter/tags/at2-build190607/src/edu/vub/at/objects/natives/NATNil.java
Java | 639 lines | 351 code | 102 blank | 186 comment | 7 complexity | aad26cfd87ebc36bba3a34b6bdf70f86 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.natives.NATFarReference; 34import edu.vub.at.actors.net.SerializationException; 35import edu.vub.at.eval.Evaluator; 36import edu.vub.at.exceptions.InterpreterException; 37import edu.vub.at.exceptions.XIllegalOperation; 38import edu.vub.at.exceptions.XSelectorNotFound; 39import edu.vub.at.exceptions.XTypeMismatch; 40import edu.vub.at.exceptions.XUnassignableField; 41import edu.vub.at.exceptions.XUndefinedSlot; 42import edu.vub.at.objects.ATBoolean; 43import edu.vub.at.objects.ATClosure; 44import edu.vub.at.objects.ATContext; 45import edu.vub.at.objects.ATField; 46import edu.vub.at.objects.ATHandler; 47import edu.vub.at.objects.ATMessage; 48import edu.vub.at.objects.ATMethod; 49import edu.vub.at.objects.ATNil; 50import edu.vub.at.objects.ATNumber; 51import edu.vub.at.objects.ATObject; 52import edu.vub.at.objects.ATTypeTag; 53import edu.vub.at.objects.ATTable; 54import edu.vub.at.objects.grammar.ATAssignVariable; 55import edu.vub.at.objects.grammar.ATBegin; 56import edu.vub.at.objects.grammar.ATDefinition; 57import edu.vub.at.objects.grammar.ATExpression; 58import edu.vub.at.objects.grammar.ATMessageCreation; 59import edu.vub.at.objects.grammar.ATSplice; 60import edu.vub.at.objects.grammar.ATStatement; 61import edu.vub.at.objects.grammar.ATSymbol; 62import edu.vub.at.objects.grammar.ATUnquoteSplice; 63import edu.vub.at.objects.mirrors.NATMirage; 64import edu.vub.at.objects.mirrors.Reflection; 65import edu.vub.at.objects.symbiosis.JavaClass; 66import edu.vub.at.objects.symbiosis.JavaObject; 67import edu.vub.at.objects.symbiosis.SymbioticATObjectMarker; 68import edu.vub.at.util.logging.Logging; 69 70import java.io.InvalidObjectException; 71import java.io.ObjectStreamException; 72import java.io.Serializable; 73 74/** 75 * NATNil implements default semantics for all test and conversion methods. 76 * It also implements the default metaobject protocol semantics for native 77 * AmbientTalk objects. 78 * <p> 79 * To allow for AmbientTalk language values to be unquoted into parsetrees, 80 * nil is considered to be a valid ambienttalk expression. 81 * 82 * @author smostinc 83 * @author tvcutsem 84 */ 85public class NATNil implements ATExpression, ATNil, Serializable { 86 87 protected NATNil() {}; 88 89 /** 90 * This field holds the sole instance of this class. In AmbientTalk, 91 * this is the object that represents <tt>nil</tt>. 92 */ 93 public final static NATNil _INSTANCE_ = new NATNil(); 94 95 /* ------------------------------ 96 * -- Message Sending Protocol -- 97 * ------------------------------ */ 98 99 /** 100 * Asynchronous messages ( o<-m( args )) sent in the context of an object o (i.e. 101 * sent in a method or closure where the self pseudovariable is bound to o) are 102 * delegated to the base-level send method of the actor in which the object o is 103 * contained. 104 */ 105 public ATObject meta_send(ATAsyncMessage message) throws InterpreterException { 106 return OBJLexicalRoot._INSTANCE_.base_getActor().base_send(message); 107 } 108 109 /** 110 * By default, when an object receives an incoming asynchronous message, it tells 111 * the message to process itself. The message's default behaviour is to subsequently 112 * invoke the method corresponding to the message's selector on this object. 113 */ 114 public ATObject meta_receive(ATAsyncMessage message) throws InterpreterException { 115 return message.base_process(this); 116 } 117 118 /** 119 * The default behaviour of 'invoke' for primitive non-object ambienttalk language values is 120 * to check whether the requested functionality is provided by a native Java method 121 * with the same selector, but prefixed with <tt>base_</tt>. 122 * 123 * Because an explicit AmbientTalk method invocation must be converted into an implicit 124 * Java method invocation, the invocation must be deified ('upped'). The result of the 125 * upped invocation is a Java object, which must subsequently be 'downed' again. 126 * 127 * If no method to invoke is found, doesNotUnderstand is invoked which should 128 * return a closure to be invoked with the appropriate arguments. 129 */ 130 public ATObject meta_invoke(ATObject receiver, ATSymbol atSelector, ATTable arguments) throws InterpreterException { 131 try { 132 String jSelector = Reflection.upBaseLevelSelector(atSelector); 133 return Reflection.upInvocation(this /*receiver*/, jSelector, atSelector, arguments); 134 } catch (XSelectorNotFound e) { 135 e.catchOnlyIfSelectorEquals(atSelector); 136 return receiver.meta_doesNotUnderstand(atSelector).asClosure().base_apply(arguments); 137 } 138 } 139 140 /** 141 * An ambienttalk language value can respond to a message if it implements 142 * a native Java method corresponding to the selector prefixed by 'base_'. 143 */ 144 public ATBoolean meta_respondsTo(ATSymbol atSelector) throws InterpreterException { 145 String jSelector = Reflection.upBaseLevelSelector(atSelector); 146 return NATBoolean.atValue(Reflection.upRespondsTo(this, jSelector)); 147 } 148 149 /** 150 * By default, when a selection is not understood by a primitive object, an error is raised. 151 */ 152 public ATObject meta_doesNotUnderstand(ATSymbol selector) throws InterpreterException { 153 throw new XSelectorNotFound(selector, this); 154 } 155 156 /* ------------------------------------------ 157 * -- Slot accessing and mutating protocol -- 158 * ------------------------------------------ */ 159 160 /** 161 * It is possible to select a method from any ambienttalk value provided that it 162 * offers the method in its provided interface. The result is a NativeMethod wrapper 163 * which encapsulates the reflective Method object as well as the receiver. 164 * 165 * There exists a certain ambiguity in field selection on AmbientTalk implementation-level objects. 166 * When nativeObject.m is evaluated, the corresponding Java class must have a method named either 167 * base_getM which means m is represented as a readable field, or 168 * base_m which means m is represented as a method 169 */ 170 public ATObject meta_select(ATObject receiver, ATSymbol selector) throws InterpreterException { 171 String jSelector = Reflection.upBaseFieldAccessSelector(selector); 172 try { 173 return Reflection.upFieldSelection(this, jSelector, selector); 174 } catch (XSelectorNotFound e) { 175 e.catchOnlyIfSelectorEquals(selector); 176 jSelector = Reflection.upBaseLevelSelector(selector); 177 178 try { 179 return Reflection.upMethodSelection(this, jSelector, selector); 180 } catch (XSelectorNotFound e2) { 181 e2.catchOnlyIfSelectorEquals(selector); 182 return receiver.meta_doesNotUnderstand(selector); 183 } 184 } 185 } 186 187 /** 188 * A lookup can only be issued at the base level by writing <tt>selector</tt> inside the scope 189 * of a particular object. For primitive language values, this should not happen 190 * as no AmbientTalk code can be possibly nested within native code. However, using 191 * meta-programming a primitive object could be installed as the lexical parent of an AmbientTalk object. 192 * 193 * One particular case where this method will often be called is when a lookup reaches 194 * the lexical root, OBJLexicalRoot, which inherits this implementation. 195 * 196 * In such cases a lookup is treated exactly like a selection, where the 'original receiver' 197 * of the selection equals the primitive object. 198 */ 199 public ATObject meta_lookup(ATSymbol selector) throws InterpreterException { 200 try { 201 return this.meta_select(this, selector); 202 } catch(XSelectorNotFound e) { 203 // transform selector not found in undefined variable access 204 throw new XUndefinedSlot("variable access", selector.base_getText().asNativeText().javaValue); 205 } 206 } 207 208 public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException { 209 throw new XIllegalOperation("Cannot add fields to " + Evaluator.valueNameOf(this.getClass())); 210 } 211 212 /** 213 * Normally, a variable assignment cannot be performed on a native AmbientTalk object. 214 * This is because a variable assignment can normally be only raised by performing 215 * an assignment in the lexical scope of an object. However, using metaprogramming 216 * a native object could be installed as the lexical parent of an AT object. In such 217 * cases, variable assignment is treated as field assignment. 218 * 219 * One particular case where this method will often be called is when a variable assignment reaches 220 * the lexical root, OBJLexicalRoot, which inherits this implementation. 221 */ 222 public ATNil meta_assignVariable(ATSymbol name, ATObject value) throws InterpreterException { 223 return this.meta_assignField(this, name, value); 224 } 225 226 public ATNil meta_assignField(ATObject receiver, ATSymbol name, ATObject value) throws InterpreterException { 227 String jSelector = Reflection.upBaseFieldMutationSelector(name); 228 229 // try to invoke a native base_setName method 230 try { 231 Reflection.upFieldAssignment(receiver, jSelector, name, value); 232 } catch (XSelectorNotFound e) { 233 e.catchOnlyIfSelectorEquals(name); 234 // if such a method does not exist, the field assignment has failed 235 throw new XUnassignableField(name.base_getText().asNativeText().javaValue); 236 } 237 238 return NATNil._INSTANCE_; 239 } 240 241 /* ------------------------------------ 242 * -- Extension and cloning protocol -- 243 * ------------------------------------ */ 244 245 public ATObject meta_clone() throws InterpreterException { 246 throw new XIllegalOperation("Cannot clone a native object of type " + this.getClass().getName()); 247 } 248 249 public ATObject meta_newInstance(ATTable initargs) throws InterpreterException { 250 return Reflection.upInstanceCreation(this, initargs); 251 } 252 253 /* --------------------------------- 254 * -- Structural Access Protocol -- 255 * --------------------------------- */ 256 257 public ATNil meta_addField(ATField field) throws InterpreterException { 258 throw new XIllegalOperation("Cannot add fields to " + Evaluator.valueNameOf(this.getClass())); 259 } 260 261 public ATNil meta_addMethod(ATMethod method) throws InterpreterException { 262 throw new XIllegalOperation("Cannot add methods to " + Evaluator.valueNameOf(this.getClass())); 263 } 264 265 public ATField meta_grabField(ATSymbol fieldName) throws InterpreterException { 266 return Reflection.downBaseLevelField(this, fieldName); 267 } 268 269 public ATMethod meta_grabMethod(ATSymbol methodName) throws InterpreterException { 270 return Reflection.downBaseLevelMethod(this, methodName); 271 } 272 273 public ATTable meta_listFields() throws InterpreterException { 274 return NATTable.atValue(Reflection.downBaseLevelFields(this)); 275 } 276 277 public ATTable meta_listMethods() throws InterpreterException { 278 return NATTable.atValue(Reflection.downBaseLevelMethods(this)); 279 } 280 281 /* --------------------------------- 282 * -- Abstract Grammar Protocol -- 283 * --------------------------------- */ 284 285 /** 286 * All NATObjects which are not Abstract Grammar elements are self-evaluating. 287 */ 288 public ATObject meta_eval(ATContext ctx) throws InterpreterException { 289 return this; 290 } 291 292 /** 293 * Quoting a native object returns itself, except for pure AG elements. 294 */ 295 public ATObject meta_quote(ATContext ctx) throws InterpreterException { 296 return this; 297 } 298 299 public NATText meta_print() throws InterpreterException { 300 return NATText.atValue("nil"); 301 } 302 303 /* ------------------------------ 304 * -- ATObject Mirror Fields -- 305 * ------------------------------ */ 306 307 /** 308 * Native objects have a SHARES-A parent link to 'nil', by default. 309 */ 310 public ATBoolean meta_isExtensionOfParent() throws InterpreterException { 311 return NATBoolean.atValue((NATObject._SHARES_A_)); 312 }; 313 314 /** 315 * By default numbers, tables and so on do not have lexical parents, 316 */ 317 public ATObject meta_getLexicalParent() throws InterpreterException { 318 return NATNil._INSTANCE_; 319 } 320 321 /* --------------------------------- 322 * -- Value Conversion Protocol -- 323 * --------------------------------- */ 324 325 public boolean isSymbol() throws InterpreterException { 326 return false; 327 } 328 329 public boolean isTable() throws InterpreterException { 330 return false; 331 } 332 333 public boolean isCallFrame() throws InterpreterException { 334 return false; 335 } 336 337 public boolean isUnquoteSplice() throws InterpreterException { 338 return false; 339 } 340 341 public boolean isVariableAssignment() throws InterpreterException { 342 return false; 343 } 344 345 public boolean isSplice() throws InterpreterException { 346 return false; 347 } 348 349 public boolean isMessageCreation() throws InterpreterException { 350 return false; 351 } 352 353 public boolean isAmbientTalkObject() { 354 return false; 355 } 356 357 public boolean isJavaObjectUnderSymbiosis() { 358 return false; 359 } 360 361 public boolean isNativeBoolean() { 362 return false; 363 } 364 365 public boolean isNativeText() { 366 return false; 367 } 368 369 public boolean isNativeField() { 370 return false; 371 } 372 373 public boolean isTypeTag() throws InterpreterException { 374 return false; 375 } 376 377 public ATClosure asClosure() throws InterpreterException { 378 throw new XTypeMismatch(ATClosure.class, this); 379 } 380 381 public ATSymbol asSymbol() throws InterpreterException { 382 throw new XTypeMismatch(ATSymbol.class, this); 383 } 384 385 public ATTable asTable() throws InterpreterException { 386 throw new XTypeMismatch(ATTable.class, this); 387 } 388 389 public ATBoolean asBoolean() throws InterpreterException { 390 throw new XTypeMismatch(ATBoolean.class, this); 391 } 392 393 public ATNumber asNumber() throws InterpreterException { 394 throw new XTypeMismatch(ATNumber.class, this); 395 } 396 397 public ATMessage asMessage() throws InterpreterException { 398 throw new XTypeMismatch(ATMessage.class, this); 399 } 400 401 public ATField asField() throws InterpreterException { 402 throw new XTypeMismatch(ATField.class, this); 403 } 404 405 public ATMethod asMethod() throws InterpreterException { 406 throw new XTypeMismatch(ATMethod.class, this); 407 } 408 409 public ATHandler asHandler() throws InterpreterException { 410 throw new XTypeMismatch(ATHandler.class, this); 411 } 412 413 public ATTypeTag asTypeTag() throws InterpreterException { 414 throw new XTypeMismatch(ATTypeTag.class, this); 415 } 416 417 // Conversions for concurrency and distribution related object 418 public boolean isFarReference() { 419 return false; 420 } 421 422 public ATFarReference asFarReference() throws InterpreterException { 423 throw new XTypeMismatch(ATFarReference.class, this); 424 } 425 426 public ATAsyncMessage asAsyncMessage() throws InterpreterException { 427 throw new XTypeMismatch(ATAsyncMessage.class, this); 428 } 429 430 public ATActorMirror asActorMirror() throws InterpreterException { 431 throw new XTypeMismatch(ATActorMirror.class, this); 432 } 433 434 // Conversions for abstract grammar elements 435 436 public ATStatement asStatement() throws InterpreterException { 437 throw new XTypeMismatch(ATStatement.class, this); 438 } 439 440 public ATDefinition asDefinition() throws InterpreterException { 441 throw new XTypeMismatch(ATDefinition.class, this); 442 } 443 444 public ATExpression asExpression() throws InterpreterException { 445 return this; 446 } 447 448 public ATBegin asBegin() throws InterpreterException { 449 throw new XTypeMismatch(ATBegin.class, this); 450 } 451 452 public ATMessageCreation asMessageCreation() throws InterpreterException { 453 throw new XTypeMismatch(ATMessageCreation.class, this); 454 } 455 456 public ATUnquoteSplice asUnquoteSplice() throws InterpreterException { 457 throw new XTypeMismatch(ATUnquoteSplice.class, this); 458 } 459 460 public ATAssignVariable asVariableAssignment() throws InterpreterException { 461 throw new XTypeMismatch(ATAssignVariable.class, this); 462 } 463 464 public ATSplice asSplice() throws InterpreterException { 465 throw new XTypeMismatch(ATSplice.class, this); 466 } 467 468 // Conversions for native values 469 public NATObject asAmbientTalkObject() throws XTypeMismatch { 470 throw new XTypeMismatch(NATObject.class, this); 471 } 472 473 public NATMirage asMirage() throws XTypeMismatch { 474 throw new XTypeMismatch(NATMirage.class, this); 475 } 476 477 public NATNumber asNativeNumber() throws XTypeMismatch { 478 throw new XTypeMismatch(NATNumber.class, this); 479 } 480 481 public NATFraction asNativeFraction() throws XTypeMismatch { 482 throw new XTypeMismatch(NATFraction.class, this); 483 } 484 485 public NATText asNativeText() throws XTypeMismatch { 486 throw new XTypeMismatch(NATText.class, this); 487 } 488 489 public NATTable asNativeTable() throws XTypeMismatch { 490 throw new XTypeMismatch(NATTable.class, this); 491 } 492 493 public NATBoolean asNativeBoolean() throws XTypeMismatch { 494 throw new XTypeMismatch(NATBoolean.class, this); 495 } 496 497 public NATNumeric asNativeNumeric() throws XTypeMismatch { 498 throw new XTypeMismatch(NATNumeric.class, this); 499 } 500 501 public NATFarReference asNativeFarReference() throws XTypeMismatch { 502 throw new XTypeMismatch(NATFarReference.class, this); 503 } 504 505 public JavaObject asJavaObjectUnderSymbiosis() throws XTypeMismatch { 506 throw new XTypeMismatch(JavaObject.class, this); 507 } 508 509 public JavaClass asJavaClassUnderSymbiosis() throws XTypeMismatch { 510 throw new XTypeMismatch(JavaClass.class, this); 511 } 512 513 /** 514 * Only true objects have a dynamic pointer, native objects denote 'nil' to 515 * be their dynamic parent when asked for it. Note that, for native objects, 516 * 'super' is a read-only field (i.e. there is no base_setSuper). 517 */ 518 public ATObject base_getSuper() throws InterpreterException { 519 return NATNil._INSTANCE_; 520 }; 521 522 public String toString() { 523 return Evaluator.toString(this); 524 } 525 526 /** 527 * Java method invocations of equals are transformed into 528 * AmbientTalk '==' method invocations. 529 */ 530 public boolean equals(Object other) { 531 try { 532 if (other instanceof ATObject) { 533 return this.base__opeql__opeql_((ATObject) other).asNativeBoolean().javaValue; 534 } else if (other instanceof SymbioticATObjectMarker) { 535 return this.base__opeql__opeql_( 536 ((SymbioticATObjectMarker) other)._returnNativeAmbientTalkObject()).asNativeBoolean().javaValue; 537 } 538 } catch (InterpreterException e) { 539 Logging.Actor_LOG.warn("Error during equality testing:", e); 540 } 541 return false; 542 } 543 544 /** 545 * By default, two AmbientTalk objects are equal if they are the 546 * same object, or one is a proxy for the same object. 547 */ 548 public ATBoolean base__opeql__opeql_(ATObject other) throws InterpreterException { 549 // by default, ATObjects use pointer equality 550 return NATBoolean.atValue(this == other); 551 } 552 553 public ATObject base_new(ATObject[] initargs) throws InterpreterException { 554 return this.meta_newInstance(NATTable.atValue(initargs)); 555 } 556 557 public ATObject base_init(ATObject[] initargs) throws InterpreterException { 558 return NATNil._INSTANCE_; 559 } 560 561 public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException { 562 return NATBoolean.atValue( 563 this.getClass() == original.getClass()); 564 } 565 566 public ATBoolean meta_isRelatedTo(ATObject object) throws InterpreterException { 567 return this.meta_isCloneOf(object); 568 } 569 570 /* --------------------------------- 571 * -- Type Testing and Querying -- 572 * --------------------------------- */ 573 574 /** 575 * Native objects implement the type test non-recursively: only the type tags 576 * returned by {@link this#meta_getTypeTags()} are tested against. 577 */ 578 public ATBoolean meta_isTaggedAs(ATTypeTag type) throws InterpreterException { 579 ATObject[] types = this.meta_getTypeTags().asNativeTable().elements_; 580 for (int i = 0; i < types.length; i++) { 581 if (types[i].asTypeTag().base_isSubtypeOf(type).asNativeBoolean().javaValue) { 582 return NATBoolean._TRUE_; 583 } 584 } 585 return NATBoolean._FALSE_; 586 } 587 588 /** 589 * By default, a native object (and also nil) has no type tags. 590 */ 591 public ATTable meta_getTypeTags() throws InterpreterException { 592 return NATTable.EMPTY; 593 } 594 595 /* ----------------------------- 596 * -- Object Passing protocol -- 597 * ----------------------------- */ 598 599 /** 600 * This method allows objects to decide which object should be serialized in their 601 * stead when they are passed as argument in an asynchronous message send that 602 * crosses actor boundaries. By default, nil decides that it is safe to serialize 603 * the object itself. Special objects such as e.g. closures should override this 604 * method and return a far reference encoding instead. 605 */ 606 public ATObject meta_pass() throws InterpreterException { 607 return this; 608 } 609 610 /** 611 * After deserialization, ensure that nil remains unique. 612 */ 613 public ATObject meta_resolve() throws InterpreterException { 614 return NATNil._INSTANCE_; 615 } 616 617 /** 618 * Delegate the responsibility of serialization to the AT/2 meta-level 619 */ 620 public Object writeReplace() throws ObjectStreamException { 621 try { 622 return this.meta_pass(); 623 } catch(InterpreterException e) { 624 throw new InvalidObjectException("Failed to pass object " + this + ": " + e.getMessage()); 625 } 626 } 627 628 /** 629 * Delegate the responsibility of deserialization to the AT/2 meta-level 630 */ 631 public Object readResolve() throws ObjectStreamException { 632 try { 633 return this.meta_resolve(); 634 } catch(InterpreterException e) { 635 throw new SerializationException(e); 636 } 637 } 638 639}