From 1bd8e01b28ca1124184a8b92d023e6731893e2a9 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Mon, 11 Apr 2022 09:59:04 -0700 Subject: [PATCH] Preparation for location aware diagnostics in the compiler. Moving `libswiftLexRegexLiteral()` and `libswiftParseRegexLiteral()` to the compiler repository because these functions are basically just briding the compiler to the actual lexing/parsing function. * Make some Lexing error APIs public. * Make LocatedErrorProtocol public and expose the `location` property * Shift the location of `LocatedError` in `parseWithDelimiters` so the client can get the valid string indices of the passed-in literal string. (cherry picked from commit 89b80bfe180ea3940ae9a35bb5765f69f448ec4e) (cherry picked from commit 84e8db29ab5b2e183ae9cef7a1db75aa791be181) --- .../Regex/Parse/DelimiterLexing.swift | 18 ++++++++++++------ .../Regex/Parse/LexicalAnalysis.swift | 2 +- Sources/_RegexParser/Regex/Parse/Mocking.swift | 3 +++ Sources/_RegexParser/Regex/Parse/Parse.swift | 12 +++++++++++- .../Regex/Parse/SourceLocation.swift | 11 +++++++++-- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/Sources/_RegexParser/Regex/Parse/DelimiterLexing.swift b/Sources/_RegexParser/Regex/Parse/DelimiterLexing.swift index bee782043..dd142f016 100644 --- a/Sources/_RegexParser/Regex/Parse/DelimiterLexing.swift +++ b/Sources/_RegexParser/Regex/Parse/DelimiterLexing.swift @@ -9,7 +9,7 @@ // //===----------------------------------------------------------------------===// -struct Delimiter: Hashable { +public struct Delimiter: Hashable { let kind: Kind let poundCount: Int @@ -74,8 +74,8 @@ extension Delimiter { } } -struct DelimiterLexError: Error, CustomStringConvertible { - enum Kind: Hashable { +public struct DelimiterLexError: Error, CustomStringConvertible { + public enum Kind: Hashable { case unterminated case invalidUTF8 // TODO: better range reporting case unknownDelimiter @@ -83,17 +83,17 @@ struct DelimiterLexError: Error, CustomStringConvertible { case multilineClosingNotOnNewline } - var kind: Kind + public var kind: Kind /// The pointer at which to resume lexing. - var resumePtr: UnsafeRawPointer + public var resumePtr: UnsafeRawPointer init(_ kind: Kind, resumeAt resumePtr: UnsafeRawPointer) { self.kind = kind self.resumePtr = resumePtr } - var description: String { + public var description: String { switch kind { case .unterminated: return "unterminated regex literal" case .invalidUTF8: return "invalid UTF-8 found in source file" @@ -462,3 +462,9 @@ func lexRegex( var lexer = DelimiterLexer(start: start, end: end, delimiters: delimiters) return try lexer.lex() } + +public func lexRegex( + start: UnsafeRawPointer, end: UnsafeRawPointer +) throws -> (contents: String, Delimiter, end: UnsafeRawPointer) { + return try lexRegex(start: start, end: end, delimiters: Delimiter.enabledDelimiters) +} diff --git a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift index 6a61ccdf7..9633b607e 100644 --- a/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift +++ b/Sources/_RegexParser/Regex/Parse/LexicalAnalysis.swift @@ -24,7 +24,7 @@ API convention: extension Error { func addingLocation(_ loc: Range) -> Error { // If we're already a LocatedError, don't change the location. - if self is _LocatedErrorProtocol { + if self is LocatedErrorProtocol { return self } return Source.LocatedError(self, loc) diff --git a/Sources/_RegexParser/Regex/Parse/Mocking.swift b/Sources/_RegexParser/Regex/Parse/Mocking.swift index dd02e0fc7..56294e2d3 100644 --- a/Sources/_RegexParser/Regex/Parse/Mocking.swift +++ b/Sources/_RegexParser/Regex/Parse/Mocking.swift @@ -9,6 +9,7 @@ // //===----------------------------------------------------------------------===// +@available(*, deprecated, message: "moving to SwiftCompilerModules") private func copyCString(_ str: String) -> UnsafePointer { let count = str.utf8.count + 1 return str.withCString { @@ -36,6 +37,7 @@ private func copyCString(_ str: String) -> UnsafePointer { /// - 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. +@available(*, deprecated, message: "moving to SwiftCompilerModules") func libswiftLexRegexLiteral( _ curPtrPtr: UnsafeMutablePointer?>?, _ bufferEndPtr: UnsafePointer?, @@ -93,6 +95,7 @@ public let currentRegexLiteralFormatVersion: CUnsignedInt = 1 /// capture structure. /// - captureStructureSize: The size of the capture structure buffer. Must be /// greater than or equal to `strlen(inputPtr)`. +@available(*, deprecated, message: "moving to SwiftCompilerModules") func libswiftParseRegexLiteral( _ inputPtr: UnsafePointer?, _ errOut: UnsafeMutablePointer?>?, diff --git a/Sources/_RegexParser/Regex/Parse/Parse.swift b/Sources/_RegexParser/Regex/Parse/Parse.swift index 975012546..a2790924a 100644 --- a/Sources/_RegexParser/Regex/Parse/Parse.swift +++ b/Sources/_RegexParser/Regex/Parse/Parse.swift @@ -583,5 +583,15 @@ public func parseWithDelimiters( _ regex: S ) throws -> AST where S.SubSequence == Substring { let (contents, delim) = droppingRegexDelimiters(String(regex)) - return try parse(contents, defaultSyntaxOptions(delim, contents: contents)) + do { + return try parse(contents, defaultSyntaxOptions(delim, contents: contents)) + } catch let error as LocatedErrorProtocol { + // Convert the range in 'contents' to the range in 'regex'. + let delimCount = delim.opening.count + let offsets = contents.offsets(of: error.location.range) + let startIndex = regex.index(atOffset: delimCount + offsets.lowerBound) + let endIndex = regex.index(atOffset: delimCount + offsets.upperBound) + + throw error._typeErasedError.addingLocation(startIndex..: Error, _LocatedErrorProtocol { + public struct LocatedError: Error, LocatedErrorProtocol { public let error: E public let location: SourceLocation @@ -118,4 +121,8 @@ extension Source.LocatedError: CustomStringConvertible { // we present the message to the compiler. "\(error)" } + + public var _typeErasedError: Error { + return error + } }