Пример #1
0
        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);
            }
        }
Пример #2
0
        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)));
        }
Пример #3
0
        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));
                    }
                }
            }
        }
Пример #4
0
 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());
 }
Пример #5
0
        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));
                }
            }
        }
Пример #6
0
        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());
        }
Пример #7
0
        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");
            }
        }
Пример #8
0
        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());
        }
Пример #9
0
        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);
            }
        }
Пример #10
0
        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());
            }
        }