diff --git a/src/DevTools/PerformanceImpact-Async-Fork/App.config b/src/DevTools/PerformanceImpact-Async-Fork/App.config
new file mode 100644
index 00000000..bae5d6d8
--- /dev/null
+++ b/src/DevTools/PerformanceImpact-Async-Fork/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/DevTools/PerformanceImpact-Async-Fork/PerformanceImpact-Async-Fork.csproj b/src/DevTools/PerformanceImpact-Async-Fork/PerformanceImpact-Async-Fork.csproj
new file mode 100644
index 00000000..708a3c26
--- /dev/null
+++ b/src/DevTools/PerformanceImpact-Async-Fork/PerformanceImpact-Async-Fork.csproj
@@ -0,0 +1,64 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {F7E4153A-B2DA-47D0-BE67-DABC54DB6670}
+ Exe
+ PerformanceImpact_Async_Fork
+ PerformanceImpact_Async_Fork
+ v4.6.1
+ 512
+ true
+ true
+
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ TRACE;DEBUG;FORK
+ prompt
+ 4
+ false
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE;FORK
+ prompt
+ 4
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {49f32476-fca0-45fd-8f89-0c7c0d15e409}
+ MoonSharp.Interpreter.portable40
+
+
+
+
\ No newline at end of file
diff --git a/src/DevTools/PerformanceImpact-Async-Fork/Program.cs b/src/DevTools/PerformanceImpact-Async-Fork/Program.cs
new file mode 100644
index 00000000..9ea4936f
--- /dev/null
+++ b/src/DevTools/PerformanceImpact-Async-Fork/Program.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Threading;
+using MoonSharp.Interpreter;
+using MoonSharp.Interpreter.Diagnostics;
+
+namespace PerformanceImpact_Async
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ var code = @"
+ function move(n, src, dst, via)
+ if n > 0 then
+ move(n - 1, src, via, dst)
+ --check(src, 'to', dst)
+ move(n - 1, via, dst, src)
+ end
+ end
+
+ function run_test()
+ for i = 1, 15000 do
+ move(4, 1, 2, 3)
+ end
+ end
+ ";
+
+ Script.WarmUp();
+
+ var S = new Script();
+
+ S.DoString(code);
+
+ long totalTime = 0;
+ long i = 0;
+
+ var run_testFunc = S.Globals.Get("run_test");
+
+#if FORK
+ var ecToken = new ExecutionControlToken();
+#endif
+
+ while (true)
+ {
+ S.PerformanceStats.Enabled = true;
+
+#if FORK
+ S.CallAsync(ecToken, run_testFunc).Wait();
+#else
+ S.CallAsync(run_testFunc).Wait();
+#endif
+
+ // Get current average
+ totalTime += S.PerformanceStats.GetPerformanceCounterResult(PerformanceCounter.Execution).Counter;
+
+ ++i;
+
+ Console.WriteLine("Current average: {0}", totalTime / i);
+
+ //Thread.Sleep(20);
+
+ S.PerformanceStats.Enabled = false;
+ }
+ }
+ }
+}
diff --git a/src/DevTools/PerformanceImpact-Async-Fork/Properties/AssemblyInfo.cs b/src/DevTools/PerformanceImpact-Async-Fork/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..b15694a2
--- /dev/null
+++ b/src/DevTools/PerformanceImpact-Async-Fork/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("PerformanceImpact-Async-Original")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("PerformanceImpact-Async-Original")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[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("a7a642d3-2efa-4eaa-9762-6dc9e0c883a1")]
+
+// 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/PerformanceImpact-Async-Fork/packages.config b/src/DevTools/PerformanceImpact-Async-Fork/packages.config
new file mode 100644
index 00000000..52a7d804
--- /dev/null
+++ b/src/DevTools/PerformanceImpact-Async-Fork/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/DevTools/PerformanceImpact-Async-Original/App.config b/src/DevTools/PerformanceImpact-Async-Original/App.config
new file mode 100644
index 00000000..bae5d6d8
--- /dev/null
+++ b/src/DevTools/PerformanceImpact-Async-Original/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/DevTools/PerformanceImpact-Async-Original/PerformanceImpact-Async-Original.csproj b/src/DevTools/PerformanceImpact-Async-Original/PerformanceImpact-Async-Original.csproj
new file mode 100644
index 00000000..4efbb193
--- /dev/null
+++ b/src/DevTools/PerformanceImpact-Async-Original/PerformanceImpact-Async-Original.csproj
@@ -0,0 +1,61 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {A7A642D3-2EFA-4EAA-9762-6DC9E0C883A1}
+ Exe
+ PerformanceImpact_Async_Original
+ PerformanceImpact_Async_Original
+ v4.6.1
+ 512
+ true
+ true
+
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ false
+
+
+
+ ..\..\packages\MoonSharp.2.0.0.0\lib\net40-client\MoonSharp.Interpreter.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/DevTools/PerformanceImpact-Async-Original/Program.cs b/src/DevTools/PerformanceImpact-Async-Original/Program.cs
new file mode 100644
index 00000000..9ea4936f
--- /dev/null
+++ b/src/DevTools/PerformanceImpact-Async-Original/Program.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Threading;
+using MoonSharp.Interpreter;
+using MoonSharp.Interpreter.Diagnostics;
+
+namespace PerformanceImpact_Async
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ var code = @"
+ function move(n, src, dst, via)
+ if n > 0 then
+ move(n - 1, src, via, dst)
+ --check(src, 'to', dst)
+ move(n - 1, via, dst, src)
+ end
+ end
+
+ function run_test()
+ for i = 1, 15000 do
+ move(4, 1, 2, 3)
+ end
+ end
+ ";
+
+ Script.WarmUp();
+
+ var S = new Script();
+
+ S.DoString(code);
+
+ long totalTime = 0;
+ long i = 0;
+
+ var run_testFunc = S.Globals.Get("run_test");
+
+#if FORK
+ var ecToken = new ExecutionControlToken();
+#endif
+
+ while (true)
+ {
+ S.PerformanceStats.Enabled = true;
+
+#if FORK
+ S.CallAsync(ecToken, run_testFunc).Wait();
+#else
+ S.CallAsync(run_testFunc).Wait();
+#endif
+
+ // Get current average
+ totalTime += S.PerformanceStats.GetPerformanceCounterResult(PerformanceCounter.Execution).Counter;
+
+ ++i;
+
+ Console.WriteLine("Current average: {0}", totalTime / i);
+
+ //Thread.Sleep(20);
+
+ S.PerformanceStats.Enabled = false;
+ }
+ }
+ }
+}
diff --git a/src/DevTools/PerformanceImpact-Async-Original/Properties/AssemblyInfo.cs b/src/DevTools/PerformanceImpact-Async-Original/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..b15694a2
--- /dev/null
+++ b/src/DevTools/PerformanceImpact-Async-Original/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("PerformanceImpact-Async-Original")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("PerformanceImpact-Async-Original")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[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("a7a642d3-2efa-4eaa-9762-6dc9e0c883a1")]
+
+// 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/PerformanceImpact-Async-Original/packages.config b/src/DevTools/PerformanceImpact-Async-Original/packages.config
new file mode 100644
index 00000000..52a7d804
--- /dev/null
+++ b/src/DevTools/PerformanceImpact-Async-Original/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/MoonSharp.Interpreter.Tests/EndToEnd/AsyncTests.cs b/src/MoonSharp.Interpreter.Tests/EndToEnd/AsyncTests.cs
new file mode 100644
index 00000000..2e5a7f55
--- /dev/null
+++ b/src/MoonSharp.Interpreter.Tests/EndToEnd/AsyncTests.cs
@@ -0,0 +1,141 @@
+#if HASDYNAMIC
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+namespace MoonSharp.Interpreter.Tests.EndToEnd
+{
+ [TestFixture]
+ public class AsyncTests
+ {
+ [Test]
+ public void ThreadPausedIfRunAsync()
+ {
+ Script S = new Script();
+
+ S.Globals.Get("os").Table["sleep"] = (Action)((ctx, args) =>
+ {
+ ctx.PauseExecution(TimeSpan.FromSeconds(2));
+ });
+
+ string code = @"
+ local timeStarted = os.clock()
+ os.sleep()
+ local timeEnded = os.clock()
+
+ return timeEnded - timeStarted > 2";
+
+ var ecToken = new ExecutionControlToken();
+ Assert.IsTrue(S.DoStringAsync(ecToken, code).Result.CastToBool());
+ }
+
+ [Test]
+ public void ThreadPausedIfRunSync()
+ {
+ Script S = new Script();
+
+ S.Globals.Get("os").Table["sleep"] = (Action)((ctx, args) =>
+ {
+ ctx.PauseExecution(TimeSpan.FromSeconds(2));
+ });
+
+ string code = @"
+ local timeStarted = os.clock()
+ os.sleep()
+ local timeEnded = os.clock()
+
+ return timeEnded - timeStarted > 2";
+
+ Assert.IsTrue(S.DoString(code).CastToBool());
+ }
+
+ [Test]
+ public void ClrFunctionExecutionCanBeCancelledIfPausedWhenRunAsync()
+ {
+ Script S = new Script();
+
+ S.Globals.Set("pause", DynValue.NewCallback((ctx, args) =>
+ {
+ ctx.PauseExecution(TimeSpan.FromSeconds(20));
+ return DynValue.NewNil();
+ }));
+
+ var ecToken = new ExecutionControlToken();
+
+ Task t = S.CallAsync(ecToken, S.Globals.Get("pause"));
+
+ t.ContinueWith(_ => Assert.Pass(), TaskContinuationOptions.OnlyOnCanceled);
+ t.ContinueWith(t_ => { if (t_.Exception.InnerExceptions.Count != 1 || !(t_.Exception.InnerException.InnerException is ScriptTerminationRequestedException)) { Assert.Fail("task faulted"); } }, TaskContinuationOptions.OnlyOnFaulted);
+ t.ContinueWith(_ => Assert.Fail("task didn't abort"), TaskContinuationOptions.OnlyOnRanToCompletion);
+
+ Thread.Sleep(500);
+ ecToken.Terminate();
+
+ while (t.Status != TaskStatus.Canceled && t.Status != TaskStatus.Faulted && t.Status != TaskStatus.RanToCompletion) { }
+ }
+
+ [Test]
+ public void LuaCodeExecutionCanBeCancelledIfPausedWhenRunAsync()
+ {
+ Script S = new Script();
+
+ S.Globals.Set("pause", DynValue.NewCallback((ctx, args) =>
+ {
+ ctx.PauseExecution(TimeSpan.FromSeconds(20));
+ return DynValue.NewNil();
+ }));
+
+ var ecToken = new ExecutionControlToken();
+
+ Task t = S.DoStringAsync(ecToken, "pause()");
+
+ t.ContinueWith(_ => Assert.Pass(), TaskContinuationOptions.OnlyOnCanceled);
+ t.ContinueWith(t_ => { if (t_.Exception.InnerExceptions.Count != 1 || !(t_.Exception.InnerException.InnerException is ScriptTerminationRequestedException)) { Assert.Fail("task faulted"); } }, TaskContinuationOptions.OnlyOnFaulted);
+ t.ContinueWith(_ => Assert.Fail("task didn't abort"), TaskContinuationOptions.OnlyOnRanToCompletion);
+
+ Thread.Sleep(500);
+ ecToken.Terminate();
+
+ while (t.Status != TaskStatus.Canceled && t.Status != TaskStatus.Faulted && t.Status != TaskStatus.RanToCompletion) { }
+ }
+
+ [Test]
+ public void ExecutionControlTokenCanBeAssociatedWithMultipleScriptsSimultaneously()
+ {
+ var callback = DynValue.NewCallback((ctx, args) =>
+ {
+ ctx.PauseExecution(TimeSpan.FromSeconds(20));
+ return DynValue.NewNil();
+ });
+
+ Script S1 = new Script();
+
+ S1.Globals.Set("pause", callback);
+
+ Script S2 = new Script();
+
+ S2.Globals.Set("pause", callback);
+
+ var ecToken = new ExecutionControlToken();
+
+ Task t1 = S1.DoStringAsync(ecToken, "pause()");
+ Task t2 = S2.DoStringAsync(ecToken, "pause()");
+
+ t1.ContinueWith(t => { foreach (var e in t.Exception.InnerExceptions) { Console.WriteLine(e.InnerException.Message); } }, TaskContinuationOptions.NotOnRanToCompletion);
+ t1.ContinueWith(t => Assert.IsTrue(t1.IsCanceled, "t1 is canceled"), TaskContinuationOptions.OnlyOnCanceled);
+ t1.ContinueWith(t => Assert.Fail(), TaskContinuationOptions.OnlyOnRanToCompletion);
+
+ t2.ContinueWith(t => { foreach (var e in t.Exception.InnerExceptions) { Console.WriteLine(e.InnerException.Message); } }, TaskContinuationOptions.NotOnRanToCompletion);
+ t2.ContinueWith(t => Assert.IsTrue(t2.IsCanceled, "t2 is canceled"), TaskContinuationOptions.OnlyOnCanceled);
+ t2.ContinueWith(t => Assert.Fail(), TaskContinuationOptions.OnlyOnRanToCompletion);
+
+ Thread.Sleep(500);
+ ecToken.Terminate();
+
+ while ((t1.Status != TaskStatus.Canceled && t1.Status != TaskStatus.Faulted && t1.Status != TaskStatus.RanToCompletion) ||
+ (t2.Status != TaskStatus.Canceled && t2.Status != TaskStatus.Faulted && t2.Status != TaskStatus.RanToCompletion)) { }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/MoonSharp.Interpreter.Tests/EndToEnd/UserDataMethodsTests.cs b/src/MoonSharp.Interpreter.Tests/EndToEnd/UserDataMethodsTests.cs
index 09d4ebfc..d4f81881 100755
--- a/src/MoonSharp.Interpreter.Tests/EndToEnd/UserDataMethodsTests.cs
+++ b/src/MoonSharp.Interpreter.Tests/EndToEnd/UserDataMethodsTests.cs
@@ -291,12 +291,12 @@ public Type Type
get { return typeof(SomeOtherClassCustomDescriptor); }
}
- public DynValue Index(Script script, object obj, DynValue index, bool dummy)
+ public DynValue Index(ExecutionControlToken ecToken, Script script, object obj, DynValue index, bool dummy)
{
return DynValue.NewNumber(index.Number * 4);
}
- public bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool dummy)
+ public bool SetIndex(ExecutionControlToken ecToken, Script script, object obj, DynValue index, DynValue value, bool dummy)
{
throw new NotImplementedException();
}
@@ -306,7 +306,7 @@ public string AsString(object obj)
return null;
}
- public DynValue MetaIndex(Script script, object obj, string metaname)
+ public DynValue MetaIndex(ExecutionControlToken ecToken, Script script, object obj, string metaname)
{
return null;
}
@@ -322,17 +322,17 @@ public bool IsTypeCompatible(Type type, object obj)
public class SelfDescribingClass : IUserDataType
{
- public DynValue Index(Script script, DynValue index, bool isNameIndex)
+ public DynValue Index(ExecutionControlToken ecToken, Script script, DynValue index, bool isNameIndex)
{
return DynValue.NewNumber(index.Number * 3);
}
- public bool SetIndex(Script script, DynValue index, DynValue value, bool isNameIndex)
+ public bool SetIndex(ExecutionControlToken ecToken, Script script, DynValue index, DynValue value, bool isNameIndex)
{
throw new NotImplementedException();
}
- public DynValue MetaIndex(Script script, string metaname)
+ public DynValue MetaIndex(ExecutionControlToken ecToken, Script script, string metaname)
{
throw new NotImplementedException();
}
diff --git a/src/MoonSharp.Interpreter.Tests/EndToEnd/VtUserDataMethodsTests.cs b/src/MoonSharp.Interpreter.Tests/EndToEnd/VtUserDataMethodsTests.cs
index 856e2d16..73280c82 100755
--- a/src/MoonSharp.Interpreter.Tests/EndToEnd/VtUserDataMethodsTests.cs
+++ b/src/MoonSharp.Interpreter.Tests/EndToEnd/VtUserDataMethodsTests.cs
@@ -290,12 +290,12 @@ public Type Type
get { return typeof(SomeOtherClassCustomDescriptor); }
}
- public DynValue Index(Script script, object obj, DynValue index, bool dummy)
+ public DynValue Index(ExecutionControlToken ecToken, Script script, object obj, DynValue index, bool dummy)
{
return DynValue.NewNumber(index.Number * 4);
}
- public bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool dummy)
+ public bool SetIndex(ExecutionControlToken ecToken, Script script, object obj, DynValue index, DynValue value, bool dummy)
{
throw new NotImplementedException();
}
@@ -305,7 +305,7 @@ public string AsString(object obj)
return null;
}
- public DynValue MetaIndex(Script script, object obj, string metaname)
+ public DynValue MetaIndex(ExecutionControlToken ecToken, Script script, object obj, string metaname)
{
return null;
}
@@ -321,17 +321,17 @@ public bool IsTypeCompatible(Type type, object obj)
public struct SelfDescribingClass : IUserDataType
{
- public DynValue Index(Script script, DynValue index, bool isNameIndex)
+ public DynValue Index(ExecutionControlToken ecToken, Script script, DynValue index, bool isNameIndex)
{
return DynValue.NewNumber(index.Number * 3);
}
- public bool SetIndex(Script script, DynValue index, DynValue value, bool isNameIndex)
+ public bool SetIndex(ExecutionControlToken ecToken, Script script, DynValue index, DynValue value, bool isNameIndex)
{
throw new NotImplementedException();
}
- public DynValue MetaIndex(Script script, string metaname)
+ public DynValue MetaIndex(ExecutionControlToken ecToken, Script script, string metaname)
{
throw new NotImplementedException();
}
diff --git a/src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.net40-client/MoonSharp.Interpreter.Tests.net40-client.csproj b/src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.net40-client/MoonSharp.Interpreter.Tests.net40-client.csproj
index 18489fdf..73153d2c 100644
--- a/src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.net40-client/MoonSharp.Interpreter.Tests.net40-client.csproj
+++ b/src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.net40-client/MoonSharp.Interpreter.Tests.net40-client.csproj
@@ -213,6 +213,7 @@
_Hardwired.cs
+
diff --git a/src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.portable40/MoonSharp.Interpreter.Tests.portable40.csproj b/src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.portable40/MoonSharp.Interpreter.Tests.portable40.csproj
index 90d0a48d..3ff9c214 100644
--- a/src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.portable40/MoonSharp.Interpreter.Tests.portable40.csproj
+++ b/src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.portable40/MoonSharp.Interpreter.Tests.portable40.csproj
@@ -213,6 +213,7 @@
_Hardwired.cs
+
diff --git a/src/MoonSharp.Interpreter/AsyncExtensions.cs b/src/MoonSharp.Interpreter/AsyncExtensions.cs
deleted file mode 100755
index eb0055c5..00000000
--- a/src/MoonSharp.Interpreter/AsyncExtensions.cs
+++ /dev/null
@@ -1,421 +0,0 @@
-#if HASDYNAMIC
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MoonSharp.Interpreter.REPL;
-
-namespace MoonSharp.Interpreter
-{
- ///
- /// This class contains extension methods providing async wrappers of many methods.
- /// Asynchronous execution is performed by scheduling the method on the thread pool (through a Task.Factory.StartNew).
- ///
- /// This type is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- public static class AsyncExtensions
- {
- private static Task ExecAsync(Func func)
- {
- return Task.Factory.StartNew(func);
- }
-
- private static Task ExecAsyncVoid(Action func)
- {
- return Task.Factory.StartNew(func);
- }
-
-
-
- ///
- /// Asynchronously calls this function with the specified args
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The function.
- ///
- /// Thrown if function is not of DataType.Function
- public static Task CallAsync(this Closure function)
- {
- return ExecAsync(() => function.Call());
- }
-
- ///
- /// Asynchronously calls this function with the specified args
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The function.
- /// The arguments to pass to the function.
- ///
- /// Thrown if function is not of DataType.Function
- public static Task CallAsync(this Closure function, params object[] args)
- {
- return ExecAsync(() => function.Call(args));
- }
-
- ///
- /// Asynchronously calls this function with the specified args
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The function.
- /// The arguments to pass to the function.
- ///
- /// Thrown if function is not of DataType.Function
- public static Task CallAsync(this Closure function, params DynValue[] args)
- {
- return ExecAsync(() => function.Call(args));
- }
-
- ///
- /// Asynchronously loads and executes a string containing a Lua/MoonSharp script.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The code.
- /// The global context.
- /// Name of the code - used to report errors, etc. Also used by debuggers to locate the original source file.
- ///
- /// A DynValue containing the result of the processing of the loaded chunk.
- ///
- public static Task DoStringAsync(this Script script, string code, Table globalContext = null, string codeFriendlyName = null)
- {
- return ExecAsync(() => script.DoString(code, globalContext, codeFriendlyName));
- }
-
-
- ///
- /// Asynchronously loads and executes a stream containing a Lua/MoonSharp script.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The stream.
- /// The global context.
- /// Name of the code - used to report errors, etc. Also used by debuggers to locate the original source file.
- ///
- /// A DynValue containing the result of the processing of the loaded chunk.
- ///
- public static Task DoStreamAsync(this Script script, Stream stream, Table globalContext = null, string codeFriendlyName = null)
- {
- return ExecAsync(() => script.DoStream(stream, globalContext, codeFriendlyName));
- }
-
-
- ///
- /// Asynchronously loads and executes a file containing a Lua/MoonSharp script.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The filename.
- /// The global context.
- /// Name of the code - used to report errors, etc. Also used by debuggers to locate the original source file.
- ///
- /// A DynValue containing the result of the processing of the loaded chunk.
- ///
- public static Task DoFileAsync(this Script script, string filename, Table globalContext = null, string codeFriendlyName = null)
- {
- return ExecAsync(() => script.DoFile(filename, globalContext, codeFriendlyName));
- }
-
- ///
- /// Asynchronously loads a string containing a Lua/MoonSharp function.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The code.
- /// The global table to bind to this chunk.
- /// Name of the function used to report errors, etc.
- ///
- /// A DynValue containing a function which will execute the loaded code.
- ///
- public static Task LoadFunctionAsync(this Script script, string code, Table globalTable = null, string funcFriendlyName = null)
- {
- return ExecAsync(() => script.LoadFunction(code, globalTable, funcFriendlyName));
- }
-
-
-
- ///
- /// Asynchronously loads a string containing a Lua/MoonSharp script.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The code.
- /// The global table to bind to this chunk.
- /// Name of the code - used to report errors, etc.
- ///
- /// A DynValue containing a function which will execute the loaded code.
- ///
- public static Task LoadStringAsync(this Script script, string code, Table globalTable = null, string codeFriendlyName = null)
- {
- return ExecAsync(() => script.LoadString(code, globalTable, codeFriendlyName));
- }
-
-
-
- ///
- /// Asynchronously loads a Lua/MoonSharp script from a System.IO.Stream. NOTE: This will *NOT* close the stream!
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The stream containing code.
- /// The global table to bind to this chunk.
- /// Name of the code - used to report errors, etc.
- ///
- /// A DynValue containing a function which will execute the loaded code.
- ///
- public static Task LoadStreamAsync(this Script script, Stream stream, Table globalTable = null, string codeFriendlyName = null)
- {
- return ExecAsync(() => script.LoadStream(stream, globalTable, codeFriendlyName));
- }
-
-
- ///
- /// Asynchronously dumps a function on the specified stream.
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The function.
- /// The stream.
- ///
- /// function arg is not a function!
- /// or
- /// stream is readonly!
- /// or
- /// function arg has upvalues other than _ENV
- public static Task DumpAsync(this Script script, DynValue function, Stream stream)
- {
- return ExecAsyncVoid(() => script.Dump(function, stream));
- }
-
-
-
- ///
- /// Asynchronously loads a string containing a Lua/MoonSharp script.
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The code.
- /// The global table to bind to this chunk.
- /// The filename to be used in error messages.
- ///
- /// A DynValue containing a function which will execute the loaded code.
- ///
- public static Task LoadFileAsync(this Script script, string filename, Table globalContext = null, string friendlyFilename = null)
- {
- return ExecAsync(() => script.LoadFile(filename, globalContext, friendlyFilename));
- }
-
-
-
- ///
- /// Calls the specified function.
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The Lua/MoonSharp function to be called
- ///
- /// The return value(s) of the function call.
- ///
- /// Thrown if function is not of DataType.Function
- public static Task CallAsync(this Script script, DynValue function)
- {
- return ExecAsync(() => script.Call(function));
- }
-
-
- ///
- /// Asynchronously calls the specified function.
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The Lua/MoonSharp function to be called
- /// The arguments to pass to the function.
- ///
- /// The return value(s) of the function call.
- ///
- /// Thrown if function is not of DataType.Function
- public static Task CallAsync(this Script script, DynValue function, params DynValue[] args)
- {
- return ExecAsync(() => script.Call(function, args));
- }
-
-
-
- ///
- /// Asynchronously calls the specified function.
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The Lua/MoonSharp function to be called
- /// The arguments to pass to the function.
- ///
- /// The return value(s) of the function call.
- ///
- /// Thrown if function is not of DataType.Function
- public static Task CallAsync(this Script script, DynValue function, params object[] args)
- {
- return ExecAsync(() => script.Call(function, args));
- }
-
-
-
- ///
- /// Asynchronously calls the specified function.
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The Lua/MoonSharp function to be called
- ///
- /// Thrown if function is not of DataType.Function
- public static Task CallAsync(this Script script, object function)
- {
- return ExecAsync(() => script.Call(function));
- }
-
-
- ///
- /// Asynchronously calls the specified function.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The Lua/MoonSharp function to be called
- /// The arguments to pass to the function.
- ///
- /// Thrown if function is not of DataType.Function
- public static Task CallAsync(this Script script, object function, params object[] args)
- {
- return ExecAsync(() => script.Call(function, args));
- }
-
- ///
- /// Asynchronously creates a new dynamic expression.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The script.
- /// The code of the expression.
- ///
- public static Task CreateDynamicExpressionAsync(this Script script, string code)
- {
- return ExecAsync(() => script.CreateDynamicExpression(code));
- }
-
- ///
- /// Asynchronously evaluates a REPL command.
- /// This method returns the result of the computation, or null if more input is needed for having valid code.
- /// In case of errors, exceptions are propagated to the caller.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The interpreter.
- /// The input.
- ///
- /// This method returns the result of the computation, or null if more input is needed for a computation.
- ///
- public static Task EvaluateAsync(this ReplInterpreter interpreter, string input)
- {
- return ExecAsync(() => interpreter.Evaluate(input));
- }
-
- ///
- /// Resumes the coroutine.
- /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The coroutine
- /// The arguments.
- ///
- /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead
- public static Task ResumeAsync(this Coroutine cor, params DynValue[] args)
- {
- return ExecAsync(() => cor.Resume(args));
- }
-
-
- ///
- /// Resumes the coroutine.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The coroutine
- /// The ScriptExecutionContext.
- /// The arguments.
- ///
- public static Task ResumeAsync(this Coroutine cor, ScriptExecutionContext context, params DynValue[] args)
- {
- return ExecAsync(() => cor.Resume(context, args));
- }
-
- ///
- /// Resumes the coroutine.
- /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The coroutine
- ///
- /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead
- public static Task ResumeAsync(this Coroutine cor)
- {
- return ExecAsync(() => cor.Resume());
- }
-
-
- ///
- /// Resumes the coroutine.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The coroutine
- /// The ScriptExecutionContext.
- ///
- public static Task ResumeAsync(this Coroutine cor, ScriptExecutionContext context)
- {
- return ExecAsync(() => cor.Resume(context));
- }
-
- ///
- /// Resumes the coroutine.
- /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead.
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The coroutine
- /// The arguments.
- ///
- /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead.
- public static Task ResumeAsync(this Coroutine cor, params object[] args)
- {
- return ExecAsync(() => cor.Resume(args));
- }
-
-
- ///
- /// Resumes the coroutine
- ///
- /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
- ///
- /// The coroutine
- /// The ScriptExecutionContext.
- /// The arguments.
- ///
- public static Task ResumeAsync(this Coroutine cor, ScriptExecutionContext context, params object[] args)
- {
- return ExecAsync(() => cor.Resume(context, args));
- }
- }
-}
-#endif
diff --git a/src/MoonSharp.Interpreter/CoreLib/ErrorHandlingModule.cs b/src/MoonSharp.Interpreter/CoreLib/ErrorHandlingModule.cs
index ffa21d03..b8d3a3fd 100644
--- a/src/MoonSharp.Interpreter/CoreLib/ErrorHandlingModule.cs
+++ b/src/MoonSharp.Interpreter/CoreLib/ErrorHandlingModule.cs
@@ -14,11 +14,12 @@ public class ErrorHandlingModule
[MoonSharpModuleMethod]
public static DynValue pcall(ScriptExecutionContext executionContext, CallbackArguments args)
{
- return SetErrorHandlerStrategy("pcall", executionContext, args, null);
+ return SetErrorHandlerStrategy(executionContext.m_EcToken, "pcall", executionContext, args, null);
}
- private static DynValue SetErrorHandlerStrategy(string funcName,
+ private static DynValue SetErrorHandlerStrategy(ExecutionControlToken ecToken,
+ string funcName,
ScriptExecutionContext executionContext,
CallbackArguments args,
DynValue handlerBeforeUnwind)
@@ -125,7 +126,7 @@ public static DynValue xpcall(ScriptExecutionContext executionContext, CallbackA
args.AsType(1, "xpcall", DataType.Function, false);
}
- return SetErrorHandlerStrategy("xpcall", executionContext, new CallbackArguments(a, false), handler);
+ return SetErrorHandlerStrategy(executionContext.m_EcToken, "xpcall", executionContext, new CallbackArguments(a, false), handler);
}
}
diff --git a/src/MoonSharp.Interpreter/DataTypes/Closure.cs b/src/MoonSharp.Interpreter/DataTypes/Closure.cs
index 0ed8e705..d2884a6e 100644
--- a/src/MoonSharp.Interpreter/DataTypes/Closure.cs
+++ b/src/MoonSharp.Interpreter/DataTypes/Closure.cs
@@ -1,4 +1,7 @@
using System.Collections.Generic;
+#if HASDYNAMIC
+using System.Threading.Tasks;
+#endif
using MoonSharp.Interpreter.Execution;
namespace MoonSharp.Interpreter
@@ -103,6 +106,50 @@ public DynValue Call(params DynValue[] args)
}
+#if HASDYNAMIC
+ ///
+ /// Asynchronously calls this function with the specified args
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The function.
+ ///
+ /// Thrown if function is not of DataType.Function
+ public Task CallAsync(ExecutionControlToken ecToken)
+ {
+ return OwnerScript.CallAsync(ecToken, this);
+ }
+
+ ///
+ /// Asynchronously calls this function with the specified args
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The function.
+ /// The arguments to pass to the function.
+ ///
+ /// Thrown if function is not of DataType.Function
+ public Task CallAsync(ExecutionControlToken ecToken, params object[] args)
+ {
+ return OwnerScript.CallAsync(ecToken, this, args);
+ }
+
+ ///
+ /// Asynchronously calls this function with the specified args
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The function.
+ /// The arguments to pass to the function.
+ ///
+ /// Thrown if function is not of DataType.Function
+ public Task CallAsync(ExecutionControlToken ecToken, params DynValue[] args)
+ {
+ return OwnerScript.CallAsync(ecToken, this, args);
+ }
+#endif
+
+
///
/// Gets a delegate wrapping calls to this scripted function
///
diff --git a/src/MoonSharp.Interpreter/DataTypes/Coroutine.cs b/src/MoonSharp.Interpreter/DataTypes/Coroutine.cs
index 07132e04..3f9e5b82 100755
--- a/src/MoonSharp.Interpreter/DataTypes/Coroutine.cs
+++ b/src/MoonSharp.Interpreter/DataTypes/Coroutine.cs
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
+#if HASDYNAMIC
+using System.Threading.Tasks;
+#endif
using MoonSharp.Interpreter.Debugging;
using MoonSharp.Interpreter.Execution.VM;
@@ -237,6 +240,96 @@ public DynValue Resume(ScriptExecutionContext context, params object[] args)
}
+#if HASDYNAMIC
+ ///
+ /// Resumes the coroutine.
+ /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The coroutine
+ /// The arguments.
+ ///
+ /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead
+ public Task ResumeAsync(params DynValue[] args)
+ {
+ return Task.Factory.StartNew(() => Resume(args));
+ }
+
+
+ ///
+ /// Resumes the coroutine.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The coroutine
+ /// The ScriptExecutionContext.
+ /// The arguments.
+ ///
+ public Task ResumeAsync(ScriptExecutionContext context, params DynValue[] args)
+ {
+ return Task.Factory.StartNew(() => Resume(context, args));
+ }
+
+ ///
+ /// Resumes the coroutine.
+ /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The coroutine
+ ///
+ /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead
+ public Task ResumeAsync()
+ {
+ return Task.Factory.StartNew(() => Resume());
+ }
+
+
+ ///
+ /// Resumes the coroutine.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The coroutine
+ /// The ScriptExecutionContext.
+ ///
+ public Task ResumeAsync(ScriptExecutionContext context)
+ {
+ return Task.Factory.StartNew(() => Resume(context));
+ }
+
+ ///
+ /// Resumes the coroutine.
+ /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The coroutine
+ /// The arguments.
+ ///
+ /// Only non-CLR coroutines can be resumed with this overload of the Resume method. Use the overload accepting a ScriptExecutionContext instead.
+ public Task ResumeAsync(params object[] args)
+ {
+ return Task.Factory.StartNew(() => Resume(args));
+ }
+
+
+ ///
+ /// Resumes the coroutine
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The coroutine
+ /// The ScriptExecutionContext.
+ /// The arguments.
+ ///
+ public Task ResumeAsync(ScriptExecutionContext context, params object[] args)
+ {
+ return Task.Factory.StartNew(() => Resume(context, args));
+ }
+#endif
+
///
diff --git a/src/MoonSharp.Interpreter/Errors/ScriptTerminationRequestedException.cs b/src/MoonSharp.Interpreter/Errors/ScriptTerminationRequestedException.cs
new file mode 100644
index 00000000..17e748c2
--- /dev/null
+++ b/src/MoonSharp.Interpreter/Errors/ScriptTerminationRequestedException.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace MoonSharp.Interpreter
+{
+ ///
+ /// Exception thrown when an async script is requested to abort
+ ///
+#if !(PCL || ((!UNITY_EDITOR) && (ENABLE_DOTNET)) || NETFX_CORE)
+ [Serializable]
+#endif
+ public class ScriptTerminationRequestedException : InterpreterException
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ internal ScriptTerminationRequestedException()
+ : base("script has been requested to abort")
+ {
+ DecoratedMessage = Message;
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/Execution/DynamicExpression.cs b/src/MoonSharp.Interpreter/Execution/DynamicExpression.cs
index e53b92c6..32519e6e 100644
--- a/src/MoonSharp.Interpreter/Execution/DynamicExpression.cs
+++ b/src/MoonSharp.Interpreter/Execution/DynamicExpression.cs
@@ -36,7 +36,7 @@ internal DynamicExpression(Script S, string strExpr, DynValue constant)
///
public DynValue Evaluate(ScriptExecutionContext context = null)
{
- context = context ?? OwnerScript.CreateDynamicExecutionContext();
+ context = context ?? OwnerScript.CreateDynamicExecutionContext(ExecutionControlToken.Dummy);
this.CheckScriptOwnership(context.GetScript());
diff --git a/src/MoonSharp.Interpreter/Execution/ScriptExecutionContext.cs b/src/MoonSharp.Interpreter/Execution/ScriptExecutionContext.cs
index 0a42ccfb..84327841 100644
--- a/src/MoonSharp.Interpreter/Execution/ScriptExecutionContext.cs
+++ b/src/MoonSharp.Interpreter/Execution/ScriptExecutionContext.cs
@@ -12,12 +12,14 @@ public class ScriptExecutionContext : IScriptPrivateResource
{
Processor m_Processor;
CallbackFunction m_Callback;
+ internal ExecutionControlToken m_EcToken;
- internal ScriptExecutionContext(Processor p, CallbackFunction callBackFunction, SourceRef sourceRef, bool isDynamic = false)
+ internal ScriptExecutionContext(ExecutionControlToken ecToken, Processor p, CallbackFunction callBackFunction, SourceRef sourceRef, bool isDynamic = false)
{
IsDynamicExecution = isDynamic;
m_Processor = p;
m_Callback = callBackFunction;
+ m_EcToken = ecToken;
CallingLocation = sourceRef;
}
@@ -74,7 +76,7 @@ public Table GetMetatable(DynValue value)
///
public DynValue GetMetamethod(DynValue value, string metamethod)
{
- return m_Processor.GetMetamethod(value, metamethod);
+ return m_Processor.GetMetamethod(m_EcToken, value, metamethod);
}
///
@@ -92,7 +94,7 @@ public DynValue GetMetamethodTailCall(DynValue value, string metamethod, params
///
public DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventName)
{
- return m_Processor.GetBinaryMetamethod(op1, op2, eventName);
+ return m_Processor.GetBinaryMetamethod(m_EcToken, op1, op2, eventName);
}
///
@@ -248,7 +250,7 @@ public Table CurrentGlobalEnv
public void PerformMessageDecorationBeforeUnwind(DynValue messageHandler, ScriptRuntimeException exception)
{
if (messageHandler != null)
- exception.DecoratedMessage = m_Processor.PerformMessageDecorationBeforeUnwind(messageHandler, exception.Message, CallingLocation);
+ exception.DecoratedMessage = m_Processor.PerformMessageDecorationBeforeUnwind(m_EcToken, messageHandler, exception.Message, CallingLocation);
else
exception.DecoratedMessage = exception.Message;
}
@@ -265,5 +267,24 @@ public Script OwnerScript
get { return this.GetScript(); }
}
+
+ ///
+ /// Pauses the script thread for the specified amount of time.
+ ///
+ ///
+ /// Timeout.
+ ///
+ public void PauseExecution(TimeSpan timeout)
+ {
+ m_EcToken.Wait(timeout);
+
+ // This is not strictly required, but why allow the code
+ // to go back to Processor::Processing_Loop if we can check right here if
+ // we should stop or not?
+ if (m_EcToken.IsAbortRequested)
+ {
+ throw new ScriptTerminationRequestedException();
+ }
+ }
}
}
diff --git a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs
index 18d689ca..09beee63 100755
--- a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs
+++ b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Threading;
using MoonSharp.Interpreter.DataStructs;
@@ -24,7 +24,6 @@ sealed partial class Processor
int m_SavedInstructionPtr = -1;
DebugContext m_Debug;
-
public Processor(Script script, Table globalContext, ByteCode byteCode)
{
m_ValueStack = new FastStack(STACK_SIZE);
@@ -65,12 +64,12 @@ internal Processor(Processor parentProcessor, Processor recycleProcessor)
m_State = CoroutineState.NotStarted;
}
- public DynValue Call(DynValue function, DynValue[] args)
+ public DynValue Call(ExecutionControlToken ecToken, 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);
+ return coroutinesStack[coroutinesStack.Count - 1].Call(ecToken, function, args);
EnterProcessor();
@@ -83,7 +82,7 @@ public DynValue Call(DynValue function, DynValue[] args)
try
{
int entrypoint = PushClrToScriptStackFrame(CallStackItemFlags.CallEntryPoint, function, args);
- return Processing_Loop(entrypoint);
+ return Processing_Loop(ecToken, entrypoint);
}
finally
{
diff --git a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Coroutines.cs b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Coroutines.cs
index be736426..853e3eb1 100644
--- a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Coroutines.cs
+++ b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Coroutines.cs
@@ -67,7 +67,7 @@ public DynValue Coroutine_Resume(DynValue[] args)
}
m_State = CoroutineState.Running;
- DynValue retVal = Processing_Loop(entrypoint);
+ DynValue retVal = Processing_Loop(ExecutionControlToken.Dummy, entrypoint);
if (retVal.Type == DataType.YieldRequest)
{
diff --git a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Debugger.cs b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Debugger.cs
index f7878780..649d3a05 100755
--- a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Debugger.cs
+++ b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Debugger.cs
@@ -256,7 +256,7 @@ private bool ToggleBreakPoint(DebuggerAction action, bool? state)
private void RefreshDebugger(bool hard, int instructionPtr)
{
SourceRef sref = GetCurrentSourceRef(instructionPtr);
- ScriptExecutionContext context = new ScriptExecutionContext(this, null, sref);
+ ScriptExecutionContext context = new ScriptExecutionContext(ExecutionControlToken.Dummy, this, null, sref);
List watchList = m_Debug.DebuggerAttached.GetWatchItems();
List callStack = Debugger_GetCallStack(sref);
diff --git a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_IExecutionContext.cs b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_IExecutionContext.cs
index e826f240..99b41ffb 100644
--- a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_IExecutionContext.cs
+++ b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_IExecutionContext.cs
@@ -19,7 +19,7 @@ internal Table GetMetatable(DynValue value)
}
}
- internal DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventName)
+ internal DynValue GetBinaryMetamethod(ExecutionControlToken ecToken, DynValue op1, DynValue op2, string eventName)
{
var op1_MetaTable = GetMetatable(op1);
if (op1_MetaTable != null)
@@ -39,7 +39,7 @@ internal DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventNa
if (op1.Type == DataType.UserData)
{
- DynValue meta = op1.UserData.Descriptor.MetaIndex(this.m_Script,
+ DynValue meta = op1.UserData.Descriptor.MetaIndex(ecToken, this.m_Script,
op1.UserData.Object, eventName);
if (meta != null)
@@ -48,7 +48,7 @@ internal DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventNa
if (op2.Type == DataType.UserData)
{
- DynValue meta = op2.UserData.Descriptor.MetaIndex(this.m_Script,
+ DynValue meta = op2.UserData.Descriptor.MetaIndex(ecToken, this.m_Script,
op2.UserData.Object, eventName);
if (meta != null)
@@ -58,11 +58,11 @@ internal DynValue GetBinaryMetamethod(DynValue op1, DynValue op2, string eventNa
return null;
}
- internal DynValue GetMetamethod(DynValue value, string metamethod)
+ internal DynValue GetMetamethod(ExecutionControlToken ecToken, DynValue value, string metamethod)
{
if (value.Type == DataType.UserData)
{
- DynValue v = value.UserData.Descriptor.MetaIndex(m_Script, value.UserData.Object, metamethod);
+ DynValue v = value.UserData.Descriptor.MetaIndex(ecToken, m_Script, value.UserData.Object, metamethod);
if (v != null)
return v;
}
diff --git a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs
index 38c0f63e..8dbd7b5f 100644
--- a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs
+++ b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs
@@ -13,7 +13,7 @@ sealed partial class Processor
internal long AutoYieldCounter = 0;
- private DynValue Processing_Loop(int instructionPtr)
+ private DynValue Processing_Loop(ExecutionControlToken ecToken, 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".
@@ -42,6 +42,11 @@ private DynValue Processing_Loop(int instructionPtr)
return DynValue.NewForcedYieldReq();
}
+ if (ecToken.IsAbortRequested)
+ {
+ throw new ScriptTerminationRequestedException();
+ }
+
++instructionPtr;
switch (i.OpCode)
@@ -63,56 +68,56 @@ private DynValue Processing_Loop(int instructionPtr)
m_ValueStack.Push(i.Value);
break;
case OpCode.Add:
- instructionPtr = ExecAdd(i, instructionPtr);
+ instructionPtr = ExecAdd(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.Concat:
- instructionPtr = ExecConcat(i, instructionPtr);
+ instructionPtr = ExecConcat(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.Neg:
- instructionPtr = ExecNeg(i, instructionPtr);
+ instructionPtr = ExecNeg(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.Sub:
- instructionPtr = ExecSub(i, instructionPtr);
+ instructionPtr = ExecSub(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.Mul:
- instructionPtr = ExecMul(i, instructionPtr);
+ instructionPtr = ExecMul(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.Div:
- instructionPtr = ExecDiv(i, instructionPtr);
+ instructionPtr = ExecDiv(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.Mod:
- instructionPtr = ExecMod(i, instructionPtr);
+ instructionPtr = ExecMod(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.Power:
- instructionPtr = ExecPower(i, instructionPtr);
+ instructionPtr = ExecPower(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.Eq:
- instructionPtr = ExecEq(i, instructionPtr);
+ instructionPtr = ExecEq(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.LessEq:
- instructionPtr = ExecLessEq(i, instructionPtr);
+ instructionPtr = ExecLessEq(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.Less:
- instructionPtr = ExecLess(i, instructionPtr);
+ instructionPtr = ExecLess(ecToken, i, instructionPtr);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
break;
case OpCode.Len:
- instructionPtr = ExecLen(i, instructionPtr);
+ instructionPtr = ExecLen(ecToken, 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);
+ instructionPtr = Internal_ExecCall(ecToken, 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:
@@ -165,7 +170,7 @@ private DynValue Processing_Loop(int instructionPtr)
ExecArgs(i);
break;
case OpCode.Ret:
- instructionPtr = ExecRet(i);
+ instructionPtr = ExecRet(ecToken, i);
if (instructionPtr == YIELD_SPECIAL_TRAP) goto yield_to_calling_coroutine;
if (instructionPtr < 0)
goto return_to_native_code;
@@ -187,7 +192,7 @@ private DynValue Processing_Loop(int instructionPtr)
m_ValueStack.Push(DynValue.NewPrimeTable());
break;
case OpCode.IterPrep:
- ExecIterPrep(i);
+ ExecIterPrep(ecToken, i);
break;
case OpCode.IterUpd:
ExecIterUpd(i);
@@ -218,19 +223,19 @@ private DynValue Processing_Loop(int instructionPtr)
case OpCode.Index:
case OpCode.IndexN:
case OpCode.IndexL:
- instructionPtr = ExecIndex(i, instructionPtr);
+ instructionPtr = ExecIndex(ecToken, 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);
+ instructionPtr = ExecIndexSet(ecToken, 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));
+ throw new NotImplementedException(string.Format("Execution for {0} not implemented yet!", i.OpCode));
}
}
@@ -272,7 +277,7 @@ private DynValue Processing_Loop(int instructionPtr)
var c = m_ExecutionStack.Peek(i);
if (c.ErrorHandlerBeforeUnwind != null)
- ex.DecoratedMessage = PerformMessageDecorationBeforeUnwind(c.ErrorHandlerBeforeUnwind, ex.DecoratedMessage, GetCurrentSourceRef(instructionPtr));
+ ex.DecoratedMessage = PerformMessageDecorationBeforeUnwind(ecToken, c.ErrorHandlerBeforeUnwind, ex.DecoratedMessage, GetCurrentSourceRef(instructionPtr));
}
@@ -292,7 +297,7 @@ private DynValue Processing_Loop(int instructionPtr)
var cbargs = new DynValue[] { DynValue.NewString(ex.DecoratedMessage) };
- DynValue handled = csi.ErrorHandler.Invoke(new ScriptExecutionContext(this, csi.ErrorHandler, GetCurrentSourceRef(instructionPtr)), cbargs);
+ DynValue handled = csi.ErrorHandler.Invoke(new ScriptExecutionContext(ecToken, this, csi.ErrorHandler, GetCurrentSourceRef(instructionPtr)), cbargs);
m_ValueStack.Push(handled);
@@ -316,7 +321,7 @@ private DynValue Processing_Loop(int instructionPtr)
}
- internal string PerformMessageDecorationBeforeUnwind(DynValue messageHandler, string decoratedMessage, SourceRef sourceRef)
+ internal string PerformMessageDecorationBeforeUnwind(ExecutionControlToken ecToken, DynValue messageHandler, string decoratedMessage, SourceRef sourceRef)
{
try
{
@@ -325,11 +330,11 @@ internal string PerformMessageDecorationBeforeUnwind(DynValue messageHandler, st
if (messageHandler.Type == DataType.Function)
{
- ret = this.Call(messageHandler, args);
+ ret = this.Call(ecToken, messageHandler, args);
}
else if (messageHandler.Type == DataType.ClrFunction)
{
- ScriptExecutionContext ctx = new ScriptExecutionContext(this, messageHandler.Callback, sourceRef);
+ ScriptExecutionContext ctx = new ScriptExecutionContext(ecToken, this, messageHandler.Callback, sourceRef);
ret = messageHandler.Callback.Invoke(ctx, args);
}
else
@@ -473,7 +478,7 @@ private void ExecExpTuple(Instruction i)
}
- private void ExecIterPrep(Instruction i)
+ private void ExecIterPrep(ExecutionControlToken ecToken, Instruction i)
{
DynValue v = m_ValueStack.Pop();
@@ -492,7 +497,7 @@ private void ExecIterPrep(Instruction i)
if (f.Type != DataType.Function && f.Type != DataType.ClrFunction)
{
- DynValue meta = this.GetMetamethod(f, "__iterator");
+ DynValue meta = this.GetMetamethod(ecToken, f, "__iterator");
if (meta != null && !meta.IsNil())
{
@@ -510,7 +515,7 @@ private void ExecIterPrep(Instruction i)
}
else if (f.Type == DataType.Table)
{
- DynValue callmeta = this.GetMetamethod(f, "__call");
+ DynValue callmeta = this.GetMetamethod(ecToken, f, "__call");
if (callmeta == null || callmeta.IsNil())
{
@@ -666,7 +671,7 @@ private void ExecArgs(Instruction I)
- private int Internal_ExecCall(int argsCount, int instructionPtr, CallbackFunction handler = null,
+ private int Internal_ExecCall(ExecutionControlToken ecToken, 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);
@@ -722,13 +727,14 @@ private int Internal_ExecCall(int argsCount, int instructionPtr, CallbackFunctio
Flags = flags,
});
- var ret = fn.Callback.Invoke(new ScriptExecutionContext(this, fn.Callback, sref), args, isMethodCall: thisCall);
+
+ var ret = fn.Callback.Invoke(new ScriptExecutionContext(ecToken, this, fn.Callback, sref), args, isMethodCall: thisCall);
m_ValueStack.RemoveLast(argsCount + 1);
m_ValueStack.Push(ret);
m_ExecutionStack.Pop();
- return Internal_CheckForTailRequests(null, instructionPtr);
+ return Internal_CheckForTailRequests(ecToken, null, instructionPtr);
}
else if (fn.Type == DataType.Function)
{
@@ -749,7 +755,7 @@ private int Internal_ExecCall(int argsCount, int instructionPtr, CallbackFunctio
}
// fallback to __call metamethod
- var m = GetMetamethod(fn, "__call");
+ var m = GetMetamethod(ecToken, fn, "__call");
if (m != null && m.IsNotNil())
{
@@ -762,7 +768,7 @@ private int Internal_ExecCall(int argsCount, int instructionPtr, CallbackFunctio
for (int i = argsCount; i >= 0; i--)
m_ValueStack.Push(tmp[i]);
- return Internal_ExecCall(argsCount + 1, instructionPtr, handler, continuation);
+ return Internal_ExecCall(ecToken, argsCount + 1, instructionPtr, handler, continuation);
}
throw ScriptRuntimeException.AttemptToCallNonFunc(fn.Type, debugText);
@@ -792,7 +798,7 @@ private int PerformTCO(int instructionPtr, int argsCount)
- private int ExecRet(Instruction i)
+ private int ExecRet(ExecutionControlToken ecToken, Instruction i)
{
CallStackItem csi;
int retpoint = 0;
@@ -813,7 +819,7 @@ private int ExecRet(Instruction i)
var argscnt = (int)(m_ValueStack.Pop().Number);
m_ValueStack.RemoveLast(argscnt + 1);
m_ValueStack.Push(retval);
- retpoint = Internal_CheckForTailRequests(i, retpoint);
+ retpoint = Internal_CheckForTailRequests(ecToken, i, retpoint);
}
else
{
@@ -821,7 +827,7 @@ private int ExecRet(Instruction i)
}
if (csi.Continuation != null)
- m_ValueStack.Push(csi.Continuation.Invoke(new ScriptExecutionContext(this, csi.Continuation, i.SourceCodeRef),
+ m_ValueStack.Push(csi.Continuation.Invoke(new ScriptExecutionContext(ecToken, this, csi.Continuation, i.SourceCodeRef),
new DynValue[1] { m_ValueStack.Pop() }));
return retpoint;
@@ -829,7 +835,7 @@ private int ExecRet(Instruction i)
- private int Internal_CheckForTailRequests(Instruction i, int instructionPtr)
+ private int Internal_CheckForTailRequests(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue tail = m_ValueStack.Peek(0);
@@ -844,7 +850,7 @@ private int Internal_CheckForTailRequests(Instruction i, int instructionPtr)
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);
+ return Internal_ExecCall(ecToken, tcd.Args.Length, instructionPtr, tcd.ErrorHandler, tcd.Continuation, false, null, tcd.ErrorHandlerBeforeUnwind);
}
else if (tail.Type == DataType.YieldRequest)
{
@@ -886,7 +892,7 @@ private int ExecShortCircuitingOperator(Instruction i, int instructionPtr)
}
- private int ExecAdd(Instruction i, int instructionPtr)
+ private int ExecAdd(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
DynValue l = m_ValueStack.Pop().ToScalar();
@@ -901,13 +907,13 @@ private int ExecAdd(Instruction i, int instructionPtr)
}
else
{
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__add", instructionPtr);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__add", instructionPtr);
if (ip >= 0) return ip;
else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
}
}
- private int ExecSub(Instruction i, int instructionPtr)
+ private int ExecSub(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
DynValue l = m_ValueStack.Pop().ToScalar();
@@ -922,14 +928,14 @@ private int ExecSub(Instruction i, int instructionPtr)
}
else
{
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__sub", instructionPtr);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__sub", instructionPtr);
if (ip >= 0) return ip;
else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
}
}
- private int ExecMul(Instruction i, int instructionPtr)
+ private int ExecMul(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
DynValue l = m_ValueStack.Pop().ToScalar();
@@ -944,13 +950,13 @@ private int ExecMul(Instruction i, int instructionPtr)
}
else
{
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__mul", instructionPtr);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__mul", instructionPtr);
if (ip >= 0) return ip;
else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
}
}
- private int ExecMod(Instruction i, int instructionPtr)
+ private int ExecMod(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
DynValue l = m_ValueStack.Pop().ToScalar();
@@ -967,13 +973,13 @@ private int ExecMod(Instruction i, int instructionPtr)
}
else
{
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__mod", instructionPtr);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__mod", instructionPtr);
if (ip >= 0) return ip;
else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
}
}
- private int ExecDiv(Instruction i, int instructionPtr)
+ private int ExecDiv(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
DynValue l = m_ValueStack.Pop().ToScalar();
@@ -988,12 +994,12 @@ private int ExecDiv(Instruction i, int instructionPtr)
}
else
{
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__div", instructionPtr);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__div", instructionPtr);
if (ip >= 0) return ip;
else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
}
}
- private int ExecPower(Instruction i, int instructionPtr)
+ private int ExecPower(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
DynValue l = m_ValueStack.Pop().ToScalar();
@@ -1008,14 +1014,14 @@ private int ExecPower(Instruction i, int instructionPtr)
}
else
{
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__pow", instructionPtr);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__pow", instructionPtr);
if (ip >= 0) return ip;
else throw ScriptRuntimeException.ArithmeticOnNonNumber(l, r);
}
}
- private int ExecNeg(Instruction i, int instructionPtr)
+ private int ExecNeg(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
double? rn = r.CastToNumber();
@@ -1027,14 +1033,14 @@ private int ExecNeg(Instruction i, int instructionPtr)
}
else
{
- int ip = Internal_InvokeUnaryMetaMethod(r, "__unm", instructionPtr);
+ int ip = Internal_InvokeUnaryMetaMethod(ecToken, r, "__unm", instructionPtr);
if (ip >= 0) return ip;
else throw ScriptRuntimeException.ArithmeticOnNonNumber(r);
}
}
- private int ExecEq(Instruction i, int instructionPtr)
+ private int ExecEq(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
DynValue l = m_ValueStack.Pop().ToScalar();
@@ -1049,7 +1055,7 @@ private int ExecEq(Instruction i, int 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);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__eq", instructionPtr);
if (ip >= 0) return ip;
}
@@ -1067,7 +1073,7 @@ private int ExecEq(Instruction i, int 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);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__eq", instructionPtr);
if (ip >= 0) return ip;
}
@@ -1076,7 +1082,7 @@ private int ExecEq(Instruction i, int instructionPtr)
return instructionPtr;
}
- private int ExecLess(Instruction i, int instructionPtr)
+ private int ExecLess(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
DynValue l = m_ValueStack.Pop().ToScalar();
@@ -1091,7 +1097,7 @@ private int ExecLess(Instruction i, int instructionPtr)
}
else
{
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__lt", instructionPtr);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__lt", instructionPtr);
if (ip < 0)
throw ScriptRuntimeException.CompareInvalidType(l, r);
else
@@ -1102,7 +1108,7 @@ private int ExecLess(Instruction i, int instructionPtr)
}
- private int ExecLessEq(Instruction i, int instructionPtr)
+ private int ExecLessEq(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
DynValue l = m_ValueStack.Pop().ToScalar();
@@ -1119,10 +1125,10 @@ private int ExecLessEq(Instruction i, int instructionPtr)
}
else
{
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__le", instructionPtr, DynValue.False);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__le", instructionPtr, DynValue.False);
if (ip < 0)
{
- ip = Internal_InvokeBinaryMetaMethod(r, l, "__lt", instructionPtr, DynValue.True);
+ ip = Internal_InvokeBinaryMetaMethod(ecToken, r, l, "__lt", instructionPtr, DynValue.True);
if (ip < 0)
throw ScriptRuntimeException.CompareInvalidType(l, r);
@@ -1136,7 +1142,7 @@ private int ExecLessEq(Instruction i, int instructionPtr)
return instructionPtr;
}
- private int ExecLen(Instruction i, int instructionPtr)
+ private int ExecLen(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
@@ -1144,7 +1150,7 @@ private int ExecLen(Instruction i, int instructionPtr)
m_ValueStack.Push(DynValue.NewNumber(r.String.Length));
else
{
- int ip = Internal_InvokeUnaryMetaMethod(r, "__len", instructionPtr);
+ int ip = Internal_InvokeUnaryMetaMethod(ecToken, r, "__len", instructionPtr);
if (ip >= 0)
return ip;
else if (r.Type == DataType.Table)
@@ -1157,7 +1163,7 @@ private int ExecLen(Instruction i, int instructionPtr)
}
- private int ExecConcat(Instruction i, int instructionPtr)
+ private int ExecConcat(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
DynValue r = m_ValueStack.Pop().ToScalar();
DynValue l = m_ValueStack.Pop().ToScalar();
@@ -1172,7 +1178,7 @@ private int ExecConcat(Instruction i, int instructionPtr)
}
else
{
- int ip = Internal_InvokeBinaryMetaMethod(l, r, "__concat", instructionPtr);
+ int ip = Internal_InvokeBinaryMetaMethod(ecToken, l, r, "__concat", instructionPtr);
if (ip >= 0) return ip;
else throw ScriptRuntimeException.ConcatOnNonString(l, r);
}
@@ -1205,7 +1211,7 @@ private void ExecTblInitN(Instruction i)
tbl.Table.Set(key, val.ToScalar());
}
- private int ExecIndexSet(Instruction i, int instructionPtr)
+ private int ExecIndexSet(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
@@ -1249,7 +1255,7 @@ private int ExecIndexSet(Instruction i, int instructionPtr)
{
UserData ud = obj.UserData;
- if (!ud.Descriptor.SetIndex(this.GetScript(), ud.Object, originalIdx, value, isNameIndex))
+ if (!ud.Descriptor.SetIndex(ecToken, this.GetScript(), ud.Object, originalIdx, value, isNameIndex))
{
throw ScriptRuntimeException.UserDataMissingField(ud.Descriptor.Name, idx.String);
}
@@ -1273,7 +1279,7 @@ private int ExecIndexSet(Instruction i, int instructionPtr)
m_ValueStack.Push(obj);
m_ValueStack.Push(idx);
m_ValueStack.Push(value);
- return Internal_ExecCall(3, instructionPtr);
+ return Internal_ExecCall(ecToken, 3, instructionPtr);
}
else
{
@@ -1284,7 +1290,7 @@ private int ExecIndexSet(Instruction i, int instructionPtr)
throw ScriptRuntimeException.LoopInNewIndex();
}
- private int ExecIndex(Instruction i, int instructionPtr)
+ private int ExecIndex(ExecutionControlToken ecToken, Instruction i, int instructionPtr)
{
int nestedMetaOps = 100; // sanity check, to avoid potential infinite loop here
@@ -1331,7 +1337,7 @@ private int ExecIndex(Instruction i, int instructionPtr)
{
UserData ud = obj.UserData;
- var v = ud.Descriptor.Index(this.GetScript(), ud.Object, originalIdx, isNameIndex);
+ var v = ud.Descriptor.Index(ecToken, this.GetScript(), ud.Object, originalIdx, isNameIndex);
if (v == null)
{
@@ -1355,7 +1361,7 @@ private int ExecIndex(Instruction i, int instructionPtr)
m_ValueStack.Push(h);
m_ValueStack.Push(obj);
m_ValueStack.Push(idx);
- return Internal_ExecCall(2, instructionPtr);
+ return Internal_ExecCall(ecToken, 2, instructionPtr);
}
else
{
diff --git a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_UtilityFunctions.cs b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_UtilityFunctions.cs
index 3ad7253d..69aa8dee 100644
--- a/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_UtilityFunctions.cs
+++ b/src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_UtilityFunctions.cs
@@ -44,13 +44,13 @@ private DynValue[] Internal_AdjustTuple(IList values)
- private int Internal_InvokeUnaryMetaMethod(DynValue op1, string eventName, int instructionPtr)
+ private int Internal_InvokeUnaryMetaMethod(ExecutionControlToken ecToken, 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);
+ m = op1.UserData.Descriptor.MetaIndex(ecToken, m_Script, op1.UserData.Object, eventName);
}
if (m == null)
@@ -69,16 +69,16 @@ private int Internal_InvokeUnaryMetaMethod(DynValue op1, string eventName, int i
{
m_ValueStack.Push(m);
m_ValueStack.Push(op1);
- return Internal_ExecCall(1, instructionPtr);
+ return Internal_ExecCall(ecToken, 1, instructionPtr);
}
else
{
return -1;
}
}
- private int Internal_InvokeBinaryMetaMethod(DynValue l, DynValue r, string eventName, int instructionPtr, DynValue extraPush = null)
+ private int Internal_InvokeBinaryMetaMethod(ExecutionControlToken ecToken, DynValue l, DynValue r, string eventName, int instructionPtr, DynValue extraPush = null)
{
- var m = GetBinaryMetamethod(l, r, eventName);
+ var m = GetBinaryMetamethod(ecToken, l, r, eventName);
if (m != null)
{
@@ -88,7 +88,7 @@ private int Internal_InvokeBinaryMetaMethod(DynValue l, DynValue r, string event
m_ValueStack.Push(m);
m_ValueStack.Push(l);
m_ValueStack.Push(r);
- return Internal_ExecCall(2, instructionPtr);
+ return Internal_ExecCall(ecToken, 2, instructionPtr);
}
else
{
diff --git a/src/MoonSharp.Interpreter/ExecutionControlToken.cs b/src/MoonSharp.Interpreter/ExecutionControlToken.cs
new file mode 100644
index 00000000..51ab9d48
--- /dev/null
+++ b/src/MoonSharp.Interpreter/ExecutionControlToken.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Threading;
+
+namespace MoonSharp.Interpreter
+{
+ ///
+ /// This class provides an interface to control execution of Lua scripts ran asynchronously.
+ ///
+ /// This class is supported only on .NET 4.x and .NET 4.x PCL targets.
+ /// On other targets, it acts as a dummy.
+ ///
+ public class ExecutionControlToken
+ {
+ public static readonly ExecutionControlToken Dummy = new ExecutionControlToken() { m_IsDummy = true };
+
+#if HASDYNAMIC
+ CancellationTokenSource m_CancellationTokenSource = new CancellationTokenSource();
+#endif
+
+ bool m_IsDummy;
+
+ ///
+ /// Creates an usable execution control token.
+ ///
+ ///
+ public ExecutionControlToken()
+ {
+ m_IsDummy = false;
+ }
+
+ ///
+ /// Aborts the execution of the script that is associated with this token.
+ ///
+ public void Terminate()
+ {
+#if HASDYNAMIC
+ if (!m_IsDummy)
+ {
+ m_CancellationTokenSource.Cancel(true);
+ }
+#endif
+ }
+
+ internal bool IsAbortRequested
+ {
+ get
+ {
+#if HASDYNAMIC
+ return m_CancellationTokenSource.IsCancellationRequested;
+#else
+ return false;
+#endif
+ }
+ }
+
+ internal void Wait(TimeSpan timeSpan)
+ {
+#if HASDYNAMIC
+ m_CancellationTokenSource.Token.WaitHandle.WaitOne(timeSpan);
+#else
+ Thread.Sleep(timeSpan);
+#endif
+
+ }
+ }
+}
diff --git a/src/MoonSharp.Interpreter/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs b/src/MoonSharp.Interpreter/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs
index 8867be86..98f33782 100644
--- a/src/MoonSharp.Interpreter/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs
+++ b/src/MoonSharp.Interpreter/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs
@@ -210,12 +210,13 @@ private void AddMemberTo(Dictionary members, string n
///
/// Performs an "index" "get" operation. This tries to resolve minor variations of member names.
///
+ /// The execution control token of the script processing thread
/// 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)
+ public virtual DynValue Index(ExecutionControlToken ecToken, Script script, object obj, DynValue index, bool isDirectIndexing)
{
if (!isDirectIndexing)
{
@@ -224,7 +225,7 @@ public virtual DynValue Index(Script script, object obj, DynValue index, bool is
.WithAccessOrNull(MemberDescriptorAccess.CanExecute);
if (mdesc != null)
- return ExecuteIndexer(mdesc, script, obj, index, null);
+ return ExecuteIndexer(ecToken, mdesc, script, obj, index, null);
}
index = index.ToScalar();
@@ -323,7 +324,7 @@ protected virtual DynValue TryIndex(Script script, object obj, string indexName)
/// 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)
+ public virtual bool SetIndex(ExecutionControlToken ecToken, Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing)
{
if (!isDirectIndexing)
{
@@ -333,7 +334,7 @@ public virtual bool SetIndex(Script script, object obj, DynValue index, DynValue
if (mdesc != null)
{
- ExecuteIndexer(mdesc, script, obj, index, value);
+ ExecuteIndexer(ecToken, mdesc, script, obj, index, value);
return true;
}
}
@@ -427,7 +428,7 @@ public virtual string AsString(object obj)
/// The dynvalue to set on a setter, or null.
///
///
- protected virtual DynValue ExecuteIndexer(IMemberDescriptor mdesc, Script script, object obj, DynValue index, DynValue value)
+ protected virtual DynValue ExecuteIndexer(ExecutionControlToken ecToken, IMemberDescriptor mdesc, Script script, object obj, DynValue index, DynValue value)
{
IList values;
@@ -456,7 +457,7 @@ protected virtual DynValue ExecuteIndexer(IMemberDescriptor mdesc, Script script
}
CallbackArguments args = new CallbackArguments(values, false);
- ScriptExecutionContext execCtx = script.CreateDynamicExecutionContext();
+ ScriptExecutionContext execCtx = script.CreateDynamicExecutionContext(ecToken);
DynValue v = mdesc.GetValue(script, obj);
@@ -485,12 +486,13 @@ protected virtual DynValue ExecuteIndexer(IMemberDescriptor mdesc, Script script
/// __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 execution control token of the script processing thread
/// 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)
+ public virtual DynValue MetaIndex(ExecutionControlToken ecToken, Script script, object obj, string metaname)
{
IMemberDescriptor desc = m_MetaMembers.GetOrDefault(metaname);
diff --git a/src/MoonSharp.Interpreter/Interop/IUserDataDescriptor.cs b/src/MoonSharp.Interpreter/Interop/IUserDataDescriptor.cs
index b93c8092..0b80218a 100644
--- a/src/MoonSharp.Interpreter/Interop/IUserDataDescriptor.cs
+++ b/src/MoonSharp.Interpreter/Interop/IUserDataDescriptor.cs
@@ -18,22 +18,24 @@ public interface IUserDataDescriptor
///
/// Performs an "index" "get" operation.
///
+ /// The execution control token of the script processing thread
/// 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.
///
- DynValue Index(Script script, object obj, DynValue index, bool isDirectIndexing);
+ DynValue Index(ExecutionControlToken ecToken, Script script, object obj, DynValue index, bool isDirectIndexing);
///
/// Performs an "index" "set" operation.
///
+ /// The execution control token of the script processing thread
/// 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.
///
- bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing);
+ bool SetIndex(ExecutionControlToken ecToken, Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing);
///
/// Converts this userdata to string
///
@@ -54,11 +56,12 @@ public interface IUserDataDescriptor
/// __index, __newindex, __tostring
///
///
+ /// The execution control token of the script processing thread
/// The script originating the request
/// The object (null if a static request is done)
/// The name of the metamember.
///
- DynValue MetaIndex(Script script, object obj, string metaname);
+ DynValue MetaIndex(ExecutionControlToken ecToken, Script script, object obj, string metaname);
///
/// Determines whether the specified object is compatible with the specified type.
/// Unless a very specific behaviour is needed, the correct implementation is a
diff --git a/src/MoonSharp.Interpreter/Interop/IUserDataType.cs b/src/MoonSharp.Interpreter/Interop/IUserDataType.cs
index 9ae18bbe..98b6253f 100644
--- a/src/MoonSharp.Interpreter/Interop/IUserDataType.cs
+++ b/src/MoonSharp.Interpreter/Interop/IUserDataType.cs
@@ -11,20 +11,22 @@ public interface IUserDataType
///
/// Performs an "index" "get" operation.
///
+ /// The execution control token of the script processing thread
/// The script originating the request
/// The index.
/// If set to true, it's indexed with a name, if false it's indexed through brackets.
///
- DynValue Index(Script script, DynValue index, bool isDirectIndexing);
+ DynValue Index(ExecutionControlToken ecToken, Script script, DynValue index, bool isDirectIndexing);
///
/// Performs an "index" "set" operation.
///
+ /// The execution control token of the script processing thread
/// The script originating the request
/// The index.
/// The value to be set
/// If set to true, it's indexed with a name, if false it's indexed through brackets.
///
- bool SetIndex(Script script, DynValue index, DynValue value, bool isDirectIndexing);
+ bool SetIndex(ExecutionControlToken ecToken, Script script, DynValue index, DynValue value, bool isDirectIndexing);
///
///
/// Gets a "meta" operation on this userdata. If a descriptor does not support this functionality,
@@ -39,9 +41,10 @@ public interface IUserDataType
/// __index, __newindex, __tostring
///
///
+ /// The execution control token of the script processing thread
/// The script originating the request
/// The name of the metamember.
///
- DynValue MetaIndex(Script script, string metaname);
+ DynValue MetaIndex(ExecutionControlToken ecToken, Script script, string metaname);
}
}
diff --git a/src/MoonSharp.Interpreter/Interop/PredefinedUserData/EnumerableWrapper.cs b/src/MoonSharp.Interpreter/Interop/PredefinedUserData/EnumerableWrapper.cs
index 6accf2ad..f6e32bad 100644
--- a/src/MoonSharp.Interpreter/Interop/PredefinedUserData/EnumerableWrapper.cs
+++ b/src/MoonSharp.Interpreter/Interop/PredefinedUserData/EnumerableWrapper.cs
@@ -61,7 +61,7 @@ internal static DynValue ConvertTable(Table table)
}
- public DynValue Index(Script script, DynValue index, bool isDirectIndexing)
+ public DynValue Index(ExecutionControlToken ecToken, Script script, DynValue index, bool isDirectIndexing)
{
if (index.Type == DataType.String)
{
@@ -83,12 +83,12 @@ public DynValue Index(Script script, DynValue index, bool isDirectIndexing)
return null;
}
- public bool SetIndex(Script script, DynValue index, DynValue value, bool isDirectIndexing)
+ public bool SetIndex(ExecutionControlToken ecToken, Script script, DynValue index, DynValue value, bool isDirectIndexing)
{
return false;
}
- public DynValue MetaIndex(Script script, string metaname)
+ public DynValue MetaIndex(ExecutionControlToken ecToken, Script script, string metaname)
{
if (metaname == "__call")
return DynValue.NewCallback(LuaIteratorCallback);
diff --git a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/AutoDescribingUserDataDescriptor.cs b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/AutoDescribingUserDataDescriptor.cs
index ea7bb48d..8cf779d1 100644
--- a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/AutoDescribingUserDataDescriptor.cs
+++ b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/AutoDescribingUserDataDescriptor.cs
@@ -42,17 +42,18 @@ public Type Type
///
/// Performs an "index" "get" operation.
///
+ /// The execution control token of the script processing thread
/// 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 DynValue Index(Script script, object obj, DynValue index, bool isDirectIndexing)
+ public DynValue Index(ExecutionControlToken ecToken, Script script, object obj, DynValue index, bool isDirectIndexing)
{
IUserDataType u = obj as IUserDataType;
if (u != null)
- return u.Index(script, index, isDirectIndexing);
+ return u.Index(ecToken, script, index, isDirectIndexing);
return null;
}
@@ -60,18 +61,19 @@ public DynValue Index(Script script, object obj, DynValue index, bool isDirectIn
///
/// Performs an "index" "set" operation.
///
+ /// The execution control token of the script processing thread
/// 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 bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing)
+ public bool SetIndex(ExecutionControlToken ecToken, Script script, object obj, DynValue index, DynValue value, bool isDirectIndexing)
{
IUserDataType u = obj as IUserDataType;
if (u != null)
- return u.SetIndex(script, index, value, isDirectIndexing);
+ return u.SetIndex(ecToken, script, index, value, isDirectIndexing);
return false;
}
@@ -99,16 +101,17 @@ public string AsString(object obj)
/// These standard metamethods are supported through other calls for efficiency:
/// __index, __newindex, __tostring
///
+ /// The execution control token of the script processing thread
/// The script originating the request
/// The object (null if a static request is done)
/// The name of the metamember.
///
- public DynValue MetaIndex(Script script, object obj, string metaname)
+ public DynValue MetaIndex(ExecutionControlToken ecToken, Script script, object obj, string metaname)
{
IUserDataType u = obj as IUserDataType;
if (u != null)
- return u.MetaIndex(script, metaname);
+ return u.MetaIndex(ecToken, script, metaname);
return null;
}
diff --git a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/CompositeUserDataDescriptor.cs b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/CompositeUserDataDescriptor.cs
index a7e1a528..ec262210 100644
--- a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/CompositeUserDataDescriptor.cs
+++ b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/CompositeUserDataDescriptor.cs
@@ -55,16 +55,17 @@ public Type Type
///
/// Performs an "index" "get" operation.
///
+ /// The execution control token of the script processing thread
/// 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 DynValue Index(Script script, object obj, DynValue index, bool isNameIndex)
+ public DynValue Index(ExecutionControlToken ecToken, Script script, object obj, DynValue index, bool isNameIndex)
{
foreach (IUserDataDescriptor dd in m_Descriptors)
{
- DynValue v = dd.Index(script, obj, index, isNameIndex);
+ DynValue v = dd.Index(ecToken, script, obj, index, isNameIndex);
if (v != null)
return v;
@@ -75,17 +76,18 @@ public DynValue Index(Script script, object obj, DynValue index, bool isNameInde
///
/// Performs an "index" "set" operation.
///
+ /// The execution control token of the script processing thread
/// 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 bool SetIndex(Script script, object obj, DynValue index, DynValue value, bool isNameIndex)
+ public bool SetIndex(ExecutionControlToken ecToken, Script script, object obj, DynValue index, DynValue value, bool isNameIndex)
{
foreach (IUserDataDescriptor dd in m_Descriptors)
{
- if (dd.SetIndex(script, obj, index, value, isNameIndex))
+ if (dd.SetIndex(ecToken, script, obj, index, value, isNameIndex))
return true;
}
return false;
@@ -112,15 +114,16 @@ public string AsString(object obj)
/// These standard metamethods are supported through other calls for efficiency:
/// __index, __newindex, __tostring
///
+ /// The execution control token of the script processing thread
/// The script originating the request
/// The object (null if a static request is done)
/// The name of the metamember.
///
- public DynValue MetaIndex(Script script, object obj, string metaname)
+ public DynValue MetaIndex(ExecutionControlToken ecToken, Script script, object obj, string metaname)
{
foreach (IUserDataDescriptor dd in m_Descriptors)
{
- DynValue v = dd.MetaIndex(script, obj, metaname);
+ DynValue v = dd.MetaIndex(ecToken, script, obj, metaname);
if (v != null)
return v;
diff --git a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/EventFacade.cs b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/EventFacade.cs
index 6b9d98b8..6f2043dc 100644
--- a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/EventFacade.cs
+++ b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/EventFacade.cs
@@ -25,7 +25,7 @@ public EventFacade(Func
-
@@ -150,6 +149,8 @@
+
+
diff --git a/src/MoonSharp.Interpreter/REPL/ReplInterpreter.cs b/src/MoonSharp.Interpreter/REPL/ReplInterpreter.cs
index 155abd0e..b7137fea 100644
--- a/src/MoonSharp.Interpreter/REPL/ReplInterpreter.cs
+++ b/src/MoonSharp.Interpreter/REPL/ReplInterpreter.cs
@@ -1,4 +1,7 @@
using System;
+#if HASDYNAMIC
+using System.Threading.Tasks;
+#endif
namespace MoonSharp.Interpreter.REPL
{
@@ -115,5 +118,24 @@ public virtual DynValue Evaluate(string input)
throw;
}
}
+
+#if HASDYNAMIC
+ ///
+ /// Asynchronously evaluates a REPL command.
+ /// This method returns the result of the computation, or null if more input is needed for having valid code.
+ /// In case of errors, exceptions are propagated to the caller.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The interpreter.
+ /// The input.
+ ///
+ /// This method returns the result of the computation, or null if more input is needed for a computation.
+ ///
+ public Task EvaluateAsync(string input)
+ {
+ return Task.Factory.StartNew(() => Evaluate(input));
+ }
+#endif
}
}
diff --git a/src/MoonSharp.Interpreter/Script.cs b/src/MoonSharp.Interpreter/Script.cs
index 19dd5141..41c13432 100755
--- a/src/MoonSharp.Interpreter/Script.cs
+++ b/src/MoonSharp.Interpreter/Script.cs
@@ -3,6 +3,9 @@
using System.IO;
using System.Linq;
using System.Text;
+#if HASDYNAMIC
+using System.Threading.Tasks;
+#endif
using MoonSharp.Interpreter.CoreLib;
using MoonSharp.Interpreter.Debugging;
using MoonSharp.Interpreter.Diagnostics;
@@ -363,7 +366,6 @@ public DynValue DoFile(string filename, Table globalContext = null, string codeF
return Call(func);
}
-
///
/// Runs the specified file with all possible defaults for quick experimenting.
///
@@ -442,23 +444,14 @@ public DynValue Call(DynValue function)
return Call(function, new DynValue[0]);
}
- ///
- /// Calls the specified function.
- ///
- /// The Lua/MoonSharp function to be called
- /// The arguments to pass to the function.
- ///
- /// The return value(s) of the function call.
- ///
- /// Thrown if function is not of DataType.Function
- public DynValue Call(DynValue function, params DynValue[] args)
+ private DynValue Internal_Call(ExecutionControlToken ecToken, DynValue function, params DynValue[] args)
{
this.CheckScriptOwnership(function);
this.CheckScriptOwnership(args);
if (function.Type != DataType.Function && function.Type != DataType.ClrFunction)
{
- DynValue metafunction = m_MainProcessor.GetMetamethod(function, "__call");
+ DynValue metafunction = m_MainProcessor.GetMetamethod(ecToken, function, "__call");
if (metafunction != null)
{
@@ -477,10 +470,24 @@ public DynValue Call(DynValue function, params DynValue[] args)
}
else if (function.Type == DataType.ClrFunction)
{
- return function.Callback.ClrCallback(this.CreateDynamicExecutionContext(function.Callback), new CallbackArguments(args, false));
+ return function.Callback.ClrCallback(this.CreateDynamicExecutionContext(ecToken, function.Callback), new CallbackArguments(args, false));
}
- return m_MainProcessor.Call(function, args);
+ return m_MainProcessor.Call(ecToken, function, args);
+ }
+
+ ///
+ /// Calls the specified function.
+ ///
+ /// The Lua/MoonSharp function to be called
+ /// The arguments to pass to the function.
+ ///
+ /// The return value(s) of the function call.
+ ///
+ /// Thrown if function is not of DataType.Function
+ public DynValue Call(DynValue function, params DynValue[] args)
+ {
+ return Internal_Call(ExecutionControlToken.Dummy, function, args);
}
///
@@ -525,6 +532,249 @@ public DynValue Call(object function, params object[] args)
return Call(DynValue.FromObject(this, function), args);
}
+
+#if HASDYNAMIC
+ ///
+ /// Asynchronously loads and executes a string containing a Lua/MoonSharp script.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The execution control token to be associated with the execution of this function
+ /// The code.
+ /// The global context.
+ /// Name of the code - used to report errors, etc. Also used by debuggers to locate the original source file.
+ ///
+ /// A DynValue containing the result of the processing of the loaded chunk.
+ ///
+ public Task DoStringAsync(ExecutionControlToken ecToken, string code, Table globalContext = null, string codeFriendlyName = null)
+ {
+ return LoadStringAsync(code, globalContext, codeFriendlyName)
+ .ContinueWith((Task prevTask) => CallAsync(ecToken, prevTask.Result).Result);
+ }
+
+
+ ///
+ /// Asynchronously loads and executes a stream containing a Lua/MoonSharp script.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The execution control token to be associated with the execution of this function
+ /// The stream.
+ /// The global context.
+ /// Name of the code - used to report errors, etc. Also used by debuggers to locate the original source file.
+ ///
+ /// A DynValue containing the result of the processing of the loaded chunk.
+ ///
+ public Task DoStreamAsync(ExecutionControlToken ecToken, Stream stream, Table globalContext = null, string codeFriendlyName = null)
+ {
+ return LoadStreamAsync(stream, globalContext, codeFriendlyName)
+ .ContinueWith((Task prevTask) => CallAsync(ecToken, prevTask.Result).Result);
+ }
+
+
+ ///
+ /// Asynchronously loads and executes a file containing a Lua/MoonSharp script.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The execution control token to be associated with the execution of this function
+ /// The filename.
+ /// The global context.
+ /// Name of the code - used to report errors, etc. Also used by debuggers to locate the original source file.
+ ///
+ /// A DynValue containing the result of the processing of the loaded chunk.
+ ///
+ public Task DoFileAsync(ExecutionControlToken ecToken, string filename, Table globalContext = null, string codeFriendlyName = null)
+ {
+ return LoadFileAsync(filename, globalContext, codeFriendlyName)
+ .ContinueWith((Task prevTask) => CallAsync(ecToken, prevTask.Result).Result);
+ }
+
+
+ ///
+ /// Asynchronously loads a string containing a Lua/MoonSharp script.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The code.
+ /// The global table to bind to this chunk.
+ /// Name of the code - used to report errors, etc.
+ ///
+ /// A DynValue containing a function which will execute the loaded code.
+ ///
+ public Task LoadStringAsync(string code, Table globalTable = null, string codeFriendlyName = null)
+ {
+ return Task.Factory.StartNew(() => LoadString(code, globalTable, codeFriendlyName));
+ }
+
+
+ ///
+ /// Asynchronously loads a Lua/MoonSharp script from a System.IO.Stream. NOTE: This will *NOT* close the stream!
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The stream containing code.
+ /// The global table to bind to this chunk.
+ /// Name of the code - used to report errors, etc.
+ ///
+ /// A DynValue containing a function which will execute the loaded code.
+ ///
+ public Task LoadStreamAsync(Stream stream, Table globalTable = null, string codeFriendlyName = null)
+ {
+ return Task.Factory.StartNew(() => LoadStream(stream, globalTable, codeFriendlyName));
+ }
+
+
+ ///
+ /// Asynchronously loads a string containing a Lua/MoonSharp script.
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The code.
+ /// The global table to bind to this chunk.
+ /// The filename to be used in error messages.
+ ///
+ /// A DynValue containing a function which will execute the loaded code.
+ ///
+ public Task LoadFileAsync(string filename, Table globalContext = null, string friendlyFilename = null)
+ {
+ return Task.Factory.StartNew(() => LoadFile(filename, globalContext, friendlyFilename));
+ }
+
+
+ ///
+ /// Asynchronously loads a string containing a Lua/MoonSharp function.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The code.
+ /// The global table to bind to this chunk.
+ /// Name of the function used to report errors, etc.
+ ///
+ /// A DynValue containing a function which will execute the loaded code.
+ ///
+ public Task LoadFunctionAsync(string code, Table globalTable = null, string funcFriendlyName = null)
+ {
+ return Task.Factory.StartNew(() => LoadFunction(code, globalTable, funcFriendlyName));
+ }
+
+
+ ///
+ /// Asynchronously dumps a function on the specified stream.
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The function.
+ /// The stream.
+ ///
+ /// function arg is not a function!
+ /// or
+ /// stream is readonly!
+ /// or
+ /// function arg has upvalues other than _ENV
+ public Task DumpAsync(DynValue function, Stream stream)
+ {
+ return Task.Factory.StartNew(() => Dump(function, stream));
+ }
+
+
+ ///
+ /// Calls the specified function.
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The execution control token to be associated with the execution of this function
+ /// The Lua/MoonSharp function to be called
+ ///
+ /// The return value(s) of the function call.
+ ///
+ /// Thrown if function is not of DataType.Function
+ public Task CallAsync(ExecutionControlToken ecToken, DynValue function)
+ {
+ return CallAsync(ecToken, function, new DynValue[0]);
+ }
+
+
+ ///
+ /// Asynchronously calls the specified function.
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The execution control token to be associated with the execution of this function
+ /// The Lua/MoonSharp function to be called
+ /// The arguments to pass to the function.
+ ///
+ /// The return value(s) of the function call.
+ ///
+ /// Thrown if function is not of DataType.Function
+ public Task CallAsync(ExecutionControlToken ecToken, DynValue function, params DynValue[] args)
+ {
+ return Task.Factory.StartNew(() => Internal_Call(ecToken, function, args));
+ }
+
+
+ ///
+ /// Asynchronously calls the specified function.
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The execution control token to be associated with the execution of this function
+ /// The Lua/MoonSharp function to be called
+ /// The arguments to pass to the function.
+ ///
+ /// The return value(s) of the function call.
+ ///
+ /// Thrown if function is not of DataType.Function
+ public Task CallAsync(ExecutionControlToken ecToken, DynValue function, params object[] args)
+ {
+ DynValue[] dargs = new DynValue[args.Length];
+
+ for (int i = 0; i < dargs.Length; i++)
+ dargs[i] = DynValue.FromObject(this, args[i]);
+
+ return CallAsync(ecToken, function, dargs);
+ }
+
+
+
+ ///
+ /// Asynchronously calls the specified function.
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The execution control token to be associated with the execution of this function
+ /// The Lua/MoonSharp function to be called
+ ///
+ /// Thrown if function is not of DataType.Function
+ public Task CallAsync(ExecutionControlToken ecToken, object function)
+ {
+ return CallAsync(ecToken, DynValue.FromObject(this, function));
+ }
+
+
+ ///
+ /// Asynchronously calls the specified function.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The execution control token to be associated with the execution of this function
+ /// The Lua/MoonSharp function to be called
+ /// The arguments to pass to the function.
+ ///
+ /// Thrown if function is not of DataType.Function
+ public Task CallAsync(ExecutionControlToken ecToken, object function, params object[] args)
+ {
+ return CallAsync(ecToken, DynValue.FromObject(this, function), args);
+ }
+
+ ///
+ /// Asynchronously creates a new dynamic expression.
+ ///
+ /// This method is supported only on .NET 4.x and .NET 4.x PCL targets.
+ ///
+ /// The code of the expression.
+ ///
+ public Task CreateDynamicExpressionAsync(string code)
+ {
+ return Task.Factory.StartNew(() => CreateDynamicExpression(code));
+ }
+#endif
+
+
///
/// Creates a coroutine pointing at the specified function.
///
@@ -731,9 +981,9 @@ public DynamicExpression CreateConstantDynamicExpression(string code, DynValue c
/// those cases where the execution engine is not really running - for example for dynamic expression
/// or calls from CLR to CLR callbacks
///
- internal ScriptExecutionContext CreateDynamicExecutionContext(CallbackFunction func = null)
+ internal ScriptExecutionContext CreateDynamicExecutionContext(ExecutionControlToken ecToken, CallbackFunction func = null)
{
- return new ScriptExecutionContext(m_MainProcessor, func, null, isDynamic: true);
+ return new ScriptExecutionContext(ecToken, m_MainProcessor, func, null, isDynamic: true);
}
///
diff --git a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.net40-client/MoonSharp.Interpreter.net40-client.csproj b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.net40-client/MoonSharp.Interpreter.net40-client.csproj
index e5ea7555..d8144fd1 100755
--- a/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.net40-client/MoonSharp.Interpreter.net40-client.csproj
+++ b/src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.net40-client/MoonSharp.Interpreter.net40-client.csproj
@@ -61,9 +61,6 @@
-
- AsyncExtensions.cs
-
AstNode.cs
@@ -817,6 +814,8 @@
WhileStatement.cs
+
+
-
- AsyncExtensions.cs
-
AstNode.cs
@@ -814,6 +811,8 @@
WhileStatement.cs
+
+