Browse Source

Merge pull request #267 from wledfor2/caseoptions

Added Options to control "fuzzy" matching of userdata methods, etc
Kevin Morgan 6 years ago
parent
commit
4e748a7a74

+ 9 - 9
src/MoonSharp.Interpreter/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs

@@ -233,18 +233,18 @@ namespace MoonSharp.Interpreter.Interop.BasicDescriptors
 				return null;
 
 			DynValue v = TryIndex(script, obj, index.String);
-			if (v == null) v = TryIndex(script, obj, UpperFirstLetter(index.String));
-			if (v == null) v = TryIndex(script, obj, Camelify(index.String));
-			if (v == null) v = TryIndex(script, obj, UpperFirstLetter(Camelify(index.String)));
+			if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter) v = TryIndex(script, obj, UpperFirstLetter(index.String));
+			if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify) v = TryIndex(script, obj, Camelify(index.String));
+			if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase)	v = TryIndex(script, obj, UpperFirstLetter(Camelify(index.String)));
 
 			if (v == null && m_ExtMethodsVersion < UserData.GetExtensionMethodsChangeVersion())
 			{
 				m_ExtMethodsVersion = UserData.GetExtensionMethodsChangeVersion();
 
 				v = TryIndexOnExtMethod(script, obj, index.String);
-				if (v == null) v = TryIndexOnExtMethod(script, obj, UpperFirstLetter(index.String));
-				if (v == null) v = TryIndexOnExtMethod(script, obj, Camelify(index.String));
-				if (v == null) v = TryIndexOnExtMethod(script, obj, UpperFirstLetter(Camelify(index.String)));
+				if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter) v = TryIndexOnExtMethod(script, obj, UpperFirstLetter(index.String));
+				if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify) v = TryIndexOnExtMethod(script, obj, Camelify(index.String));
+				if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase)	v = TryIndexOnExtMethod(script, obj, UpperFirstLetter(Camelify(index.String)));
 			}
 
 			return v;
@@ -344,9 +344,9 @@ namespace MoonSharp.Interpreter.Interop.BasicDescriptors
 				return false;
 
 			bool v = TrySetIndex(script, obj, index.String, value);
-			if (!v) v = TrySetIndex(script, obj, UpperFirstLetter(index.String), value);
-			if (!v) v = TrySetIndex(script, obj, Camelify(index.String), value);
-			if (!v) v = TrySetIndex(script, obj, UpperFirstLetter(Camelify(index.String)), value);
+			if (!v && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter) v = TrySetIndex(script, obj, UpperFirstLetter(index.String), value);
+			if (!v && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify) v = TrySetIndex(script, obj, Camelify(index.String), value);
+			if (!v && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase) v = TrySetIndex(script, obj, UpperFirstLetter(Camelify(index.String)), value);
 
 			return v;
 		}

+ 3 - 3
src/MoonSharp.Interpreter/Interop/PropertyTableAssigner.cs

@@ -182,9 +182,9 @@ namespace MoonSharp.Interpreter.Interop
 		private void AssignProperty(object obj, string name, DynValue value)
 		{
 			if (TryAssignProperty(obj, name, value)) return;
-			if (TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(name), value)) return;
-			if (TryAssignProperty(obj, DescriptorHelpers.Camelify(name), value)) return;
-			if (TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(DescriptorHelpers.Camelify(name)), value)) return;
+			if ((Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter && TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(name), value)) return;
+			if ((Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify && TryAssignProperty(obj, DescriptorHelpers.Camelify(name), value)) return;
+			if ((Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase && TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(DescriptorHelpers.Camelify(name)), value)) return;
 
 			throw new ScriptRuntimeException("Invalid property {0}", name);
 		}

+ 1 - 0
src/MoonSharp.Interpreter/MoonSharp.Interpreter.net35-client.csproj

@@ -302,6 +302,7 @@
     <Compile Include="Loaders\FileSystemScriptLoader.cs" />
     <Compile Include="Loaders\InvalidScriptLoader.cs" />
     <Compile Include="Options\ColonOperatorBehaviour.cs" />
+    <Compile Include="Options\FuzzySymbolMatchingBehavior.cs" />
     <Compile Include="Platforms\DotNetCorePlatformAccessor.cs" />
     <Compile Include="REPL\ReplHistoryNavigator.cs" />
     <Compile Include="REPL\ReplInterpreterScriptLoader.cs" />

+ 27 - 0
src/MoonSharp.Interpreter/Options/FuzzySymbolMatchingBehavior.cs

@@ -0,0 +1,27 @@
+using System;
+
+namespace MoonSharp.Interpreter {
+
+	/// <summary>
+	/// A flag that controls if/how symbols (method, property, userdata) are fuzzily matched when they do not exist. Flags can be combined for multiple checks.
+	/// </summary>
+	[Flags]
+	public enum FuzzySymbolMatchingBehavior {
+
+		/// <summary>No fuzzy matching is performed.</summary>
+		None = 0,
+
+		/// <summary>The first letter of a symbol will be uppercased (to check for common C# naming conventions). For example, testMethod() becomes TestMethod()</summary>
+		UpperFirstLetter = 1,
+
+		/// <summary>Underscores in symbols are converted to camelcase. For example, test_method() becomes testMethod()</summary>
+		Camelify = 2,
+
+		/// <summary>
+		/// Converts a symbol to pascal case. For example, test_Method_two() becomes TestMethodTwo()
+		/// </summary>
+		PascalCase = 4
+
+	}
+
+}

+ 12 - 4
src/MoonSharp.Interpreter/ScriptGlobalOptions.cs

@@ -1,5 +1,6 @@
 using MoonSharp.Interpreter.Interop;
 using MoonSharp.Interpreter.Platforms;
