/interpreter/tags/at2-build060407/src/edu/vub/at/objects/natives/OBJLexicalRoot.java
Java | 992 lines | 275 code | 92 blank | 625 comment | 8 complexity | ce2518522c49f5d35d5e1fddff939ba6 MD5 | raw file
1/** 2 * AmbientTalk/2 Project 3 * OBJLexicalRoot.java created on 8-aug-2006 at 16:51:10 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.ATFarReference; 32import edu.vub.at.actors.natives.ELActor; 33import edu.vub.at.actors.natives.ELVirtualMachine; 34import edu.vub.at.actors.natives.NATActorMirror; 35import edu.vub.at.actors.natives.NATFarReference; 36import edu.vub.at.actors.natives.Packet; 37import edu.vub.at.actors.net.OBJNetwork; 38import edu.vub.at.eval.Evaluator; 39import edu.vub.at.exceptions.InterpreterException; 40import edu.vub.at.exceptions.XAmbienttalk; 41import edu.vub.at.objects.ATAbstractGrammar; 42import edu.vub.at.objects.ATBoolean; 43import edu.vub.at.objects.ATClosure; 44import edu.vub.at.objects.ATHandler; 45import edu.vub.at.objects.ATMethod; 46import edu.vub.at.objects.ATNil; 47import edu.vub.at.objects.ATNumber; 48import edu.vub.at.objects.ATObject; 49import edu.vub.at.objects.ATStripe; 50import edu.vub.at.objects.ATTable; 51import edu.vub.at.objects.ATText; 52import edu.vub.at.objects.coercion.NativeStripes; 53import edu.vub.at.objects.mirrors.NATMirage; 54import edu.vub.at.objects.mirrors.OBJMirrorRoot; 55import edu.vub.at.objects.symbiosis.JavaObject; 56import edu.vub.at.objects.symbiosis.XJavaException; 57import edu.vub.at.parser.NATParser; 58 59/** 60 * An instance of the class OBJLexicalRoot represents the lexical root of an actor. 61 * Since a lexical root is sealed (it cannot be modified) and contains no mutable fields, 62 * it should be possible to share a singleton instance of this class among all actors. 63 * 64 * The lexical root is an object containing globally visible AmbientTalk native methods. 65 * Such methods include control structures such as if:then:else: and while:do: 66 * but also object creation methods like object: and extend:with: 67 * 68 * Furthermore, the lexical root is also responsible for ending recursive meta-level methods 69 * such as lookup and assignField. 70 * 71 * OBJLexicalRoot extends NATNil such that it inherits that class's ATObject protocol 72 * to convert AmbientTalk invocations of a method m into Java base_m invocations. 73 * 74 * Note that OBJLexicalRoot is a 'sentinel' class. The actual object bound to the 75 * lexical root of an actor will be a normal NATObject which is assumed to be 'nested' in this instance. 76 * This empty object is local to each actor and is mutable. 77 * 78 * @author smostinc 79 * @author tvcutsem 80 */ 81public final class OBJLexicalRoot extends NATByCopy { 82 83 /** 84 * The singleton instance of the sentinel lexical root 85 */ 86 static public final OBJLexicalRoot _INSTANCE_ = new OBJLexicalRoot(); 87 88 /** 89 * Constructor made private for singleton design pattern 90 */ 91 private OBJLexicalRoot() { } 92 93 /* ----------------------- 94 * -- Primitive Methods -- 95 * ----------------------- */ 96 97 /* =============================================================================== 98 * NOTE: the code below has been replaced by dedicated syntax and AST elements. 99 * However, the skeleton of this code may still prove useful in the future, if 100 * we ever plan to implement all base_ native methods as true AmbientTalk methods 101 * (i.e. as PrimitiveMethod instances). 102 * =============================================================================== 103 */ 104 105 106 /* 107 private static final AGSymbol _IMPORT_NAME_ = AGSymbol.jAlloc("import:"); 108 private static final AGSymbol _IMPORT_ALIAS_NAME_ = AGSymbol.jAlloc("import:alias:"); 109 private static final AGSymbol _IMPORT_EXCLUDE_NAME_ = AGSymbol.jAlloc("import:exclude:"); 110 private static final AGSymbol _IMPORT_ALIAS_EXCLUDE_NAME_ = AGSymbol.jAlloc("import:alias:exclude:"); 111 112 private static final AGSymbol _SRC_PARAM_ = AGSymbol.jAlloc("sourceObject"); 113 private static final AGSymbol _ALIAS_PARAM_ = AGSymbol.jAlloc("aliases"); 114 private static final AGSymbol _EXCLUDE_PARAM_ = AGSymbol.jAlloc("exclude"); 115 */ 116 117 118 /*protected static final PrimitiveMethod _PRIM_IMPORT_ = new PrimitiveMethod(_IMPORT_NAME_, NATTable.atValue(new ATObject[] { _SRC_PARAM_ })) { 119 public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException { 120 ATObject sourceObject = arguments.base_at(NATNumber.ONE); 121 return performImport(sourceObject, ctx, new Hashtable(), OBJLexicalRoot.getDefaultExcludedSlots()); 122 } 123 };*/ 124 125 /** 126 * def import: sourceObject alias: [ `oldname -> `newname , ... ] 127 */ 128 /*protected static final PrimitiveMethod _PRIM_IMPORT_ALIAS_ = new PrimitiveMethod(_IMPORT_ALIAS_NAME_, NATTable.atValue(new ATObject[] { _SRC_PARAM_, _ALIAS_PARAM_ })) { 129 public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException { 130 ATObject sourceObject = arguments.base_at(NATNumber.ONE); 131 ATObject aliases = arguments.base_at(NATNumber.atValue(2)); 132 return performImport(sourceObject, ctx, preprocessAliases(aliases.base_asTable()), OBJLexicalRoot.getDefaultExcludedSlots()); 133 } 134 };*/ 135 136 /** 137 * def import: sourceObject excludes: [ `name1, `name2, ... ] 138 */ 139 /*protected static final PrimitiveMethod _PRIM_IMPORT_EXCLUDE_ = new PrimitiveMethod(_IMPORT_EXCLUDE_NAME_, NATTable.atValue(new ATObject[] { _SRC_PARAM_, _EXCLUDE_PARAM_ })) { 140 public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException { 141 ATObject sourceObject = arguments.base_at(NATNumber.ONE); 142 ATObject exclusions = arguments.base_at(NATNumber.atValue(2)); 143 return performImport(sourceObject, ctx, new Hashtable(), preprocessExcludes(exclusions.base_asTable())); 144 } 145 };*/ 146 147 /** 148 * def import: sourceObject alias: [ `oldname -> `newname, ... ] excludes: [ `name1, `name2, ... ] 149 */ 150 /*protected static final PrimitiveMethod _PRIM_IMPORT_ALIAS_EXCLUDE_ = new PrimitiveMethod(_IMPORT_ALIAS_EXCLUDE_NAME_, 151 NATTable.atValue(new ATObject[] { _SRC_PARAM_, _ALIAS_PARAM_, _EXCLUDE_PARAM_ })) { 152 public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException { 153 ATObject sourceObject = arguments.base_at(NATNumber.ONE); 154 ATObject aliases = arguments.base_at(NATNumber.atValue(2)); 155 ATObject exclusions = arguments.base_at(NATNumber.atValue(3)); 156 return performImport(sourceObject, ctx, preprocessAliases(aliases.base_asTable()), preprocessExcludes(exclusions.base_asTable())); 157 } 158 };*/ 159 160 /** 161 * Invoked whenever a new true AmbientTalk object is created that should 162 * represent the root. This gives the lexical root a chance to install its 163 * primitive methods. 164 */ 165 /*public static void initializeRoot(NATObject root) { 166 try { 167 // add import: native 168 root.meta_addMethod(_PRIM_IMPORT_); 169 // add import:alias: native 170 root.meta_addMethod(_PRIM_IMPORT_ALIAS_); 171 // add import:exclude: native 172 root.meta_addMethod(_PRIM_IMPORT_EXCLUDE_); 173 // add import:alias:exclude: native 174 root.meta_addMethod(_PRIM_IMPORT_ALIAS_EXCLUDE_); 175 } catch (InterpreterException e) { 176 Logging.Init_LOG.fatal("Failed to initialize the root!", e); 177 } 178 }*/ 179 180 /* ---------------------- 181 * -- Global variables -- 182 * ---------------------- */ 183 184 /** 185 * nil 186 */ 187 public ATNil base_getNil() { 188 return NATNil._INSTANCE_; 189 } 190 191 /** 192 * true 193 */ 194 public ATBoolean base_getTrue() { 195 return NATBoolean._TRUE_; 196 } 197 198 /** 199 * false 200 */ 201 public ATBoolean base_getFalse() { 202 return NATBoolean._FALSE_; 203 } 204 205 /** 206 * '/' (the global namespace) 207 * '/' is an alias for 'lobby' 208 */ 209 public ATObject base_get_opdiv_() { 210 return base_getLobby(); 211 } 212 213 /** 214 * lobby (the global namespace initialized using the objectpath) 215 */ 216 public ATObject base_getLobby() { 217 return Evaluator.getLobbyNamespace(); 218 } 219 220 /** 221 * root (the global scope) 222 */ 223 public ATObject base_getRoot() { 224 return Evaluator.getGlobalLexicalScope(); 225 } 226 227 /** 228 * jlobby (the Java class package root, initialized using the Java classpath) 229 */ 230 public ATObject base_getJlobby() { 231 return Evaluator.getJLobbyRoot(); 232 } 233 234 /** 235 * network (the network control object, to go online and offline) 236 */ 237 public ATObject base_getNetwork() { 238 return OBJNetwork._INSTANCE_; 239 } 240 241 /** 242 * defaultMirror (the default mirror on objects) 243 */ 244 public ATObject base_getDefaultMirror() { 245 return Evaluator.getMirrorRoot(); 246 } 247 248 /* ------------------------ 249 * -- Control Structures -- 250 * ------------------------ */ 251 252 /** 253 * The if:then: primitive, which calls back on the boolean using ifTrue: 254 * 255 * usage: 256 * if: booleanCondition then: { consequent } 257 * 258 * @param cond a boolean object 259 * @param consequent a closure containing the code to execute if the boolean is true 260 * @return the result of invoking booleanCondition.ifTrue: { consequent } 261 * @throws InterpreterException if raised inside the consequent closure. 262 */ 263 public ATObject base_if_then_(ATBoolean cond, ATClosure consequent) throws InterpreterException { 264 return cond.base_ifTrue_(consequent); 265 } 266 267 /** 268 * The if:then:else primitive, which calls back on the boolean using ifTrue:ifFalse: 269 * 270 * usage: 271 * if: booleanCondition then: { consequent } else: { alternative } 272 * 273 * pseudo-implementation: 274 * booleanCondition.ifTrue: { consequent } ifFalse: { alternative } 275 * 276 * @param cond a boolean object 277 * @param consequent a closure containing the code to execute if the boolean is true 278 * @param alternative a closure containing the code to execute if the boolean is false 279 * @return the result of invoking booleanCondition.ifTrue: { consequent } 280 * @throws InterpreterException if raised inside the consequent or alternative closure. 281 */ 282 public ATObject base_if_then_else_(ATBoolean cond, ATClosure consequent, ATClosure alternative) throws InterpreterException { 283 return cond.base_ifTrue_ifFalse_(consequent, alternative); 284 } 285 286 /** 287 * The while:do: primitive, which calls back on the closure using whileTrue: 288 * 289 * usage: 290 * while: { condition } do: { body } 291 * 292 * pseudo-implementation: 293 * { condition }.whileTrue: { body } 294 * 295 * @param condition a closure expected to return a boolean object 296 * @param body a closure containing the code to execute as long as the condition closure returns true 297 * @return the result of invoking { body }.whileTrue: { condition } 298 * @throws InterpreterException if raised inside the condition or body closures. 299 */ 300 public ATObject base_while_do_(ATClosure condition, ATClosure body) throws InterpreterException { 301 return condition.base_whileTrue_(body); 302 } 303 304 /** 305 * The foreach:in: primitive, which calls back on the table using each: 306 * 307 * usage: 308 * foreach: { |v| body } in: [ table ] 309 * 310 * pseudo-implementation: 311 * [ table ].each: { |v| body } 312 * 313 * @param body a closure expected to take one argument to be applied to each element of the table 314 * @param tab a table to apply the iterator block to 315 * @return the result of invoking [ table ].each: { |v| body } 316 * @throws InterpreterException if raised inside the iterator block. 317 */ 318 public ATObject base_foreach_in_(ATClosure body, ATTable tab) throws InterpreterException { 319 return tab.base_each_(body); 320 } 321 322 /** 323 * The do:if: primitive, which in Ruby terminology is a 'statement modifier' 324 * 325 * usage: 326 * do: { body } if: condition 327 * 328 * pseudo-implementation: 329 * condition.ifTrue: { body } 330 * 331 * @param body a zero-argument closure to execute if the condition is true 332 * @param condition a boolean expression 333 * @return the result of invoking body if the condition is true or nil if the condition is false 334 * @throws InterpreterException if raised inside the body block. 335 */ 336 public ATObject base_do_if_(ATClosure body, ATBoolean condition) throws InterpreterException { 337 return condition.base_ifTrue_(body); 338 } 339 340 /** 341 * The do:unless: primitive, which in Ruby terminology is a 'statement modifier' 342 * 343 * usage: 344 * do: { body } unless: condition 345 * 346 * pseudo-implementation: 347 * condition.ifFalse: { body } 348 * 349 * @param body a zero-argument closure to execute if the condition is false 350 * @param condition a boolean expression 351 * @return the result of invoking body if the condition is false or nil if the condition is true 352 * @throws InterpreterException if raised inside the body block. 353 */ 354 public ATObject base_do_unless_(ATClosure body, ATBoolean condition) throws InterpreterException { 355 return condition.base_ifFalse_(body); 356 } 357 358 /** 359 * The let: primitive, which allows for the easy creation of temporary local variables. 360 * This primitive should be used in conjunction with a closure that declares optional 361 * parameters. Because the closure will be invoked with zero arguments, all of the 362 * parameters will be given their corresponding default initial value. The parameters 363 * are defined local to the closure's body. 364 * 365 * Note: this let behaves like Scheme's let* and letrec, i.e. the following is legal: 366 * let: { |var1 := value1, var2 := var1, var3 := { ... var3() ... } | ... } 367 * 368 * usage: 369 * let: { |var := value| body } 370 * 371 * pseudo-implementation: 372 * def let: closure { closure() } 373 * 374 * @param body a closure which is supposed to declare some optional parameters 375 * @return the result of invoking the body closure 376 * @throws InterpreterException if raised inside the body block. 377 */ 378 public ATObject base_let_(ATClosure body) throws InterpreterException { 379 return body.base_apply(NATTable.EMPTY); 380 } 381 382 /* ------------------------------------------ 383 * -- Actor Creation and accessing Methods -- 384 * ------------------------------------------ */ 385 386 /** 387 * actor: { code } 388 * == actor: { code } mirroredBy: <default actor mirror> 389 * 390 * The semantics of actor creation is as follows: 391 * - Mandatory parameters to the block of initialization code are treated as lexically visible 392 * variables that have to remain available in the new actor behaviour. Hence, these variables 393 * are evaluated to values immediately at creation-time and parameter-passed to the new actor. 394 * - The closure containing the initialization code is unpacked, its lexical scope is disregarded 395 * and the unwrapped method is serialized and sent to the new actor, which can use it to 396 * initialize his behaviour object. 397 * - The creating actor waits for the created actor to spawn a new behaviour and to return a far 398 * reference to this behaviour. From that point on, the creating actor can run in parallel with 399 * the created actor, which only then evaluates the initialization code to initialize its behaviour. 400 * 401 */ 402 public ATObject base_actor_(ATClosure code) throws InterpreterException { 403 ATMethod method = code.base_getMethod(); 404 NATTable copiedBindings = Evaluator.evalMandatoryPars( 405 method.base_getParameters(), 406 code.base_getContext()); 407 408 Packet serializedBindings = new Packet("actor-bindings", copiedBindings); 409 Packet serializedInitCode = new Packet("actor-initcode", method); 410 ELVirtualMachine host = ELVirtualMachine.currentVM(); 411 return NATActorMirror.createActor(host, serializedBindings, serializedInitCode, new NATActorMirror(host)); 412 } 413 414 /** 415 * actor => a reference to a mirror on the current actor 416 */ 417 public ATActorMirror base_getActor() throws InterpreterException { 418 return ELActor.currentActor().getActorMirror(); 419 } 420 421 /** 422 * export: object as: topic 423 * => object becomes discoverable by objects in other actors via topic 424 * returns a publication object that can be used to cancel the export 425 */ 426 public ATObject base_export_as_(ATObject object, ATStripe topic) throws InterpreterException { 427 return ELActor.currentActor().getActorMirror().base_provide(topic, object); 428 } 429 430 /** 431 * when: topic discovered: { code } 432 * => when an object is exported by another actor under topic, trigger the code 433 * returns a subscription object that can be used to cancel the handler 434 * 435 * Once the code block has run once, it will not be triggered again. 436 */ 437 public ATObject base_when_discovered_(ATStripe topic, ATClosure handler) throws InterpreterException { 438 return ELActor.currentActor().getActorMirror().base_require(topic, handler, NATBoolean._FALSE_); 439 } 440 441 /** 442 * whenever: topic discovered: { code } 443 * => when an object is exported by another actor under topic, trigger the code 444 * returns a subscription object that can be used to cancel the handler 445 * 446 * The code block can be fired multiple times. To stop the block from triggering upon 447 * new publications, it must be explicitly cancelled 448 */ 449 public ATObject base_whenever_discovered_(ATStripe topic, ATClosure handler) throws InterpreterException { 450 return ELActor.currentActor().getActorMirror().base_require(topic, handler, NATBoolean._TRUE_); 451 } 452 453 /** 454 * when: farReference disconnected: { code } 455 * => when the remote reference is broken due to network disconnections, trigger the code 456 * returns a subscription object that can be used to cancel the listener 457 * 458 * The code of block will be also fired when the object referenced is taken offline. 459 */ 460 public ATObject base_when_disconnected_(ATFarReference farReference, ATClosure listener) throws InterpreterException { 461 farReference.asNativeFarReference().addDisconnectionListener(listener); 462 return new NATFarReference.NATDisconnectionSubscription(farReference.asNativeFarReference(), listener); 463 } 464 465 /** 466 * when: farReference reconnected: { code } 467 * => when the remote reference is reinstated after a network disconnection, trigger the code 468 * returns a subscription object that can be used to cancel the listener 469 */ 470 public ATObject base_when_reconnected_(ATFarReference farReference, ATClosure listener) throws InterpreterException { 471 farReference.asNativeFarReference().addReconnectionListener(listener); 472 return new NATFarReference.NATReconnectionSubscription(farReference.asNativeFarReference(), listener); 473 } 474 475 /** 476 * when: farReference expired: { code } 477 * => when the (remote/local) reference is broken because the object referenced expired ( i.e. it was 478 * taken offline), trigger the code returns a subscription object that can be used to cancel the listener 479 */ 480 public ATObject base_when_expired_(ATFarReference farReference, ATClosure listener) throws InterpreterException { 481 farReference.asNativeFarReference().addExpiredListener(listener); 482 return new NATFarReference.NATExpiredSubscription(farReference.asNativeFarReference(), listener); 483 } 484 485 486 /** 487 * retract: farReference 488 * => retract all currently unsent messages from the far reference's outbox 489 * This has the side effect that the returned messages will *not* be sent automatically anymore, 490 * the programmer is responsible to resend all messages that still need to be sent by hand. 491 * 492 * Note that the returned messages are copies of the original. 493 * @return a table with a copy of all the messages being sent. 494 */ 495 public ATTable base_retract_(ATFarReference farReference) throws InterpreterException { 496 return farReference.meta_retractUnsentMessages(); 497 } 498 499 /* ----------------------------- 500 * -- Object Creation Methods -- 501 * ----------------------------- */ 502 503 /** 504 * The object: primitive, implemented as base-level code. 505 * object: expects to be passed a closure such that it can extract the correct 506 * scope to be used as the object's lexical parent. 507 * 508 * usage: 509 * object: { someCode } 510 * 511 * pseudo-implementation: 512 * { def obj := objectP.new(mirrorOf(someCode).context.lexicalScope); 513 * mirrorOf(someCode).method.body.eval(contextP.new(obj, obj, nil)); 514 * obj } 515 * = object: { someCode } childOf: nil extends: false stripedWith: [] mirroredBy: mirrorroot 516 * 517 * The code block used to initialize the object may contain formal parameters. 518 * If this is the case, the formals are evaluated in the context of the lexical scope 519 * of the code block to values. These values are then bound to the formal parameters 520 * in the object itself. This is primarily useful for copying surrounding variables 521 * within the object, e.g. for isolates which lose access to their surrounding scope. 522 * 523 * @param code a closure containing both the code with which to initialize the object and the new object's lexical parent 524 * @return a new object whose dynamic parent is NIL, whose lexical parent is the closure's lexical scope, initialized by the closure's code 525 * @throws InterpreterException if raised inside the code closure. 526 */ 527 public ATObject base_object_(ATClosure code) throws InterpreterException { 528 // TODO: delegate to actor mirror? 529 return base_object_childOf_extends_stripedWith_mirroredBy_(code, NATNil._INSTANCE_, NATBoolean._FALSE_ /* SHARES-A link */, NATTable.EMPTY, base_getDefaultMirror()); 530 } 531 532 /** 533 * The extend:with: primitive, which delegates to the extend meta operation on the parent object. 534 * 535 * usage: 536 * extend: anObject with: { someCode } 537 * 538 * pseudo-implementation: 539 * = object: { someCode } childOf: anObject extends: true stripedWith: [] mirroredBy: mirrorroot 540 * 541 * @param parent the object to extend 542 * @param code a closure containing the code to extend the parent object with 543 * @return an object whose dynamic parent is an is-a link to the parent parameter 544 * @throws InterpreterException if raised inside the code closure. 545 */ 546 public ATObject base_extend_with_(ATObject parent, ATClosure code) throws InterpreterException { 547 // TODO: delegate to actor mirror? 548 return base_object_childOf_extends_stripedWith_mirroredBy_(code, parent, NATBoolean._TRUE_ /* IS-A link */, NATTable.EMPTY, base_getDefaultMirror()); 549 } 550 551 public ATObject base_extend_with_stripedWith_(ATObject parent, ATClosure code, ATTable stripes) throws InterpreterException { 552 // TODO: delegate to actor mirror? 553 return base_object_childOf_extends_stripedWith_mirroredBy_(code, parent, NATBoolean._TRUE_ /* IS-A link */, stripes, base_getDefaultMirror()); 554 } 555 556 public ATObject base_extend_with_mirroredBy_(ATObject parent, ATClosure code, ATObject mirror) throws InterpreterException { 557 // TODO: delegate to actor mirror? 558 return base_object_childOf_extends_stripedWith_mirroredBy_(code, parent, NATBoolean._TRUE_ /* IS-A link */, NATTable.EMPTY, mirror); 559 } 560 561 public ATObject base_extend_with_stripedWith_mirroredBy_(ATObject parent, ATClosure code, ATTable stripes, ATObject mirror) throws InterpreterException { 562 // TODO: delegate to actor mirror? 563 return base_object_childOf_extends_stripedWith_mirroredBy_(code, parent, NATBoolean._TRUE_ /* IS-A link */, stripes, mirror); 564 } 565 566 /** 567 * The share:with: primitive, which delegates to the share meta operation on the parent object. 568 * 569 * usage: 570 * share: anObject with: { someCode } 571 * 572 * pseudo-implementation: 573 * = object: { someCode } childOf: anObject extends: false stripedWith: [] mirroredBy: mirrorroot 574 * 575 * @param parent the object to extend 576 * @param code a closure containing the code to extend the parent object with 577 * @return an object whose dynamic parent is a shares-a link to the parent parameter 578 * @throws InterpreterException if raised inside the code closure. 579 */ 580 public ATObject base_share_with_(ATObject parent, ATClosure code) throws InterpreterException { 581 // TODO: delegate to actor mirror? 582 return base_object_childOf_extends_stripedWith_mirroredBy_(code, parent, NATBoolean._FALSE_ /* SHARES-A link */, NATTable.EMPTY, base_getDefaultMirror()); 583 } 584 585 public ATObject base_share_with_stripedWith_(ATObject parent, ATClosure code, ATTable stripes) throws InterpreterException { 586 // TODO: delegate to actor mirror? 587 return base_object_childOf_extends_stripedWith_mirroredBy_(code, parent, NATBoolean._FALSE_ /* SHARES-A link */, stripes, base_getDefaultMirror()); 588 } 589 590 public ATObject base_share_with_mirroredBy_(ATObject parent, ATClosure code, ATObject mirror) throws InterpreterException { 591 // TODO: delegate to actor mirror? 592 return base_object_childOf_extends_stripedWith_mirroredBy_(code, parent, NATBoolean._FALSE_ /* SHARES-A link */, NATTable.EMPTY, mirror); 593 } 594 595 public ATObject base_share_with_stripedWith_mirroredBy_(ATObject parent, ATClosure code, ATTable stripes, ATObject mirror) throws InterpreterException { 596 // TODO: delegate to actor mirror? 597 return base_object_childOf_extends_stripedWith_mirroredBy_(code, parent, NATBoolean._FALSE_ /* SHARES-A link */, stripes, mirror); 598 } 599 600 /** 601 * object: { code } stripedWith: [ s1, s2, ... ] 602 * => creates a new object tagged with the given stripes 603 * = object: { code } childOf: nil extends: false stripedWith: [ s1, s2, ... ] mirroredBy: mirrorroot 604 */ 605 public ATObject base_object_stripedWith_(ATClosure code, ATTable stripes) throws InterpreterException { 606 // TODO: delegate to actor mirror? 607 return base_object_childOf_extends_stripedWith_mirroredBy_(code, NATNil._INSTANCE_, NATBoolean._FALSE_ /* SHARES-A link */, stripes, base_getDefaultMirror()); 608 } 609 610 /** 611 * isolate: { code } 612 * => create an isolate object 613 * 614 * Equivalent to: 615 * object: { code } stripedWith: [ at.stripes.Isolate ] 616 */ 617 public ATObject base_isolate_(ATClosure code) throws InterpreterException { 618 return base_object_stripedWith_(code, NATTable.of(NativeStripes._ISOLATE_)); 619 } 620 621 /** 622 * The mirror: primitive, which allows creating custom mirrors which can be used 623 * to allow intercessive reflection on objects created from this mirror. 624 * 625 * usage: 626 * mirror: { someCode } 627 * 628 * pseudo-implementation: 629 * = object: { code } childOf: mirrorroot extends: true stripedWith: [] mirroredBy: mirrorroot 630 * 631 * @param code a closure containing both the code with which to initialize the mirror and the new mirror's lexical parent 632 * @return a new mirror containing the specified definitions 633 */ 634 public ATObject base_mirror_(ATClosure code) throws InterpreterException { 635 // TODO: delegate to actor mirror? 636 return base_object_childOf_extends_stripedWith_mirroredBy_(code, base_getDefaultMirror(), NATBoolean._TRUE_ /* IS-A link */, NATTable.EMPTY, base_getDefaultMirror()); 637 } 638 639 /** 640 * object: { code } mirroredBy: mirror 641 * => return an object mirage initialized with code 642 * = object: { code } childOf: nil extends: false stripedWith: [] mirroredBy: mirror 643 */ 644 public ATObject base_object_mirroredBy_(ATClosure code, ATObject mirror) throws InterpreterException { 645 // TODO: delegate to actor mirror? 646 return base_object_childOf_extends_stripedWith_mirroredBy_(code, NATNil._INSTANCE_, NATBoolean._FALSE_ /* SHARES-A link */, NATTable.EMPTY, mirror); 647 } 648 649 /** 650 * object: { code } stripedWith: [ s1, s2, ... ] mirroredBy: mirror 651 * => return an object mirage initialized with code and striped with the given stripes 652 * = object: { code } childOf: nil extends: false stripedWith: [s1, s2, ... ] mirroredBy: mirror 653 */ 654 public ATObject base_object_stripedWith_mirroredBy_(ATClosure code, ATTable stripes, ATObject mirror) throws InterpreterException { 655 // TODO: delegate to actor mirror? 656 return base_object_childOf_extends_stripedWith_mirroredBy_(code, NATNil._INSTANCE_, NATBoolean._FALSE_ /* SHARES-A link */, stripes, mirror); 657 } 658 659 /** 660 * object: { code } childOf: parent extends: parentType stripedWith: [ stripes ] mirroredBy: mirror 661 * => return a new object o initialized with code where: 662 * o.super == parent 663 * o.lexParent == code.lexScope 664 * o.parentType == parentType 665 * o.stripes == stripes 666 * (reflect: o) == mirror.new(o) 667 * 668 * @param code the code with which to initialize the object + the object's lexical parent 669 * @param parent the object that is to become the initial parent of the newly created object 670 * @param parentType if true, the child has an IS-A relationship with the parent, SHARES-A otherwise 671 * @param stripes the stripes with which the newly created object should be striped 672 * @param mirror the custom mirror for this object, or mirrorroot for a default object 673 * @return the new object, fully initialized with code 674 */ 675 public ATObject base_object_childOf_extends_stripedWith_mirroredBy_(ATClosure code, ATObject parent, ATBoolean parentType, ATTable stripes, ATObject mirror) throws InterpreterException { 676 ATStripe[] stripeArray = NATStripe.toStripeArray(stripes); 677 boolean parentRelation = parentType.asNativeBoolean().javaValue; 678 NATObject newObject; 679 // if the mirror is a 'default' mirror... 680 if (mirror instanceof OBJMirrorRoot) { 681 // then create a native object 682 newObject = new NATObject(parent, // dynamic parent 683 code.base_getContext().base_getLexicalScope(), // lexical parent 684 parentRelation, // IS-A or SHARES-A 685 stripeArray); // initial stripes 686 } else { 687 // else create a mirage mirrored by the custom mirror 688 newObject = NATMirage.createMirage(code, parent, parentRelation, stripeArray, mirror); 689 } 690 691 newObject.initializeWithCode(code); 692 return newObject; 693 } 694 695 /** 696 * The reflect: primitive, which returns a mirror on an object. 697 * 698 * usage: 699 * reflect: anObject 700 * 701 * pseudo-implementation: 702 * at.mirrors.mirrorfactory.createMirror(anObject) 703 * 704 * @param reflectee the object to reflect upon 705 * @return a mirror reflecting the given object 706 */ 707 public ATObject base_reflect_(ATObject reflectee) throws InterpreterException { 708 return base_getActor().base_createMirror(reflectee); 709 } 710 711 /** 712 * The clone: primitive, which returns a clone of an object. 713 * 714 * When a mirror is cloned, its base field is *shared* with the original mirror (because of 715 * shallow copy semantics). However, the base object will still be tied to the original mirror. 716 * Therefore, the clone: operator is implemented as follows: 717 * 718 * def clone: obj { 719 * if: (is: obj stripedWith: Mirror) then: { 720 * reflect: (clone: obj.base) 721 * } else: { 722 * (reflect: obj).clone() 723 * } 724 * } 725 * 726 * usage: 727 * clone: anObject 728 * 729 * @param original the object to copy 730 * @return a clone of the given object 731 */ 732 public ATObject base_clone_(ATObject original) throws InterpreterException { 733 if (original.meta_isStripedWith(NativeStripes._MIRROR_).asNativeBoolean().javaValue) { 734 return base_reflect_(base_clone_(original.meta_select(original, OBJMirrorRoot._BASE_NAME_))); 735 } else { 736 return original.meta_clone(); 737 } 738 } 739 740 /** 741 * takeOffline: obj 742 * => removes an object from the export table of an actor -i.e. the object is no longer 743 * remotely accessible. 744 * @return NIL 745 */ 746 public ATNil base_takeOffline_ (ATObject object) throws InterpreterException{ 747 748 ELActor.currentActor().takeOffline(object); 749 return NATNil._INSTANCE_; 750 } 751 752 /* ------------------- 753 * -- Stripe Support - 754 * ------------------- */ 755 756 /** 757 * is: object stripedWith: stripe 758 * => returns true if the given object is striped with the given stripe 759 */ 760 public ATBoolean base_is_stripedWith_(ATObject object, ATStripe stripe) throws InterpreterException { 761 return object.meta_isStripedWith(stripe); 762 } 763 764 /** 765 * stripesOf: object 766 * => returns all of the stripes of an object 767 */ 768 public ATTable base_stripesOf_(ATObject object) throws InterpreterException { 769 return object.meta_getStripes(); 770 } 771 772 /* ------------------------------- 773 * -- Exception Handling Support - 774 * ------------------------------- */ 775 776 /** 777 * try: { tryBlock } usingHandlers: [ handler1, handler2, ... ] 778 * 779 * Applies the given closure (to []) and handles exceptions using the given exception handlers. 780 * This is the most general means of doing exception handling in AmbientTalk/2. 781 * 782 * The handlers given in the handler table represent first-class handler objects, which should respond to the 'canHandle' message. 783 */ 784 public ATObject base_try_usingHandlers_(ATClosure tryBlock, ATTable exceptionHandlers) throws InterpreterException { 785 try { 786 return tryBlock.base_apply(NATTable.EMPTY); 787 } catch(InterpreterException e) { 788 ATObject[] handlers = exceptionHandlers.asNativeTable().elements_; 789 790 // find the appropriate handler 791 for (int i = 0; i < handlers.length; i++) { 792 ATHandler handler = handlers[i].asHandler(); 793 ATObject exc = e.getAmbientTalkRepresentation(); 794 if (handler.base_canHandle(exc).asNativeBoolean().javaValue) { 795 return handler.base_handle(exc); 796 }; 797 } 798 799 // no handler found, re-throw the exception 800 throw e; 801 } 802 } 803 804 /** 805 * try: { tryBlock} using: handler 806 * 807 * Ad-hoc code for one exception handler 808 */ 809 public ATObject base_try_using_(ATClosure tryBlock, ATHandler handler) throws InterpreterException { 810 try { 811 return tryBlock.base_apply(NATTable.EMPTY); 812 } catch(InterpreterException e) { 813 ATObject exc = e.getAmbientTalkRepresentation(); 814 if (handler.base_canHandle(exc).asNativeBoolean().javaValue) { 815 return handler.base_handle(exc); 816 } else { 817 throw e; 818 } 819 } 820 } 821 822 /** 823 * try: { tryBlock} using: handler1 using: handler2 824 * 825 * Ad-hoc code for two exception handlers 826 */ 827 public ATObject base_try_using_using_(ATClosure tryBlock, ATHandler hdl1, ATHandler hdl2) throws InterpreterException { 828 return base_try_usingHandlers_(tryBlock, NATTable.atValue(new ATObject[] { hdl1, hdl2 })); 829 } 830 831 /** 832 * try: { tryBlock} using: hdl1 using: hdl2 using: hdl3 833 * 834 * Ad-hoc code for three exception handlers 835 */ 836 public ATObject base_try_using_using_using_(ATClosure tryBlock, ATHandler hdl1, ATHandler hdl2, ATHandler hdl3) throws InterpreterException { 837 return base_try_usingHandlers_(tryBlock, NATTable.atValue(new ATObject[] { hdl1, hdl2, hdl3 })); 838 } 839 840 /** 841 * try: { tryBlock} catch: stripe using: { |e| replacementCode } 842 * 843 * 'Syntactic sugar' for one in-line handler 844 */ 845 public ATObject base_try_catch_using_(ATClosure tryBlock, ATStripe filter, ATClosure replacementCode) throws InterpreterException { 846 return base_try_using_(tryBlock, new NATHandler(filter, replacementCode)); 847 } 848 849 /** 850 * try: { 851 * tryBlock 852 * } catch: stripe using: { |e| 853 * replacementCode 854 * } catch: stripe2 using: { |e| 855 * replacementCode2 856 * } 857 * 858 * 'Syntactic sugar' for two in-line handlers 859 */ 860 public ATObject base_try_catch_using_catch_using_( ATClosure tryBlock, 861 ATStripe filter1, ATClosure hdl1, 862 ATStripe filter2, ATClosure hdl2) throws InterpreterException { 863 return base_try_using_using_(tryBlock, new NATHandler(filter1, hdl1), new NATHandler(filter2, hdl2)); 864 } 865 866 /** 867 * try: { 868 * tryBlock 869 * } catch: stripe using: { |e| 870 * replacementCode 871 * } catch: stripe2 using: { |e| 872 * replacementCode2 873 * } catch: stripe3 using: { |e| 874 * replacementCode3 875 * } 876 * 877 * 'Syntactic sugar' for three in-line handlers 878 */ 879 public ATObject base_try_catch_using_catch_using_catch_using_(ATClosure tryBlock, 880 ATStripe filter1, ATClosure hdl1, 881 ATStripe filter2, ATClosure hdl2, 882 ATStripe filter3, ATClosure hdl3) throws InterpreterException { 883 return base_try_using_using_using_(tryBlock, new NATHandler(filter1, hdl1), new NATHandler(filter2, hdl2), new NATHandler(filter3, hdl3)); 884 } 885 886 /** 887 * handle: stripe with: { |e| replacementCode } 888 * 889 * Creates a first-class handler from a filter prototype and some handler code. 890 */ 891 public ATObject base_handle_with_(ATStripe filter, ATClosure replacementCode) { 892 return new NATHandler(filter, replacementCode); 893 } 894 895 /** 896 * raise: exception 897 * 898 * Raises an exception which can be caught by dynamically installed try-catch-using blocks. 899 */ 900 public ATNil base_raise_(ATObject anExceptionObject) throws InterpreterException { 901 throw Evaluator.asNativeException(anExceptionObject); 902 } 903 904 /* -------------------- 905 * -- Unary Operators - 906 * -------------------- */ 907 908 /** 909 * The unary ! primitive: 910 * !b == b.not() 911 */ 912 public ATBoolean base__opnot_(ATBoolean b) throws InterpreterException { 913 return b.base_not(); 914 } 915 916 /** 917 * The unary - primitive: 918 * -NBR(n) == NBR(-n) 919 */ 920 public ATNumber base__opmns_(ATNumber n) throws InterpreterException { 921 return NATNumber.atValue(- n.asNativeNumber().javaValue); 922 } 923 924 /** 925 * The unary + primitive: 926 * +NBR(n) == NBR(n) 927 */ 928 public ATNumber base__oppls_(ATNumber n) throws InterpreterException { 929 return n; 930 } 931 932 /* ------------------- 933 * -- Miscellaneous -- 934 * ------------------- */ 935 936 /** 937 * read: "text" => parses the given string into an AST 938 */ 939 public ATAbstractGrammar base_read_(ATText source) throws InterpreterException { 940 return NATParser._INSTANCE_.base_parse(source); 941 } 942 943 /** 944 * eval: ast in: obj => evaluates the given AST in the context of the given object, returning its value 945 */ 946 public ATObject base_eval_in_(ATAbstractGrammar ast, ATObject obj) throws InterpreterException { 947 return ast.meta_eval(new NATContext(obj, obj)); 948 } 949 950 /** 951 * print: expression => string representing the expression 952 */ 953 public ATText base_print_(ATObject obj) throws InterpreterException { 954 return obj.meta_print(); 955 } 956 957 /** 958 * custom implementation of the default object methods == and new 959 * the reason for this custom implementation: during the execution 960 * of these methods, 'this' should refer to the global lexical scope object (the root), 961 * not to the OBJLexicalRoot instance. 962 * hence, when invoking one of these methods lexically, the receiver is always 'root' 963 * For example, "==(obj)" is equivalent to "root == obj" (or "root.==(obj)") 964 */ 965 public ATBoolean base__opeql__opeql_(ATObject comparand) throws InterpreterException { 966 return Evaluator.getGlobalLexicalScope().base__opeql__opeql_(comparand); 967 } 968 969 /** 970 * Invoking root.new(args) results in an exception for reasons of safety. 971 * We could also have opted to simply return 'root' (i.e. make it a singleton) 972 * 973 * The reason for being conservative and throwing an exception is 974 * that when writing 'new(args)' in an object that does not implement 975 * new itself, this will implicitly lead to invoking root.new(args), not 976 * self.new(args), as the user will probably have intended. 977 * To catch such bugs quickly, root.new throws an exception rather than 978 * silently returning the root itself. 979 */ 980 public ATObject base_new(ATObject[] initargs) throws InterpreterException { 981 // root.new(@initargs) 982 return Evaluator.getGlobalLexicalScope().base_new(initargs); 983 } 984 985 /** 986 * After deserialization, ensure that the lexical root remains unique. 987 */ 988 public ATObject meta_resolve() throws InterpreterException { 989 return OBJLexicalRoot._INSTANCE_; 990 } 991 992}