/// <summary> /// Parses the specified method element. /// </summary> /// <param name = "functionElement">The function element.</param> /// <returns></returns> public FunctionEntity Parse(TypedEntity typedEntity, XElement functionElement) { FunctionEntity functionEntity = new FunctionEntity(); // Extract name String name = functionElement.TrimAll(); functionEntity.Name = name; this.Logger.WriteLine(" Function '" + name + "'"); // Extract abstract XElement abstractElement = (from el in functionElement.ElementsAfterSelf("p") where (String)el.Attribute("class") == "abstract" select el).FirstOrDefault(); functionEntity.Summary.Add(abstractElement.TrimAll()); // Extract declaration XElement declarationElement = (from el in functionElement.ElementsAfterSelf("pre") where (String)el.Attribute("class") == "declaration" select el).FirstOrDefault(); String signature = declarationElement.TrimAll(); if (signature.StartsWith("#define")) { this.Logger.WriteLine("SKIPPING define statement: " + name); return(null); } if (signature.StartsWith("typedef")) { this.Logger.WriteLine("SKIPPING define statement: " + name); return(null); } if (!signature.Contains("(")) // e.g. NS_DURING { this.Logger.WriteLine("SKIPPING non-function statement: " + name); return(null); } // Trim down signature while (signature.IndexOf(" ") != -1) { signature = signature.Replace(" ", " "); } functionEntity.Signature = signature; //Console.WriteLine("signature='" + signature + "'"); // Parse signature int pos = signature.IndexOf(name); if (pos == -1) { this.Logger.WriteLine("MISMATCH between name and declaration: " + name); return(null); } String returnType = signature.Substring(0, pos).Trim(); int paramsIndex = pos + name.Length; int paramsLength = signature.IndexOf(')') + 1 - paramsIndex; // Stop before getting to function body String parameters = signature.Substring(paramsIndex, paramsLength).Trim(); parameters = parameters.Trim(';', '(', ')').Trim(); if (parameters != "void") { foreach (string parameter in parameters.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { String parameterType = "NOTYPE"; String parameterName = "NONAME"; //Console.WriteLine("parameter='" + parameter + "'"); Match r = PARAMETER_REGEX.Match(parameter); if (r.Success) { parameterType = r.Groups [2].Value.Trim(); parameterName = r.Groups [3].Value.Trim(); } else if (parameter.Trim() == "...") { parameterType = "params Object[]"; parameterName = "values"; } else { this.Logger.WriteLine("FAILED to parse parameter: " + parameter); return(null); } parameterType = parameterType.Trim(); MethodParameterEntity parameterEntity = new MethodParameterEntity(); bool isOut, isByRef, isBlock; parameterEntity.Type = this.TypeManager.ConvertType(parameterType, out isOut, out isByRef, out isBlock, this.Logger); parameterEntity.IsOut = isOut; parameterEntity.IsByRef = isByRef; parameterEntity.IsBlock = isBlock; parameterEntity.Name = TypeManager.ConvertName(parameterName); functionEntity.Parameters.Add(parameterEntity); } } // Extract return type functionEntity.ReturnType = this.TypeManager.ConvertType(returnType, this.Logger); // Extract parameter documentation if (functionEntity.Parameters.Count > 0) { XElement termList = (from el in functionElement.Elements("div").Elements("dl") where (String)el.Parent.Attribute("class") == "api parameters" && (String)el.Attribute("class") == "termdef" select el).FirstOrDefault(); if (termList != null) { IEnumerable <XElement> dtList = from el in termList.Elements("dt") select el; IEnumerable <XElement> ddList = from el in termList.Elements("dd") select el; if (dtList.Count() == ddList.Count()) { // Iterate over definitions for (int i = 0; i < dtList.Count(); i++) { String term = dtList.ElementAt(i).TrimAll(); IEnumerable <String> summaries = ddList.ElementAt(i).Elements("p").Select(p => p.Value.TrimAll()); // Find the parameter MethodParameterEntity parameterEntity = functionEntity.Parameters.Find(p => String.Equals(p.Name, term)); if (parameterEntity != null) { foreach (string sum in summaries) { parameterEntity.Summary.Add(sum); } } } } } } // Fix the name only after looking for the documentation for (int i = 0; i < functionEntity.Parameters.Count; i++) { functionEntity.Parameters [i].Name = this.TypeManager.ConvertName(functionEntity.Parameters [i].Name); } // Get the summary for return type if (!String.Equals(functionEntity.ReturnType, "void", StringComparison.OrdinalIgnoreCase)) { XElement returnValueElement = (from el in functionElement.ElementsAfterSelf("div") where (String)el.Attribute("class") == "return_value" select el).FirstOrDefault(); if (returnValueElement != null) { IEnumerable <String> documentations = returnValueElement.Elements("p").Select(p => p.Value.TrimAll()); functionEntity.ReturnsDocumentation = String.Join(String.Empty, documentations.ToArray()); } } //// Extract discussion //XElement discussionElement = (from el in functionElement.ElementsAfterSelf("div") // where (String) el.Attribute("class") == "api discussion" // select el).FirstOrDefault(); //if (discussionElement != null) //{ // foreach (XElement paragraph in discussionElement.Elements("p")) // { // functionEntity.Summary.Add(paragraph.TrimAll()); // } //} // Get the availability XElement availabilityElement = (from el in functionElement.ElementsAfterSelf("div") where (String)el.Attribute("class") == "api availability" select el).FirstOrDefault(); String minAvailability = availabilityElement.Elements("ul").Elements("li").FirstOrDefault().TrimAll(); functionEntity.MinAvailability = CommentHelper.ExtractAvailability(minAvailability); return(functionEntity); }
public FunctionEntity Parse(TypedEntity typedEntity, string name, IEnumerable <XElement> elements) { FunctionEntity functionEntity = new FunctionEntity(); XElement declarationElement = (from el in elements where el.Name == "div" && el.Attribute("class") != null && el.Attribute("class").Value == "declaration_indent" select el).FirstOrDefault(); declarationElement = declarationElement ?? (from el in elements where el.Name == "pre" select el).FirstOrDefault(); XElement parameterElement = (from el in elements where el.Name == "div" && el.Attribute("class") != null && el.Attribute("class").Value == "param_indent" select el).FirstOrDefault(); XElement returnValueElement = (from el in elements where el.Name == "h5" && el.Value.Trim() == "Return Value" select el).FirstOrDefault(); //XElement discussionElement = (from el in elements // where el.Name == "h5" && el.Value.Trim() == "Discussion" // select el).FirstOrDefault(); XElement availabilityElement = (from el in elements let term = el.Descendants("dt").FirstOrDefault() let definition = el.Descendants("dd").FirstOrDefault() where el.Name == "dl" && term != null && term.Value.Trim() == "Availability" select definition).FirstOrDefault(); functionEntity.Name = name; String signature = declarationElement.TrimAll(); if (signature.StartsWith("#define")) { this.Logger.WriteLine("SKIPPING define statement: " + name); return(null); } functionEntity.Signature = signature; // Extract abstract IEnumerable <XElement> abstractElements = elements.SkipWhile(el => el.Name != "p").TakeWhile(el => el.Name == "p"); foreach (XElement element in abstractElements) { String line = element.TrimAll(); if (!String.IsNullOrEmpty(line)) { functionEntity.Summary.Add(line); } } //// Extract discussion //if (discussionElement != null) //{ // IEnumerable<XElement> discussionElements = discussionElement.ElementsAfterSelf().TakeWhile(el => el.Name == "p"); // foreach (XElement element in discussionElements) // { // String line = element.TrimAll(); // if (!String.IsNullOrEmpty(line)) // { // methodEntity.Summary.Add(line); // } // } //} // Parse signature signature = signature.Replace("extern", String.Empty).Trim(); int pos = signature.IndexOf(name); if (pos == -1) { this.Logger.WriteLine("MISMATCH between name and declaration: " + name); return(null); } String returnType = signature.Substring(0, pos).Trim(); String parameters = signature.Substring(pos + name.Length).Trim(); parameters = parameters.Trim(';', '(', ')'); if (parameters != "void") { foreach (string parameter in parameters.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { String parameterType = "NOTYPE"; String parameterName = "NONAME"; Match r = PARAMETER_REGEX.Match(parameter); if (r.Success) { parameterType = r.Groups [2].Value.Trim(); parameterName = r.Groups [3].Value.Trim(); } else if (parameter.Trim() == "...") { parameterType = "params Object[]"; parameterName = "values"; } else { this.Logger.WriteLine("FAILED to parse parameter: " + parameter); return(null); } MethodParameterEntity parameterEntity = new MethodParameterEntity(); bool isOut, isByRef, isBlock; parameterEntity.Type = this.TypeManager.ConvertType(parameterType, out isOut, out isByRef, out isBlock, this.Logger); parameterEntity.IsOut = isOut; parameterEntity.IsByRef = isByRef; parameterEntity.IsBlock = isBlock; parameterEntity.Name = TypeManager.ConvertName(parameterName); functionEntity.Parameters.Add(parameterEntity); } } // Extract return type functionEntity.ReturnType = this.TypeManager.ConvertType(returnType, this.Logger); if (functionEntity.Parameters.Count > 0 && parameterElement != null) { XElement termList = parameterElement.Descendants("dl").FirstOrDefault(); if (termList != null) { IEnumerable <XElement> dtList = from el in termList.Elements("dt") select el; IEnumerable <XElement> ddList = from el in termList.Elements("dd") select el; if (dtList.Count() == ddList.Count()) { // Iterate over definitions for (int i = 0; i < dtList.Count(); i++) { String term = dtList.ElementAt(i).TrimAll(); //String summary = ddList.ElementAt(i).TrimAll(); IEnumerable <String> summaries = ddList.ElementAt(i).Elements("p").Select(p => p.Value.TrimAll()); // Find the parameter MethodParameterEntity parameterEntity = functionEntity.Parameters.Find(p => String.Equals(p.Name, term)); if (parameterEntity != null) { //parameterEntity.Summary.Add(summary); foreach (string sum in summaries) { parameterEntity.Summary.Add(sum); } } } } } } // Fix the name only after looking for the documentation for (int i = 0; i < functionEntity.Parameters.Count; i++) { functionEntity.Parameters [i].Name = this.TypeManager.ConvertName(functionEntity.Parameters [i].Name); } // Get the summary for return type if (!String.Equals(functionEntity.ReturnType, "void", StringComparison.OrdinalIgnoreCase) && returnValueElement != null) { IEnumerable <XElement> returnTypeElements = returnValueElement.ElementsAfterSelf().TakeWhile(el => el.Name == "p"); functionEntity.ReturnsDocumentation = String.Empty; foreach (XElement element in returnTypeElements) { String line = element.TrimAll(); if (!String.IsNullOrEmpty(line)) { functionEntity.ReturnsDocumentation += line; } } } // Get the availability if (availabilityElement != null) { functionEntity.MinAvailability = CommentHelper.ExtractAvailability(availabilityElement.TrimAll()); } return(functionEntity); }