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); }
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); }
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); }
/// 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); } }
// 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); } }
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); }
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()); }