Example #1
0
        /// <summary>
        /// Whether the given type is a valid one to be a variable.
        /// </summary>
        public static bool IsValidType(Type variableType)
        {
            Contracts.CheckValue(variableType, nameof(variableType));

            // Option types should not be used to consturct graph.
            if (variableType.IsGenericType && variableType.GetGenericTypeDefinition() == typeof(Optional <>))
            {
                return(false);
            }

            if (variableType == typeof(CommonInputs.IEvaluatorInput))
            {
                return(true);
            }
            if (variableType == typeof(CommonOutputs.IEvaluatorOutput))
            {
                return(true);
            }
            if (variableType == typeof(IMlState))
            {
                return(true);
            }

            var kind = TlcModule.GetDataType(variableType);

            if (kind == TlcModule.DataKind.Array)
            {
                if (!variableType.IsArray)
                {
                    Contracts.Assert(false, "Unexpected type for array variable");
                    return(false);
                }
                return(IsValidType(variableType.GetElementType()));
            }

            if (kind == TlcModule.DataKind.Dictionary)
            {
                Contracts.Assert(variableType.IsGenericType && variableType.GetGenericTypeDefinition() == typeof(Dictionary <,>) &&
                                 variableType.GetGenericTypeArgumentsEx()[0] == typeof(string));
                return(IsValidType(variableType.GetGenericTypeArgumentsEx()[1]));
            }

            return(kind == TlcModule.DataKind.DataView ||
                   kind == TlcModule.DataKind.FileHandle ||
                   kind == TlcModule.DataKind.PredictorModel ||
                   kind == TlcModule.DataKind.TransformModel);
        }
Example #2
0
        private void GenerateColumnAddMethods(IndentingTextWriter writer, Type inputType, ModuleCatalog catalog,
                                              string className, out Type columnType)
        {
            columnType = null;
            foreach (var fieldInfo in inputType.GetFields())
            {
                var inputAttr = fieldInfo.GetCustomAttributes(typeof(ArgumentAttribute), false).FirstOrDefault() as ArgumentAttribute;
                if (inputAttr == null || inputAttr.Visibility == ArgumentAttribute.VisibilityType.CmdLineOnly)
                {
                    continue;
                }
                var type    = CSharpGeneratorUtils.ExtractOptionalOrNullableType(fieldInfo.FieldType);
                var isArray = type.IsArray;
                if (isArray)
                {
                    type = type.GetElementType();
                }
                if (type == typeof(JArray) || type == typeof(JObject))
                {
                    continue;
                }
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Var <>))
                {
                    continue;
                }
                var typeEnum = TlcModule.GetDataType(type);
                if (typeEnum != TlcModule.DataKind.Unknown)
                {
                    continue;
                }

                if (type.IsSubclassOf(typeof(OneToOneColumn)))
                {
                    columnType = GenerateOneToOneColumn(writer, className, columnType, fieldInfo, inputAttr, type, isArray);
                }
                else if (type.IsSubclassOf(typeof(ManyToOneColumn)))
                {
                    columnType = GenerateManyToOneColumn(writer, className, columnType, fieldInfo, inputAttr, type, isArray);
                }
            }
        }
Example #3
0
        public static bool IsComponent(Type inputType)
        {
            if (inputType.IsArray && Var <int> .CheckType(inputType.GetElementType()))
            {
                return(false);
            }

            if (inputType.IsGenericType && inputType.GetGenericTypeDefinition() == typeof(Dictionary <,>) &&
                inputType.GetGenericTypeArgumentsEx()[0] == typeof(string))
            {
                return(false);
            }

            if (Var <int> .CheckType(inputType))
            {
                return(false);
            }

            var type     = ExtractOptionalOrNullableType(inputType);
            var typeEnum = TlcModule.GetDataType(type);

            return(typeEnum == TlcModule.DataKind.Component);
        }
