implements PR-05.0.5

This commit is contained in:
bQUARKz 2026-03-09 06:38:57 +00:00
parent 19f293d8ea
commit 9aac65a2e9
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
3 changed files with 129 additions and 10 deletions

View File

@ -5,36 +5,50 @@ import p.studio.compiler.pbs.lexer.PbsLexer;
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.tables.FileTable;
import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.ProjectId;
import p.studio.compiler.models.SourceHandle;
import p.studio.utilities.structures.ReadOnlyList;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
public final class InterfaceModuleLoader {
private final AtomicInteger nextSyntheticFileId;
public InterfaceModuleLoader() {
this(1_000_000);
}
public InterfaceModuleLoader(final int firstSyntheticFileId) {
this.nextSyntheticFileId = new AtomicInteger(firstSyntheticFileId);
public InterfaceModuleLoader(final int ignoredSyntheticSeed) {
this();
}
public PbsModuleVisibilityValidator.ModuleUnit load(
final StdlibModuleSource moduleSource,
final ProjectId syntheticOwnerProjectId,
final FileTable fileTable,
final DiagnosticSink diagnostics) {
final var sources = new ArrayList<PbsModuleVisibilityValidator.SourceFile>(moduleSource.sourceFiles().size());
for (final var sourceFile : moduleSource.sourceFiles()) {
final var fileId = new FileId(nextSyntheticFileId.getAndIncrement());
for (int i = 0; i < moduleSource.sourceFiles().size(); i++) {
final var sourceFile = moduleSource.sourceFiles().get(i);
final var fileId = registerSyntheticFile(
syntheticOwnerProjectId,
moduleSource,
sourceFile.logicalPath(),
sourceFile.source(),
fileTable);
final var sourceAst = parseSource(sourceFile.source(), fileId, diagnostics);
sources.add(new PbsModuleVisibilityValidator.SourceFile(fileId, sourceAst));
}
final var barrels = new ArrayList<PbsModuleVisibilityValidator.BarrelFile>(1);
final var barrelFileId = new FileId(nextSyntheticFileId.getAndIncrement());
final var barrelFileId = registerSyntheticFile(
syntheticOwnerProjectId,
moduleSource,
"mod.barrel",
moduleSource.barrelSource(),
fileTable);
final var barrelAst = parseBarrel(moduleSource.barrelSource(), barrelFileId, diagnostics);
barrels.add(new PbsModuleVisibilityValidator.BarrelFile(barrelFileId, barrelAst));
@ -44,6 +58,34 @@ public final class InterfaceModuleLoader {
ReadOnlyList.wrap(barrels));
}
private FileId registerSyntheticFile(
final ProjectId syntheticOwnerProjectId,
final StdlibModuleSource moduleSource,
final String logicalPath,
final String source,
final FileTable fileTable) {
final var normalizedLogicalPath = (logicalPath == null || logicalPath.isBlank())
? "source.pbs"
: logicalPath;
final var relativePath = Path.of("@stdlib")
.resolve(moduleSource.project())
.resolve(String.join("/", moduleSource.pathSegments().asList()))
.resolve(normalizedLogicalPath);
final var canonPath = Path.of("/virtual/stdlib")
.resolve(moduleSource.project())
.resolve(String.join("/", moduleSource.pathSegments().asList()))
.resolve(normalizedLogicalPath);
final var utf8 = source == null ? new byte[0] : source.getBytes(StandardCharsets.UTF_8);
final var sourceHandle = new SourceHandle(
syntheticOwnerProjectId,
relativePath,
canonPath,
utf8.length,
0,
ignored -> () -> utf8);
return fileTable.register(sourceHandle);
}
private PbsAst.File parseSource(
final String source,
final FileId fileId,

View File

@ -22,6 +22,8 @@ import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.ModuleId;
import p.studio.compiler.source.identifiers.ProjectId;
import p.studio.compiler.source.tables.FileTable;
import p.studio.compiler.source.tables.ModuleReference;
import p.studio.compiler.source.tables.ModuleTable;
import p.studio.utilities.structures.ReadOnlyList;
@ -62,17 +64,25 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
final LogAggregator logs,
final BuildingIssueSink issues) {
final var nameTable = ctx.nameTable();
if (!(ctx.fileTable instanceof FileTable writableFileTable)) {
throw new IllegalStateException("PBS frontend requires writable FileTable for synthetic stdlib sources");
}
final var irBackendAggregator = IRBackend.aggregator();
final var parsedSourceFiles = new ArrayList<ParsedSourceFile>();
final Map<PbsModuleVisibilityValidator.ModuleCoordinates, MutableModuleUnit> modulesByCoordinates = new LinkedHashMap<>();
final var moduleTable = new ModuleTable();
final var moduleIdByFile = new HashMap<FileId, ModuleId>();
final var failedModuleIds = new HashSet<ModuleId>();
final var projectIdByName = new HashMap<String, ProjectId>();
final var defaultSyntheticOwnerProjectId = ctx.stack.reverseTopologicalOrder.isEmpty()
? null
: ctx.stack.reverseTopologicalOrder.getFirst();
for (final var pId : ctx.stack.reverseTopologicalOrder) {
final var projectDescriptor = ctx.projectTable.get(pId);
final var projectSourceKind = ctx.sourceKind(pId);
final var fileIds = ctx.fileTable.getFiles(pId);
projectIdByName.putIfAbsent(projectDescriptor.getName(), pId);
for (final var fId : fileIds) {
final var sourceHandle = ctx.fileTable.get(fId);
@ -126,6 +136,9 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
parsedSourceFiles,
moduleIdByFile,
moduleTable,
writableFileTable,
projectIdByName,
defaultSyntheticOwnerProjectId,
diagnostics,
ctx.stdlibVersion());
@ -181,6 +194,9 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
final ArrayList<ParsedSourceFile> parsedSourceFiles,
final Map<FileId, ModuleId> moduleIdByFile,
final ModuleTable moduleTable,
final FileTable fileTable,
final Map<String, ProjectId> projectIdByName,
final ProjectId defaultSyntheticOwnerProjectId,
final DiagnosticSink diagnostics,
final int stdlibVersion) {
final var stdlibEnvironment = stdlibEnvironmentResolver.resolve(stdlibVersion);
@ -203,7 +219,15 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
continue;
}
final var loadedModule = interfaceModuleLoader.load(moduleSource.get(), diagnostics);
final var syntheticOwnerProjectId = projectIdByName.getOrDefault(target.project(), defaultSyntheticOwnerProjectId);
if (syntheticOwnerProjectId == null) {
continue;
}
final var loadedModule = interfaceModuleLoader.load(
moduleSource.get(),
syntheticOwnerProjectId,
fileTable,
diagnostics);
final var moduleData = new MutableModuleUnit();
moduleData.sources.addAll(loadedModule.sourceFiles().asList());
moduleData.barrels.addAll(loadedModule.barrelFiles().asList());

View File

@ -0,0 +1,53 @@
package p.studio.compiler.pbs.stdlib;
import org.junit.jupiter.api.Test;
import p.studio.compiler.models.ProjectDescriptor;
import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.compiler.source.tables.FileTable;
import p.studio.compiler.source.tables.ProjectTable;
import p.studio.utilities.structures.ReadOnlyList;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class InterfaceModuleLoaderTest {
@Test
void shouldRegisterSyntheticStdlibFilesInFileTable() {
final var projectTable = new ProjectTable();
final var projectId = projectTable.register(ProjectDescriptor.builder()
.name("app")
.version("1.0.0")
.rootPath(Path.of("/tmp/app"))
.sourceRoots(ReadOnlyList.wrap(java.util.List.of(Path.of("/tmp/app/src"))))
.build());
final var fileTable = new FileTable(1);
final var diagnostics = DiagnosticSink.empty();
final var moduleSource = new StdlibModuleSource(
"sdk",
ReadOnlyList.wrap(java.util.List.of("gfx")),
ReadOnlyList.wrap(java.util.List.of(new StdlibModuleSource.SourceFile(
"source.pbs",
"declare host Gfx { fn draw() -> void; }"))),
"pub host Gfx;");
final var module = new InterfaceModuleLoader().load(moduleSource, projectId, fileTable, diagnostics);
assertTrue(diagnostics.isEmpty());
assertEquals(1, module.sourceFiles().size());
assertEquals(1, module.barrelFiles().size());
assertFalse(module.sourceFiles().getFirst().fileId().isNone());
assertFalse(module.barrelFiles().getFirst().fileId().isNone());
assertTrue(fileTable.get(module.sourceFiles().getFirst().fileId()).readUtf8().isPresent());
assertTrue(fileTable.get(module.barrelFiles().getFirst().fileId()).readUtf8().isPresent());
assertEquals(
"declare host Gfx { fn draw() -> void; }",
fileTable.get(module.sourceFiles().getFirst().fileId()).readUtf8().orElseThrow());
assertEquals(
"pub host Gfx;",
fileTable.get(module.barrelFiles().getFirst().fileId()).readUtf8().orElseThrow());
}
}