diff --git a/Sources/Core/SourceFile.swift b/Sources/Core/SourceFile.swift index e0303b7c4..f03bd41b1 100644 --- a/Sources/Core/SourceFile.swift +++ b/Sources/Core/SourceFile.swift @@ -33,6 +33,14 @@ public struct SourceFile { try self.init(contentsOf: URL(fileURLWithPath: filePath)) } + /// Creates an instance with the given `contents`, identified by `fileID`. + /// + /// `contents` may not reflect what—if anything—is stored on disk at `fileID`. + public init(contents: String, fileID: URL) { + let storage = Storage(fileID, replaceExisting: true) { contents[...] } + self.storage = storage + } + /// Creates an instance for the `text` given by a multiline string literal in the given /// `swiftFile`, the literal's textual content (the line after the opening quotes) being /// startLine. @@ -344,17 +352,23 @@ extension SourceFile { } /// The owner of all instances of `Storage`. - private static var allInstances = SharedMutable<[URL: Storage]>([:]) + private static let allInstances = SharedMutable<[URL: Storage]>([:]) - /// Creates an alias to the instance with the given `url` if it exists, or creates a new + /// Creates an alias to the instance with the given `url` if it exists, replacing the instance's text with the + /// result of `makeText()` iff `replaceExisting` is `true`, or creates a new /// instance having the given `url` and the text resulting from `makeText()`. fileprivate convenience init( - _ url: URL, lineStarts: [Index]? = nil, makeText: () throws -> Substring + _ url: URL, lineStarts: [Index]? = nil, replaceExisting: Bool = false, makeText: () throws -> Substring ) rethrows { self.init( aliasing: try Self.allInstances.modify { (c: inout [URL: Storage]) -> Storage in try modify(&c[url]) { v in - let r = try v ?? Storage(url: url, lineStarts: lineStarts, text: makeText()) + let r: Storage + if !replaceExisting && v != nil { + r = v! + } else { + r = try Storage(url: url, lineStarts: lineStarts, text: makeText()) + } v = r return r } diff --git a/Tests/HyloTests/SourceFileTests.swift b/Tests/HyloTests/SourceFileTests.swift index 188b05d24..fc3d4c9e1 100644 --- a/Tests/HyloTests/SourceFileTests.swift +++ b/Tests/HyloTests/SourceFileTests.swift @@ -1,5 +1,6 @@ import Core import XCTest +import Foundation final class SourceFileTests: XCTestCase { @@ -33,4 +34,12 @@ final class SourceFileTests: XCTestCase { XCTAssertEqual(source.line(containing: source.text.endIndex).number, 3) } + func testUpdateSourceFileContent() throws { + let url = URL(fileURLWithPath: "foo.hylo") + let s1 = SourceFile(contents: "import A", fileID: url) + XCTAssertEqual(s1.text, "import A") + let s2 = SourceFile(contents: "import B", fileID: url) + XCTAssertEqual(s2.text, "import B") + } + }