Skip to content

Fix newline parsing at trailing trivia #1661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 15, 2023

Conversation

TTOzzi
Copy link
Member

@TTOzzi TTOzzi commented May 14, 2023

Resolve #1626

Unlike leadingTrivia, trailingTrivia was not using the newlinePresence value of triviaResult.
Modified the logic to store the trailingTrivia newlinePresence value from the previous token and set isAtStartOfLine flag when parsing the next token.

@TTOzzi TTOzzi requested a review from ahoppen as a code owner May 14, 2023 12:15
Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Thanks for figuring this out @TTOzzi. I’ve got a couple questions/comments inline. Otherwise, this looks very good to me 👍🏽

flags.insert(.isAtStartOfLine)
}
if let previousTokenNewlinePresence, previousTokenNewlinePresence == .present,
!currentState.isParsingMultilineString {
Copy link
Member

Choose a reason for hiding this comment

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

Why do you need the isParsingMultilineString check? I just tried removing it and it looks like I just need to update three lexer tests, which seems perfectly reasonable to me because the line 1 and line 2 tokens really are on new lines.

Copy link
Member Author

Choose a reason for hiding this comment

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

In an effort to minimize side effects, I focused on maintaining the existing test cases, which led me to misunderstand the behavior of the lexer. As you mentioned, it is correct that the line1, line2, and whitespace tokens, excluding the """ character, are really on new lines.
I will try to make the modifications quickly within this week. Thank you for your prompt feedback 🙂

Comment on lines 259 to 261

/// If we have already lexed a token, the `NewlinePresence` of the previously lexed token
var previousTokenNewlinePresence: NewlinePresence?
Copy link
Member

Choose a reason for hiding this comment

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

Just a naming suggestion: I’d like to make it absolutely clear that this is about whether the previous token’s trailing trivia has a newline and avoid any confusion of whether the previous token had a newline inside its leading trivia. So I’d go with

Suggested change
/// If we have already lexed a token, the `NewlinePresence` of the previously lexed token
var previousTokenNewlinePresence: NewlinePresence?
/// If we have already lexed a token, stores whether the previous lexeme‘s trailing trivia contains a newline.
var previousLexemeTrailingTrivaNewlinePresence: NewlinePresence?

Copy link
Member Author

Choose a reason for hiding this comment

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

Great suggestion! I will try to make the modifications along with the changes mentioned above. Thank you.

@TTOzzi TTOzzi requested a review from ahoppen May 15, 2023 15:13
@@ -433,28 +445,24 @@ extension Lexer.Cursor {
if let stateTransition = result.stateTransition {
self.stateStack.perform(stateTransition: stateTransition, stateAllocator: stateAllocator)
}

Copy link
Member

Choose a reason for hiding this comment

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

I think swift-format will complain about this whitespace. Could you run format.py? https://github.com/apple/swift-syntax/blob/main/CONTRIBUTING.md#formatting

Copy link
Member Author

Choose a reason for hiding this comment

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

Oops, I missed that!
I'll make sure to run it before every commit.
Thanks for pointing that out 🙇

if let previousLexemeTrailingNewlinePresence, previousLexemeTrailingNewlinePresence == .present {
flags.insert(.isAtStartOfLine)
}
self.previousLexemeTrailingNewlinePresence = nil
Copy link
Member

Choose a reason for hiding this comment

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

Resetting to nil doesn’t really make sense here, right? If we follow the same meaning as for previousTokenKind, nil means that there hasn’t been a previous token but in this case there has been. I think the better implementation would be to have in else branch in the if statement in which you set self.previousLexemeTrailingNewlinePresence below and in it set self.previousLexemeTrailingNewlinePresence = .absent.

If you do that, I think you can also move this entire code block below the Token text lexing section and initialize flags with result.flags and avoid the union call when forming the result.

Copy link
Member Author

@TTOzzi TTOzzi May 15, 2023

Choose a reason for hiding this comment

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

As you said, it seems like it should have a non-nil value when lexing the previous token.
However, I'm concerned that it would be redundant to assign .absent to each else in the branch that sets previousLexemeTrailingNewlinePresence.

https://github.com/apple/swift-syntax/pull/1661/files#diff-253b01bc981faa185173c1697784a41bf1b586e91ec7b4de806dfd2646db52c3R1900

The code above makes it look like I need to put previousLexemeTrailingNewlinePresence = .absent in the lex logic for each case.
https://github.com/apple/swift-syntax/blob/main/Sources/SwiftParser/Lexer/Cursor.swift#L410-L431

How about assigning .absent as the default value after using previousLexemeTrailingNewlinePresence at that position?
I think we can get some reasonable logic with little modification.

Suggested change
self.previousLexemeTrailingNewlinePresence = nil
self.previousLexemeTrailingNewlinePresence = .absent

Copy link
Member Author

Choose a reason for hiding this comment

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

Additionally, if we move this block of code below the token text lexing section, the value assigned in the token text lexing logic will affect the flag value of the current token, so it would be difficult to move it 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, now that I think about it, inside the lexing logic, it makes more sense to include the flag in the lexer's result and return it.
I'll make a quick fix and commit it.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, that’s just what I was just about to suggest

Copy link
Member Author

@TTOzzi TTOzzi May 15, 2023

Choose a reason for hiding this comment

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

Similar to TriviaResult, I also added a trailingNewlinePresence property to Lexer.Result and changed it so that modifications to the previousLexemeTrailingNewlinePresence value can only be made within the nextToken method.
The flag initialize logic was also moved under the token text lexing section.

@TTOzzi TTOzzi force-pushed the fix-newline-parsing-at-trailing-trivia branch from 7732f6e to 8e6ce86 Compare May 15, 2023 16:50
@TTOzzi TTOzzi requested a review from ahoppen May 15, 2023 17:10
Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Thanks. This looks good ✅

@ahoppen
Copy link
Member

ahoppen commented May 15, 2023

@swift-ci Please test

@ahoppen ahoppen merged commit 94959f0 into swiftlang:main May 15, 2023
@TTOzzi
Copy link
Member Author

TTOzzi commented May 16, 2023

I appreciate your kind feedback. Thank you @ahoppen!

@ahoppen
Copy link
Member

ahoppen commented May 16, 2023

@TTOzzi Could you also open a PR with this changes targeting the release/5.9 branch? Since this fixes a proper parsing bug, I would like to include it in the Swift 5.9 release.

@TTOzzi
Copy link
Member Author

TTOzzi commented May 16, 2023

@ahoppen Of course, I can do it! When should I create the PR until?

@ahoppen
Copy link
Member

ahoppen commented May 16, 2023

There is no clear deadline at the moment. Earlier is always better than later though 😉

@TTOzzi
Copy link
Member Author

TTOzzi commented May 16, 2023

Ok. It's currently working hours here, so I'll create it after I finish work and leave for the day 😉

@ahoppen
Copy link
Member

ahoppen commented May 16, 2023

Anytime this week is equally good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Statements that are separated by a newline inside a block comment are not accepted
2 participants