Skip to content

Commit 636e6d1

Browse files
committed
[Macros] "Expand" builtin macros for magic literals.
Introduce an experimental option `BuiltinMacros` that takes the magic literals (`#file`, `#line`, `#function`, etc.) after type checking and processes the original source for the expression using the build syntactic macro system in the swift-syntax library. At present, the result of expansion is printed to standard output, but it's enough to verify that we're able to find the corresponding syntax node based on the C++ AST.
1 parent 9c528c6 commit 636e6d1

File tree

9 files changed

+125
-2
lines changed

9 files changed

+125
-2
lines changed

include/swift/Basic/Features.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,13 @@ EXPERIMENTAL_FEATURE(ImplicitSome)
145145
/// corresponding syntax tree.
146146
EXPERIMENTAL_FEATURE(ParserASTGen)
147147

148+
/// Enable the experimental macros feature.
148149
EXPERIMENTAL_FEATURE(Macros)
149150

151+
/// Parse using the Swift (swift-syntax) parser and use ASTGen to generate the
152+
/// corresponding syntax tree.
153+
EXPERIMENTAL_FEATURE(BuiltinMacros)
154+
150155
#undef EXPERIMENTAL_FEATURE
151156
#undef UPCOMING_FEATURE
152157
#undef SUPPRESSIBLE_LANGUAGE_FEATURE

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3098,6 +3098,10 @@ static bool usesFeatureParserASTGen(Decl *decl) {
30983098
return false;
30993099
}
31003100

