compiler: Track/Report Relative Paths Names
When the user gives relative path names for p4 files, report those in error messages (etc.). The SourceManager can/does resolve those to absolute path names. Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
@@ -85,7 +85,7 @@ public struct SourceManager {
|
|||||||
|
|
||||||
let fm = FileManager()
|
let fm = FileManager()
|
||||||
for path in self.paths {
|
for path in self.paths {
|
||||||
let combined = path.pushing(file)
|
let combined = path.pushing(file).lexicallyNormalized()
|
||||||
if fm.fileExists(atPath: combined.string) {
|
if fm.fileExists(atPath: combined.string) {
|
||||||
return combined
|
return combined
|
||||||
}
|
}
|
||||||
@@ -247,14 +247,24 @@ public struct SourceCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func do_preprocess(
|
func do_preprocess(
|
||||||
_ file: URL, _ manager: SourceManager, _ starting: Int = 0
|
_ file: FilePath, _ manager: SourceManager, _ starting: Int = 0
|
||||||
) -> Result<(FileSourceLocation, String)> {
|
) -> Result<(FileSourceLocation, String)> {
|
||||||
// First (1) match group has the name of the include file.
|
// First (1) match group has the name of the include file.
|
||||||
let re = /\#include[\s]*<([^\s>]*)>/
|
let re = /\#include[\s]*<([^\s>]*)>/
|
||||||
|
|
||||||
do {
|
do {
|
||||||
var locations: [FileSourceLocation] = Array()
|
var locations: [FileSourceLocation] = Array()
|
||||||
var contents = try String.init(contentsOf: file, encoding: String.defaultCStringEncoding)
|
|
||||||
|
// First, try to find the file.
|
||||||
|
guard let included_path = manager.firstExisting(file) else {
|
||||||
|
return .Error(
|
||||||
|
Error(
|
||||||
|
withMessage:
|
||||||
|
"Could not open \(file) for preprocessing"))
|
||||||
|
}
|
||||||
|
|
||||||
|
var contents = try String.init(
|
||||||
|
contentsOf: URL(filePath: included_path.string), encoding: String.defaultCStringEncoding)
|
||||||
var changed = true
|
var changed = true
|
||||||
|
|
||||||
while changed {
|
while changed {
|
||||||
@@ -264,20 +274,9 @@ func do_preprocess(
|
|||||||
let before = contents[..<match.range.lowerBound]
|
let before = contents[..<match.range.lowerBound]
|
||||||
let after = contents[match.range.upperBound...]
|
let after = contents[match.range.upperBound...]
|
||||||
|
|
||||||
// Determine whether there is a file with that name in the include path.
|
|
||||||
guard let included_path = manager.firstExisting(FilePath.init("\(match.1)")) else {
|
|
||||||
return .Error(
|
|
||||||
Error(
|
|
||||||
withMessage:
|
|
||||||
"Could not open \(match.1) for inclusion"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to make a url from the configured file.
|
|
||||||
let included_url = URL.init(filePath: included_path.string)
|
|
||||||
|
|
||||||
// By calling ourselves recursively, the include being processed will
|
// By calling ourselves recursively, the include being processed will
|
||||||
// be _completely_ expanded (including any nested includes).
|
// be _completely_ expanded (including any nested includes).
|
||||||
switch do_preprocess(included_url, manager, starting + before.count) {
|
switch do_preprocess(FilePath("\(match.1)"), manager, starting + before.count) {
|
||||||
case .Ok((let location, let expanded)):
|
case .Ok((let location, let expanded)):
|
||||||
// Recombine what was before and after the include being processed
|
// Recombine what was before and after the include being processed
|
||||||
// with the expanded text.
|
// with the expanded text.
|
||||||
@@ -298,7 +297,7 @@ func do_preprocess(
|
|||||||
return .Ok(
|
return .Ok(
|
||||||
(
|
(
|
||||||
FileSourceLocation(
|
FileSourceLocation(
|
||||||
SourceLocation(starting..<(starting + contents.count)), FilePath(file.path()), locations),
|
SourceLocation(starting..<(starting + contents.count)), file, locations),
|
||||||
contents
|
contents
|
||||||
))
|
))
|
||||||
|
|
||||||
@@ -316,22 +315,7 @@ public struct SourceCodePreprocessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func preprocess(_ file: FilePath) -> Result<SourceCode> {
|
public func preprocess(_ file: FilePath) -> Result<SourceCode> {
|
||||||
// First, decide whether the given file exists at the path the user gave.
|
switch do_preprocess(file, self.manager) {
|
||||||
let fm = FileManager()
|
|
||||||
let file_to_open =
|
|
||||||
if !fm.fileExists(atPath: file.string) {
|
|
||||||
self.manager.firstExisting(file)
|
|
||||||
} else {
|
|
||||||
file
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let file_to_open else {
|
|
||||||
return .Error(Error(withMessage: "Could not open \(file) for preprocessing"))
|
|
||||||
}
|
|
||||||
|
|
||||||
let url = URL.init(filePath: file_to_open.string)
|
|
||||||
|
|
||||||
switch do_preprocess(url, self.manager) {
|
|
||||||
case .Ok((let location, let contents)):
|
case .Ok((let location, let contents)):
|
||||||
return .Ok(SourceCode(contents, self.manager, location))
|
return .Ok(SourceCode(contents, self.manager, location))
|
||||||
case .Error(let e): return .Error(e)
|
case .Error(let e): return .Error(e)
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
Error: In /Users/hawkinsw/code/p4ce/TestData/Sources/action-parameters-wrong-order.p4, there was an error:
|
Error: In action-parameters-wrong-order.p4, there was an error:
|
||||||
...ion a(inout bool aa, int ax, inout bool ay) {...
|
...ion a(inout bool aa, int ax, inout bool ay) {...
|
||||||
All parameters with direction must precede directionless parameters
|
All parameters with direction must precede directionless parameters
|
||||||
|
|||||||
@@ -31,57 +31,49 @@ import TreeSitterP4
|
|||||||
@Test func test_preprocessor() async throws {
|
@Test func test_preprocessor() async throws {
|
||||||
let sm = SourceManager(["./TestData/Sources/"])
|
let sm = SourceManager(["./TestData/Sources/"])
|
||||||
let prep = SourceCodePreprocessor(sm)
|
let prep = SourceCodePreprocessor(sm)
|
||||||
let file = FilePath.init(stringLiteral: "./TestData/Sources/simple.p4")
|
let file = FilePath.init(stringLiteral: "simple.p4")
|
||||||
let expected_file = FilePath.init(FileManager().currentDirectoryPath + "/" + file.string)
|
|
||||||
.lexicallyNormalized()
|
|
||||||
|
|
||||||
let source = try! (#UseOkResult(prep.preprocess(file)))
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
||||||
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
||||||
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
||||||
#expect(source.getLocations().getPath() == expected_file)
|
#expect(source.getLocations().getPath() == file)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func test_preprocessor_search_for_file() async throws {
|
@Test func test_preprocessor_search_for_file() async throws {
|
||||||
let sm = SourceManager(["./TestData/Sources/"])
|
let sm = SourceManager(["./TestData/Sources/"])
|
||||||
let prep = SourceCodePreprocessor(sm)
|
let prep = SourceCodePreprocessor(sm)
|
||||||
let file = FilePath.init(stringLiteral: "simple.p4")
|
let file = FilePath.init(stringLiteral: "simple.p4")
|
||||||
let expected_file = FilePath.init(
|
|
||||||
FileManager().currentDirectoryPath + "/TestData/Sources/simple.p4")
|
|
||||||
|
|
||||||
let source = try! (#UseOkResult(prep.preprocess(file)))
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
||||||
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
||||||
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
||||||
#expect(source.getLocations().getPath() == expected_file)
|
#expect(source.getLocations().getPath() == file)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func test_preprocessor_nested_includes() async throws {
|
@Test func test_preprocessor_nested_includes() async throws {
|
||||||
let sm = SourceManager(["./TestData/Sources/"])
|
let sm = SourceManager(["./TestData/Sources/"])
|
||||||
let prep = SourceCodePreprocessor(sm)
|
let prep = SourceCodePreprocessor(sm)
|
||||||
let file = FilePath.init(stringLiteral: "./TestData/Sources/simple-split.p4")
|
let file = FilePath.init(stringLiteral: "simple-split.p4")
|
||||||
let expected_file = FilePath.init(FileManager().currentDirectoryPath + "/" + file.string)
|
|
||||||
.lexicallyNormalized()
|
|
||||||
|
|
||||||
#expect(#RequireOkResult(prep.preprocess(file)))
|
#expect(#RequireOkResult(prep.preprocess(file)))
|
||||||
|
|
||||||
let source = try! (#UseOkResult(prep.preprocess(file)))
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
||||||
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
||||||
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
||||||
#expect(source.getLocations().getPath() == expected_file)
|
#expect(source.getLocations().getPath() == file)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func test_preprocessor_oneline_includes() async throws {
|
@Test func test_preprocessor_oneline_includes() async throws {
|
||||||
let sm = SourceManager(["./TestData/Sources/"])
|
let sm = SourceManager(["./TestData/Sources/"])
|
||||||
let prep = SourceCodePreprocessor(sm)
|
let prep = SourceCodePreprocessor(sm)
|
||||||
let file = FilePath.init(stringLiteral: "./TestData/Sources/simple-split-oneline.p4")
|
let file = FilePath.init(stringLiteral: "simple-split-oneline.p4")
|
||||||
let expected_file = FilePath.init(FileManager().currentDirectoryPath + "/" + file.string)
|
|
||||||
.lexicallyNormalized()
|
|
||||||
|
|
||||||
#expect(#RequireOkResult(prep.preprocess(file)))
|
#expect(#RequireOkResult(prep.preprocess(file)))
|
||||||
|
|
||||||
let source = try! (#UseOkResult(prep.preprocess(file)))
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
||||||
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
||||||
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
||||||
#expect(source.getLocations().getPath() == expected_file)
|
#expect(source.getLocations().getPath() == file)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func test_preprocessor_missing_file() async throws {
|
@Test func test_preprocessor_missing_file() async throws {
|
||||||
@@ -99,11 +91,11 @@ import TreeSitterP4
|
|||||||
@Test func test_preprocessor_missing_included_file() async throws {
|
@Test func test_preprocessor_missing_included_file() async throws {
|
||||||
let sm = SourceManager(["./TestData/Sources/"])
|
let sm = SourceManager(["./TestData/Sources/"])
|
||||||
let prep = SourceCodePreprocessor(sm)
|
let prep = SourceCodePreprocessor(sm)
|
||||||
let file = FilePath.init(stringLiteral: "./TestData/Sources/simple-unfound.p4")
|
let file = FilePath.init(stringLiteral: "simple-unfound.p4")
|
||||||
|
|
||||||
#expect(
|
#expect(
|
||||||
#RequireErrorResult(
|
#RequireErrorResult(
|
||||||
Error(withMessage: "Could not open unfound.p4 for inclusion"), (prep.preprocess(file))))
|
Error(withMessage: "Could not open unfound.p4 for preprocessing"), (prep.preprocess(file))))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +123,7 @@ import TreeSitterP4
|
|||||||
@Test func test_preprocessor_oneline_includes_locations() async throws {
|
@Test func test_preprocessor_oneline_includes_locations() async throws {
|
||||||
let sm = SourceManager(["./TestData/Sources/"])
|
let sm = SourceManager(["./TestData/Sources/"])
|
||||||
let prep = SourceCodePreprocessor(sm)
|
let prep = SourceCodePreprocessor(sm)
|
||||||
let file = FilePath.init(stringLiteral: "./TestData/Sources/simple-split-oneline.p4")
|
let file = FilePath.init(stringLiteral: "simple-split-oneline.p4")
|
||||||
|
|
||||||
#expect(#RequireOkResult(prep.preprocess(file)))
|
#expect(#RequireOkResult(prep.preprocess(file)))
|
||||||
|
|
||||||
@@ -145,7 +137,7 @@ import TreeSitterP4
|
|||||||
@Test func test_preprocessor_nested_includes_locations() async throws {
|
@Test func test_preprocessor_nested_includes_locations() async throws {
|
||||||
let sm = SourceManager(["./TestData/Sources/"])
|
let sm = SourceManager(["./TestData/Sources/"])
|
||||||
let prep = SourceCodePreprocessor(sm)
|
let prep = SourceCodePreprocessor(sm)
|
||||||
let file = FilePath.init(stringLiteral: "./TestData/Sources/nested-split.p4")
|
let file = FilePath.init(stringLiteral: "nested-split.p4")
|
||||||
|
|
||||||
#expect(#RequireOkResult(prep.preprocess(file)))
|
#expect(#RequireOkResult(prep.preprocess(file)))
|
||||||
|
|
||||||
@@ -163,7 +155,7 @@ import TreeSitterP4
|
|||||||
@Test func test_preprocessor_nested_includes_annotated_source() async throws {
|
@Test func test_preprocessor_nested_includes_annotated_source() async throws {
|
||||||
let sm = SourceManager(["./TestData/Sources/"])
|
let sm = SourceManager(["./TestData/Sources/"])
|
||||||
let prep = SourceCodePreprocessor(sm)
|
let prep = SourceCodePreprocessor(sm)
|
||||||
let file = FilePath.init(stringLiteral: "./TestData/Sources/annotate.p4")
|
let file = FilePath.init(stringLiteral: "annotate.p4")
|
||||||
|
|
||||||
let expected = """
|
let expected = """
|
||||||
<struct Testing {
|
<struct Testing {
|
||||||
@@ -192,15 +184,13 @@ import TreeSitterP4
|
|||||||
@Test func test_preprocessor_nested_includes_get_file_location() async throws {
|
@Test func test_preprocessor_nested_includes_get_file_location() async throws {
|
||||||
let sm = SourceManager(["./TestData/Sources/"], FileManager()) // Add a FileManager to get absolute paths.
|
let sm = SourceManager(["./TestData/Sources/"], FileManager()) // Add a FileManager to get absolute paths.
|
||||||
let prep = SourceCodePreprocessor(sm)
|
let prep = SourceCodePreprocessor(sm)
|
||||||
let file = FilePath.init(stringLiteral: "./TestData/Sources/file-loc.p4")
|
let file = FilePath.init(stringLiteral: "file-loc.p4")
|
||||||
|
|
||||||
let source = try! (#UseOkResult(prep.preprocess(file)))
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
||||||
|
|
||||||
let expected_file = FilePath.init(FileManager().currentDirectoryPath + "/" + file.string)
|
let expected_file = file
|
||||||
.lexicallyNormalized()
|
let expected_nested_file = FilePath(stringLiteral: "file-loc-parser.p4")
|
||||||
let expected_nested_file = sm.firstExisting("file-loc-parser.p4")!.lexicallyNormalized()
|
let expected_nested_nested_file = FilePath(stringLiteral: "file-loc-parser-state.p4")
|
||||||
let expected_nested_nested_file = sm.firstExisting("file-loc-parser-state.p4")!
|
|
||||||
.lexicallyNormalized()
|
|
||||||
|
|
||||||
let found_file = try! #require(source.pathForLocation(0))
|
let found_file = try! #require(source.pathForLocation(0))
|
||||||
let found_nested_file = try! #require(source.pathForLocation(55))
|
let found_nested_file = try! #require(source.pathForLocation(55))
|
||||||
|
|||||||
Reference in New Issue
Block a user