Example #4
0
        private static object ParseJsonValue(IExceptionContext ectx, Type type, Attributes attributes, JToken value, ComponentCatalog catalog)
        {
            Contracts.AssertValue(ectx);
            ectx.AssertValue(type);
            ectx.AssertValueOrNull(value);
            ectx.AssertValue(catalog);

            if (value == null)
            {
                return(null);
            }

            if (value is JValue val && val.Value == null)
            {
                return(null);
            }

            if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Optional <>) || type.GetGenericTypeDefinition() == typeof(Nullable <>)))
            {
                if (type.GetGenericTypeDefinition() == typeof(Optional <>) && value.HasValues)
                {
                    value = value.Values().FirstOrDefault();
                }
                type = type.GetGenericArguments()[0];
            }

            if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Var <>)))
            {
                string varName = value.Value <string>();
                ectx.Check(VariableBinding.IsBindingToken(value), "Variable name expected.");
                var variable   = Activator.CreateInstance(type) as IVarSerializationHelper;
                var varBinding = VariableBinding.Create(ectx, varName);
                variable.VarName = varBinding.VariableName;
                return(variable);
            }

            if (type == typeof(JArray) && value is JArray)
            {
                return(value);
            }

            TlcModule.DataKind dt = TlcModule.GetDataType(type);

            try
            {
                switch (dt)
                {
                case TlcModule.DataKind.Bool:
                    return(value.Value <bool>());

                case TlcModule.DataKind.String:
                    return(value.Value <string>());

                case TlcModule.DataKind.Char:
                    return(value.Value <char>());

                case TlcModule.DataKind.Enum:
                    if (!Enum.IsDefined(type, value.Value <string>()))
                    {
                        throw ectx.Except($"Requested value '{value.Value<string>()}' is not a member of the Enum type '{type.Name}'");
                    }
                    return(Enum.Parse(type, value.Value <string>()));

                case TlcModule.DataKind.Float:
                    if (type == typeof(double))
                    {
                        return(value.Value <double>());
                    }
                    else if (type == typeof(float))
                    {
                        return(value.Value <float>());
                    }
                    else
                    {
                        ectx.Assert(false);
                        throw ectx.ExceptNotSupp();
                    }

                case TlcModule.DataKind.Array:
                    var ja = value as JArray;
                    ectx.Check(ja != null, "Expected array value");
                    Func <IExceptionContext, JArray, Attributes, ComponentCatalog, object> makeArray = MakeArray <int>;
                    return(Utils.MarshalInvoke(makeArray, type.GetElementType(), ectx, ja, attributes, catalog));

                case TlcModule.DataKind.Int:
                    if (type == typeof(long))
                    {
                        return(value.Value <long>());
                    }
                    if (type == typeof(int))
                    {
                        return(value.Value <int>());
                    }
                    ectx.Assert(false);
                    throw ectx.ExceptNotSupp();

                case TlcModule.DataKind.UInt:
                    if (type == typeof(ulong))
                    {
                        return(value.Value <ulong>());
                    }
                    if (type == typeof(uint))
                    {
                        return(value.Value <uint>());
                    }
                    ectx.Assert(false);
                    throw ectx.ExceptNotSupp();

                case TlcModule.DataKind.Dictionary:
                    ectx.Check(value is JObject, "Expected object value");
                    Func <IExceptionContext, JObject, Attributes, ComponentCatalog, object> makeDict = MakeDictionary <int>;
                    return(Utils.MarshalInvoke(makeDict, type.GetGenericArguments()[1], ectx, (JObject)value, attributes, catalog));

                case TlcModule.DataKind.Component:
                    var jo = value as JObject;
                    ectx.Check(jo != null, "Expected object value");
                    // REVIEW: consider accepting strings alone.
                    var jName = jo[FieldNames.Name];
                    ectx.Check(jName != null, "Field '" + FieldNames.Name + "' is required for component.");
                    ectx.Check(jName is JValue, "Expected '" + FieldNames.Name + "' field to be a string.");
                    var name = jName.Value <string>();
                    ectx.Check(jo[FieldNames.Settings] == null || jo[FieldNames.Settings] is JObject,
                               "Expected '" + FieldNames.Settings + "' field to be an object");
                    return(GetComponentJson(ectx, type, name, jo[FieldNames.Settings] as JObject, catalog));

                default:
                    var settings = value as JObject;
                    ectx.Check(settings != null, "Expected object value");
                    var inputBuilder = new InputBuilder(ectx, type, catalog);

                    if (inputBuilder._fields.Length == 0)
                    {
                        throw ectx.Except($"Unsupported input type: {dt}");
                    }

                    if (settings != null)
                    {
                        foreach (var pair in settings)
                        {
                            if (!inputBuilder.TrySetValueJson(pair.Key, pair.Value))
                            {
                                throw ectx.Except($"Unexpected value for component '{type}', field '{pair.Key}': '{pair.Value}'");
                            }
                        }
                    }

                    var missing = inputBuilder.GetMissingValues().ToArray();
                    if (missing.Length > 0)
                    {
                        throw ectx.Except($"The following required inputs were not provided for component '{type}': {string.Join(", ", missing)}");
                    }
                    return(inputBuilder.GetInstance());
                }
            }
            catch (FormatException ex)
            {
                if (ex.IsMarked())
                {
                    throw;
                }
                throw ectx.Except(ex, $"Failed to parse JSON value '{value}' as {type}");
            }
        }
