/interpreter/tags/at_build150307/src/edu/vub/at/objects/natives/OBJLexicalRoot.java

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