Пример #1
0
        public static DocNode CombineDict(List <DocNode> docs)
        {
            var sb = new System.Text.StringBuilder("Combination of: [");

            for (int i = 0; i < docs.Count; i++)
            {
                if (i > 0)
                {
                    sb.Append(", ");
                }
                sb.Append(docs[i].SourceInformation);
            }
            sb.Append("]");

            ComposedDocNode result = new ComposedDocNode(DocNodeType.Dictionary,
                                                         sourceInformation: sb.ToString());

            for (int i = 0; i < docs.Count; i++)
            {
                var doc = docs[i];
                foreach (var kv in doc.Pairs)
                {
                    result[kv.Key] = kv.Value;
                }
            }
            return(result);
        }
Пример #2
0
        public static DocNode CombineList(List <DocNode> docs)
        {
            var sb = new System.Text.StringBuilder("Combination of: [");

            for (int i = 0; i < docs.Count; i++)
            {
                if (i > 0)
                {
                    sb.Append(", ");
                }
                sb.Append(docs[i].SourceInformation);
            }
            sb.Append("]");

            ComposedDocNode result = new ComposedDocNode(DocNodeType.List,
                                                         sourceInformation: sb.ToString());

            for (int i = 0; i < docs.Count; i++)
            {
                if (docs[i].Type == DocNodeType.List)   // flatten file containing list
                {
                    for (int j = 0; j < docs[i].Count; j++)
                    {
                        result.Add(docs[i][j]);
                    }
                }
                else
                {
                    result.Add(docs[i]);
                }
            }
            return(result);
        }
Пример #3
0
        public static DocNode CombineDict(List <DocNode> docs)
        {
            ComposedDocNode result = new ComposedDocNode(DocNodeType.Dictionary);

            for (int i = 0; i < docs.Count; i++)
            {
                var doc = docs[i];
                foreach (var kv in doc.Pairs)
                {
                    result[kv.Key] = kv.Value;
                }
            }
            return(result);
        }
Пример #4
0
        /// combines hierarchies.
        /// lists are concatenated, but dicts are recursively DeepMerged.
        /// favours rhs on any conflict.
        public static DocNode DeepMerge(DocNode lhs, DocNode rhs)
        {
            if (lhs.Type != rhs.Type)
            {
                throw new ArgumentException("can not merge different types " + lhs.Type + " " + rhs.Type);
            }

            switch (lhs.Type)
            {
            case DocNodeType.List:
                return(Configs.CombineList(new List <DocNode> {
                    lhs, rhs
                }));

            case DocNodeType.Dictionary: {
                var mergedDict = new ComposedDocNode(DocNodeType.Dictionary,
                                                     sourceInformation: "Merging of: [" + lhs.SourceInformation + ", " + rhs.SourceInformation + "]");
                foreach (var lhsPair in lhs.Pairs)
                {
                    mergedDict[lhsPair.Key] = lhsPair.Value;
                }

                foreach (var rhsPair in rhs.Pairs)
                {
                    if (mergedDict.ContainsKey(rhsPair.Key))
                    {
                        mergedDict[rhsPair.Key] = DeepMerge(mergedDict[rhsPair.Key], rhsPair.Value);
                    }
                    else
                    {
                        mergedDict[rhsPair.Key] = rhsPair.Value;
                    }
                }

                return(mergedDict);
            }

            case DocNodeType.Scalar:
                return(rhs);

            default:
                throw new ArgumentException("can not merge doc nodes of type " + lhs.Type);
            }
        }
Пример #5
0
        // combines hierarchies.
        // lists are concatenated, but dicts are recursively DeepMerged.
        // favours second node on any conflict.
        public static DocNode DeepMerge(DocNode lhs, DocNode rhs)
        {
            if (lhs.Type != rhs.Type)
            {
                throw new ArgumentException("can not merge different types " + lhs.Type + " " + rhs.Type);
            }

            if (lhs.Type == DocNodeType.List)
            {
                return(Config.CombineList(new List <DocNode> {
                    lhs, rhs
                }));
            }
            else if (lhs.Type == DocNodeType.Dictionary)
            {
                var mergedDict = new ComposedDocNode(DocNodeType.Dictionary);
                foreach (var lhsPair in lhs.Pairs)
                {
                    mergedDict[lhsPair.Key] = lhsPair.Value;
                }
                foreach (var rhsPair in rhs.Pairs)
                {
                    if (mergedDict.ContainsKey(rhsPair.Key))
                    {
                        mergedDict[rhsPair.Key] = DeepMerge(mergedDict[rhsPair.Key], rhsPair.Value);
                    }
                    else
                    {
                        mergedDict[rhsPair.Key] = rhsPair.Value;
                    }
                }
                return(mergedDict);
            }
            else if (lhs.Type == DocNodeType.Scalar)
            {
                return(rhs);
            }
            else
            {
                throw new ArgumentException("can not merge doc nodes of type " + lhs.Type);
            }
        }
