diff --git a/include/swift/AST/CASTBridging.h b/include/swift/AST/CASTBridging.h new file mode 100644 index 0000000000000..f68abb0a036cb --- /dev/null +++ b/include/swift/AST/CASTBridging.h @@ -0,0 +1,144 @@ +//===--- ASTBridging.h - header for the swift SILBridging module ----------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2022 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_C_AST_ASTBRIDGING_H +#define SWIFT_C_AST_ASTBRIDGING_H + +#include + +#if __clang__ +// Provide macros to temporarily suppress warning about the use of +// _Nullable and _Nonnull. +#define SWIFT_BEGIN_NULLABILITY_ANNOTATIONS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wnullability-extension\"") \ + _Pragma("clang assume_nonnull begin") + +#define SWIFT_END_NULLABILITY_ANNOTATIONS \ + _Pragma("clang diagnostic pop") _Pragma("clang assume_nonnull end") +#else +#define SWIFT_BEGIN_NULLABILITY_ANNOTATIONS +#define SWIFT_END_NULLABILITY_ANNOTATIONS +#define _Nullable +#endif + +SWIFT_BEGIN_NULLABILITY_ANNOTATIONS + +typedef long SwiftInt; +typedef unsigned long SwiftUInt; + +typedef struct { + const void *_Nullable data; + long numElements; +} BridgedArrayRef; + +typedef struct { + void *start; + SwiftInt byteLength; +} BridgedCharSourceRange; + +typedef void *BridgedIdentifier; + +#ifdef __cplusplus +extern "C" { + +#define _Bool bool + +#endif + +BridgedIdentifier +SwiftASTContext_getIdentifier( + void *ctx, const uint8_t * _Nullable str, long len); + +void *SwiftImportDecl_create(void *, void *, void *, char, void *, + BridgedArrayRef, BridgedArrayRef); + +void *SwiftTopLevelCodeDecl_createStmt(void *ctx, void *DC, void *startLoc, + void *element, void *endLoc); +void *SwiftTopLevelCodeDecl_createExpr(void *ctx, void *DC, void *startLoc, + void *element, void *endLoc); + +void *SwiftSequenceExpr_create(void *ctx, BridgedArrayRef exprs); + +void *SwiftTupleExpr_create(void *ctx, void *lparen, BridgedArrayRef subs, + void *rparen); + +void *SwiftFunctionCallExpr_create(void *ctx, void *fn, void *args); + +void *SwiftIdentifierExpr_create(void *ctx, BridgedIdentifier base, void *loc); + +void *SwiftStringLiteralExpr_create(void *ctx, const uint8_t * _Nullable string, + long len, void *TokenLoc); + +void *SwiftIntegerLiteralExpr_create(void *ctx, const uint8_t * _Nullable string, + long len, void *TokenLoc); + +void *SwiftBooleanLiteralExpr_create(void *ctx, _Bool value, void *TokenLoc); + +void *SwiftVarDecl_create(void *ctx, BridgedIdentifier _Nullable name, + void *loc, _Bool isStatic, _Bool isLet, void *dc); + +void *IfStmt_create(void *ctx, void *ifLoc, void *cond, void *_Nullable then, void *_Nullable elseLoc, + void *_Nullable elseStmt); + +void *BraceStmt_createExpr(void *ctx, void *lbloc, BridgedArrayRef elements, void *rbloc); +void *BraceStmt_createStmt(void *ctx, void *lbloc, BridgedArrayRef elements, void *rbloc); + +void *BridgedSourceLoc_advanced(void *loc, long len); + +void *ParamDecl_create(void *ctx, void *loc, + void *_Nullable argLoc, void *_Nullable argName, + void *_Nullable paramLoc, void *_Nullable paramName, + void *declContext); + +void *FuncDecl_create(void *ctx, void *staticLoc, _Bool isStatic, void *funcLoc, + BridgedIdentifier name, void *nameLoc, + _Bool isAsync, void *_Nullable asyncLoc, + _Bool throws, void *_Nullable throwsLoc, + void *paramLLoc, BridgedArrayRef params, void *paramRLoc, + void *_Nullable body, void *_Nullable returnType, + void *declContext); + +void *SimpleIdentTypeRepr_create(void *ctx, void *loc, BridgedIdentifier id); + +void *UnresolvedDotExpr_create(void *ctx, void *base, void *dotLoc, BridgedIdentifier name, void *nameLoc); + +void *ClosureExpr_create(void *ctx, void *body, void *dc); + +void NominalTypeDecl_setMembers(void *decl, BridgedArrayRef members); + +struct DeclContextAndDecl { + void *declContext; + void *nominalDecl; + void *decl; +}; + +struct DeclContextAndDecl StructDecl_create( + void *ctx, void *loc, BridgedIdentifier name, void *nameLoc, void *dc); +struct DeclContextAndDecl ClassDecl_create( + void *ctx, void *loc, BridgedIdentifier name, void *nameLoc, void *dc); + +void TopLevelCodeDecl_dump(void *); +void Expr_dump(void *); +void Decl_dump(void *); +void Stmt_dump(void *); + +#ifdef __cplusplus +} +#endif + +SWIFT_END_NULLABILITY_ANNOTATIONS + +#undef SWIFT_BEGIN_NULLABILITY_ANNOTATIONS +#undef SWIFT_END_NULLABILITY_ANNOTATIONS + +#endif // SWIFT_C_AST_ASTBRIDGING_H diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 37d03256a8e49..7412e1d449d36 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -141,6 +141,10 @@ EXPERIMENTAL_FEATURE(ParserSequenceFolding) /// Enables implicit some while also enabling existential `any` EXPERIMENTAL_FEATURE(ImplicitSome) +/// Parse using the Swift (swift-syntax) parser and use ASTGen to generate the +/// corresponding syntax tree. +EXPERIMENTAL_FEATURE(ParserASTGen) + #undef EXPERIMENTAL_FEATURE #undef UPCOMING_FEATURE #undef SUPPRESSIBLE_LANGUAGE_FEATURE diff --git a/include/swift/module.modulemap b/include/swift/module.modulemap index 4cfbbba040e12..fe8f02bad716f 100644 --- a/include/swift/module.modulemap +++ b/include/swift/module.modulemap @@ -15,6 +15,10 @@ module ASTBridging { export * } +module CASTBridging { + header "AST/CASTBridging.h" +} + module SILBridging { header "SIL/SILBridging.h" header "SIL/SILLocation.h" diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index b18a5979d468b..6543f1d8e3dc2 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3091,6 +3091,10 @@ static bool usesFeatureAdditiveArithmeticDerivedConformances(Decl *decl) { return false; } +static bool usesFeatureParserASTGen(Decl *decl) { + return false; +} + static void suppressingFeatureNoAsyncAvailability(PrintOptions &options, llvm::function_ref action) { diff --git a/lib/AST/CASTBridging.cpp b/lib/AST/CASTBridging.cpp new file mode 100644 index 0000000000000..795219708c62a --- /dev/null +++ b/lib/AST/CASTBridging.cpp @@ -0,0 +1,288 @@ +#include "swift/AST/CASTBridging.h" + +#include "swift/AST/ASTContext.h" +#include "swift/AST/ASTNode.h" +#include "swift/AST/Decl.h" +#include "swift/AST/Expr.h" +#include "swift/AST/Stmt.h" +#include "swift/AST/Identifier.h" +#include "swift/AST/ParameterList.h" +#include "swift/AST/TypeRepr.h" + +using namespace swift; + +template +inline llvm::ArrayRef getArrayRef(BridgedArrayRef bridged) { + return {static_cast(bridged.data), size_t(bridged.numElements)}; +} + +static SourceLoc getSourceLocFromPointer(void *loc) { + auto smLoc = llvm::SMLoc::getFromPointer((const char *)loc); + return SourceLoc(smLoc); +} + +BridgedIdentifier +SwiftASTContext_getIdentifier(void *ctx, const uint8_t *_Nullable str, long len) { + return const_cast( + static_cast(ctx) + ->getIdentifier( + StringRef{reinterpret_cast(str), size_t(len)}) + .getAsOpaquePointer()); +} + +void *SwiftImportDecl_create(void *ctx, void *dc, void *importLoc, char kind, + void *kindLoc, BridgedArrayRef path, + BridgedArrayRef pathLocs) { + assert(path.numElements == pathLocs.numElements); + ASTContext &Context = *static_cast(ctx); + ImportPath::Builder importPath; + for (auto p : llvm::zip(getArrayRef(path), + getArrayRef(pathLocs))) { + Identifier ident; + SourceLoc loc; + std::tie(ident, loc) = p; + importPath.push_back(ident, loc); + } + return ImportDecl::create( + Context, static_cast(dc), + getSourceLocFromPointer(importLoc), + static_cast(kind), getSourceLocFromPointer(kindLoc), + std::move(importPath).get()); +} + +void *BridgedSourceLoc_advanced(void *loc, long len) { + SourceLoc l = getSourceLocFromPointer(loc).getAdvancedLoc(len); + return const_cast(l.getOpaquePointerValue()); +} + +void *SwiftTopLevelCodeDecl_createStmt(void *ctx, void *DC, void *startLoc, + void *element, void *endLoc) { + ASTContext &Context = *static_cast(ctx); + auto *S = static_cast(element); + auto Brace = + BraceStmt::create(Context, getSourceLocFromPointer(startLoc), + {S}, getSourceLocFromPointer(endLoc), + /*Implicit=*/true); + auto *TLCD = + new (Context) TopLevelCodeDecl(static_cast(DC), Brace); + return (Decl *)TLCD; +} + +void *SwiftTopLevelCodeDecl_createExpr(void *ctx, void *DC, void *startLoc, + void *element, void *endLoc) { + ASTContext &Context = *static_cast(ctx); + auto *E = static_cast(element); + auto Brace = + BraceStmt::create(Context, getSourceLocFromPointer(startLoc), + {E}, getSourceLocFromPointer(endLoc), + /*Implicit=*/true); + auto *TLCD = + new (Context) TopLevelCodeDecl(static_cast(DC), Brace); + return (Decl *)TLCD; +} + +void *SwiftSequenceExpr_create(void *ctx, BridgedArrayRef exprs) { + return SequenceExpr::create(*static_cast(ctx), + getArrayRef(exprs)); +} + +void *SwiftTupleExpr_create(void *ctx, void *lparen, BridgedArrayRef subs, + void *rparen) { + return TupleExpr::create( + *static_cast(ctx), getSourceLocFromPointer(lparen), + getArrayRef(subs), {}, {}, getSourceLocFromPointer(rparen), + /*Implicit*/ false); +} + +void *SwiftFunctionCallExpr_create(void *ctx, void *fn, void *args) { + ASTContext &Context = *static_cast(ctx); + TupleExpr *TE = static_cast(args); + SmallVector arguments; + for (unsigned i = 0; i < TE->getNumElements(); ++i) { + arguments.emplace_back(TE->getElementNameLoc(i), TE->getElementName(i), + TE->getElement(i)); + } + auto *argList = ArgumentList::create(Context, TE->getLParenLoc(), arguments, + TE->getRParenLoc(), None, + /*isImplicit*/ false); + return CallExpr::create(Context, static_cast(fn), argList, + /*implicit*/ false); +} + +void *SwiftIdentifierExpr_create(void *ctx, BridgedIdentifier base, void *loc) { + ASTContext &Context = *static_cast(ctx); + auto name = DeclNameRef{ + swift::Identifier::getFromOpaquePointer(base)}; + Expr *E = new (Context) UnresolvedDeclRefExpr( + name, DeclRefKind::Ordinary, DeclNameLoc{getSourceLocFromPointer(loc)}); + return E; +} + +void *SwiftStringLiteralExpr_create( + void *ctx, const uint8_t *_Nullable string, + long len, void *TokenLoc) { + ASTContext &Context = *static_cast(ctx); + return new (Context) StringLiteralExpr( + StringRef{reinterpret_cast(string), size_t(len)}, + getSourceLocFromPointer(TokenLoc)); +} + +void *SwiftIntegerLiteralExpr_create( + void *ctx, const uint8_t *_Nullable string, long len, void *TokenLoc) { + ASTContext &Context = *static_cast(ctx); + return new (Context) IntegerLiteralExpr( + StringRef{reinterpret_cast(string), size_t(len)}, + getSourceLocFromPointer(TokenLoc)); +} + +void *SwiftBooleanLiteralExpr_create(void *ctx, bool value, void *TokenLoc) { + ASTContext &Context = *static_cast(ctx); + return new (Context) BooleanLiteralExpr( + value, getSourceLocFromPointer(TokenLoc)); +} + +void *SwiftVarDecl_create(void *ctx, BridgedIdentifier _Nullable nameId, + void *loc, bool isStatic, bool isLet, void *dc) { + ASTContext &Context = *static_cast(ctx); + return new (Context) VarDecl(isStatic, + isLet ? VarDecl::Introducer::Let : VarDecl::Introducer::Var, + getSourceLocFromPointer(loc), + Identifier::getFromOpaquePointer(nameId), + reinterpret_cast(dc)); +} + +void *IfStmt_create(void *ctx, void *ifLoc, void *cond, void *_Nullable then, void *_Nullable elseLoc, + void *_Nullable elseStmt) { + ASTContext &Context = *static_cast(ctx); + return new (Context) IfStmt( + getSourceLocFromPointer(ifLoc), (Expr *)cond, (Stmt *)then, + getSourceLocFromPointer(elseLoc), (Stmt *)elseStmt, None, Context); +} + +void *BraceStmt_createExpr(void *ctx, void *lbloc, BridgedArrayRef elements, void *rbloc) { + ASTContext &Context = *static_cast(ctx); + return BraceStmt::create(Context, getSourceLocFromPointer(lbloc), + getArrayRef(elements), + getSourceLocFromPointer(rbloc)); +} + +void *BraceStmt_createStmt(void *ctx, void *lbloc, BridgedArrayRef elements, void *rbloc) { + llvm::SmallVector nodes; + for (auto stmt : getArrayRef(elements)) { + nodes.push_back(stmt); + } + + ASTContext &Context = *static_cast(ctx); + return BraceStmt::create(Context, getSourceLocFromPointer(lbloc), + Context.AllocateCopy(nodes), + getSourceLocFromPointer(rbloc)); +} + +void *ParamDecl_create( + void *ctx, void *loc, + void *_Nullable argLoc, BridgedIdentifier _Nullable argName, + void *_Nullable paramLoc, BridgedIdentifier _Nullable paramName, + void *declContext) { + ASTContext &Context = *static_cast(ctx); + return new (Context) ParamDecl(getSourceLocFromPointer(loc), + getSourceLocFromPointer(argLoc), + Identifier::getFromOpaquePointer(argName), + getSourceLocFromPointer(paramLoc), + Identifier::getFromOpaquePointer(paramName), + (DeclContext *)declContext); +} + +void *FuncDecl_create(void *ctx, void *staticLoc, bool isStatic, void *funcLoc, + BridgedIdentifier name, void *nameLoc, + bool isAsync, void *_Nullable asyncLoc, + bool throws, void *_Nullable throwsLoc, + void *paramLLoc, BridgedArrayRef params, void *paramRLoc, + void *_Nullable body, void *_Nullable returnType, + void *declContext) { + auto *paramList = ParameterList::create( + *static_cast(ctx), getSourceLocFromPointer(paramLLoc), + getArrayRef(params), getSourceLocFromPointer(paramRLoc)); + auto declName = + DeclName(*static_cast(ctx), + Identifier::getFromOpaquePointer(name), paramList); + auto *out = FuncDecl::create( + *static_cast(ctx), getSourceLocFromPointer(staticLoc), + isStatic ? StaticSpellingKind::KeywordStatic : StaticSpellingKind::None, + getSourceLocFromPointer(funcLoc), declName, + getSourceLocFromPointer(nameLoc), isAsync, + getSourceLocFromPointer(asyncLoc), throws, + getSourceLocFromPointer(throwsLoc), nullptr, + paramList, (TypeRepr *)returnType, (DeclContext *)declContext); + out->setBody((BraceStmt *)body, FuncDecl::BodyKind::Parsed); + + return static_cast(out); +} + +void *SimpleIdentTypeRepr_create(void *ctx, void *loc, BridgedIdentifier id) { + ASTContext &Context = *static_cast(ctx); + return new (Context) SimpleIdentTypeRepr( + DeclNameLoc(getSourceLocFromPointer(loc)), + DeclNameRef(Identifier::getFromOpaquePointer(id))); +} + +void *UnresolvedDotExpr_create( + void *ctx, void *base, void *dotLoc, BridgedIdentifier name, + void *nameLoc) { + ASTContext &Context = *static_cast(ctx); + return new (Context) UnresolvedDotExpr( + (Expr *)base, getSourceLocFromPointer(dotLoc), + DeclNameRef(Identifier::getFromOpaquePointer(name)), + DeclNameLoc(getSourceLocFromPointer(nameLoc)), false); +} + +void *ClosureExpr_create(void *ctx, void *body, void *dc) { + DeclAttributes attributes; + SourceRange bracketRange; + SourceLoc asyncLoc; + SourceLoc throwsLoc; + SourceLoc arrowLoc; + SourceLoc inLoc; + + ASTContext &Context = *static_cast(ctx); + auto *out = new (Context) ClosureExpr(attributes, bracketRange, nullptr, + nullptr, asyncLoc, throwsLoc, arrowLoc, + inLoc, nullptr, 0, (DeclContext *)dc); + out->setBody((BraceStmt *)body, true); + return (Expr *)out; +} + +void NominalTypeDecl_setMembers(void *decl, BridgedArrayRef members) { + auto declMembers = getArrayRef(members); + for (auto m : declMembers) + ((NominalTypeDecl *)decl)->addMember(m); +} + +DeclContextAndDecl StructDecl_create( + void *ctx, void *loc, BridgedIdentifier name, void *nameLoc, void *dc) { + ASTContext &Context = *static_cast(ctx); + auto *out = new (Context) StructDecl(getSourceLocFromPointer(loc), + Identifier::getFromOpaquePointer(name), + getSourceLocFromPointer(nameLoc), + {}, nullptr, + (DeclContext *)dc); + out->setImplicit(); // TODO: remove this. + return {(DeclContext *)out, (NominalTypeDecl *)out, (Decl *)out}; +} + +DeclContextAndDecl ClassDecl_create( + void *ctx, void *loc, BridgedIdentifier name, void *nameLoc, void *dc) { + ASTContext &Context = *static_cast(ctx); + auto *out = new (Context) ClassDecl(getSourceLocFromPointer(loc), + Identifier::getFromOpaquePointer(name), + getSourceLocFromPointer(nameLoc), + {}, nullptr, + (DeclContext *)dc, false); + out->setImplicit(); // TODO: remove this. + return {(DeclContext *)out, (NominalTypeDecl *)out, (Decl *)out}; +} + +void TopLevelCodeDecl_dump(void *decl) { ((TopLevelCodeDecl *)decl)->dump(llvm::errs()); } + +void Expr_dump(void *expr) { ((Expr *)expr)->dump(llvm::errs()); } +void Decl_dump(void *expr) { ((Decl *)expr)->dump(llvm::errs()); } +void Stmt_dump(void *expr) { ((Stmt *)expr)->dump(llvm::errs()); } diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index c33727a5ddb51..aaf1fe9579c8e 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -33,6 +33,7 @@ add_swift_host_library(swiftAST STATIC Availability.cpp AvailabilitySpec.cpp Builtins.cpp + CASTBridging.cpp CaptureInfo.cpp ClangSwiftTypeCorrespondence.cpp ClangTypeConverter.cpp diff --git a/lib/ASTGen/CMakeLists.txt b/lib/ASTGen/CMakeLists.txt new file mode 100644 index 0000000000000..9435aef15904e --- /dev/null +++ b/lib/ASTGen/CMakeLists.txt @@ -0,0 +1,53 @@ +if (SWIFT_SWIFT_PARSER) + add_library(swiftASTGen STATIC + Sources/ASTGen/ASTGen.swift + Sources/ASTGen/Decls.swift + Sources/ASTGen/Exprs.swift + Sources/ASTGen/Literals.swift + Sources/ASTGen/Misc.swift + Sources/ASTGen/Stmts.swift + ) + + # Set the appropriate target triple. + if(SWIFT_HOST_VARIANT_SDK IN_LIST SWIFT_DARWIN_PLATFORMS) + set(DEPLOYMENT_VERSION "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_DEPLOYMENT_VERSION}") + endif() + + if(SWIFT_HOST_VARIANT_SDK STREQUAL ANDROID) + set(DEPLOYMENT_VERSION ${SWIFT_ANDROID_API_LEVEL}) + endif() + + get_target_triple(target target_variant "${SWIFT_HOST_VARIANT_SDK}" "${SWIFT_HOST_VARIANT_ARCH}" + MACCATALYST_BUILD_FLAVOR "" + DEPLOYMENT_VERSION "${DEPLOYMENT_VERSION}") + + target_compile_options(swiftASTGen PRIVATE $<$:-target;${target}>) + + # Link against the SwiftSyntax parser and libraries it depends on. The actual + # formulation of this is a hack to work around a CMake bug in Ninja file + # generation that results in multiple Ninja targets producing the same file in + # a downstream SourceKit target. This should be expressed as: + # + # target_link_libraries(swiftASTGen + # PRIVATE + # SwiftSyntax::SwiftCompilerSupport + # ) + target_link_libraries(swiftASTGen + PRIVATE + $ + $ + $ + $ + $ + $ + + swiftAST + ) + + target_include_directories(swiftASTGen PUBLIC + "${SWIFT_PATH_TO_EARLYSWIFTSYNTAX_BUILD_DIR}/swift") + + add_dependencies(swiftASTGen swiftAST) + + set_property(GLOBAL APPEND PROPERTY SWIFT_EXPORTS swiftASTGen) +endif() diff --git a/lib/ASTGen/Package.swift b/lib/ASTGen/Package.swift new file mode 100644 index 0000000000000..db5a32a074a54 --- /dev/null +++ b/lib/ASTGen/Package.swift @@ -0,0 +1,39 @@ +// swift-tools-version: 5.6 + +// The CMake build system is the only one that's able to produce a working +// compiler. This Package.swift makes it easier to build and work with the +// swiftASTGen library within IDEs, but it's mainly there for editing---it +// won't create something that can be meaningfully executed. Most things with +// the new Swift parser are better implemented/tested within or on top of the +// swift-syntax package. + +import PackageDescription + +let package = Package( + name: "ASTGen", + platforms: [ + .macOS(.v10_15) + ], + products: [ + .library(name: "swiftASTGen", targets: ["swiftASTGen"]), + ], + dependencies: [ + .package(path: "../../../swift-syntax"), + ], + targets: [ + .target( + name: "swiftASTGen", + dependencies: [ + .product(name: "SwiftSyntax", package: "swift-syntax"), + .product(name: "SwiftParser", package: "swift-syntax") + ], + path: ".", + exclude: ["CMakeLists.txt"], + swiftSettings: [ + .unsafeFlags([ + "-I", "../../include/swift/", + "-I", "../../include" + ]) + ]), + ] +) diff --git a/lib/ASTGen/Sources/ASTGen/ASTGen.swift b/lib/ASTGen/Sources/ASTGen/ASTGen.swift new file mode 100644 index 0000000000000..c5d4e7e7f4768 --- /dev/null +++ b/lib/ASTGen/Sources/ASTGen/ASTGen.swift @@ -0,0 +1,82 @@ +import SwiftParser +import SwiftSyntax + +import CASTBridging + +extension Array { + public func withBridgedArrayRef(_ c: (BridgedArrayRef) -> T) -> T { + withUnsafeBytes { buf in + c(BridgedArrayRef(data: buf.baseAddress!, numElements: count)) + } + } +} + +extension UnsafePointer { + public var raw: UnsafeMutableRawPointer { + UnsafeMutableRawPointer(mutating: self) + } +} + +/// Little utility wrapper that lets us +@propertyWrapper +class Boxed { + var wrappedValue: Value + + init(wrappedValue: Value) { + self.wrappedValue = wrappedValue + } +} + +struct ASTGenVisitor: SyntaxTransformVisitor { + let ctx: UnsafeMutableRawPointer + let base: UnsafePointer + + @Boxed var declContext: UnsafeMutableRawPointer + + // TODO: this some how messes up the witness table when I uncomment it locally :/ +// public func visit(_ node: T?) -> [UnsafeMutableRawPointer]? { +// if let node = node { return visit(node) } +// return nil +// } + + @_disfavoredOverload + public func visit(_ node: SourceFileSyntax) -> UnsafeMutableRawPointer { + fatalError("Use other overload.") + } + + public func visitAny(_ node: Syntax) -> UnsafeMutableRawPointer { + fatalError("Not implemented.") + } + + public func visit(_ node: SourceFileSyntax) -> [UnsafeMutableRawPointer] { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + var out = [UnsafeMutableRawPointer]() + + for element in node.statements { + let swiftASTNodes = visit(element) + if element.item.is(StmtSyntax.self) { + out.append(SwiftTopLevelCodeDecl_createStmt(ctx, declContext, loc, swiftASTNodes, loc)) + } else if element.item.is(ExprSyntax.self) { + out.append(SwiftTopLevelCodeDecl_createExpr(ctx, declContext, loc, swiftASTNodes, loc)) + } else { + assert(element.item.is(DeclSyntax.self)) + out.append(swiftASTNodes) + } + } + + return out + } +} + +@_cdecl("parseTopLevelSwift") +public func parseTopLevelSwift( + buffer: UnsafePointer, dc: UnsafeMutableRawPointer, + ctx: UnsafeMutableRawPointer, + outputContext: UnsafeMutableRawPointer, + callback: @convention(c) (UnsafeMutableRawPointer, UnsafeMutableRawPointer) -> Void +) { + let syntax = try! Parser.parse(source: String(cString: buffer)) + ASTGenVisitor(ctx: ctx, base: buffer, declContext: dc) + .visit(syntax) + .forEach { callback($0, outputContext) } +} diff --git a/lib/ASTGen/Sources/ASTGen/Decls.swift b/lib/ASTGen/Sources/ASTGen/Decls.swift new file mode 100644 index 0000000000000..682e82df8758b --- /dev/null +++ b/lib/ASTGen/Sources/ASTGen/Decls.swift @@ -0,0 +1,120 @@ +import SwiftParser +import SwiftSyntax + +import CASTBridging + +extension ASTGenVisitor { + public func visit(_ node: StructDeclSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + var nameText = node.identifier.text + let name = nameText.withUTF8 { buf in + return SwiftASTContext_getIdentifier(ctx, buf.baseAddress, buf.count) + } + + let out = StructDecl_create(ctx, loc, name, loc, declContext) + let oldDeclContext = declContext + declContext = out.declContext + defer { declContext = oldDeclContext } + + node.members.members.map(self.visit).withBridgedArrayRef { ref in + NominalTypeDecl_setMembers(out.nominalDecl, ref) + } + + return out.decl + } + + public func visit(_ node: ClassDeclSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + var nameText = node.identifier.text + let name = nameText.withUTF8 { buf in + return SwiftASTContext_getIdentifier(ctx, buf.baseAddress, buf.count) + } + + let out = ClassDecl_create(ctx, loc, name, loc, declContext) + let oldDeclContext = declContext + declContext = out.declContext + defer { declContext = oldDeclContext } + + node.members.members.map(self.visit).withBridgedArrayRef { ref in + NominalTypeDecl_setMembers(out.nominalDecl, ref) + } + + return out.decl + } + + public func visit(_ node: VariableDeclSyntax) -> UnsafeMutableRawPointer { + let pattern = visit(node.bindings.first!.pattern) + let initializer = visit(node.bindings.first!.initializer!) + + let loc = self.base.advanced(by: node.position.utf8Offset).raw + let isStateic = false // TODO: compute this + let isLet = node.letOrVarKeyword.tokenKind == .letKeyword + + // TODO: don't drop "initializer" on the floor. + return SwiftVarDecl_create(ctx, nil, loc, isStateic, isLet, declContext) + } + + public func visit(_ node: CodeBlockSyntax) -> UnsafeMutableRawPointer { + let statements = node.statements.map(self.visit) + let loc = self.base.advanced(by: node.position.utf8Offset).raw + + return statements.withBridgedArrayRef { ref in + BraceStmt_createStmt(ctx, loc, ref, loc) + } + } + + public func visit(_ node: FunctionParameterSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + + let firstName: UnsafeMutableRawPointer? + let secondName: UnsafeMutableRawPointer? + + if let nodeFirstName = node.firstName { + var text = nodeFirstName.text + firstName = text.withUTF8 { buf in + SwiftASTContext_getIdentifier(ctx, buf.baseAddress, buf.count) + } + } else { + firstName = nil + } + + if let nodeSecondName = node.secondName { + var text = nodeSecondName.text + secondName = text.withUTF8 { buf in + SwiftASTContext_getIdentifier(ctx, buf.baseAddress, buf.count) + } + } else { + secondName = nil + } + + return ParamDecl_create(ctx, loc, loc, firstName, loc, secondName, declContext) + } + + public func visit(_ node: FunctionDeclSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + + var nameText = node.identifier.text + let name = nameText.withUTF8 { buf in + return SwiftASTContext_getIdentifier(ctx, buf.baseAddress, buf.count) + } + + let body: UnsafeMutableRawPointer? + if let nodeBody = node.body { + body = visit(nodeBody) + } else { + body = nil + } + + let returnType: UnsafeMutableRawPointer? + if let output = node.signature.output { + returnType = visit(output.returnType) + } else { + returnType = nil + } + + let params = node.signature.input.parameterList.map { visit($0) } + return params.withBridgedArrayRef { ref in + FuncDecl_create(ctx, loc, false, loc, name, loc, false, nil, false, nil, loc, ref, loc, body, returnType, declContext) + } + } +} diff --git a/lib/ASTGen/Sources/ASTGen/Exprs.swift b/lib/ASTGen/Sources/ASTGen/Exprs.swift new file mode 100644 index 0000000000000..7f8bf94689e2e --- /dev/null +++ b/lib/ASTGen/Sources/ASTGen/Exprs.swift @@ -0,0 +1,88 @@ +import SwiftParser +import SwiftSyntax + +import CASTBridging + +extension ASTGenVisitor { + public func visit(_ node: ClosureExprSyntax) -> UnsafeMutableRawPointer { + let statements = node.statements.map(self.visit) + let loc = self.base.advanced(by: node.position.utf8Offset).raw + + let body = statements.withBridgedArrayRef { ref in + BraceStmt_createExpr(ctx, loc, ref, loc) + } + + return ClosureExpr_create(ctx, body, declContext) + } + + public func visit(_ node: FunctionCallExprSyntax) -> UnsafeMutableRawPointer { + // Transform the trailing closure into an argument. + if let trailingClosure = node.trailingClosure { + let tupleElement = TupleExprElementSyntax(label: nil, colon: nil, expression: ExprSyntax(trailingClosure), trailingComma: nil) + + return visit(node.addArgument(tupleElement).withTrailingClosure(nil)) + } + + let args = visit(node.argumentList) + // TODO: hack + let callee = visit(node.calledExpression) + + return SwiftFunctionCallExpr_create(self.ctx, callee, args) + } + + public func visit(_ node: IdentifierExprSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + + var text = node.identifier.text + let id = text.withUTF8 { buf in + return SwiftASTContext_getIdentifier(ctx, buf.baseAddress, buf.count) + } + + return SwiftIdentifierExpr_create(ctx, id, loc) + } + + public func visit(_ node: SimpleTypeIdentifierSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + + var text = node.name.text + let id = text.withUTF8 { buf in + return SwiftASTContext_getIdentifier(ctx, buf.baseAddress, buf.count) + } + + return SimpleIdentTypeRepr_create(ctx, loc, id) + } + + public func visit(_ node: IdentifierPatternSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + + var text = node.identifier.text + let id = text.withUTF8 { buf in + return SwiftASTContext_getIdentifier(ctx, buf.baseAddress, buf.count) + } + + return SwiftIdentifierExpr_create(ctx, id, loc) + } + + public func visit(_ node: MemberAccessExprSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + let base = visit(node.base!) + var nameText = node.name.text + let name = nameText.withUTF8 { buf in + return SwiftASTContext_getIdentifier(ctx, buf.baseAddress, buf.count) + } + + return UnresolvedDotExpr_create(ctx, base, loc, name, loc) + } + + public func visit(_ node: TupleExprElementListSyntax) -> UnsafeMutableRawPointer { + let elements = node.map(self.visit) + + // TODO: find correct paren locs. + let lParenLoc = self.base.advanced(by: node.position.utf8Offset).raw + let rParenLoc = self.base.advanced(by: node.position.utf8Offset).raw + + return elements.withBridgedArrayRef { elementsRef in + SwiftTupleExpr_create(self.ctx, lParenLoc, elementsRef, rParenLoc) + } + } +} diff --git a/lib/ASTGen/Sources/ASTGen/Literals.swift b/lib/ASTGen/Sources/ASTGen/Literals.swift new file mode 100644 index 0000000000000..f52285f2f406e --- /dev/null +++ b/lib/ASTGen/Sources/ASTGen/Literals.swift @@ -0,0 +1,28 @@ +import SwiftParser +import SwiftSyntax + +import CASTBridging + +extension ASTGenVisitor { + public func visit(_ node: StringLiteralExprSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + var segment = node.segments.first!.as(StringSegmentSyntax.self)!.content.text + return segment.withUTF8 { buf in + return SwiftStringLiteralExpr_create(ctx, buf.baseAddress, buf.count, loc) + } + } + + public func visit(_ node: IntegerLiteralExprSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + var segment = node.digits.text + return segment.withUTF8 { buf in + return SwiftIntegerLiteralExpr_create(ctx, buf.baseAddress, buf.count, loc) + } + } + + public func visit(_ node: BooleanLiteralExprSyntax) -> UnsafeMutableRawPointer { + let loc = self.base.advanced(by: node.position.utf8Offset).raw + let value = node.booleanLiteral == .trueKeyword() + return SwiftBooleanLiteralExpr_create(ctx, value, loc) + } +} diff --git a/lib/ASTGen/Sources/ASTGen/Misc.swift b/lib/ASTGen/Sources/ASTGen/Misc.swift new file mode 100644 index 0000000000000..a2d3bf18f82e9 --- /dev/null +++ b/lib/ASTGen/Sources/ASTGen/Misc.swift @@ -0,0 +1,26 @@ +import SwiftParser +import SwiftSyntax + +import CASTBridging + +extension ASTGenVisitor { + public func visit(_ node: MemberDeclListItemSyntax) -> UnsafeMutableRawPointer { + visit(Syntax(node.decl)) + } + + public func visit(_ node: TupleExprElementSyntax) -> UnsafeMutableRawPointer { + visit(node.expression) + } + + public func visit(_ node: InitializerClauseSyntax) -> UnsafeMutableRawPointer { + visit(node.value) + } + + public func visit(_ node: ConditionElementSyntax) -> UnsafeMutableRawPointer { + visit(node.condition) + } + + public func visit(_ node: CodeBlockItemSyntax) -> UnsafeMutableRawPointer { + visit(node.item) + } +} diff --git a/lib/ASTGen/Sources/ASTGen/Stmts.swift b/lib/ASTGen/Sources/ASTGen/Stmts.swift new file mode 100644 index 0000000000000..45ff17a09db65 --- /dev/null +++ b/lib/ASTGen/Sources/ASTGen/Stmts.swift @@ -0,0 +1,20 @@ +import SwiftParser +import SwiftSyntax + +import CASTBridging + +extension ASTGenVisitor { + public func visit(_ node: IfStmtSyntax) -> UnsafeMutableRawPointer { + let conditions = node.conditions.map(self.visit) + assert(conditions.count == 1) // TODO: handle multiple conditions. + + let body = visit(node.body) + let loc = self.base.advanced(by: node.position.utf8Offset).raw + + if let elseBody = node.elseBody, node.elseKeyword != nil { + return IfStmt_create(ctx, loc, conditions.first!, body, loc, visit(elseBody)) + } + + return IfStmt_create(ctx, loc, conditions.first!, body, nil, nil) + } +} diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 1beafbc44e1bc..3b508b4662d8d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -19,6 +19,7 @@ list(APPEND LLVM_COMMON_DEPENDS swift-parse-syntax-generated-headers) add_subdirectory(APIDigester) add_subdirectory(AST) +add_subdirectory(ASTGen) add_subdirectory(ASTSectionImporter) add_subdirectory(Basic) add_subdirectory(ConstExtract) diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index 18ec5e125f30d..728c15c90b6d3 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -45,6 +45,7 @@ if (SWIFT_SWIFT_PARSER) # target_link_libraries(swiftParse # PRIVATE # SwiftSyntax::SwiftCompilerSupport + # ... # ) target_link_libraries(swiftParse PRIVATE @@ -54,6 +55,7 @@ if (SWIFT_SWIFT_PARSER) $ $ $ + $ ) target_include_directories(swiftParse diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 367222c089168..bc79658b640f6 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -160,6 +160,19 @@ namespace { }; } // end anonymous namespace +extern "C" void parseTopLevelSwift(const char *buffer, + void *declContext, + void *astContext, + void *outputContext, + void (*)(void *, void *)); + +static void appendToVector(void *declPtr, void *vecPtr) { + auto vec = static_cast *>(vecPtr); + auto decl = static_cast(declPtr); + + vec->push_back(decl); +} + /// Main entrypoint for the parser. /// /// \verbatim @@ -169,6 +182,23 @@ namespace { /// decl-sil-stage [[only in SIL mode] /// \endverbatim void Parser::parseTopLevel(SmallVectorImpl &decls) { + StringRef contents = + SourceMgr.extractText(SourceMgr.getRangeForBuffer(L->getBufferID())); + +#ifdef SWIFT_SWIFT_PARSER + if (Context.LangOpts.hasFeature(Feature::ParserASTGen) && + !SourceMgr.hasCodeCompletionBuffer() && + SF.Kind != SourceFileKind::SIL) { + parseTopLevelSwift(contents.data(), CurDeclContext, &Context, &decls, appendToVector); + + // Spin the C++ parser to the end; we won't be using it. + while (!Tok.is(tok::eof)) { + consumeToken(); + } + return; + } +#endif + // Prime the lexer. if (Tok.is(tok::NUM_TOKENS)) consumeTokenWithoutFeedingReceiver(); diff --git a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake index 12ac9499f9ae2..48ab4d81f7025 100644 --- a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake +++ b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake @@ -251,6 +251,10 @@ macro(add_sourcekit_library name) add_llvm_symbol_exports(${name} ${EXPORTED_SYMBOL_FILE}) endif() + # Once the new Swift parser is linked, everything has Swift modules. + if (SWIFT_SWIFT_PARSER AND SOURCEKITLIB_SHARED) + set(SOURCEKITLIB_HAS_SWIFT_MODULES ON) + endif() if(SOURCEKITLIB_SHARED) set(RPATH_LIST) @@ -329,6 +333,16 @@ macro(add_sourcekit_executable name) set_target_properties(${name} PROPERTIES FOLDER "SourceKit executables") add_sourcekit_default_compiler_flags("${name}") + + if(SWIFT_SWIFT_PARSER) + set(SKEXEC_HAS_SWIFT_MODULES TRUE) + else() + set(SKEXEC_HAS_SWIFT_MODULES FALSE) + endif() + + set(RPATH_LIST) + add_sourcekit_swift_runtime_link_flags(${name} "../../../.." ${SKEXEC_HAS_SWIFT_MODULES}) + endmacro() # Add a new SourceKit framework. @@ -348,6 +362,11 @@ macro(add_sourcekit_framework name) set(lib_dir ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR}) set(framework_location "${lib_dir}/${name}.framework") + # Once the new Swift parser is linked, everything has Swift modules. + if (SWIFT_SWIFT_PARSER) + set(SOURCEKITFW_HAS_SWIFT_MODULES ON) + endif() + if (NOT SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx") set(FLAT_FRAMEWORK_NAME "${name}") set(FLAT_FRAMEWORK_IDENTIFIER "com.apple.${name}") diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index a5dc3ccb84580..a732779a2bab3 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -17,6 +17,12 @@ if(${BOOTSTRAPPING_MODE} MATCHES "BOOTSTRAPPING.*") swiftDriverTool swiftCompilerStub) + if(SWIFT_SWIFT_PARSER) + target_link_libraries(swift-frontend-bootstrapping0 + PRIVATE + swiftCore) + endif() + swift_create_post_build_symlink(swift-frontend-bootstrapping0 SOURCE "swift-frontend${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION "swiftc${CMAKE_EXECUTABLE_SUFFIX}" @@ -36,6 +42,12 @@ if(${BOOTSTRAPPING_MODE} MATCHES "BOOTSTRAPPING.*") swiftDriverTool swiftCompilerModules-bootstrapping1) + if(SWIFT_SWIFT_PARSER) + target_link_libraries(swift-frontend-bootstrapping1 + PRIVATE + swiftCore) + endif() + swift_create_post_build_symlink(swift-frontend-bootstrapping1 SOURCE "swift-frontend${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION "swiftc${CMAKE_EXECUTABLE_SUFFIX}" @@ -52,6 +64,14 @@ target_link_libraries(swift-frontend swiftDriverTool swiftCompilerModules) +if(SWIFT_SWIFT_PARSER) + target_link_libraries(swift-frontend + PRIVATE + swiftCore) +endif() + +_add_swift_runtime_link_flags(swift-frontend "../../lib" "") + # Create a `swift-driver` executable adjacent to the `swift-frontend` executable # to ensure that `swiftc` forwards to the standalone driver when invoked. swift_create_early_driver_copies(swift-frontend)