123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- // Copyright (c) 2004, 2015 Per M.A. Bothner.
- // This is free software; for terms and warranty disclaimer see ./COPYING.
- package gnu.mapping;
- /* #ifdef use:java.lang.invoke */
- import java.lang.invoke.*;
- /* #else */
- // import gnu.mapping.CallContext.MethodHandle;
- /* #endif */
- /**
- * The abstract parent for all Scheme functions.
- * @author Per Bothner
- */
- public class Procedure extends PropertySet
- {
- /** A static method with signature ??apply(Procedure,CallContext)
- */
- protected /*final?*/ MethodHandle applyToObjectMethod;
- protected /*final?*/ MethodHandle applyToConsumerMethod;
- ///** Does impemention write Object to Consumer?
- // * If so, implement applyToObjectMethod using applyToConsumerMethod.
- // * If false, impement applyToConsumerMethod using applyToObjectMethod.
- // */
- //protected boolean resultGoesToConsumer() {
- // return false;
- //}
- private static final String sourceLocationKey = "source-location";
- private static final Symbol setterKey = Namespace.EmptyNamespace.getSymbol("setter");
- /** Key for a property used by gnu.expr.Inlinecalls.
- * The property value is either a String of the form "CLASSNAME:METHODNAME",
- * or a java.lang.reflect.Method (or FUTURE: MethodHandle) for a static
- * method whose parameters are
- * {@code (ApplyExp exp, InlineCalls visitor, Type required, Procedure proc)} and returns a re-written/validated {@code Expression}.
- */
- public static final Symbol validateApplyKey =
- Namespace.EmptyNamespace.getSymbol("validate-apply");
- /** Same as validateApplyKey but handles splice args. */
- public static final Symbol validateXApplyKey =
- Namespace.EmptyNamespace.getSymbol("validate-xapply");
- public static final Symbol compilerXKey =
- Namespace.EmptyNamespace.getSymbol("compile-apply");
- public static final Symbol inlineIfConstantSymbol =
- Namespace.EmptyNamespace.getSymbol("inline-if-constant");
- // This should be a LazyPropertyKey<gnu.expr.Inlineable>, but we want
- // to avoid any strict dependency on gnu.expr for run-time classes.
- public static final LazyPropertyKey<?> compilerKey
- = new LazyPropertyKey("compiler");
- public void setSourceLocation (String file, int line)
- {
- setProperty(sourceLocationKey, file + ":" + line);
- }
- public String getSourceLocation ()
- {
- Object value = getProperty(sourceLocationKey, null);
- return value == null ? null : value.toString();
- }
- public final MethodHandle getApplyToConsumerMethod() {
- return applyToConsumerMethod;
- }
- public final MethodHandle getApplyToObjectMethod() {
- return applyToObjectMethod;
- }
- public static Object applyToConsumerDefault(Procedure proc, CallContext ctx) throws Throwable {
- ctx.proc = proc;
- Object r = proc.applyToObjectMethod.invokeExact(proc, ctx);
- if (r != ctx) {
- Values.writeValues(r, ctx.consumer);
- r = null;
- }
- return r;
- }
- public static Object applyToObjectDefault(Procedure proc, CallContext ctx)
- throws Throwable {
- int start = ctx.startFromContext();
- try {
- if (proc.applyToConsumerMethod.invokeExact(proc, ctx) != ctx)
- return ctx.getFromContext(start);
- ctx.cleanupFromContext(start);
- return ctx;
- //Object v = ctx.getFromContext(start);
- //return r == ctx ? null : v;
- } catch (Throwable ex) {
- ctx.cleanupFromContext(start);
- throw ex;
- }
- //return ctx.runUntilValue();
-
- }
- public Procedure() {
- }
- public Procedure(String n) {
- setName(n);
- }
- public Procedure(boolean resultGoesToConsumer, MethodHandle applyMethod) {
- if (resultGoesToConsumer) {
- applyToConsumerMethod = applyMethod;
- applyToObjectMethod = applyToObjectDefault;
- } else {
- applyToObjectMethod = applyMethod;
- applyToConsumerMethod = applyToConsumerDefault;
- }
- }
- public Procedure(boolean resultGoesToConsumer, MethodHandle applyMethod, String n) {
- this(resultGoesToConsumer, applyMethod);
- setName(n);
- }
- public void checkBadCode(CallContext ctx) {
- int code = 0; // FIXME
- //throw MethodProc.matchFailAsException(code, this, args);
- }
- public Object applyL(ArgList args) throws Throwable {
- CallContext ctx = CallContext.getInstance();
- ctx.setupApply(this);
- ctx.addAll(args);
- return ctx.runUntilValue();
- }
- public Object applyN (Object[] args) throws Throwable {
- CallContext ctx = CallContext.getInstance();
- ctx.setupApplyAll(this, args);
- return ctx.runUntilValue();
- }
- public Object apply0() throws Throwable {
- CallContext ctx = CallContext.getInstance();
- ctx.setupApply(this);
- return ctx.runUntilValue();
- }
- public Object apply1(Object arg1) throws Throwable {
- CallContext ctx = CallContext.getInstance();
- ctx.setupApply(this, arg1);
- return ctx.runUntilValue();
- }
- public Object apply2(Object arg1,Object arg2) throws Throwable {
- CallContext ctx = CallContext.getInstance();
- ctx.setupApply(this, arg1, arg2);
- return ctx.runUntilValue();
- }
- public Object apply3(Object arg1, Object arg2,
- Object arg3) throws Throwable {
- CallContext ctx = CallContext.getInstance();
- ctx.setupApply(this, arg1, arg2, arg3);
- return ctx.runUntilValue();
- }
- public Object apply4(Object arg1, Object arg2,
- Object arg3, Object arg4) throws Throwable {
- CallContext ctx = CallContext.getInstance();
- ctx.setupApply(this, arg1, arg2, arg3, arg4);
- return ctx.runUntilValue();
- }
- /** Minimum number of arguments required. */
- public final int minArgs() { return minArgs(numArgs()); }
- /** Maximum number of arguments allowed, or -1 for unlimited.
- * (May also return -1 if there are keyword arguments, for implementation
- * reasons - FIXME.) */
- public final int maxArgs() { return maxArgs(numArgs()); }
- /** Return {@code minArgs()|(maxArgs<<12)}.
- * We use a single virtual function to reduce the number of methods
- * in the system, as well as the number of virtual method table entries.
- * We shift by 12 so the number can normally be represented using a
- * sipush instruction, without requiring a constant pool entry.
- */
- public int numArgs() { return 0xfffff000; }
- /** Extract minimum number of arguments from {@code numArgs()} encoding. */
- public static int minArgs (int num) { return num & 0xFFF; }
- /** Extract maximum number of arguments from {@code numArgs()} encoding. */
- public static int maxArgs (int num) { return num >> 12; }
- /** Check that the number of arguments in a call is valid.
- * @param proc the Procedure being called
- * @param argCount the number of arguments in the call
- * @exception WrongArguments there are too many or too
- * few actual arguments
- */
- public static void checkArgCount(Procedure proc, int argCount)
- {
- int num = proc.numArgs();
- if (argCount < minArgs(num)
- || (num >= 0 && argCount > maxArgs(num)))
- throw new WrongArguments(proc, argCount);
- }
- public Procedure getSetter()
- {
- if (! (this instanceof HasSetter))
- {
- Object setter = getProperty(setterKey, null);
- if (setter instanceof Procedure)
- return (Procedure) setter;
- throw new RuntimeException("procedure '"+getName()+ "' has no setter");
- }
- int num_args = numArgs();
- if (num_args == 0x0000)
- return new Setter0(this);
- if (num_args == 0x1001)
- return new Setter1(this);
- return new Setter(this);
- }
- public void setSetter (Procedure setter)
- {
- if (this instanceof HasSetter)
- throw new RuntimeException("procedure '"+getName()+
- "' has builtin setter - cannot be modified");
- setProperty(Procedure.setterKey, setter);
- }
- /** If HasSetter, the Procedure is called in the LHS of an assignment. */
- public void set0(Object result) throws Throwable
- {
- getSetter().apply1(result);
- }
- public void set1(Object arg1, Object value) throws Throwable
- {
- getSetter().apply2(arg1, value);
- }
- public void setN (Object[] args) throws Throwable
- {
- getSetter().applyN(args);
- }
- /** True if this Procedure (definitely) has no side-effects.
- * Note side-effect-free does not imply idempotent if this
- * allocates an object with "identity".
- */
- public boolean isSideEffectFree ()
- {
- return false;
- }
-
- /** Semi-deprecated - instead should be set at Inline time. FIXME */
- public gnu.bytecode.Type getReturnType (gnu.expr.Expression[] args)
- {
- return gnu.bytecode.Type.objectType;
- }
- public String toString ()
- {
- StringBuffer sbuf = new StringBuffer();
- sbuf.append ("#<procedure ");
- String n = getName();
- if (n == null)
- n = getSourceLocation();
- if (n == null)
- n = getClass().getName();
- sbuf.append(n);
- sbuf.append('>');
- return sbuf.toString();
- }
- public static MethodHandle lookupApplyHandle(Class clas, String mname) {
- try {
- /* #ifdef use:java.lang.invoke */
- return MethodHandles.lookup()
- .findStatic(clas, mname, applyMethodType);
- /* #else */
- // return new CallContext.ReflectMethodHandle(clas.getDeclaredMethod(mname, applyMethodType));
- /* #endif */
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
- /* #ifdef use:java.lang.invoke */
- public static final MethodType applyMethodType =
- MethodType.methodType(Object.class, Procedure.class, CallContext.class);
- /* #else */
- // public static final Class[] applyMethodType =
- // { Procedure.class, CallContext.class };
- /* #endif */
- public static final MethodHandle applyToObjectDefault
- = lookupApplyHandle(Procedure.class, "applyToObjectDefault");
- public static final MethodHandle applyToConsumerDefault
- = lookupApplyHandle(Procedure.class, "applyToConsumerDefault");
- }
|