{"action":"created","comment":{"url":"https://api.github.com/repos/dotnet/roslyn/pulls/comments/178469962","pull_request_review_id":108530108,"id":178469962,"diff_hunk":"@@ -0,0 +1,1916 @@\n+﻿// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.\n+\n+using System;\n+using System.Collections.Immutable;\n+using System.Diagnostics;\n+using System.Linq;\n+using System.Text.RegularExpressions;\n+using Microsoft.CodeAnalysis.EmbeddedLanguages.Common;\n+using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars;\n+using Microsoft.CodeAnalysis.PooledObjects;\n+using Microsoft.CodeAnalysis.Text;\n+\n+namespace Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions\n+{\n+    using static EmbeddedSyntaxHelpers;\n+    using static RegexHelpers;\n+\n+    using RegexNodeOrToken = EmbeddedSyntaxNodeOrToken<RegexKind, RegexNode>;\n+    using RegexToken = EmbeddedSyntaxToken<RegexKind>;\n+    using RegexTrivia = EmbeddedSyntaxTrivia<RegexKind>;\n+\n+    internal partial struct RegexParser\n+    {\n+        private readonly ImmutableDictionary<string, TextSpan> _captureNamesToSpan;\n+        private readonly ImmutableDictionary<int, TextSpan> _captureNumbersToSpan;\n+\n+        private RegexLexer _lexer;\n+        private RegexOptions _options;\n+        private RegexToken _currentToken;\n+        private int _recursionDepth;\n+\n+        private RegexParser(\n+            ImmutableArray<VirtualChar> text, RegexOptions options,\n+            ImmutableDictionary<string, TextSpan> captureNamesToSpan,\n+            ImmutableDictionary<int, TextSpan> captureNumbersToSpan) : this()\n+        {\n+            _lexer = new RegexLexer(text);\n+            _options = options;\n+\n+            _captureNamesToSpan = captureNamesToSpan;\n+            _captureNumbersToSpan = captureNumbersToSpan;\n+\n+            // Get the first token.  It is allowed to have trivia on it.\n+            ConsumeCurrentToken(allowTrivia: true);\n+        }\n+\n+        /// <summary>\n+        /// Returns the latest token the lexer has produced, and then asks the lexer to \n+        /// produce the next token after that.\n+        /// </summary>\n+        /// <param name=\"allowTrivia\">Whether or not trivia is allowed on the next token\n+        /// produced.  In the .net parser trivia is only allowed on a few constructs,\n+        /// and our parser mimics that behavior.  Note that even if trivia is allowed,\n+        /// the type of trivia that can be scanned depends on the current RegexOptions.\n+        /// For example, if <see cref=\"RegexOptions.IgnorePatternWhitespace\"/> is currently\n+        /// enabled, then '#...' comments are allowed.  Otherwise, only '(?#...)' comemnts\n+        /// are allowed.</param>\n+        private RegexToken ConsumeCurrentToken(bool allowTrivia)\n+        {\n+            var previous = _currentToken;\n+            _currentToken = _lexer.ScanNextToken(allowTrivia, _options);\n+            return previous;\n+        }\n+\n+        /// <summary>\n+        /// Given an input text, and set of options, parses out a fully representative syntax tree \n+        /// and list of diagnotics.  Parsing should always succeed, except in the case of the stack \n+        /// overflowing.\n+        /// </summary>\n+        public static RegexTree TryParse(ImmutableArray<VirtualChar> text, RegexOptions options)\n+        {\n+            try\n+            {\n+                // Parse the tree once, to figure out the capture groups.  These are needed\n+                // to then parse the tree again, as the captures will affect how we interpret\n+                // certain things (i.e. escape references) and what errors will be reported.\n+                //\n+                // This is necessary as .net regexes allow references to *future* captures.\n+                // As such, we don't know when we're seeing a reference if it's to something\n+                // that exists or not.\n+                var tree1 = new RegexParser(text, options,\n+                    ImmutableDictionary<string, TextSpan>.Empty,\n+                    ImmutableDictionary<int, TextSpan>.Empty).ParseTree();\n+\n+                var analyzer = new CaptureInfoAnalyzer(text);\n+                var (captureNames, captureNumbers) = analyzer.Analyze(tree1.Root, options);\n+\n+                var tree2 = new RegexParser(\n+                    text, options, captureNames, captureNumbers).ParseTree();\n+                return tree2;\n+            }\n+            catch (Exception e) when (StackGuard.IsInsufficientExecutionStackException(e))\n+            {\n+                return null;\n+            }\n+        }\n+\n+        private RegexTree ParseTree()\n+        {\n+            var expression = this.ParseAlternatingSequences(consumeCloseParen: true);\n+            Debug.Assert(_lexer.Position == _lexer.Text.Length);\n+            Debug.Assert(_currentToken.Kind == RegexKind.EndOfFile);\n+\n+            var root = new RegexCompilationUnit(expression, _currentToken);\n+\n+            var diagnostics = ArrayBuilder<EmbeddedDiagnostic>.GetInstance();\n+            CollectDiagnostics(root, diagnostics);\n+\n+            return new RegexTree(\n+                _lexer.Text, root, diagnostics.ToImmutableAndFree(),\n+                _captureNamesToSpan, _captureNumbersToSpan);\n+        }\n+\n+        private static void CollectDiagnostics(RegexNode node, ArrayBuilder<EmbeddedDiagnostic> diagnostics)\n+        {\n+            foreach (var child in node)\n+            {\n+                if (child.IsNode)\n+                {\n+                    CollectDiagnostics(child.Node, diagnostics);\n+                }\n+                else\n+                {\n+                    var token = child.Token;\n+                    foreach (var trivia in token.LeadingTrivia)\n+                    {\n+                        AddUniqueDiagnostics(trivia.Diagnostics, diagnostics);\n+                    }\n+\n+                    AddUniqueDiagnostics(token.Diagnostics, diagnostics);\n+                }\n+            }\n+        }\n+\n+        /// <summary>\n+        /// It's very common to have duplicated diagnostics.  For example, consider \"((\". This will\n+        /// have two 'missing )' diagnostics, both at the end.  Reporting both isn't helpful, so we\n+        /// filter duplicates out here.\n+        /// </summary>\n+        private static void AddUniqueDiagnostics(ImmutableArray<EmbeddedDiagnostic> from, ArrayBuilder<EmbeddedDiagnostic> to)\n+        {\n+            foreach (var diagnostic in from)\n+            {\n+                if (!to.Contains(diagnostic))\n+                {\n+                    to.Add(diagnostic);\n+                }\n+            }\n+        }\n+\n+        private RegexExpressionNode ParseAlternatingSequences(bool consumeCloseParen)\n+        {\n+            try\n+            {\n+                _recursionDepth++;\n+                StackGuard.EnsureSufficientExecutionStack(_recursionDepth);\n+                return ParseAlternatingSequencesWorker(consumeCloseParen);\n+            }\n+            finally\n+            {\n+                _recursionDepth--;\n+            }\n+        }\n+\n+        /// <summary>\n+        /// Parses out code of the form: ...|...|...\n+        /// This is the type of code you have at the top level of a regex, or inside any grouping\n+        /// contruct.  Note that sequences can be empty in .net regex.  i.e. the following is legal:\n+        /// \n+        ///     ...||...\n+        /// \n+        /// An empty sequence just means \"match at every position in the test string\".\n+        /// </summary>\n+        private RegexExpressionNode ParseAlternatingSequencesWorker(bool consumeCloseParen)\n+        {\n+            RegexExpressionNode current = ParseSequence(consumeCloseParen);\n+\n+            while (_currentToken.Kind == RegexKind.BarToken)\n+            {\n+                // Trivia allowed between the | and the next token.\n+                current = new RegexAlternationNode(\n+                    current, ConsumeCurrentToken(allowTrivia: true), ParseSequence(consumeCloseParen));\n+            }\n+\n+            return current;\n+        }\n+\n+        private RegexSequenceNode ParseSequence(bool consumeCloseParen)\n+        {\n+            var list = ArrayBuilder<RegexExpressionNode>.GetInstance();\n+\n+            if (ShouldConsumeSequenceElement(consumeCloseParen))\n+            {\n+                do\n+                {\n+                    var last = list.Count == 0 ? null : list.Last();\n+                    list.Add(ParsePrimaryExpressionAndQuantifiers(last));\n+\n+                    TryMergeLastTwoNodes(list);\n+                }\n+                while (ShouldConsumeSequenceElement(consumeCloseParen));","path":"src/Workspaces/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexParser.cs","position":213,"original_position":201,"commit_id":"d85162ad18d94b9c4b6bdd04cd597b9149321a62","original_commit_id":"ddd0090fa70a98a8224f485f1cba9688ff534e6a","user":{"login":"CyrusNajmabadi","id":4564579,"avatar_url":"https://avatars3.githubusercontent.com/u/4564579?v=4","gravatar_id":"","url":"https://api.github.com/users/CyrusNajmabadi","html_url":"https://github.com/CyrusNajmabadi","followers_url":"https://api.github.com/users/CyrusNajmabadi/followers","following_url":"https://api.github.com/users/CyrusNajmabadi/following{/other_user}","gists_url":"https://api.github.com/users/CyrusNajmabadi/gists{/gist_id}","starred_url":"https://api.github.com/users/CyrusNajmabadi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CyrusNajmabadi/subscriptions","organizations_url":"https://api.github.com/users/CyrusNajmabadi/orgs","repos_url":"https://api.github.com/users/CyrusNajmabadi/repos","events_url":"https://api.github.com/users/CyrusNajmabadi/events{/privacy}","received_events_url":"https://api.github.com/users/CyrusNajmabadi/received_events","type":"User","site_admin":false},"body":"I'm ok as-is.  #won'tfix","created_at":"2018-04-01T22:01:47Z","updated_at":"2018-04-01T22:01:48Z","html_url":"https://github.com/dotnet/roslyn/pull/23984#discussion_r178469962","pull_request_url":"https://api.github.com/repos/dotnet/roslyn/pulls/23984","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/comments/178469962"},"html":{"href":"https://github.com/dotnet/roslyn/pull/23984#discussion_r178469962"},"pull_request":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/23984"}},"in_reply_to_id":178463685},"pull_request":{"url":"https://api.github.com/repos/dotnet/roslyn/pulls/23984","id":160611106,"html_url":"https://github.com/dotnet/roslyn/pull/23984","diff_url":"https://github.com/dotnet/roslyn/pull/23984.diff","patch_url":"https://github.com/dotnet/roslyn/pull/23984.patch","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/23984","number":23984,"state":"open","locked":false,"title":"Add in a regex parser so that the IDE can provide services around regex editing.","user":{"login":"CyrusNajmabadi","id":4564579,"avatar_url":"https://avatars3.githubusercontent.com/u/4564579?v=4","gravatar_id":"","url":"https://api.github.com/users/CyrusNajmabadi","html_url":"https://github.com/CyrusNajmabadi","followers_url":"https://api.github.com/users/CyrusNajmabadi/followers","following_url":"https://api.github.com/users/CyrusNajmabadi/following{/other_user}","gists_url":"https://api.github.com/users/CyrusNajmabadi/gists{/gist_id}","starred_url":"https://api.github.com/users/CyrusNajmabadi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CyrusNajmabadi/subscriptions","organizations_url":"https://api.github.com/users/CyrusNajmabadi/orgs","repos_url":"https://api.github.com/users/CyrusNajmabadi/repos","events_url":"https://api.github.com/users/CyrusNajmabadi/events{/privacy}","received_events_url":"https://api.github.com/users/CyrusNajmabadi/received_events","type":"User","site_admin":false},"body":"I was bored flying to MN and DC.  So i decided to scratch an itch that came up when discussing things over here: https://github.com/dotnet/csharplang/issues/371\r\n\r\nThis PR introduces support in the Roslyn IDE for improved features for users working with .Net regexes.  Specifically, the intent of this PR is to support the following (entirely optional) features around regexes:\r\n\r\n1. Colorization.  Users should be able to write a regex and have it colorized automatically, with a set of colors they can customize if they want.\r\n2. Highlighting.  Users should be able to place their cursor on something like a brace and have the matching brace highlighted.  This should extend to complex regex concepts (like backreferences) as well.\r\n3. Syntax errors.  Users should see syntax errors directly in the editor and error list without having to compile or run their program.\r\n4. Fixes.  Errors in the regex should come with potential fixes to address the problem immediately.\r\n5. Suggestions.  The IDE should be able to suggest completely safe refactorings to a users regex to simplify it.  For example, suggesting that ```\"(a)(b)\"``` be simplified directly to ```ab```.\r\n\r\nHowever, supporting regexes is complicated by how regexes are supported in the language today.  Specifically because of the complexity present in how VB and C# escape values in strings on top of how complex .net regexes are as well.  To deal with that, two new components have been added to Roslyn.\r\n  \r\nThe first subsystem is called the VirtualCharService deals with the following issue.  To the final .net regex, the following snippets of code appear completely identical to it:\r\n\r\n```c#\r\n\"\\\\1\"       // In a normal string, we have to escape the \\\r\n@\"\\1\"       // But not in a verbatim string\r\n\"\\\\\\u0031\"  // The '1' could be escaped\r\n\"\\\\u005c1\"  // Even the backslash *itself* may be escaped\r\n```\r\n\r\nThese are all ways of writing the ```\\1``` regex.\r\n\r\nIn other words, C# allows a wide variety of input strings to all compile down to the same final 'value' (or 'ValueText') that the regex engine will finally see.  This is a major issue as it means that any data reported by the regex engine must be accurate with respect to the text as the user wrote it.  For example, in all of the equivalent cases above, there is the same error \"Reference to undefined group number 1\".  However, for each form the user wrote, it's necessary to understand what the right value is to highlight as the problem. i.e.\r\n\r\n![image](https://user-images.githubusercontent.com/4564579/34459671-5bb785b2-edab-11e7-8413-79c331ef373f.png)\r\n\r\nand\r\n\r\n![image](https://user-images.githubusercontent.com/4564579/34459672-6deb88dc-edab-11e7-8236-7ba7cd331247.png)\r\n\r\nSo, the purpose of the VirtualCharService is to translate all of the above pieces of user code to the same final set of characters the regex engine will see (specifically ```\\``` and ```1```) while **also** maintaining the knowledge of where those characters came from (for example, that ```1``` came from ```\\u0031``` in the last example).  In essence, the VirtualCharService is able to produce the ValueText for any string literal, while having a mapping back from each character in the ValueText back to the original source span of the document that formed this.\r\n\r\nWith the VirtualCharService user code can be translated into a common format that then can be processed uniformly.  This means that the part of the system that actually tries to understand the regex does not need to know about the differences between ```@\"\"``` and ```\"\"``` strings, or the differences between C# and VB.  It also means that it can be used by any roslyn language (for example, F#) if that is so desired.\r\n\r\nThe second service is the actual regex parser that consumes the results of the VirtualCharService.  The regex parser is a fork of the real .net regex parser (from  https://github.com/dotnet/corefx/blob/master/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs) however, changed heavily. The reason for this is that the existing regex parser is ill suited for all the needs an IDE has.  Major problems the existing parser has are:\r\n\r\n1. It is not error tolerant.  With the first error it encounters it completely bails out.  This would mean that the roslyn services would only work if the regex was written completely properly.\r\n2. it does not produce a usable tree by IDE standards.  While it does produce a tree, it is an extremely abstract one that not only does not contain much of the information that would be needed. It is also heavily processed and changed as parsing happens.  i.e. the parser will actually merge, split, erase, and even reorder nodes within the tree.\r\n3. it works with data formats that are intended to work extremely fast and efficiently when actually performing matching of regexes, but which would be very baroque and unpleasant for editing scenarios.  For example, it compresses data into a compact binary format, which it then stores in strings themselves that it intersperses with chunks of the original string.\r\n4. It will actually crash when passed in some strings (i was able to get index-out-of-bounds and even null-refs when using it).\r\n5. It can use excessive amounts of memory (even OOMing) just when parsing.  \r\n\r\nHowever, the existing parser does have certain things going for it.  Namely, it is the source of truth in the .net world.  It doesn't matter what the docs say on how .net regexes work and are parsed.  At the end of they day, this is the parser used, so it must always be deferred to when determining what is a syntactically legal regex and what isn't.\r\n\r\nThe regex parser this PR adds introduces a system far more in line with how other roslyn parsers work.  Namely, the tree it produces is immutable and fully represents all the characters in the original token.  The tree also follows roslyn invariants around nodes, tokens and trivia.  Ideally, the tree would literally be built on the syntax classes defined at the Microsoft.CodeAnalysis layer.  However, they contain internals that make them only implementable at the C# and Vb layers.  Because of that, the tree produces by the new regex parser follows the spirit of the Roslyn syntax model even if it can't fit into it perfectly.\r\n\r\nThis parser has been extensively tested and comes with 750 *seed* cases that validate it.  These are called 'test seeds' as the inputs to the engine are then mutated heavily to produce even more cases to validate the engine with (for example, testing all prefixes and suffixes of every test case to ensure no crashes or infinite loops occur).  Validation is very stringent.  All cases must parse without any problems, producing trees that abide by all roslyn invariants.  **Furthermore**, all cases validate that the new parser does not produce errors if the native parser does not.  Conversely, if the native parser produces an error, the new parser must produce **the same error** as it does.  That means that we do not even define *new* messages to show the user.  Instead, we use the same message (or message fragment) that the native regex parser gives the user.  For example:\r\n\r\n![image](https://user-images.githubusercontent.com/4564579/34459743-084b2d4a-edae-11e7-9941-2e5df87e7fb7.png)\r\n\r\n![image](https://user-images.githubusercontent.com/4564579/34459744-12d309cc-edae-11e7-8f3c-996bd684ba99.png)\r\n\r\nBecause of this validation, it's very easy to feed in new tests into the system and have it validate that the roslyn regex parser is working in line with the native parser. \r\n\r\nThe test suite currently contains all the existing positive and negative tests from the existing .net regex suite, as well as many edge cases i added while writing the new parser.\r\n\r\n--\r\n\r\nHere's the current worklist for this feature:\r\n\r\nRequired:\r\n- [x] Create VirtualCharService system \r\n- [x] Implement VirtualCharService for C#\r\n- [x] Test VirtualCharService for C#\r\n- [x] Implement VirtualCharService for VB\r\n- [x] Test VirtualCharService for VB\r\n- [x] Create regular expression parser that will produce a Roslyn tree for a regex.\r\n- [x] Test regular expression parser\r\n- [x] Add stack overflow safeguards for regex parsing.\r\n- [x] Add diagnostic analyzer that parses regexes and reports warnings for issues as Diagnostics.\r\n- [x] Add tests for regex squiggles\r\n- [x] Add colorizer and fonts/colors entries for regex components.\r\n- [x] Add tests for regex colorizer\r\n- [x] Add user facing options to disable language services for regexs.\r\n- [x] Add way to apply this system to non-obvious regexes.  For example allow users to write something like ```/* language=regex */ \"[a-zA-Z]\"```\r\n- [x] Add error for character classes that go in the wrong direction.  i.e. ```[z-a]```.\r\n- [x] Add highlighter for regex components\r\n\r\nNice to have:\r\n- [ ] Add fixer for regex errors\r\n- [ ] Add simplifier for complex regexes\r\n- [ ] Add pattern-help for regex components (i.e. when typing ```(?``` something should pop up to show you all the legal forms there are).\r\n\r\n\r\nI hope to get all this done in the next week or so.  I hope that this could serve as a pleasant addition to the C# and Vb editing experience for so many of our devs who do use regexes day to day.","created_at":"2017-12-31T06:15:04Z","updated_at":"2018-04-01T22:01:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2107919e93cb3920516d89f8da5bfa6155cf602f","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":166377917,"url":"https://api.github.com/repos/dotnet/roslyn/labels/Area-IDE","name":"Area-IDE","color":"5319e7","default":false}],"milestone":{"url":"https://api.github.com/repos/dotnet/roslyn/milestones/33","html_url":"https://github.com/dotnet/roslyn/milestone/33","labels_url":"https://api.github.com/repos/dotnet/roslyn/milestones/33/labels","id":3020805,"number":33,"title":"15.8","description":null,"creator":{"login":"sharwell","id":1408396,"avatar_url":"https://avatars1.githubusercontent.com/u/1408396?v=4","gravatar_id":"","url":"https://api.github.com/users/sharwell","html_url":"https://github.com/sharwell","followers_url":"https://api.github.com/users/sharwell/followers","following_url":"https://api.github.com/users/sharwell/following{/other_user}","gists_url":"https://api.github.com/users/sharwell/gists{/gist_id}","starred_url":"https://api.github.com/users/sharwell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sharwell/subscriptions","organizations_url":"https://api.github.com/users/sharwell/orgs","repos_url":"https://api.github.com/users/sharwell/repos","events_url":"https://api.github.com/users/sharwell/events{/privacy}","received_events_url":"https://api.github.com/users/sharwell/received_events","type":"User","site_admin":false},"open_issues":163,"closed_issues":35,"state":"open","created_at":"2018-01-08T19:35:57Z","updated_at":"2018-04-01T21:44:45Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/dotnet/roslyn/pulls/23984/commits","review_comments_url":"https://api.github.com/repos/dotnet/roslyn/pulls/23984/comments","review_comment_url":"https://api.github.com/repos/dotnet/roslyn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/23984/comments","statuses_url":"https://api.github.com/repos/dotnet/roslyn/statuses/d85162ad18d94b9c4b6bdd04cd597b9149321a62","head":{"label":"CyrusNajmabadi:regexParsing4","ref":"regexParsing4","sha":"d85162ad18d94b9c4b6bdd04cd597b9149321a62","user":{"login":"CyrusNajmabadi","id":4564579,"avatar_url":"https://avatars3.githubusercontent.com/u/4564579?v=4","gravatar_id":"","url":"https://api.github.com/users/CyrusNajmabadi","html_url":"https://github.com/CyrusNajmabadi","followers_url":"https://api.github.com/users/CyrusNajmabadi/followers","following_url":"https://api.github.com/users/CyrusNajmabadi/following{/other_user}","gists_url":"https://api.github.com/users/CyrusNajmabadi/gists{/gist_id}","starred_url":"https://api.github.com/users/CyrusNajmabadi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CyrusNajmabadi/subscriptions","organizations_url":"https://api.github.com/users/CyrusNajmabadi/orgs","repos_url":"https://api.github.com/users/CyrusNajmabadi/repos","events_url":"https://api.github.com/users/CyrusNajmabadi/events{/privacy}","received_events_url":"https://api.github.com/users/CyrusNajmabadi/received_events","type":"User","site_admin":false},"repo":{"id":30565155,"name":"roslyn","full_name":"CyrusNajmabadi/roslyn","owner":{"login":"CyrusNajmabadi","id":4564579,"avatar_url":"https://avatars3.githubusercontent.com/u/4564579?v=4","gravatar_id":"","url":"https://api.github.com/users/CyrusNajmabadi","html_url":"https://github.com/CyrusNajmabadi","followers_url":"https://api.github.com/users/CyrusNajmabadi/followers","following_url":"https://api.github.com/users/CyrusNajmabadi/following{/other_user}","gists_url":"https://api.github.com/users/CyrusNajmabadi/gists{/gist_id}","starred_url":"https://api.github.com/users/CyrusNajmabadi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CyrusNajmabadi/subscriptions","organizations_url":"https://api.github.com/users/CyrusNajmabadi/orgs","repos_url":"https://api.github.com/users/CyrusNajmabadi/repos","events_url":"https://api.github.com/users/CyrusNajmabadi/events{/privacy}","received_events_url":"https://api.github.com/users/CyrusNajmabadi/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/CyrusNajmabadi/roslyn","description":"The .NET Compiler Platform (\"Roslyn\") provides open-source C# and Visual Basic compilers with rich code analysis APIs.","fork":true,"url":"https://api.github.com/repos/CyrusNajmabadi/roslyn","forks_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/forks","keys_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/teams","hooks_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/hooks","issue_events_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/issues/events{/number}","events_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/events","assignees_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/assignees{/user}","branches_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/branches{/branch}","tags_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/tags","blobs_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/git/refs{/sha}","trees_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/statuses/{sha}","languages_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/languages","stargazers_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/stargazers","contributors_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/contributors","subscribers_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/subscribers","subscription_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/subscription","commits_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/commits{/sha}","git_commits_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/git/commits{/sha}","comments_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/comments{/number}","issue_comment_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/issues/comments{/number}","contents_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/contents/{+path}","compare_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/merges","archive_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/downloads","issues_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/issues{/number}","pulls_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/pulls{/number}","milestones_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/milestones{/number}","notifications_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/labels{/name}","releases_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/releases{/id}","deployments_url":"https://api.github.com/repos/CyrusNajmabadi/roslyn/deployments","created_at":"2015-02-09T23:45:22Z","updated_at":"2018-03-31T05:13:56Z","pushed_at":"2018-04-01T21:58:49Z","git_url":"git://github.com/CyrusNajmabadi/roslyn.git","ssh_url":"git@github.com:CyrusNajmabadi/roslyn.git","clone_url":"https://github.com/CyrusNajmabadi/roslyn.git","svn_url":"https://github.com/CyrusNajmabadi/roslyn","homepage":"","size":315612,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"dotnet:master","ref":"master","sha":"57272a2674ab1357d255dd94cb4e1f8717cf8f27","user":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars0.githubusercontent.com/u/9141961?v=4","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"repo":{"id":29078997,"name":"roslyn","full_name":"dotnet/roslyn","owner":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars0.githubusercontent.com/u/9141961?v=4","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dotnet/roslyn","description":"The .NET Compiler Platform (\"Roslyn\") provides open-source C# and Visual Basic compilers with rich code analysis APIs.","fork":false,"url":"https://api.github.com/repos/dotnet/roslyn","forks_url":"https://api.github.com/repos/dotnet/roslyn/forks","keys_url":"https://api.github.com/repos/dotnet/roslyn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dotnet/roslyn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dotnet/roslyn/teams","hooks_url":"https://api.github.com/repos/dotnet/roslyn/hooks","issue_events_url":"https://api.github.com/repos/dotnet/roslyn/issues/events{/number}","events_url":"https://api.github.com/repos/dotnet/roslyn/events","assignees_url":"https://api.github.com/repos/dotnet/roslyn/assignees{/user}","branches_url":"https://api.github.com/repos/dotnet/roslyn/branches{/branch}","tags_url":"https://api.github.com/repos/dotnet/roslyn/tags","blobs_url":"https://api.github.com/repos/dotnet/roslyn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dotnet/roslyn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dotnet/roslyn/git/refs{/sha}","trees_url":"https://api.github.com/repos/dotnet/roslyn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dotnet/roslyn/statuses/{sha}","languages_url":"https://api.github.com/repos/dotnet/roslyn/languages","stargazers_url":"https://api.github.com/repos/dotnet/roslyn/stargazers","contributors_url":"https://api.github.com/repos/dotnet/roslyn/contributors","subscribers_url":"https://api.github.com/repos/dotnet/roslyn/subscribers","subscription_url":"https://api.github.com/repos/dotnet/roslyn/subscription","commits_url":"https://api.github.com/repos/dotnet/roslyn/commits{/sha}","git_commits_url":"https://api.github.com/repos/dotnet/roslyn/git/commits{/sha}","comments_url":"https://api.github.com/repos/dotnet/roslyn/comments{/number}","issue_comment_url":"https://api.github.com/repos/dotnet/roslyn/issues/comments{/number}","contents_url":"https://api.github.com/repos/dotnet/roslyn/contents/{+path}","compare_url":"https://api.github.com/repos/dotnet/roslyn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dotnet/roslyn/merges","archive_url":"https://api.github.com/repos/dotnet/roslyn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dotnet/roslyn/downloads","issues_url":"https://api.github.com/repos/dotnet/roslyn/issues{/number}","pulls_url":"https://api.github.com/repos/dotnet/roslyn/pulls{/number}","milestones_url":"https://api.github.com/repos/dotnet/roslyn/milestones{/number}","notifications_url":"https://api.github.com/repos/dotnet/roslyn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dotnet/roslyn/labels{/name}","releases_url":"https://api.github.com/repos/dotnet/roslyn/releases{/id}","deployments_url":"https://api.github.com/repos/dotnet/roslyn/deployments","created_at":"2015-01-11T02:39:03Z","updated_at":"2018-04-01T16:14:29Z","pushed_at":"2018-04-01T21:58:51Z","git_url":"git://github.com/dotnet/roslyn.git","ssh_url":"git@github.com:dotnet/roslyn.git","clone_url":"https://github.com/dotnet/roslyn.git","svn_url":"https://github.com/dotnet/roslyn","homepage":"","size":327686,"stargazers_count":9077,"watchers_count":9077,"language":"C#","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2183,"mirror_url":null,"archived":false,"open_issues_count":4613,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":2183,"open_issues":4613,"watchers":9077,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/23984"},"html":{"href":"https://github.com/dotnet/roslyn/pull/23984"},"issue":{"href":"https://api.github.com/repos/dotnet/roslyn/issues/23984"},"comments":{"href":"https://api.github.com/repos/dotnet/roslyn/issues/23984/comments"},"review_comments":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/23984/comments"},"review_comment":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/23984/commits"},"statuses":{"href":"https://api.github.com/repos/dotnet/roslyn/statuses/d85162ad18d94b9c4b6bdd04cd597b9149321a62"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"CyrusNajmabadi"}}