Skip to content

Add in a json parser so that the IDE can provide services around json editing.#24110

Closed
CyrusNajmabadi wants to merge 37 commits intodotnet:features/embeddedJsonfrom
CyrusNajmabadi:jsonParsing
Closed

Add in a json parser so that the IDE can provide services around json editing.#24110
CyrusNajmabadi wants to merge 37 commits intodotnet:features/embeddedJsonfrom
CyrusNajmabadi:jsonParsing

Conversation

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi commented Jan 8, 2018

Followup to #23984

So JFK has busted pipes. So i've been in airport limbo :-( On a good note, it gave me some time to expand on my previous Regex PR. Now, on top of Regex support in the IDE we also support JSON strings.

This also expands the previous interaction model with built in json detection for string tokens. i.e., if we see:

image

Then we'll offer:

image

This then helps users see how they can add a comment that lights-up IDE features for these types of strings. Note: i don't do this for regexes because of a concern about too many false positives. Once the comment is added things like up like so:

image

Of course, squiggles and braces are supported, on top of just colors:

image

Also, if you're using JToken/JObject/JArray, then you don't need to provide the comment (similar to how new Regex(pattern) is automatically detected:

image

Things to note:

  1. unlike regexes, this was much simpler to provide. That's because json is much simpler and much better documented versus the .net regex model.
  2. Two forms of json are supported. A strict mode that aligns with the IETF rfc for json, as well as Json.net's format. Json.net is clearly the .net json winner (almost 100m downloads) and is most likely what people will be using. Json.net allows a superset of standard json strings (including allowing things like comments, as well as other constructs that would normally be errors in es6 json).
  3. This leverages the VirtualChar work from the regex work, demonstrating that this is a suitable subsystem for general DSL plugins.

@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner January 8, 2018 22:04
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Tagging @dotnet/roslyn-ide @Pilchie

@jasonmalinowski
Copy link
Copy Markdown
Member

@CyrusNajmabadi Should we wait until the regex one is resolved prior to looking at this one? This PR is quite, quite large.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Should we wait until the regex one is resolved prior to looking at this one?

That woudl be my recommendation :)

This PR is quite, quite large.

It's a mere 46k lines. If you do 2k lines an hour, you can finish it by tomorrow!

@sharwell sharwell added this to the 15.8 milestone Jan 8, 2018
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Options look like this:

image

@yaakov-h
Copy link
Copy Markdown
Member

yaakov-h commented Jan 9, 2018

Can we just keep you in various airports? 😆

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Tomorrow LaGuardia!

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

CyrusNajmabadi commented Mar 16, 2018

I have updated this PR to only be the json parser work. PR for IDE features around json strings has now moved into #25518

JSON parsing tests were pulled into: #25521

ImmutableArray<JsonTrivia> trailingTrivia, ImmutableArray<EmbeddedDiagnostic> diagnostics)
=> CreateToken(kind, leadingTrivia, virtualChars, trailingTrivia, diagnostics, value: null);

public static JsonToken CreateToken(JsonKind kind,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is only used once (on line 20). Inline?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. #resolved.


internal static class JsonHelpers
{
public static JsonToken CreateToken(JsonKind kind, ImmutableArray<JsonTrivia> leadingTrivia, ImmutableArray<VirtualChar> virtualChars, ImmutableArray<JsonTrivia> trailingTrivia)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: maybe break this line

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. #resolved.

@jcouv
Copy link
Copy Markdown
Member

jcouv commented Apr 3, 2018

Could you retarget to the feature branch?

{
internal enum JsonKind
{
None,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used? If not, maybe None = 0 or remove?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like this as it makes it easy to test if a token is default.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be None = 0 then?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. i can do that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#resolved.

Text = text;
}

public VirtualChar CurrentChar => Position < Text.Length ? Text[Position] : new VirtualChar((char)0, default);
Copy link
Copy Markdown
Member

@jcouv jcouv Apr 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: name span: default?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. #resolved.


public VirtualChar CurrentChar => Position < Text.Length ? Text[Position] : new VirtualChar((char)0, default);

public ImmutableArray<VirtualChar> GetSubPattern(int start, int end)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end is generally Position. Consider adding an overload where end is implicit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. #resolved.

case '\'': case '"':
return ScanString();

//case '-': case '.':
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this commented out?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comment explaining why we do not explicitly lex out numbers here, but instead let the parser take control. #resolved.

private (ImmutableArray<VirtualChar>, JsonKind, EmbeddedDiagnostic?) ScanString()
{
var start = Position;
var startChar = this.CurrentChar.Char;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps rename openChar?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. #resolved.

return (chars, JsonKind.StringToken, diagnostic);
}

private EmbeddedDiagnostic? ScanEscape(int stringStart, int escapeStart)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScanEscape could use a comment since unlike other scan methods, it doesn't return tokens or nodes, it just advances the position.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. #Resolved

return (GetSubPattern(start, Position), JsonKind.TextToken, null);
}

private (ImmutableArray<VirtualChar>, JsonKind, EmbeddedDiagnostic?)? TryScanText(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method seems unused

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed. removed. #resolved.

var chars = GetSubPattern(start, Position);
if (Position == start + 2)
{
var diagnostics = ImmutableArray.Create(new EmbeddedDiagnostic(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if // are the last two characters in the file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then you get an unterminated comment diagnostic. This matches json.net. You can see a test for that here: https://github.com/dotnet/roslyn/pull/25521/files#diff-d0475d1c64e0a4bb26665ae88ff3cf24R158

Will add a comment explaining this is intentional.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added comment. #resolved.

GetTextSpan(start, Position))));
}

public TextSpan GetTextSpan(int startInclusive, int endExclusive)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method seems to only be used once. private?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made privat.e #resolved

@justcla
Copy link
Copy Markdown

justcla commented Jun 25, 2018

FYI: JetBrains have implemented support for the short form "lang=" (as well as the original "language=" form).
It will be available in ReSharper 2018.2

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

FYI: JetBrains have implemented support for the short form "lang=" (as well as the original "language=" form).

Were you asking me to support both those forms? If so, i already do :)

Also, would you be able to assist in any way with teh reviews on this. It looks like this has completely stalled out and isn't making any forward progress, even after 6 months...

@justcla
Copy link
Copy Markdown

justcla commented Jun 25, 2018

When reviewing it, I noticed that you implemented lang= and language=.
I noticed that JetBrains also implemented as similar behavior, but they were only using the language= form. So that people using ReSharper would get the behavior expected by users who used your short form, I asked JetBrains if they would consider also implementing the short form.
And I just found out that they did. (Thanks JetBrains!)
So that makes it easier to bring your code into the product - as we will have consistency among users with different tools.

As for progress, it's just a matter of resourcing. The team has been prioritizing other features for 15.8. (You know how it is.)

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@sharwell @jinujoseph How would you like to proceed on this?

1 similar comment
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

@sharwell @jinujoseph How would you like to proceed on this?

@jinujoseph
Copy link
Copy Markdown
Contributor

Unfortunately, This feature is currently not in the top priority for us to pursue, so this is on hold at this moment. Following up to see if we can get merge this to feature branch

@sharwell sharwell removed their assignment Oct 17, 2018
@jinujoseph
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi as discussed closing this PR for now.

@jinujoseph jinujoseph closed this Nov 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants