This commit is contained in:
Даниил Заикин
2026-06-17 20:44:53 +03:00
parent 9d153773c2
commit b133e7c656
1880 changed files with 244545 additions and 0 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f7627ba6a0fc6d34182bb1aa178b4be5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class AdditionOperatorGrammar : BinaryAndUnaryOperatorGrammar
{
public override int Precedence => 0;
protected override char OperatorToken => '+';
protected override string OperatorMethodName => "op_Addition";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Add;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a0906d67478d174c896a36b20dc10c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,56 @@
using System.Collections.Generic;
using System.Linq;
namespace QFSW.QC.Grammar
{
public abstract class BinaryAndUnaryOperatorGrammar : BinaryOperatorGrammar
{
private readonly HashSet<char> _operatorChars = new HashSet<char>()
{
'+',
'-',
'*',
'/',
'&',
'|',
'^',
'=',
'!',
','
};
private readonly HashSet<char> _ignoreChars = new HashSet<char>()
{
' ',
'\0'
};
protected override int GetOperatorPosition(string value)
{
IEnumerable<int> splitPoints = TextProcessing.GetScopedSplitPoints(value, OperatorToken, TextProcessing.DefaultLeftScopers, TextProcessing.DefaultRightScopers);
foreach (int index in splitPoints.Reverse())
{
if (IsValidBinaryOperator(value, index))
{
return index;
}
}
return -1;
}
private bool IsValidBinaryOperator(string value, int position)
{
while (position > 0)
{
char ch = value[--position];
if (_operatorChars.Contains(ch)) { return false; }
if (!_ignoreChars.Contains(ch)) { return true; }
}
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 98ed033aecce1204bbfca244d563194b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,34 @@
using System;
using System.Reflection;
namespace QFSW.QC.Grammar
{
internal class BinaryOperatorData : IBinaryOperator
{
public Type LArg { get; }
public Type RArg { get; }
public Type Ret { get; }
private readonly MethodInfo _method;
public BinaryOperatorData(MethodInfo OperatorMethod)
{
_method = OperatorMethod;
Ret = OperatorMethod.ReturnType;
ParameterInfo[] paramData = _method.GetParameters();
if (paramData.Length != 2)
{
throw new ArgumentException($"Cannot create a binary operator from a method with {paramData.Length} parameters");
}
LArg = paramData[0].ParameterType;
RArg = paramData[1].ParameterType;
}
public object Invoke(object left, object right)
{
return _method.Invoke(null, new[] { left, right });
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e479a8c10bf9fa043959daa459ce97db
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;
using QFSW.QC.Utilities;
namespace QFSW.QC.Grammar
{
public abstract class BinaryOperatorGrammar : IQcGrammarConstruct
{
public abstract int Precedence { get; }
protected abstract char OperatorToken { get; }
protected abstract string OperatorMethodName { get; }
protected abstract Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator { get; }
private Regex _operatorRegex;
private readonly HashSet<Type> _missingOperatorTable = new HashSet<Type>();
private readonly Dictionary<Type, IBinaryOperator> _foundOperatorTable = new Dictionary<Type, IBinaryOperator>();
public bool Match(string value, Type type)
{
if (_missingOperatorTable.Contains(type))
{
return false;
}
if (!IsSyntaxMatch(value))
{
return false;
}
if (_foundOperatorTable.ContainsKey(type))
{
return true;
}
IBinaryOperator operatorData = GetOperatorData(type);
if (operatorData != null)
{
_foundOperatorTable.Add(type, operatorData);
return true;
}
_missingOperatorTable.Add(type);
return false;
}
private bool IsSyntaxMatch(string value)
{
if (_operatorRegex == null)
{
_operatorRegex = new Regex($@"^.+\{OperatorToken}.+$");
}
if (!_operatorRegex.IsMatch(value))
{
return false;
}
int operatorPos = GetOperatorPosition(value);
return operatorPos > 0 && operatorPos < value.Length;
}
private IBinaryOperator GetOperatorData(Type type)
{
if (type.IsPrimitive)
{
#if !UNITY_EDITOR && ENABLE_IL2CPP && !UNITY_2022_2_OR_NEWER
string typeName = QFSW.QC.Utilities.ReflectionExtensions.GetDisplayName(type);
UnityEngine.Debug.LogWarning($"{typeName} {OperatorToken} {typeName} is not supported as IL2CPP does not support dynamic value typed generics before Unity 2022.2");
#else
return GeneratePrimitiveOperator(type);
#endif
}
MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static);
BinaryOperatorData[] candidates = methods.Where(x => x.Name == OperatorMethodName)
.Where(x => x.ReturnType == type)
.Where(x => x.GetParameters().Length == 2)
.Select(x => new BinaryOperatorData(x))
.ToArray();
BinaryOperatorData idealCandidate = candidates.FirstOrDefault(x => x.LArg == type && x.RArg == type)
?? candidates.FirstOrDefault(x => x.LArg == type)
?? candidates.FirstOrDefault(x => x.RArg == type)
?? candidates.FirstOrDefault();
return idealCandidate;
}
private IBinaryOperator GeneratePrimitiveOperator(Type type)
{
ParameterExpression leftParam = Expression.Parameter(type, "left");
ParameterExpression rightParam = Expression.Parameter(type, "right");
BinaryExpression body;
try
{
body = PrimitiveExpressionGenerator(leftParam, rightParam);
}
catch (InvalidOperationException)
{
return null;
}
Delegate expr = Expression.Lambda(body, true, leftParam, rightParam).Compile();
return new DynamicBinaryOperator(expr, type, type, type);
}
/// <summary>
/// Get the position of the right-most valid operator token.
/// </summary>
/// <param name="value">The string to find the operator in.</param>
/// <returns>The position of the operator. -1 if none can be found</returns>
protected virtual int GetOperatorPosition(string value)
{
return TextProcessing.GetScopedSplitPoints(value, OperatorToken, TextProcessing.DefaultLeftScopers, TextProcessing.DefaultRightScopers).LastOr(-1);
}
public object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
IBinaryOperator operatorData = _foundOperatorTable[type];
int splitIndex = GetOperatorPosition(value);
string left = value.Substring(0, splitIndex);
string right = value.Substring(splitIndex + 1);
object leftVal = recursiveParser(left, operatorData.LArg);
object rightVal = recursiveParser(right, operatorData.RArg);
try
{
return operatorData.Invoke(leftVal, rightVal);
}
catch (TargetInvocationException e)
{
throw e.InnerException ?? e;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f3a6802829bc65049b2c671ce148f547
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class BitwiseAndOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 6;
protected override char OperatorToken => '&';
protected override string OperatorMethodName => "op_bitwiseAnd";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.And;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d9296938ddd32064d999e8e7000789ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class BitwiseOrOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 5;
protected override char OperatorToken => '|';
protected override string OperatorMethodName => "op_bitwiseOr";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Or;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a87fe84f3c6c7ba4191321937395bd84
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class DivisionOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 3;
protected override char OperatorToken => '/';
protected override string OperatorMethodName => "op_Division";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Divide;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 78358bd367d21fb44b571bf2d2dcd03f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,26 @@
using System;
namespace QFSW.QC.Grammar
{
internal class DynamicBinaryOperator : IBinaryOperator
{
public Type LArg { get; }
public Type RArg { get; }
public Type Ret { get; }
private readonly Delegate _del;
public DynamicBinaryOperator(Delegate del, Type lArg, Type rArg, Type ret)
{
_del = del;
LArg = lArg;
RArg = rArg;
Ret = ret;
}
public object Invoke(object left, object right)
{
return _del.DynamicInvoke(left, right);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18c4d964a275c32438dcb4abc6c1fb4d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class ExclusiveOrOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 7;
protected override char OperatorToken => '^';
protected override string OperatorMethodName => "op_ExclusiveOr";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.ExclusiveOr;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8528cd4143f809f459ca13f6415e8a03
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
using System;
namespace QFSW.QC.Grammar
{
public interface IBinaryOperator
{
Type LArg { get; }
Type RArg { get; }
Type Ret { get; }
object Invoke(object left, object right);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8349fa6e81e457847afbe6291aada5fd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class ModulusOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 4;
protected override char OperatorToken => '%';
protected override string OperatorMethodName => "op_Modulus";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Modulo;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fedde2bcbb582294d9c08ba7d622ab14
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class MultiplyOperatorGrammar : BinaryOperatorGrammar
{
public override int Precedence => 2;
protected override char OperatorToken => '*';
protected override string OperatorMethodName => "op_Multiply";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Multiply;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 00dd2e1128bbc2b4db7fc3c2c1e840e7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
using System;
using System.Linq.Expressions;
namespace QFSW.QC.Grammar
{
public class SubtractionOperatorGrammar : BinaryAndUnaryOperatorGrammar
{
public override int Precedence => 1;
protected override char OperatorToken => '-';
protected override string OperatorMethodName => "op_Subtraction";
protected override Func<Expression, Expression, BinaryExpression> PrimitiveExpressionGenerator => Expression.Subtract;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 48f2484f770bd9744bac9ad2f4f92de4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
using System;
using System.Text.RegularExpressions;
namespace QFSW.QC.Grammar
{
public class BooleanNegationGrammar : IQcGrammarConstruct
{
private readonly Regex _negationRegex = new Regex(@"^!\S+$");
public int Precedence => 0;
public bool Match(string value, Type type)
{
return type == typeof(bool) && _negationRegex.IsMatch(value);
}
public object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
value = value.Substring(1);
return !(bool)recursiveParser(value, type);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0674e06c549290f46914c51adb79b5f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,59 @@
using QFSW.QC.Utilities;
using System;
using System.Text.RegularExpressions;
namespace QFSW.QC.Grammar
{
public class ExpressionBodyGrammar : IQcGrammarConstruct
{
private readonly Regex _expressionBodyRegex = new Regex(@"^{.+}\??$");
public int Precedence => 0;
public bool Match(string value, Type type)
{
return _expressionBodyRegex.IsMatch(value);
}
public object Parse(string value, Type type, Func<string, Type, object> recursiveParser)
{
bool nullable = false;
if (value.EndsWith("?"))
{
nullable = true;
value = value.Substring(0, value.Length - 1);
}
value = value.ReduceScope('{', '}');
object result = QuantumConsoleProcessor.InvokeCommand(value);
if (result is null)
{
if (nullable)
{
if (type.IsClass)
{
return result;
}
else
{
throw new ParserInputException($"Expression body {{{value}}} evaluated to null which is incompatible with the expected type '{type.GetDisplayName()}'.");
}
}
else
{
throw new ParserInputException($"Expression body {{{value}}} evaluated to null. If this is intended, please use nullable expression bodies, {{expr}}?");
}
}
else if (result.GetType().IsCastableTo(type, true))
{
return type.Cast(result);
}
else
{
throw new ParserInputException($"Expression body {{{value}}} evaluated to an object of type '{result.GetType().GetDisplayName()}', " +
$"which is incompatible with the expected type '{type.GetDisplayName()}'.");
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4299ec1767412954f9b37800967fd471
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
{
"name": "QFSW.QC.Grammar",
"references": [
"QFSW.QC"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ad10a660d2aec9d449de236f5524cb5c
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: