/interpreter/tags/at2-build270707/src/edu/vub/at/objects/natives/NativeATObject.java

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