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) { if (type == typeof(Vector3)) // Isomoprhismus type = typeof(Tuple); SOMDoc[] args = type.IsGenericType ? type.GetGenericArguments().Select(t => SOMDocType(t)).ToArray() : null; if (FuncExtensions.GenericFuncTypes.Contains(type.IsGenericType ? type.GetGenericTypeDefinition() : type)) return new FUNTYPE(args[..^1], args[^1]); if (MMTConstants.TYPE_TO_OMS.TryGetValue(type, out string uri)) return type.IsGenericType ? new OMA(new OMS(uri), args) : new OMS(uri); throw new NotImplementedException(); } 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_args, object[] callArgs = null, bool[] useArgs = null) { LambdaExpression lambda_orig = GetLambdaExpression(); if (lambda_orig.Body is LambdaExpression lambda_lambda) lambda_orig = lambda_lambda; signature_args = new Type[lambda_orig.Parameters.Count + 1]; ParameterExpression object_arr = Expression.Parameter(typeof(object[]), "PARAMS_Arr"); Expression[] cast_new_to_signature = new Expression[lambda_orig.Parameters.Count]; int n_params = 0; for (int i = 0; i < lambda_orig.Parameters.Count; i++) { if (callArgs != null && callArgs.Length < i && (useArgs == null || (useArgs.Length < i && useArgs[i]))) { cast_new_to_signature[i] = Expression.Constant(callArgs[i], lambda_orig.Parameters[i].Type); continue; } signature_args[n_params++] = lambda_orig.Parameters[i].Type; cast_new_to_signature[i] = Expression.Convert( Expression.ArrayIndex( object_arr, Expression.Constant(i) ), lambda_orig.Parameters[i].Type ); } signature_args[n_params] = lambda_orig.ReturnType; signature_args = signature_args.Slice(0, n_params + 1).ToArray(); LambdaExpression final_expression = Expression.Lambda( typeof(object[]).IsAssignableFrom(lambda_orig.ReturnType) ? Expression.Invoke(lambda_orig, cast_new_to_signature) : Expression.NewArrayInit( typeof(object), new Expression[] { Expression.Convert(Expression.Invoke(lambda_orig, 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); #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)); 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)); protected internal override LambdaExpression GetLambdaExpression(LambdaExpression[] lambda_applicant, LambdaExpression[] lambda_arguments, ParameterExpression[] bound_params) { ParameterExpression[] bind_me = bound_params.ShallowCloneAppend( @params.Select(p => Expression.Parameter(p.type.ToType(), p.name)).ToArray() ); return Expression.Lambda( body.GetLambdaExpression(lambda_applicant, lambda_arguments, bind_me), 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 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() ); 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) => this.uri == sd2.uri; 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); } 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(); 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(); 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 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); } // 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(); protected internal override Type ToType(Type[] args, (string name, Type type)[] bound_params) => typeof(T); } }