Skip to content

Commit 2a1597f

Browse files
committed
Explicitly model all supported contextual keywords in the contextualKeyword RawTokenKind
The main change here is that the `contextualKeyword` `TokenKind` and `RawTokenKind` no longer have a string as an associated value but an enum that enumerates all known contextual keywords. In follow-up commits, this allows us to rename `contextualKeyword` to `keyword` and merge all the other known keywords into the `Keyword` enum that currently enumerates all contextual keywords. That way we can remove the distinction between contextual keywords and keywords we currently have. I’m also thinking that we can use this additional structure to guarantee a little more type safety in the parser, for example by generating `RawTokenKindSubset`s for children that have `text_choices` set, but I still need to look into that.
1 parent b8a1761 commit 2a1597f

File tree

61 files changed

+3035
-1935
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+3035
-1935
lines changed

CodeGeneration/Sources/SyntaxSupport/TokenSpec.swift.gyb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public class TokenSpec {
2929
public let isKeyword: Bool
3030
public let requiresLeadingSpace: Bool
3131
public let requiresTrailingSpace: Bool
32+
public let associatedValueClass: String?
3233

3334
public var swiftKind: String {
3435
let name = lowercaseFirstWord(name: self.name)
@@ -49,7 +50,8 @@ public class TokenSpec {
4950
classification: String = "None",
5051
isKeyword: Bool = false,
5152
requiresLeadingSpace: Bool = false,
52-
requiresTrailingSpace: Bool = false
53+
requiresTrailingSpace: Bool = false,
54+
associatedValueClass: String? = nil
5355
) {
5456
self.name = name
5557
self.kind = kind
@@ -64,6 +66,7 @@ public class TokenSpec {
6466
self.isKeyword = isKeyword
6567
self.requiresLeadingSpace = requiresLeadingSpace
6668
self.requiresTrailingSpace = requiresTrailingSpace
69+
self.associatedValueClass = associatedValueClass
6770
}
6871
}
6972

@@ -243,6 +246,9 @@ public let SYNTAX_TOKENS: [TokenSpec] = [
243246
% if token.requires_trailing_space:
244247
% parameters += ['requiresTrailingSpace: true']
245248
% end
249+
% end
250+
% if token.associated_value_class:
251+
% parameters += [f'associatedValueClass: "{token.associated_value_class}"']
246252
% end
247253
${class_name}Spec(${", ".join(parameters)}),
248254
% end

CodeGeneration/Sources/SyntaxSupport/gyb_generated/TokenSpec.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class TokenSpec {
2323
public let isKeyword: Bool
2424
public let requiresLeadingSpace: Bool
2525
public let requiresTrailingSpace: Bool
26+
public let associatedValueClass: String?
2627

2728
public var swiftKind: String {
2829
let name = lowercaseFirstWord(name: self.name)
@@ -43,7 +44,8 @@ public class TokenSpec {
4344
classification: String = "None",
4445
isKeyword: Bool = false,
4546
requiresLeadingSpace: Bool = false,
46-
requiresTrailingSpace: Bool = false
47+
requiresTrailingSpace: Bool = false,
48+
associatedValueClass: String? = nil
4749
) {
4850
self.name = name
4951
self.kind = kind
@@ -58,6 +60,7 @@ public class TokenSpec {
5860
self.isKeyword = isKeyword
5961
self.requiresLeadingSpace = requiresLeadingSpace
6062
self.requiresTrailingSpace = requiresTrailingSpace
63+
self.associatedValueClass = associatedValueClass
6164
}
6265
}
6366

@@ -315,7 +318,7 @@ public let SYNTAX_TOKENS: [TokenSpec] = [
315318
MiscSpec(name: "PostfixOperator", kind: "oper_postfix", nameForDiagnostics: "postfix operator", classification: "OperatorIdentifier"),
316319
MiscSpec(name: "PrefixOperator", kind: "oper_prefix", nameForDiagnostics: "prefix operator", classification: "OperatorIdentifier"),
317320
MiscSpec(name: "DollarIdentifier", kind: "dollarident", nameForDiagnostics: "dollar identifier", classification: "DollarIdentifier"),
318-
MiscSpec(name: "ContextualKeyword", kind: "contextual_keyword", nameForDiagnostics: "keyword", classification: "Keyword"),
321+
MiscSpec(name: "ContextualKeyword", kind: "contextual_keyword", nameForDiagnostics: "keyword", classification: "Keyword", associatedValueClass: "Keyword"),
319322
MiscSpec(name: "RawStringDelimiter", kind: "raw_string_delimiter", nameForDiagnostics: "raw string delimiter"),
320323
MiscSpec(name: "StringSegment", kind: "string_segment", nameForDiagnostics: "string segment", classification: "StringLiteral"),
321324
MiscSpec(name: "Yield", kind: "kw_yield", nameForDiagnostics: "yield", text: "yield"),

CodeGeneration/Sources/generate-swiftsyntax/templates/basicformat/BasicFormatFile.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ let basicFormatFile = SourceFile {
182182
}
183183
}
184184
}
185-
SwitchCase(#"case .contextualKeyword("async"):"#) {
185+
SwitchCase("case .contextualKeyword(.async):") {
186186
ReturnStmt("return true")
187187
}
188188
SwitchCase("default:") {

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/DeclarationAttributeFile.swift

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,49 @@ let declarationAttributeFile = SourceFile {
2525
)
2626

2727
ExtensionDecl("extension Parser") {
28-
EnumDecl("enum DeclarationAttribute: SyntaxText, ContextualKeywords") {
28+
EnumDecl("enum DeclarationAttribute: RawTokenKindSubset") {
2929
for attribute in DECL_ATTR_KINDS {
30-
EnumCaseDecl("case \(raw: attribute.swiftName) = \"\(raw: attribute.name)\"")
30+
EnumCaseDecl("case \(raw: attribute.swiftName)")
31+
}
32+
EnumCaseDecl("case _spi_available")
33+
34+
InitializerDecl("init?(lexeme: Lexer.Lexeme)") {
35+
SwitchStmt(switchKeyword: .switch, expression: Expr("lexeme")) {
36+
for attribute in DECL_ATTR_KINDS {
37+
SwitchCase("case RawTokenKindMatch(.\(raw: attribute.name)):") {
38+
SequenceExpr("self = .\(raw: attribute.swiftName)")
39+
}
40+
}
41+
SwitchCase("case RawTokenKindMatch(.rethrowsKeyword):") {
42+
SequenceExpr("self = .atRethrows")
43+
}
44+
SwitchCase("case RawTokenKindMatch(._spi_available):") {
45+
SequenceExpr("self = ._spi_available")
46+
}
47+
SwitchCase("default:") {
48+
ReturnStmt("return nil")
49+
}
50+
}
51+
}
52+
53+
VariableDecl(
54+
name: IdentifierPattern("rawTokenKind"),
55+
type: TypeAnnotation(
56+
colon: .colon,
57+
type: SimpleTypeIdentifier("RawTokenKind")
58+
)
59+
) {
60+
SwitchStmt(switchKeyword: .switch, expression: Expr("self")) {
61+
for attribute in DECL_ATTR_KINDS {
62+
SwitchCase("case .\(raw: attribute.swiftName):") {
63+
ReturnStmt("return .contextualKeyword(.\(raw: attribute.name))")
64+
}
65+
}
66+
SwitchCase("case ._spi_available:") {
67+
ReturnStmt("return .contextualKeyword(._spi_available)")
68+
}
69+
}
3170
}
32-
EnumCaseDecl(#"case _spi_available = "_spi_available""#)
3371
}
3472
}
3573
}

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/DeclarationModifierFile.swift

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,17 @@ let declarationModifierFile = SourceFile {
2424
"""
2525
)
2626

27-
EnumDecl("enum DeclarationModifier: SyntaxText, ContextualKeywords, RawTokenKindSubset") {
27+
EnumDecl("enum DeclarationModifier: RawTokenKindSubset") {
2828
for attribute in DECL_MODIFIER_KINDS {
29-
EnumCaseDecl("case \(raw: attribute.swiftName) = \"\(raw: attribute.name)\"")
29+
EnumCaseDecl("case \(raw: attribute.swiftName)")
3030
}
3131
InitializerDecl("init?(lexeme: Lexer.Lexeme)") {
32-
SwitchStmt(switchKeyword: .switch, expression: Expr("lexeme.tokenKind")) {
33-
for attribute in DECL_MODIFIER_KINDS where attribute.swiftName.hasSuffix("Keyword") {
34-
SwitchCase("case .\(raw: attribute.swiftName):") {
32+
SwitchStmt(expression: Expr("lexeme")) {
33+
for attribute in DECL_MODIFIER_KINDS {
34+
SwitchCase("case RawTokenKindMatch(.\(raw: attribute.swiftName)):") {
3535
SequenceExpr("self = .\(raw: attribute.swiftName)")
3636
}
3737
}
38-
SwitchCase("case .identifier:") {
39-
FunctionCallExpr("self.init(rawValue: lexeme.tokenText)")
40-
}
4138
SwitchCase("default:") {
4239
ReturnStmt("return nil")
4340
}
@@ -51,38 +48,17 @@ let declarationModifierFile = SourceFile {
5148
type: SimpleTypeIdentifier("RawTokenKind")
5249
)
5350
) {
54-
SwitchStmt(switchKeyword: .switch, expression: Expr("self")) {
51+
SwitchStmt(expression: Expr("self")) {
5552
for attribute in DECL_MODIFIER_KINDS {
5653
SwitchCase("case .\(raw: attribute.swiftName):") {
5754
if attribute.swiftName.hasSuffix("Keyword") {
5855
ReturnStmt("return .\(raw: attribute.swiftName)")
5956
} else {
60-
ReturnStmt("return .identifier")
57+
ReturnStmt("return .contextualKeyword(.\(raw: attribute.swiftName))")
6158
}
6259
}
6360
}
6461
}
6562
}
66-
67-
68-
VariableDecl(
69-
name: IdentifierPattern("contextualKeyword"),
70-
type: TypeAnnotation(
71-
colon: .colon,
72-
type: OptionalType("SyntaxText?")
73-
)
74-
) {
75-
SwitchStmt(switchKeyword: .switch, expression: Expr("self")) {
76-
for attribute in DECL_MODIFIER_KINDS where !attribute.swiftName.hasSuffix("Keyword") {
77-
SwitchCase("case .\(raw: attribute.swiftName):") {
78-
ReturnStmt("return \"\(raw: attribute.name)\"")
79-
}
80-
}
81-
82-
SwitchCase("default:") {
83-
ReturnStmt("return nil")
84-
}
85-
}
86-
}
8763
}
8864
}

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/TypeAttributeFile.swift

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,38 @@ let typeAttributeFile = SourceFile {
2525
)
2626

2727
ExtensionDecl("extension Parser") {
28-
EnumDecl("enum TypeAttribute: SyntaxText, ContextualKeywords") {
28+
EnumDecl("enum TypeAttribute: RawTokenKindSubset") {
2929
for attribute in TYPE_ATTR_KINDS {
30-
EnumCaseDecl("case \(raw: attribute.name) = \"\(raw: attribute.name)\"")
30+
EnumCaseDecl("case \(raw: attribute.name)")
31+
}
32+
33+
InitializerDecl("init?(lexeme: Lexer.Lexeme)") {
34+
SwitchStmt(switchKeyword: .switch, expression: Expr("lexeme")) {
35+
for attribute in TYPE_ATTR_KINDS {
36+
SwitchCase("case RawTokenKindMatch(.\(raw: attribute.name)):") {
37+
SequenceExpr("self = .\(raw: attribute.swiftName)")
38+
}
39+
}
40+
SwitchCase("default:") {
41+
ReturnStmt("return nil")
42+
}
43+
}
44+
}
45+
46+
VariableDecl(
47+
name: IdentifierPattern("rawTokenKind"),
48+
type: TypeAnnotation(
49+
colon: .colon,
50+
type: SimpleTypeIdentifier("RawTokenKind")
51+
)
52+
) {
53+
SwitchStmt(switchKeyword: .switch, expression: Expr("self")) {
54+
for attribute in TYPE_ATTR_KINDS {
55+
SwitchCase("case .\(raw: attribute.swiftName):") {
56+
ReturnStmt("return .contextualKeyword(.\(raw: attribute.name))")
57+
}
58+
}
59+
}
3160
}
3261
}
3362
}

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxTraitsFile.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ let syntaxTraitsFile = SourceFileSyntax {
2525

2626
for child in trait.children {
2727
VariableDeclSyntax("var \(raw: child.swiftName): \(raw: child.typeName)\(raw: child.isOptional ? "?" : "") { get }")
28-
FunctionDeclSyntax("func with\(raw: child.name)(_ newChild: \(raw: child.typeName)?) -> Self")
28+
FunctionDeclSyntax("func with\(raw: child.name)(_ newChild: \(raw: child.typeName)\(raw: child.isOptional ? "?" : "")) -> Self")
2929
}
3030
}
3131

0 commit comments

Comments
 (0)