Skip to content

Commit a0f49ca

Browse files
authored
Merge pull request #13339 from rintaro/syntax-parserposition
[Syntax] Fix roundtrip test
2 parents 9d0464c + 1615a67 commit a0f49ca

File tree

11 files changed

+129
-67
lines changed

11 files changed

+129
-67
lines changed

include/swift/Parse/CodeCompletionCallbacks.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class CodeCompletionCallbacks {
3434
protected:
3535
Parser &P;
3636
ASTContext &Context;
37-
Parser::ParserPosition ExprBeginPosition;
37+
ParserPosition ExprBeginPosition;
3838

3939
/// The declaration parsed during delayed parsing that was caused by code
4040
/// completion. This declaration contained the code completion token.
@@ -65,7 +65,7 @@ class CodeCompletionCallbacks {
6565
return CompleteExprSelectorContext != ObjCSelectorContext::None;
6666
}
6767

68-
void setExprBeginning(Parser::ParserPosition PP) {
68+
void setExprBeginning(ParserPosition PP) {
6969
ExprBeginPosition = PP;
7070
}
7171

include/swift/Parse/Lexer.h

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/DiagnosticEngine.h"
2121
#include "swift/Basic/SourceLoc.h"
2222
#include "swift/Basic/SourceManager.h"
23+
#include "swift/Parse/LexerState.h"
2324
#include "swift/Parse/Token.h"
2425
#include "swift/Syntax/References.h"
2526
#include "swift/Syntax/Trivia.h"
@@ -59,13 +60,15 @@ enum class ConflictMarkerKind {
5960
/// separated by 4 "="s, and terminated by 4 "<"s.
6061
Perforce
6162
};
62-
63+
6364
class Lexer {
6465
const LangOptions &LangOpts;
6566
const SourceManager &SourceMgr;
6667
DiagnosticEngine *Diags;
6768
const unsigned BufferID;
6869

70+
using State = LexerState;
71+
6972
/// Pointer to the first character of the buffer, even in a lexer that
7073
/// scans a subrange of the buffer.
7174
const char *BufferStart;
@@ -128,28 +131,6 @@ class Lexer {
128131
/// `TriviaRetentionMode::WithTrivia`.
129132
syntax::TriviaList TrailingTrivia;
130133

131-
public:
132-
/// \brief Lexer state can be saved/restored to/from objects of this class.
133-
class State {
134-
public:
135-
State() {}
136-
137-
bool isValid() const {
138-
return Loc.isValid();
139-
}
140-
141-
State advance(unsigned Offset) const {
142-
assert(isValid());
143-
return State(Loc.getAdvancedLoc(Offset));
144-
}
145-
146-
private:
147-
explicit State(SourceLoc Loc) : Loc(Loc) {}
148-
SourceLoc Loc;
149-
friend class Lexer;
150-
};
151-
152-
private:
153134
Lexer(const Lexer&) = delete;
154135
void operator=(const Lexer&) = delete;
155136

@@ -262,24 +243,27 @@ class Lexer {
262243
/// there.
263244
State getStateForBeginningOfToken(const Token &Tok,
264245
const syntax::Trivia &LeadingTrivia = {}) const {
265-
// If trivia parsing mode, start position of trivia is the position we want
266-
// to restore.
267-
if (TriviaRetention == TriviaRetentionMode::WithTrivia)
268-
return State(Tok.getLoc().getAdvancedLoc(-LeadingTrivia.getTextLength()));
269246

270247
// If the token has a comment attached to it, rewind to before the comment,
271248
// not just the start of the token. This ensures that we will re-lex and
272249
// reattach the comment to the token if rewound to this state.
273250
SourceLoc TokStart = Tok.getCommentStart();
274251
if (TokStart.isInvalid())
275252
TokStart = Tok.getLoc();
276-
return getStateForBeginningOfTokenLoc(TokStart);
253+
auto S = getStateForBeginningOfTokenLoc(TokStart);
254+
if (TriviaRetention == TriviaRetentionMode::WithTrivia)
255+
S.LeadingTrivia = LeadingTrivia.Pieces;
256+
return S;
277257
}
278258

279259
State getStateForEndOfTokenLoc(SourceLoc Loc) const {
280260
return State(getLocForEndOfToken(SourceMgr, Loc));
281261
}
282262

263+
bool isStateForCurrentBuffer(LexerState State) const {
264+
return SourceMgr.findBufferContainingLoc(State.Loc) == getBufferID();
265+
}
266+
283267
/// \brief Restore the lexer state to a given one, that can be located either
284268
/// before or after the current position.
285269
void restoreState(State S, bool enableDiagnostics = false) {
@@ -288,7 +272,13 @@ class Lexer {
288272
// Don't reemit diagnostics while readvancing the lexer.
289273
llvm::SaveAndRestore<DiagnosticEngine*>
290274
D(Diags, enableDiagnostics ? Diags : nullptr);
275+
291276
lexImpl();
277+
278+
// Restore Trivia.
279+
if (TriviaRetention == TriviaRetentionMode::WithTrivia)
280+
if (auto &LTrivia = S.LeadingTrivia)
281+
LeadingTrivia = std::move(*LTrivia);
292282
}
293283

294284
/// \brief Restore the lexer state to a given state that is located before

include/swift/Parse/LexerState.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//===--- LexerState.h - Lexer State -----------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the LexerState object.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_LEXERSTATE_H
18+
#define SWIFT_LEXERSTATE_H
19+
20+
#include "llvm/ADT/Optional.h"
21+
#include "swift/Basic/SourceLoc.h"
22+
#include "swift/Syntax/Trivia.h"
23+
24+
namespace swift {
25+
class Lexer;
26+
27+
/// \brief Lexer state can be saved/restored to/from objects of this class.
28+
class LexerState {
29+
public:
30+
LexerState() {}
31+
32+
bool isValid() const { return Loc.isValid(); }
33+
34+
LexerState advance(unsigned Offset) const {
35+
assert(isValid());
36+
return LexerState(Loc.getAdvancedLoc(Offset));
37+
}
38+
39+
private:
40+
explicit LexerState(SourceLoc Loc) : Loc(Loc) {}
41+
SourceLoc Loc;
42+
llvm::Optional<syntax::TriviaList> LeadingTrivia;
43+
friend class Lexer;
44+
};
45+
46+
} // end namespace swift
47+
48+
#endif

include/swift/Parse/Parser.h

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/Parse/LocalContext.h"
3131
#include "swift/Parse/PersistentParserState.h"
3232
#include "swift/Parse/Token.h"
33+
#include "swift/Parse/ParserPosition.h"
3334
#include "swift/Parse/ParserResult.h"
3435
#include "swift/Parse/SyntaxParserResult.h"
3536
#include "swift/Syntax/SyntaxParsingContext.h"
@@ -358,24 +359,6 @@ class Parser {
358359
//===--------------------------------------------------------------------===//
359360
// Routines to save and restore parser state.
360361

361-
class ParserPosition {
362-
public:
363-
ParserPosition() = default;
364-
ParserPosition &operator=(const ParserPosition &) = default;
365-
366-
bool isValid() const {
367-
return LS.isValid();
368-
}
369-
370-
private:
371-
ParserPosition(Lexer::State LS, SourceLoc PreviousLoc):
372-
LS(LS), PreviousLoc(PreviousLoc)
373-
{}
374-
Lexer::State LS;
375-
SourceLoc PreviousLoc;
376-
friend class Parser;
377-
};
378-
379362
ParserPosition getParserPosition() {
380363
return ParserPosition(L->getStateForBeginningOfToken(Tok, LeadingTrivia),
381364
PreviousLoc);

include/swift/Parse/ParserPosition.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===--- ParserPosition.h - Parser Position ---------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Parser position where Parser can jump to.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_PARSE_PARSERPOSITION_H
18+
#define SWIFT_PARSE_PARSERPOSITION_H
19+
20+
#include "swift/Basic/SourceLoc.h"
21+
#include "swift/Parse/LexerState.h"
22+
23+
namespace swift {
24+
25+
class ParserPosition {
26+
LexerState LS;
27+
SourceLoc PreviousLoc;
28+
friend class Parser;
29+
30+
ParserPosition(LexerState LS, SourceLoc PreviousLoc)
31+
: LS(LS), PreviousLoc(PreviousLoc) {}
32+
public:
33+
ParserPosition() = default;
34+
ParserPosition &operator=(const ParserPosition &) = default;
35+
36+
bool isValid() const { return LS.isValid(); }
37+
};
38+
39+
} // end namespace swift
40+
41+
#endif

include/swift/Parse/PersistentParserState.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "swift/Basic/SourceLoc.h"
2121
#include "swift/Parse/LocalContext.h"
22+
#include "swift/Parse/ParserPosition.h"
2223
#include "swift/Parse/Scope.h"
2324
#include "llvm/ADT/DenseMap.h"
2425

@@ -114,7 +115,7 @@ class PersistentParserState {
114115
DelayedAccessorBodiesTy DelayedAccessorBodies;
115116

116117
/// \brief Parser sets this if it stopped parsing before the buffer ended.
117-
ParserPos MarkedPos;
118+
ParserPosition MarkedPos;
118119

119120
std::unique_ptr<DelayedDeclState> CodeCompletionDelayedDeclState;
120121

@@ -166,16 +167,16 @@ class PersistentParserState {
166167
return TopLevelCode;
167168
}
168169

169-
void markParserPosition(SourceLoc Loc, SourceLoc PrevLoc,
170+
void markParserPosition(ParserPosition Pos,
170171
bool InPoundLineEnvironment) {
171-
MarkedPos = {Loc, PrevLoc};
172+
MarkedPos = Pos;
172173
this->InPoundLineEnvironment = InPoundLineEnvironment;
173174
}
174175

175176
/// \brief Returns the marked parser position and resets it.
176-
ParserPos takeParserPosition() {
177-
ParserPos Pos = MarkedPos;
178-
MarkedPos = ParserPos();
177+
ParserPosition takeParserPosition() {
178+
ParserPosition Pos = MarkedPos;
179+
MarkedPos = ParserPosition();
179180
return Pos;
180181
}
181182
};

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ bool Parser::parseTopLevel() {
270270

271271
// Next time start relexing from the beginning of the comment so that we can
272272
// attach it to the token.
273-
State->markParserPosition(Tok.getCommentRange().getStart(), PreviousLoc,
273+
State->markParserPosition(getParserPosition(),
274274
InPoundLineEnvironment);
275275

276276
// If we are done parsing the whole file, finalize the token receiver.

lib/Parse/ParseExpr.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,13 +1926,13 @@ ParserResult<Expr> Parser::parseExprStringLiteral() {
19261926
TmpContext.setDiscard();
19271927

19281928
// Create a temporary lexer that lexes from the body of the string.
1929-
Lexer::State BeginState =
1929+
LexerState BeginState =
19301930
L->getStateForBeginningOfTokenLoc(Segment.Loc);
19311931
// We need to set the EOF at r_paren, to prevent the Lexer from eagerly
19321932
// trying to lex the token beyond it. Parser::parseList() does a special
19331933
// check for a tok::EOF that is spelled with a ')'.
19341934
// FIXME: This seems like a hack, there must be a better way..
1935-
Lexer::State EndState = BeginState.advance(Segment.Length-1);
1935+
LexerState EndState = BeginState.advance(Segment.Length-1);
19361936
Lexer LocalLex(*L, BeginState, EndState);
19371937

19381938
// Temporarily swap out the parser's current lexer with our new one.
@@ -2235,8 +2235,8 @@ Expr *Parser::parseExprEditorPlaceholder(Token PlaceholderTok,
22352235
SourceLoc TypeStartLoc = PlaceholderTok.getLoc().getAdvancedLoc(Offset);
22362236
SourceLoc TypeEndLoc = TypeStartLoc.getAdvancedLoc(TyStr.size());
22372237

2238-
Lexer::State StartState = L->getStateForBeginningOfTokenLoc(TypeStartLoc);
2239-
Lexer::State EndState = L->getStateForBeginningOfTokenLoc(TypeEndLoc);
2238+
LexerState StartState = L->getStateForBeginningOfTokenLoc(TypeStartLoc);
2239+
LexerState EndState = L->getStateForBeginningOfTokenLoc(TypeEndLoc);
22402240

22412241
// Create a lexer for the type sub-string.
22422242
Lexer LocalLex(*L, StartState, EndState);

lib/Parse/Parser.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,9 +460,8 @@ Parser::Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF,
460460

461461
auto ParserPos = State->takeParserPosition();
462462
if (ParserPos.isValid() &&
463-
SourceMgr.findBufferContainingLoc(ParserPos.Loc) == L->getBufferID()) {
464-
auto BeginParserPosition = getParserPosition(ParserPos);
465-
restoreParserPosition(BeginParserPosition);
463+
L->isStateForCurrentBuffer(ParserPos.LS)) {
464+
restoreParserPosition(ParserPos);
466465
InPoundLineEnvironment = State->InPoundLineEnvironment;
467466
}
468467
}

unittests/Parse/LexerTests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ TEST_F(LexerTest, RestoreBasic) {
132132
ASSERT_EQ("bbb", Tok.getText());
133133
ASSERT_FALSE(Tok.isAtStartOfLine());
134134

135-
Lexer::State S = L.getStateForBeginningOfToken(Tok);
135+
LexerState S = L.getStateForBeginningOfToken(Tok);
136136

137137
L.lex(Tok);
138138
ASSERT_EQ(tok::identifier, Tok.getKind());
@@ -179,7 +179,7 @@ TEST_F(LexerTest, RestoreNewlineFlag) {
179179
ASSERT_EQ("bbb", Tok.getText());
180180
ASSERT_TRUE(Tok.isAtStartOfLine());
181181

182-
Lexer::State S = L.getStateForBeginningOfToken(Tok);
182+
LexerState S = L.getStateForBeginningOfToken(Tok);
183183

184184
L.lex(Tok);
185185
ASSERT_EQ(tok::identifier, Tok.getKind());
@@ -231,7 +231,7 @@ TEST_F(LexerTest, RestoreStopAtCodeCompletion) {
231231
ASSERT_EQ("bbb", Tok.getText());
232232
ASSERT_FALSE(Tok.isAtStartOfLine());
233233

234-
Lexer::State S = L.getStateForBeginningOfToken(Tok);
234+
LexerState S = L.getStateForBeginningOfToken(Tok);
235235

236236
L.lex(Tok);
237237
ASSERT_EQ(tok::identifier, Tok.getKind());
@@ -290,7 +290,7 @@ TEST_F(LexerTest, RestoreWithTrivia) {
290290
(Trivia{{TriviaPiece::newlines(1), TriviaPiece::spaces(1)}}));
291291
ASSERT_EQ(TrailingTrivia, (Trivia{{TriviaPiece::spaces(1)}}));
292292

293-
Lexer::State S = L.getStateForBeginningOfToken(Tok, LeadingTrivia);
293+
LexerState S = L.getStateForBeginningOfToken(Tok, LeadingTrivia);
294294

295295
L.lex(Tok, LeadingTrivia, TrailingTrivia);
296296
ASSERT_EQ(tok::identifier, Tok.getKind());

utils/round-trip-syntax-test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ This driver invokes swift-syntax-test using -round-trip-lex and
172172
args.skip_bad_syntax)
173173
for filename in all_input_files]
174174

175-
failed = reduce(lambda a, b: a and b,
175+
failed = reduce(lambda a, b: a or b,
176176
map(run_task, lex_tasks + parse_tasks))
177177
sys.exit(1 if failed else 0)
178178

0 commit comments

Comments
 (0)