using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using MoonSharp.Interpreter.Compatibility; using MoonSharp.Interpreter.Compatibility.Frameworks; using MoonSharp.Interpreter.CoreLib; using MoonSharp.Interpreter.CoreLib.IO; using MoonSharp.Interpreter.CoreLib.StringLib; using MoonSharp.Interpreter.DataStructs; using MoonSharp.Interpreter.Debugging; using MoonSharp.Interpreter.Diagnostics; using MoonSharp.Interpreter.Diagnostics.PerformanceCounters; using MoonSharp.Interpreter.Execution; using MoonSharp.Interpreter.Execution.Scopes; using MoonSharp.Interpreter.Execution.VM; using MoonSharp.Interpreter.IO; using MoonSharp.Interpreter.Interop; using MoonSharp.Interpreter.Interop.BasicDescriptors; using MoonSharp.Interpreter.Interop.Converters; using MoonSharp.Interpreter.Interop.LuaStateInterop; using MoonSharp.Interpreter.Interop.RegistrationPolicies; using MoonSharp.Interpreter.Interop.StandardDescriptors; using MoonSharp.Interpreter.Interop.UserDataRegistries; using MoonSharp.Interpreter.Loaders; using MoonSharp.Interpreter.Platforms; using MoonSharp.Interpreter.REPL; using MoonSharp.Interpreter.Serialization.Json; using MoonSharp.Interpreter.Tree; using MoonSharp.Interpreter.Tree.Expressions; using MoonSharp.Interpreter.Tree.Fast_Interface; using MoonSharp.Interpreter.Tree.Statements; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("MoonSharp.Interpreter")] [assembly: AssemblyDescription("An interpreter for the Lua language")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("http://www.moonsharp.org")] [assembly: AssemblyProduct("MoonSharp.Interpreter")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("c971e5a8-dbec-4408-8046-86e4fdd1b2e3")] [assembly: AssemblyFileVersion("2.0.0.0")] [assembly: InternalsVisibleTo("MoonSharp.Interpreter.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100F704C50BBDC3F2F011CC26A8C6C4797A40E0B4BC94CFB1335E9BA208326340696B686DC13099F10D3054544532F5E3E66C26A13FF260AEA2343E0410511FE56EDCC2AFB898AAA1BC21DA33C0D0AE60824EB441D02A0E6B7AE251CDE0946BFC748209C12B062573ECDB008A3D10CC40534B314847591CE5342A3BC6AA83CE23B8")] [assembly: InternalsVisibleTo("MoonSharp.Interpreter.Tests.net40-client, PublicKey=0024000004800000940000000602000000240000525341310004000001000100F704C50BBDC3F2F011CC26A8C6C4797A40E0B4BC94CFB1335E9BA208326340696B686DC13099F10D3054544532F5E3E66C26A13FF260AEA2343E0410511FE56EDCC2AFB898AAA1BC21DA33C0D0AE60824EB441D02A0E6B7AE251CDE0946BFC748209C12B062573ECDB008A3D10CC40534B314847591CE5342A3BC6AA83CE23B8")] [assembly: InternalsVisibleTo("MoonSharp.Interpreter.Tests.portable40, PublicKey=0024000004800000940000000602000000240000525341310004000001000100F704C50BBDC3F2F011CC26A8C6C4797A40E0B4BC94CFB1335E9BA208326340696B686DC13099F10D3054544532F5E3E66C26A13FF260AEA2343E0410511FE56EDCC2AFB898AAA1BC21DA33C0D0AE60824EB441D02A0E6B7AE251CDE0946BFC748209C12B062573ECDB008A3D10CC40534B314847591CE5342A3BC6AA83CE23B8")] [assembly: AssemblyCopyright("Copyright © 2014-2015, Marco Mastropaolo")] [assembly: InternalsVisibleTo("MoonSharp.Interpreter.Tests.net35-client, PublicKey=0024000004800000940000000602000000240000525341310004000001000100F704C50BBDC3F2F011CC26A8C6C4797A40E0B4BC94CFB1335E9BA208326340696B686DC13099F10D3054544532F5E3E66C26A13FF260AEA2343E0410511FE56EDCC2AFB898AAA1BC21DA33C0D0AE60824EB441D02A0E6B7AE251CDE0946BFC748209C12B062573ECDB008A3D10CC40534B314847591CE5342A3BC6AA83CE23B8")] [assembly: TargetFramework(".NETFramework,Version=v4.0,Profile=Client", FrameworkDisplayName = ".NET Framework 4 Client Profile")] [assembly: AssemblyVersion("2.0.0.0")] namespace MoonSharp.Interpreter { public static class AsyncExtensions { public static Task ExecAsync(Func func) { return Task.Factory.StartNew(func); } public static Task ExecAsyncVoid(Action func) { return Task.Factory.StartNew(func); } public static Task CallAsync(this Closure function) { return ExecAsync(() => function.Call()); } public static Task CallAsync(this Closure function, params object[] args) { return ExecAsync(() => function.Call(args)); } public static Task CallAsync(this Closure function, params DynValue[] args) { return ExecAsync(() => function.Call(args)); } public static Task DoStringAsync(this Script script, string code, Table globalContext = null, string codeFriendlyName = null) { return ExecAsync(() => script.DoString(code, globalContext, codeFriendlyName)); } public static Task DoStreamAsync(this Script script, Stream stream, Table globalContext = null, string codeFriendlyName = null) { return ExecAsync(() => script.DoStream(stream, globalContext, codeFriendlyName)); } public static Task DoFileAsync(this Script script, string filename, Table globalContext = null, string codeFriendlyName = null) { return ExecAsync(() => script.DoFile(filename, globalContext, codeFriendlyName)); } public static Task LoadFunctionAsync(this Script script, string code, Table globalTable = null, string funcFriendlyName = null) { return ExecAsync(() => script.LoadFunction(code, globalTable, funcFriendlyName)); } public static Task LoadStringAsync(this Script script, string code, Table globalTable = null, string codeFriendlyName = null) { return ExecAsync(() => script.LoadString(code, globalTable, codeFriendlyName)); } public static Task LoadStreamAsync(this Script script, Stream stream, Table globalTable = null, string codeFriendlyName = null) { return ExecAsync(() => script.LoadStream(stream, globalTable, codeFriendlyName)); } public static Task DumpAsync(this Script script, DynValue function, Stream stream) { return ExecAsyncVoid(delegate { script.Dump(function, stream); }); } public static Task LoadFileAsync(this Script script, string filename, Table globalContext = null, string friendlyFilename = null) { return ExecAsync(() => script.LoadFile(filename, globalContext, friendlyFilename)); } public static Task CallAsync(this Script script, DynValue function) { return ExecAsync(() => script.Call(function)); } public static Task CallAsync(this Script script, DynValue function, params DynValue[] args) { return ExecAsync(() => script.Call(function, args)); } public static Task CallAsync(this Script script, DynValue function, params object[] args) { return ExecAsync(() => script.Call(function, args)); } public static Task CallAsync(this Script script, object function) { return ExecAsync(() => script.Call(function)); } public static Task CallAsync(this Script script, object function, params object[] args) { return ExecAsync(() => script.Call(function, args)); } public static Task CreateDynamicExpressionAsync(this Script script, string code) { return ExecAsync(() => script.CreateDynamicExpression(code)); } public static Task EvaluateAsync(this ReplInterpreter interpreter, string input) { return ExecAsync(() => interpreter.Evaluate(input)); } public static Task ResumeAsync(this Coroutine cor, params DynValue[] args) { return ExecAsync(() => cor.Resume(args)); } public static Task ResumeAsync(this Coroutine cor, ScriptExecutionContext context, params DynValue[] args) { return ExecAsync(() => cor.Resume(context, args)); } public static Task ResumeAsync(this Coroutine cor) { return ExecAsync(() => cor.Resume()); } public static Task ResumeAsync(this Coroutine cor, ScriptExecutionContext context) { return ExecAsync(() => cor.Resume(context)); } public static Task ResumeAsync(this Coroutine cor, params object[] args) { return ExecAsync(() => cor.Resume(args)); } public static Task ResumeAsync(this Coroutine cor, ScriptExecutionContext context, params object[] args) { return ExecAsync(() => cor.Resume(context, args)); } } [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = true)] public sealed class MoonSharpPropertyAttribute : Attribute { public string Name { get; set; } public MoonSharpPropertyAttribute() { } public MoonSharpPropertyAttribute(string name) { Name = name; } } [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public sealed class MoonSharpUserDataMetamethodAttribute : Attribute { public string Name { get; set; } public MoonSharpUserDataMetamethodAttribute(string name) { Name = name; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = true)] public sealed class MoonSharpHideMemberAttribute : Attribute { public string MemberName { get; set; } public MoonSharpHideMemberAttribute(string memberName) { MemberName = memberName; } } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event, Inherited = true, AllowMultiple = false)] public sealed class MoonSharpHiddenAttribute : Attribute { } public delegate object ScriptFunctionDelegate(params object[] args); public delegate T ScriptFunctionDelegate(params object[] args); [Flags] public enum TypeValidationFlags { None = 0, AllowNil = 1, AutoConvert = 2, Default = 2 } [Serializable] public class DynamicExpressionException : ScriptRuntimeException { public DynamicExpressionException(string format, params object[] args) : base(": " + format, args) { } public DynamicExpressionException(string message) : base(": " + message) { } } public class DynamicExpression : IScriptPrivateResource { public DynamicExprExpression m_Exp; public DynValue m_Constant; public readonly string ExpressionCode; public Script OwnerScript { get; set; } public DynamicExpression(Script S, string strExpr, DynamicExprExpression expr) { ExpressionCode = strExpr; OwnerScript = S; m_Exp = expr; } public DynamicExpression(Script S, string strExpr, DynValue constant) { ExpressionCode = strExpr; OwnerScript = S; m_Constant = constant; } public DynValue Evaluate(ScriptExecutionContext context = null) { context = context ?? OwnerScript.CreateDynamicExecutionContext(); this.CheckScriptOwnership(context.GetScript()); if (m_Constant != null) { return m_Constant; } return m_Exp.Eval(context); } public SymbolRef FindSymbol(ScriptExecutionContext context) { this.CheckScriptOwnership(context.GetScript()); if (m_Exp != null) { return m_Exp.FindDynamic(context); } return null; } public bool IsConstant() { return m_Constant != null; } public override int GetHashCode() { return ExpressionCode.GetHashCode(); } public override bool Equals(object obj) { if (!(obj is DynamicExpression dynamicExpression)) { return false; } return dynamicExpression.ExpressionCode == ExpressionCode; } } public static class Extension_Methods { public static TValue GetOrDefault(this Dictionary dictionary, TKey key) { if (dictionary.TryGetValue(key, out var value)) { return value; } return default(TValue); } public static TValue GetOrCreate(this Dictionary dictionary, TKey key, Func creator) { if (!dictionary.TryGetValue(key, out var value)) { value = creator(); dictionary.Add(key, value); } return value; } } public class Coroutine : RefIdObject, IScriptPrivateResource { public enum CoroutineType { Coroutine, ClrCallback, ClrCallbackDead } public CallbackFunction m_ClrCallback; public Processor m_Processor; public CoroutineType Type { get; set; } public CoroutineState State { get { if (Type == CoroutineType.ClrCallback) { return CoroutineState.NotStarted; } if (Type == CoroutineType.ClrCallbackDead) { return CoroutineState.Dead; } return m_Processor.State; } } public Script OwnerScript { get; set; } public long AutoYieldCounter { get { return m_Processor.AutoYieldCounter; } set { m_Processor.AutoYieldCounter = value; } } public Coroutine(CallbackFunction function) { Type = CoroutineType.ClrCallback; m_ClrCallback = function; OwnerScript = null; } public Coroutine(Processor proc) { Type = CoroutineType.Coroutine; m_Processor = proc; m_Processor.AssociatedCoroutine = this; OwnerScript = proc.GetScript(); } public void MarkClrCallbackAsDead() { if (Type != CoroutineType.ClrCallback) { throw new InvalidOperationException("State must be CoroutineType.ClrCallback"); } Type = CoroutineType.ClrCallbackDead; } public IEnumerable AsTypedEnumerable() { if (Type != 0) { throw new InvalidOperationException("Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead"); } while (State == CoroutineState.NotStarted || State == CoroutineState.Suspended || State == CoroutineState.ForceSuspended) { yield return Resume(); } } public IEnumerable AsEnumerable() { foreach (DynValue item in AsTypedEnumerable()) { yield return item.ToScalar().ToObject(); } } public IEnumerable AsEnumerable() { foreach (DynValue item in AsTypedEnumerable()) { yield return item.ToScalar().ToObject(); } } public IEnumerator AsUnityCoroutine() { foreach (DynValue item in AsTypedEnumerable()) { _ = item; yield return null; } } public DynValue Resume(params DynValue[] args) { this.CheckScriptOwnership(args); if (Type == CoroutineType.Coroutine) { return m_Processor.Coroutine_Resume(args); } throw new InvalidOperationException("Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead"); } public DynValue Resume(ScriptExecutionContext context, params DynValue[] args) { this.CheckScriptOwnership(context); this.CheckScriptOwnership(args); if (Type == CoroutineType.Coroutine) { return m_Processor.Coroutine_Resume(args); } if (Type == CoroutineType.ClrCallback) { DynValue result = m_ClrCallback.Invoke(context, args); MarkClrCallbackAsDead(); return result; } throw ScriptRuntimeException.CannotResumeNotSuspended(CoroutineState.Dead); } public DynValue Resume() { return Resume(new DynValue[0]); } public DynValue Resume(ScriptExecutionContext context) { return Resume(context, new DynValue[0]); } public DynValue Resume(params object[] args) { if (Type != 0) { throw new InvalidOperationException("Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead"); } DynValue[] array = new DynValue[args.Length]; for (int i = 0; i < array.Length; i++) { array[i] = DynValue.FromObject(OwnerScript, args[i]); } return Resume(array); } public DynValue Resume(ScriptExecutionContext context, params object[] args) { DynValue[] array = new DynValue[args.Length]; for (int i = 0; i < array.Length; i++) { array[i] = DynValue.FromObject(context.GetScript(), args[i]); } return Resume(context, array); } public WatchItem[] GetStackTrace(int skip, SourceRef entrySourceRef = null) { if (State != CoroutineState.Running) { entrySourceRef = m_Processor.GetCoroutineSuspendedLocation(); } return m_Processor.Debugger_GetCallStack(entrySourceRef).Skip(skip).ToArray(); } } public interface IScriptPrivateResource { Script OwnerScript { get; } } public static class ScriptPrivateResource_Extension { public static void CheckScriptOwnership(this IScriptPrivateResource containingResource, DynValue[] values) { foreach (DynValue value in values) { containingResource.CheckScriptOwnership(value); } } public static void CheckScriptOwnership(this IScriptPrivateResource containingResource, DynValue value) { if (value != null) { IScriptPrivateResource asPrivateResource = value.GetAsPrivateResource(); if (asPrivateResource != null) { containingResource.CheckScriptOwnership(asPrivateResource); } } } public static void CheckScriptOwnership(this IScriptPrivateResource resource, Script script) { if (resource.OwnerScript != null && resource.OwnerScript != script && script != null) { throw new ScriptRuntimeException("Attempt to access a resource owned by a script, from another script"); } } public static void CheckScriptOwnership(this IScriptPrivateResource containingResource, IScriptPrivateResource itemResource) { if (itemResource != null) { if (containingResource.OwnerScript != null && containingResource.OwnerScript != itemResource.OwnerScript && itemResource.OwnerScript != null) { throw new ScriptRuntimeException("Attempt to perform operations with resources owned by different scripts."); } if (containingResource.OwnerScript == null && itemResource.OwnerScript != null) { throw new ScriptRuntimeException("Attempt to perform operations with a script private resource on a shared resource."); } } } } public class RefIdObject { public static int s_RefIDCounter; public int m_RefID = ++s_RefIDCounter; public int ReferenceID => m_RefID; public string FormatTypeString(string typeString) { return $"{typeString}: {m_RefID:X8}"; } } public class TailCallData { public DynValue Function { get; set; } public DynValue[] Args { get; set; } public CallbackFunction Continuation { get; set; } public CallbackFunction ErrorHandler { get; set; } public DynValue ErrorHandlerBeforeUnwind { get; set; } } public class UserData : RefIdObject { public DynValue UserValue { get; set; } public object Object { get; set; } public IUserDataDescriptor Descriptor { get; set; } public static IRegistrationPolicy RegistrationPolicy { get { return TypeDescriptorRegistry.RegistrationPolicy; } set { TypeDescriptorRegistry.RegistrationPolicy = value; } } public static InteropAccessMode DefaultAccessMode { get { return TypeDescriptorRegistry.DefaultAccessMode; } set { TypeDescriptorRegistry.DefaultAccessMode = value; } } static UserData() { RegistrationPolicy = InteropRegistrationPolicy.Default; RegisterType(InteropAccessMode.NoReflectionAllowed); RegisterType(InteropAccessMode.HideMembers); RegisterType(InteropAccessMode.NoReflectionAllowed); RegisterType(InteropAccessMode.Reflection); DefaultAccessMode = InteropAccessMode.LazyOptimized; } public static IUserDataDescriptor RegisterType(InteropAccessMode accessMode = InteropAccessMode.Default, string friendlyName = null) { return TypeDescriptorRegistry.RegisterType_Impl(typeof(T), accessMode, friendlyName, null); } public static IUserDataDescriptor RegisterType(Type type, InteropAccessMode accessMode = InteropAccessMode.Default, string friendlyName = null) { return TypeDescriptorRegistry.RegisterType_Impl(type, accessMode, friendlyName, null); } public static IUserDataDescriptor RegisterProxyType(IProxyFactory proxyFactory, InteropAccessMode accessMode = InteropAccessMode.Default, string friendlyName = null) { return TypeDescriptorRegistry.RegisterProxyType_Impl(proxyFactory, accessMode, friendlyName); } public static IUserDataDescriptor RegisterProxyType(Func wrapDelegate, InteropAccessMode accessMode = InteropAccessMode.Default, string friendlyName = null) where TProxy : class where TTarget : class { return RegisterProxyType(new DelegateProxyFactory(wrapDelegate), accessMode, friendlyName); } public static IUserDataDescriptor RegisterType(IUserDataDescriptor customDescriptor) { return TypeDescriptorRegistry.RegisterType_Impl(typeof(T), InteropAccessMode.Default, null, customDescriptor); } public static IUserDataDescriptor RegisterType(Type type, IUserDataDescriptor customDescriptor) { return TypeDescriptorRegistry.RegisterType_Impl(type, InteropAccessMode.Default, null, customDescriptor); } public static IUserDataDescriptor RegisterType(IUserDataDescriptor customDescriptor) { return TypeDescriptorRegistry.RegisterType_Impl(customDescriptor.Type, InteropAccessMode.Default, null, customDescriptor); } public static void RegisterAssembly(Assembly asm = null, bool includeExtensionTypes = false) { if (asm == null) { asm = Assembly.GetCallingAssembly(); } TypeDescriptorRegistry.RegisterAssembly(asm, includeExtensionTypes); } public static bool IsTypeRegistered(Type t) { return TypeDescriptorRegistry.IsTypeRegistered(t); } public static bool IsTypeRegistered() { return TypeDescriptorRegistry.IsTypeRegistered(typeof(T)); } public static void UnregisterType() { TypeDescriptorRegistry.UnregisterType(typeof(T)); } public static void UnregisterType(Type t) { TypeDescriptorRegistry.UnregisterType(t); } public static DynValue Create(object o, IUserDataDescriptor descr) { return DynValue.NewUserData(new UserData { Descriptor = descr, Object = o }); } public static DynValue Create(object o) { IUserDataDescriptor descriptorForObject = GetDescriptorForObject(o); if (descriptorForObject == null) { if (o is Type) { return CreateStatic((Type)o); } return null; } return Create(o, descriptorForObject); } public static DynValue CreateStatic(IUserDataDescriptor descr) { if (descr == null) { return null; } return DynValue.NewUserData(new UserData { Descriptor = descr, Object = null }); } public static DynValue CreateStatic(Type t) { return CreateStatic(GetDescriptorForType(t, searchInterfaces: false)); } public static DynValue CreateStatic() { return CreateStatic(GetDescriptorForType(typeof(T), searchInterfaces: false)); } public static void RegisterExtensionType(Type type, InteropAccessMode mode = InteropAccessMode.Default) { ExtensionMethodsRegistry.RegisterExtensionType(type, mode); } public static List GetExtensionMethodsByNameAndType(string name, Type extendedType) { return ExtensionMethodsRegistry.GetExtensionMethodsByNameAndType(name, extendedType); } public static int GetExtensionMethodsChangeVersion() { return ExtensionMethodsRegistry.GetExtensionMethodsChangeVersion(); } public static IUserDataDescriptor GetDescriptorForType(bool searchInterfaces) { return TypeDescriptorRegistry.GetDescriptorForType(typeof(T), searchInterfaces); } public static IUserDataDescriptor GetDescriptorForType(Type type, bool searchInterfaces) { return TypeDescriptorRegistry.GetDescriptorForType(type, searchInterfaces); } public static IUserDataDescriptor GetDescriptorForObject(object o) { return TypeDescriptorRegistry.GetDescriptorForType(o.GetType(), searchInterfaces: true); } public static Table GetDescriptionOfRegisteredTypes(bool useHistoricalData = false) { DynValue dynValue = DynValue.NewPrimeTable(); foreach (KeyValuePair item in useHistoricalData ? TypeDescriptorRegistry.RegisteredTypesHistory : TypeDescriptorRegistry.RegisteredTypes) { if (item.Value is IWireableDescriptor wireableDescriptor) { DynValue dynValue2 = DynValue.NewPrimeTable(); dynValue.Table.Set(item.Key.FullName, dynValue2); wireableDescriptor.PrepareForWiring(dynValue2.Table); } } return dynValue.Table; } public static IEnumerable GetRegisteredTypes(bool useHistoricalData = false) { return (useHistoricalData ? TypeDescriptorRegistry.RegisteredTypesHistory : TypeDescriptorRegistry.RegisteredTypes).Select((KeyValuePair p) => p.Value.Type); } } public static class WellKnownSymbols { public const string VARARGS = "..."; public const string ENV = "_ENV"; } public class YieldRequest { public DynValue[] ReturnValues; public bool Forced { get; set; } } [Serializable] public class ScriptRuntimeException : InterpreterException { public ScriptRuntimeException(Exception ex) : base(ex) { } public ScriptRuntimeException(ScriptRuntimeException ex) : base(ex, ex.DecoratedMessage) { base.DecoratedMessage = Message; base.DoNotDecorateMessage = true; } public ScriptRuntimeException(string message) : base(message) { } public ScriptRuntimeException(string format, params object[] args) : base(format, args) { } 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()); } 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()); } if (l.Type == DataType.String || (r != null && r.Type == DataType.String)) { return new ScriptRuntimeException("attempt to perform arithmetic on a string value"); } throw new InternalErrorException("ArithmeticOnNonNumber - both are numbers"); } 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()); } if (r != null && r.Type != DataType.Number && r.Type != DataType.String) { return new ScriptRuntimeException("attempt to concatenate a {0} value", r.Type.ToLuaTypeString()); } throw new InternalErrorException("ConcatOnNonString - both are numbers/strings"); } public static ScriptRuntimeException LenOnInvalidType(DynValue r) { return new ScriptRuntimeException("attempt to get length of a {0} value", r.Type.ToLuaTypeString()); } 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()); } return new ScriptRuntimeException("attempt to compare {0} with {1}", l.Type.ToLuaTypeString(), r.Type.ToLuaTypeString()); } public static ScriptRuntimeException BadArgument(int argNum, string funcName, string message) { return new ScriptRuntimeException("bad argument #{0} to '{1}' ({2})", argNum + 1, funcName, message); } 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"); } public static ScriptRuntimeException BadArgument(int argNum, string funcName, DataType expected, DataType got, bool allowNil) { return BadArgument(argNum, funcName, expected.ToErrorTypeString(), got.ToErrorTypeString(), allowNil); } 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); } 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()); } public static ScriptRuntimeException BadArgumentIndexOutOfRange(string funcName, int argNum) { return new ScriptRuntimeException("bad argument #{0} to '{1}' (index out of range)", argNum + 1, funcName); } 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); } public static ScriptRuntimeException BadArgumentValueExpected(int argNum, string funcName) { return new ScriptRuntimeException("bad argument #{0} to '{1}' (value expected)", argNum + 1, funcName); } public static ScriptRuntimeException IndexType(DynValue obj) { return new ScriptRuntimeException("attempt to index a {0} value", obj.Type.ToLuaTypeString()); } public static ScriptRuntimeException LoopInIndex() { return new ScriptRuntimeException("loop in gettable"); } public static ScriptRuntimeException LoopInNewIndex() { return new ScriptRuntimeException("loop in settable"); } public static ScriptRuntimeException LoopInCall() { return new ScriptRuntimeException("loop in call"); } public static ScriptRuntimeException TableIndexIsNil() { return new ScriptRuntimeException("table index is nil"); } public static ScriptRuntimeException TableIndexIsNaN() { return new ScriptRuntimeException("table index is NaN"); } public static ScriptRuntimeException ConvertToNumberFailed(int stage) { return stage switch { 1 => new ScriptRuntimeException("'for' initial value must be a number"), 2 => new ScriptRuntimeException("'for' step must be a number"), 3 => new ScriptRuntimeException("'for' limit must be a number"), _ => new ScriptRuntimeException("value must be a number"), }; } public static ScriptRuntimeException ConvertObjectFailed(object obj) { return new ScriptRuntimeException("cannot convert clr type {0}", obj.GetType()); } public static ScriptRuntimeException ConvertObjectFailed(DataType t) { return new ScriptRuntimeException("cannot convert a {0} to a clr type", t.ToString().ToLowerInvariant()); } 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); } 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); } public static ScriptRuntimeException UserDataMissingField(string typename, string fieldname) { return new ScriptRuntimeException("cannot access field {0} of userdata<{1}>", fieldname, typename); } public static ScriptRuntimeException CannotResumeNotSuspended(CoroutineState state) { if (state == CoroutineState.Dead) { return new ScriptRuntimeException("cannot resume dead coroutine"); } return new ScriptRuntimeException("cannot resume non-suspended coroutine"); } public static ScriptRuntimeException CannotYield() { return new ScriptRuntimeException("attempt to yield across a CLR-call boundary"); } public static ScriptRuntimeException CannotYieldMain() { return new ScriptRuntimeException("attempt to yield from outside a coroutine"); } public static ScriptRuntimeException AttemptToCallNonFunc(DataType type, string debugText = null) { string text = type.ToErrorTypeString(); if (debugText != null) { return new ScriptRuntimeException("attempt to call a {0} value near '{1}'", text, debugText); } return new ScriptRuntimeException("attempt to call a {0} value", text); } public static ScriptRuntimeException AccessInstanceMemberOnStatics(IMemberDescriptor desc) { return new ScriptRuntimeException("attempt to access instance member {0} from a static userdata", desc.Name); } 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); } public override void Rethrow() { if (Script.GlobalOptions.RethrowExceptionNested) { throw new ScriptRuntimeException(this); } } } [Serializable] public class InternalErrorException : InterpreterException { public InternalErrorException(string message) : base(message) { } public InternalErrorException(string format, params object[] args) : base(format, args) { } } [Serializable] public class InterpreterException : Exception { public int InstructionPtr { get; set; } public IList CallStack { get; set; } public string DecoratedMessage { get; set; } public bool DoNotDecorateMessage { get; set; } public InterpreterException(Exception ex, string message) : base(message, ex) { } public InterpreterException(Exception ex) : base(ex.Message, ex) { } public InterpreterException(string message) : base(message) { } public InterpreterException(string format, params object[] args) : base(string.Format(format, args)) { } public void DecorateMessage(Script script, SourceRef sref, int ip = -1) { if (string.IsNullOrEmpty(DecoratedMessage)) { if (DoNotDecorateMessage) { DecoratedMessage = Message; } else if (sref != null) { DecoratedMessage = $"{sref.FormatLocation(script)}: {Message}"; } else { DecoratedMessage = $"bytecode:{ip}: {Message}"; } } } public virtual void Rethrow() { } } [Serializable] public class SyntaxErrorException : InterpreterException { public Token Token { get; set; } public bool IsPrematureStreamTermination { get; set; } public SyntaxErrorException(Token t, string format, params object[] args) : base(format, args) { Token = t; } public SyntaxErrorException(Token t, string message) : base(message) { Token = t; } public SyntaxErrorException(Script script, SourceRef sref, string format, params object[] args) : base(format, args) { DecorateMessage(script, sref); } public SyntaxErrorException(Script script, SourceRef sref, string message) : base(message) { DecorateMessage(script, sref); } public SyntaxErrorException(SyntaxErrorException syntaxErrorException) : base(syntaxErrorException, syntaxErrorException.DecoratedMessage) { Token = syntaxErrorException.Token; base.DecoratedMessage = Message; } public void DecorateMessage(Script script) { if (Token != null) { DecorateMessage(script, Token.GetSourceRef(isStepStop: false)); } } public override void Rethrow() { if (Script.GlobalOptions.RethrowExceptionNested) { throw new SyntaxErrorException(this); } } } public class CallbackArguments { public IList m_Args; public int m_Count; public bool m_LastIsTuple; public int Count => m_Count; public bool IsMethodCall { get; set; } public DynValue this[int index] => RawGet(index, translateVoids: true) ?? DynValue.Void; public CallbackArguments(IList args, bool isMethodCall) { m_Args = args; if (m_Args.Count > 0) { DynValue dynValue = m_Args[m_Args.Count - 1]; if (dynValue.Type == DataType.Tuple) { m_Count = dynValue.Tuple.Length - 1 + m_Args.Count; m_LastIsTuple = true; } else if (dynValue.Type == DataType.Void) { m_Count = m_Args.Count - 1; } else { m_Count = m_Args.Count; } } else { m_Count = 0; } IsMethodCall = isMethodCall; } public DynValue RawGet(int index, bool translateVoids) { if (index >= m_Count) { return null; } DynValue dynValue = ((m_LastIsTuple && index >= m_Args.Count - 1) ? m_Args[m_Args.Count - 1].Tuple[index - (m_Args.Count - 1)] : m_Args[index]); if (dynValue.Type == DataType.Tuple) { dynValue = ((dynValue.Tuple.Length == 0) ? DynValue.Nil : dynValue.Tuple[0]); } if (translateVoids && dynValue.Type == DataType.Void) { dynValue = DynValue.Nil; } return dynValue; } public DynValue[] GetArray(int skip = 0) { if (skip >= m_Count) { return new DynValue[0]; } DynValue[] array = new DynValue[m_Count - skip]; for (int i = skip; i < m_Count; i++) { array[i - skip] = this[i]; } return array; } public DynValue AsType(int argNum, string funcName, DataType type, bool allowNil = false) { return this[argNum].CheckType(funcName, type, argNum, allowNil ? (TypeValidationFlags.AllowNil | TypeValidationFlags.AutoConvert) : TypeValidationFlags.AutoConvert); } public T AsUserData(int argNum, string funcName, bool allowNil = false) { return this[argNum].CheckUserDataType(funcName, argNum, allowNil ? TypeValidationFlags.AllowNil : TypeValidationFlags.None); } public int AsInt(int argNum, string funcName) { return (int)AsType(argNum, funcName, DataType.Number).Number; } public long AsLong(int argNum, string funcName) { return (long)AsType(argNum, funcName, DataType.Number).Number; } public string AsStringUsingMeta(ScriptExecutionContext executionContext, int argNum, string funcName) { if (this[argNum].Type == DataType.Table && this[argNum].Table.MetaTable != null && this[argNum].Table.MetaTable.RawGet("__tostring") != null) { DynValue dynValue = executionContext.GetScript().Call(this[argNum].Table.MetaTable.RawGet("__tostring"), this[argNum]); if (dynValue.Type != DataType.String) { throw new ScriptRuntimeException("'tostring' must return a string to '{0}'", funcName); } return dynValue.ToPrintString(); } return this[argNum].ToPrintString(); } public CallbackArguments SkipMethodCall() { if (IsMethodCall) { return new CallbackArguments(new Slice(m_Args, 1, m_Args.Count - 1, reversed: false), isMethodCall: false); } return this; } } public class Closure : RefIdObject, IScriptPrivateResource { public enum UpvaluesType { None, Environment, Closure } public static ClosureContext emptyClosure = new ClosureContext(); public int EntryPointByteCodeLocation { get; set; } public Script OwnerScript { get; set; } public ClosureContext ClosureContext { get; set; } public Closure(Script script, int idx, SymbolRef[] symbols, IEnumerable resolvedLocals) { OwnerScript = script; EntryPointByteCodeLocation = idx; if (symbols.Length != 0) { ClosureContext = new ClosureContext(symbols, resolvedLocals); } else { ClosureContext = emptyClosure; } } public DynValue Call() { return OwnerScript.Call(this); } public DynValue Call(params object[] args) { return OwnerScript.Call(this, args); } public DynValue Call(params DynValue[] args) { return OwnerScript.Call(this, args); } public ScriptFunctionDelegate GetDelegate() { return (object[] args) => Call(args).ToObject(); } public ScriptFunctionDelegate GetDelegate() { return (object[] args) => Call(args).ToObject(); } public int GetUpvaluesCount() { return ClosureContext.Count; } public string GetUpvalueName(int idx) { return ClosureContext.Symbols[idx]; } public DynValue GetUpvalue(int idx) { return ClosureContext[idx]; } public UpvaluesType GetUpvaluesType() { switch (GetUpvaluesCount()) { case 0: return UpvaluesType.None; case 1: if (GetUpvalueName(0) == "_ENV") { return UpvaluesType.Environment; } break; } return UpvaluesType.Closure; } } public sealed class CallbackFunction : RefIdObject { public static InteropAccessMode m_DefaultAccessMode = InteropAccessMode.LazyOptimized; public string Name { get; set; } public Func ClrCallback { get; set; } public static InteropAccessMode DefaultAccessMode { get { return m_DefaultAccessMode; } set { if (value == InteropAccessMode.Default || value == InteropAccessMode.HideMembers || value == InteropAccessMode.BackgroundOptimized) { throw new ArgumentException("DefaultAccessMode"); } m_DefaultAccessMode = value; } } public object AdditionalData { get; set; } public CallbackFunction(Func callBack, string name = null) { ClrCallback = callBack; Name = name; } public DynValue Invoke(ScriptExecutionContext executionContext, IList args, bool isMethodCall = false) { if (isMethodCall) { switch (executionContext.GetScript().Options.ColonOperatorClrCallbackBehaviour) { case ColonOperatorBehaviour.TreatAsColon: isMethodCall = false; break; case ColonOperatorBehaviour.TreatAsDotOnUserData: isMethodCall = args.Count > 0 && args[0].Type == DataType.UserData; break; } } return ClrCallback(executionContext, new CallbackArguments(args, isMethodCall)); } public static CallbackFunction FromDelegate(Script script, Delegate del, InteropAccessMode accessMode = InteropAccessMode.Default) { if (accessMode == InteropAccessMode.Default) { accessMode = m_DefaultAccessMode; } return new MethodMemberDescriptor(del.Method, accessMode).GetCallbackFunction(script, del.Target); } public static CallbackFunction FromMethodInfo(Script script, MethodInfo mi, object obj = null, InteropAccessMode accessMode = InteropAccessMode.Default) { if (accessMode == InteropAccessMode.Default) { accessMode = m_DefaultAccessMode; } return new MethodMemberDescriptor(mi, accessMode).GetCallbackFunction(script, obj); } public static bool CheckCallbackSignature(MethodInfo mi, bool requirePublicVisibility) { ParameterInfo[] parameters = mi.GetParameters(); if (parameters.Length == 2 && parameters[0].ParameterType == typeof(ScriptExecutionContext) && parameters[1].ParameterType == typeof(CallbackArguments) && mi.ReturnType == typeof(DynValue)) { if (!requirePublicVisibility) { return mi.IsPublic; } return true; } return false; } } public sealed class DynValue { public static int s_RefIDCounter; public int m_RefID = ++s_RefIDCounter; public int m_HashCode = -1; public bool m_ReadOnly; public double m_Number; public object m_Object; public DataType m_Type; public int ReferenceID => m_RefID; public DataType Type => m_Type; public Closure Function => m_Object as Closure; public double Number => m_Number; public DynValue[] Tuple => m_Object as DynValue[]; public Coroutine Coroutine => m_Object as Coroutine; public Table Table => m_Object as Table; public bool Boolean => Number != 0.0; public string String => m_Object as string; public CallbackFunction Callback => m_Object as CallbackFunction; public TailCallData TailCallData => m_Object as TailCallData; public YieldRequest YieldRequest => m_Object as YieldRequest; public UserData UserData => m_Object as UserData; public bool ReadOnly => m_ReadOnly; public static DynValue Void { get; set; } public static DynValue Nil { get; set; } public static DynValue True { get; set; } public static DynValue False { get; set; } public static DynValue NewNil() { return new DynValue(); } public static DynValue NewBoolean(bool v) { return new DynValue { m_Number = (v ? 1 : 0), m_Type = DataType.Boolean }; } public static DynValue NewNumber(double num) { return new DynValue { m_Number = num, m_Type = DataType.Number, m_HashCode = -1 }; } public static DynValue NewString(string str) { return new DynValue { m_Object = str, m_Type = DataType.String }; } public static DynValue NewString(StringBuilder sb) { return new DynValue { m_Object = sb.ToString(), m_Type = DataType.String }; } public static DynValue NewString(string format, params object[] args) { return new DynValue { m_Object = string.Format(format, args), m_Type = DataType.String }; } public static DynValue NewCoroutine(Coroutine coroutine) { return new DynValue { m_Object = coroutine, m_Type = DataType.Thread }; } public static DynValue NewClosure(Closure function) { return new DynValue { m_Object = function, m_Type = DataType.Function }; } public static DynValue NewCallback(Func callBack, string name = null) { return new DynValue { m_Object = new CallbackFunction(callBack, name), m_Type = DataType.ClrFunction }; } public static DynValue NewCallback(CallbackFunction function) { return new DynValue { m_Object = function, m_Type = DataType.ClrFunction }; } public static DynValue NewTable(Table table) { return new DynValue { m_Object = table, m_Type = DataType.Table }; } public static DynValue NewPrimeTable() { return NewTable(new Table(null)); } public static DynValue NewTable(Script script) { return NewTable(new Table(script)); } public static DynValue NewTable(Script script, params DynValue[] arrayValues) { return NewTable(new Table(script, arrayValues)); } public static DynValue NewTailCallReq(DynValue tailFn, params DynValue[] args) { return new DynValue { m_Object = new TailCallData { Args = args, Function = tailFn }, m_Type = DataType.TailCallRequest }; } public static DynValue NewTailCallReq(TailCallData tailCallData) { return new DynValue { m_Object = tailCallData, m_Type = DataType.TailCallRequest }; } public static DynValue NewYieldReq(DynValue[] args) { return new DynValue { m_Object = new YieldRequest { ReturnValues = args }, m_Type = DataType.YieldRequest }; } public static DynValue NewForcedYieldReq() { return new DynValue { m_Object = new YieldRequest { Forced = true }, m_Type = DataType.YieldRequest }; } public static DynValue NewTuple(params DynValue[] values) { if (values.Length == 0) { return NewNil(); } if (values.Length == 1) { return values[0]; } return new DynValue { m_Object = values, m_Type = DataType.Tuple }; } public static DynValue NewTupleNested(params DynValue[] values) { if (!values.Any((DynValue v) => v.Type == DataType.Tuple)) { return NewTuple(values); } if (values.Length == 1) { return values[0]; } List list = new List(); foreach (DynValue dynValue in values) { if (dynValue.Type == DataType.Tuple) { list.AddRange(dynValue.Tuple); } else { list.Add(dynValue); } } return new DynValue { m_Object = list.ToArray(), m_Type = DataType.Tuple }; } public static DynValue NewUserData(UserData userData) { return new DynValue { m_Object = userData, m_Type = DataType.UserData }; } public DynValue AsReadOnly() { if (ReadOnly) { return this; } return Clone(readOnly: true); } public DynValue Clone() { return Clone(ReadOnly); } public DynValue Clone(bool readOnly) { return new DynValue { m_Object = m_Object, m_Number = m_Number, m_HashCode = m_HashCode, m_Type = m_Type, m_ReadOnly = readOnly }; } public DynValue CloneAsWritable() { return Clone(readOnly: false); } static DynValue() { Nil = new DynValue { m_Type = DataType.Nil }.AsReadOnly(); Void = new DynValue { m_Type = DataType.Void }.AsReadOnly(); True = NewBoolean(v: true).AsReadOnly(); False = NewBoolean(v: false).AsReadOnly(); } public string ToPrintString() { if (m_Object != null && m_Object is RefIdObject) { RefIdObject refIdObject = (RefIdObject)m_Object; string typeString = Type.ToLuaTypeString(); if (m_Object is UserData) { UserData userData = (UserData)m_Object; string text = userData.Descriptor.AsString(userData.Object); if (text != null) { return text; } } return refIdObject.FormatTypeString(typeString); } return Type switch { DataType.String => String, DataType.Tuple => string.Join("\t", Tuple.Select((DynValue t) => t.ToPrintString()).ToArray()), DataType.TailCallRequest => "(TailCallRequest -- INTERNAL!)", DataType.YieldRequest => "(YieldRequest -- INTERNAL!)", _ => ToString(), }; } public string ToDebugPrintString() { if (m_Object != null && m_Object is RefIdObject) { RefIdObject refIdObject = (RefIdObject)m_Object; string typeString = Type.ToLuaTypeString(); if (m_Object is UserData) { UserData userData = (UserData)m_Object; string text = userData.Descriptor.AsString(userData.Object); if (text != null) { return text; } } return refIdObject.FormatTypeString(typeString); } return Type switch { DataType.Tuple => string.Join("\t", Tuple.Select((DynValue t) => t.ToPrintString()).ToArray()), DataType.TailCallRequest => "(TailCallRequest)", DataType.YieldRequest => "(YieldRequest)", _ => ToString(), }; } public override string ToString() { return Type switch { DataType.Void => "void", DataType.Nil => "nil", DataType.Boolean => Boolean.ToString().ToLower(), DataType.Number => Number.ToString(CultureInfo.InvariantCulture), DataType.String => "\"" + String + "\"", DataType.Function => $"(Function {Function.EntryPointByteCodeLocation:X8})", DataType.ClrFunction => string.Format("(Function CLR)", Function), DataType.Table => "(Table)", DataType.Tuple => string.Join(", ", Tuple.Select((DynValue t) => t.ToString()).ToArray()), DataType.TailCallRequest => "Tail:(" + string.Join(", ", Tuple.Select((DynValue t) => t.ToString()).ToArray()) + ")", DataType.UserData => "(UserData)", DataType.Thread => $"(Coroutine {Coroutine.ReferenceID:X8})", _ => "(???)", }; } public override int GetHashCode() { if (m_HashCode != -1) { return m_HashCode; } int num = (int)Type << 27; switch (Type) { case DataType.Nil: case DataType.Void: m_HashCode = 0; break; case DataType.Boolean: m_HashCode = (Boolean ? 1 : 2); break; case DataType.Number: m_HashCode = num ^ Number.GetHashCode(); break; case DataType.String: m_HashCode = num ^ String.GetHashCode(); break; case DataType.Function: m_HashCode = num ^ Function.GetHashCode(); break; case DataType.ClrFunction: m_HashCode = num ^ Callback.GetHashCode(); break; case DataType.Table: m_HashCode = num ^ Table.GetHashCode(); break; case DataType.Tuple: case DataType.TailCallRequest: m_HashCode = num ^ Tuple.GetHashCode(); break; default: m_HashCode = 999; break; } return m_HashCode; } public override bool Equals(object obj) { if (!(obj is DynValue dynValue)) { return false; } if ((dynValue.Type == DataType.Nil && Type == DataType.Void) || (dynValue.Type == DataType.Void && Type == DataType.Nil)) { return true; } if (dynValue.Type != Type) { return false; } switch (Type) { case DataType.Nil: case DataType.Void: return true; case DataType.Boolean: return Boolean == dynValue.Boolean; case DataType.Number: return Number == dynValue.Number; case DataType.String: return String == dynValue.String; case DataType.Function: return Function == dynValue.Function; case DataType.ClrFunction: return Callback == dynValue.Callback; case DataType.Table: return Table == dynValue.Table; case DataType.Tuple: case DataType.TailCallRequest: return Tuple == dynValue.Tuple; case DataType.Thread: return Coroutine == dynValue.Coroutine; case DataType.UserData: { UserData userData = UserData; UserData userData2 = dynValue.UserData; if (userData == null || userData2 == null) { return false; } if (userData.Descriptor != userData2.Descriptor) { return false; } if (userData.Object == null && userData2.Object == null) { return true; } if (userData.Object != null && userData2.Object != null) { return userData.Object.Equals(userData2.Object); } return false; } default: return this == dynValue; } } public string CastToString() { DynValue dynValue = ToScalar(); if (dynValue.Type == DataType.Number) { return dynValue.Number.ToString(); } if (dynValue.Type == DataType.String) { return dynValue.String; } return null; } public double? CastToNumber() { DynValue dynValue = ToScalar(); if (dynValue.Type == DataType.Number) { return dynValue.Number; } if (dynValue.Type == DataType.String && double.TryParse(dynValue.String, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } return null; } public bool CastToBool() { DynValue dynValue = ToScalar(); if (dynValue.Type == DataType.Boolean) { return dynValue.Boolean; } if (dynValue.Type != 0) { return dynValue.Type != DataType.Void; } return false; } public IScriptPrivateResource GetAsPrivateResource() { return m_Object as IScriptPrivateResource; } public DynValue ToScalar() { if (Type != DataType.Tuple) { return this; } if (Tuple.Length == 0) { return Void; } return Tuple[0].ToScalar(); } public void Assign(DynValue value) { if (ReadOnly) { throw new ScriptRuntimeException("Assigning on r-value"); } m_Number = value.m_Number; m_Object = value.m_Object; m_Type = value.Type; m_HashCode = -1; } public DynValue GetLength() { if (Type == DataType.Table) { return NewNumber(Table.Length); } if (Type == DataType.String) { return NewNumber(String.Length); } throw new ScriptRuntimeException("Can't get length of type {0}", Type); } public bool IsNil() { if (Type != 0) { return Type == DataType.Void; } return true; } public bool IsNotNil() { if (Type != 0) { return Type != DataType.Void; } return false; } public bool IsVoid() { return Type == DataType.Void; } public bool IsNotVoid() { return Type != DataType.Void; } public bool IsNilOrNan() { if (Type != 0 && Type != DataType.Void) { if (Type == DataType.Number) { return double.IsNaN(Number); } return false; } return true; } public void AssignNumber(double num) { if (ReadOnly) { throw new InternalErrorException(null, "Writing on r-value"); } if (Type != DataType.Number) { throw new InternalErrorException("Can't assign number to type {0}", Type); } m_Number = num; } public static DynValue FromObject(Script script, object obj) { return ClrToScriptConversions.ObjectToDynValue(script, obj); } public object ToObject() { return ScriptToClrConversions.DynValueToObject(this); } public object ToObject(Type desiredType) { return ScriptToClrConversions.DynValueToObjectOfType(this, desiredType, null, isOptional: false); } public T ToObject() { return (T)ToObject(typeof(T)); } public dynamic ToDynamic() { return ScriptToClrConversions.DynValueToObject(this); } public DynValue CheckType(string funcName, DataType desiredType, int argNum = -1, TypeValidationFlags flags = TypeValidationFlags.AutoConvert) { if (Type == desiredType) { return this; } bool flag = (flags & TypeValidationFlags.AllowNil) != 0; if (flag && IsNil()) { return this; } if ((flags & TypeValidationFlags.AutoConvert) != 0) { switch (desiredType) { case DataType.Boolean: return NewBoolean(CastToBool()); case DataType.Number: { double? num = CastToNumber(); if (num.HasValue) { return NewNumber(num.Value); } break; } } if (desiredType == DataType.String) { string text = CastToString(); if (text != null) { return NewString(text); } } } if (IsVoid()) { throw ScriptRuntimeException.BadArgumentNoValue(argNum, funcName, desiredType); } throw ScriptRuntimeException.BadArgument(argNum, funcName, desiredType, Type, flag); } public T CheckUserDataType(string funcName, int argNum = -1, TypeValidationFlags flags = TypeValidationFlags.AutoConvert) { DynValue dynValue = CheckType(funcName, DataType.UserData, argNum, flags); bool allowNil = (flags & TypeValidationFlags.AllowNil) != 0; if (dynValue.IsNil()) { return default(T); } object @object = dynValue.UserData.Object; if (@object != null && @object is T) { return (T)@object; } throw ScriptRuntimeException.BadArgumentUserData(argNum, funcName, typeof(T), @object, allowNil); } } public struct TablePair { public static TablePair s_NilNode = new TablePair(DynValue.Nil, DynValue.Nil); public DynValue key; public DynValue value; public DynValue Key { get { return key; } set { Key = key; } } public DynValue Value { get { return value; } set { if (key.IsNotNil()) { Value = value; } } } public static TablePair Nil => s_NilNode; public TablePair(DynValue key, DynValue val) { this.key = key; value = val; } } public class ScriptExecutionContext : IScriptPrivateResource { public Processor m_Processor; public CallbackFunction m_Callback; public bool IsDynamicExecution { get; set; } public SourceRef CallingLocation { get; set; } public object AdditionalData { get { if (m_Callback == null) { return null; } return m_Callback.AdditionalData; } set { if (m_Callback == null) { throw new InvalidOperationException("Cannot set additional data on a context which has no callback"); } m_Callback.AdditionalData = value; } } public Table CurrentGlobalEnv { get { DynValue dynValue = EvaluateSymbolByName("_ENV"); if (dynValue == null || dynValue.Type != DataType.Table) { return null; } return dynValue.Table; } } public Script OwnerScript => GetScript(); public ScriptExecutionContext(Processor p, CallbackFunction callBackFunction, SourceRef sourceRef, bool isDynamic = false) { IsDynamicExecution = isDynamic; m_Processor = p; m_Callback = callBackFunction; CallingLocation = sourceRef; } public Table GetMetatable(DynValue value) { return m_Processor.GetMetatable(value); } public DynValue GetMetamethod(DynValue value, string metamethod) { return m_Processor.GetMetamethod(value, metamethod); } public DynValue GetMetamethodTailCall(DynValue value, string metamethod, params DynValue[] args) { DynValue metamethod2 = GetMetamethod(value, metamethod); if (metamethod2 == null) { return null; } return DynValue.NewTailCallReq(metamethod2, args); } public DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventName) { return m_Processor.GetBinaryMetamethod(op1, op2, eventName); } public Script GetScript() { return m_Processor.GetScript(); } public Coroutine GetCallingCoroutine() { return m_Processor.AssociatedCoroutine; } public DynValue EmulateClassicCall(CallbackArguments args, string functionName, Func callback) { LuaState luaState = new LuaState(this, args, functionName); int retvals = callback(luaState); return luaState.GetReturnValue(retvals); } public DynValue Call(DynValue func, params DynValue[] args) { if (func.Type == DataType.Function) { return GetScript().Call(func, args); } if (func.Type == DataType.ClrFunction) { DynValue dynValue; while (true) { dynValue = func.Callback.Invoke(this, args); if (dynValue.Type == DataType.YieldRequest) { throw ScriptRuntimeException.CannotYield(); } if (dynValue.Type != DataType.TailCallRequest) { break; } TailCallData tailCallData = dynValue.TailCallData; if (tailCallData.Continuation != null || tailCallData.ErrorHandler != null) { throw new ScriptRuntimeException("the function passed cannot be called directly. wrap in a script function instead."); } args = tailCallData.Args; func = tailCallData.Function; } return dynValue; } int num = 10; while (num > 0) { DynValue metamethod = GetMetamethod(func, "__call"); if (metamethod == null && metamethod.IsNil()) { throw ScriptRuntimeException.AttemptToCallNonFunc(func.Type); } func = metamethod; if (func.Type == DataType.Function || func.Type == DataType.ClrFunction) { return Call(func, args); } } throw ScriptRuntimeException.LoopInCall(); } public DynValue EvaluateSymbol(SymbolRef symref) { if (symref == null) { return DynValue.Nil; } return m_Processor.GetGenericSymbol(symref); } public DynValue EvaluateSymbolByName(string symbol) { return EvaluateSymbol(FindSymbolByName(symbol)); } public SymbolRef FindSymbolByName(string symbol) { return m_Processor.FindSymbolByName(symbol); } public void PerformMessageDecorationBeforeUnwind(DynValue messageHandler, ScriptRuntimeException exception) { if (messageHandler != null) { exception.DecoratedMessage = m_Processor.PerformMessageDecorationBeforeUnwind(messageHandler, exception.Message, CallingLocation); } else { exception.DecoratedMessage = exception.Message; } } } public enum CoroutineState { Main, NotStarted, Suspended, ForceSuspended, Running, Dead } public static class LinqHelpers { public static IEnumerable Convert(this IEnumerable enumerable, DataType type) { return from v in enumerable where v.Type == type select v.ToObject(); } public static IEnumerable OfDataType(this IEnumerable enumerable, DataType type) { return enumerable.Where((DynValue v) => v.Type == type); } public static IEnumerable AsObjects(this IEnumerable enumerable) { return enumerable.Select((DynValue v) => v.ToObject()); } public static IEnumerable AsObjects(this IEnumerable enumerable) { return enumerable.Select((DynValue v) => v.ToObject()); } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] public sealed class MoonSharpUserDataAttribute : Attribute { public InteropAccessMode AccessMode { get; set; } public MoonSharpUserDataAttribute() { AccessMode = InteropAccessMode.Default; } } public class AutoDescribingUserDataDescriptor : IUserDataDescriptor { public string m_FriendlyName; public Type m_Type; public string Name => m_FriendlyName; public Type Type => m_Type; public AutoDescribingUserDataDescriptor(Type type, string friendlyName) { m_FriendlyName = friendlyName; m_Type = type; } public DynValue Index(Script script, object obj, DynValue index, bool isDirectIndexing) { if (obj is IUserDataType userDataType) { return userDataType.Index(script, index, isDirectIndexing); } return null; } public bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing) { if (obj is IUserDataType userDataType) { return userDataType.SetIndex(script, index, value, isDirectIndexing); } return false; } public string AsString(object obj) { return obj?.ToString(); } public DynValue MetaIndex(Script script, object obj, string metaname) { if (obj is IUserDataType userDataType) { return userDataType.MetaIndex(script, metaname); } return null; } public bool IsTypeCompatible(Type type, object obj) { return Framework.Do.IsInstanceOfType(type, obj); } } public enum InteropAccessMode { Reflection, LazyOptimized, Preoptimized, BackgroundOptimized, Hardwired, HideMembers, NoReflectionAllowed, Default } public enum SymbolRefType { Local, Upvalue, Global, DefaultEnv } public class SymbolRef { public static SymbolRef s_DefaultEnv = new SymbolRef { i_Type = SymbolRefType.DefaultEnv }; public SymbolRefType i_Type; public SymbolRef i_Env; public int i_Index; public string i_Name; public SymbolRefType Type => i_Type; public int Index => i_Index; public string Name => i_Name; public SymbolRef Environment => i_Env; public static SymbolRef DefaultEnv => s_DefaultEnv; public static SymbolRef Global(string name, SymbolRef envSymbol) { return new SymbolRef { i_Index = -1, i_Type = SymbolRefType.Global, i_Env = envSymbol, i_Name = name }; } public static SymbolRef Local(string name, int index) { return new SymbolRef { i_Index = index, i_Type = SymbolRefType.Local, i_Name = name }; } public static SymbolRef Upvalue(string name, int index) { return new SymbolRef { i_Index = index, i_Type = SymbolRefType.Upvalue, i_Name = name }; } public override string ToString() { if (i_Type == SymbolRefType.DefaultEnv) { return "(default _ENV)"; } if (i_Type == SymbolRefType.Global) { return string.Format("{2} : {0} / {1}", i_Type, i_Env, i_Name); } return string.Format("{2} : {0}[{1}]", i_Type, i_Index, i_Name); } public void WriteBinary(BinaryWriter bw) { bw.Write((byte)i_Type); bw.Write(i_Index); bw.Write(i_Name); } public static SymbolRef ReadBinary(BinaryReader br) { return new SymbolRef { i_Type = (SymbolRefType)br.ReadByte(), i_Index = br.ReadInt32(), i_Name = br.ReadString() }; } public void WriteBinaryEnv(BinaryWriter bw, Dictionary symbolMap) { if (i_Env != null) { bw.Write(symbolMap[i_Env]); } else { bw.Write(-1); } } public void ReadBinaryEnv(BinaryReader br, SymbolRef[] symbolRefs) { int num = br.ReadInt32(); if (num >= 0) { i_Env = symbolRefs[num]; } } } public enum DataType { Nil, Void, Boolean, Number, String, Function, Table, Tuple, UserData, Thread, ClrFunction, TailCallRequest, YieldRequest } public static class LuaTypeExtensions { public const DataType MaxMetaTypes = DataType.Table; public const DataType MaxConvertibleTypes = DataType.ClrFunction; public static bool CanHaveTypeMetatables(this DataType type) { return type < DataType.Table; } public static string ToErrorTypeString(this DataType type) { return type switch { DataType.Void => "no value", DataType.Nil => "nil", DataType.Boolean => "boolean", DataType.Number => "number", DataType.String => "string", DataType.Function => "function", DataType.ClrFunction => "function", DataType.Table => "table", DataType.UserData => "userdata", DataType.Thread => "coroutine", _ => $"internal<{type.ToLuaDebuggerString()}>", }; } public static string ToLuaDebuggerString(this DataType type) { return type.ToString().ToLowerInvariant(); } public static string ToLuaTypeString(this DataType type) { switch (type) { case DataType.Nil: case DataType.Void: return "nil"; case DataType.Boolean: return "boolean"; case DataType.Number: return "number"; case DataType.String: return "string"; case DataType.Function: return "function"; case DataType.ClrFunction: return "function"; case DataType.Table: return "table"; case DataType.UserData: return "userdata"; case DataType.Thread: return "thread"; default: throw new ScriptRuntimeException("Unexpected LuaType {0}", type); } } } public enum ColonOperatorBehaviour { TreatAsDot, TreatAsDotOnUserData, TreatAsColon } [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)] public sealed class MoonSharpModuleConstantAttribute : Attribute { public string Name { get; set; } } public static class NamespaceDoc { } public class Script : IScriptPrivateResource { public const string VERSION = "2.0.0.0"; public const string LUA_VERSION = "5.2"; public Processor m_MainProcessor; public ByteCode m_ByteCode; public List m_Sources = new List(); public Table m_GlobalTable; public IDebugger m_Debugger; public Table[] m_TypeMetatables = new Table[6]; public static ScriptOptions DefaultOptions { get; set; } public ScriptOptions Options { get; set; } public static ScriptGlobalOptions GlobalOptions { get; set; } public PerformanceStatistics PerformanceStats { get; set; } public Table Globals => m_GlobalTable; public bool DebuggerEnabled { get { return m_MainProcessor.DebuggerEnabled; } set { m_MainProcessor.DebuggerEnabled = value; } } public int SourceCodeCount => m_Sources.Count; public Table Registry { get; set; } Script IScriptPrivateResource.OwnerScript => this; static Script() { GlobalOptions = new ScriptGlobalOptions(); DefaultOptions = new ScriptOptions { DebugPrint = delegate(string s) { GlobalOptions.Platform.DefaultPrint(s); }, DebugInput = (string s) => GlobalOptions.Platform.DefaultInput(s), CheckThreadAccess = true, ScriptLoader = PlatformAutoDetector.GetDefaultScriptLoader(), TailCallOptimizationThreshold = 65536 }; } public Script() : this(CoreModules.Preset_Default) { } public Script(CoreModules coreModules) { Options = new ScriptOptions(DefaultOptions); PerformanceStats = new PerformanceStatistics(); Registry = new Table(this); m_ByteCode = new ByteCode(this); m_MainProcessor = new Processor(this, m_GlobalTable, m_ByteCode); m_GlobalTable = new Table(this).RegisterCoreModules(coreModules); } public DynValue LoadFunction(string code, Table globalTable = null, string funcFriendlyName = null) { this.CheckScriptOwnership(globalTable); SourceCode sourceCode = new SourceCode($"libfunc_{funcFriendlyName ?? m_Sources.Count.ToString()}", code, m_Sources.Count, this); m_Sources.Add(sourceCode); int address = Loader_Fast.LoadFunction(this, sourceCode, m_ByteCode, globalTable != null || m_GlobalTable != null); SignalSourceCodeChange(sourceCode); SignalByteCodeChange(); return MakeClosure(address, globalTable ?? m_GlobalTable); } public void SignalByteCodeChange() { if (m_Debugger != null) { m_Debugger.SetByteCode(m_ByteCode.Code.Select((Instruction s) => s.ToString()).ToArray()); } } public void SignalSourceCodeChange(SourceCode source) { if (m_Debugger != null) { m_Debugger.SetSourceCode(source); } } public DynValue LoadString(string code, Table globalTable = null, string codeFriendlyName = null) { this.CheckScriptOwnership(globalTable); if (code.StartsWith("MoonSharp_dump_b64::")) { code = code.Substring("MoonSharp_dump_b64::".Length); using MemoryStream stream = new MemoryStream(Convert.FromBase64String(code)); return LoadStream(stream, globalTable, codeFriendlyName); } string text = string.Format("{0}", codeFriendlyName ?? ("chunk_" + m_Sources.Count)); SourceCode sourceCode = new SourceCode(codeFriendlyName ?? text, code, m_Sources.Count, this); m_Sources.Add(sourceCode); int address = Loader_Fast.LoadChunk(this, sourceCode, m_ByteCode); SignalSourceCodeChange(sourceCode); SignalByteCodeChange(); return MakeClosure(address, globalTable ?? m_GlobalTable); } public DynValue LoadStream(Stream stream, Table globalTable = null, string codeFriendlyName = null) { this.CheckScriptOwnership(globalTable); Stream stream2 = new UndisposableStream(stream); if (!Processor.IsDumpStream(stream2)) { using (StreamReader streamReader = new StreamReader(stream2)) { string code = streamReader.ReadToEnd(); return LoadString(code, globalTable, codeFriendlyName); } } string text = string.Format("{0}", codeFriendlyName ?? ("dump_" + m_Sources.Count)); SourceCode sourceCode = new SourceCode(codeFriendlyName ?? text, $"-- This script was decoded from a binary dump - dump_{m_Sources.Count}", m_Sources.Count, this); m_Sources.Add(sourceCode); bool hasUpvalues; int address = m_MainProcessor.Undump(stream2, m_Sources.Count - 1, globalTable ?? m_GlobalTable, out hasUpvalues); SignalSourceCodeChange(sourceCode); SignalByteCodeChange(); if (hasUpvalues) { return MakeClosure(address, globalTable ?? m_GlobalTable); } return MakeClosure(address); } public void Dump(DynValue function, Stream stream) { this.CheckScriptOwnership(function); if (function.Type != DataType.Function) { throw new ArgumentException("function arg is not a function!"); } if (!stream.CanWrite) { throw new ArgumentException("stream is readonly!"); } Closure.UpvaluesType upvaluesType = function.Function.GetUpvaluesType(); if (upvaluesType == Closure.UpvaluesType.Closure) { throw new ArgumentException("function arg has upvalues other than _ENV"); } UndisposableStream stream2 = new UndisposableStream(stream); m_MainProcessor.Dump(stream2, function.Function.EntryPointByteCodeLocation, upvaluesType == Closure.UpvaluesType.Environment); } public DynValue LoadFile(string filename, Table globalContext = null, string friendlyFilename = null) { this.CheckScriptOwnership(globalContext); filename = Options.ScriptLoader.ResolveFileName(filename, globalContext ?? m_GlobalTable); object obj = Options.ScriptLoader.LoadFile(filename, globalContext ?? m_GlobalTable); if (obj is string) { return LoadString((string)obj, globalContext, friendlyFilename ?? filename); } if (obj is byte[]) { using (MemoryStream stream = new MemoryStream((byte[])obj)) { return LoadStream(stream, globalContext, friendlyFilename ?? filename); } } if (obj is Stream) { try { return LoadStream((Stream)obj, globalContext, friendlyFilename ?? filename); } finally { ((Stream)obj).Dispose(); } } if (obj == null) { throw new InvalidCastException("Unexpected null from IScriptLoader.LoadFile"); } throw new InvalidCastException($"Unsupported return type from IScriptLoader.LoadFile : {obj.GetType()}"); } public DynValue DoString(string code, Table globalContext = null, string codeFriendlyName = null) { DynValue function = LoadString(code, globalContext, codeFriendlyName); return Call(function); } public DynValue DoStream(Stream stream, Table globalContext = null, string codeFriendlyName = null) { DynValue function = LoadStream(stream, globalContext, codeFriendlyName); return Call(function); } public DynValue DoFile(string filename, Table globalContext = null, string codeFriendlyName = null) { DynValue function = LoadFile(filename, globalContext, codeFriendlyName); return Call(function); } public static DynValue RunFile(string filename) { return new Script().DoFile(filename); } public static DynValue RunString(string code) { return new Script().DoString(code); } public DynValue MakeClosure(int address, Table envTable = null) { this.CheckScriptOwnership(envTable); Closure function; if (envTable == null) { Instruction instruction = m_MainProcessor.FindMeta(ref address); function = ((instruction == null || instruction.NumVal2 != 0) ? new Closure(this, address, new SymbolRef[0], new DynValue[0]) : new Closure(this, address, new SymbolRef[1] { SymbolRef.Upvalue("_ENV", 0) }, new DynValue[1] { instruction.Value })); } else { SymbolRef[] symbols = new SymbolRef[1] { new SymbolRef { i_Env = null, i_Index = 0, i_Name = "_ENV", i_Type = SymbolRefType.DefaultEnv } }; DynValue[] resolvedLocals = new DynValue[1] { DynValue.NewTable(envTable) }; function = new Closure(this, address, symbols, resolvedLocals); } return DynValue.NewClosure(function); } public DynValue Call(DynValue function) { return Call(function, new DynValue[0]); } public DynValue Call(DynValue function, params DynValue[] args) { this.CheckScriptOwnership(function); this.CheckScriptOwnership(args); if (function.Type != DataType.Function && function.Type != DataType.ClrFunction) { DynValue metamethod = m_MainProcessor.GetMetamethod(function, "__call"); if (metamethod == null) { throw new ArgumentException("function is not a function and has no __call metamethod."); } DynValue[] array = new DynValue[args.Length + 1]; array[0] = function; for (int i = 0; i < args.Length; i++) { array[i + 1] = args[i]; } function = metamethod; args = array; } else if (function.Type == DataType.ClrFunction) { return function.Callback.ClrCallback(CreateDynamicExecutionContext(function.Callback), new CallbackArguments(args, isMethodCall: false)); } return m_MainProcessor.Call(function, args); } public DynValue Call(DynValue function, params object[] args) { DynValue[] array = new DynValue[args.Length]; for (int i = 0; i < array.Length; i++) { array[i] = DynValue.FromObject(this, args[i]); } return Call(function, array); } public DynValue Call(object function) { return Call(DynValue.FromObject(this, function)); } public DynValue Call(object function, params object[] args) { return Call(DynValue.FromObject(this, function), args); } public DynValue CreateCoroutine(DynValue function) { this.CheckScriptOwnership(function); if (function.Type == DataType.Function) { return m_MainProcessor.Coroutine_Create(function.Function); } if (function.Type == DataType.ClrFunction) { return DynValue.NewCoroutine(new Coroutine(function.Callback)); } throw new ArgumentException("function is not of DataType.Function or DataType.ClrFunction"); } public DynValue CreateCoroutine(object function) { return CreateCoroutine(DynValue.FromObject(this, function)); } public void AttachDebugger(IDebugger debugger) { DebuggerEnabled = true; m_Debugger = debugger; m_MainProcessor.AttachDebugger(debugger); foreach (SourceCode source in m_Sources) { SignalSourceCodeChange(source); } SignalByteCodeChange(); } public SourceCode GetSourceCode(int sourceCodeID) { return m_Sources[sourceCodeID]; } public DynValue RequireModule(string modname, Table globalContext = null) { this.CheckScriptOwnership(globalContext); Table globalContext2 = globalContext ?? m_GlobalTable; string text = Options.ScriptLoader.ResolveModuleName(modname, globalContext2); if (text == null) { throw new ScriptRuntimeException("module '{0}' not found", modname); } return LoadFile(text, globalContext, text); } public Table GetTypeMetatable(DataType type) { if (type >= DataType.Nil && (int)type < m_TypeMetatables.Length) { return m_TypeMetatables[(int)type]; } return null; } public void SetTypeMetatable(DataType type, Table metatable) { this.CheckScriptOwnership(metatable); int num = (int)type; if (num >= 0 && num < m_TypeMetatables.Length) { m_TypeMetatables[num] = metatable; return; } throw new ArgumentException("Specified type not supported : " + type); } public static void WarmUp() { new Script(CoreModules.Basic).LoadString("return 1;"); } public DynamicExpression CreateDynamicExpression(string code) { DynamicExprExpression expr = Loader_Fast.LoadDynamicExpr(this, new SourceCode("__dynamic", code, -1, this)); return new DynamicExpression(this, code, expr); } public DynamicExpression CreateConstantDynamicExpression(string code, DynValue constant) { this.CheckScriptOwnership(constant); return new DynamicExpression(this, code, constant); } public ScriptExecutionContext CreateDynamicExecutionContext(CallbackFunction func = null) { return new ScriptExecutionContext(m_MainProcessor, func, null, isDynamic: true); } public static string GetBanner(string subproduct = null) { subproduct = ((subproduct != null) ? (subproduct + " ") : ""); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(string.Format("MoonSharp {0}{1} [{2}]", subproduct, "2.0.0.0", GlobalOptions.Platform.GetPlatformName())); stringBuilder.AppendLine("Copyright (C) 2014-2016 Marco Mastropaolo"); stringBuilder.AppendLine("http://www.moonsharp.org"); return stringBuilder.ToString(); } } public class Table : RefIdObject, IScriptPrivateResource { public readonly LinkedList m_Values; public readonly LinkedListIndex m_ValueMap; public readonly LinkedListIndex m_StringMap; public readonly LinkedListIndex m_ArrayMap; public readonly Script m_Owner; public int m_InitArray; public int m_CachedLength = -1; public bool m_ContainsNilEntries; public Table m_MetaTable; public Script OwnerScript => m_Owner; public object this[params object[] keys] { get { return Get(keys).ToObject(); } set { Set(keys, DynValue.FromObject(OwnerScript, value)); } } public object this[object key] { get { return Get(key).ToObject(); } set { Set(key, DynValue.FromObject(OwnerScript, value)); } } public int Length { get { if (m_CachedLength < 0) { m_CachedLength = 0; for (int i = 1; m_ArrayMap.ContainsKey(i) && !m_ArrayMap.Find(i).Value.Value.IsNil(); i++) { m_CachedLength = i; } } return m_CachedLength; } } public Table MetaTable { get { return m_MetaTable; } set { this.CheckScriptOwnership(m_MetaTable); m_MetaTable = value; } } public IEnumerable Pairs => m_Values.Select((TablePair n) => new TablePair(n.Key, n.Value)); public IEnumerable Keys => m_Values.Select((TablePair n) => n.Key); public IEnumerable Values => m_Values.Select((TablePair n) => n.Value); public Table(Script owner) { m_Values = new LinkedList(); m_StringMap = new LinkedListIndex(m_Values); m_ArrayMap = new LinkedListIndex(m_Values); m_ValueMap = new LinkedListIndex(m_Values); m_Owner = owner; } public Table(Script owner, params DynValue[] arrayValues) : this(owner) { for (int i = 0; i < arrayValues.Length; i++) { Set(DynValue.NewNumber(i + 1), arrayValues[i]); } } public void Clear() { m_Values.Clear(); m_StringMap.Clear(); m_ArrayMap.Clear(); m_ValueMap.Clear(); m_CachedLength = -1; } public int GetIntegralKey(double d) { int num = (int)d; if (d >= 1.0 && d == (double)num) { return num; } return -1; } public Table ResolveMultipleKeys(object[] keys, out object key) { Table table = this; key = ((keys.Length != 0) ? keys[0] : null); for (int i = 1; i < keys.Length; i++) { DynValue obj = table.RawGet(key) ?? throw new ScriptRuntimeException("Key '{0}' did not point to anything"); if (obj.Type != DataType.Table) { throw new ScriptRuntimeException("Key '{0}' did not point to a table"); } table = obj.Table; key = keys[i]; } return table; } public void Append(DynValue value) { this.CheckScriptOwnership(value); PerformTableSet(m_ArrayMap, Length + 1, DynValue.NewNumber(Length + 1), value, isNumber: true, Length + 1); } public void PerformTableSet(LinkedListIndex listIndex, T key, DynValue keyDynValue, DynValue value, bool isNumber, int appendKey) { TablePair tablePair = listIndex.Set(key, new TablePair(keyDynValue, value)); if (m_ContainsNilEntries && value.IsNotNil() && (tablePair.Value == null || tablePair.Value.IsNil())) { CollectDeadKeys(); } else if (value.IsNil()) { m_ContainsNilEntries = true; if (isNumber) { m_CachedLength = -1; } } else { if (!isNumber || (tablePair.Value != null && !tablePair.Value.IsNilOrNan())) { return; } if (appendKey >= 0) { LinkedListNode linkedListNode = m_ArrayMap.Find(appendKey + 1); if (linkedListNode == null || linkedListNode.Value.Value == null || linkedListNode.Value.Value.IsNil()) { m_CachedLength++; } else { m_CachedLength = -1; } } else { m_CachedLength = -1; } } } public void Set(string key, DynValue value) { if (key == null) { throw ScriptRuntimeException.TableIndexIsNil(); } this.CheckScriptOwnership(value); PerformTableSet(m_StringMap, key, DynValue.NewString(key), value, isNumber: false, -1); } public void Set(int key, DynValue value) { this.CheckScriptOwnership(value); PerformTableSet(m_ArrayMap, key, DynValue.NewNumber(key), value, isNumber: true, -1); } public void Set(DynValue key, DynValue value) { if (key.IsNilOrNan()) { if (key.IsNil()) { throw ScriptRuntimeException.TableIndexIsNil(); } throw ScriptRuntimeException.TableIndexIsNaN(); } if (key.Type == DataType.String) { Set(key.String, value); return; } if (key.Type == DataType.Number) { int integralKey = GetIntegralKey(key.Number); if (integralKey > 0) { Set(integralKey, value); return; } } this.CheckScriptOwnership(key); this.CheckScriptOwnership(value); PerformTableSet(m_ValueMap, key, key, value, isNumber: false, -1); } public void Set(object key, DynValue value) { if (key == null) { throw ScriptRuntimeException.TableIndexIsNil(); } if (key is string) { Set((string)key, value); } else if (key is int) { Set((int)key, value); } else { Set(DynValue.FromObject(OwnerScript, key), value); } } public void Set(object[] keys, DynValue value) { if (keys == null || keys.Length == 0) { throw ScriptRuntimeException.TableIndexIsNil(); } ResolveMultipleKeys(keys, out var key).Set(key, value); } public DynValue Get(string key) { return RawGet(key) ?? DynValue.Nil; } public DynValue Get(int key) { return RawGet(key) ?? DynValue.Nil; } public DynValue Get(DynValue key) { return RawGet(key) ?? DynValue.Nil; } public DynValue Get(object key) { return RawGet(key) ?? DynValue.Nil; } public DynValue Get(params object[] keys) { return RawGet(keys) ?? DynValue.Nil; } public static DynValue RawGetValue(LinkedListNode linkedListNode) { return linkedListNode?.Value.Value; } public DynValue RawGet(string key) { return RawGetValue(m_StringMap.Find(key)); } public DynValue RawGet(int key) { return RawGetValue(m_ArrayMap.Find(key)); } public DynValue RawGet(DynValue key) { if (key.Type == DataType.String) { return RawGet(key.String); } if (key.Type == DataType.Number) { int integralKey = GetIntegralKey(key.Number); if (integralKey > 0) { return RawGet(integralKey); } } return RawGetValue(m_ValueMap.Find(key)); } public DynValue RawGet(object key) { if (key == null) { return null; } if (key is string) { return RawGet((string)key); } if (key is int) { return RawGet((int)key); } return RawGet(DynValue.FromObject(OwnerScript, key)); } public DynValue RawGet(params object[] keys) { if (keys == null || keys.Length == 0) { return null; } object key; return ResolveMultipleKeys(keys, out key).RawGet(key); } public bool PerformTableRemove(LinkedListIndex listIndex, T key, bool isNumber) { bool num = listIndex.Remove(key); if (num && isNumber) { m_CachedLength = -1; } return num; } public bool Remove(string key) { return PerformTableRemove(m_StringMap, key, isNumber: false); } public bool Remove(int key) { return PerformTableRemove(m_ArrayMap, key, isNumber: true); } public bool Remove(DynValue key) { if (key.Type == DataType.String) { return Remove(key.String); } if (key.Type == DataType.Number) { int integralKey = GetIntegralKey(key.Number); if (integralKey > 0) { return Remove(integralKey); } } return PerformTableRemove(m_ValueMap, key, isNumber: false); } public bool Remove(object key) { if (key is string) { return Remove((string)key); } if (key is int) { return Remove((int)key); } return Remove(DynValue.FromObject(OwnerScript, key)); } public bool Remove(params object[] keys) { if (keys == null || keys.Length == 0) { return false; } object key; return ResolveMultipleKeys(keys, out key).Remove(key); } public void CollectDeadKeys() { for (LinkedListNode linkedListNode = m_Values.First; linkedListNode != null; linkedListNode = linkedListNode.Next) { if (linkedListNode.Value.Value.IsNil()) { Remove(linkedListNode.Value.Key); } } m_ContainsNilEntries = false; m_CachedLength = -1; } public TablePair? NextKey(DynValue v) { if (v.IsNil()) { LinkedListNode first = m_Values.First; if (first == null) { return TablePair.Nil; } if (first.Value.Value.IsNil()) { return NextKey(first.Value.Key); } return first.Value; } if (v.Type == DataType.String) { return GetNextOf(m_StringMap.Find(v.String)); } if (v.Type == DataType.Number) { int integralKey = GetIntegralKey(v.Number); if (integralKey > 0) { return GetNextOf(m_ArrayMap.Find(integralKey)); } } return GetNextOf(m_ValueMap.Find(v)); } public TablePair? GetNextOf(LinkedListNode linkedListNode) { do { if (linkedListNode == null) { return null; } if (linkedListNode.Next == null) { return TablePair.Nil; } linkedListNode = linkedListNode.Next; } while (linkedListNode.Value.Value.IsNil()); return linkedListNode.Value; } public void InitNextArrayKeys(DynValue val, bool lastpos) { if (val.Type == DataType.Tuple && lastpos) { DynValue[] tuple = val.Tuple; foreach (DynValue val2 in tuple) { InitNextArrayKeys(val2, lastpos: true); } } else { Set(++m_InitArray, val.ToScalar()); } } } [Flags] public enum CoreModules { None = 0, Basic = 0x40, GlobalConsts = 1, TableIterators = 2, Metatables = 4, String = 8, LoadMethods = 0x10, Table = 0x20, ErrorHandling = 0x80, Math = 0x100, Coroutine = 0x200, Bit32 = 0x400, OS_Time = 0x800, OS_System = 0x1000, IO = 0x2000, Debug = 0x4000, Dynamic = 0x8000, Json = 0x10000, Preset_HardSandbox = 0x56B, Preset_SoftSandbox = 0x18FEF, Preset_Default = 0x1BFFF, Preset_Complete = 0x1FFFF } public static class CoreModules_ExtensionMethods { public static bool Has(this CoreModules val, CoreModules flag) { return (val & flag) == flag; } } public static class ModuleRegister { public static Table RegisterCoreModules(this Table table, CoreModules modules) { modules = Script.GlobalOptions.Platform.FilterSupportedCoreModules(modules); if (modules.Has(CoreModules.GlobalConsts)) { table.RegisterConstants(); } if (modules.Has(CoreModules.TableIterators)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.Basic)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.Metatables)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.String)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.LoadMethods)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.Table)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.Table)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.ErrorHandling)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.Math)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.Coroutine)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.Bit32)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.Dynamic)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.OS_System)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.OS_Time)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.IO)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.Debug)) { table.RegisterModuleType(); } if (modules.Has(CoreModules.Json)) { table.RegisterModuleType(); } return table; } public static Table RegisterConstants(this Table table) { DynValue dynValue = DynValue.NewTable(table.OwnerScript); Table table2 = dynValue.Table; table.Set("_G", DynValue.NewTable(table)); table.Set("_VERSION", DynValue.NewString(string.Format("MoonSharp {0}", "2.0.0.0"))); table.Set("_MOONSHARP", dynValue); table2.Set("version", DynValue.NewString("2.0.0.0")); table2.Set("luacompat", DynValue.NewString("5.2")); table2.Set("platform", DynValue.NewString(Script.GlobalOptions.Platform.GetPlatformName())); table2.Set("is_aot", DynValue.NewBoolean(Script.GlobalOptions.Platform.IsRunningOnAOT())); table2.Set("is_unity", DynValue.NewBoolean(PlatformAutoDetector.IsRunningOnUnity)); table2.Set("is_mono", DynValue.NewBoolean(PlatformAutoDetector.IsRunningOnMono)); table2.Set("is_clr4", DynValue.NewBoolean(PlatformAutoDetector.IsRunningOnClr4)); table2.Set("is_pcl", DynValue.NewBoolean(PlatformAutoDetector.IsPortableFramework)); table2.Set("banner", DynValue.NewString(Script.GetBanner())); return table; } public static Table RegisterModuleType(this Table gtable, Type t) { Table table = CreateModuleNamespace(gtable, t); foreach (MethodInfo item in from __mi in Framework.Do.GetMethods(t) where __mi.IsStatic select __mi) { if (item.GetCustomAttributes(typeof(MoonSharpModuleMethodAttribute), inherit: false).ToArray().Length != 0) { MoonSharpModuleMethodAttribute moonSharpModuleMethodAttribute = (MoonSharpModuleMethodAttribute)item.GetCustomAttributes(typeof(MoonSharpModuleMethodAttribute), inherit: false).First(); if (!CallbackFunction.CheckCallbackSignature(item, requirePublicVisibility: true)) { throw new ArgumentException($"Method {item.Name} does not have the right signature."); } Func callBack = (Func)Delegate.CreateDelegate(typeof(Func), item); string text = ((!string.IsNullOrEmpty(moonSharpModuleMethodAttribute.Name)) ? moonSharpModuleMethodAttribute.Name : item.Name); table.Set(text, DynValue.NewCallback(callBack, text)); } else if (item.Name == "MoonSharpInit") { object[] parameters = new object[2] { gtable, table }; item.Invoke(null, parameters); } } foreach (FieldInfo item2 in from _mi in Framework.Do.GetFields(t) where _mi.IsStatic && _mi.GetCustomAttributes(typeof(MoonSharpModuleMethodAttribute), inherit: false).ToArray().Length != 0 select _mi) { MoonSharpModuleMethodAttribute moonSharpModuleMethodAttribute2 = (MoonSharpModuleMethodAttribute)item2.GetCustomAttributes(typeof(MoonSharpModuleMethodAttribute), inherit: false).First(); string name = ((!string.IsNullOrEmpty(moonSharpModuleMethodAttribute2.Name)) ? moonSharpModuleMethodAttribute2.Name : item2.Name); RegisterScriptField(item2, null, table, t, name); } foreach (FieldInfo item3 in from _mi in Framework.Do.GetFields(t) where _mi.IsStatic && _mi.GetCustomAttributes(typeof(MoonSharpModuleConstantAttribute), inherit: false).ToArray().Length != 0 select _mi) { MoonSharpModuleConstantAttribute moonSharpModuleConstantAttribute = (MoonSharpModuleConstantAttribute)item3.GetCustomAttributes(typeof(MoonSharpModuleConstantAttribute), inherit: false).First(); string name2 = ((!string.IsNullOrEmpty(moonSharpModuleConstantAttribute.Name)) ? moonSharpModuleConstantAttribute.Name : item3.Name); RegisterScriptFieldAsConst(item3, null, table, t, name2); } return gtable; } public static void RegisterScriptFieldAsConst(FieldInfo fi, object o, Table table, Type t, string name) { if (fi.FieldType == typeof(string)) { string str = fi.GetValue(o) as string; table.Set(name, DynValue.NewString(str)); return; } if (fi.FieldType == typeof(double)) { double num = (double)fi.GetValue(o); table.Set(name, DynValue.NewNumber(num)); return; } throw new ArgumentException($"Field {name} does not have the right type - it must be string or double."); } public static void RegisterScriptField(FieldInfo fi, object o, Table table, Type t, string name) { if (fi.FieldType != typeof(string)) { throw new ArgumentException($"Field {name} does not have the right type - it must be string."); } string code = fi.GetValue(o) as string; DynValue value = table.OwnerScript.LoadFunction(code, table, name); table.Set(name, value); } public static Table CreateModuleNamespace(Table gtable, Type t) { MoonSharpModuleAttribute moonSharpModuleAttribute = (MoonSharpModuleAttribute)Framework.Do.GetCustomAttributes(t, typeof(MoonSharpModuleAttribute), inherit: false).First(); if (string.IsNullOrEmpty(moonSharpModuleAttribute.Namespace)) { return gtable; } Table table = null; DynValue dynValue = gtable.Get(moonSharpModuleAttribute.Namespace); if (dynValue.Type == DataType.Table) { table = dynValue.Table; } else { table = new Table(gtable.OwnerScript); gtable.Set(moonSharpModuleAttribute.Namespace, DynValue.NewTable(table)); } DynValue dynValue2 = gtable.RawGet("package"); if (dynValue2 == null || dynValue2.Type != DataType.Table) { gtable.Set("package", dynValue2 = DynValue.NewTable(gtable.OwnerScript)); } DynValue dynValue3 = dynValue2.Table.RawGet("loaded"); if (dynValue3 == null || dynValue3.Type != DataType.Table) { dynValue2.Table.Set("loaded", dynValue3 = DynValue.NewTable(gtable.OwnerScript)); } dynValue3.Table.Set(moonSharpModuleAttribute.Namespace, DynValue.NewTable(table)); return table; } public static Table RegisterModuleType(this Table table) { return table.RegisterModuleType(typeof(T)); } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field, Inherited = false, AllowMultiple = false)] public sealed class MoonSharpModuleMethodAttribute : Attribute { public string Name { get; set; } } [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] public sealed class MoonSharpModuleAttribute : Attribute { public string Namespace { get; set; } } public class ScriptGlobalOptions { public CustomConvertersCollection CustomConverters { get; set; } public IPlatformAccessor Platform { get; set; } public bool RethrowExceptionNested { get; set; } public ScriptGlobalOptions() { Platform = PlatformAutoDetector.GetDefaultPlatform(); CustomConverters = new CustomConvertersCollection(); } } public class ScriptOptions { public IScriptLoader ScriptLoader { get; set; } public Action DebugPrint { get; set; } public Func DebugInput { get; set; } public bool UseLuaErrorLocations { get; set; } public ColonOperatorBehaviour ColonOperatorClrCallbackBehaviour { get; set; } public Stream Stdin { get; set; } public Stream Stdout { get; set; } public Stream Stderr { get; set; } public int TailCallOptimizationThreshold { get; set; } public bool CheckThreadAccess { get; set; } public ScriptOptions() { } public ScriptOptions(ScriptOptions defaults) { DebugInput = defaults.DebugInput; DebugPrint = defaults.DebugPrint; UseLuaErrorLocations = defaults.UseLuaErrorLocations; Stdin = defaults.Stdin; Stdout = defaults.Stdout; Stderr = defaults.Stderr; TailCallOptimizationThreshold = defaults.TailCallOptimizationThreshold; ScriptLoader = defaults.ScriptLoader; CheckThreadAccess = defaults.CheckThreadAccess; } } } namespace MoonSharp.Interpreter.Tree { public interface IVariable { void CompileAssignment(ByteCode bc, int stackofs, int tupleidx); } public static class LexerUtils { public static double ParseNumber(Token T) { string text = T.Text; if (!double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { throw new SyntaxErrorException(T, "malformed number near '{0}'", text); } return result; } public static double ParseHexInteger(Token T) { string text = T.Text; if (text.Length < 2 || (text[0] != '0' && char.ToUpper(text[1]) != 'X')) { throw new InternalErrorException("hex numbers must start with '0x' near '{0}'.", text); } if (!ulong.TryParse(text.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result)) { throw new SyntaxErrorException(T, "malformed number near '{0}'", text); } return result; } public static string ReadHexProgressive(string s, ref double d, out int digits) { digits = 0; for (int i = 0; i < s.Length; i++) { char c = s[i]; if (CharIsHexDigit(c)) { int num = HexDigit2Value(c); d *= 16.0; d += num; digits++; continue; } return s.Substring(i); } return string.Empty; } public static double ParseHexFloat(Token T) { string text = T.Text; try { if (text.Length < 2 || (text[0] != '0' && char.ToUpper(text[1]) != 'X')) { throw new InternalErrorException("hex float must start with '0x' near '{0}'", text); } text = text.Substring(2); double d = 0.0; int digits = 0; text = ReadHexProgressive(text, ref d, out var _); if (text.Length > 0 && text[0] == '.') { text = text.Substring(1); text = ReadHexProgressive(text, ref d, out digits); } digits *= -4; if (text.Length > 0 && char.ToUpper(text[0]) == 'P') { if (text.Length == 1) { throw new SyntaxErrorException(T, "invalid hex float format near '{0}'", text); } text = text.Substring((text[1] != '+') ? 1 : 2); int num = int.Parse(text, CultureInfo.InvariantCulture); digits += num; } return d * Math.Pow(2.0, digits); } catch (FormatException) { throw new SyntaxErrorException(T, "malformed number near '{0}'", text); } } public static int HexDigit2Value(char c) { if (c >= '0' && c <= '9') { return c - 48; } if (c >= 'A' && c <= 'F') { return 10 + (c - 65); } if (c >= 'a' && c <= 'f') { return 10 + (c - 97); } throw new InternalErrorException("invalid hex digit near '{0}'", c); } public static bool CharIsDigit(char c) { if (c >= '0') { return c <= '9'; } return false; } public static bool CharIsHexDigit(char c) { if (!CharIsDigit(c) && c != 'a' && c != 'b' && c != 'c' && c != 'd' && c != 'e' && c != 'f' && c != 'A' && c != 'B' && c != 'C' && c != 'D' && c != 'E') { return c == 'F'; } return true; } public static string AdjustLuaLongString(string str) { if (str.StartsWith("\r\n")) { str = str.Substring(2); } else if (str.StartsWith("\n")) { str = str.Substring(1); } return str; } public static string UnescapeLuaString(Token token, string str) { if (!Framework.Do.StringContainsChar(str, '\\')) { return str; } StringBuilder stringBuilder = new StringBuilder(); bool flag = false; bool flag2 = false; int num = 0; string text = ""; string text2 = ""; bool flag3 = false; for (int i = 0; i < str.Length; i++) { char c = str[i]; do { int num2; if (flag) { if (text2.Length == 0 && !flag2 && num == 0) { switch (c) { case 'a': stringBuilder.Append('\a'); flag = false; flag3 = false; break; case '\n': stringBuilder.Append('\n'); flag = false; break; case 'b': stringBuilder.Append('\b'); flag = false; break; case 'f': stringBuilder.Append('\f'); flag = false; break; case 'n': stringBuilder.Append('\n'); flag = false; break; case 'r': stringBuilder.Append('\r'); flag = false; break; case 't': stringBuilder.Append('\t'); flag = false; break; case 'v': stringBuilder.Append('\v'); flag = false; break; case '\\': stringBuilder.Append('\\'); flag = false; flag3 = false; break; case '"': stringBuilder.Append('"'); flag = false; flag3 = false; break; case '\'': stringBuilder.Append('\''); flag = false; flag3 = false; break; case '[': stringBuilder.Append('['); flag = false; flag3 = false; break; case ']': stringBuilder.Append(']'); flag = false; flag3 = false; break; case 'x': flag2 = true; break; case 'u': num = 1; break; case 'z': flag3 = true; flag = false; break; default: if (CharIsDigit(c)) { text2 += c; break; } throw new SyntaxErrorException(token, "invalid escape sequence near '\\{0}'", c); case '\r': break; } break; } switch (num) { case 1: if (c != '{') { throw new SyntaxErrorException(token, "'{' expected near '\\u'"); } num = 2; break; case 2: if (c == '}') { int i3 = int.Parse(text2, NumberStyles.HexNumber, CultureInfo.InvariantCulture); stringBuilder.Append(ConvertUtf32ToChar(i3)); num = 0; text2 = string.Empty; flag = false; } else { if (text2.Length >= 8) { throw new SyntaxErrorException(token, "'}' missing, or unicode code point too large after '\\u'"); } text2 += c; } break; default: if (flag2) { if (CharIsHexDigit(c)) { text2 += c; if (text2.Length == 2) { int i2 = int.Parse(text2, NumberStyles.HexNumber, CultureInfo.InvariantCulture); stringBuilder.Append(ConvertUtf32ToChar(i2)); flag3 = false; flag = false; } break; } throw new SyntaxErrorException(token, "hexadecimal digit expected near '\\{0}{1}{2}'", text, text2, c); } if (text2.Length <= 0) { break; } if (CharIsDigit(c)) { text2 += c; } if (text2.Length != 3 && CharIsDigit(c)) { break; } num2 = int.Parse(text2, CultureInfo.InvariantCulture); if (num2 > 255) { throw new SyntaxErrorException(token, "decimal escape too large near '\\{0}'", text2); } goto IL_0361; } } else if (c == '\\') { flag = true; flag2 = false; text2 = ""; } else if (!flag3 || !char.IsWhiteSpace(c)) { stringBuilder.Append(c); flag3 = false; } break; IL_0361: stringBuilder.Append(ConvertUtf32ToChar(num2)); flag3 = false; flag = false; } while (!CharIsDigit(c)); } if (flag && !flag2 && text2.Length > 0) { int i4 = int.Parse(text2, CultureInfo.InvariantCulture); stringBuilder.Append(ConvertUtf32ToChar(i4)); flag = false; } if (flag) { throw new SyntaxErrorException(token, "unfinished string near '\"{0}\"'", stringBuilder.ToString()); } return stringBuilder.ToString(); } public static string ConvertUtf32ToChar(int i) { return char.ConvertFromUtf32(i); } } public abstract class Expression : NodeBase { public Expression(ScriptLoadingContext lcontext) : base(lcontext) { } public virtual string GetFriendlyDebugName() { return null; } public abstract DynValue Eval(ScriptExecutionContext context); public virtual SymbolRef FindDynamic(ScriptExecutionContext context) { return null; } public static List ExprListAfterFirstExpr(ScriptLoadingContext lcontext, Expression expr1) { List list = new List(); list.Add(expr1); while (lcontext.Lexer.Current.Type == TokenType.Comma) { lcontext.Lexer.Next(); list.Add(Expr(lcontext)); } return list; } public static List ExprList(ScriptLoadingContext lcontext) { List list = new List(); while (true) { list.Add(Expr(lcontext)); if (lcontext.Lexer.Current.Type != TokenType.Comma) { break; } lcontext.Lexer.Next(); } return list; } public static Expression Expr(ScriptLoadingContext lcontext) { return SubExpr(lcontext, isPrimary: true); } public static Expression SubExpr(ScriptLoadingContext lcontext, bool isPrimary) { Expression expression = null; Token current = lcontext.Lexer.Current; if (current.IsUnaryOperator()) { lcontext.Lexer.Next(); expression = SubExpr(lcontext, isPrimary: false); Token unaryOpToken = current; current = lcontext.Lexer.Current; if (isPrimary && current.Type == TokenType.Op_Pwr) { List list = new List(); list.Add(expression); while (isPrimary && current.Type == TokenType.Op_Pwr) { lcontext.Lexer.Next(); list.Add(SubExpr(lcontext, isPrimary: false)); current = lcontext.Lexer.Current; } expression = list[list.Count - 1]; for (int num = list.Count - 2; num >= 0; num--) { expression = BinaryOperatorExpression.CreatePowerExpression(list[num], expression, lcontext); } } expression = new UnaryOperatorExpression(lcontext, expression, unaryOpToken); } else { expression = SimpleExp(lcontext); } current = lcontext.Lexer.Current; if (isPrimary && current.IsBinaryOperator()) { object chain = BinaryOperatorExpression.BeginOperatorChain(); BinaryOperatorExpression.AddExpressionToChain(chain, expression); while (current.IsBinaryOperator()) { BinaryOperatorExpression.AddOperatorToChain(chain, current); lcontext.Lexer.Next(); Expression exp = SubExpr(lcontext, isPrimary: false); BinaryOperatorExpression.AddExpressionToChain(chain, exp); current = lcontext.Lexer.Current; } expression = BinaryOperatorExpression.CommitOperatorChain(chain, lcontext); } return expression; } public static Expression SimpleExp(ScriptLoadingContext lcontext) { Token current = lcontext.Lexer.Current; switch (current.Type) { case TokenType.False: case TokenType.Nil: case TokenType.True: case TokenType.String: case TokenType.String_Long: case TokenType.Number: case TokenType.Number_HexFloat: case TokenType.Number_Hex: return new LiteralExpression(lcontext, current); case TokenType.VarArgs: return new SymbolRefExpression(current, lcontext); case TokenType.Brk_Open_Curly: case TokenType.Brk_Open_Curly_Shared: return new TableConstructor(lcontext, current.Type == TokenType.Brk_Open_Curly_Shared); case TokenType.Function: lcontext.Lexer.Next(); return new FunctionDefinitionExpression(lcontext, pushSelfParam: false, isLambda: false); case TokenType.Lambda: return new FunctionDefinitionExpression(lcontext, pushSelfParam: false, isLambda: true); default: return PrimaryExp(lcontext); } } public static Expression PrimaryExp(ScriptLoadingContext lcontext) { Expression expression = PrefixExp(lcontext); while (true) { Token current = lcontext.Lexer.Current; Token thisCallName = null; switch (current.Type) { case TokenType.Dot: { lcontext.Lexer.Next(); Token token = NodeBase.CheckTokenType(lcontext, TokenType.Name); expression = new MoonSharp.Interpreter.Tree.Expressions.IndexExpression(expression, token.Text, lcontext); break; } case TokenType.Brk_Open_Square: { Token current2 = lcontext.Lexer.Current; lcontext.Lexer.Next(); Expression expression2 = Expr(lcontext); if (lcontext.Lexer.Current.Type == TokenType.Comma) { expression2 = new ExprListExpression(ExprListAfterFirstExpr(lcontext, expression2), lcontext); } NodeBase.CheckMatch(lcontext, current2, TokenType.Brk_Close_Square, "]"); expression = new MoonSharp.Interpreter.Tree.Expressions.IndexExpression(expression, expression2, lcontext); break; } case TokenType.Colon: lcontext.Lexer.Next(); thisCallName = NodeBase.CheckTokenType(lcontext, TokenType.Name); goto case TokenType.Brk_Open_Curly; case TokenType.Brk_Open_Curly: case TokenType.Brk_Open_Round: case TokenType.String: case TokenType.String_Long: case TokenType.Brk_Open_Curly_Shared: expression = new FunctionCallExpression(lcontext, expression, thisCallName); break; default: return expression; } } } public static Expression PrefixExp(ScriptLoadingContext lcontext) { Token current = lcontext.Lexer.Current; switch (current.Type) { case TokenType.Brk_Open_Round: { lcontext.Lexer.Next(); Expression exp = Expr(lcontext); exp = new AdjustmentExpression(lcontext, exp); NodeBase.CheckMatch(lcontext, current, TokenType.Brk_Close_Round, ")"); return exp; } case TokenType.Name: return new SymbolRefExpression(current, lcontext); default: throw new SyntaxErrorException(current, "unexpected symbol near '{0}'", current.Text) { IsPrematureStreamTermination = (current.Type == TokenType.Eof) }; } } } public class Lexer { public Token m_Current; public string m_Code; public int m_PrevLineTo; public int m_PrevColTo = 1; public int m_Cursor; public int m_Line = 1; public int m_Col; public int m_SourceId; public bool m_AutoSkipComments; public Token Current { get { if (m_Current == null) { Next(); } return m_Current; } } public Lexer(int sourceID, string scriptContent, bool autoSkipComments) { m_Code = scriptContent; m_SourceId = sourceID; if (m_Code.Length > 0 && m_Code[0] == '\ufeff') { m_Code = m_Code.Substring(1); } m_AutoSkipComments = autoSkipComments; } public Token FetchNewToken() { Token token; do { token = ReadToken(); } while ((token.Type == TokenType.Comment || token.Type == TokenType.HashBang) && m_AutoSkipComments); return token; } public void Next() { m_Current = FetchNewToken(); } public Token PeekNext() { int cursor = m_Cursor; Token current = m_Current; int line = m_Line; int col = m_Col; Next(); Token current2 = Current; m_Cursor = cursor; m_Current = current; m_Line = line; m_Col = col; return current2; } public void CursorNext() { if (CursorNotEof()) { if (CursorChar() == '\n') { m_Col = 0; m_Line++; } else { m_Col++; } m_Cursor++; } } public char CursorChar() { if (m_Cursor < m_Code.Length) { return m_Code[m_Cursor]; } return '\0'; } public char CursorCharNext() { CursorNext(); return CursorChar(); } public bool CursorMatches(string pattern) { for (int i = 0; i < pattern.Length; i++) { int num = m_Cursor + i; if (num >= m_Code.Length) { return false; } if (m_Code[num] != pattern[i]) { return false; } } return true; } public bool CursorNotEof() { return m_Cursor < m_Code.Length; } public bool IsWhiteSpace(char c) { return char.IsWhiteSpace(c); } public void SkipWhiteSpace() { while (CursorNotEof() && IsWhiteSpace(CursorChar())) { CursorNext(); } } public Token ReadToken() { SkipWhiteSpace(); int line = m_Line; int col = m_Col; if (!CursorNotEof()) { return CreateToken(TokenType.Eof, line, col, ""); } char c = CursorChar(); switch (c) { case '|': CursorCharNext(); return CreateToken(TokenType.Lambda, line, col, "|"); case ';': CursorCharNext(); return CreateToken(TokenType.SemiColon, line, col, ";"); case '=': return PotentiallyDoubleCharOperator('=', TokenType.Op_Assignment, TokenType.Op_Equal, line, col); case '<': return PotentiallyDoubleCharOperator('=', TokenType.Op_LessThan, TokenType.Op_LessThanEqual, line, col); case '>': return PotentiallyDoubleCharOperator('=', TokenType.Op_GreaterThan, TokenType.Op_GreaterThanEqual, line, col); case '!': case '~': if (CursorCharNext() != '=') { throw new SyntaxErrorException(CreateToken(TokenType.Invalid, line, col), "unexpected symbol near '{0}'", c); } CursorCharNext(); return CreateToken(TokenType.Op_NotEqual, line, col, "~="); case '.': { char c3 = CursorCharNext(); if (c3 == '.') { return PotentiallyDoubleCharOperator('.', TokenType.Op_Concat, TokenType.VarArgs, line, col); } if (LexerUtils.CharIsDigit(c3)) { return ReadNumberToken(line, col, leadingDot: true); } return CreateToken(TokenType.Dot, line, col, "."); } case '+': return CreateSingleCharToken(TokenType.Op_Add, line, col); case '-': if (CursorCharNext() == '-') { return ReadComment(line, col); } return CreateToken(TokenType.Op_MinusOrSub, line, col, "-"); case '*': return CreateSingleCharToken(TokenType.Op_Mul, line, col); case '/': return CreateSingleCharToken(TokenType.Op_Div, line, col); case '%': return CreateSingleCharToken(TokenType.Op_Mod, line, col); case '^': return CreateSingleCharToken(TokenType.Op_Pwr, line, col); case '$': return PotentiallyDoubleCharOperator('{', TokenType.Op_Dollar, TokenType.Brk_Open_Curly_Shared, line, col); case '#': if (m_Cursor == 0 && m_Code.Length > 1 && m_Code[1] == '!') { return ReadHashBang(line, col); } return CreateSingleCharToken(TokenType.Op_Len, line, col); case '[': { char c2 = CursorCharNext(); if (c2 == '=' || c2 == '[') { string text = ReadLongString(line, col, null, "string"); return CreateToken(TokenType.String_Long, line, col, text); } return CreateToken(TokenType.Brk_Open_Square, line, col, "["); } case ']': return CreateSingleCharToken(TokenType.Brk_Close_Square, line, col); case '(': return CreateSingleCharToken(TokenType.Brk_Open_Round, line, col); case ')': return CreateSingleCharToken(TokenType.Brk_Close_Round, line, col); case '{': return CreateSingleCharToken(TokenType.Brk_Open_Curly, line, col); case '}': return CreateSingleCharToken(TokenType.Brk_Close_Curly, line, col); case ',': return CreateSingleCharToken(TokenType.Comma, line, col); case ':': return PotentiallyDoubleCharOperator(':', TokenType.Colon, TokenType.DoubleColon, line, col); case '"': case '\'': return ReadSimpleStringToken(line, col); case '\0': throw new SyntaxErrorException(CreateToken(TokenType.Invalid, line, col), "unexpected symbol near '{0}'", CursorChar()) { IsPrematureStreamTermination = true }; default: if (char.IsLetter(c) || c == '_') { string name = ReadNameToken(); return CreateNameToken(name, line, col); } if (LexerUtils.CharIsDigit(c)) { return ReadNumberToken(line, col, leadingDot: false); } throw new SyntaxErrorException(CreateToken(TokenType.Invalid, line, col), "unexpected symbol near '{0}'", CursorChar()); } } public string ReadLongString(int fromLine, int fromCol, string startpattern, string subtypeforerrors) { StringBuilder stringBuilder = new StringBuilder(1024); string text = "]"; if (startpattern == null) { char c = CursorChar(); while (true) { if (c == '\0' || !CursorNotEof()) { throw new SyntaxErrorException(CreateToken(TokenType.Invalid, fromLine, fromCol), "unfinished long {0} near ''", subtypeforerrors) { IsPrematureStreamTermination = true }; } switch (c) { case '=': goto IL_0056; case '[': break; default: throw new SyntaxErrorException(CreateToken(TokenType.Invalid, fromLine, fromCol), "invalid long {0} delimiter near '{1}'", subtypeforerrors, c) { IsPrematureStreamTermination = true }; } break; IL_0056: text += "="; c = CursorCharNext(); } text += "]"; } else { text = startpattern.Replace('[', ']'); } char c2 = CursorCharNext(); while (true) { if (c2 != '\r') { if (c2 == '\0' || !CursorNotEof()) { throw new SyntaxErrorException(CreateToken(TokenType.Invalid, fromLine, fromCol), "unfinished long {0} near '{1}'", subtypeforerrors, stringBuilder.ToString()) { IsPrematureStreamTermination = true }; } if (c2 == ']' && CursorMatches(text)) { break; } stringBuilder.Append(c2); } c2 = CursorCharNext(); } for (int i = 0; i < text.Length; i++) { CursorCharNext(); } return LexerUtils.AdjustLuaLongString(stringBuilder.ToString()); } public Token ReadNumberToken(int fromLine, int fromCol, bool leadingDot) { StringBuilder stringBuilder = new StringBuilder(32); bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; if (leadingDot) { stringBuilder.Append("0."); } else if (CursorChar() == '0') { stringBuilder.Append(CursorChar()); char c = CursorCharNext(); if (c == 'x' || c == 'X') { flag = true; stringBuilder.Append(CursorChar()); CursorCharNext(); } } char c2 = CursorChar(); while (CursorNotEof()) { if (flag4 && (c2 == '+' || c2 == '-')) { flag4 = false; stringBuilder.Append(c2); } else if (LexerUtils.CharIsDigit(c2)) { stringBuilder.Append(c2); } else if (c2 == '.' && !flag2) { flag2 = true; stringBuilder.Append(c2); } else if (LexerUtils.CharIsHexDigit(c2) && flag && !flag3) { stringBuilder.Append(c2); } else { if (c2 != 'e' && c2 != 'E' && (!flag || (c2 != 'p' && c2 != 'P'))) { break; } stringBuilder.Append(c2); flag3 = true; flag4 = true; flag2 = true; } c2 = CursorCharNext(); } TokenType tokenType = TokenType.Number; if (flag && (flag2 || flag3)) { tokenType = TokenType.Number_HexFloat; } else if (flag) { tokenType = TokenType.Number_Hex; } string text = stringBuilder.ToString(); return CreateToken(tokenType, fromLine, fromCol, text); } public Token CreateSingleCharToken(TokenType tokenType, int fromLine, int fromCol) { char c = CursorChar(); CursorCharNext(); return CreateToken(tokenType, fromLine, fromCol, c.ToString()); } public Token ReadHashBang(int fromLine, int fromCol) { StringBuilder stringBuilder = new StringBuilder(32); char c = CursorChar(); while (CursorNotEof()) { switch (c) { case '\n': CursorCharNext(); return CreateToken(TokenType.HashBang, fromLine, fromCol, stringBuilder.ToString()); default: stringBuilder.Append(c); break; case '\r': break; } c = CursorCharNext(); } return CreateToken(TokenType.HashBang, fromLine, fromCol, stringBuilder.ToString()); } public Token ReadComment(int fromLine, int fromCol) { StringBuilder stringBuilder = new StringBuilder(32); bool flag = false; char c = CursorCharNext(); while (CursorNotEof()) { if (c == '[' && !flag && stringBuilder.Length > 0) { stringBuilder.Append('['); string text = ReadLongString(fromLine, fromCol, stringBuilder.ToString(), "comment"); return CreateToken(TokenType.Comment, fromLine, fromCol, text); } if (c == '\n') { flag = true; CursorCharNext(); return CreateToken(TokenType.Comment, fromLine, fromCol, stringBuilder.ToString()); } if (c != '\r') { if (c != '[' && c != '=') { flag = true; } stringBuilder.Append(c); } c = CursorCharNext(); } return CreateToken(TokenType.Comment, fromLine, fromCol, stringBuilder.ToString()); } public Token ReadSimpleStringToken(int fromLine, int fromCol) { StringBuilder stringBuilder = new StringBuilder(32); char c = CursorChar(); char c2 = CursorCharNext(); while (CursorNotEof()) { while (true) { switch (c2) { case '\\': stringBuilder.Append(c2); c2 = CursorCharNext(); stringBuilder.Append(c2); switch (c2) { case '\r': c2 = CursorCharNext(); if (c2 != '\n') { continue; } stringBuilder.Append(c2); break; case 'z': c2 = CursorCharNext(); if (char.IsWhiteSpace(c2)) { SkipWhiteSpace(); } c2 = CursorChar(); continue; } break; case '\n': case '\r': throw new SyntaxErrorException(CreateToken(TokenType.Invalid, fromLine, fromCol), "unfinished string near '{0}'", stringBuilder.ToString()); default: if (c2 == c) { CursorCharNext(); Token token = CreateToken(TokenType.String, fromLine, fromCol); token.Text = LexerUtils.UnescapeLuaString(token, stringBuilder.ToString()); return token; } stringBuilder.Append(c2); break; } break; } c2 = CursorCharNext(); } throw new SyntaxErrorException(CreateToken(TokenType.Invalid, fromLine, fromCol), "unfinished string near '{0}'", stringBuilder.ToString()) { IsPrematureStreamTermination = true }; } public Token PotentiallyDoubleCharOperator(char expectedSecondChar, TokenType singleCharToken, TokenType doubleCharToken, int fromLine, int fromCol) { string text = CursorChar().ToString(); CursorCharNext(); if (CursorChar() == expectedSecondChar) { CursorCharNext(); return CreateToken(doubleCharToken, fromLine, fromCol, text + expectedSecondChar); } return CreateToken(singleCharToken, fromLine, fromCol, text); } public Token CreateNameToken(string name, int fromLine, int fromCol) { TokenType? reservedTokenType = Token.GetReservedTokenType(name); if (reservedTokenType.HasValue) { return CreateToken(reservedTokenType.Value, fromLine, fromCol, name); } return CreateToken(TokenType.Name, fromLine, fromCol, name); } public Token CreateToken(TokenType tokenType, int fromLine, int fromCol, string text = null) { Token result = new Token(tokenType, m_SourceId, fromLine, fromCol, m_Line, m_Col, m_PrevLineTo, m_PrevColTo) { Text = text }; m_PrevLineTo = m_Line; m_PrevColTo = m_Col; return result; } public string ReadNameToken() { StringBuilder stringBuilder = new StringBuilder(32); char c = CursorChar(); while (CursorNotEof() && (char.IsLetterOrDigit(c) || c == '_')) { stringBuilder.Append(c); c = CursorCharNext(); } return stringBuilder.ToString(); } } public class Token { public readonly int SourceId; public readonly int FromCol; public readonly int ToCol; public readonly int FromLine; public readonly int ToLine; public readonly int PrevCol; public readonly int PrevLine; public readonly TokenType Type; public string Text { get; set; } public Token(TokenType type, int sourceId, int fromLine, int fromCol, int toLine, int toCol, int prevLine, int prevCol) { Type = type; SourceId = sourceId; FromLine = fromLine; FromCol = fromCol; ToCol = toCol; ToLine = toLine; PrevCol = prevCol; PrevLine = prevLine; } public override string ToString() { string arg = (Type.ToString() + " ").Substring(0, 16); string text = $"{FromLine}:{FromCol}-{ToLine}:{ToCol}"; text = (text + " ").Substring(0, 10); return string.Format("{0} - {1} - '{2}'", arg, text, Text ?? ""); } public static TokenType? GetReservedTokenType(string reservedWord) { return reservedWord switch { "and" => TokenType.And, "break" => TokenType.Break, "do" => TokenType.Do, "else" => TokenType.Else, "elseif" => TokenType.ElseIf, "end" => TokenType.End, "false" => TokenType.False, "for" => TokenType.For, "function" => TokenType.Function, "goto" => TokenType.Goto, "if" => TokenType.If, "in" => TokenType.In, "local" => TokenType.Local, "nil" => TokenType.Nil, "not" => TokenType.Not, "or" => TokenType.Or, "repeat" => TokenType.Repeat, "return" => TokenType.Return, "then" => TokenType.Then, "true" => TokenType.True, "until" => TokenType.Until, "while" => TokenType.While, _ => null, }; } public double GetNumberValue() { if (Type == TokenType.Number) { return LexerUtils.ParseNumber(this); } if (Type == TokenType.Number_Hex) { return LexerUtils.ParseHexInteger(this); } if (Type == TokenType.Number_HexFloat) { return LexerUtils.ParseHexFloat(this); } throw new NotSupportedException("GetNumberValue is supported only on numeric tokens"); } public bool IsEndOfBlock() { switch (Type) { case TokenType.Eof: case TokenType.Else: case TokenType.ElseIf: case TokenType.End: case TokenType.Until: return true; default: return false; } } public bool IsUnaryOperator() { if (Type != TokenType.Op_MinusOrSub && Type != TokenType.Not) { return Type == TokenType.Op_Len; } return true; } public bool IsBinaryOperator() { switch (Type) { case TokenType.And: case TokenType.Or: case TokenType.Op_Equal: case TokenType.Op_LessThan: case TokenType.Op_LessThanEqual: case TokenType.Op_GreaterThanEqual: case TokenType.Op_GreaterThan: case TokenType.Op_NotEqual: case TokenType.Op_Concat: case TokenType.Op_Pwr: case TokenType.Op_Mod: case TokenType.Op_Div: case TokenType.Op_Mul: case TokenType.Op_MinusOrSub: case TokenType.Op_Add: return true; default: return false; } } public SourceRef GetSourceRef(bool isStepStop = true) { return new SourceRef(SourceId, FromCol, ToCol, FromLine, ToLine, isStepStop); } public SourceRef GetSourceRef(Token to, bool isStepStop = true) { return new SourceRef(SourceId, FromCol, to.ToCol, FromLine, to.ToLine, isStepStop); } public SourceRef GetSourceRefUpTo(Token to, bool isStepStop = true) { return new SourceRef(SourceId, FromCol, to.PrevCol, FromLine, to.PrevLine, isStepStop); } } public enum TokenType { Eof, HashBang, Name, And, Break, Do, Else, ElseIf, End, False, For, Function, Lambda, Goto, If, In, Local, Nil, Not, Or, Repeat, Return, Then, True, Until, While, Op_Equal, Op_Assignment, Op_LessThan, Op_LessThanEqual, Op_GreaterThanEqual, Op_GreaterThan, Op_NotEqual, Op_Concat, VarArgs, Dot, Colon, DoubleColon, Comma, Brk_Close_Curly, Brk_Open_Curly, Brk_Close_Round, Brk_Open_Round, Brk_Close_Square, Brk_Open_Square, Op_Len, Op_Pwr, Op_Mod, Op_Div, Op_Mul, Op_MinusOrSub, Op_Add, Comment, String, String_Long, Number, Number_HexFloat, Number_Hex, SemiColon, Invalid, Brk_Open_Curly_Shared, Op_Dollar } public class Loop : ILoop { public RuntimeScopeBlock Scope; public List BreakJumps = new List(); public void CompileBreak(ByteCode bc) { bc.Emit_Exit(Scope); BreakJumps.Add(bc.Emit_Jump(OpCode.Jump, -1)); } public bool IsBoundary() { return false; } } public class LoopBoundary : ILoop { public void CompileBreak(ByteCode bc) { throw new InternalErrorException("CompileBreak called on LoopBoundary"); } public bool IsBoundary() { return true; } } public abstract class NodeBase { public Script Script { get; set; } public ScriptLoadingContext LoadingContext { get; set; } public NodeBase(ScriptLoadingContext lcontext) { Script = lcontext.Script; } public abstract void Compile(ByteCode bc); public static Token UnexpectedTokenType(Token t) { throw new SyntaxErrorException(t, "unexpected symbol near '{0}'", t.Text) { IsPrematureStreamTermination = (t.Type == TokenType.Eof) }; } public static Token CheckTokenType(ScriptLoadingContext lcontext, TokenType tokenType) { Token current = lcontext.Lexer.Current; if (current.Type != tokenType) { return UnexpectedTokenType(current); } lcontext.Lexer.Next(); return current; } public static Token CheckTokenType(ScriptLoadingContext lcontext, TokenType tokenType1, TokenType tokenType2) { Token current = lcontext.Lexer.Current; if (current.Type != tokenType1 && current.Type != tokenType2) { return UnexpectedTokenType(current); } lcontext.Lexer.Next(); return current; } public static Token CheckTokenType(ScriptLoadingContext lcontext, TokenType tokenType1, TokenType tokenType2, TokenType tokenType3) { Token current = lcontext.Lexer.Current; if (current.Type != tokenType1 && current.Type != tokenType2 && current.Type != tokenType3) { return UnexpectedTokenType(current); } lcontext.Lexer.Next(); return current; } public static void CheckTokenTypeNotNext(ScriptLoadingContext lcontext, TokenType tokenType) { Token current = lcontext.Lexer.Current; if (current.Type != tokenType) { UnexpectedTokenType(current); } } public static Token CheckMatch(ScriptLoadingContext lcontext, Token originalToken, TokenType expectedTokenType, string expectedTokenText) { Token current = lcontext.Lexer.Current; if (current.Type != expectedTokenType) { throw new SyntaxErrorException(lcontext.Lexer.Current, "'{0}' expected (to close '{1}' at line {2}) near '{3}'", expectedTokenText, originalToken.Text, originalToken.FromLine, current.Text) { IsPrematureStreamTermination = (current.Type == TokenType.Eof) }; } lcontext.Lexer.Next(); return current; } } public abstract class Statement : NodeBase { public Statement(ScriptLoadingContext lcontext) : base(lcontext) { } public static Statement CreateStatement(ScriptLoadingContext lcontext, out bool forceLast) { Token current = lcontext.Lexer.Current; forceLast = false; switch (current.Type) { case TokenType.DoubleColon: return new LabelStatement(lcontext); case TokenType.Goto: return new GotoStatement(lcontext); case TokenType.SemiColon: lcontext.Lexer.Next(); return new EmptyStatement(lcontext); case TokenType.If: return new IfStatement(lcontext); case TokenType.While: return new WhileStatement(lcontext); case TokenType.Do: return new ScopeBlockStatement(lcontext); case TokenType.For: return DispatchForLoopStatement(lcontext); case TokenType.Repeat: return new RepeatStatement(lcontext); case TokenType.Function: return new FunctionDefinitionStatement(lcontext, local: false, null); case TokenType.Local: { Token current3 = lcontext.Lexer.Current; lcontext.Lexer.Next(); if (lcontext.Lexer.Current.Type == TokenType.Function) { return new FunctionDefinitionStatement(lcontext, local: true, current3); } return new AssignmentStatement(lcontext, current3); } case TokenType.Return: forceLast = true; return new ReturnStatement(lcontext); case TokenType.Break: return new BreakStatement(lcontext); default: { Token current2 = lcontext.Lexer.Current; Expression expression = Expression.PrimaryExp(lcontext); if (expression is FunctionCallExpression functionCallExpression) { return new FunctionCallStatement(lcontext, functionCallExpression); } return new AssignmentStatement(lcontext, expression, current2); } } } public static Statement DispatchForLoopStatement(ScriptLoadingContext lcontext) { Token forToken = NodeBase.CheckTokenType(lcontext, TokenType.For); Token token = NodeBase.CheckTokenType(lcontext, TokenType.Name); if (lcontext.Lexer.Current.Type == TokenType.Op_Assignment) { return new ForLoopStatement(lcontext, token, forToken); } return new ForEachLoopStatement(lcontext, token, forToken); } } } namespace MoonSharp.Interpreter.Tree.Statements { public class GotoStatement : Statement { public Instruction m_Jump; public int m_LabelAddress = -1; public SourceRef SourceRef { get; set; } public Token GotoToken { get; set; } public string Label { get; set; } public int DefinedVarsCount { get; set; } public string LastDefinedVarName { get; set; } public GotoStatement(ScriptLoadingContext lcontext) : base(lcontext) { GotoToken = NodeBase.CheckTokenType(lcontext, TokenType.Goto); Token token = NodeBase.CheckTokenType(lcontext, TokenType.Name); SourceRef = GotoToken.GetSourceRef(token); Label = token.Text; lcontext.Scope.RegisterGoto(this); } public override void Compile(ByteCode bc) { m_Jump = bc.Emit_Jump(OpCode.Jump, m_LabelAddress); } public void SetDefinedVars(int definedVarsCount, string lastDefinedVarsName) { DefinedVarsCount = definedVarsCount; LastDefinedVarName = lastDefinedVarsName; } public void SetAddress(int labelAddress) { m_LabelAddress = labelAddress; if (m_Jump != null) { m_Jump.NumVal = labelAddress; } } } public class EmptyStatement : Statement { public EmptyStatement(ScriptLoadingContext lcontext) : base(lcontext) { } public override void Compile(ByteCode bc) { } } public class FunctionCallStatement : Statement { public FunctionCallExpression m_FunctionCallExpression; public FunctionCallStatement(ScriptLoadingContext lcontext, FunctionCallExpression functionCallExpression) : base(lcontext) { m_FunctionCallExpression = functionCallExpression; lcontext.Source.Refs.Add(m_FunctionCallExpression.SourceRef); } public override void Compile(ByteCode bc) { using (bc.EnterSource(m_FunctionCallExpression.SourceRef)) { m_FunctionCallExpression.Compile(bc); RemoveBreakpointStop(bc.Emit_Pop()); } } public void RemoveBreakpointStop(Instruction instruction) { instruction.SourceCodeRef = null; } } public class FunctionDefinitionStatement : Statement { public SymbolRef m_FuncSymbol; public SourceRef m_SourceRef; public bool m_Local; public bool m_IsMethodCallingConvention; public string m_MethodName; public string m_FriendlyName; public List m_TableAccessors; public FunctionDefinitionExpression m_FuncDef; public FunctionDefinitionStatement(ScriptLoadingContext lcontext, bool local, Token localToken) : base(lcontext) { Token token = NodeBase.CheckTokenType(lcontext, TokenType.Function); token = localToken ?? token; m_Local = local; if (m_Local) { Token token2 = NodeBase.CheckTokenType(lcontext, TokenType.Name); m_FuncSymbol = lcontext.Scope.TryDefineLocal(token2.Text); m_FriendlyName = $"{token2.Text} (local)"; m_SourceRef = token.GetSourceRef(token2); } else { Token token3 = NodeBase.CheckTokenType(lcontext, TokenType.Name); string text = token3.Text; m_SourceRef = token.GetSourceRef(token3); m_FuncSymbol = lcontext.Scope.Find(text); m_FriendlyName = text; if (lcontext.Lexer.Current.Type != TokenType.Brk_Open_Round) { m_TableAccessors = new List(); while (lcontext.Lexer.Current.Type != TokenType.Brk_Open_Round) { Token current = lcontext.Lexer.Current; if (current.Type != TokenType.Colon && current.Type != TokenType.Dot) { NodeBase.UnexpectedTokenType(current); } lcontext.Lexer.Next(); Token token4 = NodeBase.CheckTokenType(lcontext, TokenType.Name); m_FriendlyName = m_FriendlyName + current.Text + token4.Text; m_SourceRef = token.GetSourceRef(token4); if (current.Type == TokenType.Colon) { m_MethodName = token4.Text; m_IsMethodCallingConvention = true; break; } m_TableAccessors.Add(token4.Text); } if (m_MethodName == null && m_TableAccessors.Count > 0) { m_MethodName = m_TableAccessors[m_TableAccessors.Count - 1]; m_TableAccessors.RemoveAt(m_TableAccessors.Count - 1); } } } m_FuncDef = new FunctionDefinitionExpression(lcontext, m_IsMethodCallingConvention, isLambda: false); lcontext.Source.Refs.Add(m_SourceRef); } public override void Compile(ByteCode bc) { using (bc.EnterSource(m_SourceRef)) { if (m_Local) { bc.Emit_Literal(DynValue.Nil); bc.Emit_Store(m_FuncSymbol, 0, 0); m_FuncDef.Compile(bc, () => SetFunction(bc, 2), m_FriendlyName); } else if (m_MethodName == null) { m_FuncDef.Compile(bc, () => SetFunction(bc, 1), m_FriendlyName); } else { m_FuncDef.Compile(bc, () => SetMethod(bc), m_FriendlyName); } } } public int SetMethod(ByteCode bc) { int num = 0; num += bc.Emit_Load(m_FuncSymbol); foreach (string tableAccessor in m_TableAccessors) { bc.Emit_Index(DynValue.NewString(tableAccessor), isNameIndex: true); num++; } bc.Emit_IndexSet(0, 0, DynValue.NewString(m_MethodName), isNameIndex: true); return 1 + num; } public int SetFunction(ByteCode bc, int numPop) { int num = bc.Emit_Store(m_FuncSymbol, 0, 0); bc.Emit_Pop(numPop); return num + 1; } } public class AssignmentStatement : Statement { public List m_LValues = new List(); public List m_RValues; public SourceRef m_Ref; public AssignmentStatement(ScriptLoadingContext lcontext, Token startToken) : base(lcontext) { List list = new List(); while (true) { Token token = NodeBase.CheckTokenType(lcontext, TokenType.Name); list.Add(token.Text); if (lcontext.Lexer.Current.Type != TokenType.Comma) { break; } lcontext.Lexer.Next(); } if (lcontext.Lexer.Current.Type == TokenType.Op_Assignment) { NodeBase.CheckTokenType(lcontext, TokenType.Op_Assignment); m_RValues = Expression.ExprList(lcontext); } else { m_RValues = new List(); } foreach (string item2 in list) { SymbolRef refr = lcontext.Scope.TryDefineLocal(item2); SymbolRefExpression item = new SymbolRefExpression(lcontext, refr); m_LValues.Add(item); } Token current2 = lcontext.Lexer.Current; m_Ref = startToken.GetSourceRefUpTo(current2); lcontext.Source.Refs.Add(m_Ref); } public AssignmentStatement(ScriptLoadingContext lcontext, Expression firstExpression, Token first) : base(lcontext) { m_LValues.Add(CheckVar(lcontext, firstExpression)); while (lcontext.Lexer.Current.Type == TokenType.Comma) { lcontext.Lexer.Next(); Expression firstExpression2 = Expression.PrimaryExp(lcontext); m_LValues.Add(CheckVar(lcontext, firstExpression2)); } NodeBase.CheckTokenType(lcontext, TokenType.Op_Assignment); m_RValues = Expression.ExprList(lcontext); Token current = lcontext.Lexer.Current; m_Ref = first.GetSourceRefUpTo(current); lcontext.Source.Refs.Add(m_Ref); } public IVariable CheckVar(ScriptLoadingContext lcontext, Expression firstExpression) { if (!(firstExpression is IVariable result)) { throw new SyntaxErrorException(lcontext.Lexer.Current, "unexpected symbol near '{0}' - not a l-value", lcontext.Lexer.Current); } return result; } public override void Compile(ByteCode bc) { using (bc.EnterSource(m_Ref)) { foreach (Expression rValue in m_RValues) { rValue.Compile(bc); } for (int i = 0; i < m_LValues.Count; i++) { m_LValues[i].CompileAssignment(bc, Math.Max(m_RValues.Count - 1 - i, 0), i - Math.Min(i, m_RValues.Count - 1)); } bc.Emit_Pop(m_RValues.Count); } } } public class ChunkStatement : Statement, IClosureBuilder { public Statement m_Block; public RuntimeScopeFrame m_StackFrame; public SymbolRef m_Env; public SymbolRef m_VarArgs; public ChunkStatement(ScriptLoadingContext lcontext) : base(lcontext) { lcontext.Scope.PushFunction(this, hasVarArgs: true); m_Env = lcontext.Scope.DefineLocal("_ENV"); m_VarArgs = lcontext.Scope.DefineLocal("..."); m_Block = new CompositeStatement(lcontext); if (lcontext.Lexer.Current.Type != 0) { throw new SyntaxErrorException(lcontext.Lexer.Current, " expected near '{0}'", lcontext.Lexer.Current.Text); } m_StackFrame = lcontext.Scope.PopFunction(); } public override void Compile(ByteCode bc) { Instruction instruction = bc.Emit_Meta("", OpCodeMetadataType.ChunkEntrypoint); int jumpPointForLastInstruction = bc.GetJumpPointForLastInstruction(); bc.Emit_BeginFn(m_StackFrame); bc.Emit_Args(m_VarArgs); bc.Emit_Load(SymbolRef.Upvalue("_ENV", 0)); bc.Emit_Store(m_Env, 0, 0); bc.Emit_Pop(); m_Block.Compile(bc); bc.Emit_Ret(0); instruction.NumVal = bc.GetJumpPointForLastInstruction() - jumpPointForLastInstruction; } public SymbolRef CreateUpvalue(BuildTimeScope scope, SymbolRef symbol) { return null; } } public class CompositeStatement : Statement { public List m_Statements = new List(); public CompositeStatement(ScriptLoadingContext lcontext) : base(lcontext) { while (!lcontext.Lexer.Current.IsEndOfBlock()) { bool forceLast; Statement item = Statement.CreateStatement(lcontext, out forceLast); m_Statements.Add(item); if (forceLast) { break; } } while (lcontext.Lexer.Current.Type == TokenType.SemiColon) { lcontext.Lexer.Next(); } } public override void Compile(ByteCode bc) { if (m_Statements == null) { return; } foreach (Statement statement in m_Statements) { statement.Compile(bc); } } } public class BreakStatement : Statement { public SourceRef m_Ref; public BreakStatement(ScriptLoadingContext lcontext) : base(lcontext) { m_Ref = NodeBase.CheckTokenType(lcontext, TokenType.Break).GetSourceRef(); lcontext.Source.Refs.Add(m_Ref); } public override void Compile(ByteCode bc) { using (bc.EnterSource(m_Ref)) { if (bc.LoopTracker.Loops.Count == 0) { throw new SyntaxErrorException(base.Script, m_Ref, " at line {0} not inside a loop", m_Ref.FromLine); } ILoop loop = bc.LoopTracker.Loops.Peek(); if (loop.IsBoundary()) { throw new SyntaxErrorException(base.Script, m_Ref, " at line {0} not inside a loop", m_Ref.FromLine); } loop.CompileBreak(bc); } } } public class ForEachLoopStatement : Statement { public RuntimeScopeBlock m_StackFrame; public SymbolRef[] m_Names; public IVariable[] m_NameExps; public Expression m_RValues; public Statement m_Block; public SourceRef m_RefFor; public SourceRef m_RefEnd; public ForEachLoopStatement(ScriptLoadingContext lcontext, Token firstNameToken, Token forToken) : base(lcontext) { List list = new List { firstNameToken.Text }; while (lcontext.Lexer.Current.Type == TokenType.Comma) { lcontext.Lexer.Next(); Token token = NodeBase.CheckTokenType(lcontext, TokenType.Name); list.Add(token.Text); } NodeBase.CheckTokenType(lcontext, TokenType.In); m_RValues = new ExprListExpression(Expression.ExprList(lcontext), lcontext); lcontext.Scope.PushBlock(); m_Names = list.Select((string n) => lcontext.Scope.TryDefineLocal(n)).ToArray(); m_NameExps = m_Names.Select((SymbolRef s) => new SymbolRefExpression(lcontext, s)).Cast().ToArray(); m_RefFor = forToken.GetSourceRef(NodeBase.CheckTokenType(lcontext, TokenType.Do)); m_Block = new CompositeStatement(lcontext); m_RefEnd = NodeBase.CheckTokenType(lcontext, TokenType.End).GetSourceRef(); m_StackFrame = lcontext.Scope.PopBlock(); lcontext.Source.Refs.Add(m_RefFor); lcontext.Source.Refs.Add(m_RefEnd); } public override void Compile(ByteCode bc) { bc.PushSourceRef(m_RefFor); Loop loop = new Loop { Scope = m_StackFrame }; bc.LoopTracker.Loops.Push(loop); m_RValues.Compile(bc); bc.Emit_IterPrep(); int jumpPointForNextInstruction = bc.GetJumpPointForNextInstruction(); bc.Emit_Enter(m_StackFrame); bc.Emit_ExpTuple(0); bc.Emit_Call(2, "for..in"); for (int i = 0; i < m_NameExps.Length; i++) { m_NameExps[i].CompileAssignment(bc, 0, i); } bc.Emit_Pop(); bc.Emit_Load(m_Names[0]); bc.Emit_IterUpd(); Instruction instruction = bc.Emit_Jump(OpCode.JNil, -1); m_Block.Compile(bc); bc.PopSourceRef(); bc.PushSourceRef(m_RefEnd); bc.Emit_Leave(m_StackFrame); bc.Emit_Jump(OpCode.Jump, jumpPointForNextInstruction); bc.LoopTracker.Loops.Pop(); int jumpPointForNextInstruction2 = bc.GetJumpPointForNextInstruction(); bc.Emit_Leave(m_StackFrame); int jumpPointForNextInstruction3 = bc.GetJumpPointForNextInstruction(); bc.Emit_Pop(); foreach (Instruction breakJump in loop.BreakJumps) { breakJump.NumVal = jumpPointForNextInstruction3; } instruction.NumVal = jumpPointForNextInstruction2; bc.PopSourceRef(); } } public class ForLoopStatement : Statement { public RuntimeScopeBlock m_StackFrame; public Statement m_InnerBlock; public SymbolRef m_VarName; public Expression m_Start; public Expression m_End; public Expression m_Step; public SourceRef m_RefFor; public SourceRef m_RefEnd; public ForLoopStatement(ScriptLoadingContext lcontext, Token nameToken, Token forToken) : base(lcontext) { NodeBase.CheckTokenType(lcontext, TokenType.Op_Assignment); m_Start = Expression.Expr(lcontext); NodeBase.CheckTokenType(lcontext, TokenType.Comma); m_End = Expression.Expr(lcontext); if (lcontext.Lexer.Current.Type == TokenType.Comma) { lcontext.Lexer.Next(); m_Step = Expression.Expr(lcontext); } else { m_Step = new LiteralExpression(lcontext, DynValue.NewNumber(1.0)); } lcontext.Scope.PushBlock(); m_VarName = lcontext.Scope.DefineLocal(nameToken.Text); m_RefFor = forToken.GetSourceRef(NodeBase.CheckTokenType(lcontext, TokenType.Do)); m_InnerBlock = new CompositeStatement(lcontext); m_RefEnd = NodeBase.CheckTokenType(lcontext, TokenType.End).GetSourceRef(); m_StackFrame = lcontext.Scope.PopBlock(); lcontext.Source.Refs.Add(m_RefFor); lcontext.Source.Refs.Add(m_RefEnd); } public override void Compile(ByteCode bc) { bc.PushSourceRef(m_RefFor); Loop loop = new Loop { Scope = m_StackFrame }; bc.LoopTracker.Loops.Push(loop); m_End.Compile(bc); bc.Emit_ToNum(3); m_Step.Compile(bc); bc.Emit_ToNum(2); m_Start.Compile(bc); bc.Emit_ToNum(1); int jumpPointForNextInstruction = bc.GetJumpPointForNextInstruction(); Instruction instruction = bc.Emit_Jump(OpCode.JFor, -1); bc.Emit_Enter(m_StackFrame); bc.Emit_Store(m_VarName, 0, 0); m_InnerBlock.Compile(bc); bc.PopSourceRef(); bc.PushSourceRef(m_RefEnd); bc.Emit_Leave(m_StackFrame); bc.Emit_Incr(1); bc.Emit_Jump(OpCode.Jump, jumpPointForNextInstruction); bc.LoopTracker.Loops.Pop(); int jumpPointForNextInstruction2 = bc.GetJumpPointForNextInstruction(); foreach (Instruction breakJump in loop.BreakJumps) { breakJump.NumVal = jumpPointForNextInstruction2; } instruction.NumVal = jumpPointForNextInstruction2; bc.Emit_Pop(3); bc.PopSourceRef(); } } public class IfStatement : Statement { public class IfBlock { public Expression Exp; public Statement Block; public RuntimeScopeBlock StackFrame; public SourceRef Source; } public List m_Ifs = new List(); public IfBlock m_Else; public SourceRef m_End; public IfStatement(ScriptLoadingContext lcontext) : base(lcontext) { while (lcontext.Lexer.Current.Type != TokenType.Else && lcontext.Lexer.Current.Type != TokenType.End) { m_Ifs.Add(CreateIfBlock(lcontext)); } if (lcontext.Lexer.Current.Type == TokenType.Else) { m_Else = CreateElseBlock(lcontext); } m_End = NodeBase.CheckTokenType(lcontext, TokenType.End).GetSourceRef(); lcontext.Source.Refs.Add(m_End); } public IfBlock CreateIfBlock(ScriptLoadingContext lcontext) { Token token = NodeBase.CheckTokenType(lcontext, TokenType.If, TokenType.ElseIf); lcontext.Scope.PushBlock(); IfBlock ifBlock = new IfBlock(); ifBlock.Exp = Expression.Expr(lcontext); ifBlock.Source = token.GetSourceRef(NodeBase.CheckTokenType(lcontext, TokenType.Then)); ifBlock.Block = new CompositeStatement(lcontext); ifBlock.StackFrame = lcontext.Scope.PopBlock(); lcontext.Source.Refs.Add(ifBlock.Source); return ifBlock; } public IfBlock CreateElseBlock(ScriptLoadingContext lcontext) { Token token = NodeBase.CheckTokenType(lcontext, TokenType.Else); lcontext.Scope.PushBlock(); IfBlock ifBlock = new IfBlock(); ifBlock.Block = new CompositeStatement(lcontext); ifBlock.StackFrame = lcontext.Scope.PopBlock(); ifBlock.Source = token.GetSourceRef(); lcontext.Source.Refs.Add(ifBlock.Source); return ifBlock; } public override void Compile(ByteCode bc) { List list = new List(); Instruction instruction = null; foreach (IfBlock @if in m_Ifs) { using (bc.EnterSource(@if.Source)) { if (instruction != null) { instruction.NumVal = bc.GetJumpPointForNextInstruction(); } @if.Exp.Compile(bc); instruction = bc.Emit_Jump(OpCode.Jf, -1); bc.Emit_Enter(@if.StackFrame); @if.Block.Compile(bc); } using (bc.EnterSource(m_End)) { bc.Emit_Leave(@if.StackFrame); } list.Add(bc.Emit_Jump(OpCode.Jump, -1)); } instruction.NumVal = bc.GetJumpPointForNextInstruction(); if (m_Else != null) { using (bc.EnterSource(m_Else.Source)) { bc.Emit_Enter(m_Else.StackFrame); m_Else.Block.Compile(bc); } using (bc.EnterSource(m_End)) { bc.Emit_Leave(m_Else.StackFrame); } } foreach (Instruction item in list) { item.NumVal = bc.GetJumpPointForNextInstruction(); } } } public class LabelStatement : Statement { public List m_Gotos = new List(); public RuntimeScopeBlock m_StackFrame; public string Label { get; set; } public int Address { get; set; } public SourceRef SourceRef { get; set; } public Token NameToken { get; set; } public int DefinedVarsCount { get; set; } public string LastDefinedVarName { get; set; } public LabelStatement(ScriptLoadingContext lcontext) : base(lcontext) { NodeBase.CheckTokenType(lcontext, TokenType.DoubleColon); NameToken = NodeBase.CheckTokenType(lcontext, TokenType.Name); NodeBase.CheckTokenType(lcontext, TokenType.DoubleColon); SourceRef = NameToken.GetSourceRef(); Label = NameToken.Text; lcontext.Scope.DefineLabel(this); } public void SetDefinedVars(int definedVarsCount, string lastDefinedVarsName) { DefinedVarsCount = definedVarsCount; LastDefinedVarName = lastDefinedVarsName; } public void RegisterGoto(GotoStatement gotostat) { m_Gotos.Add(gotostat); } public override void Compile(ByteCode bc) { bc.Emit_Clean(m_StackFrame); Address = bc.GetJumpPointForLastInstruction(); foreach (GotoStatement @goto in m_Gotos) { @goto.SetAddress(Address); } } public void SetScope(RuntimeScopeBlock runtimeScopeBlock) { m_StackFrame = runtimeScopeBlock; } } public class RepeatStatement : Statement { public Expression m_Condition; public Statement m_Block; public RuntimeScopeBlock m_StackFrame; public SourceRef m_Repeat; public SourceRef m_Until; public RepeatStatement(ScriptLoadingContext lcontext) : base(lcontext) { m_Repeat = NodeBase.CheckTokenType(lcontext, TokenType.Repeat).GetSourceRef(); lcontext.Scope.PushBlock(); m_Block = new CompositeStatement(lcontext); Token token = NodeBase.CheckTokenType(lcontext, TokenType.Until); m_Condition = Expression.Expr(lcontext); m_Until = token.GetSourceRefUpTo(lcontext.Lexer.Current); m_StackFrame = lcontext.Scope.PopBlock(); lcontext.Source.Refs.Add(m_Repeat); lcontext.Source.Refs.Add(m_Until); } public override void Compile(ByteCode bc) { Loop loop = new Loop { Scope = m_StackFrame }; bc.PushSourceRef(m_Repeat); bc.LoopTracker.Loops.Push(loop); int jumpPointForNextInstruction = bc.GetJumpPointForNextInstruction(); bc.Emit_Enter(m_StackFrame); m_Block.Compile(bc); bc.PopSourceRef(); bc.PushSourceRef(m_Until); m_Condition.Compile(bc); bc.Emit_Leave(m_StackFrame); bc.Emit_Jump(OpCode.Jf, jumpPointForNextInstruction); bc.LoopTracker.Loops.Pop(); int jumpPointForNextInstruction2 = bc.GetJumpPointForNextInstruction(); foreach (Instruction breakJump in loop.BreakJumps) { breakJump.NumVal = jumpPointForNextInstruction2; } bc.PopSourceRef(); } } public class ReturnStatement : Statement { public Expression m_Expression; public SourceRef m_Ref; public ReturnStatement(ScriptLoadingContext lcontext, Expression e, SourceRef sref) : base(lcontext) { m_Expression = e; m_Ref = sref; lcontext.Source.Refs.Add(sref); } public ReturnStatement(ScriptLoadingContext lcontext) : base(lcontext) { Token current = lcontext.Lexer.Current; lcontext.Lexer.Next(); Token current2 = lcontext.Lexer.Current; if (current2.IsEndOfBlock() || current2.Type == TokenType.SemiColon) { m_Expression = null; m_Ref = current.GetSourceRef(); } else { m_Expression = new ExprListExpression(Expression.ExprList(lcontext), lcontext); m_Ref = current.GetSourceRefUpTo(lcontext.Lexer.Current); } lcontext.Source.Refs.Add(m_Ref); } public override void Compile(ByteCode bc) { using (bc.EnterSource(m_Ref)) { if (m_Expression != null) { m_Expression.Compile(bc); bc.Emit_Ret(1); } else { bc.Emit_Ret(0); } } } } public class ScopeBlockStatement : Statement { public Statement m_Block; public RuntimeScopeBlock m_StackFrame; public SourceRef m_Do; public SourceRef m_End; public ScopeBlockStatement(ScriptLoadingContext lcontext) : base(lcontext) { lcontext.Scope.PushBlock(); m_Do = NodeBase.CheckTokenType(lcontext, TokenType.Do).GetSourceRef(); m_Block = new CompositeStatement(lcontext); m_End = NodeBase.CheckTokenType(lcontext, TokenType.End).GetSourceRef(); m_StackFrame = lcontext.Scope.PopBlock(); lcontext.Source.Refs.Add(m_Do); lcontext.Source.Refs.Add(m_End); } public override void Compile(ByteCode bc) { using (bc.EnterSource(m_Do)) { bc.Emit_Enter(m_StackFrame); } m_Block.Compile(bc); using (bc.EnterSource(m_End)) { bc.Emit_Leave(m_StackFrame); } } } public class WhileStatement : Statement { public Expression m_Condition; public Statement m_Block; public RuntimeScopeBlock m_StackFrame; public SourceRef m_Start; public SourceRef m_End; public WhileStatement(ScriptLoadingContext lcontext) : base(lcontext) { Token token = NodeBase.CheckTokenType(lcontext, TokenType.While); m_Condition = Expression.Expr(lcontext); m_Start = token.GetSourceRefUpTo(lcontext.Lexer.Current); lcontext.Scope.PushBlock(); NodeBase.CheckTokenType(lcontext, TokenType.Do); m_Block = new CompositeStatement(lcontext); m_End = NodeBase.CheckTokenType(lcontext, TokenType.End).GetSourceRef(); m_StackFrame = lcontext.Scope.PopBlock(); lcontext.Source.Refs.Add(m_Start); lcontext.Source.Refs.Add(m_End); } public override void Compile(ByteCode bc) { Loop loop = new Loop { Scope = m_StackFrame }; bc.LoopTracker.Loops.Push(loop); bc.PushSourceRef(m_Start); int jumpPointForNextInstruction = bc.GetJumpPointForNextInstruction(); m_Condition.Compile(bc); Instruction instruction = bc.Emit_Jump(OpCode.Jf, -1); bc.Emit_Enter(m_StackFrame); m_Block.Compile(bc); bc.PopSourceRef(); bc.PushSourceRef(m_End); bc.Emit_Leave(m_StackFrame); bc.Emit_Jump(OpCode.Jump, jumpPointForNextInstruction); bc.LoopTracker.Loops.Pop(); int jumpPointForNextInstruction2 = bc.GetJumpPointForNextInstruction(); foreach (Instruction breakJump in loop.BreakJumps) { breakJump.NumVal = jumpPointForNextInstruction2; } instruction.NumVal = jumpPointForNextInstruction2; bc.PopSourceRef(); } } } namespace MoonSharp.Interpreter.Tree.Fast_Interface { public static class Loader_Fast { public static DynamicExprExpression LoadDynamicExpr(Script script, SourceCode source) { ScriptLoadingContext scriptLoadingContext = CreateLoadingContext(script, source); try { scriptLoadingContext.IsDynamicExpression = true; scriptLoadingContext.Anonymous = true; Expression exp; using (script.PerformanceStats.StartStopwatch(PerformanceCounter.AstCreation)) { exp = Expression.Expr(scriptLoadingContext); } return new DynamicExprExpression(exp, scriptLoadingContext); } catch (SyntaxErrorException ex) { ex.DecorateMessage(script); ex.Rethrow(); throw; } } public static ScriptLoadingContext CreateLoadingContext(Script script, SourceCode source) { return new ScriptLoadingContext(script) { Scope = new BuildTimeScope(), Source = source, Lexer = new Lexer(source.SourceID, source.Code, autoSkipComments: true) }; } public static int LoadChunk(Script script, SourceCode source, ByteCode bytecode) { ScriptLoadingContext lcontext = CreateLoadingContext(script, source); try { Statement statement; using (script.PerformanceStats.StartStopwatch(PerformanceCounter.AstCreation)) { statement = new ChunkStatement(lcontext); } int result = -1; using (script.PerformanceStats.StartStopwatch(PerformanceCounter.Compilation)) { using (bytecode.EnterSource(null)) { bytecode.Emit_Nop($"Begin chunk {source.Name}"); result = bytecode.GetJumpPointForLastInstruction(); statement.Compile(bytecode); bytecode.Emit_Nop($"End chunk {source.Name}"); } } return result; } catch (SyntaxErrorException ex) { ex.DecorateMessage(script); ex.Rethrow(); throw; } } public static int LoadFunction(Script script, SourceCode source, ByteCode bytecode, bool usesGlobalEnv) { ScriptLoadingContext lcontext = CreateLoadingContext(script, source); try { FunctionDefinitionExpression functionDefinitionExpression; using (script.PerformanceStats.StartStopwatch(PerformanceCounter.AstCreation)) { functionDefinitionExpression = new FunctionDefinitionExpression(lcontext, usesGlobalEnv); } int result = -1; using (script.PerformanceStats.StartStopwatch(PerformanceCounter.Compilation)) { using (bytecode.EnterSource(null)) { bytecode.Emit_Nop($"Begin function {source.Name}"); result = functionDefinitionExpression.CompileBody(bytecode, source.Name); bytecode.Emit_Nop($"End function {source.Name}"); } } return result; } catch (SyntaxErrorException ex) { ex.DecorateMessage(script); ex.Rethrow(); throw; } } } } namespace MoonSharp.Interpreter.Tree.Expressions { public class AdjustmentExpression : Expression { public Expression expression; public AdjustmentExpression(ScriptLoadingContext lcontext, Expression exp) : base(lcontext) { expression = exp; } public override void Compile(ByteCode bc) { expression.Compile(bc); bc.Emit_Scalar(); } public override DynValue Eval(ScriptExecutionContext context) { return expression.Eval(context).ToScalar(); } } public class BinaryOperatorExpression : Expression { [Flags] public enum Operator { NotAnOperator = 0, Or = 1, And = 2, Less = 4, Greater = 8, LessOrEqual = 0x10, GreaterOrEqual = 0x20, NotEqual = 0x40, Equal = 0x80, StrConcat = 0x100, Add = 0x200, Sub = 0x400, Mul = 0x1000, Div = 0x2000, Mod = 0x4000, Power = 0x8000 } public class Node { public Expression Expr; public Operator Op; public Node Prev; public Node Next; } public class LinkedList { public Node Nodes; public Node Last; public Operator OperatorMask; } public const Operator POWER = Operator.Power; public const Operator MUL_DIV_MOD = Operator.Mul | Operator.Div | Operator.Mod; public const Operator ADD_SUB = Operator.Add | Operator.Sub; public const Operator STRCAT = Operator.StrConcat; public const Operator COMPARES = Operator.Less | Operator.Greater | Operator.LessOrEqual | Operator.GreaterOrEqual | Operator.NotEqual | Operator.Equal; public const Operator LOGIC_AND = Operator.And; public const Operator LOGIC_OR = Operator.Or; public Expression m_Exp1; public Expression m_Exp2; public Operator m_Operator; public static object BeginOperatorChain() { return new LinkedList(); } public static void AddExpressionToChain(object chain, Expression exp) { LinkedList list = (LinkedList)chain; Node node = new Node { Expr = exp }; AddNode(list, node); } public static void AddOperatorToChain(object chain, Token op) { LinkedList list = (LinkedList)chain; Node node = new Node { Op = ParseBinaryOperator(op) }; AddNode(list, node); } public static Expression CommitOperatorChain(object chain, ScriptLoadingContext lcontext) { return CreateSubTree((LinkedList)chain, lcontext); } public static Expression CreatePowerExpression(Expression op1, Expression op2, ScriptLoadingContext lcontext) { return new BinaryOperatorExpression(op1, op2, Operator.Power, lcontext); } public static void AddNode(LinkedList list, Node node) { list.OperatorMask |= node.Op; if (list.Nodes == null) { list.Nodes = (list.Last = node); return; } list.Last.Next = node; node.Prev = list.Last; list.Last = node; } public static Expression CreateSubTree(LinkedList list, ScriptLoadingContext lcontext) { Operator operatorMask = list.OperatorMask; Node node = list.Nodes; if ((operatorMask & Operator.Power) != 0) { node = PrioritizeRightAssociative(node, lcontext, Operator.Power); } if ((operatorMask & (Operator.Mul | Operator.Div | Operator.Mod)) != 0) { node = PrioritizeLeftAssociative(node, lcontext, Operator.Mul | Operator.Div | Operator.Mod); } if ((operatorMask & (Operator.Add | Operator.Sub)) != 0) { node = PrioritizeLeftAssociative(node, lcontext, Operator.Add | Operator.Sub); } if ((operatorMask & Operator.StrConcat) != 0) { node = PrioritizeRightAssociative(node, lcontext, Operator.StrConcat); } if ((operatorMask & (Operator.Less | Operator.Greater | Operator.LessOrEqual | Operator.GreaterOrEqual | Operator.NotEqual | Operator.Equal)) != 0) { node = PrioritizeLeftAssociative(node, lcontext, Operator.Less | Operator.Greater | Operator.LessOrEqual | Operator.GreaterOrEqual | Operator.NotEqual | Operator.Equal); } if ((operatorMask & Operator.And) != 0) { node = PrioritizeLeftAssociative(node, lcontext, Operator.And); } if ((operatorMask & Operator.Or) != 0) { node = PrioritizeLeftAssociative(node, lcontext, Operator.Or); } if (node.Next != null || node.Prev != null) { throw new InternalErrorException("Expression reduction didn't work! - 1"); } if (node.Expr == null) { throw new InternalErrorException("Expression reduction didn't work! - 2"); } return node.Expr; } public static Node PrioritizeLeftAssociative(Node nodes, ScriptLoadingContext lcontext, Operator operatorsToFind) { for (Node node = nodes; node != null; node = node.Next) { Operator op = node.Op; if ((op & operatorsToFind) != 0) { node.Op = Operator.NotAnOperator; node.Expr = new BinaryOperatorExpression(node.Prev.Expr, node.Next.Expr, op, lcontext); node.Prev = node.Prev.Prev; node.Next = node.Next.Next; if (node.Next != null) { node.Next.Prev = node; } if (node.Prev != null) { node.Prev.Next = node; } else { nodes = node; } } } return nodes; } public static Node PrioritizeRightAssociative(Node nodes, ScriptLoadingContext lcontext, Operator operatorsToFind) { Node node = nodes; while (node.Next != null) { node = node.Next; } for (Node node2 = node; node2 != null; node2 = node2.Prev) { Operator op = node2.Op; if ((op & operatorsToFind) != 0) { node2.Op = Operator.NotAnOperator; node2.Expr = new BinaryOperatorExpression(node2.Prev.Expr, node2.Next.Expr, op, lcontext); node2.Prev = node2.Prev.Prev; node2.Next = node2.Next.Next; if (node2.Next != null) { node2.Next.Prev = node2; } if (node2.Prev != null) { node2.Prev.Next = node2; } else { nodes = node2; } } } return nodes; } public static Operator ParseBinaryOperator(Token token) { return token.Type switch { TokenType.Or => Operator.Or, TokenType.And => Operator.And, TokenType.Op_LessThan => Operator.Less, TokenType.Op_GreaterThan => Operator.Greater, TokenType.Op_LessThanEqual => Operator.LessOrEqual, TokenType.Op_GreaterThanEqual => Operator.GreaterOrEqual, TokenType.Op_NotEqual => Operator.NotEqual, TokenType.Op_Equal => Operator.Equal, TokenType.Op_Concat => Operator.StrConcat, TokenType.Op_Add => Operator.Add, TokenType.Op_MinusOrSub => Operator.Sub, TokenType.Op_Mul => Operator.Mul, TokenType.Op_Div => Operator.Div, TokenType.Op_Mod => Operator.Mod, TokenType.Op_Pwr => Operator.Power, _ => throw new InternalErrorException("Unexpected binary operator '{0}'", token.Text), }; } public BinaryOperatorExpression(Expression exp1, Expression exp2, Operator op, ScriptLoadingContext lcontext) : base(lcontext) { m_Exp1 = exp1; m_Exp2 = exp2; m_Operator = op; } public static bool ShouldInvertBoolean(Operator op) { if (op != Operator.NotEqual && op != Operator.GreaterOrEqual) { return op == Operator.Greater; } return true; } public static OpCode OperatorToOpCode(Operator op) { switch (op) { case Operator.Less: case Operator.GreaterOrEqual: return OpCode.Less; case Operator.Greater: case Operator.LessOrEqual: return OpCode.LessEq; case Operator.NotEqual: case Operator.Equal: return OpCode.Eq; case Operator.StrConcat: return OpCode.Concat; case Operator.Add: return OpCode.Add; case Operator.Sub: return OpCode.Sub; case Operator.Mul: return OpCode.Mul; case Operator.Div: return OpCode.Div; case Operator.Mod: return OpCode.Mod; case Operator.Power: return OpCode.Power; default: throw new InternalErrorException("Unsupported operator {0}", op); } } public override void Compile(ByteCode bc) { m_Exp1.Compile(bc); if (m_Operator == Operator.Or) { Instruction instruction = bc.Emit_Jump(OpCode.JtOrPop, -1); m_Exp2.Compile(bc); instruction.NumVal = bc.GetJumpPointForNextInstruction(); return; } if (m_Operator == Operator.And) { Instruction instruction2 = bc.Emit_Jump(OpCode.JfOrPop, -1); m_Exp2.Compile(bc); instruction2.NumVal = bc.GetJumpPointForNextInstruction(); return; } if (m_Exp2 != null) { m_Exp2.Compile(bc); } bc.Emit_Operator(OperatorToOpCode(m_Operator)); if (ShouldInvertBoolean(m_Operator)) { bc.Emit_Operator(OpCode.Not); } } public override DynValue Eval(ScriptExecutionContext context) { DynValue dynValue = m_Exp1.Eval(context).ToScalar(); if (m_Operator == Operator.Or) { if (dynValue.CastToBool()) { return dynValue; } return m_Exp2.Eval(context).ToScalar(); } if (m_Operator == Operator.And) { if (!dynValue.CastToBool()) { return dynValue; } return m_Exp2.Eval(context).ToScalar(); } DynValue dynValue2 = m_Exp2.Eval(context).ToScalar(); if ((m_Operator & (Operator.Less | Operator.Greater | Operator.LessOrEqual | Operator.GreaterOrEqual | Operator.NotEqual | Operator.Equal)) != 0) { return DynValue.NewBoolean(EvalComparison(dynValue, dynValue2, m_Operator)); } if (m_Operator == Operator.StrConcat) { string text = dynValue.CastToString(); string text2 = dynValue2.CastToString(); if (text == null || text2 == null) { throw new DynamicExpressionException("Attempt to perform concatenation on non-strings."); } return DynValue.NewString(text + text2); } return DynValue.NewNumber(EvalArithmetic(dynValue, dynValue2)); } public double EvalArithmetic(DynValue v1, DynValue v2) { double? num = v1.CastToNumber(); double? num2 = v2.CastToNumber(); if (!num.HasValue || !num2.HasValue) { throw new DynamicExpressionException("Attempt to perform arithmetic on non-numbers."); } double value = num.Value; double value2 = num2.Value; switch (m_Operator) { case Operator.Add: return value + value2; case Operator.Sub: return value - value2; case Operator.Mul: return value * value2; case Operator.Div: return value / value2; case Operator.Mod: { double num3 = Math.IEEERemainder(value, value2); if (num3 < 0.0) { num3 += value2; } return num3; } default: throw new DynamicExpressionException("Unsupported operator {0}", m_Operator); } } public bool EvalComparison(DynValue l, DynValue r, Operator op) { switch (op) { case Operator.Less: if (l.Type == DataType.Number && r.Type == DataType.Number) { return l.Number < r.Number; } if (l.Type == DataType.String && r.Type == DataType.String) { return l.String.CompareTo(r.String) < 0; } throw new DynamicExpressionException("Attempt to compare non-numbers, non-strings."); case Operator.LessOrEqual: if (l.Type == DataType.Number && r.Type == DataType.Number) { return l.Number <= r.Number; } if (l.Type == DataType.String && r.Type == DataType.String) { return l.String.CompareTo(r.String) <= 0; } throw new DynamicExpressionException("Attempt to compare non-numbers, non-strings."); case Operator.Equal: if (r == l) { return true; } if (r.Type != l.Type) { if ((l.Type == DataType.Nil && r.Type == DataType.Void) || (l.Type == DataType.Void && r.Type == DataType.Nil)) { return true; } return false; } return r.Equals(l); case Operator.Greater: return !EvalComparison(l, r, Operator.LessOrEqual); case Operator.GreaterOrEqual: return !EvalComparison(l, r, Operator.Less); case Operator.NotEqual: return !EvalComparison(l, r, Operator.Equal); default: throw new DynamicExpressionException("Unsupported operator {0}", op); } } } public class DynamicExprExpression : Expression { public Expression m_Exp; public DynamicExprExpression(Expression exp, ScriptLoadingContext lcontext) : base(lcontext) { lcontext.Anonymous = true; m_Exp = exp; } public override DynValue Eval(ScriptExecutionContext context) { return m_Exp.Eval(context); } public override void Compile(ByteCode bc) { throw new InvalidOperationException(); } public override SymbolRef FindDynamic(ScriptExecutionContext context) { return m_Exp.FindDynamic(context); } } public class FunctionCallExpression : Expression { public List m_Arguments; public Expression m_Function; public string m_Name; public string m_DebugErr; public SourceRef SourceRef { get; set; } public FunctionCallExpression(ScriptLoadingContext lcontext, Expression function, Token thisCallName) : base(lcontext) { Token token = thisCallName ?? lcontext.Lexer.Current; m_Name = thisCallName?.Text; m_DebugErr = function.GetFriendlyDebugName(); m_Function = function; switch (lcontext.Lexer.Current.Type) { case TokenType.Brk_Open_Round: { Token current = lcontext.Lexer.Current; lcontext.Lexer.Next(); Token current2 = lcontext.Lexer.Current; if (current2.Type == TokenType.Brk_Close_Round) { m_Arguments = new List(); SourceRef = token.GetSourceRef(current2); lcontext.Lexer.Next(); } else { m_Arguments = Expression.ExprList(lcontext); SourceRef = token.GetSourceRef(NodeBase.CheckMatch(lcontext, current, TokenType.Brk_Close_Round, ")")); } break; } case TokenType.String: case TokenType.String_Long: { m_Arguments = new List(); Expression item = new LiteralExpression(lcontext, lcontext.Lexer.Current); m_Arguments.Add(item); SourceRef = token.GetSourceRef(lcontext.Lexer.Current); break; } case TokenType.Brk_Open_Curly: case TokenType.Brk_Open_Curly_Shared: m_Arguments = new List(); m_Arguments.Add(new TableConstructor(lcontext, lcontext.Lexer.Current.Type == TokenType.Brk_Open_Curly_Shared)); SourceRef = token.GetSourceRefUpTo(lcontext.Lexer.Current); break; default: throw new SyntaxErrorException(lcontext.Lexer.Current, "function arguments expected") { IsPrematureStreamTermination = (lcontext.Lexer.Current.Type == TokenType.Eof) }; } } public override void Compile(ByteCode bc) { m_Function.Compile(bc); int num = m_Arguments.Count; if (!string.IsNullOrEmpty(m_Name)) { bc.Emit_Copy(0); bc.Emit_Index(DynValue.NewString(m_Name), isNameIndex: true); bc.Emit_Swap(0, 1); num++; } for (int i = 0; i < m_Arguments.Count; i++) { m_Arguments[i].Compile(bc); } if (!string.IsNullOrEmpty(m_Name)) { bc.Emit_ThisCall(num, m_DebugErr); } else { bc.Emit_Call(num, m_DebugErr); } } public override DynValue Eval(ScriptExecutionContext context) { throw new DynamicExpressionException("Dynamic Expressions cannot call functions."); } } public class FunctionDefinitionExpression : Expression, IClosureBuilder { public SymbolRef[] m_ParamNames; public Statement m_Statement; public RuntimeScopeFrame m_StackFrame; public List m_Closure = new List(); public bool m_HasVarArgs; public Instruction m_ClosureInstruction; public bool m_UsesGlobalEnv; public SymbolRef m_Env; public SourceRef m_Begin; public SourceRef m_End; public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool usesGlobalEnv) : this(lcontext, pushSelfParam: false, usesGlobalEnv, isLambda: false) { } public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSelfParam, bool isLambda) : this(lcontext, pushSelfParam, usesGlobalEnv: false, isLambda) { } public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSelfParam, bool usesGlobalEnv, bool isLambda) : base(lcontext) { if (m_UsesGlobalEnv = usesGlobalEnv) { NodeBase.CheckTokenType(lcontext, TokenType.Function); } Token token = NodeBase.CheckTokenType(lcontext, isLambda ? TokenType.Lambda : TokenType.Brk_Open_Round); List paramnames = BuildParamList(lcontext, pushSelfParam, token, isLambda); m_Begin = token.GetSourceRefUpTo(lcontext.Lexer.Current); lcontext.Scope.PushFunction(this, m_HasVarArgs); if (m_UsesGlobalEnv) { m_Env = lcontext.Scope.DefineLocal("_ENV"); } else { lcontext.Scope.ForceEnvUpValue(); } m_ParamNames = DefineArguments(paramnames, lcontext); if (isLambda) { m_Statement = CreateLambdaBody(lcontext); } else { m_Statement = CreateBody(lcontext); } m_StackFrame = lcontext.Scope.PopFunction(); lcontext.Source.Refs.Add(m_Begin); lcontext.Source.Refs.Add(m_End); } public Statement CreateLambdaBody(ScriptLoadingContext lcontext) { Token current = lcontext.Lexer.Current; Expression e = Expression.Expr(lcontext); Token current2 = lcontext.Lexer.Current; SourceRef sourceRefUpTo = current.GetSourceRefUpTo(current2); return new ReturnStatement(lcontext, e, sourceRefUpTo); } public Statement CreateBody(ScriptLoadingContext lcontext) { Statement result = new CompositeStatement(lcontext); if (lcontext.Lexer.Current.Type != TokenType.End) { throw new SyntaxErrorException(lcontext.Lexer.Current, "'end' expected near '{0}'", lcontext.Lexer.Current.Text) { IsPrematureStreamTermination = (lcontext.Lexer.Current.Type == TokenType.Eof) }; } m_End = lcontext.Lexer.Current.GetSourceRef(); lcontext.Lexer.Next(); return result; } public List BuildParamList(ScriptLoadingContext lcontext, bool pushSelfParam, Token openBracketToken, bool isLambda) { TokenType tokenType = (isLambda ? TokenType.Lambda : TokenType.Brk_Close_Round); List list = new List(); if (pushSelfParam) { list.Add("self"); } while (lcontext.Lexer.Current.Type != tokenType) { Token current = lcontext.Lexer.Current; if (current.Type == TokenType.Name) { list.Add(current.Text); } else if (current.Type == TokenType.VarArgs) { m_HasVarArgs = true; list.Add("..."); } else { NodeBase.UnexpectedTokenType(current); } lcontext.Lexer.Next(); current = lcontext.Lexer.Current; if (current.Type == TokenType.Comma) { lcontext.Lexer.Next(); continue; } NodeBase.CheckMatch(lcontext, openBracketToken, tokenType, isLambda ? "|" : ")"); break; } if (lcontext.Lexer.Current.Type == tokenType) { lcontext.Lexer.Next(); } return list; } public SymbolRef[] DefineArguments(List paramnames, ScriptLoadingContext lcontext) { HashSet hashSet = new HashSet(); SymbolRef[] array = new SymbolRef[paramnames.Count]; for (int num = paramnames.Count - 1; num >= 0; num--) { if (!hashSet.Add(paramnames[num])) { paramnames[num] = paramnames[num] + "@" + num; } array[num] = lcontext.Scope.DefineLocal(paramnames[num]); } return array; } public SymbolRef CreateUpvalue(BuildTimeScope scope, SymbolRef symbol) { for (int i = 0; i < m_Closure.Count; i++) { if (m_Closure[i].i_Name == symbol.i_Name) { return SymbolRef.Upvalue(symbol.i_Name, i); } } m_Closure.Add(symbol); if (m_ClosureInstruction != null) { m_ClosureInstruction.SymbolList = m_Closure.ToArray(); } return SymbolRef.Upvalue(symbol.i_Name, m_Closure.Count - 1); } public override DynValue Eval(ScriptExecutionContext context) { throw new DynamicExpressionException("Dynamic Expressions cannot define new functions."); } public int CompileBody(ByteCode bc, string friendlyName) { string funcName = friendlyName ?? ("<" + m_Begin.FormatLocation(bc.Script, forceClassicFormat: true) + ">"); bc.PushSourceRef(m_Begin); Instruction instruction = bc.Emit_Jump(OpCode.Jump, -1); Instruction instruction2 = bc.Emit_Meta(funcName, OpCodeMetadataType.FunctionEntrypoint); int jumpPointForLastInstruction = bc.GetJumpPointForLastInstruction(); bc.Emit_BeginFn(m_StackFrame); bc.LoopTracker.Loops.Push(new LoopBoundary()); int jumpPointForLastInstruction2 = bc.GetJumpPointForLastInstruction(); if (m_UsesGlobalEnv) { bc.Emit_Load(SymbolRef.Upvalue("_ENV", 0)); bc.Emit_Store(m_Env, 0, 0); bc.Emit_Pop(); } if (m_ParamNames.Length != 0) { bc.Emit_Args(m_ParamNames); } m_Statement.Compile(bc); bc.PopSourceRef(); bc.PushSourceRef(m_End); bc.Emit_Ret(0); bc.LoopTracker.Loops.Pop(); instruction.NumVal = bc.GetJumpPointForNextInstruction(); instruction2.NumVal = bc.GetJumpPointForLastInstruction() - jumpPointForLastInstruction; bc.PopSourceRef(); return jumpPointForLastInstruction2; } public int Compile(ByteCode bc, Func afterDecl, string friendlyName) { using (bc.EnterSource(m_Begin)) { SymbolRef[] symbols = m_Closure.ToArray(); m_ClosureInstruction = bc.Emit_Closure(symbols, bc.GetJumpPointForNextInstruction()); int num = afterDecl(); m_ClosureInstruction.NumVal += 2 + num; } return CompileBody(bc, friendlyName); } public override void Compile(ByteCode bc) { Compile(bc, () => 0, null); } } public class LiteralExpression : Expression { public DynValue m_Value; public DynValue Value => m_Value; public LiteralExpression(ScriptLoadingContext lcontext, DynValue value) : base(lcontext) { m_Value = value; } public LiteralExpression(ScriptLoadingContext lcontext, Token t) : base(lcontext) { switch (t.Type) { case TokenType.Number: case TokenType.Number_HexFloat: case TokenType.Number_Hex: m_Value = DynValue.NewNumber(t.GetNumberValue()).AsReadOnly(); break; case TokenType.String: case TokenType.String_Long: m_Value = DynValue.NewString(t.Text).AsReadOnly(); break; case TokenType.True: m_Value = DynValue.True; break; case TokenType.False: m_Value = DynValue.False; break; case TokenType.Nil: m_Value = DynValue.Nil; break; default: throw new InternalErrorException("type mismatch"); } if (m_Value == null) { throw new SyntaxErrorException(t, "unknown literal format near '{0}'", t.Text); } lcontext.Lexer.Next(); } public override void Compile(ByteCode bc) { bc.Emit_Literal(m_Value); } public override DynValue Eval(ScriptExecutionContext context) { return m_Value; } } public class UnaryOperatorExpression : Expression { public Expression m_Exp; public string m_OpText; public UnaryOperatorExpression(ScriptLoadingContext lcontext, Expression subExpression, Token unaryOpToken) : base(lcontext) { m_OpText = unaryOpToken.Text; m_Exp = subExpression; } public override void Compile(ByteCode bc) { m_Exp.Compile(bc); switch (m_OpText) { case "not": bc.Emit_Operator(OpCode.Not); break; case "#": bc.Emit_Operator(OpCode.Len); break; case "-": bc.Emit_Operator(OpCode.Neg); break; default: throw new InternalErrorException("Unexpected unary operator '{0}'", m_OpText); } } public override DynValue Eval(ScriptExecutionContext context) { DynValue dynValue = m_Exp.Eval(context).ToScalar(); switch (m_OpText) { case "not": return DynValue.NewBoolean(!dynValue.CastToBool()); case "#": return dynValue.GetLength(); case "-": { double? num = dynValue.CastToNumber(); if (num.HasValue) { return DynValue.NewNumber(0.0 - num.Value); } throw new DynamicExpressionException("Attempt to perform arithmetic on non-numbers."); } default: throw new DynamicExpressionException("Unexpected unary operator '{0}'", m_OpText); } } } public class ExprListExpression : Expression { public List expressions; public ExprListExpression(List exps, ScriptLoadingContext lcontext) : base(lcontext) { expressions = exps; } public Expression[] GetExpressions() { return expressions.ToArray(); } public override void Compile(ByteCode bc) { foreach (Expression expression in expressions) { expression.Compile(bc); } if (expressions.Count > 1) { bc.Emit_MkTuple(expressions.Count); } } public override DynValue Eval(ScriptExecutionContext context) { if (expressions.Count >= 1) { return expressions[0].Eval(context); } return DynValue.Void; } } public class IndexExpression : Expression, IVariable { public Expression m_BaseExp; public Expression m_IndexExp; public string m_Name; public IndexExpression(Expression baseExp, Expression indexExp, ScriptLoadingContext lcontext) : base(lcontext) { m_BaseExp = baseExp; m_IndexExp = indexExp; } public IndexExpression(Expression baseExp, string name, ScriptLoadingContext lcontext) : base(lcontext) { m_BaseExp = baseExp; m_Name = name; } public override void Compile(ByteCode bc) { m_BaseExp.Compile(bc); if (m_Name != null) { bc.Emit_Index(DynValue.NewString(m_Name), isNameIndex: true); } else if (m_IndexExp is LiteralExpression) { LiteralExpression literalExpression = (LiteralExpression)m_IndexExp; bc.Emit_Index(literalExpression.Value); } else { m_IndexExp.Compile(bc); bc.Emit_Index(null, isNameIndex: false, m_IndexExp is ExprListExpression); } } public void CompileAssignment(ByteCode bc, int stackofs, int tupleidx) { m_BaseExp.Compile(bc); if (m_Name != null) { bc.Emit_IndexSet(stackofs, tupleidx, DynValue.NewString(m_Name), isNameIndex: true); } else if (m_IndexExp is LiteralExpression) { LiteralExpression literalExpression = (LiteralExpression)m_IndexExp; bc.Emit_IndexSet(stackofs, tupleidx, literalExpression.Value); } else { m_IndexExp.Compile(bc); bc.Emit_IndexSet(stackofs, tupleidx, null, isNameIndex: false, m_IndexExp is ExprListExpression); } } public override DynValue Eval(ScriptExecutionContext context) { DynValue dynValue = m_BaseExp.Eval(context).ToScalar(); DynValue dynValue2 = ((m_IndexExp != null) ? m_IndexExp.Eval(context).ToScalar() : DynValue.NewString(m_Name)); if (dynValue.Type != DataType.Table) { throw new DynamicExpressionException("Attempt to index non-table."); } if (dynValue2.IsNilOrNan()) { throw new DynamicExpressionException("Attempt to index with nil or nan key."); } return dynValue.Table.Get(dynValue2) ?? DynValue.Nil; } } public class SymbolRefExpression : Expression, IVariable { public SymbolRef m_Ref; public string m_VarName; public SymbolRefExpression(Token T, ScriptLoadingContext lcontext) : base(lcontext) { m_VarName = T.Text; if (T.Type == TokenType.VarArgs) { m_Ref = lcontext.Scope.Find("..."); if (!lcontext.Scope.CurrentFunctionHasVarArgs()) { throw new SyntaxErrorException(T, "cannot use '...' outside a vararg function"); } if (lcontext.IsDynamicExpression) { throw new DynamicExpressionException("cannot use '...' in a dynamic expression."); } } else if (!lcontext.IsDynamicExpression) { m_Ref = lcontext.Scope.Find(m_VarName); } lcontext.Lexer.Next(); } public SymbolRefExpression(ScriptLoadingContext lcontext, SymbolRef refr) : base(lcontext) { m_Ref = refr; if (lcontext.IsDynamicExpression) { throw new DynamicExpressionException("Unsupported symbol reference expression detected."); } } public override void Compile(ByteCode bc) { bc.Emit_Load(m_Ref); } public void CompileAssignment(ByteCode bc, int stackofs, int tupleidx) { bc.Emit_Store(m_Ref, stackofs, tupleidx); } public override DynValue Eval(ScriptExecutionContext context) { return context.EvaluateSymbolByName(m_VarName); } public override SymbolRef FindDynamic(ScriptExecutionContext context) { return context.FindSymbolByName(m_VarName); } } public class TableConstructor : Expression { public bool m_Shared; public List m_PositionalValues = new List(); public List> m_CtorArgs = new List>(); public TableConstructor(ScriptLoadingContext lcontext, bool shared) : base(lcontext) { m_Shared = shared; NodeBase.CheckTokenType(lcontext, TokenType.Brk_Open_Curly, TokenType.Brk_Open_Curly_Shared); while (lcontext.Lexer.Current.Type != TokenType.Brk_Close_Curly) { switch (lcontext.Lexer.Current.Type) { case TokenType.Name: if (lcontext.Lexer.PeekNext().Type == TokenType.Op_Assignment) { StructField(lcontext); } else { ArrayField(lcontext); } break; case TokenType.Brk_Open_Square: MapField(lcontext); break; default: ArrayField(lcontext); break; } Token current = lcontext.Lexer.Current; if (current.Type != TokenType.Comma && current.Type != TokenType.SemiColon) { break; } lcontext.Lexer.Next(); } NodeBase.CheckTokenType(lcontext, TokenType.Brk_Close_Curly); } public void MapField(ScriptLoadingContext lcontext) { lcontext.Lexer.Next(); Expression key = Expression.Expr(lcontext); NodeBase.CheckTokenType(lcontext, TokenType.Brk_Close_Square); NodeBase.CheckTokenType(lcontext, TokenType.Op_Assignment); Expression value = Expression.Expr(lcontext); m_CtorArgs.Add(new KeyValuePair(key, value)); } public void StructField(ScriptLoadingContext lcontext) { Expression key = new LiteralExpression(lcontext, DynValue.NewString(lcontext.Lexer.Current.Text)); lcontext.Lexer.Next(); NodeBase.CheckTokenType(lcontext, TokenType.Op_Assignment); Expression value = Expression.Expr(lcontext); m_CtorArgs.Add(new KeyValuePair(key, value)); } public void ArrayField(ScriptLoadingContext lcontext) { Expression item = Expression.Expr(lcontext); m_PositionalValues.Add(item); } public override void Compile(ByteCode bc) { bc.Emit_NewTable(m_Shared); foreach (KeyValuePair ctorArg in m_CtorArgs) { ctorArg.Key.Compile(bc); ctorArg.Value.Compile(bc); bc.Emit_TblInitN(); } for (int i = 0; i < m_PositionalValues.Count; i++) { m_PositionalValues[i].Compile(bc); bc.Emit_TblInitI(i == m_PositionalValues.Count - 1); } } public override DynValue Eval(ScriptExecutionContext context) { if (!m_Shared) { throw new DynamicExpressionException("Dynamic Expressions cannot define new non-prime tables."); } DynValue dynValue = DynValue.NewPrimeTable(); Table table = dynValue.Table; int num = 0; foreach (Expression positionalValue in m_PositionalValues) { table.Set(++num, positionalValue.Eval(context)); } foreach (KeyValuePair ctorArg in m_CtorArgs) { table.Set(ctorArg.Key.Eval(context), ctorArg.Value.Eval(context)); } return dynValue; } } } namespace MoonSharp.Interpreter.Serialization { public static class ObjectValueConverter { public static DynValue SerializeObjectToDynValue(Script script, object o, DynValue valueForNulls = null) { if (o == null) { return valueForNulls ?? DynValue.Nil; } DynValue dynValue = ClrToScriptConversions.TryObjectToTrivialDynValue(script, o); if (dynValue != null) { return dynValue; } if (o is Enum) { return DynValue.NewNumber(NumericConversions.TypeToDouble(Enum.GetUnderlyingType(o.GetType()), o)); } Table table = new Table(script); if (o is IEnumerable enumerable) { foreach (object item in enumerable) { table.Append(SerializeObjectToDynValue(script, item, valueForNulls)); } } else { Type type = o.GetType(); PropertyInfo[] properties = Framework.Do.GetProperties(type); foreach (PropertyInfo propertyInfo in properties) { MethodInfo getMethod = Framework.Do.GetGetMethod(propertyInfo); object o2 = getMethod.Invoke(getMethod.IsStatic ? null : o, null); table.Set(propertyInfo.Name, SerializeObjectToDynValue(script, o2, valueForNulls)); } } return DynValue.NewTable(table); } } public static class SerializationExtensions { public static HashSet LUAKEYWORDS = new HashSet { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" }; public static string Serialize(this Table table, bool prefixReturn = false, int tabs = 0) { if (table.OwnerScript != null) { throw new ScriptRuntimeException("Table is not a prime table."); } string value = new string('\t', tabs); StringBuilder stringBuilder = new StringBuilder(); if (prefixReturn) { stringBuilder.Append("return "); } if (!table.Values.Any()) { stringBuilder.Append("${ }"); return stringBuilder.ToString(); } stringBuilder.AppendLine("${"); foreach (TablePair pair in table.Pairs) { stringBuilder.Append(value); string arg = (IsStringIdentifierValid(pair.Key) ? pair.Key.String : ("[" + pair.Key.SerializeValue(tabs + 1) + "]")); stringBuilder.AppendFormat("\t{0} = {1},\n", arg, pair.Value.SerializeValue(tabs + 1)); } stringBuilder.Append(value); stringBuilder.Append("}"); if (tabs == 0) { stringBuilder.AppendLine(); } return stringBuilder.ToString(); } public static bool IsStringIdentifierValid(DynValue dynValue) { if (dynValue.Type != DataType.String) { return false; } if (dynValue.String.Length == 0) { return false; } if (LUAKEYWORDS.Contains(dynValue.String)) { return false; } if (!char.IsLetter(dynValue.String[0]) && dynValue.String[0] != '_') { return false; } string @string = dynValue.String; foreach (char c in @string) { if (!char.IsLetterOrDigit(c) && c != '_') { return false; } } return true; } public static string SerializeValue(this DynValue dynValue, int tabs = 0) { if (dynValue.Type == DataType.Nil || dynValue.Type == DataType.Void) { return "nil"; } if (dynValue.Type == DataType.Tuple) { if (!dynValue.Tuple.Any()) { return "nil"; } return dynValue.Tuple[0].SerializeValue(tabs); } if (dynValue.Type == DataType.Number) { return dynValue.Number.ToString("r"); } if (dynValue.Type == DataType.Boolean) { if (!dynValue.Boolean) { return "false"; } return "true"; } if (dynValue.Type == DataType.String) { return EscapeString(dynValue.String ?? ""); } if (dynValue.Type == DataType.Table && dynValue.Table.OwnerScript == null) { return dynValue.Table.Serialize(prefixReturn: false, tabs); } throw new ScriptRuntimeException("Value is not a primitive value or a prime table."); } public static string EscapeString(string s) { s = s.Replace("\\", "\\\\"); s = s.Replace("\n", "\\n"); s = s.Replace("\r", "\\r"); s = s.Replace("\t", "\\t"); s = s.Replace("\a", "\\a"); s = s.Replace("\f", "\\f"); s = s.Replace("\b", "\\b"); s = s.Replace("\v", "\\v"); s = s.Replace("\"", "\\\""); s = s.Replace("'", "\\'"); return "\"" + s + "\""; } } } namespace MoonSharp.Interpreter.Serialization.Json { public sealed class JsonNull { public static bool isNull() { return true; } [MoonSharpHidden] public static bool IsJsonNull(DynValue v) { if (v.Type == DataType.UserData && v.UserData.Descriptor != null) { return v.UserData.Descriptor.Type == typeof(JsonNull); } return false; } [MoonSharpHidden] public static DynValue Create() { return UserData.CreateStatic(); } } public static class JsonTableConverter { public static string TableToJson(this Table table) { StringBuilder stringBuilder = new StringBuilder(); TableToJson(stringBuilder, table); return stringBuilder.ToString(); } public static void TableToJson(StringBuilder sb, Table table) { bool flag = true; if (table.Length == 0) { sb.Append("{"); foreach (TablePair pair in table.Pairs) { if (pair.Key.Type == DataType.String && IsValueJsonCompatible(pair.Value)) { if (!flag) { sb.Append(','); } ValueToJson(sb, pair.Key); sb.Append(':'); ValueToJson(sb, pair.Value); flag = false; } } sb.Append("}"); return; } sb.Append("["); for (int i = 1; i <= table.Length; i++) { DynValue value = table.Get(i); if (IsValueJsonCompatible(value)) { if (!flag) { sb.Append(','); } ValueToJson(sb, value); flag = false; } } sb.Append("]"); } public static string ObjectToJson(object obj) { return ObjectValueConverter.SerializeObjectToDynValue(null, obj, JsonNull.Create()).Table.TableToJson(); } public static void ValueToJson(StringBuilder sb, DynValue value) { switch (value.Type) { case DataType.Boolean: sb.Append(value.Boolean ? "true" : "false"); break; case DataType.Number: sb.Append(value.Number.ToString("r")); break; case DataType.String: sb.Append(EscapeString(value.String ?? "")); break; case DataType.Table: TableToJson(sb, value.Table); break; default: sb.Append("null"); break; } } public static string EscapeString(string s) { s = s.Replace("\\", "\\\\"); s = s.Replace("/", "\\/"); s = s.Replace("\"", "\\\""); s = s.Replace("\f", "\\f"); s = s.Replace("\b", "\\b"); s = s.Replace("\n", "\\n"); s = s.Replace("\r", "\\r"); s = s.Replace("\t", "\\t"); return "\"" + s + "\""; } public static bool IsValueJsonCompatible(DynValue value) { if (value.Type != DataType.Boolean && !value.IsNil() && value.Type != DataType.Number && value.Type != DataType.String && value.Type != DataType.Table) { return JsonNull.IsJsonNull(value); } return true; } public static Table JsonToTable(string json, Script script = null) { Lexer lexer = new Lexer(0, json, autoSkipComments: false); if (lexer.Current.Type == TokenType.Brk_Open_Curly) { return ParseJsonObject(lexer, script); } if (lexer.Current.Type == TokenType.Brk_Open_Square) { return ParseJsonArray(lexer, script); } throw new SyntaxErrorException(lexer.Current, "Unexpected token : '{0}'", lexer.Current.Text); } public static void AssertToken(Lexer L, TokenType type) { if (L.Current.Type != type) { throw new SyntaxErrorException(L.Current, "Unexpected token : '{0}'", L.Current.Text); } } public static Table ParseJsonArray(Lexer L, Script script) { Table table = new Table(script); L.Next(); while (L.Current.Type != TokenType.Brk_Close_Square) { DynValue value = ParseJsonValue(L, script); table.Append(value); L.Next(); if (L.Current.Type == TokenType.Comma) { L.Next(); } } return table; } public static Table ParseJsonObject(Lexer L, Script script) { Table table = new Table(script); L.Next(); while (L.Current.Type != TokenType.Brk_Close_Curly) { AssertToken(L, TokenType.String); string text = L.Current.Text; L.Next(); AssertToken(L, TokenType.Colon); L.Next(); DynValue value = ParseJsonValue(L, script); table.Set(text, value); L.Next(); if (L.Current.Type == TokenType.Comma) { L.Next(); } } return table; } public static DynValue ParseJsonValue(Lexer L, Script script) { if (L.Current.Type == TokenType.Brk_Open_Curly) { return DynValue.NewTable(ParseJsonObject(L, script)); } if (L.Current.Type == TokenType.Brk_Open_Square) { return DynValue.NewTable(ParseJsonArray(L, script)); } if (L.Current.Type == TokenType.String) { return DynValue.NewString(L.Current.Text); } if (L.Current.Type == TokenType.Number) { return DynValue.NewNumber(L.Current.GetNumberValue()).AsReadOnly(); } if (L.Current.Type == TokenType.True) { return DynValue.True; } if (L.Current.Type == TokenType.False) { return DynValue.False; } if (L.Current.Type == TokenType.Name && L.Current.Text == "null") { return JsonNull.Create(); } throw new SyntaxErrorException(L.Current, "Unexpected token : '{0}'", L.Current.Text); } } } namespace MoonSharp.Interpreter.Platforms { public static class NamespaceDoc { } public interface IPlatformAccessor { CoreModules FilterSupportedCoreModules(CoreModules module); string GetEnvironmentVariable(string envvarname); bool IsRunningOnAOT(); string GetPlatformName(); void DefaultPrint(string content); string DefaultInput(string prompt); Stream IO_OpenFile(Script script, string filename, Encoding encoding, string mode); Stream IO_GetStandardStream(StandardFileType type); string IO_OS_GetTempFilename(); void OS_ExitFast(int exitCode); bool OS_FileExists(string file); void OS_FileDelete(string file); void OS_FileMove(string src, string dst); int OS_Execute(string cmdline); } public abstract class PlatformAccessorBase : IPlatformAccessor { public abstract string GetPlatformNamePrefix(); public string GetPlatformName() { string text = null; text = (PlatformAutoDetector.IsRunningOnUnity ? (PlatformAutoDetector.IsUnityNative ? ("unity." + GetUnityPlatformName().ToLower() + "." + GetUnityRuntimeName()) : ((!PlatformAutoDetector.IsRunningOnMono) ? "unity.dll.unknown" : "unity.dll.mono")) : ((!PlatformAutoDetector.IsRunningOnMono) ? "dotnet" : "mono")); if (PlatformAutoDetector.IsPortableFramework) { text += ".portable"; } text = ((!PlatformAutoDetector.IsRunningOnClr4) ? (text + ".clr2") : (text + ".clr4")); if (PlatformAutoDetector.IsRunningOnAOT) { text += ".aot"; } return GetPlatformNamePrefix() + "." + text; } public string GetUnityRuntimeName() { return "unknown"; } public string GetUnityPlatformName() { return "UNKNOWNHW"; } public abstract void DefaultPrint(string content); [Obsolete("Replace with DefaultInput(string)")] public virtual string DefaultInput() { return null; } public virtual string DefaultInput(string prompt) { return DefaultInput(); } public abstract Stream IO_OpenFile(Script script, string filename, Encoding encoding, string mode); public abstract Stream IO_GetStandardStream(StandardFileType type); public abstract string IO_OS_GetTempFilename(); public abstract void OS_ExitFast(int exitCode); public abstract bool OS_FileExists(string file); public abstract void OS_FileDelete(string file); public abstract void OS_FileMove(string src, string dst); public abstract int OS_Execute(string cmdline); public abstract CoreModules FilterSupportedCoreModules(CoreModules module); public abstract string GetEnvironmentVariable(string envvarname); public virtual bool IsRunningOnAOT() { return PlatformAutoDetector.IsRunningOnAOT; } public PlatformAccessorBase() { } } public static class PlatformAutoDetector { public static bool? m_IsRunningOnAOT; public static bool m_AutoDetectionsDone; public static bool IsRunningOnMono { get; set; } public static bool IsRunningOnClr4 { get; set; } public static bool IsRunningOnUnity { get; set; } public static bool IsPortableFramework { get; set; } public static bool IsUnityNative { get; set; } public static bool IsUnityIL2CPP { get; set; } public static bool IsRunningOnAOT { get { if (!m_IsRunningOnAOT.HasValue) { try { ((Expression>)(() => 5)).Compile(); m_IsRunningOnAOT = false; } catch (Exception) { m_IsRunningOnAOT = true; } } return m_IsRunningOnAOT.Value; } } public static void AutoDetectPlatformFlags() { if (!m_AutoDetectionsDone) { IsRunningOnUnity = AppDomain.CurrentDomain.GetAssemblies().SelectMany((Assembly a) => a.SafeGetTypes()).Any((Type t) => t.FullName.StartsWith("UnityEngine.")); IsRunningOnMono = Type.GetType("Mono.Runtime") != null; IsRunningOnClr4 = Type.GetType("System.Lazy`1") != null; m_AutoDetectionsDone = true; } } public static IPlatformAccessor GetDefaultPlatform() { AutoDetectPlatformFlags(); if (IsRunningOnUnity) { return new LimitedPlatformAccessor(); } return new StandardPlatformAccessor(); } public static IScriptLoader GetDefaultScriptLoader() { AutoDetectPlatformFlags(); if (IsRunningOnUnity) { return new UnityAssetsScriptLoader(); } return new FileSystemScriptLoader(); } } public class LimitedPlatformAccessor : PlatformAccessorBase { public override string GetEnvironmentVariable(string envvarname) { return null; } public override CoreModules FilterSupportedCoreModules(CoreModules module) { return module & ~(CoreModules.OS_System | CoreModules.IO); } public override Stream IO_OpenFile(Script script, string filename, Encoding encoding, string mode) { throw new NotImplementedException("The current platform accessor does not support 'io' and 'os' operations. Provide your own implementation of platform to work around this limitation, if needed."); } public override Stream IO_GetStandardStream(StandardFileType type) { throw new NotImplementedException("The current platform accessor does not support 'io' and 'os' operations. Provide your own implementation of platform to work around this limitation, if needed."); } public override string IO_OS_GetTempFilename() { throw new NotImplementedException("The current platform accessor does not support 'io' and 'os' operations. Provide your own implementation of platform to work around this limitation, if needed."); } public override void OS_ExitFast(int exitCode) { throw new NotImplementedException("The current platform accessor does not support 'io' and 'os' operations. Provide your own implementation of platform to work around this limitation, if needed."); } public override bool OS_FileExists(string file) { throw new NotImplementedException("The current platform accessor does not support 'io' and 'os' operations. Provide your own implementation of platform to work around this limitation, if needed."); } public override void OS_FileDelete(string file) { throw new NotImplementedException("The current platform accessor does not support 'io' and 'os' operations. Provide your own implementation of platform to work around this limitation, if needed."); } public override void OS_FileMove(string src, string dst) { throw new NotImplementedException("The current platform accessor does not support 'io' and 'os' operations. Provide your own implementation of platform to work around this limitation, if needed."); } public override int OS_Execute(string cmdline) { throw new NotImplementedException("The current platform accessor does not support 'io' and 'os' operations. Provide your own implementation of platform to work around this limitation, if needed."); } public override string GetPlatformNamePrefix() { return "limited"; } public override void DefaultPrint(string content) { } } public enum StandardFileType { StdIn, StdOut, StdErr } public class StandardPlatformAccessor : PlatformAccessorBase { public static FileAccess ParseFileAccess(string mode) { mode = mode.Replace("b", ""); switch (mode) { case "r": return FileAccess.Read; case "r+": return FileAccess.ReadWrite; case "w": return FileAccess.Write; default: _ = mode == "w+"; return FileAccess.ReadWrite; } } public static FileMode ParseFileMode(string mode) { mode = mode.Replace("b", ""); return mode switch { "r" => FileMode.Open, "r+" => FileMode.OpenOrCreate, "w" => FileMode.Create, "w+" => FileMode.Truncate, _ => FileMode.Append, }; } public override Stream IO_OpenFile(Script script, string filename, Encoding encoding, string mode) { return new FileStream(filename, ParseFileMode(mode), ParseFileAccess(mode), FileShare.ReadWrite | FileShare.Delete); } public override string GetEnvironmentVariable(string envvarname) { return Environment.GetEnvironmentVariable(envvarname); } public override Stream IO_GetStandardStream(StandardFileType type) { return type switch { StandardFileType.StdIn => Console.OpenStandardInput(), StandardFileType.StdOut => Console.OpenStandardOutput(), StandardFileType.StdErr => Console.OpenStandardError(), _ => throw new ArgumentException("type"), }; } public override void DefaultPrint(string content) { Console.WriteLine(content); } public override string IO_OS_GetTempFilename() { return Path.GetTempFileName(); } public override void OS_ExitFast(int exitCode) { Environment.Exit(exitCode); } public override bool OS_FileExists(string file) { return File.Exists(file); } public override void OS_FileDelete(string file) { File.Delete(file); } public override void OS_FileMove(string src, string dst) { File.Move(src, dst); } public override int OS_Execute(string cmdline) { Process? process = Process.Start(new ProcessStartInfo("cmd.exe", $"/C {cmdline}") { ErrorDialog = false }); process.WaitForExit(); return process.ExitCode; } public override CoreModules FilterSupportedCoreModules(CoreModules module) { return module; } public override string GetPlatformNamePrefix() { return "std"; } } } namespace MoonSharp.Interpreter.REPL { public class ReplHistoryInterpreter : ReplInterpreter { public string[] m_History; public int m_Last = -1; public int m_Navi = -1; public ReplHistoryInterpreter(Script script, int historySize) : base(script) { m_History = new string[historySize]; } public override DynValue Evaluate(string input) { m_Navi = -1; m_Last = (m_Last + 1) % m_History.Length; m_History[m_Last] = input; return base.Evaluate(input); } public string HistoryPrev() { if (m_Navi == -1) { m_Navi = m_Last; } else { m_Navi = (m_Navi - 1 + m_History.Length) % m_History.Length; } if (m_Navi >= 0) { return m_History[m_Navi]; } return null; } public string HistoryNext() { if (m_Navi == -1) { return null; } m_Navi = (m_Navi + 1) % m_History.Length; if (m_Navi >= 0) { return m_History[m_Navi]; } return null; } } public class ReplInterpreterScriptLoader : FileSystemScriptLoader { public ReplInterpreterScriptLoader() { string environmentVariable = Environment.GetEnvironmentVariable("MOONSHARP_PATH"); if (!string.IsNullOrEmpty(environmentVariable)) { base.ModulePaths = ScriptLoaderBase.UnpackStringPaths(environmentVariable); } if (base.ModulePaths == null) { environmentVariable = Environment.GetEnvironmentVariable("LUA_PATH_5_2"); if (!string.IsNullOrEmpty(environmentVariable)) { base.ModulePaths = ScriptLoaderBase.UnpackStringPaths(environmentVariable); } } if (base.ModulePaths == null) { environmentVariable = Environment.GetEnvironmentVariable("LUA_PATH"); if (!string.IsNullOrEmpty(environmentVariable)) { base.ModulePaths = ScriptLoaderBase.UnpackStringPaths(environmentVariable); } } if (base.ModulePaths == null) { base.ModulePaths = ScriptLoaderBase.UnpackStringPaths("?;?.lua"); } } public override string ResolveModuleName(string modname, Table globalContext) { DynValue dynValue = globalContext.RawGet("LUA_PATH"); if (dynValue != null && dynValue.Type == DataType.String) { return ResolveModuleName(modname, ScriptLoaderBase.UnpackStringPaths(dynValue.String)); } return base.ResolveModuleName(modname, globalContext); } } public static class NamespaceDoc { } public class ReplInterpreter { public Script m_Script; public string m_CurrentCommand = string.Empty; public bool HandleDynamicExprs { get; set; } public bool HandleClassicExprsSyntax { get; set; } public virtual bool HasPendingCommand => m_CurrentCommand.Length > 0; public virtual string CurrentPendingCommand => m_CurrentCommand; public virtual string ClassicPrompt { get { if (!HasPendingCommand) { return ">"; } return ">>"; } } public ReplInterpreter(Script script) { m_Script = script; } public virtual DynValue Evaluate(string input) { bool flag = !HasPendingCommand; bool flag2 = input == ""; m_CurrentCommand += input; if (m_CurrentCommand.Length == 0) { return DynValue.Void; } m_CurrentCommand += "\n"; try { DynValue dynValue = null; if (flag && HandleClassicExprsSyntax && m_CurrentCommand.StartsWith("=")) { m_CurrentCommand = "return " + m_CurrentCommand.Substring(1); } if (flag && HandleDynamicExprs && m_CurrentCommand.StartsWith("?")) { string code = m_CurrentCommand.Substring(1); dynValue = m_Script.CreateDynamicExpression(code).Evaluate(); } else { DynValue function = m_Script.LoadString(m_CurrentCommand, null, "stdin"); dynValue = m_Script.Call(function); } m_CurrentCommand = ""; return dynValue; } catch (SyntaxErrorException ex) { if (flag2 || !ex.IsPrematureStreamTermination) { m_CurrentCommand = ""; ex.Rethrow(); throw; } return null; } catch (ScriptRuntimeException ex2) { m_CurrentCommand = ""; ex2.Rethrow(); throw; } catch (Exception) { m_CurrentCommand = ""; throw; } } } } namespace MoonSharp.Interpreter.Loaders { public class EmbeddedResourcesScriptLoader : ScriptLoaderBase { public Assembly m_ResourceAssembly; public HashSet m_ResourceNames; public string m_Namespace; public EmbeddedResourcesScriptLoader(Assembly resourceAssembly = null) { if (resourceAssembly == null) { resourceAssembly = Assembly.GetCallingAssembly(); } m_ResourceAssembly = resourceAssembly; m_Namespace = m_ResourceAssembly.FullName.Split(new char[1] { ',' }).First(); m_ResourceNames = new HashSet(m_ResourceAssembly.GetManifestResourceNames()); } public string FileNameToResource(string file) { file = file.Replace('/', '.'); file = file.Replace('\\', '.'); return m_Namespace + "." + file; } public override bool ScriptFileExists(string name) { name = FileNameToResource(name); return m_ResourceNames.Contains(name); } public override object LoadFile(string file, Table globalContext) { file = FileNameToResource(file); return m_ResourceAssembly.GetManifestResourceStream(file); } } public class FileSystemScriptLoader : ScriptLoaderBase { public override bool ScriptFileExists(string name) { return File.Exists(name); } public override object LoadFile(string file, Table globalContext) { return new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); } } public class InvalidScriptLoader : IScriptLoader { public string m_Error; public InvalidScriptLoader(string frameworkname) { m_Error = $"Loading scripts from files is not automatically supported on {frameworkname}. \nPlease implement your own IScriptLoader (possibly, extending ScriptLoaderBase for easier implementation),\nuse a preexisting loader like EmbeddedResourcesScriptLoader or UnityAssetsScriptLoader or load scripts from strings."; } public object LoadFile(string file, Table globalContext) { throw new PlatformNotSupportedException(m_Error); } public string ResolveFileName(string filename, Table globalContext) { return filename; } public string ResolveModuleName(string modname, Table globalContext) { throw new PlatformNotSupportedException(m_Error); } } public abstract class ScriptLoaderBase : IScriptLoader { public string[] ModulePaths { get; set; } public bool IgnoreLuaPathGlobal { get; set; } public abstract bool ScriptFileExists(string name); public abstract object LoadFile(string file, Table globalContext); public virtual string ResolveModuleName(string modname, string[] paths) { if (paths == null) { return null; } modname = modname.Replace('.', '/'); for (int i = 0; i < paths.Length; i++) { string text = paths[i].Replace("?", modname); if (ScriptFileExists(text)) { return text; } } return null; } public virtual string ResolveModuleName(string modname, Table globalContext) { if (!IgnoreLuaPathGlobal) { DynValue dynValue = globalContext.RawGet("LUA_PATH"); if (dynValue != null && dynValue.Type == DataType.String) { return ResolveModuleName(modname, UnpackStringPaths(dynValue.String)); } } return ResolveModuleName(modname, ModulePaths); } public static string[] UnpackStringPaths(string str) { return (from s in str.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim() into s where !string.IsNullOrEmpty(s) select s).ToArray(); } public static string[] GetDefaultEnvironmentPaths() { string[] array = null; if (array == null) { string environmentVariable = Script.GlobalOptions.Platform.GetEnvironmentVariable("MOONSHARP_PATH"); if (!string.IsNullOrEmpty(environmentVariable)) { array = UnpackStringPaths(environmentVariable); } if (array == null) { environmentVariable = Script.GlobalOptions.Platform.GetEnvironmentVariable("LUA_PATH"); if (!string.IsNullOrEmpty(environmentVariable)) { array = UnpackStringPaths(environmentVariable); } } if (array == null) { array = UnpackStringPaths("?;?.lua"); } } return array; } public virtual string ResolveFileName(string filename, Table globalContext) { return filename; } public ScriptLoaderBase() { } } public interface IScriptLoader { object LoadFile(string file, Table globalContext); [Obsolete("This serves almost no purpose. Kept here just to preserve backward compatibility.")] string ResolveFileName(string filename, Table globalContext); string ResolveModuleName(string modname, Table globalContext); } public class UnityAssetsScriptLoader : ScriptLoaderBase { public Dictionary m_Resources = new Dictionary(); public const string DEFAULT_PATH = "MoonSharp/Scripts"; public UnityAssetsScriptLoader(string assetsPath = null) { assetsPath = assetsPath ?? "MoonSharp/Scripts"; LoadResourcesWithReflection(assetsPath); } public UnityAssetsScriptLoader(Dictionary scriptToCodeMap) { m_Resources = scriptToCodeMap; } public void LoadResourcesWithReflection(string assetsPath) { try { Type type = Type.GetType("UnityEngine.Resources, UnityEngine"); Type type2 = Type.GetType("UnityEngine.TextAsset, UnityEngine"); MethodInfo getMethod = Framework.Do.GetGetMethod(Framework.Do.GetProperty(type2, "name")); MethodInfo getMethod2 = Framework.Do.GetGetMethod(Framework.Do.GetProperty(type2, "text")); Array array = (Array)Framework.Do.GetMethod(type, "LoadAll", new Type[2] { typeof(string), typeof(Type) }).Invoke(null, new object[2] { assetsPath, type2 }); for (int i = 0; i < array.Length; i++) { object value = array.GetValue(i); string key = getMethod.Invoke(value, null) as string; string value2 = getMethod2.Invoke(value, null) as string; m_Resources.Add(key, value2); } } catch (Exception arg) { Console.WriteLine("Error initializing UnityScriptLoader : {0}", arg); } } public string GetFileName(string filename) { int num = Math.Max(filename.LastIndexOf('\\'), filename.LastIndexOf('/')); if (num > 0) { filename = filename.Substring(num + 1); } return filename; } public override object LoadFile(string file, Table globalContext) { file = GetFileName(file); if (m_Resources.ContainsKey(file)) { return m_Resources[file]; } throw new Exception(string.Format("Cannot load script '{0}'. By default, scripts should be .txt files placed under a Assets/Resources/{1} directory.\r\nIf you want scripts to be put in another directory or another way, use a custom instance of UnityAssetsScriptLoader or implement\r\nyour own IScriptLoader (possibly extending ScriptLoaderBase).", file, "MoonSharp/Scripts")); } public override bool ScriptFileExists(string file) { file = GetFileName(file); return m_Resources.ContainsKey(file); } public string[] GetLoadedScripts() { return m_Resources.Keys.ToArray(); } } public static class NamespaceDoc { } } namespace MoonSharp.Interpreter.Diagnostics { public enum PerformanceCounter { AstCreation, Compilation, Execution, AdaptersCompilation, LastValue } public enum PerformanceCounterType { MemoryBytes, TimeMilliseconds } public class PerformanceStatistics { public IPerformanceStopwatch[] m_Stopwatches = new IPerformanceStopwatch[4]; public static IPerformanceStopwatch[] m_GlobalStopwatches = new IPerformanceStopwatch[4]; public bool m_Enabled; public bool Enabled { get { return m_Enabled; } set { if (value && !m_Enabled) { if (m_GlobalStopwatches[3] == null) { m_GlobalStopwatches[3] = new GlobalPerformanceStopwatch(PerformanceCounter.AdaptersCompilation); } for (int i = 0; i < 4; i++) { m_Stopwatches[i] = m_GlobalStopwatches[i] ?? new PerformanceStopwatch((PerformanceCounter)i); } } else if (!value && m_Enabled) { m_Stopwatches = new IPerformanceStopwatch[4]; m_GlobalStopwatches = new IPerformanceStopwatch[4]; } m_Enabled = value; } } public PerformanceResult GetPerformanceCounterResult(PerformanceCounter pc) { return m_Stopwatches[(int)pc]?.GetResult(); } public IDisposable StartStopwatch(PerformanceCounter pc) { return m_Stopwatches[(int)pc]?.Start(); } public static IDisposable StartGlobalStopwatch(PerformanceCounter pc) { return m_GlobalStopwatches[(int)pc]?.Start(); } public string GetPerformanceLog() { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < 4; i++) { PerformanceResult performanceCounterResult = GetPerformanceCounterResult((PerformanceCounter)i); if (performanceCounterResult != null) { stringBuilder.AppendLine(performanceCounterResult.ToString()); } } return stringBuilder.ToString(); } } public class PerformanceResult { public string Name { get; set; } public long Counter { get; set; } public int Instances { get; set; } public bool Global { get; set; } public PerformanceCounterType Type { get; set; } public override string ToString() { return string.Format("{0}{1} : {2} times / {3} {4}", Name, Global ? "(g)" : "", Instances, Counter, PerformanceCounterTypeToString(Type)); } public static string PerformanceCounterTypeToString(PerformanceCounterType Type) { return Type switch { PerformanceCounterType.MemoryBytes => "bytes", PerformanceCounterType.TimeMilliseconds => "ms", _ => throw new InvalidOperationException("PerformanceCounterType has invalid value " + Type), }; } } public static class NamespaceDoc { } } namespace MoonSharp.Interpreter.Diagnostics.PerformanceCounters { public class DummyPerformanceStopwatch : IPerformanceStopwatch, IDisposable { public static DummyPerformanceStopwatch Instance = new DummyPerformanceStopwatch(); public PerformanceResult m_Result; public DummyPerformanceStopwatch() { m_Result = new PerformanceResult { Counter = 0L, Global = true, Instances = 0, Name = "::dummy::", Type = PerformanceCounterType.TimeMilliseconds }; } public IDisposable Start() { return this; } public PerformanceResult GetResult() { return m_Result; } public void Dispose() { } } public interface IPerformanceStopwatch { IDisposable Start(); PerformanceResult GetResult(); } public class GlobalPerformanceStopwatch : IPerformanceStopwatch { public class GlobalPerformanceStopwatch_StopwatchObject : IDisposable { public Stopwatch m_Stopwatch; public GlobalPerformanceStopwatch m_Parent; public GlobalPerformanceStopwatch_StopwatchObject(GlobalPerformanceStopwatch parent) { m_Parent = parent; m_Stopwatch = Stopwatch.StartNew(); } public void Dispose() { m_Stopwatch.Stop(); m_Parent.SignalStopwatchTerminated(m_Stopwatch); } } public int m_Count; public long m_Elapsed; public PerformanceCounter m_Counter; public GlobalPerformanceStopwatch(PerformanceCounter perfcounter) { m_Counter = perfcounter; } public void SignalStopwatchTerminated(Stopwatch sw) { m_Elapsed += sw.ElapsedMilliseconds; m_Count++; } public IDisposable Start() { return new GlobalPerformanceStopwatch_StopwatchObject(this); } public PerformanceResult GetResult() { return new PerformanceResult { Type = PerformanceCounterType.TimeMilliseconds, Global = false, Name = m_Counter.ToString(), Instances = m_Count, Counter = m_Elapsed }; } } public class PerformanceStopwatch : IDisposable, IPerformanceStopwatch { public Stopwatch m_Stopwatch = new Stopwatch(); public int m_Count; public int m_Reentrant; public PerformanceCounter m_Counter; public PerformanceStopwatch(PerformanceCounter perfcounter) { m_Counter = perfcounter; } public IDisposable Start() { if (m_Reentrant == 0) { m_Count++; m_Stopwatch.Start(); } m_Reentrant++; return this; } public void Dispose() { m_Reentrant--; if (m_Reentrant == 0) { m_Stopwatch.Stop(); } } public PerformanceResult GetResult() { return new PerformanceResult { Type = PerformanceCounterType.TimeMilliseconds, Global = false, Name = m_Counter.ToString(), Instances = m_Count, Counter = m_Stopwatch.ElapsedMilliseconds }; } } } namespace MoonSharp.Interpreter.IO { public class BinDumpBinaryReader : BinaryReader { public List m_Strings = new List(); public BinDumpBinaryReader(Stream s) : base(s) { } public BinDumpBinaryReader(Stream s, Encoding e) : base(s, e) { } public override int ReadInt32() { sbyte b = base.ReadSByte(); return b switch { sbyte.MaxValue => base.ReadInt16(), 126 => base.ReadInt32(), _ => b, }; } public override uint ReadUInt32() { byte b = base.ReadByte(); return b switch { 127 => base.ReadUInt16(), 126 => base.ReadUInt32(), _ => b, }; } public override string ReadString() { int num = ReadInt32(); if (num < m_Strings.Count) { return m_Strings[num]; } if (num == m_Strings.Count) { string text = base.ReadString(); m_Strings.Add(text); return text; } throw new IOException("string map failure"); } } public class BinDumpBinaryWriter : BinaryWriter { public Dictionary m_StringMap = new Dictionary(); public BinDumpBinaryWriter(Stream s) : base(s) { } public BinDumpBinaryWriter(Stream s, Encoding e) : base(s, e) { } public override void Write(uint value) { byte b = (byte)value; if (b == value && b != 127 && b != 126) { base.Write(b); return; } ushort num = (ushort)value; if (num == value) { base.Write((byte)127); base.Write(num); } else { base.Write((byte)126); base.Write(value); } } public override void Write(int value) { sbyte b = (sbyte)value; if (b == value && b != sbyte.MaxValue && b != 126) { base.Write(b); return; } short num = (short)value; if (num == value) { base.Write(sbyte.MaxValue); base.Write(num); } else { base.Write((sbyte)126); base.Write(value); } } public override void Write(string value) { if (m_StringMap.TryGetValue(value, out var value2)) { Write(m_StringMap[value]); return; } value2 = m_StringMap.Count; m_StringMap[value] = value2; Write(value2); base.Write(value); } } public class UndisposableStream : Stream { public Stream m_Stream; public override bool CanRead => m_Stream.CanRead; public override bool CanSeek => m_Stream.CanSeek; public override bool CanWrite => m_Stream.CanWrite; public override long Length => m_Stream.Length; public override long Position { get { return m_Stream.Position; } set { m_Stream.Position = value; } } public override bool CanTimeout => m_Stream.CanTimeout; public override int ReadTimeout { get { return m_Stream.ReadTimeout; } set { m_Stream.ReadTimeout = value; } } public override int WriteTimeout { get { return m_Stream.WriteTimeout; } set { m_Stream.WriteTimeout = value; } } public UndisposableStream(Stream stream) { m_Stream = stream; } public override void Dispose(bool disposing) { } public override void Close() { } public override void Flush() { m_Stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { return m_Stream.Read(buffer, offset, count); } public override long Seek(long offset, SeekOrigin origin) { return m_Stream.Seek(offset, origin); } public override void SetLength(long value) { m_Stream.SetLength(value); } public override void Write(byte[] buffer, int offset, int count) { m_Stream.Write(buffer, offset, count); } public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return m_Stream.BeginRead(buffer, offset, count, callback, state); } public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { return m_Stream.BeginWrite(buffer, offset, count, callback, state); } public override void EndWrite(IAsyncResult asyncResult) { m_Stream.EndWrite(asyncResult); } public override int EndRead(IAsyncResult asyncResult) { return m_Stream.EndRead(asyncResult); } public override bool Equals(object obj) { return m_Stream.Equals(obj); } public override int GetHashCode() { return m_Stream.GetHashCode(); } public override int ReadByte() { return m_Stream.ReadByte(); } public override string ToString() { return m_Stream.ToString(); } public override void WriteByte(byte value) { m_Stream.WriteByte(value); } } } namespace MoonSharp.Interpreter.Interop { public class CustomConvertersCollection { public Dictionary>[] m_Script2Clr = new Dictionary>[11]; public Dictionary> m_Clr2Script = new Dictionary>(); public CustomConvertersCollection() { for (int i = 0; i < m_Script2Clr.Length; i++) { m_Script2Clr[i] = new Dictionary>(); } } public void SetScriptToClrCustomConversion(DataType scriptDataType, Type clrDataType, Func converter = null) { if ((int)scriptDataType > m_Script2Clr.Length) { throw new ArgumentException("scriptDataType"); } Dictionary> dictionary = m_Script2Clr[(int)scriptDataType]; if (converter == null) { if (dictionary.ContainsKey(clrDataType)) { dictionary.Remove(clrDataType); } } else { dictionary[clrDataType] = converter; } } public Func GetScriptToClrCustomConversion(DataType scriptDataType, Type clrDataType) { if ((int)scriptDataType > m_Script2Clr.Length) { return null; } return m_Script2Clr[(int)scriptDataType].GetOrDefault(clrDataType); } public void SetClrToScriptCustomConversion(Type clrDataType, Func converter = null) { if (converter == null) { if (m_Clr2Script.ContainsKey(clrDataType)) { m_Clr2Script.Remove(clrDataType); } } else { m_Clr2Script[clrDataType] = converter; } } public void SetClrToScriptCustomConversion(Func converter = null) { SetClrToScriptCustomConversion(typeof(T), (Script s, object o) => converter(s, (T)o)); } public Func GetClrToScriptCustomConversion(Type clrDataType) { return m_Clr2Script.GetOrDefault(clrDataType); } [Obsolete("This method is deprecated. Use the overloads accepting functions with a Script argument.")] public void SetClrToScriptCustomConversion(Type clrDataType, Func converter = null) { SetClrToScriptCustomConversion(clrDataType, (Script s, object o) => converter(o)); } [Obsolete("This method is deprecated. Use the overloads accepting functions with a Script argument.")] public void SetClrToScriptCustomConversion(Func converter = null) { SetClrToScriptCustomConversion(typeof(T), (object o) => converter((T)o)); } public void Clear() { m_Clr2Script.Clear(); for (int i = 0; i < m_Script2Clr.Length; i++) { m_Script2Clr[i].Clear(); } } } public static class DescriptorHelpers { public static bool? GetVisibilityFromAttributes(this MemberInfo mi) { if (mi == null) { return false; } MoonSharpVisibleAttribute moonSharpVisibleAttribute = mi.GetCustomAttributes(inherit: true).OfType().SingleOrDefault(); MoonSharpHiddenAttribute moonSharpHiddenAttribute = mi.GetCustomAttributes(inherit: true).OfType().SingleOrDefault(); if (moonSharpVisibleAttribute != null && moonSharpHiddenAttribute != null && moonSharpVisibleAttribute.Visible) { throw new InvalidOperationException($"A member ('{mi.Name}') can't have discording MoonSharpHiddenAttribute and MoonSharpVisibleAttribute."); } if (moonSharpHiddenAttribute != null) { return false; } return moonSharpVisibleAttribute?.Visible; } public static bool IsDelegateType(this Type t) { return Framework.Do.IsAssignableFrom(typeof(Delegate), t); } public static string GetClrVisibility(this Type type) { if (type.IsPublic || type.IsNestedPublic) { return "public"; } if ((type.IsNotPublic && !type.IsNested) || type.IsNestedAssembly) { return "internal"; } if (type.IsNestedFamORAssem) { return "protected-internal"; } if (type.IsNestedFamANDAssem || type.IsNestedFamily) { return "protected"; } if (type.IsNestedPrivate) { return "private"; } return "unknown"; } public static string GetClrVisibility(this FieldInfo info) { if (info.IsPublic) { return "public"; } if (info.IsAssembly) { return "internal"; } if (info.IsFamilyOrAssembly) { return "protected-internal"; } if (info.IsFamilyAndAssembly || info.IsFamily) { return "protected"; } if (info.IsPrivate) { return "private"; } return "unknown"; } public static string GetClrVisibility(this PropertyInfo info) { MethodInfo getMethod = Framework.Do.GetGetMethod(info); MethodInfo setMethod = Framework.Do.GetSetMethod(info); string text = ((getMethod != null) ? getMethod.GetClrVisibility() : "private"); string text2 = ((setMethod != null) ? setMethod.GetClrVisibility() : "private"); if (text == "public" || text2 == "public") { return "public"; } if (text == "internal" || text2 == "internal") { return "internal"; } return text; } public static string GetClrVisibility(this MethodBase info) { if (info.IsPublic) { return "public"; } if (info.IsAssembly) { return "internal"; } if (info.IsFamilyOrAssembly) { return "protected-internal"; } if (info.IsFamilyAndAssembly || info.IsFamily) { return "protected"; } if (info.IsPrivate) { return "private"; } return "unknown"; } public static bool IsPropertyInfoPublic(this PropertyInfo pi) { MethodInfo getMethod = Framework.Do.GetGetMethod(pi); MethodInfo setMethod = Framework.Do.GetSetMethod(pi); if (!(getMethod != null) || !getMethod.IsPublic) { if (setMethod != null) { return setMethod.IsPublic; } return false; } return true; } public static List GetMetaNamesFromAttributes(this MethodInfo mi) { return (from a in mi.GetCustomAttributes(typeof(MoonSharpUserDataMetamethodAttribute), inherit: true).OfType() select a.Name).ToList(); } public static Type[] SafeGetTypes(this Assembly asm) { try { return Framework.Do.GetAssemblyTypes(asm); } catch (ReflectionTypeLoadException) { return new Type[0]; } } public static string GetConversionMethodName(this Type type) { StringBuilder stringBuilder = new StringBuilder(type.Name); for (int i = 0; i < stringBuilder.Length; i++) { if (!char.IsLetterOrDigit(stringBuilder[i])) { stringBuilder[i] = '_'; } } return "__to" + stringBuilder.ToString(); } public static IEnumerable GetAllImplementedTypes(this Type t) { Type ot = t; while (ot != null) { yield return ot; ot = Framework.Do.GetBaseType(ot); } Type[] interfaces = Framework.Do.GetInterfaces(t); for (int i = 0; i < interfaces.Length; i++) { yield return interfaces[i]; } } public static bool IsValidSimpleIdentifier(string str) { if (string.IsNullOrEmpty(str)) { return false; } if (str[0] != '_' && !char.IsLetter(str[0])) { return false; } for (int i = 1; i < str.Length; i++) { if (str[i] != '_' && !char.IsLetterOrDigit(str[i])) { return false; } } return true; } public static string ToValidSimpleIdentifier(string str) { if (string.IsNullOrEmpty(str)) { return "_"; } if (str[0] != '_' && !char.IsLetter(str[0])) { str = "_" + str; } StringBuilder stringBuilder = new StringBuilder(str); for (int i = 0; i < stringBuilder.Length; i++) { if (stringBuilder[i] != '_' && !char.IsLetterOrDigit(stringBuilder[i])) { stringBuilder[i] = '_'; } } return stringBuilder.ToString(); } public static string Camelify(string name) { StringBuilder stringBuilder = new StringBuilder(name.Length); bool flag = false; for (int i = 0; i < name.Length; i++) { if (name[i] == '_' && i != 0) { flag = true; continue; } if (flag) { stringBuilder.Append(char.ToUpperInvariant(name[i])); } else { stringBuilder.Append(name[i]); } flag = false; } return stringBuilder.ToString(); } public static string UpperFirstLetter(string name) { if (!string.IsNullOrEmpty(name)) { return char.ToUpperInvariant(name[0]) + name.Substring(1); } return name; } } public interface IGeneratorUserDataDescriptor : IUserDataDescriptor { IUserDataDescriptor Generate(Type type); } public class PropertyTableAssigner : IPropertyTableAssigner { public PropertyTableAssigner m_InternalAssigner; public PropertyTableAssigner(params string[] expectedMissingProperties) { m_InternalAssigner = new PropertyTableAssigner(typeof(T), expectedMissingProperties); } public void AddExpectedMissingProperty(string name) { m_InternalAssigner.AddExpectedMissingProperty(name); } public void AssignObject(T obj, Table data) { m_InternalAssigner.AssignObject(obj, data); } public PropertyTableAssigner GetTypeUnsafeAssigner() { return m_InternalAssigner; } public void SetSubassignerForType(Type propertyType, IPropertyTableAssigner assigner) { m_InternalAssigner.SetSubassignerForType(propertyType, assigner); } public void SetSubassigner(PropertyTableAssigner assigner) { m_InternalAssigner.SetSubassignerForType(typeof(SubassignerType), assigner); } void IPropertyTableAssigner.AssignObjectUnchecked(object o, Table data) { AssignObject((T)o, data); } } public class PropertyTableAssigner : IPropertyTableAssigner { public Type m_Type; public Dictionary m_PropertyMap = new Dictionary(); public Dictionary m_SubAssigners = new Dictionary(); public PropertyTableAssigner(Type type, params string[] expectedMissingProperties) { m_Type = type; if (Framework.Do.IsValueType(m_Type)) { throw new ArgumentException("Type cannot be a value type."); } foreach (string key in expectedMissingProperties) { m_PropertyMap.Add(key, null); } PropertyInfo[] properties = Framework.Do.GetProperties(m_Type); foreach (PropertyInfo propertyInfo in properties) { foreach (MoonSharpPropertyAttribute item in propertyInfo.GetCustomAttributes(inherit: true).OfType()) { string text = item.Name ?? propertyInfo.Name; if (m_PropertyMap.ContainsKey(text)) { throw new ArgumentException($"Type {m_Type.FullName} has two definitions for MoonSharp property {text}"); } m_PropertyMap.Add(text, propertyInfo); } } } public void AddExpectedMissingProperty(string name) { m_PropertyMap.Add(name, null); } public bool TryAssignProperty(object obj, string name, DynValue value) { if (m_PropertyMap.ContainsKey(name)) { PropertyInfo propertyInfo = m_PropertyMap[name]; if (propertyInfo != null) { object obj2; if (value.Type == DataType.Table && m_SubAssigners.ContainsKey(propertyInfo.PropertyType)) { IPropertyTableAssigner propertyTableAssigner = m_SubAssigners[propertyInfo.PropertyType]; obj2 = Activator.CreateInstance(propertyInfo.PropertyType); propertyTableAssigner.AssignObjectUnchecked(obj2, value.Table); } else { obj2 = ScriptToClrConversions.DynValueToObjectOfType(value, propertyInfo.PropertyType, null, isOptional: false); } Framework.Do.GetSetMethod(propertyInfo).Invoke(obj, new object[1] { obj2 }); } return true; } return false; } public void AssignProperty(object obj, string name, DynValue value) { if (TryAssignProperty(obj, name, value) || TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(name), value) || TryAssignProperty(obj, DescriptorHelpers.Camelify(name), value) || TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(DescriptorHelpers.Camelify(name)), value)) { return; } throw new ScriptRuntimeException("Invalid property {0}", name); } public void AssignObject(object obj, Table data) { if (obj == null) { throw new ArgumentNullException("Object is null"); } if (!Framework.Do.IsInstanceOfType(m_Type, obj)) { throw new ArgumentException($"Invalid type of object : got '{obj.GetType().FullName}', expected {m_Type.FullName}"); } foreach (TablePair pair in data.Pairs) { if (pair.Key.Type != DataType.String) { throw new ScriptRuntimeException("Invalid property of type {0}", pair.Key.Type.ToErrorTypeString()); } AssignProperty(obj, pair.Key.String, pair.Value); } } public void SetSubassignerForType(Type propertyType, IPropertyTableAssigner assigner) { if (Framework.Do.IsAbstract(propertyType) || Framework.Do.IsGenericType(propertyType) || Framework.Do.IsInterface(propertyType) || Framework.Do.IsValueType(propertyType)) { throw new ArgumentException("propertyType must be a concrete, reference type"); } m_SubAssigners[propertyType] = assigner; } void IPropertyTableAssigner.AssignObjectUnchecked(object obj, Table data) { AssignObject(obj, data); } } public interface IPropertyTableAssigner { void AssignObjectUnchecked(object o, Table data); } public class DelegateProxyFactory : IProxyFactory, IProxyFactory where TProxy : class where TTarget : class { public Func wrapDelegate; public Type TargetType => typeof(TTarget); public Type ProxyType => typeof(TProxy); public DelegateProxyFactory(Func wrapDelegate) { this.wrapDelegate = wrapDelegate; } public TProxy CreateProxyObject(TTarget target) { return wrapDelegate(target); } public object CreateProxyObject(object o) { return CreateProxyObject((TTarget)o); } } public interface IProxyFactory { Type TargetType { get; } Type ProxyType { get; } object CreateProxyObject(object o); } public interface IProxyFactory : IProxyFactory where TProxy : class where TTarget : class { TProxy CreateProxyObject(TTarget target); } public enum ReflectionSpecialNameType { IndexGetter, IndexSetter, ImplicitCast, ExplicitCast, OperatorTrue, OperatorFalse, PropertyGetter, PropertySetter, AddEvent, RemoveEvent, OperatorAdd, OperatorAnd, OperatorOr, OperatorDec, OperatorDiv, OperatorEq, OperatorXor, OperatorGt, OperatorGte, OperatorInc, OperatorNeq, OperatorLt, OperatorLte, OperatorNot, OperatorMod, OperatorMul, OperatorCompl, OperatorSub, OperatorNeg, OperatorUnaryPlus } public struct ReflectionSpecialName { public ReflectionSpecialNameType Type { get; set; } public string Argument { get; set; } public ReflectionSpecialName(ReflectionSpecialNameType type, string argument = null) { this = default(ReflectionSpecialName); Type = type; Argument = argument; } public ReflectionSpecialName(string name) { this = default(ReflectionSpecialName); if (name.Contains(".")) { name = name.Split(new char[1] { '.' })[^1]; } switch (name) { case "op_Explicit": Type = ReflectionSpecialNameType.ExplicitCast; return; case "op_Implicit": Type = ReflectionSpecialNameType.ImplicitCast; return; case "set_Item": Type = ReflectionSpecialNameType.IndexSetter; return; case "get_Item": Type = ReflectionSpecialNameType.IndexGetter; return; case "op_Addition": Type = ReflectionSpecialNameType.OperatorAdd; Argument = "+"; return; case "op_BitwiseAnd": Type = ReflectionSpecialNameType.OperatorAnd; Argument = "&"; return; case "op_BitwiseOr": Type = ReflectionSpecialNameType.OperatorOr; Argument = "|"; return; case "op_Decrement": Type = ReflectionSpecialNameType.OperatorDec; Argument = "--"; return; case "op_Division": Type = ReflectionSpecialNameType.OperatorDiv; Argument = "/"; return; case "op_Equality": Type = ReflectionSpecialNameType.OperatorEq; Argument = "=="; return; case "op_ExclusiveOr": Type = ReflectionSpecialNameType.OperatorXor; Argument = "^"; return; case "op_False": Type = ReflectionSpecialNameType.OperatorFalse; return; case "op_GreaterThan": Type = ReflectionSpecialNameType.OperatorGt; Argument = ">"; return; case "op_GreaterThanOrEqual": Type = ReflectionSpecialNameType.OperatorGte; Argument = ">="; return; case "op_Increment": Type = ReflectionSpecialNameType.OperatorInc; Argument = "++"; return; case "op_Inequality": Type = ReflectionSpecialNameType.OperatorNeq; Argument = "!="; return; case "op_LessThan": Type = ReflectionSpecialNameType.OperatorLt; Argument = "<"; return; case "op_LessThanOrEqual": Type = ReflectionSpecialNameType.OperatorLte; Argument = "<="; return; case "op_LogicalNot": Type = ReflectionSpecialNameType.OperatorNot; Argument = "!"; return; case "op_Modulus": Type = ReflectionSpecialNameType.OperatorMod; Argument = "%"; return; case "op_Multiply": Type = ReflectionSpecialNameType.OperatorMul; Argument = "*"; return; case "op_OnesComplement": Type = ReflectionSpecialNameType.OperatorCompl; Argument = "~"; return; case "op_Subtraction": Type = ReflectionSpecialNameType.OperatorSub; Argument = "-"; return; case "op_True": Type = ReflectionSpecialNameType.OperatorTrue; return; case "op_UnaryNegation": Type = ReflectionSpecialNameType.OperatorNeg; Argument = "-"; return; case "op_UnaryPlus": Type = ReflectionSpecialNameType.OperatorUnaryPlus; Argument = "+"; return; } if (name.StartsWith("get_")) { Type = ReflectionSpecialNameType.PropertyGetter; Argument = name.Substring(4); } else if (name.StartsWith("set_")) { Type = ReflectionSpecialNameType.PropertySetter; Argument = name.Substring(4); } else if (name.StartsWith("add_")) { Type = ReflectionSpecialNameType.AddEvent; Argument = name.Substring(4); } else if (name.StartsWith("remove_")) { Type = ReflectionSpecialNameType.RemoveEvent; Argument = name.Substring(7); } } } public class ArrayMemberDescriptor : ObjectCallbackMemberDescriptor, IWireableDescriptor { public bool m_IsSetter; public ArrayMemberDescriptor(string name, bool isSetter, ParameterDescriptor[] indexerParams) : base(name, isSetter ? new Func(ArrayIndexerSet) : new Func(ArrayIndexerGet), indexerParams) { m_IsSetter = isSetter; } public ArrayMemberDescriptor(string name, bool isSetter) : base(name, isSetter ? new Func(ArrayIndexerSet) : new Func(ArrayIndexerGet)) { m_IsSetter = isSetter; } public void PrepareForWiring(Table t) { t.Set("class", DynValue.NewString(GetType().FullName)); t.Set("name", DynValue.NewString(base.Name)); t.Set("setter", DynValue.NewBoolean(m_IsSetter)); if (base.Parameters != null) { DynValue dynValue = DynValue.NewPrimeTable(); t.Set("params", dynValue); int num = 0; ParameterDescriptor[] parameters = base.Parameters; foreach (ParameterDescriptor obj in parameters) { DynValue dynValue2 = DynValue.NewPrimeTable(); dynValue.Table.Set(++num, dynValue2); obj.PrepareForWiring(dynValue2.Table); } } } public static int[] BuildArrayIndices(CallbackArguments args, int count) { int[] array = new int[count]; for (int i = 0; i < count; i++) { array[i] = args.AsInt(i, "userdata_array_indexer"); } return array; } public static object ArrayIndexerSet(object arrayObj, ScriptExecutionContext ctx, CallbackArguments args) { Array array = (Array)arrayObj; int[] indices = BuildArrayIndices(args, args.Count - 1); DynValue value = args[args.Count - 1]; Type elementType = array.GetType().GetElementType(); object value2 = ScriptToClrConversions.DynValueToObjectOfType(value, elementType, null, isOptional: false); array.SetValue(value2, indices); return DynValue.Void; } public static object ArrayIndexerGet(object arrayObj, ScriptExecutionContext ctx, CallbackArguments args) { Array obj = (Array)arrayObj; int[] indices = BuildArrayIndices(args, args.Count); return obj.GetValue(indices); } } public sealed class ProxyUserDataDescriptor : IUserDataDescriptor { public IUserDataDescriptor m_ProxyDescriptor; public IProxyFactory m_ProxyFactory; public IUserDataDescriptor InnerDescriptor => m_ProxyDescriptor; public string Name { get; set; } public Type Type => m_ProxyFactory.TargetType; public ProxyUserDataDescriptor(IProxyFactory proxyFactory, IUserDataDescriptor proxyDescriptor, string friendlyName = null) { m_ProxyFactory = proxyFactory; Name = friendlyName ?? (proxyFactory.TargetType.Name + "::proxy"); m_ProxyDescriptor = proxyDescriptor; } public object Proxy(object obj) { if (obj == null) { return null; } return m_ProxyFactory.CreateProxyObject(obj); } public DynValue Index(Script script, object obj, DynValue index, bool isDirectIndexing) { return m_ProxyDescriptor.Index(script, Proxy(obj), index, isDirectIndexing); } public bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing) { return m_ProxyDescriptor.SetIndex(script, Proxy(obj), index, value, isDirectIndexing); } public string AsString(object obj) { return m_ProxyDescriptor.AsString(Proxy(obj)); } public DynValue MetaIndex(Script script, object obj, string metaname) { return m_ProxyDescriptor.MetaIndex(script, Proxy(obj), metaname); } public bool IsTypeCompatible(Type type, object obj) { return Framework.Do.IsInstanceOfType(type, obj); } } public class ObjectCallbackMemberDescriptor : FunctionMemberDescriptorBase { public Func m_CallbackFunc; public ObjectCallbackMemberDescriptor(string funcName) : this(funcName, (object o, ScriptExecutionContext c, CallbackArguments a) => DynValue.Void, new ParameterDescriptor[0]) { } public ObjectCallbackMemberDescriptor(string funcName, Func callBack) : this(funcName, callBack, new ParameterDescriptor[0]) { } public ObjectCallbackMemberDescriptor(string funcName, Func callBack, ParameterDescriptor[] parameters) { m_CallbackFunc = callBack; Initialize(funcName, isStatic: false, parameters, isExtensionMethod: false); } public override DynValue Execute(Script script, object obj, ScriptExecutionContext context, CallbackArguments args) { if (m_CallbackFunc != null) { object obj2 = m_CallbackFunc(obj, context, args); return ClrToScriptConversions.ObjectToDynValue(script, obj2); } return DynValue.Void; } } public abstract class FunctionMemberDescriptorBase : IOverloadableMemberDescriptor, IMemberDescriptor { public bool IsStatic { get; set; } public string Name { get; set; } public string SortDiscriminant { get; set; } public ParameterDescriptor[] Parameters { get; set; } public Type ExtensionMethodType { get; set; } public Type VarArgsArrayType { get; set; } public Type VarArgsElementType { get; set; } public MemberDescriptorAccess MemberAccess => MemberDescriptorAccess.CanRead | MemberDescriptorAccess.CanExecute; public void Initialize(string funcName, bool isStatic, ParameterDescriptor[] parameters, bool isExtensionMethod) { Name = funcName; IsStatic = isStatic; Parameters = parameters; if (isExtensionMethod) { ExtensionMethodType = Parameters[0].Type; } if (Parameters.Length != 0 && Parameters[Parameters.Length - 1].IsVarArgs) { VarArgsArrayType = Parameters[Parameters.Length - 1].Type; VarArgsElementType = Parameters[Parameters.Length - 1].Type.GetElementType(); } SortDiscriminant = string.Join(":", Parameters.Select((ParameterDescriptor pi) => pi.Type.FullName).ToArray()); } public Func GetCallback(Script script, object obj = null) { return (ScriptExecutionContext c, CallbackArguments a) => Execute(script, obj, c, a); } public CallbackFunction GetCallbackFunction(Script script, object obj = null) { return new CallbackFunction(GetCallback(script, obj), Name); } public DynValue GetCallbackAsDynValue(Script script, object obj = null) { return DynValue.NewCallback(GetCallbackFunction(script, obj)); } public static DynValue CreateCallbackDynValue(Script script, MethodInfo mi, object obj = null) { return new MethodMemberDescriptor(mi).GetCallbackAsDynValue(script, obj); } public virtual object[] BuildArgumentList(Script script, object obj, ScriptExecutionContext context, CallbackArguments args, out List outParams) { ParameterDescriptor[] parameters = Parameters; object[] array = new object[parameters.Length]; int num = (args.IsMethodCall ? 1 : 0); outParams = null; for (int i = 0; i < array.Length; i++) { if (parameters[i].Type.IsByRef) { if (outParams == null) { outParams = new List(); } outParams.Add(i); } if (ExtensionMethodType != null && obj != null && i == 0) { array[i] = obj; } else if (parameters[i].Type == typeof(Script)) { array[i] = script; } else if (parameters[i].Type == typeof(ScriptExecutionContext)) { array[i] = context; } else if (parameters[i].Type == typeof(CallbackArguments)) { array[i] = args.SkipMethodCall(); } else if (parameters[i].IsOut) { array[i] = null; } else if (i == parameters.Length - 1 && VarArgsArrayType != null) { List list = new List(); while (true) { DynValue dynValue = args.RawGet(num, translateVoids: false); num++; if (dynValue == null) { break; } list.Add(dynValue); } if (list.Count == 1) { DynValue dynValue2 = list[0]; if (dynValue2.Type == DataType.UserData && dynValue2.UserData.Object != null && Framework.Do.IsAssignableFrom(VarArgsArrayType, dynValue2.UserData.Object.GetType())) { array[i] = dynValue2.UserData.Object; continue; } } Array array2 = Array.CreateInstance(VarArgsElementType, list.Count); for (int j = 0; j < list.Count; j++) { array2.SetValue(ScriptToClrConversions.DynValueToObjectOfType(list[j], VarArgsElementType, null, isOptional: false), j); } array[i] = array2; } else { DynValue value = args.RawGet(num, translateVoids: false) ?? DynValue.Void; array[i] = ScriptToClrConversions.DynValueToObjectOfType(value, parameters[i].Type, parameters[i].DefaultValue, parameters[i].HasDefaultValue); num++; } } return array; } public static DynValue BuildReturnValue(Script script, List outParams, object[] pars, object retv) { if (outParams == null) { return ClrToScriptConversions.ObjectToDynValue(script, retv); } DynValue[] array = new DynValue[outParams.Count + 1]; if (retv is DynValue && ((DynValue)retv).IsVoid()) { array[0] = DynValue.Nil; } else { array[0] = ClrToScriptConversions.ObjectToDynValue(script, retv); } for (int i = 0; i < outParams.Count; i++) { array[i + 1] = ClrToScriptConversions.ObjectToDynValue(script, pars[outParams[i]]); } return DynValue.NewTuple(array); } public abstract DynValue Execute(Script script, object obj, ScriptExecutionContext context, CallbackArguments args); public virtual DynValue GetValue(Script script, object obj) { this.CheckAccess(MemberDescriptorAccess.CanRead, obj); return GetCallbackAsDynValue(script, obj); } public virtual void SetValue(Script script, object obj, DynValue v) { this.CheckAccess(MemberDescriptorAccess.CanWrite, obj); } public FunctionMemberDescriptorBase() { } } public class StandardEnumUserDataDescriptor : DispatchingUserDataDescriptor { public Func m_EnumToULong; public Func m_ULongToEnum; public Func m_EnumToLong; public Func m_LongToEnum; public Type UnderlyingType { get; set; } public bool IsUnsigned { get; set; } public bool IsFlags { get; set; } public StandardEnumUserDataDescriptor(Type enumType, string friendlyName = null, string[] names = null, object[] values = null, Type underlyingType = null) : base(enumType, friendlyName) { if (!Framework.Do.IsEnum(enumType)) { throw new ArgumentException("enumType must be an enum!"); } UnderlyingType = underlyingType ?? Enum.GetUnderlyingType(enumType); IsUnsigned = UnderlyingType == typeof(byte) || UnderlyingType == typeof(ushort) || UnderlyingType == typeof(uint) || UnderlyingType == typeof(ulong); names = names ?? Enum.GetNames(base.Type); values = values ?? Enum.GetValues(base.Type).OfType().ToArray(); FillMemberList(names, values); } public void FillMemberList(string[] names, object[] values) { for (int i = 0; i < names.Length; i++) { string name = names[i]; DynValue value = UserData.Create(values.GetValue(i), this); AddDynValue(name, value); } Attribute[] customAttributes = Framework.Do.GetCustomAttributes(base.Type, typeof(FlagsAttribute), inherit: true); if (customAttributes != null && customAttributes.Length != 0) { IsFlags = true; AddEnumMethod("flagsAnd", DynValue.NewCallback(Callback_And)); AddEnumMethod("flagsOr", DynValue.NewCallback(Callback_Or)); AddEnumMethod("flagsXor", DynValue.NewCallback(Callback_Xor)); AddEnumMethod("flagsNot", DynValue.NewCallback(Callback_BwNot)); AddEnumMethod("hasAll", DynValue.NewCallback(Callback_HasAll)); AddEnumMethod("hasAny", DynValue.NewCallback(Callback_HasAny)); } } public void AddEnumMethod(string name, DynValue dynValue) { if (!HasMember(name)) { AddDynValue(name, dynValue); } if (!HasMember("__" + name)) { AddDynValue("__" + name, dynValue); } } public long GetValueSigned(DynValue dv) { CreateSignedConversionFunctions(); if (dv.Type == DataType.Number) { return (long)dv.Number; } if (dv.Type != DataType.UserData || dv.UserData.Descriptor != this || dv.UserData.Object == null) { throw new ScriptRuntimeException("Enum userdata or number expected, or enum is not of the correct type."); } return m_EnumToLong(dv.UserData.Object); } public ulong GetValueUnsigned(DynValue dv) { CreateUnsignedConversionFunctions(); if (dv.Type == DataType.Number) { return (ulong)dv.Number; } if (dv.Type != DataType.UserData || dv.UserData.Descriptor != this || dv.UserData.Object == null) { throw new ScriptRuntimeException("Enum userdata or number expected, or enum is not of the correct type."); } return m_EnumToULong(dv.UserData.Object); } public DynValue CreateValueSigned(long value) { CreateSignedConversionFunctions(); return UserData.Create(m_LongToEnum(value), this); } public DynValue CreateValueUnsigned(ulong value) { CreateUnsignedConversionFunctions(); return UserData.Create(m_ULongToEnum(value), this); } public void CreateSignedConversionFunctions() { if (m_EnumToLong != null && m_LongToEnum != null) { return; } if (UnderlyingType == typeof(sbyte)) { m_EnumToLong = (object o) => (sbyte)o; m_LongToEnum = (long o) => (sbyte)o; return; } if (UnderlyingType == typeof(short)) { m_EnumToLong = (object o) => (short)o; m_LongToEnum = (long o) => (short)o; return; } if (UnderlyingType == typeof(int)) { m_EnumToLong = (object o) => (int)o; m_LongToEnum = (long o) => (int)o; return; } if (UnderlyingType == typeof(long)) { m_EnumToLong = (object o) => (long)o; m_LongToEnum = (long o) => o; return; } throw new ScriptRuntimeException("Unexpected enum underlying type : {0}", UnderlyingType.FullName); } public void CreateUnsignedConversionFunctions() { if (m_EnumToULong != null && m_ULongToEnum != null) { return; } if (UnderlyingType == typeof(byte)) { m_EnumToULong = (object o) => (byte)o; m_ULongToEnum = (ulong o) => (byte)o; return; } if (UnderlyingType == typeof(ushort)) { m_EnumToULong = (object o) => (ushort)o; m_ULongToEnum = (ulong o) => (ushort)o; return; } if (UnderlyingType == typeof(uint)) { m_EnumToULong = (object o) => (uint)o; m_ULongToEnum = (ulong o) => (uint)o; return; } if (UnderlyingType == typeof(ulong)) { m_EnumToULong = (object o) => (ulong)o; m_ULongToEnum = (ulong o) => o; return; } throw new ScriptRuntimeException("Unexpected enum underlying type : {0}", UnderlyingType.FullName); } public DynValue PerformBinaryOperationS(string funcName, ScriptExecutionContext ctx, CallbackArguments args, Func operation) { if (args.Count != 2) { throw new ScriptRuntimeException("Enum.{0} expects two arguments", funcName); } long valueSigned = GetValueSigned(args[0]); long valueSigned2 = GetValueSigned(args[1]); return operation(valueSigned, valueSigned2); } public DynValue PerformBinaryOperationU(string funcName, ScriptExecutionContext ctx, CallbackArguments args, Func operation) { if (args.Count != 2) { throw new ScriptRuntimeException("Enum.{0} expects two arguments", funcName); } ulong valueUnsigned = GetValueUnsigned(args[0]); ulong valueUnsigned2 = GetValueUnsigned(args[1]); return operation(valueUnsigned, valueUnsigned2); } public DynValue PerformBinaryOperationS(string funcName, ScriptExecutionContext ctx, CallbackArguments args, Func operation) { return PerformBinaryOperationS(funcName, ctx, args, (long v1, long v2) => CreateValueSigned(operation(v1, v2))); } public DynValue PerformBinaryOperationU(string funcName, ScriptExecutionContext ctx, CallbackArguments args, Func operation) { return PerformBinaryOperationU(funcName, ctx, args, (ulong v1, ulong v2) => CreateValueUnsigned(operation(v1, v2))); } public DynValue PerformUnaryOperationS(string funcName, ScriptExecutionContext ctx, CallbackArguments args, Func operation) { if (args.Count != 1) { throw new ScriptRuntimeException("Enum.{0} expects one argument.", funcName); } long valueSigned = GetValueSigned(args[0]); long value = operation(valueSigned); return CreateValueSigned(value); } public DynValue PerformUnaryOperationU(string funcName, ScriptExecutionContext ctx, CallbackArguments args, Func operation) { if (args.Count != 1) { throw new ScriptRuntimeException("Enum.{0} expects one argument.", funcName); } ulong valueUnsigned = GetValueUnsigned(args[0]); ulong value = operation(valueUnsigned); return CreateValueUnsigned(value); } public DynValue Callback_Or(ScriptExecutionContext ctx, CallbackArguments args) { if (IsUnsigned) { return PerformBinaryOperationU("or", ctx, args, (ulong v1, ulong v2) => v1 | v2); } return PerformBinaryOperationS("or", ctx, args, (long v1, long v2) => v1 | v2); } public DynValue Callback_And(ScriptExecutionContext ctx, CallbackArguments args) { if (IsUnsigned) { return PerformBinaryOperationU("and", ctx, args, (ulong v1, ulong v2) => v1 & v2); } return PerformBinaryOperationS("and", ctx, args, (long v1, long v2) => v1 & v2); } public DynValue Callback_Xor(ScriptExecutionContext ctx, CallbackArguments args) { if (IsUnsigned) { return PerformBinaryOperationU("xor", ctx, args, (ulong v1, ulong v2) => v1 ^ v2); } return PerformBinaryOperationS("xor", ctx, args, (long v1, long v2) => v1 ^ v2); } public DynValue Callback_BwNot(ScriptExecutionContext ctx, CallbackArguments args) { if (IsUnsigned) { return PerformUnaryOperationU("not", ctx, args, (ulong v1) => ~v1); } return PerformUnaryOperationS("not", ctx, args, (long v1) => ~v1); } public DynValue Callback_HasAll(ScriptExecutionContext ctx, CallbackArguments args) { if (IsUnsigned) { return PerformBinaryOperationU("hasAll", ctx, args, (ulong v1, ulong v2) => DynValue.NewBoolean((v1 & v2) == v2)); } return PerformBinaryOperationS("hasAll", ctx, args, (long v1, long v2) => DynValue.NewBoolean((v1 & v2) == v2)); } public DynValue Callback_HasAny(ScriptExecutionContext ctx, CallbackArguments args) { if (IsUnsigned) { return PerformBinaryOperationU("hasAny", ctx, args, (ulong v1, ulong v2) => DynValue.NewBoolean((v1 & v2) != 0)); } return PerformBinaryOperationS("hasAny", ctx, args, (long v1, long v2) => DynValue.NewBoolean((v1 & v2) != 0)); } public override bool IsTypeCompatible(Type type, object obj) { if (obj != null) { return base.Type == type; } return base.IsTypeCompatible(type, obj); } public override DynValue MetaIndex(Script script, object obj, string metaname) { if (metaname == "__concat" && IsFlags) { return DynValue.NewCallback(Callback_Or); } return null; } } public class DynValueMemberDescriptor : IMemberDescriptor, IWireableDescriptor { public DynValue m_Value; public bool IsStatic => true; public string Name { get; set; } public MemberDescriptorAccess MemberAccess { get; set; } public virtual DynValue Value => m_Value; public DynValueMemberDescriptor(string name, string serializedTableValue) { DynValue dynValue = new Script().CreateDynamicExpression(serializedTableValue).Evaluate(); m_Value = dynValue.Table.Get(1); Name = name; MemberAccess = MemberDescriptorAccess.CanRead; } public DynValueMemberDescriptor(string name) { MemberAccess = MemberDescriptorAccess.CanRead; m_Value = null; Name = name; } public DynValueMemberDescriptor(string name, DynValue value) { m_Value = value; Name = name; if (value.Type == DataType.ClrFunction) { MemberAccess = MemberDescriptorAccess.CanRead | MemberDescriptorAccess.CanExecute; } else { MemberAccess = MemberDescriptorAccess.CanRead; } } public DynValue GetValue(Script script, object obj) { return Value; } public void SetValue(Script script, object obj, DynValue value) { throw new ScriptRuntimeException("userdata '{0}' cannot be written to.", Name); } public void PrepareForWiring(Table t) { t.Set("class", DynValue.NewString(GetType().FullName)); t.Set("name", DynValue.NewString(Name)); switch (Value.Type) { case DataType.Nil: case DataType.Void: case DataType.Boolean: case DataType.Number: case DataType.String: case DataType.Tuple: t.Set("value", Value); break; case DataType.Table: if (Value.Table.OwnerScript == null) { t.Set("value", Value); } else { t.Set("error", DynValue.NewString("Wiring of non-prime table value members not supported.")); } break; case DataType.UserData: if (Value.UserData.Object == null) { t.Set("type", DynValue.NewString("userdata")); t.Set("staticType", DynValue.NewString(Value.UserData.Descriptor.Type.FullName)); t.Set("visibility", DynValue.NewString(Value.UserData.Descriptor.Type.GetClrVisibility())); } else { t.Set("error", DynValue.NewString("Wiring of non-static userdata value members not supported.")); } break; default: t.Set("error", DynValue.NewString($"Wiring of '{Value.Type.ToErrorTypeString()}' value members not supported.")); break; } } } public class EventMemberDescriptor : IMemberDescriptor { public delegate void EventWrapper00(); public delegate void EventWrapper01(object o1); public delegate void EventWrapper02(object o1, object o2); public delegate void EventWrapper03(object o1, object o2, object o3); public delegate void EventWrapper04(object o1, object o2, object o3, object o4); public delegate void EventWrapper05(object o1, object o2, object o3, object o4, object o5); public delegate void EventWrapper06(object o1, object o2, object o3, object o4, object o5, object o6); public delegate void EventWrapper07(object o1, object o2, object o3, object o4, object o5, object o6, object o7); public delegate void EventWrapper08(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8); public delegate void EventWrapper09(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9); public delegate void EventWrapper10(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10); public delegate void EventWrapper11(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11); public delegate void EventWrapper12(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11, object o12); public delegate void EventWrapper13(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11, object o12, object o13); public delegate void EventWrapper14(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11, object o12, object o13, object o14); public delegate void EventWrapper15(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11, object o12, object o13, object o14, object o15); public delegate void EventWrapper16(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11, object o12, object o13, object o14, object o15, object o16); public const int MAX_ARGS_IN_DELEGATE = 16; public object m_Lock = new object(); public MultiDictionary m_Callbacks = new MultiDictionary(new MoonSharp.Interpreter.DataStructs.ReferenceEqualityComparer()); public Dictionary m_Delegates = new Dictionary(new MoonSharp.Interpreter.DataStructs.ReferenceEqualityComparer()); public MethodInfo m_Add; public MethodInfo m_Remove; public EventInfo EventInfo { get; set; } public bool IsStatic { get; set; } public string Name => EventInfo.Name; public MemberDescriptorAccess MemberAccess => MemberDescriptorAccess.CanRead; public static EventMemberDescriptor TryCreateIfVisible(EventInfo ei, InteropAccessMode accessMode) { if (!CheckEventIsCompatible(ei, throwException: false)) { return null; } MethodInfo addMethod = Framework.Do.GetAddMethod(ei); MethodInfo removeMethod = Framework.Do.GetRemoveMethod(ei); bool? visibilityFromAttributes = ei.GetVisibilityFromAttributes(); bool num; if (!visibilityFromAttributes.HasValue) { if (!(removeMethod != null) || !removeMethod.IsPublic || !(addMethod != null)) { goto IL_006c; } num = addMethod.IsPublic; } else { num = visibilityFromAttributes.GetValueOrDefault(); } if (num) { return new EventMemberDescriptor(ei, accessMode); } goto IL_006c; IL_006c: return null; } public static bool CheckEventIsCompatible(EventInfo ei, bool throwException) { if (Framework.Do.IsValueType(ei.DeclaringType)) { if (throwException) { throw new ArgumentException("Events are not supported on value types"); } return false; } if (Framework.Do.GetAddMethod(ei) == null || Framework.Do.GetRemoveMethod(ei) == null) { if (throwException) { throw new ArgumentException("Event must have add and remove methods"); } return false; } MethodInfo method = Framework.Do.GetMethod(ei.EventHandlerType, "Invoke"); if (method == null) { if (throwException) { throw new ArgumentException("Event handler type doesn't seem to be a delegate"); } return false; } if (!MethodMemberDescriptor.CheckMethodIsCompatible(method, throwException)) { return false; } if (method.ReturnType != typeof(void)) { if (throwException) { throw new ArgumentException("Event handler cannot have a return type"); } return false; } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length > 16) { if (throwException) { throw new ArgumentException($"Event handler cannot have more than {16} parameters"); } return false; } ParameterInfo[] array = parameters; foreach (ParameterInfo parameterInfo in array) { if (Framework.Do.IsValueType(parameterInfo.ParameterType)) { if (throwException) { throw new ArgumentException("Event handler cannot have value type parameters"); } return false; } if (parameterInfo.ParameterType.IsByRef) { if (throwException) { throw new ArgumentException("Event handler cannot have by-ref type parameters"); } return false; } } return true; } public EventMemberDescriptor(EventInfo ei, InteropAccessMode accessMode = InteropAccessMode.Default) { CheckEventIsCompatible(ei, throwException: true); EventInfo = ei; m_Add = Framework.Do.GetAddMethod(ei); m_Remove = Framework.Do.GetRemoveMethod(ei); IsStatic = m_Add.IsStatic; } public DynValue GetValue(Script script, object obj) { this.CheckAccess(MemberDescriptorAccess.CanRead, obj); if (IsStatic) { obj = this; } return UserData.Create(new EventFacade(this, obj)); } public DynValue AddCallback(object o, ScriptExecutionContext context, CallbackArguments args) { lock (m_Lock) { Closure function = args.AsType(0, $"userdata<{EventInfo.DeclaringType}>.{EventInfo.Name}.add", DataType.Function).Function; if (m_Callbacks.Add(o, function)) { RegisterCallback(o); } return DynValue.Void; } } public DynValue RemoveCallback(object o, ScriptExecutionContext context, CallbackArguments args) { lock (m_Lock) { Closure function = args.AsType(0, $"userdata<{EventInfo.DeclaringType}>.{EventInfo.Name}.remove", DataType.Function).Function; if (m_Callbacks.RemoveValue(o, function)) { UnregisterCallback(o); } return DynValue.Void; } } public void RegisterCallback(object o) { m_Delegates.GetOrCreate(o, delegate { Delegate @delegate = CreateDelegate(o); Delegate delegate2 = Delegate.CreateDelegate(EventInfo.EventHandlerType, @delegate.Target, @delegate.Method); m_Add.Invoke(o, new object[1] { delegate2 }); return delegate2; }); } public void UnregisterCallback(object o) { Delegate orDefault = m_Delegates.GetOrDefault(o); if ((object)orDefault == null) { throw new InternalErrorException("can't unregister null delegate"); } m_Delegates.Remove(o); m_Remove.Invoke(o, new object[1] { orDefault }); } public Delegate CreateDelegate(object sender) { return Framework.Do.GetMethod(EventInfo.EventHandlerType, "Invoke").GetParameters().Length switch { 0 => (EventWrapper00)delegate { DispatchEvent(sender); }, 1 => (EventWrapper01)delegate(object o1) { DispatchEvent(sender, o1); }, 2 => (EventWrapper02)delegate(object o1, object o2) { DispatchEvent(sender, o1, o2); }, 3 => (EventWrapper03)delegate(object o1, object o2, object o3) { DispatchEvent(sender, o1, o2, o3); }, 4 => (EventWrapper04)delegate(object o1, object o2, object o3, object o4) { DispatchEvent(sender, o1, o2, o3, o4); }, 5 => (EventWrapper05)delegate(object o1, object o2, object o3, object o4, object o5) { DispatchEvent(sender, o1, o2, o3, o4, o5); }, 6 => (EventWrapper06)delegate(object o1, object o2, object o3, object o4, object o5, object o6) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6); }, 7 => (EventWrapper07)delegate(object o1, object o2, object o3, object o4, object o5, object o6, object o7) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6, o7); }, 8 => (EventWrapper08)delegate(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6, o7, o8); }, 9 => (EventWrapper09)delegate(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6, o7, o8, o9); }, 10 => (EventWrapper10)delegate(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10); }, 11 => (EventWrapper11)delegate(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11); }, 12 => (EventWrapper12)delegate(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11, object o12) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12); }, 13 => (EventWrapper13)delegate(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11, object o12, object o13) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13); }, 14 => (EventWrapper14)delegate(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11, object o12, object o13, object o14) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14); }, 15 => (EventWrapper15)delegate(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11, object o12, object o13, object o14, object o15) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15); }, 16 => (EventWrapper16)delegate(object o1, object o2, object o3, object o4, object o5, object o6, object o7, object o8, object o9, object o10, object o11, object o12, object o13, object o14, object o15, object o16) { DispatchEvent(sender, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, o16); }, _ => throw new InternalErrorException("too many args in delegate type"), }; } public void DispatchEvent(object sender, object o01 = null, object o02 = null, object o03 = null, object o04 = null, object o05 = null, object o06 = null, object o07 = null, object o08 = null, object o09 = null, object o10 = null, object o11 = null, object o12 = null, object o13 = null, object o14 = null, object o15 = null, object o16 = null) { Closure[] array = null; lock (m_Lock) { array = m_Callbacks.Find(sender).ToArray(); } Closure[] array2 = array; for (int i = 0; i < array2.Length; i++) { array2[i].Call(o01, o02, o03, o04, o05, o06, o07, o08, o09, o10, o11, o12, o13, o14, o15, o16); } } public void SetValue(Script script, object obj, DynValue v) { this.CheckAccess(MemberDescriptorAccess.CanWrite, obj); } } public class OverloadedMethodMemberDescriptor : IOptimizableDescriptor, IMemberDescriptor, IWireableDescriptor { public class OverloadableMemberDescriptorComparer : IComparer { public int Compare(IOverloadableMemberDescriptor x, IOverloadableMemberDescriptor y) { return x.SortDiscriminant.CompareTo(y.SortDiscriminant); } } public class OverloadCacheItem { public bool HasObject; public IOverloadableMemberDescriptor Method; public List ArgsDataType; public List ArgsUserDataType; public int HitIndexAtLastHit; } public const int CACHE_SIZE = 5; public List m_Overloads = new List(); public List m_ExtOverloads = new List(); public bool m_Unsorted = true; public OverloadCacheItem[] m_Cache = new OverloadCacheItem[5]; public int m_CacheHits; public int m_ExtensionMethodVersion; public bool IgnoreExtensionMethods { get; set; } public string Name { get; set; } public Type DeclaringType { get; set; } public int OverloadCount => m_Overloads.Count; public bool IsStatic => m_Overloads.Any((IOverloadableMemberDescriptor o) => o.IsStatic); public MemberDescriptorAccess MemberAccess => MemberDescriptorAccess.CanRead | MemberDescriptorAccess.CanExecute; public OverloadedMethodMemberDescriptor(string name, Type declaringType) { Name = name; DeclaringType = declaringType; } public OverloadedMethodMemberDescriptor(string name, Type declaringType, IOverloadableMemberDescriptor descriptor) : this(name, declaringType) { m_Overloads.Add(descriptor); } public OverloadedMethodMemberDescriptor(string name, Type declaringType, IEnumerable descriptors) : this(name, declaringType) { m_Overloads.AddRange(descriptors); } public void SetExtensionMethodsSnapshot(int version, List extMethods) { m_ExtOverloads = extMethods; m_ExtensionMethodVersion = version; } public void AddOverload(IOverloadableMemberDescriptor overload) { m_Overloads.Add(overload); m_Unsorted = true; } public DynValue PerformOverloadedCall(Script script, object obj, ScriptExecutionContext context, CallbackArguments args) { bool flag = IgnoreExtensionMethods || obj == null || m_ExtensionMethodVersion == UserData.GetExtensionMethodsChangeVersion(); if (m_Overloads.Count == 1 && m_ExtOverloads.Count == 0 && flag) { return m_Overloads[0].Execute(script, obj, context, args); } if (m_Unsorted) { m_Overloads.Sort(new OverloadableMemberDescriptorComparer()); m_Unsorted = false; } if (flag) { for (int i = 0; i < m_Cache.Length; i++) { if (m_Cache[i] != null && CheckMatch(obj != null, args, m_Cache[i])) { return m_Cache[i].Method.Execute(script, obj, context, args); } } } int num = 0; IOverloadableMemberDescriptor overloadableMemberDescriptor = null; for (int j = 0; j < m_Overloads.Count; j++) { if (obj != null || m_Overloads[j].IsStatic) { int num2 = CalcScoreForOverload(context, args, m_Overloads[j], isExtMethod: false); if (num2 > num) { num = num2; overloadableMemberDescriptor = m_Overloads[j]; } } } if (!IgnoreExtensionMethods && obj != null) { if (!flag) { m_ExtensionMethodVersion = UserData.GetExtensionMethodsChangeVersion(); m_ExtOverloads = UserData.GetExtensionMethodsByNameAndType(Name, DeclaringType); } for (int k = 0; k < m_ExtOverloads.Count; k++) { int num3 = CalcScoreForOverload(context, args, m_ExtOverloads[k], isExtMethod: true); if (num3 > num) { num = num3; overloadableMemberDescriptor = m_ExtOverloads[k]; } } } if (overloadableMemberDescriptor != null) { Cache(obj != null, args, overloadableMemberDescriptor); return overloadableMemberDescriptor.Execute(script, obj, context, args); } throw new ScriptRuntimeException("function call doesn't match any overload"); } public void Cache(bool hasObject, CallbackArguments args, IOverloadableMemberDescriptor bestOverload) { int num = int.MaxValue; OverloadCacheItem overloadCacheItem = null; for (int i = 0; i < m_Cache.Length; i++) { if (m_Cache[i] == null) { overloadCacheItem = new OverloadCacheItem { ArgsDataType = new List(), ArgsUserDataType = new List() }; m_Cache[i] = overloadCacheItem; break; } if (m_Cache[i].HitIndexAtLastHit < num) { num = m_Cache[i].HitIndexAtLastHit; overloadCacheItem = m_Cache[i]; } } if (overloadCacheItem == null) { m_Cache = new OverloadCacheItem[5]; overloadCacheItem = new OverloadCacheItem { ArgsDataType = new List(), ArgsUserDataType = new List() }; m_Cache[0] = overloadCacheItem; m_CacheHits = 0; } overloadCacheItem.Method = bestOverload; overloadCacheItem.HitIndexAtLastHit = ++m_CacheHits; overloadCacheItem.ArgsDataType.Clear(); overloadCacheItem.HasObject = hasObject; for (int j = 0; j < args.Count; j++) { overloadCacheItem.ArgsDataType.Add(args[j].Type); if (args[j].Type == DataType.UserData) { overloadCacheItem.ArgsUserDataType.Add(args[j].UserData.Descriptor.Type); } else { overloadCacheItem.ArgsUserDataType.Add(null); } } } public bool CheckMatch(bool hasObject, CallbackArguments args, OverloadCacheItem overloadCacheItem) { if (overloadCacheItem.HasObject && !hasObject) { return false; } if (args.Count != overloadCacheItem.ArgsDataType.Count) { return false; } for (int i = 0; i < args.Count; i++) { if (args[i].Type != overloadCacheItem.ArgsDataType[i]) { return false; } if (args[i].Type == DataType.UserData && args[i].UserData.Descriptor.Type != overloadCacheItem.ArgsUserDataType[i]) { return false; } } overloadCacheItem.HitIndexAtLastHit = ++m_CacheHits; return true; } public int CalcScoreForOverload(ScriptExecutionContext context, CallbackArguments args, IOverloadableMemberDescriptor method, bool isExtMethod) { int num = 100; int num2 = (args.IsMethodCall ? 1 : 0); int num3 = num2; bool flag = false; for (int i = 0; i < method.Parameters.Length; i++) { if ((isExtMethod && i == 0) || method.Parameters[i].IsOut) { continue; } Type type = method.Parameters[i].Type; if (type == typeof(Script) || type == typeof(ScriptExecutionContext) || type == typeof(CallbackArguments)) { continue; } if (i == method.Parameters.Length - 1 && method.VarArgsArrayType != null) { int num4 = 0; DynValue dynValue = null; int num5 = num; while (true) { DynValue dynValue2 = args.RawGet(num3, translateVoids: false); if (dynValue2 == null) { break; } if (dynValue == null) { dynValue = dynValue2; } num3++; num4++; int val = CalcScoreForSingleArgument(method.Parameters[i], method.VarArgsElementType, dynValue2, isOptional: false); num = Math.Min(num, val); } if (num4 == 1 && dynValue.Type == DataType.UserData && dynValue.UserData.Object != null && Framework.Do.IsAssignableFrom(method.VarArgsArrayType, dynValue.UserData.Object.GetType())) { num = num5; continue; } if (num4 == 0) { num = Math.Min(num, 40); } flag = true; } else { DynValue arg = args.RawGet(num3, translateVoids: false) ?? DynValue.Void; int val2 = CalcScoreForSingleArgument(method.Parameters[i], type, arg, method.Parameters[i].HasDefaultValue); num = Math.Min(num, val2); num3++; } } if (num > 0) { if (args.Count - num2 <= method.Parameters.Length) { num += 100; num *= 1000; } else if (flag) { num--; num *= 1000; } else { num *= 1000; num -= 2 * (args.Count - num2 - method.Parameters.Length); num = Math.Max(1, num); } } return num; } public static int CalcScoreForSingleArgument(ParameterDescriptor desc, Type parameterType, DynValue arg, bool isOptional) { int num = ScriptToClrConversions.DynValueToObjectOfTypeWeight(arg, parameterType, isOptional); if (parameterType.IsByRef || desc.IsOut || desc.IsRef) { num = Math.Max(0, num + -10); } return num; } public Func GetCallback(Script script, object obj) { return (ScriptExecutionContext context, CallbackArguments args) => PerformOverloadedCall(script, obj, context, args); } void IOptimizableDescriptor.Optimize() { foreach (IOptimizableDescriptor item in m_Overloads.OfType()) { item.Optimize(); } } public CallbackFunction GetCallbackFunction(Script script, object obj = null) { return new CallbackFunction(GetCallback(script, obj), Name); } public DynValue GetValue(Script script, object obj) { return DynValue.NewCallback(GetCallbackFunction(script, obj)); } public void SetValue(Script script, object obj, DynValue value) { this.CheckAccess(MemberDescriptorAccess.CanWrite, obj); } public void PrepareForWiring(Table t) { t.Set("class", DynValue.NewString(GetType().FullName)); t.Set("name", DynValue.NewString(Name)); t.Set("decltype", DynValue.NewString(DeclaringType.FullName)); DynValue dynValue = DynValue.NewPrimeTable(); t.Set("overloads", dynValue); int num = 0; foreach (IOverloadableMemberDescriptor overload in m_Overloads) { if (overload is IWireableDescriptor wireableDescriptor) { DynValue dynValue2 = DynValue.NewPrimeTable(); dynValue.Table.Set(++num, dynValue2); wireableDescriptor.PrepareForWiring(dynValue2.Table); } else { dynValue.Table.Set(++num, DynValue.NewString($"unsupported - {overload.GetType().FullName} is not serializable")); } } } } public class FieldMemberDescriptor : IMemberDescriptor, IOptimizableDescriptor, IWireableDescriptor { public object m_ConstValue; public Func m_OptimizedGetter; public FieldInfo FieldInfo { get; set; } public InteropAccessMode AccessMode { get; set; } public bool IsStatic { get; set; } public string Name { get; set; } public bool IsConst { get; set; } public bool IsReadonly { get; set; } public MemberDescriptorAccess MemberAccess { get { if (IsReadonly || IsConst) { return MemberDescriptorAccess.CanRead; } return MemberDescriptorAccess.CanRead | MemberDescriptorAccess.CanWrite; } } public static FieldMemberDescriptor TryCreateIfVisible(FieldInfo fi, InteropAccessMode accessMode) { if (fi.GetVisibilityFromAttributes() ?? fi.IsPublic) { return new FieldMemberDescriptor(fi, accessMode); } return null; } public FieldMemberDescriptor(FieldInfo fi, InteropAccessMode accessMode) { if (Script.GlobalOptions.Platform.IsRunningOnAOT()) { accessMode = InteropAccessMode.Reflection; } FieldInfo = fi; AccessMode = accessMode; Name = fi.Name; IsStatic = FieldInfo.IsStatic; if (FieldInfo.IsLiteral) { IsConst = true; m_ConstValue = FieldInfo.GetValue(null); } else { IsReadonly = FieldInfo.IsInitOnly; } if (AccessMode == InteropAccessMode.Preoptimized) { OptimizeGetter(); } } public DynValue GetValue(Script script, object obj) { this.CheckAccess(MemberDescriptorAccess.CanRead, obj); if (IsConst) { return ClrToScriptConversions.ObjectToDynValue(script, m_ConstValue); } if (AccessMode == InteropAccessMode.LazyOptimized && m_OptimizedGetter == null) { OptimizeGetter(); } object obj2 = null; obj2 = ((m_OptimizedGetter == null) ? FieldInfo.GetValue(obj) : m_OptimizedGetter(obj)); return ClrToScriptConversions.ObjectToDynValue(script, obj2); } public void OptimizeGetter() { if (IsConst) { return; } using (PerformanceStatistics.StartGlobalStopwatch(PerformanceCounter.AdaptersCompilation)) { if (IsStatic) { ParameterExpression parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(object), "dummy"); Expression> expression = System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression.Field(null, FieldInfo), typeof(object)), new ParameterExpression[1] { parameterExpression }); Interlocked.Exchange(ref m_OptimizedGetter, expression.Compile()); } else { ParameterExpression parameterExpression2 = System.Linq.Expressions.Expression.Parameter(typeof(object), "obj"); Expression> expression2 = System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression.Field(System.Linq.Expressions.Expression.Convert(parameterExpression2, FieldInfo.DeclaringType), FieldInfo), typeof(object)), new ParameterExpression[1] { parameterExpression2 }); Interlocked.Exchange(ref m_OptimizedGetter, expression2.Compile()); } } } public void SetValue(Script script, object obj, DynValue v) { this.CheckAccess(MemberDescriptorAccess.CanWrite, obj); if (IsReadonly || IsConst) { throw new ScriptRuntimeException("userdata field '{0}.{1}' cannot be written to.", FieldInfo.DeclaringType.Name, Name); } object obj2 = ScriptToClrConversions.DynValueToObjectOfType(v, FieldInfo.FieldType, null, isOptional: false); try { if (obj2 is double) { obj2 = NumericConversions.DoubleToType(FieldInfo.FieldType, (double)obj2); } FieldInfo.SetValue(IsStatic ? null : obj, obj2); } catch (ArgumentException) { throw ScriptRuntimeException.UserDataArgumentTypeMismatch(v.Type, FieldInfo.FieldType); } catch (InvalidCastException) { throw ScriptRuntimeException.UserDataArgumentTypeMismatch(v.Type, FieldInfo.FieldType); } catch (FieldAccessException ex3) { throw new ScriptRuntimeException(ex3); } } void IOptimizableDescriptor.Optimize() { if (m_OptimizedGetter == null) { OptimizeGetter(); } } public void PrepareForWiring(Table t) { t.Set("class", DynValue.NewString(GetType().FullName)); t.Set("visibility", DynValue.NewString(FieldInfo.GetClrVisibility())); t.Set("name", DynValue.NewString(Name)); t.Set("static", DynValue.NewBoolean(IsStatic)); t.Set("const", DynValue.NewBoolean(IsConst)); t.Set("readonly", DynValue.NewBoolean(IsReadonly)); t.Set("decltype", DynValue.NewString(FieldInfo.DeclaringType.FullName)); t.Set("declvtype", DynValue.NewBoolean(Framework.Do.IsValueType(FieldInfo.DeclaringType))); t.Set("type", DynValue.NewString(FieldInfo.FieldType.FullName)); t.Set("read", DynValue.NewBoolean(v: true)); t.Set("write", DynValue.NewBoolean(!IsConst && !IsReadonly)); } } public class ValueTypeDefaultCtorMemberDescriptor : IOverloadableMemberDescriptor, IMemberDescriptor, IWireableDescriptor { public bool IsStatic => true; public string Name { get; set; } public Type ValueTypeDefaultCtor { get; set; } public ParameterDescriptor[] Parameters { get; set; } public Type ExtensionMethodType => null; public Type VarArgsArrayType => null; public Type VarArgsElementType => null; public string SortDiscriminant => "@.ctor"; public MemberDescriptorAccess MemberAccess => MemberDescriptorAccess.CanRead | MemberDescriptorAccess.CanExecute; public ValueTypeDefaultCtorMemberDescriptor(Type valueType) { if (!Framework.Do.IsValueType(valueType)) { throw new ArgumentException("valueType is not a value type"); } Name = "__new"; Parameters = new ParameterDescriptor[0]; ValueTypeDefaultCtor = valueType; } public DynValue Execute(Script script, object obj, ScriptExecutionContext context, CallbackArguments args) { this.CheckAccess(MemberDescriptorAccess.CanRead, obj); object obj2 = Activator.CreateInstance(ValueTypeDefaultCtor); return ClrToScriptConversions.ObjectToDynValue(script, obj2); } public DynValue GetValue(Script script, object obj) { this.CheckAccess(MemberDescriptorAccess.CanRead, obj); object obj2 = Activator.CreateInstance(ValueTypeDefaultCtor); return ClrToScriptConversions.ObjectToDynValue(script, obj2); } public void SetValue(Script script, object obj, DynValue value) { this.CheckAccess(MemberDescriptorAccess.CanWrite, obj); } public void PrepareForWiring(Table t) { t.Set("class", DynValue.NewString(GetType().FullName)); t.Set("type", DynValue.NewString(ValueTypeDefaultCtor.FullName)); t.Set("name", DynValue.NewString(Name)); } } public class StandardGenericsUserDataDescriptor : IUserDataDescriptor, IGeneratorUserDataDescriptor { public InteropAccessMode AccessMode { get; set; } public string Name { get; set; } public Type Type { get; set; } public StandardGenericsUserDataDescriptor(Type type, InteropAccessMode accessMode) { if (accessMode == InteropAccessMode.NoReflectionAllowed) { throw new ArgumentException("Can't create a StandardGenericsUserDataDescriptor under a NoReflectionAllowed access mode"); } AccessMode = accessMode; Type = type; Name = "@@" + type.FullName; } public DynValue Index(Script script, object obj, DynValue index, bool isDirectIndexing) { return null; } public bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing) { return false; } public string AsString(object obj) { return obj.ToString(); } public DynValue MetaIndex(Script script, object obj, string metaname) { return null; } public bool IsTypeCompatible(Type type, object obj) { return Framework.Do.IsInstanceOfType(type, obj); } public IUserDataDescriptor Generate(Type type) { if (UserData.IsTypeRegistered(type)) { return null; } if (Framework.Do.IsGenericTypeDefinition(type)) { return null; } return UserData.RegisterType(type, AccessMode); } } public static class InteropRegistrationPolicy { public static IRegistrationPolicy Default => new DefaultRegistrationPolicy(); [Obsolete("Please use InteropRegistrationPolicy.Default instead.")] public static IRegistrationPolicy Explicit => new DefaultRegistrationPolicy(); public static IRegistrationPolicy Automatic => new AutomaticRegistrationPolicy(); } public interface IUserDataType { DynValue Index(Script script, DynValue index, bool isDirectIndexing); bool SetIndex(Script script, DynValue index, DynValue value, bool isDirectIndexing); DynValue MetaIndex(Script script, string metaname); } public class AnonWrapper { } public class AnonWrapper : AnonWrapper { public T Value { get; set; } public AnonWrapper() { } public AnonWrapper(T o) { Value = o; } } public interface IUserDataDescriptor { string Name { get; } Type Type { get; } DynValue Index(Script script, object obj, DynValue index, bool isDirectIndexing); bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing); string AsString(object obj); DynValue MetaIndex(Script script, object obj, string metaname); bool IsTypeCompatible(Type type, object obj); } public class EnumerableWrapper : IUserDataType { public IEnumerator m_Enumerator; public Script m_Script; public DynValue m_Prev = DynValue.Nil; public bool m_HasTurnOnce; public EnumerableWrapper(Script script, IEnumerator enumerator) { m_Script = script; m_Enumerator = enumerator; } public void Reset() { if (m_HasTurnOnce) { m_Enumerator.Reset(); } m_HasTurnOnce = true; } public DynValue GetNext(DynValue prev) { if (prev.IsNil()) { Reset(); } while (m_Enumerator.MoveNext()) { DynValue dynValue = ClrToScriptConversions.ObjectToDynValue(m_Script, m_Enumerator.Current); if (!dynValue.IsNil()) { return dynValue; } } return DynValue.Nil; } public DynValue LuaIteratorCallback(ScriptExecutionContext executionContext, CallbackArguments args) { m_Prev = GetNext(m_Prev); return m_Prev; } public static DynValue ConvertIterator(Script script, IEnumerator enumerator) { EnumerableWrapper o = new EnumerableWrapper(script, enumerator); return DynValue.NewTuple(UserData.Create(o), DynValue.Nil, DynValue.Nil); } public static DynValue ConvertTable(Table table) { return ConvertIterator(table.OwnerScript, table.Values.GetEnumerator()); } public DynValue Index(Script script, DynValue index, bool isDirectIndexing) { if (index.Type == DataType.String) { switch (index.String) { case "Current": case "current": return DynValue.FromObject(script, m_Enumerator.Current); case "MoveNext": case "moveNext": case "move_next": return DynValue.NewCallback((ScriptExecutionContext ctx, CallbackArguments args) => DynValue.NewBoolean(m_Enumerator.MoveNext())); case "Reset": case "reset": return DynValue.NewCallback(delegate { Reset(); return DynValue.Nil; }); } } return null; } public bool SetIndex(Script script, DynValue index, DynValue value, bool isDirectIndexing) { return false; } public DynValue MetaIndex(Script script, string metaname) { if (metaname == "__call") { return DynValue.NewCallback(LuaIteratorCallback); } return null; } } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event, Inherited = true, AllowMultiple = false)] public sealed class MoonSharpVisibleAttribute : Attribute { public bool Visible { get; set; } public MoonSharpVisibleAttribute(bool visible) { Visible = visible; } } public class CompositeUserDataDescriptor : IUserDataDescriptor { public List m_Descriptors; public Type m_Type; public IList Descriptors => m_Descriptors; public string Name => "^" + m_Type.FullName; public Type Type => m_Type; public CompositeUserDataDescriptor(List descriptors, Type type) { m_Descriptors = descriptors; m_Type = type; } public DynValue Index(Script script, object obj, DynValue index, bool isNameIndex) { foreach (IUserDataDescriptor descriptor in m_Descriptors) { DynValue dynValue = descriptor.Index(script, obj, index, isNameIndex); if (dynValue != null) { return dynValue; } } return null; } public bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool isNameIndex) { foreach (IUserDataDescriptor descriptor in m_Descriptors) { if (descriptor.SetIndex(script, obj, index, value, isNameIndex)) { return true; } } return false; } public string AsString(object obj) { return obj?.ToString(); } public DynValue MetaIndex(Script script, object obj, string metaname) { foreach (IUserDataDescriptor descriptor in m_Descriptors) { DynValue dynValue = descriptor.MetaIndex(script, obj, metaname); if (dynValue != null) { return dynValue; } } return null; } public bool IsTypeCompatible(Type type, object obj) { return Framework.Do.IsInstanceOfType(type, obj); } } public class StandardUserDataDescriptor : DispatchingUserDataDescriptor, IWireableDescriptor { public InteropAccessMode AccessMode { get; set; } public StandardUserDataDescriptor(Type type, InteropAccessMode accessMode, string friendlyName = null) : base(type, friendlyName) { if (accessMode == InteropAccessMode.NoReflectionAllowed) { throw new ArgumentException("Can't create a StandardUserDataDescriptor under a NoReflectionAllowed access mode"); } if (Script.GlobalOptions.Platform.IsRunningOnAOT()) { accessMode = InteropAccessMode.Reflection; } if (accessMode == InteropAccessMode.Default) { accessMode = UserData.DefaultAccessMode; } AccessMode = accessMode; FillMemberList(); } public void FillMemberList() { HashSet hashSet = new HashSet(from a in Framework.Do.GetCustomAttributes(base.Type, typeof(MoonSharpHideMemberAttribute), inherit: true).OfType() select a.MemberName); Type type = base.Type; if (AccessMode == InteropAccessMode.HideMembers) { return; } if (!type.IsDelegateType()) { ConstructorInfo[] constructors = Framework.Do.GetConstructors(type); foreach (ConstructorInfo methodBase in constructors) { if (!hashSet.Contains("__new")) { AddMember("__new", MethodMemberDescriptor.TryCreateIfVisible(methodBase, AccessMode)); } } if (Framework.Do.IsValueType(type) && !hashSet.Contains("__new")) { AddMember("__new", new ValueTypeDefaultCtorMemberDescriptor(type)); } } MethodInfo[] methods = Framework.Do.GetMethods(type); foreach (MethodInfo methodInfo in methods) { if (hashSet.Contains(methodInfo.Name)) { continue; } MethodMemberDescriptor methodMemberDescriptor = MethodMemberDescriptor.TryCreateIfVisible(methodInfo, AccessMode); if (methodMemberDescriptor == null || !MethodMemberDescriptor.CheckMethodIsCompatible(methodInfo, throwException: false)) { continue; } string name = methodInfo.Name; if (methodInfo.IsSpecialName && (methodInfo.Name == "op_Explicit" || methodInfo.Name == "op_Implicit")) { name = methodInfo.ReturnType.GetConversionMethodName(); } AddMember(name, methodMemberDescriptor); foreach (string metaNamesFromAttribute in methodInfo.GetMetaNamesFromAttributes()) { AddMetaMember(metaNamesFromAttribute, methodMemberDescriptor); } } PropertyInfo[] properties = Framework.Do.GetProperties(type); foreach (PropertyInfo propertyInfo in properties) { if (!propertyInfo.IsSpecialName && !propertyInfo.GetIndexParameters().Any() && !hashSet.Contains(propertyInfo.Name)) { AddMember(propertyInfo.Name, PropertyMemberDescriptor.TryCreateIfVisible(propertyInfo, AccessMode)); } } FieldInfo[] fields = Framework.Do.GetFields(type); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsSpecialName && !hashSet.Contains(fieldInfo.Name)) { AddMember(fieldInfo.Name, FieldMemberDescriptor.TryCreateIfVisible(fieldInfo, AccessMode)); } } EventInfo[] events = Framework.Do.GetEvents(type); foreach (EventInfo eventInfo in events) { if (!eventInfo.IsSpecialName && !hashSet.Contains(eventInfo.Name)) { AddMember(eventInfo.Name, EventMemberDescriptor.TryCreateIfVisible(eventInfo, AccessMode)); } } Type[] nestedTypes = Framework.Do.GetNestedTypes(type); foreach (Type type2 in nestedTypes) { if (!hashSet.Contains(type2.Name) && !Framework.Do.IsGenericTypeDefinition(type2) && (Framework.Do.IsNestedPublic(type2) || Framework.Do.GetCustomAttributes(type2, typeof(MoonSharpUserDataAttribute), inherit: true).Length != 0) && UserData.RegisterType(type2, AccessMode) != null) { AddDynValue(type2.Name, UserData.CreateStatic(type2)); } } if (hashSet.Contains("[this]")) { return; } if (base.Type.IsArray) { int arrayRank = base.Type.GetArrayRank(); ParameterDescriptor[] array = new ParameterDescriptor[arrayRank]; ParameterDescriptor[] array2 = new ParameterDescriptor[arrayRank + 1]; for (int j = 0; j < arrayRank; j++) { array[j] = (array2[j] = new ParameterDescriptor("idx" + j, typeof(int))); } array2[arrayRank] = new ParameterDescriptor("value", base.Type.GetElementType()); AddMember("set_Item", new ArrayMemberDescriptor("set_Item", isSetter: true, array2)); AddMember("get_Item", new ArrayMemberDescriptor("get_Item", isSetter: false, array)); } else if (base.Type == typeof(Array)) { AddMember("set_Item", new ArrayMemberDescriptor("set_Item", isSetter: true)); AddMember("get_Item", new ArrayMemberDescriptor("get_Item", isSetter: false)); } } public void PrepareForWiring(Table t) { if (AccessMode == InteropAccessMode.HideMembers || Framework.Do.GetAssembly(base.Type) == Framework.Do.GetAssembly(GetType())) { t.Set("skip", DynValue.NewBoolean(v: true)); return; } t.Set("visibility", DynValue.NewString(base.Type.GetClrVisibility())); t.Set("class", DynValue.NewString(GetType().FullName)); DynValue dynValue = DynValue.NewPrimeTable(); t.Set("members", dynValue); DynValue dynValue2 = DynValue.NewPrimeTable(); t.Set("metamembers", dynValue2); Serialize(dynValue.Table, base.Members); Serialize(dynValue2.Table, base.MetaMembers); } public void Serialize(Table t, IEnumerable> members) { foreach (KeyValuePair member in members) { if (member.Value is IWireableDescriptor wireableDescriptor) { DynValue dynValue = DynValue.NewPrimeTable(); t.Set(member.Key, dynValue); wireableDescriptor.PrepareForWiring(dynValue.Table); } else { t.Set(member.Key, DynValue.NewString("unsupported member type : " + member.Value.GetType().FullName)); } } } } public class MethodMemberDescriptor : FunctionMemberDescriptorBase, IOptimizableDescriptor, IWireableDescriptor { public Func m_OptimizedFunc; public Action m_OptimizedAction; public bool m_IsAction; public bool m_IsArrayCtor; public MethodBase MethodInfo { get; set; } public InteropAccessMode AccessMode { get; set; } public bool IsConstructor { get; set; } public MethodMemberDescriptor(MethodBase methodBase, InteropAccessMode accessMode = InteropAccessMode.Default) { CheckMethodIsCompatible(methodBase, throwException: true); IsConstructor = methodBase is ConstructorInfo; MethodInfo = methodBase; bool isStatic = methodBase.IsStatic || IsConstructor; if (IsConstructor) { m_IsAction = false; } else { m_IsAction = ((MethodInfo)methodBase).ReturnType == typeof(void); } ParameterInfo[] parameters = methodBase.GetParameters(); ParameterDescriptor[] array; if (MethodInfo.DeclaringType.IsArray) { m_IsArrayCtor = true; int arrayRank = MethodInfo.DeclaringType.GetArrayRank(); array = new ParameterDescriptor[arrayRank]; for (int i = 0; i < arrayRank; i++) { array[i] = new ParameterDescriptor("idx" + i, typeof(int)); } } else { array = parameters.Select((ParameterInfo pi) => new ParameterDescriptor(pi)).ToArray(); } bool isExtensionMethod = methodBase.IsStatic && array.Length != 0 && methodBase.GetCustomAttributes(typeof(ExtensionAttribute), inherit: false).Any(); Initialize(methodBase.Name, isStatic, array, isExtensionMethod); if (Script.GlobalOptions.Platform.IsRunningOnAOT()) { accessMode = InteropAccessMode.Reflection; } if (accessMode == InteropAccessMode.Default) { accessMode = UserData.DefaultAccessMode; } if (accessMode == InteropAccessMode.HideMembers) { throw new ArgumentException("Invalid accessMode"); } if (array.Any((ParameterDescriptor p) => p.Type.IsByRef)) { accessMode = InteropAccessMode.Reflection; } AccessMode = accessMode; if (AccessMode == InteropAccessMode.Preoptimized) { ((IOptimizableDescriptor)this).Optimize(); } } public static MethodMemberDescriptor TryCreateIfVisible(MethodBase methodBase, InteropAccessMode accessMode, bool forceVisibility = false) { if (!CheckMethodIsCompatible(methodBase, throwException: false)) { return null; } if (forceVisibility || (methodBase.GetVisibilityFromAttributes() ?? methodBase.IsPublic)) { return new MethodMemberDescriptor(methodBase, accessMode); } return null; } public static bool CheckMethodIsCompatible(MethodBase methodBase, bool throwException) { if (methodBase.ContainsGenericParameters) { if (throwException) { throw new ArgumentException("Method cannot contain unresolved generic parameters"); } return false; } if (methodBase.GetParameters().Any((ParameterInfo p) => p.ParameterType.IsPointer)) { if (throwException) { throw new ArgumentException("Method cannot contain pointer parameters"); } return false; } MethodInfo methodInfo = methodBase as MethodInfo; if (methodInfo != null) { if (methodInfo.ReturnType.IsPointer) { if (throwException) { throw new ArgumentException("Method cannot have a pointer return type"); } return false; } if (Framework.Do.IsGenericTypeDefinition(methodInfo.ReturnType)) { if (throwException) { throw new ArgumentException("Method cannot have an unresolved generic return type"); } return false; } } return true; } public override DynValue Execute(Script script, object obj, ScriptExecutionContext context, CallbackArguments args) { this.CheckAccess(MemberDescriptorAccess.CanExecute, obj); if (AccessMode == InteropAccessMode.LazyOptimized && m_OptimizedFunc == null && m_OptimizedAction == null) { ((IOptimizableDescriptor)this).Optimize(); } List outParams = null; object[] array = base.BuildArgumentList(script, obj, context, args, out outParams); object obj2 = null; if (m_OptimizedFunc != null) { obj2 = m_OptimizedFunc(obj, array); } else if (m_OptimizedAction != null) { m_OptimizedAction(obj, array); obj2 = DynValue.Void; } else if (!m_IsAction) { obj2 = ((!IsConstructor) ? MethodInfo.Invoke(obj, array) : ((ConstructorInfo)MethodInfo).Invoke(array)); } else { MethodInfo.Invoke(obj, array); obj2 = DynValue.Void; } return FunctionMemberDescriptorBase.BuildReturnValue(script, outParams, array, obj2); } void IOptimizableDescriptor.Optimize() { ParameterDescriptor[] parameters = base.Parameters; if (AccessMode == InteropAccessMode.Reflection) { return; } MethodInfo methodInfo = MethodInfo as MethodInfo; if (methodInfo == null) { return; } using (PerformanceStatistics.StartGlobalStopwatch(PerformanceCounter.AdaptersCompilation)) { ParameterExpression parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(object[]), "pars"); ParameterExpression parameterExpression2 = System.Linq.Expressions.Expression.Parameter(typeof(object), "instance"); UnaryExpression instance = System.Linq.Expressions.Expression.Convert(parameterExpression2, MethodInfo.DeclaringType); System.Linq.Expressions.Expression[] array = new System.Linq.Expressions.Expression[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { if (parameters[i].OriginalType.IsByRef) { throw new InternalErrorException("Out/Ref params cannot be precompiled."); } BinaryExpression expression = System.Linq.Expressions.Expression.ArrayIndex(parameterExpression, System.Linq.Expressions.Expression.Constant(i)); array[i] = System.Linq.Expressions.Expression.Convert(expression, parameters[i].OriginalType); } System.Linq.Expressions.Expression expression2 = ((!base.IsStatic) ? System.Linq.Expressions.Expression.Call(instance, methodInfo, array) : System.Linq.Expressions.Expression.Call(methodInfo, array)); if (m_IsAction) { Expression> expression3 = System.Linq.Expressions.Expression.Lambda>(expression2, new ParameterExpression[2] { parameterExpression2, parameterExpression }); Interlocked.Exchange(ref m_OptimizedAction, expression3.Compile()); } else { Expression> expression4 = System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression.Convert(expression2, typeof(object)), new ParameterExpression[2] { parameterExpression2, parameterExpression }); Interlocked.Exchange(ref m_OptimizedFunc, expression4.Compile()); } } } public void PrepareForWiring(Table t) { t.Set("class", DynValue.NewString(GetType().FullName)); t.Set("name", DynValue.NewString(base.Name)); t.Set("ctor", DynValue.NewBoolean(IsConstructor)); t.Set("special", DynValue.NewBoolean(MethodInfo.IsSpecialName)); t.Set("visibility", DynValue.NewString(MethodInfo.GetClrVisibility())); if (IsConstructor) { t.Set("ret", DynValue.NewString(((ConstructorInfo)MethodInfo).DeclaringType.FullName)); } else { t.Set("ret", DynValue.NewString(((MethodInfo)MethodInfo).ReturnType.FullName)); } if (m_IsArrayCtor) { t.Set("arraytype", DynValue.NewString(MethodInfo.DeclaringType.GetElementType().FullName)); } t.Set("decltype", DynValue.NewString(MethodInfo.DeclaringType.FullName)); t.Set("static", DynValue.NewBoolean(base.IsStatic)); t.Set("extension", DynValue.NewBoolean(base.ExtensionMethodType != null)); DynValue dynValue = DynValue.NewPrimeTable(); t.Set("params", dynValue); int num = 0; ParameterDescriptor[] parameters = base.Parameters; foreach (ParameterDescriptor obj in parameters) { DynValue dynValue2 = DynValue.NewPrimeTable(); dynValue.Table.Set(++num, dynValue2); obj.PrepareForWiring(dynValue2.Table); } } } public class PropertyMemberDescriptor : IMemberDescriptor, IOptimizableDescriptor, IWireableDescriptor { public MethodInfo m_Getter; public MethodInfo m_Setter; public Func m_OptimizedGetter; public Action m_OptimizedSetter; public PropertyInfo PropertyInfo { get; set; } public InteropAccessMode AccessMode { get; set; } public bool IsStatic { get; set; } public string Name { get; set; } public bool CanRead => m_Getter != null; public bool CanWrite => m_Setter != null; public MemberDescriptorAccess MemberAccess { get { MemberDescriptorAccess memberDescriptorAccess = (MemberDescriptorAccess)0; if (m_Setter != null) { memberDescriptorAccess |= MemberDescriptorAccess.CanWrite; } if (m_Getter != null) { memberDescriptorAccess |= MemberDescriptorAccess.CanRead; } return memberDescriptorAccess; } } public static PropertyMemberDescriptor TryCreateIfVisible(PropertyInfo pi, InteropAccessMode accessMode) { MethodInfo getMethod = Framework.Do.GetGetMethod(pi); MethodInfo setMethod = Framework.Do.GetSetMethod(pi); bool? visibilityFromAttributes = pi.GetVisibilityFromAttributes(); bool? visibilityFromAttributes2 = getMethod.GetVisibilityFromAttributes(); bool? visibilityFromAttributes3 = setMethod.GetVisibilityFromAttributes(); if (visibilityFromAttributes.HasValue) { return TryCreate(pi, accessMode, (visibilityFromAttributes2 ?? visibilityFromAttributes.Value) ? getMethod : null, (visibilityFromAttributes3 ?? visibilityFromAttributes.Value) ? setMethod : null); } return TryCreate(pi, accessMode, (visibilityFromAttributes2 ?? getMethod.IsPublic) ? getMethod : null, (visibilityFromAttributes3 ?? setMethod.IsPublic) ? setMethod : null); } public static PropertyMemberDescriptor TryCreate(PropertyInfo pi, InteropAccessMode accessMode, MethodInfo getter, MethodInfo setter) { if (getter == null && setter == null) { return null; } return new PropertyMemberDescriptor(pi, accessMode, getter, setter); } public PropertyMemberDescriptor(PropertyInfo pi, InteropAccessMode accessMode) : this(pi, accessMode, Framework.Do.GetGetMethod(pi), Framework.Do.GetSetMethod(pi)) { } public PropertyMemberDescriptor(PropertyInfo pi, InteropAccessMode accessMode, MethodInfo getter, MethodInfo setter) { if (getter == null && setter == null) { throw new ArgumentNullException("getter and setter cannot both be null"); } if (Script.GlobalOptions.Platform.IsRunningOnAOT()) { accessMode = InteropAccessMode.Reflection; } PropertyInfo = pi; AccessMode = accessMode; Name = pi.Name; m_Getter = getter; m_Setter = setter; IsStatic = (m_Getter ?? m_Setter).IsStatic; if (AccessMode == InteropAccessMode.Preoptimized) { OptimizeGetter(); OptimizeSetter(); } } public DynValue GetValue(Script script, object obj) { this.CheckAccess(MemberDescriptorAccess.CanRead, obj); if (m_Getter == null) { throw new ScriptRuntimeException("userdata property '{0}.{1}' cannot be read from.", PropertyInfo.DeclaringType.Name, Name); } if (AccessMode == InteropAccessMode.LazyOptimized && m_OptimizedGetter == null) { OptimizeGetter(); } object obj2 = null; obj2 = ((m_OptimizedGetter == null) ? m_Getter.Invoke(IsStatic ? null : obj, null) : m_OptimizedGetter(obj)); return ClrToScriptConversions.ObjectToDynValue(script, obj2); } public void OptimizeGetter() { using (PerformanceStatistics.StartGlobalStopwatch(PerformanceCounter.AdaptersCompilation)) { if (m_Getter != null) { if (IsStatic) { ParameterExpression parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(object), "dummy"); Expression> expression = System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression.Property(null, PropertyInfo), typeof(object)), new ParameterExpression[1] { parameterExpression }); Interlocked.Exchange(ref m_OptimizedGetter, expression.Compile()); } else { ParameterExpression parameterExpression2 = System.Linq.Expressions.Expression.Parameter(typeof(object), "obj"); Expression> expression2 = System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression.Convert(parameterExpression2, PropertyInfo.DeclaringType), PropertyInfo), typeof(object)), new ParameterExpression[1] { parameterExpression2 }); Interlocked.Exchange(ref m_OptimizedGetter, expression2.Compile()); } } } } public void OptimizeSetter() { using (PerformanceStatistics.StartGlobalStopwatch(PerformanceCounter.AdaptersCompilation)) { if (m_Setter != null && !Framework.Do.IsValueType(PropertyInfo.DeclaringType)) { MethodInfo setMethod = Framework.Do.GetSetMethod(PropertyInfo); if (IsStatic) { ParameterExpression parameterExpression = System.Linq.Expressions.Expression.Parameter(typeof(object), "dummy"); ParameterExpression parameterExpression2 = System.Linq.Expressions.Expression.Parameter(typeof(object), "val"); UnaryExpression arg = System.Linq.Expressions.Expression.Convert(parameterExpression2, PropertyInfo.PropertyType); Expression> expression = System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression.Call(setMethod, arg), new ParameterExpression[2] { parameterExpression, parameterExpression2 }); Interlocked.Exchange(ref m_OptimizedSetter, expression.Compile()); } else { ParameterExpression parameterExpression3 = System.Linq.Expressions.Expression.Parameter(typeof(object), "obj"); ParameterExpression parameterExpression4 = System.Linq.Expressions.Expression.Parameter(typeof(object), "val"); UnaryExpression instance = System.Linq.Expressions.Expression.Convert(parameterExpression3, PropertyInfo.DeclaringType); UnaryExpression unaryExpression = System.Linq.Expressions.Expression.Convert(parameterExpression4, PropertyInfo.PropertyType); Expression> expression2 = System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression.Call(instance, setMethod, unaryExpression), new ParameterExpression[2] { parameterExpression3, parameterExpression4 }); Interlocked.Exchange(ref m_OptimizedSetter, expression2.Compile()); } } } } public void SetValue(Script script, object obj, DynValue v) { this.CheckAccess(MemberDescriptorAccess.CanWrite, obj); if (m_Setter == null) { throw new ScriptRuntimeException("userdata property '{0}.{1}' cannot be written to.", PropertyInfo.DeclaringType.Name, Name); } object obj2 = ScriptToClrConversions.DynValueToObjectOfType(v, PropertyInfo.PropertyType, null, isOptional: false); try { if (obj2 is double) { obj2 = NumericConversions.DoubleToType(PropertyInfo.PropertyType, (double)obj2); } if (AccessMode == InteropAccessMode.LazyOptimized && m_OptimizedSetter == null) { OptimizeSetter(); } if (m_OptimizedSetter != null) { m_OptimizedSetter(obj, obj2); return; } m_Setter.Invoke(IsStatic ? null : obj, new object[1] { obj2 }); } catch (ArgumentException) { throw ScriptRuntimeException.UserDataArgumentTypeMismatch(v.Type, PropertyInfo.PropertyType); } catch (InvalidCastException) { throw ScriptRuntimeException.UserDataArgumentTypeMismatch(v.Type, PropertyInfo.PropertyType); } } void IOptimizableDescriptor.Optimize() { OptimizeGetter(); OptimizeSetter(); } public void PrepareForWiring(Table t) { t.Set("class", DynValue.NewString(GetType().FullName)); t.Set("visibility", DynValue.NewString(PropertyInfo.GetClrVisibility())); t.Set("name", DynValue.NewString(Name)); t.Set("static", DynValue.NewBoolean(IsStatic)); t.Set("read", DynValue.NewBoolean(CanRead)); t.Set("write", DynValue.NewBoolean(CanWrite)); t.Set("decltype", DynValue.NewString(PropertyInfo.DeclaringType.FullName)); t.Set("declvtype", DynValue.NewBoolean(Framework.Do.IsValueType(PropertyInfo.DeclaringType))); t.Set("type", DynValue.NewString(PropertyInfo.PropertyType.FullName)); } } public static class NamespaceDoc { } } namespace MoonSharp.Interpreter.Interop.LuaStateInterop { public class CharPtr { public char[] chars; public int index; public char this[int offset] { get { return chars[index + offset]; } set { chars[index + offset] = value; } } public char this[uint offset] { get { return chars[index + offset]; } set { chars[index + offset] = value; } } public char this[long offset] { get { return chars[index + (int)offset]; } set { chars[index + (int)offset] = value; } } public static implicit operator CharPtr(string str) { return new CharPtr(str); } public static implicit operator CharPtr(char[] chars) { return new CharPtr(chars); } public static implicit operator CharPtr(byte[] bytes) { return new CharPtr(bytes); } public CharPtr() { chars = null; index = 0; } public CharPtr(string str) { chars = (str + "\0").ToCharArray(); index = 0; } public CharPtr(CharPtr ptr) { chars = ptr.chars; index = ptr.index; } public CharPtr(CharPtr ptr, int index) { chars = ptr.chars; this.index = index; } public CharPtr(char[] chars) { this.chars = chars; index = 0; } public CharPtr(char[] chars, int index) { this.chars = chars; this.index = index; } public CharPtr(byte[] bytes) { chars = new char[bytes.Length]; for (int i = 0; i < bytes.Length; i++) { chars[i] = (char)bytes[i]; } index = 0; } public CharPtr(IntPtr ptr) { chars = new char[0]; index = 0; } public static CharPtr operator +(CharPtr ptr, int offset) { return new CharPtr(ptr.chars, ptr.index + offset); } public static CharPtr operator -(CharPtr ptr, int offset) { return new CharPtr(ptr.chars, ptr.index - offset); } public static CharPtr operator +(CharPtr ptr, uint offset) { return new CharPtr(ptr.chars, ptr.index + (int)offset); } public static CharPtr operator -(CharPtr ptr, uint offset) { return new CharPtr(ptr.chars, ptr.index - (int)offset); } public void inc() { index++; } public void dec() { index--; } public CharPtr next() { return new CharPtr(chars, index + 1); } public CharPtr prev() { return new CharPtr(chars, index - 1); } public CharPtr add(int ofs) { return new CharPtr(chars, index + ofs); } public CharPtr sub(int ofs) { return new CharPtr(chars, index - ofs); } public static bool operator ==(CharPtr ptr, char ch) { return ptr[0] == ch; } public static bool operator ==(char ch, CharPtr ptr) { return ptr[0] == ch; } public static bool operator !=(CharPtr ptr, char ch) { return ptr[0] != ch; } public static bool operator !=(char ch, CharPtr ptr) { return ptr[0] != ch; } public static CharPtr operator +(CharPtr ptr1, CharPtr ptr2) { string text = ""; for (int i = 0; ptr1[i] != 0; i++) { text += ptr1[i]; } for (int j = 0; ptr2[j] != 0; j++) { text += ptr2[j]; } return new CharPtr(text); } public static int operator -(CharPtr ptr1, CharPtr ptr2) { return ptr1.index - ptr2.index; } public static bool operator <(CharPtr ptr1, CharPtr ptr2) { return ptr1.index < ptr2.index; } public static bool operator <=(CharPtr ptr1, CharPtr ptr2) { return ptr1.index <= ptr2.index; } public static bool operator >(CharPtr ptr1, CharPtr ptr2) { return ptr1.index > ptr2.index; } public static bool operator >=(CharPtr ptr1, CharPtr ptr2) { return ptr1.index >= ptr2.index; } public static bool operator ==(CharPtr ptr1, CharPtr ptr2) { if ((object)ptr1 == null && (object)ptr2 == null) { return true; } if ((object)ptr1 == null) { return false; } if ((object)ptr2 == null) { return false; } if (ptr1.chars == ptr2.chars) { return ptr1.index == ptr2.index; } return false; } public static bool operator !=(CharPtr ptr1, CharPtr ptr2) { return !(ptr1 == ptr2); } public override bool Equals(object o) { return this == o as CharPtr; } public override int GetHashCode() { return 0; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); for (int i = index; i < chars.Length && chars[i] != 0; i++) { stringBuilder.Append(chars[i]); } return stringBuilder.ToString(); } public string ToString(int length) { StringBuilder stringBuilder = new StringBuilder(); for (int i = index; i < chars.Length && i < length + index; i++) { stringBuilder.Append(chars[i]); } return stringBuilder.ToString(); } } public class LuaBase { public const int LUA_TNONE = -1; public const int LUA_TNIL = 0; public const int LUA_TBOOLEAN = 1; public const int LUA_TLIGHTUSERDATA = 2; public const int LUA_TNUMBER = 3; public const int LUA_TSTRING = 4; public const int LUA_TTABLE = 5; public const int LUA_TFUNCTION = 6; public const int LUA_TUSERDATA = 7; public const int LUA_TTHREAD = 8; public const int LUA_MULTRET = -1; public const string LUA_INTFRMLEN = "l"; public static DynValue GetArgument(LuaState L, int pos) { return L.At(pos); } public static DynValue ArgAsType(LuaState L, int pos, DataType type, bool allowNil = false) { return GetArgument(L, pos).CheckType(L.FunctionName, type, pos - 1, allowNil ? (TypeValidationFlags.AllowNil | TypeValidationFlags.AutoConvert) : TypeValidationFlags.AutoConvert); } public static int LuaType(LuaState L, int p) { return GetArgument(L, p).Type switch { DataType.Void => -1, DataType.Nil => 0, DataType.Boolean => 0, DataType.Number => 3, DataType.String => 4, DataType.Function => 6, DataType.Table => 5, DataType.UserData => 7, DataType.Thread => 8, DataType.ClrFunction => 6, _ => throw new ScriptRuntimeException("Can't call LuaType on any type"), }; } public static string LuaLCheckLString(LuaState L, int argNum, out uint l) { string @string = ArgAsType(L, argNum, DataType.String).String; l = (uint)@string.Length; return @string; } public static void LuaPushInteger(LuaState L, int val) { L.Push(DynValue.NewNumber(val)); } public static int LuaToBoolean(LuaState L, int p) { if (!GetArgument(L, p).CastToBool()) { return 0; } return 1; } public static string LuaToLString(LuaState luaState, int p, out uint l) { return LuaLCheckLString(luaState, p, out l); } public static string LuaToString(LuaState luaState, int p) { uint l; return LuaLCheckLString(luaState, p, out l); } public static void LuaLAddValue(LuaLBuffer b) { b.StringBuilder.Append(b.LuaState.Pop().ToPrintString()); } public static void LuaLAddLString(LuaLBuffer b, CharPtr s, uint p) { b.StringBuilder.Append(s.ToString((int)p)); } public static void LuaLAddString(LuaLBuffer b, string s) { b.StringBuilder.Append(s.ToString()); } public static int LuaLOptInteger(LuaState L, int pos, int def) { DynValue dynValue = ArgAsType(L, pos, DataType.Number, allowNil: true); if (dynValue.IsNil()) { return def; } return (int)dynValue.Number; } public static int LuaLCheckInteger(LuaState L, int pos) { return (int)ArgAsType(L, pos, DataType.Number).Number; } public static void LuaLArgCheck(LuaState L, bool condition, int argNum, string message) { if (!condition) { LuaLArgError(L, argNum, message); } } public static int LuaLCheckInt(LuaState L, int argNum) { return LuaLCheckInteger(L, argNum); } public static int LuaGetTop(LuaState L) { return L.Count; } public static int LuaLError(LuaState luaState, string message, params object[] args) { throw new ScriptRuntimeException(message, args); } public static void LuaLAddChar(LuaLBuffer b, char p) { b.StringBuilder.Append(p); } public static void LuaLBuffInit(LuaState L, LuaLBuffer b) { } public static void LuaPushLiteral(LuaState L, string literalString) { L.Push(DynValue.NewString(literalString)); } public static void LuaLPushResult(LuaLBuffer b) { LuaPushLiteral(b.LuaState, b.StringBuilder.ToString()); } public static void LuaPushLString(LuaState L, CharPtr s, uint len) { string str = s.ToString((int)len); L.Push(DynValue.NewString(str)); } public static void LuaLCheckStack(LuaState L, int n, string message) { } public static string LUA_QL(string p) { return "'" + p + "'"; } public static void LuaPushNil(LuaState L) { L.Push(DynValue.Nil); } public static void LuaAssert(bool p) { } public static string LuaLTypeName(LuaState L, int p) { return L.At(p).Type.ToErrorTypeString(); } public static int LuaIsString(LuaState L, int p) { DynValue dynValue = L.At(p); if (dynValue.Type != DataType.String && dynValue.Type != DataType.Number) { return 0; } return 1; } public static void LuaPop(LuaState L, int p) { for (int i = 0; i < p; i++) { L.Pop(); } } public static void LuaGetTable(LuaState L, int p) { DynValue key = L.Pop(); DynValue dynValue = L.At(p); if (dynValue.Type != DataType.Table) { throw new NotImplementedException(); } DynValue v = dynValue.Table.Get(key); L.Push(v); } public static int LuaLOptInt(LuaState L, int pos, int def) { return LuaLOptInteger(L, pos, def); } public static CharPtr LuaLCheckString(LuaState L, int p) { uint l; return LuaLCheckLString(L, p, out l); } public static string LuaLCheckStringStr(LuaState L, int p) { uint l; return LuaLCheckLString(L, p, out l); } public static void LuaLArgError(LuaState L, int arg, string p) { throw ScriptRuntimeException.BadArgument(arg - 1, L.FunctionName, p); } public static double LuaLCheckNumber(LuaState L, int pos) { return ArgAsType(L, pos, DataType.Number).Number; } public static void LuaPushValue(LuaState L, int arg) { DynValue v = L.At(arg); L.Push(v); } public static void LuaCall(LuaState L, int nargs, int nresults = -1) { DynValue[] topArray = L.GetTopArray(nargs); L.Discard(nargs); DynValue func = L.Pop(); DynValue dynValue = L.ExecutionContext.Call(func, topArray); switch (nresults) { case -1: nresults = ((dynValue.Type != DataType.Tuple) ? 1 : dynValue.Tuple.Length); break; case 0: return; } DynValue[] array = ((dynValue.Type == DataType.Tuple) ? dynValue.Tuple : new DynValue[1] { dynValue }); int num = 0; int num2 = 0; while (num2 < array.Length && num < nresults) { L.Push(array[num2]); num2++; num++; } while (num < nresults) { L.Push(DynValue.Nil); } } public static int memcmp(CharPtr ptr1, CharPtr ptr2, uint size) { return memcmp(ptr1, ptr2, (int)size); } public static int memcmp(CharPtr ptr1, CharPtr ptr2, int size) { for (int i = 0; i < size; i++) { if (ptr1[i] != ptr2[i]) { if (ptr1[i] < ptr2[i]) { return -1; } return 1; } } return 0; } public static CharPtr memchr(CharPtr ptr, char c, uint count) { for (uint num = 0u; num < count; num++) { if (ptr[num] == c) { return new CharPtr(ptr.chars, (int)(ptr.index + num)); } } return null; } public static CharPtr strpbrk(CharPtr str, CharPtr charset) { for (int i = 0; str[i] != 0; i++) { for (int j = 0; charset[j] != 0; j++) { if (str[i] == charset[j]) { return new CharPtr(str.chars, str.index + i); } } } return null; } public static bool isalpha(char c) { return char.IsLetter(c); } public static bool iscntrl(char c) { return char.IsControl(c); } public static bool isdigit(char c) { return char.IsDigit(c); } public static bool islower(char c) { return char.IsLower(c); } public static bool ispunct(char c) { return char.IsPunctuation(c); } public static bool isspace(char c) { if (c != ' ') { if (c >= '\t') { return c <= '\r'; } return false; } return true; } public static bool isupper(char c) { return char.IsUpper(c); } public static bool isalnum(char c) { return char.IsLetterOrDigit(c); } public static bool isxdigit(char c) { return "0123456789ABCDEFabcdef".IndexOf(c) >= 0; } public static bool isgraph(char c) { if (!char.IsControl(c)) { return !char.IsWhiteSpace(c); } return false; } public static bool isalpha(int c) { return char.IsLetter((char)c); } public static bool iscntrl(int c) { return char.IsControl((char)c); } public static bool isdigit(int c) { return char.IsDigit((char)c); } public static bool islower(int c) { return char.IsLower((char)c); } public static bool ispunct(int c) { if ((ushort)c != 32) { return !isalnum((char)c); } return false; } public static bool isspace(int c) { if ((ushort)c != 32) { if ((ushort)c >= 9) { return (ushort)c <= 13; } return false; } return true; } public static bool isupper(int c) { return char.IsUpper((char)c); } public static bool isalnum(int c) { return char.IsLetterOrDigit((char)c); } public static bool isgraph(int c) { if (!char.IsControl((char)c)) { return !char.IsWhiteSpace((char)c); } return false; } public static char tolower(char c) { return char.ToLower(c); } public static char toupper(char c) { return char.ToUpper(c); } public static char tolower(int c) { return char.ToLower((char)c); } public static char toupper(int c) { return char.ToUpper((char)c); } public static CharPtr strchr(CharPtr str, char c) { for (int i = str.index; str.chars[i] != 0; i++) { if (str.chars[i] == c) { return new CharPtr(str.chars, i); } } return null; } public static CharPtr strcpy(CharPtr dst, CharPtr src) { int i; for (i = 0; src[i] != 0; i++) { dst[i] = src[i]; } dst[i] = '\0'; return dst; } public static CharPtr strncpy(CharPtr dst, CharPtr src, int length) { int i; for (i = 0; src[i] != 0 && i < length; i++) { dst[i] = src[i]; } while (i < length) { dst[i++] = '\0'; } return dst; } public static int strlen(CharPtr str) { int i; for (i = 0; str[i] != 0; i++) { } return i; } public static void sprintf(CharPtr buffer, CharPtr str, params object[] argv) { string text = Tools.sprintf(str.ToString(), argv); strcpy(buffer, text); } } public static class Tools { public static Regex r = new Regex("\\%(\\d*\\$)?([\\'\\#\\-\\+ ]*)(\\d*)(?:\\.(\\d+))?([hl])?([dioxXucsfeEgGpn%])"); public static bool IsNumericType(object o) { if (!(o is byte) && !(o is sbyte) && !(o is short) && !(o is ushort) && !(o is int) && !(o is uint) && !(o is long) && !(o is ulong) && !(o is float) && !(o is double)) { return o is decimal; } return true; } public static bool IsPositive(object Value, bool ZeroIsPositive) { Type type = Value.GetType(); if (type == typeof(sbyte)) { if (!ZeroIsPositive) { return (sbyte)Value > 0; } return (sbyte)Value >= 0; } if (type == typeof(short)) { if (!ZeroIsPositive) { return (short)Value > 0; } return (short)Value >= 0; } if (type == typeof(int)) { if (!ZeroIsPositive) { return (int)Value > 0; } return (int)Value >= 0; } if (type == typeof(long)) { if (!ZeroIsPositive) { return (long)Value > 0; } return (long)Value >= 0; } if (type == typeof(byte)) { if (!ZeroIsPositive) { return (byte)Value > 0; } return true; } if (type == typeof(ushort)) { if (!ZeroIsPositive) { return (ushort)Value > 0; } return true; } if (type == typeof(uint)) { if (!ZeroIsPositive) { return (uint)Value != 0; } return true; } if (type == typeof(ulong)) { if (!ZeroIsPositive) { return (ulong)Value != 0; } return true; } if (type == typeof(float)) { if (!ZeroIsPositive) { return (float)Value > 0f; } return (float)Value >= 0f; } if (type == typeof(double)) { if (!ZeroIsPositive) { return (double)Value > 0.0; } return (double)Value >= 0.0; } if (type == typeof(decimal)) { if (!ZeroIsPositive) { return (decimal)Value > 0m; } return (decimal)Value >= 0m; } if (type == typeof(char)) { if (!ZeroIsPositive) { return (char)Value != '\0'; } return true; } return ZeroIsPositive; } public static object ToUnsigned(object Value) { Type type = Value.GetType(); if (type == typeof(sbyte)) { return (byte)(sbyte)Value; } if (type == typeof(short)) { return (ushort)(short)Value; } if (type == typeof(int)) { return (uint)(int)Value; } if (type == typeof(long)) { return (ulong)(long)Value; } if (type == typeof(byte)) { return Value; } if (type == typeof(ushort)) { return Value; } if (type == typeof(uint)) { return Value; } if (type == typeof(ulong)) { return Value; } if (type == typeof(float)) { return (uint)(float)Value; } if (type == typeof(double)) { return (ulong)(double)Value; } if (type == typeof(decimal)) { return (ulong)(decimal)Value; } return null; } public static object ToInteger(object Value, bool Round) { Type type = Value.GetType(); if (type == typeof(sbyte)) { return Value; } if (type == typeof(short)) { return Value; } if (type == typeof(int)) { return Value; } if (type == typeof(long)) { return Value; } if (type == typeof(byte)) { return Value; } if (type == typeof(ushort)) { return Value; } if (type == typeof(uint)) { return Value; } if (type == typeof(ulong)) { return Value; } if (type == typeof(float)) { return Round ? ((int)Math.Round((float)Value)) : ((int)(float)Value); } if (type == typeof(double)) { return Round ? ((long)Math.Round((double)Value)) : ((long)(double)Value); } if (type == typeof(decimal)) { return Round ? Math.Round((decimal)Value) : ((decimal)Value); } return null; } public static long UnboxToLong(object Value, bool Round) { Type type = Value.GetType(); if (type == typeof(sbyte)) { return (sbyte)Value; } if (type == typeof(short)) { return (short)Value; } if (type == typeof(int)) { return (int)Value; } if (type == typeof(long)) { return (long)Value; } if (type == typeof(byte)) { return (byte)Value; } if (type == typeof(ushort)) { return (ushort)Value; } if (type == typeof(uint)) { return (uint)Value; } if (type == typeof(ulong)) { return (long)(ulong)Value; } if (type == typeof(float)) { if (!Round) { return (long)(float)Value; } return (long)Math.Round((float)Value); } if (type == typeof(double)) { if (!Round) { return (long)(double)Value; } return (long)Math.Round((double)Value); } if (type == typeof(decimal)) { if (!Round) { return (long)(decimal)Value; } return (long)Math.Round((decimal)Value); } return 0L; } public static string ReplaceMetaChars(string input) { return Regex.Replace(input, "(\\\\)(\\d{3}|[^\\d])?", ReplaceMetaCharsMatch); } public static string ReplaceMetaCharsMatch(Match m) { if (m.Groups[2].Length == 3) { return Convert.ToChar(Convert.ToByte(m.Groups[2].Value, 8)).ToString(); } return m.Groups[2].Value switch { "0" => "\0", "a" => "\a", "b" => "\b", "f" => "\f", "v" => "\v", "r" => "\r", "n" => "\n", "t" => "\t", _ => m.Groups[2].Value, }; } public static void fprintf(TextWriter Destination, string Format, params object[] Parameters) { Destination.Write(sprintf(Format, Parameters)); } public static string sprintf(string Format, params object[] Parameters) { StringBuilder stringBuilder = new StringBuilder(); Match match = null; string empty = string.Empty; int num = 0; object obj = null; bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; bool flag5 = false; bool flag6 = false; int num2 = 0; int num3 = 0; char c = '\0'; char c2 = '\0'; char c3 = ' '; stringBuilder.Append(Format); match = r.Match(stringBuilder.ToString()); while (match.Success) { int num4 = num; if (match.Groups[1] != null && match.Groups[1].Value.Length > 0) { num4 = Convert.ToInt32(match.Groups[1].Value.Substring(0, match.Groups[1].Value.Length - 1)) - 1; } flag2 = false; flag = false; flag3 = false; flag4 = false; flag5 = false; flag6 = false; if (match.Groups[2] != null && match.Groups[2].Value.Length > 0) { string value = match.Groups[2].Value; flag2 = value.IndexOf('#') >= 0; flag = value.IndexOf('-') >= 0; flag3 = value.IndexOf('+') >= 0; flag4 = value.IndexOf(' ') >= 0; flag6 = value.IndexOf('\'') >= 0; if (flag3 && flag4) { flag4 = false; } } c3 = ' '; num2 = int.MinValue; if (match.Groups[3] != null && match.Groups[3].Value.Length > 0) { num2 = Convert.ToInt32(match.Groups[3].Value); flag5 = match.Groups[3].Value[0] == '0'; } if (flag5) { c3 = '0'; } if (flag && flag5) { flag5 = false; c3 = ' '; } num3 = int.MinValue; if (match.Groups[4] != null && match.Groups[4].Value.Length > 0) { num3 = Convert.ToInt32(match.Groups[4].Value); } c = '\0'; if (match.Groups[5] != null && match.Groups[5].Value.Length > 0) { c = match.Groups[5].Value[0]; } c2 = '\0'; if (match.Groups[6] != null && match.Groups[6].Value.Length > 0) { c2 = match.Groups[6].Value[0]; } if (num3 == int.MinValue && c2 != 's' && c2 != 'c' && char.ToUpper(c2) != 'X' && c2 != 'o') { num3 = 6; } if (Parameters == null || num4 >= Parameters.Length) { obj = null; } else { obj = Parameters[num4]; switch (c) { case 'h': if (obj is int) { obj = (short)(int)obj; } else if (obj is long) { obj = (short)(long)obj; } else if (obj is uint) { obj = (ushort)(uint)obj; } else if (obj is ulong) { obj = (ushort)(ulong)obj; } break; case 'l': if (obj is short) { obj = (long)(short)obj; } else if (obj is int) { obj = (long)(int)obj; } else if (obj is ushort) { obj = (ulong)(ushort)obj; } else if (obj is uint) { obj = (ulong)(uint)obj; } break; } } empty = string.Empty; switch (c2) { case '%': empty = "%"; break; case 'd': case 'i': empty = FormatNumber(flag6 ? "n" : "d", flag2, num2, int.MinValue, flag, flag3, flag4, c3, obj); num++; break; case 'o': empty = FormatOct("o", flag2, num2, int.MinValue, flag, c3, obj); num++; break; case 'x': empty = FormatHex("x", flag2, num2, num3, flag, c3, obj); num++; break; case 'X': empty = FormatHex("X", flag2, num2, num3, flag, c3, obj); num++; break; case 'u': empty = FormatNumber(flag6 ? "n" : "d", flag2, num2, int.MinValue, flag, PositiveSign: false, PositiveSpace: false, c3, ToUnsigned(obj)); num++; break; case 'c': if (IsNumericType(obj)) { empty = Convert.ToChar(obj).ToString(); } else if (obj is char c4) { empty = c4.ToString(); } else if (obj is string && ((string)obj).Length > 0) { empty = ((string)obj)[0].ToString(); } num++; break; case 's': empty = obj.ToString(); if (num3 >= 0) { empty = empty.Substring(0, num3); } if (num2 != int.MinValue) { empty = ((!flag) ? empty.PadLeft(num2, c3) : empty.PadRight(num2, c3)); } num++; break; case 'f': empty = FormatNumber(flag6 ? "n" : "f", flag2, num2, num3, flag, flag3, flag4, c3, obj); num++; break; case 'e': empty = FormatNumber("e", flag2, num2, num3, flag, flag3, flag4, c3, obj); num++; break; case 'E': empty = FormatNumber("E", flag2, num2, num3, flag, flag3, flag4, c3, obj); num++; break; case 'g': empty = FormatNumber("g", flag2, num2, num3, flag, flag3, flag4, c3, obj); num++; break; case 'G': empty = FormatNumber("G", flag2, num2, num3, flag, flag3, flag4, c3, obj); num++; break; case 'p': if (obj is IntPtr) { empty = "0x" + ((IntPtr)obj).ToString("x"); } num++; break; case 'n': empty = FormatNumber("d", flag2, num2, int.MinValue, flag, flag3, flag4, c3, match.Index); break; default: empty = string.Empty; num++; break; } stringBuilder.Remove(match.Index, match.Length); stringBuilder.Insert(match.Index, empty); match = r.Match(stringBuilder.ToString(), match.Index + empty.Length); } return stringBuilder.ToString(); } public static string FormatOct(string NativeFormat, bool Alternate, int FieldLength, int FieldPrecision, bool Left2Right, char Padding, object Value) { string text = string.Empty; string format = "{0" + ((FieldLength != int.MinValue) ? ("," + (Left2Right ? "-" : string.Empty) + FieldLength) : string.Empty) + "}"; if (IsNumericType(Value)) { text = Convert.ToString(UnboxToLong(Value, Round: true), 8); if (Left2Right || Padding == ' ') { if (Alternate && text != "0") { text = "0" + text; } text = string.Format(format, text); } else { if (FieldLength != int.MinValue) { text = text.PadLeft(FieldLength - ((Alternate && text != "0") ? 1 : 0), Padding); } if (Alternate && text != "0") { text = "0" + text; } } } return text; } public static string FormatHex(string NativeFormat, bool Alternate, int FieldLength, int FieldPrecision, bool Left2Right, char Padding, object Value) { string text = string.Empty; string format = "{0" + ((FieldLength != int.MinValue) ? ("," + (Left2Right ? "-" : string.Empty) + FieldLength) : string.Empty) + "}"; string format2 = "{0:" + NativeFormat + ((FieldPrecision != int.MinValue) ? FieldPrecision.ToString() : string.Empty) + "}"; if (IsNumericType(Value)) { text = string.Format(format2, Value); if (Left2Right || Padding == ' ') { if (Alternate) { text = ((NativeFormat == "x") ? "0x" : "0X") + text; } text = string.Format(format, text); } else { if (FieldLength != int.MinValue) { text = text.PadLeft(FieldLength - (Alternate ? 2 : 0), Padding); } if (Alternate) { text = ((NativeFormat == "x") ? "0x" : "0X") + text; } } } return text; } public static string FormatNumber(string NativeFormat, bool Alternate, int FieldLength, int FieldPrecision, bool Left2Right, bool PositiveSign, bool PositiveSpace, char Padding, object Value) { string result = string.Empty; string format = "{0" + ((FieldLength != int.MinValue) ? ("," + (Left2Right ? "-" : string.Empty) + FieldLength) : string.Empty) + "}"; string format2 = "{0:" + NativeFormat + ((FieldPrecision != int.MinValue) ? FieldPrecision.ToString() : "0") + "}"; if (IsNumericType(Value)) { result = string.Format(CultureInfo.InvariantCulture, format2, new object[1] { Value }); if (Left2Right || Padding == ' ') { if (IsPositive(Value, ZeroIsPositive: true)) { result = (PositiveSign ? "+" : (PositiveSpace ? " " : string.Empty)) + result; } result = string.Format(format, result); } else { if (result.StartsWith("-")) { result = result.Substring(1); } if (FieldLength != int.MinValue) { result = ((!PositiveSign) ? result.PadLeft(FieldLength, Padding) : result.PadLeft(FieldLength - 1, Padding)); } result = ((!IsPositive(Value, ZeroIsPositive: true)) ? ("-" + result) : ((PositiveSign ? "+" : "") + result)); } } return result; } } public class LuaLBuffer { public StringBuilder StringBuilder { get; set; } public LuaState LuaState { get; set; } public LuaLBuffer(LuaState l) { StringBuilder = new StringBuilder(); LuaState = l; } } public class LuaState { public List m_Stack; public ScriptExecutionContext ExecutionContext { get; set; } public string FunctionName { get; set; } public int Count => m_Stack.Count; public LuaState(ScriptExecutionContext executionContext, CallbackArguments args, string functionName) { ExecutionContext = executionContext; m_Stack = new List(16); for (int i = 0; i < args.Count; i++) { m_Stack.Add(args[i]); } FunctionName = functionName; } public DynValue Top(int pos = 0) { return m_Stack[m_Stack.Count - 1 - pos]; } public DynValue At(int pos) { if (pos < 0) { pos = m_Stack.Count + pos + 1; } if (pos > m_Stack.Count) { return DynValue.Void; } return m_Stack[pos - 1]; } public void Push(DynValue v) { m_Stack.Add(v); } public DynValue Pop() { DynValue result = Top(); m_Stack.RemoveAt(m_Stack.Count - 1); return result; } public DynValue[] GetTopArray(int num) { DynValue[] array = new DynValue[num]; for (int i = 0; i < num; i++) { array[num - i - 1] = Top(i); } return array; } public DynValue GetReturnValue(int retvals) { return retvals switch { 0 => DynValue.Nil, 1 => Top(), _ => DynValue.NewTupleNested(GetTopArray(retvals)), }; } public void Discard(int nargs) { for (int i = 0; i < nargs; i++) { m_Stack.RemoveAt(m_Stack.Count - 1); } } } public static class NamespaceDoc { } } namespace MoonSharp.Interpreter.Interop.UserDataRegistries { public class ExtensionMethodsRegistry { public class UnresolvedGenericMethod { public readonly MethodInfo Method; public readonly InteropAccessMode AccessMode; public readonly HashSet AlreadyAddedTypes = new HashSet(); public UnresolvedGenericMethod(MethodInfo mi, InteropAccessMode mode) { AccessMode = mode; Method = mi; } } public static object s_Lock = new object(); public static MultiDictionary s_Registry = new MultiDictionary(); public static MultiDictionary s_UnresolvedGenericsRegistry = new MultiDictionary(); public static int s_ExtensionMethodChangeVersion = 0; public static void RegisterExtensionType(Type type, InteropAccessMode mode = InteropAccessMode.Default) { lock (s_Lock) { bool flag = false; foreach (MethodInfo item in from _mi in Framework.Do.GetMethods(type) where _mi.IsStatic select _mi) { if (item.GetCustomAttributes(typeof(ExtensionAttribute), inherit: false).Count() != 0) { if (item.ContainsGenericParameters) { s_UnresolvedGenericsRegistry.Add(item.Name, new UnresolvedGenericMethod(item, mode)); flag = true; } else if (MethodMemberDescriptor.CheckMethodIsCompatible(item, throwException: false)) { MethodMemberDescriptor value = new MethodMemberDescriptor(item, mode); s_Registry.Add(item.Name, value); flag = true; } } } if (flag) { s_ExtensionMethodChangeVersion++; } } } public static object FrameworkGetMethods() { throw new NotImplementedException(); } public static IEnumerable GetExtensionMethodsByName(string name) { lock (s_Lock) { return new List(s_Registry.Find(name)); } } public static int GetExtensionMethodsChangeVersion() { return s_ExtensionMethodChangeVersion; } public static List GetExtensionMethodsByNameAndType(string name, Type extendedType) { List list = null; lock (s_Lock) { list = s_UnresolvedGenericsRegistry.Find(name).ToList(); } foreach (UnresolvedGenericMethod item in list) { ParameterInfo[] parameters = item.Method.GetParameters(); if (parameters.Length == 0) { continue; } Type parameterType = parameters[0].ParameterType; Type genericMatch = GetGenericMatch(parameterType, extendedType); if (item.AlreadyAddedTypes.Add(genericMatch) && genericMatch != null) { MethodInfo methodInfo = InstantiateMethodInfo(item.Method, parameterType, genericMatch, extendedType); if (methodInfo != null && MethodMemberDescriptor.CheckMethodIsCompatible(methodInfo, throwException: false)) { MethodMemberDescriptor value = new MethodMemberDescriptor(methodInfo, item.AccessMode); s_Registry.Add(item.Method.Name, value); s_ExtensionMethodChangeVersion++; } } } return (from d in s_Registry.Find(name) where d.ExtensionMethodType != null && Framework.Do.IsAssignableFrom(d.ExtensionMethodType, extendedType) select d).ToList(); } public static MethodInfo InstantiateMethodInfo(MethodInfo mi, Type extensionType, Type genericType, Type extendedType) { Type[] genericArguments = mi.GetGenericArguments(); Type[] genericArguments2 = Framework.Do.GetGenericArguments(genericType); if (genericArguments2.Length == genericArguments.Length) { return mi.MakeGenericMethod(genericArguments2); } return null; } public static Type GetGenericMatch(Type extensionType, Type extendedType) { if (!extensionType.IsGenericParameter) { extensionType = extensionType.GetGenericTypeDefinition(); foreach (Type allImplementedType in extendedType.GetAllImplementedTypes()) { if (Framework.Do.IsGenericType(allImplementedType) && allImplementedType.GetGenericTypeDefinition() == extensionType) { return allImplementedType; } } } return null; } } public static class TypeDescriptorRegistry { public static object s_Lock = new object(); public static Dictionary s_TypeRegistry = new Dictionary(); public static Dictionary s_TypeRegistryHistory = new Dictionary(); public static InteropAccessMode s_DefaultAccessMode; public static InteropAccessMode DefaultAccessMode { get { return s_DefaultAccessMode; } set { if (value == InteropAccessMode.Default) { throw new ArgumentException("InteropAccessMode is InteropAccessMode.Default"); } s_DefaultAccessMode = value; } } public static IEnumerable> RegisteredTypes { get { lock (s_Lock) { return s_TypeRegistry.ToArray(); } } } public static IEnumerable> RegisteredTypesHistory { get { lock (s_Lock) { return s_TypeRegistryHistory.ToArray(); } } } public static IRegistrationPolicy RegistrationPolicy { get; set; } public static void RegisterAssembly(Assembly asm = null, bool includeExtensionTypes = false) { if (asm == null) { asm = Assembly.GetCallingAssembly(); } if (includeExtensionTypes) { foreach (var item in from t in asm.SafeGetTypes() let attributes = Framework.Do.GetCustomAttributes(t, typeof(ExtensionAttribute), inherit: true) where attributes != null && attributes.Length != 0 select new { Attributes = attributes, DataType = t }) { UserData.RegisterExtensionType(item.DataType); } } foreach (var item2 in from t in asm.SafeGetTypes() let attributes = Framework.Do.GetCustomAttributes(t, typeof(MoonSharpUserDataAttribute), inherit: true) where attributes != null && attributes.Length != 0 select new { Attributes = attributes, DataType = t }) { UserData.RegisterType(item2.DataType, item2.Attributes.OfType().First().AccessMode); } } public static bool IsTypeRegistered(Type type) { lock (s_Lock) { return s_TypeRegistry.ContainsKey(type); } } public static void UnregisterType(Type t) { lock (s_Lock) { if (s_TypeRegistry.ContainsKey(t)) { PerformRegistration(t, null, s_TypeRegistry[t]); } } } public static IUserDataDescriptor RegisterProxyType_Impl(IProxyFactory proxyFactory, InteropAccessMode accessMode, string friendlyName) { IUserDataDescriptor proxyDescriptor = RegisterType_Impl(proxyFactory.ProxyType, accessMode, friendlyName, null); return RegisterType_Impl(proxyFactory.TargetType, accessMode, friendlyName, new ProxyUserDataDescriptor(proxyFactory, proxyDescriptor, friendlyName)); } public static IUserDataDescriptor RegisterType_Impl(Type type, InteropAccessMode accessMode, string friendlyName, IUserDataDescriptor descriptor) { accessMode = ResolveDefaultAccessModeForType(accessMode, type); lock (s_Lock) { IUserDataDescriptor value = null; s_TypeRegistry.TryGetValue(type, out value); if (descriptor == null) { if (IsTypeBlacklisted(type)) { return null; } if (Framework.Do.GetInterfaces(type).Any((Type ii) => ii == typeof(IUserDataType))) { AutoDescribingUserDataDescriptor newDescriptor = new AutoDescribingUserDataDescriptor(type, friendlyName); return PerformRegistration(type, newDescriptor, value); } if (Framework.Do.IsGenericTypeDefinition(type)) { StandardGenericsUserDataDescriptor newDescriptor2 = new StandardGenericsUserDataDescriptor(type, accessMode); return PerformRegistration(type, newDescriptor2, value); } if (Framework.Do.IsEnum(type)) { StandardEnumUserDataDescriptor newDescriptor3 = new StandardEnumUserDataDescriptor(type, friendlyName); return PerformRegistration(type, newDescriptor3, value); } StandardUserDataDescriptor udd = new StandardUserDataDescriptor(type, accessMode, friendlyName); if (accessMode == InteropAccessMode.BackgroundOptimized) { ThreadPool.QueueUserWorkItem(delegate { ((IOptimizableDescriptor)udd).Optimize(); }); } return PerformRegistration(type, udd, value); } PerformRegistration(type, descriptor, value); return descriptor; } } public static IUserDataDescriptor PerformRegistration(Type type, IUserDataDescriptor newDescriptor, IUserDataDescriptor oldDescriptor) { IUserDataDescriptor userDataDescriptor = RegistrationPolicy.HandleRegistration(newDescriptor, oldDescriptor); if (userDataDescriptor != oldDescriptor) { if (userDataDescriptor == null) { s_TypeRegistry.Remove(type); } else { s_TypeRegistry[type] = userDataDescriptor; s_TypeRegistryHistory[type] = userDataDescriptor; } } return userDataDescriptor; } public static InteropAccessMode ResolveDefaultAccessModeForType(InteropAccessMode accessMode, Type type) { if (accessMode == InteropAccessMode.Default) { MoonSharpUserDataAttribute moonSharpUserDataAttribute = Framework.Do.GetCustomAttributes(type, inherit: true).OfType().SingleOrDefault(); if (moonSharpUserDataAttribute != null) { accessMode = moonSharpUserDataAttribute.AccessMode; } } if (accessMode == InteropAccessMode.Default) { accessMode = s_DefaultAccessMode; } return accessMode; } public static IUserDataDescriptor GetDescriptorForType(Type type, bool searchInterfaces) { lock (s_Lock) { IUserDataDescriptor userDataDescriptor = null; if (s_TypeRegistry.ContainsKey(type)) { return s_TypeRegistry[type]; } if (RegistrationPolicy.AllowTypeAutoRegistration(type) && !Framework.Do.IsAssignableFrom(typeof(Delegate), type)) { return RegisterType_Impl(type, DefaultAccessMode, type.FullName, null); } Type type2 = type; while (type2 != null) { if (s_TypeRegistry.TryGetValue(type2, out var value)) { userDataDescriptor = value; break; } if (Framework.Do.IsGenericType(type2) && s_TypeRegistry.TryGetValue(type2.GetGenericTypeDefinition(), out value)) { userDataDescriptor = value; break; } type2 = Framework.Do.GetBaseType(type2); } if (userDataDescriptor is IGeneratorUserDataDescriptor) { userDataDescriptor = ((IGeneratorUserDataDescriptor)userDataDescriptor).Generate(type); } if (!searchInterfaces) { return userDataDescriptor; } List list = new List(); if (userDataDescriptor != null) { list.Add(userDataDescriptor); } if (searchInterfaces) { Type[] interfaces = Framework.Do.GetInterfaces(type); foreach (Type type3 in interfaces) { if (s_TypeRegistry.TryGetValue(type3, out var value2)) { if (value2 is IGeneratorUserDataDescriptor) { value2 = ((IGeneratorUserDataDescriptor)value2).Generate(type); } if (value2 != null) { list.Add(value2); } } else if (Framework.Do.IsGenericType(type3) && s_TypeRegistry.TryGetValue(type3.GetGenericTypeDefinition(), out value2)) { if (value2 is IGeneratorUserDataDescriptor) { value2 = ((IGeneratorUserDataDescriptor)value2).Generate(type); } if (value2 != null) { list.Add(value2); } } } } if (list.Count == 1) { return list[0]; } if (list.Count == 0) { return null; } return new CompositeUserDataDescriptor(list, type); } } public static bool FrameworkIsAssignableFrom(Type type) { throw new NotImplementedException(); } public static bool IsTypeBlacklisted(Type t) { if (Framework.Do.IsValueType(t) && Framework.Do.GetInterfaces(t).Contains(typeof(IEnumerator))) { return true; } return false; } } } namespace MoonSharp.Interpreter.Interop.StandardDescriptors { public class EventFacade : IUserDataType { public Func m_AddCallback; public Func m_RemoveCallback; public object m_Object; public EventFacade(EventMemberDescriptor parent, object obj) { m_Object = obj; m_AddCallback = parent.AddCallback; m_RemoveCallback = parent.RemoveCallback; } public EventFacade(Func addCallback, Func removeCallback, object obj) { m_Object = obj; m_AddCallback = addCallback; m_RemoveCallback = removeCallback; } public DynValue Index(Script script, DynValue index, bool isDirectIndexing) { if (index.Type == DataType.String) { if (index.String == "add") { return DynValue.NewCallback((ScriptExecutionContext c, CallbackArguments a) => m_AddCallback(m_Object, c, a)); } if (index.String == "remove") { return DynValue.NewCallback((ScriptExecutionContext c, CallbackArguments a) => m_RemoveCallback(m_Object, c, a)); } } throw new ScriptRuntimeException("Events only support add and remove methods"); } public bool SetIndex(Script script, DynValue index, DynValue value, bool isDirectIndexing) { throw new ScriptRuntimeException("Events do not have settable fields"); } public DynValue MetaIndex(Script script, string metaname) { return null; } } } namespace MoonSharp.Interpreter.Interop.StandardDescriptors.HardwiredDescriptors { public sealed class DefaultValue { public static readonly DefaultValue Instance = new DefaultValue(); } public abstract class HardwiredMemberDescriptor : IMemberDescriptor { public Type MemberType { get; set; } public bool IsStatic { get; set; } public string Name { get; set; } public MemberDescriptorAccess MemberAccess { get; set; } public HardwiredMemberDescriptor(Type memberType, string name, bool isStatic, MemberDescriptorAccess access) { IsStatic = isStatic; Name = name; MemberAccess = access; MemberType = memberType; } public DynValue GetValue(Script script, object obj) { this.CheckAccess(MemberDescriptorAccess.CanRead, obj); object valueImpl = GetValueImpl(script, obj); return ClrToScriptConversions.ObjectToDynValue(script, valueImpl); } public void SetValue(Script script, object obj, DynValue value) { this.CheckAccess(MemberDescriptorAccess.CanWrite, obj); object value2 = ScriptToClrConversions.DynValueToObjectOfType(value, MemberType, null, isOptional: false); SetValueImpl(script, obj, value2); } public virtual object GetValueImpl(Script script, object obj) { throw new InvalidOperationException("GetValue on write-only hardwired descriptor " + Name); } public virtual void SetValueImpl(Script script, object obj, object value) { throw new InvalidOperationException("SetValue on read-only hardwired descriptor " + Name); } } public abstract class HardwiredMethodMemberDescriptor : FunctionMemberDescriptorBase { public override DynValue Execute(Script script, object obj, ScriptExecutionContext context, CallbackArguments args) { this.CheckAccess(MemberDescriptorAccess.CanExecute, obj); List outParams = null; object[] pars = base.BuildArgumentList(script, obj, context, args, out outParams); object obj2 = Invoke(script, obj, pars, CalcArgsCount(pars)); return DynValue.FromObject(script, obj2); } public int CalcArgsCount(object[] pars) { int num = pars.Length; for (int i = 0; i < pars.Length; i++) { if (base.Parameters[i].HasDefaultValue && pars[i] is DefaultValue) { num--; } } return num; } public abstract object Invoke(Script script, object obj, object[] pars, int argscount); public HardwiredMethodMemberDescriptor() { } } public abstract class HardwiredUserDataDescriptor : DispatchingUserDataDescriptor { public HardwiredUserDataDescriptor(Type T) : base(T, "::hardwired::" + T.Name) { } } } namespace MoonSharp.Interpreter.Interop.RegistrationPolicies { public class AutomaticRegistrationPolicy : DefaultRegistrationPolicy { public override bool AllowTypeAutoRegistration(Type type) { return true; } } public class DefaultRegistrationPolicy : IRegistrationPolicy { public IUserDataDescriptor HandleRegistration(IUserDataDescriptor newDescriptor, IUserDataDescriptor oldDescriptor) { if (newDescriptor == null) { return null; } return oldDescriptor ?? newDescriptor; } public virtual bool AllowTypeAutoRegistration(Type type) { return false; } } public class PermanentRegistrationPolicy : IRegistrationPolicy { public IUserDataDescriptor HandleRegistration(IUserDataDescriptor newDescriptor, IUserDataDescriptor oldDescriptor) { return oldDescriptor ?? newDescriptor; } public bool AllowTypeAutoRegistration(Type type) { return false; } } public interface IRegistrationPolicy { IUserDataDescriptor HandleRegistration(IUserDataDescriptor newDescriptor, IUserDataDescriptor oldDescriptor); bool AllowTypeAutoRegistration(Type type); } } namespace MoonSharp.Interpreter.Interop.Converters { public static class ClrToScriptConversions { public static DynValue TryObjectToTrivialDynValue(Script script, object obj) { if (obj == null) { return DynValue.Nil; } if (obj is DynValue) { return (DynValue)obj; } Type type = obj.GetType(); if (obj is bool) { return DynValue.NewBoolean((bool)obj); } if (obj is string || obj is StringBuilder || obj is char) { return DynValue.NewString(obj.ToString()); } if (NumericConversions.NumericTypes.Contains(type)) { return DynValue.NewNumber(NumericConversions.TypeToDouble(type, obj)); } if (obj is Table) { return DynValue.NewTable((Table)obj); } return null; } public static DynValue TryObjectToSimpleDynValue(Script script, object obj) { if (obj == null) { return DynValue.Nil; } if (obj is DynValue) { return (DynValue)obj; } Func clrToScriptCustomConversion = Script.GlobalOptions.CustomConverters.GetClrToScriptCustomConversion(obj.GetType()); if (clrToScriptCustomConversion != null) { DynValue dynValue = clrToScriptCustomConversion(script, obj); if (dynValue != null) { return dynValue; } } Type type = obj.GetType(); if (obj is bool) { return DynValue.NewBoolean((bool)obj); } if (obj is string || obj is StringBuilder || obj is char) { return DynValue.NewString(obj.ToString()); } if (obj is Closure) { return DynValue.NewClosure((Closure)obj); } if (NumericConversions.NumericTypes.Contains(type)) { return DynValue.NewNumber(NumericConversions.TypeToDouble(type, obj)); } if (obj is Table) { return DynValue.NewTable((Table)obj); } if (obj is CallbackFunction) { return DynValue.NewCallback((CallbackFunction)obj); } if (obj is Delegate) { Delegate @delegate = (Delegate)obj; if (CallbackFunction.CheckCallbackSignature(@delegate.Method, requirePublicVisibility: false)) { return DynValue.NewCallback((Func)@delegate); } } return null; } public static DynValue ObjectToDynValue(Script script, object obj) { DynValue dynValue = TryObjectToSimpleDynValue(script, obj); if (dynValue != null) { return dynValue; } dynValue = UserData.Create(obj); if (dynValue != null) { return dynValue; } if (obj is Type) { dynValue = UserData.CreateStatic(obj as Type); } if (obj is Enum) { return DynValue.NewNumber(NumericConversions.TypeToDouble(Enum.GetUnderlyingType(obj.GetType()), obj)); } if (dynValue != null) { return dynValue; } if (obj is Delegate) { return DynValue.NewCallback(CallbackFunction.FromDelegate(script, (Delegate)obj)); } if (obj is MethodInfo) { MethodInfo methodInfo = (MethodInfo)obj; if (methodInfo.IsStatic) { return DynValue.NewCallback(CallbackFunction.FromMethodInfo(script, methodInfo)); } } if (obj is IList) { return DynValue.NewTable(TableConversions.ConvertIListToTable(script, (IList)obj)); } if (obj is IDictionary) { return DynValue.NewTable(TableConversions.ConvertIDictionaryToTable(script, (IDictionary)obj)); } DynValue dynValue2 = EnumerationToDynValue(script, obj); if (dynValue2 != null) { return dynValue2; } throw ScriptRuntimeException.ConvertObjectFailed(obj); } public static DynValue EnumerationToDynValue(Script script, object obj) { if (obj is IEnumerable) { IEnumerable enumerable = (IEnumerable)obj; return EnumerableWrapper.ConvertIterator(script, enumerable.GetEnumerator()); } if (obj is IEnumerator) { IEnumerator enumerator = (IEnumerator)obj; return EnumerableWrapper.ConvertIterator(script, enumerator); } return null; } } public static class NumericConversions { public static readonly HashSet NumericTypes; public static readonly Type[] NumericTypesOrdered; static NumericConversions() { NumericTypesOrdered = new Type[11] { typeof(double), typeof(decimal), typeof(float), typeof(long), typeof(int), typeof(short), typeof(sbyte), typeof(ulong), typeof(uint), typeof(ushort), typeof(byte) }; NumericTypes = new HashSet(NumericTypesOrdered); } public static object DoubleToType(Type type, double d) { type = Nullable.GetUnderlyingType(type) ?? type; if (type == typeof(double)) { return d; } if (type == typeof(sbyte)) { return (sbyte)d; } if (type == typeof(byte)) { return (byte)d; } if (type == typeof(short)) { return (short)d; } if (type == typeof(ushort)) { return (ushort)d; } if (type == typeof(int)) { return (int)d; } if (type == typeof(uint)) { return (uint)d; } if (type == typeof(long)) { return (long)d; } if (type == typeof(ulong)) { return (ulong)d; } if (type == typeof(float)) { return (float)d; } if (type == typeof(decimal)) { return (decimal)d; } return d; } public static double TypeToDouble(Type type, object d) { if (type == typeof(double)) { return (double)d; } if (type == typeof(sbyte)) { return (sbyte)d; } if (type == typeof(byte)) { return (int)(byte)d; } if (type == typeof(short)) { return (short)d; } if (type == typeof(ushort)) { return (int)(ushort)d; } if (type == typeof(int)) { return (int)d; } if (type == typeof(uint)) { return (uint)d; } if (type == typeof(long)) { return (long)d; } if (type == typeof(ulong)) { return (ulong)d; } if (type == typeof(float)) { return (float)d; } if (type == typeof(decimal)) { return (double)(decimal)d; } return (double)d; } } public static class ScriptToClrConversions { public const int WEIGHT_MAX_VALUE = 100; public const int WEIGHT_CUSTOM_CONVERTER_MATCH = 100; public const int WEIGHT_EXACT_MATCH = 100; public const int WEIGHT_STRING_TO_STRINGBUILDER = 99; public const int WEIGHT_STRING_TO_CHAR = 98; public const int WEIGHT_NIL_TO_NULLABLE = 100; public const int WEIGHT_NIL_TO_REFTYPE = 100; public const int WEIGHT_VOID_WITH_DEFAULT = 50; public const int WEIGHT_VOID_WITHOUT_DEFAULT = 25; public const int WEIGHT_NIL_WITH_DEFAULT = 25; public const int WEIGHT_BOOL_TO_STRING = 5; public const int WEIGHT_NUMBER_TO_STRING = 50; public const int WEIGHT_NUMBER_TO_ENUM = 90; public const int WEIGHT_USERDATA_TO_STRING = 5; public const int WEIGHT_TABLE_CONVERSION = 90; public const int WEIGHT_NUMBER_DOWNCAST = 99; public const int WEIGHT_NO_MATCH = 0; public const int WEIGHT_NO_EXTRA_PARAMS_BONUS = 100; public const int WEIGHT_EXTRA_PARAMS_MALUS = 2; public const int WEIGHT_BYREF_BONUSMALUS = -10; public const int WEIGHT_VARARGS_MALUS = 1; public const int WEIGHT_VARARGS_EMPTY = 40; public static object DynValueToObject(DynValue value) { Func scriptToClrCustomConversion = Script.GlobalOptions.CustomConverters.GetScriptToClrCustomConversion(value.Type, typeof(object)); if (scriptToClrCustomConversion != null) { object obj = scriptToClrCustomConversion(value); if (obj != null) { return obj; } } switch (value.Type) { case DataType.Nil: case DataType.Void: return null; case DataType.Boolean: return value.Boolean; case DataType.Number: return value.Number; case DataType.String: return value.String; case DataType.Function: return value.Function; case DataType.Table: return value.Table; case DataType.Tuple: return value.Tuple; case DataType.UserData: if (value.UserData.Object != null) { return value.UserData.Object; } if (value.UserData.Descriptor != null) { return value.UserData.Descriptor.Type; } return null; case DataType.ClrFunction: return value.Callback; default: throw ScriptRuntimeException.ConvertObjectFailed(value.Type); } } public static object DynValueToObjectOfType(DynValue value, Type desiredType, object defaultValue, bool isOptional) { if (desiredType.IsByRef) { desiredType = desiredType.GetElementType(); } Func scriptToClrCustomConversion = Script.GlobalOptions.CustomConverters.GetScriptToClrCustomConversion(value.Type, desiredType); if (scriptToClrCustomConversion != null) { object obj = scriptToClrCustomConversion(value); if (obj != null) { return obj; } } if (desiredType == typeof(DynValue)) { return value; } if (desiredType == typeof(object)) { return DynValueToObject(value); } StringConversions.StringSubtype stringSubtype = StringConversions.GetStringSubtype(desiredType); string text = null; Type underlyingType = Nullable.GetUnderlyingType(desiredType); Type type = null; if (underlyingType != null) { type = desiredType; desiredType = underlyingType; } switch (value.Type) { case DataType.Void: if (isOptional) { return defaultValue; } if (!Framework.Do.IsValueType(desiredType) || type != null) { return null; } break; case DataType.Nil: if (Framework.Do.IsValueType(desiredType)) { if (type != null) { return null; } if (isOptional) { return defaultValue; } break; } return null; case DataType.Boolean: if (desiredType == typeof(bool)) { return value.Boolean; } if (stringSubtype != 0) { text = value.Boolean.ToString(); } break; case DataType.Number: if (Framework.Do.IsEnum(desiredType)) { return NumericConversions.DoubleToType(Enum.GetUnderlyingType(desiredType), value.Number); } if (NumericConversions.NumericTypes.Contains(desiredType)) { return NumericConversions.DoubleToType(desiredType, value.Number); } if (stringSubtype != 0) { text = value.Number.ToString(); } break; case DataType.String: if (stringSubtype != 0) { text = value.String; } break; case DataType.Function: if (desiredType == typeof(Closure)) { return value.Function; } if (desiredType == typeof(ScriptFunctionDelegate)) { return value.Function.GetDelegate(); } break; case DataType.ClrFunction: if (desiredType == typeof(CallbackFunction)) { return value.Callback; } if (desiredType == typeof(Func)) { return value.Callback.ClrCallback; } break; case DataType.UserData: if (value.UserData.Object != null) { object @object = value.UserData.Object; IUserDataDescriptor descriptor = value.UserData.Descriptor; if (descriptor.IsTypeCompatible(desiredType, @object)) { return @object; } if (stringSubtype != 0) { text = descriptor.AsString(@object); } } break; case DataType.Table: { if (desiredType == typeof(Table) || Framework.Do.IsAssignableFrom(desiredType, typeof(Table))) { return value.Table; } object obj2 = TableConversions.ConvertTableToType(value.Table, desiredType); if (obj2 != null) { return obj2; } break; } } if (stringSubtype != 0 && text != null) { return StringConversions.ConvertString(stringSubtype, text, desiredType, value.Type); } throw ScriptRuntimeException.ConvertObjectFailed(value.Type, desiredType); } public static int DynValueToObjectOfTypeWeight(DynValue value, Type desiredType, bool isOptional) { if (desiredType.IsByRef) { desiredType = desiredType.GetElementType(); } if (Script.GlobalOptions.CustomConverters.GetScriptToClrCustomConversion(value.Type, desiredType) != null) { return 100; } if (desiredType == typeof(DynValue)) { return 100; } if (desiredType == typeof(object)) { return 100; } StringConversions.StringSubtype stringSubtype = StringConversions.GetStringSubtype(desiredType); Type underlyingType = Nullable.GetUnderlyingType(desiredType); Type type = null; if (underlyingType != null) { type = desiredType; desiredType = underlyingType; } switch (value.Type) { case DataType.Void: if (isOptional) { return 50; } if (!Framework.Do.IsValueType(desiredType) || type != null) { return 25; } break; case DataType.Nil: if (Framework.Do.IsValueType(desiredType)) { if (type != null) { return 100; } if (isOptional) { return 25; } break; } return 100; case DataType.Boolean: if (desiredType == typeof(bool)) { return 100; } if (stringSubtype != 0) { return 5; } break; case DataType.Number: if (Framework.Do.IsEnum(desiredType)) { return 90; } if (NumericConversions.NumericTypes.Contains(desiredType)) { return GetNumericTypeWeight(desiredType); } if (stringSubtype != 0) { return 50; } break; case DataType.String: switch (stringSubtype) { case StringConversions.StringSubtype.String: return 100; case StringConversions.StringSubtype.StringBuilder: return 99; case StringConversions.StringSubtype.Char: return 98; } break; case DataType.Function: if (desiredType == typeof(Closure)) { return 100; } if (desiredType == typeof(ScriptFunctionDelegate)) { return 100; } break; case DataType.ClrFunction: if (desiredType == typeof(CallbackFunction)) { return 100; } if (desiredType == typeof(Func)) { return 100; } break; case DataType.UserData: if (value.UserData.Object != null) { object @object = value.UserData.Object; if (value.UserData.Descriptor.IsTypeCompatible(desiredType, @object)) { return 100; } if (stringSubtype != 0) { return 5; } } break; case DataType.Table: if (desiredType == typeof(Table) || Framework.Do.IsAssignableFrom(desiredType, typeof(Table))) { return 100; } if (TableConversions.CanConvertTableToType(value.Table, desiredType)) { return 90; } break; } return 0; } public static int GetNumericTypeWeight(Type desiredType) { if (desiredType == typeof(double) || desiredType == typeof(decimal)) { return 100; } return 99; } } public static class StringConversions { public enum StringSubtype { None, String, StringBuilder, Char } public static StringSubtype GetStringSubtype(Type desiredType) { if (desiredType == typeof(string)) { return StringSubtype.String; } if (desiredType == typeof(StringBuilder)) { return StringSubtype.StringBuilder; } if (desiredType == typeof(char)) { return StringSubtype.Char; } return StringSubtype.None; } public static object ConvertString(StringSubtype stringSubType, string str, Type desiredType, DataType dataType) { switch (stringSubType) { case StringSubtype.String: return str; case StringSubtype.StringBuilder: return new StringBuilder(str); case StringSubtype.Char: if (!string.IsNullOrEmpty(str)) { return str[0]; } break; } throw ScriptRuntimeException.ConvertObjectFailed(dataType, desiredType); } } public static class TableConversions { public static Table ConvertIListToTable(Script script, IList list) { Table table = new Table(script); for (int i = 0; i < list.Count; i++) { table[i + 1] = ClrToScriptConversions.ObjectToDynValue(script, list[i]); } return table; } public static Table ConvertIDictionaryToTable(Script script, IDictionary dict) { Table table = new Table(script); foreach (DictionaryEntry item in dict) { DynValue key = ClrToScriptConversions.ObjectToDynValue(script, item.Key); DynValue value = ClrToScriptConversions.ObjectToDynValue(script, item.Value); table.Set(key, value); } return table; } public static bool CanConvertTableToType(Table table, Type t) { if (Framework.Do.IsAssignableFrom(t, typeof(Dictionary))) { return true; } if (Framework.Do.IsAssignableFrom(t, typeof(Dictionary))) { return true; } if (Framework.Do.IsAssignableFrom(t, typeof(List))) { return true; } if (Framework.Do.IsAssignableFrom(t, typeof(List))) { return true; } if (Framework.Do.IsAssignableFrom(t, typeof(object[]))) { return true; } if (Framework.Do.IsAssignableFrom(t, typeof(DynValue[]))) { return true; } if (Framework.Do.IsGenericType(t)) { Type genericTypeDefinition = t.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(List<>) || genericTypeDefinition == typeof(IList<>) || genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>)) { return true; } if (genericTypeDefinition == typeof(Dictionary<, >) || genericTypeDefinition == typeof(IDictionary<, >)) { return true; } } if (t.IsArray && t.GetArrayRank() == 1) { return true; } return false; } public static object ConvertTableToType(Table table, Type t) { if (Framework.Do.IsAssignableFrom(t, typeof(Dictionary))) { return TableToDictionary(table, (DynValue v) => v.ToObject(), (DynValue v) => v.ToObject()); } if (Framework.Do.IsAssignableFrom(t, typeof(Dictionary))) { return TableToDictionary(table, (DynValue v) => v, (DynValue v) => v); } if (Framework.Do.IsAssignableFrom(t, typeof(List))) { return TableToList(table, (DynValue v) => v.ToObject()); } if (Framework.Do.IsAssignableFrom(t, typeof(List))) { return TableToList(table, (DynValue v) => v); } if (Framework.Do.IsAssignableFrom(t, typeof(object[]))) { return TableToList(table, (DynValue v) => v.ToObject()).ToArray(); } if (Framework.Do.IsAssignableFrom(t, typeof(DynValue[]))) { return TableToList(table, (DynValue v) => v).ToArray(); } if (Framework.Do.IsGenericType(t)) { Type genericTypeDefinition = t.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(List<>) || genericTypeDefinition == typeof(IList<>) || genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>)) { return ConvertTableToListOfGenericType(t, Framework.Do.GetGenericArguments(t)[0], table); } if (genericTypeDefinition == typeof(Dictionary<, >) || genericTypeDefinition == typeof(IDictionary<, >)) { return ConvertTableToDictionaryOfGenericType(t, Framework.Do.GetGenericArguments(t)[0], Framework.Do.GetGenericArguments(t)[1], table); } } if (t.IsArray && t.GetArrayRank() == 1) { return ConvertTableToArrayOfGenericType(t, t.GetElementType(), table); } return null; } public static object ConvertTableToDictionaryOfGenericType(Type dictionaryType, Type keyType, Type valueType, Table table) { if (dictionaryType.GetGenericTypeDefinition() != typeof(Dictionary<, >)) { dictionaryType = typeof(Dictionary<, >); dictionaryType = dictionaryType.MakeGenericType(keyType, valueType); } IDictionary dictionary = (IDictionary)Activator.CreateInstance(dictionaryType); foreach (TablePair pair in table.Pairs) { object key = ScriptToClrConversions.DynValueToObjectOfType(pair.Key, keyType, null, isOptional: false); object value = ScriptToClrConversions.DynValueToObjectOfType(pair.Value, valueType, null, isOptional: false); dictionary.Add(key, value); } return dictionary; } public static object ConvertTableToArrayOfGenericType(Type arrayType, Type itemType, Table table) { List list = new List(); int i = 1; for (int length = table.Length; i <= length; i++) { object item = ScriptToClrConversions.DynValueToObjectOfType(table.Get(i), itemType, null, isOptional: false); list.Add(item); } IList list2 = (IList)Activator.CreateInstance(arrayType, list.Count); for (int j = 0; j < list.Count; j++) { list2[j] = list[j]; } return list2; } public static object ConvertTableToListOfGenericType(Type listType, Type itemType, Table table) { if (listType.GetGenericTypeDefinition() != typeof(List<>)) { listType = typeof(List<>); listType = listType.MakeGenericType(itemType); } IList list = (IList)Activator.CreateInstance(listType); int i = 1; for (int length = table.Length; i <= length; i++) { object value = ScriptToClrConversions.DynValueToObjectOfType(table.Get(i), itemType, null, isOptional: false); list.Add(value); } return list; } public static List TableToList(Table table, Func converter) { List list = new List(); int i = 1; for (int length = table.Length; i <= length; i++) { DynValue arg = table.Get(i); T item = converter(arg); list.Add(item); } return list; } public static Dictionary TableToDictionary(Table table, Func keyconverter, Func valconverter) { Dictionary dictionary = new Dictionary(); foreach (TablePair pair in table.Pairs) { TK key = keyconverter(pair.Key); TV value = valconverter(pair.Value); dictionary.Add(key, value); } return dictionary; } } } namespace MoonSharp.Interpreter.Interop.BasicDescriptors { public interface IMemberDescriptor { bool IsStatic { get; } string Name { get; } MemberDescriptorAccess MemberAccess { get; } DynValue GetValue(Script script, object obj); void SetValue(Script script, object obj, DynValue value); } public static class MemberDescriptor { public static bool HasAllFlags(this MemberDescriptorAccess access, MemberDescriptorAccess flag) { return (access & flag) == flag; } public static bool CanRead(this IMemberDescriptor desc) { return desc.MemberAccess.HasAllFlags(MemberDescriptorAccess.CanRead); } public static bool CanWrite(this IMemberDescriptor desc) { return desc.MemberAccess.HasAllFlags(MemberDescriptorAccess.CanWrite); } public static bool CanExecute(this IMemberDescriptor desc) { return desc.MemberAccess.HasAllFlags(MemberDescriptorAccess.CanExecute); } public static DynValue GetGetterCallbackAsDynValue(this IMemberDescriptor desc, Script script, object obj) { return DynValue.NewCallback((ScriptExecutionContext p1, CallbackArguments p2) => desc.GetValue(script, obj)); } public static IMemberDescriptor WithAccessOrNull(this IMemberDescriptor desc, MemberDescriptorAccess access) { if (desc == null) { return null; } if (desc.MemberAccess.HasAllFlags(access)) { return desc; } return null; } public static void CheckAccess(this IMemberDescriptor desc, MemberDescriptorAccess access, object obj) { if (!desc.IsStatic && obj == null) { throw ScriptRuntimeException.AccessInstanceMemberOnStatics(desc); } if (access.HasAllFlags(MemberDescriptorAccess.CanExecute) && !desc.CanExecute()) { throw new ScriptRuntimeException("userdata member {0} cannot be called.", desc.Name); } if (access.HasAllFlags(MemberDescriptorAccess.CanWrite) && !desc.CanWrite()) { throw new ScriptRuntimeException("userdata member {0} cannot be assigned to.", desc.Name); } if (access.HasAllFlags(MemberDescriptorAccess.CanRead) && !desc.CanRead()) { throw new ScriptRuntimeException("userdata member {0} cannot be read from.", desc.Name); } } } public interface IOptimizableDescriptor { void Optimize(); } public interface IOverloadableMemberDescriptor : IMemberDescriptor { Type ExtensionMethodType { get; } ParameterDescriptor[] Parameters { get; } Type VarArgsArrayType { get; } Type VarArgsElementType { get; } string SortDiscriminant { get; } DynValue Execute(Script script, object obj, ScriptExecutionContext context, CallbackArguments args); } public interface IWireableDescriptor { void PrepareForWiring(Table t); } [Flags] public enum MemberDescriptorAccess { CanRead = 1, CanWrite = 2, CanExecute = 4 } public sealed class ParameterDescriptor : IWireableDescriptor { public Type m_OriginalType; public string Name { get; set; } public Type Type { get; set; } public bool HasDefaultValue { get; set; } public object DefaultValue { get; set; } public bool IsOut { get; set; } public bool IsRef { get; set; } public bool IsVarArgs { get; set; } public bool HasBeenRestricted => m_OriginalType != null; public Type OriginalType => m_OriginalType ?? Type; public ParameterDescriptor(string name, Type type, bool hasDefaultValue = false, object defaultValue = null, bool isOut = false, bool isRef = false, bool isVarArgs = false) { Name = name; Type = type; HasDefaultValue = hasDefaultValue; DefaultValue = defaultValue; IsOut = isOut; IsRef = isRef; IsVarArgs = isVarArgs; } public ParameterDescriptor(string name, Type type, bool hasDefaultValue, object defaultValue, bool isOut, bool isRef, bool isVarArgs, Type typeRestriction) { Name = name; Type = type; HasDefaultValue = hasDefaultValue; DefaultValue = defaultValue; IsOut = isOut; IsRef = isRef; IsVarArgs = isVarArgs; if (typeRestriction != null) { RestrictType(typeRestriction); } } public ParameterDescriptor(ParameterInfo pi) { Name = pi.Name; Type = pi.ParameterType; HasDefaultValue = !Framework.Do.IsDbNull(pi.DefaultValue); DefaultValue = pi.DefaultValue; IsOut = pi.IsOut; IsRef = pi.ParameterType.IsByRef; IsVarArgs = pi.ParameterType.IsArray && pi.GetCustomAttributes(typeof(ParamArrayAttribute), inherit: true).Any(); } public override string ToString() { return string.Format("{0} {1}{2}", Type.Name, Name, HasDefaultValue ? " = ..." : ""); } public void RestrictType(Type type) { if (IsOut || IsRef || IsVarArgs) { throw new InvalidOperationException("Cannot restrict a ref/out or varargs param"); } if (!Framework.Do.IsAssignableFrom(Type, type)) { throw new InvalidOperationException("Specified operation is not a restriction"); } m_OriginalType = Type; Type = type; } public void PrepareForWiring(Table table) { table.Set("name", DynValue.NewString(Name)); if (Type.IsByRef) { table.Set("type", DynValue.NewString(Type.GetElementType().FullName)); } else { table.Set("type", DynValue.NewString(Type.FullName)); } if (OriginalType.IsByRef) { table.Set("origtype", DynValue.NewString(OriginalType.GetElementType().FullName)); } else { table.Set("origtype", DynValue.NewString(OriginalType.FullName)); } table.Set("default", DynValue.NewBoolean(HasDefaultValue)); table.Set("out", DynValue.NewBoolean(IsOut)); table.Set("ref", DynValue.NewBoolean(IsRef)); table.Set("varargs", DynValue.NewBoolean(IsVarArgs)); table.Set("restricted", DynValue.NewBoolean(HasBeenRestricted)); } } public abstract class DispatchingUserDataDescriptor : IUserDataDescriptor, IOptimizableDescriptor { public int m_ExtMethodsVersion; public Dictionary m_MetaMembers = new Dictionary(); public Dictionary m_Members = new Dictionary(); public const string SPECIALNAME_INDEXER_GET = "get_Item"; public const string SPECIALNAME_INDEXER_SET = "set_Item"; public const string SPECIALNAME_CAST_EXPLICIT = "op_Explicit"; public const string SPECIALNAME_CAST_IMPLICIT = "op_Implicit"; public string Name { get; set; } public Type Type { get; set; } public string FriendlyName { get; set; } public IEnumerable MemberNames => m_Members.Keys; public IEnumerable> Members => m_Members; public IEnumerable MetaMemberNames => m_MetaMembers.Keys; public IEnumerable> MetaMembers => m_MetaMembers; public DispatchingUserDataDescriptor(Type type, string friendlyName = null) { Type = type; Name = type.FullName; FriendlyName = friendlyName ?? type.Name; } public void AddMetaMember(string name, IMemberDescriptor desc) { if (desc != null) { AddMemberTo(m_MetaMembers, name, desc); } } public void AddDynValue(string name, DynValue value) { DynValueMemberDescriptor desc = new DynValueMemberDescriptor(name, value); AddMemberTo(m_Members, name, desc); } public void AddMember(string name, IMemberDescriptor desc) { if (desc != null) { AddMemberTo(m_Members, name, desc); } } public IMemberDescriptor FindMember(string memberName) { return m_Members.GetOrDefault(memberName); } public void RemoveMember(string memberName) { m_Members.Remove(memberName); } public IMemberDescriptor FindMetaMember(string memberName) { return m_MetaMembers.GetOrDefault(memberName); } public void RemoveMetaMember(string memberName) { m_MetaMembers.Remove(memberName); } public void AddMemberTo(Dictionary members, string name, IMemberDescriptor desc) { if (desc is IOverloadableMemberDescriptor overloadableMemberDescriptor) { if (members.ContainsKey(name)) { if (!(members[name] is OverloadedMethodMemberDescriptor overloadedMethodMemberDescriptor)) { throw new ArgumentException($"Multiple members named {name} are being added to type {Type.FullName} and one or more of these members do not support overloads."); } overloadedMethodMemberDescriptor.AddOverload(overloadableMemberDescriptor); } else { members.Add(name, new OverloadedMethodMemberDescriptor(name, Type, overloadableMemberDescriptor)); } } else { if (members.ContainsKey(name)) { throw new ArgumentException($"Multiple members named {name} are being added to type {Type.FullName} and one or more of these members do not support overloads."); } members.Add(name, desc); } } public virtual DynValue Index(Script script, object obj, DynValue index, bool isDirectIndexing) { if (!isDirectIndexing) { IMemberDescriptor memberDescriptor = m_Members.GetOrDefault("get_Item").WithAccessOrNull(MemberDescriptorAccess.CanExecute); if (memberDescriptor != null) { return ExecuteIndexer(memberDescriptor, script, obj, index, null); } } index = index.ToScalar(); if (index.Type != DataType.String) { return null; } DynValue dynValue = TryIndex(script, obj, index.String); if (dynValue == null) { dynValue = TryIndex(script, obj, UpperFirstLetter(index.String)); } if (dynValue == null) { dynValue = TryIndex(script, obj, Camelify(index.String)); } if (dynValue == null) { dynValue = TryIndex(script, obj, UpperFirstLetter(Camelify(index.String))); } if (dynValue == null && m_ExtMethodsVersion < UserData.GetExtensionMethodsChangeVersion()) { m_ExtMethodsVersion = UserData.GetExtensionMethodsChangeVersion(); dynValue = TryIndexOnExtMethod(script, obj, index.String); if (dynValue == null) { dynValue = TryIndexOnExtMethod(script, obj, UpperFirstLetter(index.String)); } if (dynValue == null) { dynValue = TryIndexOnExtMethod(script, obj, Camelify(index.String)); } if (dynValue == null) { dynValue = TryIndexOnExtMethod(script, obj, UpperFirstLetter(Camelify(index.String))); } } return dynValue; } public DynValue TryIndexOnExtMethod(Script script, object obj, string indexName) { List extensionMethodsByNameAndType = UserData.GetExtensionMethodsByNameAndType(indexName, Type); if (extensionMethodsByNameAndType != null && extensionMethodsByNameAndType.Count > 0) { OverloadedMethodMemberDescriptor overloadedMethodMemberDescriptor = new OverloadedMethodMemberDescriptor(indexName, Type); overloadedMethodMemberDescriptor.SetExtensionMethodsSnapshot(UserData.GetExtensionMethodsChangeVersion(), extensionMethodsByNameAndType); m_Members.Add(indexName, overloadedMethodMemberDescriptor); return DynValue.NewCallback(overloadedMethodMemberDescriptor.GetCallback(script, obj)); } return null; } public bool HasMember(string exactName) { return m_Members.ContainsKey(exactName); } public bool HasMetaMember(string exactName) { return m_MetaMembers.ContainsKey(exactName); } public virtual DynValue TryIndex(Script script, object obj, string indexName) { if (m_Members.TryGetValue(indexName, out var value)) { return value.GetValue(script, obj); } return null; } public virtual bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing) { if (!isDirectIndexing) { IMemberDescriptor memberDescriptor = m_Members.GetOrDefault("set_Item").WithAccessOrNull(MemberDescriptorAccess.CanExecute); if (memberDescriptor != null) { ExecuteIndexer(memberDescriptor, script, obj, index, value); return true; } } index = index.ToScalar(); if (index.Type != DataType.String) { return false; } bool flag = TrySetIndex(script, obj, index.String, value); if (!flag) { flag = TrySetIndex(script, obj, UpperFirstLetter(index.String), value); } if (!flag) { flag = TrySetIndex(script, obj, Camelify(index.String), value); } if (!flag) { flag = TrySetIndex(script, obj, UpperFirstLetter(Camelify(index.String)), value); } return flag; } public virtual bool TrySetIndex(Script script, object obj, string indexName, DynValue value) { IMemberDescriptor orDefault = m_Members.GetOrDefault(indexName); if (orDefault != null) { orDefault.SetValue(script, obj, value); return true; } return false; } void IOptimizableDescriptor.Optimize() { foreach (IOptimizableDescriptor item in m_MetaMembers.Values.OfType()) { item.Optimize(); } foreach (IOptimizableDescriptor item2 in m_Members.Values.OfType()) { item2.Optimize(); } } public static string Camelify(string name) { return DescriptorHelpers.Camelify(name); } public static string UpperFirstLetter(string name) { return DescriptorHelpers.UpperFirstLetter(name); } public virtual string AsString(object obj) { return obj?.ToString(); } public virtual DynValue ExecuteIndexer(IMemberDescriptor mdesc, Script script, object obj, DynValue index, DynValue value) { IList list; if (index.Type != DataType.Tuple) { list = ((value != null) ? new DynValue[2] { index, value } : new DynValue[1] { index }); } else if (value == null) { list = index.Tuple; } else { list = new List(index.Tuple); list.Add(value); } CallbackArguments arg = new CallbackArguments(list, isMethodCall: false); ScriptExecutionContext arg2 = script.CreateDynamicExecutionContext(); DynValue value2 = mdesc.GetValue(script, obj); if (value2.Type != DataType.ClrFunction) { throw new ScriptRuntimeException("a clr callback was expected in member {0}, while a {1} was found", mdesc.Name, value2.Type); } return value2.Callback.ClrCallback(arg2, arg); } public virtual DynValue MetaIndex(Script script, object obj, string metaname) { IMemberDescriptor orDefault = m_MetaMembers.GetOrDefault(metaname); if (orDefault != null) { return orDefault.GetValue(script, obj); } return metaname switch { "__add" => DispatchMetaOnMethod(script, obj, "op_Addition"), "__sub" => DispatchMetaOnMethod(script, obj, "op_Subtraction"), "__mul" => DispatchMetaOnMethod(script, obj, "op_Multiply"), "__div" => DispatchMetaOnMethod(script, obj, "op_Division"), "__mod" => DispatchMetaOnMethod(script, obj, "op_Modulus"), "__unm" => DispatchMetaOnMethod(script, obj, "op_UnaryNegation"), "__eq" => MultiDispatchEqual(script, obj), "__lt" => MultiDispatchLessThan(script, obj), "__le" => MultiDispatchLessThanOrEqual(script, obj), "__len" => TryDispatchLength(script, obj), "__tonumber" => TryDispatchToNumber(script, obj), "__tobool" => TryDispatchToBool(script, obj), "__iterator" => ClrToScriptConversions.EnumerationToDynValue(script, obj), _ => null, }; } public int PerformComparison(object obj, object p1, object p2) { IComparable comparable = (IComparable)obj; if (comparable != null) { if (obj == p1) { return comparable.CompareTo(p2); } if (obj == p2) { return -comparable.CompareTo(p1); } } throw new InternalErrorException("unexpected case"); } public DynValue MultiDispatchLessThanOrEqual(Script script, object obj) { if (obj is IComparable) { return DynValue.NewCallback((ScriptExecutionContext context, CallbackArguments args) => DynValue.NewBoolean(PerformComparison(obj, args[0].ToObject(), args[1].ToObject()) <= 0)); } return null; } public DynValue MultiDispatchLessThan(Script script, object obj) { if (obj is IComparable) { return DynValue.NewCallback((ScriptExecutionContext context, CallbackArguments args) => DynValue.NewBoolean(PerformComparison(obj, args[0].ToObject(), args[1].ToObject()) < 0)); } return null; } public DynValue TryDispatchLength(Script script, object obj) { if (obj == null) { return null; } IMemberDescriptor orDefault = m_Members.GetOrDefault("Length"); if (orDefault != null && orDefault.CanRead() && !orDefault.CanExecute()) { return orDefault.GetGetterCallbackAsDynValue(script, obj); } IMemberDescriptor orDefault2 = m_Members.GetOrDefault("Count"); if (orDefault2 != null && orDefault2.CanRead() && !orDefault2.CanExecute()) { return orDefault2.GetGetterCallbackAsDynValue(script, obj); } return null; } public DynValue MultiDispatchEqual(Script script, object obj) { return DynValue.NewCallback((ScriptExecutionContext context, CallbackArguments args) => DynValue.NewBoolean(CheckEquality(obj, args[0].ToObject(), args[1].ToObject()))); } public bool CheckEquality(object obj, object p1, object p2) { if (obj != null) { if (obj == p1) { return obj.Equals(p2); } if (obj == p2) { return obj.Equals(p1); } } return p1?.Equals(p2) ?? p2?.Equals(p1) ?? true; } public DynValue DispatchMetaOnMethod(Script script, object obj, string methodName) { return m_Members.GetOrDefault(methodName)?.GetValue(script, obj); } public DynValue TryDispatchToNumber(Script script, object obj) { Type[] numericTypesOrdered = NumericConversions.NumericTypesOrdered; for (int i = 0; i < numericTypesOrdered.Length; i++) { string conversionMethodName = numericTypesOrdered[i].GetConversionMethodName(); DynValue dynValue = DispatchMetaOnMethod(script, obj, conversionMethodName); if (dynValue != null) { return dynValue; } } return null; } public DynValue TryDispatchToBool(Script script, object obj) { string conversionMethodName = typeof(bool).GetConversionMethodName(); DynValue dynValue = DispatchMetaOnMethod(script, obj, conversionMethodName); if (dynValue != null) { return dynValue; } return DispatchMetaOnMethod(script, obj, "op_True"); } public virtual bool IsTypeCompatible(Type type, object obj) { return Framework.Do.IsInstanceOfType(type, obj); } } } namespace MoonSharp.Interpreter.Execution { [Flags] public enum InstructionFieldUsage { None = 0, Symbol = 1, SymbolList = 2, Name = 4, Value = 8, NumVal = 0x10, NumVal2 = 0x20, NumValAsCodeAddress = 0x8010 } public static class InstructionFieldUsage_Extensions { public static InstructionFieldUsage GetFieldUsage(this OpCode op) { switch (op) { case OpCode.NewTable: case OpCode.TblInitN: case OpCode.Concat: case OpCode.LessEq: case OpCode.Less: case OpCode.Eq: case OpCode.Add: case OpCode.Sub: case OpCode.Mul: case OpCode.Div: case OpCode.Mod: case OpCode.Not: case OpCode.Len: case OpCode.Neg: case OpCode.Power: case OpCode.CNot: case OpCode.Scalar: case OpCode.ToBool: case OpCode.IterPrep: case OpCode.IterUpd: return InstructionFieldUsage.None; case OpCode.Pop: case OpCode.Copy: case OpCode.TblInitI: case OpCode.Ret: case OpCode.MkTuple: case OpCode.Incr: case OpCode.ToNum: case OpCode.ExpTuple: return InstructionFieldUsage.NumVal; case OpCode.Jump: case OpCode.Jf: case OpCode.JNil: case OpCode.JFor: case OpCode.JtOrPop: case OpCode.JfOrPop: return InstructionFieldUsage.NumValAsCodeAddress; case OpCode.Swap: case OpCode.Clean: return InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2; case OpCode.Local: case OpCode.Upvalue: return InstructionFieldUsage.Symbol; case OpCode.IndexSet: case OpCode.IndexSetN: case OpCode.IndexSetL: return InstructionFieldUsage.Symbol | InstructionFieldUsage.Value | InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2; case OpCode.StoreLcl: case OpCode.StoreUpv: return InstructionFieldUsage.Symbol | InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2; case OpCode.Literal: case OpCode.Index: case OpCode.IndexN: case OpCode.IndexL: return InstructionFieldUsage.Value; case OpCode.Args: return InstructionFieldUsage.SymbolList; case OpCode.BeginFn: return InstructionFieldUsage.SymbolList | InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2; case OpCode.Closure: return InstructionFieldUsage.SymbolList | InstructionFieldUsage.NumVal; case OpCode.Nop: case OpCode.Debug: case OpCode.Invalid: return InstructionFieldUsage.Name; case OpCode.Call: case OpCode.ThisCall: return InstructionFieldUsage.Name | InstructionFieldUsage.NumVal; case OpCode.Meta: return InstructionFieldUsage.Name | InstructionFieldUsage.Value | InstructionFieldUsage.NumVal | InstructionFieldUsage.NumVal2; default: throw new NotImplementedException($"InstructionFieldUsage for instruction {(int)op}"); } } } public class ClosureContext : List { public string[] Symbols { get; set; } public ClosureContext(SymbolRef[] symbols, IEnumerable values) { Symbols = symbols.Select((SymbolRef s) => s.i_Name).ToArray(); AddRange(values); } public ClosureContext() { Symbols = new string[0]; } } public interface ILoop { void CompileBreak(ByteCode bc); bool IsBoundary(); } public class LoopTracker { public FastStack Loops = new FastStack(16384); } public interface IClosureBuilder { SymbolRef CreateUpvalue(BuildTimeScope scope, SymbolRef symbol); } public class BuildTimeScope { public List m_Frames = new List(); public List m_ClosureBuilders = new List(); public void PushFunction(IClosureBuilder closureBuilder, bool hasVarArgs) { m_ClosureBuilders.Add(closureBuilder); m_Frames.Add(new BuildTimeScopeFrame(hasVarArgs)); } public void PushBlock() { m_Frames.Last().PushBlock(); } public RuntimeScopeBlock PopBlock() { return m_Frames.Last().PopBlock(); } public RuntimeScopeFrame PopFunction() { BuildTimeScopeFrame buildTimeScopeFrame = m_Frames.Last(); buildTimeScopeFrame.ResolveLRefs(); m_Frames.RemoveAt(m_Frames.Count - 1); m_ClosureBuilders.RemoveAt(m_ClosureBuilders.Count - 1); return buildTimeScopeFrame.GetRuntimeFrameData(); } public SymbolRef Find(string name) { SymbolRef symbolRef = m_Frames.Last().Find(name); if (symbolRef != null) { return symbolRef; } for (int num = m_Frames.Count - 2; num >= 0; num--) { SymbolRef symbolRef2 = m_Frames[num].Find(name); if (symbolRef2 != null) { symbolRef2 = CreateUpValue(this, symbolRef2, num, m_Frames.Count - 2); if (symbolRef2 != null) { return symbolRef2; } } } return CreateGlobalReference(name); } public SymbolRef CreateGlobalReference(string name) { if (name == "_ENV") { throw new InternalErrorException("_ENV passed in CreateGlobalReference"); } SymbolRef envSymbol = Find("_ENV"); return SymbolRef.Global(name, envSymbol); } public void ForceEnvUpValue() { Find("_ENV"); } public SymbolRef CreateUpValue(BuildTimeScope buildTimeScope, SymbolRef symb, int closuredFrame, int currentFrame) { if (closuredFrame == currentFrame) { return m_ClosureBuilders[currentFrame + 1].CreateUpvalue(this, symb); } SymbolRef symbol = CreateUpValue(buildTimeScope, symb, closuredFrame, currentFrame - 1); return m_ClosureBuilders[currentFrame + 1].CreateUpvalue(this, symbol); } public SymbolRef DefineLocal(string name) { return m_Frames.Last().DefineLocal(name); } public SymbolRef TryDefineLocal(string name) { return m_Frames.Last().TryDefineLocal(name); } public bool CurrentFunctionHasVarArgs() { return m_Frames.Last().HasVarArgs; } public void DefineLabel(LabelStatement label) { m_Frames.Last().DefineLabel(label); } public void RegisterGoto(GotoStatement gotostat) { m_Frames.Last().RegisterGoto(gotostat); } } public class RuntimeScopeBlock { public int From { get; set; } public int To { get; set; } public int ToInclusive { get; set; } public override string ToString() { return $"ScopeBlock : {From} -> {To} --> {ToInclusive}"; } } public class RuntimeScopeFrame { public List DebugSymbols { get; set; } public int Count => DebugSymbols.Count; public int ToFirstBlock { get; set; } public RuntimeScopeFrame() { DebugSymbols = new List(); } public override string ToString() { return $"ScopeFrame : #{Count}"; } } public class ScriptLoadingContext { public Script Script { get; set; } public BuildTimeScope Scope { get; set; } public SourceCode Source { get; set; } public bool Anonymous { get; set; } public bool IsDynamicExpression { get; set; } public Lexer Lexer { get; set; } public ScriptLoadingContext(Script s) { Script = s; } } } namespace MoonSharp.Interpreter.Execution.Scopes { public class BuildTimeScopeBlock { public Dictionary m_DefinedNames = new Dictionary(); public List m_PendingGotos; public Dictionary m_LocalLabels; public string m_LastDefinedName; public BuildTimeScopeBlock Parent { get; set; } public List ChildNodes { get; set; } public RuntimeScopeBlock ScopeBlock { get; set; } public void Rename(string name) { SymbolRef value = m_DefinedNames[name]; m_DefinedNames.Remove(name); m_DefinedNames.Add(string.Format("@{0}_{1}", name, Guid.NewGuid().ToString("N")), value); } public BuildTimeScopeBlock(BuildTimeScopeBlock parent) { Parent = parent; ChildNodes = new List(); ScopeBlock = new RuntimeScopeBlock(); } public BuildTimeScopeBlock AddChild() { BuildTimeScopeBlock buildTimeScopeBlock = new BuildTimeScopeBlock(this); ChildNodes.Add(buildTimeScopeBlock); return buildTimeScopeBlock; } public SymbolRef Find(string name) { return m_DefinedNames.GetOrDefault(name); } public SymbolRef Define(string name) { SymbolRef symbolRef = SymbolRef.Local(name, -1); m_DefinedNames.Add(name, symbolRef); m_LastDefinedName = name; return symbolRef; } public int ResolveLRefs(BuildTimeScopeFrame buildTimeScopeFrame) { int num = -1; int num2 = -1; foreach (SymbolRef value in m_DefinedNames.Values) { int num3 = buildTimeScopeFrame.AllocVar(value); if (num < 0) { num = num3; } num2 = num3; } ScopeBlock.From = num; RuntimeScopeBlock scopeBlock = ScopeBlock; int toInclusive = (ScopeBlock.To = num2); scopeBlock.ToInclusive = toInclusive; if (num < 0) { ScopeBlock.From = buildTimeScopeFrame.GetPosForNextVar(); } foreach (BuildTimeScopeBlock childNode in ChildNodes) { ScopeBlock.ToInclusive = Math.Max(ScopeBlock.ToInclusive, childNode.ResolveLRefs(buildTimeScopeFrame)); } if (m_LocalLabels != null) { foreach (LabelStatement value2 in m_LocalLabels.Values) { value2.SetScope(ScopeBlock); } } return ScopeBlock.ToInclusive; } public void DefineLabel(LabelStatement label) { if (m_LocalLabels == null) { m_LocalLabels = new Dictionary(); } if (m_LocalLabels.ContainsKey(label.Label)) { throw new SyntaxErrorException(label.NameToken, "label '{0}' already defined on line {1}", label.Label, m_LocalLabels[label.Label].SourceRef.FromLine); } m_LocalLabels.Add(label.Label, label); label.SetDefinedVars(m_DefinedNames.Count, m_LastDefinedName); } public void RegisterGoto(GotoStatement gotostat) { if (m_PendingGotos == null) { m_PendingGotos = new List(); } m_PendingGotos.Add(gotostat); gotostat.SetDefinedVars(m_DefinedNames.Count, m_LastDefinedName); } public void ResolveGotos() { if (m_PendingGotos == null) { return; } foreach (GotoStatement pendingGoto in m_PendingGotos) { if (m_LocalLabels != null && m_LocalLabels.TryGetValue(pendingGoto.Label, out var value)) { if (value.DefinedVarsCount > pendingGoto.DefinedVarsCount) { throw new SyntaxErrorException(pendingGoto.GotoToken, " at line {1} jumps into the scope of local '{2}'", pendingGoto.Label, pendingGoto.GotoToken.FromLine, value.LastDefinedVarName); } value.RegisterGoto(pendingGoto); } else { if (Parent == null) { throw new SyntaxErrorException(pendingGoto.GotoToken, "no visible label '{0}' for at line {1}", pendingGoto.Label, pendingGoto.GotoToken.FromLine); } Parent.RegisterGoto(pendingGoto); } } m_PendingGotos.Clear(); } } public class BuildTimeScopeFrame { public BuildTimeScopeBlock m_ScopeTreeRoot; public BuildTimeScopeBlock m_ScopeTreeHead; public RuntimeScopeFrame m_ScopeFrame = new RuntimeScopeFrame(); public bool HasVarArgs { get; set; } public BuildTimeScopeFrame(bool hasVarArgs) { HasVarArgs = hasVarArgs; m_ScopeTreeHead = (m_ScopeTreeRoot = new BuildTimeScopeBlock(null)); } public void PushBlock() { m_ScopeTreeHead = m_ScopeTreeHead.AddChild(); } public RuntimeScopeBlock PopBlock() { BuildTimeScopeBlock scopeTreeHead = m_ScopeTreeHead; m_ScopeTreeHead.ResolveGotos(); m_ScopeTreeHead = m_ScopeTreeHead.Parent; if (m_ScopeTreeHead == null) { throw new InternalErrorException("Can't pop block - stack underflow"); } return scopeTreeHead.ScopeBlock; } public RuntimeScopeFrame GetRuntimeFrameData() { if (m_ScopeTreeHead != m_ScopeTreeRoot) { throw new InternalErrorException("Misaligned scope frames/blocks!"); } m_ScopeFrame.ToFirstBlock = m_ScopeTreeRoot.ScopeBlock.To; return m_ScopeFrame; } public SymbolRef Find(string name) { for (BuildTimeScopeBlock buildTimeScopeBlock = m_ScopeTreeHead; buildTimeScopeBlock != null; buildTimeScopeBlock = buildTimeScopeBlock.Parent) { SymbolRef symbolRef = buildTimeScopeBlock.Find(name); if (symbolRef != null) { return symbolRef; } } return null; } public SymbolRef DefineLocal(string name) { return m_ScopeTreeHead.Define(name); } public SymbolRef TryDefineLocal(string name) { if (m_ScopeTreeHead.Find(name) != null) { m_ScopeTreeHead.Rename(name); } return m_ScopeTreeHead.Define(name); } public void ResolveLRefs() { m_ScopeTreeRoot.ResolveGotos(); m_ScopeTreeRoot.ResolveLRefs(this); } public int AllocVar(SymbolRef var) { var.i_Index = m_ScopeFrame.DebugSymbols.Count; m_ScopeFrame.DebugSymbols.Add(var); return var.i_Index; } public int GetPosForNextVar() { return m_ScopeFrame.DebugSymbols.Count; } public void DefineLabel(LabelStatement label) { m_ScopeTreeHead.DefineLabel(label); } public void RegisterGoto(GotoStatement gotostat) { m_ScopeTreeHead.RegisterGoto(gotostat); } } } namespace MoonSharp.Interpreter.Execution.VM { public enum OpCodeMetadataType { ChunkEntrypoint, FunctionEntrypoint } public sealed class Processor { public class DebugContext { public bool DebuggerEnabled = true; public IDebugger DebuggerAttached; public DebuggerAction.ActionType DebuggerCurrentAction = DebuggerAction.ActionType.None; public int DebuggerCurrentActionTarget = -1; public SourceRef LastHlRef; public int ExStackDepthAtStep = -1; public List BreakPoints = new List(); public bool LineBasedBreakPoints; } public const ulong DUMP_CHUNK_MAGIC = 1877195438928383261uL; public const int DUMP_CHUNK_VERSION = 336; public ByteCode m_RootChunk; public FastStack m_ValueStack = new FastStack(131072); public FastStack m_ExecutionStack = new FastStack(131072); public List m_CoroutinesStack; public Table m_GlobalTable; public Script m_Script; public Processor m_Parent; public CoroutineState m_State; public bool m_CanYield = true; public int m_SavedInstructionPtr = -1; public DebugContext m_Debug; public int m_OwningThreadID = -1; public int m_ExecutionNesting; public const int YIELD_SPECIAL_TRAP = -99; public long AutoYieldCounter; public CoroutineState State => m_State; public Coroutine AssociatedCoroutine { get; set; } public bool DebuggerEnabled { get { return m_Debug.DebuggerEnabled; } set { m_Debug.DebuggerEnabled = value; } } public static bool IsDumpStream(Stream stream) { if (stream.Length >= 8) { using (BinaryReader binaryReader = new BinaryReader(stream, Encoding.UTF8)) { ulong num = binaryReader.ReadUInt64(); stream.Seek(-8L, SeekOrigin.Current); return num == 1877195438928383261L; } } return false; } public int Dump(Stream stream, int baseAddress, bool hasUpvalues) { using BinaryWriter binaryWriter = new BinDumpBinaryWriter(stream, Encoding.UTF8); Dictionary dictionary = new Dictionary(); Instruction instruction = FindMeta(ref baseAddress); if (instruction == null) { throw new ArgumentException("baseAddress"); } binaryWriter.Write(1877195438928383261uL); binaryWriter.Write(336); binaryWriter.Write(hasUpvalues); binaryWriter.Write(instruction.NumVal); SymbolRef[] array; for (int i = 0; i <= instruction.NumVal; i++) { m_RootChunk.Code[baseAddress + i].GetSymbolReferences(out var symbolList, out var symbol); if (symbol != null) { AddSymbolToMap(dictionary, symbol); } if (symbolList != null) { array = symbolList; foreach (SymbolRef s in array) { AddSymbolToMap(dictionary, s); } } } array = dictionary.Keys.ToArray(); foreach (SymbolRef symbolRef in array) { if (symbolRef.i_Env != null) { AddSymbolToMap(dictionary, symbolRef.i_Env); } } SymbolRef[] array2 = new SymbolRef[dictionary.Count]; foreach (KeyValuePair item in dictionary) { array2[item.Value] = item.Key; } binaryWriter.Write(dictionary.Count); array = array2; for (int j = 0; j < array.Length; j++) { array[j].WriteBinary(binaryWriter); } array = array2; for (int j = 0; j < array.Length; j++) { array[j].WriteBinaryEnv(binaryWriter, dictionary); } for (int k = 0; k <= instruction.NumVal; k++) { m_RootChunk.Code[baseAddress + k].WriteBinary(binaryWriter, baseAddress, dictionary); } return instruction.NumVal + baseAddress + 1; } public void AddSymbolToMap(Dictionary symbolMap, SymbolRef s) { if (!symbolMap.ContainsKey(s)) { symbolMap.Add(s, symbolMap.Count); } } public int Undump(Stream stream, int sourceID, Table envTable, out bool hasUpvalues) { int count = m_RootChunk.Code.Count; SourceRef chunkRef = new SourceRef(sourceID, 0, 0, 0, 0, isStepStop: false); using BinaryReader binaryReader = new BinDumpBinaryReader(stream, Encoding.UTF8); if (binaryReader.ReadUInt64() != 1877195438928383261L) { throw new ArgumentException("Not a MoonSharp chunk"); } if (binaryReader.ReadInt32() != 336) { throw new ArgumentException("Invalid version"); } hasUpvalues = binaryReader.ReadBoolean(); int num = binaryReader.ReadInt32(); int num2 = binaryReader.ReadInt32(); SymbolRef[] array = new SymbolRef[num2]; for (int i = 0; i < num2; i++) { array[i] = SymbolRef.ReadBinary(binaryReader); } for (int j = 0; j < num2; j++) { array[j].ReadBinaryEnv(binaryReader, array); } for (int k = 0; k <= num; k++) { Instruction item = Instruction.ReadBinary(chunkRef, binaryReader, count, envTable, array); m_RootChunk.Code.Add(item); } return count; } public DynValue Coroutine_Create(Closure closure) { Processor processor = new Processor(this); processor.m_ValueStack.Push(DynValue.NewClosure(closure)); return DynValue.NewCoroutine(new Coroutine(processor)); } public DynValue Coroutine_Resume(DynValue[] args) { EnterProcessor(); try { int instructionPtr = 0; if (m_State != CoroutineState.NotStarted && m_State != CoroutineState.Suspended && m_State != CoroutineState.ForceSuspended) { throw ScriptRuntimeException.CannotResumeNotSuspended(m_State); } if (m_State == CoroutineState.NotStarted) { instructionPtr = PushClrToScriptStackFrame(CallStackItemFlags.ResumeEntryPoint, null, args); } else if (m_State == CoroutineState.Suspended) { m_ValueStack.Push(DynValue.NewTuple(args)); instructionPtr = m_SavedInstructionPtr; } else if (m_State == CoroutineState.ForceSuspended) { if (args != null && args.Length != 0) { throw new ArgumentException("When resuming a force-suspended coroutine, args must be empty."); } instructionPtr = m_SavedInstructionPtr; } m_State = CoroutineState.Running; DynValue dynValue = Processing_Loop(instructionPtr); if (dynValue.Type == DataType.YieldRequest) { if (dynValue.YieldRequest.Forced) { m_State = CoroutineState.ForceSuspended; return dynValue; } m_State = CoroutineState.Suspended; return DynValue.NewTuple(dynValue.YieldRequest.ReturnValues); } m_State = CoroutineState.Dead; return dynValue; } catch (Exception) { m_State = CoroutineState.Dead; throw; } finally { LeaveProcessor(); } } public SourceRef GetCurrentSourceRef(int instructionPtr) { if (instructionPtr >= 0 && instructionPtr < m_RootChunk.Code.Count) { return m_RootChunk.Code[instructionPtr].SourceCodeRef; } return null; } public void FillDebugData(InterpreterException ex, int ip) { ip = ((ip != -99) ? (ip - 1) : m_SavedInstructionPtr); ex.InstructionPtr = ip; SourceRef currentSourceRef = GetCurrentSourceRef(ip); ex.DecorateMessage(m_Script, currentSourceRef, ip); ex.CallStack = Debugger_GetCallStack(currentSourceRef); } public Processor(Script script, Table globalContext, ByteCode byteCode) { m_CoroutinesStack = new List(); m_Debug = new DebugContext(); m_RootChunk = byteCode; m_GlobalTable = globalContext; m_Script = script; m_State = CoroutineState.Main; DynValue.NewCoroutine(new Coroutine(this)); } public Processor(Processor parentProcessor) { m_Debug = parentProcessor.m_Debug; m_RootChunk = parentProcessor.m_RootChunk; m_GlobalTable = parentProcessor.m_GlobalTable; m_Script = parentProcessor.m_Script; m_Parent = parentProcessor; m_State = CoroutineState.NotStarted; } public DynValue Call(DynValue function, DynValue[] args) { List list = ((m_Parent != null) ? m_Parent.m_CoroutinesStack : m_CoroutinesStack); if (list.Count > 0 && list[list.Count - 1] != this) { return list[list.Count - 1].Call(function, args); } EnterProcessor(); try { IDisposable disposable = m_Script.PerformanceStats.StartStopwatch(PerformanceCounter.Execution); m_CanYield = false; try { int instructionPtr = PushClrToScriptStackFrame(CallStackItemFlags.CallEntryPoint, function, args); return Processing_Loop(instructionPtr); } finally { m_CanYield = true; disposable?.Dispose(); } } finally { LeaveProcessor(); } } public int PushClrToScriptStackFrame(CallStackItemFlags flags, DynValue function, DynValue[] args) { if (function == null) { function = m_ValueStack.Peek(); } else { m_ValueStack.Push(function); } args = Internal_AdjustTuple(args); for (int i = 0; i < args.Length; i++) { m_ValueStack.Push(args[i]); } m_ValueStack.Push(DynValue.NewNumber(args.Length)); m_ExecutionStack.Push(new CallStackItem { BasePointer = m_ValueStack.Count, Debug_EntryPoint = function.Function.EntryPointByteCodeLocation, ReturnAddress = -1, ClosureScope = function.Function.ClosureContext, CallingSourceRef = SourceRef.GetClrLocation(), Flags = flags }); return function.Function.EntryPointByteCodeLocation; } public void LeaveProcessor() { m_ExecutionNesting--; m_OwningThreadID = -1; if (m_Parent != null) { m_Parent.m_CoroutinesStack.RemoveAt(m_Parent.m_CoroutinesStack.Count - 1); } if (m_ExecutionNesting == 0 && m_Debug != null && m_Debug.DebuggerEnabled && m_Debug.DebuggerAttached != null) { m_Debug.DebuggerAttached.SignalExecutionEnded(); } } public int GetThreadId() { return Thread.CurrentThread.ManagedThreadId; } public void EnterProcessor() { int threadId = GetThreadId(); if (m_OwningThreadID >= 0 && m_OwningThreadID != threadId && m_Script.Options.CheckThreadAccess) { throw new InvalidOperationException($"Cannot enter the same MoonSharp processor from two different threads : {m_OwningThreadID} and {threadId}"); } m_OwningThreadID = threadId; m_ExecutionNesting++; if (m_Parent != null) { m_Parent.m_CoroutinesStack.Add(this); } } public SourceRef GetCoroutineSuspendedLocation() { return GetCurrentSourceRef(m_SavedInstructionPtr); } public Instruction FindMeta(ref int baseAddress) { Instruction instruction = m_RootChunk.Code[baseAddress]; while (instruction.OpCode == OpCode.Nop) { baseAddress++; instruction = m_RootChunk.Code[baseAddress]; } if (instruction.OpCode != OpCode.Meta) { return null; } return instruction; } public void AttachDebugger(IDebugger debugger) { m_Debug.DebuggerAttached = debugger; m_Debug.LineBasedBreakPoints = (debugger.GetDebuggerCaps() & DebuggerCaps.HasLineBasedBreakpoints) != 0; debugger.SetDebugService(new DebugService(m_Script, this)); } public void ListenDebugger(Instruction instr, int instructionPtr) { bool flag = false; if (instr.SourceCodeRef != null && m_Debug.LastHlRef != null) { flag = ((!m_Debug.LineBasedBreakPoints) ? (instr.SourceCodeRef != m_Debug.LastHlRef) : (instr.SourceCodeRef.SourceIdx != m_Debug.LastHlRef.SourceIdx || instr.SourceCodeRef.FromLine != m_Debug.LastHlRef.FromLine)); } else if (m_Debug.LastHlRef == null) { flag = instr.SourceCodeRef != null; } if (m_Debug.DebuggerAttached.IsPauseRequested() || (instr.SourceCodeRef != null && instr.SourceCodeRef.Breakpoint && flag)) { m_Debug.DebuggerCurrentAction = DebuggerAction.ActionType.None; m_Debug.DebuggerCurrentActionTarget = -1; } switch (m_Debug.DebuggerCurrentAction) { case DebuggerAction.ActionType.Run: if (m_Debug.LineBasedBreakPoints) { m_Debug.LastHlRef = instr.SourceCodeRef; } return; case DebuggerAction.ActionType.ByteCodeStepOver: if (m_Debug.DebuggerCurrentActionTarget != instructionPtr) { return; } break; case DebuggerAction.ActionType.ByteCodeStepOut: case DebuggerAction.ActionType.StepOut: if (m_ExecutionStack.Count >= m_Debug.ExStackDepthAtStep) { return; } break; case DebuggerAction.ActionType.StepIn: if (m_ExecutionStack.Count >= m_Debug.ExStackDepthAtStep && (instr.SourceCodeRef == null || instr.SourceCodeRef == m_Debug.LastHlRef)) { return; } break; case DebuggerAction.ActionType.StepOver: if (instr.SourceCodeRef == null || instr.SourceCodeRef == m_Debug.LastHlRef || m_ExecutionStack.Count > m_Debug.ExStackDepthAtStep) { return; } break; } RefreshDebugger(hard: false, instructionPtr); while (true) { DebuggerAction action = m_Debug.DebuggerAttached.GetAction(instructionPtr, instr.SourceCodeRef); switch (action.Action) { case DebuggerAction.ActionType.ByteCodeStepOut: case DebuggerAction.ActionType.StepIn: case DebuggerAction.ActionType.StepOver: case DebuggerAction.ActionType.StepOut: m_Debug.DebuggerCurrentAction = action.Action; m_Debug.LastHlRef = instr.SourceCodeRef; m_Debug.ExStackDepthAtStep = m_ExecutionStack.Count; return; case DebuggerAction.ActionType.ByteCodeStepIn: m_Debug.DebuggerCurrentAction = DebuggerAction.ActionType.ByteCodeStepIn; m_Debug.DebuggerCurrentActionTarget = -1; return; case DebuggerAction.ActionType.ByteCodeStepOver: m_Debug.DebuggerCurrentAction = DebuggerAction.ActionType.ByteCodeStepOver; m_Debug.DebuggerCurrentActionTarget = instructionPtr + 1; return; case DebuggerAction.ActionType.Run: m_Debug.DebuggerCurrentAction = DebuggerAction.ActionType.Run; m_Debug.LastHlRef = instr.SourceCodeRef; m_Debug.DebuggerCurrentActionTarget = -1; return; case DebuggerAction.ActionType.ToggleBreakpoint: ToggleBreakPoint(action, null); RefreshDebugger(hard: true, instructionPtr); break; case DebuggerAction.ActionType.ResetBreakpoints: ResetBreakPoints(action); RefreshDebugger(hard: true, instructionPtr); break; case DebuggerAction.ActionType.SetBreakpoint: ToggleBreakPoint(action, true); RefreshDebugger(hard: true, instructionPtr); break; case DebuggerAction.ActionType.ClearBreakpoint: ToggleBreakPoint(action, false); RefreshDebugger(hard: true, instructionPtr); break; case DebuggerAction.ActionType.Refresh: RefreshDebugger(hard: false, instructionPtr); break; case DebuggerAction.ActionType.HardRefresh: RefreshDebugger(hard: true, instructionPtr); break; } } } public void ResetBreakPoints(DebuggerAction action) { SourceCode sourceCode = m_Script.GetSourceCode(action.SourceID); ResetBreakPoints(sourceCode, new HashSet(action.Lines)); } public HashSet ResetBreakPoints(SourceCode src, HashSet lines) { HashSet hashSet = new HashSet(); foreach (SourceRef @ref in src.Refs) { if (!@ref.CannotBreakpoint) { @ref.Breakpoint = lines.Contains(@ref.FromLine); if (@ref.Breakpoint) { hashSet.Add(@ref.FromLine); } } } return hashSet; } public bool ToggleBreakPoint(DebuggerAction action, bool? state) { SourceCode sourceCode = m_Script.GetSourceCode(action.SourceID); bool flag = false; foreach (SourceRef @ref in sourceCode.Refs) { if (!@ref.CannotBreakpoint && @ref.IncludesLocation(action.SourceID, action.SourceLine, action.SourceCol)) { flag = true; if (!state.HasValue) { @ref.Breakpoint = !@ref.Breakpoint; } else { @ref.Breakpoint = state.Value; } if (@ref.Breakpoint) { m_Debug.BreakPoints.Add(@ref); } else { m_Debug.BreakPoints.Remove(@ref); } } } if (!flag) { int num = int.MaxValue; SourceRef sourceRef = null; foreach (SourceRef ref2 in sourceCode.Refs) { if (!ref2.CannotBreakpoint) { int locationDistance = ref2.GetLocationDistance(action.SourceID, action.SourceLine, action.SourceCol); if (locationDistance < num) { num = locationDistance; sourceRef = ref2; } } } if (sourceRef != null) { if (!state.HasValue) { sourceRef.Breakpoint = !sourceRef.Breakpoint; } else { sourceRef.Breakpoint = state.Value; } if (sourceRef.Breakpoint) { m_Debug.BreakPoints.Add(sourceRef); } else { m_Debug.BreakPoints.Remove(sourceRef); } return true; } return false; } return true; } public void RefreshDebugger(bool hard, int instructionPtr) { SourceRef currentSourceRef = GetCurrentSourceRef(instructionPtr); ScriptExecutionContext context = new ScriptExecutionContext(this, null, currentSourceRef); List watchItems = m_Debug.DebuggerAttached.GetWatchItems(); List items = Debugger_GetCallStack(currentSourceRef); List items2 = Debugger_RefreshWatches(context, watchItems); List items3 = Debugger_RefreshVStack(); List items4 = Debugger_RefreshLocals(context); List items5 = Debugger_RefreshThreads(context); m_Debug.DebuggerAttached.Update(WatchType.CallStack, items); m_Debug.DebuggerAttached.Update(WatchType.Watches, items2); m_Debug.DebuggerAttached.Update(WatchType.VStack, items3); m_Debug.DebuggerAttached.Update(WatchType.Locals, items4); m_Debug.DebuggerAttached.Update(WatchType.Threads, items5); if (hard) { m_Debug.DebuggerAttached.RefreshBreakpoints(m_Debug.BreakPoints); } } public List Debugger_RefreshThreads(ScriptExecutionContext context) { return ((m_Parent != null) ? m_Parent.m_CoroutinesStack : m_CoroutinesStack).Select((Processor c) => new WatchItem { Address = c.AssociatedCoroutine.ReferenceID, Name = "coroutine #" + c.AssociatedCoroutine.ReferenceID }).ToList(); } public List Debugger_RefreshVStack() { List list = new List(); for (int i = 0; i < Math.Min(32, m_ValueStack.Count); i++) { list.Add(new WatchItem { Address = i, Value = m_ValueStack.Peek(i) }); } return list; } public List Debugger_RefreshWatches(ScriptExecutionContext context, List watchList) { return watchList.Select((DynamicExpression w) => Debugger_RefreshWatch(context, w)).ToList(); } public List Debugger_RefreshLocals(ScriptExecutionContext context) { List list = new List(); CallStackItem callStackItem = m_ExecutionStack.Peek(); if (callStackItem != null && callStackItem.Debug_Symbols != null && callStackItem.LocalScope != null) { int num = Math.Min(callStackItem.Debug_Symbols.Length, callStackItem.LocalScope.Length); for (int i = 0; i < num; i++) { list.Add(new WatchItem { IsError = false, LValue = callStackItem.Debug_Symbols[i], Value = callStackItem.LocalScope[i], Name = callStackItem.Debug_Symbols[i].i_Name }); } } return list; } public WatchItem Debugger_RefreshWatch(ScriptExecutionContext context, DynamicExpression dynExpr) { try { SymbolRef lValue = dynExpr.FindSymbol(context); DynValue value = dynExpr.Evaluate(context); return new WatchItem { IsError = dynExpr.IsConstant(), LValue = lValue, Value = value, Name = dynExpr.ExpressionCode }; } catch (Exception ex) { return new WatchItem { IsError = true, Value = DynValue.NewString(ex.Message), Name = dynExpr.ExpressionCode }; } } public List Debugger_GetCallStack(SourceRef startingRef) { List list = new List(); for (int i = 0; i < m_ExecutionStack.Count; i++) { CallStackItem callStackItem = m_ExecutionStack.Peek(i); Instruction instruction = m_RootChunk.Code[callStackItem.Debug_EntryPoint]; string name = ((instruction.OpCode == OpCode.Meta) ? instruction.Name : null); if (callStackItem.ClrFunction != null) { list.Add(new WatchItem { Address = -1, BasePtr = -1, RetAddress = callStackItem.ReturnAddress, Location = startingRef, Name = callStackItem.ClrFunction.Name }); } else { list.Add(new WatchItem { Address = callStackItem.Debug_EntryPoint, BasePtr = callStackItem.BasePointer, RetAddress = callStackItem.ReturnAddress, Name = name, Location = startingRef }); } startingRef = callStackItem.CallingSourceRef; if (callStackItem.Continuation != null) { list.Add(new WatchItem { Name = callStackItem.Continuation.Name, Location = SourceRef.GetClrLocation() }); } } return list; } public Table GetMetatable(DynValue value) { if (value.Type == DataType.Table) { return value.Table.MetaTable; } if (value.Type.CanHaveTypeMetatables()) { return m_Script.GetTypeMetatable(value.Type); } return null; } public DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventName) { Table metatable = GetMetatable(op1); if (metatable != null) { DynValue dynValue = metatable.RawGet(eventName); if (dynValue != null && dynValue.IsNotNil()) { return dynValue; } } Table metatable2 = GetMetatable(op2); if (metatable2 != null) { DynValue dynValue2 = metatable2.RawGet(eventName); if (dynValue2 != null && dynValue2.IsNotNil()) { return dynValue2; } } if (op1.Type == DataType.UserData) { DynValue dynValue3 = op1.UserData.Descriptor.MetaIndex(m_Script, op1.UserData.Object, eventName); if (dynValue3 != null) { return dynValue3; } } if (op2.Type == DataType.UserData) { DynValue dynValue4 = op2.UserData.Descriptor.MetaIndex(m_Script, op2.UserData.Object, eventName); if (dynValue4 != null) { return dynValue4; } } return null; } public DynValue GetMetamethod(DynValue value, string metamethod) { if (value.Type == DataType.UserData) { DynValue dynValue = value.UserData.Descriptor.MetaIndex(m_Script, value.UserData.Object, metamethod); if (dynValue != null) { return dynValue; } } return GetMetamethodRaw(value, metamethod); } public DynValue GetMetamethodRaw(DynValue value, string metamethod) { Table metatable = GetMetatable(value); if (metatable == null) { return null; } DynValue dynValue = metatable.RawGet(metamethod); if (dynValue == null || dynValue.IsNil()) { return null; } return dynValue; } public Script GetScript() { return m_Script; } public DynValue Processing_Loop(int instructionPtr) { long num = 0L; bool flag = AutoYieldCounter > 0 && m_CanYield && State != CoroutineState.Main; while (true) { try { while (true) { Instruction instruction = m_RootChunk.Code[instructionPtr]; if (m_Debug.DebuggerAttached != null) { ListenDebugger(instruction, instructionPtr); } num++; if (flag && num > AutoYieldCounter) { m_SavedInstructionPtr = instructionPtr; return DynValue.NewForcedYieldReq(); } instructionPtr++; switch (instruction.OpCode) { case OpCode.Nop: case OpCode.Debug: case OpCode.Meta: continue; case OpCode.Pop: m_ValueStack.RemoveLast(instruction.NumVal); continue; case OpCode.Copy: m_ValueStack.Push(m_ValueStack.Peek(instruction.NumVal)); continue; case OpCode.Swap: ExecSwap(instruction); continue; case OpCode.Literal: m_ValueStack.Push(instruction.Value); continue; case OpCode.Add: instructionPtr = ExecAdd(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Concat: instructionPtr = ExecConcat(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Neg: instructionPtr = ExecNeg(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Sub: instructionPtr = ExecSub(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Mul: instructionPtr = ExecMul(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Div: instructionPtr = ExecDiv(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Mod: instructionPtr = ExecMod(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Power: instructionPtr = ExecPower(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Eq: instructionPtr = ExecEq(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.LessEq: instructionPtr = ExecLessEq(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Less: instructionPtr = ExecLess(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Len: instructionPtr = ExecLen(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Call: case OpCode.ThisCall: instructionPtr = Internal_ExecCall(instruction.NumVal, instructionPtr, null, null, instruction.OpCode == OpCode.ThisCall, instruction.Name); if (instructionPtr != -99) { continue; } break; case OpCode.Scalar: m_ValueStack.Push(m_ValueStack.Pop().ToScalar()); continue; case OpCode.Not: ExecNot(instruction); continue; case OpCode.CNot: ExecCNot(instruction); continue; case OpCode.JtOrPop: case OpCode.JfOrPop: instructionPtr = ExecShortCircuitingOperator(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.JNil: { DynValue dynValue = m_ValueStack.Pop().ToScalar(); if (dynValue.Type == DataType.Nil || dynValue.Type == DataType.Void) { instructionPtr = instruction.NumVal; } if (instructionPtr != -99) { continue; } break; } case OpCode.Jf: instructionPtr = JumpBool(instruction, expectedValueForJump: false, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Jump: instructionPtr = instruction.NumVal; if (instructionPtr != -99) { continue; } break; case OpCode.MkTuple: ExecMkTuple(instruction); continue; case OpCode.Clean: ClearBlockData(instruction); continue; case OpCode.Closure: ExecClosure(instruction); continue; case OpCode.BeginFn: ExecBeginFn(instruction); continue; case OpCode.ToBool: m_ValueStack.Push(DynValue.NewBoolean(m_ValueStack.Pop().ToScalar().CastToBool())); continue; case OpCode.Args: ExecArgs(instruction); continue; case OpCode.Ret: instructionPtr = ExecRet(instruction); if (instructionPtr == -99) { break; } if (instructionPtr >= 0) { continue; } goto end_IL_0023; case OpCode.Incr: ExecIncr(instruction); continue; case OpCode.ToNum: ExecToNum(instruction); continue; case OpCode.JFor: instructionPtr = ExecJFor(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.NewTable: if (instruction.NumVal == 0) { m_ValueStack.Push(DynValue.NewTable(m_Script)); } else { m_ValueStack.Push(DynValue.NewPrimeTable()); } continue; case OpCode.IterPrep: ExecIterPrep(instruction); continue; case OpCode.IterUpd: ExecIterUpd(instruction); continue; case OpCode.ExpTuple: ExecExpTuple(instruction); continue; case OpCode.Local: { DynValue[] localScope = m_ExecutionStack.Peek().LocalScope; int i_Index = instruction.Symbol.i_Index; m_ValueStack.Push(localScope[i_Index].AsReadOnly()); continue; } case OpCode.Upvalue: m_ValueStack.Push(m_ExecutionStack.Peek().ClosureScope[instruction.Symbol.i_Index].AsReadOnly()); continue; case OpCode.StoreUpv: ExecStoreUpv(instruction); continue; case OpCode.StoreLcl: ExecStoreLcl(instruction); continue; case OpCode.TblInitN: ExecTblInitN(instruction); continue; case OpCode.TblInitI: ExecTblInitI(instruction); continue; case OpCode.Index: case OpCode.IndexN: case OpCode.IndexL: instructionPtr = ExecIndex(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.IndexSet: case OpCode.IndexSetN: case OpCode.IndexSetL: instructionPtr = ExecIndexSet(instruction, instructionPtr); if (instructionPtr != -99) { continue; } break; case OpCode.Invalid: throw new NotImplementedException($"Invalid opcode : {instruction.Name}"); default: throw new NotImplementedException($"Execution for {instruction.OpCode} not implented yet!"); } DynValue result = m_ValueStack.Pop().ToScalar(); if (m_CanYield) { return result; } if (State == CoroutineState.Main) { throw ScriptRuntimeException.CannotYieldMain(); } throw ScriptRuntimeException.CannotYield(); continue; end_IL_0023: break; } } catch (InterpreterException ex) { FillDebugData(ex, instructionPtr); if (!(ex is ScriptRuntimeException)) { ex.Rethrow(); throw; } if (m_Debug.DebuggerAttached != null && m_Debug.DebuggerAttached.SignalRuntimeException((ScriptRuntimeException)ex) && instructionPtr >= 0 && instructionPtr < m_RootChunk.Code.Count) { ListenDebugger(m_RootChunk.Code[instructionPtr], instructionPtr); } for (int i = 0; i < m_ExecutionStack.Count; i++) { CallStackItem callStackItem = m_ExecutionStack.Peek(i); if (callStackItem.ErrorHandlerBeforeUnwind != null) { ex.DecoratedMessage = PerformMessageDecorationBeforeUnwind(callStackItem.ErrorHandlerBeforeUnwind, ex.DecoratedMessage, GetCurrentSourceRef(instructionPtr)); } } CallStackItem callStackItem2; while (true) { if (m_ExecutionStack.Count > 0) { callStackItem2 = PopToBasePointer(); if (callStackItem2.ErrorHandler != null) { break; } if ((callStackItem2.Flags & CallStackItemFlags.EntryPoint) != 0) { ex.Rethrow(); throw; } continue; } ex.Rethrow(); throw; } instructionPtr = callStackItem2.ReturnAddress; if (callStackItem2.ClrFunction == null) { int num2 = (int)m_ValueStack.Pop().Number; m_ValueStack.RemoveLast(num2 + 1); } DynValue[] args = new DynValue[1] { DynValue.NewString(ex.DecoratedMessage) }; DynValue item = callStackItem2.ErrorHandler.Invoke(new ScriptExecutionContext(this, callStackItem2.ErrorHandler, GetCurrentSourceRef(instructionPtr)), args); m_ValueStack.Push(item); continue; } break; } return m_ValueStack.Pop(); } public string PerformMessageDecorationBeforeUnwind(DynValue messageHandler, string decoratedMessage, SourceRef sourceRef) { try { DynValue[] args = new DynValue[1] { DynValue.NewString(decoratedMessage) }; DynValue nil = DynValue.Nil; if (messageHandler.Type == DataType.Function) { nil = Call(messageHandler, args); } else { if (messageHandler.Type != DataType.ClrFunction) { throw new ScriptRuntimeException("error handler not set to a function"); } ScriptExecutionContext executionContext = new ScriptExecutionContext(this, messageHandler.Callback, sourceRef); nil = messageHandler.Callback.Invoke(executionContext, args); } string text = nil.ToPrintString(); if (text != null) { return text; } return decoratedMessage; } catch (ScriptRuntimeException ex) { return ex.Message + "\n" + decoratedMessage; } } public void AssignLocal(SymbolRef symref, DynValue value) { CallStackItem callStackItem = m_ExecutionStack.Peek(); DynValue dynValue = callStackItem.LocalScope[symref.i_Index]; if (dynValue == null) { dynValue = (callStackItem.LocalScope[symref.i_Index] = DynValue.NewNil()); } dynValue.Assign(value); } public void ExecStoreLcl(Instruction i) { DynValue storeValue = GetStoreValue(i); SymbolRef symbol = i.Symbol; AssignLocal(symbol, storeValue); } public void ExecStoreUpv(Instruction i) { DynValue storeValue = GetStoreValue(i); SymbolRef symbol = i.Symbol; CallStackItem callStackItem = m_ExecutionStack.Peek(); DynValue dynValue = callStackItem.ClosureScope[symbol.i_Index]; if (dynValue == null) { dynValue = (callStackItem.ClosureScope[symbol.i_Index] = DynValue.NewNil()); } dynValue.Assign(storeValue); } public void ExecSwap(Instruction i) { DynValue item = m_ValueStack.Peek(i.NumVal); DynValue item2 = m_ValueStack.Peek(i.NumVal2); m_ValueStack.Set(i.NumVal, item2); m_ValueStack.Set(i.NumVal2, item); } public DynValue GetStoreValue(Instruction i) { int numVal = i.NumVal; int numVal2 = i.NumVal2; DynValue dynValue = m_ValueStack.Peek(numVal); if (dynValue.Type == DataType.Tuple) { if (numVal2 >= dynValue.Tuple.Length) { return DynValue.NewNil(); } return dynValue.Tuple[numVal2]; } if (numVal2 != 0) { return DynValue.NewNil(); } return dynValue; } public void ExecClosure(Instruction i) { Closure function = new Closure(m_Script, i.NumVal, i.SymbolList, i.SymbolList.Select((SymbolRef s) => GetUpvalueSymbol(s)).ToList()); m_ValueStack.Push(DynValue.NewClosure(function)); } public DynValue GetUpvalueSymbol(SymbolRef s) { if (s.Type == SymbolRefType.Local) { return m_ExecutionStack.Peek().LocalScope[s.i_Index]; } if (s.Type == SymbolRefType.Upvalue) { return m_ExecutionStack.Peek().ClosureScope[s.i_Index]; } throw new Exception("unsupported symbol type"); } public void ExecMkTuple(Instruction i) { Slice values = new Slice(m_ValueStack, m_ValueStack.Count - i.NumVal, i.NumVal, reversed: false); DynValue[] values2 = Internal_AdjustTuple(values); m_ValueStack.RemoveLast(i.NumVal); m_ValueStack.Push(DynValue.NewTuple(values2)); } public void ExecToNum(Instruction i) { double? num = m_ValueStack.Pop().ToScalar().CastToNumber(); if (num.HasValue) { m_ValueStack.Push(DynValue.NewNumber(num.Value)); return; } throw ScriptRuntimeException.ConvertToNumberFailed(i.NumVal); } public void ExecIterUpd(Instruction i) { DynValue dynValue = m_ValueStack.Peek(); m_ValueStack.Peek(1).Tuple[2] = dynValue; } public void ExecExpTuple(Instruction i) { DynValue dynValue = m_ValueStack.Peek(i.NumVal); if (dynValue.Type == DataType.Tuple) { for (int j = 0; j < dynValue.Tuple.Length; j++) { m_ValueStack.Push(dynValue.Tuple[j]); } } else { m_ValueStack.Push(dynValue); } } public void ExecIterPrep(Instruction i) { DynValue dynValue = m_ValueStack.Pop(); if (dynValue.Type != DataType.Tuple) { dynValue = DynValue.NewTuple(dynValue, DynValue.Nil, DynValue.Nil); } DynValue dynValue2 = ((dynValue.Tuple.Length >= 1) ? dynValue.Tuple[0] : DynValue.Nil); DynValue dynValue3 = ((dynValue.Tuple.Length >= 2) ? dynValue.Tuple[1] : DynValue.Nil); DynValue dynValue4 = ((dynValue.Tuple.Length >= 3) ? dynValue.Tuple[2] : DynValue.Nil); if (dynValue2.Type != DataType.Function && dynValue2.Type != DataType.ClrFunction) { DynValue metamethod = GetMetamethod(dynValue2, "__iterator"); if (metamethod != null && !metamethod.IsNil()) { dynValue = ((metamethod.Type == DataType.Tuple) ? metamethod : GetScript().Call(metamethod, dynValue2, dynValue3, dynValue4)); dynValue2 = ((dynValue.Tuple.Length >= 1) ? dynValue.Tuple[0] : DynValue.Nil); dynValue3 = ((dynValue.Tuple.Length >= 2) ? dynValue.Tuple[1] : DynValue.Nil); dynValue4 = ((dynValue.Tuple.Length >= 3) ? dynValue.Tuple[2] : DynValue.Nil); m_ValueStack.Push(DynValue.NewTuple(dynValue2, dynValue3, dynValue4)); } else if (dynValue2.Type == DataType.Table) { DynValue metamethod2 = GetMetamethod(dynValue2, "__call"); if (metamethod2 == null || metamethod2.IsNil()) { m_ValueStack.Push(EnumerableWrapper.ConvertTable(dynValue2.Table)); } } } m_ValueStack.Push(DynValue.NewTuple(dynValue2, dynValue3, dynValue4)); } public int ExecJFor(Instruction i, int instructionPtr) { double number = m_ValueStack.Peek().Number; double number2 = m_ValueStack.Peek(1).Number; double number3 = m_ValueStack.Peek(2).Number; if (!((number2 > 0.0) ? (number <= number3) : (number >= number3))) { return i.NumVal; } return instructionPtr; } public void ExecIncr(Instruction i) { DynValue dynValue = m_ValueStack.Peek(); DynValue dynValue2 = m_ValueStack.Peek(i.NumVal); if (dynValue.ReadOnly) { m_ValueStack.Pop(); if (dynValue.ReadOnly) { dynValue = dynValue.CloneAsWritable(); } m_ValueStack.Push(dynValue); } dynValue.AssignNumber(dynValue.Number + dynValue2.Number); } public void ExecCNot(Instruction i) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); if (dynValue2.Type != DataType.Boolean) { throw new InternalErrorException("CNOT had non-bool arg"); } if (dynValue2.CastToBool()) { m_ValueStack.Push(DynValue.NewBoolean(!dynValue.CastToBool())); } else { m_ValueStack.Push(DynValue.NewBoolean(dynValue.CastToBool())); } } public void ExecNot(Instruction i) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); m_ValueStack.Push(DynValue.NewBoolean(!dynValue.CastToBool())); } public void ExecBeginFn(Instruction i) { CallStackItem callStackItem = m_ExecutionStack.Peek(); callStackItem.Debug_Symbols = i.SymbolList; callStackItem.LocalScope = new DynValue[i.NumVal]; ClearBlockData(i); } public CallStackItem PopToBasePointer() { CallStackItem callStackItem = m_ExecutionStack.Pop(); if (callStackItem.BasePointer >= 0) { m_ValueStack.CropAtCount(callStackItem.BasePointer); } return callStackItem; } public int PopExecStackAndCheckVStack(int vstackguard) { CallStackItem callStackItem = m_ExecutionStack.Pop(); if (vstackguard != callStackItem.BasePointer) { throw new InternalErrorException("StackGuard violation"); } return callStackItem.ReturnAddress; } public IList CreateArgsListForFunctionCall(int numargs, int offsFromTop) { if (numargs == 0) { return new DynValue[0]; } DynValue dynValue = m_ValueStack.Peek(offsFromTop); if (dynValue.Type == DataType.Tuple && dynValue.Tuple.Length > 1) { List list = new List(); for (int i = 0; i < numargs - 1; i++) { list.Add(m_ValueStack.Peek(numargs - i - 1 + offsFromTop)); } for (int j = 0; j < dynValue.Tuple.Length; j++) { list.Add(dynValue.Tuple[j]); } return list; } return new Slice(m_ValueStack, m_ValueStack.Count - numargs - offsFromTop, numargs, reversed: false); } public void ExecArgs(Instruction I) { int numargs = (int)m_ValueStack.Peek().Number; IList list = CreateArgsListForFunctionCall(numargs, 1); for (int i = 0; i < I.SymbolList.Length; i++) { if (i >= list.Count) { AssignLocal(I.SymbolList[i], DynValue.NewNil()); } else if (i == I.SymbolList.Length - 1 && I.SymbolList[i].i_Name == "...") { int num = list.Count - i; DynValue[] array = new DynValue[num]; int num2 = 0; while (num2 < num) { array[num2] = list[i].ToScalar().CloneAsWritable(); num2++; i++; } AssignLocal(I.SymbolList[I.SymbolList.Length - 1], DynValue.NewTuple(Internal_AdjustTuple(array))); } else { AssignLocal(I.SymbolList[i], list[i].ToScalar().CloneAsWritable()); } } } public int Internal_ExecCall(int argsCount, int instructionPtr, CallbackFunction handler = null, CallbackFunction continuation = null, bool thisCall = false, string debugText = null, DynValue unwindHandler = null) { DynValue dynValue = m_ValueStack.Peek(argsCount); CallStackItemFlags callStackItemFlags = (thisCall ? CallStackItemFlags.MethodCall : CallStackItemFlags.None); if (((m_ExecutionStack.Count > m_Script.Options.TailCallOptimizationThreshold && m_ExecutionStack.Count > 1) || (m_ValueStack.Count > m_Script.Options.TailCallOptimizationThreshold && m_ValueStack.Count > 1)) && instructionPtr >= 0 && instructionPtr < m_RootChunk.Code.Count) { Instruction instruction = m_RootChunk.Code[instructionPtr]; if (instruction.OpCode == OpCode.Ret && instruction.NumVal == 1) { CallStackItem callStackItem = m_ExecutionStack.Peek(); if (callStackItem.ClrFunction == null && callStackItem.Continuation == null && callStackItem.ErrorHandler == null && callStackItem.ErrorHandlerBeforeUnwind == null && continuation == null && unwindHandler == null && handler == null) { instructionPtr = PerformTCO(instructionPtr, argsCount); callStackItemFlags |= CallStackItemFlags.TailCall; } } } if (dynValue.Type == DataType.ClrFunction) { IList args = CreateArgsListForFunctionCall(argsCount, 0); SourceRef currentSourceRef = GetCurrentSourceRef(instructionPtr); m_ExecutionStack.Push(new CallStackItem { ClrFunction = dynValue.Callback, ReturnAddress = instructionPtr, CallingSourceRef = currentSourceRef, BasePointer = -1, ErrorHandler = handler, Continuation = continuation, ErrorHandlerBeforeUnwind = unwindHandler, Flags = callStackItemFlags }); DynValue item = dynValue.Callback.Invoke(new ScriptExecutionContext(this, dynValue.Callback, currentSourceRef), args, thisCall); m_ValueStack.RemoveLast(argsCount + 1); m_ValueStack.Push(item); m_ExecutionStack.Pop(); return Internal_CheckForTailRequests(null, instructionPtr); } if (dynValue.Type == DataType.Function) { m_ValueStack.Push(DynValue.NewNumber(argsCount)); m_ExecutionStack.Push(new CallStackItem { BasePointer = m_ValueStack.Count, ReturnAddress = instructionPtr, Debug_EntryPoint = dynValue.Function.EntryPointByteCodeLocation, CallingSourceRef = GetCurrentSourceRef(instructionPtr), ClosureScope = dynValue.Function.ClosureContext, ErrorHandler = handler, Continuation = continuation, ErrorHandlerBeforeUnwind = unwindHandler, Flags = callStackItemFlags }); return dynValue.Function.EntryPointByteCodeLocation; } DynValue metamethod = GetMetamethod(dynValue, "__call"); if (metamethod != null && metamethod.IsNotNil()) { DynValue[] array = new DynValue[argsCount + 1]; for (int i = 0; i < argsCount + 1; i++) { array[i] = m_ValueStack.Pop(); } m_ValueStack.Push(metamethod); for (int num = argsCount; num >= 0; num--) { m_ValueStack.Push(array[num]); } return Internal_ExecCall(argsCount + 1, instructionPtr, handler, continuation); } throw ScriptRuntimeException.AttemptToCallNonFunc(dynValue.Type, debugText); } public int PerformTCO(int instructionPtr, int argsCount) { DynValue[] array = new DynValue[argsCount + 1]; for (int i = 0; i <= argsCount; i++) { array[i] = m_ValueStack.Pop(); } int returnAddress = PopToBasePointer().ReturnAddress; int num = (int)m_ValueStack.Pop().Number; m_ValueStack.RemoveLast(num + 1); for (int num2 = argsCount; num2 >= 0; num2--) { m_ValueStack.Push(array[num2]); } return returnAddress; } public int ExecRet(Instruction i) { int num = 0; CallStackItem callStackItem; if (i.NumVal == 0) { callStackItem = PopToBasePointer(); num = callStackItem.ReturnAddress; int num2 = (int)m_ValueStack.Pop().Number; m_ValueStack.RemoveLast(num2 + 1); m_ValueStack.Push(DynValue.Void); } else { if (i.NumVal != 1) { throw new InternalErrorException("RET supports only 0 and 1 ret val scenarios"); } DynValue item = m_ValueStack.Pop(); callStackItem = PopToBasePointer(); num = callStackItem.ReturnAddress; int num3 = (int)m_ValueStack.Pop().Number; m_ValueStack.RemoveLast(num3 + 1); m_ValueStack.Push(item); num = Internal_CheckForTailRequests(i, num); } if (callStackItem.Continuation != null) { m_ValueStack.Push(callStackItem.Continuation.Invoke(new ScriptExecutionContext(this, callStackItem.Continuation, i.SourceCodeRef), new DynValue[1] { m_ValueStack.Pop() })); } return num; } public int Internal_CheckForTailRequests(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Peek(); if (dynValue.Type == DataType.TailCallRequest) { m_ValueStack.Pop(); TailCallData tailCallData = dynValue.TailCallData; m_ValueStack.Push(tailCallData.Function); for (int j = 0; j < tailCallData.Args.Length; j++) { m_ValueStack.Push(tailCallData.Args[j]); } return Internal_ExecCall(tailCallData.Args.Length, instructionPtr, tailCallData.ErrorHandler, tailCallData.Continuation, thisCall: false, null, tailCallData.ErrorHandlerBeforeUnwind); } if (dynValue.Type == DataType.YieldRequest) { m_SavedInstructionPtr = instructionPtr; return -99; } return instructionPtr; } public int JumpBool(Instruction i, bool expectedValueForJump, int instructionPtr) { if (m_ValueStack.Pop().ToScalar().CastToBool() == expectedValueForJump) { return i.NumVal; } return instructionPtr; } public int ExecShortCircuitingOperator(Instruction i, int instructionPtr) { bool flag = i.OpCode == OpCode.JtOrPop; if (m_ValueStack.Peek().ToScalar().CastToBool() == flag) { return i.NumVal; } m_ValueStack.Pop(); return instructionPtr; } public int ExecAdd(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); double? num = dynValue.CastToNumber(); double? num2 = dynValue2.CastToNumber(); if (num2.HasValue && num.HasValue) { m_ValueStack.Push(DynValue.NewNumber(num2.Value + num.Value)); return instructionPtr; } int num3 = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__add", instructionPtr); if (num3 >= 0) { return num3; } throw ScriptRuntimeException.ArithmeticOnNonNumber(dynValue2, dynValue); } public int ExecSub(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); double? num = dynValue.CastToNumber(); double? num2 = dynValue2.CastToNumber(); if (num2.HasValue && num.HasValue) { m_ValueStack.Push(DynValue.NewNumber(num2.Value - num.Value)); return instructionPtr; } int num3 = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__sub", instructionPtr); if (num3 >= 0) { return num3; } throw ScriptRuntimeException.ArithmeticOnNonNumber(dynValue2, dynValue); } public int ExecMul(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); double? num = dynValue.CastToNumber(); double? num2 = dynValue2.CastToNumber(); if (num2.HasValue && num.HasValue) { m_ValueStack.Push(DynValue.NewNumber(num2.Value * num.Value)); return instructionPtr; } int num3 = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__mul", instructionPtr); if (num3 >= 0) { return num3; } throw ScriptRuntimeException.ArithmeticOnNonNumber(dynValue2, dynValue); } public int ExecMod(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); double? num = dynValue.CastToNumber(); double? num2 = dynValue2.CastToNumber(); if (num2.HasValue && num.HasValue) { double num3 = Math.IEEERemainder(num2.Value, num.Value); if (num3 < 0.0) { num3 += num.Value; } m_ValueStack.Push(DynValue.NewNumber(num3)); return instructionPtr; } int num4 = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__mod", instructionPtr); if (num4 >= 0) { return num4; } throw ScriptRuntimeException.ArithmeticOnNonNumber(dynValue2, dynValue); } public int ExecDiv(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); double? num = dynValue.CastToNumber(); double? num2 = dynValue2.CastToNumber(); if (num2.HasValue && num.HasValue) { m_ValueStack.Push(DynValue.NewNumber(num2.Value / num.Value)); return instructionPtr; } int num3 = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__div", instructionPtr); if (num3 >= 0) { return num3; } throw ScriptRuntimeException.ArithmeticOnNonNumber(dynValue2, dynValue); } public int ExecPower(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); double? num = dynValue.CastToNumber(); double? num2 = dynValue2.CastToNumber(); if (num2.HasValue && num.HasValue) { m_ValueStack.Push(DynValue.NewNumber(Math.Pow(num2.Value, num.Value))); return instructionPtr; } int num3 = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__pow", instructionPtr); if (num3 >= 0) { return num3; } throw ScriptRuntimeException.ArithmeticOnNonNumber(dynValue2, dynValue); } public int ExecNeg(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); double? num = dynValue.CastToNumber(); if (num.HasValue) { m_ValueStack.Push(DynValue.NewNumber(0.0 - num.Value)); return instructionPtr; } int num2 = Internal_InvokeUnaryMetaMethod(dynValue, "__unm", instructionPtr); if (num2 >= 0) { return num2; } throw ScriptRuntimeException.ArithmeticOnNonNumber(dynValue); } public int ExecEq(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); if (dynValue == dynValue2) { m_ValueStack.Push(DynValue.True); return instructionPtr; } if (dynValue2.Type == DataType.UserData || dynValue.Type == DataType.UserData) { int num = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__eq", instructionPtr); if (num >= 0) { return num; } } if (dynValue.Type != dynValue2.Type) { if ((dynValue2.Type == DataType.Nil && dynValue.Type == DataType.Void) || (dynValue2.Type == DataType.Void && dynValue.Type == DataType.Nil)) { m_ValueStack.Push(DynValue.True); } else { m_ValueStack.Push(DynValue.False); } return instructionPtr; } if (dynValue2.Type == DataType.Table && GetMetatable(dynValue2) != null && GetMetatable(dynValue2) == GetMetatable(dynValue)) { int num2 = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__eq", instructionPtr); if (num2 >= 0) { return num2; } } m_ValueStack.Push(DynValue.NewBoolean(dynValue.Equals(dynValue2))); return instructionPtr; } public int ExecLess(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); if (dynValue2.Type == DataType.Number && dynValue.Type == DataType.Number) { m_ValueStack.Push(DynValue.NewBoolean(dynValue2.Number < dynValue.Number)); } else { if (dynValue2.Type != DataType.String || dynValue.Type != DataType.String) { int num = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__lt", instructionPtr); if (num < 0) { throw ScriptRuntimeException.CompareInvalidType(dynValue2, dynValue); } return num; } m_ValueStack.Push(DynValue.NewBoolean(dynValue2.String.CompareTo(dynValue.String) < 0)); } return instructionPtr; } public int ExecLessEq(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); if (dynValue2.Type == DataType.Number && dynValue.Type == DataType.Number) { m_ValueStack.Push(DynValue.False); m_ValueStack.Push(DynValue.NewBoolean(dynValue2.Number <= dynValue.Number)); } else { if (dynValue2.Type != DataType.String || dynValue.Type != DataType.String) { int num = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__le", instructionPtr, DynValue.False); if (num < 0) { num = Internal_InvokeBinaryMetaMethod(dynValue, dynValue2, "__lt", instructionPtr, DynValue.True); if (num < 0) { throw ScriptRuntimeException.CompareInvalidType(dynValue2, dynValue); } return num; } return num; } m_ValueStack.Push(DynValue.False); m_ValueStack.Push(DynValue.NewBoolean(dynValue2.String.CompareTo(dynValue.String) <= 0)); } return instructionPtr; } public int ExecLen(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); if (dynValue.Type == DataType.String) { m_ValueStack.Push(DynValue.NewNumber(dynValue.String.Length)); } else { int num = Internal_InvokeUnaryMetaMethod(dynValue, "__len", instructionPtr); if (num >= 0) { return num; } if (dynValue.Type != DataType.Table) { throw ScriptRuntimeException.LenOnInvalidType(dynValue); } m_ValueStack.Push(DynValue.NewNumber(dynValue.Table.Length)); } return instructionPtr; } public int ExecConcat(Instruction i, int instructionPtr) { DynValue dynValue = m_ValueStack.Pop().ToScalar(); DynValue dynValue2 = m_ValueStack.Pop().ToScalar(); string text = dynValue.CastToString(); string text2 = dynValue2.CastToString(); if (text != null && text2 != null) { m_ValueStack.Push(DynValue.NewString(text2 + text)); return instructionPtr; } int num = Internal_InvokeBinaryMetaMethod(dynValue2, dynValue, "__concat", instructionPtr); if (num >= 0) { return num; } throw ScriptRuntimeException.ConcatOnNonString(dynValue2, dynValue); } public void ExecTblInitI(Instruction i) { DynValue val = m_ValueStack.Pop(); DynValue dynValue = m_ValueStack.Peek(); if (dynValue.Type != DataType.Table) { throw new InternalErrorException("Unexpected type in table ctor : {0}", dynValue); } dynValue.Table.InitNextArrayKeys(val, i.NumVal != 0); } public void ExecTblInitN(Instruction i) { DynValue dynValue = m_ValueStack.Pop(); DynValue key = m_ValueStack.Pop(); DynValue dynValue2 = m_ValueStack.Peek(); if (dynValue2.Type != DataType.Table) { throw new InternalErrorException("Unexpected type in table ctor : {0}", dynValue2); } dynValue2.Table.Set(key, dynValue.ToScalar()); } public int ExecIndexSet(Instruction i, int instructionPtr) { int num = 100; bool isDirectIndexing = i.OpCode == OpCode.IndexSetN; bool flag = i.OpCode == OpCode.IndexSetL; DynValue dynValue = i.Value ?? m_ValueStack.Pop(); DynValue dynValue2 = dynValue.ToScalar(); DynValue dynValue3 = m_ValueStack.Pop().ToScalar(); DynValue storeValue = GetStoreValue(i); DynValue dynValue4 = null; while (num > 0) { num--; if (dynValue3.Type == DataType.Table) { if (!flag && !dynValue3.Table.Get(dynValue2).IsNil()) { dynValue3.Table.Set(dynValue2, storeValue); return instructionPtr; } dynValue4 = GetMetamethodRaw(dynValue3, "__newindex"); if (dynValue4 == null || dynValue4.IsNil()) { if (flag) { throw new ScriptRuntimeException("cannot multi-index a table. userdata expected"); } dynValue3.Table.Set(dynValue2, storeValue); return instructionPtr; } } else { if (dynValue3.Type == DataType.UserData) { UserData userData = dynValue3.UserData; if (!userData.Descriptor.SetIndex(GetScript(), userData.Object, dynValue, storeValue, isDirectIndexing)) { throw ScriptRuntimeException.UserDataMissingField(userData.Descriptor.Name, dynValue2.String); } return instructionPtr; } dynValue4 = GetMetamethodRaw(dynValue3, "__newindex"); if (dynValue4 == null || dynValue4.IsNil()) { throw ScriptRuntimeException.IndexType(dynValue3); } } if (dynValue4.Type == DataType.Function || dynValue4.Type == DataType.ClrFunction) { if (flag) { throw new ScriptRuntimeException("cannot multi-index through metamethods. userdata expected"); } m_ValueStack.Pop(); m_ValueStack.Push(dynValue4); m_ValueStack.Push(dynValue3); m_ValueStack.Push(dynValue2); m_ValueStack.Push(storeValue); return Internal_ExecCall(3, instructionPtr); } dynValue3 = dynValue4; dynValue4 = null; } throw ScriptRuntimeException.LoopInNewIndex(); } public int ExecIndex(Instruction i, int instructionPtr) { int num = 100; bool isDirectIndexing = i.OpCode == OpCode.IndexN; bool flag = i.OpCode == OpCode.IndexL; DynValue dynValue = i.Value ?? m_ValueStack.Pop(); DynValue dynValue2 = dynValue.ToScalar(); DynValue dynValue3 = m_ValueStack.Pop().ToScalar(); DynValue dynValue4 = null; while (num > 0) { num--; if (dynValue3.Type == DataType.Table) { if (!flag) { DynValue dynValue5 = dynValue3.Table.Get(dynValue2); if (!dynValue5.IsNil()) { m_ValueStack.Push(dynValue5.AsReadOnly()); return instructionPtr; } } dynValue4 = GetMetamethodRaw(dynValue3, "__index"); if (dynValue4 == null || dynValue4.IsNil()) { if (flag) { throw new ScriptRuntimeException("cannot multi-index a table. userdata expected"); } m_ValueStack.Push(DynValue.Nil); return instructionPtr; } } else { if (dynValue3.Type == DataType.UserData) { UserData userData = dynValue3.UserData; DynValue dynValue6 = userData.Descriptor.Index(GetScript(), userData.Object, dynValue, isDirectIndexing); if (dynValue6 == null) { throw ScriptRuntimeException.UserDataMissingField(userData.Descriptor.Name, dynValue2.String); } m_ValueStack.Push(dynValue6.AsReadOnly()); return instructionPtr; } dynValue4 = GetMetamethodRaw(dynValue3, "__index"); if (dynValue4 == null || dynValue4.IsNil()) { throw ScriptRuntimeException.IndexType(dynValue3); } } if (dynValue4.Type == DataType.Function || dynValue4.Type == DataType.ClrFunction) { if (flag) { throw new ScriptRuntimeException("cannot multi-index through metamethods. userdata expected"); } m_ValueStack.Push(dynValue4); m_ValueStack.Push(dynValue3); m_ValueStack.Push(dynValue2); return Internal_ExecCall(2, instructionPtr); } dynValue3 = dynValue4; dynValue4 = null; } throw ScriptRuntimeException.LoopInIndex(); } public void ClearBlockData(Instruction I) { int numVal = I.NumVal; int numVal2 = I.NumVal2; DynValue[] localScope = m_ExecutionStack.Peek().LocalScope; if (numVal2 >= 0 && numVal >= 0 && numVal2 >= numVal) { Array.Clear(localScope, numVal, numVal2 - numVal + 1); } } public DynValue GetGenericSymbol(SymbolRef symref) { return symref.i_Type switch { SymbolRefType.DefaultEnv => DynValue.NewTable(GetScript().Globals), SymbolRefType.Global => GetGlobalSymbol(GetGenericSymbol(symref.i_Env), symref.i_Name), SymbolRefType.Local => GetTopNonClrFunction().LocalScope[symref.i_Index], SymbolRefType.Upvalue => GetTopNonClrFunction().ClosureScope[symref.i_Index], _ => throw new InternalErrorException("Unexpected {0} LRef at resolution: {1}", symref.i_Type, symref.i_Name), }; } public DynValue GetGlobalSymbol(DynValue dynValue, string name) { if (dynValue.Type != DataType.Table) { throw new InvalidOperationException($"_ENV is not a table but a {dynValue.Type}"); } return dynValue.Table.Get(name); } public void SetGlobalSymbol(DynValue dynValue, string name, DynValue value) { if (dynValue.Type != DataType.Table) { throw new InvalidOperationException($"_ENV is not a table but a {dynValue.Type}"); } dynValue.Table.Set(name, value ?? DynValue.Nil); } public void AssignGenericSymbol(SymbolRef symref, DynValue value) { switch (symref.i_Type) { case SymbolRefType.Global: SetGlobalSymbol(GetGenericSymbol(symref.i_Env), symref.i_Name, value); break; case SymbolRefType.Local: { CallStackItem topNonClrFunction2 = GetTopNonClrFunction(); DynValue dynValue3 = topNonClrFunction2.LocalScope[symref.i_Index]; if (dynValue3 == null) { dynValue3 = (topNonClrFunction2.LocalScope[symref.i_Index] = DynValue.NewNil()); } dynValue3.Assign(value); break; } case SymbolRefType.Upvalue: { CallStackItem topNonClrFunction = GetTopNonClrFunction(); DynValue dynValue = topNonClrFunction.ClosureScope[symref.i_Index]; if (dynValue == null) { dynValue = (topNonClrFunction.ClosureScope[symref.i_Index] = DynValue.NewNil()); } dynValue.Assign(value); break; } case SymbolRefType.DefaultEnv: throw new ArgumentException("Can't AssignGenericSymbol on a DefaultEnv symbol"); default: throw new InternalErrorException("Unexpected {0} LRef at resolution: {1}", symref.i_Type, symref.i_Name); } } public CallStackItem GetTopNonClrFunction() { CallStackItem callStackItem = null; for (int i = 0; i < m_ExecutionStack.Count; i++) { callStackItem = m_ExecutionStack.Peek(i); if (callStackItem.ClrFunction == null) { break; } } return callStackItem; } public SymbolRef FindSymbolByName(string name) { if (m_ExecutionStack.Count > 0) { CallStackItem topNonClrFunction = GetTopNonClrFunction(); if (topNonClrFunction != null) { if (topNonClrFunction.Debug_Symbols != null) { for (int num = topNonClrFunction.Debug_Symbols.Length - 1; num >= 0; num--) { SymbolRef symbolRef = topNonClrFunction.Debug_Symbols[num]; if (symbolRef.i_Name == name && topNonClrFunction.LocalScope[num] != null) { return symbolRef; } } } ClosureContext closureScope = topNonClrFunction.ClosureScope; if (closureScope != null) { for (int i = 0; i < closureScope.Symbols.Length; i++) { if (closureScope.Symbols[i] == name) { return SymbolRef.Upvalue(name, i); } } } } } if (name != "_ENV") { SymbolRef envSymbol = FindSymbolByName("_ENV"); return SymbolRef.Global(name, envSymbol); } return SymbolRef.DefaultEnv; } public DynValue[] Internal_AdjustTuple(IList values) { if (values == null || values.Count == 0) { return new DynValue[0]; } if (values[values.Count - 1].Type == DataType.Tuple) { DynValue[] array = new DynValue[values.Count - 1 + values[values.Count - 1].Tuple.Length]; for (int i = 0; i < values.Count - 1; i++) { array[i] = values[i].ToScalar(); } for (int j = 0; j < values[values.Count - 1].Tuple.Length; j++) { array[values.Count + j - 1] = values[values.Count - 1].Tuple[j]; } if (array[^1].Type == DataType.Tuple) { return Internal_AdjustTuple(array); } return array; } DynValue[] array2 = new DynValue[values.Count]; for (int k = 0; k < values.Count; k++) { array2[k] = values[k].ToScalar(); } return array2; } public int Internal_InvokeUnaryMetaMethod(DynValue op1, string eventName, int instructionPtr) { DynValue dynValue = null; if (op1.Type == DataType.UserData) { dynValue = op1.UserData.Descriptor.MetaIndex(m_Script, op1.UserData.Object, eventName); } if (dynValue == null) { Table metatable = GetMetatable(op1); if (metatable != null) { DynValue dynValue2 = metatable.RawGet(eventName); if (dynValue2 != null && dynValue2.IsNotNil()) { dynValue = dynValue2; } } } if (dynValue != null) { m_ValueStack.Push(dynValue); m_ValueStack.Push(op1); return Internal_ExecCall(1, instructionPtr); } return -1; } public int Internal_InvokeBinaryMetaMethod(DynValue l, DynValue r, string eventName, int instructionPtr, DynValue extraPush = null) { DynValue binaryMetamethod = GetBinaryMetamethod(l, r, eventName); if (binaryMetamethod != null) { if (extraPush != null) { m_ValueStack.Push(extraPush); } m_ValueStack.Push(binaryMetamethod); m_ValueStack.Push(l); m_ValueStack.Push(r); return Internal_ExecCall(2, instructionPtr); } return -1; } public DynValue[] StackTopToArray(int items, bool pop) { DynValue[] array = new DynValue[items]; if (pop) { for (int i = 0; i < items; i++) { array[i] = m_ValueStack.Pop(); } } else { for (int j = 0; j < items; j++) { array[j] = m_ValueStack[m_ValueStack.Count - 1 - j]; } } return array; } public DynValue[] StackTopToArrayReverse(int items, bool pop) { DynValue[] array = new DynValue[items]; if (pop) { for (int i = 0; i < items; i++) { array[items - 1 - i] = m_ValueStack.Pop(); } } else { for (int j = 0; j < items; j++) { array[items - 1 - j] = m_ValueStack[m_ValueStack.Count - 1 - j]; } } return array; } } [Flags] public enum CallStackItemFlags { None = 0, EntryPoint = 1, ResumeEntryPoint = 3, CallEntryPoint = 5, TailCall = 0x10, MethodCall = 0x20 } public sealed class ExecutionState { public FastStack ValueStack = new FastStack(131072); public FastStack ExecutionStack = new FastStack(131072); public int InstructionPtr; public CoroutineState State = CoroutineState.NotStarted; } public class ByteCode : RefIdObject { public class SourceCodeStackGuard : IDisposable { public ByteCode m_Bc; public SourceCodeStackGuard(SourceRef sref, ByteCode bc) { m_Bc = bc; m_Bc.PushSourceRef(sref); } public void Dispose() { m_Bc.PopSourceRef(); } } public List Code = new List(); public List m_SourceRefStack = new List(); public SourceRef m_CurrentSourceRef; public LoopTracker LoopTracker = new LoopTracker(); public Script Script { get; set; } public ByteCode(Script script) { Script = script; } public IDisposable EnterSource(SourceRef sref) { return new SourceCodeStackGuard(sref, this); } public void PushSourceRef(SourceRef sref) { m_SourceRefStack.Add(sref); m_CurrentSourceRef = sref; } public void PopSourceRef() { m_SourceRefStack.RemoveAt(m_SourceRefStack.Count - 1); m_CurrentSourceRef = ((m_SourceRefStack.Count > 0) ? m_SourceRefStack[m_SourceRefStack.Count - 1] : null); } public void Dump(string file) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < Code.Count; i++) { if (Code[i].OpCode == OpCode.Debug) { stringBuilder.AppendFormat(" {0}\n", Code[i]); } else { stringBuilder.AppendFormat("{0:X8} {1}\n", i, Code[i]); } } File.WriteAllText(file, stringBuilder.ToString()); } public int GetJumpPointForNextInstruction() { return Code.Count; } public int GetJumpPointForLastInstruction() { return Code.Count - 1; } public Instruction GetLastInstruction() { return Code[Code.Count - 1]; } public Instruction AppendInstruction(Instruction c) { Code.Add(c); return c; } public Instruction Emit_Nop(string comment) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Nop, Name = comment }); } public Instruction Emit_Invalid(string type) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Invalid, Name = type }); } public Instruction Emit_Pop(int num = 1) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Pop, NumVal = num }); } public void Emit_Call(int argCount, string debugName) { AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Call, NumVal = argCount, Name = debugName }); } public void Emit_ThisCall(int argCount, string debugName) { AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.ThisCall, NumVal = argCount, Name = debugName }); } public Instruction Emit_Literal(DynValue value) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Literal, Value = value }); } public Instruction Emit_Jump(OpCode jumpOpCode, int idx, int optPar = 0) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = jumpOpCode, NumVal = idx, NumVal2 = optPar }); } public Instruction Emit_MkTuple(int cnt) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.MkTuple, NumVal = cnt }); } public Instruction Emit_Operator(OpCode opcode) { Instruction result = AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = opcode }); if (opcode == OpCode.LessEq) { AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.CNot }); } if (opcode == OpCode.Eq || opcode == OpCode.Less) { AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.ToBool }); } return result; } [Conditional("EMIT_DEBUG_OPS")] public void Emit_Debug(string str) { AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Debug, Name = str.Substring(0, Math.Min(32, str.Length)) }); } public Instruction Emit_Enter(RuntimeScopeBlock runtimeScopeBlock) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Clean, NumVal = runtimeScopeBlock.From, NumVal2 = runtimeScopeBlock.ToInclusive }); } public Instruction Emit_Leave(RuntimeScopeBlock runtimeScopeBlock) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Clean, NumVal = runtimeScopeBlock.From, NumVal2 = runtimeScopeBlock.To }); } public Instruction Emit_Exit(RuntimeScopeBlock runtimeScopeBlock) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Clean, NumVal = runtimeScopeBlock.From, NumVal2 = runtimeScopeBlock.ToInclusive }); } public Instruction Emit_Clean(RuntimeScopeBlock runtimeScopeBlock) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Clean, NumVal = runtimeScopeBlock.To + 1, NumVal2 = runtimeScopeBlock.ToInclusive }); } public Instruction Emit_Closure(SymbolRef[] symbols, int jmpnum) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Closure, SymbolList = symbols, NumVal = jmpnum }); } public Instruction Emit_Args(params SymbolRef[] symbols) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Args, SymbolList = symbols }); } public Instruction Emit_Ret(int retvals) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Ret, NumVal = retvals }); } public Instruction Emit_ToNum(int stage = 0) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.ToNum, NumVal = stage }); } public Instruction Emit_Incr(int i) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Incr, NumVal = i }); } public Instruction Emit_NewTable(bool shared) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.NewTable, NumVal = (shared ? 1 : 0) }); } public Instruction Emit_IterPrep() { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.IterPrep }); } public Instruction Emit_ExpTuple(int stackOffset) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.ExpTuple, NumVal = stackOffset }); } public Instruction Emit_IterUpd() { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.IterUpd }); } public Instruction Emit_Meta(string funcName, OpCodeMetadataType metaType, DynValue value = null) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Meta, Name = funcName, NumVal2 = (int)metaType, Value = value }); } public Instruction Emit_BeginFn(RuntimeScopeFrame stackFrame) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.BeginFn, SymbolList = stackFrame.DebugSymbols.ToArray(), NumVal = stackFrame.Count, NumVal2 = stackFrame.ToFirstBlock }); } public Instruction Emit_Scalar() { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Scalar }); } public int Emit_Load(SymbolRef sym) { switch (sym.Type) { case SymbolRefType.Global: Emit_Load(sym.i_Env); AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Index, Value = DynValue.NewString(sym.i_Name) }); return 2; case SymbolRefType.Local: AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Local, Symbol = sym }); return 1; case SymbolRefType.Upvalue: AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Upvalue, Symbol = sym }); return 1; default: throw new InternalErrorException("Unexpected symbol type : {0}", sym); } } public int Emit_Store(SymbolRef sym, int stackofs, int tupleidx) { switch (sym.Type) { case SymbolRefType.Global: Emit_Load(sym.i_Env); AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.IndexSet, Symbol = sym, NumVal = stackofs, NumVal2 = tupleidx, Value = DynValue.NewString(sym.i_Name) }); return 2; case SymbolRefType.Local: AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.StoreLcl, Symbol = sym, NumVal = stackofs, NumVal2 = tupleidx }); return 1; case SymbolRefType.Upvalue: AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.StoreUpv, Symbol = sym, NumVal = stackofs, NumVal2 = tupleidx }); return 1; default: throw new InternalErrorException("Unexpected symbol type : {0}", sym); } } public Instruction Emit_TblInitN() { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.TblInitN }); } public Instruction Emit_TblInitI(bool lastpos) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.TblInitI, NumVal = (lastpos ? 1 : 0) }); } public Instruction Emit_Index(DynValue index = null, bool isNameIndex = false, bool isExpList = false) { OpCode opCode = (isNameIndex ? OpCode.IndexN : ((!isExpList) ? OpCode.Index : OpCode.IndexL)); return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = opCode, Value = index }); } public Instruction Emit_IndexSet(int stackofs, int tupleidx, DynValue index = null, bool isNameIndex = false, bool isExpList = false) { OpCode opCode = (isNameIndex ? OpCode.IndexSetN : ((!isExpList) ? OpCode.IndexSet : OpCode.IndexSetL)); return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = opCode, NumVal = stackofs, NumVal2 = tupleidx, Value = index }); } public Instruction Emit_Copy(int numval) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Copy, NumVal = numval }); } public Instruction Emit_Swap(int p1, int p2) { return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = OpCode.Swap, NumVal = p1, NumVal2 = p2 }); } } public class Instruction { public OpCode OpCode; public SymbolRef Symbol; public SymbolRef[] SymbolList; public string Name; public DynValue Value; public int NumVal; public int NumVal2; public SourceRef SourceCodeRef; public Instruction(SourceRef sourceref) { SourceCodeRef = sourceref; } public override string ToString() { string text = OpCode.ToString().ToUpperInvariant(); int fieldUsage = (int)OpCode.GetFieldUsage(); if (fieldUsage != 0) { text += GenSpaces(); } if (OpCode == OpCode.Meta || (fieldUsage & 0x8010) == 32784) { text = text + " " + NumVal.ToString("X8"); } else if (((uint)fieldUsage & 0x10u) != 0) { text = text + " " + NumVal; } if (((uint)fieldUsage & 0x20u) != 0) { text = text + " " + NumVal2; } if (((uint)fieldUsage & 4u) != 0) { text = text + " " + Name; } if (((uint)fieldUsage & 8u) != 0) { text = text + " " + PurifyFromNewLines(Value); } if (((uint)fieldUsage & (true ? 1u : 0u)) != 0) { text = text + " " + Symbol; } if (((uint)fieldUsage & 2u) != 0 && SymbolList != null) { text = text + " " + string.Join(",", SymbolList.Select((SymbolRef s) => s.ToString()).ToArray()); } return text; } public string PurifyFromNewLines(DynValue Value) { if (Value == null) { return ""; } return Value.ToString().Replace('\n', ' ').Replace('\r', ' '); } public string GenSpaces() { return new string(' ', 10 - OpCode.ToString().Length); } public void WriteBinary(BinaryWriter wr, int baseAddress, Dictionary symbolMap) { wr.Write((byte)OpCode); int fieldUsage = (int)OpCode.GetFieldUsage(); if ((fieldUsage & 0x8010) == 32784) { wr.Write(NumVal - baseAddress); } else if (((uint)fieldUsage & 0x10u) != 0) { wr.Write(NumVal); } if (((uint)fieldUsage & 0x20u) != 0) { wr.Write(NumVal2); } if (((uint)fieldUsage & 4u) != 0) { wr.Write(Name ?? ""); } if (((uint)fieldUsage & 8u) != 0) { DumpValue(wr, Value); } if (((uint)fieldUsage & (true ? 1u : 0u)) != 0) { WriteSymbol(wr, Symbol, symbolMap); } if (((uint)fieldUsage & 2u) != 0) { wr.Write(SymbolList.Length); for (int i = 0; i < SymbolList.Length; i++) { WriteSymbol(wr, SymbolList[i], symbolMap); } } } public static void WriteSymbol(BinaryWriter wr, SymbolRef symbolRef, Dictionary symbolMap) { int value = ((symbolRef == null) ? (-1) : symbolMap[symbolRef]); wr.Write(value); } public static SymbolRef ReadSymbol(BinaryReader rd, SymbolRef[] deserializedSymbols) { int num = rd.ReadInt32(); if (num < 0) { return null; } return deserializedSymbols[num]; } public static Instruction ReadBinary(SourceRef chunkRef, BinaryReader rd, int baseAddress, Table envTable, SymbolRef[] deserializedSymbols) { Instruction instruction = new Instruction(chunkRef); instruction.OpCode = (OpCode)rd.ReadByte(); int fieldUsage = (int)instruction.OpCode.GetFieldUsage(); if ((fieldUsage & 0x8010) == 32784) { instruction.NumVal = rd.ReadInt32() + baseAddress; } else if (((uint)fieldUsage & 0x10u) != 0) { instruction.NumVal = rd.ReadInt32(); } if (((uint)fieldUsage & 0x20u) != 0) { instruction.NumVal2 = rd.ReadInt32(); } if (((uint)fieldUsage & 4u) != 0) { instruction.Name = rd.ReadString(); } if (((uint)fieldUsage & 8u) != 0) { instruction.Value = ReadValue(rd, envTable); } if (((uint)fieldUsage & (true ? 1u : 0u)) != 0) { instruction.Symbol = ReadSymbol(rd, deserializedSymbols); } if (((uint)fieldUsage & 2u) != 0) { int num = rd.ReadInt32(); instruction.SymbolList = new SymbolRef[num]; for (int i = 0; i < instruction.SymbolList.Length; i++) { instruction.SymbolList[i] = ReadSymbol(rd, deserializedSymbols); } } return instruction; } public static DynValue ReadValue(BinaryReader rd, Table envTable) { if (!rd.ReadBoolean()) { return null; } DataType dataType = (DataType)rd.ReadByte(); return dataType switch { DataType.Nil => DynValue.NewNil(), DataType.Void => DynValue.Void, DataType.Boolean => DynValue.NewBoolean(rd.ReadBoolean()), DataType.Number => DynValue.NewNumber(rd.ReadDouble()), DataType.String => DynValue.NewString(rd.ReadString()), DataType.Table => DynValue.NewTable(envTable), _ => throw new NotSupportedException($"Unsupported type in chunk dump : {dataType}"), }; } public void DumpValue(BinaryWriter wr, DynValue value) { if (value == null) { wr.Write(value: false); return; } wr.Write(value: true); wr.Write((byte)value.Type); switch (value.Type) { case DataType.Boolean: wr.Write(value.Boolean); break; case DataType.Number: wr.Write(value.Number); break; case DataType.String: wr.Write(value.String); break; default: throw new NotSupportedException($"Unsupported type in chunk dump : {value.Type}"); case DataType.Nil: case DataType.Void: case DataType.Table: break; } } public void GetSymbolReferences(out SymbolRef[] symbolList, out SymbolRef symbol) { InstructionFieldUsage fieldUsage = OpCode.GetFieldUsage(); symbol = null; symbolList = null; if ((fieldUsage & InstructionFieldUsage.Symbol) != 0) { symbol = Symbol; } if ((fieldUsage & InstructionFieldUsage.SymbolList) != 0) { symbolList = SymbolList; } } } public enum OpCode { Nop, Debug, Pop, Copy, Swap, Literal, Closure, NewTable, TblInitN, TblInitI, StoreLcl, Local, StoreUpv, Upvalue, IndexSet, Index, IndexSetN, IndexN, IndexSetL, IndexL, Clean, Meta, BeginFn, Args, Call, ThisCall, Ret, Jump, Jf, JNil, JFor, JtOrPop, JfOrPop, Concat, LessEq, Less, Eq, Add, Sub, Mul, Div, Mod, Not, Len, Neg, Power, CNot, MkTuple, Scalar, Incr, ToNum, ToBool, ExpTuple, IterPrep, IterUpd, Invalid } public class CallStackItem { public int Debug_EntryPoint; public SymbolRef[] Debug_Symbols; public SourceRef CallingSourceRef; public CallbackFunction ClrFunction; public CallbackFunction Continuation; public CallbackFunction ErrorHandler; public DynValue ErrorHandlerBeforeUnwind; public int BasePointer; public int ReturnAddress; public DynValue[] LocalScope; public ClosureContext ClosureScope; public CallStackItemFlags Flags; } } namespace MoonSharp.Interpreter.Debugging { [Flags] public enum DebuggerCaps { CanDebugSourceCode = 1, CanDebugByteCode = 2, HasLineBasedBreakpoints = 4 } public sealed class DebugService : IScriptPrivateResource { public Processor m_Processor; public Script OwnerScript { get; set; } public DebugService(Script script, Processor processor) { OwnerScript = script; m_Processor = processor; } public HashSet ResetBreakPoints(SourceCode src, HashSet lines) { return m_Processor.ResetBreakPoints(src, lines); } } public class DebuggerAction { public enum ActionType { ByteCodeStepIn, ByteCodeStepOver, ByteCodeStepOut, StepIn, StepOver, StepOut, Run, ToggleBreakpoint, SetBreakpoint, ClearBreakpoint, ResetBreakpoints, Refresh, HardRefresh, None } public ActionType Action { get; set; } public DateTime TimeStampUTC { get; set; } public int SourceID { get; set; } public int SourceLine { get; set; } public int SourceCol { get; set; } public int[] Lines { get; set; } public TimeSpan Age => DateTime.UtcNow - TimeStampUTC; public DebuggerAction() { TimeStampUTC = DateTime.UtcNow; } public override string ToString() { if (Action == ActionType.ToggleBreakpoint || Action == ActionType.SetBreakpoint || Action == ActionType.ClearBreakpoint) { return $"{Action} {SourceID}:({SourceLine},{SourceCol})"; } return Action.ToString(); } } public interface IDebugger { DebuggerCaps GetDebuggerCaps(); void SetDebugService(DebugService debugService); void SetSourceCode(SourceCode sourceCode); void SetByteCode(string[] byteCode); bool IsPauseRequested(); bool SignalRuntimeException(ScriptRuntimeException ex); DebuggerAction GetAction(int ip, SourceRef sourceref); void SignalExecutionEnded(); void Update(WatchType watchType, IEnumerable items); List GetWatchItems(); void RefreshBreakpoints(IEnumerable refs); } public class SourceRef { public bool Breakpoint; public bool IsClrLocation { get; set; } public int SourceIdx { get; set; } public int FromChar { get; set; } public int ToChar { get; set; } public int FromLine { get; set; } public int ToLine { get; set; } public bool IsStepStop { get; set; } public bool CannotBreakpoint { get; set; } public static SourceRef GetClrLocation() { return new SourceRef(0, 0, 0, 0, 0, isStepStop: false) { IsClrLocation = true }; } public SourceRef(SourceRef src, bool isStepStop) { SourceIdx = src.SourceIdx; FromChar = src.FromChar; ToChar = src.ToChar; FromLine = src.FromLine; ToLine = src.ToLine; IsStepStop = isStepStop; } public SourceRef(int sourceIdx, int from, int to, int fromline, int toline, bool isStepStop) { SourceIdx = sourceIdx; FromChar = from; ToChar = to; FromLine = fromline; ToLine = toline; IsStepStop = isStepStop; } public override string ToString() { return string.Format("[{0}]{1} ({2}, {3}) -> ({4}, {5})", SourceIdx, IsStepStop ? "*" : " ", FromLine, FromChar, ToLine, ToChar); } public int GetLocationDistance(int sourceIdx, int line, int col) { if (sourceIdx != SourceIdx) { return int.MaxValue; } if (FromLine == ToLine) { if (line == FromLine) { if (col >= FromChar && col <= ToChar) { return 0; } if (col < FromChar) { return FromChar - col; } return col - ToChar; } return Math.Abs(line - FromLine) * 1600; } if (line == FromLine) { if (col < FromChar) { return FromChar - col; } return 0; } if (line == ToLine) { if (col > ToChar) { return col - ToChar; } return 0; } if (line > FromLine && line < ToLine) { return 0; } if (line < FromLine) { return (FromLine - line) * 1600; } return (line - ToLine) * 1600; } public bool IncludesLocation(int sourceIdx, int line, int col) { if (sourceIdx != SourceIdx || line < FromLine || line > ToLine) { return false; } if (FromLine == ToLine) { if (col >= FromChar) { return col <= ToChar; } return false; } if (line == FromLine) { return col >= FromChar; } if (line == ToLine) { return col <= ToChar; } return true; } public SourceRef SetNoBreakPoint() { CannotBreakpoint = true; return this; } public string FormatLocation(Script script, bool forceClassicFormat = false) { SourceCode sourceCode = script.GetSourceCode(SourceIdx); if (IsClrLocation) { return "[clr]"; } if (script.Options.UseLuaErrorLocations || forceClassicFormat) { return $"{sourceCode.Name}:{FromLine}"; } if (FromLine == ToLine) { if (FromChar == ToChar) { return string.Format("{0}:({1},{2})", sourceCode.Name, FromLine, FromChar, ToLine, ToChar); } return string.Format("{0}:({1},{2}-{4})", sourceCode.Name, FromLine, FromChar, ToLine, ToChar); } return $"{sourceCode.Name}:({FromLine},{FromChar}-{ToLine},{ToChar})"; } } public class WatchItem { public int Address { get; set; } public int BasePtr { get; set; } public int RetAddress { get; set; } public string Name { get; set; } public DynValue Value { get; set; } public SymbolRef LValue { get; set; } public bool IsError { get; set; } public SourceRef Location { get; set; } public override string ToString() { return string.Format("{0}:{1}:{2}:{3}:{4}:{5}", Address, BasePtr, RetAddress, Name ?? "(null)", (Value != null) ? Value.ToString() : "(null)", (LValue != null) ? LValue.ToString() : "(null)"); } } public enum WatchType { Watches, VStack, CallStack, Coroutines, Locals, Threads, MaxValue } public class SourceCode : IScriptPrivateResource { public string Name { get; set; } public string Code { get; set; } public string[] Lines { get; set; } public Script OwnerScript { get; set; } public int SourceID { get; set; } public List Refs { get; set; } public SourceCode(string name, string code, int sourceID, Script ownerScript) { Refs = new List(); List list = new List(); Name = name; Code = code; list.Add($"-- Begin of chunk : {name} "); list.AddRange(Code.Split(new char[1] { '\n' })); Lines = list.ToArray(); OwnerScript = ownerScript; SourceID = sourceID; } public string GetCodeSnippet(SourceRef sourceCodeRef) { if (sourceCodeRef.FromLine == sourceCodeRef.ToLine) { int num = AdjustStrIndex(Lines[sourceCodeRef.FromLine], sourceCodeRef.FromChar); int num2 = AdjustStrIndex(Lines[sourceCodeRef.FromLine], sourceCodeRef.ToChar); return Lines[sourceCodeRef.FromLine].Substring(num, num2 - num); } StringBuilder stringBuilder = new StringBuilder(); for (int i = sourceCodeRef.FromLine; i <= sourceCodeRef.ToLine; i++) { if (i == sourceCodeRef.FromLine) { int startIndex = AdjustStrIndex(Lines[i], sourceCodeRef.FromChar); stringBuilder.Append(Lines[i].Substring(startIndex)); } else if (i == sourceCodeRef.ToLine) { int num3 = AdjustStrIndex(Lines[i], sourceCodeRef.ToChar); stringBuilder.Append(Lines[i].Substring(0, num3 + 1)); } else { stringBuilder.Append(Lines[i]); } } return stringBuilder.ToString(); } public int AdjustStrIndex(string str, int loc) { return Math.Max(Math.Min(str.Length, loc), 0); } } public static class NamespaceDoc { } } namespace MoonSharp.Interpreter.DataStructs { public class MultiDictionary { public Dictionary> m_Map; public V[] m_DefaultRet = new V[0]; public IEnumerable Keys => m_Map.Keys; public MultiDictionary() { m_Map = new Dictionary>(); } public MultiDictionary(IEqualityComparer eqComparer) { m_Map = new Dictionary>(eqComparer); } public bool Add(K key, V value) { if (m_Map.TryGetValue(key, out var value2)) { value2.Add(value); return false; } value2 = new List(); value2.Add(value); m_Map.Add(key, value2); return true; } public IEnumerable Find(K key) { if (m_Map.TryGetValue(key, out var value)) { return value; } return m_DefaultRet; } public bool ContainsKey(K key) { return m_Map.ContainsKey(key); } public void Clear() { m_Map.Clear(); } public void Remove(K key) { m_Map.Remove(key); } public bool RemoveValue(K key, V value) { if (m_Map.TryGetValue(key, out var value2)) { value2.Remove(value); if (value2.Count == 0) { Remove(key); return true; } } return false; } } public class ReferenceEqualityComparer : IEqualityComparer { bool IEqualityComparer.Equals(object x, object y) { return x == y; } int IEqualityComparer.GetHashCode(object obj) { return obj.GetHashCode(); } } public class FastStackDynamic : List { public FastStackDynamic(int startingCapacity) : base(startingCapacity) { } public void Set(int idxofs, T item) { base[base.Count - 1 - idxofs] = item; } public T Push(T item) { Add(item); return item; } public void Expand(int size) { for (int i = 0; i < size; i++) { Add(default(T)); } } public void Zero(int index) { base[index] = default(T); } public T Peek(int idxofs = 0) { return base[base.Count - 1 - idxofs]; } public void CropAtCount(int p) { RemoveLast(base.Count - p); } public void RemoveLast(int cnt = 1) { if (cnt == 1) { RemoveAt(base.Count - 1); } else { RemoveRange(base.Count - cnt, cnt); } } public T Pop() { T result = base[base.Count - 1]; RemoveAt(base.Count - 1); return result; } } public class LinkedListIndex { public LinkedList m_LinkedList; public Dictionary> m_Map; public LinkedListIndex(LinkedList linkedList) { m_LinkedList = linkedList; } public LinkedListNode Find(TKey key) { if (m_Map == null) { return null; } if (m_Map.TryGetValue(key, out var value)) { return value; } return null; } public TValue Set(TKey key, TValue value) { LinkedListNode linkedListNode = Find(key); if (linkedListNode == null) { Add(key, value); return default(TValue); } TValue value2 = linkedListNode.Value; linkedListNode.Value = value; return value2; } public void Add(TKey key, TValue value) { LinkedListNode value2 = m_LinkedList.AddLast(value); if (m_Map == null) { m_Map = new Dictionary>(); } m_Map.Add(key, value2); } public bool Remove(TKey key) { LinkedListNode linkedListNode = Find(key); if (linkedListNode != null) { m_LinkedList.Remove(linkedListNode); return m_Map.Remove(key); } return false; } public bool ContainsKey(TKey key) { if (m_Map == null) { return false; } return m_Map.ContainsKey(key); } public void Clear() { if (m_Map != null) { m_Map.Clear(); } } } public class Slice : IEnumerable, IEnumerable, IList, ICollection { public IList m_SourceList; public int m_From; public int m_Length; public bool m_Reversed; public T this[int index] { get { return m_SourceList[CalcRealIndex(index)]; } set { m_SourceList[CalcRealIndex(index)] = value; } } public int From => m_From; public int Count => m_Length; public bool Reversed => m_Reversed; public bool IsReadOnly => true; public Slice(IList list, int from, int length, bool reversed) { m_SourceList = list; m_From = from; m_Length = length; m_Reversed = reversed; } public int CalcRealIndex(int index) { if (index < 0 || index >= m_Length) { throw new ArgumentOutOfRangeException("index"); } if (m_Reversed) { return m_From + m_Length - index - 1; } return m_From + index; } public IEnumerator GetEnumerator() { for (int i = 0; i < m_Length; i++) { yield return m_SourceList[CalcRealIndex(i)]; } } IEnumerator IEnumerable.GetEnumerator() { for (int i = 0; i < m_Length; i++) { yield return m_SourceList[CalcRealIndex(i)]; } } public T[] ToArray() { T[] array = new T[m_Length]; for (int i = 0; i < m_Length; i++) { array[i] = m_SourceList[CalcRealIndex(i)]; } return array; } public List ToList() { List list = new List(m_Length); for (int i = 0; i < m_Length; i++) { list.Add(m_SourceList[CalcRealIndex(i)]); } return list; } public int IndexOf(T item) { for (int i = 0; i < Count; i++) { if (this[i].Equals(item)) { return i; } } return -1; } public void Insert(int index, T item) { throw new InvalidOperationException("Slices are readonly"); } public void RemoveAt(int index) { throw new InvalidOperationException("Slices are readonly"); } public void Add(T item) { throw new InvalidOperationException("Slices are readonly"); } public void Clear() { throw new InvalidOperationException("Slices are readonly"); } public bool Contains(T item) { return IndexOf(item) >= 0; } public void CopyTo(T[] array, int arrayIndex) { for (int i = 0; i < Count; i++) { array[i + arrayIndex] = this[i]; } } public bool Remove(T item) { throw new InvalidOperationException("Slices are readonly"); } } public class FastStack : IList, ICollection, IEnumerable, IEnumerable { public T[] m_Storage; public int m_HeadIdx; public T this[int index] { get { return m_Storage[index]; } set { m_Storage[index] = value; } } public int Count => m_HeadIdx; T IList.this[int index] { get { return this[index]; } set { this[index] = value; } } int ICollection.Count => Count; bool ICollection.IsReadOnly => false; public FastStack(int maxCapacity) { m_Storage = new T[maxCapacity]; } public T Push(T item) { m_Storage[m_HeadIdx++] = item; return item; } public void Expand(int size) { m_HeadIdx += size; } public void Zero(int from, int to) { Array.Clear(m_Storage, from, to - from + 1); } public void Zero(int index) { m_Storage[index] = default(T); } public T Peek(int idxofs = 0) { return m_Storage[m_HeadIdx - 1 - idxofs]; } public void Set(int idxofs, T item) { m_Storage[m_HeadIdx - 1 - idxofs] = item; } public void CropAtCount(int p) { RemoveLast(Count - p); } public void RemoveLast(int cnt = 1) { if (cnt == 1) { m_HeadIdx--; m_Storage[m_HeadIdx] = default(T); } else { int headIdx = m_HeadIdx; m_HeadIdx -= cnt; Zero(m_HeadIdx, headIdx); } } public T Pop() { m_HeadIdx--; T result = m_Storage[m_HeadIdx]; m_Storage[m_HeadIdx] = default(T); return result; } public void Clear() { Array.Clear(m_Storage, 0, m_Storage.Length); m_HeadIdx = 0; } int IList.IndexOf(T item) { throw new NotImplementedException(); } void IList.Insert(int index, T item) { throw new NotImplementedException(); } void IList.RemoveAt(int index) { throw new NotImplementedException(); } void ICollection.Add(T item) { Push(item); } void ICollection.Clear() { Clear(); } bool ICollection.Contains(T item) { throw new NotImplementedException(); } void ICollection.CopyTo(T[] array, int arrayIndex) { throw new NotImplementedException(); } bool ICollection.Remove(T item) { throw new NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } } } namespace MoonSharp.Interpreter.CoreLib { [MoonSharpModule(Namespace = "coroutine")] public class CoroutineModule { [MoonSharpModuleMethod] public static DynValue create(ScriptExecutionContext executionContext, CallbackArguments args) { if (args[0].Type != DataType.Function && args[0].Type != DataType.ClrFunction) { args.AsType(0, "create", DataType.Function); } return executionContext.GetScript().CreateCoroutine(args[0]); } [MoonSharpModuleMethod] public static DynValue wrap(ScriptExecutionContext executionContext, CallbackArguments args) { if (args[0].Type != DataType.Function && args[0].Type != DataType.ClrFunction) { args.AsType(0, "wrap", DataType.Function); } DynValue additionalData = create(executionContext, args); DynValue dynValue = DynValue.NewCallback(__wrap_wrapper); dynValue.Callback.AdditionalData = additionalData; return dynValue; } public static DynValue __wrap_wrapper(ScriptExecutionContext executionContext, CallbackArguments args) { return ((DynValue)executionContext.AdditionalData).Coroutine.Resume(args.GetArray()); } [MoonSharpModuleMethod] public static DynValue resume(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "resume", DataType.Thread); try { DynValue dynValue2 = dynValue.Coroutine.Resume(args.GetArray(1)); List list = new List(); list.Add(DynValue.True); if (dynValue2.Type == DataType.Tuple) { for (int i = 0; i < dynValue2.Tuple.Length; i++) { DynValue dynValue3 = dynValue2.Tuple[i]; if (i == dynValue2.Tuple.Length - 1 && dynValue3.Type == DataType.Tuple) { list.AddRange(dynValue3.Tuple); } else { list.Add(dynValue3); } } } else { list.Add(dynValue2); } return DynValue.NewTuple(list.ToArray()); } catch (ScriptRuntimeException ex) { return DynValue.NewTuple(DynValue.False, DynValue.NewString(ex.Message)); } } [MoonSharpModuleMethod] public static DynValue yield(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewYieldReq(args.GetArray()); } [MoonSharpModuleMethod] public static DynValue running(ScriptExecutionContext executionContext, CallbackArguments args) { Coroutine callingCoroutine = executionContext.GetCallingCoroutine(); return DynValue.NewTuple(DynValue.NewCoroutine(callingCoroutine), DynValue.NewBoolean(callingCoroutine.State == CoroutineState.Main)); } [MoonSharpModuleMethod] public static DynValue status(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "status", DataType.Thread); Coroutine callingCoroutine = executionContext.GetCallingCoroutine(); CoroutineState state = dynValue.Coroutine.State; switch (state) { case CoroutineState.Main: case CoroutineState.Running: if (dynValue.Coroutine != callingCoroutine) { return DynValue.NewString("normal"); } return DynValue.NewString("running"); case CoroutineState.NotStarted: case CoroutineState.Suspended: case CoroutineState.ForceSuspended: return DynValue.NewString("suspended"); case CoroutineState.Dead: return DynValue.NewString("dead"); default: throw new InternalErrorException("Unexpected coroutine state {0}", state); } } } [MoonSharpModule] public class BasicModule { [MoonSharpModuleMethod] public static DynValue type(ScriptExecutionContext executionContext, CallbackArguments args) { if (args.Count < 1) { throw ScriptRuntimeException.BadArgumentValueExpected(0, "type"); } return DynValue.NewString(args[0].Type.ToLuaTypeString()); } [MoonSharpModuleMethod] public static DynValue assert(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args[0]; DynValue dynValue2 = args[1]; if (!dynValue.CastToBool()) { if (dynValue2.IsNil()) { throw new ScriptRuntimeException("assertion failed!"); } throw new ScriptRuntimeException(dynValue2.ToPrintString()); } return DynValue.NewTupleNested(args.GetArray()); } [MoonSharpModuleMethod] public static DynValue collectgarbage(ScriptExecutionContext executionContext, CallbackArguments args) { switch (args[0].CastToString()) { case null: case "collect": case "restart": GC.Collect(2, GCCollectionMode.Forced); break; } return DynValue.Nil; } [MoonSharpModuleMethod] public static DynValue error(ScriptExecutionContext executionContext, CallbackArguments args) { throw new ScriptRuntimeException(args.AsType(0, "error", DataType.String).String); } [MoonSharpModuleMethod] public static DynValue tostring(ScriptExecutionContext executionContext, CallbackArguments args) { if (args.Count < 1) { throw ScriptRuntimeException.BadArgumentValueExpected(0, "tostring"); } DynValue dynValue = args[0]; DynValue metamethodTailCall = executionContext.GetMetamethodTailCall(dynValue, "__tostring", dynValue); if (metamethodTailCall == null || metamethodTailCall.IsNil()) { return DynValue.NewString(dynValue.ToPrintString()); } metamethodTailCall.TailCallData.Continuation = new CallbackFunction(__tostring_continuation, "__tostring"); return metamethodTailCall; } public static DynValue __tostring_continuation(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args[0].ToScalar(); if (dynValue.IsNil()) { return dynValue; } if (dynValue.Type != DataType.String) { throw new ScriptRuntimeException("'tostring' must return a string"); } return dynValue; } [MoonSharpModuleMethod] public static DynValue select(ScriptExecutionContext executionContext, CallbackArguments args) { if (args[0].Type == DataType.String && args[0].String == "#") { if (args[args.Count - 1].Type == DataType.Tuple) { return DynValue.NewNumber(args.Count - 1 + args[args.Count - 1].Tuple.Length); } return DynValue.NewNumber(args.Count - 1); } int num = (int)args.AsType(0, "select", DataType.Number).Number; List list = new List(); if (num > 0) { for (int i = num; i < args.Count; i++) { list.Add(args[i]); } } else { if (num >= 0) { throw ScriptRuntimeException.BadArgumentIndexOutOfRange("select", 0); } num = args.Count + num; if (num < 1) { throw ScriptRuntimeException.BadArgumentIndexOutOfRange("select", 0); } for (int j = num; j < args.Count; j++) { list.Add(args[j]); } } return DynValue.NewTupleNested(list.ToArray()); } [MoonSharpModuleMethod] public static DynValue tonumber(ScriptExecutionContext executionContext, CallbackArguments args) { if (args.Count < 1) { throw ScriptRuntimeException.BadArgumentValueExpected(0, "tonumber"); } DynValue dynValue = args[0]; DynValue dynValue2 = args.AsType(1, "tonumber", DataType.Number, allowNil: true); if (dynValue2.IsNil()) { if (dynValue.Type == DataType.Number) { return dynValue; } if (dynValue.Type != DataType.String) { return DynValue.Nil; } if (double.TryParse(dynValue.String, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return DynValue.NewNumber(result); } return DynValue.Nil; } DynValue dynValue3 = ((args[0].Type == DataType.Number) ? DynValue.NewString(args[0].Number.ToString(CultureInfo.InvariantCulture)) : args.AsType(0, "tonumber", DataType.String)); int num = (int)dynValue2.Number; uint num2 = 0u; switch (num) { case 2: case 8: case 10: case 16: num2 = Convert.ToUInt32(dynValue3.String.Trim(), num); break; case 3: case 4: case 5: case 6: case 7: case 9: { string text = dynValue3.String.Trim(); for (int i = 0; i < text.Length; i++) { int num3 = text[i] - 48; if (num3 < 0 || num3 >= num) { throw new ScriptRuntimeException("bad argument #1 to 'tonumber' (invalid character)"); } num2 = (uint)((int)(num2 * num) + num3); } break; } default: throw new ScriptRuntimeException("bad argument #2 to 'tonumber' (base out of range)"); } return DynValue.NewNumber(num2); } [MoonSharpModuleMethod] public static DynValue print(ScriptExecutionContext executionContext, CallbackArguments args) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < args.Count && !args[i].IsVoid(); i++) { if (i != 0) { stringBuilder.Append('\t'); } stringBuilder.Append(args.AsStringUsingMeta(executionContext, i, "print")); } executionContext.GetScript().Options.DebugPrint(stringBuilder.ToString()); return DynValue.Nil; } } [MoonSharpModule(Namespace = "debug")] public class DebugModule { [MoonSharpModuleMethod] public static DynValue debug(ScriptExecutionContext executionContext, CallbackArguments args) { Script script = executionContext.GetScript(); if (script.Options.DebugInput == null) { throw new ScriptRuntimeException("debug.debug not supported on this platform/configuration"); } ReplInterpreter replInterpreter = new ReplInterpreter(script) { HandleDynamicExprs = false, HandleClassicExprsSyntax = true }; while (true) { string input = script.Options.DebugInput(replInterpreter.ClassicPrompt + " "); try { DynValue dynValue = replInterpreter.Evaluate(input); if (dynValue != null && dynValue.Type != DataType.Void) { script.Options.DebugPrint($"{dynValue}"); } } catch (InterpreterException ex) { script.Options.DebugPrint($"{ex.DecoratedMessage ?? ex.Message}"); } catch (Exception ex2) { script.Options.DebugPrint($"{ex2.Message}"); } } } [MoonSharpModuleMethod] public static DynValue getuservalue(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args[0]; if (dynValue.Type != DataType.UserData) { return DynValue.Nil; } return dynValue.UserData.UserValue ?? DynValue.Nil; } [MoonSharpModuleMethod] public static DynValue setuservalue(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "setuservalue", DataType.UserData); DynValue dynValue2 = args.AsType(0, "setuservalue", DataType.Table, allowNil: true); return dynValue.UserData.UserValue = dynValue2; } [MoonSharpModuleMethod] public static DynValue getregistry(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewTable(executionContext.GetScript().Registry); } [MoonSharpModuleMethod] public static DynValue getmetatable(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args[0]; Script script = executionContext.GetScript(); if (dynValue.Type.CanHaveTypeMetatables()) { return DynValue.NewTable(script.GetTypeMetatable(dynValue.Type)); } if (dynValue.Type == DataType.Table) { return DynValue.NewTable(dynValue.Table.MetaTable); } return DynValue.Nil; } [MoonSharpModuleMethod] public static DynValue setmetatable(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args[0]; DynValue dynValue2 = args.AsType(1, "setmetatable", DataType.Table, allowNil: true); Table table = (dynValue2.IsNil() ? null : dynValue2.Table); Script script = executionContext.GetScript(); if (dynValue.Type.CanHaveTypeMetatables()) { script.SetTypeMetatable(dynValue.Type, table); } else { if (dynValue.Type != DataType.Table) { throw new ScriptRuntimeException("cannot debug.setmetatable on type {0}", dynValue.Type.ToErrorTypeString()); } dynValue.Table.MetaTable = table; } return dynValue; } [MoonSharpModuleMethod] public static DynValue getupvalue(ScriptExecutionContext executionContext, CallbackArguments args) { int num = (int)args.AsType(1, "getupvalue", DataType.Number).Number - 1; if (args[0].Type == DataType.ClrFunction) { return DynValue.Nil; } ClosureContext closureContext = args.AsType(0, "getupvalue", DataType.Function).Function.ClosureContext; if (num < 0 || num >= closureContext.Count) { return DynValue.Nil; } return DynValue.NewTuple(DynValue.NewString(closureContext.Symbols[num]), closureContext[num]); } [MoonSharpModuleMethod] public static DynValue upvalueid(ScriptExecutionContext executionContext, CallbackArguments args) { int num = (int)args.AsType(1, "getupvalue", DataType.Number).Number - 1; if (args[0].Type == DataType.ClrFunction) { return DynValue.Nil; } ClosureContext closureContext = args.AsType(0, "getupvalue", DataType.Function).Function.ClosureContext; if (num < 0 || num >= closureContext.Count) { return DynValue.Nil; } return DynValue.NewNumber(closureContext[num].ReferenceID); } [MoonSharpModuleMethod] public static DynValue setupvalue(ScriptExecutionContext executionContext, CallbackArguments args) { int num = (int)args.AsType(1, "setupvalue", DataType.Number).Number - 1; if (args[0].Type == DataType.ClrFunction) { return DynValue.Nil; } ClosureContext closureContext = args.AsType(0, "setupvalue", DataType.Function).Function.ClosureContext; if (num < 0 || num >= closureContext.Count) { return DynValue.Nil; } closureContext[num].Assign(args[2]); return DynValue.NewString(closureContext.Symbols[num]); } [MoonSharpModuleMethod] public static DynValue upvaluejoin(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "upvaluejoin", DataType.Function); DynValue dynValue2 = args.AsType(2, "upvaluejoin", DataType.Function); int num = args.AsInt(1, "upvaluejoin") - 1; int num2 = args.AsInt(3, "upvaluejoin") - 1; Closure function = dynValue.Function; Closure function2 = dynValue2.Function; if (num < 0 || num >= function.ClosureContext.Count) { throw ScriptRuntimeException.BadArgument(1, "upvaluejoin", "invalid upvalue index"); } if (num2 < 0 || num2 >= function2.ClosureContext.Count) { throw ScriptRuntimeException.BadArgument(3, "upvaluejoin", "invalid upvalue index"); } function2.ClosureContext[num2] = function.ClosureContext[num]; return DynValue.Void; } [MoonSharpModuleMethod] public static DynValue traceback(ScriptExecutionContext executionContext, CallbackArguments args) { StringBuilder stringBuilder = new StringBuilder(); DynValue dynValue = args[0]; DynValue dynValue2 = args[1]; double num = 1.0; Coroutine coroutine = executionContext.GetCallingCoroutine(); if (dynValue.Type == DataType.Thread) { coroutine = dynValue.Coroutine; dynValue = args[1]; dynValue2 = args[2]; num = 0.0; } if (dynValue.IsNotNil() && dynValue.Type != DataType.String && dynValue.Type != DataType.Number) { return dynValue; } string text = dynValue.CastToString(); int val = (int)(dynValue2.CastToNumber() ?? num); WatchItem[] stackTrace = coroutine.GetStackTrace(Math.Max(0, val)); if (text != null) { stringBuilder.AppendLine(text); } stringBuilder.AppendLine("stack traceback:"); WatchItem[] array = stackTrace; foreach (WatchItem watchItem in array) { string arg = ((watchItem.Name != null) ? ("function '" + watchItem.Name + "'") : ((watchItem.RetAddress >= 0) ? "?" : "main chunk")); string arg2 = ((watchItem.Location != null) ? watchItem.Location.FormatLocation(executionContext.GetScript()) : "[clr]"); stringBuilder.AppendFormat("\t{0}: in {1}\n", arg2, arg); } return DynValue.NewString(stringBuilder); } } [MoonSharpModule(Namespace = "dynamic")] public class DynamicModule { public class DynamicExprWrapper { public DynamicExpression Expr; } public static void MoonSharpInit(Table globalTable, Table stringTable) { UserData.RegisterType(InteropAccessMode.HideMembers); } [MoonSharpModuleMethod] public static DynValue eval(ScriptExecutionContext executionContext, CallbackArguments args) { try { if (args[0].Type == DataType.UserData) { UserData userData = args[0].UserData; if (userData.Object is DynamicExprWrapper) { return ((DynamicExprWrapper)userData.Object).Expr.Evaluate(executionContext); } throw ScriptRuntimeException.BadArgument(0, "dynamic.eval", "A userdata was passed, but was not a previously prepared expression."); } DynValue dynValue = args.AsType(0, "dynamic.eval", DataType.String); return executionContext.GetScript().CreateDynamicExpression(dynValue.String).Evaluate(executionContext); } catch (SyntaxErrorException ex) { throw new ScriptRuntimeException(ex); } } [MoonSharpModuleMethod] public static DynValue prepare(ScriptExecutionContext executionContext, CallbackArguments args) { try { DynValue dynValue = args.AsType(0, "dynamic.prepare", DataType.String); DynamicExpression expr = executionContext.GetScript().CreateDynamicExpression(dynValue.String); return UserData.Create(new DynamicExprWrapper { Expr = expr }); } catch (SyntaxErrorException ex) { throw new ScriptRuntimeException(ex); } } } [MoonSharpModule] public class ErrorHandlingModule { [MoonSharpModuleMethod] public static DynValue pcall(ScriptExecutionContext executionContext, CallbackArguments args) { return SetErrorHandlerStrategy("pcall", executionContext, args, null); } public static DynValue SetErrorHandlerStrategy(string funcName, ScriptExecutionContext executionContext, CallbackArguments args, DynValue handlerBeforeUnwind) { DynValue function = args[0]; DynValue[] array = new DynValue[args.Count - 1]; for (int i = 1; i < args.Count; i++) { array[i - 1] = args[i]; } if (args[0].Type == DataType.ClrFunction) { try { DynValue dynValue = args[0].Callback.Invoke(executionContext, array); if (dynValue.Type == DataType.TailCallRequest) { if (dynValue.TailCallData.Continuation != null || dynValue.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 = dynValue.TailCallData.Args, Function = dynValue.TailCallData.Function, Continuation = new CallbackFunction(pcall_continuation, funcName), ErrorHandler = new CallbackFunction(pcall_onerror, funcName), ErrorHandlerBeforeUnwind = handlerBeforeUnwind }); } if (dynValue.Type == DataType.YieldRequest) { throw new ScriptRuntimeException("the function passed to {0} cannot be called directly by {0}. wrap in a script function instead.", funcName); } return DynValue.NewTupleNested(DynValue.True, dynValue); } catch (ScriptRuntimeException ex) { executionContext.PerformMessageDecorationBeforeUnwind(handlerBeforeUnwind, ex); return DynValue.NewTupleNested(DynValue.False, DynValue.NewString(ex.DecoratedMessage)); } } if (args[0].Type != DataType.Function) { return DynValue.NewTupleNested(DynValue.False, DynValue.NewString("attempt to " + funcName + " a non-function")); } return DynValue.NewTailCallReq(new TailCallData { Args = array, Function = function, Continuation = new CallbackFunction(pcall_continuation, funcName), ErrorHandler = new CallbackFunction(pcall_onerror, funcName), ErrorHandlerBeforeUnwind = handlerBeforeUnwind }); } public static DynValue MakeReturnTuple(bool retstatus, CallbackArguments args) { DynValue[] array = new DynValue[args.Count + 1]; for (int i = 0; i < args.Count; i++) { array[i + 1] = args[i]; } array[0] = DynValue.NewBoolean(retstatus); return DynValue.NewTuple(array); } public static DynValue pcall_continuation(ScriptExecutionContext executionContext, CallbackArguments args) { return MakeReturnTuple(retstatus: true, args); } public static DynValue pcall_onerror(ScriptExecutionContext executionContext, CallbackArguments args) { return MakeReturnTuple(retstatus: false, args); } [MoonSharpModuleMethod] public static DynValue xpcall(ScriptExecutionContext executionContext, CallbackArguments args) { List list = new List(); for (int i = 0; i < args.Count; i++) { if (i != 1) { list.Add(args[i]); } } DynValue handlerBeforeUnwind = null; if (args[1].Type == DataType.Function || args[1].Type == DataType.ClrFunction) { handlerBeforeUnwind = args[1]; } else if (args[1].Type != 0) { args.AsType(1, "xpcall", DataType.Function); } return SetErrorHandlerStrategy("xpcall", executionContext, new CallbackArguments(list, isMethodCall: false), handlerBeforeUnwind); } } [MoonSharpModule(Namespace = "io")] public class IoModule { public static void MoonSharpInit(Table globalTable, Table ioTable) { UserData.RegisterType(InteropAccessMode.Default, "file"); Table table = new Table(ioTable.OwnerScript); DynValue value = DynValue.NewCallback(new CallbackFunction(__index_callback, "__index_callback")); table.Set("__index", value); ioTable.MetaTable = table; SetStandardFile(globalTable.OwnerScript, StandardFileType.StdIn, globalTable.OwnerScript.Options.Stdin); SetStandardFile(globalTable.OwnerScript, StandardFileType.StdOut, globalTable.OwnerScript.Options.Stdout); SetStandardFile(globalTable.OwnerScript, StandardFileType.StdErr, globalTable.OwnerScript.Options.Stderr); } public static DynValue __index_callback(ScriptExecutionContext executionContext, CallbackArguments args) { return args[1].CastToString() switch { "stdin" => GetStandardFile(executionContext.GetScript(), StandardFileType.StdIn), "stdout" => GetStandardFile(executionContext.GetScript(), StandardFileType.StdOut), "stderr" => GetStandardFile(executionContext.GetScript(), StandardFileType.StdErr), _ => DynValue.Nil, }; } public static DynValue GetStandardFile(Script S, StandardFileType file) { return S.Registry.Get("853BEAAF298648839E2C99D005E1DF94_STD_" + file); } public static void SetStandardFile(Script S, StandardFileType file, Stream optionsStream) { Table registry = S.Registry; optionsStream = optionsStream ?? Script.GlobalOptions.Platform.IO_GetStandardStream(file); FileUserDataBase fileUserDataBase = null; registry.Set(value: UserData.Create((file != 0) ? StandardIOFileUserDataBase.CreateOutputStream(optionsStream) : StandardIOFileUserDataBase.CreateInputStream(optionsStream)), key: "853BEAAF298648839E2C99D005E1DF94_STD_" + file); } public static FileUserDataBase GetDefaultFile(ScriptExecutionContext executionContext, StandardFileType file) { DynValue dynValue = executionContext.GetScript().Registry.Get("853BEAAF298648839E2C99D005E1DF94_" + file); if (dynValue.IsNil()) { dynValue = GetStandardFile(executionContext.GetScript(), file); } return dynValue.CheckUserDataType("getdefaultfile(" + file.ToString() + ")"); } public static void SetDefaultFile(ScriptExecutionContext executionContext, StandardFileType file, FileUserDataBase fileHandle) { SetDefaultFile(executionContext.GetScript(), file, fileHandle); } public static void SetDefaultFile(Script script, StandardFileType file, FileUserDataBase fileHandle) { script.Registry.Set("853BEAAF298648839E2C99D005E1DF94_" + file, UserData.Create(fileHandle)); } public static void SetDefaultFile(Script script, StandardFileType file, Stream stream) { if (file == StandardFileType.StdIn) { SetDefaultFile(script, file, StandardIOFileUserDataBase.CreateInputStream(stream)); } else { SetDefaultFile(script, file, StandardIOFileUserDataBase.CreateOutputStream(stream)); } } [MoonSharpModuleMethod] public static DynValue close(ScriptExecutionContext executionContext, CallbackArguments args) { return (args.AsUserData(0, "close", allowNil: true) ?? GetDefaultFile(executionContext, StandardFileType.StdOut)).close(executionContext, args); } [MoonSharpModuleMethod] public static DynValue flush(ScriptExecutionContext executionContext, CallbackArguments args) { (args.AsUserData(0, "close", allowNil: true) ?? GetDefaultFile(executionContext, StandardFileType.StdOut)).flush(); return DynValue.True; } [MoonSharpModuleMethod] public static DynValue input(ScriptExecutionContext executionContext, CallbackArguments args) { return HandleDefaultStreamSetter(executionContext, args, StandardFileType.StdIn); } [MoonSharpModuleMethod] public static DynValue output(ScriptExecutionContext executionContext, CallbackArguments args) { return HandleDefaultStreamSetter(executionContext, args, StandardFileType.StdOut); } public static DynValue HandleDefaultStreamSetter(ScriptExecutionContext executionContext, CallbackArguments args, StandardFileType defaultFiles) { if (args.Count == 0 || args[0].IsNil()) { return UserData.Create(GetDefaultFile(executionContext, defaultFiles)); } FileUserDataBase fileUserDataBase = null; if (args[0].Type == DataType.String || args[0].Type == DataType.Number) { string filename = args[0].CastToString(); fileUserDataBase = Open(executionContext, filename, GetUTF8Encoding(), (defaultFiles == StandardFileType.StdIn) ? "r" : "w"); } else { fileUserDataBase = args.AsUserData(0, (defaultFiles == StandardFileType.StdIn) ? "input" : "output"); } SetDefaultFile(executionContext, defaultFiles, fileUserDataBase); return UserData.Create(fileUserDataBase); } public static Encoding GetUTF8Encoding() { return new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); } [MoonSharpModuleMethod] public static DynValue lines(ScriptExecutionContext executionContext, CallbackArguments args) { string @string = args.AsType(0, "lines", DataType.String).String; try { List list = new List(); using (Stream stream = Script.GlobalOptions.Platform.IO_OpenFile(executionContext.GetScript(), @string, null, "r")) { using StreamReader streamReader = new StreamReader(stream); while (!streamReader.EndOfStream) { string str = streamReader.ReadLine(); list.Add(DynValue.NewString(str)); } } list.Add(DynValue.Nil); return DynValue.FromObject(executionContext.GetScript(), list.Select((DynValue s) => s)); } catch (Exception ex) { throw new ScriptRuntimeException(IoExceptionToLuaMessage(ex, @string)); } } [MoonSharpModuleMethod] public static DynValue open(ScriptExecutionContext executionContext, CallbackArguments args) { string @string = args.AsType(0, "open", DataType.String).String; DynValue dynValue = args.AsType(1, "open", DataType.String, allowNil: true); DynValue dynValue2 = args.AsType(2, "open", DataType.String, allowNil: true); string text = (dynValue.IsNil() ? "r" : dynValue.String); if (text.Replace("+", "").Replace("r", "").Replace("a", "") .Replace("w", "") .Replace("b", "") .Replace("t", "") .Length > 0) { throw ScriptRuntimeException.BadArgument(1, "open", "invalid mode"); } try { string text2 = (dynValue2.IsNil() ? null : dynValue2.String); Encoding encoding = null; bool flag = Framework.Do.StringContainsChar(text, 'b'); if (text2 == "binary") { flag = true; encoding = new BinaryEncoding(); } else if (text2 == null) { encoding = (flag ? new BinaryEncoding() : GetUTF8Encoding()); } else { if (flag) { throw new ScriptRuntimeException("Can't specify encodings other than nil or 'binary' for binary streams."); } encoding = Encoding.GetEncoding(text2); } return UserData.Create(Open(executionContext, @string, encoding, text)); } catch (Exception ex) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(IoExceptionToLuaMessage(ex, @string))); } } public static string IoExceptionToLuaMessage(Exception ex, string filename) { if (ex is FileNotFoundException) { return $"{filename}: No such file or directory"; } return ex.Message; } [MoonSharpModuleMethod] public static DynValue type(ScriptExecutionContext executionContext, CallbackArguments args) { if (args[0].Type != DataType.UserData) { return DynValue.Nil; } if (!(args[0].UserData.Object is FileUserDataBase fileUserDataBase)) { return DynValue.Nil; } if (fileUserDataBase.isopen()) { return DynValue.NewString("file"); } return DynValue.NewString("closed file"); } [MoonSharpModuleMethod] public static DynValue read(ScriptExecutionContext executionContext, CallbackArguments args) { return GetDefaultFile(executionContext, StandardFileType.StdIn).read(executionContext, args); } [MoonSharpModuleMethod] public static DynValue write(ScriptExecutionContext executionContext, CallbackArguments args) { return GetDefaultFile(executionContext, StandardFileType.StdOut).write(executionContext, args); } [MoonSharpModuleMethod] public static DynValue tmpfile(ScriptExecutionContext executionContext, CallbackArguments args) { string filename = Script.GlobalOptions.Platform.IO_OS_GetTempFilename(); return UserData.Create(Open(executionContext, filename, GetUTF8Encoding(), "w")); } public static FileUserDataBase Open(ScriptExecutionContext executionContext, string filename, Encoding encoding, string mode) { return new FileUserData(executionContext.GetScript(), filename, encoding, mode); } } [MoonSharpModule(Namespace = "json")] public class JsonModule { [MoonSharpModuleMethod] public static DynValue parse(ScriptExecutionContext executionContext, CallbackArguments args) { try { return DynValue.NewTable(JsonTableConverter.JsonToTable(args.AsType(0, "parse", DataType.String).String, executionContext.GetScript())); } catch (SyntaxErrorException ex) { throw new ScriptRuntimeException(ex); } } [MoonSharpModuleMethod] public static DynValue serialize(ScriptExecutionContext executionContext, CallbackArguments args) { try { return DynValue.NewString(args.AsType(0, "serialize", DataType.Table).Table.TableToJson()); } catch (SyntaxErrorException ex) { throw new ScriptRuntimeException(ex); } } [MoonSharpModuleMethod] public static DynValue isnull(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args[0]; return DynValue.NewBoolean(JsonNull.IsJsonNull(dynValue) || dynValue.IsNil()); } [MoonSharpModuleMethod] public static DynValue @null(ScriptExecutionContext executionContext, CallbackArguments args) { return JsonNull.Create(); } } [MoonSharpModule] public class LoadModule { [MoonSharpModuleMethod] public const string require = "\nfunction(modulename)\n\tif (package == nil) then package = { }; end\n\tif (package.loaded == nil) then package.loaded = { }; end\n\n\tlocal m = package.loaded[modulename];\n\n\tif (m ~= nil) then\n\t\treturn m;\n\tend\n\n\tlocal func = __require_clr_impl(modulename);\n\n\tlocal res = func(modulename);\n\n\tif (res == nil) then\n\t\tres = true;\n\tend\n\n\tpackage.loaded[modulename] = res;\n\n\treturn res;\nend"; public static void MoonSharpInit(Table globalTable, Table ioTable) { DynValue dynValue = globalTable.Get("package"); if (dynValue.IsNil()) { dynValue = (DynValue)(globalTable["package"] = DynValue.NewTable(globalTable.OwnerScript)); } else if (dynValue.Type != DataType.Table) { throw new InternalErrorException("'package' global variable was found and it is not a table"); } char directorySeparatorChar = Path.DirectorySeparatorChar; string str = directorySeparatorChar + "\n;\n?\n!\n-\n"; dynValue.Table.Set("config", DynValue.NewString(str)); } [MoonSharpModuleMethod] public static DynValue load(ScriptExecutionContext executionContext, CallbackArguments args) { return load_impl(executionContext, args, null); } [MoonSharpModuleMethod] public static DynValue loadsafe(ScriptExecutionContext executionContext, CallbackArguments args) { return load_impl(executionContext, args, GetSafeDefaultEnv(executionContext)); } public static DynValue load_impl(ScriptExecutionContext executionContext, CallbackArguments args, Table defaultEnv) { try { Script script = executionContext.GetScript(); DynValue dynValue = args[0]; string text = ""; if (dynValue.Type == DataType.Function) { DynValue dynValue2; while (true) { dynValue2 = executionContext.GetScript().Call(dynValue); if (dynValue2.Type != DataType.String || dynValue2.String.Length <= 0) { break; } text += dynValue2.String; } if (!dynValue2.IsNil()) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString("reader function must return a string")); } } else if (dynValue.Type == DataType.String) { text = dynValue.String; } else { args.AsType(0, "load", DataType.Function); } DynValue dynValue3 = args.AsType(1, "load", DataType.String, allowNil: true); DynValue dynValue4 = args.AsType(3, "load", DataType.Table, allowNil: true); return script.LoadString(text, (!dynValue4.IsNil()) ? dynValue4.Table : defaultEnv, (!dynValue3.IsNil()) ? dynValue3.String : "=(load)"); } catch (SyntaxErrorException ex) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(ex.DecoratedMessage ?? ex.Message)); } } [MoonSharpModuleMethod] public static DynValue loadfile(ScriptExecutionContext executionContext, CallbackArguments args) { return loadfile_impl(executionContext, args, null); } [MoonSharpModuleMethod] public static DynValue loadfilesafe(ScriptExecutionContext executionContext, CallbackArguments args) { return loadfile_impl(executionContext, args, GetSafeDefaultEnv(executionContext)); } public static DynValue loadfile_impl(ScriptExecutionContext executionContext, CallbackArguments args, Table defaultEnv) { try { Script script = executionContext.GetScript(); DynValue dynValue = args.AsType(0, "loadfile", DataType.String); DynValue dynValue2 = args.AsType(2, "loadfile", DataType.Table, allowNil: true); return script.LoadFile(dynValue.String, dynValue2.IsNil() ? defaultEnv : dynValue2.Table); } catch (SyntaxErrorException ex) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(ex.DecoratedMessage ?? ex.Message)); } } public static Table GetSafeDefaultEnv(ScriptExecutionContext executionContext) { return executionContext.CurrentGlobalEnv ?? throw new ScriptRuntimeException("current environment cannot be backtracked."); } [MoonSharpModuleMethod] public static DynValue dofile(ScriptExecutionContext executionContext, CallbackArguments args) { try { Script script = executionContext.GetScript(); DynValue dynValue = args.AsType(0, "dofile", DataType.String); return DynValue.NewTailCallReq(script.LoadFile(dynValue.String)); } catch (SyntaxErrorException ex) { throw new ScriptRuntimeException(ex); } } [MoonSharpModuleMethod] public static DynValue __require_clr_impl(ScriptExecutionContext executionContext, CallbackArguments args) { Script script = executionContext.GetScript(); DynValue dynValue = args.AsType(0, "__require_clr_impl", DataType.String); return script.RequireModule(dynValue.String); } } [MoonSharpModule(Namespace = "bit32")] public class Bit32Module { public static readonly uint[] MASKS = new uint[32] { 1u, 3u, 7u, 15u, 31u, 63u, 127u, 255u, 511u, 1023u, 2047u, 4095u, 8191u, 16383u, 32767u, 65535u, 131071u, 262143u, 524287u, 1048575u, 2097151u, 4194303u, 8388607u, 16777215u, 33554431u, 67108863u, 134217727u, 268435455u, 536870911u, 1073741823u, 2147483647u, 4294967295u }; public static uint ToUInt32(DynValue v) { return (uint)Math.IEEERemainder(v.Number, Math.Pow(2.0, 32.0)); } public static int ToInt32(DynValue v) { return (int)Math.IEEERemainder(v.Number, Math.Pow(2.0, 32.0)); } public static uint NBitMask(int bits) { if (bits <= 0) { return 0u; } if (bits >= 32) { return MASKS[31]; } return MASKS[bits - 1]; } public static uint Bitwise(string funcName, CallbackArguments args, Func accumFunc) { uint num = ToUInt32(args.AsType(0, funcName, DataType.Number)); for (int i = 1; i < args.Count; i++) { uint arg = ToUInt32(args.AsType(i, funcName, DataType.Number)); num = accumFunc(num, arg); } return num; } [MoonSharpModuleMethod] public static DynValue extract(ScriptExecutionContext executionContext, CallbackArguments args) { uint num = ToUInt32(args.AsType(0, "extract", DataType.Number)); DynValue dynValue = args.AsType(1, "extract", DataType.Number); DynValue dynValue2 = args.AsType(2, "extract", DataType.Number, allowNil: true); int num2 = (int)dynValue.Number; int num3 = (dynValue2.IsNilOrNan() ? 1 : ((int)dynValue2.Number)); ValidatePosWidth("extract", 2, num2, num3); return DynValue.NewNumber((num >> num2) & NBitMask(num3)); } [MoonSharpModuleMethod] public static DynValue replace(ScriptExecutionContext executionContext, CallbackArguments args) { uint num = ToUInt32(args.AsType(0, "replace", DataType.Number)); uint num2 = ToUInt32(args.AsType(1, "replace", DataType.Number)); DynValue dynValue = args.AsType(2, "replace", DataType.Number); DynValue dynValue2 = args.AsType(3, "replace", DataType.Number, allowNil: true); int num3 = (int)dynValue.Number; int num4 = (dynValue2.IsNilOrNan() ? 1 : ((int)dynValue2.Number)); ValidatePosWidth("replace", 3, num3, num4); uint num5 = NBitMask(num4) << num3; uint num6 = num & ~num5; num2 &= num5; return DynValue.NewNumber(num6 | num2); } public static void ValidatePosWidth(string func, int argPos, int pos, int width) { if (pos > 31 || pos + width > 31) { throw new ScriptRuntimeException("trying to access non-existent bits"); } if (pos < 0) { throw new ScriptRuntimeException("bad argument #{1} to '{0}' (field cannot be negative)", func, argPos); } if (width <= 0) { throw new ScriptRuntimeException("bad argument #{1} to '{0}' (width must be positive)", func, argPos + 1); } } [MoonSharpModuleMethod] public static DynValue arshift(ScriptExecutionContext executionContext, CallbackArguments args) { int num = ToInt32(args.AsType(0, "arshift", DataType.Number)); int num2 = (int)args.AsType(1, "arshift", DataType.Number).Number; num = ((num2 >= 0) ? (num >> num2) : (num << -num2)); return DynValue.NewNumber(num); } [MoonSharpModuleMethod] public static DynValue rshift(ScriptExecutionContext executionContext, CallbackArguments args) { uint num = ToUInt32(args.AsType(0, "rshift", DataType.Number)); int num2 = (int)args.AsType(1, "rshift", DataType.Number).Number; num = ((num2 >= 0) ? (num >> num2) : (num << -num2)); return DynValue.NewNumber(num); } [MoonSharpModuleMethod] public static DynValue lshift(ScriptExecutionContext executionContext, CallbackArguments args) { uint num = ToUInt32(args.AsType(0, "lshift", DataType.Number)); int num2 = (int)args.AsType(1, "lshift", DataType.Number).Number; num = ((num2 >= 0) ? (num << num2) : (num >> -num2)); return DynValue.NewNumber(num); } [MoonSharpModuleMethod] public static DynValue band(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewNumber(Bitwise("band", args, (uint x, uint y) => x & y)); } [MoonSharpModuleMethod] public static DynValue btest(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewBoolean(Bitwise("btest", args, (uint x, uint y) => x & y) != 0); } [MoonSharpModuleMethod] public static DynValue bor(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewNumber(Bitwise("bor", args, (uint x, uint y) => x | y)); } [MoonSharpModuleMethod] public static DynValue bnot(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewNumber(~ToUInt32(args.AsType(0, "bnot", DataType.Number))); } [MoonSharpModuleMethod] public static DynValue bxor(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewNumber(Bitwise("bxor", args, (uint x, uint y) => x ^ y)); } [MoonSharpModuleMethod] public static DynValue lrotate(ScriptExecutionContext executionContext, CallbackArguments args) { uint num = ToUInt32(args.AsType(0, "lrotate", DataType.Number)); int num2 = (int)args.AsType(1, "lrotate", DataType.Number).Number % 32; num = ((num2 >= 0) ? ((num << num2) | (num >> 32 - num2)) : ((num >> -num2) | (num << 32 + num2))); return DynValue.NewNumber(num); } [MoonSharpModuleMethod] public static DynValue rrotate(ScriptExecutionContext executionContext, CallbackArguments args) { uint num = ToUInt32(args.AsType(0, "rrotate", DataType.Number)); int num2 = (int)args.AsType(1, "rrotate", DataType.Number).Number % 32; num = ((num2 >= 0) ? ((num >> num2) | (num << 32 - num2)) : ((num << -num2) | (num >> 32 + num2))); return DynValue.NewNumber(num); } } [MoonSharpModule(Namespace = "math")] public class MathModule { [MoonSharpModuleConstant] public const double pi = Math.PI; [MoonSharpModuleConstant] public const double huge = double.MaxValue; public static Random GetRandom(Script s) { return (s.Registry.Get("F61E3AA7247D4D1EB7A45430B0C8C9BB_MATH_RANDOM").UserData.Object as AnonWrapper).Value; } public static void SetRandom(Script s, Random random) { DynValue value = UserData.Create(new AnonWrapper(random)); s.Registry.Set("F61E3AA7247D4D1EB7A45430B0C8C9BB_MATH_RANDOM", value); } public static void MoonSharpInit(Table globalTable, Table ioTable) { SetRandom(globalTable.OwnerScript, new Random()); } public static DynValue exec1(CallbackArguments args, string funcName, Func func) { DynValue dynValue = args.AsType(0, funcName, DataType.Number); return DynValue.NewNumber(func(dynValue.Number)); } public static DynValue exec2(CallbackArguments args, string funcName, Func func) { DynValue dynValue = args.AsType(0, funcName, DataType.Number); DynValue dynValue2 = args.AsType(1, funcName, DataType.Number); return DynValue.NewNumber(func(dynValue.Number, dynValue2.Number)); } public static DynValue exec2n(CallbackArguments args, string funcName, double defVal, Func func) { DynValue dynValue = args.AsType(0, funcName, DataType.Number); DynValue dynValue2 = args.AsType(1, funcName, DataType.Number, allowNil: true); return DynValue.NewNumber(func(dynValue.Number, dynValue2.IsNil() ? defVal : dynValue2.Number)); } public static DynValue execaccum(CallbackArguments args, string funcName, Func func) { double num = double.NaN; if (args.Count == 0) { throw new ScriptRuntimeException("bad argument #1 to '{0}' (number expected, got no value)", funcName); } for (int i = 0; i < args.Count; i++) { DynValue dynValue = args.AsType(i, funcName, DataType.Number); num = ((i != 0) ? func(num, dynValue.Number) : dynValue.Number); } return DynValue.NewNumber(num); } [MoonSharpModuleMethod] public static DynValue abs(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "abs", (double d) => Math.Abs(d)); } [MoonSharpModuleMethod] public static DynValue acos(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "acos", (double d) => Math.Acos(d)); } [MoonSharpModuleMethod] public static DynValue asin(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "asin", (double d) => Math.Asin(d)); } [MoonSharpModuleMethod] public static DynValue atan(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "atan", (double d) => Math.Atan(d)); } [MoonSharpModuleMethod] public static DynValue atan2(ScriptExecutionContext executionContext, CallbackArguments args) { return exec2(args, "atan2", (double d1, double d2) => Math.Atan2(d1, d2)); } [MoonSharpModuleMethod] public static DynValue ceil(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "ceil", (double d) => Math.Ceiling(d)); } [MoonSharpModuleMethod] public static DynValue cos(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "cos", (double d) => Math.Cos(d)); } [MoonSharpModuleMethod] public static DynValue cosh(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "cosh", (double d) => Math.Cosh(d)); } [MoonSharpModuleMethod] public static DynValue deg(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "deg", (double d) => d * 180.0 / Math.PI); } [MoonSharpModuleMethod] public static DynValue exp(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "exp", (double d) => Math.Exp(d)); } [MoonSharpModuleMethod] public static DynValue floor(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "floor", (double d) => Math.Floor(d)); } [MoonSharpModuleMethod] public static DynValue fmod(ScriptExecutionContext executionContext, CallbackArguments args) { return exec2(args, "fmod", (double d1, double d2) => Math.IEEERemainder(d1, d2)); } [MoonSharpModuleMethod] public static DynValue frexp(ScriptExecutionContext executionContext, CallbackArguments args) { long num = BitConverter.DoubleToInt64Bits(args.AsType(0, "frexp", DataType.Number).Number); bool flag = num < 0; int num2 = (int)((num >> 52) & 0x7FF); long num3 = num & 0xFFFFFFFFFFFFFL; if (num2 == 0) { num2++; } else { num3 |= 0x10000000000000L; } num2 -= 1075; if (num3 == 0L) { return DynValue.NewTuple(DynValue.NewNumber(0.0), DynValue.NewNumber(0.0)); } while ((num3 & 1) == 0L) { num3 >>= 1; num2++; } double num4 = num3; double num5 = num2; while (num4 >= 1.0) { num4 /= 2.0; num5 += 1.0; } if (flag) { num4 = 0.0 - num4; } return DynValue.NewTuple(DynValue.NewNumber(num4), DynValue.NewNumber(num5)); } [MoonSharpModuleMethod] public static DynValue ldexp(ScriptExecutionContext executionContext, CallbackArguments args) { return exec2(args, "ldexp", (double d1, double d2) => d1 * Math.Pow(2.0, d2)); } [MoonSharpModuleMethod] public static DynValue log(ScriptExecutionContext executionContext, CallbackArguments args) { return exec2n(args, "log", Math.E, (double d1, double d2) => Math.Log(d1, d2)); } [MoonSharpModuleMethod] public static DynValue max(ScriptExecutionContext executionContext, CallbackArguments args) { return execaccum(args, "max", (double d1, double d2) => Math.Max(d1, d2)); } [MoonSharpModuleMethod] public static DynValue min(ScriptExecutionContext executionContext, CallbackArguments args) { return execaccum(args, "min", (double d1, double d2) => Math.Min(d1, d2)); } [MoonSharpModuleMethod] public static DynValue modf(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "modf", DataType.Number); return DynValue.NewTuple(DynValue.NewNumber(Math.Floor(dynValue.Number)), DynValue.NewNumber(dynValue.Number - Math.Floor(dynValue.Number))); } [MoonSharpModuleMethod] public static DynValue pow(ScriptExecutionContext executionContext, CallbackArguments args) { return exec2(args, "pow", (double d1, double d2) => Math.Pow(d1, d2)); } [MoonSharpModuleMethod] public static DynValue rad(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "rad", (double d) => d * Math.PI / 180.0); } [MoonSharpModuleMethod] public static DynValue random(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "random", DataType.Number, allowNil: true); DynValue dynValue2 = args.AsType(1, "random", DataType.Number, allowNil: true); Random random = GetRandom(executionContext.GetScript()); double num; if (dynValue.IsNil() && dynValue2.IsNil()) { num = random.NextDouble(); } else { int num2 = (dynValue2.IsNil() ? 1 : ((int)dynValue2.Number)); int num3 = (int)dynValue.Number; num = ((num2 >= num3) ? ((double)random.Next(num3, num2 + 1)) : ((double)random.Next(num2, num3 + 1))); } return DynValue.NewNumber(num); } [MoonSharpModuleMethod] public static DynValue randomseed(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "randomseed", DataType.Number); SetRandom(executionContext.GetScript(), new Random((int)dynValue.Number)); return DynValue.Nil; } [MoonSharpModuleMethod] public static DynValue sin(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "sin", (double d) => Math.Sin(d)); } [MoonSharpModuleMethod] public static DynValue sinh(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "sinh", (double d) => Math.Sinh(d)); } [MoonSharpModuleMethod] public static DynValue sqrt(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "sqrt", (double d) => Math.Sqrt(d)); } [MoonSharpModuleMethod] public static DynValue tan(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "tan", (double d) => Math.Tan(d)); } [MoonSharpModuleMethod] public static DynValue tanh(ScriptExecutionContext executionContext, CallbackArguments args) { return exec1(args, "tanh", (double d) => Math.Tanh(d)); } } [MoonSharpModule] public class MetaTableModule { [MoonSharpModuleMethod] public static DynValue setmetatable(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "setmetatable", DataType.Table); DynValue dynValue2 = args.AsType(1, "setmetatable", DataType.Table, allowNil: true); if (executionContext.GetMetamethod(dynValue, "__metatable") != null) { throw new ScriptRuntimeException("cannot change a protected metatable"); } dynValue.Table.MetaTable = dynValue2.Table; return dynValue; } [MoonSharpModuleMethod] public static DynValue getmetatable(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args[0]; Table table = null; if (dynValue.Type.CanHaveTypeMetatables()) { table = executionContext.GetScript().GetTypeMetatable(dynValue.Type); } if (dynValue.Type == DataType.Table) { table = dynValue.Table.MetaTable; } if (table == null) { return DynValue.Nil; } if (table.RawGet("__metatable") != null) { return table.Get("__metatable"); } return DynValue.NewTable(table); } [MoonSharpModuleMethod] public static DynValue rawget(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "rawget", DataType.Table); DynValue key = args[1]; return dynValue.Table.Get(key); } [MoonSharpModuleMethod] public static DynValue rawset(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "rawset", DataType.Table); DynValue key = args[1]; dynValue.Table.Set(key, args[2]); return dynValue; } [MoonSharpModuleMethod] public static DynValue rawequal(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args[0]; DynValue obj = args[1]; return DynValue.NewBoolean(dynValue.Equals(obj)); } [MoonSharpModuleMethod] public static DynValue rawlen(ScriptExecutionContext executionContext, CallbackArguments args) { if (args[0].Type != DataType.String && args[0].Type != DataType.Table) { throw ScriptRuntimeException.BadArgument(0, "rawlen", "table or string", args[0].Type.ToErrorTypeString(), allowNil: false); } return args[0].GetLength(); } } [MoonSharpModule(Namespace = "os")] public class OsSystemModule { [MoonSharpModuleMethod] public static DynValue execute(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "execute", DataType.String, allowNil: true); if (dynValue.IsNil()) { return DynValue.NewBoolean(v: true); } try { int num = Script.GlobalOptions.Platform.OS_Execute(dynValue.String); return DynValue.NewTuple(DynValue.Nil, DynValue.NewString("exit"), DynValue.NewNumber(num)); } catch (Exception) { return DynValue.Nil; } } [MoonSharpModuleMethod] public static DynValue exit(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "exit", DataType.Number, allowNil: true); int exitCode = 0; if (dynValue.IsNotNil()) { exitCode = (int)dynValue.Number; } Script.GlobalOptions.Platform.OS_ExitFast(exitCode); throw new InvalidOperationException("Unreachable code.. reached."); } [MoonSharpModuleMethod] public static DynValue getenv(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "getenv", DataType.String); string environmentVariable = Script.GlobalOptions.Platform.GetEnvironmentVariable(dynValue.String); if (environmentVariable == null) { return DynValue.Nil; } return DynValue.NewString(environmentVariable); } [MoonSharpModuleMethod] public static DynValue remove(ScriptExecutionContext executionContext, CallbackArguments args) { string @string = args.AsType(0, "remove", DataType.String).String; try { if (Script.GlobalOptions.Platform.OS_FileExists(@string)) { Script.GlobalOptions.Platform.OS_FileDelete(@string); return DynValue.True; } return DynValue.NewTuple(DynValue.Nil, DynValue.NewString("{0}: No such file or directory.", @string), DynValue.NewNumber(-1.0)); } catch (Exception ex) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(ex.Message), DynValue.NewNumber(-1.0)); } } [MoonSharpModuleMethod] public static DynValue rename(ScriptExecutionContext executionContext, CallbackArguments args) { string @string = args.AsType(0, "rename", DataType.String).String; string string2 = args.AsType(1, "rename", DataType.String).String; try { if (!Script.GlobalOptions.Platform.OS_FileExists(@string)) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString("{0}: No such file or directory.", @string), DynValue.NewNumber(-1.0)); } Script.GlobalOptions.Platform.OS_FileMove(@string, string2); return DynValue.True; } catch (Exception ex) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(ex.Message), DynValue.NewNumber(-1.0)); } } [MoonSharpModuleMethod] public static DynValue setlocale(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewString("n/a"); } [MoonSharpModuleMethod] public static DynValue tmpname(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewString(Script.GlobalOptions.Platform.IO_OS_GetTempFilename()); } } [MoonSharpModule(Namespace = "os")] public class OsTimeModule { public static DateTime Time0 = DateTime.UtcNow; public static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public static DynValue GetUnixTime(DateTime dateTime, DateTime? epoch = null) { double totalSeconds = (dateTime - (epoch ?? Epoch)).TotalSeconds; if (totalSeconds < 0.0) { return DynValue.Nil; } return DynValue.NewNumber(totalSeconds); } public static DateTime FromUnixTime(double unixtime) { TimeSpan timeSpan = TimeSpan.FromSeconds(unixtime); return Epoch + timeSpan; } [MoonSharpModuleMethod] public static DynValue clock(ScriptExecutionContext executionContext, CallbackArguments args) { return GetUnixTime(DateTime.UtcNow, Time0); } [MoonSharpModuleMethod] public static DynValue difftime(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "difftime", DataType.Number); DynValue dynValue2 = args.AsType(1, "difftime", DataType.Number, allowNil: true); if (dynValue2.IsNil()) { return DynValue.NewNumber(dynValue.Number); } return DynValue.NewNumber(dynValue.Number - dynValue2.Number); } [MoonSharpModuleMethod] public static DynValue time(ScriptExecutionContext executionContext, CallbackArguments args) { DateTime dateTime = DateTime.UtcNow; if (args.Count > 0) { DynValue dynValue = args.AsType(0, "time", DataType.Table, allowNil: true); if (dynValue.Type == DataType.Table) { dateTime = ParseTimeTable(dynValue.Table); } } return GetUnixTime(dateTime); } public static DateTime ParseTimeTable(Table t) { int second = GetTimeTableField(t, "sec") ?? 0; int minute = GetTimeTableField(t, "min") ?? 0; int hour = GetTimeTableField(t, "hour") ?? 12; int? timeTableField = GetTimeTableField(t, "day"); int? timeTableField2 = GetTimeTableField(t, "month"); int? timeTableField3 = GetTimeTableField(t, "year"); if (!timeTableField.HasValue) { throw new ScriptRuntimeException("field 'day' missing in date table"); } if (!timeTableField2.HasValue) { throw new ScriptRuntimeException("field 'month' missing in date table"); } if (!timeTableField3.HasValue) { throw new ScriptRuntimeException("field 'year' missing in date table"); } return new DateTime(timeTableField3.Value, timeTableField2.Value, timeTableField.Value, hour, minute, second); } public static int? GetTimeTableField(Table t, string key) { double? num = t.Get(key).CastToNumber(); if (num.HasValue) { return (int)num.Value; } return null; } [MoonSharpModuleMethod] public static DynValue date(ScriptExecutionContext executionContext, CallbackArguments args) { DateTime dateTime = DateTime.UtcNow; DynValue dynValue = args.AsType(0, "date", DataType.String, allowNil: true); DynValue dynValue2 = args.AsType(1, "date", DataType.Number, allowNil: true); string text = (dynValue.IsNil() ? "%c" : dynValue.String); if (dynValue2.IsNotNil()) { dateTime = FromUnixTime(dynValue2.Number); } bool v = false; if (text.StartsWith("!")) { text = text.Substring(1); } else { try { dateTime = TimeZoneInfo.ConvertTimeFromUtc(dateTime, TimeZoneInfo.Local); v = dateTime.IsDaylightSavingTime(); } catch (TimeZoneNotFoundException) { } } if (text == "*t") { Table table = new Table(executionContext.GetScript()); table.Set("year", DynValue.NewNumber(dateTime.Year)); table.Set("month", DynValue.NewNumber(dateTime.Month)); table.Set("day", DynValue.NewNumber(dateTime.Day)); table.Set("hour", DynValue.NewNumber(dateTime.Hour)); table.Set("min", DynValue.NewNumber(dateTime.Minute)); table.Set("sec", DynValue.NewNumber(dateTime.Second)); table.Set("wday", DynValue.NewNumber((double)(dateTime.DayOfWeek + 1))); table.Set("yday", DynValue.NewNumber(dateTime.DayOfYear)); table.Set("isdst", DynValue.NewBoolean(v)); return DynValue.NewTable(table); } return DynValue.NewString(StrFTime(text, dateTime)); } public static string StrFTime(string format, DateTime d) { Dictionary dictionary = new Dictionary { { 'a', "ddd" }, { 'A', "dddd" }, { 'b', "MMM" }, { 'B', "MMMM" }, { 'c', "f" }, { 'd', "dd" }, { 'D', "MM/dd/yy" }, { 'F', "yyyy-MM-dd" }, { 'g', "yy" }, { 'G', "yyyy" }, { 'h', "MMM" }, { 'H', "HH" }, { 'I', "hh" }, { 'm', "MM" }, { 'M', "mm" }, { 'p', "tt" }, { 'r', "h:mm:ss tt" }, { 'R', "HH:mm" }, { 'S', "ss" }, { 'T', "HH:mm:ss" }, { 'y', "yy" }, { 'Y', "yyyy" }, { 'x', "d" }, { 'X', "T" }, { 'z', "zzz" }, { 'Z', "zzz" } }; StringBuilder stringBuilder = new StringBuilder(); bool flag = false; foreach (char c in format) { if (c == '%') { if (flag) { stringBuilder.Append('%'); flag = false; } else { flag = true; } } else if (!flag) { stringBuilder.Append(c); } else { if (c == 'O' || c == 'E') { continue; } flag = false; if (dictionary.ContainsKey(c)) { stringBuilder.Append(d.ToString(dictionary[c])); continue; } switch (c) { case 'e': { string text = d.ToString("%d"); if (text.Length < 2) { text = " " + text; } stringBuilder.Append(text); break; } case 'n': stringBuilder.Append('\n'); break; case 't': stringBuilder.Append('\t'); break; case 'C': stringBuilder.Append(d.Year / 100); break; case 'j': stringBuilder.Append(d.DayOfYear.ToString("000")); break; case 'u': { int num = (int)d.DayOfWeek; if (num == 0) { num = 7; } stringBuilder.Append(num); break; } case 'w': { int dayOfWeek = (int)d.DayOfWeek; stringBuilder.Append(dayOfWeek); break; } case 'U': stringBuilder.Append("??"); break; case 'V': stringBuilder.Append("??"); break; case 'W': stringBuilder.Append("??"); break; default: throw new ScriptRuntimeException("bad argument #1 to 'date' (invalid conversion specifier '{0}')", format); } } } return stringBuilder.ToString(); } } [MoonSharpModule(Namespace = "string")] public class StringModule { public const string BASE64_DUMP_HEADER = "MoonSharp_dump_b64::"; public static void MoonSharpInit(Table globalTable, Table stringTable) { Table table = new Table(globalTable.OwnerScript); table.Set("__index", DynValue.NewTable(stringTable)); globalTable.OwnerScript.SetTypeMetatable(DataType.String, table); } [MoonSharpModuleMethod] public static DynValue dump(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue function = args.AsType(0, "dump", DataType.Function); try { byte[] inArray; using (MemoryStream memoryStream = new MemoryStream()) { executionContext.GetScript().Dump(function, memoryStream); memoryStream.Seek(0L, SeekOrigin.Begin); inArray = memoryStream.ToArray(); } string text = Convert.ToBase64String(inArray); return DynValue.NewString("MoonSharp_dump_b64::" + text); } catch (Exception ex) { throw new ScriptRuntimeException(ex.Message); } } [MoonSharpModuleMethod] public static DynValue @char(ScriptExecutionContext executionContext, CallbackArguments args) { StringBuilder stringBuilder = new StringBuilder(args.Count); for (int i = 0; i < args.Count; i++) { DynValue dynValue = args[i]; double num = 0.0; if (dynValue.Type == DataType.String) { double? num2 = dynValue.CastToNumber(); if (!num2.HasValue) { args.AsType(i, "char", DataType.Number); } else { num = num2.Value; } } else { args.AsType(i, "char", DataType.Number); num = dynValue.Number; } stringBuilder.Append((char)num); } return DynValue.NewString(stringBuilder.ToString()); } [MoonSharpModuleMethod] public static DynValue @byte(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue vs = args.AsType(0, "byte", DataType.String); DynValue vi = args.AsType(1, "byte", DataType.Number, allowNil: true); DynValue vj = args.AsType(2, "byte", DataType.Number, allowNil: true); return PerformByteLike(vs, vi, vj, (int i) => Unicode2Ascii(i)); } [MoonSharpModuleMethod] public static DynValue unicode(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue vs = args.AsType(0, "unicode", DataType.String); DynValue vi = args.AsType(1, "unicode", DataType.Number, allowNil: true); DynValue vj = args.AsType(2, "unicode", DataType.Number, allowNil: true); return PerformByteLike(vs, vi, vj, (int i) => i); } public static int Unicode2Ascii(int i) { if (i >= 0 && i < 255) { return i; } return 63; } public static DynValue PerformByteLike(DynValue vs, DynValue vi, DynValue vj, Func filter) { string text = StringRange.FromLuaRange(vi, vj).ApplyToString(vs.String); int length = text.Length; DynValue[] array = new DynValue[length]; for (int i = 0; i < length; i++) { array[i] = DynValue.NewNumber(filter(text[i])); } return DynValue.NewTuple(array); } public static int? AdjustIndex(string s, DynValue vi, int defval) { if (vi.IsNil()) { return defval; } int num = (int)Math.Round(vi.Number, 0); if (num == 0) { return null; } if (num > 0) { return num - 1; } return s.Length - num; } [MoonSharpModuleMethod] public static DynValue len(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewNumber(args.AsType(0, "len", DataType.String).String.Length); } [MoonSharpModuleMethod] public static DynValue match(ScriptExecutionContext executionContext, CallbackArguments args) { return executionContext.EmulateClassicCall(args, "match", KopiLua_StringLib.str_match); } [MoonSharpModuleMethod] public static DynValue gmatch(ScriptExecutionContext executionContext, CallbackArguments args) { return executionContext.EmulateClassicCall(args, "gmatch", KopiLua_StringLib.str_gmatch); } [MoonSharpModuleMethod] public static DynValue gsub(ScriptExecutionContext executionContext, CallbackArguments args) { return executionContext.EmulateClassicCall(args, "gsub", KopiLua_StringLib.str_gsub); } [MoonSharpModuleMethod] public static DynValue find(ScriptExecutionContext executionContext, CallbackArguments args) { return executionContext.EmulateClassicCall(args, "find", KopiLua_StringLib.str_find); } [MoonSharpModuleMethod] public static DynValue lower(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewString(args.AsType(0, "lower", DataType.String).String.ToLower()); } [MoonSharpModuleMethod] public static DynValue upper(ScriptExecutionContext executionContext, CallbackArguments args) { return DynValue.NewString(args.AsType(0, "upper", DataType.String).String.ToUpper()); } [MoonSharpModuleMethod] public static DynValue rep(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "rep", DataType.String); DynValue dynValue2 = args.AsType(1, "rep", DataType.Number); DynValue dynValue3 = args.AsType(2, "rep", DataType.String, allowNil: true); if (string.IsNullOrEmpty(dynValue.String) || dynValue2.Number < 1.0) { return DynValue.NewString(""); } string text = (dynValue3.IsNotNil() ? dynValue3.String : null); int num = (int)dynValue2.Number; StringBuilder stringBuilder = new StringBuilder(dynValue.String.Length * num); for (int i = 0; i < num; i++) { if (i != 0 && text != null) { stringBuilder.Append(text); } stringBuilder.Append(dynValue.String); } return DynValue.NewString(stringBuilder.ToString()); } [MoonSharpModuleMethod] public static DynValue format(ScriptExecutionContext executionContext, CallbackArguments args) { return executionContext.EmulateClassicCall(args, "format", KopiLua_StringLib.str_format); } [MoonSharpModuleMethod] public static DynValue reverse(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "reverse", DataType.String); if (string.IsNullOrEmpty(dynValue.String)) { return DynValue.NewString(""); } char[] array = dynValue.String.ToCharArray(); Array.Reverse((Array)array); return DynValue.NewString(new string(array)); } [MoonSharpModuleMethod] public static DynValue sub(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "sub", DataType.String); DynValue start = args.AsType(1, "sub", DataType.Number, allowNil: true); DynValue end = args.AsType(2, "sub", DataType.Number, allowNil: true); return DynValue.NewString(StringRange.FromLuaRange(start, end, -1).ApplyToString(dynValue.String)); } [MoonSharpModuleMethod] public static DynValue startsWith(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "startsWith", DataType.String, allowNil: true); DynValue dynValue2 = args.AsType(1, "startsWith", DataType.String, allowNil: true); if (dynValue.IsNil() || dynValue2.IsNil()) { return DynValue.False; } return DynValue.NewBoolean(dynValue.String.StartsWith(dynValue2.String)); } [MoonSharpModuleMethod] public static DynValue endsWith(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "endsWith", DataType.String, allowNil: true); DynValue dynValue2 = args.AsType(1, "endsWith", DataType.String, allowNil: true); if (dynValue.IsNil() || dynValue2.IsNil()) { return DynValue.False; } return DynValue.NewBoolean(dynValue.String.EndsWith(dynValue2.String)); } [MoonSharpModuleMethod] public static DynValue contains(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "contains", DataType.String, allowNil: true); DynValue dynValue2 = args.AsType(1, "contains", DataType.String, allowNil: true); if (dynValue.IsNil() || dynValue2.IsNil()) { return DynValue.False; } return DynValue.NewBoolean(dynValue.String.Contains(dynValue2.String)); } } [MoonSharpModule] public class TableIteratorsModule { [MoonSharpModuleMethod] public static DynValue ipairs(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args[0]; return executionContext.GetMetamethodTailCall(dynValue, "__ipairs", args.GetArray()) ?? DynValue.NewTuple(DynValue.NewCallback(__next_i), dynValue, DynValue.NewNumber(0.0)); } [MoonSharpModuleMethod] public static DynValue pairs(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args[0]; return executionContext.GetMetamethodTailCall(dynValue, "__pairs", args.GetArray()) ?? DynValue.NewTuple(DynValue.NewCallback(next), dynValue); } [MoonSharpModuleMethod] public static DynValue next(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "next", DataType.Table); DynValue v = args[1]; TablePair? tablePair = dynValue.Table.NextKey(v); if (tablePair.HasValue) { return DynValue.NewTuple(tablePair.Value.Key, tablePair.Value.Value); } throw new ScriptRuntimeException("invalid key to 'next'"); } public static DynValue __next_i(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "!!next_i!!", DataType.Table); int num = (int)args.AsType(1, "!!next_i!!", DataType.Number).Number + 1; DynValue dynValue2 = dynValue.Table.Get(num); if (dynValue2.Type != 0) { return DynValue.NewTuple(DynValue.NewNumber(num), dynValue2); } return DynValue.Nil; } } [MoonSharpModule(Namespace = "table")] public class TableModule { [MoonSharpModuleMethod] public static DynValue unpack(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "unpack", DataType.Table); DynValue dynValue2 = args.AsType(1, "unpack", DataType.Number, allowNil: true); DynValue dynValue3 = args.AsType(2, "unpack", DataType.Number, allowNil: true); int num = (dynValue2.IsNil() ? 1 : ((int)dynValue2.Number)); int num2 = (dynValue3.IsNil() ? GetTableLength(executionContext, dynValue) : ((int)dynValue3.Number)); Table table = dynValue.Table; DynValue[] array = new DynValue[num2 - num + 1]; int num3 = 0; for (int i = num; i <= num2; i++) { array[num3++] = table.Get(i); } return DynValue.NewTuple(array); } [MoonSharpModuleMethod] public static DynValue pack(ScriptExecutionContext executionContext, CallbackArguments args) { Table table = new Table(executionContext.GetScript()); DynValue result = DynValue.NewTable(table); for (int i = 0; i < args.Count; i++) { table.Set(i + 1, args[i]); } table.Set("n", DynValue.NewNumber(args.Count)); return result; } [MoonSharpModuleMethod] public static DynValue sort(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "sort", DataType.Table); DynValue lt = args[1]; if (lt.Type != DataType.Function && lt.Type != DataType.ClrFunction && lt.IsNotNil()) { args.AsType(1, "sort", DataType.Function, allowNil: true); } int tableLength = GetTableLength(executionContext, dynValue); List list = new List(); for (int i = 1; i <= tableLength; i++) { list.Add(dynValue.Table.Get(i)); } try { list.Sort((DynValue a, DynValue b) => SortComparer(executionContext, a, b, lt)); } catch (InvalidOperationException ex) { if (ex.InnerException is ScriptRuntimeException) { throw ex.InnerException; } } for (int j = 0; j < list.Count; j++) { dynValue.Table.Set(j + 1, list[j]); } return dynValue; } public static int SortComparer(ScriptExecutionContext executionContext, DynValue a, DynValue b, DynValue lt) { if (lt == null || lt.IsNil()) { lt = executionContext.GetBinaryMetamethod(a, b, "__lt"); if (lt == null || lt.IsNil()) { if (a.Type == DataType.Number && b.Type == DataType.Number) { return a.Number.CompareTo(b.Number); } if (a.Type == DataType.String && b.Type == DataType.String) { return a.String.CompareTo(b.String); } throw ScriptRuntimeException.CompareInvalidType(a, b); } return LuaComparerToClrComparer(executionContext.GetScript().Call(lt, a, b), executionContext.GetScript().Call(lt, b, a)); } return LuaComparerToClrComparer(executionContext.GetScript().Call(lt, a, b), executionContext.GetScript().Call(lt, b, a)); } public static int LuaComparerToClrComparer(DynValue dynValue1, DynValue dynValue2) { bool flag = dynValue1.CastToBool(); bool flag2 = dynValue2.CastToBool(); if (flag && !flag2) { return -1; } if (flag2 && !flag) { return 1; } if (flag || flag2) { throw new ScriptRuntimeException("invalid order function for sorting"); } return 0; } [MoonSharpModuleMethod] public static DynValue insert(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "table.insert", DataType.Table); DynValue dynValue2 = args[1]; DynValue dynValue3 = args[2]; if (args.Count > 3) { throw new ScriptRuntimeException("wrong number of arguments to 'insert'"); } int tableLength = GetTableLength(executionContext, dynValue); Table table = dynValue.Table; if (dynValue3.IsNil()) { dynValue3 = dynValue2; dynValue2 = DynValue.NewNumber(tableLength + 1); } if (dynValue2.Type != DataType.Number) { throw ScriptRuntimeException.BadArgument(1, "table.insert", DataType.Number, dynValue2.Type, allowNil: false); } int num = (int)dynValue2.Number; if (num > tableLength + 1 || num < 1) { throw new ScriptRuntimeException("bad argument #2 to 'insert' (position out of bounds)"); } for (int num2 = tableLength; num2 >= num; num2--) { table.Set(num2 + 1, table.Get(num2)); } table.Set(num, dynValue3); return dynValue; } [MoonSharpModuleMethod] public static DynValue remove(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "table.remove", DataType.Table); DynValue dynValue2 = args.AsType(1, "table.remove", DataType.Number, allowNil: true); DynValue result = DynValue.Nil; if (args.Count > 2) { throw new ScriptRuntimeException("wrong number of arguments to 'remove'"); } int tableLength = GetTableLength(executionContext, dynValue); Table table = dynValue.Table; int num = (dynValue2.IsNil() ? tableLength : ((int)dynValue2.Number)); if (num >= tableLength + 1 || (num < 1 && tableLength > 0)) { throw new ScriptRuntimeException("bad argument #1 to 'remove' (position out of bounds)"); } for (int i = num; i <= tableLength; i++) { if (i == num) { result = table.Get(i); } table.Set(i, table.Get(i + 1)); } return result; } [MoonSharpModuleMethod] public static DynValue concat(ScriptExecutionContext executionContext, CallbackArguments args) { DynValue dynValue = args.AsType(0, "concat", DataType.Table); DynValue dynValue2 = args.AsType(1, "concat", DataType.String, allowNil: true); DynValue dynValue3 = args.AsType(2, "concat", DataType.Number, allowNil: true); DynValue dynValue4 = args.AsType(3, "concat", DataType.Number, allowNil: true); Table table = dynValue.Table; string value = (dynValue2.IsNil() ? "" : dynValue2.String); int num = (dynValue3.IsNilOrNan() ? 1 : ((int)dynValue3.Number)); int num2 = ((!dynValue4.IsNilOrNan()) ? ((int)dynValue4.Number) : GetTableLength(executionContext, dynValue)); if (num2 < num) { return DynValue.NewString(string.Empty); } StringBuilder stringBuilder = new StringBuilder(); for (int i = num; i <= num2; i++) { DynValue dynValue5 = table.Get(i); if (dynValue5.Type != DataType.Number && dynValue5.Type != DataType.String) { throw new ScriptRuntimeException("invalid value ({1}) at index {0} in table for 'concat'", i, dynValue5.Type.ToLuaTypeString()); } string value2 = dynValue5.ToPrintString(); if (i != num) { stringBuilder.Append(value); } stringBuilder.Append(value2); } return DynValue.NewString(stringBuilder.ToString()); } public static int GetTableLength(ScriptExecutionContext executionContext, DynValue vlist) { DynValue metamethod = executionContext.GetMetamethod(vlist, "__len"); if (metamethod != null) { double? num = executionContext.GetScript().Call(metamethod, vlist).CastToNumber(); if (!num.HasValue) { throw new ScriptRuntimeException("object length is not a number"); } return (int)num.Value; } return vlist.Table.Length; } } [MoonSharpModule] public class TableModule_Globals { [MoonSharpModuleMethod] public static DynValue unpack(ScriptExecutionContext executionContext, CallbackArguments args) { return TableModule.unpack(executionContext, args); } [MoonSharpModuleMethod] public static DynValue pack(ScriptExecutionContext executionContext, CallbackArguments args) { return TableModule.pack(executionContext, args); } } public static class NamespaceDoc { } } namespace MoonSharp.Interpreter.CoreLib.StringLib { public class KopiLua_StringLib : LuaBase { public class MatchState { public class capture_ { public CharPtr init; public int len; } public int matchdepth; public CharPtr src_init; public CharPtr src_end; public LuaState L; public int level; public capture_[] capture = new capture_[32]; public MatchState() { for (int i = 0; i < 32; i++) { capture[i] = new capture_(); } } } public class GMatchAuxData { public CharPtr S; public CharPtr P; public uint LS; public uint POS; } public const int LUA_MAXCAPTURES = 32; public const int CAP_UNFINISHED = -1; public const int CAP_POSITION = -2; public const int MAXCCALLS = 200; public const char L_ESC = '%'; public const string SPECIALS = "^$*+?.([%-"; public const int MAX_ITEM = 512; public const string FLAGS = "-+ #0"; public static readonly int MAX_FORMAT = "-+ #0".Length + 1 + ("l".Length + 1) + 10; public static int posrelat(int pos, uint len) { if (pos < 0) { pos += (int)(len + 1); } if (pos < 0) { return 0; } return pos; } public static int check_capture(MatchState ms, int l) { l -= 49; if (l < 0 || l >= ms.level || ms.capture[l].len == -1) { return LuaBase.LuaLError(ms.L, "invalid capture index {0}", l + 1); } return l; } public static int capture_to_close(MatchState ms) { int level = ms.level; for (level--; level >= 0; level--) { if (ms.capture[level].len == -1) { return level; } } return LuaBase.LuaLError(ms.L, "invalid pattern capture"); } public static CharPtr classend(MatchState ms, CharPtr p) { p = new CharPtr(p); char c = p[0]; p = p.next(); switch (c) { case '%': if (p[0] == '\0') { LuaBase.LuaLError(ms.L, "malformed pattern (ends with " + LuaBase.LUA_QL("%") + ")"); } return p + 1; case '[': if (p[0] == '^') { p = p.next(); } do { if (p[0] == '\0') { LuaBase.LuaLError(ms.L, "malformed pattern (missing " + LuaBase.LUA_QL("]") + ")"); } c = p[0]; p = p.next(); if (c == '%' && p[0] != 0) { p = p.next(); } } while (p[0] != ']'); return p + 1; default: return p; } } public static int match_class(char c, char cl) { bool flag; switch (LuaBase.tolower(cl)) { case 'a': flag = LuaBase.isalpha(c); break; case 'c': flag = LuaBase.iscntrl(c); break; case 'd': flag = LuaBase.isdigit(c); break; case 'l': flag = LuaBase.islower(c); break; case 'p': flag = LuaBase.ispunct(c); break; case 's': flag = LuaBase.isspace(c); break; case 'g': flag = LuaBase.isgraph(c); break; case 'u': flag = LuaBase.isupper(c); break; case 'w': flag = LuaBase.isalnum(c); break; case 'x': flag = LuaBase.isxdigit(c); break; case 'z': flag = c == '\0'; break; default: if (cl != c) { return 0; } return 1; } if (!LuaBase.islower(cl)) { if (flag) { return 0; } return 1; } if (!flag) { return 0; } return 1; } public static int matchbracketclass(int c, CharPtr p, CharPtr ec) { int num = 1; if (p[1] == '^') { num = 0; p = p.next(); } while ((p = p.next()) < ec) { if (p == '%') { p = p.next(); if (match_class((char)c, p[0]) != 0) { return num; } } else if (p[1] == '-' && p + 2 < ec) { p += 2; if ((byte)p[-2] <= c && c <= (byte)p[0]) { return num; } } else if ((byte)p[0] == c) { return num; } } if (num != 0) { return 0; } return 1; } public static int singlematch(int c, CharPtr p, CharPtr ep) { switch (p[0]) { case '.': return 1; case '%': return match_class((char)c, p[1]); case '[': return matchbracketclass(c, p, ep - 1); default: if ((byte)p[0] != c) { return 0; } return 1; } } public static CharPtr matchbalance(MatchState ms, CharPtr s, CharPtr p) { if (p[0] == '\0' || p[1] == '\0') { LuaBase.LuaLError(ms.L, "unbalanced pattern"); } if (s[0] != p[0]) { return null; } int num = p[0]; int num2 = p[1]; int num3 = 1; while ((s = s.next()) < ms.src_end) { if (s[0] == num2) { if (--num3 == 0) { return s + 1; } } else if (s[0] == num) { num3++; } } return null; } public static CharPtr max_expand(MatchState ms, CharPtr s, CharPtr p, CharPtr ep) { int i; for (i = 0; s + i < ms.src_end && singlematch((byte)s[i], p, ep) != 0; i++) { } while (i >= 0) { CharPtr charPtr = match(ms, s + i, ep + 1); if (charPtr != null) { return charPtr; } i--; } return null; } public static CharPtr min_expand(MatchState ms, CharPtr s, CharPtr p, CharPtr ep) { while (true) { CharPtr charPtr = match(ms, s, ep + 1); if (charPtr != null) { return charPtr; } if (!(s < ms.src_end) || singlematch((byte)s[0], p, ep) == 0) { break; } s = s.next(); } return null; } public static CharPtr start_capture(MatchState ms, CharPtr s, CharPtr p, int what) { int level = ms.level; if (level >= 32) { LuaBase.LuaLError(ms.L, "too many captures"); } ms.capture[level].init = s; ms.capture[level].len = what; ms.level = level + 1; CharPtr charPtr = match(ms, s, p); if (charPtr == null) { ms.level--; } return charPtr; } public static CharPtr end_capture(MatchState ms, CharPtr s, CharPtr p) { int num = capture_to_close(ms); ms.capture[num].len = s - ms.capture[num].init; CharPtr charPtr = match(ms, s, p); if (charPtr == null) { ms.capture[num].len = -1; } return charPtr; } public static CharPtr match_capture(MatchState ms, CharPtr s, int l) { l = check_capture(ms, l); uint len = (uint)ms.capture[l].len; if ((uint)(ms.src_end - s) >= len && LuaBase.memcmp(ms.capture[l].init, s, len) == 0) { return s + len; } return null; } public static CharPtr match(MatchState ms, CharPtr s, CharPtr p) { s = new CharPtr(s); p = new CharPtr(p); if (ms.matchdepth-- == 0) { LuaBase.LuaLError(ms.L, "pattern too complex"); } while (true) { switch (p[0]) { case '(': if (p[1] == ')') { return start_capture(ms, s, p + 2, -2); } return start_capture(ms, s, p + 1, -1); case ')': return end_capture(ms, s, p + 1); case '%': { switch (p[1]) { case 'b': s = matchbalance(ms, s, p + 2); if (s == null) { return null; } p += 4; continue; case 'f': { p += 2; if (p[0] != '[') { LuaBase.LuaLError(ms.L, "missing " + LuaBase.LUA_QL("[") + " after " + LuaBase.LUA_QL("%f") + " in pattern"); } CharPtr charPtr = classend(ms, p); if (matchbracketclass((byte)((!(s == ms.src_init)) ? s[-1] : '\0'), p, charPtr - 1) != 0 || matchbracketclass((byte)s[0], p, charPtr - 1) == 0) { return null; } p = charPtr; continue; } } if (LuaBase.isdigit(p[1])) { s = match_capture(ms, s, (byte)p[1]); if (s == null) { return null; } p += 2; continue; } CharPtr charPtr2 = classend(ms, p); int num = ((s < ms.src_end && singlematch((byte)s[0], p, charPtr2) != 0) ? 1 : 0); switch (charPtr2[0]) { case '?': { CharPtr result; if (num != 0 && (result = match(ms, s + 1, charPtr2 + 1)) != null) { return result; } p = charPtr2 + 1; continue; } case '*': return max_expand(ms, s, p, charPtr2); case '+': if (num == 0) { return null; } return max_expand(ms, s + 1, p, charPtr2); case '-': return min_expand(ms, s, p, charPtr2); } if (num == 0) { return null; } s = s.next(); p = charPtr2; continue; } case '\0': return s; case '$': if (p[1] == '\0') { if (!(s == ms.src_end)) { return null; } return s; } break; } CharPtr charPtr3 = classend(ms, p); int num2 = ((s < ms.src_end && singlematch((byte)s[0], p, charPtr3) != 0) ? 1 : 0); switch (charPtr3[0]) { case '?': { CharPtr result2; if (num2 != 0 && (result2 = match(ms, s + 1, charPtr3 + 1)) != null) { return result2; } p = charPtr3 + 1; continue; } case '*': return max_expand(ms, s, p, charPtr3); case '+': if (num2 == 0) { return null; } return max_expand(ms, s + 1, p, charPtr3); case '-': return min_expand(ms, s, p, charPtr3); } if (num2 == 0) { return null; } s = s.next(); p = charPtr3; } } public static CharPtr lmemfind(CharPtr s1, uint l1, CharPtr s2, uint l2) { if (l2 == 0) { return s1; } if (l2 > l1) { return null; } l2--; l1 -= l2; CharPtr charPtr; while (l1 != 0 && (charPtr = LuaBase.memchr(s1, s2[0], l1)) != null) { charPtr = charPtr.next(); if (LuaBase.memcmp(charPtr, s2 + 1, l2) == 0) { return charPtr - 1; } l1 -= (uint)(charPtr - s1); s1 = charPtr; } return null; } public static void push_onecapture(MatchState ms, int i, CharPtr s, CharPtr e) { if (i >= ms.level) { if (i == 0) { LuaBase.LuaPushLString(ms.L, s, (uint)(e - s)); } else { LuaBase.LuaLError(ms.L, "invalid capture index"); } return; } int len = ms.capture[i].len; if (len == -1) { LuaBase.LuaLError(ms.L, "unfinished capture"); } if (len == -2) { LuaBase.LuaPushInteger(ms.L, ms.capture[i].init - ms.src_init + 1); } else { LuaBase.LuaPushLString(ms.L, ms.capture[i].init, (uint)len); } } public static int push_captures(MatchState ms, CharPtr s, CharPtr e) { int num = ((ms.level == 0 && s != null) ? 1 : ms.level); LuaBase.LuaLCheckStack(ms.L, num, "too many captures"); for (int i = 0; i < num; i++) { push_onecapture(ms, i, s, e); } return num; } public static int str_find_aux(LuaState L, int find) { uint l; CharPtr charPtr = LuaBase.LuaLCheckLString(L, 1, out l); uint l2; CharPtr charPtr2 = PatchPattern(LuaBase.LuaLCheckLString(L, 2, out l2)); int num = posrelat(LuaBase.LuaLOptInteger(L, 3, 1), l) - 1; if (num < 0) { num = 0; } else if ((uint)num > l) { num = (int)l; } if (find != 0 && (LuaBase.LuaToBoolean(L, 4) != 0 || LuaBase.strpbrk(charPtr2, "^$*+?.([%-") == null)) { CharPtr charPtr3 = lmemfind(charPtr + num, (uint)(l - num), charPtr2, l2); if (charPtr3 != null) { LuaBase.LuaPushInteger(L, charPtr3 - charPtr + 1); LuaBase.LuaPushInteger(L, (int)(charPtr3 - charPtr + l2)); return 2; } } else { MatchState matchState = new MatchState(); int num2 = 0; if (charPtr2[0] == '^') { charPtr2 = charPtr2.next(); num2 = 1; } CharPtr charPtr4 = charPtr + num; matchState.L = L; matchState.matchdepth = 200; matchState.src_init = charPtr; matchState.src_end = charPtr + l; do { matchState.level = 0; matchState.matchdepth = 200; CharPtr charPtr5; if ((charPtr5 = match(matchState, charPtr4, charPtr2)) != null) { if (find != 0) { LuaBase.LuaPushInteger(L, charPtr4 - charPtr + 1); LuaBase.LuaPushInteger(L, charPtr5 - charPtr); return push_captures(matchState, null, null) + 2; } return push_captures(matchState, charPtr4, charPtr5); } } while ((charPtr4 = charPtr4.next()) <= matchState.src_end && num2 == 0); } LuaBase.LuaPushNil(L); return 1; } public static int str_find(LuaState L) { return str_find_aux(L, 1); } public static int str_match(LuaState L) { return str_find_aux(L, 0); } public static int gmatch_aux(LuaState L, GMatchAuxData auxdata) { MatchState matchState = new MatchState(); uint lS = auxdata.LS; CharPtr s = auxdata.S; CharPtr p = auxdata.P; matchState.L = L; matchState.matchdepth = 200; matchState.src_init = s; matchState.src_end = s + lS; CharPtr charPtr = s + auxdata.POS; while (charPtr <= matchState.src_end) { matchState.level = 0; matchState.matchdepth = 200; CharPtr charPtr2; if ((charPtr2 = match(matchState, charPtr, p)) != null) { int num = charPtr2 - s; if (charPtr2 == charPtr) { num++; } auxdata.POS = (uint)num; return push_captures(matchState, charPtr, charPtr2); } charPtr = charPtr.next(); } return 0; } public static DynValue gmatch_aux_2(ScriptExecutionContext executionContext, CallbackArguments args) { return executionContext.EmulateClassicCall(args, "gmatch", (LuaState L) => gmatch_aux(L, (GMatchAuxData)executionContext.AdditionalData)); } public static int str_gmatch(LuaState L) { CallbackFunction callbackFunction = new CallbackFunction(gmatch_aux_2, "gmatch"); string @string = LuaBase.ArgAsType(L, 1, DataType.String).String; string str = PatchPattern(LuaBase.ArgAsType(L, 2, DataType.String).String); callbackFunction.AdditionalData = new GMatchAuxData { S = new CharPtr(@string), P = new CharPtr(str), LS = (uint)@string.Length, POS = 0u }; L.Push(DynValue.NewCallback(callbackFunction)); return 1; } public static int gfind_nodef(LuaState L) { return LuaBase.LuaLError(L, LuaBase.LUA_QL("string.gfind") + " was renamed to " + LuaBase.LUA_QL("string.gmatch")); } public static void add_s(MatchState ms, LuaLBuffer b, CharPtr s, CharPtr e) { uint l; CharPtr charPtr = LuaBase.LuaToLString(ms.L, 3, out l); for (uint num = 0u; num < l; num++) { if (charPtr[num] != '%') { LuaBase.LuaLAddChar(b, charPtr[num]); continue; } num++; if (!LuaBase.isdigit(charPtr[num])) { if (charPtr[num] != '%') { LuaBase.LuaLError(ms.L, "invalid use of '%' in replacement string"); } LuaBase.LuaLAddChar(b, charPtr[num]); } else if (charPtr[num] == '0') { LuaBase.LuaLAddLString(b, s, (uint)(e - s)); } else { push_onecapture(ms, charPtr[num] - 49, s, e); LuaBase.LuaLAddValue(b); } } } public static void add_value(MatchState ms, LuaLBuffer b, CharPtr s, CharPtr e) { LuaState l = ms.L; switch (LuaBase.LuaType(l, 3)) { case 3: case 4: add_s(ms, b, s, e); return; case 6: { LuaBase.LuaPushValue(l, 3); int nargs = push_captures(ms, s, e); LuaBase.LuaCall(l, nargs, 1); break; } case 5: push_onecapture(ms, 0, s, e); LuaBase.LuaGetTable(l, 3); break; } if (LuaBase.LuaToBoolean(l, -1) == 0) { LuaBase.LuaPop(l, 1); LuaBase.LuaPushLString(l, s, (uint)(e - s)); } else if (LuaBase.LuaIsString(l, -1) == 0) { LuaBase.LuaLError(l, "invalid replacement value (a {0})", LuaBase.LuaLTypeName(l, -1)); } LuaBase.LuaLAddValue(b); } public static int str_gsub(LuaState L) { uint l; CharPtr charPtr = LuaBase.LuaLCheckLString(L, 1, out l); CharPtr charPtr2 = PatchPattern(LuaBase.LuaLCheckStringStr(L, 2)); int num = LuaBase.LuaType(L, 3); int num2 = LuaBase.LuaLOptInt(L, 4, (int)(l + 1)); int num3 = 0; if (charPtr2[0] == '^') { charPtr2 = charPtr2.next(); num3 = 1; } int num4 = 0; MatchState matchState = new MatchState(); LuaLBuffer b = new LuaLBuffer(L); LuaBase.LuaLArgCheck(L, num == 3 || num == 4 || num == 6 || num == 5 || num == 7, 3, "string/function/table expected"); LuaBase.LuaLBuffInit(L, b); matchState.L = L; matchState.matchdepth = 200; matchState.src_init = charPtr; matchState.src_end = charPtr + l; while (num4 < num2) { matchState.level = 0; matchState.matchdepth = 200; CharPtr charPtr3 = match(matchState, charPtr, charPtr2); if (charPtr3 != null) { num4++; add_value(matchState, b, charPtr, charPtr3); } if (charPtr3 != null && charPtr3 > charPtr) { charPtr = charPtr3; } else { if (!(charPtr < matchState.src_end)) { break; } char p = charPtr[0]; charPtr = charPtr.next(); LuaBase.LuaLAddChar(b, p); } if (num3 != 0) { break; } } LuaBase.LuaLAddLString(b, charPtr, (uint)(matchState.src_end - charPtr)); LuaBase.LuaLPushResult(b); LuaBase.LuaPushInteger(L, num4); return 2; } public static void addquoted(LuaState L, LuaLBuffer b, int arg) { uint l; CharPtr charPtr = LuaBase.LuaLCheckLString(L, arg, out l); LuaBase.LuaLAddChar(b, '"'); while (l-- != 0) { switch (charPtr[0]) { case '\n': case '"': case '\\': LuaBase.LuaLAddChar(b, '\\'); LuaBase.LuaLAddChar(b, charPtr[0]); break; case '\r': LuaBase.LuaLAddLString(b, "\\r", 2u); break; default: if (charPtr[0] < '\u0010') { bool flag = false; if (l >= 1 && char.IsNumber(charPtr[1])) { flag = true; } if (flag) { LuaBase.LuaLAddString(b, $"\\{(int)charPtr[0]:000}"); } else { LuaBase.LuaLAddString(b, $"\\{(int)charPtr[0]}"); } } else { LuaBase.LuaLAddChar(b, charPtr[0]); } break; } charPtr = charPtr.next(); } LuaBase.LuaLAddChar(b, '"'); } public static CharPtr scanformat(LuaState L, CharPtr strfrmt, CharPtr form) { CharPtr charPtr = strfrmt; while (charPtr[0] != 0 && LuaBase.strchr("-+ #0", charPtr[0]) != null) { charPtr = charPtr.next(); } if ((uint)(charPtr - strfrmt) >= "-+ #0".Length + 1) { LuaBase.LuaLError(L, "invalid format (repeated flags)"); } if (LuaBase.isdigit((byte)charPtr[0])) { charPtr = charPtr.next(); } if (LuaBase.isdigit((byte)charPtr[0])) { charPtr = charPtr.next(); } if (charPtr[0] == '.') { charPtr = charPtr.next(); if (LuaBase.isdigit((byte)charPtr[0])) { charPtr = charPtr.next(); } if (LuaBase.isdigit((byte)charPtr[0])) { charPtr = charPtr.next(); } } if (LuaBase.isdigit((byte)charPtr[0])) { LuaBase.LuaLError(L, "invalid format (width or precision too long)"); } form[0] = '%'; form = form.next(); LuaBase.strncpy(form, strfrmt, charPtr - strfrmt + 1); form += charPtr - strfrmt + 1; form[0] = '\0'; return charPtr; } public static void addintlen(CharPtr form) { uint num = (uint)LuaBase.strlen(form); char value = form[num - 1]; LuaBase.strcpy(form + num - 1, "l"); form[num + ("l".Length + 1) - 2] = value; form[num + ("l".Length + 1) - 1] = '\0'; } public static int str_format(LuaState L) { int num = LuaBase.LuaGetTop(L); int num2 = 1; CharPtr charPtr = LuaBase.LuaLCheckLString(L, num2, out var l); CharPtr charPtr2 = charPtr + l; LuaLBuffer b = new LuaLBuffer(L); LuaBase.LuaLBuffInit(L, b); while (charPtr < charPtr2) { if (charPtr[0] != '%') { LuaBase.LuaLAddChar(b, charPtr[0]); charPtr = charPtr.next(); continue; } if (charPtr[1] == '%') { LuaBase.LuaLAddChar(b, charPtr[0]); charPtr += 2; continue; } charPtr = charPtr.next(); CharPtr charPtr3 = new char[MAX_FORMAT]; CharPtr charPtr4 = new char[512]; if (++num2 > num) { LuaBase.LuaLArgError(L, num2, "no value"); } charPtr = scanformat(L, charPtr, charPtr3); char c = charPtr[0]; charPtr = charPtr.next(); switch (c) { case 'c': LuaBase.sprintf(charPtr4, charPtr3, (int)LuaBase.LuaLCheckNumber(L, num2)); break; case 'd': case 'i': addintlen(charPtr3); LuaBase.sprintf(charPtr4, charPtr3, (long)LuaBase.LuaLCheckNumber(L, num2)); break; case 'X': case 'o': case 'u': case 'x': addintlen(charPtr3); LuaBase.sprintf(charPtr4, charPtr3, (ulong)LuaBase.LuaLCheckNumber(L, num2)); break; case 'E': case 'G': case 'e': case 'f': case 'g': LuaBase.sprintf(charPtr4, charPtr3, LuaBase.LuaLCheckNumber(L, num2)); break; case 'q': addquoted(L, b, num2); continue; case 's': { uint l2; CharPtr charPtr5 = LuaBase.LuaLCheckLString(L, num2, out l2); if (LuaBase.strchr(charPtr3, '.') == null && l2 >= 100) { LuaBase.LuaPushValue(L, num2); LuaBase.LuaLAddValue(b); continue; } LuaBase.sprintf(charPtr4, charPtr3, charPtr5); break; } default: return LuaBase.LuaLError(L, "invalid option " + LuaBase.LUA_QL("%" + c) + " to " + LuaBase.LUA_QL("format"), charPtr[-1]); } LuaBase.LuaLAddLString(b, charPtr4, (uint)LuaBase.strlen(charPtr4)); } LuaBase.LuaLPushResult(b); return 1; } public static string PatchPattern(string charPtr) { return charPtr.Replace("\0", "%z"); } } public class StringRange { public int Start { get; set; } public int End { get; set; } public StringRange() { Start = 0; End = 0; } public StringRange(int start, int end) { Start = start; End = end; } public static StringRange FromLuaRange(DynValue start, DynValue end, int? defaultEnd = null) { int num = (start.IsNil() ? 1 : ((int)start.Number)); int end2 = ((!end.IsNil()) ? ((int)end.Number) : (defaultEnd ?? num)); return new StringRange(num, end2); } public string ApplyToString(string value) { int num = ((Start < 0) ? (Start + value.Length + 1) : Start); int num2 = ((End < 0) ? (End + value.Length + 1) : End); if (num < 1) { num = 1; } if (num2 > value.Length) { num2 = value.Length; } if (num > num2) { return string.Empty; } return value.Substring(num - 1, num2 - num + 1); } public int Length() { return End - Start + 1; } } } namespace MoonSharp.Interpreter.CoreLib.IO { public class BinaryEncoding : Encoding { public override int GetByteCount(char[] chars, int index, int count) { return count; } public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { for (int i = 0; i < charCount; i++) { bytes[byteIndex + i] = (byte)chars[charIndex + i]; } return charCount; } public override int GetCharCount(byte[] bytes, int index, int count) { return count; } public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { for (int i = 0; i < byteCount; i++) { chars[charIndex + i] = (char)bytes[byteIndex + i]; } return byteCount; } public override int GetMaxByteCount(int charCount) { return charCount; } public override int GetMaxCharCount(int byteCount) { return byteCount; } } public class FileUserData : StreamFileUserDataBase { public FileUserData(Script script, string filename, Encoding encoding, string mode) { Stream stream = Script.GlobalOptions.Platform.IO_OpenFile(script, filename, encoding, mode); Initialize(stream, stream.CanRead ? new StreamReader(stream, encoding) : null, stream.CanWrite ? new StreamWriter(stream, encoding) : null); } } public abstract class FileUserDataBase : RefIdObject { public DynValue lines(ScriptExecutionContext executionContext, CallbackArguments args) { List list = new List(); DynValue dynValue = null; do { dynValue = read(executionContext, args); list.Add(dynValue); } while (dynValue.IsNotNil()); return DynValue.FromObject(executionContext.GetScript(), list.Select((DynValue s) => s)); } public DynValue read(ScriptExecutionContext executionContext, CallbackArguments args) { if (args.Count == 0) { string text = ReadLine(); if (text == null) { return DynValue.Nil; } text = text.TrimEnd('\n', '\r'); return DynValue.NewString(text); } List list = new List(); for (int i = 0; i < args.Count; i++) { DynValue item; if (args[i].Type == DataType.Number) { if (Eof()) { return DynValue.Nil; } int p = (int)args[i].Number; item = DynValue.NewString(ReadBuffer(p)); } else { string @string = args.AsType(i, "read", DataType.String).String; if (Eof()) { item = (@string.StartsWith("*a") ? DynValue.NewString("") : DynValue.Nil); } else if (@string.StartsWith("*n")) { double? num = ReadNumber(); item = ((!num.HasValue) ? DynValue.Nil : DynValue.NewNumber(num.Value)); } else if (@string.StartsWith("*a")) { item = DynValue.NewString(ReadToEnd()); } else if (@string.StartsWith("*l")) { item = DynValue.NewString(ReadLine().TrimEnd('\n', '\r')); } else { if (!@string.StartsWith("*L")) { throw ScriptRuntimeException.BadArgument(i, "read", "invalid option"); } item = DynValue.NewString(ReadLine().TrimEnd('\n', '\r') + "\n"); } } list.Add(item); } return DynValue.NewTuple(list.ToArray()); } public DynValue write(ScriptExecutionContext executionContext, CallbackArguments args) { try { for (int i = 0; i < args.Count; i++) { string @string = args.AsType(i, "write", DataType.String).String; Write(@string); } return UserData.Create(this); } catch (ScriptRuntimeException) { throw; } catch (Exception ex2) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(ex2.Message)); } } public DynValue close(ScriptExecutionContext executionContext, CallbackArguments args) { try { string text = Close(); if (text == null) { return DynValue.True; } return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(text)); } catch (ScriptRuntimeException) { throw; } catch (Exception ex2) { return DynValue.NewTuple(DynValue.Nil, DynValue.NewString(ex2.Message)); } } public double? ReadNumber() { string text = ""; while (!Eof()) { char c = Peek(); if (char.IsWhiteSpace(c)) { ReadBuffer(1); continue; } if (!IsNumericChar(c, text)) { break; } ReadBuffer(1); text += c; } if (double.TryParse(text, out var result)) { return result; } return null; } public bool IsNumericChar(char c, string numAsFar) { if (char.IsDigit(c)) { return true; } switch (c) { case '-': return numAsFar.Length == 0; case '.': return !Framework.Do.StringContainsChar(numAsFar, '.'); case 'E': case 'e': if (!Framework.Do.StringContainsChar(numAsFar, 'E')) { return !Framework.Do.StringContainsChar(numAsFar, 'e'); } return false; default: return false; } } public abstract bool Eof(); public abstract string ReadLine(); public abstract string ReadBuffer(int p); public abstract string ReadToEnd(); public abstract char Peek(); public abstract void Write(string value); public abstract bool isopen(); public abstract string Close(); public abstract bool flush(); public abstract long seek(string whence, long offset); public abstract bool setvbuf(string mode); public override string ToString() { if (isopen()) { return $"file ({base.ReferenceID:X8})"; } return "file (closed)"; } public FileUserDataBase() { } } public class StandardIOFileUserDataBase : StreamFileUserDataBase { public override string Close() { return "cannot close standard file"; } public static StandardIOFileUserDataBase CreateInputStream(Stream stream) { StandardIOFileUserDataBase standardIOFileUserDataBase = new StandardIOFileUserDataBase(); standardIOFileUserDataBase.Initialize(stream, new StreamReader(stream), null); return standardIOFileUserDataBase; } public static StandardIOFileUserDataBase CreateOutputStream(Stream stream) { StandardIOFileUserDataBase standardIOFileUserDataBase = new StandardIOFileUserDataBase(); standardIOFileUserDataBase.Initialize(stream, null, new StreamWriter(stream)); return standardIOFileUserDataBase; } } public abstract class StreamFileUserDataBase : FileUserDataBase { public Stream m_Stream; public StreamReader m_Reader; public StreamWriter m_Writer; public bool m_Closed; public void Initialize(Stream stream, StreamReader reader, StreamWriter writer) { m_Stream = stream; m_Reader = reader; m_Writer = writer; } public void CheckFileIsNotClosed() { if (m_Closed) { throw new ScriptRuntimeException("attempt to use a closed file"); } } public override bool Eof() { CheckFileIsNotClosed(); if (m_Reader != null) { return m_Reader.EndOfStream; } return false; } public override string ReadLine() { CheckFileIsNotClosed(); return m_Reader.ReadLine(); } public override string ReadToEnd() { CheckFileIsNotClosed(); return m_Reader.ReadToEnd(); } public override string ReadBuffer(int p) { CheckFileIsNotClosed(); char[] array = new char[p]; int length = m_Reader.ReadBlock(array, 0, p); return new string(array, 0, length); } public override char Peek() { CheckFileIsNotClosed(); return (char)m_Reader.Peek(); } public override void Write(string value) { CheckFileIsNotClosed(); m_Writer.Write(value); } public override string Close() { CheckFileIsNotClosed(); if (m_Writer != null) { m_Writer.Dispose(); } if (m_Reader != null) { m_Reader.Dispose(); } m_Stream.Dispose(); m_Closed = true; return null; } public override bool flush() { CheckFileIsNotClosed(); if (m_Writer != null) { m_Writer.Flush(); } return true; } public override long seek(string whence, long offset) { CheckFileIsNotClosed(); switch (whence) { case "set": m_Stream.Seek(offset, SeekOrigin.Begin); break; case "cur": m_Stream.Seek(offset, SeekOrigin.Current); break; case "end": m_Stream.Seek(offset, SeekOrigin.End); break; default: throw ScriptRuntimeException.BadArgument(0, "seek", "invalid option '" + whence + "'"); case null: break; } return m_Stream.Position; } public override bool setvbuf(string mode) { CheckFileIsNotClosed(); if (m_Writer != null) { m_Writer.AutoFlush = mode == "no" || mode == "line"; } return true; } public override bool isopen() { return !m_Closed; } public StreamFileUserDataBase() { } } public static class NamespaceDoc { } } namespace MoonSharp.Interpreter.Compatibility { public static class Framework { public static FrameworkCurrent s_FrameworkCurrent = new FrameworkCurrent(); public static FrameworkBase Do => s_FrameworkCurrent; } } namespace MoonSharp.Interpreter.Compatibility.Frameworks { public abstract class FrameworkBase { public abstract bool StringContainsChar(string str, char chr); public abstract bool IsValueType(Type t); public abstract Assembly GetAssembly(Type t); public abstract Type GetBaseType(Type t); public abstract bool IsGenericType(Type t); public abstract bool IsGenericTypeDefinition(Type t); public abstract bool IsEnum(Type t); public abstract bool IsNestedPublic(Type t); public abstract bool IsAbstract(Type t); public abstract bool IsInterface(Type t); public abstract Attribute[] GetCustomAttributes(Type t, bool inherit); public abstract Attribute[] GetCustomAttributes(Type t, Type at, bool inherit); public abstract Type[] GetInterfaces(Type t); public abstract bool IsInstanceOfType(Type t, object o); public abstract MethodInfo GetAddMethod(EventInfo ei); public abstract MethodInfo GetRemoveMethod(EventInfo ei); public abstract MethodInfo GetGetMethod(PropertyInfo pi); public abstract MethodInfo GetSetMethod(PropertyInfo pi); public abstract Type GetInterface(Type type, string name); public abstract PropertyInfo[] GetProperties(Type type); public abstract PropertyInfo GetProperty(Type type, string name); public abstract Type[] GetNestedTypes(Type type); public abstract EventInfo[] GetEvents(Type type); public abstract ConstructorInfo[] GetConstructors(Type type); public abstract Type[] GetAssemblyTypes(Assembly asm); public abstract MethodInfo[] GetMethods(Type type); public abstract FieldInfo[] GetFields(Type t); public abstract MethodInfo GetMethod(Type type, string name); public abstract Type[] GetGenericArguments(Type t); public abstract bool IsAssignableFrom(Type current, Type toCompare); public abstract bool IsDbNull(object o); public abstract MethodInfo GetMethod(Type resourcesType, string v, Type[] type); public FrameworkBase() { } } public class FrameworkCurrent : FrameworkClrBase { public override Type GetTypeInfoFromType(Type t) { return t; } public override bool IsDbNull(object o) { if (o != null) { return Convert.IsDBNull(o); } return false; } public override bool StringContainsChar(string str, char chr) { return Enumerable.Contains(str, chr); } public override Type GetInterface(Type type, string name) { return type.GetInterface(name); } } public abstract class FrameworkReflectionBase : FrameworkBase { public abstract Type GetTypeInfoFromType(Type t); public override Assembly GetAssembly(Type t) { return GetTypeInfoFromType(t).Assembly; } public override Type GetBaseType(Type t) { return GetTypeInfoFromType(t).BaseType; } public override bool IsValueType(Type t) { return GetTypeInfoFromType(t).IsValueType; } public override bool IsInterface(Type t) { return GetTypeInfoFromType(t).IsInterface; } public override bool IsNestedPublic(Type t) { return GetTypeInfoFromType(t).IsNestedPublic; } public override bool IsAbstract(Type t) { return GetTypeInfoFromType(t).IsAbstract; } public override bool IsEnum(Type t) { return GetTypeInfoFromType(t).IsEnum; } public override bool IsGenericTypeDefinition(Type t) { return GetTypeInfoFromType(t).IsGenericTypeDefinition; } public override bool IsGenericType(Type t) { return GetTypeInfoFromType(t).IsGenericType; } public override Attribute[] GetCustomAttributes(Type t, bool inherit) { return GetTypeInfoFromType(t).GetCustomAttributes(inherit).OfType().ToArray(); } public override Attribute[] GetCustomAttributes(Type t, Type at, bool inherit) { return GetTypeInfoFromType(t).GetCustomAttributes(at, inherit).OfType().ToArray(); } public FrameworkReflectionBase() { } } public abstract class FrameworkClrBase : FrameworkReflectionBase { public BindingFlags BINDINGFLAGS_MEMBER = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; public BindingFlags BINDINGFLAGS_INNERCLASS = BindingFlags.Public | BindingFlags.NonPublic; public override MethodInfo GetAddMethod(EventInfo ei) { return ei.GetAddMethod(nonPublic: true); } public override ConstructorInfo[] GetConstructors(Type type) { return GetTypeInfoFromType(type).GetConstructors(BINDINGFLAGS_MEMBER); } public override EventInfo[] GetEvents(Type type) { return GetTypeInfoFromType(type).GetEvents(BINDINGFLAGS_MEMBER); } public override FieldInfo[] GetFields(Type type) { return GetTypeInfoFromType(type).GetFields(BINDINGFLAGS_MEMBER); } public override Type[] GetGenericArguments(Type type) { return GetTypeInfoFromType(type).GetGenericArguments(); } public override MethodInfo GetGetMethod(PropertyInfo pi) { return pi.GetGetMethod(nonPublic: true); } public override Type[] GetInterfaces(Type t) { return GetTypeInfoFromType(t).GetInterfaces(); } public override MethodInfo GetMethod(Type type, string name) { return GetTypeInfoFromType(type).GetMethod(name); } public override MethodInfo[] GetMethods(Type type) { return GetTypeInfoFromType(type).GetMethods(BINDINGFLAGS_MEMBER); } public override Type[] GetNestedTypes(Type type) { return GetTypeInfoFromType(type).GetNestedTypes(BINDINGFLAGS_INNERCLASS); } public override PropertyInfo[] GetProperties(Type type) { return GetTypeInfoFromType(type).GetProperties(BINDINGFLAGS_MEMBER); } public override PropertyInfo GetProperty(Type type, string name) { return GetTypeInfoFromType(type).GetProperty(name); } public override MethodInfo GetRemoveMethod(EventInfo ei) { return ei.GetRemoveMethod(nonPublic: true); } public override MethodInfo GetSetMethod(PropertyInfo pi) { return pi.GetSetMethod(nonPublic: true); } public override bool IsAssignableFrom(Type current, Type toCompare) { return GetTypeInfoFromType(current).IsAssignableFrom(toCompare); } public override bool IsInstanceOfType(Type t, object o) { return GetTypeInfoFromType(t).IsInstanceOfType(o); } public override MethodInfo GetMethod(Type resourcesType, string name, Type[] types) { return GetTypeInfoFromType(resourcesType).GetMethod(name, types); } public override Type[] GetAssemblyTypes(Assembly asm) { return asm.GetTypes(); } public FrameworkClrBase() { } } } namespace MoonSharp.Interpreter.CodeAnalysis { public class AstNode { } }