Commits

Taku Miyakawa  committed d366635

tailCall and tailInvoke methods return a specific tail-call instance instead of null

  • Participants
  • Parent commits 9c1dd4d
  • Branches issue520-call-result-type-hierarchy

Comments (0)

Files changed (10)

File src/main/java/org/kink_lang/kink/Fun.java

      * <p>The result of this method should be immediately returned
      * from a function action.</p>
      *
-     * @return {@code null}.
+     * @return
+     *      Result which indicates the tail-call.
      *
      * @see #tailCall(Value...)
      */
      * @param arg0
      *     Single argument.
      *
-     * @return {@code null}.
+     * @return
+     *      Result which indicates the tail-call.
      *
      * @see #tailCall(Value...)
      */
      * @param arg1
      *     Second argument.
      *
-     * @return {@code null}.
+     * @return
+     *      Result which indicates the tail-call.
      *
      * @see #tailCall(Value...)
      */
      * @param arg2
      *     Third argument.
      *
-     * @return {@code null}.
+     * @return
+     *      Result which indicates the tail-call.
      *
      * @see #tailCall(Value...)
      */
      * @param arguments
      *     Arguments of the call.
      *
-     * @return {@code null}.
+     * @return
+     *      Result which indicates the tail-call.
      */
     public final CallResult tailCall( Value ... arguments ) {
         Objects.requireNonNull( arguments , "arguments is null" );
      * @param receiver
      *     Receiver of a call.
      *
-     * @return {@code null}.
+     * @return
+     *      Result which indicates the tail-call.
      */
     public final CallResult tailInvoke( String symbol , Area area , Value receiver ) {
-        Invoker.setupTailCall( symbol , area , receiver , this
+        return Invoker.tailInvoke( symbol , area , receiver , this
                 , null , null , null , EMPTY_VALUES );
-        return null;
     }
 
 
      * @param arg0
      *     Single argument.
      *
-     * @return {@code null}.
+     * @return
+     *      Result which indicates the tail-call.
      */
     public final CallResult tailInvoke( String symbol , Area area , Value receiver
             , Value arg0 ) {
-        Invoker.setupTailCall( symbol , area , receiver , this
+        return Invoker.tailInvoke( symbol , area , receiver , this
                 , arg0 , null , null , null );
-        return null;
     }
 
 
      * @param arg1
      *     Second argument.
      *
-     * @return {@code null}.
+     * @return
+     *      Result which indicates the tail-call.
      */
     public final CallResult tailInvoke( String symbol , Area area , Value receiver
             , Value arg0 , Value arg1 ) {
-        Invoker.setupTailCall( symbol , area , receiver , this
+        return Invoker.tailInvoke( symbol , area , receiver , this
                 , arg0 , arg1 , null , null );
-        return null;
     }
 
 
      * @param arg2
      *     Third argument.
      *
-     * @return {@code null}.
+     * @return
+     *      Result which indicates the tail-call.
      */
     public final CallResult tailInvoke( String symbol , Area area , Value receiver
             , Value arg0 , Value arg1 , Value arg2 ) {
-        Invoker.setupTailCall( symbol , area , receiver , this
+        return Invoker.tailInvoke( symbol , area , receiver , this
                 , arg0 , arg1 , arg2 , null );
-        return null;
     }
 
 
      * @param args
      *     Arguments of a call.
      *
-     * @return {@code null}.
+     * @return
+     *      Result which indicates the tail-call.
      */
     public final CallResult tailInvoke( String symbol , Area area , Value receiver
             , Value ... args ) {
-        Invoker.setupTailCall( symbol , area , receiver , this
+        return Invoker.tailInvoke( symbol , area , receiver , this
                 , null , null , null , args );
-        return null;
     }
 
 

File src/main/java/org/kink_lang/kink/Value.java

      *     GetSite of the method.
      *
      * @return
-     *     {@code null}.
+     *     Result which indicates the tail-call.
      *
      * @throws KinkException
      *     If {@code this} receiver does not have the specified variable,
      *     First argument of the method call.
      *
      * @return
-     *     {@code null}.
+     *     Result which indicates the tail-call.
      *
      * @throws KinkException
      *     If {@code this} receiver does not have the specified variable,
      *     Second argument of the method call.
      *
      * @return
-     *     {@code null}.
+     *     Result which indicates the tail-call.
      *
      * @throws KinkException
      *     If {@code this} receiver does not have the specified variable,
      *     Third argument of the method call.
      *
      * @return
-     *     {@code null}.
+     *     Result which indicates the tail-call.
      *
      * @throws KinkException
      *     If {@code this} receiver does not have the specified variable,
      *     Arguments of the method call.
      *
      * @return
-     *     {@code null}.
+     *     Result which indicates the tail-call.
      *
      * @throws KinkException
      *     If {@code this} receiver does not have the specified variable,

File src/main/java/org/kink_lang/kink/internal/define/ReflectionMethodFunProxy.java

 
 
     /** Runs the function by reflection. */
-    private Value runReflection( Value receiver , Value[] args ) throws Throwable {
+    private CallResult runReflection( Value receiver , Value[] args ) throws Throwable {
         checkArguments( args.length );
         Object[] parameters = makeParameters( receiver , args );
         return invokeMethod( parameters );
 
 
     /** Invokes the backing method and returns the result. */
-    private Value invokeMethod( Object[] parameters ) throws Throwable {
+    private CallResult invokeMethod( Object[] parameters ) throws Throwable {
         try {
             Method method = javaMethod.getMethod();
-            Value result = (Value) method.invoke( definition , parameters );
+            CallResult result = (CallResult) method.invoke( definition , parameters );
             return ( javaMethod.isVoid() ? Value.base() : result );
         } catch ( InvocationTargetException exception ) {
             throw Exceptions.getCause( exception );

File src/main/java/org/kink_lang/kink/internal/invoke/Context.java

         while ( true ) {
             frame.pushTrace( symbol , area );
             CallResult result = runFun();
-            if ( result != null ) {
+            if ( result instanceof Value ) {
                 return (Value) result;
             }
         }

File src/main/java/org/kink_lang/kink/internal/invoke/Invoker.java

 
 import org.kink_lang.kink.Fun;
 import org.kink_lang.kink.Value;
+import org.kink_lang.kink.CallResult;
 import org.kink_lang.kink.Area;
 import org.kink_lang.kink.Trace;
 
      *
      * @param rawArgs
      *     Arguments; can be null.
+     *
+     * @return
+     *      Result which indicates the tail-call.
      */
-    public static void setupTailCall( String symbol , Area area
+    public static CallResult tailInvoke( String symbol , Area area
             , Value receiver , Fun fun
             , Value rawArg0 , Value rawArg1
             , Value rawArg2 , Value[] rawArgs ) {
         Context context = CONTEXTS.get();
+        // FIXME What happens if there is no context?
         if ( context != null ) {
             context.setupInvocation( symbol , area , receiver , fun
                     , rawArg0 , rawArg1 , rawArg2 , rawArgs );
         }
+        return TailCallResult.instance();
     }
 }
 

File src/main/java/org/kink_lang/kink/internal/invoke/TailCallResult.java

+/*
+ * Copyright (c) 2013 Miyakawa Taku
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.kink_lang.kink.internal.invoke;
+
+import org.kink_lang.kink.CallResult;
+
+/**
+ * Class to indicate a tail-call result.
+ *
+ * <p>Instances themselves do not hold any information.
+ * The current thread context holds the information about calling.</p>
+ */
+class TailCallResult implements CallResult {
+
+
+    /** Singleton tail-call result. */
+    private static final TailCallResult INSTANCE = new TailCallResult();
+
+    /**
+     * Returns the singleton tail-call result.
+     */
+    static TailCallResult instance() {
+        return INSTANCE;
+    }
+}
+
+// vim: et sw=4 sts=4

File src/test/java/org/kink_lang/kink/internal/eval/BinaryThenEvaluatorTest.java

 import static org.junit.Assert.assertThat;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.CoreMatchers.instanceOf;
 
 
 /**
 
 
     /** Evaluates 'then' on the tail context. */
-    private Value evaluateTail( Evaluator then ) {
-        Value ret = (Value) then.evaluateTail( env , receiver
+    private CallResult evaluateTail( Evaluator then ) {
+        CallResult ret = then.evaluateTail( env , receiver
                 , rawArg0 , rawArg1 , rawArg2 , rawArgs );
-        assertThat( ret , is( nullValue() ) );
-        return null;
+        assertThat( ret , is( not( instanceOf( Value.class ) ) ) );
+        return ret;
     }
 }
 

File src/test/java/org/kink_lang/kink/internal/eval/ThenUtilsTest.java

 import static org.junit.Assert.assertThat;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.nullValue;
 
 
     public void tail_block_fun() {
         final Fun tailBlockFun = ThenUtils.tailBlockFun( block );
         Fun caller = Fun.builder().build( receiver -> {
-            assertThat( tailBlockFun.tailInvoke( "then" , area , enclosingEnv )
-                    , is( nullValue() ) );
-            return null;
+            CallResult ret = tailBlockFun.tailInvoke( "then" , area , enclosingEnv );
+            assertThat( ret , is( not( instanceOf( Value.class ) ) ) );
+            return ret;
         } );
         assertThat( caller.call() , is( result ) );
     }

File src/test/java/org/kink_lang/kink/internal/eval/UnaryThenEvaluatorTest.java

 import static org.junit.Assert.assertThat;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.nullValue;
 
 
 
 
     /** Evaluates 'then' on the tail context. */
-    private Value evaluateTail( Evaluator then ) {
-        Value ret = (Value) then.evaluateTail( env , receiver
+    private CallResult evaluateTail( Evaluator then ) {
+        CallResult ret = then.evaluateTail( env , receiver
                 , rawArg0 , rawArg1 , rawArg2 , rawArgs );
-        assertThat( ret , is( nullValue() ) );
-        return null;
+        assertThat( ret , is( not( instanceOf( Value.class ) ) ) );
+        return ret;
     }
 }
 

File src/test/java/org/kink_lang/kink/internal/invoke/InvokerTest.java

     }
 
 
+    // FIXME this is not a good behaviour
     @Test
     public void no_effect_when_setup_tail_call_at_top_level() {
-        Invoker.setupTailCall( null , null , null , null
+        Invoker.tailInvoke( null , null , null , null
                 , null , null , null , null );
         assertThat( true , is( true ) );
     }