Skip to content

A Grab Bag of Miscellaneous Parser Fixes #793

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 9 commits into from
Sep 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions Sources/SwiftParser/Attributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ extension Parser {
return RawSyntax(self.parseDynamicReplacementAttribute())
case ._spi:
return RawSyntax(self.parseSPIAttribute())
case ._implements:
return RawSyntax(self.parseImplementsAttribute())
case ._semantics:
return RawSyntax(self.parseSemanticsAttribute())
default:
break
}
Expand Down Expand Up @@ -682,6 +686,43 @@ extension Parser {
}
}

extension Parser {
mutating func parseImplementsAttribute() -> RawAttributeSyntax {
let (unexpectedBeforeAtSign, atSign) = self.expect(.atSign)
let (unexpectedBeforeSpiToken, spiToken) = self.expectContextualKeyword("_implements")
let (unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen)
let label = self.parseImplementsAttributeArguments()
let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
return RawAttributeSyntax(
unexpectedBeforeAtSign,
atSignToken: atSign,
unexpectedBeforeSpiToken,
attributeName: spiToken,
unexpectedBeforeLeftParen,
leftParen: leftParen,
argument: RawSyntax(label),
unexpectedBeforeRightParen,
rightParen: rightParen,
tokenList: nil,
arena: self.arena)
}

mutating func parseImplementsAttributeArguments() -> RawImplementsAttributeArgumentsSyntax {
let type = self.parseTypeIdentifier()
let (unexpectedBeforeComma, comma) = self.expect(.comma)
let (name, args) = self.parseDeclNameRef([
.zeroArgCompoundNames,
.operators,
])
return RawImplementsAttributeArgumentsSyntax(
type: type,
unexpectedBeforeComma, comma: comma,
declBaseName: name,
declNameArguments: args,
arena: self.arena)
}
}

