public static ParseNode[] GetFieldIdentifier(this ParseNode declaration) { ParseNode content = declaration.ChildrenSkipUnnamed().FirstOrDefault(n => n.RuleType == "plus" && n.RuleName == "declaration_content"); if (content == null) { return(Array.Empty <ParseNode>()); } return(content.ChildrenSkipUnnamed() .TakeWhile(n => !EqualsMatch.IsMatch(n.ToString())) .Select(Identifier) .Where(n => n != null) .ToArray()); ParseNode Identifier(ParseNode parent) { if (parent.RuleType == "choice" && parent.RuleName == "node") { ParseNode result = parent.FirstOrDefault(); if (result?.RuleName == "identifier" || result?.RuleName == "generic") { return(result); } } return(null); } }
protected CppType(string ns, string name, string[] usings, ParseNode content, List <ParserMessage> messages, ParseNode typeDeclaration, string attributePrefix, bool parseFields = true) : base(name, attributePrefix) { Namespace = ns; if (parseFields) { ParseFields(ns, usings, content, messages, typeDeclaration, attributePrefix); } Comments = GetComments(); IComment[] GetComments() { //ParseNode content = declaration.ChildrenSkipUnnamed().First(n => n.RuleType == "plus" && n.RuleName == "declaration_content"); return(content.ChildrenSkipUnnamed() .Where(IsComment) .Where(c => !string.IsNullOrEmpty(c.ToString())) .Select(CppComment.Parse) .ToArray()); bool IsComment(ParseNode node) { return(node.RuleType == "sequence" && node.RuleName == "comment_set"); } } //content first is type dec // children is comment IEnumerable <string> baseTypeNames = typeDeclaration.GetBaseTypes(); baseTypes.AddRange(baseTypeNames.Select(n => new CppDataType(n, usings, ns))); }
public CppEnum(string ns, string name, string[] usings, ParseNode content, List <ParserMessage> messages, ParseNode typeDeclaration, string attributePrefix) : base( ns, name, usings, content, messages, typeDeclaration, attributePrefix, false) { ParseSymbols(); void ParseSymbols() { ParseNode declarationContent = content.GetHierarchy().FirstOrDefault(n => n.RuleName == "declaration_content"); ParseNode[] allSymbols = declarationContent.ChildrenSkipUnnamed().Where(n => n.RuleName != "comment_set").ToArray(); CppSymbol lastSymbol = null; foreach (ParseNode[] symbol in SplitSymbols()) { lastSymbol = CppSymbol.ParseSymbol(symbol, lastSymbol); symbols.Add(lastSymbol); } IEnumerable <ParseNode[]> SplitSymbols() { List <ParseNode[]> groups = new List <ParseNode[]>(); List <ParseNode> nodes = new List <ParseNode>(allSymbols); ParseNode comma = FindFirstComma(); while (comma != null) { comma = FindFirstComma(); int index = nodes.IndexOf(comma); ParseNode[] group = nodes.Take(index).ToArray(); if (group.Any()) { groups.Add(group); } nodes.RemoveRange(0, index + 1); } if (nodes.Any()) { groups.Add(nodes.ToArray()); } return(groups); ParseNode FindFirstComma() { return(nodes.FirstOrDefault(n => n.GetHierarchy() .FirstOrDefault(t => t.RuleName == "symbol") ?.ToString().Contains(",") == true)); } } } }
protected static ParseNode GetDeclarationList(ParseNode content, ParseNode typeDeclaration) { return((from node in content.ChildrenSkipUnnamed() .SkipWhile(c => !c.GetHierarchy().Contains(typeDeclaration)) .Where(c => c.RuleType == "choice" && c.RuleName == "node") select node.FirstOrDefault() into nodeContent where nodeContent?.RuleType == "sequence" && nodeContent.RuleName == "brace_group" select nodeContent.FirstOrDefault(n => n.RuleType == "recursive" && n.RuleName == "declaration_list")) .FirstOrDefault()); }
private void ParseFields(string ns, string[] usings, ParseNode content, List <ParserMessage> messages, ParseNode typeDeclaration, string attributePrefix) { ParseNode list = GetDeclarationList(content, typeDeclaration); if (list != null) { foreach (ParseNode declaration in list.ChildrenSkipUnnamed().Where(n => n.RuleName == "declaration")) { fields.AddRange(CppField.Parse(declaration, usings, $"{ns}::{Name}", messages, attributePrefix, this)); } } }
public static ParseNode[] GetFieldValue(this ParseNode declaration) { ParseNode content = declaration.ChildrenSkipUnnamed().FirstOrDefault(n => n.RuleType == "plus" && n.RuleName == "declaration_content"); if (content == null) { return(Array.Empty <ParseNode>()); } return(content.ChildrenSkipUnnamed() .SkipWhile(n => !EqualsMatch.IsMatch(n.ToString())) .Skip(1) .Where(n => n.ToString() != ";") .ToArray()); }
public static CppComment[] GetFieldComments(this ParseNode declaration) { ParseNode content = declaration.ChildrenSkipUnnamed().First(n => n.RuleType == "plus" && n.RuleName == "declaration_content"); return(content.ChildrenSkipUnnamed() .ToArray() .SkipAfterLastVisibilityGroup() .Where(IsComment) .Where(c => !string.IsNullOrEmpty(c.ToString())) .Select(CppComment.Parse) .ToArray()); bool IsComment(ParseNode node) { return(node.RuleType == "sequence" && node.RuleName == "comment_set"); } }
private static string[] GetUsing(ParseNode root) { List <string> result = new(); foreach (ParseNode usingNode in root.GetHierarchy().Where(n => n.RuleType == "leaf" && n.RuleName == "identifier" && n.ToString() == "using")) { ParseNode declarationParent = GetDeclarationContentParent(usingNode); string[] identifier = declarationParent.ChildrenSkipUnnamed() .Select(Identifier) .Where(i => i != null) .Select(i => i.ToString()) .ToArray(); if (identifier.Length > 2 && identifier[0] == "using" && identifier[1] == "namespace") { result.Add(identifier.Skip(2).Aggregate(string.Empty, (s, s1) => s + s1)); } } return(result.ToArray()); }
public ParserResult Parse(VirtualFile file) { log.LogVerbose($"Parse file {file.FullName}."); List <CodeSpecificException> codeSpecificExceptions = new List <CodeSpecificException>(); List <ParserMessage> messages = new List <ParserMessage>(); IDictionary <IType, CodePosition> types = new Dictionary <IType, CodePosition>(); CppStreamParser parser = new CppStreamParser(); ParseNode root = parser.Parse(file.OpenRead()); if (!parser.Succeeded) { messages.Add(parser.Exception == null ? new ParserMessage("CPP0004", 1, 1) : new ParserMessage("CPP0005", parser.Exception.Row, parser.Exception.Col, $"{Environment.NewLine}{parser.Exception.Message}")); codeSpecificExceptions.AddRange(messages.Select(m => m.ToException(file))); return(new ParserResult(codeSpecificExceptions)); } string[] usings = GetUsings(); foreach (ParseNode typeDeclaration in GetTypeDeclarations(root)) { ParseNode content = GetDeclarationContentParent(typeDeclaration); if (content != null && IsValidDecalration(content, typeDeclaration)) { string name = GetName(typeDeclaration); string ns = GetNamespace(typeDeclaration); switch (typeDeclaration[1].RuleName) { case "struct_decl": CppStructure structure = new CppStructure(ns, name, usings, content, messages, typeDeclaration, settingsProvider.Settings.AttributePrefix); types.Add(structure, new CodePosition(typeDeclaration.Position.line, typeDeclaration.Position.column)); break; case "class_decl": CppClass cppClass = new CppClass(ns, name, usings, content, typeDeclaration[1], messages, settingsProvider.Settings.AttributePrefix); types.Add(cppClass, new CodePosition(typeDeclaration.Position.line, typeDeclaration.Position.column)); break; case "enum_decl": CppEnum cppEnum = new CppEnum(ns, name, usings, content, messages, typeDeclaration[1], settingsProvider.Settings.AttributePrefix); types.Add(cppEnum, new CodePosition(typeDeclaration.Position.line, typeDeclaration.Position.column)); break; default: //do nothing break; } } } codeSpecificExceptions.AddRange(messages.Select(m => m.ToException(file))); string[] includes = GetIncludes(); return(new ParserResult(codeSpecificExceptions, types, includes)); bool IsValidDecalration(ParseNode content, ParseNode typeDeclaration) { return(content.Count >= 2 && content.Any(c => c.GetHierarchy().Contains(typeDeclaration)) && content.SkipWhile(c => !c.GetHierarchy().Contains(typeDeclaration)) .Skip(1).Any(c => c.GetHierarchy().Any(n => n.RuleName == "brace_group"))); } string GetName(ParseNode typeDeclaration) { ParseNode leaf = typeDeclaration.GetHierarchy() .FirstOrDefault(n => n.RuleName == "identifier" || n.RuleName == "generic"); if (leaf == null) { return(Guid.NewGuid().ToByteString()); } return(leaf.ToString()); } ParseNode GetDeclarationContentParent(ParseNode current) { while (current != null && current.RuleType != "plus" && current.RuleName != "declaration_content") { current = current.GetParent(); } return(current); } IEnumerable <ParseNode> GetTypeDeclarations(ParseNode current) { foreach (ParseNode node in current) { if (node.RuleType == "sequence" && node.RuleName == "type_decl") { yield return(node); } else { foreach (ParseNode child in GetTypeDeclarations(node)) { yield return(child); } } } } string[] GetIncludes() { List <string> result = new List <string>(); foreach (ParseNode includeNode in root.GetHierarchy().Where(n => n.RuleType == "sequence" && n.RuleName == "pp_directive" && n.Any(c => c.ToString().Equals("include", StringComparison.OrdinalIgnoreCase)))) { ParseNode include = includeNode.FirstOrDefault(n => n.RuleName == "until_eol"); if (include != null) { result.Add(include.ToString().Trim('\"')); } } return(result.ToArray()); } string[] GetUsings() { List <string> result = new List <string>(); foreach (ParseNode usingNode in root.GetHierarchy().Where(n => n.RuleType == "leaf" && n.RuleName == "identifier" && n.ToString() == "using")) { ParseNode declarationParent = GetDeclarationContentParent(usingNode); string[] identifier = declarationParent.ChildrenSkipUnnamed() .Select(Identifier) .Where(i => i != null) .Select(i => i.ToString()) .ToArray(); if (identifier.Length > 2 && identifier[0] == "using" && identifier[1] == "namespace") { result.Add(identifier.Skip(2).Aggregate(string.Empty, (s, s1) => s + s1)); } } return(result.ToArray()); } ParseNode Identifier(ParseNode parent) { if (parent.RuleType == "choice" && parent.RuleName == "node") { ParseNode result = parent.FirstOrDefault(); if (result?.RuleType == "leaf" && result.RuleName == "identifier") { return(result); } } return(null); } string GetNamespace(ParseNode typeDeclaration) { ParseNode declarationParent; typeDeclaration = GetDeclarationContentParent(typeDeclaration).GetParent(); string result = string.Empty; while ((declarationParent = GetDeclarationContentParent(typeDeclaration)) != null) { string[] identifier = declarationParent.ChildrenSkipUnnamed() .Where(r => r.RuleName != "comment_set") .Select(Identifier) .TakeWhile(i => i != null) .Select(i => i.ToString()) .ToArray(); if (identifier.Length > 1 && identifier[0] == "namespace") { result = $"{identifier.Skip(1).Aggregate(string.Empty, (s, s1) => s + s1)}::{result}"; } else if (identifier.Length == 0) { ParseNode parentTypeDeclaration = declarationParent.ChildrenSkipUnnamed() .Where(c => c.RuleType == "choice" && c.RuleName == "node") .SelectMany(c => c.ChildrenSkipUnnamed()) .FirstOrDefault( c => c.RuleType == "sequence" && c.RuleName == "type_decl"); ParseNode name = parentTypeDeclaration?.GetHierarchy() .FirstOrDefault(n => n.RuleType == "leaf" && n.RuleName == "identifier"); if (name != null) { result = $"{name}::{result}"; } } typeDeclaration = declarationParent.GetParent(); } if (!string.IsNullOrEmpty(result)) { result = result.Substring(0, result.Length - 2); } return(result); } }
public static IEnumerable <CppField> Parse(ParseNode declaration, string[] usings, string ns, List <ParserMessage> messages, string attributePrefix, CppType containingType) { if (declaration.GetHierarchy().Any(n => n.RuleName == "paran_group") || declaration.GetHierarchy().Any(n => n.RuleName == "typedef_decl") || declaration.GetHierarchy().Any(n => n.RuleName == "pp_directive")) { return(Enumerable.Empty <CppField>()); } ParseNode[] identifiers = GetIdentifier(); ParseNode[] typeNodes = GetTypeDeclarationName() ?? GetTypeNodes(identifiers); if (identifiers.SequenceEqual(typeNodes)) { if (typeNodes.Any()) { (int line, int column)position = declaration.Position; messages.Add(new ParserMessage("CPP0001", position.line, position.column)); } //Empty group "private:" return(Enumerable.Empty <CppField>()); } string dataTypeName = typeNodes.Aggregate(string.Empty, (s, node) => $"{s}{node}"); IEnumerable <(string name, int[] multiplicity)> fields = identifiers.Except(typeNodes).Select(i => (i.ToString(), GetMultiplicity(i.GetParent()))); IComment[] comments = GetComments(); CppDataType dataType = new CppDataType(dataTypeName, usings, ns); return(fields.Select(fd => new CppField(fd.name, dataType, comments, fd.multiplicity, attributePrefix, containingType))); ParseNode[] GetTypeDeclarationName() { ParseNode typeDeclaration = declaration.GetHierarchy().FirstOrDefault(n => n.RuleName == "type_decl"); return(typeDeclaration?.GetHierarchy().Select(Identifier).Where(n => n != null).ToArray()); ParseNode Identifier(ParseNode node) { if (node.RuleType == "leaf" && node.RuleName == "identifier") { return(node); } return(null); } } IComment[] GetComments() { ParseNode content = declaration.ChildrenSkipUnnamed().First(n => n.RuleType == "plus" && n.RuleName == "declaration_content"); return(content.ChildrenSkipUnnamed() .Where(IsComment) .Where(c => !string.IsNullOrEmpty(c.ToString())) .Select(CppComment.Parse) .ToArray()); bool IsComment(ParseNode node) { return(node.RuleType == "sequence" && node.RuleName == "comment_set"); } } ParseNode[] GetIdentifier() { ParseNode content = declaration.ChildrenSkipUnnamed().FirstOrDefault(n => n.RuleType == "plus" && n.RuleName == "declaration_content"); if (content == null) { return(Array.Empty <ParseNode>()); } return(content.ChildrenSkipUnnamed() .Select(Identifier).Where(n => n != null) .ToArray()); ParseNode Identifier(ParseNode parent) { if (parent.RuleType == "choice" && parent.RuleName == "node") { ParseNode result = parent.FirstOrDefault(); if (result?.RuleType == "leaf" && result.RuleName == "identifier") { return(result); } } return(null); } } int[] GetMultiplicity(ParseNode identifier) { identifier = identifier.SkipUnnamedParents(); int index = identifier.GetParentIndex(); ParseNode parent = identifier.GetParent(); List <int> multiplicities = new List <int>(); bool firstMultiplicityFound = false; foreach (ParseNode sibling in parent.Skip(index + 1).SkipUnnamed()) { if (sibling.RuleType == "choice" && sibling.RuleName == "node") { ParseNode child = sibling.FirstOrDefault(); if (child?.RuleType == "sequence" && child.RuleName == "bracketed_group") { string bracketGroup = child.ToString().Trim(); if (int.TryParse(bracketGroup.Substring(1, bracketGroup.Length - 2), out int result)) { multiplicities.Add(result); firstMultiplicityFound = true; } } else if (firstMultiplicityFound) { break; } } } return(multiplicities.ToArray()); } ParseNode[] GetTypeNodes(ParseNode[] parseNodes) { return(parseNodes.TakeWhile(n => n.ToString().EndsWith("::", StringComparison.Ordinal)) .Concat(parseNodes.SkipWhile(n => n.ToString().EndsWith("::", StringComparison.Ordinal)).Take(1)) .ToArray()); } }