diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsFrontendCompiler.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsFrontendCompiler.java index 0065eca7..ee7f1d0b 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsFrontendCompiler.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsFrontendCompiler.java @@ -31,6 +31,7 @@ import p.studio.utilities.structures.ReadOnlyList; import java.util.ArrayList; import java.util.HashSet; +import java.util.Map; public final class PbsFrontendCompiler { private final PbsFlowSemanticsValidator flowSemanticsValidator = new PbsFlowSemanticsValidator(); @@ -103,7 +104,8 @@ public final class PbsFrontendCompiler { ReadOnlyList.empty(), ReadOnlyList.empty(), ReadOnlyList.empty(), - IRReservedMetadata.empty()); + IRReservedMetadata.empty(), + Map.of()); } public IRBackendFile compileParsedFile( @@ -118,7 +120,8 @@ public final class PbsFrontendCompiler { final ReadOnlyList supplementalTopDecls, final ReadOnlyList importedCallables, final ReadOnlyList importedGlobals, - final IRReservedMetadata importedReservedMetadata) { + final IRReservedMetadata importedReservedMetadata, + final Map declaredGlobalVisibilityByName) { final var effectiveModuleId = moduleId == null ? ModuleId.none() : moduleId; final var effectiveModulePool = modulePool == null ? ReadOnlyList.empty() : modulePool; final var effectiveNameTable = nameTable == null ? new NameTable() : nameTable; @@ -134,6 +137,9 @@ public final class PbsFrontendCompiler { final var effectiveImportedReservedMetadata = importedReservedMetadata == null ? IRReservedMetadata.empty() : importedReservedMetadata; + final var effectiveDeclaredGlobalVisibilityByName = declaredGlobalVisibilityByName == null + ? Map.of() + : Map.copyOf(declaredGlobalVisibilityByName); final var semanticsErrorBaseline = diagnostics.errorCount(); new PbsDeclarationSemanticsValidator(effectiveNameTable).validate( ast, @@ -164,7 +170,7 @@ public final class PbsFrontendCompiler { : lowerSyntheticFunctions(fileId, effectiveModuleId, ast); final ReadOnlyList globals = sourceKind == SourceKind.SDK_INTERFACE ? ReadOnlyList.empty() - : lowerGlobals(fileId, effectiveModuleId, ast); + : lowerGlobals(fileId, effectiveModuleId, ast, effectiveDeclaredGlobalVisibilityByName); final var loweringErrorBaseline = diagnostics.errorCount(); final var executableLowering = executableLoweringService.lower( fileId, @@ -243,7 +249,8 @@ public final class PbsFrontendCompiler { private ReadOnlyList lowerGlobals( final FileId fileId, final ModuleId moduleId, - final PbsAst.File ast) { + final PbsAst.File ast, + final Map declaredGlobalVisibilityByName) { final var globals = new ArrayList(); var nextSlot = 0; for (final var topDecl : ast.topDecls()) { @@ -256,7 +263,7 @@ public final class PbsFrontendCompiler { globalDecl.name(), PbsReservedMetadataExtractor.typeSurfaceKey(globalDecl.explicitType()), nextSlot++, - IRGlobalVisibility.MODULE, + declaredGlobalVisibilityByName.getOrDefault(globalDecl.name(), IRGlobalVisibility.MODULE), false, p.studio.compiler.models.IRHiddenGlobalKind.NONE, new IRGlobalOrigin( diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PBSFrontendPhaseService.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PBSFrontendPhaseService.java index e41d9017..91ff0df0 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PBSFrontendPhaseService.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PBSFrontendPhaseService.java @@ -89,7 +89,8 @@ public class PBSFrontendPhaseService implements FrontendPhaseService { importedSemanticContext.supplementalTopDecls(), importedSemanticContext.importedCallables(), importedSemanticContext.importedGlobals(), - importedSemanticContext.importedReservedMetadata()); + importedSemanticContext.importedReservedMetadata(), + assembly.globalVisibilityByModule().getOrDefault(parsedSource.moduleId(), Map.of())); if (diagnostics.errorCount() > compileErrorBaseline) { failedModuleIds.add(parsedSource.moduleId()); } diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PbsModuleAssembly.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PbsModuleAssembly.java index e1f05835..5c056144 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PbsModuleAssembly.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PbsModuleAssembly.java @@ -1,5 +1,6 @@ package p.studio.compiler.services; +import p.studio.compiler.models.IRGlobalVisibility; import p.studio.compiler.source.identifiers.ModuleId; import p.studio.compiler.source.tables.ModuleReference; import p.studio.compiler.source.tables.ModuleTable; @@ -15,7 +16,8 @@ record PbsModuleAssembly( Map> moduleDependencyGraph, ReadOnlyList canonicalModulePool, Set failedModuleIds, - ModuleTable moduleTable) { + ModuleTable moduleTable, + Map> globalVisibilityByModule) { PbsModuleAssembly { parsedSourceFiles = parsedSourceFiles == null ? ReadOnlyList.empty() : parsedSourceFiles; canonicalModulePool = canonicalModulePool == null ? ReadOnlyList.empty() : canonicalModulePool; @@ -34,6 +36,15 @@ record PbsModuleAssembly( if (moduleTable == null) { moduleTable = new ModuleTable(); } + if (globalVisibilityByModule == null || globalVisibilityByModule.isEmpty()) { + globalVisibilityByModule = Map.of(); + } else { + final var copiedVisibility = new HashMap>(); + for (final var entry : globalVisibilityByModule.entrySet()) { + copiedVisibility.put(entry.getKey(), Map.copyOf(entry.getValue() == null ? Map.of() : entry.getValue())); + } + globalVisibilityByModule = Map.copyOf(copiedVisibility); + } } Set mutableFailedModuleIds() { diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PbsModuleAssemblyService.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PbsModuleAssemblyService.java index 3d1b44d5..de396340 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PbsModuleAssemblyService.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PbsModuleAssemblyService.java @@ -2,6 +2,7 @@ package p.studio.compiler.services; import p.studio.compiler.messages.BuildingIssueSink; import p.studio.compiler.messages.FrontendPhaseContext; +import p.studio.compiler.models.IRGlobalVisibility; import p.studio.compiler.models.ProjectDescriptor; import p.studio.compiler.models.SourceHandle; import p.studio.compiler.models.SourceKind; @@ -116,7 +117,34 @@ final class PbsModuleAssemblyService { buildModuleDependencyGraph(parsedSourceFiles, moduleTable), emitModulePool(moduleTable), failedModuleIds, - moduleTable); + moduleTable, + collectGlobalVisibilityByModule(modulesByCoordinates, moduleTable)); + } + + private Map> collectGlobalVisibilityByModule( + final Map modulesByCoordinates, + final ModuleTable moduleTable) { + final var visibilityByModule = new LinkedHashMap>(); + for (final var entry : modulesByCoordinates.entrySet()) { + final var moduleId = moduleId(moduleTable, entry.getKey()); + final var visibilityByGlobal = new LinkedHashMap(); + for (final var barrelFile : entry.getValue().barrels) { + for (final var item : barrelFile.ast().items()) { + if (!(item instanceof PbsAst.BarrelGlobalItem globalItem)) { + continue; + } + visibilityByGlobal.put( + globalItem.name(), + globalItem.visibility() == PbsAst.Visibility.PUB + ? IRGlobalVisibility.PUBLIC + : IRGlobalVisibility.MODULE); + } + } + if (!visibilityByGlobal.isEmpty()) { + visibilityByModule.put(moduleId, Map.copyOf(visibilityByGlobal)); + } + } + return Map.copyOf(visibilityByModule); } private void consumeSourceFile( diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsFrontendCompilerTest.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsFrontendCompilerTest.java index 6b1b4c49..8b11df44 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsFrontendCompilerTest.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsFrontendCompilerTest.java @@ -3,6 +3,7 @@ package p.studio.compiler.pbs; import org.junit.jupiter.api.Test; import p.studio.compiler.messages.HostAdmissionContext; import p.studio.compiler.models.IRHiddenGlobalKind; +import p.studio.compiler.models.IRGlobalVisibility; import p.studio.compiler.models.IRSyntheticCallableKind; import p.studio.compiler.models.SourceKind; import p.studio.compiler.pbs.lexer.LexErrors; @@ -63,6 +64,7 @@ class PbsFrontendCompilerTest { assertEquals(1, fileBackend.globals().size()); assertEquals("SCORE", fileBackend.globals().getFirst().name()); assertEquals(0, fileBackend.globals().getFirst().slot()); + assertEquals(IRGlobalVisibility.MODULE, fileBackend.globals().getFirst().visibility()); assertFalse(fileBackend.globals().getFirst().isHidden()); assertEquals(IRHiddenGlobalKind.NONE, fileBackend.globals().getFirst().hiddenKind()); assertEquals("SCORE", fileBackend.globals().getFirst().origin().derivedFromUserSymbol()); diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java index ac6ab486..411c9f75 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import p.studio.compiler.messages.BuildingIssueSink; import p.studio.compiler.messages.FrontendPhaseContext; +import p.studio.compiler.models.IRGlobalVisibility; import p.studio.compiler.models.BuildStack; import p.studio.compiler.models.IRHiddenGlobalKind; import p.studio.compiler.models.ProjectDescriptor; @@ -363,11 +364,17 @@ class PBSFrontendPhaseServiceTest { assertTrue(diagnostics.isEmpty(), diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString()); assertTrue(irBackend.getEntryPointCallableName().startsWith("__pbs.frame_wrapper$m")); + final var scoreGlobal = irBackend.getGlobals().stream() + .filter(global -> "SCORE".equals(global.name())) + .findFirst() + .orElseThrow(); + assertEquals(IRGlobalVisibility.PUBLIC, scoreGlobal.visibility()); final var bootGuard = irBackend.getGlobals().stream() .filter(global -> global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD) .findFirst() .orElseThrow(); assertTrue(bootGuard.isHidden()); + assertEquals(IRGlobalVisibility.MODULE, bootGuard.visibility()); assertTrue(bootGuard.name().startsWith("__pbs.boot_guard$m")); assertEquals(1, bootGuard.slot()); final var wrapper = irBackend.getExecutableFunctions().stream() @@ -449,7 +456,8 @@ class PBSFrontendPhaseServiceTest { function.callableName().startsWith("__pbs.module_init$m"))); assertTrue(irBackend.getExecutableFunctions().stream().anyMatch(function -> function.callableName().startsWith("__pbs.project_init$m"))); - assertTrue(irBackend.getGlobals().stream().anyMatch(global -> "SCORE".equals(global.name()))); + assertTrue(irBackend.getGlobals().stream().anyMatch(global -> + "SCORE".equals(global.name()) && global.visibility() == IRGlobalVisibility.PUBLIC)); assertTrue(irBackend.getGlobals().stream().anyMatch(global -> global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD)); }