Пример #6
0
        public static DocNode CombineList(List <DocNode> docs)
        {
            ComposedDocNode result = new ComposedDocNode(DocNodeType.List);

            for (int i = 0; i < docs.Count; i++)
            {
                if (docs[i].Type == DocNodeType.List)   // flatten file containing list
                {
                    for (int j = 0; j < docs[i].Count; j++)
                    {
                        result.Add(docs[i][j]);
                    }
                }
                else
                {
                    result.Add(docs[i]);
                }
            }
            return(result);
        }
Пример #7
0
        static object ValueOfType(Type fieldType, object existing, DocNode value, ConfigOptions?options)
        {
            try {
                if (fieldType == typeof(System.Boolean))
                {
                    return(Convert.ToBoolean(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                // floating-point value types
                if (fieldType == typeof(System.Single))
                {
                    return(Convert.ToSingle(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Double))
                {
                    return(Convert.ToDouble(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Decimal))
                {
                    return(Convert.ToDecimal(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                // integral value types
                if (fieldType == typeof(System.SByte))
                {
                    return(Convert.ToSByte(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Byte))
                {
                    return(Convert.ToByte(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Char))
                {
                    return(Convert.ToChar(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Int16))
                {
                    return(Convert.ToInt16(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.UInt16))
                {
                    return(Convert.ToUInt16(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Int32))
                {
                    return(Convert.ToInt32(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.UInt32))
                {
                    return(Convert.ToUInt32(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.Int64))
                {
                    return(Convert.ToInt64(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(System.UInt64))
                {
                    return(Convert.ToUInt64(value.StringValue, System.Globalization.CultureInfo.InvariantCulture));
                }
                if (fieldType == typeof(string))
                {
                    return(value.StringValue);
                }
                if (fieldType.IsEnum)          // AudioRolloffMode, "Custom" => AudioRolloffMode.Custom
                {
                    return(Enum.Parse(fieldType, value.StringValue, true));
                }
                if (fieldType == typeof(DocNode))
                {
                    return(value);
                }
                if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    if (value.Type == DocNodeType.Scalar && value.StringValue == "null")
                    {
                        return(null);
                    }
                    var innerType = Nullable.GetUnderlyingType(fieldType);
                    return(ValueOfType(innerType, existing, value, options));
                }
                if (s_fromDocs.ContainsKey(fieldType))
                {
                    existing = s_fromDocs[fieldType](existing, value);
                    return(CallPostDoc(fieldType, existing));
                }
                if (fieldType.IsArray)                      // [1,2,3,4,5] => new int[] { 1,2,3,4,5 }
                {
                    Type arrTyp = fieldType.GetElementType();
                    if (fieldType.GetArrayRank() == 2)
                    {
                        var firstList = value[0];
                        var destArr   = Array.CreateInstance(arrTyp, firstList.Count, value.Count);
                        int j         = 0;
                        foreach (DocNode subList in value.Values)
                        {
                            int i = 0;
                            foreach (var val in subList.Values.Select(item => ValueOfType(arrTyp, null, item, options)))
                            {
                                destArr.SetValue(val, new int[] { i, j });
                                i++;
                            }
                            j++;
                        }
                        return(destArr);
                    }
                    else
                    {
                        var iexisting = (Array)existing;
                        if (iexisting == null)
                        {
                            iexisting = Array.CreateInstance(arrTyp, value.Count);
                        }
                        else if (iexisting.Length != value.Count)
                        {
                            var oldArr = iexisting;
                            iexisting = Array.CreateInstance(arrTyp, value.Count);
                            for (int i = 0; i < iexisting.Length && i < oldArr.Length; i++)
                            {
                                iexisting.SetValue(oldArr.GetValue(i), i);
                            }
                        }
                        for (int i = 0; i < iexisting.Length; i++)
                        {
                            var existingElt = iexisting.GetValue(i);
                            var updatedElt  = ValueOfType(arrTyp, existingElt, value[i], options);
                            iexisting.SetValue(updatedElt, i);
                        }
                        return(iexisting);
                    }
                }
                if (fieldType.IsGenericType)
                {
                    // this chunk of code handles generic dictionaries and lists; it only
                    // works with string keys on the dictionaries, and for now any values
                    // must have zero-args constructors
                    if (fieldType.GetGenericTypeDefinition() == typeof(Dictionary <,>))
                    {
                        Type[] typeParameters = fieldType.GetGenericArguments();

                        if (existing == null)
                        {
                            existing = Activator.CreateInstance(fieldType);
                        }
                        var              iexisting = (System.Collections.IDictionary)existing;
                        Type             kType     = typeParameters[0];
                        Type             vType     = typeParameters[1];
                        ComposedDocNode  keyNode   = new ComposedDocNode(DocNodeType.Scalar); // can reuse this one object
                        HashSet <object> usedKeys  = new HashSet <object>();

                        // create/update all pairs in the doc
                        foreach (var kv in value.Pairs)
                        {
                            keyNode.StringValue = kv.Key;
                            object existingKey   = ValueOfType(kType, null, keyNode, options);
                            object existingValue = null;
                            if (iexisting.Contains(existingKey))
                            {
                                existingValue = iexisting[existingKey];
                            }
                            var updated = ValueOfType(vType, existingValue, kv.Value, options);
                            iexisting[existingKey] = updated;
                            usedKeys.Add(existingKey);
                        }
                        // remove any pairs not in the doc
                        var keysToRemove = new List <object>();
                        foreach (var k in iexisting.Keys)
                        {
                            if (!usedKeys.Contains(k))
                            {
                                keysToRemove.Add(k);
                            }
                        }
                        foreach (var k in keysToRemove)
                        {
                            iexisting.Remove(k);
                        }
                        return(iexisting);
                    }
                    if (fieldType.GetGenericTypeDefinition() == typeof(List <>))
                    {
                        Type[] typeParameters = fieldType.GetGenericArguments();
                        if (existing == null)
                        {
                            existing = Activator.CreateInstance(fieldType);
                        }

                        var iexisting = (System.Collections.IList)existing;
                        while (iexisting.Count > value.Count)
                        {
                            iexisting.RemoveAt(iexisting.Count - 1);
                        }
                        for (int i = 0; i < iexisting.Count; i++)
                        {
                            var existingElt = iexisting[i];
                            var updatedElt  = ValueOfType(typeParameters[0], existingElt, value[i], options);
                            iexisting[i] = updatedElt;
                        }
                        while (iexisting.Count < value.Count)
                        {
                            var newElt = ValueOfType(typeParameters[0], null, value[iexisting.Count], options);
                            iexisting.Add(newElt);
                        }
                        return(existing);
                    }
                }
                var fromDocMethod = ReflectionCache.GetFromDoc(fieldType);
                if (fromDocMethod != null)   // if there's a custom parser method on the class, delegate all work to that
                // TODO: this doesn't do inherited FromDoc methods properly, but it should
                {
                    try {
                        existing = fromDocMethod.Invoke(null, new[] { existing, value });
                        return(CallPostDoc(fieldType, existing));
                    } catch (System.Reflection.TargetInvocationException e) {
                        throw e.InnerException;
                    }
                }
                if (fieldType.IsClass)
                {
                    if (existing == null)
                    {
                        existing = CreateInstance(fieldType, value, options);
                        return(CallPostDoc(fieldType, existing));
                    }
                    else
                    {
                        SetFieldsOnObject(fieldType, ref existing, value, DefaultedOptions(options));
                        return(CallPostDoc(fieldType, existing));
                    }
                }
                if (fieldType.IsValueType)
                {
                    // a struct; set the members and return it
                    if (existing == null)
                    {
                        // structs can be null when boxed
                        existing = CreateInstance(fieldType, value, options);
                        return(CallPostDoc(fieldType, existing));
                    }
                    else
                    {
                        SetFieldsOnObject(fieldType, ref existing, value, DefaultedOptions(options));
                        return(CallPostDoc(fieldType, existing));
                    }
                }
            } catch (Exception e) {
                throw new ParseException("Exception based on document starting at: " + value.SourceInformation, e);
            }

            throw new System.NotSupportedException("Don't know how to update value of type " + fieldType.ToString());
        }