Skip to content
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

[Parse] An implementation for SE-0182 #11080

Merged
merged 1 commit into from
Jul 25, 2017
Merged

[Parse] An implementation for SE-0182 #11080

merged 1 commit into from
Jul 25, 2017

Conversation

johnno1962
Copy link
Contributor

@johnno1962 johnno1962 commented Jul 20, 2017

@milseman, here is an implementation of SE-0182 - https://github.com/apple/swift-evolution/blob/7c84029d89163dd65bdd4766e8aea0aa398b12fe/proposals/0182-newline-escape-in-strings.md. It is complete and tested except for checking whether the \ escape is used on the last line which is, TBH, hard to implement and a no-op anyway. If you have any other suggesttions for tests let me know. I think the two tests I added exercise all code paths in the changes to the implementation.

@milseman
Copy link
Member

@swift-ci please test

Copy link
Member

@milseman milseman left a comment

Choose a reason for hiding this comment

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

Overall looks good. I would like some more tests, and maybe some weigh-in from @jrose-apple or @nkcsgexi

}
}
return false;
}
Copy link
Member

Choose a reason for hiding this comment

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

I realize much of the Lexer is inconsistent in this usage, but Clang's CharInfo.h (which is used in this file) does provide isWhitespace, isHorizontalWhitespace and isVerticalWhitespace.

@jrose-apple or @nkcsgexi or anyone who would know better, is it desirable to use these instead?

Similarly for the rest of this patch

Copy link
Contributor Author

Choose a reason for hiding this comment

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

difficult to use in a switch the way things are coded

// CHECK: "substring1 "
// CHECK: "substring2 substring3"

_ = """
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if this is tested here, but is all whitespace after the \ skipped?

Also, we should explicitly test behavior when non-whitespace follows the backslash, including comments, as an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

all whitespace skipped. I’ll add an error on non-whitespace test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

… which reveals a bug :)

@jrose-apple jrose-apple requested a review from rintaro July 20, 2017 22:01
Copy link
Contributor

@jrose-apple jrose-apple left a comment

Choose a reason for hiding this comment

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

Not so familiar with Parse these days, so deferring to Xi and Rintaro.

@@ -1189,6 +1189,27 @@ unsigned Lexer::lexUnicodeEscape(const char *&CurPtr, Lexer *Diags) {
return CharValue;
}

/// isElidedNewlineEscape - Check for valid elided newline escape and
/// move pointer passed in to the character after the end of the line.
static bool isElidedNewlineEscape(const char *&CurPtr, ssize_t Offset) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm unhappy with a function named like a predicate having side effects. How about something like maybeConsumeNewlineEscape?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair enough, renamed.

@johnno1962
Copy link
Contributor Author

Toolchain uploaded for test drive: http://johnholdsworth.com/swift-LOCAL-2017-07-20-a-osx.tar.gz

@@ -1921,6 +1952,12 @@ StringRef Lexer::getEncodedStringSegment(StringRef Bytes,
case '\'': TempString.push_back('\''); continue;
case '\\': TempString.push_back('\\'); continue;

case ' ': case '\t': case '\n': case '\r':
if(maybeConsumeNewlineEscape(BytesPtr, -1)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: insert space after if :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ha! There had to be something :)

"""

// CHECK: "trailing "
// CHECK: "substring1 "
Copy link
Member

@rintaro rintaro Jul 21, 2017

Choose a reason for hiding this comment

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

This shouldn't be "substring1 " (3 space) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How do you mean?

Copy link
Member

Choose a reason for hiding this comment

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

Ah my bad, please ignore this comment.

\("""
substring2 \
substring3
""")\
Copy link
Member

Choose a reason for hiding this comment

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

Rationale for SE-182 states:

It also discussed whether \ should be allowed on the line immediately following the close """ and agreed that it was best to not allow it in this go-around.

This \ should be rejected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This looks like a mistake in the updated proposal. It should read “immediately preceding”.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not implemented as an error.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, sorry. I didn't read the PR comment.

@rintaro
Copy link
Member

rintaro commented Jul 21, 2017

Could you add tests for these cases?

_ = """
    foo\ ↵
↵
    bar↵
    """ // -> "foo\nbar"

_ = """
    foo\ ↵
    ↵
    bar↵
    """ // -> "foo\nbar"

@rintaro
Copy link
Member

rintaro commented Jul 21, 2017

Also:

_ = """
    foo \
      bar
    """ // -> "foo   bar"

line one \ non-whitepace
line two
"""
// expected-error@-3 {{Invalid escape sequence in literal}}
Copy link
Member

Choose a reason for hiding this comment

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

nit: "invalid not "Invalid

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks!

case ' ': case '\t': case '\n': case '\r':
if (MultilineString && maybeConsumeNewlineEscape(CurPtr, -1))
continue;
LLVM_FALLTHROUGH;
Copy link
Member

@rintaro rintaro Jul 21, 2017

Choose a reason for hiding this comment

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

Maybe not a big problem, but this regress the diagnostics for "foo \("\ ")"

test.swift:1:21: error: unterminated string literal
let a = "foo \("\ ")"
                    ^
test.swift:1:20: error: consecutive statements on a line must be separated by ';'
let a = "foo \("\ ")"
                   ^
                   ;
test.swift:1:20: error: expected expression
let a = "foo \("\ ")"
                   ^

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 this would be sufficient:

        case '\n': case '\r':
          if (AllowNewline.back())
            continue;
          LLVM_FALLTHROUGH;
        case 0:
          // Don't jump over newline/EOF due to preceding backslash!
          return CurPtr-1;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well spotted! fixed

@rintaro
Copy link
Member

rintaro commented Jul 21, 2017

LGTM, deferring to @nkcsgexi

@rintaro rintaro requested a review from nkcsgexi July 21, 2017 04:54
escapedChar == ' ' || escapedChar == '\t')
continue;
LLVM_FALLTHROUGH;
case 0:
// Don't jump over newline/EOF due to preceding backslash!
Copy link
Collaborator

Choose a reason for hiding this comment

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

This comment needs to be updated, methinks.

@johnno1962
Copy link
Contributor Author

Updated toolchain toolchain: http://johnholdsworth.com/swift-LOCAL-2017-07-21-a-osx.tar.gz

@johnno1962 johnno1962 changed the title An implementation for SE-0182 [Parse] An implementation for SE-0182 Jul 21, 2017
@DougGregor
Copy link
Member

@swift-ci please smoke test

@DougGregor DougGregor merged commit 6d06792 into swiftlang:master Jul 25, 2017
@johnno1962
Copy link
Contributor Author

Thanks @DougGregor, @milseman, @rintaro, @xwu

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.

None yet

6 participants