using System; using MoonSharp.Interpreter.Interop; using MoonSharp.Interpreter.Interop.BasicDescriptors; namespace MoonSharp.Interpreter { /// /// Exception for all runtime errors. In addition to constructors, it offers a lot of static methods /// generating more "standard" Lua errors. /// #if !(PCL || ((!UNITY_EDITOR) && (ENABLE_DOTNET)) || NETFX_CORE) [Serializable] #endif public class ScriptRuntimeException : InterpreterException { /// /// Initializes a new instance of the class. /// /// The ex. public ScriptRuntimeException(Exception ex) : base(ex) { } /// /// Initializes a new instance of the class. /// /// The ex. public ScriptRuntimeException(ScriptRuntimeException ex) : base(ex, ex.DecoratedMessage) { this.DecoratedMessage = Message; this.DoNotDecorateMessage = true; } /// /// Initializes a new instance of the class. /// /// The message that describes the error. public ScriptRuntimeException(string message) : base(message) { } /// /// Initializes a new instance of the class. /// /// The format. /// The arguments. public ScriptRuntimeException(string format, params object[] args) : base(format, args) { } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// an arithmetic operation was attempted on non-numbers /// /// The left operand. /// The right operand (or null). /// The exception to be raised. /// If both are numbers public static ScriptRuntimeException ArithmeticOnNonNumber(DynValue l, DynValue r = null) { if (l.Type != DataType.Number && l.Type != DataType.String) return new ScriptRuntimeException("attempt to perform arithmetic on a {0} value", l.Type.ToLuaTypeString()); else if (r != null && r.Type != DataType.Number && r.Type != DataType.String) return new ScriptRuntimeException("attempt to perform arithmetic on a {0} value", r.Type.ToLuaTypeString()); else if (l.Type == DataType.String || (r != null && r.Type == DataType.String)) return new ScriptRuntimeException("attempt to perform arithmetic on a string value"); else throw new InternalErrorException("ArithmeticOnNonNumber - both are numbers"); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a concat operation was attempted on non-strings /// /// The left operand. /// The right operand. /// The exception to be raised. /// If both are numbers or strings public static ScriptRuntimeException ConcatOnNonString(DynValue l, DynValue r) { if (l.Type != DataType.Number && l.Type != DataType.String) return new ScriptRuntimeException("attempt to concatenate a {0} value", l.Type.ToLuaTypeString()); else if (r != null && r.Type != DataType.Number && r.Type != DataType.String) return new ScriptRuntimeException("attempt to concatenate a {0} value", r.Type.ToLuaTypeString()); else throw new InternalErrorException("ConcatOnNonString - both are numbers/strings"); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a len operator was applied on an invalid operand /// /// The operand. /// The exception to be raised. public static ScriptRuntimeException LenOnInvalidType(DynValue r) { return new ScriptRuntimeException("attempt to get length of a {0} value", r.Type.ToLuaTypeString()); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a comparison operator was applied on an invalid combination of operand types /// /// The left operand. /// The right operand. /// The exception to be raised. public static ScriptRuntimeException CompareInvalidType(DynValue l, DynValue r) { if (l.Type.ToLuaTypeString() == r.Type.ToLuaTypeString()) return new ScriptRuntimeException("attempt to compare two {0} values", l.Type.ToLuaTypeString()); else return new ScriptRuntimeException("attempt to compare {0} with {1}", l.Type.ToLuaTypeString(), r.Type.ToLuaTypeString()); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a function was called with a bad argument /// /// The argument number (0-based). /// Name of the function generating this error. /// The error message. /// The exception to be raised. public static ScriptRuntimeException BadArgument(int argNum, string funcName, string message) { return new ScriptRuntimeException("bad argument #{0} to '{1}' ({2})", argNum + 1, funcName, message); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a function was called with a bad userdata argument /// /// The argument number (0-based). /// Name of the function generating this error. /// The expected System.Type. /// The object which was used. /// True if nils were allowed in this call. /// /// The exception to be raised. /// public static ScriptRuntimeException BadArgumentUserData(int argNum, string funcName, Type expected, object got, bool allowNil) { return new ScriptRuntimeException("bad argument #{0} to '{1}' (userdata<{2}>{3} expected, got {4})", argNum + 1, funcName, expected.Name, allowNil ? "nil or " : "", got != null ? "userdata<" + got.GetType().Name + ">" : "null" ); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a function was called with a bad argument /// /// The argument number (0-based). /// Name of the function generating this error. /// The expected data type. /// The data type received. /// True if nils were allowed in this call. /// /// The exception to be raised. /// public static ScriptRuntimeException BadArgument(int argNum, string funcName, DataType expected, DataType got, bool allowNil) { return BadArgument(argNum, funcName, expected.ToErrorTypeString(), got.ToErrorTypeString(), allowNil); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a function was called with a bad argument /// /// The argument number (0-based). /// Name of the function generating this error. /// The expected type description. /// The description of the type received. /// True if nils were allowed in this call. /// /// The exception to be raised. /// public static ScriptRuntimeException BadArgument(int argNum, string funcName, string expected, string got, bool allowNil) { return new ScriptRuntimeException("bad argument #{0} to '{1}' ({2}{3} expected, got {4})", argNum + 1, funcName, allowNil ? "nil or " : "", expected, got); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a function was called with no value when a value was required. /// /// This function creates a message like "bad argument #xxx to 'yyy' (zzz expected, got no value)" /// while creates a message like "bad argument #xxx to 'yyy' (value expected)" /// /// The argument number (0-based). /// Name of the function generating this error. /// The expected data type. /// /// The exception to be raised. /// public static ScriptRuntimeException BadArgumentNoValue(int argNum, string funcName, DataType expected) { return new ScriptRuntimeException("bad argument #{0} to '{1}' ({2} expected, got no value)", argNum + 1, funcName, expected.ToErrorTypeString()); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// an out of range index was specified /// /// The argument number (0-based). /// Name of the function generating this error. /// /// The exception to be raised. /// public static ScriptRuntimeException BadArgumentIndexOutOfRange(string funcName, int argNum) { return new ScriptRuntimeException("bad argument #{0} to '{1}' (index out of range)", argNum + 1, funcName); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a function was called with a negative number when a positive one was expected. /// /// The argument number (0-based). /// Name of the function generating this error. /// /// The exception to be raised. /// public static ScriptRuntimeException BadArgumentNoNegativeNumbers(int argNum, string funcName) { return new ScriptRuntimeException("bad argument #{0} to '{1}' (not a non-negative number in proper range)", argNum + 1, funcName); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a function was called with no value when a value was required. /// This function creates a message like "bad argument #xxx to 'yyy' (value expected)" /// while creates a message like "bad argument #xxx to 'yyy' (zzz expected, got no value)" /// /// The argument number (0-based). /// Name of the function generating this error. /// /// The exception to be raised. /// public static ScriptRuntimeException BadArgumentValueExpected(int argNum, string funcName) { return new ScriptRuntimeException("bad argument #{0} to '{1}' (value expected)", argNum + 1, funcName); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// an invalid attempt to index the specified object was made /// /// The object. /// /// The exception to be raised. /// public static ScriptRuntimeException IndexType(DynValue obj) { return new ScriptRuntimeException("attempt to index a {0} value", obj.Type.ToLuaTypeString()); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a loop was detected when performing __index over metatables. /// /// /// The exception to be raised. /// public static ScriptRuntimeException LoopInIndex() { return new ScriptRuntimeException("loop in gettable"); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a loop was detected when performing __newindex over metatables. /// /// /// The exception to be raised. /// public static ScriptRuntimeException LoopInNewIndex() { return new ScriptRuntimeException("loop in settable"); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a loop was detected when performing __call over metatables. /// /// /// The exception to be raised. /// public static ScriptRuntimeException LoopInCall() { return new ScriptRuntimeException("loop in call"); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a table indexing operation used nil as the key. /// /// /// The exception to be raised. /// public static ScriptRuntimeException TableIndexIsNil() { return new ScriptRuntimeException("table index is nil"); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a table indexing operation used a NaN as the key. /// /// /// The exception to be raised. /// public static ScriptRuntimeException TableIndexIsNaN() { return new ScriptRuntimeException("table index is NaN"); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a conversion to number failed. /// /// /// Selects the correct error message: /// 0 - "value must be a number" /// 1 - "'for' initial value must be a number" /// 2 - "'for' step must be a number" /// 3 - "'for' limit must be a number" /// /// /// The exception to be raised. /// public static ScriptRuntimeException ConvertToNumberFailed(int stage) { switch (stage) { case 1: return new ScriptRuntimeException("'for' initial value must be a number"); case 2: return new ScriptRuntimeException("'for' step must be a number"); case 3: return new ScriptRuntimeException("'for' limit must be a number"); default: return new ScriptRuntimeException("value must be a number"); } } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a conversion of a CLR type to a Lua type has failed. /// /// The object which could not be converted. /// /// The exception to be raised. /// public static ScriptRuntimeException ConvertObjectFailed(object obj) { return new ScriptRuntimeException("cannot convert clr type {0}", obj.GetType()); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a conversion of a Lua type to a CLR type has failed. /// /// The Lua type. /// /// The exception to be raised. /// public static ScriptRuntimeException ConvertObjectFailed(DataType t) { return new ScriptRuntimeException("cannot convert a {0} to a clr type", t.ToString().ToLowerInvariant()); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a constrained conversion of a Lua type to a CLR type has failed. /// /// The Lua type. /// The expected CLR type. /// /// The exception to be raised. /// public static ScriptRuntimeException ConvertObjectFailed(DataType t, Type t2) { return new ScriptRuntimeException("cannot convert a {0} to a clr type {1}", t.ToString().ToLowerInvariant(), t2.FullName); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a userdata of a specific CLR type was expected and a non-userdata type was passed. /// /// The Lua type. /// The expected CLR type. /// /// The exception to be raised. /// public static ScriptRuntimeException UserDataArgumentTypeMismatch(DataType t, Type clrType) { return new ScriptRuntimeException("cannot find a conversion from a MoonSharp {0} to a clr {1}", t.ToString().ToLowerInvariant(), clrType.FullName); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// an attempt to index an invalid member of a userdata was done. /// /// The name of the userdata type. /// The field name. /// /// The exception to be raised. /// public static ScriptRuntimeException UserDataMissingField(string typename, string fieldname) { return new ScriptRuntimeException("cannot access field {0} of userdata<{1}>", fieldname, typename); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// an attempt resume a coroutine in an invalid state was done. /// /// The state of the coroutine. /// /// The exception to be raised. /// public static ScriptRuntimeException CannotResumeNotSuspended(CoroutineState state) { if (state == CoroutineState.Dead) return new ScriptRuntimeException("cannot resume dead coroutine"); else return new ScriptRuntimeException("cannot resume non-suspended coroutine"); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// an attempt to yield across a CLR boundary was made. /// /// /// The exception to be raised. /// public static ScriptRuntimeException CannotYield() { return new ScriptRuntimeException("attempt to yield across a CLR-call boundary"); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// an attempt to yield from the main coroutine was made. /// /// /// The exception to be raised. /// public static ScriptRuntimeException CannotYieldMain() { return new ScriptRuntimeException("attempt to yield from outside a coroutine"); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// an attempt to call a non-function was made /// /// The lua non-function data type. /// The debug text to aid location (appears as "near 'xxx'"). /// public static ScriptRuntimeException AttemptToCallNonFunc(DataType type, string debugText = null) { string functype = type.ToErrorTypeString(); if (debugText != null) return new ScriptRuntimeException("attempt to call a {0} value near '{1}'", functype, debugText); else return new ScriptRuntimeException("attempt to call a {0} value", functype); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// an attempt to access a non-static member from a static userdata was made /// /// The member descriptor. public static ScriptRuntimeException AccessInstanceMemberOnStatics(IMemberDescriptor desc) { return new ScriptRuntimeException("attempt to access instance member {0} from a static userdata", desc.Name); } /// /// Creates a ScriptRuntimeException with a predefined error message specifying that /// an attempt to access a non-static member from a static userdata was made /// /// The type descriptor. /// The member descriptor. /// public static ScriptRuntimeException AccessInstanceMemberOnStatics(IUserDataDescriptor typeDescr, IMemberDescriptor desc) { return new ScriptRuntimeException("attempt to access instance member {0}.{1} from a static userdata", typeDescr.Name, desc.Name); } /// /// Rethrows this instance if /// /// public override void Rethrow() { if (Script.GlobalOptions.RethrowExceptionNested) throw new ScriptRuntimeException(this); } } }