using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MoonSharp.Interpreter.Execution;
using MoonSharp.Interpreter.Execution.VM;
namespace MoonSharp.Interpreter.CoreLib
{
///
/// Class implementing error handling Lua functions (pcall and xpcall)
///
[MoonSharpModule]
public class ErrorHandlingModule
{
[MoonSharpMethod]
public static DynValue pcall(ScriptExecutionContext executionContext, CallbackArguments args)
{
return SetErrorHandlerStrategy("pcall", executionContext, args, null);
}
private static DynValue SetErrorHandlerStrategy(string funcName,
ScriptExecutionContext executionContext,
CallbackArguments args,
DynValue handlerBeforeUnwind)
{
DynValue v = args[0];
DynValue[] a = new DynValue[args.Count - 1];
for (int i = 1; i < args.Count; i++)
a[i - 1] = args[i];
if (args[0].Type == DataType.ClrFunction)
{
try
{
DynValue ret = args[0].Callback.Invoke(executionContext, a);
if (ret.Type == DataType.TailCallRequest)
{
if (ret.TailCallData.Continuation != null || ret.TailCallData.ErrorHandler != null)
throw new ScriptRuntimeException("the function passed to {0} cannot be called directly by {0}. wrap in a script function instead.", funcName);
return DynValue.NewTailCallReq(new TailCallData()
{
Args = ret.TailCallData.Args,
Function = ret.TailCallData.Function,
Continuation = new CallbackFunction(pcall_continuation, funcName),
ErrorHandler = new CallbackFunction(pcall_onerror, funcName),
ErrorHandlerBeforeUnwind = handlerBeforeUnwind
});
}
else if (ret.Type == DataType.YieldRequest)
{
throw new ScriptRuntimeException("the function passed to {0} cannot be called directly by {0}. wrap in a script function instead.", funcName);
}
else
{
return DynValue.NewTupleNested(DynValue.True, ret);
}
}
catch (ScriptRuntimeException ex)
{
executionContext.PerformMessageDecorationBeforeUnwind(handlerBeforeUnwind, ex);
return DynValue.NewTupleNested(DynValue.False, DynValue.NewString(ex.DecoratedMessage));
}
}
else if (args[0].Type != DataType.Function)
{
return DynValue.NewTupleNested(DynValue.False, DynValue.NewString("attempt to " + funcName + " a non-function"));
}
else
{
return DynValue.NewTailCallReq(new TailCallData()
{
Args = a,
Function = v,
Continuation = new CallbackFunction(pcall_continuation, funcName),
ErrorHandler = new CallbackFunction(pcall_onerror, funcName),
ErrorHandlerBeforeUnwind = handlerBeforeUnwind
});
}
}
private static DynValue MakeReturnTuple(bool retstatus, CallbackArguments args)
{
DynValue[] rets = new DynValue[args.Count + 1];
for (int i = 0; i < args.Count; i++)
rets[i + 1] = args[i];
rets[0] = DynValue.NewBoolean(retstatus);
return DynValue.NewTuple(rets);
}
public static DynValue pcall_continuation(ScriptExecutionContext executionContext, CallbackArguments args)
{
return MakeReturnTuple(true, args);
}
public static DynValue pcall_onerror(ScriptExecutionContext executionContext, CallbackArguments args)
{
return MakeReturnTuple(false, args);
}
[MoonSharpMethod]
public static DynValue xpcall(ScriptExecutionContext executionContext, CallbackArguments args)
{
List a = new List();
for (int i = 0; i < args.Count; i++)
{
if (i != 1)
a.Add(args[i]);
}
DynValue handler = null;
if (args[1].Type == DataType.Function || args[1].Type == DataType.ClrFunction)
{
handler = args[1];
}
else if (args[1].Type != DataType.Nil)
{
args.AsType(1, "xpcall", DataType.Function, false);
}
return SetErrorHandlerStrategy("xpcall", executionContext, new CallbackArguments(a, false), handler);
}
}
}