internal static object GetNodeData(Node node, Type type) { if (node.Value == Utilities.NullIndicator) { return(null); } // Ensures that the type's static constructor has been run before we try to load it. // A convenient place to add base type rules is in the type's static constructor, so // this ensures the base type rules are registered before they are needed. System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle); if (type == typeof(string) && node.Value == MultiLineStringNode.Terminator && node.ChildNodeType == NodeChildrenType.multiLineString && node.ChildLines.Count > 0) { return(MultiLineStringSpecialCaseHandler.ParseSpecialStringCase(node)); } if (BaseTypesManager.IsBaseType(type)) { return(RetrieveDataWithErrorChecking(() => RetrieveBaseTypeNode(node, type))); } if (CollectionTypesManager.IsSupportedType(type)) { return(RetrieveDataWithErrorChecking(() => CollectionTypesManager.RetrieveCollection(node, type))); } if (!node.Value.IsNullOrEmpty()) { return(RetrieveDataWithErrorChecking(() => ComplexTypeShortcuts.GetFromShortcut(node.Value, type))); } return(RetrieveDataWithErrorChecking(() => ComplexTypes.RetrieveComplexType(node, type))); object RetrieveDataWithErrorChecking(Func <object> retrieveDataFunction) { try { return(retrieveDataFunction.Invoke()); } catch (CannotRetrieveDataFromNodeException deeperException) { // If there's a parsing error deeper in the tree, we want to throw *that* error, so the user gets a line // number appropriate to the actual error. throw deeperException; } catch { throw new CannotRetrieveDataFromNodeException(node, type); } } }
private static bool TryConstructorShortcut(string shortcut, Type type, out object result) { try { if (shortcut.StartsWith("(") && shortcut.EndsWith(")")) { string text = shortcut.Substring(1, shortcut.Length - 2); // remove the ( and ) var paramStrings = text.Split(','); var constructors = type.GetConstructors(); ConstructorInfo constructor = constructors[0]; if (constructors.Length > 1) { foreach (var c in constructors) { // todo: it would be nice to check constructor parameter types for compatibility with paramStrings. // say a type had one constructor that took a string, and one constructor that took an int. We should be able to pick the right one. if (c.GetParameters().Length == paramStrings.Length) { constructor = c; break; } } } var parameters = constructor.GetParameters(); var constructorParams = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { if (i < paramStrings.Length) { constructorParams[i] = BaseTypesManager.ParseBaseType(paramStrings[i].Trim(), parameters[i].ParameterType); } else // optional parameter support { constructorParams[i] = parameters[i].DefaultValue; } } result = constructor.Invoke(constructorParams); return(true); } } catch { } // I am a good programmer result = null; return(false); }
internal static void SetNodeData(Node node, object data, Type type, FileStyle style) { if (data == null) { node.ClearChildren(); node.Value = Utilities.NullIndicator; return; } else if (node.Value == Utilities.NullIndicator) { node.Value = String.Empty; } // Ensure the type is initialized. This is especially important if it's added as // a base type in the type's static constructor. System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.TypeHandle); // If we try to save a single-line string and find it is currently saved as a multi-line string, we do NOT remove the mutli-line formatting. // The reason for this is that there might be comments on the """s, and we want to preserve those comments. // Also, this happens in only two cases: // 1. A string that is usually single-line is manually switched to multi-line formatting by a user // 2. A string is saved as multi-line, then later saved as single-line // In case 1, we don't want to piss off the user; keep it how they like it. // In case 2, the string is probably going to be saved again later with multiple lines. It doesn't seem necessary to disrupt the structure // of the file for something temporary. string dataAsString = data as string; if (type == typeof(string) && (dataAsString.ContainsNewLine() || node.ChildNodes.Count > 0)) { MultiLineStringSpecialCaseHandler.SetStringSpecialCase(node, dataAsString, style); } else if (BaseTypesManager.IsBaseType(type)) { SetBaseTypeNode(node, data, type, style); } else if (CollectionTypesManager.IsSupportedType(type)) { CollectionTypesManager.SetCollectionNode(node, data, type, style); } else { ComplexTypes.SetComplexNode(node, data, type, style); } }
private static object RetrieveBaseTypeNode(Node node, Type type) { // Base types are unique in that they CAN be serialized as a single line, and indeed that is how SUCC will always save them. // However, you CAN manually write a file that uses complex type rules for a base type, and thanks to the logic in this method, // it will still work. // See https://github.com/JimmyCushnie/SUCC/issues/26 if (node.ChildNodeType == NodeChildrenType.key && node.ChildNodes.Count > 0) { return(ComplexTypes.RetrieveComplexType(node, type)); } if (BaseTypesManager.TryParseBaseType(node.Value, type, out var result)) { return(result); } return(ComplexTypeShortcuts.GetFromShortcut(node.Value, type)); }
private static bool TryMethodShortcut(string shortcut, Type type, out object result) { try { if (shortcut.Contains("(") && shortcut.Contains(")")) { string methodname = shortcut.Substring(0, shortcut.IndexOf('(')); var method = type.GetMethod(methodname, BindingFlags.Public | BindingFlags.Static); if (method != null && method.ReturnType == type) { var parameters = method.GetParameters(); string s = shortcut.Substring(shortcut.IndexOf('(') + 1, shortcut.Length - shortcut.IndexOf('(') - 2); var paramStrings = s.Split(','); var methodParams = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { if (i < paramStrings.Length) { methodParams[i] = BaseTypesManager.ParseBaseType(paramStrings[i].Trim(), parameters[i].ParameterType); } else // optional parameter support { methodParams[i] = parameters[i].DefaultValue; } } result = method.Invoke(null, methodParams); return(true); } } } catch { } // Who am I kidding. I am a bad programmer :( result = null; return(false); }
private static void SetBaseTypeNode(Node node, object data, Type type, FileStyle style) { node.ClearChildren(NodeChildrenType.none); node.Value = BaseTypesManager.SerializeBaseType(data, type, style); }