refactoring and reducing complexity
This commit is contained in:
parent
2bc99cc901
commit
2288ed75f9
@ -18,7 +18,6 @@ import p.studio.compiler.source.diagnostics.DiagnosticPhase;
|
|||||||
import p.studio.compiler.source.identifiers.CallableShapeId;
|
import p.studio.compiler.source.identifiers.CallableShapeId;
|
||||||
import p.studio.compiler.source.identifiers.CallableId;
|
import p.studio.compiler.source.identifiers.CallableId;
|
||||||
import p.studio.compiler.source.identifiers.FileId;
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
import p.studio.compiler.source.identifiers.IntrinsicId;
|
|
||||||
import p.studio.compiler.source.identifiers.ModuleId;
|
import p.studio.compiler.source.identifiers.ModuleId;
|
||||||
import p.studio.compiler.source.identifiers.NameId;
|
import p.studio.compiler.source.identifiers.NameId;
|
||||||
import p.studio.compiler.source.identifiers.TypeSurfaceId;
|
import p.studio.compiler.source.identifiers.TypeSurfaceId;
|
||||||
@ -38,7 +37,6 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public final class PbsFrontendCompiler {
|
public final class PbsFrontendCompiler {
|
||||||
private final PbsFlowSemanticsValidator flowSemanticsValidator = new PbsFlowSemanticsValidator();
|
private final PbsFlowSemanticsValidator flowSemanticsValidator = new PbsFlowSemanticsValidator();
|
||||||
@ -88,38 +86,6 @@ public final class PbsFrontendCompiler {
|
|||||||
return irBackendFile;
|
return irBackendFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRBackendFile compileParsedFile(
|
|
||||||
final FileId fileId,
|
|
||||||
final PbsAst.File ast,
|
|
||||||
final DiagnosticSink diagnostics) {
|
|
||||||
return compileParsedFile(fileId, ast, diagnostics, SourceKind.PROJECT, HostAdmissionContext.permissiveDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
public IRBackendFile compileParsedFile(
|
|
||||||
final FileId fileId,
|
|
||||||
final PbsAst.File ast,
|
|
||||||
final DiagnosticSink diagnostics,
|
|
||||||
final SourceKind sourceKind) {
|
|
||||||
return compileParsedFile(fileId, ast, diagnostics, sourceKind, HostAdmissionContext.permissiveDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
public IRBackendFile compileParsedFile(
|
|
||||||
final FileId fileId,
|
|
||||||
final PbsAst.File ast,
|
|
||||||
final DiagnosticSink diagnostics,
|
|
||||||
final SourceKind sourceKind,
|
|
||||||
final HostAdmissionContext hostAdmissionContext) {
|
|
||||||
return compileParsedFile(
|
|
||||||
fileId,
|
|
||||||
ast,
|
|
||||||
diagnostics,
|
|
||||||
sourceKind,
|
|
||||||
ModuleId.none(),
|
|
||||||
ReadOnlyList.empty(),
|
|
||||||
hostAdmissionContext,
|
|
||||||
new NameTable());
|
|
||||||
}
|
|
||||||
|
|
||||||
public IRBackendFile compileParsedFile(
|
public IRBackendFile compileParsedFile(
|
||||||
final FileId fileId,
|
final FileId fileId,
|
||||||
final PbsAst.File ast,
|
final PbsAst.File ast,
|
||||||
|
|||||||
@ -5,51 +5,28 @@ import p.studio.compiler.PBSDefinitions;
|
|||||||
import p.studio.compiler.messages.BuildingIssueSink;
|
import p.studio.compiler.messages.BuildingIssueSink;
|
||||||
import p.studio.compiler.messages.FrontendPhaseContext;
|
import p.studio.compiler.messages.FrontendPhaseContext;
|
||||||
import p.studio.compiler.models.IRBackend;
|
import p.studio.compiler.models.IRBackend;
|
||||||
import p.studio.compiler.models.IRReservedMetadata;
|
|
||||||
import p.studio.compiler.models.ProjectDescriptor;
|
|
||||||
import p.studio.compiler.models.SourceHandle;
|
|
||||||
import p.studio.compiler.models.SourceKind;
|
|
||||||
import p.studio.compiler.pbs.PbsFrontendCompiler;
|
import p.studio.compiler.pbs.PbsFrontendCompiler;
|
||||||
import p.studio.compiler.pbs.ast.PbsAst;
|
|
||||||
import p.studio.compiler.pbs.metadata.PbsReservedMetadataExtractor;
|
import p.studio.compiler.pbs.metadata.PbsReservedMetadataExtractor;
|
||||||
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.pbs.stdlib.InterfaceModuleLoader;
|
import p.studio.compiler.pbs.stdlib.InterfaceModuleLoader;
|
||||||
import p.studio.compiler.pbs.stdlib.ResourceStdlibEnvironmentResolver;
|
import p.studio.compiler.pbs.stdlib.ResourceStdlibEnvironmentResolver;
|
||||||
import p.studio.compiler.pbs.stdlib.StdlibEnvironmentResolver;
|
import p.studio.compiler.pbs.stdlib.StdlibEnvironmentResolver;
|
||||||
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.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.ModuleTable;
|
|
||||||
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.util.ArrayDeque;
|
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;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class PBSFrontendPhaseService implements FrontendPhaseService {
|
public class PBSFrontendPhaseService implements FrontendPhaseService {
|
||||||
private final PbsFrontendCompiler frontendCompiler = new PbsFrontendCompiler();
|
private final PbsFrontendCompiler frontendCompiler;
|
||||||
private final PbsReservedMetadataExtractor reservedMetadataExtractor = new PbsReservedMetadataExtractor();
|
private final PbsModuleAssemblyService moduleAssemblyService;
|
||||||
private final PbsModuleVisibilityValidator moduleVisibilityValidator = new PbsModuleVisibilityValidator();
|
private final PbsImportedSemanticContextService importedSemanticContextService;
|
||||||
private final StdlibEnvironmentResolver stdlibEnvironmentResolver;
|
|
||||||
private final InterfaceModuleLoader interfaceModuleLoader;
|
|
||||||
|
|
||||||
public PBSFrontendPhaseService() {
|
public PBSFrontendPhaseService() {
|
||||||
this(new ResourceStdlibEnvironmentResolver(), new InterfaceModuleLoader());
|
this(new ResourceStdlibEnvironmentResolver(), new InterfaceModuleLoader());
|
||||||
@ -58,8 +35,16 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
PBSFrontendPhaseService(
|
PBSFrontendPhaseService(
|
||||||
final StdlibEnvironmentResolver stdlibEnvironmentResolver,
|
final StdlibEnvironmentResolver stdlibEnvironmentResolver,
|
||||||
final InterfaceModuleLoader interfaceModuleLoader) {
|
final InterfaceModuleLoader interfaceModuleLoader) {
|
||||||
this.stdlibEnvironmentResolver = stdlibEnvironmentResolver;
|
final var reservedMetadataExtractor = new PbsReservedMetadataExtractor();
|
||||||
this.interfaceModuleLoader = interfaceModuleLoader;
|
final var moduleVisibilityValidator = new p.studio.compiler.pbs.linking.PbsModuleVisibilityValidator();
|
||||||
|
this.frontendCompiler = new PbsFrontendCompiler();
|
||||||
|
this.moduleAssemblyService = new PbsModuleAssemblyService(
|
||||||
|
stdlibEnvironmentResolver,
|
||||||
|
interfaceModuleLoader,
|
||||||
|
moduleVisibilityValidator);
|
||||||
|
this.importedSemanticContextService = new PbsImportedSemanticContextService(
|
||||||
|
reservedMetadataExtractor,
|
||||||
|
frontendCompiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -69,98 +54,12 @@ 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)) {
|
final var assembly = moduleAssemblyService.assemble(ctx, nameTable, diagnostics, issues);
|
||||||
throw new IllegalStateException("PBS frontend requires writable FileTable for synthetic stdlib sources");
|
final var parsedSourceFiles = assembly.parsedSourceFiles();
|
||||||
}
|
final var importedSemanticContexts = importedSemanticContextService.build(parsedSourceFiles, assembly.moduleTable());
|
||||||
final var irBackendAggregator = IRBackend.aggregator();
|
final var failedModuleIds = assembly.mutableFailedModuleIds();
|
||||||
final var parsedSourceFiles = new ArrayList<ParsedSourceFile>();
|
final var moduleDependencyGraph = assembly.moduleDependencyGraph();
|
||||||
final Map<PbsModuleVisibilityValidator.ModuleCoordinates, MutableModuleUnit> modulesByCoordinates = new LinkedHashMap<>();
|
final var canonicalModulePool = assembly.canonicalModulePool();
|
||||||
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);
|
|
||||||
sourceHandle.readUtf8().ifPresentOrElse(
|
|
||||||
utf8Content -> {
|
|
||||||
final var coordinates = resolveModuleCoordinates(projectDescriptor, sourceHandle);
|
|
||||||
final var moduleId = moduleId(moduleTable, coordinates);
|
|
||||||
final var moduleUnit = modulesByCoordinates.computeIfAbsent(
|
|
||||||
coordinates,
|
|
||||||
ignored -> new MutableModuleUnit());
|
|
||||||
switch (sourceHandle.getExtension()) {
|
|
||||||
case "pbs" -> {
|
|
||||||
moduleIdByFile.put(fId, moduleId);
|
|
||||||
final var parseErrorBaseline = diagnostics.errorCount();
|
|
||||||
final var ast = parseSourceFile(fId, utf8Content, diagnostics, projectSourceKind);
|
|
||||||
moduleUnit.sources.add(new PbsModuleVisibilityValidator.SourceFile(fId, ast));
|
|
||||||
parsedSourceFiles.add(new ParsedSourceFile(fId, ast, moduleId, projectSourceKind));
|
|
||||||
if (diagnostics.errorCount() > parseErrorBaseline) {
|
|
||||||
failedModuleIds.add(moduleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "barrel" -> {
|
|
||||||
moduleIdByFile.put(fId, moduleId);
|
|
||||||
if ("mod.barrel".equals(sourceHandle.getFilename())) {
|
|
||||||
final var parseErrorBaseline = diagnostics.errorCount();
|
|
||||||
final var barrelAst = parseBarrelFile(fId, utf8Content, diagnostics);
|
|
||||||
moduleUnit.barrels.add(new PbsModuleVisibilityValidator.BarrelFile(fId, barrelAst));
|
|
||||||
if (diagnostics.errorCount() > parseErrorBaseline) {
|
|
||||||
failedModuleIds.add(moduleId);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
|
||||||
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));
|
|
||||||
failedModuleIds.add(moduleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() -> issues.report(builder -> builder
|
|
||||||
.error(true)
|
|
||||||
.message("Failed to read file content: %s".formatted(sourceHandle.toString()))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadReservedStdlibModules(
|
|
||||||
modulesByCoordinates,
|
|
||||||
parsedSourceFiles,
|
|
||||||
moduleIdByFile,
|
|
||||||
moduleTable,
|
|
||||||
writableFileTable,
|
|
||||||
projectIdByName,
|
|
||||||
defaultSyntheticOwnerProjectId,
|
|
||||||
diagnostics,
|
|
||||||
ctx.stdlibVersion());
|
|
||||||
|
|
||||||
final var modules = new ArrayList<PbsModuleVisibilityValidator.ModuleUnit>(modulesByCoordinates.size());
|
|
||||||
for (final var entry : modulesByCoordinates.entrySet()) {
|
|
||||||
final var coordinates = entry.getKey();
|
|
||||||
final var moduleUnit = entry.getValue();
|
|
||||||
modules.add(new PbsModuleVisibilityValidator.ModuleUnit(
|
|
||||||
coordinates,
|
|
||||||
ReadOnlyList.wrap(moduleUnit.sources),
|
|
||||||
ReadOnlyList.wrap(moduleUnit.barrels)));
|
|
||||||
}
|
|
||||||
moduleVisibilityValidator.validate(ReadOnlyList.wrap(modules), nameTable, diagnostics);
|
|
||||||
markModulesWithLinkingErrors(diagnostics, moduleIdByFile, failedModuleIds);
|
|
||||||
final var moduleDependencyGraph = buildModuleDependencyGraph(parsedSourceFiles, moduleTable);
|
|
||||||
final var importedSemanticContexts = buildImportedSemanticContexts(parsedSourceFiles, moduleTable);
|
|
||||||
final var canonicalModulePool = emitModulePool(moduleTable);
|
|
||||||
|
|
||||||
final var compiledSourceFiles = new ArrayList<CompiledSourceFile>(parsedSourceFiles.size());
|
final var compiledSourceFiles = new ArrayList<CompiledSourceFile>(parsedSourceFiles.size());
|
||||||
for (final var parsedSource : parsedSourceFiles) {
|
for (final var parsedSource : parsedSourceFiles) {
|
||||||
@ -170,7 +69,7 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
}
|
}
|
||||||
final var importedSemanticContext = importedSemanticContexts.getOrDefault(
|
final var importedSemanticContext = importedSemanticContexts.getOrDefault(
|
||||||
parsedSource.fileId(),
|
parsedSource.fileId(),
|
||||||
ImportedSemanticContext.empty());
|
PbsImportedSemanticContext.empty());
|
||||||
final var compileErrorBaseline = diagnostics.errorCount();
|
final var compileErrorBaseline = diagnostics.errorCount();
|
||||||
final var irBackendFile = frontendCompiler.compileParsedFile(
|
final var irBackendFile = frontendCompiler.compileParsedFile(
|
||||||
parsedSource.fileId(),
|
parsedSource.fileId(),
|
||||||
@ -190,9 +89,23 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
compiledSourceFiles.add(new CompiledSourceFile(parsedSource.moduleId(), irBackendFile));
|
compiledSourceFiles.add(new CompiledSourceFile(parsedSource.moduleId(), irBackendFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final var irBackend = mergeCompiledSources(
|
||||||
|
compiledSourceFiles,
|
||||||
|
failedModuleIds,
|
||||||
|
moduleDependencyGraph);
|
||||||
|
logs.using(log).debug("PBS frontend lowered to IR BE:\n%s".formatted(irBackend));
|
||||||
|
return irBackend;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IRBackend mergeCompiledSources(
|
||||||
|
final ArrayList<CompiledSourceFile> compiledSourceFiles,
|
||||||
|
final Set<ModuleId> failedModuleIds,
|
||||||
|
final Map<ModuleId, Set<ModuleId>> moduleDependencyGraph) {
|
||||||
|
final var irBackendAggregator = IRBackend.aggregator();
|
||||||
final var blockedModuleIds = blockedModulesByDependency(failedModuleIds, moduleDependencyGraph);
|
final var blockedModuleIds = blockedModulesByDependency(failedModuleIds, moduleDependencyGraph);
|
||||||
final var entryPointCallableName = PBSDefinitions.PBS.getEntryPointCallableName();
|
final var entryPointCallableName = PBSDefinitions.PBS.getEntryPointCallableName();
|
||||||
final var entryPointModuleCandidates = new LinkedHashSet<ModuleId>();
|
final var entryPointModuleCandidates = new LinkedHashSet<ModuleId>();
|
||||||
|
|
||||||
for (final var compiledSource : compiledSourceFiles) {
|
for (final var compiledSource : compiledSourceFiles) {
|
||||||
if (blockedModuleIds.contains(compiledSource.moduleId())) {
|
if (blockedModuleIds.contains(compiledSource.moduleId())) {
|
||||||
continue;
|
continue;
|
||||||
@ -207,559 +120,12 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
irBackendAggregator.entryPointCallableName(entryPointCallableName);
|
irBackendAggregator.entryPointCallableName(entryPointCallableName);
|
||||||
if (entryPointModuleCandidates.size() == 1) {
|
if (entryPointModuleCandidates.size() == 1) {
|
||||||
irBackendAggregator.entryPointModuleId(entryPointModuleCandidates.iterator().next());
|
irBackendAggregator.entryPointModuleId(entryPointModuleCandidates.iterator().next());
|
||||||
}
|
}
|
||||||
|
return irBackendAggregator.emit();
|
||||||
final var irBackend = irBackendAggregator.emit();
|
|
||||||
logs.using(log).debug("PBS frontend lowered to IR BE:\n%s".formatted(irBackend));
|
|
||||||
return irBackend;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadReservedStdlibModules(
|
|
||||||
final Map<PbsModuleVisibilityValidator.ModuleCoordinates, MutableModuleUnit> modulesByCoordinates,
|
|
||||||
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);
|
|
||||||
final var pending = new ArrayDeque<PbsModuleVisibilityValidator.ModuleCoordinates>();
|
|
||||||
final var resolved = new HashSet<ModuleId>();
|
|
||||||
|
|
||||||
enqueueReservedImportsFromKnownModules(modulesByCoordinates, pending);
|
|
||||||
while (!pending.isEmpty()) {
|
|
||||||
final var target = pending.removeFirst();
|
|
||||||
final var targetId = moduleId(moduleTable, target);
|
|
||||||
if (!resolved.add(targetId)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (modulesByCoordinates.containsKey(target)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final var moduleSource = stdlibEnvironment.resolveModule(target.project(), target.pathSegments());
|
|
||||||
if (moduleSource.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
modulesByCoordinates.put(loadedModule.coordinates(), moduleData);
|
|
||||||
for (final var sourceFile : loadedModule.sourceFiles()) {
|
|
||||||
moduleIdByFile.put(sourceFile.fileId(), targetId);
|
|
||||||
parsedSourceFiles.add(new ParsedSourceFile(
|
|
||||||
sourceFile.fileId(),
|
|
||||||
sourceFile.ast(),
|
|
||||||
targetId,
|
|
||||||
SourceKind.SDK_INTERFACE));
|
|
||||||
}
|
|
||||||
for (final var barrelFile : loadedModule.barrelFiles()) {
|
|
||||||
moduleIdByFile.put(barrelFile.fileId(), targetId);
|
|
||||||
}
|
|
||||||
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(
|
|
||||||
final FileId fileId,
|
|
||||||
final String source,
|
|
||||||
final DiagnosticSink diagnostics,
|
|
||||||
final SourceKind sourceKind) {
|
|
||||||
final var tokens = PbsLexer.lex(source, fileId, diagnostics);
|
|
||||||
final var parseMode = sourceKind == SourceKind.SDK_INTERFACE
|
|
||||||
? PbsParser.ParseMode.INTERFACE_MODULE
|
|
||||||
: PbsParser.ParseMode.ORDINARY;
|
|
||||||
return PbsParser.parse(tokens, fileId, diagnostics, parseMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.BarrelFile parseBarrelFile(
|
|
||||||
final FileId fileId,
|
|
||||||
final String source,
|
|
||||||
final DiagnosticSink diagnostics) {
|
|
||||||
final var tokens = PbsLexer.lex(source, fileId, diagnostics);
|
|
||||||
return PbsBarrelParser.parse(tokens, fileId, diagnostics);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsModuleVisibilityValidator.ModuleCoordinates resolveModuleCoordinates(
|
|
||||||
final ProjectDescriptor projectDescriptor,
|
|
||||||
final SourceHandle sourceHandle) {
|
|
||||||
final var sourceRelativePath = sourceRelativePath(projectDescriptor, sourceHandle);
|
|
||||||
final var modulePath = sourceRelativePath.getParent();
|
|
||||||
final var pathSegments = new ArrayList<String>();
|
|
||||||
if (modulePath != null) {
|
|
||||||
for (final var segment : modulePath) {
|
|
||||||
pathSegments.add(segment.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PbsModuleVisibilityValidator.ModuleCoordinates(
|
|
||||||
projectDescriptor.getName(),
|
|
||||||
ReadOnlyList.wrap(pathSegments));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path sourceRelativePath(
|
|
||||||
final ProjectDescriptor projectDescriptor,
|
|
||||||
final SourceHandle sourceHandle) {
|
|
||||||
final var canonPath = sourceHandle.getCanonPath();
|
|
||||||
for (final var sourceRoot : projectDescriptor.getSourceRoots()) {
|
|
||||||
if (canonPath.startsWith(sourceRoot)) {
|
|
||||||
return sourceRoot.relativize(canonPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sourceHandle.getRelativePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markModulesWithLinkingErrors(
|
|
||||||
final DiagnosticSink diagnostics,
|
|
||||||
final Map<FileId, ModuleId> moduleIdByFile,
|
|
||||||
final Set<ModuleId> failedModuleIds) {
|
|
||||||
for (final var diagnostic : diagnostics) {
|
|
||||||
if (!diagnostic.getSeverity().isError()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (diagnostic.getPhase() != DiagnosticPhase.LINKING) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final var moduleId = moduleIdByFile.get(diagnostic.getSpan().getFileId());
|
|
||||||
if (moduleId != null) {
|
|
||||||
failedModuleIds.add(moduleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<ModuleId, Set<ModuleId>> buildModuleDependencyGraph(
|
|
||||||
final ArrayList<ParsedSourceFile> parsedSourceFiles,
|
|
||||||
final ModuleTable moduleTable) {
|
|
||||||
final Map<ModuleId, Set<ModuleId>> dependenciesByModule = new HashMap<>();
|
|
||||||
for (final var parsedSource : parsedSourceFiles) {
|
|
||||||
final var moduleDependencies = dependenciesByModule.computeIfAbsent(
|
|
||||||
parsedSource.moduleId(),
|
|
||||||
ignored -> new HashSet<>());
|
|
||||||
for (final var importDecl : parsedSource.ast().imports()) {
|
|
||||||
final var moduleRef = importDecl.moduleRef();
|
|
||||||
moduleDependencies.add(moduleId(moduleTable, moduleRef.project(), moduleRef.pathSegments()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dependenciesByModule;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<FileId, ImportedSemanticContext> buildImportedSemanticContexts(
|
|
||||||
final ArrayList<ParsedSourceFile> parsedSourceFiles,
|
|
||||||
final ModuleTable moduleTable) {
|
|
||||||
final Map<ModuleId, ArrayList<ParsedSourceFile>> sourcesByModule = new HashMap<>();
|
|
||||||
for (final var parsedSource : parsedSourceFiles) {
|
|
||||||
sourcesByModule
|
|
||||||
.computeIfAbsent(parsedSource.moduleId(), ignored -> new ArrayList<>())
|
|
||||||
.add(parsedSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<ModuleId, IRReservedMetadata> reservedMetadataByModule = new HashMap<>();
|
|
||||||
for (final var entry : sourcesByModule.entrySet()) {
|
|
||||||
var merged = IRReservedMetadata.empty();
|
|
||||||
for (final var source : entry.getValue()) {
|
|
||||||
final var extracted = reservedMetadataExtractor.extract(source.ast(), source.sourceKind());
|
|
||||||
merged = mergeReservedMetadata(merged, extracted);
|
|
||||||
}
|
|
||||||
reservedMetadataByModule.put(entry.getKey(), merged);
|
|
||||||
}
|
|
||||||
final Map<ModuleId, Map<String, ArrayList<PbsAst.TopDecl>>> topDeclsByNameByModule = new HashMap<>();
|
|
||||||
for (final var entry : sourcesByModule.entrySet()) {
|
|
||||||
topDeclsByNameByModule.put(entry.getKey(), indexTopDeclsByName(entry.getValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<FileId, ImportedSemanticContext> contexts = new HashMap<>();
|
|
||||||
for (final var parsedSource : parsedSourceFiles) {
|
|
||||||
final var supplementalTopDecls = new ArrayList<PbsAst.TopDecl>();
|
|
||||||
final var importedCallables = new ArrayList<PbsFrontendCompiler.ImportedCallableSurface>();
|
|
||||||
final var importedCallableKeys = new HashSet<String>();
|
|
||||||
final var supplementalKeys = new HashSet<String>();
|
|
||||||
var importedReservedMetadata = IRReservedMetadata.empty();
|
|
||||||
|
|
||||||
for (final var importDecl : parsedSource.ast().imports()) {
|
|
||||||
final var moduleRef = importDecl.moduleRef();
|
|
||||||
final var importedModuleId = moduleId(moduleTable, moduleRef.project(), moduleRef.pathSegments());
|
|
||||||
final var importedSources = sourcesByModule.get(importedModuleId);
|
|
||||||
if (importedSources == null || importedSources.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final var importedTopDeclsByName = topDeclsByNameByModule.get(importedModuleId);
|
|
||||||
if (importedTopDeclsByName == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
importedReservedMetadata = mergeReservedMetadata(
|
|
||||||
importedReservedMetadata,
|
|
||||||
reservedMetadataByModule.getOrDefault(importedModuleId, IRReservedMetadata.empty()));
|
|
||||||
|
|
||||||
for (final var importItem : importDecl.items()) {
|
|
||||||
final var importName = importItem.name();
|
|
||||||
final var localName = importItemLocalName(importItem);
|
|
||||||
final var directDecls = importedTopDeclsByName.getOrDefault(importName, new ArrayList<>());
|
|
||||||
for (final var topDecl : directDecls) {
|
|
||||||
appendSupplementalTopDecl(topDecl, supplementalTopDecls, supplementalKeys);
|
|
||||||
appendTypeDependencyDecls(topDecl, importedTopDeclsByName, supplementalTopDecls, supplementalKeys);
|
|
||||||
if (topDecl instanceof PbsAst.ServiceDecl serviceDecl) {
|
|
||||||
for (final var method : serviceDecl.methods()) {
|
|
||||||
appendImportedCallable(
|
|
||||||
importedCallables,
|
|
||||||
importedCallableKeys,
|
|
||||||
new PbsFrontendCompiler.ImportedCallableSurface(
|
|
||||||
importedModuleId,
|
|
||||||
localName + "." + method.name(),
|
|
||||||
method.parameters().size(),
|
|
||||||
returnSlotsFor(method),
|
|
||||||
frontendCompiler.callableShapeSurfaceOf(method)));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.FunctionDecl functionDecl) {
|
|
||||||
appendImportedCallable(
|
|
||||||
importedCallables,
|
|
||||||
importedCallableKeys,
|
|
||||||
new PbsFrontendCompiler.ImportedCallableSurface(
|
|
||||||
importedModuleId,
|
|
||||||
localName,
|
|
||||||
functionDecl.parameters().size(),
|
|
||||||
returnSlotsFor(functionDecl),
|
|
||||||
frontendCompiler.callableShapeSurfaceOf(functionDecl)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contexts.put(parsedSource.fileId(), new ImportedSemanticContext(
|
|
||||||
ReadOnlyList.wrap(supplementalTopDecls),
|
|
||||||
ReadOnlyList.wrap(importedCallables),
|
|
||||||
importedReservedMetadata));
|
|
||||||
}
|
|
||||||
return contexts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, ArrayList<PbsAst.TopDecl>> indexTopDeclsByName(
|
|
||||||
final ArrayList<ParsedSourceFile> moduleSources) {
|
|
||||||
final Map<String, ArrayList<PbsAst.TopDecl>> index = new HashMap<>();
|
|
||||||
for (final var source : moduleSources) {
|
|
||||||
for (final var topDecl : source.ast().topDecls()) {
|
|
||||||
final var declName = topDeclName(topDecl);
|
|
||||||
if (declName == null || declName.isBlank()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
index.computeIfAbsent(declName, ignored -> new ArrayList<>()).add(topDecl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendTypeDependencyDecls(
|
|
||||||
final PbsAst.TopDecl rootDecl,
|
|
||||||
final Map<String, ArrayList<PbsAst.TopDecl>> topDeclsByName,
|
|
||||||
final ArrayList<PbsAst.TopDecl> supplementalTopDecls,
|
|
||||||
final Set<String> supplementalKeys) {
|
|
||||||
final var pendingTypeNames = new ArrayDeque<String>();
|
|
||||||
final var visitedTypeNames = new HashSet<String>();
|
|
||||||
collectReferencedTypeNames(rootDecl, pendingTypeNames);
|
|
||||||
while (!pendingTypeNames.isEmpty()) {
|
|
||||||
final var typeName = pendingTypeNames.removeFirst();
|
|
||||||
if (!visitedTypeNames.add(typeName)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final var candidates = topDeclsByName.get(typeName);
|
|
||||||
if (candidates == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (final var candidate : candidates) {
|
|
||||||
if (!isTypeDecl(candidate)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
appendSupplementalTopDecl(candidate, supplementalTopDecls, supplementalKeys);
|
|
||||||
collectReferencedTypeNames(candidate, pendingTypeNames);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectReferencedTypeNames(
|
|
||||||
final PbsAst.TopDecl topDecl,
|
|
||||||
final ArrayDeque<String> sink) {
|
|
||||||
if (topDecl instanceof PbsAst.StructDecl structDecl) {
|
|
||||||
for (final var field : structDecl.fields()) {
|
|
||||||
collectReferencedTypeNames(field.typeRef(), sink);
|
|
||||||
}
|
|
||||||
for (final var method : structDecl.methods()) {
|
|
||||||
collectReferencedTypeNames(method, sink);
|
|
||||||
}
|
|
||||||
for (final var ctor : structDecl.ctors()) {
|
|
||||||
for (final var parameter : ctor.parameters()) {
|
|
||||||
collectReferencedTypeNames(parameter.typeRef(), sink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.BuiltinTypeDecl builtinTypeDecl) {
|
|
||||||
for (final var field : builtinTypeDecl.fields()) {
|
|
||||||
collectReferencedTypeNames(field.typeRef(), sink);
|
|
||||||
}
|
|
||||||
for (final var signature : builtinTypeDecl.signatures()) {
|
|
||||||
collectReferencedTypeNames(signature, sink);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.ServiceDecl serviceDecl) {
|
|
||||||
for (final var method : serviceDecl.methods()) {
|
|
||||||
collectReferencedTypeNames(method, sink);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.HostDecl hostDecl) {
|
|
||||||
for (final var signature : hostDecl.signatures()) {
|
|
||||||
collectReferencedTypeNames(signature, sink);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.ContractDecl contractDecl) {
|
|
||||||
for (final var signature : contractDecl.signatures()) {
|
|
||||||
collectReferencedTypeNames(signature, sink);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.CallbackDecl callbackDecl) {
|
|
||||||
collectReferencedTypeNames(callbackDecl.parameters(), callbackDecl.returnType(), callbackDecl.resultErrorType(), sink);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.FunctionDecl functionDecl) {
|
|
||||||
collectReferencedTypeNames(functionDecl, sink);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.ConstDecl constDecl && constDecl.explicitType() != null) {
|
|
||||||
collectReferencedTypeNames(constDecl.explicitType(), sink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectReferencedTypeNames(
|
|
||||||
final PbsAst.FunctionDecl functionDecl,
|
|
||||||
final ArrayDeque<String> sink) {
|
|
||||||
collectReferencedTypeNames(
|
|
||||||
functionDecl.parameters(),
|
|
||||||
functionDecl.returnType(),
|
|
||||||
functionDecl.resultErrorType(),
|
|
||||||
sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectReferencedTypeNames(
|
|
||||||
final PbsAst.FunctionSignature functionSignature,
|
|
||||||
final ArrayDeque<String> sink) {
|
|
||||||
collectReferencedTypeNames(
|
|
||||||
functionSignature.parameters(),
|
|
||||||
functionSignature.returnType(),
|
|
||||||
functionSignature.resultErrorType(),
|
|
||||||
sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectReferencedTypeNames(
|
|
||||||
final ReadOnlyList<PbsAst.Parameter> parameters,
|
|
||||||
final PbsAst.TypeRef returnType,
|
|
||||||
final PbsAst.TypeRef resultErrorType,
|
|
||||||
final ArrayDeque<String> sink) {
|
|
||||||
for (final var parameter : parameters) {
|
|
||||||
collectReferencedTypeNames(parameter.typeRef(), sink);
|
|
||||||
}
|
|
||||||
collectReferencedTypeNames(returnType, sink);
|
|
||||||
collectReferencedTypeNames(resultErrorType, sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectReferencedTypeNames(
|
|
||||||
final PbsAst.TypeRef typeRef,
|
|
||||||
final ArrayDeque<String> sink) {
|
|
||||||
if (typeRef == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (typeRef.kind()) {
|
|
||||||
case SIMPLE -> {
|
|
||||||
final var simpleName = typeRef.name();
|
|
||||||
if (!isPrimitiveTypeName(simpleName)) {
|
|
||||||
sink.addLast(simpleName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case OPTIONAL, GROUP -> collectReferencedTypeNames(typeRef.inner(), sink);
|
|
||||||
case NAMED_TUPLE -> {
|
|
||||||
for (final var field : typeRef.fields()) {
|
|
||||||
collectReferencedTypeNames(field.typeRef(), sink);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case UNIT, SELF, ERROR -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isPrimitiveTypeName(final String typeName) {
|
|
||||||
return "int".equals(typeName)
|
|
||||||
|| "float".equals(typeName)
|
|
||||||
|| "bool".equals(typeName)
|
|
||||||
|| "str".equals(typeName)
|
|
||||||
|| "unit".equals(typeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isTypeDecl(final PbsAst.TopDecl topDecl) {
|
|
||||||
return topDecl instanceof PbsAst.StructDecl
|
|
||||||
|| topDecl instanceof PbsAst.BuiltinTypeDecl
|
|
||||||
|| topDecl instanceof PbsAst.ServiceDecl
|
|
||||||
|| topDecl instanceof PbsAst.HostDecl
|
|
||||||
|| topDecl instanceof PbsAst.ContractDecl
|
|
||||||
|| topDecl instanceof PbsAst.CallbackDecl
|
|
||||||
|| topDecl instanceof PbsAst.EnumDecl
|
|
||||||
|| topDecl instanceof PbsAst.ErrorDecl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendSupplementalTopDecl(
|
|
||||||
final PbsAst.TopDecl topDecl,
|
|
||||||
final ArrayList<PbsAst.TopDecl> supplementalTopDecls,
|
|
||||||
final Set<String> supplementalKeys) {
|
|
||||||
final var key = topDeclKey(topDecl);
|
|
||||||
if (key == null || key.isBlank()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (supplementalKeys.add(key)) {
|
|
||||||
supplementalTopDecls.add(topDecl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendImportedCallable(
|
|
||||||
final ArrayList<PbsFrontendCompiler.ImportedCallableSurface> importedCallables,
|
|
||||||
final Set<String> importedCallableKeys,
|
|
||||||
final PbsFrontendCompiler.ImportedCallableSurface importedCallableSurface) {
|
|
||||||
final var callableKey = importedCallableSurface.moduleId().getIndex()
|
|
||||||
+ "#"
|
|
||||||
+ importedCallableSurface.callableName()
|
|
||||||
+ "#"
|
|
||||||
+ importedCallableSurface.arity()
|
|
||||||
+ "#"
|
|
||||||
+ importedCallableSurface.shapeSurface();
|
|
||||||
if (importedCallableKeys.add(callableKey)) {
|
|
||||||
importedCallables.add(importedCallableSurface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String topDeclKey(final PbsAst.TopDecl topDecl) {
|
|
||||||
final var declName = topDeclName(topDecl);
|
|
||||||
if (declName == null || declName.isBlank()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return topDecl.getClass().getSimpleName() + ":" + declName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String topDeclName(final PbsAst.TopDecl topDecl) {
|
|
||||||
if (topDecl instanceof PbsAst.StructDecl structDecl) {
|
|
||||||
return structDecl.name();
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.BuiltinTypeDecl builtinTypeDecl) {
|
|
||||||
return builtinTypeDecl.name();
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.ConstDecl constDecl) {
|
|
||||||
return constDecl.name();
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.ServiceDecl serviceDecl) {
|
|
||||||
return serviceDecl.name();
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.HostDecl hostDecl) {
|
|
||||||
return hostDecl.name();
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.ContractDecl contractDecl) {
|
|
||||||
return contractDecl.name();
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.FunctionDecl functionDecl) {
|
|
||||||
return functionDecl.name();
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.CallbackDecl callbackDecl) {
|
|
||||||
return callbackDecl.name();
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.EnumDecl enumDecl) {
|
|
||||||
return enumDecl.name();
|
|
||||||
}
|
|
||||||
if (topDecl instanceof PbsAst.ErrorDecl errorDecl) {
|
|
||||||
return errorDecl.name();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IRReservedMetadata mergeReservedMetadata(
|
|
||||||
final IRReservedMetadata left,
|
|
||||||
final IRReservedMetadata right) {
|
|
||||||
final var hostBindings = new ArrayList<IRReservedMetadata.HostMethodBinding>();
|
|
||||||
hostBindings.addAll(left.hostMethodBindings().asList());
|
|
||||||
hostBindings.addAll(right.hostMethodBindings().asList());
|
|
||||||
|
|
||||||
final var builtinTypeSurfaces = new ArrayList<IRReservedMetadata.BuiltinTypeSurface>();
|
|
||||||
builtinTypeSurfaces.addAll(left.builtinTypeSurfaces().asList());
|
|
||||||
builtinTypeSurfaces.addAll(right.builtinTypeSurfaces().asList());
|
|
||||||
|
|
||||||
final var builtinConstSurfaces = new ArrayList<IRReservedMetadata.BuiltinConstSurface>();
|
|
||||||
builtinConstSurfaces.addAll(left.builtinConstSurfaces().asList());
|
|
||||||
builtinConstSurfaces.addAll(right.builtinConstSurfaces().asList());
|
|
||||||
|
|
||||||
final var requiredCapabilities = new HashSet<String>();
|
|
||||||
requiredCapabilities.addAll(left.requiredCapabilities().asList());
|
|
||||||
requiredCapabilities.addAll(right.requiredCapabilities().asList());
|
|
||||||
|
|
||||||
return new IRReservedMetadata(
|
|
||||||
ReadOnlyList.wrap(hostBindings),
|
|
||||||
ReadOnlyList.wrap(builtinTypeSurfaces),
|
|
||||||
ReadOnlyList.wrap(builtinConstSurfaces),
|
|
||||||
ReadOnlyList.wrap(requiredCapabilities.stream().toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private int returnSlotsFor(final PbsAst.FunctionDecl functionDecl) {
|
|
||||||
return switch (functionDecl.returnKind()) {
|
|
||||||
case INFERRED_UNIT, EXPLICIT_UNIT -> 0;
|
|
||||||
case PLAIN, RESULT -> 1;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private String importItemLocalName(final PbsAst.ImportItem importItem) {
|
|
||||||
if (importItem.alias() == null || importItem.alias().isBlank()) {
|
|
||||||
return importItem.name();
|
|
||||||
}
|
|
||||||
return importItem.alias();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<ModuleId> blockedModulesByDependency(
|
private Set<ModuleId> blockedModulesByDependency(
|
||||||
@ -788,50 +154,8 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
|
|||||||
return blocked;
|
return blocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModuleId moduleId(
|
|
||||||
final ModuleTable moduleTable,
|
|
||||||
final PbsModuleVisibilityValidator.ModuleCoordinates coordinates) {
|
|
||||||
return moduleId(moduleTable, coordinates.project(), coordinates.pathSegments());
|
|
||||||
}
|
|
||||||
|
|
||||||
private ModuleId moduleId(
|
|
||||||
final ModuleTable moduleTable,
|
|
||||||
final String project,
|
|
||||||
final ReadOnlyList<String> pathSegments) {
|
|
||||||
return moduleTable.register(new ModuleReference(project, pathSegments));
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReadOnlyList<ModuleReference> emitModulePool(final ModuleTable moduleTable) {
|
|
||||||
final var pool = new ArrayList<ModuleReference>(moduleTable.size());
|
|
||||||
for (final var moduleId : moduleTable.identifiers()) {
|
|
||||||
pool.add(moduleTable.get(moduleId));
|
|
||||||
}
|
|
||||||
return ReadOnlyList.wrap(pool);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class MutableModuleUnit {
|
|
||||||
private final ArrayList<PbsModuleVisibilityValidator.SourceFile> sources = new ArrayList<>();
|
|
||||||
private final ArrayList<PbsModuleVisibilityValidator.BarrelFile> barrels = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private record ParsedSourceFile(
|
|
||||||
FileId fileId,
|
|
||||||
PbsAst.File ast,
|
|
||||||
ModuleId moduleId,
|
|
||||||
SourceKind sourceKind) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private record CompiledSourceFile(
|
private record CompiledSourceFile(
|
||||||
ModuleId moduleId,
|
ModuleId moduleId,
|
||||||
p.studio.compiler.models.IRBackendFile irBackendFile) {
|
p.studio.compiler.models.IRBackendFile irBackendFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private record ImportedSemanticContext(
|
|
||||||
ReadOnlyList<PbsAst.TopDecl> supplementalTopDecls,
|
|
||||||
ReadOnlyList<PbsFrontendCompiler.ImportedCallableSurface> importedCallables,
|
|
||||||
IRReservedMetadata importedReservedMetadata) {
|
|
||||||
private static ImportedSemanticContext empty() {
|
|
||||||
return new ImportedSemanticContext(ReadOnlyList.empty(), ReadOnlyList.empty(), IRReservedMetadata.empty());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
package p.studio.compiler.services;
|
||||||
|
|
||||||
|
import p.studio.compiler.models.IRReservedMetadata;
|
||||||
|
import p.studio.compiler.pbs.PbsFrontendCompiler;
|
||||||
|
import p.studio.compiler.pbs.ast.PbsAst;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
record PbsImportedSemanticContext(
|
||||||
|
ReadOnlyList<PbsAst.TopDecl> supplementalTopDecls,
|
||||||
|
ReadOnlyList<PbsFrontendCompiler.ImportedCallableSurface> importedCallables,
|
||||||
|
IRReservedMetadata importedReservedMetadata) {
|
||||||
|
static PbsImportedSemanticContext empty() {
|
||||||
|
return new PbsImportedSemanticContext(ReadOnlyList.empty(), ReadOnlyList.empty(), IRReservedMetadata.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,409 @@
|
|||||||
|
package p.studio.compiler.services;
|
||||||
|
|
||||||
|
import p.studio.compiler.models.IRReservedMetadata;
|
||||||
|
import p.studio.compiler.pbs.PbsFrontendCompiler;
|
||||||
|
import p.studio.compiler.pbs.ast.PbsAst;
|
||||||
|
import p.studio.compiler.pbs.metadata.PbsReservedMetadataExtractor;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
import p.studio.compiler.source.identifiers.ModuleId;
|
||||||
|
import p.studio.compiler.source.tables.ModuleTable;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
final class PbsImportedSemanticContextService {
|
||||||
|
private final PbsReservedMetadataExtractor reservedMetadataExtractor;
|
||||||
|
private final PbsFrontendCompiler frontendCompiler;
|
||||||
|
|
||||||
|
PbsImportedSemanticContextService(
|
||||||
|
final PbsReservedMetadataExtractor reservedMetadataExtractor,
|
||||||
|
final PbsFrontendCompiler frontendCompiler) {
|
||||||
|
this.reservedMetadataExtractor = reservedMetadataExtractor;
|
||||||
|
this.frontendCompiler = frontendCompiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<FileId, PbsImportedSemanticContext> build(
|
||||||
|
final ReadOnlyList<PbsParsedSourceFile> parsedSourceFiles,
|
||||||
|
final ModuleTable moduleTable) {
|
||||||
|
final Map<ModuleId, ArrayList<PbsParsedSourceFile>> sourcesByModule = new HashMap<>();
|
||||||
|
for (final var parsedSource : parsedSourceFiles) {
|
||||||
|
sourcesByModule
|
||||||
|
.computeIfAbsent(parsedSource.moduleId(), ignored -> new ArrayList<>())
|
||||||
|
.add(parsedSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<ModuleId, IRReservedMetadata> reservedMetadataByModule = new HashMap<>();
|
||||||
|
for (final var entry : sourcesByModule.entrySet()) {
|
||||||
|
var merged = IRReservedMetadata.empty();
|
||||||
|
for (final var source : entry.getValue()) {
|
||||||
|
final var extracted = reservedMetadataExtractor.extract(source.ast(), source.sourceKind());
|
||||||
|
merged = mergeReservedMetadata(merged, extracted);
|
||||||
|
}
|
||||||
|
reservedMetadataByModule.put(entry.getKey(), merged);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<ModuleId, Map<String, ArrayList<PbsAst.TopDecl>>> topDeclsByNameByModule = new HashMap<>();
|
||||||
|
for (final var entry : sourcesByModule.entrySet()) {
|
||||||
|
topDeclsByNameByModule.put(entry.getKey(), indexTopDeclsByName(entry.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<FileId, PbsImportedSemanticContext> contexts = new HashMap<>();
|
||||||
|
for (final var parsedSource : parsedSourceFiles) {
|
||||||
|
final var supplementalTopDecls = new ArrayList<PbsAst.TopDecl>();
|
||||||
|
final var importedCallables = new ArrayList<PbsFrontendCompiler.ImportedCallableSurface>();
|
||||||
|
final var importedCallableKeys = new HashSet<String>();
|
||||||
|
final var supplementalKeys = new HashSet<String>();
|
||||||
|
var importedReservedMetadata = IRReservedMetadata.empty();
|
||||||
|
|
||||||
|
for (final var importDecl : parsedSource.ast().imports()) {
|
||||||
|
final var moduleRef = importDecl.moduleRef();
|
||||||
|
final var importedModuleId = moduleTable.register(
|
||||||
|
new p.studio.compiler.source.tables.ModuleReference(moduleRef.project(), moduleRef.pathSegments()));
|
||||||
|
final var importedSources = sourcesByModule.get(importedModuleId);
|
||||||
|
if (importedSources == null || importedSources.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final var importedTopDeclsByName = topDeclsByNameByModule.get(importedModuleId);
|
||||||
|
if (importedTopDeclsByName == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
importedReservedMetadata = mergeReservedMetadata(
|
||||||
|
importedReservedMetadata,
|
||||||
|
reservedMetadataByModule.getOrDefault(importedModuleId, IRReservedMetadata.empty()));
|
||||||
|
|
||||||
|
for (final var importItem : importDecl.items()) {
|
||||||
|
final var importName = importItem.name();
|
||||||
|
final var localName = importItemLocalName(importItem);
|
||||||
|
final var directDecls = importedTopDeclsByName.getOrDefault(importName, new ArrayList<>());
|
||||||
|
for (final var topDecl : directDecls) {
|
||||||
|
appendSupplementalTopDecl(topDecl, supplementalTopDecls, supplementalKeys);
|
||||||
|
appendTypeDependencyDecls(topDecl, importedTopDeclsByName, supplementalTopDecls, supplementalKeys);
|
||||||
|
if (topDecl instanceof PbsAst.ServiceDecl serviceDecl) {
|
||||||
|
for (final var method : serviceDecl.methods()) {
|
||||||
|
appendImportedCallable(
|
||||||
|
importedCallables,
|
||||||
|
importedCallableKeys,
|
||||||
|
new PbsFrontendCompiler.ImportedCallableSurface(
|
||||||
|
importedModuleId,
|
||||||
|
localName + "." + method.name(),
|
||||||
|
method.parameters().size(),
|
||||||
|
returnSlotsFor(method),
|
||||||
|
frontendCompiler.callableShapeSurfaceOf(method)));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.FunctionDecl functionDecl) {
|
||||||
|
appendImportedCallable(
|
||||||
|
importedCallables,
|
||||||
|
importedCallableKeys,
|
||||||
|
new PbsFrontendCompiler.ImportedCallableSurface(
|
||||||
|
importedModuleId,
|
||||||
|
localName,
|
||||||
|
functionDecl.parameters().size(),
|
||||||
|
returnSlotsFor(functionDecl),
|
||||||
|
frontendCompiler.callableShapeSurfaceOf(functionDecl)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contexts.put(parsedSource.fileId(), new PbsImportedSemanticContext(
|
||||||
|
ReadOnlyList.wrap(supplementalTopDecls),
|
||||||
|
ReadOnlyList.wrap(importedCallables),
|
||||||
|
importedReservedMetadata));
|
||||||
|
}
|
||||||
|
|
||||||
|
return contexts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, ArrayList<PbsAst.TopDecl>> indexTopDeclsByName(
|
||||||
|
final List<PbsParsedSourceFile> moduleSources) {
|
||||||
|
final Map<String, ArrayList<PbsAst.TopDecl>> index = new HashMap<>();
|
||||||
|
for (final var source : moduleSources) {
|
||||||
|
for (final var topDecl : source.ast().topDecls()) {
|
||||||
|
final var declName = topDeclName(topDecl);
|
||||||
|
if (declName == null || declName.isBlank()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
index.computeIfAbsent(declName, ignored -> new ArrayList<>()).add(topDecl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendTypeDependencyDecls(
|
||||||
|
final PbsAst.TopDecl rootDecl,
|
||||||
|
final Map<String, ArrayList<PbsAst.TopDecl>> topDeclsByName,
|
||||||
|
final ArrayList<PbsAst.TopDecl> supplementalTopDecls,
|
||||||
|
final Set<String> supplementalKeys) {
|
||||||
|
final var pendingTypeNames = new ArrayDeque<String>();
|
||||||
|
final var visitedTypeNames = new HashSet<String>();
|
||||||
|
collectReferencedTypeNames(rootDecl, pendingTypeNames);
|
||||||
|
while (!pendingTypeNames.isEmpty()) {
|
||||||
|
final var typeName = pendingTypeNames.removeFirst();
|
||||||
|
if (!visitedTypeNames.add(typeName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final var candidates = topDeclsByName.get(typeName);
|
||||||
|
if (candidates == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (final var candidate : candidates) {
|
||||||
|
if (!isTypeDecl(candidate)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
appendSupplementalTopDecl(candidate, supplementalTopDecls, supplementalKeys);
|
||||||
|
collectReferencedTypeNames(candidate, pendingTypeNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectReferencedTypeNames(
|
||||||
|
final PbsAst.TopDecl topDecl,
|
||||||
|
final ArrayDeque<String> sink) {
|
||||||
|
if (topDecl instanceof PbsAst.StructDecl structDecl) {
|
||||||
|
for (final var field : structDecl.fields()) {
|
||||||
|
collectReferencedTypeNames(field.typeRef(), sink);
|
||||||
|
}
|
||||||
|
for (final var method : structDecl.methods()) {
|
||||||
|
collectReferencedTypeNames(method, sink);
|
||||||
|
}
|
||||||
|
for (final var ctor : structDecl.ctors()) {
|
||||||
|
for (final var parameter : ctor.parameters()) {
|
||||||
|
collectReferencedTypeNames(parameter.typeRef(), sink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.BuiltinTypeDecl builtinTypeDecl) {
|
||||||
|
for (final var field : builtinTypeDecl.fields()) {
|
||||||
|
collectReferencedTypeNames(field.typeRef(), sink);
|
||||||
|
}
|
||||||
|
for (final var signature : builtinTypeDecl.signatures()) {
|
||||||
|
collectReferencedTypeNames(signature, sink);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.ServiceDecl serviceDecl) {
|
||||||
|
for (final var method : serviceDecl.methods()) {
|
||||||
|
collectReferencedTypeNames(method, sink);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.HostDecl hostDecl) {
|
||||||
|
for (final var signature : hostDecl.signatures()) {
|
||||||
|
collectReferencedTypeNames(signature, sink);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.ContractDecl contractDecl) {
|
||||||
|
for (final var signature : contractDecl.signatures()) {
|
||||||
|
collectReferencedTypeNames(signature, sink);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.CallbackDecl callbackDecl) {
|
||||||
|
collectReferencedTypeNames(callbackDecl.parameters(), callbackDecl.returnType(), callbackDecl.resultErrorType(), sink);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.FunctionDecl functionDecl) {
|
||||||
|
collectReferencedTypeNames(functionDecl, sink);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.ConstDecl constDecl && constDecl.explicitType() != null) {
|
||||||
|
collectReferencedTypeNames(constDecl.explicitType(), sink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectReferencedTypeNames(
|
||||||
|
final PbsAst.FunctionDecl functionDecl,
|
||||||
|
final ArrayDeque<String> sink) {
|
||||||
|
collectReferencedTypeNames(
|
||||||
|
functionDecl.parameters(),
|
||||||
|
functionDecl.returnType(),
|
||||||
|
functionDecl.resultErrorType(),
|
||||||
|
sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectReferencedTypeNames(
|
||||||
|
final PbsAst.FunctionSignature functionSignature,
|
||||||
|
final ArrayDeque<String> sink) {
|
||||||
|
collectReferencedTypeNames(
|
||||||
|
functionSignature.parameters(),
|
||||||
|
functionSignature.returnType(),
|
||||||
|
functionSignature.resultErrorType(),
|
||||||
|
sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectReferencedTypeNames(
|
||||||
|
final ReadOnlyList<PbsAst.Parameter> parameters,
|
||||||
|
final PbsAst.TypeRef returnType,
|
||||||
|
final PbsAst.TypeRef resultErrorType,
|
||||||
|
final ArrayDeque<String> sink) {
|
||||||
|
for (final var parameter : parameters) {
|
||||||
|
collectReferencedTypeNames(parameter.typeRef(), sink);
|
||||||
|
}
|
||||||
|
collectReferencedTypeNames(returnType, sink);
|
||||||
|
collectReferencedTypeNames(resultErrorType, sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectReferencedTypeNames(
|
||||||
|
final PbsAst.TypeRef typeRef,
|
||||||
|
final ArrayDeque<String> sink) {
|
||||||
|
if (typeRef == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (typeRef.kind()) {
|
||||||
|
case SIMPLE -> {
|
||||||
|
final var simpleName = typeRef.name();
|
||||||
|
if (!isPrimitiveTypeName(simpleName)) {
|
||||||
|
sink.addLast(simpleName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case OPTIONAL, GROUP -> collectReferencedTypeNames(typeRef.inner(), sink);
|
||||||
|
case NAMED_TUPLE -> {
|
||||||
|
for (final var field : typeRef.fields()) {
|
||||||
|
collectReferencedTypeNames(field.typeRef(), sink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case UNIT, SELF, ERROR -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPrimitiveTypeName(final String typeName) {
|
||||||
|
return "int".equals(typeName)
|
||||||
|
|| "float".equals(typeName)
|
||||||
|
|| "bool".equals(typeName)
|
||||||
|
|| "str".equals(typeName)
|
||||||
|
|| "unit".equals(typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTypeDecl(final PbsAst.TopDecl topDecl) {
|
||||||
|
return topDecl instanceof PbsAst.StructDecl
|
||||||
|
|| topDecl instanceof PbsAst.BuiltinTypeDecl
|
||||||
|
|| topDecl instanceof PbsAst.ServiceDecl
|
||||||
|
|| topDecl instanceof PbsAst.HostDecl
|
||||||
|
|| topDecl instanceof PbsAst.ContractDecl
|
||||||
|
|| topDecl instanceof PbsAst.CallbackDecl
|
||||||
|
|| topDecl instanceof PbsAst.EnumDecl
|
||||||
|
|| topDecl instanceof PbsAst.ErrorDecl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendSupplementalTopDecl(
|
||||||
|
final PbsAst.TopDecl topDecl,
|
||||||
|
final ArrayList<PbsAst.TopDecl> supplementalTopDecls,
|
||||||
|
final Set<String> supplementalKeys) {
|
||||||
|
final var key = topDeclKey(topDecl);
|
||||||
|
if (key == null || key.isBlank()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (supplementalKeys.add(key)) {
|
||||||
|
supplementalTopDecls.add(topDecl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendImportedCallable(
|
||||||
|
final ArrayList<PbsFrontendCompiler.ImportedCallableSurface> importedCallables,
|
||||||
|
final Set<String> importedCallableKeys,
|
||||||
|
final PbsFrontendCompiler.ImportedCallableSurface importedCallableSurface) {
|
||||||
|
final var callableKey = importedCallableSurface.moduleId().getIndex()
|
||||||
|
+ "#"
|
||||||
|
+ importedCallableSurface.callableName()
|
||||||
|
+ "#"
|
||||||
|
+ importedCallableSurface.arity()
|
||||||
|
+ "#"
|
||||||
|
+ importedCallableSurface.shapeSurface();
|
||||||
|
if (importedCallableKeys.add(callableKey)) {
|
||||||
|
importedCallables.add(importedCallableSurface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String topDeclKey(final PbsAst.TopDecl topDecl) {
|
||||||
|
final var declName = topDeclName(topDecl);
|
||||||
|
if (declName == null || declName.isBlank()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return topDecl.getClass().getSimpleName() + ":" + declName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String topDeclName(final PbsAst.TopDecl topDecl) {
|
||||||
|
if (topDecl instanceof PbsAst.StructDecl structDecl) {
|
||||||
|
return structDecl.name();
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.BuiltinTypeDecl builtinTypeDecl) {
|
||||||
|
return builtinTypeDecl.name();
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.ConstDecl constDecl) {
|
||||||
|
return constDecl.name();
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.ServiceDecl serviceDecl) {
|
||||||
|
return serviceDecl.name();
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.HostDecl hostDecl) {
|
||||||
|
return hostDecl.name();
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.ContractDecl contractDecl) {
|
||||||
|
return contractDecl.name();
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.FunctionDecl functionDecl) {
|
||||||
|
return functionDecl.name();
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.CallbackDecl callbackDecl) {
|
||||||
|
return callbackDecl.name();
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.EnumDecl enumDecl) {
|
||||||
|
return enumDecl.name();
|
||||||
|
}
|
||||||
|
if (topDecl instanceof PbsAst.ErrorDecl errorDecl) {
|
||||||
|
return errorDecl.name();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IRReservedMetadata mergeReservedMetadata(
|
||||||
|
final IRReservedMetadata left,
|
||||||
|
final IRReservedMetadata right) {
|
||||||
|
final var hostBindings = new ArrayList<IRReservedMetadata.HostMethodBinding>();
|
||||||
|
hostBindings.addAll(left.hostMethodBindings().asList());
|
||||||
|
hostBindings.addAll(right.hostMethodBindings().asList());
|
||||||
|
|
||||||
|
final var builtinTypeSurfaces = new ArrayList<IRReservedMetadata.BuiltinTypeSurface>();
|
||||||
|
builtinTypeSurfaces.addAll(left.builtinTypeSurfaces().asList());
|
||||||
|
builtinTypeSurfaces.addAll(right.builtinTypeSurfaces().asList());
|
||||||
|
|
||||||
|
final var builtinConstSurfaces = new ArrayList<IRReservedMetadata.BuiltinConstSurface>();
|
||||||
|
builtinConstSurfaces.addAll(left.builtinConstSurfaces().asList());
|
||||||
|
builtinConstSurfaces.addAll(right.builtinConstSurfaces().asList());
|
||||||
|
|
||||||
|
final var requiredCapabilities = new HashSet<String>();
|
||||||
|
requiredCapabilities.addAll(left.requiredCapabilities().asList());
|
||||||
|
requiredCapabilities.addAll(right.requiredCapabilities().asList());
|
||||||
|
|
||||||
|
return new IRReservedMetadata(
|
||||||
|
ReadOnlyList.wrap(hostBindings),
|
||||||
|
ReadOnlyList.wrap(builtinTypeSurfaces),
|
||||||
|
ReadOnlyList.wrap(builtinConstSurfaces),
|
||||||
|
ReadOnlyList.wrap(requiredCapabilities.stream().toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int returnSlotsFor(final PbsAst.FunctionDecl functionDecl) {
|
||||||
|
return switch (functionDecl.returnKind()) {
|
||||||
|
case INFERRED_UNIT, EXPLICIT_UNIT -> 0;
|
||||||
|
case PLAIN, RESULT -> 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String importItemLocalName(final PbsAst.ImportItem importItem) {
|
||||||
|
if (importItem.alias() == null || importItem.alias().isBlank()) {
|
||||||
|
return importItem.name();
|
||||||
|
}
|
||||||
|
return importItem.alias();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package p.studio.compiler.services;
|
||||||
|
|
||||||
|
import p.studio.compiler.source.identifiers.ModuleId;
|
||||||
|
import p.studio.compiler.source.tables.ModuleReference;
|
||||||
|
import p.studio.compiler.source.tables.ModuleTable;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
record PbsModuleAssembly(
|
||||||
|
ReadOnlyList<PbsParsedSourceFile> parsedSourceFiles,
|
||||||
|
Map<ModuleId, Set<ModuleId>> moduleDependencyGraph,
|
||||||
|
ReadOnlyList<ModuleReference> canonicalModulePool,
|
||||||
|
Set<ModuleId> failedModuleIds,
|
||||||
|
ModuleTable moduleTable) {
|
||||||
|
PbsModuleAssembly {
|
||||||
|
parsedSourceFiles = parsedSourceFiles == null ? ReadOnlyList.empty() : parsedSourceFiles;
|
||||||
|
canonicalModulePool = canonicalModulePool == null ? ReadOnlyList.empty() : canonicalModulePool;
|
||||||
|
failedModuleIds = failedModuleIds == null ? Set.of() : Set.copyOf(failedModuleIds);
|
||||||
|
|
||||||
|
if (moduleDependencyGraph == null || moduleDependencyGraph.isEmpty()) {
|
||||||
|
moduleDependencyGraph = Map.of();
|
||||||
|
} else {
|
||||||
|
final var copiedGraph = new HashMap<ModuleId, Set<ModuleId>>();
|
||||||
|
for (final var entry : moduleDependencyGraph.entrySet()) {
|
||||||
|
copiedGraph.put(entry.getKey(), Set.copyOf(entry.getValue() == null ? Set.of() : entry.getValue()));
|
||||||
|
}
|
||||||
|
moduleDependencyGraph = Map.copyOf(copiedGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleTable == null) {
|
||||||
|
moduleTable = new ModuleTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<ModuleId> mutableFailedModuleIds() {
|
||||||
|
return new HashSet<>(failedModuleIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,372 @@
|
|||||||
|
package p.studio.compiler.services;
|
||||||
|
|
||||||
|
import p.studio.compiler.messages.BuildingIssueSink;
|
||||||
|
import p.studio.compiler.messages.FrontendPhaseContext;
|
||||||
|
import p.studio.compiler.models.ProjectDescriptor;
|
||||||
|
import p.studio.compiler.models.SourceHandle;
|
||||||
|
import p.studio.compiler.models.SourceKind;
|
||||||
|
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.pbs.stdlib.InterfaceModuleLoader;
|
||||||
|
import p.studio.compiler.pbs.stdlib.StdlibEnvironmentResolver;
|
||||||
|
import p.studio.compiler.source.Span;
|
||||||
|
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
|
||||||
|
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||||
|
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.compiler.source.tables.NameTable;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
final class PbsModuleAssemblyService {
|
||||||
|
private final StdlibEnvironmentResolver stdlibEnvironmentResolver;
|
||||||
|
private final InterfaceModuleLoader interfaceModuleLoader;
|
||||||
|
private final PbsModuleVisibilityValidator moduleVisibilityValidator;
|
||||||
|
|
||||||
|
PbsModuleAssemblyService(
|
||||||
|
final StdlibEnvironmentResolver stdlibEnvironmentResolver,
|
||||||
|
final InterfaceModuleLoader interfaceModuleLoader,
|
||||||
|
final PbsModuleVisibilityValidator moduleVisibilityValidator) {
|
||||||
|
this.stdlibEnvironmentResolver = stdlibEnvironmentResolver;
|
||||||
|
this.interfaceModuleLoader = interfaceModuleLoader;
|
||||||
|
this.moduleVisibilityValidator = moduleVisibilityValidator;
|
||||||
|
}
|
||||||
|
|
||||||
|
PbsModuleAssembly assemble(
|
||||||
|
final FrontendPhaseContext ctx,
|
||||||
|
final NameTable nameTable,
|
||||||
|
final DiagnosticSink diagnostics,
|
||||||
|
final BuildingIssueSink issues) {
|
||||||
|
if (!(ctx.fileTable instanceof FileTable writableFileTable)) {
|
||||||
|
throw new IllegalStateException("PBS frontend requires writable FileTable for synthetic stdlib sources");
|
||||||
|
}
|
||||||
|
|
||||||
|
final var parsedSourceFiles = new ArrayList<PbsParsedSourceFile>();
|
||||||
|
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 projectId : ctx.stack.reverseTopologicalOrder) {
|
||||||
|
final var projectDescriptor = ctx.projectTable.get(projectId);
|
||||||
|
final var projectSourceKind = ctx.sourceKind(projectId);
|
||||||
|
final var fileIds = ctx.fileTable.getFiles(projectId);
|
||||||
|
projectIdByName.putIfAbsent(projectDescriptor.getName(), projectId);
|
||||||
|
|
||||||
|
for (final var fileId : fileIds) {
|
||||||
|
final var sourceHandle = ctx.fileTable.get(fileId);
|
||||||
|
sourceHandle.readUtf8().ifPresentOrElse(
|
||||||
|
utf8Content -> consumeSourceFile(
|
||||||
|
projectDescriptor,
|
||||||
|
projectSourceKind,
|
||||||
|
sourceHandle,
|
||||||
|
fileId,
|
||||||
|
utf8Content,
|
||||||
|
diagnostics,
|
||||||
|
modulesByCoordinates,
|
||||||
|
moduleTable,
|
||||||
|
moduleIdByFile,
|
||||||
|
failedModuleIds,
|
||||||
|
parsedSourceFiles),
|
||||||
|
() -> issues.report(builder -> builder
|
||||||
|
.error(true)
|
||||||
|
.message("Failed to read file content: %s".formatted(sourceHandle.toString()))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadReservedStdlibModules(
|
||||||
|
modulesByCoordinates,
|
||||||
|
parsedSourceFiles,
|
||||||
|
moduleIdByFile,
|
||||||
|
moduleTable,
|
||||||
|
writableFileTable,
|
||||||
|
projectIdByName,
|
||||||
|
defaultSyntheticOwnerProjectId,
|
||||||
|
diagnostics,
|
||||||
|
ctx.stdlibVersion());
|
||||||
|
|
||||||
|
final var modules = new ArrayList<PbsModuleVisibilityValidator.ModuleUnit>(modulesByCoordinates.size());
|
||||||
|
for (final var entry : modulesByCoordinates.entrySet()) {
|
||||||
|
modules.add(new PbsModuleVisibilityValidator.ModuleUnit(
|
||||||
|
entry.getKey(),
|
||||||
|
ReadOnlyList.wrap(entry.getValue().sources),
|
||||||
|
ReadOnlyList.wrap(entry.getValue().barrels)));
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleVisibilityValidator.validate(ReadOnlyList.wrap(modules), nameTable, diagnostics);
|
||||||
|
markModulesWithLinkingErrors(diagnostics, moduleIdByFile, failedModuleIds);
|
||||||
|
|
||||||
|
return new PbsModuleAssembly(
|
||||||
|
ReadOnlyList.wrap(parsedSourceFiles),
|
||||||
|
buildModuleDependencyGraph(parsedSourceFiles, moduleTable),
|
||||||
|
emitModulePool(moduleTable),
|
||||||
|
failedModuleIds,
|
||||||
|
moduleTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void consumeSourceFile(
|
||||||
|
final ProjectDescriptor projectDescriptor,
|
||||||
|
final SourceKind projectSourceKind,
|
||||||
|
final SourceHandle sourceHandle,
|
||||||
|
final FileId fileId,
|
||||||
|
final String utf8Content,
|
||||||
|
final DiagnosticSink diagnostics,
|
||||||
|
final Map<PbsModuleVisibilityValidator.ModuleCoordinates, MutableModuleUnit> modulesByCoordinates,
|
||||||
|
final ModuleTable moduleTable,
|
||||||
|
final Map<FileId, ModuleId> moduleIdByFile,
|
||||||
|
final Set<ModuleId> failedModuleIds,
|
||||||
|
final ArrayList<PbsParsedSourceFile> parsedSourceFiles) {
|
||||||
|
final var coordinates = resolveModuleCoordinates(projectDescriptor, sourceHandle);
|
||||||
|
final var moduleId = moduleId(moduleTable, coordinates);
|
||||||
|
final var moduleUnit = modulesByCoordinates.computeIfAbsent(coordinates, ignored -> new MutableModuleUnit());
|
||||||
|
|
||||||
|
switch (sourceHandle.getExtension()) {
|
||||||
|
case "pbs" -> {
|
||||||
|
moduleIdByFile.put(fileId, moduleId);
|
||||||
|
final var parseErrorBaseline = diagnostics.errorCount();
|
||||||
|
final var ast = parseSourceFile(fileId, utf8Content, diagnostics, projectSourceKind);
|
||||||
|
moduleUnit.sources.add(new PbsModuleVisibilityValidator.SourceFile(fileId, ast));
|
||||||
|
parsedSourceFiles.add(new PbsParsedSourceFile(fileId, ast, moduleId, projectSourceKind));
|
||||||
|
if (diagnostics.errorCount() > parseErrorBaseline) {
|
||||||
|
failedModuleIds.add(moduleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "barrel" -> {
|
||||||
|
moduleIdByFile.put(fileId, moduleId);
|
||||||
|
if ("mod.barrel".equals(sourceHandle.getFilename())) {
|
||||||
|
final var parseErrorBaseline = diagnostics.errorCount();
|
||||||
|
final var barrelAst = parseBarrelFile(fileId, utf8Content, diagnostics);
|
||||||
|
moduleUnit.barrels.add(new PbsModuleVisibilityValidator.BarrelFile(fileId, barrelAst));
|
||||||
|
if (diagnostics.errorCount() > parseErrorBaseline) {
|
||||||
|
failedModuleIds.add(moduleId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p.studio.compiler.source.diagnostics.Diagnostics.error(
|
||||||
|
diagnostics,
|
||||||
|
PbsLinkErrors.E_LINK_INVALID_BARREL_FILENAME.name(),
|
||||||
|
"Only 'mod.barrel' is allowed as barrel filename",
|
||||||
|
new Span(fileId, 0, utf8Content.getBytes(StandardCharsets.UTF_8).length));
|
||||||
|
failedModuleIds.add(moduleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadReservedStdlibModules(
|
||||||
|
final Map<PbsModuleVisibilityValidator.ModuleCoordinates, MutableModuleUnit> modulesByCoordinates,
|
||||||
|
final ArrayList<PbsParsedSourceFile> 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);
|
||||||
|
final var pending = new ArrayDeque<PbsModuleVisibilityValidator.ModuleCoordinates>();
|
||||||
|
final var resolved = new HashSet<ModuleId>();
|
||||||
|
|
||||||
|
enqueueReservedImportsFromKnownModules(modulesByCoordinates, pending);
|
||||||
|
while (!pending.isEmpty()) {
|
||||||
|
final var target = pending.removeFirst();
|
||||||
|
final var targetId = moduleId(moduleTable, target);
|
||||||
|
if (!resolved.add(targetId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (modulesByCoordinates.containsKey(target)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final var moduleSource = stdlibEnvironment.resolveModule(target.project(), target.pathSegments());
|
||||||
|
if (moduleSource.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
modulesByCoordinates.put(loadedModule.coordinates(), moduleData);
|
||||||
|
for (final var sourceFile : loadedModule.sourceFiles()) {
|
||||||
|
moduleIdByFile.put(sourceFile.fileId(), targetId);
|
||||||
|
parsedSourceFiles.add(new PbsParsedSourceFile(
|
||||||
|
sourceFile.fileId(),
|
||||||
|
sourceFile.ast(),
|
||||||
|
targetId,
|
||||||
|
SourceKind.SDK_INTERFACE));
|
||||||
|
}
|
||||||
|
for (final var barrelFile : loadedModule.barrelFiles()) {
|
||||||
|
moduleIdByFile.put(barrelFile.fileId(), targetId);
|
||||||
|
}
|
||||||
|
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(
|
||||||
|
final FileId fileId,
|
||||||
|
final String source,
|
||||||
|
final DiagnosticSink diagnostics,
|
||||||
|
final SourceKind sourceKind) {
|
||||||
|
final var tokens = PbsLexer.lex(source, fileId, diagnostics);
|
||||||
|
final var parseMode = sourceKind == SourceKind.SDK_INTERFACE
|
||||||
|
? PbsParser.ParseMode.INTERFACE_MODULE
|
||||||
|
: PbsParser.ParseMode.ORDINARY;
|
||||||
|
return PbsParser.parse(tokens, fileId, diagnostics, parseMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PbsAst.BarrelFile parseBarrelFile(
|
||||||
|
final FileId fileId,
|
||||||
|
final String source,
|
||||||
|
final DiagnosticSink diagnostics) {
|
||||||
|
final var tokens = PbsLexer.lex(source, fileId, diagnostics);
|
||||||
|
return PbsBarrelParser.parse(tokens, fileId, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PbsModuleVisibilityValidator.ModuleCoordinates resolveModuleCoordinates(
|
||||||
|
final ProjectDescriptor projectDescriptor,
|
||||||
|
final SourceHandle sourceHandle) {
|
||||||
|
final var sourceRelativePath = sourceRelativePath(projectDescriptor, sourceHandle);
|
||||||
|
final var modulePath = sourceRelativePath.getParent();
|
||||||
|
final var pathSegments = new ArrayList<String>();
|
||||||
|
if (modulePath != null) {
|
||||||
|
for (final var segment : modulePath) {
|
||||||
|
pathSegments.add(segment.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PbsModuleVisibilityValidator.ModuleCoordinates(
|
||||||
|
projectDescriptor.getName(),
|
||||||
|
ReadOnlyList.wrap(pathSegments));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path sourceRelativePath(
|
||||||
|
final ProjectDescriptor projectDescriptor,
|
||||||
|
final SourceHandle sourceHandle) {
|
||||||
|
final var canonPath = sourceHandle.getCanonPath();
|
||||||
|
for (final var sourceRoot : projectDescriptor.getSourceRoots()) {
|
||||||
|
if (canonPath.startsWith(sourceRoot)) {
|
||||||
|
return sourceRoot.relativize(canonPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sourceHandle.getRelativePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markModulesWithLinkingErrors(
|
||||||
|
final DiagnosticSink diagnostics,
|
||||||
|
final Map<FileId, ModuleId> moduleIdByFile,
|
||||||
|
final Set<ModuleId> failedModuleIds) {
|
||||||
|
for (final var diagnostic : diagnostics) {
|
||||||
|
if (!diagnostic.getSeverity().isError()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (diagnostic.getPhase() != DiagnosticPhase.LINKING) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final var moduleId = moduleIdByFile.get(diagnostic.getSpan().getFileId());
|
||||||
|
if (moduleId != null) {
|
||||||
|
failedModuleIds.add(moduleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<ModuleId, Set<ModuleId>> buildModuleDependencyGraph(
|
||||||
|
final ArrayList<PbsParsedSourceFile> parsedSourceFiles,
|
||||||
|
final ModuleTable moduleTable) {
|
||||||
|
final Map<ModuleId, Set<ModuleId>> dependenciesByModule = new HashMap<>();
|
||||||
|
for (final var parsedSource : parsedSourceFiles) {
|
||||||
|
final var moduleDependencies = dependenciesByModule.computeIfAbsent(
|
||||||
|
parsedSource.moduleId(),
|
||||||
|
ignored -> new HashSet<>());
|
||||||
|
for (final var importDecl : parsedSource.ast().imports()) {
|
||||||
|
final var moduleRef = importDecl.moduleRef();
|
||||||
|
moduleDependencies.add(moduleId(moduleTable, moduleRef.project(), moduleRef.pathSegments()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dependenciesByModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModuleId moduleId(
|
||||||
|
final ModuleTable moduleTable,
|
||||||
|
final PbsModuleVisibilityValidator.ModuleCoordinates coordinates) {
|
||||||
|
return moduleId(moduleTable, coordinates.project(), coordinates.pathSegments());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModuleId moduleId(
|
||||||
|
final ModuleTable moduleTable,
|
||||||
|
final String project,
|
||||||
|
final ReadOnlyList<String> pathSegments) {
|
||||||
|
return moduleTable.register(new ModuleReference(project, pathSegments));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReadOnlyList<ModuleReference> emitModulePool(final ModuleTable moduleTable) {
|
||||||
|
final var pool = new ArrayList<ModuleReference>(moduleTable.size());
|
||||||
|
for (final var moduleId : moduleTable.identifiers()) {
|
||||||
|
pool.add(moduleTable.get(moduleId));
|
||||||
|
}
|
||||||
|
return ReadOnlyList.wrap(pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class MutableModuleUnit {
|
||||||
|
private final ArrayList<PbsModuleVisibilityValidator.SourceFile> sources = new ArrayList<>();
|
||||||
|
private final ArrayList<PbsModuleVisibilityValidator.BarrelFile> barrels = new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package p.studio.compiler.services;
|
||||||
|
|
||||||
|
import p.studio.compiler.models.SourceKind;
|
||||||
|
import p.studio.compiler.pbs.ast.PbsAst;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
import p.studio.compiler.source.identifiers.ModuleId;
|
||||||
|
|
||||||
|
record PbsParsedSourceFile(
|
||||||
|
FileId fileId,
|
||||||
|
PbsAst.File ast,
|
||||||
|
ModuleId moduleId,
|
||||||
|
SourceKind sourceKind) {
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user