Example #5
0
        private void GenerateClasses(IndentingTextWriter writer, Type inputType, ModuleCatalog catalog, string currentNamespace)
        {
            foreach (var fieldInfo in inputType.GetFields())
            {
                var inputAttr = fieldInfo.GetCustomAttributes(typeof(ArgumentAttribute), false).FirstOrDefault() as ArgumentAttribute;
                if (inputAttr == null || inputAttr.Visibility == ArgumentAttribute.VisibilityType.CmdLineOnly)
                {
                    continue;
                }

                var type = fieldInfo.FieldType;
                type = CSharpGeneratorUtils.ExtractOptionalOrNullableType(type);
                if (type.IsArray)
                {
                    type = type.GetElementType();
                }
                if (type == typeof(JArray) || type == typeof(JObject))
                {
                    continue;
                }
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Var <>))
                {
                    continue;
                }
                if (type == typeof(CommonInputs.IEvaluatorInput))
                {
                    continue;
                }
                if (type == typeof(CommonOutputs.IEvaluatorOutput))
                {
                    continue;
                }
                var typeEnum = TlcModule.GetDataType(type);
                if (typeEnum == TlcModule.DataKind.State)
                {
                    continue;
                }
                if (typeEnum != TlcModule.DataKind.Unknown)
                {
                    continue;
                }

                if (_generatedClasses.IsGenerated(type.FullName))
                {
                    continue;
                }
                GenerateEnums(writer, type, currentNamespace);
                GenerateClasses(writer, type, catalog, currentNamespace);

                var    apiName   = _generatedClasses.GetApiName(type, currentNamespace);
                string classBase = "";
                if (type.IsSubclassOf(typeof(OneToOneColumn)))
                {
                    classBase = $" : OneToOneColumn<{apiName}>, IOneToOneColumn";
                }
                else if (type.IsSubclassOf(typeof(ManyToOneColumn)))
                {
                    classBase = $" : ManyToOneColumn<{apiName}>, IManyToOneColumn";
                }
                writer.WriteLine($"public sealed partial class {apiName}{classBase}");
                writer.WriteLine("{");
                writer.Indent();
                _generatedClasses.MarkAsGenerated(type.FullName);
                GenerateInputFields(writer, type, catalog, currentNamespace);
                writer.Outdent();
                writer.WriteLine("}");
                writer.WriteLine();
            }
        }
Example #6
0
        private void GenerateEnums(IndentingTextWriter writer, Type inputType, string currentNamespace)
        {
            foreach (var fieldInfo in inputType.GetFields())
            {
                var inputAttr = fieldInfo.GetCustomAttributes(typeof(ArgumentAttribute), false).FirstOrDefault() as ArgumentAttribute;
                if (inputAttr == null || inputAttr.Visibility == ArgumentAttribute.VisibilityType.CmdLineOnly)
                {
                    continue;
                }
                var type = CSharpGeneratorUtils.ExtractOptionalOrNullableType(fieldInfo.FieldType);
                if (_generatedClasses.IsGenerated(type.FullName))
                {
                    continue;
                }

                if (!type.IsEnum)
                {
                    var typeEnum = TlcModule.GetDataType(type);
                    if (typeEnum == TlcModule.DataKind.Unknown)
                    {
                        GenerateEnums(writer, type, currentNamespace);
                    }
                    continue;
                }

                var enumType = Enum.GetUnderlyingType(type);

                var apiName = _generatedClasses.GetApiName(type, currentNamespace);
                if (enumType == typeof(int))
                {
                    writer.WriteLine($"public enum {apiName}");
                }
                else
                {
                    Contracts.Assert(enumType == typeof(byte));
                    writer.WriteLine($"public enum {apiName} : byte");
                }

                _generatedClasses.MarkAsGenerated(type.FullName);
                writer.Write("{");
                writer.Indent();
                var    names  = Enum.GetNames(type);
                var    values = Enum.GetValues(type);
                string prefix = "";
                for (int i = 0; i < names.Length; i++)
                {
                    var name = names[i];
                    if (type.GetField(name).GetCustomAttribute <HideEnumValueAttribute>() != null)
                    {
                        continue;
                    }
                    var value = values.GetValue(i);
                    writer.WriteLine(prefix);
                    if (enumType == typeof(int))
                    {
                        writer.Write($"{name} = {(int)value}");
                    }
                    else
                    {
                        Contracts.Assert(enumType == typeof(byte));
                        writer.Write($"{name} = {(byte)value}");
                    }
                    prefix = ",";
                }
                writer.WriteLine();
                writer.Outdent();
                writer.WriteLine("}");
                writer.WriteLine();
            }
        }
Example #7
0
        private static JToken BuildValueToken(IExceptionContext ectx, object value, Type valueType, ModuleCatalog catalog)
        {
            Contracts.AssertValueOrNull(ectx);
            ectx.AssertValueOrNull(value);
            ectx.AssertValue(valueType);
            ectx.AssertValue(catalog);

            if (value == null)
            {
                return(null);
            }

            // Dive inside Nullable.
            if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                valueType = valueType.GetGenericArguments()[0];
            }

            // Dive inside Optional.
            if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Optional <>))
            {
                valueType = valueType.GetGenericArguments()[0];
                value     = ((Optional)value).GetValue();
            }

            var dataType = TlcModule.GetDataType(valueType);

            switch (dataType)
            {
            case TlcModule.DataKind.Bool:
            case TlcModule.DataKind.Int:
            case TlcModule.DataKind.UInt:
            case TlcModule.DataKind.Float:
            case TlcModule.DataKind.String:
                return(new JValue(value));

            case TlcModule.DataKind.Char:
                return(new JValue(value.ToString()));

            case TlcModule.DataKind.Array:
                var valArray = value as Array;
                var ja       = new JArray();
                foreach (var item in valArray)
                {
                    ja.Add(BuildValueToken(ectx, item, item.GetType(), catalog));
                }
                return(ja);

            case TlcModule.DataKind.Enum:
                return(value.ToString());

            case TlcModule.DataKind.Dictionary:
                // REVIEW: need to figure out how to represent these.
                throw ectx.ExceptNotSupp("Dictionary and component default values are not supported");

            case TlcModule.DataKind.Component:
                var factory = value as IComponentFactory;
                ectx.AssertValue(factory);
                return(BuildComponentToken(ectx, factory, catalog));

            default:
                throw ectx.ExceptNotSupp("Encountered a default value for unsupported type {0}", dataType);
            }
        }
