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

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