Skip to content

Commit 1b2b70e

Browse files
author
Nathan Hawes
committed
[SyntaxParse] Parse PoundAssertStmt
Also added parseExpressionSyntax as an intermediate syntax parser until expression parsing is completely implemented.
1 parent 07f2e53 commit 1b2b70e

File tree

7 files changed

+163
-27
lines changed

7 files changed

+163
-27
lines changed

include/swift/Parse/ASTGen.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class ASTGen {
3838
// them
3939
/// Types that cannot be represented by Syntax or generated by ASTGen.
4040
llvm::DenseMap<SourceLoc, TypeRepr *> Types;
41+
/// Exprs that cannot be represented by Syntax or generated by ASTGen.
42+
llvm::DenseMap<SourceLoc, Expr *> Exprs;
4143

4244
llvm::DenseMap<SourceLoc, DeclAttributes> ParsedDeclAttrs;
4345

@@ -74,6 +76,13 @@ class ASTGen {
7476
static MagicIdentifierLiteralExpr::Kind
7577
getMagicIdentifierLiteralKind(tok Kind);
7678

79+
public:
80+
//===--------------------------------------------------------------------===//
81+
// Statements
82+
83+
Stmt *generate(const syntax::PoundAssertStmtSyntax &Stmt,
84+
const SourceLoc Loc);
85+
7786
public:
7887
//===--------------------------------------------------------------------===//
7988
// Types.
@@ -160,6 +169,13 @@ class ASTGen {
160169
static SourceLoc advanceLocBegin(const SourceLoc &Loc,
161170
const syntax::Syntax &Node);
162171

172+
/// Advance \p Loc to the last non-missing token of the \p Node or, if it
173+
/// doesn't contain any, the last non-missing token preceding it in the tree.
174+
/// \p Loc must be the leading trivia of the first token in the tree in which
175+
/// \p Node resides
176+
static SourceLoc advanceLocEnd(const SourceLoc &Loc,
177+
const syntax::Syntax &Node);
178+
163179
ValueDecl *lookupInScope(DeclName Name);
164180

165181
void addToScope(ValueDecl *D, bool diagnoseRedefinitions = true);
@@ -173,6 +189,10 @@ class ASTGen {
173189
bool hasType(const SourceLoc Loc) const;
174190
TypeRepr *getType(const SourceLoc Loc) const;
175191

192+
void addExpr(Expr *Expr, const SourceLoc Loc);
193+
bool hasExpr(const SourceLoc Loc) const;
194+
Expr *getExpr(const SourceLoc Loc) const;
195+
176196
void addDeclAttributes(DeclAttributes attrs, const SourceLoc Loc);
177197
bool hasDeclAttributes(SourceLoc Loc) const;
178198
DeclAttributes getDeclAttributes(const SourceLoc Loc) const;

include/swift/Parse/Parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,7 @@ class Parser {
14201420

14211421
//===--------------------------------------------------------------------===//
14221422
// Expression Parsing
1423+
ParsedSyntaxResult<ParsedExprSyntax> parseExpressionSyntax(Diag<> ID);
14231424
ParserResult<Expr> parseExpr(Diag<> ID) {
14241425
return parseExprImpl(ID, /*isExprBasic=*/false);
14251426
}
@@ -1603,6 +1604,7 @@ class Parser {
16031604
ParserStatus parseStmtCases(SmallVectorImpl<ASTNode> &cases, bool IsActive);
16041605
ParserResult<CaseStmt> parseStmtCase(bool IsActive);
16051606
ParserResult<Stmt> parseStmtPoundAssert();
1607+
ParsedSyntaxResult<ParsedPoundAssertStmtSyntax> parseStmtPoundAssertSyntax();
16061608

16071609
//===--------------------------------------------------------------------===//
16081610
// Generics Parsing

include/swift/Syntax/Syntax.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ class Syntax {
169169
/// Returns true if the node is "present" in the source.
170170
bool isPresent() const;
171171

172+
/// Get the node immediately before this current node that does contain a
173+
/// non-missing token. Return nullptr if we cannot find such node.
174+
Optional<Syntax> getPreviousNode() const;
172175

173176
/// Returns the first non-missing token in this syntax. Returns None if there
174177
/// is no non-missing token.

lib/Parse/ASTGen.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,10 +711,50 @@ LayoutConstraint ASTGen::generate(const LayoutConstraintSyntax &constraint,
711711
Context);
712712
}
713713

714+
Stmt *ASTGen::generate(const syntax::PoundAssertStmtSyntax &Stmt,
715+
const SourceLoc Loc) {
716+
// Don't form a PoundAssertStmt without a condition
717+
if (Stmt.getCondition().isUnknown())
718+
return nullptr;
719+
SourceLoc CondLoc = advanceLocBegin(Loc, Stmt.getCondition());
720+
if (!hasExpr(CondLoc))
721+
return nullptr;
722+
723+
Expr *CondExpr = getExpr(CondLoc);
724+
SourceLoc Start = advanceLocBegin(Loc, Stmt.getPoundAssert());
725+
SourceLoc End = advanceLocEnd(Loc, Stmt.getRightParen());
726+
727+
StringRef MessageText = "";
728+
if (auto Message = Stmt.getMessage()) {
729+
auto Tok = P.L->getTokenAt(generate(*Message, Loc));
730+
SmallVector<Lexer::StringSegment, 1> Segments;
731+
P.L->getStringLiteralSegments(Tok, Segments);
732+
if (Segments.size() == 1 &&
733+
Segments.front().Kind == Lexer::StringSegment::Literal &&
734+
// FIXME: Support extended escaping string literal.
735+
Tok.getCustomDelimiterLen() == 0) {
736+
MessageText = P.SourceMgr.extractText(
737+
CharSourceRange(Segments.front().Loc, Segments.front().Length));
738+
}
739+
}
740+
return new (Context) PoundAssertStmt(SourceRange(Start, End), CondExpr,
741+
MessageText);
742+
}
743+
714744
SourceLoc ASTGen::advanceLocBegin(const SourceLoc &Loc, const Syntax &Node) {
715745
return Loc.getAdvancedLoc(Node.getAbsolutePosition().getOffset());
716746
}
717747

748+
SourceLoc ASTGen::advanceLocEnd(const SourceLoc &Loc,
749+
const syntax::Syntax &Node) {
750+
if (auto Tok = Node.getLastToken())
751+
return advanceLocBegin(Loc, *Tok);
752+
if (auto Prev = Node.getPreviousNode())
753+
return advanceLocBegin(Loc, *Prev->getLastToken());
754+
assert(false && "No tokens in tree?");
755+
return Loc;
756+
}
757+
718758
StringRef ASTGen::copyAndStripUnderscores(StringRef Orig) {
719759
return copyAndStripUnderscores(Orig, Context);
720760
}
@@ -780,6 +820,30 @@ TypeRepr *ASTGen::getType(const SourceLoc Loc) const {
780820
return Types.find(Loc)->second;
781821
}
782822

823+
void ASTGen::addExpr(Expr *E, const SourceLoc Loc) {
824+
#ifndef NDEBUG
825+
if (hasExpr(Loc)) {
826+
bool PrevIsSubExpr = false;
827+
Expr *Prev = Exprs.find(Loc)->second;
828+
E->forEachChildExpr([&](Expr *Child) {
829+
if (Child == Prev)
830+
PrevIsSubExpr = true;
831+
return Child;
832+
});
833+
assert(PrevIsSubExpr);
834+
}
835+
#endif
836+
Exprs.insert({Loc, E});
837+
}
838+
839+
bool ASTGen::hasExpr(const SourceLoc Loc) const {
840+
return Exprs.find(Loc) != Exprs.end();
841+
}
842+
843+
Expr *ASTGen::getExpr(const SourceLoc Loc) const {
844+
return Exprs.find(Loc)->second;
845+
}
846+
783847
void ASTGen::addDeclAttributes(DeclAttributes attrs, SourceLoc Loc) {
784848
ParsedDeclAttrs.insert({Loc, attrs});
785849
}

lib/Parse/ParseExpr.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@
3434
using namespace swift;
3535
using namespace swift::syntax;
3636

37+
ParsedSyntaxResult<ParsedExprSyntax> Parser::parseExpressionSyntax(Diag<> ID) {
38+
SourceLoc ExprLoc = Tok.getLoc();
39+
SyntaxParsingContext ExprParsingContext(SyntaxContext, SyntaxContextKind::Expr);
40+
ExprParsingContext.setTransparent();
41+
ParserResult<Expr> Result = parseExpr(ID);
42+
if (auto ParsedExpr = ExprParsingContext.popIf<ParsedExprSyntax>()) {
43+
Generator.addExpr(Result.getPtrOrNull(), ExprLoc);
44+
return makeParsedResult(std::move(*ParsedExpr), Result.getStatus());
45+
}
46+
return Result.getStatus();
47+
}
48+
3749
/// parseExpr
3850
///
3951
/// expr:

lib/Parse/ParseStmt.cpp

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "swift/Parse/Lexer.h"
2424
#include "swift/Parse/Parser.h"
2525
#include "swift/Parse/SyntaxParsingContext.h"
26+
#include "swift/Parse/ParsedSyntaxBuilders.h"
27+
#include "swift/Parse/ParsedSyntaxRecorder.h"
2628
#include "swift/Subsystems.h"
2729
#include "swift/Syntax/TokenSyntax.h"
2830
#include "llvm/ADT/PointerUnion.h"
@@ -2529,49 +2531,76 @@ ParserResult<CaseStmt> Parser::parseStmtCase(bool IsActive) {
25292531
/// stmt-pound-assert:
25302532
/// '#assert' '(' expr (',' string_literal)? ')'
25312533
ParserResult<Stmt> Parser::parseStmtPoundAssert() {
2532-
SyntaxContext->setCreateSyntax(SyntaxKind::PoundAssertStmt);
2534+
auto leadingLoc = leadingTriviaLoc();
2535+
auto parsed = parseStmtPoundAssertSyntax();
2536+
SyntaxContext->addSyntax(parsed.get());
2537+
auto poundAssertSyntax = SyntaxContext->topNode<PoundAssertStmtSyntax>();
2538+
auto poundAssert = Generator.generate(poundAssertSyntax, leadingLoc);
2539+
return makeParserResult(parsed.getStatus(), poundAssert);
2540+
}
25332541

2534-
SourceLoc startLoc = consumeToken(tok::pound_assert);
2535-
SourceLoc endLoc;
2542+
ParsedSyntaxResult<ParsedPoundAssertStmtSyntax>
2543+
Parser::parseStmtPoundAssertSyntax() {
2544+
ParsedPoundAssertStmtSyntaxBuilder builder(*SyntaxContext);
2545+
ParserStatus status;
25362546

2537-
if (Tok.isNot(tok::l_paren)) {
2538-
diagnose(Tok, diag::pound_assert_expected_lparen);
2539-
return makeParserError();
2547+
SourceLoc startLoc = Tok.getLoc();
2548+
builder.usePoundAssert(consumeTokenSyntax(tok::pound_assert));
2549+
if (!Tok.isFollowingLParen()) {
2550+
diagnose(Tok.getLoc(), diag::pound_assert_expected_lparen);
2551+
status.setIsParseError();
2552+
builder.useCondition(ParsedSyntaxRecorder::makeUnknownExpr({}, *SyntaxContext));
2553+
return makeParsedResult(builder.build(), status);
25402554
}
2541-
SourceLoc LBLoc = consumeToken(tok::l_paren);
2555+
SourceLoc lParenLoc = Tok.getLoc();
2556+
builder.useLeftParen(consumeTokenSyntax(tok::l_paren));
25422557

2543-
auto conditionExprResult = parseExpr(diag::pound_assert_expected_expression);
2544-
if (conditionExprResult.isParseError())
2545-
return ParserStatus(conditionExprResult);
2558+
auto conditionExprResult = parseExpressionSyntax(diag::pound_assert_expected_expression);
2559+
status |= conditionExprResult.getStatus();
2560+
builder.useCondition(conditionExprResult.isNull()
2561+
? ParsedSyntaxRecorder::makeUnknownExpr({}, *SyntaxContext)
2562+
: conditionExprResult.get());
2563+
2564+
if (auto Comma = consumeTokenSyntaxIf(tok::comma)) {
2565+
builder.useComma(std::move(*Comma));
25462566

2547-
StringRef message;
2548-
if (consumeIf(tok::comma)) {
25492567
if (Tok.isNot(tok::string_literal)) {
25502568
diagnose(Tok.getLoc(), diag::pound_assert_expected_string_literal);
2551-
return makeParserError();
2569+
status.setIsParseError();
2570+
return makeParsedResult(builder.build(), status);
25522571
}
2553-
2554-
auto messageOpt = getStringLiteralIfNotInterpolated(Tok.getLoc(),
2555-
"'#assert' message");
2556-
consumeToken();
2557-
if (!messageOpt)
2558-
return makeParserError();
2559-
2560-
message = *messageOpt;
2572+
auto MessageLoc = Tok.getLoc();
2573+
// FIXME: Support extended escaping string literal.
2574+
if (Tok.getCustomDelimiterLen()) {
2575+
diagnose(MessageLoc, diag::forbidden_extended_escaping_string, "'#assert' message");
2576+
status.setIsParseError();
2577+
} else {
2578+
SmallVector<Lexer::StringSegment, 1> Segments;
2579+
L->getStringLiteralSegments(Tok, Segments);
2580+
if (Segments.size() != 1 ||
2581+
Segments.front().Kind == Lexer::StringSegment::Expr) {
2582+
diagnose(MessageLoc, diag::forbidden_interpolated_string, "'#assert' message");
2583+
status.setIsParseError();
2584+
}
2585+
}
2586+
builder.useMessage(consumeTokenSyntax(tok::string_literal));
25612587
}
25622588

2563-
if (parseMatchingToken(tok::r_paren, endLoc,
2564-
diag::pound_assert_expected_rparen, LBLoc)) {
2565-
return makeParserError();
2589+
SourceLoc EndLoc;
2590+
if (auto rParen = parseMatchingTokenSyntax(tok::r_paren, EndLoc,
2591+
diag::pound_assert_expected_rparen,
2592+
lParenLoc)) {
2593+
builder.useRightParen(std::move(*rParen));
2594+
} else {
2595+
status.setIsParseError();
25662596
}
25672597

25682598
// We check this after consuming everything, so that the SyntaxContext
25692599
// understands this statement even when the feature is disabled.
25702600
if (!Context.LangOpts.EnableExperimentalStaticAssert) {
25712601
diagnose(startLoc, diag::pound_assert_disabled);
2572-
return makeParserError();
2602+
status.setIsParseError();
25732603
}
25742604

2575-
return makeParserResult<Stmt>(new (Context) PoundAssertStmt(
2576-
SourceRange(startLoc, endLoc), conditionExprResult.get(), message));
2605+
return makeParsedResult(builder.build(), status);
25772606
}

lib/Syntax/Syntax.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ llvm::Optional<Syntax> Syntax::getChild(const size_t N) const {
9898
return Syntax {Root, ChildData.get()};
9999
}
100100

101+
Optional<Syntax> Syntax::getPreviousNode() const {
102+
if (auto prev = getData().getPreviousNode())
103+
return TokenSyntax(Root, prev.get());
104+
return None;
105+
}
106+
101107
Optional<TokenSyntax> Syntax::getFirstToken() const {
102108
if (auto tok = getData().getFirstToken())
103109
return TokenSyntax(Root, tok.get());

0 commit comments

Comments
 (0)