Example #8
0
        private static JToken BuildTypeToken(IExceptionContext ectx, FieldInfo fieldInfo, Type type, ModuleCatalog catalog)
        {
            Contracts.AssertValueOrNull(ectx);
            ectx.AssertValue(type);
            ectx.AssertValue(catalog);

            // REVIEW: Allows newly introduced types to not break the manifest bulding process.
            // Where possible, these types should be replaced by component kinds.
            if (type == typeof(CommonInputs.IEvaluatorInput) ||
                type == typeof(CommonOutputs.IEvaluatorOutput))
            {
                var jo         = new JObject();
                var typeString = $"{type}".Replace("Microsoft.ML.Runtime.EntryPoints.", "");
                jo[FieldNames.Kind]     = "EntryPoint";
                jo[FieldNames.ItemType] = typeString;
                return(jo);
            }
            type = CSharpGeneratorUtils.ExtractOptionalOrNullableType(type);

            // Dive inside Var.
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Var <>))
            {
                type = type.GetGenericArguments()[0];
            }

            var typeEnum = TlcModule.GetDataType(type);

            switch (typeEnum)
            {
            case TlcModule.DataKind.Unknown:
                var jo = new JObject();
                if (type == typeof(JArray))
                {
                    jo[FieldNames.Kind]     = TlcModule.DataKind.Array.ToString();
                    jo[FieldNames.ItemType] = "Node";
                    return(jo);
                }
                if (type == typeof(JObject))
                {
                    return("Bindings");
                }
                var fields = BuildInputManifest(ectx, type, catalog);
                if (fields.Count == 0)
                {
                    throw ectx.Except("Unexpected parameter type: {0}", type);
                }
                jo[FieldNames.Kind]   = "Struct";
                jo[FieldNames.Fields] = fields;
                return(jo);

            case TlcModule.DataKind.Float:
            case TlcModule.DataKind.Int:
            case TlcModule.DataKind.UInt:
            case TlcModule.DataKind.Char:
            case TlcModule.DataKind.String:
            case TlcModule.DataKind.Bool:
            case TlcModule.DataKind.DataView:
            case TlcModule.DataKind.TransformModel:
            case TlcModule.DataKind.PredictorModel:
            case TlcModule.DataKind.FileHandle:
                return(typeEnum.ToString());

            case TlcModule.DataKind.Enum:
                jo = new JObject();
                jo[FieldNames.Kind] = typeEnum.ToString();
                var values = Enum.GetNames(type);
                jo[FieldNames.Values] = new JArray(values);
                return(jo);

            case TlcModule.DataKind.Array:
                jo = new JObject();
                jo[FieldNames.Kind]     = typeEnum.ToString();
                jo[FieldNames.ItemType] = BuildTypeToken(ectx, fieldInfo, type.GetElementType(), catalog);
                return(jo);

            case TlcModule.DataKind.Dictionary:
                jo = new JObject();
                jo[FieldNames.Kind]     = typeEnum.ToString();
                jo[FieldNames.ItemType] = BuildTypeToken(ectx, fieldInfo, type.GetGenericArguments()[1], catalog);
                return(jo);

            case TlcModule.DataKind.Component:
                string kind;
                if (!catalog.TryGetComponentKind(type, out kind))
                {
                    throw ectx.Except("Field '{0}' is a component of unknown kind", fieldInfo.Name);
                }

                jo = new JObject();
                jo[FieldNames.Kind]          = typeEnum.ToString();
                jo[FieldNames.ComponentKind] = kind;
                return(jo);

            case TlcModule.DataKind.State:
                jo = new JObject();
                var typeString = $"{type}".Replace("Microsoft.ML.Runtime.Interfaces.", "");
                jo[FieldNames.Kind]     = "C# Object";
                jo[FieldNames.ItemType] = typeString;
                return(jo);

            default:
                ectx.Assert(false);
                throw ectx.ExceptNotSupp();
            }
        }
