001/*
002 * This file is part of OCaml-Java runtime.
003 * Copyright (C) 2007-2013 Xavier Clerc.
004 *
005 * OCaml-Java runtime is free software; you can redistribute it and/or modify
006 * it under the terms of the GNU Lesser General Public License as published by
007 * the Free Software Foundation; either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * OCaml-Java runtime is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.ocamljava.runtime.wrappers;
020
021import java.lang.invoke.MethodHandle;
022import java.lang.invoke.MethodHandles;
023import java.lang.invoke.MethodType;
024
025import org.ocamljava.runtime.values.Value;
026
027/**
028 * The {@code OCamlFunction} class represent an OCaml function taking one
029 * parameter.
030 *
031 * @author <a href="mailto:xclerc@ocamljava.org">Xavier Clerc</a>
032 * @version 2.0
033 * @since 2.0
034 */
035public abstract class OCamlFunction<T0 extends OCamlValue,
036                                    TR extends OCamlValue> extends OCamlValue {
037
038    /** Wrapper for first parameter. */
039    protected final Wrapper<T0> wrapper0;
040
041    /** Wrapper for return value. */
042    protected final Wrapper<TR> wrapperr;
043
044    /** Method handle for function actually called from the OCaml runtime. */
045    private static final MethodHandle METHOD_HANDLE;
046
047    static { // XXX factorize in OCamlWrappers
048        MethodHandle mh;
049        try {
050            final MethodHandles.Lookup lookup = MethodHandles.lookup();
051            final MethodType mt = MethodType.methodType(Value.class, Value.class);
052            mh = lookup.findVirtual(OCamlFunctionCaller.class, "called", mt);
053        } catch (final NoSuchMethodException | IllegalAccessException e) {
054            assert false : "OCamlFunction: unable to get method handle";
055            mh = null;
056        } // end try/catch
057        METHOD_HANDLE = mh;
058    } // end static block
059
060    /**
061     * Constructs a new instance. <br/>
062     * To be used by Java implementations.
063     * @param w0 wrapper for first parameter - should not be {@code null}
064     * @param wr wrapper for result - should not be {@code null}
065     */
066    public OCamlFunction(final Wrapper<T0> w0,
067                         final Wrapper<TR> wr) {
068        super(Value.UNIT);
069        assert w0 != null : "null w0";
070        assert wr != null : "null wr";
071        this.wrapper0 = w0;
072        this.wrapperr = wr;
073    } // end constructor(Wrapper<T0>, Wrapper<TR>)
074
075    /**
076     * Constructs a new instance. <br/>
077     * To be used by Java implementations.
078     */
079    @SuppressWarnings("unchecked")
080    public OCamlFunction() {
081        this((Wrapper<T0>) OCamlValue.WRAPPER,
082             (Wrapper<TR>) OCamlValue.WRAPPER);
083    } // end empty constructor
084
085    /**
086     * Constructs a new instance from a value. <br/>
087     * To be used by OCaml implementations.
088     * @param w0 wrapper for first parameter - should not be {@code null}
089     * @param wr wrapper for result - should not be {@code null}
090     */
091    OCamlFunction(final Value v,
092                  final Wrapper<T0> w0,
093                  final Wrapper<TR> wr) {
094        super(v);
095        assert w0 != null : "null w0";
096        assert wr != null : "null wr";
097        this.wrapper0 = w0;
098        this.wrapperr = wr;
099    } // end constructor(Value, Wrapper<T0>, Wrapper<TR>)
100
101    /**
102     * {@inheritDoc}
103     */
104    @Override
105    public final Wrapper<? extends OCamlFunction<T0, TR>> getWrapper() {
106        return OCamlFunction.wrapper(this.wrapper0, this.wrapperr);
107    } // end method 'getWrapper()'
108
109    /**
110     * {@inheritDoc}
111     */
112    @Override
113    public Wrapper<? extends OCamlValue> getWrapper(final int idx) {
114        switch (idx) {
115        case 0: return this.wrapper0;
116        case 1: return this.wrapperr;
117        default: return OCamlUnit.WRAPPER;
118        } // end switch
119    } // end method 'getWrapper(int)'
120
121    /**
122     * Returns the closure to be executed from the OCaml runtime.
123     * @param w0 wrapper for first parameter - should not be {@code null}
124     * @return the closure to be executed on the OCaml side
125     */
126    public Value getClosure(final Wrapper<T0> w0) {
127        assert w0 != null : "null w0";
128        final OCamlFunctionCaller<T0, TR> ofc = new OCamlFunctionCaller<>(w0, this);
129        return Value.createClosure(OCamlFunction.METHOD_HANDLE.bindTo(ofc));
130    } // end method 'getClosure(Wrapper<T0>)'
131
132    /**
133     * The actual implementation of the function
134     * @param p0 first parameter - should not be {@code null}
135     * @throws OCamlException if function fails
136     */
137    public abstract TR execute(final T0 p0) throws OCamlException;
138
139    /**
140     * {@inheritDoc}
141     */
142    @Override
143    public final int hashCode() {
144        return super.hashCode();
145    } // end method 'hashCode()'
146
147    /**
148     * {@inheritDoc}
149     */
150    @Override
151    public final boolean equals(final Object obj) {
152        if (obj instanceof OCamlFunction) {
153            final OCamlFunction<?, ?> that = (OCamlFunction) obj;
154            return this == that;
155        } else {
156            return false;
157        } // end if/else
158    } // end method 'equals(Object)'
159
160    /**
161     * {@inheritDoc}
162     */
163    @Override
164    public final String toString() {
165        return "OCamlFunction(...)";
166    } // end method 'toString()'
167
168    /**
169     * Wraps the passed value.
170     * @param w0 wrapper for first parameter - should not be {@code null}
171     * @param wr wrapper for result - should not be {@code null}
172     * @param v value to wrap - should not be {@code null}
173     * @return a new {@code OCamlFunction} instance wrapping the passed value
174     */
175    public static <T0 extends OCamlValue,
176                   TR extends OCamlValue>
177        OCamlFunction<T0, TR> wrap(final Wrapper<T0> w0,
178                                   final Wrapper<TR> wr,
179                                   final Value v) {
180        assert w0 != null : "null w0";
181        assert wr != null : "null wr";
182        assert v != null : "null v";
183        return new OCamlFunctionImpl<T0, TR>(w0, wr, v);
184    } // end method 'wrap(Wrapper<T0>, Wrapper<TR>, Value)'
185
186    /**
187     * Returns a wrapper for {@code OCamlFunction} values.
188     * @param w0 wrapper for first parameter - should not be {@code null}
189     * @param wr wrapper for result - should not be {@code null}
190     * @return a wrapper for {@code OCamlFunction} values
191     */
192    @SuppressWarnings("unchecked")
193    public static <T0 extends OCamlValue,
194                   TR extends OCamlValue>
195        Wrapper<? extends OCamlFunction<T0, TR>> wrapper(final Wrapper<T0> w0,
196                                                         final Wrapper<TR> wr) {
197        assert w0 != null : "null w0";
198        assert wr != null : "null wr";
199        return new ComposedWrapper<OCamlFunction<T0, TR>>(w0, wr) {
200            /**
201             * {@inheritDoc}
202             */
203            @Override
204                public OCamlFunction<T0, TR> wrap(final Value v) {
205                return new OCamlFunctionImpl<T0, TR>(w0, wr, v);
206            } // end method 'wrap(Value)'
207        }; // end anonymous inner-class
208    } // end method 'wrapper(Wrapper<T0>, Wrapper<TR>)'
209
210} // end class 'OCamlFunction'