+using MoonSharp.Interpreter;
 
 namespace MoonSharp.Interpreter
 {
@@ -7,12 +8,11 @@ namespace MoonSharp.Interpreter
 	/// Class containing script global options, that is options which cannot be customized per-script.
 	/// <see cref="Script.GlobalOptions"/>
 	/// </summary>
-	public class ScriptGlobalOptions
-	{
-		internal ScriptGlobalOptions()
-		{
+	public class ScriptGlobalOptions {
+		internal ScriptGlobalOptions() {
 			Platform = PlatformAutoDetector.GetDefaultPlatform();
 			CustomConverters = new CustomConvertersCollection();
+			FuzzySymbolMatching = FuzzySymbolMatchingBehavior.Camelify | FuzzySymbolMatchingBehavior.UpperFirstLetter | FuzzySymbolMatchingBehavior.PascalCase;
 		}
 
 		/// <summary>
@@ -33,5 +33,13 @@ namespace MoonSharp.Interpreter
 		/// re-thrown as nested exceptions.
 		/// </summary>
 		public bool RethrowExceptionNested { get; set; }
+
+		/// <summary>
+		/// Gets or sets an enum that controls behaviour when a symbol (method, property, userdata) is not found in a userdata's descriptor. For instance,
+		/// when this value is <see cref="FuzzySymbolMatchingBehavior.UpperFirstLetter"/> and Lua code calls the non-existent method <c>someuserdata.someMethod()</c>,
+		/// <c>someuserdata.SomeMethod()</c> will also be tried.
+		/// </summary>
+		public FuzzySymbolMatchingBehavior FuzzySymbolMatching { get; set; }
+
 	}
 }

+ 3 - 0
src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.net40-client/MoonSharp.Interpreter.net40-client.csproj

@@ -576,6 +576,9 @@
     <Compile Include="..\..\Options\ColonOperatorBehaviour.cs">
       <Link>ColonOperatorBehaviour.cs</Link>
     </Compile>
+    <Compile Include="..\..\Options\FuzzySymbolMatchingBehavior.cs">
+      <Link>FuzzySymbolMatchingBehaviour.cs</Link>
+    </Compile>
     <Compile Include="..\..\Platforms\DotNetCorePlatformAccessor.cs">
       <Link>DotNetCorePlatformAccessor.cs</Link>
     </Compile>

+ 9 - 9
src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs

@@ -233,18 +233,18 @@ namespace MoonSharp.Interpreter.Interop.BasicDescriptors
 				return null;
 
 			DynValue v = TryIndex(script, obj, index.String);
-			if (v == null) v = TryIndex(script, obj, UpperFirstLetter(index.String));
-			if (v == null) v = TryIndex(script, obj, Camelify(index.String));
-			if (v == null) v = TryIndex(script, obj, UpperFirstLetter(Camelify(index.String)));
+			if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter) v = TryIndex(script, obj, UpperFirstLetter(index.String));
+			if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify) v = TryIndex(script, obj, Camelify(index.String));
+			if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase) v = TryIndex(script, obj, UpperFirstLetter(Camelify(index.String)));
 
 			if (v == null && m_ExtMethodsVersion < UserData.GetExtensionMethodsChangeVersion())
 			{
 				m_ExtMethodsVersion = UserData.GetExtensionMethodsChangeVersion();
 
 				v = TryIndexOnExtMethod(script, obj, index.String);
-				if (v == null) v = TryIndexOnExtMethod(script, obj, UpperFirstLetter(index.String));
-				if (v == null) v = TryIndexOnExtMethod(script, obj, Camelify(index.String));
-				if (v == null) v = TryIndexOnExtMethod(script, obj, UpperFirstLetter(Camelify(index.String)));
+				if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter) v = TryIndexOnExtMethod(script, obj, UpperFirstLetter(index.String));
+				if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify) v = TryIndexOnExtMethod(script, obj, Camelify(index.String));
+				if (v == null && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase) v = TryIndexOnExtMethod(script, obj, UpperFirstLetter(Camelify(index.String)));
 			}
 
 			return v;
@@ -344,9 +344,9 @@ namespace MoonSharp.Interpreter.Interop.BasicDescriptors
 				return false;
 
 			bool v = TrySetIndex(script, obj, index.String, value);
-			if (!v) v = TrySetIndex(script, obj, UpperFirstLetter(index.String), value);
-			if (!v) v = TrySetIndex(script, obj, Camelify(index.String), value);
-			if (!v) v = TrySetIndex(script, obj, UpperFirstLetter(Camelify(index.String)), value);
+			if (!v && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter) v = TrySetIndex(script, obj, UpperFirstLetter(index.String), value);
+			if (!v && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify) v = TrySetIndex(script, obj, Camelify(index.String), value);
+			if (!v && (Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase) v = TrySetIndex(script, obj, UpperFirstLetter(Camelify(index.String)), value);
 
 			return v;
 		}

+ 3 - 3
src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Interop/PropertyTableAssigner.cs

@@ -182,9 +182,9 @@ namespace MoonSharp.Interpreter.Interop
 		private void AssignProperty(object obj, string name, DynValue value)
 		{
 			if (TryAssignProperty(obj, name, value)) return;
-			if (TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(name), value)) return;
-			if (TryAssignProperty(obj, DescriptorHelpers.Camelify(name), value)) return;
-			if (TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(DescriptorHelpers.Camelify(name)), value)) return;
+			if ((Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.UpperFirstLetter) == FuzzySymbolMatchingBehavior.UpperFirstLetter && TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(name), value)) return;
+			if ((Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.Camelify) == FuzzySymbolMatchingBehavior.Camelify && TryAssignProperty(obj, DescriptorHelpers.Camelify(name), value)) return;
+			if ((Script.GlobalOptions.FuzzySymbolMatching & FuzzySymbolMatchingBehavior.PascalCase) == FuzzySymbolMatchingBehavior.PascalCase && TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(DescriptorHelpers.Camelify(name)), value)) return;
 
 			throw new ScriptRuntimeException("Invalid property {0}", name);
 		}