extension Parser {
mutating func parseOpaqueReturnTypeOfAttributeArguments() -> RawOpaqueReturnTypeOfAttributeArgumentsSyntax {
let (unexpectedBeforeString, mangledName) = self.expect(.stringLiteral)
Expand All @@ -698,6 +739,28 @@ extension Parser {
}
}

extension Parser {
mutating func parseSemanticsAttribute() -> RawAttributeSyntax {
let (unexpectedBeforeAtSign, atSign) = self.expect(.atSign)
let (unexpectedBeforeSemanticsToken, semanticsToken) = self.expectContextualKeyword("_semantics")
let (unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen)
let label = self.parseStringLiteral()
let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
return RawAttributeSyntax(
unexpectedBeforeAtSign,
atSignToken: atSign,
unexpectedBeforeSemanticsToken,
attributeName: semanticsToken,
unexpectedBeforeLeftParen,
leftParen: leftParen,
argument: RawSyntax(label),
unexpectedBeforeRightParen,
rightParen: rightParen,
tokenList: nil,
arena: self.arena)
}
}

// MARK: Lookahead

extension Parser.Lookahead {
Expand Down
23 changes: 22 additions & 1 deletion Sources/SwiftParser/Declarations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,17 @@ extension Parser {
attrs = self.parseAttributeList()
}

let unexpectedBeforeIsolated: RawUnexpectedNodesSyntax?
let isolated: RawTokenSyntax?
if self.currentToken.isContextualKeyword("isolated") &&
!self.lookahead().startsParameterName(subject.isClosure) {
(unexpectedBeforeIsolated, isolated) = self.expectContextualKeyword("isolated")
} else {
unexpectedBeforeIsolated = nil
isolated = nil
}
let const = self.consumeIfContextualKeyword("_const")

let firstName: RawTokenSyntax?
let secondName: RawTokenSyntax?
let unexpectedBeforeColon: RawUnexpectedNodesSyntax?
Expand Down Expand Up @@ -1291,6 +1302,9 @@ extension Parser {
keepGoing = trailingComma != nil
elements.append(RawFunctionParameterSyntax(
attributes: attrs,
unexpectedBeforeIsolated,
isolated: isolated,
const: const,
firstName: firstName,
secondName: secondName,
unexpectedBeforeColon,
Expand Down Expand Up @@ -1398,7 +1412,14 @@ extension Parser {
public mutating func parseFunctionSignature() -> RawFunctionSignatureSyntax {
let input = self.parseParameterClause(for: .functionParameters)

let async = self.consumeIfContextualKeyword("async")
let async: RawTokenSyntax?
if let asyncTok = self.consumeIfContextualKeyword("async") {
async = asyncTok
} else if let reasync = self.consumeIfContextualKeyword("reasync") {
async = reasync
} else {
async = nil
}

var throwsKeyword = self.consume(ifAny: [.throwsKeyword, .rethrowsKeyword])

Expand Down
63 changes: 43 additions & 20 deletions Sources/SwiftParser/Expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,11 @@ extension Parser {
}
}

switch self.at(anyIn: AwaitTry.self) {
switch self.at(anyIn: AwaitTryMove.self) {
case (.awaitContextualKeyword, let handle)?:
let awaitTok = self.eat(handle)
let sub = self.parseSequenceExpressionElement(flavor, inVarOrLet: inVarOrLet)
let sub = self.parseSequenceExpressionElement(
flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
return RawExprSyntax(RawAwaitExprSyntax(
awaitKeyword: awaitTok,
expression: sub,
Expand All @@ -330,13 +331,22 @@ extension Parser {
let tryKeyword = self.eat(handle)
let mark = self.consume(ifAny: [.exclamationMark, .postfixQuestionMark])

let expression = self.parseSequenceExpressionElement(flavor, inVarOrLet: inVarOrLet)
let expression = self.parseSequenceExpressionElement(
flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
return RawExprSyntax(RawTryExprSyntax(
tryKeyword: tryKeyword,
questionOrExclamationMark: mark,
expression: expression,
arena: self.arena
))
case (._moveContextualKeyword, let handle)?:
let moveTok = self.eat(handle)
let sub = self.parseSequenceExpressionElement(
flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
return RawExprSyntax(RawMoveExprSyntax(
moveKeyword: moveTok,
expression: sub,
arena: self.arena))
case nil:
return self.parseUnaryExpression(flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
}
Expand Down Expand Up @@ -383,7 +393,9 @@ extension Parser {

default:
// If the next token is not an operator, just parse this as expr-postfix.
return self.parsePostfixExpression(flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
return self.parsePostfixExpression(
flavor, forDirective: forDirective, inVarOrLet: inVarOrLet,
periodHasKeyPathBehavior: false)
}
}

Expand All @@ -405,26 +417,21 @@ extension Parser {
public mutating func parsePostfixExpression(
_ flavor: ExprFlavor,
forDirective: Bool,
inVarOrLet: Bool
inVarOrLet: Bool,
periodHasKeyPathBehavior: Bool
) -> RawExprSyntax {
let head = self.parsePrimaryExpression(inVarOrLet: inVarOrLet)
guard !head.is(RawMissingExprSyntax.self) else {
return head
}
return self.parsePostfixExpressionSuffix(head, flavor, forDirective: forDirective)
return self.parsePostfixExpressionSuffix(
head, flavor, forDirective: forDirective,
periodHasKeyPathBehavior: periodHasKeyPathBehavior)
}

@_spi(RawSyntax)
public mutating func parseDottedExpressionSuffix(_ start: RawExprSyntax?) -> RawExprSyntax {
assert(self.at(any: [.period, .prefixPeriod]))

// A key path is special, because it allows .[, unlike anywhere else. The
// period itself should be left in the token stream. (.? and .! end up
// being operators, and so aren't handled here.)
// if (periodHasKeyPathBehavior && peekToken().is(tok::l_square)) {
// break
// }

let period = self.consumeAnyToken(remapping: .period)
// Handle "x.42" - a tuple index.
if let name = self.consume(if: .integerLiteral) {
Expand Down Expand Up @@ -478,7 +485,9 @@ extension Parser {
// TODO: diagnose and skip.
return nil
}
let result = parser.parsePostfixExpressionSuffix(head, flavor, forDirective: forDirective)
let result = parser.parsePostfixExpressionSuffix(
head, flavor, forDirective: forDirective,
periodHasKeyPathBehavior: false)

// TODO: diagnose and skip the remaining token in the current clause.
return result
Expand Down Expand Up @@ -513,7 +522,8 @@ extension Parser {
public mutating func parsePostfixExpressionSuffix(
_ start: RawExprSyntax,
_ flavor: ExprFlavor,
forDirective: Bool
forDirective: Bool,
periodHasKeyPathBehavior: Bool
) -> RawExprSyntax {
// Handle suffix expressions.
var leadingExpr = start
Expand All @@ -525,6 +535,13 @@ extension Parser {

// Check for a .foo suffix.
if self.at(any: [.period, .prefixPeriod]) {
// A key path is special, because it allows .[, unlike anywhere else. The
// period itself should be left in the token stream. (.? and .! end up
// being operators, and so aren't handled here.)
if periodHasKeyPathBehavior && self.peek().tokenKind == .leftSquareBracket {
break
}

leadingExpr = self.parseDottedExpressionSuffix(leadingExpr)
continue
}
Expand Down Expand Up @@ -700,7 +717,9 @@ extension Parser {
// the token is a operator starts with '.', or the following token is '['.
let root: RawExprSyntax?
if !self.currentToken.starts(with: ".") {
root = self.parsePostfixExpression(.basic, forDirective: forDirective, inVarOrLet: inVarOrLet)
root = self.parsePostfixExpression(
.basic, forDirective: forDirective, inVarOrLet: inVarOrLet,
periodHasKeyPathBehavior: true)
} else {
root = nil
}
Expand All @@ -714,12 +733,16 @@ extension Parser {
dot = self.consumeAnyToken()
}
let base = RawExprSyntax(RawKeyPathBaseExprSyntax(period: dot, arena: self.arena))
expression = self.parsePostfixExpressionSuffix(base, .basic, forDirective: forDirective)
expression = self.parsePostfixExpressionSuffix(
base, .basic, forDirective: forDirective,
periodHasKeyPathBehavior: false)
} else if self.at(any: [.period, .prefixPeriod]) {
// Inside a keypath's path, the period always behaves normally: the key path
// behavior is only the separation between type and path.
let base = self.parseDottedExpressionSuffix(nil)
expression = self.parsePostfixExpressionSuffix(base, .basic, forDirective: forDirective)
expression = self.parsePostfixExpressionSuffix(
base, .basic, forDirective: forDirective,
periodHasKeyPathBehavior: false)
} else {
expression = RawExprSyntax(RawMissingExprSyntax(arena: self.arena))
}
Expand Down Expand Up @@ -870,7 +893,7 @@ extension Parser {
// 'any' followed by another identifier is an existential type.
if self.atContextualKeyword("any"),
self.peek().tokenKind == .identifier,
self.peek().isAtStartOfLine
!self.peek().isAtStartOfLine
{
let ty = self.parseType()
return RawExprSyntax(RawTypeExprSyntax(type: ty, arena: self.arena))
Expand Down
72 changes: 42 additions & 30 deletions Sources/SwiftParser/Modifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ extension Parser {
(.internalKeyword, _)?,
(.publicKeyword, _)?:
elements.append(parseAccessLevelModifier())
case (.open, _)?:
elements.append(parseOpenAccessLevelModifier())
case (.staticKeyword, let handle)?:
let staticKeyword = self.eat(handle)
elements.append(RawDeclModifierSyntax(
Expand Down Expand Up @@ -64,7 +66,6 @@ extension Parser {
(.nonmutating, _)?,
(.convenience, _)?,
(.override, _)?,
(.open, _)?,
(.weak, _)?,
(.indirect, _)?,
(.isolated, _)?,
Expand Down Expand Up @@ -130,43 +131,54 @@ extension Parser {
)
}

mutating func parseOpenAccessLevelModifier() -> RawDeclModifierSyntax {
let (unexpectedBeforeName, name) = self.expectContextualKeyword("open")
let details = self.parseAccessModifierDetails()
return RawDeclModifierSyntax(
unexpectedBeforeName,
name: name,
detail: details,
arena: self.arena)
}

mutating func parseAccessLevelModifier() -> RawDeclModifierSyntax {
let (unexpectedBeforeName, name) = expectAny(
[.privateKeyword, .fileprivateKeyword, .internalKeyword, .publicKeyword],
default: .internalKeyword
)
let details: RawDeclModifierDetailSyntax?
if let leftParen = consume(if: .leftParen) {
let unexpectedBeforeDetail: RawUnexpectedNodesSyntax?
let detail: RawTokenSyntax
if let setHandle = canRecoverToContextualKeyword("set", precedence: .weakBracketClose) {
(unexpectedBeforeDetail, detail) = eat(setHandle)
} else {
unexpectedBeforeDetail = nil
detail = RawTokenSyntax(
missing: .contextualKeyword,
text: "set",
arena: arena
)
}
let (unexpectedBeforeRightParen, rightParen) = expect(.rightParen)

details = RawDeclModifierDetailSyntax(
leftParen: leftParen,
unexpectedBeforeDetail,
detail: detail,
unexpectedBeforeRightParen,
rightParen: rightParen,
arena: arena
)
} else {
details = nil
}
let details = self.parseAccessModifierDetails()
return RawDeclModifierSyntax(
unexpectedBeforeName,
name: name,
detail: details,
arena: arena
)
arena: self.arena)
}

mutating func parseAccessModifierDetails() -> RawDeclModifierDetailSyntax? {
guard let leftParen = consume(if: .leftParen) else {
return nil
}

let unexpectedBeforeDetail: RawUnexpectedNodesSyntax?
let detail: RawTokenSyntax
if let setHandle = canRecoverToContextualKeyword("set", precedence: .weakBracketClose) {
(unexpectedBeforeDetail, detail) = eat(setHandle)
} else {
unexpectedBeforeDetail = nil
detail = RawTokenSyntax(
missing: .contextualKeyword,
text: "set",
arena: arena
)
}
let (unexpectedBeforeRightParen, rightParen) = expect(.rightParen)

return RawDeclModifierDetailSyntax(
leftParen: leftParen,
unexpectedBeforeDetail,
detail: detail,
unexpectedBeforeRightParen,
rightParen: rightParen,
arena: self.arena)
}
}
Loading