package org.metaborg.spoofax.core.stratego.primitive;

import org.metaborg.util.functions.Function2;
import org.spoofax.interpreter.core.IContext;
import org.spoofax.interpreter.core.InterpreterException;
import org.spoofax.interpreter.core.Tools;
import org.spoofax.interpreter.library.AbstractPrimitive;
import org.spoofax.interpreter.stratego.Strategy;
import org.spoofax.interpreter.terms.IStrategoString;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.spoofax.interpreter.terms.IStrategoTuple;
import org.spoofax.jsglr.client.imploder.Injections;

public class ExplicateInjectionsPrimitive extends AbstractPrimitive {

    public ExplicateInjectionsPrimitive() {
        super("SSL_EXT_explicate_injections", 1, 0);
    }

    @Override public boolean call(IContext env, Strategy[] svars, IStrategoTerm[] tvars) throws InterpreterException {
        final Strategy sInjName = svars[0];
        final Function2<String, String, String> injName = (sort, intoSort) -> {
            final IStrategoTerm originalTerm = env.current();
            try {
                final IStrategoString sortTerm = env.getFactory().makeString(sort);
                final IStrategoString intoSortTerm = env.getFactory().makeString(intoSort);
                final IStrategoTuple input = env.getFactory().makeTuple(sortTerm, intoSortTerm);
                env.setCurrent(input);
                if(sInjName.evaluate(env)) {
                    return Tools.asJavaString(env.current());
                } else {
                    throw new InterpreterRuntimeException(new InterpreterException("Strategy to construct injection name failed."));
                }
            } catch(InterpreterException ex) {
                throw new InterpreterRuntimeException(ex);
            } finally {
                env.setCurrent(originalTerm);
            }
        };
        final Injections injections = new Injections(env.getFactory(), injName);
        final IStrategoTerm result;
        try {
            result = injections.explicate(env.current());
        } catch(InterpreterRuntimeException ex) {
            throw ex.getCause();
        }
        env.setCurrent(result);
        return true;
    }

    private static class InterpreterRuntimeException extends RuntimeException {
        private static final long serialVersionUID = 1L;

        public final InterpreterException cause;

        public InterpreterRuntimeException(InterpreterException cause) {
            super(cause);
            this.cause = cause;
        }

        @Override public synchronized InterpreterException getCause() {
            return cause;
        }

    }

}
@@ -48,16 +48,44 @@
 itive;%0A%0A
+import java.util.Optional;%0A%0A
 import o
@@ -111,16 +111,23 @@
 nctions.
+Partial
 Function
@@ -949,16 +949,23 @@
   final 
+Partial
 Function
@@ -1088,30 +1088,8 @@
 ();%0A
-            try %7B%0A    
     
@@ -1160,28 +1160,24 @@
 ring(sort);%0A
-    
             
@@ -1256,36 +1256,32 @@
 t);%0A            
-    
 final IStrategoT
@@ -1341,24 +1341,42 @@
 oSortTerm);%0A
+            try %7B%0A
             
@@ -1474,16 +1474,28 @@
  return 
+Optional.of(
 Tools.as
@@ -1511,32 +1511,33 @@
 g(env.current())
+)
 ;%0A              
@@ -1571,118 +1571,30 @@
     
-throw new InterpreterRuntimeException(new InterpreterException(%22Strategy to construct injection name failed.%22)
+return Optional.empty(
 );%0A 

Allow strategy to ignore injections.