Example #9
0
        /// <summary>
        /// Builds a JSON representation of all entry points and components of the <paramref name="catalog"/>.
        /// </summary>
        /// <param name="ectx">The exception context to use</param>
        /// <param name="catalog">The module catalog</param>
        public static JObject BuildAllManifests(IExceptionContext ectx, ModuleCatalog catalog)
        {
            Contracts.CheckValueOrNull(ectx);
            ectx.CheckValue(catalog, nameof(catalog));

            var jEntryPoints    = new JArray();
            var entryPointInfos = catalog.AllEntryPoints().ToArray();

            foreach (var entryPointInfo in entryPointInfos.OrderBy(x => x.Name))
            {
                jEntryPoints.Add(BuildEntryPointManifest(ectx, entryPointInfo, catalog));
            }

            var jKinds = new JArray();

            foreach (var kind in catalog.GetAllComponentKinds())
            {
                var jKind = new JObject();
                jKind[FieldNames.Kind] = kind;
                var jComponents = new JArray();
                foreach (var component in catalog.GetAllComponents(kind))
                {
                    jComponents.Add(BuildComponentManifest(ectx, component, catalog));
                }

                jKind[FieldNames.Components] = jComponents;

                jKinds.Add(jKind);
            }

            var jepKinds = new JArray();
            var kinds    = new List <Type>();

            foreach (var entryPointInfo in entryPointInfos)
            {
                if (entryPointInfo.InputKinds != null)
                {
                    kinds.AddRange(entryPointInfo.InputKinds);
                }
                if (entryPointInfo.OutputKinds != null)
                {
                    kinds.AddRange(entryPointInfo.OutputKinds);
                }
            }

            foreach (var epKind in kinds.Distinct().OrderBy(k => k.Name))
            {
                var jepKind = new JObject();
                jepKind[FieldNames.Kind] = epKind.Name;
                var jepKindFields = new JArray();
                var propertyInfos = epKind.GetProperties().AsEnumerable();
                propertyInfos = epKind.GetInterfaces().Aggregate(propertyInfos, (current, face) => current.Union(face.GetProperties()));
                foreach (var fieldInfo in propertyInfos)
                {
                    var jField = new JObject();
                    jField[FieldNames.Name] = fieldInfo.Name;
                    var type = CSharpGeneratorUtils.ExtractOptionalOrNullableType(fieldInfo.PropertyType);
                    // Dive inside Var.
                    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Var <>))
                    {
                        type = type.GetGenericArguments()[0];
                    }
                    var typeEnum = TlcModule.GetDataType(type);
                    jField[FieldNames.Type] = typeEnum.ToString();
                    jepKindFields.Add(jField);
                }
                jepKind[FieldNames.Settings] = jepKindFields;
                jepKinds.Add(jepKind);
            }

            var jResult = new JObject();

            jResult[FieldNames.TopEntryPoints]     = jEntryPoints;
            jResult[FieldNames.TopComponents]      = jKinds;
            jResult[FieldNames.TopEntryPointKinds] = jepKinds;
            return(jResult);
        }
