implements PR006.1
This commit is contained in:
parent
f60346e174
commit
0cf2e3e099
@ -2,6 +2,7 @@ package p.studio.compiler.pbs.linking;
|
||||
|
||||
public enum PbsLinkErrors {
|
||||
E_LINK_MISSING_BARREL,
|
||||
E_LINK_INVALID_BARREL_FILENAME,
|
||||
E_LINK_DUPLICATE_BARREL_FILE,
|
||||
E_LINK_DUPLICATE_BARREL_ENTRY,
|
||||
E_LINK_UNRESOLVED_BARREL_ENTRY,
|
||||
|
||||
@ -215,6 +215,7 @@ public final class PbsModuleVisibilityValidator {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO(pbs-interface-modules): include top-level host declarations when interface-module mode is added.
|
||||
if (topDecl instanceof PbsAst.StructDecl structDecl) {
|
||||
registerNonFunctionDeclaration(declarations, NonFunctionKind.STRUCT, structDecl.name(), structDecl.span(), nameTable);
|
||||
} else if (topDecl instanceof PbsAst.ContractDecl contractDecl) {
|
||||
|
||||
@ -9,14 +9,17 @@ import p.studio.compiler.models.SourceHandle;
|
||||
import p.studio.compiler.pbs.PbsFrontendCompiler;
|
||||
import p.studio.compiler.pbs.ast.PbsAst;
|
||||
import p.studio.compiler.pbs.lexer.PbsLexer;
|
||||
import p.studio.compiler.pbs.linking.PbsLinkErrors;
|
||||
import p.studio.compiler.pbs.linking.PbsModuleVisibilityValidator;
|
||||
import p.studio.compiler.pbs.parser.PbsBarrelParser;
|
||||
import p.studio.compiler.pbs.parser.PbsParser;
|
||||
import p.studio.compiler.source.Span;
|
||||
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||
import p.studio.compiler.source.identifiers.FileId;
|
||||
import p.studio.utilities.structures.ReadOnlyList;
|
||||
import p.studio.utilities.logs.LogAggregator;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -59,6 +62,11 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
||||
if ("mod.barrel".equals(sourceHandle.getFilename())) {
|
||||
final var barrelAst = parseBarrelFile(fId, utf8Content, diagnostics);
|
||||
moduleUnit.barrels.add(new PbsModuleVisibilityValidator.BarrelFile(fId, barrelAst));
|
||||
} else {
|
||||
diagnostics.error(
|
||||
PbsLinkErrors.E_LINK_INVALID_BARREL_FILENAME.name(),
|
||||
"Only 'mod.barrel' is allowed as barrel filename",
|
||||
new Span(fId, 0, utf8Content.getBytes(StandardCharsets.UTF_8).length));
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
|
||||
@ -26,7 +26,7 @@ class PbsModuleVisibilityTest {
|
||||
"""
|
||||
fn sum(a: int, b: int) -> int { return a + b; }
|
||||
"""
|
||||
), null, nextFileId, diagnostics);
|
||||
), (String) null, nextFileId, diagnostics);
|
||||
|
||||
new PbsModuleVisibilityValidator().validate(ReadOnlyList.wrap(List.of(module)), diagnostics);
|
||||
|
||||
@ -57,6 +57,31 @@ class PbsModuleVisibilityTest {
|
||||
assertEquals(2, duplicateCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReportDuplicateBarrelFiles() {
|
||||
final var diagnostics = DiagnosticSink.empty();
|
||||
final var nextFileId = new AtomicInteger(0);
|
||||
final var module = module("core", "math", List.of(
|
||||
"""
|
||||
fn run() -> int { return 1; }
|
||||
"""
|
||||
), List.of(
|
||||
"""
|
||||
pub fn run() -> int;
|
||||
""",
|
||||
"""
|
||||
pub fn run() -> int;
|
||||
"""
|
||||
), nextFileId, diagnostics);
|
||||
|
||||
new PbsModuleVisibilityValidator().validate(ReadOnlyList.wrap(List.of(module)), diagnostics);
|
||||
|
||||
final long duplicateBarrelCount = diagnostics.stream()
|
||||
.filter(d -> d.getCode().equals(PbsLinkErrors.E_LINK_DUPLICATE_BARREL_FILE.name()))
|
||||
.count();
|
||||
assertEquals(1, duplicateBarrelCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReportUnresolvedBarrelEntries() {
|
||||
final var diagnostics = DiagnosticSink.empty();
|
||||
@ -111,6 +136,24 @@ class PbsModuleVisibilityTest {
|
||||
assertTrue(importVisibilityDiagnostics.getFirst().getMessage().contains("secret"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveBarrelFunctionWithResultReturnSurface() {
|
||||
final var diagnostics = DiagnosticSink.empty();
|
||||
final var nextFileId = new AtomicInteger(0);
|
||||
final var module = module("core", "math", List.of(
|
||||
"""
|
||||
fn run(input: int) -> result<Err> (left: int, right: int) { return input; }
|
||||
"""
|
||||
), """
|
||||
pub fn run(v: int) -> result<Err> (a: int, b: int);
|
||||
""", nextFileId, diagnostics);
|
||||
|
||||
new PbsModuleVisibilityValidator().validate(ReadOnlyList.wrap(List.of(module)), diagnostics);
|
||||
|
||||
assertTrue(diagnostics.stream().noneMatch(d ->
|
||||
d.getCode().equals(PbsLinkErrors.E_LINK_UNRESOLVED_BARREL_ENTRY.name())));
|
||||
}
|
||||
|
||||
private PbsModuleVisibilityValidator.ModuleUnit module(
|
||||
final String project,
|
||||
final String modulePath,
|
||||
@ -118,6 +161,16 @@ class PbsModuleVisibilityTest {
|
||||
final String barrelContent,
|
||||
final AtomicInteger nextFileId,
|
||||
final DiagnosticSink diagnostics) {
|
||||
return module(project, modulePath, sourceContents, barrelContent == null ? List.of() : List.of(barrelContent), nextFileId, diagnostics);
|
||||
}
|
||||
|
||||
private PbsModuleVisibilityValidator.ModuleUnit module(
|
||||
final String project,
|
||||
final String modulePath,
|
||||
final List<String> sourceContents,
|
||||
final List<String> barrelContents,
|
||||
final AtomicInteger nextFileId,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final var sources = new ArrayList<PbsModuleVisibilityValidator.SourceFile>();
|
||||
for (final var sourceContent : sourceContents) {
|
||||
final var fileId = new FileId(nextFileId.getAndIncrement());
|
||||
@ -126,7 +179,7 @@ class PbsModuleVisibilityTest {
|
||||
}
|
||||
|
||||
final var barrels = new ArrayList<PbsModuleVisibilityValidator.BarrelFile>();
|
||||
if (barrelContent != null) {
|
||||
for (final var barrelContent : barrelContents) {
|
||||
final var fileId = new FileId(nextFileId.getAndIncrement());
|
||||
final var barrelAst = parseBarrel(barrelContent, fileId, diagnostics);
|
||||
barrels.add(new PbsModuleVisibilityValidator.BarrelFile(fileId, barrelAst));
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
package p.studio.compiler.services;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import p.studio.compiler.messages.BuildingIssueSink;
|
||||
import p.studio.compiler.messages.FrontendPhaseContext;
|
||||
import p.studio.compiler.models.BuildStack;
|
||||
import p.studio.compiler.models.ProjectDescriptor;
|
||||
import p.studio.compiler.models.SourceHandle;
|
||||
import p.studio.compiler.pbs.linking.PbsLinkErrors;
|
||||
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||
import p.studio.compiler.source.tables.FileTable;
|
||||
import p.studio.compiler.source.tables.ProjectTable;
|
||||
import p.studio.compiler.utilities.SourceProviderFactory;
|
||||
import p.studio.utilities.logs.LogAggregator;
|
||||
import p.studio.utilities.structures.ReadOnlyList;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class PBSFrontendPhaseServiceTest {
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
|
||||
@Test
|
||||
void shouldReportInvalidBarrelFilename() throws IOException {
|
||||
final var projectRoot = tempDir.resolve("project");
|
||||
final var sourceRoot = projectRoot.resolve("src");
|
||||
final var modulePath = sourceRoot.resolve("math");
|
||||
Files.createDirectories(modulePath);
|
||||
|
||||
final var sourceFile = modulePath.resolve("source.pbs");
|
||||
final var modBarrel = modulePath.resolve("mod.barrel");
|
||||
final var invalidBarrel = modulePath.resolve("extra.barrel");
|
||||
Files.writeString(sourceFile, "fn run() -> int { return 1; }");
|
||||
Files.writeString(modBarrel, "pub fn run() -> int;");
|
||||
Files.writeString(invalidBarrel, "pub fn run() -> int;");
|
||||
|
||||
final var projectTable = new ProjectTable();
|
||||
final var fileTable = new FileTable(1);
|
||||
final var projectId = projectTable.register(ProjectDescriptor.builder()
|
||||
.rootPath(projectRoot)
|
||||
.name("core")
|
||||
.version("1.0.0")
|
||||
.sourceRoots(ReadOnlyList.wrap(List.of(sourceRoot)))
|
||||
.build());
|
||||
|
||||
registerFile(projectId, projectRoot, sourceFile, fileTable);
|
||||
registerFile(projectId, projectRoot, modBarrel, fileTable);
|
||||
registerFile(projectId, projectRoot, invalidBarrel, fileTable);
|
||||
|
||||
final var ctx = new FrontendPhaseContext(
|
||||
projectTable,
|
||||
fileTable,
|
||||
new BuildStack(ReadOnlyList.wrap(List.of(projectId))));
|
||||
final var diagnostics = DiagnosticSink.empty();
|
||||
|
||||
new PBSFrontendPhaseService().compile(
|
||||
ctx,
|
||||
diagnostics,
|
||||
LogAggregator.empty(),
|
||||
BuildingIssueSink.empty());
|
||||
|
||||
assertTrue(diagnostics.stream().anyMatch(d -> d.getCode().equals(PbsLinkErrors.E_LINK_INVALID_BARREL_FILENAME.name())));
|
||||
}
|
||||
|
||||
private void registerFile(
|
||||
final p.studio.compiler.source.identifiers.ProjectId projectId,
|
||||
final Path projectRoot,
|
||||
final Path file,
|
||||
final FileTable fileTable) throws IOException {
|
||||
final BasicFileAttributes attributes = Files.readAttributes(file, BasicFileAttributes.class);
|
||||
fileTable.register(new SourceHandle(
|
||||
projectId,
|
||||
projectRoot.relativize(file),
|
||||
file,
|
||||
attributes.size(),
|
||||
attributes.lastModifiedTime().toMillis(),
|
||||
SourceProviderFactory.filesystem()));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user