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 {
|
public enum PbsLinkErrors {
|
||||||
E_LINK_MISSING_BARREL,
|
E_LINK_MISSING_BARREL,
|
||||||
|
E_LINK_INVALID_BARREL_FILENAME,
|
||||||
E_LINK_DUPLICATE_BARREL_FILE,
|
E_LINK_DUPLICATE_BARREL_FILE,
|
||||||
E_LINK_DUPLICATE_BARREL_ENTRY,
|
E_LINK_DUPLICATE_BARREL_ENTRY,
|
||||||
E_LINK_UNRESOLVED_BARREL_ENTRY,
|
E_LINK_UNRESOLVED_BARREL_ENTRY,
|
||||||
|
|||||||
@ -215,6 +215,7 @@ public final class PbsModuleVisibilityValidator {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(pbs-interface-modules): include top-level host declarations when interface-module mode is added.
|
||||||
if (topDecl instanceof PbsAst.StructDecl structDecl) {
|
if (topDecl instanceof PbsAst.StructDecl structDecl) {
|
||||||
registerNonFunctionDeclaration(declarations, NonFunctionKind.STRUCT, structDecl.name(), structDecl.span(), nameTable);
|
registerNonFunctionDeclaration(declarations, NonFunctionKind.STRUCT, structDecl.name(), structDecl.span(), nameTable);
|
||||||
} else if (topDecl instanceof PbsAst.ContractDecl contractDecl) {
|
} 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.PbsFrontendCompiler;
|
||||||
import p.studio.compiler.pbs.ast.PbsAst;
|
import p.studio.compiler.pbs.ast.PbsAst;
|
||||||
import p.studio.compiler.pbs.lexer.PbsLexer;
|
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.linking.PbsModuleVisibilityValidator;
|
||||||
import p.studio.compiler.pbs.parser.PbsBarrelParser;
|
import p.studio.compiler.pbs.parser.PbsBarrelParser;
|
||||||
import p.studio.compiler.pbs.parser.PbsParser;
|
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.diagnostics.DiagnosticSink;
|
||||||
import p.studio.compiler.source.identifiers.FileId;
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
import p.studio.utilities.structures.ReadOnlyList;
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
import p.studio.utilities.logs.LogAggregator;
|
import p.studio.utilities.logs.LogAggregator;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@ -59,6 +62,11 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
if ("mod.barrel".equals(sourceHandle.getFilename())) {
|
if ("mod.barrel".equals(sourceHandle.getFilename())) {
|
||||||
final var barrelAst = parseBarrelFile(fId, utf8Content, diagnostics);
|
final var barrelAst = parseBarrelFile(fId, utf8Content, diagnostics);
|
||||||
moduleUnit.barrels.add(new PbsModuleVisibilityValidator.BarrelFile(fId, barrelAst));
|
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 -> {
|
default -> {
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class PbsModuleVisibilityTest {
|
|||||||
"""
|
"""
|
||||||
fn sum(a: int, b: int) -> int { return a + b; }
|
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);
|
new PbsModuleVisibilityValidator().validate(ReadOnlyList.wrap(List.of(module)), diagnostics);
|
||||||
|
|
||||||
@ -57,6 +57,31 @@ class PbsModuleVisibilityTest {
|
|||||||
assertEquals(2, duplicateCount);
|
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
|
@Test
|
||||||
void shouldReportUnresolvedBarrelEntries() {
|
void shouldReportUnresolvedBarrelEntries() {
|
||||||
final var diagnostics = DiagnosticSink.empty();
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
@ -111,6 +136,24 @@ class PbsModuleVisibilityTest {
|
|||||||
assertTrue(importVisibilityDiagnostics.getFirst().getMessage().contains("secret"));
|
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(
|
private PbsModuleVisibilityValidator.ModuleUnit module(
|
||||||
final String project,
|
final String project,
|
||||||
final String modulePath,
|
final String modulePath,
|
||||||
@ -118,6 +161,16 @@ class PbsModuleVisibilityTest {
|
|||||||
final String barrelContent,
|
final String barrelContent,
|
||||||
final AtomicInteger nextFileId,
|
final AtomicInteger nextFileId,
|
||||||
final DiagnosticSink diagnostics) {
|
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>();
|
final var sources = new ArrayList<PbsModuleVisibilityValidator.SourceFile>();
|
||||||
for (final var sourceContent : sourceContents) {
|
for (final var sourceContent : sourceContents) {
|
||||||
final var fileId = new FileId(nextFileId.getAndIncrement());
|
final var fileId = new FileId(nextFileId.getAndIncrement());
|
||||||
@ -126,7 +179,7 @@ class PbsModuleVisibilityTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final var barrels = new ArrayList<PbsModuleVisibilityValidator.BarrelFile>();
|
final var barrels = new ArrayList<PbsModuleVisibilityValidator.BarrelFile>();
|
||||||
if (barrelContent != null) {
|
for (final var barrelContent : barrelContents) {
|
||||||
final var fileId = new FileId(nextFileId.getAndIncrement());
|
final var fileId = new FileId(nextFileId.getAndIncrement());
|
||||||
final var barrelAst = parseBarrel(barrelContent, fileId, diagnostics);
|
final var barrelAst = parseBarrel(barrelContent, fileId, diagnostics);
|
||||||
barrels.add(new PbsModuleVisibilityValidator.BarrelFile(fileId, barrelAst));
|
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