From e51695d3a76a713833e4ac9ed7f90be830a3435d Mon Sep 17 00:00:00 2001 From: Alex Hoppen Date: Thu, 24 Aug 2023 15:11:18 -0700 Subject: [PATCH 1/2] Unify `forDirective` and `ExprFlavor` --- Sources/SwiftParser/Declarations.swift | 1 - Sources/SwiftParser/Directives.swift | 8 ++--- Sources/SwiftParser/Expressions.swift | 50 ++++++++------------------ 3 files changed, 19 insertions(+), 40 deletions(-) diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift index 792a48399f9..7e88eb0eb29 100644 --- a/Sources/SwiftParser/Declarations.swift +++ b/Sources/SwiftParser/Declarations.swift @@ -1251,7 +1251,6 @@ extension Parser { ) ), .basic, - forDirective: false, pattern: .none ) initializer = RawInitializerClauseSyntax( diff --git a/Sources/SwiftParser/Directives.swift b/Sources/SwiftParser/Directives.swift index b3fd95f58cf..a8e42edfda9 100644 --- a/Sources/SwiftParser/Directives.swift +++ b/Sources/SwiftParser/Directives.swift @@ -70,7 +70,7 @@ extension Parser { // Parse #if let (unexpectedBeforePoundIf, poundIf) = self.expect(.poundIf) - let condition = RawExprSyntax(self.parseSequenceExpression(.basic, forDirective: true)) + let condition = RawExprSyntax(self.parseSequenceExpression(.poundIfDirective)) let unexpectedBetweenConditionAndElements = self.consumeRemainingTokenOnLine() clauses.append( @@ -95,14 +95,14 @@ extension Parser { switch match { case .poundElseif: (unexpectedBeforePound, pound) = self.eat(handle) - condition = RawExprSyntax(self.parseSequenceExpression(.basic, forDirective: true)) + condition = RawExprSyntax(self.parseSequenceExpression(.poundIfDirective)) unexpectedBetweenConditionAndElements = self.consumeRemainingTokenOnLine() case .poundElse: (unexpectedBeforePound, pound) = self.eat(handle) if let ifToken = self.consume(if: .init(.if, allowAtStartOfLine: false)) { unexpectedBeforePound = RawUnexpectedNodesSyntax(combining: unexpectedBeforePound, pound, ifToken, arena: self.arena) pound = self.missingToken(.poundElseif) - condition = RawExprSyntax(self.parseSequenceExpression(.basic, forDirective: true)) + condition = RawExprSyntax(self.parseSequenceExpression(.poundIfDirective)) } else { condition = nil } @@ -115,7 +115,7 @@ extension Parser { } unexpectedBeforePound = RawUnexpectedNodesSyntax(combining: unexpectedBeforePound, pound, elif, arena: self.arena) pound = self.missingToken(.poundElseif) - condition = RawExprSyntax(self.parseSequenceExpression(.basic, forDirective: true)) + condition = RawExprSyntax(self.parseSequenceExpression(.poundIfDirective)) unexpectedBetweenConditionAndElements = self.consumeRemainingTokenOnLine() } else { break LOOP diff --git a/Sources/SwiftParser/Expressions.swift b/Sources/SwiftParser/Expressions.swift index 0a94e8b35fa..8ea582855ac 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -65,6 +65,7 @@ extension Parser { enum ExprFlavor { case basic case trailingClosure + case poundIfDirective } enum PatternContext { @@ -115,10 +116,9 @@ extension Parser { /// Parse a sequence of expressions. mutating func parseSequenceExpression( _ flavor: ExprFlavor, - forDirective: Bool = false, pattern: PatternContext = .none ) -> RawExprSyntax { - if forDirective && self.atStartOfLine { + if flavor == .poundIfDirective && self.atStartOfLine { return RawExprSyntax(RawMissingExprSyntax(arena: self.arena)) } @@ -132,7 +132,6 @@ extension Parser { lastElement = self.parseSequenceExpressionElement( flavor, - forDirective: forDirective, pattern: pattern ) @@ -140,7 +139,7 @@ extension Parser { while self.hasProgressed(&loopProgress) { guard !lastElement.is(RawMissingExprSyntax.self), - !(forDirective && self.atStartOfLine) + !(flavor == .poundIfDirective && self.atStartOfLine) else { break } @@ -160,14 +159,13 @@ extension Parser { if let rhsExpr { // Operator parsing returned the RHS. lastElement = rhsExpr - } else if forDirective && self.atStartOfLine { + } else if flavor == .poundIfDirective && self.atStartOfLine { // Don't allow RHS at a newline for `#if` conditions. lastElement = RawExprSyntax(RawMissingExprSyntax(arena: self.arena)) break } else { lastElement = self.parseSequenceExpressionElement( flavor, - forDirective: forDirective, pattern: pattern ) } @@ -365,7 +363,6 @@ extension Parser { /// Parse an expression sequence element. mutating func parseSequenceExpressionElement( _ flavor: ExprFlavor, - forDirective: Bool = false, pattern: PatternContext = .none ) -> RawExprSyntax { // Try to parse '@' sign or 'inout' as an attributed typerepr. @@ -387,7 +384,6 @@ extension Parser { let awaitTok = self.eat(handle) let sub = self.parseSequenceExpressionElement( flavor, - forDirective: forDirective, pattern: pattern ) return RawExprSyntax( @@ -403,7 +399,6 @@ extension Parser { let expression = self.parseSequenceExpressionElement( flavor, - forDirective: forDirective, pattern: pattern ) return RawExprSyntax( @@ -418,7 +413,6 @@ extension Parser { let moveKeyword = self.eat(handle) let sub = self.parseSequenceExpressionElement( flavor, - forDirective: forDirective, pattern: pattern ) return RawExprSyntax( @@ -432,7 +426,6 @@ extension Parser { let borrowTok = self.eat(handle) let sub = self.parseSequenceExpressionElement( flavor, - forDirective: forDirective, pattern: pattern ) return RawExprSyntax( @@ -451,7 +444,6 @@ extension Parser { let copyTok = self.eat(handle) let sub = self.parseSequenceExpressionElement( flavor, - forDirective: forDirective, pattern: pattern ) return RawExprSyntax( @@ -470,7 +462,6 @@ extension Parser { let consumeKeyword = self.eat(handle) let sub = self.parseSequenceExpressionElement( flavor, - forDirective: forDirective, pattern: pattern ) return RawExprSyntax( @@ -512,13 +503,12 @@ extension Parser { case nil: break } - return self.parseUnaryExpression(flavor, forDirective: forDirective, pattern: pattern) + return self.parseUnaryExpression(flavor, pattern: pattern) } /// Parse an optional prefix operator followed by an expression. mutating func parseUnaryExpression( _ flavor: ExprFlavor, - forDirective: Bool = false, pattern: PatternContext = .none ) -> RawExprSyntax { // First check to see if we have the start of a regex literal `/.../`. @@ -541,7 +531,7 @@ extension Parser { switch self.at(anyIn: ExpressionPrefixOperator.self) { case (.prefixAmpersand, let handle)?: let amp = self.eat(handle) - let expr = self.parseUnaryExpression(flavor, forDirective: forDirective, pattern: pattern) + let expr = self.parseUnaryExpression(flavor, pattern: pattern) return RawExprSyntax( RawInOutExprSyntax( ampersand: amp, @@ -551,11 +541,11 @@ extension Parser { ) case (.backslash, _)?: - return RawExprSyntax(self.parseKeyPathExpression(forDirective: forDirective, pattern: pattern)) + return RawExprSyntax(self.parseKeyPathExpression(pattern: pattern)) case (.prefixOperator, let handle)?: let op = self.eat(handle) - let postfix = self.parseUnaryExpression(flavor, forDirective: forDirective, pattern: pattern) + let postfix = self.parseUnaryExpression(flavor, pattern: pattern) return RawExprSyntax( RawPrefixOperatorExprSyntax( operator: op, @@ -568,7 +558,6 @@ extension Parser { // If the next token is not an operator, just parse this as expr-postfix. return self.parsePostfixExpression( flavor, - forDirective: forDirective, pattern: pattern ) } @@ -577,17 +566,15 @@ extension Parser { /// Parse a postfix expression applied to another expression. mutating func parsePostfixExpression( _ flavor: ExprFlavor, - forDirective: Bool, pattern: PatternContext ) -> RawExprSyntax { - let head = self.parsePrimaryExpression(pattern: pattern, forDirective: forDirective, flavor: flavor) + let head = self.parsePrimaryExpression(pattern: pattern, flavor: flavor) guard !head.is(RawMissingExprSyntax.self) else { return head } return self.parsePostfixExpressionSuffix( head, flavor, - forDirective: forDirective, pattern: pattern ) } @@ -661,8 +648,7 @@ extension Parser { mutating func parseIfConfigExpressionSuffix( _ start: RawExprSyntax?, - _ flavor: ExprFlavor, - forDirective: Bool + _ flavor: ExprFlavor ) -> RawExprSyntax { precondition(self.at(.poundIf)) @@ -674,7 +660,7 @@ extension Parser { if parser.at(.period) { head = parser.parseDottedExpressionSuffix(nil) } else if parser.at(.poundIf) { - head = parser.parseIfConfigExpressionSuffix(nil, flavor, forDirective: forDirective) + head = parser.parseIfConfigExpressionSuffix(nil, flavor) } else { // TODO: diagnose and skip. return nil @@ -682,7 +668,6 @@ extension Parser { let result = parser.parsePostfixExpressionSuffix( head, flavor, - forDirective: forDirective, pattern: .none ) @@ -709,14 +694,13 @@ extension Parser { mutating func parsePostfixExpressionSuffix( _ start: RawExprSyntax, _ flavor: ExprFlavor, - forDirective: Bool, pattern: PatternContext ) -> RawExprSyntax { // Handle suffix expressions. var leadingExpr = start var loopProgress = LoopProgressCondition() while self.hasProgressed(&loopProgress) { - if forDirective && self.atStartOfLine { + if flavor == .poundIfDirective && self.atStartOfLine { return leadingExpr } @@ -881,8 +865,7 @@ extension Parser { leadingExpr = self.parseIfConfigExpressionSuffix( leadingExpr, - flavor, - forDirective: forDirective + flavor ) continue } @@ -957,7 +940,7 @@ extension Parser { } /// Parse a keypath expression. - mutating func parseKeyPathExpression(forDirective: Bool, pattern: PatternContext) -> RawKeyPathExprSyntax { + mutating func parseKeyPathExpression(pattern: PatternContext) -> RawKeyPathExprSyntax { // Consume '\'. let (unexpectedBeforeBackslash, backslash) = self.expect(.backslash) @@ -1079,12 +1062,9 @@ extension Parser { /// Swift expression grammar. mutating func parsePrimaryExpression( pattern: PatternContext, - forDirective: Bool, flavor: ExprFlavor ) -> RawExprSyntax { - if forDirective == true, - let directiveExpr = self.parsePrimaryExprForDirective() - { + if flavor == .poundIfDirective, let directiveExpr = self.parsePrimaryExprForDirective() { return RawExprSyntax(directiveExpr) } From 536fd8181aa14d291b50145a1ae2674703286a14 Mon Sep 17 00:00:00 2001 From: Alex Hoppen Date: Thu, 24 Aug 2023 11:43:05 -0700 Subject: [PATCH 2/2] Rename `ExprFlavor` cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename - `basic` -> `stmtCondition` because this case is used primarily in statement conditions that need to disambiguate trailing closures from the statement’s body - `trailingClosure` -> `basic` because this is the base case that we use inside normal expression parsing Also add argument labels to `flavor` to match the `pattern` parameter that also has a label and make `parseExpression` parameters required so that each caller needs to make a conscious choice about the values and so it’s easier to search for where each of the flavors is being used. --- .../GenerateSwiftSyntax.swift | 2 +- ...le.swift => LayoutNodesParsableFile.swift} | 10 +- Sources/SwiftParser/Declarations.swift | 14 +-- Sources/SwiftParser/Directives.swift | 8 +- Sources/SwiftParser/Expressions.swift | 113 ++++++++++-------- Sources/SwiftParser/Patterns.swift | 2 +- Sources/SwiftParser/Statements.swift | 22 ++-- Sources/SwiftParser/TopLevel.swift | 2 +- .../generated/LayoutNodes+Parsable.swift | 4 + 9 files changed, 101 insertions(+), 76 deletions(-) rename CodeGeneration/Sources/generate-swift-syntax/templates/swiftparser/{ParserEntryFile.swift => LayoutNodesParsableFile.swift} (91%) diff --git a/CodeGeneration/Sources/generate-swift-syntax/GenerateSwiftSyntax.swift b/CodeGeneration/Sources/generate-swift-syntax/GenerateSwiftSyntax.swift index 65e54c99fbe..d80270c42d9 100644 --- a/CodeGeneration/Sources/generate-swift-syntax/GenerateSwiftSyntax.swift +++ b/CodeGeneration/Sources/generate-swift-syntax/GenerateSwiftSyntax.swift @@ -89,7 +89,7 @@ struct GenerateSwiftSyntax: ParsableCommand { var fileSpecs: [GeneratedFileSpec] = [ // SwiftParser GeneratedFileSpec(swiftParserGeneratedDir + ["IsLexerClassified.swift"], isLexerClassifiedFile), - GeneratedFileSpec(swiftParserGeneratedDir + ["LayoutNodes+Parsable.swift"], parserEntryFile), + GeneratedFileSpec(swiftParserGeneratedDir + ["LayoutNodes+Parsable.swift"], layoutNodesParsableFile), GeneratedFileSpec(swiftParserGeneratedDir + ["Parser+TokenSpecSet.swift"], parserTokenSpecSetFile), GeneratedFileSpec(swiftParserGeneratedDir + ["TokenSpecStaticMembers.swift"], tokenSpecStaticMembersFile), diff --git a/CodeGeneration/Sources/generate-swift-syntax/templates/swiftparser/ParserEntryFile.swift b/CodeGeneration/Sources/generate-swift-syntax/templates/swiftparser/LayoutNodesParsableFile.swift similarity index 91% rename from CodeGeneration/Sources/generate-swift-syntax/templates/swiftparser/ParserEntryFile.swift rename to CodeGeneration/Sources/generate-swift-syntax/templates/swiftparser/LayoutNodesParsableFile.swift index 5dd1b7533b7..19d4e3b90bf 100644 --- a/CodeGeneration/Sources/generate-swift-syntax/templates/swiftparser/ParserEntryFile.swift +++ b/CodeGeneration/Sources/generate-swift-syntax/templates/swiftparser/LayoutNodesParsableFile.swift @@ -15,7 +15,7 @@ import SwiftSyntaxBuilder import SyntaxSupport import Utils -let parserEntryFile = SourceFileSyntax(leadingTrivia: copyrightHeader) { +let layoutNodesParsableFile = SourceFileSyntax(leadingTrivia: copyrightHeader) { DeclSyntax("@_spi(RawSyntax) import SwiftSyntax") DeclSyntax( @@ -74,5 +74,13 @@ let parserEntryFile = SourceFileSyntax(leadingTrivia: copyrightHeader) { } """ ) + + DeclSyntax( + """ + mutating func parseExpression() -> RawExprSyntax { + return self.parseExpression(flavor: .basic, pattern: .none) + } + """ + ) } } diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift index 7e88eb0eb29..cf41df2a91d 100644 --- a/Sources/SwiftParser/Declarations.swift +++ b/Sources/SwiftParser/Declarations.swift @@ -799,7 +799,7 @@ extension Parser { // See if there's a raw value expression. let rawValue: RawInitializerClauseSyntax? if let eq = self.consume(if: .equal) { - let value = self.parseExpression() + let value = self.parseExpression(flavor: .basic, pattern: .none) rawValue = RawInitializerClauseSyntax( equal: eq, value: value, @@ -1219,7 +1219,7 @@ extension Parser { // Parse an initializer if present. let initializer: RawInitializerClauseSyntax? if let equal = self.consume(if: .equal) { - var value = self.parseExpression() + var value = self.parseExpression(flavor: .basic, pattern: .none) if hasTryBeforeIntroducer && !value.is(RawTryExprSyntax.self) { value = RawExprSyntax( RawTryExprSyntax( @@ -1250,7 +1250,7 @@ extension Parser { arena: self.arena ) ), - .basic, + flavor: .basic, pattern: .none ) initializer = RawInitializerClauseSyntax( @@ -1267,7 +1267,7 @@ extension Parser { ) } else if self.atStartOfExpression(), !self.at(.leftBrace), !self.atStartOfLine { let missingEqual = RawTokenSyntax(missing: .equal, arena: self.arena) - let expr = self.parseExpression() + let expr = self.parseExpression(flavor: .basic, pattern: .none) initializer = RawInitializerClauseSyntax( equal: missingEqual, value: expr, @@ -1848,7 +1848,7 @@ extension Parser { // Initializer, if any. let definition: RawInitializerClauseSyntax? if let equal = self.consume(if: .equal) { - let expr = self.parseExpression() + let expr = self.parseExpression(flavor: .basic, pattern: .none) definition = RawInitializerClauseSyntax( equal: equal, value: expr, @@ -1932,10 +1932,10 @@ extension Parser { let trailingClosure: RawClosureExprSyntax? let additionalTrailingClosures: RawMultipleTrailingClosureElementListSyntax if self.at(.leftBrace), - self.withLookahead({ $0.atValidTrailingClosure(.trailingClosure) }) + self.withLookahead({ $0.atValidTrailingClosure(flavor: .basic) }) { (trailingClosure, additionalTrailingClosures) = - self.parseTrailingClosures(.trailingClosure) + self.parseTrailingClosures(flavor: .basic) } else { trailingClosure = nil additionalTrailingClosures = self.emptyCollection(RawMultipleTrailingClosureElementListSyntax.self) diff --git a/Sources/SwiftParser/Directives.swift b/Sources/SwiftParser/Directives.swift index a8e42edfda9..eb4c6e1b577 100644 --- a/Sources/SwiftParser/Directives.swift +++ b/Sources/SwiftParser/Directives.swift @@ -70,7 +70,7 @@ extension Parser { // Parse #if let (unexpectedBeforePoundIf, poundIf) = self.expect(.poundIf) - let condition = RawExprSyntax(self.parseSequenceExpression(.poundIfDirective)) + let condition = RawExprSyntax(self.parseSequenceExpression(flavor: .poundIfDirective)) let unexpectedBetweenConditionAndElements = self.consumeRemainingTokenOnLine() clauses.append( @@ -95,14 +95,14 @@ extension Parser { switch match { case .poundElseif: (unexpectedBeforePound, pound) = self.eat(handle) - condition = RawExprSyntax(self.parseSequenceExpression(.poundIfDirective)) + condition = RawExprSyntax(self.parseSequenceExpression(flavor: .poundIfDirective)) unexpectedBetweenConditionAndElements = self.consumeRemainingTokenOnLine() case .poundElse: (unexpectedBeforePound, pound) = self.eat(handle) if let ifToken = self.consume(if: .init(.if, allowAtStartOfLine: false)) { unexpectedBeforePound = RawUnexpectedNodesSyntax(combining: unexpectedBeforePound, pound, ifToken, arena: self.arena) pound = self.missingToken(.poundElseif) - condition = RawExprSyntax(self.parseSequenceExpression(.poundIfDirective)) + condition = RawExprSyntax(self.parseSequenceExpression(flavor: .poundIfDirective)) } else { condition = nil } @@ -115,7 +115,7 @@ extension Parser { } unexpectedBeforePound = RawUnexpectedNodesSyntax(combining: unexpectedBeforePound, pound, elif, arena: self.arena) pound = self.missingToken(.poundElseif) - condition = RawExprSyntax(self.parseSequenceExpression(.poundIfDirective)) + condition = RawExprSyntax(self.parseSequenceExpression(flavor: .poundIfDirective)) unexpectedBetweenConditionAndElements = self.consumeRemainingTokenOnLine() } else { break LOOP diff --git a/Sources/SwiftParser/Expressions.swift b/Sources/SwiftParser/Expressions.swift index 8ea582855ac..944d5468c43 100644 --- a/Sources/SwiftParser/Expressions.swift +++ b/Sources/SwiftParser/Expressions.swift @@ -63,14 +63,26 @@ extension TokenConsumer { extension Parser { enum ExprFlavor { + /// Parsing a normal expression, eg. inside a function calls. case basic - case trailingClosure + + /// Parsing the condition of a `if`/`guard`/`for`/... statement or something + /// like the `where` clause after a `catch` clause. + /// + /// In these cases we need to disambiguate trailing closures from the + /// statement's body. + case stmtCondition + + /// Parsing the condition of a `#if` directive. + /// + /// We don't allow allow newlines here. case poundIfDirective } enum PatternContext { /// There is no ambient pattern context. case none + /// We're parsing a matching pattern that is not introduced via `let` or `var`. /// /// In this context, identifiers are references to the enclosing scopes, not a variable binding. @@ -79,6 +91,7 @@ extension Parser { /// case x.y <- 'x' must refer to some 'x' defined in another scope, it cannot be e.g. an enum type. /// ``` case matching + /// We're parsing a matching pattern that is introduced via `let`, `var`, or `inout` /// /// ``` @@ -97,7 +110,7 @@ extension Parser { } /// Parse an expression. - mutating func parseExpression(_ flavor: ExprFlavor = .trailingClosure, pattern: PatternContext = .none) -> RawExprSyntax { + mutating func parseExpression(flavor: ExprFlavor, pattern: PatternContext) -> RawExprSyntax { // If we are parsing a refutable pattern, check to see if this is the start // of a let/var/is pattern. If so, parse it as an UnresolvedPatternExpr and // let pattern type checking determine its final form. @@ -108,14 +121,14 @@ extension Parser { let pattern = self.parseMatchingPattern(context: .matching) return RawExprSyntax(RawPatternExprSyntax(pattern: pattern, arena: self.arena)) } - return RawExprSyntax(self.parseSequenceExpression(flavor, pattern: pattern)) + return RawExprSyntax(self.parseSequenceExpression(flavor: flavor, pattern: pattern)) } } extension Parser { /// Parse a sequence of expressions. mutating func parseSequenceExpression( - _ flavor: ExprFlavor, + flavor: ExprFlavor, pattern: PatternContext = .none ) -> RawExprSyntax { if flavor == .poundIfDirective && self.atStartOfLine { @@ -131,7 +144,7 @@ extension Parser { var lastElement: RawExprSyntax lastElement = self.parseSequenceExpressionElement( - flavor, + flavor: flavor, pattern: pattern ) @@ -147,7 +160,7 @@ extension Parser { // Parse the operator. guard let (operatorExpr, rhsExpr) = - self.parseSequenceExpressionOperator(flavor, pattern: pattern) + self.parseSequenceExpressionOperator(flavor: flavor, pattern: pattern) else { // Not an operator. We're done. break @@ -165,7 +178,7 @@ extension Parser { break } else { lastElement = self.parseSequenceExpressionElement( - flavor, + flavor: flavor, pattern: pattern ) } @@ -217,7 +230,7 @@ extension Parser { /// expression. The right operand is only returned if it is not a common /// sequence element. mutating func parseSequenceExpressionOperator( - _ flavor: ExprFlavor, + flavor: ExprFlavor, pattern: PatternContext ) -> (operator: RawExprSyntax, rhs: RawExprSyntax?)? { enum ExpectedTokenKind: TokenSpecSet { @@ -268,7 +281,7 @@ extension Parser { case (.infixQuestionMark, let handle)?: // Save the '?'. let question = self.eat(handle) - let firstChoice = self.parseSequenceExpression(flavor, pattern: pattern) + let firstChoice = self.parseSequenceExpression(flavor: flavor, pattern: pattern) // Make sure there's a matching ':' after the middle expr. let (unexpectedBeforeColon, colon) = self.expect(.colon) @@ -362,7 +375,7 @@ extension Parser { /// Parse an expression sequence element. mutating func parseSequenceExpressionElement( - _ flavor: ExprFlavor, + flavor: ExprFlavor, pattern: PatternContext = .none ) -> RawExprSyntax { // Try to parse '@' sign or 'inout' as an attributed typerepr. @@ -383,7 +396,7 @@ extension Parser { case (.await, let handle)?: let awaitTok = self.eat(handle) let sub = self.parseSequenceExpressionElement( - flavor, + flavor: flavor, pattern: pattern ) return RawExprSyntax( @@ -398,7 +411,7 @@ extension Parser { let mark = self.consume(if: .exclamationMark, .postfixQuestionMark) let expression = self.parseSequenceExpressionElement( - flavor, + flavor: flavor, pattern: pattern ) return RawExprSyntax( @@ -412,7 +425,7 @@ extension Parser { case (._move, let handle)?: let moveKeyword = self.eat(handle) let sub = self.parseSequenceExpressionElement( - flavor, + flavor: flavor, pattern: pattern ) return RawExprSyntax( @@ -425,7 +438,7 @@ extension Parser { case (._borrow, let handle)?: let borrowTok = self.eat(handle) let sub = self.parseSequenceExpressionElement( - flavor, + flavor: flavor, pattern: pattern ) return RawExprSyntax( @@ -443,7 +456,7 @@ extension Parser { let copyTok = self.eat(handle) let sub = self.parseSequenceExpressionElement( - flavor, + flavor: flavor, pattern: pattern ) return RawExprSyntax( @@ -461,7 +474,7 @@ extension Parser { let consumeKeyword = self.eat(handle) let sub = self.parseSequenceExpressionElement( - flavor, + flavor: flavor, pattern: pattern ) return RawExprSyntax( @@ -474,7 +487,7 @@ extension Parser { case (.repeat, let handle)?: // 'repeat' is the start of a pack expansion expression. - return RawExprSyntax(parsePackExpansionExpr(repeatHandle: handle, flavor, pattern: pattern)) + return RawExprSyntax(parsePackExpansionExpr(repeatHandle: handle, flavor: flavor, pattern: pattern)) case (.each, let handle)?: if !atContextualExpressionModifier() { @@ -482,7 +495,7 @@ extension Parser { } let each = self.eat(handle) - let pack = self.parseSequenceExpressionElement(flavor, pattern: pattern) + let pack = self.parseSequenceExpressionElement(flavor: flavor, pattern: pattern) return RawExprSyntax( RawPackElementExprSyntax( eachKeyword: each, @@ -503,12 +516,12 @@ extension Parser { case nil: break } - return self.parseUnaryExpression(flavor, pattern: pattern) + return self.parseUnaryExpression(flavor: flavor, pattern: pattern) } /// Parse an optional prefix operator followed by an expression. mutating func parseUnaryExpression( - _ flavor: ExprFlavor, + flavor: ExprFlavor, pattern: PatternContext = .none ) -> RawExprSyntax { // First check to see if we have the start of a regex literal `/.../`. @@ -531,7 +544,7 @@ extension Parser { switch self.at(anyIn: ExpressionPrefixOperator.self) { case (.prefixAmpersand, let handle)?: let amp = self.eat(handle) - let expr = self.parseUnaryExpression(flavor, pattern: pattern) + let expr = self.parseUnaryExpression(flavor: flavor, pattern: pattern) return RawExprSyntax( RawInOutExprSyntax( ampersand: amp, @@ -545,7 +558,7 @@ extension Parser { case (.prefixOperator, let handle)?: let op = self.eat(handle) - let postfix = self.parseUnaryExpression(flavor, pattern: pattern) + let postfix = self.parseUnaryExpression(flavor: flavor, pattern: pattern) return RawExprSyntax( RawPrefixOperatorExprSyntax( operator: op, @@ -557,7 +570,7 @@ extension Parser { default: // If the next token is not an operator, just parse this as expr-postfix. return self.parsePostfixExpression( - flavor, + flavor: flavor, pattern: pattern ) } @@ -565,7 +578,7 @@ extension Parser { /// Parse a postfix expression applied to another expression. mutating func parsePostfixExpression( - _ flavor: ExprFlavor, + flavor: ExprFlavor, pattern: PatternContext ) -> RawExprSyntax { let head = self.parsePrimaryExpression(pattern: pattern, flavor: flavor) @@ -574,7 +587,7 @@ extension Parser { } return self.parsePostfixExpressionSuffix( head, - flavor, + flavor: flavor, pattern: pattern ) } @@ -648,7 +661,7 @@ extension Parser { mutating func parseIfConfigExpressionSuffix( _ start: RawExprSyntax?, - _ flavor: ExprFlavor + flavor: ExprFlavor ) -> RawExprSyntax { precondition(self.at(.poundIf)) @@ -660,14 +673,14 @@ extension Parser { if parser.at(.period) { head = parser.parseDottedExpressionSuffix(nil) } else if parser.at(.poundIf) { - head = parser.parseIfConfigExpressionSuffix(nil, flavor) + head = parser.parseIfConfigExpressionSuffix(nil, flavor: flavor) } else { // TODO: diagnose and skip. return nil } let result = parser.parsePostfixExpressionSuffix( head, - flavor, + flavor: flavor, pattern: .none ) @@ -693,7 +706,7 @@ extension Parser { /// Parse the suffix of a postfix expression. mutating func parsePostfixExpressionSuffix( _ start: RawExprSyntax, - _ flavor: ExprFlavor, + flavor: ExprFlavor, pattern: PatternContext ) -> RawExprSyntax { // Handle suffix expressions. @@ -718,8 +731,8 @@ extension Parser { // If we can parse trailing closures, do so. let trailingClosure: RawClosureExprSyntax? let additionalTrailingClosures: RawMultipleTrailingClosureElementListSyntax - if case .trailingClosure = flavor, self.at(.leftBrace), self.withLookahead({ $0.atValidTrailingClosure(flavor) }) { - (trailingClosure, additionalTrailingClosures) = self.parseTrailingClosures(flavor) + if case .basic = flavor, self.at(.leftBrace), self.withLookahead({ $0.atValidTrailingClosure(flavor: flavor) }) { + (trailingClosure, additionalTrailingClosures) = self.parseTrailingClosures(flavor: flavor) } else { trailingClosure = nil additionalTrailingClosures = self.emptyCollection(RawMultipleTrailingClosureElementListSyntax.self) @@ -754,8 +767,8 @@ extension Parser { // If we can parse trailing closures, do so. let trailingClosure: RawClosureExprSyntax? let additionalTrailingClosures: RawMultipleTrailingClosureElementListSyntax - if case .trailingClosure = flavor, self.at(.leftBrace), self.withLookahead({ $0.atValidTrailingClosure(flavor) }) { - (trailingClosure, additionalTrailingClosures) = self.parseTrailingClosures(flavor) + if case .basic = flavor, self.at(.leftBrace), self.withLookahead({ $0.atValidTrailingClosure(flavor: flavor) }) { + (trailingClosure, additionalTrailingClosures) = self.parseTrailingClosures(flavor: flavor) } else { trailingClosure = nil additionalTrailingClosures = self.emptyCollection(RawMultipleTrailingClosureElementListSyntax.self) @@ -777,11 +790,11 @@ extension Parser { } // Check for a trailing closure, if allowed. - if self.at(.leftBrace) && self.withLookahead({ $0.atValidTrailingClosure(flavor) }) { + if self.at(.leftBrace) && self.withLookahead({ $0.atValidTrailingClosure(flavor: flavor) }) { // FIXME: if Result has a trailing closure, break out. // Add dummy blank argument list to the call expression syntax. let list = RawLabeledExprListSyntax(elements: [], arena: self.arena) - let (first, rest) = self.parseTrailingClosures(flavor) + let (first, rest) = self.parseTrailingClosures(flavor: flavor) leadingExpr = RawExprSyntax( RawFunctionCallExprSyntax( @@ -865,7 +878,7 @@ extension Parser { leadingExpr = self.parseIfConfigExpressionSuffix( leadingExpr, - flavor + flavor: flavor ) continue } @@ -1301,8 +1314,8 @@ extension Parser { // Parse the optional trailing closures. let trailingClosure: RawClosureExprSyntax? let additionalTrailingClosures: RawMultipleTrailingClosureElementListSyntax - if case .trailingClosure = flavor, self.at(.leftBrace), self.withLookahead({ $0.atValidTrailingClosure(flavor) }) { - (trailingClosure, additionalTrailingClosures) = self.parseTrailingClosures(flavor) + if case .basic = flavor, self.at(.leftBrace), self.withLookahead({ $0.atValidTrailingClosure(flavor: flavor) }) { + (trailingClosure, additionalTrailingClosures) = self.parseTrailingClosures(flavor: flavor) } else { trailingClosure = nil additionalTrailingClosures = self.emptyCollection(RawMultipleTrailingClosureElementListSyntax.self) @@ -1332,11 +1345,11 @@ extension Parser { /// Parse a pack expansion as an expression. mutating func parsePackExpansionExpr( repeatHandle: TokenConsumptionHandle, - _ flavor: ExprFlavor, + flavor: ExprFlavor, pattern: PatternContext ) -> RawPackExpansionExprSyntax { let repeatKeyword = self.eat(repeatHandle) - let repetitionPattern = self.parseExpression(flavor, pattern: pattern) + let repetitionPattern = self.parseExpression(flavor: flavor, pattern: pattern) return RawPackExpansionExprSyntax( repeatKeyword: repeatKeyword, @@ -1422,7 +1435,7 @@ extension Parser { /// Parse an element of an array or dictionary literal. mutating func parseCollectionElement(_ existing: CollectionKind?) -> CollectionKind { - let key = self.parseExpression() + let key = self.parseExpression(flavor: .basic, pattern: .none) switch existing { case .array(_): return .array(key) @@ -1433,7 +1446,7 @@ extension Parser { fallthrough case .dictionary: let (unexpectedBeforeColon, colon) = self.expect(.colon) - let value = self.parseExpression() + let value = self.parseExpression(flavor: .basic, pattern: .none) return .dictionary(key: key, unexpectedBeforeColon: unexpectedBeforeColon, colon: colon, value: value) } } @@ -1591,7 +1604,7 @@ extension Parser { (unexpectedBeforeEq, eq) = self.expect(.equal) } - let expr = self.parseExpression() + let expr = self.parseExpression(flavor: .basic, pattern: .none) return RawInitializerClauseSyntax( unexpectedBeforeEq, equal: eq, @@ -1677,7 +1690,7 @@ extension Parser { // The name is a new declaration. (unexpectedBeforeName, name) = self.expect(.identifier, TokenSpec(.self, remapping: .identifier), default: .identifier) (unexpectedBeforeEqual, equal) = self.expect(.equal) - expression = self.parseExpression() + expression = self.parseExpression(flavor: .basic, pattern: .none) } else { // This is the simple case - the identifier is both the name and // the expression to capture. @@ -1870,7 +1883,7 @@ extension Parser { if self.at(.binaryOperator) && self.peek(isAt: .comma, .rightParen, .rightSquare) { expr = RawExprSyntax(self.parseDeclReferenceExpr(.operators)) } else { - expr = self.parseExpression(pattern: pattern) + expr = self.parseExpression(flavor: .basic, pattern: pattern) } keepGoing = self.consume(if: .comma) result.append( @@ -1890,7 +1903,7 @@ extension Parser { extension Parser { /// Parse the trailing closure(s) following a call expression. - mutating func parseTrailingClosures(_ flavor: ExprFlavor) -> (RawClosureExprSyntax, RawMultipleTrailingClosureElementListSyntax) { + mutating func parseTrailingClosures(flavor: ExprFlavor) -> (RawClosureExprSyntax, RawMultipleTrailingClosureElementListSyntax) { // Parse the closure. let closure = self.parseClosureExpression() @@ -1952,7 +1965,7 @@ extension Parser.Lookahead { /// where the parser requires an expr-basic (which does not allow them). We /// handle this by doing some lookahead in common situations. And later, Sema /// will emit a diagnostic with a fixit to add wrapping parens. - mutating func atValidTrailingClosure(_ flavor: Parser.ExprFlavor) -> Bool { + mutating func atValidTrailingClosure(flavor: Parser.ExprFlavor) -> Bool { precondition(self.at(.leftBrace), "Couldn't be a trailing closure") // If this is the start of a get/set accessor, then it isn't a trailing @@ -1973,7 +1986,7 @@ extension Parser.Lookahead { // {...}() // by looking ahead for the ()'s, but this has been replaced by do{}, so this // probably isn't worthwhile. - guard case .basic = flavor else { + guard case .stmtCondition = flavor else { return true } @@ -2101,7 +2114,7 @@ extension Parser { if self.at(.leftBrace) { subject = RawExprSyntax(RawMissingExprSyntax(arena: self.arena)) } else { - subject = self.parseExpression(.basic) + subject = self.parseExpression(flavor: .stmtCondition, pattern: .none) } let (unexpectedBeforeLBrace, lbrace) = self.expect(.leftBrace) @@ -2320,7 +2333,7 @@ extension Parser { // vars in scope. let whereClause: RawWhereClauseSyntax? if let whereKeyword = self.consume(if: .keyword(.where)) { - let condition = self.parseExpression(.trailingClosure) + let condition = self.parseExpression(flavor: .basic, pattern: .none) whereClause = RawWhereClauseSyntax( whereKeyword: whereKeyword, condition: condition, diff --git a/Sources/SwiftParser/Patterns.swift b/Sources/SwiftParser/Patterns.swift index 8832e2e4e44..159e18543e0 100644 --- a/Sources/SwiftParser/Patterns.swift +++ b/Sources/SwiftParser/Patterns.swift @@ -252,7 +252,7 @@ extension Parser { // matching-pattern ::= expr // Fall back to expression parsing for ambiguous forms. Name lookup will // disambiguate. - let patternSyntax = self.parseSequenceExpression(.basic, pattern: context) + let patternSyntax = self.parseSequenceExpression(flavor: .stmtCondition, pattern: context) if let pat = patternSyntax.as(RawPatternExprSyntax.self) { // The most common case here is to parse something that was a lexically // obvious pattern, which will come back wrapped in an immediate diff --git a/Sources/SwiftParser/Statements.swift b/Sources/SwiftParser/Statements.swift index 2f2354055b9..91c4cd934f0 100644 --- a/Sources/SwiftParser/Statements.swift +++ b/Sources/SwiftParser/Statements.swift @@ -191,7 +191,7 @@ extension Parser { // another clause, so parse it as an expression. This also avoids // lookahead + backtracking on simple if conditions that are obviously // boolean conditions. - return .expression(self.parseExpression(.basic)) + return .expression(self.parseExpression(flavor: .stmtCondition, pattern: .none)) } // We're parsing a conditional binding. @@ -237,7 +237,7 @@ extension Parser { // `let newBinding`, which is shorthand for `let newBinding = newBinding` let initializer: RawInitializerClauseSyntax? if let eq = self.consume(if: .equal) { - let value = self.parseExpression(.basic) + let value = self.parseExpression(flavor: .stmtCondition, pattern: .none) initializer = RawInitializerClauseSyntax( equal: eq, value: value, @@ -312,7 +312,7 @@ extension Parser { mutating func parseThrowStatement(throwHandle: RecoveryConsumptionHandle) -> RawThrowStmtSyntax { let (unexpectedBeforeThrowKeyword, throwKeyword) = self.eat(throwHandle) let hasMisplacedTry = unexpectedBeforeThrowKeyword?.containsToken(where: { TokenSpec(.try) ~= $0 }) ?? false - var expr = self.parseExpression() + var expr = self.parseExpression(flavor: .basic, pattern: .none) if hasMisplacedTry && !expr.is(RawTryExprSyntax.self) { expr = RawExprSyntax( RawTryExprSyntax( @@ -338,7 +338,7 @@ extension Parser { /// Parse a discard statement. mutating func parseDiscardStatement(discardHandle: RecoveryConsumptionHandle) -> RawDiscardStmtSyntax { let (unexpectedBeforeDiscardKeyword, discardKeyword) = self.eat(discardHandle) - let expr = self.parseExpression() + let expr = self.parseExpression(flavor: .basic, pattern: .none) return RawDiscardStmtSyntax( unexpectedBeforeDiscardKeyword, discardKeyword: discardKeyword, @@ -437,7 +437,7 @@ extension Parser { // Parse the optional 'where' guard. let whereClause: RawWhereClauseSyntax? if let whereKeyword = self.consume(if: .keyword(.where)) { - let condition = self.parseExpression(.basic) + let condition = self.parseExpression(flavor: .stmtCondition, pattern: .none) whereClause = RawWhereClauseSyntax( whereKeyword: whereKeyword, condition: condition, @@ -489,7 +489,7 @@ extension Parser { let (unexpectedBeforeRepeatKeyword, repeatKeyword) = self.eat(repeatHandle) let body = self.parseCodeBlock(introducer: repeatKeyword) let (unexpectedBeforeWhileKeyword, whileKeyword) = self.expect(.keyword(.while)) - let condition = self.parseExpression() + let condition = self.parseExpression(flavor: .basic, pattern: .none) return RawRepeatStmtSyntax( unexpectedBeforeRepeatKeyword, repeatKeyword: repeatKeyword, @@ -542,13 +542,13 @@ extension Parser { if self.at(.leftBrace) { expr = RawExprSyntax(RawMissingExprSyntax(arena: self.arena)) } else { - expr = self.parseExpression(.basic) + expr = self.parseExpression(flavor: .stmtCondition, pattern: .none) } // Parse the 'where' expression if present. let whereClause: RawWhereClauseSyntax? if let whereKeyword = self.consume(if: .keyword(.where)) { - let condition = self.parseExpression(.basic) + let condition = self.parseExpression(flavor: .stmtCondition, pattern: .none) whereClause = RawWhereClauseSyntax( whereKeyword: whereKeyword, condition: condition, @@ -646,7 +646,7 @@ extension Parser { // followed by a '}', '', statement or decl start keyword sequence. let expr: RawExprSyntax? if isStartOfReturnExpr() { - let parsedExpr = self.parseExpression() + let parsedExpr = self.parseExpression(flavor: .basic, pattern: .none) if hasMisplacedTry && !parsedExpr.is(RawTryExprSyntax.self) { expr = RawExprSyntax( RawTryExprSyntax( @@ -686,7 +686,7 @@ extension Parser { var elementList = [RawYieldedExpressionSyntax]() var loopProgress = LoopProgressCondition() while !self.at(.endOfFile, .rightParen) && keepGoing && self.hasProgressed(&loopProgress) { - let expr = self.parseExpression() + let expr = self.parseExpression(flavor: .basic, pattern: .none) let comma = self.consume(if: .comma) elementList.append( RawYieldedExpressionSyntax( @@ -711,7 +711,7 @@ extension Parser { ) ) } else { - yieldedExpressions = .single(self.parseExpression()) + yieldedExpressions = .single(self.parseExpression(flavor: .basic, pattern: .none)) } return RawYieldStmtSyntax( diff --git a/Sources/SwiftParser/TopLevel.swift b/Sources/SwiftParser/TopLevel.swift index 3dee2442501..dbfcf43d5b0 100644 --- a/Sources/SwiftParser/TopLevel.swift +++ b/Sources/SwiftParser/TopLevel.swift @@ -240,7 +240,7 @@ extension Parser { } else if self.atStartOfStatement() { return self.parseStatementItem() } else if self.atStartOfExpression() { - return .expr(self.parseExpression()) + return .expr(self.parseExpression(flavor: .basic, pattern: .none)) } else if self.atStartOfDeclaration(isAtTopLevel: isAtTopLevel, allowInitDecl: allowInitDecl, allowRecovery: true) { return .decl(self.parseDeclaration()) } else if self.atStartOfStatement(allowRecovery: true) { diff --git a/Sources/SwiftParser/generated/LayoutNodes+Parsable.swift b/Sources/SwiftParser/generated/LayoutNodes+Parsable.swift index 6d85fce7971..796dcc276f2 100644 --- a/Sources/SwiftParser/generated/LayoutNodes+Parsable.swift +++ b/Sources/SwiftParser/generated/LayoutNodes+Parsable.swift @@ -345,4 +345,8 @@ fileprivate extension Parser { } return node } + + mutating func parseExpression() -> RawExprSyntax { + return self.parseExpression(flavor: .basic, pattern: .none) + } }