3101+
static bool usesFeatureBuiltinMacros(Decl *decl) {
3102+
return false;
3103+
}
3104+
31013105
static void
31023106
suppressingFeatureNoAsyncAvailability(PrintOptions &options,
31033107
llvm::function_ref<void()> action) {

lib/ASTGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ if (SWIFT_SWIFT_PARSER)
44
Sources/ASTGen/Decls.swift
55
Sources/ASTGen/Exprs.swift
66
Sources/ASTGen/Literals.swift
7+
Sources/ASTGen/Macros.swift
78
Sources/ASTGen/Misc.swift
89
Sources/ASTGen/SourceFile.swift
910
Sources/ASTGen/Stmts.swift

lib/ASTGen/Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ let package = Package(
2525
name: "swiftASTGen",
2626
dependencies: [
2727
.product(name: "SwiftSyntax", package: "swift-syntax"),
28-
.product(name: "SwiftParser", package: "swift-syntax")
28+
.product(name: "SwiftParser", package: "swift-syntax"),
29+
.product(name: "_SwiftSyntaxMacros", package: "swift-syntax")
2930
],
3031
path: ".",
3132
exclude: ["CMakeLists.txt"],
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import SwiftSyntax
2+
@_spi(Testing) import _SwiftSyntaxMacros
3+
4+
extension SyntaxProtocol {
5+
func token(at position: AbsolutePosition) -> TokenSyntax? {
6+
// If the position isn't within this node at all, return early.
7+
guard position >= self.position && position < self.endPosition else {
8+
return nil
9+
}
10+
11+
// If we are a token syntax, that's it!
12+
if let token = Syntax(self).as(TokenSyntax.self) {
13+
return token
14+
}
15+
16+
// Otherwise, it must be one of our children.
17+
return children(viewMode: .sourceAccurate).lazy.compactMap { child in
18+
child.token(at: position)
19+
}.first
20+
}
21+
}
22+
23+
@_cdecl("swift_ASTGen_printMacroResult")
24+
public func printMacroResult(
25+
sourceFilePtr: UnsafeRawPointer,
26+
sourceLocationPtr: UnsafePointer<UInt8>?
27+
) -> Int {
28+
guard let sourceLocationPtr = sourceLocationPtr else {
29+
print("NULL source location")
30+
return -1
31+
}
32+
33+
return sourceFilePtr.withMemoryRebound(
34+
to: ExportedSourceFile.self, capacity: 1
35+
) { (sourceFile: UnsafePointer<ExportedSourceFile>) -> Int in
36+
// Find the offset.
37+
let buffer = sourceFile.pointee.buffer
38+
let offset = sourceLocationPtr - buffer.baseAddress!
39+
if offset < 0 || offset >= buffer.count {
40+
print("source location isn't inside this buffer")
41+
return -1
42+
}
43+
44+
let sf = sourceFile.pointee.syntax
45+
guard let token = sf.token(at: AbsolutePosition(utf8Offset: offset)) else {
46+
print("couldn't find token at offset \(offset)")
47+
return -1
48+
}
49+
50+
guard let parentSyntax = token.parent,
51+
parentSyntax.is(MacroExpansionExprSyntax.self) else {
52+
print("not on a macro expansion node: \(token.recursiveDescription)")
53+
return -1
54+
}
55+
56+
let macroSystem = MacroSystem.exampleSystem
57+
let converter = SourceLocationConverter(
58+
file: sourceFile.pointee.fileName, tree: sf
59+
)
60+
let context = MacroEvaluationContext(
61+
moduleName: sourceFile.pointee.moduleName,
62+
sourceLocationConverter: converter
63+
)
64+
65+
let evaluatedSyntax = parentSyntax.evaluateMacro(
66+
with: macroSystem, context: context
67+
) { error in
68+
/* TODO: Report errors */
69+
}
70+
71+
print("Macro rewrite: \(parentSyntax.withoutTrivia()) --> \(evaluatedSyntax.withoutTrivia())")
72+
73+
return 0
74+
}
75+
}

lib/Parse/ParseDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ extern "C" void swift_ASTGen_buildTopLevelASTNodes(void *sourceFile,
199199
/// \endverbatim
200200
void Parser::parseTopLevel(SmallVectorImpl<Decl *> &decls) {
201201
#ifdef SWIFT_SWIFT_PARSER
202-
if (Context.LangOpts.hasFeature(Feature::ParserASTGen) &&
202+
if ((Context.LangOpts.hasFeature(Feature::BuiltinMacros) ||
203+
Context.LangOpts.hasFeature(Feature::ParserASTGen)) &&
203204
!SourceMgr.hasCodeCompletionBuffer() &&
204205
SF.Kind != SourceFileKind::SIL) {
205206
StringRef contents =

lib/Sema/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ if(SWIFT_FORCE_OPTIMIZED_TYPECHECKER)
7979
target_compile_options(swiftSema PRIVATE -O3)
8080
endif()
8181
endif()
82+
83+
if (SWIFT_SWIFT_PARSER)
84+
target_compile_definitions(swiftSema
85+
PRIVATE
86+
SWIFT_SWIFT_PARSER
87+
)
88+
endif()
89+
8290
target_link_libraries(swiftSema PRIVATE
8391
swiftAST
8492
swiftParse

lib/Sema/CSApply.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "swift/AST/OperatorNameLookup.h"
3434
#include "swift/AST/ParameterList.h"
3535
#include "swift/AST/ProtocolConformance.h"
36+
#include "swift/AST/SourceFile.h"
3637
#include "swift/AST/SubstitutionMap.h"
3738
#include "swift/Basic/Defer.h"
3839
#include "swift/Basic/StringExtras.h"
@@ -53,6 +54,9 @@
5354
using namespace swift;
5455
using namespace constraints;
5556

57+
extern "C" ptrdiff_t swift_ASTGen_printMacroResult(
58+
void *sourceFile, const void *sourceLocation);
59+
5660
bool Solution::hasFixedType(TypeVariableType *typeVar) const {
5761
auto knownBinding = typeBindings.find(typeVar);
5862
return knownBinding != typeBindings.end();
@@ -2969,6 +2973,18 @@ namespace {
29692973
}
29702974

29712975
Expr *visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *expr) {
2976+
#if SWIFT_SWIFT_PARSER
2977+
auto &ctx = cs.getASTContext();
2978+
if (ctx.LangOpts.hasFeature(Feature::BuiltinMacros)) {
2979+
if (auto sf = dc->getParentSourceFile()) {
2980+
if (auto astGenSF = sf->exportedSourceFile) {
2981+
swift_ASTGen_printMacroResult(
2982+
astGenSF, expr->getStartLoc().getOpaquePointerValue());
2983+
}
2984+
}
2985+
}
2986+
#endif
2987+
29722988
switch (expr->getKind()) {
29732989
#define MAGIC_STRING_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
29742990
case MagicIdentifierLiteralExpr::NAME: \

test/Macros/builtin_macros.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinMacros -typecheck %s -module-name MacrosTest 2>&1 | %FileCheck %s
2+
// REQUIRES: OS=macosx
3+
4+
// CHECK: #function --> "MacrosTest"
5+
print(#function)
6+
7+
func f(a: Int, b: Int) {
8+
print(#function, #line, #column)
9+
// CHECK-NEXT: #function --> "f(a:b:)"
10+
// CHECK-NEXT: #line --> 8
11+
// CHECK-NEXT: #column --> 27
12+
}

0 commit comments

Comments
 (0)