package org.mozartoz.truffle.nodes.call;

import org.mozartoz.truffle.Options;
import org.mozartoz.truffle.nodes.DerefNode;
import org.mozartoz.truffle.nodes.OzNode;
import org.mozartoz.truffle.runtime.Errors;
import org.mozartoz.truffle.runtime.OzCons;
import org.mozartoz.truffle.runtime.OzLanguage;
import org.mozartoz.truffle.runtime.OzObject;
import org.mozartoz.truffle.runtime.OzProc;

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CreateCast;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;

@NodeChildren({
		@NodeChild(value = "receiver", type = OzNode.class),
		@NodeChild(value = "arguments", type = OzNode.class)
})
public abstract class CallNode extends CallableNode {

	@CreateCast("receiver")
	protected OzNode derefReceiver(OzNode var) {
		return DerefNode.create(var);
	}

	public static CallableNode create() {
		return create(null, null);
	}

	public static CallableNode create(OzNode receiver, OzNode arguments) {
		if (OzLanguage.getOptions().get(Options.TAIL_CALLS)) {
			// Always create a TailCallCatcherNode to ensure a TailCallException
			// never goes back further than the current call.
			return new TailCallCatcherNode(CallNodeGen.create(receiver, arguments));
		} else {
			return CallNodeGen.create(receiver, arguments);
		}
	}

	public abstract Object executeCall(VirtualFrame frame, Object receiver, Object[] arguments);

	@Specialization
	protected Object callProc(OzProc proc, Object[] arguments,
			@Cached CallProcNode callProcNode) {
		return callProcNode.executeCall(proc, arguments);
	}

	@Specialization
	protected Object callObject(OzObject object, Object[] arguments,
			@Cached CallMethodNode callMethodNode) {
		return callMethodNode.executeCall(object, arguments);
	}

	@Specialization
	protected Object callOther(VirtualFrame frame, Object object, Object[] arguments) {
		throw Errors.kernelError(this, "type", unit, new OzCons(object, "nil"), "Callable", 1L, "nil");
	}

}

@@ -35,16 +35,60 @@
 .call;%0A%0A
+import com.oracle.truffle.api.dsl.Fallback;%0A
 import o
@@ -1928,38 +1928,32 @@
 nts);%0A%09%7D%0A%0A%09@
-Specialization
+Fallback
 %0A%09protected 
@@ -1969,36 +1969,16 @@
 llOther(
-VirtualFrame frame, 
 Object o
@@ -1982,34 +1982,32 @@
 t object, Object
-%5B%5D
  arguments) %7B%0A%09%09

Fix fallback specialization in CallNode