implements PR-05.0.5
This commit is contained in:
parent
19f293d8ea
commit
9aac65a2e9
@ -5,36 +5,50 @@ import p.studio.compiler.pbs.lexer.PbsLexer;
|
|||||||
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.tables.FileTable;
|
||||||
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.compiler.source.identifiers.ProjectId;
|
||||||
|
import p.studio.compiler.models.SourceHandle;
|
||||||
import p.studio.utilities.structures.ReadOnlyList;
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
public final class InterfaceModuleLoader {
|
public final class InterfaceModuleLoader {
|
||||||
private final AtomicInteger nextSyntheticFileId;
|
|
||||||
|
|
||||||
public InterfaceModuleLoader() {
|
public InterfaceModuleLoader() {
|
||||||
this(1_000_000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public InterfaceModuleLoader(final int firstSyntheticFileId) {
|
public InterfaceModuleLoader(final int ignoredSyntheticSeed) {
|
||||||
this.nextSyntheticFileId = new AtomicInteger(firstSyntheticFileId);
|
this();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PbsModuleVisibilityValidator.ModuleUnit load(
|
public PbsModuleVisibilityValidator.ModuleUnit load(
|
||||||
final StdlibModuleSource moduleSource,
|
final StdlibModuleSource moduleSource,
|
||||||
|
final ProjectId syntheticOwnerProjectId,
|
||||||
|
final FileTable fileTable,
|
||||||
final DiagnosticSink diagnostics) {
|
final DiagnosticSink diagnostics) {
|
||||||
final var sources = new ArrayList<PbsModuleVisibilityValidator.SourceFile>(moduleSource.sourceFiles().size());
|
final var sources = new ArrayList<PbsModuleVisibilityValidator.SourceFile>(moduleSource.sourceFiles().size());
|
||||||
for (final var sourceFile : moduleSource.sourceFiles()) {
|
for (int i = 0; i < moduleSource.sourceFiles().size(); i++) {
|
||||||
final var fileId = new FileId(nextSyntheticFileId.getAndIncrement());
|
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);
|
final var sourceAst = parseSource(sourceFile.source(), fileId, diagnostics);
|
||||||
sources.add(new PbsModuleVisibilityValidator.SourceFile(fileId, sourceAst));
|
sources.add(new PbsModuleVisibilityValidator.SourceFile(fileId, sourceAst));
|
||||||
}
|
}
|
||||||
|
|
||||||
final var barrels = new ArrayList<PbsModuleVisibilityValidator.BarrelFile>(1);
|
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);
|
final var barrelAst = parseBarrel(moduleSource.barrelSource(), barrelFileId, diagnostics);
|
||||||
barrels.add(new PbsModuleVisibilityValidator.BarrelFile(barrelFileId, barrelAst));
|
barrels.add(new PbsModuleVisibilityValidator.BarrelFile(barrelFileId, barrelAst));
|
||||||
|
|
||||||
@ -44,6 +58,34 @@ public final class InterfaceModuleLoader {
|
|||||||
ReadOnlyList.wrap(barrels));
|
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(
|
private PbsAst.File parseSource(
|
||||||
final String source,
|
final String source,
|
||||||
final FileId fileId,
|
final FileId fileId,
|
||||||
|
|||||||
@ -22,6 +22,8 @@ import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
|||||||
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
|
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
|
||||||
import p.studio.compiler.source.identifiers.FileId;
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
import p.studio.compiler.source.identifiers.ModuleId;
|
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.ModuleReference;
|
||||||
import p.studio.compiler.source.tables.ModuleTable;
|
import p.studio.compiler.source.tables.ModuleTable;
|
||||||
import p.studio.utilities.structures.ReadOnlyList;
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
@ -62,17 +64,25 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
final LogAggregator logs,
|
final LogAggregator logs,
|
||||||
final BuildingIssueSink issues) {
|
final BuildingIssueSink issues) {
|
||||||
final var nameTable = ctx.nameTable();
|
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 irBackendAggregator = IRBackend.aggregator();
|
||||||
final var parsedSourceFiles = new ArrayList<ParsedSourceFile>();
|
final var parsedSourceFiles = new ArrayList<ParsedSourceFile>();
|
||||||
final Map<PbsModuleVisibilityValidator.ModuleCoordinates, MutableModuleUnit> modulesByCoordinates = new LinkedHashMap<>();
|
final Map<PbsModuleVisibilityValidator.ModuleCoordinates, MutableModuleUnit> modulesByCoordinates = new LinkedHashMap<>();
|
||||||
final var moduleTable = new ModuleTable();
|
final var moduleTable = new ModuleTable();
|
||||||
final var moduleIdByFile = new HashMap<FileId, ModuleId>();
|
final var moduleIdByFile = new HashMap<FileId, ModuleId>();
|
||||||
final var failedModuleIds = new HashSet<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) {
|
for (final var pId : ctx.stack.reverseTopologicalOrder) {
|
||||||
final var projectDescriptor = ctx.projectTable.get(pId);
|
final var projectDescriptor = ctx.projectTable.get(pId);
|
||||||
final var projectSourceKind = ctx.sourceKind(pId);
|
final var projectSourceKind = ctx.sourceKind(pId);
|
||||||
final var fileIds = ctx.fileTable.getFiles(pId);
|
final var fileIds = ctx.fileTable.getFiles(pId);
|
||||||
|
projectIdByName.putIfAbsent(projectDescriptor.getName(), pId);
|
||||||
|
|
||||||
for (final var fId : fileIds) {
|
for (final var fId : fileIds) {
|
||||||
final var sourceHandle = ctx.fileTable.get(fId);
|
final var sourceHandle = ctx.fileTable.get(fId);
|
||||||
@ -126,6 +136,9 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
parsedSourceFiles,
|
parsedSourceFiles,
|
||||||
moduleIdByFile,
|
moduleIdByFile,
|
||||||
moduleTable,
|
moduleTable,
|
||||||
|
writableFileTable,
|
||||||
|
projectIdByName,
|
||||||
|
defaultSyntheticOwnerProjectId,
|
||||||
diagnostics,
|
diagnostics,
|
||||||
ctx.stdlibVersion());
|
ctx.stdlibVersion());
|
||||||
|
|
||||||
@ -181,6 +194,9 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
final ArrayList<ParsedSourceFile> parsedSourceFiles,
|
final ArrayList<ParsedSourceFile> parsedSourceFiles,
|
||||||
final Map<FileId, ModuleId> moduleIdByFile,
|
final Map<FileId, ModuleId> moduleIdByFile,
|
||||||
final ModuleTable moduleTable,
|
final ModuleTable moduleTable,
|
||||||
|
final FileTable fileTable,
|
||||||
|
final Map<String, ProjectId> projectIdByName,
|
||||||
|
final ProjectId defaultSyntheticOwnerProjectId,
|
||||||
final DiagnosticSink diagnostics,
|
final DiagnosticSink diagnostics,
|
||||||
final int stdlibVersion) {
|
final int stdlibVersion) {
|
||||||
final var stdlibEnvironment = stdlibEnvironmentResolver.resolve(stdlibVersion);
|
final var stdlibEnvironment = stdlibEnvironmentResolver.resolve(stdlibVersion);
|
||||||
@ -203,7 +219,15 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
continue;
|
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();
|
final var moduleData = new MutableModuleUnit();
|
||||||
moduleData.sources.addAll(loadedModule.sourceFiles().asList());
|
moduleData.sources.addAll(loadedModule.sourceFiles().asList());
|
||||||
moduleData.barrels.addAll(loadedModule.barrelFiles().asList());
|
moduleData.barrels.addAll(loadedModule.barrelFiles().asList());
|
||||||
|
|||||||
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user