package com.oracle.truffle.llvm.runtime.nodes.intrinsics.interop;
import java.io.IOException;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.TruffleLanguage.Env;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.LanguageInfo;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.llvm.runtime.CommonNodeFactory;
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.llvm.LLVMIntrinsic;
import com.oracle.truffle.llvm.runtime.LLVMContext;
import com.oracle.truffle.llvm.runtime.LLVMLanguage;
import com.oracle.truffle.llvm.runtime.except.LLVMPolyglotException;
import com.oracle.truffle.llvm.runtime.interop.convert.ForeignToLLVM;
import com.oracle.truffle.llvm.runtime.interop.convert.ForeignToLLVM.ForeignToLLVMType;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMNode;
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.interop.LLVMPolyglotEvalNodeGen.GetSourceFileNodeGen;
import com.oracle.truffle.llvm.runtime.nodes.intrinsics.interop.LLVMPolyglotEvalNodeGen.GetSourceStringNodeGen;
@NodeChild(type = LLVMExpressionNode.class)
@NodeChild(type = LLVMExpressionNode.class)
public abstract class LLVMPolyglotEval extends LLVMIntrinsic {
@Child GetSourceNode getSource;
public static LLVMPolyglotEval create(LLVMExpressionNode id, LLVMExpressionNode code) {
return LLVMPolyglotEvalNodeGen.create(GetSourceStringNodeGen.create(), id, code);
}
public static LLVMPolyglotEval createFile(LLVMExpressionNode id, LLVMExpressionNode filename) {
return LLVMPolyglotEvalNodeGen.create(GetSourceFileNodeGen.create(), id, filename);
}
LLVMPolyglotEval(GetSourceNode getSource) {
this.getSource = getSource;
}
@Specialization
protected Object doEval(Object idPointer, Object srcPointer,
@Cached("createReadString()") LLVMReadStringNode readId,
@Cached("createReadString()") LLVMReadStringNode readSrc,
@Cached("createForeignToLLVM()") ForeignToLLVM toLLVM) {
try {
CallTarget callTarget = getSource.execute(readId.executeWithTarget(idPointer), readSrc.executeWithTarget(srcPointer));
Object foreign = callTarget.call();
return toLLVM.executeWithTarget(foreign);
} catch (IllegalStateException e) {
CompilerDirectives.transferToInterpreter();
throw new LLVMPolyglotException(this, e.getMessage());
}
}
protected ForeignToLLVM createForeignToLLVM() {
return CommonNodeFactory.createForeignToLLVM(ForeignToLLVMType.POINTER);
}
abstract static class GetSourceNode extends LLVMNode {
abstract CallTarget execute(String languageId, String source);
}
abstract static class GetSourceStringNode extends GetSourceNode {
@Specialization(limit = "2", guards = {"id.equals(cachedId)", "code.equals(cachedCode)"}, assumptions = "singleContextAssumption()")
CallTarget doCached(String id, String code,
@Cached("id") @SuppressWarnings("unused") String cachedId,
@Cached("code") @SuppressWarnings("unused") String cachedCode,
@CachedContext(LLVMLanguage.class) @SuppressWarnings("unused") ContextReference<LLVMContext> ctxRef,
@Cached("uncached(cachedId, cachedCode, ctxRef)") CallTarget callTarget) {
return callTarget;
}
@TruffleBoundary
@Specialization(replaces = "doCached")
CallTarget uncached(String id, String code,
@CachedContext(LLVMLanguage.class) ContextReference<LLVMContext> ctxRef) {
LLVMContext ctx = ctxRef.get();
Env env = ctx.getEnv();
LanguageInfo lang = env.getPublicLanguages().get(id);
if (lang == null) {
throw new LLVMPolyglotException(this, "Language '%s' not found.", id);
}
Source sourceObject = Source.newBuilder(id, code, "<eval>").build();
return ctx.getEnv().parsePublic(sourceObject);
}
}
abstract static class GetSourceFileNode extends GetSourceNode {
@TruffleBoundary
@Specialization
CallTarget uncached(String id, String filename,
@CachedContext(LLVMLanguage.class) LLVMContext ctx) {
try {
Env env = ctx.getEnv();
Source sourceObject = Source.newBuilder(id, env.getPublicTruffleFile(filename)).build();
return env.parsePublic(sourceObject);
} catch (IOException ex) {
throw new LLVMPolyglotException(this, "Could not parse file %s (%s).", filename, ex.getMessage());
}
}
}
}