implements PR023
This commit is contained in:
parent
213c6a2f76
commit
57f1a617ac
@ -0,0 +1,22 @@
|
|||||||
|
package p.studio.compiler.pbs.stdlib;
|
||||||
|
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public final class EmptyStdlibEnvironmentResolver implements StdlibEnvironmentResolver {
|
||||||
|
private static final StdlibEnvironment EMPTY = new StdlibEnvironment() {
|
||||||
|
@Override
|
||||||
|
public Optional<StdlibModuleSource> resolveModule(
|
||||||
|
final String project,
|
||||||
|
final ReadOnlyList<String> pathSegments) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StdlibEnvironment resolve(final int stdlibVersion) {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
package p.studio.compiler.pbs.stdlib;
|
||||||
|
|
||||||
|
import p.studio.compiler.pbs.ast.PbsAst;
|
||||||
|
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.diagnostics.DiagnosticSink;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
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 PbsModuleVisibilityValidator.ModuleUnit load(
|
||||||
|
final StdlibModuleSource moduleSource,
|
||||||
|
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());
|
||||||
|
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 barrelAst = parseBarrel(moduleSource.barrelSource(), barrelFileId, diagnostics);
|
||||||
|
barrels.add(new PbsModuleVisibilityValidator.BarrelFile(barrelFileId, barrelAst));
|
||||||
|
|
||||||
|
return new PbsModuleVisibilityValidator.ModuleUnit(
|
||||||
|
new PbsModuleVisibilityValidator.ModuleCoordinates(moduleSource.project(), moduleSource.pathSegments()),
|
||||||
|
ReadOnlyList.wrap(sources),
|
||||||
|
ReadOnlyList.wrap(barrels));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PbsAst.File parseSource(
|
||||||
|
final String source,
|
||||||
|
final FileId fileId,
|
||||||
|
final DiagnosticSink diagnostics) {
|
||||||
|
final var tokens = PbsLexer.lex(source, fileId, diagnostics);
|
||||||
|
return PbsParser.parse(tokens, fileId, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PbsAst.BarrelFile parseBarrel(
|
||||||
|
final String source,
|
||||||
|
final FileId fileId,
|
||||||
|
final DiagnosticSink diagnostics) {
|
||||||
|
final var tokens = PbsLexer.lex(source, fileId, diagnostics);
|
||||||
|
return PbsBarrelParser.parse(tokens, fileId, diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package p.studio.compiler.pbs.stdlib;
|
||||||
|
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface StdlibEnvironment {
|
||||||
|
Optional<StdlibModuleSource> resolveModule(String project, ReadOnlyList<String> pathSegments);
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
package p.studio.compiler.pbs.stdlib;
|
||||||
|
|
||||||
|
public interface StdlibEnvironmentResolver {
|
||||||
|
StdlibEnvironment resolve(int stdlibVersion);
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package p.studio.compiler.pbs.stdlib;
|
||||||
|
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record StdlibModuleSource(
|
||||||
|
String project,
|
||||||
|
ReadOnlyList<String> pathSegments,
|
||||||
|
ReadOnlyList<SourceFile> sourceFiles,
|
||||||
|
String barrelSource) {
|
||||||
|
|
||||||
|
public StdlibModuleSource {
|
||||||
|
project = Objects.requireNonNull(project, "project");
|
||||||
|
pathSegments = pathSegments == null ? ReadOnlyList.empty() : pathSegments;
|
||||||
|
sourceFiles = sourceFiles == null ? ReadOnlyList.empty() : sourceFiles;
|
||||||
|
barrelSource = Objects.requireNonNull(barrelSource, "barrelSource");
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SourceFile(
|
||||||
|
String logicalPath,
|
||||||
|
String source) {
|
||||||
|
public SourceFile {
|
||||||
|
logicalPath = Objects.requireNonNull(logicalPath, "logicalPath");
|
||||||
|
source = Objects.requireNonNull(source, "source");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -14,6 +14,9 @@ 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.pbs.stdlib.EmptyStdlibEnvironmentResolver;
|
||||||
|
import p.studio.compiler.pbs.stdlib.InterfaceModuleLoader;
|
||||||
|
import p.studio.compiler.pbs.stdlib.StdlibEnvironmentResolver;
|
||||||
import p.studio.compiler.source.Span;
|
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.diagnostics.DiagnosticPhase;
|
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
|
||||||
@ -23,6 +26,7 @@ import p.studio.utilities.logs.LogAggregator;
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -34,6 +38,19 @@ import java.util.Set;
|
|||||||
public class PBSFrontendPhaseService implements FrontendPhaseService {
|
public class PBSFrontendPhaseService implements FrontendPhaseService {
|
||||||
private final PbsFrontendCompiler frontendCompiler = new PbsFrontendCompiler();
|
private final PbsFrontendCompiler frontendCompiler = new PbsFrontendCompiler();
|
||||||
private final PbsModuleVisibilityValidator moduleVisibilityValidator = new PbsModuleVisibilityValidator();
|
private final PbsModuleVisibilityValidator moduleVisibilityValidator = new PbsModuleVisibilityValidator();
|
||||||
|
private final StdlibEnvironmentResolver stdlibEnvironmentResolver;
|
||||||
|
private final InterfaceModuleLoader interfaceModuleLoader;
|
||||||
|
|
||||||
|
public PBSFrontendPhaseService() {
|
||||||
|
this(new EmptyStdlibEnvironmentResolver(), new InterfaceModuleLoader());
|
||||||
|
}
|
||||||
|
|
||||||
|
PBSFrontendPhaseService(
|
||||||
|
final StdlibEnvironmentResolver stdlibEnvironmentResolver,
|
||||||
|
final InterfaceModuleLoader interfaceModuleLoader) {
|
||||||
|
this.stdlibEnvironmentResolver = stdlibEnvironmentResolver;
|
||||||
|
this.interfaceModuleLoader = interfaceModuleLoader;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IRBackend compile(
|
public IRBackend compile(
|
||||||
@ -99,6 +116,8 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadReservedStdlibModules(modulesByCoordinates, diagnostics, ctx.stdlibVersion());
|
||||||
|
|
||||||
final var modules = new ArrayList<PbsModuleVisibilityValidator.ModuleUnit>(modulesByCoordinates.size());
|
final var modules = new ArrayList<PbsModuleVisibilityValidator.ModuleUnit>(modulesByCoordinates.size());
|
||||||
for (final var entry : modulesByCoordinates.entrySet()) {
|
for (final var entry : modulesByCoordinates.entrySet()) {
|
||||||
final var coordinates = entry.getKey();
|
final var coordinates = entry.getKey();
|
||||||
@ -127,6 +146,67 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
return irBackend;
|
return irBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadReservedStdlibModules(
|
||||||
|
final Map<PbsModuleVisibilityValidator.ModuleCoordinates, MutableModuleUnit> modulesByCoordinates,
|
||||||
|
final DiagnosticSink diagnostics,
|
||||||
|
final int stdlibVersion) {
|
||||||
|
final var stdlibEnvironment = stdlibEnvironmentResolver.resolve(stdlibVersion);
|
||||||
|
final var pending = new ArrayDeque<PbsModuleVisibilityValidator.ModuleCoordinates>();
|
||||||
|
final var resolved = new HashSet<String>();
|
||||||
|
|
||||||
|
enqueueReservedImportsFromKnownModules(modulesByCoordinates, pending);
|
||||||
|
while (!pending.isEmpty()) {
|
||||||
|
final var target = pending.removeFirst();
|
||||||
|
final var targetKey = moduleKey(target);
|
||||||
|
if (!resolved.add(targetKey)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (modulesByCoordinates.containsKey(target)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final var moduleSource = stdlibEnvironment.resolveModule(target.project(), target.pathSegments());
|
||||||
|
if (moduleSource.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final var loadedModule = interfaceModuleLoader.load(moduleSource.get(), diagnostics);
|
||||||
|
final var moduleData = new MutableModuleUnit();
|
||||||
|
moduleData.sources.addAll(loadedModule.sourceFiles().asList());
|
||||||
|
moduleData.barrels.addAll(loadedModule.barrelFiles().asList());
|
||||||
|
modulesByCoordinates.put(loadedModule.coordinates(), moduleData);
|
||||||
|
enqueueReservedImportsFromSourceFiles(loadedModule.sourceFiles().asList(), pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enqueueReservedImportsFromKnownModules(
|
||||||
|
final Map<PbsModuleVisibilityValidator.ModuleCoordinates, MutableModuleUnit> modulesByCoordinates,
|
||||||
|
final ArrayDeque<PbsModuleVisibilityValidator.ModuleCoordinates> pending) {
|
||||||
|
for (final var moduleUnit : modulesByCoordinates.values()) {
|
||||||
|
enqueueReservedImportsFromSourceFiles(moduleUnit.sources, pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enqueueReservedImportsFromSourceFiles(
|
||||||
|
final Iterable<PbsModuleVisibilityValidator.SourceFile> sourceFiles,
|
||||||
|
final ArrayDeque<PbsModuleVisibilityValidator.ModuleCoordinates> pending) {
|
||||||
|
for (final var source : sourceFiles) {
|
||||||
|
for (final var importDecl : source.ast().imports()) {
|
||||||
|
final var moduleRef = importDecl.moduleRef();
|
||||||
|
if (!isReservedProjectSpace(moduleRef.project())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pending.addLast(new PbsModuleVisibilityValidator.ModuleCoordinates(
|
||||||
|
moduleRef.project(),
|
||||||
|
moduleRef.pathSegments()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isReservedProjectSpace(final String projectName) {
|
||||||
|
return "core".equals(projectName) || "sdk".equals(projectName);
|
||||||
|
}
|
||||||
|
|
||||||
private PbsAst.File parseSourceFile(
|
private PbsAst.File parseSourceFile(
|
||||||
final FileId fileId,
|
final FileId fileId,
|
||||||
final String source,
|
final String source,
|
||||||
|
|||||||
@ -8,6 +8,10 @@ import p.studio.compiler.models.BuildStack;
|
|||||||
import p.studio.compiler.models.ProjectDescriptor;
|
import p.studio.compiler.models.ProjectDescriptor;
|
||||||
import p.studio.compiler.models.SourceHandle;
|
import p.studio.compiler.models.SourceHandle;
|
||||||
import p.studio.compiler.models.SourceKind;
|
import p.studio.compiler.models.SourceKind;
|
||||||
|
import p.studio.compiler.pbs.stdlib.InterfaceModuleLoader;
|
||||||
|
import p.studio.compiler.pbs.stdlib.StdlibEnvironment;
|
||||||
|
import p.studio.compiler.pbs.stdlib.StdlibEnvironmentResolver;
|
||||||
|
import p.studio.compiler.pbs.stdlib.StdlibModuleSource;
|
||||||
import p.studio.compiler.pbs.linking.PbsLinkErrors;
|
import p.studio.compiler.pbs.linking.PbsLinkErrors;
|
||||||
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||||
import p.studio.compiler.source.identifiers.ProjectId;
|
import p.studio.compiler.source.identifiers.ProjectId;
|
||||||
@ -21,7 +25,10 @@ import java.io.IOException;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
@ -216,6 +223,111 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
assertEquals(0, irBackend.getFunctions().size());
|
assertEquals(0, irBackend.getFunctions().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldResolveReservedImportsThroughStdlibResolverForSelectedMajor() throws IOException {
|
||||||
|
final var projectRoot = tempDir.resolve("project-stdlib");
|
||||||
|
final var sourceRoot = projectRoot.resolve("src");
|
||||||
|
final var modulePath = sourceRoot.resolve("app");
|
||||||
|
Files.createDirectories(modulePath);
|
||||||
|
|
||||||
|
final var sourceFile = modulePath.resolve("source.pbs");
|
||||||
|
final var modBarrel = modulePath.resolve("mod.barrel");
|
||||||
|
Files.writeString(sourceFile, """
|
||||||
|
import { draw } from @sdk:gfx;
|
||||||
|
fn use() -> int { return 1; }
|
||||||
|
""");
|
||||||
|
Files.writeString(modBarrel, "pub fn use() -> int;");
|
||||||
|
|
||||||
|
final var projectTable = new ProjectTable();
|
||||||
|
final var fileTable = new FileTable(1);
|
||||||
|
final var projectId = projectTable.register(ProjectDescriptor.builder()
|
||||||
|
.rootPath(projectRoot)
|
||||||
|
.name("app")
|
||||||
|
.version("1.0.0")
|
||||||
|
.sourceRoots(ReadOnlyList.wrap(List.of(sourceRoot)))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
registerFile(projectId, projectRoot, sourceFile, fileTable);
|
||||||
|
registerFile(projectId, projectRoot, modBarrel, fileTable);
|
||||||
|
|
||||||
|
final var stdlibModule = new StdlibModuleSource(
|
||||||
|
"sdk",
|
||||||
|
ReadOnlyList.wrap(List.of("gfx")),
|
||||||
|
ReadOnlyList.wrap(List.of(new StdlibModuleSource.SourceFile("gfx.pbs", "fn draw() -> int { return 1; }"))),
|
||||||
|
"pub fn draw() -> int;");
|
||||||
|
final var frontendService = new PBSFrontendPhaseService(
|
||||||
|
resolverForMajor(7, stdlibModule),
|
||||||
|
new InterfaceModuleLoader(2_000_000));
|
||||||
|
|
||||||
|
final var ctx = new FrontendPhaseContext(
|
||||||
|
projectTable,
|
||||||
|
fileTable,
|
||||||
|
new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
|
||||||
|
7);
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
final var irBackend = frontendService.compile(
|
||||||
|
ctx,
|
||||||
|
diagnostics,
|
||||||
|
LogAggregator.empty(),
|
||||||
|
BuildingIssueSink.empty());
|
||||||
|
|
||||||
|
assertTrue(diagnostics.stream().noneMatch(d ->
|
||||||
|
d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_MODULE_NOT_FOUND.name())));
|
||||||
|
assertTrue(diagnostics.stream().noneMatch(d ->
|
||||||
|
d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_SYMBOL_UNRESOLVED.name())));
|
||||||
|
assertEquals(1, irBackend.getFunctions().size());
|
||||||
|
assertEquals("use", irBackend.getFunctions().getFirst().name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReportReservedImportModuleNotFoundWhenStdlibResolverMissesModule() throws IOException {
|
||||||
|
final var projectRoot = tempDir.resolve("project-stdlib-missing");
|
||||||
|
final var sourceRoot = projectRoot.resolve("src");
|
||||||
|
final var modulePath = sourceRoot.resolve("app");
|
||||||
|
Files.createDirectories(modulePath);
|
||||||
|
|
||||||
|
final var sourceFile = modulePath.resolve("source.pbs");
|
||||||
|
final var modBarrel = modulePath.resolve("mod.barrel");
|
||||||
|
Files.writeString(sourceFile, """
|
||||||
|
import { draw } from @sdk:gfx;
|
||||||
|
fn use() -> int { return 1; }
|
||||||
|
""");
|
||||||
|
Files.writeString(modBarrel, "pub fn use() -> int;");
|
||||||
|
|
||||||
|
final var projectTable = new ProjectTable();
|
||||||
|
final var fileTable = new FileTable(1);
|
||||||
|
final var projectId = projectTable.register(ProjectDescriptor.builder()
|
||||||
|
.rootPath(projectRoot)
|
||||||
|
.name("app")
|
||||||
|
.version("1.0.0")
|
||||||
|
.sourceRoots(ReadOnlyList.wrap(List.of(sourceRoot)))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
registerFile(projectId, projectRoot, sourceFile, fileTable);
|
||||||
|
registerFile(projectId, projectRoot, modBarrel, fileTable);
|
||||||
|
|
||||||
|
final var frontendService = new PBSFrontendPhaseService(
|
||||||
|
resolverForMajor(7),
|
||||||
|
new InterfaceModuleLoader(2_100_000));
|
||||||
|
final var ctx = new FrontendPhaseContext(
|
||||||
|
projectTable,
|
||||||
|
fileTable,
|
||||||
|
new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
|
||||||
|
7);
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
final var irBackend = frontendService.compile(
|
||||||
|
ctx,
|
||||||
|
diagnostics,
|
||||||
|
LogAggregator.empty(),
|
||||||
|
BuildingIssueSink.empty());
|
||||||
|
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_MODULE_NOT_FOUND.name())));
|
||||||
|
assertEquals(0, irBackend.getFunctions().size());
|
||||||
|
}
|
||||||
|
|
||||||
private void registerFile(
|
private void registerFile(
|
||||||
final ProjectId projectId,
|
final ProjectId projectId,
|
||||||
final Path projectRoot,
|
final Path projectRoot,
|
||||||
@ -231,4 +343,32 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
SourceProviderFactory.filesystem()));
|
SourceProviderFactory.filesystem()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private StdlibEnvironmentResolver resolverForMajor(
|
||||||
|
final int acceptedStdlib,
|
||||||
|
final StdlibModuleSource... modules) {
|
||||||
|
final var byModuleKey = new HashMap<String, StdlibModuleSource>();
|
||||||
|
for (final var module : modules) {
|
||||||
|
byModuleKey.put(moduleKey(module.project(), module.pathSegments()), module);
|
||||||
|
}
|
||||||
|
return stdlib -> {
|
||||||
|
if (stdlib != acceptedStdlib) {
|
||||||
|
return (project, pathSegments) -> Optional.empty();
|
||||||
|
}
|
||||||
|
return new StdlibEnvironment() {
|
||||||
|
@Override
|
||||||
|
public Optional<StdlibModuleSource> resolveModule(
|
||||||
|
final String project,
|
||||||
|
final ReadOnlyList<String> pathSegments) {
|
||||||
|
return Optional.ofNullable(byModuleKey.get(moduleKey(project, pathSegments)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String moduleKey(
|
||||||
|
final String project,
|
||||||
|
final ReadOnlyList<String> pathSegments) {
|
||||||
|
return project + ":" + String.join("/", pathSegments.asList());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,11 @@ public class FrontendPhasePipelineStage implements PipelineStage {
|
|||||||
}
|
}
|
||||||
final var projectTable = ctx.resolvedWorkspace.graph().projectTable();
|
final var projectTable = ctx.resolvedWorkspace.graph().projectTable();
|
||||||
final var fileTable = ctx.fileTable;
|
final var fileTable = ctx.fileTable;
|
||||||
final var frontendPhaseContext = new FrontendPhaseContext(projectTable, fileTable, ctx.resolvedWorkspace.stack());
|
final var frontendPhaseContext = new FrontendPhaseContext(
|
||||||
|
projectTable,
|
||||||
|
fileTable,
|
||||||
|
ctx.resolvedWorkspace.stack(),
|
||||||
|
ctx.resolvedWorkspace.stdlib());
|
||||||
final var diagnostics = DiagnosticSink.empty();
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
final var issues = BuildingIssueSink.empty();
|
final var issues = BuildingIssueSink.empty();
|
||||||
ctx.irBackend = service.get().compile(frontendPhaseContext, diagnostics, logs, issues);
|
ctx.irBackend = service.get().compile(frontendPhaseContext, diagnostics, logs, issues);
|
||||||
|
|||||||
@ -47,7 +47,7 @@ public final class DependencyContext {
|
|||||||
throw new BuildException("dependenciesByProjectId: internal error: rootProjectId ProjectId not set");
|
throw new BuildException("dependenciesByProjectId: internal error: rootProjectId ProjectId not set");
|
||||||
}
|
}
|
||||||
if (rootStdlib == null) {
|
if (rootStdlib == null) {
|
||||||
throw new BuildException("dependenciesByProjectId: internal error: rootStdlibMajor not set");
|
throw new BuildException("dependenciesByProjectId: internal error: rootStdlib not set");
|
||||||
}
|
}
|
||||||
final var dependenciesByProject = buildDependenciesByProject();
|
final var dependenciesByProject = buildDependenciesByProject();
|
||||||
final var workspaceGraph = new WorkspaceGraph(projectTable, dependenciesByProject);
|
final var workspaceGraph = new WorkspaceGraph(projectTable, dependenciesByProject);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import p.studio.compiler.source.identifiers.ProjectId;
|
|||||||
public record ResolvedWorkspace(
|
public record ResolvedWorkspace(
|
||||||
ProjectId mainProjectId,
|
ProjectId mainProjectId,
|
||||||
FrontendSpec frontendSpec,
|
FrontendSpec frontendSpec,
|
||||||
int stdlibMajor,
|
int stdlib,
|
||||||
WorkspaceGraph graph,
|
WorkspaceGraph graph,
|
||||||
BuildStack stack) {
|
BuildStack stack) {
|
||||||
public ProjectDescriptor mainProject() {
|
public ProjectDescriptor mainProject() {
|
||||||
|
|||||||
@ -45,7 +45,7 @@ public final class PrometeuManifestUtils {
|
|||||||
.error(true)
|
.error(true)
|
||||||
.message("[DEPS]: manifest missing 'version': " + manifestPathCanon));
|
.message("[DEPS]: manifest missing 'version': " + manifestPathCanon));
|
||||||
}
|
}
|
||||||
final var stdlibMajorMaybe = parseStdlibMajor(dto.stdlib(), manifestPathCanon, issuesLocal);
|
final var stdlibMaybe = parseStdlib(dto.stdlib(), manifestPathCanon, issuesLocal);
|
||||||
final var language = StringUtils.isBlank(dto.language())
|
final var language = StringUtils.isBlank(dto.language())
|
||||||
? FrontendRegistryService.getDefaultFrontendSpec().getLanguageId()
|
? FrontendRegistryService.getDefaultFrontendSpec().getLanguageId()
|
||||||
: dto.language();
|
: dto.language();
|
||||||
@ -54,34 +54,34 @@ public final class PrometeuManifestUtils {
|
|||||||
issues.merge(issuesLocal);
|
issues.merge(issuesLocal);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
return Optional.of(new PrometeuManifest(dto.name(), dto.version(), language, stdlibMajorMaybe.getAsInt(), ReadOnlyList.wrap(dependencies)));
|
return Optional.of(new PrometeuManifest(dto.name(), dto.version(), language, stdlibMaybe.getAsInt(), ReadOnlyList.wrap(dependencies)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OptionalInt parseStdlibMajor(
|
private static OptionalInt parseStdlib(
|
||||||
final String stdlib,
|
final String stdlibStr,
|
||||||
final Path manifestPathCanon,
|
final Path manifestPathCanon,
|
||||||
final BuildingIssueSink issues) {
|
final BuildingIssueSink issues) {
|
||||||
if (StringUtils.isBlank(stdlib)) {
|
if (StringUtils.isBlank(stdlibStr)) {
|
||||||
issues.report(builder -> builder
|
issues.report(builder -> builder
|
||||||
.error(true)
|
.error(true)
|
||||||
.message("[DEPS]: manifest missing 'stdlib': " + manifestPathCanon));
|
.message("[DEPS]: manifest missing 'stdlib': " + manifestPathCanon));
|
||||||
return OptionalInt.empty();
|
return OptionalInt.empty();
|
||||||
}
|
}
|
||||||
final int stdlibMajor;
|
final int stdlib;
|
||||||
try {
|
try {
|
||||||
stdlibMajor = Integer.parseInt(stdlib);
|
stdlib = Integer.parseInt(stdlibStr);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
issues.report(builder -> builder
|
issues.report(builder -> builder
|
||||||
.error(true)
|
.error(true)
|
||||||
.message("[DEPS]: invalid 'stdlib' major version \"" + stdlib + "\": " + manifestPathCanon));
|
.message("[DEPS]: invalid 'stdlib' major version \"" + stdlibStr + "\": " + manifestPathCanon));
|
||||||
return OptionalInt.empty();
|
return OptionalInt.empty();
|
||||||
}
|
}
|
||||||
if (stdlibMajor <= 0 || !stdlib.equals(Integer.toString(stdlibMajor))) {
|
if (stdlib <= 0 || !stdlibStr.equals(Integer.toString(stdlib))) {
|
||||||
issues.report(builder -> builder
|
issues.report(builder -> builder
|
||||||
.error(true)
|
.error(true)
|
||||||
.message("[DEPS]: invalid 'stdlib' major version \"" + stdlib + "\": " + manifestPathCanon));
|
.message("[DEPS]: invalid 'stdlib' major version \"" + stdlibStr + "\": " + manifestPathCanon));
|
||||||
return OptionalInt.empty();
|
return OptionalInt.empty();
|
||||||
}
|
}
|
||||||
return OptionalInt.of(stdlibMajor);
|
return OptionalInt.of(stdlib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class PrometeuManifestUtilsTest {
|
|||||||
Path tempDir;
|
Path tempDir;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void buildManifestParsesStdlibMajor() throws IOException {
|
void buildManifestParsesStdlib() throws IOException {
|
||||||
final var manifestPath = writeManifest("""
|
final var manifestPath = writeManifest("""
|
||||||
{
|
{
|
||||||
"name": "main",
|
"name": "main",
|
||||||
|
|||||||
@ -10,17 +10,31 @@ public class FrontendPhaseContext {
|
|||||||
public final ProjectTableReader projectTable;
|
public final ProjectTableReader projectTable;
|
||||||
public final FileTableReader fileTable;
|
public final FileTableReader fileTable;
|
||||||
public final BuildStack stack;
|
public final BuildStack stack;
|
||||||
|
private final int stdlibVersion;
|
||||||
|
|
||||||
public FrontendPhaseContext(
|
public FrontendPhaseContext(
|
||||||
final ProjectTableReader projectTable,
|
final ProjectTableReader projectTable,
|
||||||
final FileTableReader fileTable,
|
final FileTableReader fileTable,
|
||||||
final BuildStack stack) {
|
final BuildStack stack) {
|
||||||
|
this(projectTable, fileTable, stack, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrontendPhaseContext(
|
||||||
|
final ProjectTableReader projectTable,
|
||||||
|
final FileTableReader fileTable,
|
||||||
|
final BuildStack stack,
|
||||||
|
final int stdlibVersion) {
|
||||||
this.projectTable = projectTable;
|
this.projectTable = projectTable;
|
||||||
this.fileTable = fileTable;
|
this.fileTable = fileTable;
|
||||||
this.stack = stack;
|
this.stack = stack;
|
||||||
|
this.stdlibVersion = stdlibVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SourceKind sourceKind(final ProjectId projectId) {
|
public SourceKind sourceKind(final ProjectId projectId) {
|
||||||
return projectTable.sourceKind(projectId);
|
return projectTable.sourceKind(projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int stdlibVersion() {
|
||||||
|
return stdlibVersion;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user