Example #10
0
        private static JArray BuildInputManifest(IExceptionContext ectx, Type inputType, ModuleCatalog catalog)
        {
            Contracts.AssertValueOrNull(ectx);
            ectx.AssertValue(inputType);
            ectx.AssertValue(catalog);

            // Instantiate a value of the input, to pull defaults out of.
            var defaults = Activator.CreateInstance(inputType);

            var inputs = new List <KeyValuePair <Double, JObject> >();

            foreach (var fieldInfo in inputType.GetFields())
            {
                var inputAttr = fieldInfo.GetCustomAttributes(typeof(ArgumentAttribute), false).FirstOrDefault() as ArgumentAttribute;
                if (inputAttr == null || inputAttr.Visibility == ArgumentAttribute.VisibilityType.CmdLineOnly)
                {
                    continue;
                }
                var jo = new JObject();
                jo[FieldNames.Name] = inputAttr.Name ?? fieldInfo.Name;
                jo[FieldNames.Type] = BuildTypeToken(ectx, fieldInfo, fieldInfo.FieldType, catalog);
                jo[FieldNames.Desc] = inputAttr.HelpText;
                if (inputAttr.Aliases != null)
                {
                    jo[FieldNames.Aliases] = new JArray(inputAttr.Aliases);
                }

                jo[FieldNames.Required]   = inputAttr.IsRequired;
                jo[FieldNames.SortOrder]  = inputAttr.SortOrder;
                jo[FieldNames.IsNullable] = fieldInfo.FieldType.IsGenericType && (fieldInfo.FieldType.GetGenericTypeDefinition() == typeof(Nullable <>));

                var defaultValue = fieldInfo.GetValue(defaults);
                var dataType     = TlcModule.GetDataType(fieldInfo.FieldType);
                if (!inputAttr.IsRequired || (dataType != TlcModule.DataKind.Unknown && defaultValue != null))
                {
                    jo[FieldNames.Default] = BuildValueToken(ectx, defaultValue, fieldInfo.FieldType, catalog);
                }

                if (fieldInfo.FieldType.IsGenericType &&
                    fieldInfo.FieldType.GetGenericTypeDefinition() == typeof(Optional <>))
                {
                    var val = fieldInfo.GetValue(defaults) as Optional;
                    if (val == null && !inputAttr.IsRequired)
                    {
                        throw ectx.Except("Field '{0}' is an Optional<> type but is null by default, instead of set to a constructed implicit default.", fieldInfo.Name);
                    }
                    if (val != null && val.IsExplicit)
                    {
                        throw ectx.Except("Field '{0}' is an Optional<> type with a non-implicit default value.", fieldInfo.Name);
                    }
                }

                var rangeAttr = fieldInfo.GetCustomAttributes(typeof(TlcModule.RangeAttribute), false).FirstOrDefault() as TlcModule.RangeAttribute;
                if (rangeAttr != null)
                {
                    if (!TlcModule.IsNumericKind(TlcModule.GetDataType(fieldInfo.FieldType)))
                    {
                        throw ectx.Except("Field '{0}' has a range but is of a non-numeric type.", fieldInfo.Name);
                    }

                    if (!rangeAttr.Type.Equals(fieldInfo.FieldType))
                    {
                        throw ectx.Except("Field '{0}' has a range attribute that uses a type which is not equal to the field's FieldType.", fieldInfo.Name);
                    }

                    var jRange = new JObject();
                    if (rangeAttr.Sup != null)
                    {
                        jRange[FieldNames.Range.Sup] = JToken.FromObject(rangeAttr.Sup);
                    }
                    if (rangeAttr.Inf != null)
                    {
                        jRange[FieldNames.Range.Inf] = JToken.FromObject(rangeAttr.Inf);
                    }
                    if (rangeAttr.Max != null)
                    {
                        jRange[FieldNames.Range.Max] = JToken.FromObject(rangeAttr.Max);
                    }
                    if (rangeAttr.Min != null)
                    {
                        jRange[FieldNames.Range.Min] = JToken.FromObject(rangeAttr.Min);
                    }
                    jo[FieldNames.Range.Type] = jRange;
                }

                // Handle deprecated/obsolete attributes, passing along the message to the manifest.
                if (fieldInfo.GetCustomAttributes(typeof(ObsoleteAttribute), false).FirstOrDefault() is ObsoleteAttribute obsAttr)
                {
                    var jParam = new JObject
                    {
                        [FieldNames.Deprecated.Message] = JToken.FromObject(obsAttr.Message),
                    };
                    jo[FieldNames.Deprecated.ToString()] = jParam;
                }

                if (fieldInfo.GetCustomAttributes(typeof(TlcModule.SweepableLongParamAttribute), false).FirstOrDefault() is TlcModule.SweepableLongParamAttribute slpAttr)
                {
                    var jParam = new JObject
                    {
                        [FieldNames.SweepableLongParam.RangeType] = JToken.FromObject("Long"),
                        [FieldNames.SweepableLongParam.Min]       = JToken.FromObject(slpAttr.Min),
                        [FieldNames.SweepableLongParam.Max]       = JToken.FromObject(slpAttr.Max)
                    };
                    if (slpAttr.StepSize != null)
                    {
                        jParam[FieldNames.SweepableLongParam.StepSize] = JToken.FromObject(slpAttr.StepSize);
                    }
                    if (slpAttr.NumSteps != null)
                    {
                        jParam[FieldNames.SweepableLongParam.NumSteps] = JToken.FromObject(slpAttr.NumSteps);
                    }
                    if (slpAttr.IsLogScale)
                    {
                        jParam[FieldNames.SweepableLongParam.IsLogScale] = JToken.FromObject(true);
                    }
                    jo[FieldNames.SweepableLongParam.ToString()] = jParam;
                }

                if (fieldInfo.GetCustomAttributes(typeof(TlcModule.SweepableFloatParamAttribute), false).FirstOrDefault() is TlcModule.SweepableFloatParamAttribute sfpAttr)
                {
                    var jParam = new JObject
                    {
                        [FieldNames.SweepableFloatParam.RangeType] = JToken.FromObject("Float"),
                        [FieldNames.SweepableFloatParam.Min]       = JToken.FromObject(sfpAttr.Min),
                        [FieldNames.SweepableFloatParam.Max]       = JToken.FromObject(sfpAttr.Max)
                    };
                    if (sfpAttr.StepSize != null)
                    {
                        jParam[FieldNames.SweepableFloatParam.StepSize] = JToken.FromObject(sfpAttr.StepSize);
                    }
                    if (sfpAttr.NumSteps != null)
                    {
                        jParam[FieldNames.SweepableFloatParam.NumSteps] = JToken.FromObject(sfpAttr.NumSteps);
                    }
                    if (sfpAttr.IsLogScale)
                    {
                        jParam[FieldNames.SweepableFloatParam.IsLogScale] = JToken.FromObject(true);
                    }
                    jo[FieldNames.SweepableFloatParam.ToString()] = jParam;
                }

                if (fieldInfo.GetCustomAttributes(typeof(TlcModule.SweepableDiscreteParamAttribute), false).FirstOrDefault() is TlcModule.SweepableDiscreteParamAttribute sdpAttr)
                {
                    var jParam = new JObject
                    {
                        [FieldNames.SweepableDiscreteParam.RangeType] = JToken.FromObject("Discrete"),
                        [FieldNames.SweepableDiscreteParam.Options]   = JToken.FromObject(sdpAttr.Options)
                    };
                    jo[FieldNames.SweepableDiscreteParam.ToString()] = jParam;
                }

                inputs.Add(new KeyValuePair <Double, JObject>(inputAttr.SortOrder, jo));
            }
            return(new JArray(inputs.OrderBy(x => x.Key).Select(x => x.Value).ToArray()));
        }
