commit cd185ed2e59dfb1638fc9691a1b94d69f2bfe34d Author: Deukhoofd Date: Wed Jun 5 17:50:01 2019 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ee0c90 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Common IntelliJ Platform excludes + +# User specific +**/.idea/**/workspace.xml +**/.idea/**/tasks.xml +**/.idea/shelf/* +**/.idea/dictionaries + +# Sensitive or high-churn files +**/.idea/**/dataSources/ +**/.idea/**/dataSources.ids +**/.idea/**/dataSources.xml +**/.idea/**/dataSources.local.xml +**/.idea/**/sqlDataSources.xml +**/.idea/**/dynamic.xml + +# Rider +# Rider auto-generates .iml files, and contentModel.xml +**/.idea/**/*.iml +**/.idea/**/contentModel.xml +**/.idea/**/modules.xml + +*.suo +*.user +.vs/ +[Bb]in/ +[Oo]bj/ +_UpgradeReport_Files/ +[Pp]ackages/ + +Thumbs.db +Desktop.ini +.DS_Store diff --git a/.idea/.idea.PorygonSharp/.idea/indexLayout.xml b/.idea/.idea.PorygonSharp/.idea/indexLayout.xml new file mode 100644 index 0000000..27ba142 --- /dev/null +++ b/.idea/.idea.PorygonSharp/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.PorygonSharp/.idea/vcs.xml b/.idea/.idea.PorygonSharp/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/.idea.PorygonSharp/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PorygonSharp.sln b/PorygonSharp.sln new file mode 100644 index 0000000..13056b0 --- /dev/null +++ b/PorygonSharp.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PorygonSharp", "PorygonSharp\PorygonSharp.csproj", "{0C0E73BC-C4D9-498F-8A41-E247B104DF84}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PorygonSharpTests", "PorygonSharpTests\PorygonSharpTests.csproj", "{095D66BC-028A-49D0-8E4B-ED407D3AA20F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PorygonSharpCLI", "PorygonSharpCLI\PorygonSharpCLI.csproj", "{8F945B4C-8F2A-401C-8568-FD2BC94E5A39}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0C0E73BC-C4D9-498F-8A41-E247B104DF84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C0E73BC-C4D9-498F-8A41-E247B104DF84}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C0E73BC-C4D9-498F-8A41-E247B104DF84}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C0E73BC-C4D9-498F-8A41-E247B104DF84}.Release|Any CPU.Build.0 = Release|Any CPU + {095D66BC-028A-49D0-8E4B-ED407D3AA20F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {095D66BC-028A-49D0-8E4B-ED407D3AA20F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {095D66BC-028A-49D0-8E4B-ED407D3AA20F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {095D66BC-028A-49D0-8E4B-ED407D3AA20F}.Release|Any CPU.Build.0 = Release|Any CPU + {8F945B4C-8F2A-401C-8568-FD2BC94E5A39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F945B4C-8F2A-401C-8568-FD2BC94E5A39}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F945B4C-8F2A-401C-8568-FD2BC94E5A39}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F945B4C-8F2A-401C-8568-FD2BC94E5A39}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/PorygonSharp.sln.DotSettings b/PorygonSharp.sln.DotSettings new file mode 100644 index 0000000..6e2539c --- /dev/null +++ b/PorygonSharp.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/PorygonSharp/DiagnosticHandling/DiagnosticCode.cs b/PorygonSharp/DiagnosticHandling/DiagnosticCode.cs new file mode 100644 index 0000000..37f5dd4 --- /dev/null +++ b/PorygonSharp/DiagnosticHandling/DiagnosticCode.cs @@ -0,0 +1,21 @@ +namespace PorygonSharp.DiagnosticHandling +{ + public enum DiagnosticCode + { + // Lex diagnostics + UnexpectedCharacter, + InvalidStringControlCharacter, + + // Parse diagnostics + UnexpectedToken, + + // Bind diagnostics + NoBinaryOperationFound, + NoUnaryOperationFound, + CantAssignVariable, + VariableNotFound, + ExpressionIsNotAFunction, + ParameterCountMismatch, + ParameterTypeMismatch, + } +} \ No newline at end of file diff --git a/PorygonSharp/DiagnosticHandling/DiagnosticItem.cs b/PorygonSharp/DiagnosticHandling/DiagnosticItem.cs new file mode 100644 index 0000000..694eb84 --- /dev/null +++ b/PorygonSharp/DiagnosticHandling/DiagnosticItem.cs @@ -0,0 +1,18 @@ +using System.Runtime.InteropServices; + +namespace PorygonSharp.DiagnosticHandling +{ + [StructLayout(LayoutKind.Sequential)] + public struct DiagnosticItem + { + private readonly int _severity; + private readonly DiagnosticCode _code; + private readonly uint _start; + private readonly uint _length; + + public DiagnosticCode GetCode() + { + return _code; + } + } +} \ No newline at end of file diff --git a/PorygonSharp/DiagnosticHandling/Diagnostics.cs b/PorygonSharp/DiagnosticHandling/Diagnostics.cs new file mode 100644 index 0000000..e39c5f0 --- /dev/null +++ b/PorygonSharp/DiagnosticHandling/Diagnostics.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace PorygonSharp.DiagnosticHandling +{ + [StructLayout(LayoutKind.Sequential)] + internal struct InternalDiagnostics + { + private readonly byte _hasErrors; + + public bool HasErrors() + { + return _hasErrors == 1; + } + } + + public class Diagnostics : IDisposable + { + private readonly IntPtr _handle; + private InternalDiagnostics _internal; + + public Diagnostics(IntPtr handle) + { + _handle = handle; + _internal = Marshal.PtrToStructure(handle); + } + + public void Dispose() + { + Marshal.FreeHGlobal(_handle); + } + + public bool HasErrors() + { + return _internal.HasErrors(); + } + + public int DiagnosticsCount() + { + return GetDiagnosticsCount(_handle); + } + + public IEnumerable GetDiagnostics() + { + var count = DiagnosticsCount(); + for (var i = 0; i < count; i++) + { + var ptr = GetDiagnosticAt(_handle, i); + yield return Marshal.PtrToStructure(ptr); + } + } + + [DllImport("libPorygonLang", EntryPoint = "GetDiagnosticsCount")] + private static extern int GetDiagnosticsCount(IntPtr ptr); + + [DllImport("libPorygonLang", EntryPoint = "GetDiagnosticAt")] + private static extern IntPtr GetDiagnosticAt(IntPtr ptr, int position); + } +} \ No newline at end of file diff --git a/PorygonSharp/EvalValue.cs b/PorygonSharp/EvalValue.cs new file mode 100644 index 0000000..2d27b10 --- /dev/null +++ b/PorygonSharp/EvalValue.cs @@ -0,0 +1,64 @@ +using System; +using System.Runtime.InteropServices; + +namespace PorygonSharp +{ + public class EvalValue : IDisposable + { + private IntPtr _handle; + + public EvalValue(IntPtr handle) + { + _handle = handle; + } + + public void Dispose() + { + if (_handle != IntPtr.Zero) + { + Marshal.FreeHGlobal(_handle); + _handle = IntPtr.Zero; + } + } + + public TypeClass GetTypeClass() + { + return (TypeClass)GetTypeClass(_handle); + } + + public long EvaluateInteger() + { + return EvaluateInteger(_handle); + } + + public double EvaluateFloat() + { + return EvaluateFloat(_handle); + } + + public bool EvaluateBool() + { + return EvaluateBool(_handle); + } + + public string EvaluateString() + { + var ptr = EvaluateString(_handle); + return Marshal.PtrToStringUTF8(ptr); + } + + [DllImport("libPorygonLang", EntryPoint = "GetEvalValueTypeClass", CallingConvention = CallingConvention.Cdecl)] + private static extern int GetTypeClass(IntPtr ptr); + [DllImport("libPorygonLang", EntryPoint = "GetEvalValueType", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr GetScriptType(IntPtr ptr); + [DllImport("libPorygonLang", EntryPoint = "EvaluateEvalValueInteger", CallingConvention = CallingConvention.Cdecl)] + private static extern long EvaluateInteger(IntPtr ptr); + [DllImport("libPorygonLang", EntryPoint = "EvaluateEvalValueFloat", CallingConvention = CallingConvention.Cdecl)] + private static extern double EvaluateFloat(IntPtr ptr); + [DllImport("libPorygonLang", EntryPoint = "EvaluateEvalValueBool", CallingConvention = CallingConvention.Cdecl)] + private static extern bool EvaluateBool(IntPtr ptr); + [DllImport("libPorygonLang", EntryPoint = "EvaluateEvalValueString",CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr EvaluateString(IntPtr ptr); + + } +} \ No newline at end of file diff --git a/PorygonSharp/PorygonSharp.csproj b/PorygonSharp/PorygonSharp.csproj new file mode 100644 index 0000000..aa2ce34 --- /dev/null +++ b/PorygonSharp/PorygonSharp.csproj @@ -0,0 +1,8 @@ + + + + netcoreapp2.2 + true + + + diff --git a/PorygonSharp/Script.cs b/PorygonSharp/Script.cs new file mode 100644 index 0000000..9d10360 --- /dev/null +++ b/PorygonSharp/Script.cs @@ -0,0 +1,70 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +using PorygonSharp.DiagnosticHandling; + +namespace PorygonSharp +{ + [StructLayout(LayoutKind.Sequential)] + internal struct InternalScript + { + private readonly IntPtr _evaluator; + private readonly IntPtr _scriptVariables; + private readonly IntPtr _boundScript; + internal readonly IntPtr Diagnostics; + } + + public class Script : IDisposable + { + private readonly IntPtr _internalScriptHandle; + private readonly InternalScript _internalScript; + + private Diagnostics _diagnostics; + public Diagnostics Diagnostics => _diagnostics ?? (_diagnostics = new Diagnostics(_internalScript.Diagnostics)); + + public Script(string s) + { + _internalScriptHandle = Create(new StringBuilder(s)); + _internalScript = Marshal.PtrToStructure(_internalScriptHandle); + } + + public void Dispose() + { + Marshal.FreeHGlobal(_internalScriptHandle); + Diagnostics.Dispose(); + } + + public void Evaluate() + { + Evaluate(_internalScriptHandle); + } + + public EvalValue GetLastValue() + { + var ptr = GetLastValue(_internalScriptHandle); + return new EvalValue(ptr); + } + + public bool HasVariable(string key) + { + return HasVariable(_internalScriptHandle, key); + } + + public EvalValue GetVariable(string key) + { + var ptr = GetVariable(_internalScriptHandle, key); + return new EvalValue(ptr); + } + + [DllImport("libPorygonLang", EntryPoint = "CreateScript", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr Create(StringBuilder s); + [DllImport("libPorygonLang", EntryPoint = "EvaluateScript", CallingConvention = CallingConvention.Cdecl)] + private static extern void Evaluate(IntPtr script); + [DllImport("libPorygonLang", EntryPoint = "GetLastValue", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr GetLastValue(IntPtr script); + [DllImport("libPorygonLang", EntryPoint = "HasVariable", CallingConvention = CallingConvention.Cdecl)] + private static extern bool HasVariable(IntPtr script, string key); + [DllImport("libPorygonLang", EntryPoint = "GetVariable", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr GetVariable(IntPtr script, string key); + } +} \ No newline at end of file diff --git a/PorygonSharp/TypeClass.cs b/PorygonSharp/TypeClass.cs new file mode 100644 index 0000000..9c1271a --- /dev/null +++ b/PorygonSharp/TypeClass.cs @@ -0,0 +1,14 @@ +namespace PorygonSharp +{ + public enum TypeClass + { + Error, + Nil, + Number, + Bool, + String, + Function, + UserData, + Table, + } +} \ No newline at end of file diff --git a/PorygonSharpCLI/PorygonSharpCLI.csproj b/PorygonSharpCLI/PorygonSharpCLI.csproj new file mode 100644 index 0000000..d325333 --- /dev/null +++ b/PorygonSharpCLI/PorygonSharpCLI.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp2.2 + + + + + + + diff --git a/PorygonSharpCLI/Program.cs b/PorygonSharpCLI/Program.cs new file mode 100644 index 0000000..5432454 --- /dev/null +++ b/PorygonSharpCLI/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Diagnostics; +using PorygonSharp; + +namespace PorygonSharpCLI +{ + class Program + { + static void Main(string[] args) + { + var sw = Stopwatch.StartNew(); + for (var i = 0; i < 100000; i++) + { + var script = new Script("a = 500"); + script.Evaluate(); + script.Dispose(); + } + sw.Stop(); + Console.WriteLine($"Time elapsed: {sw.ElapsedMilliseconds}"); + } + } +} \ No newline at end of file diff --git a/PorygonSharpTests/PorygonSharpTests.csproj b/PorygonSharpTests/PorygonSharpTests.csproj new file mode 100644 index 0000000..10f4136 --- /dev/null +++ b/PorygonSharpTests/PorygonSharpTests.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp2.2 + + false + + + + + + + + + + + + + diff --git a/PorygonSharpTests/UnitTest1.cs b/PorygonSharpTests/UnitTest1.cs new file mode 100644 index 0000000..2731d38 --- /dev/null +++ b/PorygonSharpTests/UnitTest1.cs @@ -0,0 +1,97 @@ +using System; +using NUnit.Framework; +using PorygonSharp; + +namespace PorygonSharpTests +{ + public class Tests + { + [Test] + public void Test1() + { + using (var script = new Script("true")) + { + var diags = script.Diagnostics.GetDiagnostics(); + foreach (var diag in diags) + { + throw new Exception(diag.GetCode().ToString()); + } + Assert.False(script.Diagnostics.HasErrors()); + } + } + [Test] + public void Test2() + { + using (var script = new Script("1+true")) + { + Assert.True(script.Diagnostics.HasErrors()); + } + } + + [Test] + public void Test3() + { + using (var script = new Script("1+10")) + { + script.Evaluate(); + var lastVal = script.GetLastValue(); + Assert.AreEqual(TypeClass.Number, lastVal.GetTypeClass()); + var val = lastVal.EvaluateInteger(); + Assert.AreEqual(11, val); + } + } + + [Test] + public void Test4() + { + using (var script = new Script("1+10.24")) + { + script.Evaluate(); + var lastVal = script.GetLastValue(); + Assert.AreEqual(TypeClass.Number, lastVal.GetTypeClass()); + var val = lastVal.EvaluateFloat(); + Assert.AreEqual(11.24d, val, 5); + } + } + + [Test] + public void Test5() + { + using (var script = new Script("true and true")) + { + script.Evaluate(); + var lastVal = script.GetLastValue(); + Assert.AreEqual(TypeClass.Bool, lastVal.GetTypeClass()); + var val = lastVal.EvaluateBool(); + Assert.AreEqual(true, val); + } + } + + [Test] + public void Test6() + { + using (var script = new Script("'foo' + 'bar'")) + { + script.Evaluate(); + var lastVal = script.GetLastValue(); + Assert.AreEqual(TypeClass.String, lastVal.GetTypeClass()); + var val = lastVal.EvaluateString(); + Assert.AreEqual("foobar", val); + } + } + + [Test] + public void Test7() + { + using (var script = new Script("a = 100 + 50")) + { + script.Evaluate(); + var variable = script.GetVariable("a"); + Assert.AreEqual(TypeClass.Number, variable.GetTypeClass()); + var val = variable.EvaluateInteger(); + Assert.AreEqual(150, val); + } + } + + } +} \ No newline at end of file diff --git a/libPorygonLang.so b/libPorygonLang.so new file mode 100755 index 0000000..76c34b0 Binary files /dev/null and b/libPorygonLang.so differ