diff --git a/SwiftCompilerSources/CMakeLists.txt b/SwiftCompilerSources/CMakeLists.txt index 9e8bda8489566..4069e71c785fe 100644 --- a/SwiftCompilerSources/CMakeLists.txt +++ b/SwiftCompilerSources/CMakeLists.txt @@ -251,3 +251,23 @@ else() endif() +# Configure 'SwiftCompilerModules' SwiftPM package. The 'Package.swift' will +# be created at '${build_dir}/SwiftCompilerSources/Package.swift' and can be +# built with 'swift-build'. +# Note that this SwiftPM package itself is just for development purposes, and +# is not actually used for the compiler building. +set(swiftcompiler_source_dir_name "_Sources") +configure_file(Package.swift.in + "${CMAKE_CURRENT_BINARY_DIR}/Package.swift" @ONLY) +# SwiftPM requires all sources are inside the directory of 'Package.swift'. +# Create symlinks to the actual source directories. +execute_process(COMMAND + "${CMAKE_COMMAND}" -E create_symlink + "${CMAKE_CURRENT_SOURCE_DIR}/Sources" + "${CMAKE_CURRENT_BINARY_DIR}/${swiftcompiler_source_dir_name}") +if(SWIFT_BUILD_REGEX_PARSER_IN_COMPILER) + execute_process(COMMAND + "${CMAKE_COMMAND}" -E create_symlink + "${EXPERIMENTAL_STRING_PROCESSING_SOURCE_DIR}/Sources/_RegexParser" + "${CMAKE_CURRENT_BINARY_DIR}/_RegexParser_Sources") +endif() diff --git a/SwiftCompilerSources/Package.swift b/SwiftCompilerSources/Package.swift deleted file mode 100644 index a3c90e3ad278b..0000000000000 --- a/SwiftCompilerSources/Package.swift +++ /dev/null @@ -1,51 +0,0 @@ -// swift-tools-version:5.3 - -import PackageDescription - -let package = Package( - name: "SwiftCompilerSources", - platforms: [ - .macOS("10.9"), - ], - products: [ - .library( - name: "Swift", - type: .static, - targets: ["SIL", "Optimizer", "_CompilerRegexParser"]), - ], - dependencies: [ - ], - // Note that all modules must be added to LIBSWIFT_MODULES in the top-level - // CMakeLists.txt file to get debugging working. - targets: [ - .target( - name: "SIL", - dependencies: [], - swiftSettings: [SwiftSetting.unsafeFlags([ - "-I", "../include/swift", - "-cross-module-optimization" - ])]), - .target( - name: "_CompilerRegexParser", - dependencies: [], - path: "_RegexParser", - swiftSettings: [ - .unsafeFlags([ - "-I", "../include/swift", - "-cross-module-optimization", - ]), - // Workaround until `_RegexParser` is imported as implementation-only - // by `_StringProcessing`. - .unsafeFlags([ - "-Xfrontend", - "-disable-implicit-string-processing-module-import" - ])]), - .target( - name: "Optimizer", - dependencies: ["SIL", "_CompilerRegexParser"], - swiftSettings: [SwiftSetting.unsafeFlags([ - "-I", "../include/swift", - "-cross-module-optimization" - ])]), - ] -) diff --git a/SwiftCompilerSources/Package.swift.in b/SwiftCompilerSources/Package.swift.in new file mode 100644 index 0000000000000..bfbe0e9bd6a52 --- /dev/null +++ b/SwiftCompilerSources/Package.swift.in @@ -0,0 +1,92 @@ +// swift-tools-version:5.3 +//===--- Package.swift.in - SwiftCompiler SwiftPM package -----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2021 - 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 +// +//===----------------------------------------------------------------------===// + +// NOTE: This 'Package.swift.in' file is for CMake configure_file(). +// Generated 'Package.swift' can be found in +// '${swift_build_dir}/SwiftCompilerSources/Package.swift'. + +import PackageDescription + +private extension Target { + static let defaultSwiftSettings: [SwiftSetting] = [ + .unsafeFlags([ + "-Xfrontend", "-validate-tbd-against-ir=none", + "-Xfrontend", "-enable-cxx-interop", + // Bridging modules and headers + "-Xcc", "-I", "-Xcc", "@SWIFT_SOURCE_DIR@/include", + // Generated C headers + "-Xcc", "-I", "-Xcc", "@CMAKE_BINARY_DIR@/include", + "-cross-module-optimization" + ]), + ] + + static func compilerModuleTarget( + name: String, + dependencies: [Dependency], + path: String? = nil, + sources: [String]? = nil, + swiftSettings: [SwiftSetting] = []) -> Target { + .target( + name: name, + dependencies: dependencies, + path: path ?? "@swiftcompiler_source_dir_name@/\(name)", + exclude: ["CMakeLists.txt"], + sources: sources, + swiftSettings: defaultSwiftSettings + swiftSettings) + } +} + +let package = Package( + name: "SwiftCompilerSources", + platforms: [ + .macOS("10.9"), + ], + products: [ + .library( + name: "swiftCompilerModules", + type: .static, + targets: ["Basic", "AST", "Parse", "SIL", "Optimizer", "_CompilerRegexParser"]), + ], + dependencies: [ + ], + // Note that targets and their dependencies must align with + // 'SwiftCompilerSources/Sources/CMakeLists.txt' + targets: [ + .compilerModuleTarget( + name: "_CompilerRegexParser", + dependencies: [], + path: "_RegexParser_Sources", + swiftSettings: [ + // Workaround until `_CompilerRegexParser` is imported as implementation-only + // by `_StringProcessing`. + .unsafeFlags([ + "-Xfrontend", + "-disable-implicit-string-processing-module-import" + ])]), + .compilerModuleTarget( + name: "Basic", + dependencies: []), + .compilerModuleTarget( + name: "AST", + dependencies: ["Basic"]), + .compilerModuleTarget( + name: "Parse", + dependencies: ["Basic", "AST", "_CompilerRegexParser"]), + .compilerModuleTarget( + name: "SIL", + dependencies: ["Basic"]), + .compilerModuleTarget( + name: "Optimizer", + dependencies: ["Basic", "SIL", "Parse"]), + ] +) diff --git a/SwiftCompilerSources/Sources/AST/DiagnosticEngine.swift b/SwiftCompilerSources/Sources/AST/DiagnosticEngine.swift index 4ad82aedf90c7..78a56c7e8e798 100644 --- a/SwiftCompilerSources/Sources/AST/DiagnosticEngine.swift +++ b/SwiftCompilerSources/Sources/AST/DiagnosticEngine.swift @@ -67,6 +67,12 @@ public struct DiagnosticEngine { public init(bridged: BridgedDiagnosticEngine) { self.bridged = bridged } + public init?(bridged: BridgedOptionalDiagnosticEngine) { + guard let object = bridged.object else { + return nil + } + self.bridged = BridgedDiagnosticEngine(object: object) + } public func diagnose(_ position: SourceLoc?, _ id: DiagID, diff --git a/SwiftCompilerSources/Sources/Basic/SourceLoc.swift b/SwiftCompilerSources/Sources/Basic/SourceLoc.swift index f5016a6a9f06a..1fa3dc731d64f 100644 --- a/SwiftCompilerSources/Sources/Basic/SourceLoc.swift +++ b/SwiftCompilerSources/Sources/Basic/SourceLoc.swift @@ -33,6 +33,12 @@ public struct SourceLoc { } } +extension SourceLoc { + public func advanced(by n: Int) -> SourceLoc { + SourceLoc(locationInFile: locationInFile.advanced(by: n))! + } +} + extension Optional where Wrapped == SourceLoc { public var bridged: BridgedSourceLoc { self?.bridged ?? .init(pointer: nil) diff --git a/SwiftCompilerSources/Sources/CMakeLists.txt b/SwiftCompilerSources/Sources/CMakeLists.txt index 515c94dc2de5a..af6900ff8d0e9 100644 --- a/SwiftCompilerSources/Sources/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/CMakeLists.txt @@ -8,10 +8,11 @@ # NOTE: Subdirectories must be added in dependency order. -add_subdirectory(Basic) -add_subdirectory(AST) if(SWIFT_BUILD_REGEX_PARSER_IN_COMPILER) add_subdirectory(_RegexParser) endif() +add_subdirectory(Basic) +add_subdirectory(AST) +add_subdirectory(Parse) add_subdirectory(SIL) add_subdirectory(Optimizer) diff --git a/SwiftCompilerSources/Sources/Optimizer/CMakeLists.txt b/SwiftCompilerSources/Sources/Optimizer/CMakeLists.txt index 929e0a54581ab..ed754dd792c94 100644 --- a/SwiftCompilerSources/Sources/Optimizer/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/Optimizer/CMakeLists.txt @@ -7,10 +7,7 @@ # See http://swift.org/CONTRIBUTORS.txt for Swift project authors set(dependencies) -list(APPEND dependencies Basic SIL) -if(SWIFT_BUILD_REGEX_PARSER_IN_COMPILER) - list(APPEND dependencies _CompilerRegexParser) -endif() +list(APPEND dependencies Basic SIL Parse) add_swift_compiler_module(Optimizer DEPENDS ${dependencies}) diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift index 1f6c1f6cd9f2b..c21f8809f6f93 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift @@ -12,19 +12,13 @@ import SIL import OptimizerBridging - -#if canImport(_CompilerRegexParser) -import _CompilerRegexParser -#endif +import Parse @_cdecl("initializeSwiftModules") public func initializeSwiftModules() { registerSILClasses() registerSwiftPasses() - - #if canImport(_CompilerRegexParser) registerRegexParser() - #endif } private func registerPass( diff --git a/SwiftCompilerSources/Sources/Parse/CMakeLists.txt b/SwiftCompilerSources/Sources/Parse/CMakeLists.txt new file mode 100644 index 0000000000000..e4c52316ff1df --- /dev/null +++ b/SwiftCompilerSources/Sources/Parse/CMakeLists.txt @@ -0,0 +1,18 @@ +# 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for Swift project authors + +set(dependencies Basic AST) +if(SWIFT_BUILD_REGEX_PARSER_IN_COMPILER) + list(APPEND dependencies _CompilerRegexParser) +endif() + +add_swift_compiler_module(Parse + DEPENDS + ${dependencies} + SOURCES + Regex.swift) diff --git a/SwiftCompilerSources/Sources/Parse/Regex.swift b/SwiftCompilerSources/Sources/Parse/Regex.swift new file mode 100644 index 0000000000000..22d0c3aa2bcf0 --- /dev/null +++ b/SwiftCompilerSources/Sources/Parse/Regex.swift @@ -0,0 +1,146 @@ +//===--- Regex.swift - SourceLoc bridiging utilities ------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +import _RegexParserBridging +import AST +import Basic + +#if canImport(_CompilerRegexParser) +import _CompilerRegexParser + +public func registerRegexParser() { + Parser_registerRegexLiteralParsingFn(_RegexLiteralParsingFn) + Parser_registerRegexLiteralLexingFn(_RegexLiteralLexingFn) +} + +/// Bridging between C++ lexer and _CompilerRegexParser.lexRegex() +/// +/// Attempt to lex a regex literal string. +/// +/// - Parameters: +/// - CurPtrPtr: A pointer to the current pointer of lexer, which should be +/// the start of the literal. This will be advanced to the point +/// at which the lexer should resume, or will remain the same if +/// this is not a regex literal. +/// - BufferEndPtr: A pointer to the end of the buffer, which should not be +/// lexed past. +/// - mustBeRegex: A bool value whether an error during lexing should be +/// considered a regex literal, or some thing else. If true +/// advace the curPtrPtr and emit the diagnostic. If false, +/// curPtrPtr won't be modified. +/// - bridgedDiagnosticEngine: Diagnostic engine to emit diagnostics. +/// +/// - Returns: A bool indicating whether lexing was completely erroneous, and +/// cannot be recovered from, or false if there either was no error, +/// or there was a recoverable error. +private func _RegexLiteralLexingFn( + _ curPtrPtr: UnsafeMutablePointer>, + _ bufferEndPtr: UnsafePointer, + _ mustBeRegex: CBool, + _ bridgedDiagnosticEngine: BridgedOptionalDiagnosticEngine +) -> /*CompletelyErroneous*/ CBool { + let inputPtr = curPtrPtr.pointee + + do { + let (_, _, endPtr) = try lexRegex(start: inputPtr, end: bufferEndPtr) + curPtrPtr.pointee = endPtr.assumingMemoryBound(to: CChar.self) + return false + } catch let error as DelimiterLexError { + if !mustBeRegex { + // This token can be something else. Let the client fallback. + return false; + } + if error.kind == .unknownDelimiter { + // An unknown delimiter should be recovered from, as we may want to try + // lex something else. + return false + } + + if let diagEngine = DiagnosticEngine(bridged: bridgedDiagnosticEngine) { + // Emit diagnostic. + let startLoc = SourceLoc( + locationInFile: UnsafeRawPointer(inputPtr).assumingMemoryBound(to: UInt8.self))! + diagEngine.diagnose(startLoc, .regex_literal_parsing_error, "\(error)") + } + + // Advance the current pointer. + curPtrPtr.pointee = error.resumePtr.assumingMemoryBound(to: CChar.self) + + switch error.kind { + case .unterminated, .multilineClosingNotOnNewline: + // These can be recovered from. + return false + case .unprintableASCII, .invalidUTF8: + // We don't currently have good recovery behavior for these. + return true + case .unknownDelimiter: + fatalError("Already handled") + } + } catch { + fatalError("Should be a DelimiterLexError") + } +} + +/// Bridging between C++ parser and _CompilerRegexParser.parseWithDelimiters() +/// +/// - Parameters: +/// - inputPtr: A null-terminated C string. +/// - errOut: A buffer accepting an error string upon error. +/// - versionOut: A buffer accepting a regex literal format +/// version. +/// - captureStructureOut: A buffer accepting a byte sequence representing the +/// capture structure. +/// - captureStructureSize: The size of the capture structure buffer. Must be +/// greater than or equal to `strlen(inputPtr)`. +/// - bridgedDiagnosticBaseLoc: Source location of the start of the literal +/// - bridgedDiagnosticEngine: Diagnostic engine to emit diagnostics. +public func _RegexLiteralParsingFn( + _ inputPtr: UnsafePointer, + _ versionOut: UnsafeMutablePointer, + _ captureStructureOut: UnsafeMutableRawPointer, + _ captureStructureSize: CUnsignedInt, + _ bridgedDiagnosticBaseLoc: BridgedSourceLoc, + _ bridgedDiagnosticEngine: BridgedDiagnosticEngine +) -> Bool { + versionOut.pointee = currentRegexLiteralFormatVersion + + let str = String(cString: inputPtr) + do { + let ast = try parseWithDelimiters(str) + // Serialize the capture structure for later type inference. + assert(captureStructureSize >= str.utf8.count) + let buffer = UnsafeMutableRawBufferPointer( + start: captureStructureOut, count: Int(captureStructureSize)) + ast.captureStructure.encode(to: buffer) + return false; + } catch { + var diagLoc = SourceLoc(bridged: bridgedDiagnosticBaseLoc) + let diagEngine = DiagnosticEngine(bridged: bridgedDiagnosticEngine) + if let _diagLoc = diagLoc, + let locatedError = error as? LocatedErrorProtocol { + let offset = str.utf8.distance(from: str.startIndex, + to: locatedError.location.start) + diagLoc = _diagLoc.advanced(by: offset) + } + diagEngine.diagnose( + diagLoc, .regex_literal_parsing_error, + "cannot parse regular expression: \(String(describing: error))") + return true + } +} + +#else // canImport(_CompilerRegexParser) + +#warning("Regex parsing is disabled") +public func registerRegexParser() {} + +#endif // canImport(_CompilerRegexParser) diff --git a/SwiftCompilerSources/Sources/_RegexParser/CMakeLists.txt b/SwiftCompilerSources/Sources/_RegexParser/CMakeLists.txt index 32fc6f667c1c9..b1d2ae37978f7 100644 --- a/SwiftCompilerSources/Sources/_RegexParser/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/_RegexParser/CMakeLists.txt @@ -16,5 +16,4 @@ endforeach() message(STATUS "Using Experimental String Processing library for libswift _RegexParser (${EXPERIMENTAL_STRING_PROCESSING_SOURCE_DIR}).") add_swift_compiler_module(_CompilerRegexParser - "${LIBSWIFT_REGEX_PARSER_SOURCES}" - Regex.swift) + "${LIBSWIFT_REGEX_PARSER_SOURCES}") diff --git a/SwiftCompilerSources/Sources/_RegexParser/Regex.swift b/SwiftCompilerSources/Sources/_RegexParser/Regex.swift deleted file mode 100644 index fb484bd793529..0000000000000 --- a/SwiftCompilerSources/Sources/_RegexParser/Regex.swift +++ /dev/null @@ -1,6 +0,0 @@ -import _RegexParserBridging - -public func registerRegexParser() { - Parser_registerRegexLiteralParsingFn(libswiftParseRegexLiteral) - Parser_registerRegexLiteralLexingFn(libswiftLexRegexLiteral) -} diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 99ca2e68d6c18..daeb249a76497 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -65,6 +65,10 @@ typedef struct { void * _Nonnull object; } BridgedDiagnosticEngine; +typedef struct { + void *_Nullable object; +} BridgedOptionalDiagnosticEngine; + // FIXME: Can we bridge InFlightDiagnostic? void DiagnosticEngine_diagnose(BridgedDiagnosticEngine, BridgedSourceLoc loc, BridgedDiagID diagID, BridgedArrayRef arguments, diff --git a/include/swift/AST/BridgingUtils.h b/include/swift/AST/BridgingUtils.h index 0de9cb21b5831..6f5a0dfbbbe90 100644 --- a/include/swift/AST/BridgingUtils.h +++ b/include/swift/AST/BridgingUtils.h @@ -21,6 +21,10 @@ namespace swift { inline BridgedDiagnosticEngine getBridgedDiagnosticEngine(DiagnosticEngine *D) { return {(void *)D}; } +inline BridgedOptionalDiagnosticEngine +getBridgedOptionalDiagnosticEngine(DiagnosticEngine *D) { + return {(void *)D}; +} } // namespace swift diff --git a/include/swift/Parse/RegexParserBridging.h b/include/swift/Parse/RegexParserBridging.h index 5fa054cf03689..bc2f97ed2d9cf 100644 --- a/include/swift/Parse/RegexParserBridging.h +++ b/include/swift/Parse/RegexParserBridging.h @@ -14,6 +14,7 @@ #ifndef REGEX_PARSER_BRIDGING #define REGEX_PARSER_BRIDGING +#include "swift/AST/ASTBridging.h" #include #ifdef __cplusplus @@ -28,32 +29,40 @@ extern "C" { /// is not a regex literal. /// - BufferEnd: A pointer to the end of the buffer, which should not be lexed /// past. -/// - ErrorOut: If an error is encountered, this will be set to the error -/// string. +/// - MustBeRegex: whether an error during lexing should be considered a regex +/// literal, or some thing else. +/// - BridgedOptionalDiagnosticEngine: RegexLiteralLexingFn should diagnose the +/// token using this engine. /// /// Returns: A bool indicating whether lexing was completely erroneous, and /// cannot be recovered from, or false if there either was no error, /// or there was a recoverable error. -typedef bool (* RegexLiteralLexingFn)(/*CurPtrPtr*/ const char **, - /*BufferEnd*/ const char *, - /*ErrorOut*/ const char **); -void Parser_registerRegexLiteralLexingFn(RegexLiteralLexingFn fn); +typedef bool (*RegexLiteralLexingFn)( + /*CurPtrPtr*/ const char *_Nonnull *_Nonnull, + /*BufferEnd*/ const char *_Nonnull, + /*MustBeRegex*/ bool, BridgedOptionalDiagnosticEngine); +void Parser_registerRegexLiteralLexingFn(RegexLiteralLexingFn _Nullable fn); /// Parse a regex literal string. Takes the following arguments: /// /// - InputPtr: A null-terminated C string of the regex literal. -/// - ErrorOut: A buffer accepting an error string upon error. /// - VersionOut: A buffer accepting a regex literal format version. /// - CaptureStructureOut: A buffer accepting a byte sequence representing the /// capture structure of the literal. /// - CaptureStructureSize: The size of the capture structure buffer. Must be /// greater than or equal to `strlen(InputPtr) + 3`. -typedef void(* RegexLiteralParsingFn)(/*InputPtr*/ const char *, - /*ErrorOut*/ const char **, - /*VersionOut*/ unsigned *, - /*CaptureStructureOut*/ void *, - /*CaptureStructureSize*/ unsigned); -void Parser_registerRegexLiteralParsingFn(RegexLiteralParsingFn fn); +/// - DiagnosticBaseLoc: Start location of the regex literal. +/// - BridgedDiagnosticEngine: RegexLiteralParsingFn should diagnose the +/// parsing errors using this engine. +/// +/// Returns: A bool value indicating if there was an error while parsing. +typedef bool (*RegexLiteralParsingFn)(/*InputPtr*/ const char *_Nonnull, + /*VersionOut*/ unsigned *_Nonnull, + /*CaptureStructureOut*/ void *_Nonnull, + /*CaptureStructureSize*/ unsigned, + /*DiagnosticBaseLoc*/ BridgedSourceLoc, + BridgedDiagnosticEngine); +void Parser_registerRegexLiteralParsingFn(RegexLiteralParsingFn _Nullable fn); #ifdef __cplusplus } // extern "C" diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp index 4b08f2776efec..47b02a0ed5f11 100644 --- a/lib/Parse/Lexer.cpp +++ b/lib/Parse/Lexer.cpp @@ -14,27 +14,27 @@ // //===----------------------------------------------------------------------===// -#include "swift/Parse/Confusables.h" #include "swift/Parse/Lexer.h" +#include "swift/AST/BridgingUtils.h" #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/Identifier.h" #include "swift/Basic/LangOptions.h" #include "swift/Basic/SourceManager.h" +#include "swift/Parse/Confusables.h" #include "swift/Parse/RegexParserBridging.h" #include "swift/Syntax/Trivia.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/MemoryBuffer.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" // FIXME: Figure out if this can be migrated to LLVM. #include "clang/Basic/CharInfo.h" #include // Regex lexing delivered via libSwift. -#include "swift/Parse/RegexParserBridging.h" static RegexLiteralLexingFn regexLiteralLexingFn = nullptr; void Parser_registerRegexLiteralLexingFn(RegexLiteralLexingFn fn) { regexLiteralLexingFn = fn; @@ -2039,25 +2039,18 @@ bool Lexer::tryLexRegexLiteral(const char *TokStart) { // Ask the Swift library to try and lex a regex literal. // - Ptr will not be advanced if this is not for a regex literal. - // - ErrStr will be set if there is any error to emit. // - CompletelyErroneous will be set if there was an error that cannot be // recovered from. auto *Ptr = TokStart; - const char *ErrStr = nullptr; - bool CompletelyErroneous = regexLiteralLexingFn(&Ptr, BufferEnd, &ErrStr); + bool CompletelyErroneous = regexLiteralLexingFn( + &Ptr, BufferEnd, MustBeRegex, + getBridgedOptionalDiagnosticEngine(getTokenDiags())); // If we didn't make any lexing progress, this isn't a regex literal and we // should fallback to lexing as something else. if (Ptr == TokStart) return false; - if (ErrStr) { - if (!MustBeRegex) - return false; - - diagnose(TokStart, diag::regex_literal_parsing_error, ErrStr); - } - // If we're lexing `/.../`, error if we ended on the opening of a comment. // We prefer to lex the comment as it's more likely than not that is what // the user is expecting. @@ -2078,7 +2071,6 @@ bool Lexer::tryLexRegexLiteral(const char *TokStart) { // If the lexing was completely erroneous, form an unknown token. if (CompletelyErroneous) { - assert(ErrStr); formToken(tok::unknown, TokStart); return true; } diff --git a/lib/Parse/ParseRegex.cpp b/lib/Parse/ParseRegex.cpp index c7fa4e95a2917..d0d3e3eae944c 100644 --- a/lib/Parse/ParseRegex.cpp +++ b/lib/Parse/ParseRegex.cpp @@ -14,9 +14,11 @@ // //===----------------------------------------------------------------------===// -#include "swift/Parse/Parser.h" +#include "swift/AST/BridgingUtils.h" #include "swift/AST/DiagnosticsParse.h" +#include "swift/Basic/BridgingUtils.h" #include "swift/Parse/ParsedSyntaxRecorder.h" +#include "swift/Parse/Parser.h" #include "swift/Parse/SyntaxParsingContext.h" #include "swift/Syntax/SyntaxKind.h" @@ -41,19 +43,18 @@ ParserResult Parser::parseExprRegexLiteral() { // Let the Swift library parse the contents, returning an error, or null if // successful. - // TODO: We need to be able to pass back a source location to emit the error - // at. - const char *errorStr = nullptr; unsigned version; auto capturesBuf = Context.AllocateUninitialized( RegexLiteralExpr::getCaptureStructureSerializationAllocationSize( regexText.size())); - regexLiteralParsingFn(regexText.str().c_str(), &errorStr, &version, - /*captureStructureOut*/ capturesBuf.data(), - /*captureStructureSize*/ capturesBuf.size()); + bool hadError = + regexLiteralParsingFn(regexText.str().c_str(), &version, + /*captureStructureOut*/ capturesBuf.data(), + /*captureStructureSize*/ capturesBuf.size(), + /*diagBaseLoc*/ getBridgedSourceLoc(Tok.getLoc()), + getBridgedDiagnosticEngine(&Diags)); auto loc = consumeToken(); - if (errorStr) { - diagnose(loc, diag::regex_literal_parsing_error, errorStr); + if (hadError) { return makeParserResult(new (Context) ErrorExpr(loc)); } return makeParserResult(RegexLiteralExpr::createParsed( diff --git a/test/StringProcessing/Parse/forward-slash-regex.swift b/test/StringProcessing/Parse/forward-slash-regex.swift index e416816c2e5b6..26d0a3040829c 100644 --- a/test/StringProcessing/Parse/forward-slash-regex.swift +++ b/test/StringProcessing/Parse/forward-slash-regex.swift @@ -242,16 +242,19 @@ baz(/,/) // expected-error@-2 {{missing argument for parameter #2 in call}} baz((/), /) +func bazbaz(_ x: (Int, Int) -> Int, _ y: Int) {} +bazbaz(/, 0) + func qux(_ x: (Int, Int) -> Int, _ y: T) -> Int { 0 } do { _ = qux(/, 1) / 2 - // expected-error@-1 {{cannot parse regular expression: closing ')' does not balance any groups openings}} - // expected-error@-2 {{expected ',' separator}} + // expected-error@-1:15 {{cannot parse regular expression: closing ')' does not balance any groups openings}} + // expected-error@-2:19 {{expected ',' separator}} } do { _ = qux(/, "(") / 2 // expected-error@-1 {{cannot convert value of type 'Regex<(Substring, Substring)>' to expected argument type '(Int, Int) -> Int'}} - // expected-error@-2 {{expected ',' separator}} + // expected-error@-2:21 {{expected ',' separator}} } _ = qux(/, 1) // this comment tests to make sure we don't try and end the regex on the starting '/' of '//'. diff --git a/test/StringProcessing/Parse/regex.swift b/test/StringProcessing/Parse/regex.swift index f351e503833c6..797fc2af85eec 100644 --- a/test/StringProcessing/Parse/regex.swift +++ b/test/StringProcessing/Parse/regex.swift @@ -19,5 +19,5 @@ _ = #/#/\/\#\\/# _ = ##/#|\|\#\\/## _ = (#/[*/#, #/+]/#, #/.]/#) -// expected-error@-1 {{cannot parse regular expression: quantifier '+' must appear after expression}} -// expected-error@-2 {{cannot parse regular expression: expected ']'}} +// expected-error@-1:16 {{cannot parse regular expression: quantifier '+' must appear after expression}} +// expected-error@-2:10 {{cannot parse regular expression: expected ']'}} diff --git a/test/StringProcessing/Parse/regex_parse_end_of_buffer.swift b/test/StringProcessing/Parse/regex_parse_end_of_buffer.swift index 53ef39918bd7e..5c62181c0c8c2 100644 --- a/test/StringProcessing/Parse/regex_parse_end_of_buffer.swift +++ b/test/StringProcessing/Parse/regex_parse_end_of_buffer.swift @@ -2,5 +2,6 @@ // REQUIRES: swift_in_compiler // Note there is purposefully no trailing newline here. -// expected-error@+1 {{unterminated regex literal}} -var unterminated = #/xy +// expected-error@+2:20 {{unterminated regex literal}} +// expected-error@+1:25 {{cannot parse regular expression: expected ')'}} +var unterminated = #/(xy \ No newline at end of file diff --git a/test/StringProcessing/Parse/regex_parse_error.swift b/test/StringProcessing/Parse/regex_parse_error.swift index b53500d8aed52..80e428469256d 100644 --- a/test/StringProcessing/Parse/regex_parse_error.swift +++ b/test/StringProcessing/Parse/regex_parse_error.swift @@ -1,28 +1,28 @@ // RUN: %target-typecheck-verify-swift -enable-bare-slash-regex -disable-availability-checking // REQUIRES: swift_in_compiler -_ = /(/ // expected-error {{expected ')'}} -_ = #/(/# // expected-error {{expected ')'}} +_ = /(/ // expected-error@:7 {{expected ')'}} +_ = #/(/# // expected-error@:8 {{expected ')'}} // FIXME: Should be 'group openings' -_ = /)/ // expected-error {{closing ')' does not balance any groups openings}} -_ = #/)/# // expected-error {{closing ')' does not balance any groups openings}} +_ = /)/ // expected-error@:6 {{closing ')' does not balance any groups openings}} +_ = #/)/# // expected-error@:7 {{closing ')' does not balance any groups openings}} -_ = #/\\/''/ // expected-error {{unterminated regex literal}} -_ = #/\| // expected-error {{unterminated regex literal}} -_ = #// // expected-error {{unterminated regex literal}} +_ = #/\\/''/ // expected-error@:5 {{unterminated regex literal}} +_ = #/\| // expected-error@:5 {{unterminated regex literal}} +_ = #// // expected-error@:5 {{unterminated regex literal}} -_ = #/xy // expected-error {{unterminated regex literal}} +_ = #/xy // expected-error@:5 {{unterminated regex literal}} -_ = #/(?/# // expected-error {{expected group specifier}} -_ = #/(?'/# // expected-error {{expected group name}} -_ = #/(?'abc/# // expected-error {{expected '''}} -_ = #/(?'abc /# // expected-error {{expected '''}} +_ = #/(?/# // expected-error@:7 {{expected group specifier}} +_ = #/(?'/# // expected-error@:10 {{expected group name}} +_ = #/(?'abc/# // expected-error@:13 {{expected '''}} +_ = #/(?'abc /# // expected-error@:13 {{expected '''}} do { _ = #/(?'a - // expected-error@-1 {{unterminated regex literal}} - // expected-error@-2 {{cannot parse regular expression: expected '''}} + // expected-error@-1:7 {{unterminated regex literal}} + // expected-error@-2:13 {{cannot parse regular expression: expected '''}} } _ = #/\(?'abc/# @@ -30,21 +30,21 @@ _ = #/\(?'abc/# do { _ = /\ / - // expected-error@-2 {{unterminated regex literal}} - // expected-error@-3 {{expected escape sequence}} -} // expected-error {{expected expression after operator}} + // expected-error@-2:7 {{unterminated regex literal}} + // expected-error@-3:9 {{expected escape sequence}} +} // expected-error@:1 {{expected expression after operator}} do { _ = #/\ /# - // expected-error@-2 {{unterminated regex literal}} - // expected-error@-3 {{expected escape sequence}} - // expected-error@-3 {{unterminated regex literal}} - // expected-warning@-4 {{regular expression literal is unused}} + // expected-error@-2:7 {{unterminated regex literal}} + // expected-error@-3:10 {{expected escape sequence}} + // expected-error@-3:3 {{unterminated regex literal}} + // expected-warning@-4:3 {{regular expression literal is unused}} } func foo(_ x: T, _ y: T) {} -foo(#/(?/#, #/abc/#) // expected-error {{expected group specifier}} -foo(#/(?C/#, #/abc/#) // expected-error {{expected ')'}} +foo(#/(?/#, #/abc/#) // expected-error@:7 {{expected group specifier}} +foo(#/(?C/#, #/abc/#) // expected-error@:10 {{expected ')'}} -foo(#/(?'/#, #/abc/#) // expected-error {{expected group name}} +foo(#/(?'/#, #/abc/#) // expected-error@:10 {{expected group name}} diff --git a/tools/SourceKit/lib/Support/CMakeLists.txt b/tools/SourceKit/lib/Support/CMakeLists.txt index 3b18cc18e98c9..c4e2cbcd31e03 100644 --- a/tools/SourceKit/lib/Support/CMakeLists.txt +++ b/tools/SourceKit/lib/Support/CMakeLists.txt @@ -7,7 +7,6 @@ add_sourcekit_library(SourceKitSupport UIDRegistry.cpp) target_link_libraries(SourceKitSupport PRIVATE swiftBasic - swiftSyntax clangBasic clangRewrite) if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) @@ -15,4 +14,3 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) dispatch BlocksRuntime) endif() - diff --git a/tools/SourceKit/lib/Support/Tracing.cpp b/tools/SourceKit/lib/Support/Tracing.cpp index 00df43a90044c..96eaa99de82a5 100644 --- a/tools/SourceKit/lib/Support/Tracing.cpp +++ b/tools/SourceKit/lib/Support/Tracing.cpp @@ -12,8 +12,6 @@ #include "SourceKit/Support/Tracing.h" -#include "swift/Frontend/Frontend.h" - #include "llvm/Support/Mutex.h" #include "llvm/Support/YAMLTraits.h"