Example #11
0
        public static string GetInputType(ComponentCatalog catalog, Type inputType, GeneratedClasses generatedClasses, string rootNameSpace)
        {
            if (inputType.IsGenericType && inputType.GetGenericTypeDefinition() == typeof(Var <>))
            {
                return($"Var<{GetCSharpTypeName(inputType.GetGenericTypeArgumentsEx()[0])}>");
            }

            if (inputType.IsArray && Var <int> .CheckType(inputType.GetElementType()))
            {
                return($"ArrayVar<{GetCSharpTypeName(inputType.GetElementType())}>");
            }

            if (inputType.IsGenericType && inputType.GetGenericTypeDefinition() == typeof(Dictionary <,>) &&
                inputType.GetGenericTypeArgumentsEx()[0] == typeof(string))
            {
                return($"DictionaryVar<{GetCSharpTypeName(inputType.GetGenericTypeArgumentsEx()[1])}>");
            }

            if (Var <int> .CheckType(inputType))
            {
                return($"Var<{GetCSharpTypeName(inputType)}>");
            }

            var type     = ExtractOptionalOrNullableType(inputType, out bool isNullable, out bool isOptional);
            var typeEnum = TlcModule.GetDataType(type);

            switch (typeEnum)
            {
            case TlcModule.DataKind.Float:
            case TlcModule.DataKind.Int:
            case TlcModule.DataKind.UInt:
            case TlcModule.DataKind.Char:
            case TlcModule.DataKind.String:
            case TlcModule.DataKind.Bool:
            case TlcModule.DataKind.DataView:
            case TlcModule.DataKind.TransformModel:
            case TlcModule.DataKind.PredictorModel:
            case TlcModule.DataKind.FileHandle:
                return(GetCSharpTypeName(inputType));

            case TlcModule.DataKind.Array:
                return(GetInputType(catalog, inputType.GetElementType(), generatedClasses, rootNameSpace) + "[]");

            case TlcModule.DataKind.Component:
                string kind;
                bool   success = catalog.TryGetComponentKind(type, out kind);
                Contracts.Assert(success);
                return($"{kind}");

            case TlcModule.DataKind.Enum:
                var enumName = generatedClasses.GetApiName(type, rootNameSpace);
                if (isNullable)
                {
                    return($"{enumName}?");
                }
                if (isOptional)
                {
                    return($"Optional<{enumName}>");
                }
                return($"{enumName}");

            default:
                if (isNullable)
                {
                    return(generatedClasses.GetApiName(type, rootNameSpace) + "?");
                }
                if (isOptional)
                {
                    return($"Optional<{generatedClasses.GetApiName(type, rootNameSpace)}>");
                }
                return(generatedClasses.GetApiName(type, rootNameSpace));
            }
        }
