using JsonSubTypes; using Newtonsoft.Json; using System.Collections.Generic; using System.Linq.Expressions; using System.Linq; using System; using UnityEngine; using MoreLinq; namespace REST_JSON_API { [JsonConverter(typeof(JsonSubtypes), "kind")] [JsonSubtypes.KnownSubType(typeof(OMA), "OMA")] [JsonSubtypes.KnownSubType(typeof(OMS), "OMS")] [JsonSubtypes.KnownSubType(typeof(OMSTR), "OMSTR")] [JsonSubtypes.KnownSubType(typeof(OMF), "OMF")] [JsonSubtypes.KnownSubType(typeof(OMV), "VAR")] [JsonSubtypes.KnownSubType(typeof(RAW), "RAW")] [JsonSubtypes.KnownSubType(typeof(FUN), "FUN")] [JsonSubtypes.KnownSubType(typeof(FUNTYPE), "FUNTYPE")] //[JsonSubtypes.KnownSubType(typeof(OMC<T>), "OMC<" + typeof(T) + ">")] [JsonSubtypes.KnownSubType(typeof(OMC<Vector3>), "OMC<UnityEngine.Vector3>")] [JsonSubtypes.KnownSubType(typeof(OMC<float>), "OMC<System.Single>")] [JsonSubtypes.KnownSubType(typeof(OMC<double>), "OMC<System.Double>")] [JsonSubtypes.FallBackSubType(typeof(FallbackWrapper))] abstract public partial class SOMDoc { public string kind; protected SOMDoc() { kind = this.GetType().Name; } protected internal abstract SOMDoc SOMDocType(SOMDoc[] args, FUN.Param[] bound_params); public SOMDoc SOMDocType() => SOMDocType(new SOMDoc[0], new FUN.Param[0]); public static SOMDoc SOMDocType(Type type) { SOMDoc[] args = type.IsGenericType ? type.GetGenericArguments().Select(t => SOMDocType(t)).ToArray() : type.HasElementType ? new[] { SOMDocType(type.GetElementType()) } : null; if (type == typeof(Vector3) // Isomoprhismus || TupleExtensions.IsTupleType(type, out _)) // Dictionary does not like Generics type = typeof(Tuple); if (type.HasElementType) // pretend its a List type = typeof(List<>); // Dictionary does not like Generics if (FuncExtensions.IsFuncType(type, out _)) return new FUNTYPE(args[..^1], args[^1]); if (MMTConstants.TYPE_TO_OMS.TryGetValue(type, out string uri)) return args != null ? new OMA(new OMS(uri), args) : new OMS(uri); throw new NotImplementedException($"For Type {type}"); } protected internal abstract Type ToType(Type[] args, (string name, Type type)[] bound_params); public Type ToType() => ToType(new Type[0], new (string name, Type type)[0]); public static bool Equivalent(SOMDoc sd1, SOMDoc sd2) => sd1 != null && sd2 != null && sd1.Equivalent(sd2); public abstract bool Equivalent(SOMDoc sd2); public Func<object[], object[]> PartialInvokeCastingLambdaExpression(out Type[] signature, object[] callArgs = null, bool[] useArgs = null) { Expression to_compile; List<Type> signature_list; LambdaExpression lambda_orig = GetLambdaExpression(); if (FuncExtensions.IsFuncType(lambda_orig.ReturnType, out int signature_count)) { signature_list = lambda_orig.ReturnType.GetGenericArguments().ToList(); to_compile = lambda_orig.Body; } else { signature_count = lambda_orig.Parameters.Count + 1; signature_list = Enumerable.Append( lambda_orig.Parameters.Select(p => p.Type), lambda_orig.ReturnType) .ToList(); to_compile = lambda_orig; } ParameterExpression object_arr = Expression.Parameter(typeof(object[]), "PARAMS_Arr"); Expression[] cast_new_to_signature = new Expression[signature_count - 1]; List<int> removed = new(); for (int i = 0; i < signature_count - 1; i++) { if (callArgs != null && callArgs.Length < i && (useArgs == null || (useArgs.Length < i && useArgs[i]))) { cast_new_to_signature[i] = Expression.Constant(callArgs[i], signature_list[i]); removed.Add(i); continue; } cast_new_to_signature[i] = Expression.Convert( Expression.ArrayIndex( object_arr, Expression.Constant(i) ), signature_list[i] ); } removed.ForEach(signature_list.RemoveAt); signature = signature_list.ToArray(); LambdaExpression final_expression = Expression.Lambda( typeof(object[]).IsAssignableFrom(signature[^1]) ? Expression.Invoke(to_compile, cast_new_to_signature) : Expression.NewArrayInit( typeof(object), new Expression[] { Expression.Convert(Expression.Invoke(to_compile, cast_new_to_signature), typeof(object)) }), object_arr ); return final_expression.Compile() as Func<object[], object[]>; } public LambdaExpression GetLambdaExpression() => GetLambdaExpression(new LambdaExpression[0], new LambdaExpression[0], new ParameterExpression[0]); protected internal abstract LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params); public abstract override string ToString(); public abstract SOMDoc MapURIs(Dictionary<string, string> old_to_new); public abstract string[] GetDependentFactIds(); #region MakeMMT_OMS_URItoSOMDoc public static Vector3 MakeVector3(OMA tuple) { if (tuple.arguments is not OMF[] xyz || xyz.Length < 3) throw new FormatException("Argument " + nameof(tuple) + "." + nameof(OMA.arguments) + " expected to be: " + nameof(OMF) + "[3]"); return new Vector3(xyz[0].@float, xyz[1].@float, xyz[2].@float); } public static OMA MakeVector3(Vector3 vec) => MakeTupel(new[] { new OMF(vec.x), new OMF(vec.y), new OMF(vec.z), }); public static OMA MakeTupel(SOMDoc[] args) => new( new OMS(MMTConstants.Tuple), args ); public static OMA MakeShallowList(SOMDoc[] args) => new( new OMS(MMTConstants.ListApplicant), args ); public static OMA MakeDeepList(SOMDoc[] args, SOMDoc SOMDoc_type) { SOMDoc[] end_of_list = new SOMDoc[] { new OMA( new OMS(MMTConstants.ListEnd), new[] { SOMDoc_type, } ), args.Length == 0 ? null : args[^1] }; if (args.Length == 0) end_of_list = end_of_list[..^0]; SOMDoc defines = new OMA( new OMS(MMTConstants.ListLiteral), end_of_list ); for (int i = args.Length - 2; i >= 0; i--) { defines = new OMA( new OMS(MMTConstants.ListLiteral), new[] { defines, args[i], }); } SOMDoc type = new OMA( new OMS(MMTConstants.ListType), new[] { SOMDoc_type } ); return new OMA(type, new[] { defines }); } #endregion MakeMMT_OMS_URItoSOMDoc } public abstract class SOMDocCRTP<T> : SOMDoc where T : SOMDocCRTP<T> { protected SOMDocCRTP() : base() { } public override bool Equivalent(SOMDoc sd2) => this.GetType() == sd2.GetType() && (this as T).EquivalentWrapped(sd2 as T); protected abstract bool EquivalentWrapped(T sd2); public override SOMDoc MapURIs(Dictionary<string, string> old_to_new) => MapURIsWrapped(old_to_new); protected abstract T MapURIsWrapped(Dictionary<string, string> old_to_new); } public class FUNTYPE : SOMDocCRTP<FUNTYPE> { public new string kind = "FUNTYPE"; public SOMDoc[] @params; public SOMDoc ret; [JsonConstructor] public FUNTYPE(SOMDoc[] @params, SOMDoc ret) { this.@params = @params; this.ret = ret; } public override string ToString() => "[" + string.Join(", ", @params.Select(p => p.ToString())) + "] => {" + ret.ToString() + "}"; protected override bool EquivalentWrapped(FUNTYPE sd2) => @params.Length == sd2.@params.Length && @params.Zip(sd2.@params, (a, b) => a.Equivalent(b)) .All(b => b) && ret.Equivalent(sd2.ret); protected override FUNTYPE MapURIsWrapped(Dictionary<string, string> old_to_new) => new(@params.Select(p => p.MapURIs(old_to_new)).ToArray() , ret.MapURIs(old_to_new)); public override string[] GetDependentFactIds() => new string[0]; protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { throw new NotImplementedException(); } protected internal override SOMDoc SOMDocType(SOMDoc[] args, FUN.Param[] bound_params) { throw new NotImplementedException(); } protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) => FuncExtensions.CreateFuncType(Enumerable.Append(@params.Select(p => p.ToType()), ret.ToType()).ToArray()); } public class FUN : SOMDocCRTP<FUN> { public new string kind = "FUN"; public Param[] @params; public SOMDoc body; [JsonConstructor] public FUN(Param[] @params, SOMDoc body) { this.@params = @params; this.body = body; } public class Param { public string name; [JsonProperty("tp")] public SOMDoc type; [JsonConstructor] public Param(string name, SOMDoc tp) { this.name = name; this.type = tp; } public override string ToString() => name + "(" + type.ToString() + ")"; } public override string ToString() => "[" + string.Join(", ", @params.Select(p => p.ToString())) + "] => {" + body.ToString() + "}"; protected override bool EquivalentWrapped(FUN sd2) => @params.Length == sd2.@params.Length && @params.Zip(sd2.@params, (a, b) => a.name.Equals(b.name) && a.type.Equivalent(b.type)) .All(b => b) && body.Equivalent(sd2.body); protected override FUN MapURIsWrapped(Dictionary<string, string> old_to_new) => new(@params.Select(p => new Param(p.name, p.type.MapURIs(old_to_new))).ToArray() , body.MapURIs(old_to_new)); public override string[] GetDependentFactIds() => body.GetDependentFactIds(); protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { ParameterExpression[] local_param = @params.Select(p => Expression.Parameter(p.type.ToType(), p.name)).ToArray(); LambdaExpression body_lambda = body.GetLambdaExpression( lambda_applicant, lambda_arguments, bound_params.ShallowCloneAppend(local_param) ); return Expression.Lambda( Expression.Lambda( body_lambda.Body, local_param ), bound_params ); } protected internal override SOMDoc SOMDocType(SOMDoc[] args, Param[] bound_params) { Param[] bind_me = bound_params.ShallowCloneAppend(@params); return new FUNTYPE( @params.Select(p => p.type).ToArray(), body.SOMDocType(new SOMDoc[0], bind_me) ); } protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) { (string name, Type)[] bind_me = bound_params .AppendRange(@params.Select(p => (p.name, p.type.ToType()))) .ToArray(); return SOMDocType().ToType(new Type[0], bind_me); } } public class OMV : SOMDocCRTP<OMV> { public new string kind = "VAR"; public string name; [JsonConstructor] public OMV(string name) : base() { this.name = name; } protected override bool EquivalentWrapped(OMV sd2) => this.name == sd2.name; protected internal override SOMDoc SOMDocType(SOMDoc[] args, FUN.Param[] bound_params) { FUN.Param p = bound_params.FirstOrDefault(param => param.name.Equals(name)) ?? throw new FormatException($"Unable to find {nameof(FUN.Param)} for {nameof(OMV)} with name: {name}"); return p.type; } protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) { (string name, Type type) p = bound_params.FirstOrDefault(param => param.name.Equals(name)); if (p == default) throw new FormatException($"Unable to find {nameof(FUN.Param)} for {nameof(OMV)} with name: {name}"); return p.type; } protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { ParameterExpression v = bound_params.FirstOrDefault(param => param.Name.Equals(name)); if (v == null) { Debug.LogErrorFormat("Unable to find {0} for {1} with name: {2}", nameof(FUN.Param), nameof(OMV), name); return Expression.Lambda(Expression.Empty(), null); } else return Expression.Lambda(v, new[] { v }); } public override string ToString() => "Variable_" + "(" + name + ")"; protected override OMV MapURIsWrapped(Dictionary<string, string> old_to_new) => (OMV)this.MemberwiseClone(); public override string[] GetDependentFactIds() => new string[0]; } public class OMA : SOMDocCRTP<OMA> { public new string kind = "OMA"; public SOMDoc applicant; public SOMDoc[] arguments; [JsonConstructor] public OMA(SOMDoc applicant, SOMDoc[] arguments) : base() { this.applicant = applicant; this.arguments = arguments; } protected internal override SOMDoc SOMDocType(SOMDoc[] args, FUN.Param[] bound_params) => applicant.SOMDocType( arguments.Select(a => a.SOMDocType(new SOMDoc[0], bound_params)).ToArray(), bound_params ); protected override bool EquivalentWrapped(OMA sd2) => Equivalent(this.applicant, sd2.applicant) && this.arguments .Zip(sd2.arguments, (arg1, arg2) => Equivalent(arg1, arg2)) .All(b => b); protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_arguments_paps, LambdaExpression[] lambda_arguments_grands, ParameterExpression[] bound_params) => applicant.GetLambdaExpression( arguments.Select(arg => arg.GetLambdaExpression(new LambdaExpression[0], new LambdaExpression[0], bound_params)).ToArray(), lambda_arguments_paps, bound_params ); public override string ToString() => applicant.ToString() + "(" + string.Join(", ", arguments.Select(a => a.ToString())) + ")"; protected override OMA MapURIsWrapped(Dictionary<string, string> old_to_new) => new OMA( applicant.MapURIs(old_to_new), arguments.Select(arg => arg.MapURIs(old_to_new)).ToArray() ); public override string[] GetDependentFactIds() => applicant.GetDependentFactIds() .AppendRange(arguments.SelectMany(arg => arg.GetDependentFactIds())) .ToArray(); protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) => applicant.ToType( arguments.Select(arg => arg.ToType(new Type[0], bound_params)).ToArray(), bound_params ); } public class OMS : SOMDocCRTP<OMS> { public new string kind = "OMS"; public string uri; [JsonConstructor] public OMS(string uri) : base() { this.uri = uri; } protected override bool EquivalentWrapped(OMS sd2) { bool b1 = FactRecorder.AllFacts.TryGetValue(uri, out Fact f1), b2 = FactRecorder.AllFacts.TryGetValue(sd2.uri, out Fact f2); return (b1 == b2 && uri == sd2.uri) || (b1 && b2 && f1.Equivalent(f2)); } protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_arguments_paps, LambdaExpression[] lambda_arguments_grands, ParameterExpression[] bound_params) => SOMDocToLambdaExpression<float>.MakeLambdaExpression(uri, lambda_arguments_paps, lambda_arguments_grands, bound_params); public override string ToString() => uri; protected override OMS MapURIsWrapped(Dictionary<string, string> old_to_new) { if (!old_to_new.TryGetValue(uri, out string new_uri)) new_uri = uri; return new OMS(new_uri); } public override string[] GetDependentFactIds() => FactRecorder.AllFacts.ContainsKey(uri) ? new string[] { uri } : new string[0]; protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) { if (FactRecorder.AllFacts.TryGetValue(uri, out Fact found)) return found.GetType(); if (MMTConstants.HeterogenApplication_TO_TypeOF.TryGetValue(uri, out string s_type)) { Type type = MMTConstants.OMS_TO_TYPE[s_type]; if (type.Equals(typeof(Tuple))) { // authors note: Not a fan, but has to be done somewhwere... if (args.Length == 3 && args.All(t => t == typeof(float))) return typeof(Vector3); type = TupleExtensions.GetGenericTupleType(args.Length); } else if (type.Equals(typeof(Func<>))) return FuncExtensions.CreateFuncType(args); return type .MakeGenericType(args); } if (MMTConstants.HomogenApplication_TO_TypeOF.TryGetValue(uri, out s_type)) return MMTConstants.OMS_TO_TYPE[s_type] .MakeGenericType(args[0]); if (MMTConstants.URI_TO_TypeOF.TryGetValue(uri, out s_type)) return MMTConstants.OMS_TO_TYPE[s_type]; if (MMTConstants.OMS_TO_TYPE.TryGetValue(uri, out Type t_type)) return t_type; throw new NotImplementedException(); } protected internal override SOMDoc SOMDocType(SOMDoc[] args, FUN.Param[] bound_params) { string _uri = uri; bool use_uri; if (use_uri = MMTConstants.OMS_TO_TYPE.TryGetValue(_uri, out Type tmp_type)) _uri = MMTConstants.TYPE_TO_OMS[tmp_type]; if (FactRecorder.AllFacts.TryGetValue(_uri, out Fact found)) return new OMS(MMTConstants.TYPE_TO_OMS[found.GetType()]); if (MMTConstants.HeterogenApplication_TO_TypeOF.TryGetValue(_uri, out string type)) return new OMA( new OMS(type), args ); if (MMTConstants.HomogenApplication_TO_TypeOF.TryGetValue(_uri, out type)) return new OMA( new OMS(type), new[] { args[0] } ); if (MMTConstants.URI_TO_TypeOF.TryGetValue(_uri, out type)) return new OMS(type); if (use_uri) return SOMDocType(tmp_type); //return new OMS(_uri); throw new NotImplementedException(uri); } } public class OMSTR : SOMDocCRTP<OMSTR> { public new string kind = "OMSTR"; [JsonProperty("float")] public string s; [JsonConstructor] public OMSTR(string s) : base() { this.s = s; } protected internal override SOMDoc SOMDocType(SOMDoc[] args, FUN.Param[] bound_params) => throw new NotImplementedException(); protected override bool EquivalentWrapped(OMSTR sd2) => this.s == sd2.s; protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => Expression.Lambda(Expression.Constant(s, typeof(string)), null); public override string ToString() => s; protected override OMSTR MapURIsWrapped(Dictionary<string, string> old_to_new) => (OMSTR)this.MemberwiseClone(); public override string[] GetDependentFactIds() => new string[0]; protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) => typeof(string); } public class OMF : SOMDocCRTP<OMF> { public new string kind = "OMF"; [JsonProperty("float")] public float @float; [JsonConstructor] public OMF(float f) : base() { this.@float = f; } protected internal override SOMDoc SOMDocType(SOMDoc[] args, FUN.Param[] bound_params) => new OMS(MMTConstants.RealLit); protected override bool EquivalentWrapped(OMF sd2) => Mathf.Approximately(@float, sd2.@float); protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => Expression.Lambda(Expression.Constant(@float, typeof(float)), null); public override string ToString() => @float.ToString(); protected override OMF MapURIsWrapped(Dictionary<string, string> old_to_new) => (OMF)this.MemberwiseClone(); public override string[] GetDependentFactIds() => new string[0]; protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) => typeof(float); } public class RAW : SOMDocCRTP<RAW> { public new string kind = "RAW"; public string xml; [JsonConstructor] public RAW(string xml) : base() { this.xml = xml; } protected internal override SOMDoc SOMDocType(SOMDoc[] args, FUN.Param[] bound_params) => throw new NotSupportedException(); protected override RAW MapURIsWrapped(Dictionary<string, string> old_to_new) { string copy = xml; foreach (KeyValuePair<string, string> KeyVal in old_to_new) copy = copy.Replace(KeyVal.Key, KeyVal.Value); return new RAW(copy); } public override string[] GetDependentFactIds() => new string[0]; public override string ToString() => xml; protected override bool EquivalentWrapped(RAW sd2) => throw new NotImplementedException(); //xml == sd2.xml; // only exact protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => throw new NotSupportedException(); protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) => throw new NotSupportedException(); } // temporary fix if Serialzation is broken public class FallbackWrapper : SOMDocCRTP<FallbackWrapper> { public SOMDoc SFunction; [JsonConstructor] public FallbackWrapper(SOMDoc SFunction) { this.SFunction = SFunction; } public override string ToString() => SFunction.ToString(); protected override bool EquivalentWrapped(FallbackWrapper sd2) => SFunction.Equivalent(sd2); protected override FallbackWrapper MapURIsWrapped(Dictionary<string, string> old_to_new) => new(SFunction.MapURIs(old_to_new)); protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => SFunction.GetLambdaExpression(lambda_applicant, lambda_arguments, bound_params); protected internal override SOMDoc SOMDocType(SOMDoc[] args, FUN.Param[] bound_params) => SFunction.SOMDocType(args, bound_params); protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) => SFunction.ToType(args, bound_params); public override string[] GetDependentFactIds() => SFunction.GetDependentFactIds(); } // internal use only public class OMC<T> : SOMDocCRTP<OMC<T>> { public new string kind = "OMC<" + typeof(T) + ">"; public T value; [JsonConstructor] public OMC(T value) : base() { this.value = value; } protected internal override SOMDoc SOMDocType(SOMDoc[] args, FUN.Param[] bound_params) => SOMDocType(typeof(T)); protected override bool EquivalentWrapped(OMC<T> sd2) { Debug.LogWarning("Cannot check Equivalency for " + this.GetType() + "; only whether it's exact!"); return this.value.Equals(value); } protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) => Expression.Lambda(Expression.Constant(value, typeof(T)), null); public override string ToString() => "C_" + typeof(T) + "(" + value.ToString() + ")"; protected override OMC<T> MapURIsWrapped(Dictionary<string, string> old_to_new) => (OMC<T>)this.MemberwiseClone(); public override string[] GetDependentFactIds() => new string[0]; protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) => typeof(T); } }