mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[ASTGen] Generate miscellaneous builtin pound
`#error`, `#warning`, and `#assert`. Also #_hasSymbol statement condition
This commit is contained in:
@@ -388,7 +388,7 @@ struct BridgedDeclObj {
|
||||
BRIDGED_INLINE bool Destructor_isIsolated() const;
|
||||
};
|
||||
|
||||
enum ENUM_EXTENSIBILITY_ATTR(open) BridgedASTNodeKind : uint8_t {
|
||||
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedASTNodeKind : uint8_t {
|
||||
BridgedASTNodeKindExpr,
|
||||
BridgedASTNodeKindStmt,
|
||||
BridgedASTNodeKindDecl
|
||||
@@ -2323,6 +2323,13 @@ BridgedPoundAvailableInfo BridgedPoundAvailableInfo_createParsed(
|
||||
BridgedSourceLoc cLParenLoc, BridgedArrayRef cSpecs,
|
||||
BridgedSourceLoc cRParenLoc, bool isUnavailability);
|
||||
|
||||
SWIFT_NAME("BridgedStmtConditionElement.createHasSymbol(_:poundLoc:lParenLoc:"
|
||||
"symbol:rParenLoc:)")
|
||||
BridgedStmtConditionElement BridgedStmtConditionElement_createHasSymbol(
|
||||
BridgedASTContext cContext, BridgedSourceLoc cPoundLoc,
|
||||
BridgedSourceLoc cLParenLoc, BridgedNullableExpr cSymbolExpr,
|
||||
BridgedSourceLoc cRParenLoc);
|
||||
|
||||
struct BridgedCaseLabelItemInfo {
|
||||
SWIFT_NAME("isDefault")
|
||||
bool IsDefault;
|
||||
@@ -2425,6 +2432,11 @@ BridgedIfStmt BridgedIfStmt_createParsed(
|
||||
BridgedSourceLoc cIfLoc, BridgedArrayRef cConds, BridgedBraceStmt cThen,
|
||||
BridgedSourceLoc cElseLoc, BridgedNullableStmt cElse);
|
||||
|
||||
SWIFT_NAME("BridgedPoundAssertStmt.createParsed(_:range:condition:message:)")
|
||||
BridgedPoundAssertStmt BridgedPoundAssertStmt_createParsed(
|
||||
BridgedASTContext cContext, BridgedSourceRange cRange,
|
||||
BridgedExpr cConditionExpr, BridgedStringRef cMessage);
|
||||
|
||||
SWIFT_NAME("BridgedRepeatWhileStmt.createParsed(_:labelInfo:repeatLoc:cond:"
|
||||
"whileLoc:body:)")
|
||||
BridgedRepeatWhileStmt BridgedRepeatWhileStmt_createParsed(
|
||||
@@ -3110,6 +3122,15 @@ struct BridgedFingerprint {
|
||||
BRIDGED_INLINE swift::Fingerprint unbridged() const;
|
||||
};
|
||||
|
||||
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedPoundKeyword : uint8_t {
|
||||
#define POUND_KEYWORD(NAME) BridgedPoundKeyword_##NAME,
|
||||
#include "swift/AST/TokenKinds.def"
|
||||
BridgedPoundKeyword_None,
|
||||
};
|
||||
|
||||
SWIFT_NAME("BridgedPoundKeyword.init(from:)")
|
||||
BridgedPoundKeyword BridgedPoundKeyword_fromString(BridgedStringRef cStr);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MARK: #if handling
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -149,3 +149,14 @@ BridgedOwnedString BridgedGenericSignature::getDebugDescription() const {
|
||||
unbridged().print(os);
|
||||
return BridgedOwnedString(str);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MARK: BridgedPoundKeyword
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
BridgedPoundKeyword BridgedPoundKeyword_fromString(BridgedStringRef cStr) {
|
||||
return llvm::StringSwitch<BridgedPoundKeyword>(cStr.unbridged())
|
||||
#define POUND_KEYWORD(NAME) .Case(#NAME, BridgedPoundKeyword_##NAME)
|
||||
#include "swift/AST/TokenKinds.def"
|
||||
.Default(BridgedPoundKeyword_None);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,15 @@ BridgedPoundAvailableInfo BridgedPoundAvailableInfo_createParsed(
|
||||
cRParenLoc.unbridged(), isUnavailability);
|
||||
}
|
||||
|
||||
BridgedStmtConditionElement BridgedStmtConditionElement_createHasSymbol(
|
||||
BridgedASTContext cContext, BridgedSourceLoc cPoundLoc,
|
||||
BridgedSourceLoc cLParenLoc, BridgedNullableExpr cSymbolExpr,
|
||||
BridgedSourceLoc cRParenLoc) {
|
||||
return StmtConditionElement(PoundHasSymbolInfo::create(
|
||||
cContext.unbridged(), cPoundLoc.unbridged(), cLParenLoc.unbridged(),
|
||||
cSymbolExpr.unbridged(), cRParenLoc.unbridged()));
|
||||
}
|
||||
|
||||
BridgedBraceStmt BridgedBraceStmt_createParsed(BridgedASTContext cContext,
|
||||
BridgedSourceLoc cLBLoc,
|
||||
BridgedArrayRef elements,
|
||||
@@ -229,6 +238,13 @@ BridgedIfStmt BridgedIfStmt_createParsed(
|
||||
cThen.unbridged(), cElseLoc.unbridged(), cElse.unbridged());
|
||||
}
|
||||
|
||||
BridgedPoundAssertStmt BridgedPoundAssertStmt_createParsed(
|
||||
BridgedASTContext cContext, BridgedSourceRange cRange,
|
||||
BridgedExpr cConditionExpr, BridgedStringRef cMessage) {
|
||||
return new (cContext.unbridged()) PoundAssertStmt(
|
||||
cRange.unbridged(), cConditionExpr.unbridged(), cMessage.unbridged());
|
||||
}
|
||||
|
||||
BridgedRepeatWhileStmt BridgedRepeatWhileStmt_createParsed(
|
||||
BridgedASTContext cContext, BridgedLabeledStmtInfo cLabelInfo,
|
||||
BridgedSourceLoc cRepeatLoc, BridgedExpr cCond, BridgedSourceLoc cWhileLoc,
|
||||
|
||||
@@ -58,38 +58,41 @@ struct ASTGenVisitor {
|
||||
}
|
||||
|
||||
func generate(sourceFile node: SourceFileSyntax) -> [BridgedASTNode] {
|
||||
var out = [BridgedASTNode]()
|
||||
let isTopLevel = self.declContext.isModuleScopeContext
|
||||
|
||||
visitIfConfigElements(
|
||||
node.statements,
|
||||
of: CodeBlockItemSyntax.self,
|
||||
split: Self.splitCodeBlockItemIfConfig
|
||||
) { element in
|
||||
|
||||
func generateStmtOrExpr(_ body: () -> BridgedASTNode) -> BridgedASTNode {
|
||||
if !isTopLevel {
|
||||
return body()
|
||||
// If not top-level, no need for 'TopLevelCodeDecl' treatment.
|
||||
if !self.declContext.isModuleScopeContext {
|
||||
return self.generate(codeBlockItemList: node.statements)
|
||||
} else {
|
||||
return self.generateTopLevel(codeBlockItemList: node.statements)
|
||||
}
|
||||
}
|
||||
|
||||
let topLevelDecl = BridgedTopLevelCodeDecl.create(self.ctx, declContext: self.declContext)
|
||||
let astNode = withDeclContext(topLevelDecl.asDeclContext) {
|
||||
body()
|
||||
func generateTopLevel(codeBlockItem node: CodeBlockItemSyntax) -> BridgedASTNode? {
|
||||
let parentDC = self.declContext
|
||||
|
||||
func maybeTopLevelCodeDecl(body: () -> BridgedASTNode?) -> BridgedASTNode? {
|
||||
let topLevelDecl: BridgedTopLevelCodeDecl = BridgedTopLevelCodeDecl.create(self.ctx, declContext: self.declContext)
|
||||
guard let astNode = withDeclContext(topLevelDecl.asDeclContext, body) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Diagnose top level code in non-script file.
|
||||
if (!declContext.parentSourceFile.isScriptMode) {
|
||||
switch element.item {
|
||||
if astNode.kind == .decl {
|
||||
// If a decl is generated, discard the TopLevelCodeDecl.
|
||||
return astNode
|
||||
}
|
||||
|
||||
// Diagnose top-level code in non-script files.
|
||||
if !declContext.parentSourceFile.isScriptMode {
|
||||
switch astNode.kind {
|
||||
case .stmt:
|
||||
self.diagnose(.illegalTopLevelStmt(element))
|
||||
self.diagnose(.illegalTopLevelStmt(node))
|
||||
case .expr:
|
||||
self.diagnose(.illegalTopLevelExpr(element))
|
||||
self.diagnose(.illegalTopLevelExpr(node))
|
||||
case .decl:
|
||||
fatalError("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
let bodyRange = self.generateImplicitBraceRange(element)
|
||||
let bodyRange = self.generateImplicitBraceRange(node)
|
||||
let body = BridgedBraceStmt.createImplicit(
|
||||
self.ctx,
|
||||
lBraceLoc: bodyRange.start,
|
||||
@@ -100,31 +103,67 @@ struct ASTGenVisitor {
|
||||
return .decl(topLevelDecl.asDecl)
|
||||
}
|
||||
|
||||
// TODO: Set semicolon loc.
|
||||
switch element.item {
|
||||
switch node.item {
|
||||
case .decl(let node):
|
||||
if let d = self.generate(decl: node) {
|
||||
out.append(.decl(d))
|
||||
if let node = node.as(MacroExpansionDeclSyntax.self) {
|
||||
return maybeTopLevelCodeDecl {
|
||||
switch self.maybeGenerateBuiltinPound(freestandingMacroExpansion: node) {
|
||||
case .generated(let generated):
|
||||
return generated
|
||||
case .ignored:
|
||||
/// If it is actually a macro expansion decl, it should use the parent DC.
|
||||
return self.withDeclContext(parentDC) {
|
||||
return .decl(self.generate(macroExpansionDecl: node).asDecl)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Regular 'decl' nodes never be a stmt or expr. No top-level code treatment.
|
||||
return self.generate(decl: node).map { .decl($0) }
|
||||
|
||||
// Hoist 'VarDecl' to the top-level.
|
||||
withBridgedSwiftClosure { ptr in
|
||||
let hoisted = ptr!.load(as: BridgedDecl.self)
|
||||
out.append(.decl(hoisted))
|
||||
} call: { handle in
|
||||
d.forEachDeclToHoist(handle)
|
||||
}
|
||||
}
|
||||
case .stmt(let node):
|
||||
out.append(generateStmtOrExpr {
|
||||
.stmt(self.generate(stmt: node))
|
||||
})
|
||||
case .expr(let node):
|
||||
out.append(generateStmtOrExpr {
|
||||
.expr(self.generate(expr: node))
|
||||
})
|
||||
return maybeTopLevelCodeDecl {
|
||||
if let node = node.as(MacroExpansionExprSyntax.self) {
|
||||
switch self.maybeGenerateBuiltinPound(freestandingMacroExpansion: node) {
|
||||
case .generated(let generated):
|
||||
return generated
|
||||
case .ignored:
|
||||
// Let regular 'self.generate(expr:)' generate the macro expansions.
|
||||
break
|
||||
}
|
||||
}
|
||||
return .expr(self.generate(expr: node))
|
||||
}
|
||||
|
||||
case .stmt(let node):
|
||||
return maybeTopLevelCodeDecl {
|
||||
return .stmt(self.generate(stmt: node))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateTopLevel(codeBlockItemList node: CodeBlockItemListSyntax) -> [BridgedASTNode] {
|
||||
var out = [BridgedASTNode]()
|
||||
visitIfConfigElements(
|
||||
node,
|
||||
of: CodeBlockItemSyntax.self,
|
||||
split: Self.splitCodeBlockItemIfConfig
|
||||
) { element in
|
||||
guard let item = self.generateTopLevel(codeBlockItem: element) else {
|
||||
return
|
||||
}
|
||||
out.append(item)
|
||||
|
||||
// Hoist 'VarDecl' to the block.
|
||||
if item.kind == .decl {
|
||||
withBridgedSwiftClosure { ptr in
|
||||
let d = ptr!.load(as: BridgedDecl.self)
|
||||
out.append(.decl(d))
|
||||
} call: { handle in
|
||||
item.castToDecl().forEachDeclToHoist(handle)
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
204
lib/ASTGen/Sources/ASTGen/BuiltinPound.swift
Normal file
204
lib/ASTGen/Sources/ASTGen/BuiltinPound.swift
Normal file
@@ -0,0 +1,204 @@
|
||||
//===--- BuiltinPound.swift -----------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2025 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import ASTBridging
|
||||
import BasicBridging
|
||||
@_spi(RawSyntax) import SwiftSyntax
|
||||
|
||||
extension ASTGenVisitor {
|
||||
/// 3 state result:
|
||||
/// * successfully generated: `.generated(.some(T))`
|
||||
/// * handled but failed: `.generated(.none)`
|
||||
/// * fallback to default behavior: `.ignored`
|
||||
enum MaybeGenerated<T> {
|
||||
case generated(T?)
|
||||
case ignored
|
||||
}
|
||||
|
||||
func maybeGenerateBuiltinPound(macroExpansionDecl node: MacroExpansionDeclSyntax) -> MaybeGenerated<BridgedASTNode> {
|
||||
let result = maybeGenerateBuiltinPound(freestandingMacroExpansion: node)
|
||||
|
||||
switch result {
|
||||
case .generated(_):
|
||||
guard node.attributes.isEmpty && node.modifiers.isEmpty else {
|
||||
// TODO: Diagnose.
|
||||
fatalError("attributes not applied")
|
||||
}
|
||||
break
|
||||
case .ignored:
|
||||
break
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/// Handle built in pound keywords.
|
||||
func maybeGenerateBuiltinPound(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> MaybeGenerated<BridgedASTNode> {
|
||||
let macroNameText = node.macroName.rawText;
|
||||
|
||||
// '#file', '#line' etc.
|
||||
let magicIdentifierKind = BridgedMagicIdentifierLiteralKind(from: macroNameText.bridged)
|
||||
if magicIdentifierKind != .none {
|
||||
let magicIdentifierExpr = self.generateMagicIdentifierExpr(
|
||||
freestandingMacroExpansion: node,
|
||||
kind: magicIdentifierKind
|
||||
)
|
||||
return .generated(.expr(magicIdentifierExpr.asExpr))
|
||||
}
|
||||
|
||||
// '#colorLiteral' et al.
|
||||
let objectLiteralKind = BridgedObjectLiteralKind(from: macroNameText.bridged)
|
||||
if objectLiteralKind != .none {
|
||||
let objectLiteralExpr = self.generateObjectLiteralExpr(
|
||||
freestandingMacroExpansion: node,
|
||||
kind: objectLiteralKind
|
||||
)
|
||||
return .generated(.expr(objectLiteralExpr.asExpr))
|
||||
}
|
||||
|
||||
// Other built-in pound syntax.
|
||||
let keyword = BridgedPoundKeyword(from: macroNameText.bridged)
|
||||
switch keyword {
|
||||
case .selector:
|
||||
let selectorExpr = self.generateObjCSelectorExpr(freestandingMacroExpansion: node)
|
||||
return .generated(.expr(selectorExpr.asExpr))
|
||||
|
||||
case .keyPath:
|
||||
let keypathExpr = self.generateObjCKeyPathExpr(freestandingMacroExpansion: node)
|
||||
return .generated(.expr(keypathExpr.asExpr))
|
||||
|
||||
case .assert where ctx.langOptsHasFeature(.StaticAssert):
|
||||
let assertStmtOpt = self.generatePoundAssertStmt(freestandingMacroExpansion: node)
|
||||
return .generated(assertStmtOpt.map({ .stmt($0.asStmt) }))
|
||||
|
||||
case .error, .warning:
|
||||
self.handlePoundDiagnostic(freestandingMacroExpansion: node, kind: keyword == .error ? .error : .warning)
|
||||
// '#error' and '#warning' don't produce an AST node.
|
||||
return .generated(nil)
|
||||
|
||||
case ._hasSymbol, .available, .unavailable:
|
||||
// TODO: Diagnose
|
||||
fatalError("stmt condition outside control flow statement")
|
||||
// return .generated(nil)
|
||||
|
||||
case .none, .assert:
|
||||
// Not a builtin pound keyword.
|
||||
return .ignored
|
||||
|
||||
case .file, .fileID, .filePath, .function, .line, .column, .dsohandle,
|
||||
.colorLiteral, .imageLiteral, .fileLiteral:
|
||||
// Should be handled above
|
||||
fatalError("(compiler bug) unreachable")
|
||||
|
||||
case .if, .elseif, .else, .endif, .sourceLocation:
|
||||
fatalError("(compiler bug) builtin pound keyword as macro expansion expr")
|
||||
}
|
||||
}
|
||||
|
||||
enum PoundDiagnosticKind {
|
||||
case warning, error
|
||||
}
|
||||
|
||||
func handlePoundDiagnostic(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax, kind: PoundDiagnosticKind) {
|
||||
|
||||
switch node.parent?.kind {
|
||||
case .codeBlockItem, .memberBlockItem, nil:
|
||||
break
|
||||
default:
|
||||
// TODO: Diagnose.
|
||||
fatalError("#error/#warning must be declaration level")
|
||||
// return
|
||||
}
|
||||
|
||||
guard node.arguments.count == 1,
|
||||
let arg = node.arguments.first,
|
||||
arg.label == nil,
|
||||
let literal = arg.expression.as(StringLiteralExprSyntax.self),
|
||||
let message = literal.representedLiteralValue
|
||||
else {
|
||||
// TODO: Diagnose.
|
||||
fatalError("expected single simple string literal in #error/#warning")
|
||||
}
|
||||
|
||||
// Unconditionally emit the diagnostic. Inactive #if regions are not generated.
|
||||
self.diagnose(.poundDiagnostic(literal, message: message, isError: kind == .error))
|
||||
}
|
||||
|
||||
func generatePoundAssertStmt(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedPoundAssertStmt? {
|
||||
assert(self.ctx.langOptsHasFeature(.StaticAssert))
|
||||
var args = node.arguments[...]
|
||||
let conditionExpr = self.generateConsumingAttrOption(args: &args, label: nil) { conditionNode in
|
||||
self.generate(expr: conditionNode)
|
||||
}
|
||||
guard let conditionExpr else {
|
||||
return nil
|
||||
}
|
||||
let message: BridgedStringRef?
|
||||
if !args.isEmpty {
|
||||
message = self.generateConsumingSimpleStringLiteralAttrOption(args: &args)
|
||||
} else {
|
||||
message = nil
|
||||
}
|
||||
|
||||
return .createParsed(
|
||||
self.ctx,
|
||||
range: self.generateSourceRange(node),
|
||||
condition: conditionExpr,
|
||||
message: message ?? BridgedStringRef()
|
||||
)
|
||||
}
|
||||
|
||||
func generateMagicIdentifierExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax, kind: BridgedMagicIdentifierLiteralKind) -> BridgedMagicIdentifierLiteralExpr {
|
||||
guard node.lastToken(viewMode: .sourceAccurate) == node.macroName else {
|
||||
// TODO: Diagnose.
|
||||
fatalError("magic identifier token with arguments")
|
||||
}
|
||||
|
||||
return BridgedMagicIdentifierLiteralExpr.createParsed(
|
||||
self.ctx,
|
||||
kind: kind,
|
||||
loc: self.generateSourceLoc(node.macroName)
|
||||
)
|
||||
}
|
||||
|
||||
func generateObjectLiteralExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax, kind: BridgedObjectLiteralKind) -> BridgedObjectLiteralExpr {
|
||||
guard
|
||||
node.genericArgumentClause == nil,
|
||||
node.trailingClosure == nil,
|
||||
node.additionalTrailingClosures.isEmpty
|
||||
else {
|
||||
// TODO: Diagnose.
|
||||
fatalError("object identifier with generic specialization")
|
||||
}
|
||||
|
||||
return BridgedObjectLiteralExpr.createParsed(
|
||||
self.ctx,
|
||||
poundLoc: self.generateSourceLoc(node.pound),
|
||||
kind: kind,
|
||||
args: self.generateArgumentList(
|
||||
leftParen: node.leftParen,
|
||||
labeledExprList: node.arguments,
|
||||
rightParen: node.rightParen,
|
||||
trailingClosure: nil,
|
||||
additionalTrailingClosures: nil
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func generateObjCSelectorExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedObjCSelectorExpr {
|
||||
fatalError("unimplemented")
|
||||
}
|
||||
|
||||
func generateObjCKeyPathExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedKeyPathExpr {
|
||||
fatalError("unimplemented")
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ add_pure_swift_host_library(swiftASTGen STATIC CXX_INTEROP
|
||||
ASTGen+CompilerBuildConfiguration.swift
|
||||
Availability.swift
|
||||
Bridge.swift
|
||||
BuiltinPound.swift
|
||||
CompilerBuildConfiguration.swift
|
||||
DeclAttrs.swift
|
||||
Decls.swift
|
||||
|
||||
@@ -2201,7 +2201,8 @@ extension ASTGenVisitor {
|
||||
return extractRawText(segments).bridged
|
||||
}
|
||||
// TODO: Diagnose.
|
||||
return nil
|
||||
fatalError("expected string literal without interpolation")
|
||||
// return nil
|
||||
}
|
||||
|
||||
/// Convenient method for processing an attribute with `LabeledExprListSyntax`.
|
||||
|
||||
@@ -72,11 +72,6 @@ extension ASTGenVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
func generate(memberBlockItem node: MemberBlockItemSyntax) -> BridgedDecl? {
|
||||
// TODO: Set semicolon loc.
|
||||
generate(decl: node.decl)
|
||||
}
|
||||
|
||||
func generateIdentifierDeclNameAndLoc(_ node: TokenSyntax) -> (identifier: BridgedIdentifier, sourceLoc: BridgedSourceLoc)? {
|
||||
guard node.presence == .present else {
|
||||
return nil
|
||||
@@ -483,7 +478,7 @@ extension ASTGenVisitor {
|
||||
let brace = BridgedBraceStmt.createParsed(
|
||||
self.ctx,
|
||||
lBraceLoc: leftBrace,
|
||||
elements: self.generate(codeBlockItemList: codeBlock),
|
||||
elements: self.generate(codeBlockItemList: codeBlock).lazy.bridgedArray(in: self),
|
||||
rBraceLoc: rightBrace
|
||||
)
|
||||
accessor.setParsedBody(brace)
|
||||
@@ -836,9 +831,16 @@ extension ASTGenVisitor {
|
||||
|
||||
extension ASTGenVisitor {
|
||||
func generate(macroExpansionDecl node: MacroExpansionDeclSyntax) -> BridgedMacroExpansionDecl {
|
||||
switch self.maybeGenerateBuiltinPound(macroExpansionDecl: node) {
|
||||
case .generated(_):
|
||||
fatalError("(compiler bug) builtin pound keywords should be handled elsewhere")
|
||||
case .ignored:
|
||||
// Fallback to MacroExpansionDecl.
|
||||
break
|
||||
}
|
||||
|
||||
let attrs = self.generateDeclAttributes(node, allowStatic: true)
|
||||
let info = self.generate(freestandingMacroExpansion: node)
|
||||
|
||||
let decl = BridgedMacroExpansionDecl.createParsed(
|
||||
self.declContext,
|
||||
poundLoc: info.poundLoc,
|
||||
@@ -1059,6 +1061,29 @@ extension ASTGenVisitor {
|
||||
}
|
||||
|
||||
extension ASTGenVisitor {
|
||||
func generate(memberBlockItem node: MemberBlockItemSyntax) -> BridgedDecl? {
|
||||
if let node = node.decl.as(MacroExpansionDeclSyntax.self) {
|
||||
switch self.maybeGenerateBuiltinPound(macroExpansionDecl: node) {
|
||||
case .generated(let generated?):
|
||||
switch generated.kind {
|
||||
case .decl:
|
||||
// Actually unreachable as no builtin pound emits a declaration.
|
||||
return generated.castToDecl()
|
||||
case .stmt, .expr:
|
||||
// TODO: Diagnose
|
||||
fatalError("builtin pound keyword in declaration member block")
|
||||
//return nil
|
||||
}
|
||||
case .generated(nil):
|
||||
return nil
|
||||
case .ignored:
|
||||
// Fallback to normal macro expansion.
|
||||
break
|
||||
}
|
||||
}
|
||||
return self.generate(decl: node.decl)
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
func generate(memberBlockItemList node: MemberBlockItemListSyntax) -> [BridgedDecl] {
|
||||
var allMembers: [BridgedDecl] = []
|
||||
@@ -1068,8 +1093,8 @@ extension ASTGenVisitor {
|
||||
}
|
||||
|
||||
return .underlying(element)
|
||||
} body: { member in
|
||||
guard let member = self.generate(decl: member.decl) else {
|
||||
} body: { node in
|
||||
guard let member = self.generate(memberBlockItem: node) else {
|
||||
return
|
||||
}
|
||||
// TODO: Set semicolon loc.
|
||||
|
||||
@@ -165,3 +165,13 @@ extension ASTGenDiagnostic {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension ASTGenDiagnostic {
|
||||
static func poundDiagnostic(_ node: StringLiteralExprSyntax, message: String, isError: Bool) -> Self {
|
||||
Self(
|
||||
node: node,
|
||||
message: node.representedLiteralValue!,
|
||||
severity: isError ? .error : .warning
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,7 +388,7 @@ extension ASTGenVisitor {
|
||||
BridgedBraceStmt.createParsed(
|
||||
self.ctx,
|
||||
lBraceLoc: self.generateSourceLoc(node.leftBrace),
|
||||
elements: self.generate(codeBlockItemList: node.statements),
|
||||
elements: self.generate(codeBlockItemList: node.statements).lazy.bridgedArray(in: self),
|
||||
rBraceLoc: self.generateSourceLoc(node.rightBrace)
|
||||
)
|
||||
}
|
||||
@@ -847,83 +847,24 @@ extension ASTGenVisitor {
|
||||
)
|
||||
}
|
||||
|
||||
func generateMagicIdentifierExpr(macroExpansionExpr node: MacroExpansionExprSyntax, kind: BridgedMagicIdentifierLiteralKind) -> BridgedMagicIdentifierLiteralExpr {
|
||||
guard node.lastToken(viewMode: .sourceAccurate) == node.macroName else {
|
||||
// TODO: Diagnose.
|
||||
fatalError("magic identifier token with arguments")
|
||||
}
|
||||
|
||||
return BridgedMagicIdentifierLiteralExpr.createParsed(
|
||||
self.ctx,
|
||||
kind: kind,
|
||||
loc: self.generateSourceLoc(node.macroName)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
func generateObjectLiteralExpr(macroExpansionExpr node: MacroExpansionExprSyntax, kind: BridgedObjectLiteralKind) -> BridgedObjectLiteralExpr {
|
||||
guard
|
||||
node.genericArgumentClause == nil,
|
||||
node.trailingClosure == nil,
|
||||
node.additionalTrailingClosures.isEmpty
|
||||
else {
|
||||
// TODO: Diagnose.
|
||||
fatalError("object identifier with generic specialization")
|
||||
}
|
||||
|
||||
return BridgedObjectLiteralExpr.createParsed(
|
||||
self.ctx,
|
||||
poundLoc: self.generateSourceLoc(node.pound),
|
||||
kind: kind,
|
||||
args: self.generateArgumentList(
|
||||
leftParen: node.leftParen,
|
||||
labeledExprList: node.arguments,
|
||||
rightParen: node.rightParen,
|
||||
trailingClosure: nil,
|
||||
additionalTrailingClosures: nil
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func generateObjCSelectorExpr(macroExpansionExpr node: MacroExpansionExprSyntax) -> BridgedObjCSelectorExpr {
|
||||
fatalError("unimplemented")
|
||||
}
|
||||
|
||||
func generateObjCKeyPathExpr(macroExpansionExpr node: MacroExpansionExprSyntax) -> BridgedKeyPathExpr {
|
||||
fatalError("unimplemented")
|
||||
}
|
||||
|
||||
func generate(macroExpansionExpr node: MacroExpansionExprSyntax) -> BridgedExpr {
|
||||
let macroNameText = node.macroName.rawText;
|
||||
|
||||
// '#file', '#line' etc.
|
||||
let magicIdentifierKind = BridgedMagicIdentifierLiteralKind(from: macroNameText.bridged)
|
||||
if magicIdentifierKind != .none {
|
||||
return self.generateMagicIdentifierExpr(
|
||||
macroExpansionExpr: node,
|
||||
kind: magicIdentifierKind
|
||||
switch self.maybeGenerateBuiltinPound(freestandingMacroExpansion: node) {
|
||||
case .generated(let astNode):
|
||||
guard let astNode else {
|
||||
return BridgedErrorExpr.create(
|
||||
self.ctx,
|
||||
loc: self.generateSourceRange(node)
|
||||
).asExpr
|
||||
}
|
||||
|
||||
// '#colorLiteral' et al.
|
||||
let objectLiteralKind = BridgedObjectLiteralKind(from: macroNameText.bridged)
|
||||
if objectLiteralKind != .none {
|
||||
return self.generateObjectLiteralExpr(
|
||||
macroExpansionExpr: node,
|
||||
kind: objectLiteralKind
|
||||
).asExpr
|
||||
switch astNode.kind {
|
||||
case .expr:
|
||||
return astNode.castToExpr()
|
||||
case .stmt, .decl:
|
||||
// TODO: Diagnose
|
||||
fatalError("builtin pound directive in expression position")
|
||||
// return BridgedErrorExpr.create(...)
|
||||
}
|
||||
|
||||
// Other built-in pound expressions.
|
||||
switch macroNameText {
|
||||
case "selector":
|
||||
return self.generateObjCSelectorExpr(macroExpansionExpr: node).asExpr
|
||||
case "keyPath":
|
||||
return self.generateObjCKeyPathExpr(macroExpansionExpr: node).asExpr
|
||||
case "assert" where ctx.langOptsHasFeature(.StaticAssert), "error", "warning":
|
||||
// TODO: Diagnose.
|
||||
fatalError("Directives in expression position");
|
||||
default:
|
||||
case .ignored:
|
||||
// Fallback to MacroExpansionExpr.
|
||||
break
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import ASTBridging
|
||||
import SwiftDiagnostics
|
||||
@_spi(ExperimentalLanguageFeatures) import SwiftSyntax
|
||||
@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) import SwiftSyntax
|
||||
|
||||
protocol DoStmtOrExprSyntax {
|
||||
var doKeyword: TokenSyntax { get }
|
||||
@@ -70,16 +70,34 @@ extension ASTGenVisitor {
|
||||
// TODO: Set semicolon loc.
|
||||
switch node.item {
|
||||
case .decl(let node):
|
||||
if let node = node.as(MacroExpansionDeclSyntax.self) {
|
||||
switch self.maybeGenerateBuiltinPound(macroExpansionDecl: node) {
|
||||
case .generated(let generated):
|
||||
return generated
|
||||
case .ignored:
|
||||
// Fallback to normal macro expansion.
|
||||
break
|
||||
}
|
||||
}
|
||||
return self.generate(decl: node).map { .decl($0) }
|
||||
case .stmt(let node):
|
||||
return .stmt(self.generate(stmt: node))
|
||||
case .expr(let node):
|
||||
if let node = node.as(MacroExpansionExprSyntax.self) {
|
||||
switch self.maybeGenerateBuiltinPound(freestandingMacroExpansion: node) {
|
||||
case .generated(let generated):
|
||||
return generated
|
||||
case .ignored:
|
||||
// Fallback to normal macro expansion.
|
||||
break
|
||||
}
|
||||
}
|
||||
return .expr(self.generate(expr: node))
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
func generate(codeBlockItemList node: CodeBlockItemListSyntax) -> BridgedArrayRef {
|
||||
func generate(codeBlockItemList node: CodeBlockItemListSyntax) -> [BridgedASTNode] {
|
||||
var allItems: [BridgedASTNode] = []
|
||||
visitIfConfigElements(
|
||||
node,
|
||||
@@ -102,7 +120,7 @@ extension ASTGenVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
return allItems.lazy.bridgedArray(in: self)
|
||||
return allItems
|
||||
}
|
||||
|
||||
/// Function that splits a code block item into either an #if or the item.
|
||||
@@ -121,19 +139,47 @@ extension ASTGenVisitor {
|
||||
BridgedBraceStmt.createParsed(
|
||||
self.ctx,
|
||||
lBraceLoc: self.generateSourceLoc(node.leftBrace),
|
||||
elements: self.generate(codeBlockItemList: node.statements),
|
||||
elements: self.generate(codeBlockItemList: node.statements).lazy.bridgedArray(in: self),
|
||||
rBraceLoc: self.generateSourceLoc(node.rightBrace)
|
||||
)
|
||||
}
|
||||
|
||||
func generateHasSymbolStmtCondition(macroExpansionExpr node: MacroExpansionExprSyntax) -> BridgedStmtConditionElement {
|
||||
var args = node.arguments[...]
|
||||
let symbol: BridgedExpr?
|
||||
if let arg = args.popFirst() {
|
||||
symbol = self.generate(expr: arg.expression)
|
||||
if arg.label != nil {
|
||||
// TODO: Diagnose
|
||||
fatalError("unexpected label")
|
||||
}
|
||||
if !args.isEmpty {
|
||||
// TODO: Diagnose
|
||||
fatalError("extra args")
|
||||
}
|
||||
} else {
|
||||
symbol = nil
|
||||
}
|
||||
return .createHasSymbol(
|
||||
self.ctx,
|
||||
poundLoc: self.generateSourceLoc(node.pound),
|
||||
lParenLoc: self.generateSourceLoc(node.leftParen),
|
||||
symbol: symbol.asNullable,
|
||||
rParenLoc: self.generateSourceLoc(node.rightParen)
|
||||
)
|
||||
}
|
||||
|
||||
func generate(conditionElement node: ConditionElementSyntax) -> BridgedStmtConditionElement {
|
||||
// FIXME: _hasSymbol is not implemented in SwiftSyntax/SwiftParser.
|
||||
switch node.condition {
|
||||
case .availability(let node):
|
||||
return .createPoundAvailable(
|
||||
info: self.generate(availabilityCondition: node)
|
||||
)
|
||||
case .expression(let node):
|
||||
if let node = node.as(MacroExpansionExprSyntax.self),
|
||||
node.macroName.rawText == "_hasSymbol" {
|
||||
return generateHasSymbolStmtCondition(macroExpansionExpr: node)
|
||||
}
|
||||
return .createBoolean(
|
||||
expr: self.generate(expr: node)
|
||||
)
|
||||
@@ -487,7 +533,7 @@ extension ASTGenVisitor {
|
||||
let body = BridgedBraceStmt.createParsed(
|
||||
self.ctx,
|
||||
lBraceLoc: nil,
|
||||
elements: self.generate(codeBlockItemList: node.statements),
|
||||
elements: self.generate(codeBlockItemList: node.statements).lazy.bridgedArray(in: self),
|
||||
rBraceLoc: nil
|
||||
)
|
||||
|
||||
|
||||
@@ -58,5 +58,7 @@ func testPoundIf() {
|
||||
// pass
|
||||
} else if #unavailable(macOS 80) {
|
||||
// pass
|
||||
} else if #_hasSymbol(Int.self) { // expected-warning {{struct 'Int' is not a weakly linked declaration}}
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,3 +36,18 @@ struct S {
|
||||
|
||||
struct ExpansionRequirementTest<each T> {}
|
||||
extension ExpansionRequirementTest where repeat each T == Int {} // expected-error {{same-element requirements are not yet supported}}
|
||||
|
||||
|
||||
#warning("this is a warning") // expected-warning {{this is a warning}}
|
||||
|
||||
func testDiagnosticInFunc() {
|
||||
#error("this is an error") // expected-error {{this is an error}}
|
||||
}
|
||||
|
||||
class TestDiagnosticInNominalTy {
|
||||
#error("this is an error member") // expected-error {{this is an error member}}
|
||||
}
|
||||
|
||||
#if FLAG_NOT_ENABLED
|
||||
#error("error in inactive") // no diagnostis
|
||||
#endif
|
||||
|
||||
21
test/ASTGen/pound_assert.swift
Normal file
21
test/ASTGen/pound_assert.swift
Normal file
@@ -0,0 +1,21 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend-dump-parse -enable-experimental-feature ParserASTGen \
|
||||
// RUN: -enable-experimental-feature StaticAssert \
|
||||
// RUN: | %sanitize-address > %t/astgen.ast
|
||||
// RUN: %target-swift-frontend-dump-parse \
|
||||
// RUN: -enable-experimental-feature StaticAssert \
|
||||
// RUN: | %sanitize-address > %t/cpp-parser.ast
|
||||
|
||||
// RUN: %diff -u %t/astgen.ast %t/cpp-parser.ast
|
||||
|
||||
// RUN: %target-swift-emit-sil -verify %s -enable-experimental-feature ParserASTGen \
|
||||
// RUN: -enable-experimental-feature StaticAssert
|
||||
|
||||
// REQUIRES: swift_swift_parser
|
||||
// REQUIRES: swift_feature_ParserASTGen
|
||||
// REQUIRES: swift_feature_StaticAssert
|
||||
|
||||
func testPoundAssert() {
|
||||
#assert(1 == 1.0, "1 must be 1.0") // OK
|
||||
#assert(1 == 1.5, "1 is 1.5 ??") // expected-error {{1 is 1.5 ??}}
|
||||
}
|
||||
Reference in New Issue
Block a user