Example #12
0
        public static string GetValue(ComponentCatalog catalog, Type fieldType, object fieldValue,
                                      GeneratedClasses generatedClasses, string rootNameSpace)
        {
            if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Var <>))
            {
                return($"new Var<{GetCSharpTypeName(fieldType.GetGenericTypeArgumentsEx()[0])}>()");
            }

            if (fieldType.IsArray && Var <int> .CheckType(fieldType.GetElementType()))
            {
                return($"new ArrayVar<{GetCSharpTypeName(fieldType.GetElementType())}>()");
            }

            if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Dictionary <,>) &&
                fieldType.GetGenericTypeArgumentsEx()[0] == typeof(string))
            {
                return($"new DictionaryVar<{GetCSharpTypeName(fieldType.GetGenericTypeArgumentsEx()[1])}>()");
            }

            if (Var <int> .CheckType(fieldType))
            {
                return($"new Var<{GetCSharpTypeName(fieldType)}>()");
            }

            if (fieldValue == null)
            {
                return(null);
            }

            if (!fieldType.IsInterface)
            {
                try
                {
                    var defaultFieldValue = Activator.CreateInstance(fieldType);
                    if (defaultFieldValue == fieldValue)
                    {
                        return(null);
                    }
                }
                catch (MissingMethodException)
                {
                    // No parameterless constructor, ignore.
                }
            }

            var typeEnum = TlcModule.GetDataType(fieldType);

            fieldType = ExtractOptionalOrNullableType(fieldType, out bool isNullable, out bool isOptional);
            switch (typeEnum)
            {
            case TlcModule.DataKind.Array:
                var arr = fieldValue as Array;
                if (arr != null && arr.GetLength(0) > 0)
                {
                    return($"{{ {string.Join(", ", arr.Cast<object>().Select(item => GetValue(catalog, fieldType.GetElementType(), item, generatedClasses, rootNameSpace)))} }}");
                }
                return(null);

            case TlcModule.DataKind.String:
                var strval = fieldValue as string;
                if (strval != null)
                {
                    return(Quote(strval));
                }
                return(null);

            case TlcModule.DataKind.Float:
                if (fieldValue is double d)
                {
                    if (double.IsPositiveInfinity(d))
                    {
                        return("double.PositiveInfinity");
                    }
                    if (double.IsNegativeInfinity(d))
                    {
                        return("double.NegativeInfinity");
                    }
                    if (d != 0)
                    {
                        return(d.ToString("R") + "d");
                    }
                }
                else if (fieldValue is float f)
                {
                    if (float.IsPositiveInfinity(f))
                    {
                        return("float.PositiveInfinity");
                    }
                    if (float.IsNegativeInfinity(f))
                    {
                        return("float.NegativeInfinity");
                    }
                    if (f != 0)
                    {
                        return(f.ToString("R") + "f");
                    }
                }
                return(null);

            case TlcModule.DataKind.Int:
                if (fieldValue is int i)
                {
                    if (i != 0)
                    {
                        return(i.ToString());
                    }
                }
                else if (fieldValue is long l)
                {
                    if (l != 0)
                    {
                        return(l.ToString());
                    }
                }
                return(null);

            case TlcModule.DataKind.Bool:
                return((bool)fieldValue ? "true" : "false");

            case TlcModule.DataKind.Enum:
                string enumAsString = fieldValue.ToString();
                if (fieldType.GetField(enumAsString).GetCustomAttribute <HideEnumValueAttribute>() != null)
                {
                    // The default value for the enum has the hiding attribute on it. We will search for
                    // alternate names. Regrettably I see no way beyond a manual scan.

                    string unhiddenName = Enum.GetNames(fieldType).Zip(Enum.GetValues(fieldType).Cast <object>(), (name, val) => (name, val))
                                          .Where(pair => pair.val.Equals(fieldValue))
                                          .Where(pair => fieldType.GetField(pair.name).GetCustomAttribute <HideEnumValueAttribute>() == null)
                                          .Select(pair => pair.name).FirstOrDefault();
                    enumAsString = unhiddenName ?? throw Contracts.Except($"Could not find unhidden alternative for '{fieldValue}' in type '{fieldType}'");
                }
                if (generatedClasses.IsGenerated(fieldType.FullName))
                {
                    return(generatedClasses.GetApiName(fieldType, rootNameSpace) + "." + enumAsString);
                }
                else
                {
                    return(generatedClasses.GetApiName(fieldType, "Runtime") + "." + enumAsString);
                }

            case TlcModule.DataKind.Char:
                return($"'{GetCharAsString((char)fieldValue)}'");

            case TlcModule.DataKind.Component:
                var type = fieldValue.GetType();
                ComponentCatalog.ComponentInfo componentInfo;
                if (!catalog.TryFindComponent(fieldType, type, out componentInfo))
                {
                    return(null);
                }
                object defaultComponent = null;
                try
                {
                    defaultComponent = Activator.CreateInstance(componentInfo.ArgumentType);
                }
                catch (MissingMethodException)
                {
                    // No parameterless constructor, ignore.
                }
                var propertyBag = new List <string>();
                if (defaultComponent != null)
                {
                    foreach (var fieldInfo in componentInfo.ArgumentType.GetFields())
                    {
                        var inputAttr = fieldInfo.GetCustomAttributes(typeof(ArgumentAttribute), false).FirstOrDefault() as ArgumentAttribute;
                        if (inputAttr == null || inputAttr.Visibility == ArgumentAttribute.VisibilityType.CmdLineOnly)
                        {
                            continue;
                        }
                        if (fieldInfo.FieldType == typeof(JArray) || fieldInfo.FieldType == typeof(JObject))
                        {
                            continue;
                        }

                        var propertyValue        = GetValue(catalog, fieldInfo.FieldType, fieldInfo.GetValue(fieldValue), generatedClasses, rootNameSpace);
                        var defaultPropertyValue = GetValue(catalog, fieldInfo.FieldType, fieldInfo.GetValue(defaultComponent), generatedClasses, rootNameSpace);
                        if (propertyValue != defaultPropertyValue)
                        {
                            propertyBag.Add($"{Capitalize(inputAttr.Name ?? fieldInfo.Name)} = {propertyValue}");
                        }
                    }
                }
                var properties = propertyBag.Count > 0 ? $" {{ {string.Join(", ", propertyBag)} }}" : "";
                return($"new {GetComponentName(componentInfo)}(){properties}");

            case TlcModule.DataKind.Unknown:
                return($"new {generatedClasses.GetApiName(fieldType, rootNameSpace)}()");

            default:
                return(fieldValue.ToString());
            }
        }