using System; using System.Globalization; using System.Linq; using System.Reflection; namespace UdonSharp { public class OperatorParameterInfo : ParameterInfo { public override string Name { get { return NameImpl; } } public override bool HasDefaultValue { get { return false; } } public OperatorParameterInfo(System.Type type) { ClassImpl = type; NameImpl = type.Name; } } public enum BuiltinOperatorType { // -- Math Addition, Subtraction, Multiplication, Division, Remainder, LeftShift, RightShift, // UnaryPlus // This should be discarded before it gets to this point. I don't think there are any types that are relevant in Udon where this would matter UnaryMinus, // These operators are not present in Udon so we should handle them at a higher level, and we need handling for prefix vs postfix // UnaryIncrement, // UnaryDecrement, // -- Comparison GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual, Equality, Inequality, // -- Boolean operators UnaryNegation, ConditionalAnd, ConditionalOr, ConditionalXor, // This doesn't exist in C#? // -- Bitwise operators LogicalAnd, LogicalOr, LogicalXor, BitwiseNot, // Now has hack workaround handling } /// /// Used to represent builtin operations on base types that aren't represented by a method in CIL and just have a corresponding instruction. /// Example: The addition operator on base types is an add instruction, this happens with most basic arithmetic ops /// Udon exports generated functions for all of the operators on base types, for instance "SystemSingle.__op_Addition__SystemSingle_SystemSingle__SystemSingle" for float addition /// public class OperatorMethodInfo : MethodInfo { public override ICustomAttributeProvider ReturnTypeCustomAttributes => throw new NotImplementedException(); // Treat these methods like they are static since that's the calling convention Udon uses for them // Assignment variants of these operators will be handled at a higher level public override MethodAttributes Attributes { get { return MethodAttributes.Static; } } public override RuntimeMethodHandle MethodHandle => throw new NotImplementedException(); public override Type DeclaringType { get { return operatorSourceType; } } public override string Name { get { return $"op_{Enum.GetName(typeof(BuiltinOperatorType), operatorType)}"; } } public override Type ReturnType { get { if (operatorType == BuiltinOperatorType.ConditionalAnd || operatorType == BuiltinOperatorType.ConditionalOr || operatorType == BuiltinOperatorType.GreaterThan || operatorType == BuiltinOperatorType.GreaterThanOrEqual || operatorType == BuiltinOperatorType.LessThan || operatorType == BuiltinOperatorType.LessThanOrEqual || operatorType == BuiltinOperatorType.Equality || operatorType == BuiltinOperatorType.Inequality) return typeof(bool); if (operatorSourceType == typeof(byte) || operatorSourceType == typeof(sbyte) || operatorSourceType == typeof(char) || operatorSourceType == typeof(short) || operatorSourceType == typeof(ushort)) { return typeof(int); } return operatorSourceType; } } public override Type ReflectedType { get { return operatorSourceType; } } public Type operatorSourceType { get; private set; } public BuiltinOperatorType operatorType { get; private set; } public OperatorMethodInfo(Type type, BuiltinOperatorType operatorTypeIn) { operatorSourceType = type; operatorType = operatorTypeIn; } public override MethodInfo GetBaseDefinition() { throw new NotImplementedException(); } public override object[] GetCustomAttributes(bool inherit) { return null; } public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return null; } public override string ToString() { return $"UdonSharp Operator {ReturnType} {Name}({string.Join(", ", GetParameters().Select(e => e.Name))})"; } public override bool Equals(object obj) { OperatorMethodInfo other = obj as OperatorMethodInfo; if (other == null) return false; return operatorSourceType == other.operatorSourceType && operatorType == other.operatorType; } public override int GetHashCode() { return operatorSourceType.GetHashCode() + operatorType.GetHashCode(); } public override MethodImplAttributes GetMethodImplementationFlags() { return MethodImplAttributes.Runtime; } public override ParameterInfo[] GetParameters() { if (operatorType == BuiltinOperatorType.UnaryMinus || operatorType == BuiltinOperatorType.UnaryNegation) { return new ParameterInfo[] { new OperatorParameterInfo(operatorSourceType) }; } else { if (operatorType == BuiltinOperatorType.LeftShift || operatorType == BuiltinOperatorType.RightShift) { if (operatorSourceType == typeof(uint)) return new ParameterInfo[] { new OperatorParameterInfo(operatorSourceType), new OperatorParameterInfo(typeof(int)) }; else if (operatorSourceType == typeof(ulong)) return new ParameterInfo[] { new OperatorParameterInfo(operatorSourceType), new OperatorParameterInfo(typeof(int)) }; else if (operatorSourceType == typeof(long)) return new ParameterInfo[] { new OperatorParameterInfo(operatorSourceType), new OperatorParameterInfo(typeof(int)) }; } return new ParameterInfo[] { new OperatorParameterInfo(operatorSourceType), new OperatorParameterInfo(operatorSourceType) }; } } public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) { throw new NotImplementedException("This is a stub, invoke is not needed unless we want to do constant folding and such ourselves."); } public override bool IsDefined(Type attributeType, bool inherit) { throw new NotImplementedException(); } } }