bc51b4e280
Can now support showing the trail of includes in an error message. Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
259 lines
8.6 KiB
Swift
259 lines
8.6 KiB
Swift
// p4rse, Copyright 2026, Will Hawkins
|
|
//
|
|
// This file is part of p4rse.
|
|
//
|
|
// This file is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
import Foundation
|
|
import Macros
|
|
import P4Compiler
|
|
import P4Lang
|
|
import P4Runtime
|
|
import SwiftTreeSitter
|
|
import SystemPackage
|
|
import Testing
|
|
import TreeSitter
|
|
import TreeSitterP4
|
|
|
|
@testable import Common
|
|
|
|
@Test func test_preprocessor() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "simple.p4")
|
|
|
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
|
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
|
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
|
#expect(source.getLocations().getPath() == file)
|
|
}
|
|
|
|
@Test func test_preprocessor_search_for_file() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "simple.p4")
|
|
|
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
|
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
|
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
|
#expect(source.getLocations().getPath() == file)
|
|
}
|
|
|
|
@Test func test_preprocessor_nested_includes() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "simple-split.p4")
|
|
|
|
#expect(#RequireOkResult(prep.preprocess(file)))
|
|
|
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
|
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
|
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
|
#expect(source.getLocations().getPath() == file)
|
|
}
|
|
|
|
@Test func test_preprocessor_oneline_includes() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "simple-split-oneline.p4")
|
|
|
|
#expect(#RequireOkResult(prep.preprocess(file)))
|
|
|
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
|
let program = try! #UseOkResult(Program.Compile(source.getSource()))
|
|
#expect(#RequireOkResult((program.find_parser(withName: Identifier(name: "main_parser")))))
|
|
#expect(source.getLocations().getPath() == file)
|
|
}
|
|
|
|
@Test func test_preprocessor_missing_file() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "./TestData/Sources/unfound.p4")
|
|
|
|
#expect(
|
|
#RequireErrorResult(
|
|
Error(withMessage: "Could not open ./TestData/Sources/unfound.p4 for preprocessing"),
|
|
(prep.preprocess(file))))
|
|
|
|
}
|
|
|
|
@Test func test_preprocessor_missing_included_file() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "simple-unfound.p4")
|
|
|
|
#expect(
|
|
#RequireErrorResult(
|
|
Error(withMessage: "Could not open unfound.p4 for preprocessing"), (prep.preprocess(file))))
|
|
|
|
}
|
|
|
|
@Test func test_preprocessor_no_change_locations() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "testing.p4")
|
|
|
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
|
|
|
#expect(source.getLocations().getLocation() == SourceLocation(0..<173))
|
|
}
|
|
|
|
@Test func test_preprocessor_change_locations() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "testing-split-a.p4")
|
|
|
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
|
|
|
#expect(source.getLocations().getLocation() == SourceLocation(0..<173))
|
|
#expect(source.getLocations().getNestedLocations()[0].getLocation() == SourceLocation(48..<173))
|
|
}
|
|
|
|
@Test func test_preprocessor_oneline_includes_locations() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "simple-split-oneline.p4")
|
|
|
|
#expect(#RequireOkResult(prep.preprocess(file)))
|
|
|
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
|
|
|
#expect(source.getLocations().getLocation() == SourceLocation(0..<173))
|
|
#expect(source.getLocations().getNestedLocations()[0].getLocation() == SourceLocation(0..<70))
|
|
#expect(source.getLocations().getNestedLocations()[1].getLocation() == SourceLocation(70..<173))
|
|
}
|
|
|
|
@Test func test_preprocessor_nested_includes_locations() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "nested-split.p4")
|
|
|
|
#expect(#RequireOkResult(prep.preprocess(file)))
|
|
|
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
|
|
|
#expect(source.getLocations().getLocation() == SourceLocation(0..<173))
|
|
/*
|
|
#expect(
|
|
source.getLocations().getNestedLocations()[0].getNestedLocations()[0].getLocation()
|
|
== SourceLocation(27..<47))
|
|
#expect(
|
|
source.getLocations().getNestedLocations()[0].getNestedLocations()[1].getLocation()
|
|
== SourceLocation(48..<166))
|
|
*/
|
|
}
|
|
|
|
@Test func test_preprocessor_nested_includes_annotated_source() async throws {
|
|
let sm = SourceManager(["./TestData/Sources/"])
|
|
let prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "annotate.p4")
|
|
|
|
let expected = """
|
|
<struct Testing {
|
|
< bool yesno;
|
|
int count;>
|
|
};
|
|
<parser main_parser() {
|
|
< state start {
|
|
Testing ts;
|
|
ts.yesno = true;
|
|
ts.count = 5;
|
|
transition select (ts.count == 5) {
|
|
true: accept;
|
|
false: reject;
|
|
};
|
|
}
|
|
>
|
|
}>>
|
|
"""
|
|
|
|
#expect(#RequireOkResult(prep.preprocess(file)))
|
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
|
#expect(source.getSource(annotated: true) == expected)
|
|
}
|
|
|
|
@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 prep = SourceCodePreprocessor(sm)
|
|
let file = FilePath.init(stringLiteral: "file-loc.p4")
|
|
|
|
let source = try! (#UseOkResult(prep.preprocess(file)))
|
|
|
|
let expected_file = file
|
|
let expected_nested_file = FilePath(stringLiteral: "file-loc-parser.p4")
|
|
let expected_nested_nested_file = FilePath(stringLiteral: "file-loc-parser-state.p4")
|
|
|
|
let found_nested_files = try! #require(source.pathForLocation(78))
|
|
|
|
#expect(found_nested_files[0].path == expected_file)
|
|
#expect(found_nested_files[1].path == expected_nested_file)
|
|
#expect(found_nested_files[2].path == expected_nested_nested_file)
|
|
}
|
|
|
|
@Test func test_source_location_contains() async throws {
|
|
let outer = SourceLocation(0..<500)
|
|
let inner = SourceLocation(0..<499)
|
|
|
|
#expect(outer.contains(inner))
|
|
}
|
|
|
|
@Test func test_source_location_contains_a() async throws {
|
|
let outer = SourceLocation(0, 500)
|
|
let inner = SourceLocation(0, 499)
|
|
|
|
#expect(outer.contains(inner))
|
|
}
|
|
|
|
@Test func test_source_location_contains2() async throws {
|
|
let outer = SourceLocation(0..<500)
|
|
let not_inner = SourceLocation(0..<501)
|
|
|
|
#expect(!outer.contains(not_inner))
|
|
}
|
|
|
|
@Test func test_source_location_contains2_a() async throws {
|
|
let outer = SourceLocation(0, 500)
|
|
let not_inner = SourceLocation(0, 501)
|
|
|
|
#expect(!outer.contains(not_inner))
|
|
}
|
|
|
|
@Test func test_source_location_contains3() async throws {
|
|
let outer = SourceLocation(200..<500)
|
|
let inner = SourceLocation(200..<499)
|
|
|
|
#expect(outer.contains(inner))
|
|
}
|
|
|
|
@Test func test_source_location_contains3_a() async throws {
|
|
let outer = SourceLocation(200, 300)
|
|
let inner = SourceLocation(200, 299)
|
|
|
|
#expect(outer.contains(inner))
|
|
}
|
|
|
|
@Test func test_source_location_contains4() async throws {
|
|
let outer = SourceLocation(200..<500)
|
|
let inner = SourceLocation(200, 299)
|
|
|
|
#expect(outer.contains(inner))
|
|
}
|
|
|
|
@Test func test_source_location_contains5() async throws {
|
|
let outer = SourceLocation(200..<300)
|
|
let not_inner = SourceLocation(200, 101)
|
|
|
|
#expect(!outer.contains(not_inner))
|
|
}
|