+ 27 - 0
src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/Options/FuzzySymbolMatchingBehavior.cs

@@ -0,0 +1,27 @@
+using System;
+
+namespace MoonSharp.Interpreter {
+
+	/// <summary>
+	/// A flag that controls if/how symbols (method, property, userdata) are fuzzily matched when they do not exist. Flags can be combined for multiple checks.
+	/// </summary>
+	[Flags]
+	public enum FuzzySymbolMatchingBehavior {
+
+		/// <summary>No fuzzy matching is performed.</summary>
+		None = 0,
+
+		/// <summary>The first letter of a symbol will be uppercased (to check for common C# naming conventions). For example, testMethod() becomes TestMethod()</summary>
+		UpperFirstLetter = 1,
+
+		/// <summary>Underscores in symbols are converted to camelcase. For example, test_method() becomes testMethod()</summary>
+		Camelify = 2,
+
+		/// <summary>
+		/// Converts a symbol to pascal case. For example, test_Method_two() becomes TestMethodTwo()
+		/// </summary>
+		PascalCase = 4
+
+	}
+
+}

+ 12 - 4
src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.netcore/src/ScriptGlobalOptions.cs

@@ -1,5 +1,6 @@
 using MoonSharp.Interpreter.Interop;
 using MoonSharp.Interpreter.Platforms;
+using MoonSharp.Interpreter;
 
 namespace MoonSharp.Interpreter
 {
@@ -7,12 +8,11 @@ namespace MoonSharp.Interpreter
 	/// Class containing script global options, that is options which cannot be customized per-script.
 	/// <see cref="Script.GlobalOptions"/>
 	/// </summary>
-	public class ScriptGlobalOptions
-	{
-		internal ScriptGlobalOptions()
-		{
+	public class ScriptGlobalOptions {
+		internal ScriptGlobalOptions() {
 			Platform = PlatformAutoDetector.GetDefaultPlatform();
 			CustomConverters = new CustomConvertersCollection();
+			FuzzySymbolMatching = FuzzySymbolMatchingBehavior.Camelify | FuzzySymbolMatchingBehavior.UpperFirstLetter | FuzzySymbolMatchingBehavior.PascalCase;
 		}
 
 		/// <summary>
@@ -33,5 +33,13 @@ namespace MoonSharp.Interpreter
 		/// re-thrown as nested exceptions.
 		/// </summary>
 		public bool RethrowExceptionNested { get; set; }
+
+		/// <summary>
+		/// Gets or sets an enum that controls behaviour when a symbol (method, property, userdata) is not found in a userdata's descriptor. For instance,
+		/// when this value is <see cref="FuzzySymbolMatchingBehavior.UpperFirstLetter"/> and Lua code calls the non-existent method <c>someuserdata.someMethod()</c>,
+		/// <c>someuserdata.SomeMethod()</c> will also be tried.
+		/// </summary>
+		public FuzzySymbolMatchingBehavior FuzzySymbolMatching { get; set; }
+
 	}
 }

+ 3 - 0
src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.portable40/MoonSharp.Interpreter.portable40.csproj

@@ -573,6 +573,9 @@
     <Compile Include="..\..\Options\ColonOperatorBehaviour.cs">
       <Link>ColonOperatorBehaviour.cs</Link>
     </Compile>
+    <Compile Include="..\..\Options\FuzzySymbolMatchingBehavior.cs">
+      <Link>FuzzySymbolMatchingBehavior.cs</Link>
+    </Compile>
     <Compile Include="..\..\Platforms\DotNetCorePlatformAccessor.cs">
       <Link>DotNetCorePlatformAccessor.cs</Link>
     </Compile>