diff --git a/.gitignore b/.gitignore
index 79a83c4b..c2fc1cd9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,9 @@ build/
[Oo]bj/
bin-debug/
+# VS2017 .vs directory
+src/.vs/
+
# Remove generated docs
diff --git a/LICENSE b/LICENSE
old mode 100644
new mode 100755
index 2bccfd87..33d21309
--- a/LICENSE
+++ b/LICENSE
@@ -1,15 +1,17 @@
-Copyright (c) 2014, Marco Mastropaolo
+Copyright (c) 2014-2016, Marco Mastropaolo
All rights reserved.
Parts of the string library are based on the KopiLua project (https://github.com/NLua/KopiLua)
Copyright (c) 2012 LoDC
-Debugger icons are from the Eclipse project (https://www.eclipse.org/).
+Visual Studio Code debugger code is based on code from Microsoft vscode-mono-debug project (https://github.com/Microsoft/vscode-mono-debug).
+Copyright (c) Microsoft Corporation - released under MIT license.
+
+Remote Debugger icons are from the Eclipse project (https://www.eclipse.org/).
Copyright of The Eclipse Foundation
The MoonSharp icon is (c) Isaac, 2014-2015
-
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
diff --git a/README.md b/README.md
old mode 100644
new mode 100755
index 6c980e89..56246141
--- a/README.md
+++ b/README.md
@@ -10,16 +10,19 @@ Features:
* 99% compatible with Lua 5.2 (with the only unsupported feature being weak tables support)
* Support for metalua style anonymous functions (lambda-style)
* Easy to use API
-* Source based remote **debugger** accessible with a web browser and Flash (PCL targets not supported)
-* Runs on .NET 3.5, .NET 4.x, Mono, Xamarin and Unity3D
+* **Debugger** support for Visual Studio Code (PCL targets not supported)
+* Remote debugger accessible with a web browser and Flash (PCL targets not supported)
+* Runs on .NET 3.5, .NET 4.x, .NET Core, Mono, Xamarin and Unity3D
* Runs on Ahead-of-time platforms like iOS
+* Runs on IL2CPP converted code
* Runs on platforms requiring a .NET 4.x portable class library (e.g. Windows Phone)
* No external dependencies, implemented in as few targets as possible
* Easy and performant interop with CLR objects, with runtime code generation where supported
* Interop with methods, extension methods, overloads, fields, properties and indexers supported
-* Support for the complete Lua standard library with very few exceptions (mostly located on the 'debug' module)
+* Support for the complete Lua standard library with very few exceptions (mostly located on the 'debug' module) and a few extensions (in the string library, mostly)
* Async methods for .NET 4.x targets
* Supports dumping/loading bytecode for obfuscation and quicker parsing at runtime
+* An embedded JSON parser (with no dependencies) to convert between JSON and Lua tables
* Easy opt-out of Lua standard library modules to sandbox what scripts can access
* Easy to use error handling (script errors are exceptions)
* Support for coroutines, including invocation of coroutines as C# iterators
diff --git a/src/.vs/restore.dg b/src/.vs/restore.dg
new file mode 100755
index 00000000..0a8c8d32
--- /dev/null
+++ b/src/.vs/restore.dg
@@ -0,0 +1,7 @@
+#:Z:\git\my\moonsharp\src\MoonSharp.VsCodeDebugger\_Projects\MoonSharp.VsCodeDebugger.netcore\MoonSharp.VsCodeDebugger.netcore.xproj
+Z:\git\my\moonsharp\src\MoonSharp.VsCodeDebugger\_Projects\MoonSharp.VsCodeDebugger.netcore\MoonSharp.VsCodeDebugger.netcore.xproj|Z:\git\my\moonsharp\src\MoonSharp.Interpreter\_Projects\MoonSharp.Interpreter.netcore\MoonSharp.Interpreter.netcore.xproj
+#:Z:\git\my\moonsharp\src\TestRunners\DotNetCoreTestRunner\DotNetCoreTestRunner.xproj
+Z:\git\my\moonsharp\src\TestRunners\DotNetCoreTestRunner\DotNetCoreTestRunner.xproj|Z:\git\my\moonsharp\src\MoonSharp.Interpreter\_Projects\MoonSharp.Interpreter.netcore\MoonSharp.Interpreter.netcore.xproj
+Z:\git\my\moonsharp\src\TestRunners\DotNetCoreTestRunner\DotNetCoreTestRunner.xproj|Z:\git\my\moonsharp\src\MoonSharp.VsCodeDebugger\_Projects\MoonSharp.VsCodeDebugger.netcore\MoonSharp.VsCodeDebugger.netcore.xproj
+Z:\git\my\moonsharp\src\MoonSharp.VsCodeDebugger\_Projects\MoonSharp.VsCodeDebugger.netcore\MoonSharp.VsCodeDebugger.netcore.xproj|Z:\git\my\moonsharp\src\MoonSharp.Interpreter\_Projects\MoonSharp.Interpreter.netcore\MoonSharp.Interpreter.netcore.xproj
+#:Z:\git\my\moonsharp\src\MoonSharp.Interpreter\_Projects\MoonSharp.Interpreter.netcore\MoonSharp.Interpreter.netcore.xproj
diff --git a/src/DevTools/MoonSharp.VmDebugger/MainForm.cs b/src/DevTools/MoonSharp.VmDebugger/MainForm.cs
index 9b9516c0..fae87cab 100644
--- a/src/DevTools/MoonSharp.VmDebugger/MainForm.cs
+++ b/src/DevTools/MoonSharp.VmDebugger/MainForm.cs
@@ -31,7 +31,7 @@ private void MainForm_Load(object sender, EventArgs e)
{
m_Ctx = SynchronizationContext.Current;
Script.WarmUp();
- Script.DefaultOptions.TailCallOptimizationThreshold = 1;
+ //Script.DefaultOptions.TailCallOptimizationThreshold = 1;
}
private void openToolStripMenuItem_Click(object sender, EventArgs e)
@@ -67,15 +67,17 @@ private void Console_WriteLine(string fmt, params object[] args)
private void DebugScript(string filename)
{
- m_Script = new Script(CoreModules.Preset_HardSandbox);
- m_Script.Options.UseLuaErrorLocations = true;
+ m_Script = new Script(CoreModules.Basic | CoreModules.Table | CoreModules.TableIterators | CoreModules.Metatables);
+ // m_Script.Options.UseLuaErrorLocations = true;
m_Script.Options.DebugPrint = s => { Console_WriteLine("{0}", s); };
- ((ScriptLoaderBase)m_Script.Options.ScriptLoader).ModulePaths = ScriptLoaderBase.UnpackStringPaths("Modules/?;Modules/?.lua");
+ // ((ScriptLoaderBase)m_Script.Options.ScriptLoader).ModulePaths = ScriptLoaderBase.UnpackStringPaths("Modules/?;Modules/?.lua");
+
+ DynValue fn;
try
{
- m_Script.LoadFile(filename, null, filename.Replace(':', '|'));
+ fn = m_Script.LoadFile(filename, null, filename.Replace(':', '|'));
}
catch (Exception ex)
{
@@ -86,7 +88,7 @@ private void DebugScript(string filename)
m_Script.AttachDebugger(this);
- Thread m_Debugger = new Thread(DebugMain);
+ Thread m_Debugger = new Thread(() => DebugMain(fn));
m_Debugger.Name = "MoonSharp Execution Thread";
m_Debugger.IsBackground = true;
m_Debugger.Start();
@@ -171,11 +173,11 @@ void DebugAction(DebuggerAction action)
}
- void DebugMain()
+ void DebugMain(DynValue fn)
{
try
{
- m_Script.Call(m_Script.GetMainChunk());
+ fn.Function.Call();
}
catch (ScriptRuntimeException ex)
{
@@ -439,5 +441,14 @@ private void btnOpenTest_Click(object sender, EventArgs e)
{
}
+
+ public void SetDebugService(DebugService debugService)
+ {
+ }
+
+ public DebuggerCaps GetDebuggerCaps()
+ {
+ return DebuggerCaps.CanDebugByteCode;
+ }
}
}
diff --git a/src/DevTools/Playground/Playground.csproj b/src/DevTools/Playground/Playground.csproj
index 6c416e15..304834cf 100644
--- a/src/DevTools/Playground/Playground.csproj
+++ b/src/DevTools/Playground/Playground.csproj
@@ -47,6 +47,15 @@
+
+ Always
+
+
+ Always
+
+
+ Always
+
diff --git a/src/DevTools/Playground/Program.cs b/src/DevTools/Playground/Program.cs
index 334e5706..f570edc1 100644
--- a/src/DevTools/Playground/Program.cs
+++ b/src/DevTools/Playground/Program.cs
@@ -1,34 +1,39 @@
using MoonSharp.Interpreter;
using System;
+using System.Diagnostics;
+using System.IO;
+using MoonSharp.Interpreter.Loaders;
namespace Test
{
- [MoonSharpUserData]
- class MyClass
- {
- public double calcHypotenuse(double a, double b)
- {
- return Math.Sqrt(a * a + b * b);
- }
- }
-
class Program
{
static void Main(string[] args)
{
- string scriptCode = @"return obj.calcHypotenuse(3, 4);";
+ ((ScriptLoaderBase)Script.DefaultOptions.ScriptLoader).ModulePaths = new string[] { "./?", "./?.lua" };
+
+ try
+ {
+ Script S = new Script();
+ S.Options.ColonOperatorClrCallbackBehaviour = ColonOperatorBehaviour.TreatAsDotOnUserData;
+
+ S.DoString(@"
+
+require 'test'
+require 'test2'
- // Automatically register all MoonSharpUserData types
- UserData.RegisterAssembly();
+");
- Script script = new Script();
- // Pass an instance of MyClass to the script in a global
- script.Globals["obj"] = new MyClass();
+ }
+ catch (InterpreterException ex)
+ {
+ Console.WriteLine(ex.DecoratedMessage);
+ }
- DynValue res = script.DoString(scriptCode);
+ Console.WriteLine(">> DONE");
- return;
+ Console.ReadKey();
}
}
}
\ No newline at end of file
diff --git a/src/DevTools/Playground/core.lua b/src/DevTools/Playground/core.lua
new file mode 100644
index 00000000..450e9a29
--- /dev/null
+++ b/src/DevTools/Playground/core.lua
@@ -0,0 +1,5 @@
+
+print "in core.lua"
+
+print(os.date("*t", os.time()).hour)
+print(os.date("!*t", os.time()).hour)
diff --git a/src/DevTools/Playground/test.lua b/src/DevTools/Playground/test.lua
new file mode 100644
index 00000000..3761ebaf
--- /dev/null
+++ b/src/DevTools/Playground/test.lua
@@ -0,0 +1,2 @@
+require "core"
+print("in test 1")
diff --git a/src/DevTools/Playground/test2.lua b/src/DevTools/Playground/test2.lua
new file mode 100644
index 00000000..1431f0cd
--- /dev/null
+++ b/src/DevTools/Playground/test2.lua
@@ -0,0 +1,2 @@
+require "core"
+print("in test 2")
diff --git a/src/DevTools/SynchProjects/Program.cs b/src/DevTools/SynchProjects/Program.cs
old mode 100644
new mode 100755
index 6c8bbd8c..5597ec99
--- a/src/DevTools/SynchProjects/Program.cs
+++ b/src/DevTools/SynchProjects/Program.cs
@@ -99,6 +99,12 @@ private static string AdjustBasePath(string str)
static void Main(string[] args)
{
+ Console.ForegroundColor = ConsoleColor.Magenta;
+ Console.WriteLine("********************************************************");
+ Console.WriteLine("* !! REMEMBER TO RSYNC UNITY AND .NET CORE PROJECTS !! *");
+ Console.WriteLine("********************************************************");
+
+
const string INTERPRETER_PROJECT = @"{BASEPATH}\MoonSharp.Interpreter\MoonSharp.Interpreter.net35-client.csproj";
const string INTERPRETER_SUBPROJECTS_PATHS = @"{BASEPATH}\MoonSharp.Interpreter\_Projects\MoonSharp.Interpreter.{0}\MoonSharp.Interpreter.{0}.csproj";
const string INTERPRETER_PATH_PREFIX = @"..\..\";
@@ -107,12 +113,17 @@ static void Main(string[] args)
const string DEBUGGER_SUBPROJECTS_PATHS = @"{BASEPATH}\MoonSharp.RemoteDebugger\_Projects\MoonSharp.RemoteDebugger.{0}\MoonSharp.RemoteDebugger.{0}.csproj";
const string DEBUGGER_PATH_PREFIX = @"..\..\";
+ const string VSCODEDEBUGGER_PROJECT = @"{BASEPATH}\MoonSharp.VsCodeDebugger\MoonSharp.VsCodeDebugger.net35-client.csproj";
+ const string VSCODEDEBUGGER_SUBPROJECTS_PATHS = @"{BASEPATH}\MoonSharp.VsCodeDebugger\_Projects\MoonSharp.VsCodeDebugger.{0}\MoonSharp.VsCodeDebugger.{0}.csproj";
+ const string VSCODEDEBUGGER_PATH_PREFIX = @"..\..\";
+
const string TESTS_PROJECT = @"{BASEPATH}\MoonSharp.Interpreter.Tests\MoonSharp.Interpreter.Tests.net35-client.csproj";
const string TESTS_SUBPROJECTS_PATHS = @"{BASEPATH}\MoonSharp.Interpreter.Tests\_Projects\MoonSharp.Interpreter.Tests.{0}\MoonSharp.Interpreter.Tests.{0}.csproj";
const string TESTS_PATH_PREFIX = @"..\..\";
string[] INTERPRETER_PLATFORMS = new string[] { "net40-client", "portable40" };
string[] DEBUGGER_PLATFORMS = new string[] { "net40-client" };
+ string[] VSCODEDEBUGGER_PLATFORMS = new string[] { "net40-client" };
string[] TESTS_PLATFORMS = new string[] { "net40-client", "portable40", "Embeddable.portable40" };
CalcBasePath();
@@ -123,6 +134,9 @@ static void Main(string[] args)
foreach (string platform in DEBUGGER_PLATFORMS)
CopyCompileFilesAsLinks(platform, DEBUGGER_PROJECT, DEBUGGER_SUBPROJECTS_PATHS, DEBUGGER_PATH_PREFIX);
+ foreach (string platform in VSCODEDEBUGGER_PLATFORMS)
+ CopyCompileFilesAsLinks(platform, VSCODEDEBUGGER_PROJECT, VSCODEDEBUGGER_SUBPROJECTS_PATHS, VSCODEDEBUGGER_PATH_PREFIX);
+
foreach (string platform in TESTS_PLATFORMS)
CopyCompileFilesAsLinks(platform, TESTS_PROJECT, TESTS_SUBPROJECTS_PATHS, TESTS_PATH_PREFIX);
diff --git a/src/DevTools/VsCodeDebugger_Testbed/Program.cs b/src/DevTools/VsCodeDebugger_Testbed/Program.cs
new file mode 100755
index 00000000..93db7805
--- /dev/null
+++ b/src/DevTools/VsCodeDebugger_Testbed/Program.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using MoonSharp.Interpreter;
+using MoonSharp.VsCodeDebugger;
+using MoonSharp.VsCodeDebugger.SDK;
+
+namespace VsCodeDebugger_Testbed
+{
+ class Program
+ {
+ public static void Main(string[] argv)
+ {
+ MoonSharpVsCodeDebugServer server = new MoonSharpVsCodeDebugServer();
+ server.Logger = s => Console.WriteLine(s);
+ server.Start();
+
+ Script script1 = new Script();
+ script1.DoFile(@"Z:/HDD/temp/lua/fact.lua");
+ server.AttachToScript(script1, "Script #1");
+ Closure func1 = script1.Globals.Get("run").Function;
+
+ Script script2 = new Script();
+ script2.DoFile(@"Z:/HDD/temp/lua/fact2.lua");
+ server.AttachToScript(script2, "Script #2");
+ Closure func2 = script2.Globals.Get("run").Function;
+
+ Console.WriteLine("READY.");
+ int i = 0;
+
+ server.Current = null;
+
+ while (true)//(Console.ReadKey().Key != ConsoleKey.Escape)
+ {
+ if (Console.KeyAvailable)
+ {
+ Console.ReadKey();
+ server.Detach(script2);
+ Console.WriteLine("Detached");
+ }
+
+ Closure func = ((++i) % 2) == 0 ? func1 : func2;
+
+ try
+ {
+ var val = func.Call(5);
+ Console.ForegroundColor = ConsoleColor.Magenta;
+ Console.WriteLine(val.Number);
+ System.Threading.Thread.Sleep(1000);
+ }
+ catch (InterpreterException ex)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.Write(ex.DecoratedMessage);
+ }
+ }
+ }
+ }
+}
diff --git a/src/DevTools/VsCodeDebugger_Testbed/Properties/AssemblyInfo.cs b/src/DevTools/VsCodeDebugger_Testbed/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..3a7bab12
--- /dev/null
+++ b/src/DevTools/VsCodeDebugger_Testbed/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("VsCodeDebugger_Testbed")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("VsCodeDebugger_Testbed")]
+[assembly: AssemblyCopyright("Copyright © 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("d17dd647-76cf-4d87-bdf7-75e1704e8783")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/DevTools/VsCodeDebugger_Testbed/VsCodeDebugger_Testbed.csproj b/src/DevTools/VsCodeDebugger_Testbed/VsCodeDebugger_Testbed.csproj
new file mode 100644
index 00000000..dc30aa4c
--- /dev/null
+++ b/src/DevTools/VsCodeDebugger_Testbed/VsCodeDebugger_Testbed.csproj
@@ -0,0 +1,64 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {D17DD647-76CF-4D87-BDF7-75E1704E8783}
+ Exe
+ Properties
+ VsCodeDebugger_Testbed
+ VsCodeDebugger_Testbed
+ v3.5
+ 512
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {91ea9b9d-fe03-4273-bdaf-8ad42ede1e59}
+ MoonSharp.Interpreter.net35-client
+
+
+ {eb7d4595-299f-489b-90ac-55066a4675f9}
+ MoonSharp.VsCodeDebugger.net35-client
+
+
+
+
+
\ No newline at end of file
diff --git a/src/MoonSharp.Documentation/MoonSharp.Documentation.shfbproj b/src/MoonSharp.Documentation/MoonSharp.Documentation.shfbproj
index 03f693d2..74bbce11 100644
--- a/src/MoonSharp.Documentation/MoonSharp.Documentation.shfbproj
+++ b/src/MoonSharp.Documentation/MoonSharp.Documentation.shfbproj
@@ -7,7 +7,7 @@
AnyCPU
2.0
26b3033c-d1e2-4188-870c-d197e95a7f6b
- 1.9.9.0
+ 2015.6.5.0
MoonSharp.Documentation
MoonSharp.Documentation
diff --git a/src/MoonSharp.Hardwire/MoonSharp.Hardwire.net35-client.csproj b/src/MoonSharp.Hardwire/MoonSharp.Hardwire.net35-client.csproj
index dccd3b12..3c2247b7 100644
--- a/src/MoonSharp.Hardwire/MoonSharp.Hardwire.net35-client.csproj
+++ b/src/MoonSharp.Hardwire/MoonSharp.Hardwire.net35-client.csproj
@@ -29,6 +29,12 @@
prompt
4
+
+ true
+
+
+ keypair.snk
+
@@ -62,6 +68,9 @@
MoonSharp.Interpreter.net35-client
+
+
+
{2}", From, To, ToInclusive);
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/Scopes/RuntimeScopeFrame.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/Scopes/RuntimeScopeFrame.cs
new file mode 100644
index 00000000..0738dc3b
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/Scopes/RuntimeScopeFrame.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+
+namespace MoonSharp.Interpreter.Execution
+{
+ internal class RuntimeScopeFrame
+ {
+ public List DebugSymbols { get; private set; }
+ public int Count { get { return DebugSymbols.Count; } }
+ public int ToFirstBlock { get; internal set; }
+
+ public RuntimeScopeFrame()
+ {
+ DebugSymbols = new List();
+ }
+
+ public override string ToString()
+ {
+ return string.Format("ScopeFrame : #{0}", Count);
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/ScriptExecutionContext.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/ScriptExecutionContext.cs
new file mode 100644
index 00000000..0a42ccfb
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/ScriptExecutionContext.cs
@@ -0,0 +1,269 @@
+using System;
+using MoonSharp.Interpreter.Debugging;
+using MoonSharp.Interpreter.Execution.VM;
+using MoonSharp.Interpreter.Interop.LuaStateInterop;
+
+namespace MoonSharp.Interpreter
+{
+ ///
+ /// Class giving access to details of the environment where the script is executing
+ ///
+ public class ScriptExecutionContext : IScriptPrivateResource
+ {
+ Processor m_Processor;
+ CallbackFunction m_Callback;
+
+ internal ScriptExecutionContext(Processor p, CallbackFunction callBackFunction, SourceRef sourceRef, bool isDynamic = false)
+ {
+ IsDynamicExecution = isDynamic;
+ m_Processor = p;
+ m_Callback = callBackFunction;
+ CallingLocation = sourceRef;
+ }
+
+ ///
+ /// Gets a value indicating whether this instance is running a dynamic execution.
+ /// Under a dynamic execution, most methods of ScriptExecutionContext are not reliable as the
+ /// processing engine of the script is not "really" running or is not available.
+ ///
+ public bool IsDynamicExecution
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Gets the location of the code calling back
+ ///
+ public SourceRef CallingLocation
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Gets or sets the additional data associated to this CLR function call.
+ ///
+ public object AdditionalData
+ {
+ get { return (m_Callback != null) ? m_Callback.AdditionalData : null; }
+ set
+ {
+ if (m_Callback == null) throw new InvalidOperationException("Cannot set additional data on a context which has no callback");
+ m_Callback.AdditionalData = value;
+ }
+ }
+
+
+ ///
+ /// Gets the metatable associated with the given value.
+ ///
+ /// The value.
+ ///
+ public Table GetMetatable(DynValue value)
+ {
+ return m_Processor.GetMetatable(value);
+ }
+
+
+ ///
+ /// Gets the specified metamethod associated with the given value.
+ ///
+ /// The value.
+ /// The metamethod name.
+ ///
+ public DynValue GetMetamethod(DynValue value, string metamethod)
+ {
+ return m_Processor.GetMetamethod(value, metamethod);
+ }
+
+ ///
+ /// prepares a tail call request for the specified metamethod, or null if no metamethod is found.
+ ///
+ public DynValue GetMetamethodTailCall(DynValue value, string metamethod, params DynValue[] args)
+ {
+ DynValue meta = this.GetMetamethod(value, metamethod);
+ if (meta == null) return null;
+ return DynValue.NewTailCallReq(meta, args);
+ }
+
+ ///
+ /// Gets the metamethod to be used for a binary operation using op1 and op2.
+ ///
+ public DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventName)
+ {
+ return m_Processor.GetBinaryMetamethod(op1, op2, eventName);
+ }
+
+ ///
+ /// Gets the script object associated with this request
+ ///
+ ///
+ public Script GetScript()
+ {
+ return m_Processor.GetScript();
+ }
+
+ ///
+ /// Gets the coroutine which is performing the call
+ ///
+ public Coroutine GetCallingCoroutine()
+ {
+ return m_Processor.AssociatedCoroutine;
+ }
+
+ ///
+ /// Calls a callback function implemented in "classic way".
+ /// Useful to port C code from Lua, or C# code from UniLua and KopiLua.
+ /// Lua : http://www.lua.org/
+ /// UniLua : http://github.com/xebecnan/UniLua
+ /// KopiLua : http://github.com/NLua/KopiLua
+ ///
+ /// The arguments.
+ /// Name of the function - for error messages.
+ /// The callback.
+ ///
+ public DynValue EmulateClassicCall(CallbackArguments args, string functionName, Func callback)
+ {
+ LuaState L = new LuaState(this, args, functionName);
+ int retvals = callback(L);
+ return L.GetReturnValue(retvals);
+ }
+
+ ///
+ /// Calls the specified function, supporting most cases. The called function must not yield.
+ ///
+ /// The function; it must be a Function or ClrFunction or have a call metamethod defined.
+ /// The arguments.
+ ///
+ /// If the function yields, returns a tail call request with continuations/handlers or, of course, if it encounters errors.
+ public DynValue Call(DynValue func, params DynValue[] args)
+ {
+ if (func.Type == DataType.Function)
+ {
+ return this.GetScript().Call(func, args);
+ }
+ else if (func.Type == DataType.ClrFunction)
+ {
+ while (true)
+ {
+ DynValue ret = func.Callback.Invoke(this, args, false);
+
+ if (ret.Type == DataType.YieldRequest)
+ {
+ throw ScriptRuntimeException.CannotYield();
+ }
+ else if (ret.Type == DataType.TailCallRequest)
+ {
+ var tail = ret.TailCallData;
+
+ if (tail.Continuation != null || tail.ErrorHandler != null)
+ {
+ throw new ScriptRuntimeException("the function passed cannot be called directly. wrap in a script function instead.");
+ }
+ else
+ {
+ args = tail.Args;
+ func = tail.Function;
+ }
+ }
+ else
+ {
+ return ret;
+ }
+ }
+ }
+ else
+ {
+ int maxloops = 10;
+
+ while (maxloops > 0)
+ {
+ DynValue v = this.GetMetamethod(func, "__call");
+
+ if (v == null && v.IsNil())
+ {
+ throw ScriptRuntimeException.AttemptToCallNonFunc(func.Type);
+ }
+
+ func = v;
+
+ if (func.Type == DataType.Function || func.Type == DataType.ClrFunction)
+ {
+ return Call(func, args);
+ }
+ }
+
+ throw ScriptRuntimeException.LoopInCall();
+ }
+ }
+
+ ///
+ /// Tries to get the reference of a symbol in the current execution state
+ ///
+ public DynValue EvaluateSymbol(SymbolRef symref)
+ {
+ if (symref == null)
+ return DynValue.Nil;
+
+ return m_Processor.GetGenericSymbol(symref);
+ }
+
+ ///
+ /// Tries to get the value of a symbol in the current execution state
+ ///
+ public DynValue EvaluateSymbolByName(string symbol)
+ {
+ return this.EvaluateSymbol(this.FindSymbolByName(symbol));
+ }
+
+ ///
+ /// Finds a symbol by name in the current execution state
+ ///
+ public SymbolRef FindSymbolByName(string symbol)
+ {
+ return m_Processor.FindSymbolByName(symbol);
+ }
+
+ ///
+ /// Gets the current global env, or null if not found.
+ ///
+ public Table CurrentGlobalEnv
+ {
+ get
+ {
+ DynValue env = EvaluateSymbolByName(WellKnownSymbols.ENV);
+
+ if (env == null || env.Type != DataType.Table)
+ return null;
+ else return env.Table;
+ }
+ }
+
+ ///
+ /// Performs a message decoration before unwinding after an error. To be used in the implementation of xpcall like functions.
+ ///
+ /// The message handler.
+ /// The exception.
+ public void PerformMessageDecorationBeforeUnwind(DynValue messageHandler, ScriptRuntimeException exception)
+ {
+ if (messageHandler != null)
+ exception.DecoratedMessage = m_Processor.PerformMessageDecorationBeforeUnwind(messageHandler, exception.Message, CallingLocation);
+ else
+ exception.DecoratedMessage = exception.Message;
+ }
+
+
+ ///
+ /// Gets the script owning this resource.
+ ///
+ ///
+ /// The script owning this resource.
+ ///
+ public Script OwnerScript
+ {
+ get { return this.GetScript(); }
+ }
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/ScriptLoadingContext.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/ScriptLoadingContext.cs
new file mode 100644
index 00000000..69093c10
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/ScriptLoadingContext.cs
@@ -0,0 +1,21 @@
+using MoonSharp.Interpreter.Debugging;
+using MoonSharp.Interpreter.Tree;
+
+namespace MoonSharp.Interpreter.Execution
+{
+ class ScriptLoadingContext
+ {
+ public Script Script { get; private 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;
+ }
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/ByteCode.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/ByteCode.cs
new file mode 100755
index 00000000..41a66e89
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/ByteCode.cs
@@ -0,0 +1,331 @@
+#define EMIT_DEBUG_OPS
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using MoonSharp.Interpreter.Debugging;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ internal class ByteCode : RefIdObject
+ {
+ public List Code = new List();
+ public Script Script { get; private set; }
+ private List m_SourceRefStack = new List();
+ private SourceRef m_CurrentSourceRef = null;
+
+ internal LoopTracker LoopTracker = new LoopTracker();
+
+ public ByteCode(Script script)
+ {
+ Script = script;
+ }
+
+
+ public IDisposable EnterSource(SourceRef sref)
+ {
+ return new SourceCodeStackGuard(sref, this);
+ }
+
+
+ private class SourceCodeStackGuard : IDisposable
+ {
+ ByteCode m_Bc;
+
+ public SourceCodeStackGuard(SourceRef sref, ByteCode bc)
+ {
+ m_Bc = bc;
+ m_Bc.PushSourceRef(sref);
+ }
+
+ public void Dispose()
+ {
+ m_Bc.PopSourceRef();
+ }
+ }
+
+
+ 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;
+ }
+
+ #if (!PCL) && ((!UNITY_5) || UNITY_STANDALONE) && (!(NETFX_CORE))
+ public void Dump(string file)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ for (int i = 0; i < Code.Count; i++)
+ {
+ if (Code[i].OpCode == OpCode.Debug)
+ sb.AppendFormat(" {0}\n", Code[i]);
+ else
+ sb.AppendFormat("{0:X8} {1}\n", i, Code[i]);
+ }
+
+ File.WriteAllText(file, sb.ToString());
+ }
+ #endif
+
+ public int GetJumpPointForNextInstruction()
+ {
+ return Code.Count;
+ }
+ public int GetJumpPointForLastInstruction()
+ {
+ return Code.Count - 1;
+ }
+
+ public Instruction GetLastInstruction()
+ {
+ return Code[Code.Count - 1];
+ }
+
+ private 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)
+ {
+ var i = 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 i;
+ }
+
+
+ [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 o;
+ if (isNameIndex) o = OpCode.IndexN;
+ else if (isExpList) o = OpCode.IndexL;
+ else o = OpCode.Index;
+
+ return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = o, Value = index });
+ }
+
+ public Instruction Emit_IndexSet(int stackofs, int tupleidx, DynValue index = null, bool isNameIndex = false, bool isExpList = false)
+ {
+ OpCode o;
+ if (isNameIndex) o = OpCode.IndexSetN;
+ else if (isExpList) o = OpCode.IndexSetL;
+ else o = OpCode.IndexSet;
+
+ return AppendInstruction(new Instruction(m_CurrentSourceRef) { OpCode = o, 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 });
+ }
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/CallStackItem.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/CallStackItem.cs
new file mode 100644
index 00000000..9d29fb9c
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/CallStackItem.cs
@@ -0,0 +1,25 @@
+using MoonSharp.Interpreter.Debugging;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ internal 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;
+ }
+
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/CallStackItemFlags.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/CallStackItemFlags.cs
new file mode 100644
index 00000000..9e6d6eae
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/CallStackItemFlags.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ [Flags]
+ internal enum CallStackItemFlags
+ {
+ None = 0,
+
+ EntryPoint = 1,
+ ResumeEntryPoint = 3,
+ CallEntryPoint = 5,
+
+ TailCall = 0x10,
+ MethodCall = 0x20,
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/ExecutionState.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/ExecutionState.cs
new file mode 100644
index 00000000..ed35fc3d
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/ExecutionState.cs
@@ -0,0 +1,12 @@
+using MoonSharp.Interpreter.DataStructs;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ internal sealed class ExecutionState
+ {
+ public FastStack ValueStack = new FastStack(131072);
+ public FastStack ExecutionStack = new FastStack(131072);
+ public int InstructionPtr = 0;
+ public CoroutineState State = CoroutineState.NotStarted;
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Instruction.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Instruction.cs
new file mode 100644
index 00000000..c6034014
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Instruction.cs
@@ -0,0 +1,226 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using MoonSharp.Interpreter.Debugging;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ internal class Instruction
+ {
+ internal OpCode OpCode;
+ internal SymbolRef Symbol;
+ internal SymbolRef[] SymbolList;
+ internal string Name;
+ internal DynValue Value;
+ internal int NumVal;
+ internal int NumVal2;
+ internal SourceRef SourceCodeRef;
+
+ internal Instruction(SourceRef sourceref)
+ {
+ SourceCodeRef = sourceref;
+ }
+
+ public override string ToString()
+ {
+ string append = this.OpCode.ToString().ToUpperInvariant();
+
+ int usage = (int)OpCode.GetFieldUsage();
+
+ if (usage != 0)
+ append += GenSpaces();
+
+ if ((this.OpCode == VM.OpCode.Meta) ||((usage & ((int)InstructionFieldUsage.NumValAsCodeAddress)) == (int)InstructionFieldUsage.NumValAsCodeAddress))
+ append += " " + NumVal.ToString("X8");
+ else if ((usage & ((int)InstructionFieldUsage.NumVal)) != 0)
+ append += " " + NumVal.ToString();
+
+ if ((usage & ((int)InstructionFieldUsage.NumVal2)) != 0)
+ append += " " + NumVal2.ToString();
+
+ if ((usage & ((int)InstructionFieldUsage.Name)) != 0)
+ append += " " + Name;
+
+ if ((usage & ((int)InstructionFieldUsage.Value)) != 0)
+ append += " " + PurifyFromNewLines(Value);
+
+ if ((usage & ((int)InstructionFieldUsage.Symbol)) != 0)
+ append += " " + Symbol;
+
+ if (((usage & ((int)InstructionFieldUsage.SymbolList)) != 0) && (SymbolList != null))
+ append += " " + string.Join(",", SymbolList.Select(s => s.ToString()).ToArray());
+
+ return append;
+ }
+
+ private string PurifyFromNewLines(DynValue Value)
+ {
+ if (Value == null)
+ return "";
+
+ return Value.ToString().Replace('\n', ' ').Replace('\r', ' ');
+ }
+
+ private string GenSpaces()
+ {
+ return new string(' ', 10 - this.OpCode.ToString().Length);
+ }
+
+ internal void WriteBinary(BinaryWriter wr, int baseAddress, Dictionary symbolMap)
+ {
+ wr.Write((byte)this.OpCode);
+
+ int usage = (int)OpCode.GetFieldUsage();
+
+ if ((usage & ((int)InstructionFieldUsage.NumValAsCodeAddress)) == (int)InstructionFieldUsage.NumValAsCodeAddress)
+ wr.Write(this.NumVal - baseAddress);
+ else if ((usage & ((int)InstructionFieldUsage.NumVal)) != 0)
+ wr.Write(this.NumVal);
+
+ if ((usage & ((int)InstructionFieldUsage.NumVal2)) != 0)
+ wr.Write(this.NumVal2);
+
+ if ((usage & ((int)InstructionFieldUsage.Name)) != 0)
+ wr.Write(Name ?? "");
+
+ if ((usage & ((int)InstructionFieldUsage.Value)) != 0)
+ DumpValue(wr, Value);
+
+ if ((usage & ((int)InstructionFieldUsage.Symbol)) != 0)
+ WriteSymbol(wr, Symbol, symbolMap);
+
+ if ((usage & ((int)InstructionFieldUsage.SymbolList)) != 0)
+ {
+ wr.Write(this.SymbolList.Length);
+ for (int i = 0; i < this.SymbolList.Length; i++)
+ WriteSymbol(wr, SymbolList[i], symbolMap);
+ }
+ }
+
+ private static void WriteSymbol(BinaryWriter wr, SymbolRef symbolRef, Dictionary symbolMap)
+ {
+ int id = (symbolRef == null) ? -1 : symbolMap[symbolRef];
+ wr.Write(id);
+ }
+
+ private static SymbolRef ReadSymbol(BinaryReader rd, SymbolRef[] deserializedSymbols)
+ {
+ int id = rd.ReadInt32();
+
+ if (id < 0) return null;
+ return deserializedSymbols[id];
+ }
+
+ internal static Instruction ReadBinary(SourceRef chunkRef, BinaryReader rd, int baseAddress, Table envTable, SymbolRef[] deserializedSymbols)
+ {
+ Instruction that = new Instruction(chunkRef);
+
+ that.OpCode = (OpCode)rd.ReadByte();
+
+ int usage = (int)that.OpCode.GetFieldUsage();
+
+ if ((usage & ((int)InstructionFieldUsage.NumValAsCodeAddress)) == (int)InstructionFieldUsage.NumValAsCodeAddress)
+ that.NumVal = rd.ReadInt32() + baseAddress;
+ else if ((usage & ((int)InstructionFieldUsage.NumVal)) != 0)
+ that.NumVal = rd.ReadInt32();
+
+ if ((usage & ((int)InstructionFieldUsage.NumVal2)) != 0)
+ that.NumVal2 = rd.ReadInt32();
+
+ if ((usage & ((int)InstructionFieldUsage.Name)) != 0)
+ that.Name = rd.ReadString();
+
+ if ((usage & ((int)InstructionFieldUsage.Value)) != 0)
+ that.Value = ReadValue(rd, envTable);
+
+ if ((usage & ((int)InstructionFieldUsage.Symbol)) != 0)
+ that.Symbol = ReadSymbol(rd, deserializedSymbols);
+
+ if ((usage & ((int)InstructionFieldUsage.SymbolList)) != 0)
+ {
+ int len = rd.ReadInt32();
+ that.SymbolList = new SymbolRef[len];
+
+ for (int i = 0; i < that.SymbolList.Length; i++)
+ that.SymbolList[i] = ReadSymbol(rd, deserializedSymbols);
+ }
+
+ return that;
+ }
+
+ private static DynValue ReadValue(BinaryReader rd, Table envTable)
+ {
+ bool isnull = !rd.ReadBoolean();
+
+ if (isnull) return null;
+
+ DataType dt = (DataType)rd.ReadByte();
+
+ switch (dt)
+ {
+ case DataType.Nil:
+ return DynValue.NewNil();
+ case DataType.Void:
+ return DynValue.Void;
+ case DataType.Boolean:
+ return DynValue.NewBoolean(rd.ReadBoolean());
+ case DataType.Number:
+ return DynValue.NewNumber(rd.ReadDouble());
+ case DataType.String:
+ return DynValue.NewString(rd.ReadString());
+ case DataType.Table :
+ return DynValue.NewTable(envTable);
+ default:
+ throw new NotSupportedException(string.Format("Unsupported type in chunk dump : {0}", dt));
+ }
+ }
+
+
+ private void DumpValue(BinaryWriter wr, DynValue value)
+ {
+ if (value == null)
+ {
+ wr.Write(false);
+ return;
+ }
+
+ wr.Write(true);
+ wr.Write((byte)value.Type);
+
+ switch (value.Type)
+ {
+ case DataType.Nil:
+ case DataType.Void:
+ case DataType.Table:
+ break;
+ 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(string.Format("Unsupported type in chunk dump : {0}", value.Type));
+ }
+ }
+
+ internal void GetSymbolReferences(out SymbolRef[] symbolList, out SymbolRef symbol)
+ {
+ int usage = (int)OpCode.GetFieldUsage();
+
+ symbol = null;
+ symbolList = null;
+
+ if ((usage & ((int)InstructionFieldUsage.Symbol)) != 0)
+ symbol = this.Symbol;
+
+ if ((usage & ((int)InstructionFieldUsage.SymbolList)) != 0)
+ symbolList = this.SymbolList;
+
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/OpCode.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/OpCode.cs
new file mode 100644
index 00000000..15ba552b
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/OpCode.cs
@@ -0,0 +1,77 @@
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ internal enum OpCode
+ {
+ // Meta-opcodes
+ Nop, // Does not perform any operation.
+ Debug, // Does not perform any operation. Used to help debugging.
+
+ // Stack ops and assignment
+ Pop, // Discards the topmost n elements from the v-stack.
+ Copy, // Copies the n-th value of the stack on the top
+ Swap, // Swaps two entries relative to the v-stack
+ Literal, // Pushes a literal (constant value) on the stack.
+ Closure, // Creates a closure on the top of the v-stack, using the symbols for upvalues and num-val for entry point of the function.
+ NewTable, // Creates a new empty table on the stack
+ TblInitN, // Initializes a table named entry
+ TblInitI, // Initializes a table positional entry
+
+ StoreLcl, Local,
+ StoreUpv, Upvalue,
+ IndexSet, Index,
+ IndexSetN, IndexN,
+ IndexSetL, IndexL,
+
+ // Stack-frame ops and calls
+ Clean, // Cleansup locals setting them as null
+
+ Meta, // Injects function metadata used for reflection things (dumping, debugging)
+ BeginFn, // Adjusts for start of function, taking in parameters and allocating locals
+ Args, // Takes the arguments passed to a function and sets the appropriate symbols in the local scope
+ Call, // Calls the function specified on the specified element from the top of the v-stack. If the function is a MoonSharp function, it pushes its numeric value on the v-stack, then pushes the current PC onto the x-stack, enters the function closure and jumps to the function first instruction. If the function is a CLR function, it pops the function value from the v-stack, then invokes the function synchronously and finally pushes the result on the v-stack.
+ ThisCall, // Same as call, but the call is a ':' method invocation
+ Ret, // Pops the top n values of the v-stack. Then pops an X value from the v-stack. Then pops X values from the v-stack. Afterwards, it pushes the top n values popped in the first step, pops the top of the x-stack and jumps to that location.
+
+ // Jumps
+ Jump, // Jumps to the specified PC
+ Jf, // Pops the top of the v-stack and jumps to the specified location if it's false
+ JNil, // Jumps if the top of the stack is nil
+ JFor, // Peeks at the top, top-1 and top-2 values of the v-stack which it assumes to be numbers. Then if top-1 is less than zero, checks if top is <= top-2, otherwise it checks that top is >= top-2. Then if the condition is false, it jumps.
+ JtOrPop, // Peeks at the topmost value of the v-stack as a boolean. If true, it performs a jump, otherwise it removes the topmost value from the v-stack.
+ JfOrPop, // Peeks at the topmost value of the v-stack as a boolean. If false, it performs a jump, otherwise it removes the topmost value from the v-stack.
+
+ // Operators
+ Concat, // Concatenation of the two topmost operands on the v-stack
+ LessEq, // Compare <= of the two topmost operands on the v-stack
+ Less, // Compare < of the two topmost operands on the v-stack
+ Eq, // Compare == of the two topmost operands on the v-stack
+ Add, // Addition of the two topmost operands on the v-stack
+ Sub, // Subtraction of the two topmost operands on the v-stack
+ Mul, // Multiplication of the two topmost operands on the v-stack
+ Div, // Division of the two topmost operands on the v-stack
+ Mod, // Modulus of the two topmost operands on the v-stack
+ Not, // Logical inversion of the topmost operand on the v-stack
+ Len, // Size operator of the topmost operand on the v-stack
+ Neg, // Negation (unary minus) operator of the topmost operand on the v-stack
+ Power, // Power of the two topmost operands on the v-stack
+ CNot, // Conditional NOT - takes second operand from the v-stack (must be bool), if true execs a NOT otherwise execs a TOBOOL
+
+
+ // Type conversions and manipulations
+ MkTuple, // Creates a tuple from the topmost n values
+ Scalar, // Converts the topmost tuple to a scalar
+ Incr, // Performs an add operation, without extracting the operands from the v-stack and assuming the operands are numbers.
+ ToNum, // Converts the top of the stack to a number
+ ToBool, // Converts the top of the stack to a boolean
+ ExpTuple, // Expands a tuple on the stack
+
+
+ // Iterators
+ IterPrep, // Prepares an iterator for execution
+ IterUpd, // Updates the var part of an iterator
+
+ // Meta
+ Invalid, // Crashes the executor with an unrecoverable NotImplementedException. This MUST always be the last opcode in enum
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/OpCodeMetadataType.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/OpCodeMetadataType.cs
new file mode 100644
index 00000000..8b5dd3fd
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/OpCodeMetadataType.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ public enum OpCodeMetadataType
+ {
+ ChunkEntrypoint,
+ FunctionEntrypoint,
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/DebugContext.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/DebugContext.cs
new file mode 100644
index 00000000..eabe0f9d
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/DebugContext.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using MoonSharp.Interpreter.Debugging;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ sealed partial class Processor
+ {
+ private class DebugContext
+ {
+ public bool DebuggerEnabled = true;
+ public IDebugger DebuggerAttached = null;
+ public DebuggerAction.ActionType DebuggerCurrentAction = DebuggerAction.ActionType.None;
+ public int DebuggerCurrentActionTarget = -1;
+ public SourceRef LastHlRef = null;
+ public int ExStackDepthAtStep = -1;
+ public List BreakPoints = new List();
+ public bool LineBasedBreakPoints = false;
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor.cs
new file mode 100755
index 00000000..7e2a068f
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor.cs
@@ -0,0 +1,167 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using MoonSharp.Interpreter.DataStructs;
+using MoonSharp.Interpreter.Debugging;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ sealed partial class Processor
+ {
+ ByteCode m_RootChunk;
+
+ FastStack m_ValueStack = new FastStack(131072);
+ FastStack m_ExecutionStack = new FastStack(131072);
+ List m_CoroutinesStack;
+
+ Table m_GlobalTable;
+ Script m_Script;
+ Processor m_Parent = null;
+ CoroutineState m_State;
+ bool m_CanYield = true;
+ int m_SavedInstructionPtr = -1;
+ DebugContext m_Debug;
+
+ 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)); // creates an associated coroutine for the main processor
+ }
+
+ private 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 coroutinesStack = m_Parent != null ? m_Parent.m_CoroutinesStack : this.m_CoroutinesStack;
+
+ if (coroutinesStack.Count > 0 && coroutinesStack[coroutinesStack.Count - 1] != this)
+ return coroutinesStack[coroutinesStack.Count - 1].Call(function, args);
+
+ EnterProcessor();
+
+ try
+ {
+ var stopwatch = this.m_Script.PerformanceStats.StartStopwatch(Diagnostics.PerformanceCounter.Execution);
+
+ m_CanYield = false;
+
+ try
+ {
+ int entrypoint = PushClrToScriptStackFrame(CallStackItemFlags.CallEntryPoint, function, args);
+ return Processing_Loop(entrypoint);
+ }
+ finally
+ {
+ m_CanYield = true;
+
+ if (stopwatch != null)
+ stopwatch.Dispose();
+ }
+ }
+ finally
+ {
+ LeaveProcessor();
+ }
+ }
+
+ // pushes all what's required to perform a clr-to-script function call. function can be null if it's already
+ // at vstack top.
+ private int PushClrToScriptStackFrame(CallStackItemFlags flags, DynValue function, DynValue[] args)
+ {
+ if (function == null)
+ function = m_ValueStack.Peek();
+ else
+ m_ValueStack.Push(function); // func val
+
+ args = Internal_AdjustTuple(args);
+
+ for (int i = 0; i < args.Length; i++)
+ m_ValueStack.Push(args[i]);
+
+ m_ValueStack.Push(DynValue.NewNumber(args.Length)); // func args count
+
+ 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;
+ }
+
+
+ int m_OwningThreadID = -1;
+ int m_ExecutionNesting = 0;
+
+ private void LeaveProcessor()
+ {
+ m_ExecutionNesting -= 1;
+ 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();
+ }
+ }
+
+ int GetThreadId()
+ {
+ #if ENABLE_DOTNET || NETFX_CORE
+ return 1;
+ #else
+ return Thread.CurrentThread.ManagedThreadId;
+ #endif
+ }
+
+ private void EnterProcessor()
+ {
+ int threadID = GetThreadId();
+
+ if (m_OwningThreadID >= 0 && m_OwningThreadID != threadID && m_Script.Options.CheckThreadAccess)
+ {
+ string msg = string.Format("Cannot enter the same MoonSharp processor from two different threads : {0} and {1}", m_OwningThreadID, threadID);
+ throw new InvalidOperationException(msg);
+ }
+
+ m_OwningThreadID = threadID;
+
+ m_ExecutionNesting += 1;
+
+ if (m_Parent != null)
+ {
+ m_Parent.m_CoroutinesStack.Add(this);
+ }
+ }
+
+ internal SourceRef GetCoroutineSuspendedLocation()
+ {
+ return GetCurrentSourceRef(m_SavedInstructionPtr);
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_BinaryDump.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_BinaryDump.cs
new file mode 100644
index 00000000..549ee9d3
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_BinaryDump.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using MoonSharp.Interpreter.Debugging;
+using MoonSharp.Interpreter.IO;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ sealed partial class Processor
+ {
+ const ulong DUMP_CHUNK_MAGIC = 0x1A0D234E4F4F4D1D;
+ const int DUMP_CHUNK_VERSION = 0x150;
+
+ internal static bool IsDumpStream(Stream stream)
+ {
+ if (stream.Length >= 8)
+ {
+ using (BinaryReader br = new BinaryReader(stream, Encoding.UTF8))
+ {
+ ulong magic = br.ReadUInt64();
+ stream.Seek(-8, SeekOrigin.Current);
+ return magic == DUMP_CHUNK_MAGIC;
+ }
+ }
+ return false;
+ }
+
+ internal int Dump(Stream stream, int baseAddress, bool hasUpvalues)
+ {
+ using (BinaryWriter bw = new BinDumpBinaryWriter(stream, Encoding.UTF8))
+ {
+ Dictionary symbolMap = new Dictionary();
+
+ Instruction meta = FindMeta(ref baseAddress);
+
+ if (meta == null)
+ throw new ArgumentException("baseAddress");
+
+ bw.Write(DUMP_CHUNK_MAGIC);
+ bw.Write(DUMP_CHUNK_VERSION);
+ bw.Write(hasUpvalues);
+ bw.Write(meta.NumVal);
+
+ for (int i = 0; i <= meta.NumVal; i++)
+ {
+ SymbolRef[] symbolList;
+ SymbolRef symbol;
+
+ m_RootChunk.Code[baseAddress + i].GetSymbolReferences(out symbolList, out symbol);
+
+ if (symbol != null)
+ AddSymbolToMap(symbolMap, symbol);
+
+ if (symbolList != null)
+ foreach (var s in symbolList)
+ AddSymbolToMap(symbolMap, s);
+ }
+
+ foreach (SymbolRef sr in symbolMap.Keys.ToArray())
+ {
+ if (sr.i_Env != null)
+ AddSymbolToMap(symbolMap, sr.i_Env);
+ }
+
+ SymbolRef[] allSymbols = new SymbolRef[symbolMap.Count];
+
+ foreach (KeyValuePair pair in symbolMap)
+ {
+ allSymbols[pair.Value] = pair.Key;
+ }
+
+ bw.Write(symbolMap.Count);
+
+ foreach (SymbolRef sym in allSymbols)
+ sym.WriteBinary(bw);
+
+ foreach (SymbolRef sym in allSymbols)
+ sym.WriteBinaryEnv(bw, symbolMap);
+
+ for (int i = 0; i <= meta.NumVal; i++)
+ m_RootChunk.Code[baseAddress + i].WriteBinary(bw, baseAddress, symbolMap);
+
+ return meta.NumVal + baseAddress + 1;
+ }
+ }
+
+ private void AddSymbolToMap(Dictionary symbolMap, SymbolRef s)
+ {
+ if (!symbolMap.ContainsKey(s))
+ symbolMap.Add(s, symbolMap.Count);
+ }
+
+ internal int Undump(Stream stream, int sourceID, Table envTable, out bool hasUpvalues)
+ {
+ int baseAddress = m_RootChunk.Code.Count;
+ SourceRef sourceRef = new SourceRef(sourceID, 0, 0, 0, 0, false);
+
+ using (BinaryReader br = new BinDumpBinaryReader(stream, Encoding.UTF8))
+ {
+ ulong headerMark = br.ReadUInt64();
+
+ if (headerMark != DUMP_CHUNK_MAGIC)
+ throw new ArgumentException("Not a MoonSharp chunk");
+
+ int version = br.ReadInt32();
+
+ if (version != DUMP_CHUNK_VERSION)
+ throw new ArgumentException("Invalid version");
+
+ hasUpvalues = br.ReadBoolean();
+
+ int len = br.ReadInt32();
+
+ int numSymbs = br.ReadInt32();
+ SymbolRef[] allSymbs = new SymbolRef[numSymbs];
+
+ for (int i = 0; i < numSymbs; i++)
+ allSymbs[i] = SymbolRef.ReadBinary(br);
+
+ for (int i = 0; i < numSymbs; i++)
+ allSymbs[i].ReadBinaryEnv(br, allSymbs);
+
+ for (int i = 0; i <= len; i++)
+ {
+ Instruction I = Instruction.ReadBinary(sourceRef, br, baseAddress, envTable, allSymbs);
+ m_RootChunk.Code.Add(I);
+ }
+
+ return baseAddress;
+ }
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Coroutines.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Coroutines.cs
new file mode 100644
index 00000000..a9664670
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Coroutines.cs
@@ -0,0 +1,91 @@
+using System;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ // This part is practically written procedural style - it looks more like C than C#.
+ // This is intentional so to avoid this-calls and virtual-calls as much as possible.
+ // Same reason for the "sealed" declaration.
+ sealed partial class Processor
+ {
+ public DynValue Coroutine_Create(Closure closure)
+ {
+ // create a processor instance
+ Processor P = new Processor(this);
+
+ // Put the closure as first value on the stack, for future reference
+ P.m_ValueStack.Push(DynValue.NewClosure(closure));
+
+ // Return the coroutine handle
+ return DynValue.NewCoroutine(new Coroutine(P));
+ }
+
+ public CoroutineState State { get { return m_State; } }
+ public Coroutine AssociatedCoroutine { get; set; }
+
+ public DynValue Coroutine_Resume(DynValue[] args)
+ {
+ EnterProcessor();
+
+ try
+ {
+ int entrypoint = 0;
+
+ if (m_State != CoroutineState.NotStarted && m_State != CoroutineState.Suspended && m_State != CoroutineState.ForceSuspended)
+ throw ScriptRuntimeException.CannotResumeNotSuspended(m_State);
+
+ if (m_State == CoroutineState.NotStarted)
+ {
+ entrypoint = PushClrToScriptStackFrame(CallStackItemFlags.ResumeEntryPoint, null, args);
+ }
+ else if (m_State == CoroutineState.Suspended)
+ {
+ m_ValueStack.Push(DynValue.NewTuple(args));
+ entrypoint = 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.");
+
+ entrypoint = m_SavedInstructionPtr;
+ }
+
+ m_State = CoroutineState.Running;
+ DynValue retVal = Processing_Loop(entrypoint);
+
+ if (retVal.Type == DataType.YieldRequest)
+ {
+ if (retVal.YieldRequest.Forced)
+ {
+ m_State = CoroutineState.ForceSuspended;
+ return retVal;
+ }
+ else
+ {
+ m_State = CoroutineState.Suspended;
+ return DynValue.NewTuple(retVal.YieldRequest.ReturnValues);
+ }
+ }
+ else
+ {
+ m_State = CoroutineState.Dead;
+ return retVal;
+ }
+ }
+ catch (Exception)
+ {
+ // Unhandled exception - move to dead
+ m_State = CoroutineState.Dead;
+ throw;
+ }
+ finally
+ {
+ LeaveProcessor();
+ }
+ }
+
+
+
+ }
+
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Debugger.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Debugger.cs
new file mode 100755
index 00000000..f7878780
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Debugger.cs
@@ -0,0 +1,411 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MoonSharp.Interpreter.Debugging;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ // This part is practically written procedural style - it looks more like C than C#.
+ // This is intentional so to avoid this-calls and virtual-calls as much as possible.
+ // Same reason for the "sealed" declaration.
+ sealed partial class Processor
+ {
+ internal Instruction FindMeta(ref int baseAddress)
+ {
+ Instruction meta = m_RootChunk.Code[baseAddress];
+
+ // skip nops
+ while (meta.OpCode == OpCode.Nop)
+ {
+ baseAddress++;
+ meta = m_RootChunk.Code[baseAddress];
+ }
+
+ if (meta.OpCode != OpCode.Meta)
+ return null;
+
+ return meta;
+ }
+
+
+ internal void AttachDebugger(IDebugger debugger)
+ {
+ m_Debug.DebuggerAttached = debugger;
+ m_Debug.LineBasedBreakPoints = (debugger.GetDebuggerCaps() & DebuggerCaps.HasLineBasedBreakpoints) != 0;
+ debugger.SetDebugService(new DebugService(m_Script, this));
+ }
+
+ internal bool DebuggerEnabled
+ {
+ get { return m_Debug.DebuggerEnabled; }
+ set { m_Debug.DebuggerEnabled = value; }
+ }
+
+
+ private void ListenDebugger(Instruction instr, int instructionPtr)
+ {
+ bool isOnDifferentRef = false;
+
+ if (instr.SourceCodeRef != null && m_Debug.LastHlRef != null)
+ {
+ if (m_Debug.LineBasedBreakPoints)
+ {
+ isOnDifferentRef = instr.SourceCodeRef.SourceIdx != m_Debug.LastHlRef.SourceIdx ||
+ instr.SourceCodeRef.FromLine != m_Debug.LastHlRef.FromLine;
+ }
+ else
+ {
+ isOnDifferentRef = instr.SourceCodeRef != m_Debug.LastHlRef;
+ }
+ }
+ else if (m_Debug.LastHlRef == null)
+ {
+ isOnDifferentRef = instr.SourceCodeRef != null;
+ }
+
+
+ if (m_Debug.DebuggerAttached.IsPauseRequested() ||
+ (instr.SourceCodeRef != null && instr.SourceCodeRef.Breakpoint && isOnDifferentRef))
+ {
+ 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(false, instructionPtr);
+
+ while (true)
+ {
+ var action = m_Debug.DebuggerAttached.GetAction(instructionPtr, instr.SourceCodeRef);
+
+ switch (action.Action)
+ {
+ case DebuggerAction.ActionType.StepIn:
+ case DebuggerAction.ActionType.StepOver:
+ case DebuggerAction.ActionType.StepOut:
+ case DebuggerAction.ActionType.ByteCodeStepOut:
+ 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(true, instructionPtr);
+ break;
+ case DebuggerAction.ActionType.ResetBreakpoints:
+ ResetBreakPoints(action);
+ RefreshDebugger(true, instructionPtr);
+ break;
+ case DebuggerAction.ActionType.SetBreakpoint:
+ ToggleBreakPoint(action, true);
+ RefreshDebugger(true, instructionPtr);
+ break;
+ case DebuggerAction.ActionType.ClearBreakpoint:
+ ToggleBreakPoint(action, false);
+ RefreshDebugger(true, instructionPtr);
+ break;
+ case DebuggerAction.ActionType.Refresh:
+ RefreshDebugger(false, instructionPtr);
+ break;
+ case DebuggerAction.ActionType.HardRefresh:
+ RefreshDebugger(true, instructionPtr);
+ break;
+ case DebuggerAction.ActionType.None:
+ default:
+ break;
+ }
+ }
+ }
+
+ private void ResetBreakPoints(DebuggerAction action)
+ {
+ SourceCode src = m_Script.GetSourceCode(action.SourceID);
+ ResetBreakPoints(src, new HashSet(action.Lines));
+ }
+
+ internal HashSet ResetBreakPoints(SourceCode src, HashSet lines)
+ {
+ HashSet result = new HashSet();
+
+ foreach (SourceRef srf in src.Refs)
+ {
+ if (srf.CannotBreakpoint)
+ continue;
+
+ srf.Breakpoint = lines.Contains(srf.FromLine);
+
+ if (srf.Breakpoint)
+ result.Add(srf.FromLine);
+ }
+
+ return result;
+ }
+
+ private bool ToggleBreakPoint(DebuggerAction action, bool? state)
+ {
+ SourceCode src = m_Script.GetSourceCode(action.SourceID);
+
+ bool found = false;
+ foreach (SourceRef srf in src.Refs)
+ {
+ if (srf.CannotBreakpoint)
+ continue;
+
+ if (srf.IncludesLocation(action.SourceID, action.SourceLine, action.SourceCol))
+ {
+ found = true;
+
+ //System.Diagnostics.Debug.WriteLine(string.Format("BRK: found {0} for {1} on contains", srf, srf.Type));
+
+ if (state == null)
+ srf.Breakpoint = !srf.Breakpoint;
+ else
+ srf.Breakpoint = state.Value;
+
+ if (srf.Breakpoint)
+ {
+ m_Debug.BreakPoints.Add(srf);
+ }
+ else
+ {
+ m_Debug.BreakPoints.Remove(srf);
+ }
+ }
+ }
+
+ if (!found)
+ {
+ int minDistance = int.MaxValue;
+ SourceRef nearest = null;
+
+ foreach (SourceRef srf in src.Refs)
+ {
+ if (srf.CannotBreakpoint)
+ continue;
+
+ int dist = srf.GetLocationDistance(action.SourceID, action.SourceLine, action.SourceCol);
+
+ if (dist < minDistance)
+ {
+ minDistance = dist;
+ nearest = srf;
+ }
+ }
+
+ if (nearest != null)
+ {
+ //System.Diagnostics.Debug.WriteLine(string.Format("BRK: found {0} for {1} on distance {2}", nearest, nearest.Type, minDistance));
+
+ if (state == null)
+ nearest.Breakpoint = !nearest.Breakpoint;
+ else
+ nearest.Breakpoint = state.Value;
+
+ if (nearest.Breakpoint)
+ {
+ m_Debug.BreakPoints.Add(nearest);
+ }
+ else
+ {
+ m_Debug.BreakPoints.Remove(nearest);
+ }
+
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return true;
+ }
+
+ private void RefreshDebugger(bool hard, int instructionPtr)
+ {
+ SourceRef sref = GetCurrentSourceRef(instructionPtr);
+ ScriptExecutionContext context = new ScriptExecutionContext(this, null, sref);
+
+ List watchList = m_Debug.DebuggerAttached.GetWatchItems();
+ List callStack = Debugger_GetCallStack(sref);
+ List watches = Debugger_RefreshWatches(context, watchList);
+ List vstack = Debugger_RefreshVStack();
+ List locals = Debugger_RefreshLocals(context);
+ List threads = Debugger_RefreshThreads(context);
+
+ m_Debug.DebuggerAttached.Update(WatchType.CallStack, callStack);
+ m_Debug.DebuggerAttached.Update(WatchType.Watches, watches);
+ m_Debug.DebuggerAttached.Update(WatchType.VStack, vstack);
+ m_Debug.DebuggerAttached.Update(WatchType.Locals, locals);
+ m_Debug.DebuggerAttached.Update(WatchType.Threads, threads);
+
+ if (hard)
+ m_Debug.DebuggerAttached.RefreshBreakpoints(m_Debug.BreakPoints);
+ }
+
+ private List Debugger_RefreshThreads(ScriptExecutionContext context)
+ {
+ List coroutinesStack = m_Parent != null ? m_Parent.m_CoroutinesStack : this.m_CoroutinesStack;
+
+ return coroutinesStack.Select(c => new WatchItem()
+ {
+ Address = c.AssociatedCoroutine.ReferenceID,
+ Name = "coroutine #" + c.AssociatedCoroutine.ReferenceID.ToString()
+ }).ToList();
+ }
+
+ private List Debugger_RefreshVStack()
+ {
+ List lwi = new List();
+ for (int i = 0; i < Math.Min(32, m_ValueStack.Count); i++)
+ {
+ lwi.Add(new WatchItem()
+ {
+ Address = i,
+ Value = m_ValueStack.Peek(i)
+ });
+ }
+
+ return lwi;
+ }
+
+ private List Debugger_RefreshWatches(ScriptExecutionContext context, List watchList)
+ {
+ return watchList.Select(w => Debugger_RefreshWatch(context, w)).ToList();
+ }
+
+ private List Debugger_RefreshLocals(ScriptExecutionContext context)
+ {
+ List locals = new List();
+ var top = this.m_ExecutionStack.Peek();
+
+ if (top != null && top.Debug_Symbols != null && top.LocalScope != null)
+ {
+ int len = Math.Min(top.Debug_Symbols.Length, top.LocalScope.Length);
+
+ for (int i = 0; i < len; i++)
+ {
+ locals.Add(new WatchItem()
+ {
+ IsError = false,
+ LValue = top.Debug_Symbols[i],
+ Value = top.LocalScope[i],
+ Name = top.Debug_Symbols[i].i_Name
+ });
+ }
+ }
+
+ return locals;
+ }
+
+ private WatchItem Debugger_RefreshWatch(ScriptExecutionContext context, DynamicExpression dynExpr)
+ {
+ try
+ {
+ SymbolRef L = dynExpr.FindSymbol(context);
+ DynValue v = dynExpr.Evaluate(context);
+
+ return new WatchItem()
+ {
+ IsError = dynExpr.IsConstant(),
+ LValue = L,
+ Value = v,
+ Name = dynExpr.ExpressionCode
+ };
+ }
+ catch (Exception ex)
+ {
+ return new WatchItem()
+ {
+ IsError = true,
+ Value = DynValue.NewString(ex.Message),
+ Name = dynExpr.ExpressionCode
+ };
+ }
+ }
+
+ internal List Debugger_GetCallStack(SourceRef startingRef)
+ {
+ List wis = new List();
+
+ for (int i = 0; i < m_ExecutionStack.Count; i++)
+ {
+ var c = m_ExecutionStack.Peek(i);
+
+ var I = m_RootChunk.Code[c.Debug_EntryPoint];
+
+ string callname = I.OpCode == OpCode.Meta ? I.Name : null;
+
+ if (c.ClrFunction != null)
+ {
+ wis.Add(new WatchItem()
+ {
+ Address = -1,
+ BasePtr = -1,
+ RetAddress = c.ReturnAddress,
+ Location = startingRef,
+ Name = c.ClrFunction.Name
+ });
+ }
+ else
+ {
+ wis.Add(new WatchItem()
+ {
+ Address = c.Debug_EntryPoint,
+ BasePtr = c.BasePointer,
+ RetAddress = c.ReturnAddress,
+ Name = callname,
+ Location = startingRef,
+ });
+ }
+
+ startingRef = c.CallingSourceRef;
+
+ if (c.Continuation != null)
+ {
+ wis.Add(new WatchItem()
+ {
+ Name = c.Continuation.Name,
+ Location = SourceRef.GetClrLocation()
+ });
+ }
+
+
+ }
+
+ return wis;
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Errors.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Errors.cs
new file mode 100644
index 00000000..65e78659
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Errors.cs
@@ -0,0 +1,36 @@
+using MoonSharp.Interpreter.Debugging;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ sealed partial class Processor
+ {
+ private SourceRef GetCurrentSourceRef(int instructionPtr)
+ {
+ if (instructionPtr >= 0 && instructionPtr < m_RootChunk.Code.Count)
+ {
+ return m_RootChunk.Code[instructionPtr].SourceCodeRef;
+ }
+ return null;
+ }
+
+
+ private void FillDebugData(InterpreterException ex, int ip)
+ {
+ // adjust IP
+ if (ip == YIELD_SPECIAL_TRAP)
+ ip = m_SavedInstructionPtr;
+ else
+ ip -= 1;
+
+ ex.InstructionPtr = ip;
+
+ SourceRef sref = GetCurrentSourceRef(ip);
+
+ ex.DecorateMessage(m_Script, sref, ip);
+
+ ex.CallStack = Debugger_GetCallStack(sref);
+ }
+
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_IExecutionContext.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_IExecutionContext.cs
new file mode 100644
index 00000000..e826f240
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_IExecutionContext.cs
@@ -0,0 +1,94 @@
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ sealed partial class Processor
+ {
+ internal Table GetMetatable(DynValue value)
+ {
+ if (value.Type == DataType.Table)
+ {
+ return value.Table.MetaTable;
+ }
+ else if (value.Type.CanHaveTypeMetatables())
+ {
+ return m_Script.GetTypeMetatable(value.Type);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ internal DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventName)
+ {
+ var op1_MetaTable = GetMetatable(op1);
+ if (op1_MetaTable != null)
+ {
+ DynValue meta1 = op1_MetaTable.RawGet(eventName);
+ if (meta1 != null && meta1.IsNotNil())
+ return meta1;
+ }
+
+ var op2_MetaTable = GetMetatable(op2);
+ if (op2_MetaTable != null)
+ {
+ DynValue meta2 = op2_MetaTable.RawGet(eventName);
+ if (meta2 != null && meta2.IsNotNil())
+ return meta2;
+ }
+
+ if (op1.Type == DataType.UserData)
+ {
+ DynValue meta = op1.UserData.Descriptor.MetaIndex(this.m_Script,
+ op1.UserData.Object, eventName);
+
+ if (meta != null)
+ return meta;
+ }
+
+ if (op2.Type == DataType.UserData)
+ {
+ DynValue meta = op2.UserData.Descriptor.MetaIndex(this.m_Script,
+ op2.UserData.Object, eventName);
+
+ if (meta != null)
+ return meta;
+ }
+
+ return null;
+ }
+
+ internal DynValue GetMetamethod(DynValue value, string metamethod)
+ {
+ if (value.Type == DataType.UserData)
+ {
+ DynValue v = value.UserData.Descriptor.MetaIndex(m_Script, value.UserData.Object, metamethod);
+ if (v != null)
+ return v;
+ }
+
+ return GetMetamethodRaw(value, metamethod);
+ }
+
+
+ internal DynValue GetMetamethodRaw(DynValue value, string metamethod)
+ {
+ var metatable = GetMetatable(value);
+
+ if (metatable == null)
+ return null;
+
+ var metameth = metatable.RawGet(metamethod);
+
+ if (metameth == null || metameth.IsNil())
+ return null;
+
+ return metameth;
+ }
+
+ internal Script GetScript()
+ {
+ return m_Script;
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_InstructionLoop.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_InstructionLoop.cs
new file mode 100644
index 00000000..ec6c05b1
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_InstructionLoop.cs
@@ -0,0 +1,1370 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MoonSharp.Interpreter.DataStructs;
+using MoonSharp.Interpreter.Debugging;
+using MoonSharp.Interpreter.Interop;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ sealed partial class Processor
+ {
+ const int YIELD_SPECIAL_TRAP = -99;
+
+ internal long AutoYieldCounter = 0;
+
+ private DynValue Processing_Loop(int instructionPtr)
+ {
+ // This is the main loop of the processor, has a weird control flow and needs to be as fast as possible.
+ // This sentence is just a convoluted way to say "don't complain about gotos".
+
+ long executedInstructions = 0;
+ bool canAutoYield = (AutoYieldCounter > 0) && m_CanYield && (this.State != CoroutineState.Main);
+
+ repeat_execution:
+
+ try
+ {
+ while (true)
+ {
+ Instruction i = m_RootChunk.Code[instructionPtr];
+
+ if (m_Debug.DebuggerAttached != null)
+ {
+ ListenDebugger(i, instructionPtr);
+ }
+
+ ++executedInstructions;
+
+ if (canAutoYield && executedInstructions > AutoYieldCounter)
+ {
+ m_SavedInstructionPtr = instructionPtr;
+ return DynValue.NewForcedYieldReq();
+ }
+
+ ++instructionPtr;
+
+ switch (i.OpCode)
+ {
+ case OpCode.Nop:
+ case OpCode.Debug:
+ case OpCode.Meta:
+ break;
+ case OpCode.Pop:
+ m_ValueStack.RemoveLast(i.NumVal);
+ break;
+ case OpCode.Copy:
+ m_ValueStack.Push(m_ValueStack.Peek(i.NumVal));
+ break;
+ case OpCode.Swap:
+ ExecSwap(i);
+ break;
+ case OpCode.Literal:
+ m_ValueStack.Push(i.Value);
+ break;
+ case OpCode.Add:
+ instructionPtr = ExecAdd(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Concat:
+ instructionPtr = ExecConcat(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Neg:
+ instructionPtr = ExecNeg(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Sub:
+ instructionPtr = ExecSub(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Mul:
+ instructionPtr = ExecMul(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Div:
+ instructionPtr = ExecDiv(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Mod:
+ instructionPtr = ExecMod(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Power:
+ instructionPtr = ExecPower(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Eq:
+ instructionPtr = ExecEq(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.LessEq:
+ instructionPtr = ExecLessEq(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Less:
+ instructionPtr = ExecLess(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Len:
+ instructionPtr = ExecLen(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Call:
+ case OpCode.ThisCall:
+ instructionPtr = Internal_ExecCall(i.NumVal, instructionPtr, null, null, i.OpCode == OpCode.ThisCall, i.Name);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Scalar:
+ m_ValueStack.Push(m_ValueStack.Pop().ToScalar());
+ break;
+ case OpCode.Not:
+ ExecNot(i);
+ break;
+ case OpCode.CNot:
+ ExecCNot(i);
+ break;
+ case OpCode.JfOrPop:
+ case OpCode.JtOrPop:
+ instructionPtr = ExecShortCircuitingOperator(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.JNil:
+ {
+ DynValue v = m_ValueStack.Pop().ToScalar();
+
+ if (v.Type == DataType.Nil || v.Type == DataType.Void)
+ instructionPtr = i.NumVal;
+ }
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Jf:
+ instructionPtr = JumpBool(i, false, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Jump:
+ instructionPtr = i.NumVal;
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.MkTuple:
+ ExecMkTuple(i);
+ break;
+ case OpCode.Clean:
+ ClearBlockData(i);
+ break;
+ case OpCode.Closure:
+ ExecClosure(i);
+ break;
+ case OpCode.BeginFn:
+ ExecBeginFn(i);
+ break;
+ case OpCode.ToBool:
+ m_ValueStack.Push(DynValue.NewBoolean(m_ValueStack.Pop().ToScalar().CastToBool()));
+ break;
+ case OpCode.Args:
+ ExecArgs(i);
+ break;
+ case OpCode.Ret:
+ instructionPtr = ExecRet(i);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ if (instructionPtr < 0)
+ goto return_to_native_code;
+ break;
+ case OpCode.Incr:
+ ExecIncr(i);
+ break;
+ case OpCode.ToNum:
+ ExecToNum(i);
+ break;
+ case OpCode.JFor:
+ instructionPtr = ExecJFor(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.NewTable:
+ if (i.NumVal == 0)
+ m_ValueStack.Push(DynValue.NewTable(this.m_Script));
+ else
+ m_ValueStack.Push(DynValue.NewPrimeTable());
+ break;
+ case OpCode.IterPrep:
+ ExecIterPrep(i);
+ break;
+ case OpCode.IterUpd:
+ ExecIterUpd(i);
+ break;
+ case OpCode.ExpTuple:
+ ExecExpTuple(i);
+ break;
+ case OpCode.Local:
+ var scope = m_ExecutionStack.Peek().LocalScope;
+ var index = i.Symbol.i_Index;
+ m_ValueStack.Push(scope[index].AsReadOnly());
+ break;
+ case OpCode.Upvalue:
+ m_ValueStack.Push(m_ExecutionStack.Peek().ClosureScope[i.Symbol.i_Index].AsReadOnly());
+ break;
+ case OpCode.StoreUpv:
+ ExecStoreUpv(i);
+ break;
+ case OpCode.StoreLcl:
+ ExecStoreLcl(i);
+ break;
+ case OpCode.TblInitN:
+ ExecTblInitN(i);
+ break;
+ case OpCode.TblInitI:
+ ExecTblInitI(i);
+ break;
+ case OpCode.Index:
+ case OpCode.IndexN:
+ case OpCode.IndexL:
+ instructionPtr = ExecIndex(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.IndexSet:
+ case OpCode.IndexSetN:
+ case OpCode.IndexSetL:
+ instructionPtr = ExecIndexSet(i, instructionPtr);
+ if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
+ break;
+ case OpCode.Invalid:
+ throw new NotImplementedException(string.Format("Invalid opcode : {0}", i.Name));
+ default:
+ throw new NotImplementedException(string.Format("Execution for {0} not implented yet!", i.OpCode));
+ }
+ }
+
+ yield_to_calling_coroutine:
+
+ DynValue yieldRequest = m_ValueStack.Pop().ToScalar();
+
+ if (m_CanYield)
+ return yieldRequest;
+ else if (this.State == CoroutineState.Main)
+ throw ScriptRuntimeException.CannotYieldMain();
+ else
+ throw ScriptRuntimeException.CannotYield();
+
+ }
+ catch (InterpreterException ex)
+ {
+ FillDebugData(ex, instructionPtr);
+
+ if (!(ex is ScriptRuntimeException))
+ {
+ ex.Rethrow();
+ throw;
+ }
+
+ if (m_Debug.DebuggerAttached != null)
+ {
+ if (m_Debug.DebuggerAttached.SignalRuntimeException((ScriptRuntimeException)ex))
+ {
+ if (instructionPtr >= 0 && instructionPtr < this.m_RootChunk.Code.Count)
+ {
+ ListenDebugger(m_RootChunk.Code[instructionPtr], instructionPtr);
+ }
+ }
+ }
+
+ for (int i = 0; i < m_ExecutionStack.Count; i++)
+ {
+ var c = m_ExecutionStack.Peek(i);
+
+ if (c.ErrorHandlerBeforeUnwind != null)
+ ex.DecoratedMessage = PerformMessageDecorationBeforeUnwind(c.ErrorHandlerBeforeUnwind, ex.DecoratedMessage, GetCurrentSourceRef(instructionPtr));
+ }
+
+
+ while (m_ExecutionStack.Count > 0)
+ {
+ CallStackItem csi = PopToBasePointer();
+
+ if (csi.ErrorHandler != null)
+ {
+ instructionPtr = csi.ReturnAddress;
+
+ if (csi.ClrFunction == null)
+ {
+ var argscnt = (int)(m_ValueStack.Pop().Number);
+ m_ValueStack.RemoveLast(argscnt + 1);
+ }
+
+ var cbargs = new DynValue[] { DynValue.NewString(ex.DecoratedMessage) };
+
+ DynValue handled = csi.ErrorHandler.Invoke(new ScriptExecutionContext(this, csi.ErrorHandler, GetCurrentSourceRef(instructionPtr)), cbargs);
+
+ m_ValueStack.Push(handled);
+
+ goto repeat_execution;
+ }
+ else if ((csi.Flags & CallStackItemFlags.EntryPoint) != 0)
+ {
+ ex.Rethrow();
+ throw;
+ }
+ }
+
+ ex.Rethrow();
+ throw;
+ }
+
+ return_to_native_code:
+ return m_ValueStack.Pop();
+
+
+ }
+
+
+ internal string PerformMessageDecorationBeforeUnwind(DynValue messageHandler, string decoratedMessage, SourceRef sourceRef)
+ {
+ try
+ {
+ DynValue[] args = new DynValue[] { DynValue.NewString(decoratedMessage) };
+ DynValue ret = DynValue.Nil;
+
+ if (messageHandler.Type == DataType.Function)
+ {
+ ret = this.Call(messageHandler, args);
+ }
+ else if (messageHandler.Type == DataType.ClrFunction)
+ {
+ ScriptExecutionContext ctx = new ScriptExecutionContext(this, messageHandler.Callback, sourceRef);
+ ret = messageHandler.Callback.Invoke(ctx, args);
+ }
+ else
+ {
+ throw new ScriptRuntimeException("error handler not set to a function");
+ }
+
+ string newmsg = ret.ToPrintString();
+ if (newmsg != null)
+ return newmsg;
+ }
+ catch (ScriptRuntimeException innerEx)
+ {
+ return innerEx.Message + "\n" + decoratedMessage;
+ }
+
+ return decoratedMessage;
+ }
+
+
+
+ private void AssignLocal(SymbolRef symref, DynValue value)
+ {
+ var stackframe = m_ExecutionStack.Peek();
+
+ DynValue v = stackframe.LocalScope[symref.i_Index];
+ if (v == null)
+ stackframe.LocalScope[symref.i_Index] = v = DynValue.NewNil();
+
+ v.Assign(value);
+ }
+
+ private void ExecStoreLcl(Instruction i)
+ {
+ DynValue value = GetStoreValue(i);
+ SymbolRef symref = i.Symbol;
+
+ AssignLocal(symref, value);
+ }
+
+ private void ExecStoreUpv(Instruction i)
+ {
+ DynValue value = GetStoreValue(i);
+ SymbolRef symref = i.Symbol;
+
+ var stackframe = m_ExecutionStack.Peek();
+
+ DynValue v = stackframe.ClosureScope[symref.i_Index];
+ if (v == null)
+ stackframe.ClosureScope[symref.i_Index] = v = DynValue.NewNil();
+
+ v.Assign(value);
+ }
+
+ private void ExecSwap(Instruction i)
+ {
+ DynValue v1 = m_ValueStack.Peek(i.NumVal);
+ DynValue v2 = m_ValueStack.Peek(i.NumVal2);
+
+ m_ValueStack.Set(i.NumVal, v2);
+ m_ValueStack.Set(i.NumVal2, v1);
+ }
+
+
+ private DynValue GetStoreValue(Instruction i)
+ {
+ int stackofs = i.NumVal;
+ int tupleidx = i.NumVal2;
+
+ DynValue v = m_ValueStack.Peek(stackofs);
+
+ if (v.Type == DataType.Tuple)
+ {
+ return (tupleidx < v.Tuple.Length) ? v.Tuple[tupleidx] : DynValue.NewNil();
+ }
+ else
+ {
+ return (tupleidx == 0) ? v : DynValue.NewNil();
+ }
+ }
+
+ private void ExecClosure(Instruction i)
+ {
+ Closure c = new Closure(this.m_Script, i.NumVal, i.SymbolList,
+ i.SymbolList.Select(s => this.GetUpvalueSymbol(s)).ToList());
+
+ m_ValueStack.Push(DynValue.NewClosure(c));
+ }
+
+ private DynValue GetUpvalueSymbol(SymbolRef s)
+ {
+ if (s.Type == SymbolRefType.Local)
+ return m_ExecutionStack.Peek().LocalScope[s.i_Index];
+ else if (s.Type == SymbolRefType.Upvalue)
+ return m_ExecutionStack.Peek().ClosureScope[s.i_Index];
+ else
+ throw new Exception("unsupported symbol type");
+ }
+
+ private void ExecMkTuple(Instruction i)
+ {
+ Slice slice = new Slice(m_ValueStack, m_ValueStack.Count - i.NumVal, i.NumVal, false);
+
+ var v = Internal_AdjustTuple(slice);
+
+ m_ValueStack.RemoveLast(i.NumVal);
+
+ m_ValueStack.Push(DynValue.NewTuple(v));
+ }
+
+ private void ExecToNum(Instruction i)
+ {
+ double? v = m_ValueStack.Pop().ToScalar().CastToNumber();
+ if (v.HasValue)
+ m_ValueStack.Push(DynValue.NewNumber(v.Value));
+ else
+ throw ScriptRuntimeException.ConvertToNumberFailed(i.NumVal);
+ }
+
+
+ private void ExecIterUpd(Instruction i)
+ {
+ DynValue v = m_ValueStack.Peek(0);
+ DynValue t = m_ValueStack.Peek(1);
+ t.Tuple[2] = v;
+ }
+
+ private void ExecExpTuple(Instruction i)
+ {
+ DynValue t = m_ValueStack.Peek(i.NumVal);
+
+ if (t.Type == DataType.Tuple)
+ {
+ for (int idx = 0; idx < t.Tuple.Length; idx++)
+ m_ValueStack.Push(t.Tuple[idx]);
+ }
+ else
+ {
+ m_ValueStack.Push(t);
+ }
+
+ }
+
+ private void ExecIterPrep(Instruction i)
+ {
+ DynValue v = m_ValueStack.Pop();
+
+ if (v.Type != DataType.Tuple)
+ {
+ v = DynValue.NewTuple(v, DynValue.Nil, DynValue.Nil);
+ }
+
+ DynValue f = v.Tuple.Length >= 1 ? v.Tuple[0] : DynValue.Nil;
+ DynValue s = v.Tuple.Length >= 2 ? v.Tuple[1] : DynValue.Nil;
+ DynValue var = v.Tuple.Length >= 3 ? v.Tuple[2] : DynValue.Nil;
+
+ // MoonSharp additions - given f, s, var
+ // 1) if f is not a function and has a __iterator metamethod, call __iterator to get the triplet
+ // 2) if f is a table with no __call metamethod, use a default table iterator
+
+ if (f.Type != DataType.Function && f.Type != DataType.ClrFunction)
+ {
+ DynValue meta = this.GetMetamethod(f, "__iterator");
+
+ if (meta != null && !meta.IsNil())
+ {
+ if (meta.Type != DataType.Tuple)
+ v = this.GetScript().Call(meta, f, s, var);
+ else
+ v = meta;
+
+ f = v.Tuple.Length >= 1 ? v.Tuple[0] : DynValue.Nil;
+ s = v.Tuple.Length >= 2 ? v.Tuple[1] : DynValue.Nil;
+ var = v.Tuple.Length >= 3 ? v.Tuple[2] : DynValue.Nil;
+
+ m_ValueStack.Push(DynValue.NewTuple(f, s, var));
+ }
+ else if (f.Type == DataType.Table)
+ {
+ DynValue callmeta = this.GetMetamethod(f, "__call");
+
+ if (callmeta == null || callmeta.IsNil())
+ {
+ m_ValueStack.Push(EnumerableWrapper.ConvertTable(f.Table));
+ }
+ }
+ }
+
+ m_ValueStack.Push(DynValue.NewTuple(f, s, var));
+ }
+
+
+ private int ExecJFor(Instruction i, int instructionPtr)
+ {
+ double val = m_ValueStack.Peek(0).Number;
+ double step = m_ValueStack.Peek(1).Number;
+ double stop = m_ValueStack.Peek(2).Number;
+
+ bool whileCond = (step > 0) ? val <= stop : val >= stop;
+
+ if (!whileCond)
+ return i.NumVal;
+ else
+ return instructionPtr;
+ }
+
+
+
+ private void ExecIncr(Instruction i)
+ {
+ DynValue top = m_ValueStack.Peek(0);
+ DynValue btm = m_ValueStack.Peek(i.NumVal);
+
+ if (top.ReadOnly)
+ {
+ m_ValueStack.Pop();
+
+ if (top.ReadOnly)
+ top = top.CloneAsWritable();
+
+ m_ValueStack.Push(top);
+ }
+
+ top.AssignNumber(top.Number + btm.Number);
+ }
+
+
+ private void ExecCNot(Instruction i)
+ {
+ DynValue v = m_ValueStack.Pop().ToScalar();
+ DynValue not = m_ValueStack.Pop().ToScalar();
+
+ if (not.Type != DataType.Boolean)
+ throw new InternalErrorException("CNOT had non-bool arg");
+
+ if (not.CastToBool())
+ m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
+ else
+ m_ValueStack.Push(DynValue.NewBoolean(v.CastToBool()));
+ }
+
+ private void ExecNot(Instruction i)
+ {
+ DynValue v = m_ValueStack.Pop().ToScalar();
+ m_ValueStack.Push(DynValue.NewBoolean(!(v.CastToBool())));
+ }
+
+ private void ExecBeginFn(Instruction i)
+ {
+ CallStackItem cur = m_ExecutionStack.Peek();
+
+ cur.Debug_Symbols = i.SymbolList;
+ cur.LocalScope = new DynValue[i.NumVal];
+
+ ClearBlockData(i);
+ }
+
+ private CallStackItem PopToBasePointer()
+ {
+ var csi = m_ExecutionStack.Pop();
+ if (csi.BasePointer >= 0)
+ m_ValueStack.CropAtCount(csi.BasePointer);
+ return csi;
+ }
+
+ private int PopExecStackAndCheckVStack(int vstackguard)
+ {
+ var xs = m_ExecutionStack.Pop();
+ if (vstackguard != xs.BasePointer)
+ throw new InternalErrorException("StackGuard violation");
+
+ return xs.ReturnAddress;
+ }
+
+ private IList CreateArgsListForFunctionCall(int numargs, int offsFromTop)
+ {
+ if (numargs == 0) return new DynValue[0];
+
+ DynValue lastParam = m_ValueStack.Peek(offsFromTop);
+
+ if (lastParam.Type == DataType.Tuple && lastParam.Tuple.Length > 1)
+ {
+ List values = new List();
+
+ for (int idx = 0; idx < numargs - 1; idx++)
+ values.Add(m_ValueStack.Peek(numargs - idx - 1 + offsFromTop));
+
+ for (int idx = 0; idx < lastParam.Tuple.Length; idx++)
+ values.Add(lastParam.Tuple[idx]);
+
+ return values;
+ }
+ else
+ {
+ return new Slice(m_ValueStack, m_ValueStack.Count - numargs - offsFromTop, numargs, false);
+ }
+ }
+
+
+ private void ExecArgs(Instruction I)
+ {
+ int numargs = (int)m_ValueStack.Peek(0).Number;
+
+ // unpacks last tuple arguments to simplify a lot of code down under
+ var argsList = CreateArgsListForFunctionCall(numargs, 1);
+
+ for (int i = 0; i < I.SymbolList.Length; i++)
+ {
+ if (i >= argsList.Count)
+ {
+ this.AssignLocal(I.SymbolList[i], DynValue.NewNil());
+ }
+ else if ((i == I.SymbolList.Length - 1) && (I.SymbolList[i].i_Name == WellKnownSymbols.VARARGS))
+ {
+ int len = argsList.Count - i;
+ DynValue[] varargs = new DynValue[len];
+
+ for (int ii = 0; ii < len; ii++, i++)
+ {
+ varargs[ii] = argsList[i].ToScalar().CloneAsWritable();
+ }
+
+ this.AssignLocal(I.SymbolList[I.SymbolList.Length - 1], DynValue.NewTuple(Internal_AdjustTuple(varargs)));
+ }
+ else
+ {
+ this.AssignLocal(I.SymbolList[i], argsList[i].ToScalar().CloneAsWritable());
+ }
+ }
+ }
+
+
+
+
+ private int Internal_ExecCall(int argsCount, int instructionPtr, CallbackFunction handler = null,
+ CallbackFunction continuation = null, bool thisCall = false, string debugText = null, DynValue unwindHandler = null)
+ {
+ DynValue fn = m_ValueStack.Peek(argsCount);
+ CallStackItemFlags flags = (thisCall ? CallStackItemFlags.MethodCall : CallStackItemFlags.None);
+
+ // if TCO threshold reached
+ if ((m_ExecutionStack.Count > this.m_Script.Options.TailCallOptimizationThreshold && m_ExecutionStack.Count > 1)
+ || (m_ValueStack.Count > this.m_Script.Options.TailCallOptimizationThreshold && m_ValueStack.Count > 1))
+ {
+ // and the "will-be" return address is valid (we don't want to crash here)
+ if (instructionPtr >= 0 && instructionPtr < this.m_RootChunk.Code.Count)
+ {
+ Instruction I = this.m_RootChunk.Code[instructionPtr];
+
+ // and we are followed *exactly* by a RET 1
+ if (I.OpCode == OpCode.Ret && I.NumVal == 1)
+ {
+ CallStackItem csi = m_ExecutionStack.Peek();
+
+ // if the current stack item has no "odd" things pending and neither has the new coming one..
+ if (csi.ClrFunction == null && csi.Continuation == null && csi.ErrorHandler == null
+ && csi.ErrorHandlerBeforeUnwind == null && continuation == null && unwindHandler == null && handler == null)
+ {
+ instructionPtr = PerformTCO(instructionPtr, argsCount);
+ flags |= CallStackItemFlags.TailCall;
+ }
+ }
+ }
+ }
+
+
+
+ if (fn.Type == DataType.ClrFunction)
+ {
+ //IList args = new Slice(m_ValueStack, m_ValueStack.Count - argsCount, argsCount, false);
+ IList args = CreateArgsListForFunctionCall(argsCount, 0);
+ // we expand tuples before callbacks
+ // args = DynValue.ExpandArgumentsToList(args);
+ SourceRef sref = GetCurrentSourceRef(instructionPtr);
+
+ m_ExecutionStack.Push(new CallStackItem()
+ {
+ ClrFunction = fn.Callback,
+ ReturnAddress = instructionPtr,
+ CallingSourceRef = sref,
+ BasePointer = -1,
+ ErrorHandler = handler,
+ Continuation = continuation,
+ ErrorHandlerBeforeUnwind = unwindHandler,
+ Flags = flags,
+ });
+
+ var ret = fn.Callback.Invoke(new ScriptExecutionContext(this, fn.Callback, sref), args, isMethodCall: thisCall);
+ m_ValueStack.RemoveLast(argsCount + 1);
+ m_ValueStack.Push(ret);
+
+ m_ExecutionStack.Pop();
+
+ return Internal_CheckForTailRequests(null, instructionPtr);
+ }
+ else if (fn.Type == DataType.Function)
+ {
+ m_ValueStack.Push(DynValue.NewNumber(argsCount));
+ m_ExecutionStack.Push(new CallStackItem()
+ {
+ BasePointer = m_ValueStack.Count,
+ ReturnAddress = instructionPtr,
+ Debug_EntryPoint = fn.Function.EntryPointByteCodeLocation,
+ CallingSourceRef = GetCurrentSourceRef(instructionPtr),
+ ClosureScope = fn.Function.ClosureContext,
+ ErrorHandler = handler,
+ Continuation = continuation,
+ ErrorHandlerBeforeUnwind = unwindHandler,
+ Flags = flags,
+ });
+ return fn.Function.EntryPointByteCodeLocation;
+ }
+
+ // fallback to __call metamethod
+ var m = GetMetamethod(fn, "__call");
+
+ if (m != null && m.IsNotNil())
+ {
+ DynValue[] tmp = new DynValue[argsCount + 1];
+ for (int i = 0; i < argsCount + 1; i++)
+ tmp[i] = m_ValueStack.Pop();
+
+ m_ValueStack.Push(m);
+
+ for (int i = argsCount; i >= 0; i--)
+ m_ValueStack.Push(tmp[i]);
+
+ return Internal_ExecCall(argsCount + 1, instructionPtr, handler, continuation);
+ }
+
+ throw ScriptRuntimeException.AttemptToCallNonFunc(fn.Type, debugText);
+ }
+
+ private int PerformTCO(int instructionPtr, int argsCount)
+ {
+ DynValue[] args = new DynValue[argsCount + 1];
+
+ // Remove all cur args and func ptr
+ for (int i = 0; i <= argsCount; i++)
+ args[i] = m_ValueStack.Pop();
+
+ // perform a fake RET
+ CallStackItem csi = PopToBasePointer();
+ int retpoint = csi.ReturnAddress;
+ var argscnt = (int)(m_ValueStack.Pop().Number);
+ m_ValueStack.RemoveLast(argscnt + 1);
+
+ // Re-push all cur args and func ptr
+ for (int i = argsCount; i >= 0; i--)
+ m_ValueStack.Push(args[i]);
+
+ return retpoint;
+ }
+
+
+
+
+ private int ExecRet(Instruction i)
+ {
+ CallStackItem csi;
+ int retpoint = 0;
+
+ if (i.NumVal == 0)
+ {
+ csi = PopToBasePointer();
+ retpoint = csi.ReturnAddress;
+ var argscnt = (int)(m_ValueStack.Pop().Number);
+ m_ValueStack.RemoveLast(argscnt + 1);
+ m_ValueStack.Push(DynValue.Void);
+ }
+ else if (i.NumVal == 1)
+ {
+ var retval = m_ValueStack.Pop();
+ csi = PopToBasePointer();
+ retpoint = csi.ReturnAddress;
+ var argscnt = (int)(m_ValueStack.Pop().Number);
+ m_ValueStack.RemoveLast(argscnt + 1);
+ m_ValueStack.Push(retval);
+ retpoint = Internal_CheckForTailRequests(i, retpoint);
+ }
+ else
+ {
+ throw new InternalErrorException("RET supports only 0 and 1 ret val scenarios");
+ }
+
+ if (csi.Continuation != null)
+ m_ValueStack.Push(csi.Continuation.Invoke(new ScriptExecutionContext(this, csi.Continuation, i.SourceCodeRef),
+ new DynValue[1] { m_ValueStack.Pop() }));
+
+ return retpoint;
+ }
+
+
+
+ private int Internal_CheckForTailRequests(Instruction i, int instructionPtr)
+ {
+ DynValue tail = m_ValueStack.Peek(0);
+
+ if (tail.Type == DataType.TailCallRequest)
+ {
+ m_ValueStack.Pop(); // discard tail call request
+
+ TailCallData tcd = tail.TailCallData;
+
+ m_ValueStack.Push(tcd.Function);
+
+ for (int ii = 0; ii < tcd.Args.Length; ii++)
+ m_ValueStack.Push(tcd.Args[ii]);
+
+ return Internal_ExecCall(tcd.Args.Length, instructionPtr, tcd.ErrorHandler, tcd.Continuation, false, null, tcd.ErrorHandlerBeforeUnwind);
+ }
+ else if (tail.Type == DataType.YieldRequest)
+ {
+ m_SavedInstructionPtr = instructionPtr;
+ return YIELD_SPECIAL_TRAP;
+ }
+
+
+ return instructionPtr;
+ }
+
+
+
+ private int JumpBool(Instruction i, bool expectedValueForJump, int instructionPtr)
+ {
+ DynValue op = m_ValueStack.Pop().ToScalar();
+
+ if (op.CastToBool() == expectedValueForJump)
+ return i.NumVal;
+
+ return instructionPtr;
+ }
+
+ private int ExecShortCircuitingOperator(Instruction i, int instructionPtr)
+ {
+ bool expectedValToShortCircuit = i.OpCode == OpCode.JtOrPop;
+
+ DynValue op = m_ValueStack.Peek().ToScalar();
+
+ if (op.CastToBool() == expectedValToShortCircuit)
+ {
+ return i.NumVal;
+ }
+ else
+ {
+ m_ValueStack.Pop();
+ return instructionPtr;
+ }
+ }
+
+
+ private int ExecAdd(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ DynValue l = m_ValueStack.Pop().ToScalar();
+
+ double? rn = r.CastToNumber();
+ double? ln = l.CastToNumber();
+
+ if (ln.HasValue && rn.HasValue)
+ {
+ m_ValueStack.Push(DynValue.NewNumber(ln.Value + rn.Value));
+ return instructionPtr;
+ }
+ else
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__add", instructionPtr);
+ if (ip >= 0) return ip;
+ else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
+ }
+ }
+
+ private int ExecSub(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ DynValue l = m_ValueStack.Pop().ToScalar();
+
+ double? rn = r.CastToNumber();
+ double? ln = l.CastToNumber();
+
+ if (ln.HasValue && rn.HasValue)
+ {
+ m_ValueStack.Push(DynValue.NewNumber(ln.Value - rn.Value));
+ return instructionPtr;
+ }
+ else
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__sub", instructionPtr);
+ if (ip >= 0) return ip;
+ else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
+ }
+ }
+
+
+ private int ExecMul(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ DynValue l = m_ValueStack.Pop().ToScalar();
+
+ double? rn = r.CastToNumber();
+ double? ln = l.CastToNumber();
+
+ if (ln.HasValue && rn.HasValue)
+ {
+ m_ValueStack.Push(DynValue.NewNumber(ln.Value * rn.Value));
+ return instructionPtr;
+ }
+ else
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__mul", instructionPtr);
+ if (ip >= 0) return ip;
+ else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
+ }
+ }
+
+ private int ExecMod(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ DynValue l = m_ValueStack.Pop().ToScalar();
+
+ double? rn = r.CastToNumber();
+ double? ln = l.CastToNumber();
+
+ if (ln.HasValue && rn.HasValue)
+ {
+ double mod = Math.IEEERemainder(ln.Value, rn.Value);
+ if (mod < 0) mod += rn.Value;
+ m_ValueStack.Push(DynValue.NewNumber(mod));
+ return instructionPtr;
+ }
+ else
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__mod", instructionPtr);
+ if (ip >= 0) return ip;
+ else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
+ }
+ }
+
+ private int ExecDiv(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ DynValue l = m_ValueStack.Pop().ToScalar();
+
+ double? rn = r.CastToNumber();
+ double? ln = l.CastToNumber();
+
+ if (ln.HasValue && rn.HasValue)
+ {
+ m_ValueStack.Push(DynValue.NewNumber(ln.Value / rn.Value));
+ return instructionPtr;
+ }
+ else
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__div", instructionPtr);
+ if (ip >= 0) return ip;
+ else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
+ }
+ }
+ private int ExecPower(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ DynValue l = m_ValueStack.Pop().ToScalar();
+
+ double? rn = r.CastToNumber();
+ double? ln = l.CastToNumber();
+
+ if (ln.HasValue && rn.HasValue)
+ {
+ m_ValueStack.Push(DynValue.NewNumber(Math.Pow(ln.Value, rn.Value)));
+ return instructionPtr;
+ }
+ else
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__pow", instructionPtr);
+ if (ip >= 0) return ip;
+ else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
+ }
+
+ }
+
+ private int ExecNeg(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ double? rn = r.CastToNumber();
+
+ if (rn.HasValue)
+ {
+ m_ValueStack.Push(DynValue.NewNumber(-rn.Value));
+ return instructionPtr;
+ }
+ else
+ {
+ int ip = Internal_InvokeUnaryMetaMethod(r, "__unm", instructionPtr);
+ if (ip >= 0) return ip;
+ else throw ScriptRuntimeException.ArithmeticOnNonNumber(r);
+ }
+ }
+
+
+ private int ExecEq(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ DynValue l = m_ValueStack.Pop().ToScalar();
+
+ // first we do a brute force equals over the references
+ if (object.ReferenceEquals(r, l))
+ {
+ m_ValueStack.Push(DynValue.True);
+ return instructionPtr;
+ }
+
+ // then if they are userdatas, attempt meta
+ if (l.Type == DataType.UserData || r.Type == DataType.UserData)
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__eq", instructionPtr);
+ if (ip >= 0) return ip;
+ }
+
+ // then if types are different, ret false
+ if (r.Type != l.Type)
+ {
+ if ((l.Type == DataType.Nil && r.Type == DataType.Void) || (l.Type == DataType.Void && r.Type == DataType.Nil))
+ m_ValueStack.Push(DynValue.True);
+ else
+ m_ValueStack.Push(DynValue.False);
+
+ return instructionPtr;
+ }
+
+ // then attempt metatables for tables
+ if ((l.Type == DataType.Table) && (GetMetatable(l) != null) && (GetMetatable(l) == GetMetatable(r)))
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__eq", instructionPtr);
+ if (ip >= 0) return ip;
+ }
+
+ // else perform standard comparison
+ m_ValueStack.Push(DynValue.NewBoolean(r.Equals(l)));
+ return instructionPtr;
+ }
+
+ private int ExecLess(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ DynValue l = m_ValueStack.Pop().ToScalar();
+
+ if (l.Type == DataType.Number && r.Type == DataType.Number)
+ {
+ m_ValueStack.Push(DynValue.NewBoolean(l.Number < r.Number));
+ }
+ else if (l.Type == DataType.String && r.Type == DataType.String)
+ {
+ m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) < 0));
+ }
+ else
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__lt", instructionPtr);
+ if (ip < 0)
+ throw ScriptRuntimeException.CompareInvalidType(l, r);
+ else
+ return ip;
+ }
+
+ return instructionPtr;
+ }
+
+
+ private int ExecLessEq(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ DynValue l = m_ValueStack.Pop().ToScalar();
+
+ if (l.Type == DataType.Number && r.Type == DataType.Number)
+ {
+ m_ValueStack.Push(DynValue.False);
+ m_ValueStack.Push(DynValue.NewBoolean(l.Number <= r.Number));
+ }
+ else if (l.Type == DataType.String && r.Type == DataType.String)
+ {
+ m_ValueStack.Push(DynValue.False);
+ m_ValueStack.Push(DynValue.NewBoolean(l.String.CompareTo(r.String) <= 0));
+ }
+ else
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__le", instructionPtr, DynValue.False);
+ if (ip < 0)
+ {
+ ip = Internal_InvokeBinaryMetaMethod(r, l, "__lt", instructionPtr, DynValue.True);
+
+ if (ip < 0)
+ throw ScriptRuntimeException.CompareInvalidType(l, r);
+ else
+ return ip;
+ }
+ else
+ return ip;
+ }
+
+ return instructionPtr;
+ }
+
+ private int ExecLen(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+
+ if (r.Type == DataType.String)
+ m_ValueStack.Push(DynValue.NewNumber(r.String.Length));
+ else
+ {
+ int ip = Internal_InvokeUnaryMetaMethod(r, "__len", instructionPtr);
+ if (ip >= 0)
+ return ip;
+ else if (r.Type == DataType.Table)
+ m_ValueStack.Push(DynValue.NewNumber(r.Table.Length));
+
+ else throw ScriptRuntimeException.LenOnInvalidType(r);
+ }
+
+ return instructionPtr;
+ }
+
+
+ private int ExecConcat(Instruction i, int instructionPtr)
+ {
+ DynValue r = m_ValueStack.Pop().ToScalar();
+ DynValue l = m_ValueStack.Pop().ToScalar();
+
+ string rs = r.CastToString();
+ string ls = l.CastToString();
+
+ if (rs != null && ls != null)
+ {
+ m_ValueStack.Push(DynValue.NewString(ls + rs));
+ return instructionPtr;
+ }
+ else
+ {
+ int ip = Internal_InvokeBinaryMetaMethod(l, r, "__concat", instructionPtr);
+ if (ip >= 0) return ip;
+ else throw ScriptRuntimeException.ConcatOnNonString(l, r);
+ }
+
+ }
+
+
+ private void ExecTblInitI(Instruction i)
+ {
+ // stack: tbl - val
+ DynValue val = m_ValueStack.Pop();
+ DynValue tbl = m_ValueStack.Peek();
+
+ if (tbl.Type != DataType.Table)
+ throw new InternalErrorException("Unexpected type in table ctor : {0}", tbl);
+
+ tbl.Table.InitNextArrayKeys(val, i.NumVal != 0);
+ }
+
+ private void ExecTblInitN(Instruction i)
+ {
+ // stack: tbl - key - val
+ DynValue val = m_ValueStack.Pop();
+ DynValue key = m_ValueStack.Pop();
+ DynValue tbl = m_ValueStack.Peek();
+
+ if (tbl.Type != DataType.Table)
+ throw new InternalErrorException("Unexpected type in table ctor : {0}", tbl);
+
+ tbl.Table.Set(key, val.ToScalar());
+ }
+
+ private int ExecIndexSet(Instruction i, int instructionPtr)
+ {
+ int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
+
+ // stack: vals.. - base - index
+ bool isNameIndex = i.OpCode == OpCode.IndexSetN;
+ bool isMultiIndex = (i.OpCode == OpCode.IndexSetL);
+
+ DynValue originalIdx = i.Value ?? m_ValueStack.Pop();
+ DynValue idx = originalIdx.ToScalar();
+ DynValue obj = m_ValueStack.Pop().ToScalar();
+ var value = GetStoreValue(i);
+ DynValue h = null;
+
+
+ while (nestedMetaOps > 0)
+ {
+ --nestedMetaOps;
+
+ if (obj.Type == DataType.Table)
+ {
+ if (!isMultiIndex)
+ {
+ if (!obj.Table.Get(idx).IsNil())
+ {
+ obj.Table.Set(idx, value);
+ return instructionPtr;
+ }
+ }
+
+ h = GetMetamethodRaw(obj, "__newindex");
+
+ if (h == null || h.IsNil())
+ {
+ if (isMultiIndex) throw new ScriptRuntimeException("cannot multi-index a table. userdata expected");
+
+ obj.Table.Set(idx, value);
+ return instructionPtr;
+ }
+ }
+ else if (obj.Type == DataType.UserData)
+ {
+ UserData ud = obj.UserData;
+
+ if (!ud.Descriptor.SetIndex(this.GetScript(), ud.Object, originalIdx, value, isNameIndex))
+ {
+ throw ScriptRuntimeException.UserDataMissingField(ud.Descriptor.Name, idx.String);
+ }
+
+ return instructionPtr;
+ }
+ else
+ {
+ h = GetMetamethodRaw(obj, "__newindex");
+
+ if (h == null || h.IsNil())
+ throw ScriptRuntimeException.IndexType(obj);
+ }
+
+ if (h.Type == DataType.Function || h.Type == DataType.ClrFunction)
+ {
+ if (isMultiIndex) throw new ScriptRuntimeException("cannot multi-index through metamethods. userdata expected");
+ m_ValueStack.Pop(); // burn extra value ?
+
+ m_ValueStack.Push(h);
+ m_ValueStack.Push(obj);
+ m_ValueStack.Push(idx);
+ m_ValueStack.Push(value);
+ return Internal_ExecCall(3, instructionPtr);
+ }
+ else
+ {
+ obj = h;
+ h = null;
+ }
+ }
+ throw ScriptRuntimeException.LoopInNewIndex();
+ }
+
+ private int ExecIndex(Instruction i, int instructionPtr)
+ {
+ int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
+
+ // stack: base - index
+ bool isNameIndex = i.OpCode == OpCode.IndexN;
+
+ bool isMultiIndex = (i.OpCode == OpCode.IndexL);
+
+ DynValue originalIdx = i.Value ?? m_ValueStack.Pop();
+ DynValue idx = originalIdx.ToScalar();
+ DynValue obj = m_ValueStack.Pop().ToScalar();
+
+ DynValue h = null;
+
+
+ while (nestedMetaOps > 0)
+ {
+ --nestedMetaOps;
+
+ if (obj.Type == DataType.Table)
+ {
+ if (!isMultiIndex)
+ {
+ var v = obj.Table.Get(idx);
+
+ if (!v.IsNil())
+ {
+ m_ValueStack.Push(v.AsReadOnly());
+ return instructionPtr;
+ }
+ }
+
+ h = GetMetamethodRaw(obj, "__index");
+
+ if (h == null || h.IsNil())
+ {
+ if (isMultiIndex) throw new ScriptRuntimeException("cannot multi-index a table. userdata expected");
+
+ m_ValueStack.Push(DynValue.Nil);
+ return instructionPtr;
+ }
+ }
+ else if (obj.Type == DataType.UserData)
+ {
+ UserData ud = obj.UserData;
+
+ var v = ud.Descriptor.Index(this.GetScript(), ud.Object, originalIdx, isNameIndex);
+
+ if (v == null)
+ {
+ throw ScriptRuntimeException.UserDataMissingField(ud.Descriptor.Name, idx.String);
+ }
+
+ m_ValueStack.Push(v.AsReadOnly());
+ return instructionPtr;
+ }
+ else
+ {
+ h = GetMetamethodRaw(obj, "__index");
+
+ if (h == null || h.IsNil())
+ throw ScriptRuntimeException.IndexType(obj);
+ }
+
+ if (h.Type == DataType.Function || h.Type == DataType.ClrFunction)
+ {
+ if (isMultiIndex) throw new ScriptRuntimeException("cannot multi-index through metamethods. userdata expected");
+ m_ValueStack.Push(h);
+ m_ValueStack.Push(obj);
+ m_ValueStack.Push(idx);
+ return Internal_ExecCall(2, instructionPtr);
+ }
+ else
+ {
+ obj = h;
+ h = null;
+ }
+ }
+
+ throw ScriptRuntimeException.LoopInIndex();
+ }
+
+
+
+
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Scope.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Scope.cs
new file mode 100644
index 00000000..f08ccff4
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_Scope.cs
@@ -0,0 +1,152 @@
+using System;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ sealed partial class Processor
+ {
+ private void ClearBlockData(Instruction I)
+ {
+ int from = I.NumVal;
+ int to = I.NumVal2;
+
+ var array = this.m_ExecutionStack.Peek().LocalScope;
+
+ if (to >= 0 && from >= 0 && to >= from)
+ {
+ Array.Clear(array, from, to - from + 1);
+ }
+ }
+
+
+ public DynValue GetGenericSymbol(SymbolRef symref)
+ {
+ switch (symref.i_Type)
+ {
+ case SymbolRefType.DefaultEnv:
+ return DynValue.NewTable(this.GetScript().Globals);
+ case SymbolRefType.Global:
+ return GetGlobalSymbol(GetGenericSymbol(symref.i_Env), symref.i_Name);
+ case SymbolRefType.Local:
+ return GetTopNonClrFunction().LocalScope[symref.i_Index];
+ case SymbolRefType.Upvalue:
+ return GetTopNonClrFunction().ClosureScope[symref.i_Index];
+ default:
+ throw new InternalErrorException("Unexpected {0} LRef at resolution: {1}", symref.i_Type, symref.i_Name);
+ }
+ }
+
+ private DynValue GetGlobalSymbol(DynValue dynValue, string name)
+ {
+ if (dynValue.Type != DataType.Table)
+ throw new InvalidOperationException(string.Format("_ENV is not a table but a {0}", dynValue.Type));
+
+ return dynValue.Table.Get(name);
+ }
+
+ private void SetGlobalSymbol(DynValue dynValue, string name, DynValue value)
+ {
+ if (dynValue.Type != DataType.Table)
+ throw new InvalidOperationException(string.Format("_ENV is not a table but a {0}", 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:
+ {
+ var stackframe = GetTopNonClrFunction();
+
+ DynValue v = stackframe.LocalScope[symref.i_Index];
+ if (v == null)
+ stackframe.LocalScope[symref.i_Index] = v = DynValue.NewNil();
+
+ v.Assign(value);
+ }
+ break;
+ case SymbolRefType.Upvalue:
+ {
+ var stackframe = GetTopNonClrFunction();
+
+ DynValue v = stackframe.ClosureScope[symref.i_Index];
+ if (v == null)
+ stackframe.ClosureScope[symref.i_Index] = v = DynValue.NewNil();
+
+ v.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);
+ }
+ }
+
+ CallStackItem GetTopNonClrFunction()
+ {
+ CallStackItem stackframe = null;
+
+ for (int i = 0; i < m_ExecutionStack.Count; i++)
+ {
+ stackframe = m_ExecutionStack.Peek(i);
+
+ if (stackframe.ClrFunction == null)
+ break;
+ }
+
+ return stackframe;
+ }
+
+
+ public SymbolRef FindSymbolByName(string name)
+ {
+ if (m_ExecutionStack.Count > 0)
+ {
+ CallStackItem stackframe = GetTopNonClrFunction();
+
+ if (stackframe != null)
+ {
+ if (stackframe.Debug_Symbols != null)
+ {
+ for (int i = stackframe.Debug_Symbols.Length - 1; i >= 0; i--)
+ {
+ var l = stackframe.Debug_Symbols[i];
+
+ if (l.i_Name == name && stackframe.LocalScope[i] != null)
+ return l;
+ }
+ }
+
+
+ var closure = stackframe.ClosureScope;
+
+ if (closure != null)
+ {
+ for (int i = 0; i < closure.Symbols.Length; i++)
+ if (closure.Symbols[i] == name)
+ return SymbolRef.Upvalue(name, i);
+ }
+ }
+ }
+
+ if (name != WellKnownSymbols.ENV)
+ {
+ SymbolRef env = FindSymbolByName(WellKnownSymbols.ENV);
+ return SymbolRef.Global(name, env);
+ }
+ else
+ {
+ return SymbolRef.DefaultEnv;
+ }
+ }
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_UtilityFunctions.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_UtilityFunctions.cs
new file mode 100644
index 00000000..3ad7253d
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Execution/VM/Processor/Processor_UtilityFunctions.cs
@@ -0,0 +1,149 @@
+using System.Collections.Generic;
+
+namespace MoonSharp.Interpreter.Execution.VM
+{
+ sealed partial class Processor
+ {
+ private DynValue[] Internal_AdjustTuple(IList values)
+ {
+ if (values == null || values.Count == 0)
+ return new DynValue[0];
+
+ if (values[values.Count - 1].Type == DataType.Tuple)
+ {
+ int baseLen = values.Count - 1 + values[values.Count - 1].Tuple.Length;
+ DynValue[] result = new DynValue[baseLen];
+
+ for (int i = 0; i < values.Count - 1; i++)
+ {
+ result[i] = values[i].ToScalar();
+ }
+
+ for (int i = 0; i < values[values.Count - 1].Tuple.Length; i++)
+ {
+ result[values.Count + i - 1] = values[values.Count - 1].Tuple[i];
+ }
+
+ if (result[result.Length - 1].Type == DataType.Tuple)
+ return Internal_AdjustTuple(result);
+ else
+ return result;
+ }
+ else
+ {
+ DynValue[] result = new DynValue[values.Count];
+
+ for (int i = 0; i < values.Count; i++)
+ {
+ result[i] = values[i].ToScalar();
+ }
+
+ return result;
+ }
+ }
+
+
+
+ private int Internal_InvokeUnaryMetaMethod(DynValue op1, string eventName, int instructionPtr)
+ {
+ DynValue m = null;
+
+ if (op1.Type == DataType.UserData)
+ {
+ m = op1.UserData.Descriptor.MetaIndex(m_Script, op1.UserData.Object, eventName);
+ }
+
+ if (m == null)
+ {
+ var op1_MetaTable = GetMetatable(op1);
+
+ if (op1_MetaTable != null)
+ {
+ DynValue meta1 = op1_MetaTable.RawGet(eventName);
+ if (meta1 != null && meta1.IsNotNil())
+ m = meta1;
+ }
+ }
+
+ if (m != null)
+ {
+ m_ValueStack.Push(m);
+ m_ValueStack.Push(op1);
+ return Internal_ExecCall(1, instructionPtr);
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ private int Internal_InvokeBinaryMetaMethod(DynValue l, DynValue r, string eventName, int instructionPtr, DynValue extraPush = null)
+ {
+ var m = GetBinaryMetamethod(l, r, eventName);
+
+ if (m != null)
+ {
+ if (extraPush != null)
+ m_ValueStack.Push(extraPush);
+
+ m_ValueStack.Push(m);
+ m_ValueStack.Push(l);
+ m_ValueStack.Push(r);
+ return Internal_ExecCall(2, instructionPtr);
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+
+
+
+ private DynValue[] StackTopToArray(int items, bool pop)
+ {
+ DynValue[] values = new DynValue[items];
+
+ if (pop)
+ {
+ for (int i = 0; i < items; i++)
+ {
+ values[i] = m_ValueStack.Pop();
+ }
+ }
+ else
+ {
+ for (int i = 0; i < items; i++)
+ {
+ values[i] = m_ValueStack[m_ValueStack.Count - 1 - i];
+ }
+ }
+
+ return values;
+ }
+
+ private DynValue[] StackTopToArrayReverse(int items, bool pop)
+ {
+ DynValue[] values = new DynValue[items];
+
+ if (pop)
+ {
+ for (int i = 0; i < items; i++)
+ {
+ values[items - 1 - i] = m_ValueStack.Pop();
+ }
+ }
+ else
+ {
+ for (int i = 0; i < items; i++)
+ {
+ values[items - 1 - i] = m_ValueStack[m_ValueStack.Count - 1 - i];
+ }
+ }
+
+ return values;
+ }
+
+
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/IO/BinDumpBinaryReader.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/IO/BinDumpBinaryReader.cs
new file mode 100755
index 00000000..f10b98d4
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/IO/BinDumpBinaryReader.cs
@@ -0,0 +1,61 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace MoonSharp.Interpreter.IO
+{
+ ///
+ /// "Optimized" BinaryReader which shares strings and use a dumb compression for integers
+ ///
+ public class BinDumpBinaryReader : BinaryReader
+ {
+ public BinDumpBinaryReader(Stream s) : base(s) { }
+ public BinDumpBinaryReader(Stream s, Encoding e) : base(s, e) { }
+
+ List m_Strings = new List();
+
+ public override int ReadInt32()
+ {
+ sbyte b = base.ReadSByte();
+
+ if (b == 0x7F)
+ return (int)base.ReadInt16();
+ else if (b == 0x7E)
+ return (int)base.ReadInt32();
+ else
+ return (int)b;
+ }
+
+ public override uint ReadUInt32()
+ {
+ byte b = base.ReadByte();
+
+ if (b == 0x7F)
+ return (uint)base.ReadUInt16();
+ else if (b == 0x7E)
+ return (uint)base.ReadUInt32();
+ else
+ return (uint)b;
+ }
+
+ public override string ReadString()
+ {
+ int pos = ReadInt32();
+
+ if (pos < m_Strings.Count)
+ {
+ return m_Strings[pos];
+ }
+ else if (pos == m_Strings.Count)
+ {
+ string str = base.ReadString();
+ m_Strings.Add(str);
+ return str;
+ }
+ else
+ {
+ throw new IOException("string map failure");
+ }
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/IO/BinDumpBinaryWriter.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/IO/BinDumpBinaryWriter.cs
new file mode 100755
index 00000000..bd360fd6
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/IO/BinDumpBinaryWriter.cs
@@ -0,0 +1,85 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace MoonSharp.Interpreter.IO
+{
+ ///
+ /// "Optimized" BinaryWriter which shares strings and use a dumb compression for integers
+ ///
+ public class BinDumpBinaryWriter : BinaryWriter
+ {
+ 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 v8 = (byte)value;
+
+ if ((uint)v8 == value && (v8 != 0x7F) && (v8 != 0x7E))
+ {
+ base.Write(v8);
+ }
+ else
+ {
+ ushort v16 = (ushort)value;
+
+ if ((uint)v16 == value)
+ {
+ base.Write((byte)0x7F);
+ base.Write(v16);
+ }
+ else
+ {
+ base.Write((byte)0x7E);
+ base.Write(value);
+ }
+ }
+ }
+
+ public override void Write(int value)
+ {
+ sbyte vsbyte = (sbyte)value;
+
+ if ((int)vsbyte == value && (vsbyte != 0x7F) && (vsbyte != 0x7E))
+ {
+ base.Write(vsbyte);
+ }
+ else
+ {
+ short vshort = (short)value;
+
+ if ((int)vshort == value)
+ {
+ base.Write((sbyte)0x7F);
+ base.Write(vshort);
+ }
+ else
+ {
+ base.Write((sbyte)0x7E);
+ base.Write(value);
+ }
+ }
+ }
+
+ public override void Write(string value)
+ {
+ int pos;
+
+ if (m_StringMap.TryGetValue(value, out pos))
+ {
+ this.Write(m_StringMap[value]);
+ }
+ else
+ {
+ pos = m_StringMap.Count;
+ m_StringMap[value] = pos;
+
+ this.Write(pos);
+ base.Write(value);
+ }
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/IO/UndisposableStream.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/IO/UndisposableStream.cs
new file mode 100755
index 00000000..622b929b
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/IO/UndisposableStream.cs
@@ -0,0 +1,161 @@
+using System;
+using System.IO;
+
+namespace MoonSharp.Interpreter.IO
+{
+ ///
+ /// An adapter over Stream which bypasses the Dispose and Close methods.
+ /// Used to work around the pesky wrappers .NET has over Stream (BinaryReader, StreamWriter, etc.) which think they
+ /// own the Stream and close them when they shouldn't. Damn.
+ ///
+ public class UndisposableStream : Stream
+ {
+ Stream m_Stream;
+
+ public UndisposableStream(Stream stream)
+ {
+ m_Stream = stream;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ }
+
+#if !(PCL || ENABLE_DOTNET || NETFX_CORE)
+ public override void Close()
+ {
+ }
+#endif
+
+
+ public override bool CanRead
+ {
+ get { return m_Stream.CanRead; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return m_Stream.CanSeek; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return m_Stream.CanWrite; }
+ }
+
+ public override void Flush()
+ {
+ m_Stream.Flush();
+ }
+
+ public override long Length
+ {
+ get { return m_Stream.Length; }
+ }
+
+ public override long Position
+ {
+ get { return m_Stream.Position; }
+ set { m_Stream.Position = value; }
+ }
+
+ 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);
+ }
+
+#if (!(NETFX_CORE))
+ 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);
+ }
+#endif
+ public override bool CanTimeout
+ {
+ get { return m_Stream.CanTimeout; }
+ }
+
+
+ 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 int ReadTimeout
+ {
+ get
+ {
+ return m_Stream.ReadTimeout;
+ }
+ set
+ {
+ m_Stream.ReadTimeout = value;
+ }
+ }
+
+ public override string ToString()
+ {
+ return m_Stream.ToString();
+ }
+
+ public override void WriteByte(byte value)
+ {
+ m_Stream.WriteByte(value);
+ }
+
+ public override int WriteTimeout
+ {
+ get
+ {
+ return m_Stream.WriteTimeout;
+ }
+ set
+ {
+ m_Stream.WriteTimeout = value;
+ }
+ }
+
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpHiddenAttribute.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpHiddenAttribute.cs
new file mode 100644
index 00000000..7012483d
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpHiddenAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace MoonSharp.Interpreter
+{
+ ///
+ /// Forces a class member visibility to scripts. Can be used to hide public members. Equivalent to MoonSharpVisible(false).
+ ///
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field
+ | AttributeTargets.Constructor | AttributeTargets.Event, Inherited = true, AllowMultiple = false)]
+ public sealed class MoonSharpHiddenAttribute : Attribute
+ {
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpHideMemberAttribute.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpHideMemberAttribute.cs
new file mode 100644
index 00000000..cc5df024
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpHideMemberAttribute.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace MoonSharp.Interpreter
+{
+ ///
+ /// Lists a userdata member not to be exposed to scripts referencing it by name.
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = true)]
+ public sealed class MoonSharpHideMemberAttribute : Attribute
+ {
+ ///
+ /// Gets the name of the member to be hidden.
+ ///
+ public string MemberName { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Name of the member to hide.
+ public MoonSharpHideMemberAttribute(string memberName)
+ {
+ MemberName = memberName;
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpPropertyAttribute.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpPropertyAttribute.cs
new file mode 100644
index 00000000..a3fe6fec
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpPropertyAttribute.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace MoonSharp.Interpreter
+{
+
+ ///
+ /// Marks a property as a configruation property
+ ///
+ [AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = true)]
+ public sealed class MoonSharpPropertyAttribute : Attribute
+ {
+ ///
+ /// The metamethod name (like '__div', '__ipairs', etc.)
+ ///
+ public string Name { get; private set; }
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public MoonSharpPropertyAttribute()
+ {
+
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name for this property
+ public MoonSharpPropertyAttribute(string name)
+ {
+ Name = name;
+ }
+ }
+
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpUserDataAttribute.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpUserDataAttribute.cs
new file mode 100644
index 00000000..ec2c5c64
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpUserDataAttribute.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace MoonSharp.Interpreter
+{
+ ///
+ /// Marks a type of automatic registration as userdata (which happens only if UserData.RegisterAssembly is called).
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
+ public sealed class MoonSharpUserDataAttribute : Attribute
+ {
+ ///
+ /// The interop access mode
+ ///
+ public InteropAccessMode AccessMode { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public MoonSharpUserDataAttribute()
+ {
+ AccessMode = InteropAccessMode.Default;
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpUserDataMetamethodAttribute.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpUserDataMetamethodAttribute.cs
new file mode 100644
index 00000000..42fb93ba
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpUserDataMetamethodAttribute.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace MoonSharp.Interpreter
+{
+ ///
+ /// Marks a method as the handler of metamethods of a userdata type
+ ///
+ [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
+ public sealed class MoonSharpUserDataMetamethodAttribute : Attribute
+ {
+ ///
+ /// The metamethod name (like '__div', '__ipairs', etc.)
+ ///
+ public string Name { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The metamethod name (like '__div', '__ipairs', etc.)
+ public MoonSharpUserDataMetamethodAttribute(string name)
+ {
+ Name = name;
+ }
+ }
+
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpVisibleAttribute.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpVisibleAttribute.cs
new file mode 100644
index 00000000..03b43369
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Attributes/MoonSharpVisibleAttribute.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace MoonSharp.Interpreter.Interop
+{
+ ///
+ /// Forces a class member visibility to scripts. Can be used to hide public members or to expose non-public ones.
+ ///
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field
+ | AttributeTargets.Constructor | AttributeTargets.Event, Inherited = true, AllowMultiple = false)]
+ public sealed class MoonSharpVisibleAttribute : Attribute
+ {
+ ///
+ /// Gets a value indicating whether this is set to "visible".
+ ///
+ public bool Visible { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// if set to true the member will be exposed to scripts, if false the member will be hidden.
+ public MoonSharpVisibleAttribute(bool visible)
+ {
+ Visible = visible;
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs
new file mode 100644
index 00000000..17ccd53b
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs
@@ -0,0 +1,665 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MoonSharp.Interpreter.Compatibility;
+using MoonSharp.Interpreter.Interop.Converters;
+
+namespace MoonSharp.Interpreter.Interop.BasicDescriptors
+{
+ ///
+ /// An abstract user data descriptor which accepts members described by objects and
+ /// correctly dispatches to them.
+ /// Metamethods are also by default dispatched to operator overloads and other similar methods - see
+ /// .
+ ///
+ public abstract class DispatchingUserDataDescriptor : IUserDataDescriptor, IOptimizableDescriptor
+ {
+ private int m_ExtMethodsVersion = 0;
+ private Dictionary m_MetaMembers = new Dictionary();
+ private Dictionary m_Members = new Dictionary();
+
+ ///
+ /// The special name used by CLR for indexer getters
+ ///
+ protected const string SPECIALNAME_INDEXER_GET = "get_Item";
+ ///
+ /// The special name used by CLR for indexer setters
+ ///
+ protected const string SPECIALNAME_INDEXER_SET = "set_Item";
+
+ ///
+ /// The special name used by CLR for explicit cast conversions
+ ///
+ protected const string SPECIALNAME_CAST_EXPLICIT = "op_Explicit";
+ ///
+ /// The special name used by CLR for implicit cast conversions
+ ///
+ protected const string SPECIALNAME_CAST_IMPLICIT = "op_Implicit";
+
+
+ ///
+ /// Gets the name of the descriptor (usually, the name of the type described).
+ ///
+ public string Name { get; private set; }
+ ///
+ /// Gets the type this descriptor refers to
+ ///
+ public Type Type { get; private set; }
+ ///
+ /// Gets a human readable friendly name of the descriptor
+ ///
+ public string FriendlyName { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The type this descriptor refers to.
+ /// A friendly name for the type, or null.
+ protected DispatchingUserDataDescriptor(Type type, string friendlyName = null)
+ {
+ Type = type;
+ Name = type.FullName;
+ FriendlyName = friendlyName ?? type.Name;
+ }
+
+ ///
+ /// Adds a member to the meta-members list.
+ ///
+ /// The name of the metamethod.
+ /// The desc.
+ ///
+ /// Thrown if a name conflict is detected and one of the conflicting members does not support overloads.
+ ///
+ public void AddMetaMember(string name, IMemberDescriptor desc)
+ {
+ if (desc != null)
+ AddMemberTo(m_MetaMembers, name, desc);
+ }
+
+
+ ///
+ /// Adds a DynValue as a member
+ ///
+ /// The name.
+ /// The value.
+ public void AddDynValue(string name, DynValue value)
+ {
+ var desc = new DynValueMemberDescriptor(name, value);
+ AddMemberTo(m_Members, name, desc);
+ }
+
+ ///
+ /// Adds a property to the member list
+ ///
+ /// The name.
+ /// The descriptor.
+ ///
+ /// Thrown if a name conflict is detected and one of the conflicting members does not support overloads.
+ ///
+ public void AddMember(string name, IMemberDescriptor desc)
+ {
+ if (desc != null)
+ AddMemberTo(m_Members, name, desc);
+ }
+
+ ///
+ /// Gets the member names.
+ ///
+ public IEnumerable MemberNames
+ {
+ get { return m_Members.Keys; }
+ }
+
+ ///
+ /// Gets the members.
+ ///
+ public IEnumerable> Members
+ {
+ get { return m_Members; }
+ }
+
+ ///
+ /// Finds the member with a given name. If not found, null is returned.
+ ///
+ /// Name of the member.
+ ///
+ public IMemberDescriptor FindMember(string memberName)
+ {
+ return m_Members.GetOrDefault(memberName);
+ }
+
+ ///
+ /// Removes the member with a given name. In case of overloaded functions, all overloads are removed.
+ ///
+ /// Name of the member.
+ public void RemoveMember(string memberName)
+ {
+ m_Members.Remove(memberName);
+ }
+
+ ///
+ /// Gets the meta member names.
+ ///
+ public IEnumerable MetaMemberNames
+ {
+ get { return m_MetaMembers.Keys; }
+ }
+
+ ///
+ /// Gets the meta members.
+ ///
+ public IEnumerable> MetaMembers
+ {
+ get { return m_MetaMembers; }
+ }
+
+ ///
+ /// Finds the meta member with a given name. If not found, null is returned.
+ ///
+ /// Name of the member.
+ public IMemberDescriptor FindMetaMember(string memberName)
+ {
+ return m_MetaMembers.GetOrDefault(memberName);
+ }
+
+ ///
+ /// Removes the meta member with a given name. In case of overloaded functions, all overloads are removed.
+ ///
+ /// Name of the member.
+ public void RemoveMetaMember(string memberName)
+ {
+ m_MetaMembers.Remove(memberName);
+ }
+
+
+
+
+ private void AddMemberTo(Dictionary members, string name, IMemberDescriptor desc)
+ {
+ IOverloadableMemberDescriptor odesc = desc as IOverloadableMemberDescriptor;
+
+ if (odesc != null)
+ {
+ if (members.ContainsKey(name))
+ {
+ OverloadedMethodMemberDescriptor overloads = members[name] as OverloadedMethodMemberDescriptor;
+
+ if (overloads != null)
+ overloads.AddOverload(odesc);
+ else
+ throw new ArgumentException(string.Format("Multiple members named {0} are being added to type {1} and one or more of these members do not support overloads.", name, this.Type.FullName));
+ }
+ else
+ {
+ members.Add(name, new OverloadedMethodMemberDescriptor(name, this.Type, odesc));
+ }
+ }
+ else
+ {
+ if (members.ContainsKey(name))
+ {
+ throw new ArgumentException(string.Format("Multiple members named {0} are being added to type {1} and one or more of these members do not support overloads.", name, this.Type.FullName));
+ }
+ else
+ {
+ members.Add(name, desc);
+ }
+ }
+ }
+
+ ///
+ /// Performs an "index" "get" operation. This tries to resolve minor variations of member names.
+ ///
+ /// The script originating the request
+ /// The object (null if a static request is done)
+ /// The index.
+ /// If set to true, it's indexed with a name, if false it's indexed through brackets.
+ ///
+ public virtual DynValue Index(Script script, object obj, DynValue index, bool isDirectIndexing)
+ {
+ if (!isDirectIndexing)
+ {
+ IMemberDescriptor mdesc = m_Members
+ .GetOrDefault(SPECIALNAME_INDEXER_GET)
+ .WithAccessOrNull(MemberDescriptorAccess.CanExecute);
+
+ if (mdesc != null)
+ return ExecuteIndexer(mdesc, script, obj, index, null);
+ }
+
+ index = index.ToScalar();
+
+ if (index.Type != DataType.String)
+ return null;
+
+ DynValue v = TryIndex(script, obj, index.String);
+ if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter) v = TryIndex(script, obj, UpperFirstLetter(index.String));
+ if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify) v = TryIndex(script, obj, Camelify(index.String));
+ if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase) v = TryIndex(script, obj, UpperFirstLetter(Camelify(index.String)));
+
+ if (v == null && m_ExtMethodsVersion < UserData.GetExtensionMethodsChangeVersion())
+ {
+ m_ExtMethodsVersion = UserData.GetExtensionMethodsChangeVersion();
+
+ v = TryIndexOnExtMethod(script, obj, index.String);
+ if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter) v = TryIndexOnExtMethod(script, obj, UpperFirstLetter(index.String));
+ if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify) v = TryIndexOnExtMethod(script, obj, Camelify(index.String));
+ if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase) v = TryIndexOnExtMethod(script, obj, UpperFirstLetter(Camelify(index.String)));
+ }
+
+ return v;
+ }
+
+
+ ///
+ /// Tries to perform an indexing operation by checking newly added extension methods for the given indexName.
+ ///
+ /// The script.
+ /// The object.
+ /// Member name to be indexed.
+ ///
+ ///
+ private DynValue TryIndexOnExtMethod(Script script, object obj, string indexName)
+ {
+ List methods = UserData.GetExtensionMethodsByNameAndType(indexName, this.Type);
+
+ if (methods != null && methods.Count > 0)
+ {
+ var ext = new OverloadedMethodMemberDescriptor(indexName, this.Type);
+ ext.SetExtensionMethodsSnapshot(UserData.GetExtensionMethodsChangeVersion(), methods);
+ m_Members.Add(indexName, ext);
+ return DynValue.NewCallback(ext.GetCallback(script, obj));
+ }
+
+ return null;
+ }
+
+ ///
+ /// Determines whether the descriptor contains the specified member (by exact name)
+ ///
+ /// Name of the member.
+ ///
+ public bool HasMember(string exactName)
+ {
+ return m_Members.ContainsKey(exactName);
+ }
+
+ ///
+ /// Determines whether the descriptor contains the specified member in the meta list (by exact name)
+ ///
+ /// Name of the meta-member.
+ ///
+ public bool HasMetaMember(string exactName)
+ {
+ return m_MetaMembers.ContainsKey(exactName);
+ }
+
+
+ ///
+ /// Tries to perform an indexing operation by checking methods and properties for the given indexName
+ ///
+ /// The script.
+ /// The object.
+ /// Member name to be indexed.
+ ///
+ protected virtual DynValue TryIndex(Script script, object obj, string indexName)
+ {
+ IMemberDescriptor desc;
+
+ if (m_Members.TryGetValue(indexName, out desc))
+ {
+ return desc.GetValue(script, obj);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Performs an "index" "set" operation. This tries to resolve minor variations of member names.
+ ///
+ /// The script originating the request
+ /// The object (null if a static request is done)
+ /// The index.
+ /// The value to be set
+ /// If set to true, it's indexed with a name, if false it's indexed through brackets.
+ ///
+ public virtual bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing)
+ {
+ if (!isDirectIndexing)
+ {
+ IMemberDescriptor mdesc = m_Members
+ .GetOrDefault(SPECIALNAME_INDEXER_SET)
+ .WithAccessOrNull(MemberDescriptorAccess.CanExecute);
+
+ if (mdesc != null)
+ {
+ ExecuteIndexer(mdesc, script, obj, index, value);
+ return true;
+ }
+ }
+
+ index = index.ToScalar();
+
+ if (index.Type != DataType.String)
+ return false;
+
+ bool v = TrySetIndex(script, obj, index.String, value);
+ if (!v && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter) v = TrySetIndex(script, obj, UpperFirstLetter(index.String), value);
+ if (!v && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify) v = TrySetIndex(script, obj, Camelify(index.String), value);
+ if (!v && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase) v = TrySetIndex(script, obj, UpperFirstLetter(Camelify(index.String)), value);
+
+ return v;
+ }
+
+ ///
+ /// Tries to perform an indexing "set" operation by checking methods and properties for the given indexName
+ ///
+ /// The script.
+ /// The object.
+ /// Member name to be indexed.
+ /// The value.
+ ///
+ protected virtual bool TrySetIndex(Script script, object obj, string indexName, DynValue value)
+ {
+ IMemberDescriptor descr = m_Members.GetOrDefault(indexName);
+
+ if (descr != null)
+ {
+ descr.SetValue(script, obj, value);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ void IOptimizableDescriptor.Optimize()
+ {
+ foreach (var m in this.m_MetaMembers.Values.OfType())
+ m.Optimize();
+
+ foreach (var m in this.m_Members.Values.OfType())
+ m.Optimize();
+ }
+
+ ///
+ /// Converts the specified name from underscore_case to camelCase.
+ /// Just a wrapper over the method with the same name,
+ ///
+ /// The name.
+ ///
+ protected static string Camelify(string name)
+ {
+ return DescriptorHelpers.Camelify(name);
+ }
+
+ ///
+ /// Converts the specified name to one with an uppercase first letter (something to Something).
+ /// Just a wrapper over the method with the same name,
+ ///
+ /// The name.
+ ///
+ protected static string UpperFirstLetter(string name)
+ {
+ return DescriptorHelpers.UpperFirstLetter(name);
+ }
+
+ ///
+ /// Converts this userdata to string
+ ///
+ /// The object.
+ ///
+ public virtual string AsString(object obj)
+ {
+ return (obj != null) ? obj.ToString() : null;
+ }
+
+
+
+ ///
+ /// Executes the specified indexer method.
+ ///
+ /// The method descriptor
+ /// The script.
+ /// The object.
+ /// The indexer parameter
+ /// The dynvalue to set on a setter, or null.
+ ///
+ ///
+ protected virtual DynValue ExecuteIndexer(IMemberDescriptor mdesc, Script script, object obj, DynValue index, DynValue value)
+ {
+ IList values;
+
+ if (index.Type == DataType.Tuple)
+ {
+ if (value == null)
+ {
+ values = index.Tuple;
+ }
+ else
+ {
+ values = new List(index.Tuple);
+ values.Add(value);
+ }
+ }
+ else
+ {
+ if (value == null)
+ {
+ values = new DynValue[] { index };
+ }
+ else
+ {
+ values = new DynValue[] { index, value };
+ }
+ }
+
+ CallbackArguments args = new CallbackArguments(values, false);
+ ScriptExecutionContext execCtx = script.CreateDynamicExecutionContext();
+
+ DynValue v = mdesc.GetValue(script, obj);
+
+ if (v.Type != DataType.ClrFunction)
+ throw new ScriptRuntimeException("a clr callback was expected in member {0}, while a {1} was found", mdesc.Name, v.Type);
+
+ return v.Callback.ClrCallback(execCtx, args);
+ }
+
+
+ ///
+ /// Gets a "meta" operation on this userdata. If a descriptor does not support this functionality,
+ /// it should return "null" (not a nil).
+ /// See for further details.
+ ///
+ /// If a method exists marked with for the specific
+ /// metamethod requested, that method is returned.
+ ///
+ /// If the above fails, the following dispatching occur:
+ ///
+ /// __add, __sub, __mul, __div, __mod and __unm are dispatched to C# operator overloads (if they exist)
+ /// __eq is dispatched to System.Object.Equals.
+ /// __lt and __le are dispatched IComparable.Compare, if the type implements IComparable or IComparable{object}
+ /// __len is dispatched to Length and Count properties, if those exist.
+ /// __iterator is handled if the object implements IEnumerable or IEnumerator.
+ /// __tonumber is dispatched to implicit or explicit conversion operators to standard numeric types.
+ /// __tobool is dispatched to an implicit or explicit conversion operator to bool. If that fails, operator true is used.
+ ///
+ /// The script originating the request
+ /// The object (null if a static request is done)
+ /// The name of the metamember.
+ ///
+ ///
+ public virtual DynValue MetaIndex(Script script, object obj, string metaname)
+ {
+ IMemberDescriptor desc = m_MetaMembers.GetOrDefault(metaname);
+
+ if (desc != null)
+ {
+ return desc.GetValue(script, obj);
+ }
+
+ switch (metaname)
+ {
+ case "__add":
+ return DispatchMetaOnMethod(script, obj, "op_Addition");
+ case "__sub":
+ return DispatchMetaOnMethod(script, obj, "op_Subtraction");
+ case "__mul":
+ return DispatchMetaOnMethod(script, obj, "op_Multiply");
+ case "__div":
+ return DispatchMetaOnMethod(script, obj, "op_Division");
+ case "__mod":
+ return DispatchMetaOnMethod(script, obj, "op_Modulus");
+ case "__unm":
+ return DispatchMetaOnMethod(script, obj, "op_UnaryNegation");
+ case "__eq":
+ return MultiDispatchEqual(script, obj);
+ case "__lt":
+ return MultiDispatchLessThan(script, obj);
+ case "__le":
+ return MultiDispatchLessThanOrEqual(script, obj);
+ case "__len":
+ return TryDispatchLength(script, obj);
+ case "__tonumber":
+ return TryDispatchToNumber(script, obj);
+ case "__tobool":
+ return TryDispatchToBool(script, obj);
+ case "__iterator":
+ return ClrToScriptConversions.EnumerationToDynValue(script, obj);
+ default:
+ return null;
+ }
+ }
+
+ #region MetaMethodsDispatching
+
+
+ private int PerformComparison(object obj, object p1, object p2)
+ {
+ IComparable comp = (IComparable)obj;
+
+ if (comp != null)
+ {
+ if (object.ReferenceEquals(obj, p1))
+ return comp.CompareTo(p2);
+ else if (object.ReferenceEquals(obj, p2))
+ return -comp.CompareTo(p1);
+ }
+
+ throw new InternalErrorException("unexpected case");
+ }
+
+
+ private DynValue MultiDispatchLessThanOrEqual(Script script, object obj)
+ {
+ IComparable comp = obj as IComparable;
+ if (comp != null)
+ {
+ return DynValue.NewCallback(
+ (context, args) =>
+ DynValue.NewBoolean(PerformComparison(obj, args[0].ToObject(), args[1].ToObject()) <= 0));
+ }
+
+ return null;
+ }
+
+ private DynValue MultiDispatchLessThan(Script script, object obj)
+ {
+ IComparable comp = obj as IComparable;
+ if (comp != null)
+ {
+ return DynValue.NewCallback(
+ (context, args) =>
+ DynValue.NewBoolean(PerformComparison(obj, args[0].ToObject(), args[1].ToObject()) < 0));
+ }
+
+ return null;
+ }
+
+ private DynValue TryDispatchLength(Script script, object obj)
+ {
+ if (obj == null) return null;
+
+ var lenprop = m_Members.GetOrDefault("Length");
+ if (lenprop != null && lenprop.CanRead() && !lenprop.CanExecute()) return lenprop.GetGetterCallbackAsDynValue(script, obj);
+
+ var countprop = m_Members.GetOrDefault("Count");
+ if (countprop != null && countprop.CanRead() && !countprop.CanExecute()) return countprop.GetGetterCallbackAsDynValue(script, obj);
+
+ return null;
+ }
+
+
+ private DynValue MultiDispatchEqual(Script script, object obj)
+ {
+ return DynValue.NewCallback(
+ (context, args) => DynValue.NewBoolean(CheckEquality(obj, args[0].ToObject(), args[1].ToObject())));
+ }
+
+
+ private bool CheckEquality(object obj, object p1, object p2)
+ {
+ if (obj != null)
+ {
+ if (object.ReferenceEquals(obj, p1))
+ return obj.Equals(p2);
+ else if (object.ReferenceEquals(obj, p2))
+ return obj.Equals(p1);
+ }
+
+ if (p1 != null) return p1.Equals(p2);
+ else if (p2 != null) return p2.Equals(p1);
+ else return true;
+ }
+
+ private DynValue DispatchMetaOnMethod(Script script, object obj, string methodName)
+ {
+ IMemberDescriptor desc = m_Members.GetOrDefault(methodName);
+
+ if (desc != null)
+ {
+ return desc.GetValue(script, obj);
+ }
+ else
+ return null;
+ }
+
+
+ private DynValue TryDispatchToNumber(Script script, object obj)
+ {
+ foreach (Type t in NumericConversions.NumericTypesOrdered)
+ {
+ var name = t.GetConversionMethodName();
+ var v = DispatchMetaOnMethod(script, obj, name);
+ if (v != null) return v;
+ }
+ return null;
+ }
+
+
+ private DynValue TryDispatchToBool(Script script, object obj)
+ {
+ var name = typeof(bool).GetConversionMethodName();
+ var v = DispatchMetaOnMethod(script, obj, name);
+ if (v != null) return v;
+ return DispatchMetaOnMethod(script, obj, "op_True");
+ }
+
+ #endregion
+
+
+ ///
+ /// Determines whether the specified object is compatible with the specified type.
+ /// Unless a very specific behaviour is needed, the correct implementation is a
+ /// simple " return type.IsInstanceOfType(obj); "
+ ///
+ /// The type.
+ /// The object.
+ ///
+ public virtual bool IsTypeCompatible(Type type, object obj)
+ {
+ return Framework.Do.IsInstanceOfType(type, obj);
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/IMemberDescriptor.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/IMemberDescriptor.cs
new file mode 100644
index 00000000..02dacfc7
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/IMemberDescriptor.cs
@@ -0,0 +1,147 @@
+
+namespace MoonSharp.Interpreter.Interop.BasicDescriptors
+{
+ ///
+ /// Base interface to describe access to members of a given type.
+ /// While it's not infrastructural to implement custom type descriptors, it's needed for
+ /// classes extending .
+ ///
+ public interface IMemberDescriptor
+ {
+ ///
+ /// Gets a value indicating whether the described member is static.
+ ///
+ bool IsStatic { get; }
+ ///
+ /// Gets the name of the member
+ ///
+ string Name { get; }
+ ///
+ /// Gets the types of access supported by this member
+ ///
+ MemberDescriptorAccess MemberAccess { get; }
+ ///
+ /// Gets the value of this member as a to be exposed to scripts.
+ /// Implementors should raise exceptions if the value cannot be read or if access to an
+ /// instance member through a static userdata is attempted.
+ ///
+ /// The script.
+ /// The object owning this member, or null if static.
+ /// The value of this member as a .
+ DynValue GetValue(Script script, object obj);
+ ///
+ /// Sets the value of this member from a .
+ /// Implementors should raise exceptions if the value cannot be read or if access to an
+ /// instance member through a static userdata is attempted.
+ ///
+ /// The script.
+ /// The object owning this member, or null if static.
+ /// The value to be set.
+ void SetValue(Script script, object obj, DynValue value);
+ }
+
+
+ ///
+ /// Extension methods for and .
+ ///
+ public static class MemberDescriptor
+ {
+ ///
+ /// Determines whether the specified MemberDescriptorAccess has ALL the specified flags.
+ ///
+ /// The access.
+ /// The flag.
+ ///
+ public static bool HasAllFlags(this MemberDescriptorAccess access, MemberDescriptorAccess flag)
+ {
+ return (access & flag) == flag;
+ }
+
+ ///
+ /// Determines whether this instance can be read
+ ///
+ /// The descriptor instance.
+ ///
+ public static bool CanRead(this IMemberDescriptor desc)
+ {
+ return desc.MemberAccess.HasAllFlags(MemberDescriptorAccess.CanRead);
+ }
+
+ ///
+ /// Determines whether this instance can be written to
+ ///
+ /// The descriptor instance.
+ ///
+ public static bool CanWrite(this IMemberDescriptor desc)
+ {
+ return desc.MemberAccess.HasAllFlags(MemberDescriptorAccess.CanWrite);
+ }
+
+ ///
+ /// Determines whether this instance can be executed (called as a function)
+ ///
+ /// The descriptor instance.
+ ///
+ public static bool CanExecute(this IMemberDescriptor desc)
+ {
+ return desc.MemberAccess.HasAllFlags(MemberDescriptorAccess.CanExecute);
+ }
+
+ ///
+ /// Gets the getter of the member as a DynValue containing a callback
+ ///
+ /// The descriptor instance.
+ /// The script.
+ /// The object.
+ ///
+ public static DynValue GetGetterCallbackAsDynValue(this IMemberDescriptor desc, Script script, object obj)
+ {
+ return DynValue.NewCallback((p1, p2) => desc.GetValue(script, obj));
+ }
+
+ ///
+ /// Returns the specified descriptor if it supports all the specified access modes, otherwise returns null.
+ ///
+ /// The descriptor instance.
+ /// The access mode(s).
+ ///
+ public static IMemberDescriptor WithAccessOrNull(this IMemberDescriptor desc, MemberDescriptorAccess access)
+ {
+ if (desc == null)
+ return null;
+
+ if (desc.MemberAccess.HasAllFlags(access))
+ return desc;
+
+ return null;
+ }
+
+ ///
+ /// Raises an appropriate ScriptRuntimeException if the specified access is not supported.
+ /// Checks are made for the MemberDescriptorAccess permissions AND for the access of instance
+ /// members through static userdatas.
+ ///
+ /// The desc.
+ /// The access.
+ /// The object to be checked for access.
+ 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);
+ }
+
+
+
+
+ }
+
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/IOptimizableDescriptor.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/IOptimizableDescriptor.cs
new file mode 100644
index 00000000..15edb797
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/IOptimizableDescriptor.cs
@@ -0,0 +1,15 @@
+
+namespace MoonSharp.Interpreter.Interop.BasicDescriptors
+{
+ ///
+ /// Interface for descriptors of any kind which support optimizations of their implementation according to InteropAccessMode
+ /// modes. This should seldom - if ever - be implemented in user code.
+ ///
+ public interface IOptimizableDescriptor
+ {
+ ///
+ /// Called by standard descriptors when background optimization or preoptimization needs to be performed.
+ ///
+ void Optimize();
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/IOverloadableMemberDescriptor.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/IOverloadableMemberDescriptor.cs
new file mode 100644
index 00000000..bfd37043
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/IOverloadableMemberDescriptor.cs
@@ -0,0 +1,49 @@
+using System;
+
+namespace MoonSharp.Interpreter.Interop.BasicDescriptors
+{
+ ///
+ /// Specialized for members supporting overloads resolution.
+ ///
+ public interface IOverloadableMemberDescriptor : IMemberDescriptor
+ {
+ ///
+ /// Invokes the member from script.
+ /// Implementors should raise exceptions if the value cannot be executed or if access to an
+ /// instance member through a static userdata is attempted.
+ ///
+ /// The script.
+ /// The object.
+ /// The context.
+ /// The arguments.
+ ///
+ DynValue Execute(Script script, object obj, ScriptExecutionContext context, CallbackArguments args);
+
+ ///
+ /// Gets the type which this extension method extends, null if this is not an extension method.
+ ///
+ Type ExtensionMethodType { get; }
+
+ ///
+ /// Gets the type of the arguments of the underlying CLR function
+ ///
+ ParameterDescriptor[] Parameters { get; }
+
+ ///
+ /// Gets a value indicating the type of the ParamArray parameter of a var-args function. If the function is not var-args,
+ /// null is returned.
+ ///
+ Type VarArgsArrayType { get; }
+ ///
+ /// Gets a value indicating the type of the elements of the ParamArray parameter of a var-args function. If the function is not var-args,
+ /// null is returned.
+ ///
+ Type VarArgsElementType { get; }
+
+ ///
+ /// Gets a sort discriminant to give consistent overload resolution matching in case of perfectly equal scores
+ ///
+ string SortDiscriminant { get; }
+ }
+
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/MemberDescriptorAccess.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/MemberDescriptorAccess.cs
new file mode 100644
index 00000000..adbeac67
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/MemberDescriptorAccess.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace MoonSharp.Interpreter.Interop.BasicDescriptors
+{
+ ///
+ /// Permissions for members access
+ ///
+ [Flags]
+ public enum MemberDescriptorAccess
+ {
+ ///
+ /// The member can be read from
+ ///
+ CanRead = 1,
+ ///
+ /// The member can be written to
+ ///
+ CanWrite = 2,
+ ///
+ /// The can be invoked
+ ///
+ CanExecute = 4
+ }
+
+
+
+
+
+
+
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/ParameterDescriptor.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/ParameterDescriptor.cs
new file mode 100755
index 00000000..547fe66c
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/ParameterDescriptor.cs
@@ -0,0 +1,184 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using MoonSharp.Interpreter.Compatibility;
+
+namespace MoonSharp.Interpreter.Interop.BasicDescriptors
+{
+ ///
+ /// Descriptor of parameters used in implementations.
+ ///
+ public sealed class ParameterDescriptor : IWireableDescriptor
+ {
+ ///
+ /// Gets the name of the parameter
+ ///
+ public string Name { get; private set; }
+ ///
+ /// Gets the type of the parameter
+ ///
+ public Type Type { get; private set; }
+ ///
+ /// Gets a value indicating whether this instance has a default value.
+ ///
+ public bool HasDefaultValue { get; private set; }
+ ///
+ /// Gets the default value
+ ///
+ public object DefaultValue { get; private set; }
+ ///
+ /// Gets a value indicating whether this instance is an out parameter
+ ///
+ public bool IsOut { get; private set; }
+ ///
+ /// Gets a value indicating whether this instance is a "ref" parameter
+ ///
+ public bool IsRef { get; private set; }
+ ///
+ /// Gets a value indicating whether this instance is a variable arguments param
+ ///
+ public bool IsVarArgs { get; private set; }
+ ///
+ /// Gets a value indicating whether this instance has been restricted.
+ ///
+ public bool HasBeenRestricted { get { return m_OriginalType != null; } }
+ ///
+ /// Gets the original type of the parameter before any restriction has been applied.
+ ///
+ public Type OriginalType { get { return m_OriginalType ?? Type; } }
+
+
+ ///
+ /// If the type got restricted, the original type before the restriction.
+ ///
+ private Type m_OriginalType = null;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name.
+ /// The type.
+ /// if set to true the parameter has default value.
+ /// The default value.
+ /// if set to true, is an out param.
+ /// if set to true is a ref param.
+ /// if set to true is variable arguments param.
+ 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;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name.
+ /// The type.
+ /// if set to true the parameter has default value.
+ /// The default value.
+ /// if set to true, is an out param.
+ /// if set to true is a ref param.
+ /// if set to true is variable arguments param.
+ /// The type restriction, or nll.
+ 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);
+ }
+ }
+
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// A ParameterInfo taken from reflection.
+ 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), true).Any());
+ }
+
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ ///
+ /// A that represents this instance.
+ ///
+ public override string ToString()
+ {
+ return string.Format("{0} {1}{2}", Type.Name, Name, HasDefaultValue ? " = ..." : "");
+ }
+
+ ///
+ /// Restricts the type of this parameter to a tighter constraint.
+ /// Restrictions must be applied before the containing this
+ /// parameter is used in any way.
+ ///
+ /// The new type.
+ ///
+ /// Cannot restrict a ref/out or varargs param
+ /// or
+ /// Specified operation is not a restriction
+ ///
+ 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;
+ }
+
+
+ ///
+ /// Prepares the descriptor for hard-wiring.
+ /// The descriptor fills the passed table with all the needed data for hardwire generators to generate the appropriate code.
+ ///
+ /// The table to be filled
+ 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));
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/ClrToScriptConversions.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/ClrToScriptConversions.cs
new file mode 100755
index 00000000..7576ffdb
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/ClrToScriptConversions.cs
@@ -0,0 +1,180 @@
+using System;
+using System.Reflection;
+using System.Text;
+using MoonSharp.Interpreter.Interop.RegistrationPolicies;
+
+namespace MoonSharp.Interpreter.Interop.Converters
+{
+ internal static class ClrToScriptConversions
+ {
+ ///
+ /// Tries to convert a CLR object to a MoonSharp value, using "trivial" logic.
+ /// Skips on custom conversions, etc.
+ /// Does NOT throw on failure.
+ ///
+ internal static DynValue TryObjectToTrivialDynValue(Script script, object obj)
+ {
+ if (obj == null)
+ return DynValue.Nil;
+
+ if (obj is DynValue)
+ return (DynValue)obj;
+
+ Type t = 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(t))
+ return DynValue.NewNumber(NumericConversions.TypeToDouble(t, obj));
+
+ if (obj is Table)
+ return DynValue.NewTable((Table)obj);
+
+ return null;
+ }
+
+
+ ///
+ /// Tries to convert a CLR object to a MoonSharp value, using "simple" logic.
+ /// Does NOT throw on failure.
+ ///
+ internal static DynValue TryObjectToSimpleDynValue(Script script, object obj)
+ {
+ if (obj == null)
+ return DynValue.Nil;
+
+ if (obj is DynValue)
+ return (DynValue)obj;
+
+
+ var converter = Script.GlobalOptions.CustomConverters.GetClrToScriptCustomConversion(obj.GetType());
+ if (converter != null)
+ {
+ var v = converter(script, obj);
+ if (v != null)
+ return v;
+ }
+
+ Type t = 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(t))
+ return DynValue.NewNumber(NumericConversions.TypeToDouble(t, obj));
+
+ if (obj is Table)
+ return DynValue.NewTable((Table)obj);
+
+ if (obj is CallbackFunction)
+ return DynValue.NewCallback((CallbackFunction)obj);
+
+ if (obj is Delegate)
+ {
+ Delegate d = (Delegate)obj;
+
+
+#if NETFX_CORE
+ MethodInfo mi = d.GetMethodInfo();
+#else
+ MethodInfo mi = d.Method;
+#endif
+
+ if (CallbackFunction.CheckCallbackSignature(mi, false))
+ return DynValue.NewCallback((Func)d);
+ }
+
+ return null;
+ }
+
+
+ ///
+ /// Tries to convert a CLR object to a MoonSharp value, using more in-depth analysis
+ ///
+ internal static DynValue ObjectToDynValue(Script script, object obj)
+ {
+ DynValue v = TryObjectToSimpleDynValue(script, obj);
+
+ if (v != null) return v;
+
+ v = UserData.Create(obj);
+ if (v != null) return v;
+
+ if (obj is Type)
+ v = UserData.CreateStatic(obj as Type);
+
+ // unregistered enums go as integers
+ if (obj is Enum)
+ return DynValue.NewNumber(NumericConversions.TypeToDouble(Enum.GetUnderlyingType(obj.GetType()), obj));
+
+ if (v != null) return v;
+
+ if (obj is Delegate)
+ return DynValue.NewCallback(CallbackFunction.FromDelegate(script, (Delegate)obj));
+
+ if (obj is MethodInfo)
+ {
+ MethodInfo mi = (MethodInfo)obj;
+
+ if (mi.IsStatic)
+ {
+ return DynValue.NewCallback(CallbackFunction.FromMethodInfo(script, mi));
+ }
+ }
+
+ if (obj is System.Collections.IList)
+ {
+ Table t = TableConversions.ConvertIListToTable(script, (System.Collections.IList)obj);
+ return DynValue.NewTable(t);
+ }
+
+ if (obj is System.Collections.IDictionary)
+ {
+ Table t = TableConversions.ConvertIDictionaryToTable(script, (System.Collections.IDictionary)obj);
+ return DynValue.NewTable(t);
+ }
+
+ var enumerator = EnumerationToDynValue(script, obj);
+ if (enumerator != null) return enumerator;
+
+
+ throw ScriptRuntimeException.ConvertObjectFailed(obj);
+ }
+
+ ///
+ /// Converts an IEnumerable or IEnumerator to a DynValue
+ ///
+ /// The script.
+ /// The object.
+ ///
+ public static DynValue EnumerationToDynValue(Script script, object obj)
+ {
+ if (obj is System.Collections.IEnumerable)
+ {
+ var enumer = (System.Collections.IEnumerable)obj;
+ return EnumerableWrapper.ConvertIterator(script, enumer.GetEnumerator());
+ }
+
+ if (obj is System.Collections.IEnumerator)
+ {
+ var enumer = (System.Collections.IEnumerator)obj;
+ return EnumerableWrapper.ConvertIterator(script, enumer);
+ }
+
+ return null;
+ }
+
+
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/NumericConversions.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/NumericConversions.cs
new file mode 100644
index 00000000..e022c486
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/NumericConversions.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+
+namespace MoonSharp.Interpreter.Interop.Converters
+{
+ ///
+ /// Static functions to handle conversions of numeric types
+ ///
+ internal static class NumericConversions
+ {
+ static NumericConversions()
+ {
+ NumericTypesOrdered = new Type[]
+ {
+ 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);
+ }
+
+ ///
+ /// HashSet of numeric types
+ ///
+ internal static readonly HashSet NumericTypes;
+ ///
+ /// Array of numeric types in order used for some conversions
+ ///
+ internal static readonly Type[] NumericTypesOrdered;
+
+ ///
+ /// Converts a double to another type
+ ///
+ internal 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;
+ }
+
+ ///
+ /// Converts a type to double
+ ///
+ internal static double TypeToDouble(Type type, object d)
+ {
+ if (type == typeof(double)) return (double)d;
+ if (type == typeof(sbyte)) return (double)(sbyte)d;
+ if (type == typeof(byte)) return (double)(byte)d;
+ if (type == typeof(short)) return (double)(short)d;
+ if (type == typeof(ushort)) return (double)(ushort)d;
+ if (type == typeof(int)) return (double)(int)d;
+ if (type == typeof(uint)) return (double)(uint)d;
+ if (type == typeof(long)) return (double)(long)d;
+ if (type == typeof(ulong)) return (double)(ulong)d;
+ if (type == typeof(float)) return (double)(float)d;
+ if (type == typeof(decimal)) return (double)(decimal)d;
+ return (double)d;
+ }
+
+
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/ScriptToClrConversions.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/ScriptToClrConversions.cs
new file mode 100755
index 00000000..6b595805
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/ScriptToClrConversions.cs
@@ -0,0 +1,317 @@
+using System;
+using System.Globalization;
+using MoonSharp.Interpreter.Compatibility;
+
+namespace MoonSharp.Interpreter.Interop.Converters
+{
+ internal static class ScriptToClrConversions
+ {
+ internal const int WEIGHT_MAX_VALUE = 100;
+ internal const int WEIGHT_CUSTOM_CONVERTER_MATCH = 100;
+ internal const int WEIGHT_EXACT_MATCH = 100;
+ internal const int WEIGHT_STRING_TO_STRINGBUILDER = 99;
+ internal const int WEIGHT_STRING_TO_CHAR = 98;
+ internal const int WEIGHT_NIL_TO_NULLABLE = 100;
+ internal const int WEIGHT_NIL_TO_REFTYPE = 100;
+ internal const int WEIGHT_VOID_WITH_DEFAULT = 50;
+ internal const int WEIGHT_VOID_WITHOUT_DEFAULT = 25;
+ internal const int WEIGHT_NIL_WITH_DEFAULT = 25;
+ internal const int WEIGHT_BOOL_TO_STRING = 5;
+ internal const int WEIGHT_NUMBER_TO_STRING = 50;
+ internal const int WEIGHT_NUMBER_TO_ENUM = 90;
+ internal const int WEIGHT_USERDATA_TO_STRING = 5;
+ internal const int WEIGHT_TABLE_CONVERSION = 90;
+ internal const int WEIGHT_NUMBER_DOWNCAST = 99;
+ internal const int WEIGHT_NO_MATCH = 0;
+ internal const int WEIGHT_NO_EXTRA_PARAMS_BONUS = 100;
+ internal const int WEIGHT_EXTRA_PARAMS_MALUS = 2;
+ internal const int WEIGHT_BYREF_BONUSMALUS = -10;
+ internal const int WEIGHT_VARARGS_MALUS = 1;
+ internal const int WEIGHT_VARARGS_EMPTY = 40;
+
+ ///
+ /// Converts a DynValue to a CLR object [simple conversion]
+ ///
+ internal static object DynValueToObject(DynValue value)
+ {
+ var converter = Script.GlobalOptions.CustomConverters.GetScriptToClrCustomConversion(value.Type, typeof(System.Object));
+ if (converter != null)
+ {
+ var v = converter(value);
+ if (v != null)
+ return v;
+ }
+
+ switch (value.Type)
+ {
+ case DataType.Void:
+ case DataType.Nil:
+ 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;
+ else if (value.UserData.Descriptor != null)
+ return value.UserData.Descriptor.Type;
+ else
+ return null;
+ case DataType.ClrFunction:
+ return value.Callback;
+ default:
+ throw ScriptRuntimeException.ConvertObjectFailed(value.Type);
+ }
+ }
+
+
+ ///
+ /// Converts a DynValue to a CLR object of a specific type
+ ///
+ internal static object DynValueToObjectOfType(DynValue value, Type desiredType, object defaultValue, bool isOptional)
+ {
+ if (desiredType.IsByRef)
+ desiredType = desiredType.GetElementType();
+
+ var converter = Script.GlobalOptions.CustomConverters.GetScriptToClrCustomConversion(value.Type, desiredType);
+ if (converter != null)
+ {
+ var v = converter(value);
+ if (v != null) return v;
+ }
+
+ if (desiredType == typeof(DynValue))
+ return value;
+
+ if (desiredType == typeof(object))
+ return DynValueToObject(value);
+
+ StringConversions.StringSubtype stringSubType = StringConversions.GetStringSubtype(desiredType);
+ string str = null;
+
+ Type nt = Nullable.GetUnderlyingType(desiredType);
+ Type nullableType = null;
+
+ if (nt != null)
+ {
+ nullableType = desiredType;
+ desiredType = nt;
+ }
+
+ switch (value.Type)
+ {
+ case DataType.Void:
+ if (isOptional)
+ return defaultValue;
+ else if ((!Framework.Do.IsValueType(desiredType)) || (nullableType != null))
+ return null;
+ break;
+ case DataType.Nil:
+ if (Framework.Do.IsValueType(desiredType))
+ {
+ if (nullableType != null)
+ return null;
+
+ if (isOptional)
+ return defaultValue;
+ }
+ else
+ {
+ return null;
+ }
+ break;
+ case DataType.Boolean:
+ if (desiredType == typeof(bool))
+ return value.Boolean;
+ if (stringSubType != StringConversions.StringSubtype.None)
+ str = value.Boolean.ToString();
+ break;
+ case DataType.Number:
+ if (Framework.Do.IsEnum(desiredType))
+ { // number to enum conv
+ Type underType = Enum.GetUnderlyingType(desiredType);
+ return NumericConversions.DoubleToType(underType, value.Number);
+ }
+ if (NumericConversions.NumericTypes.Contains(desiredType))
+ return NumericConversions.DoubleToType(desiredType, value.Number);
+ if (stringSubType != StringConversions.StringSubtype.None)
+ str = value.Number.ToString(CultureInfo.InvariantCulture);
+ break;
+ case DataType.String:
+ if (stringSubType != StringConversions.StringSubtype.None)
+ str = value.String;
+ break;
+ case DataType.Function:
+ if (desiredType == typeof(Closure)) return value.Function;
+ else if (desiredType == typeof(ScriptFunctionDelegate)) return value.Function.GetDelegate();
+ break;
+ case DataType.ClrFunction:
+ if (desiredType == typeof(CallbackFunction)) return value.Callback;
+ else if (desiredType == typeof(Func)) return value.Callback.ClrCallback;
+ break;
+ case DataType.UserData:
+ if (value.UserData.Object != null)
+ {
+ var udObj = value.UserData.Object;
+ var udDesc = value.UserData.Descriptor;
+
+ if (udDesc.IsTypeCompatible(desiredType, udObj))
+ return udObj;
+
+ if (stringSubType != StringConversions.StringSubtype.None)
+ str = udDesc.AsString(udObj);
+ }
+ break;
+ case DataType.Table:
+ if (desiredType == typeof(Table) || Framework.Do.IsAssignableFrom(desiredType, typeof(Table)))
+ return value.Table;
+ else
+ {
+ object o = TableConversions.ConvertTableToType(value.Table, desiredType);
+ if (o != null)
+ return o;
+ }
+ break;
+ case DataType.Tuple:
+ break;
+ }
+
+ if (stringSubType != StringConversions.StringSubtype.None && str != null)
+ return StringConversions.ConvertString(stringSubType, str, desiredType, value.Type);
+
+ throw ScriptRuntimeException.ConvertObjectFailed(value.Type, desiredType);
+ }
+
+ ///
+ /// Gets a relative weight of how much the conversion is matching the given types.
+ /// Implementation must follow that of DynValueToObjectOfType.. it's not very DRY in that sense.
+ /// However here we are in perf-sensitive path.. TODO : double-check the gain and see if a DRY impl is better.
+ ///
+ internal static int DynValueToObjectOfTypeWeight(DynValue value, Type desiredType, bool isOptional)
+ {
+ if (desiredType.IsByRef)
+ desiredType = desiredType.GetElementType();
+
+ var customConverter = Script.GlobalOptions.CustomConverters.GetScriptToClrCustomConversion(value.Type, desiredType);
+ if (customConverter != null)
+ return WEIGHT_CUSTOM_CONVERTER_MATCH;
+
+ if (desiredType == typeof(DynValue))
+ return WEIGHT_EXACT_MATCH;
+
+ if (desiredType == typeof(object))
+ return WEIGHT_EXACT_MATCH;
+
+ StringConversions.StringSubtype stringSubType = StringConversions.GetStringSubtype(desiredType);
+
+ Type nt = Nullable.GetUnderlyingType(desiredType);
+ Type nullableType = null;
+
+ if (nt != null)
+ {
+ nullableType = desiredType;
+ desiredType = nt;
+ }
+
+ switch (value.Type)
+ {
+ case DataType.Void:
+ if (isOptional)
+ return WEIGHT_VOID_WITH_DEFAULT;
+ else if ((!Framework.Do.IsValueType(desiredType)) || (nullableType != null))
+ return WEIGHT_VOID_WITHOUT_DEFAULT;
+ break;
+ case DataType.Nil:
+ if (Framework.Do.IsValueType(desiredType))
+ {
+ if (nullableType != null)
+ return WEIGHT_NIL_TO_NULLABLE;
+
+ if (isOptional)
+ return WEIGHT_NIL_WITH_DEFAULT;
+ }
+ else
+ {
+ return WEIGHT_NIL_TO_REFTYPE;
+ }
+ break;
+ case DataType.Boolean:
+ if (desiredType == typeof(bool))
+ return WEIGHT_EXACT_MATCH;
+ if (stringSubType != StringConversions.StringSubtype.None)
+ return WEIGHT_BOOL_TO_STRING;
+ break;
+ case DataType.Number:
+ if (Framework.Do.IsEnum(desiredType))
+ { // number to enum conv
+ return WEIGHT_NUMBER_TO_ENUM;
+ }
+ if (NumericConversions.NumericTypes.Contains(desiredType))
+ return GetNumericTypeWeight(desiredType);
+ if (stringSubType != StringConversions.StringSubtype.None)
+ return WEIGHT_NUMBER_TO_STRING;
+ break;
+ case DataType.String:
+ if (stringSubType == StringConversions.StringSubtype.String)
+ return WEIGHT_EXACT_MATCH;
+ else if (stringSubType == StringConversions.StringSubtype.StringBuilder)
+ return WEIGHT_STRING_TO_STRINGBUILDER;
+ else if (stringSubType == StringConversions.StringSubtype.Char)
+ return WEIGHT_STRING_TO_CHAR;
+ break;
+ case DataType.Function:
+ if (desiredType == typeof(Closure)) return WEIGHT_EXACT_MATCH;
+ else if (desiredType == typeof(ScriptFunctionDelegate)) return WEIGHT_EXACT_MATCH;
+ break;
+ case DataType.ClrFunction:
+ if (desiredType == typeof(CallbackFunction)) return WEIGHT_EXACT_MATCH;
+ else if (desiredType == typeof(Func)) return WEIGHT_EXACT_MATCH;
+ break;
+ case DataType.UserData:
+ if (value.UserData.Object != null)
+ {
+ var udObj = value.UserData.Object;
+ var udDesc = value.UserData.Descriptor;
+
+ if (udDesc.IsTypeCompatible(desiredType, udObj))
+ return WEIGHT_EXACT_MATCH;
+
+ if (stringSubType != StringConversions.StringSubtype.None)
+ return WEIGHT_USERDATA_TO_STRING;
+ }
+ break;
+ case DataType.Table:
+ if (desiredType == typeof(Table) || Framework.Do.IsAssignableFrom(desiredType, typeof(Table)))
+ return WEIGHT_EXACT_MATCH;
+ else if (TableConversions.CanConvertTableToType(value.Table, desiredType))
+ return WEIGHT_TABLE_CONVERSION;
+ break;
+ case DataType.Tuple:
+ break;
+ }
+
+ return WEIGHT_NO_MATCH;
+ }
+
+ private static int GetNumericTypeWeight(Type desiredType)
+ {
+ if (desiredType == typeof(double) || desiredType == typeof(decimal))
+ return WEIGHT_EXACT_MATCH;
+ else
+ return WEIGHT_NUMBER_DOWNCAST;
+ }
+
+
+
+
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/StringConversions.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/StringConversions.cs
new file mode 100644
index 00000000..f49708a5
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/StringConversions.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Interop.Converters
+{
+ internal static class StringConversions
+ {
+ internal enum StringSubtype
+ {
+ None,
+ String,
+ StringBuilder,
+ Char
+ }
+
+ internal static StringSubtype GetStringSubtype(Type desiredType)
+ {
+ if (desiredType == typeof(string))
+ return StringSubtype.String;
+ else if (desiredType == typeof(StringBuilder))
+ return StringSubtype.StringBuilder;
+ else if (desiredType == typeof(char))
+ return StringSubtype.Char;
+ else
+ return StringSubtype.None;
+ }
+
+
+ internal 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;
+ case StringSubtype.None:
+ default:
+ break;
+ }
+
+ throw ScriptRuntimeException.ConvertObjectFailed(dataType, desiredType);
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/TableConversions.cs b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/TableConversions.cs
new file mode 100644
index 00000000..0f744f45
--- /dev/null
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/Converters/TableConversions.cs
@@ -0,0 +1,239 @@
+using System;
+using System.Collections.Generic;
+using MoonSharp.Interpreter.Compatibility;
+
+namespace MoonSharp.Interpreter.Interop.Converters
+{
+ internal static class TableConversions
+ {
+ ///
+ /// Converts an IList to a Lua table.
+ ///
+ internal static Table ConvertIListToTable(Script script, System.Collections.IList list)
+ {
+ Table t = new Table(script);
+ for (int i = 0; i < list.Count; i++)
+ {
+ t[i + 1] = ClrToScriptConversions.ObjectToDynValue(script, list[i]);
+ }
+ return t;
+ }
+
+ ///
+ /// Converts an IDictionary to a Lua table.
+ ///
+ internal static Table ConvertIDictionaryToTable(Script script, System.Collections.IDictionary dict)
+ {
+ Table t = new Table(script);
+
+ foreach (System.Collections.DictionaryEntry kvp in dict)
+ {
+ DynValue key = ClrToScriptConversions.ObjectToDynValue(script, kvp.Key);
+ DynValue val = ClrToScriptConversions.ObjectToDynValue(script, kvp.Value);
+ t.Set(key, val);
+ }
+
+ return t;
+ }
+
+ ///
+ /// Determines whether the specified table can be converted to the specified type
+ ///
+ /// The table.
+ /// The type.
+ ///
+ internal static bool CanConvertTableToType(Table table, Type t)
+ {
+ if (Framework.Do.IsAssignableFrom(t, typeof(Dictionary