/interpreter/tags/at2dist091109/src/edu/vub/at/objects/natives/NativeATObject.java

http://ambienttalk.googlecode.com/ · Java · 1037 lines · 591 code · 135 blank · 311 comment · 67 complexity · 0c424b575d2ec74347d2fc8fe373ac03 MD5 · raw file

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