add AppMode for best boundaries over stdlib #10

Merged
bquarkz merged 1 commits from dev/add-app-mode-boundaries-for-stdlib into master 2026-05-14 10:41:12 +00:00
54 changed files with 700 additions and 546 deletions
Showing only changes of commit 991863d086 - Show all commits

2
.gitignore vendored
View File

@ -13,6 +13,8 @@ build
.python-version .python-version
.venv .venv
# IA
.junie
/debug/ /debug/
!prometeu-studio/src/main/java/p/studio/workspaces/debug/ !prometeu-studio/src/main/java/p/studio/workspaces/debug/
!prometeu-studio/src/main/java/p/studio/workspaces/debug/** !prometeu-studio/src/main/java/p/studio/workspaces/debug/**

View File

@ -1,5 +1,6 @@
package p.studio.compiler; package p.studio.compiler;
import p.studio.AppMode;
import p.studio.compiler.models.FrontendSemanticToken; import p.studio.compiler.models.FrontendSemanticToken;
import p.studio.compiler.models.FrontendSemanticTokenProvider; import p.studio.compiler.models.FrontendSemanticTokenProvider;
import p.studio.compiler.pbs.ast.PbsAst; import p.studio.compiler.pbs.ast.PbsAst;
@ -26,6 +27,7 @@ import java.util.Set;
public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProvider { public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProvider {
private static final Set<String> BUILTIN_TYPE_NAMES = Set.of("int", "float", "bool", "string", "i32", "i64", "f32", "f64"); private static final Set<String> BUILTIN_TYPE_NAMES = Set.of("int", "float", "bool", "string", "i32", "i64", "f32", "f64");
private static final int DEFAULT_STDLIB_VERSION = 1; private static final int DEFAULT_STDLIB_VERSION = 1;
private static final AppMode DEFAULT_TARGET = AppMode.Game;
private static final ResourceStdlibEnvironmentResolver STDLIB_RESOLVER = new ResourceStdlibEnvironmentResolver(); private static final ResourceStdlibEnvironmentResolver STDLIB_RESOLVER = new ResourceStdlibEnvironmentResolver();
private static final Map<PbsTokenKind, PbsSemanticKind> DECLARATION_KINDS = declarationKinds(); private static final Map<PbsTokenKind, PbsSemanticKind> DECLARATION_KINDS = declarationKinds();
@ -210,7 +212,7 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv
} }
private Map<String, PbsSemanticKind> resolveStdlibExportKinds(final PbsAst.ModuleRef moduleRef) { private Map<String, PbsSemanticKind> resolveStdlibExportKinds(final PbsAst.ModuleRef moduleRef) {
final var stdlibEnvironment = STDLIB_RESOLVER.resolve(DEFAULT_STDLIB_VERSION); final var stdlibEnvironment = STDLIB_RESOLVER.resolve(DEFAULT_STDLIB_VERSION, DEFAULT_TARGET);
return stdlibEnvironment.resolveModule(moduleRef.project(), moduleRef.pathSegments()) return stdlibEnvironment.resolveModule(moduleRef.project(), moduleRef.pathSegments())
.map(this::parseStdlibVisibleKinds) .map(this::parseStdlibVisibleKinds)
.orElseGet(Map::of); .orElseGet(Map::of);

View File

@ -1,21 +1,14 @@
package p.studio.compiler.pbs.stdlib; package p.studio.compiler.pbs.stdlib;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.AppMode;
import java.util.Optional; import java.util.Optional;
public final class EmptyStdlibEnvironmentResolver implements StdlibEnvironmentResolver { public final class EmptyStdlibEnvironmentResolver implements StdlibEnvironmentResolver {
private static final StdlibEnvironment EMPTY = new StdlibEnvironment() { private static final StdlibEnvironment EMPTY = (project, pathSegments) -> Optional.empty();
@Override
public Optional<StdlibModuleSource> resolveModule(
final String project,
final ReadOnlyList<String> pathSegments) {
return Optional.empty();
}
};
@Override @Override
public StdlibEnvironment resolve(final int stdlibVersion) { public StdlibEnvironment resolve(final int stdlibVersion, final AppMode target) {
return EMPTY; return EMPTY;
} }
} }

View File

@ -1,26 +1,23 @@
package p.studio.compiler.pbs.stdlib; package p.studio.compiler.pbs.stdlib;
import p.studio.AppMode;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional; import java.util.Optional;
public final class ResourceStdlibEnvironmentResolver implements StdlibEnvironmentResolver { public final class ResourceStdlibEnvironmentResolver implements StdlibEnvironmentResolver {
private static final String STDLIB_ROOT = "stdlib"; private static final String STDLIB_ROOT = "stdlib";
@Override @Override
public StdlibEnvironment resolve(final int stdlibVersion) { public StdlibEnvironment resolve(final int stdlibVersion, final AppMode target) {
return new ResourceStdlibEnvironment(stdlibVersion); return new ResourceStdlibEnvironment(stdlibVersion, target);
} }
private static final class ResourceStdlibEnvironment implements StdlibEnvironment { private record ResourceStdlibEnvironment(int stdlibVersion, AppMode target) implements StdlibEnvironment {
private final int stdlibVersion;
private ResourceStdlibEnvironment(final int stdlibVersion) {
this.stdlibVersion = stdlibVersion;
}
@Override @Override
public Optional<StdlibModuleSource> resolveModule( public Optional<StdlibModuleSource> resolveModule(
@ -36,7 +33,7 @@ public final class ResourceStdlibEnvironmentResolver implements StdlibEnvironmen
return Optional.of(new StdlibModuleSource( return Optional.of(new StdlibModuleSource(
project, project,
pathSegments, pathSegments,
ReadOnlyList.wrap(java.util.List.of(new StdlibModuleSource.SourceFile("main.pbs", mainSource.get()))), ReadOnlyList.wrap(List.of(new StdlibModuleSource.SourceFile("main.pbs", mainSource.get()))),
barrelSource.get())); barrelSource.get()));
} }
@ -44,7 +41,10 @@ public final class ResourceStdlibEnvironmentResolver implements StdlibEnvironmen
final String project, final String project,
final ReadOnlyList<String> pathSegments) { final ReadOnlyList<String> pathSegments) {
final var pathBuilder = new StringBuilder(); final var pathBuilder = new StringBuilder();
pathBuilder.append(STDLIB_ROOT) pathBuilder
.append(target.exportReferenceName().toLowerCase())
.append('/')
.append(STDLIB_ROOT)
.append('/') .append('/')
.append(stdlibVersion) .append(stdlibVersion)
.append('/') .append('/')

View File

@ -1,6 +1,8 @@
package p.studio.compiler.pbs.stdlib; package p.studio.compiler.pbs.stdlib;
import p.studio.AppMode;
public interface StdlibEnvironmentResolver { public interface StdlibEnvironmentResolver {
StdlibEnvironment resolve(int stdlibVersion); StdlibEnvironment resolve(int stdlibVersion, AppMode target);
} }

View File

@ -1,5 +1,6 @@
package p.studio.compiler.services; package p.studio.compiler.services;
import p.studio.AppMode;
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.IRGlobalVisibility; import p.studio.compiler.models.IRGlobalVisibility;
@ -99,7 +100,8 @@ final class PbsModuleAssemblyService {
projectIdByName, projectIdByName,
defaultSyntheticOwnerProjectId, defaultSyntheticOwnerProjectId,
diagnostics, diagnostics,
ctx.stdlibVersion()); ctx.stdlibVersion(),
ctx.target());
final var modules = new ArrayList<PbsModuleVisibilityValidator.ModuleUnit>(modulesByCoordinates.size()); final var modules = new ArrayList<PbsModuleVisibilityValidator.ModuleUnit>(modulesByCoordinates.size());
for (final var entry : modulesByCoordinates.entrySet()) { for (final var entry : modulesByCoordinates.entrySet()) {
@ -206,28 +208,29 @@ final class PbsModuleAssemblyService {
final Map<String, ProjectId> projectIdByName, final Map<String, ProjectId> projectIdByName,
final ProjectId defaultSyntheticOwnerProjectId, final ProjectId defaultSyntheticOwnerProjectId,
final DiagnosticSink diagnostics, final DiagnosticSink diagnostics,
final int stdlibVersion) { final int stdlibVersion,
final var stdlibEnvironment = stdlibEnvironmentResolver.resolve(stdlibVersion); final AppMode target) {
final var stdlibEnvironment = stdlibEnvironmentResolver.resolve(stdlibVersion, target);
final var pending = new ArrayDeque<PbsModuleVisibilityValidator.ModuleCoordinates>(); final var pending = new ArrayDeque<PbsModuleVisibilityValidator.ModuleCoordinates>();
final var resolved = new HashSet<ModuleId>(); final var resolved = new HashSet<ModuleId>();
enqueueReservedImportsFromKnownModules(modulesByCoordinates, pending); enqueueReservedImportsFromKnownModules(modulesByCoordinates, pending);
while (!pending.isEmpty()) { while (!pending.isEmpty()) {
final var target = pending.removeFirst(); final var moduleCoordinates = pending.removeFirst();
final var targetId = moduleId(moduleTable, target); final var moduleId = moduleId(moduleTable, moduleCoordinates);
if (!resolved.add(targetId)) { if (!resolved.add(moduleId)) {
continue; continue;
} }
if (modulesByCoordinates.containsKey(target)) { if (modulesByCoordinates.containsKey(moduleCoordinates)) {
continue; continue;
} }
final var moduleSource = stdlibEnvironment.resolveModule(target.project(), target.pathSegments()); final var moduleSource = stdlibEnvironment.resolveModule(moduleCoordinates.project(), moduleCoordinates.pathSegments());
if (moduleSource.isEmpty()) { if (moduleSource.isEmpty()) {
continue; continue;
} }
final var syntheticOwnerProjectId = projectIdByName.getOrDefault(target.project(), defaultSyntheticOwnerProjectId); final var syntheticOwnerProjectId = projectIdByName.getOrDefault(moduleCoordinates.project(), defaultSyntheticOwnerProjectId);
if (syntheticOwnerProjectId == null) { if (syntheticOwnerProjectId == null) {
continue; continue;
} }
@ -241,15 +244,15 @@ final class PbsModuleAssemblyService {
moduleData.barrels.addAll(loadedModule.barrelFiles().asList()); moduleData.barrels.addAll(loadedModule.barrelFiles().asList());
modulesByCoordinates.put(loadedModule.coordinates(), moduleData); modulesByCoordinates.put(loadedModule.coordinates(), moduleData);
for (final var sourceFile : loadedModule.sourceFiles()) { for (final var sourceFile : loadedModule.sourceFiles()) {
moduleIdByFile.put(sourceFile.fileId(), targetId); moduleIdByFile.put(sourceFile.fileId(), moduleId);
parsedSourceFiles.add(new PbsParsedSourceFile( parsedSourceFiles.add(new PbsParsedSourceFile(
sourceFile.fileId(), sourceFile.fileId(),
sourceFile.ast(), sourceFile.ast(),
targetId, moduleId,
SourceKind.SDK_INTERFACE)); SourceKind.SDK_INTERFACE));
} }
for (final var barrelFile : loadedModule.barrelFiles()) { for (final var barrelFile : loadedModule.barrelFiles()) {
moduleIdByFile.put(barrelFile.fileId(), targetId); moduleIdByFile.put(barrelFile.fileId(), moduleId);
} }
enqueueReservedImportsFromSourceFiles(loadedModule.sourceFiles().asList(), pending); enqueueReservedImportsFromSourceFiles(loadedModule.sourceFiles().asList(), pending);
} }

View File

@ -2,6 +2,7 @@ package p.studio.compiler.pbs;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.studio.AppMode;
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.*; import p.studio.compiler.models.*;
@ -460,7 +461,8 @@ class PbsGateUSdkInterfaceConformanceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
stdlibVersion); stdlibVersion,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(

View File

@ -2,6 +2,7 @@ package p.studio.compiler.pbs;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import p.studio.AppMode;
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.BuildStack; import p.studio.compiler.models.BuildStack;
@ -79,7 +80,8 @@ class PbsGateUStdlibCompileTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(projectIds)), new BuildStack(ReadOnlyList.wrap(projectIds)),
stdlibVersion); stdlibVersion,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
new PBSFrontendPhaseService().compile( new PBSFrontendPhaseService().compile(
@ -96,7 +98,7 @@ class PbsGateUStdlibCompileTest {
private Map<String, StdlibProjectFiles> discoverStdlibProjects( private Map<String, StdlibProjectFiles> discoverStdlibProjects(
final int stdlibVersion) throws Exception { final int stdlibVersion) throws Exception {
final var resourcePath = "stdlib/" + stdlibVersion; final var resourcePath = "game/stdlib/" + stdlibVersion;
final var classLoader = PbsGateUStdlibCompileTest.class.getClassLoader(); final var classLoader = PbsGateUStdlibCompileTest.class.getClassLoader();
final var resource = classLoader.getResource(resourcePath); final var resource = classLoader.getResource(resourcePath);
assertNotNull(resource, "Stdlib version " + stdlibVersion + " was not found on classpath at " + resourcePath); assertNotNull(resource, "Stdlib version " + stdlibVersion + " was not found on classpath at " + resourcePath);

View File

@ -2,16 +2,12 @@ package p.studio.compiler.services;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.studio.AppMode;
import p.studio.compiler.messages.Addressable; import p.studio.compiler.messages.Addressable;
import p.studio.compiler.messages.BuildingIssueSink; import p.studio.compiler.messages.BuildingIssueSink;
import p.studio.compiler.messages.FESurfaceContext; import p.studio.compiler.messages.FESurfaceContext;
import p.studio.compiler.messages.FrontendPhaseContext; import p.studio.compiler.messages.FrontendPhaseContext;
import p.studio.compiler.models.IRGlobalVisibility; import p.studio.compiler.models.*;
import p.studio.compiler.models.BuildStack;
import p.studio.compiler.models.IRHiddenGlobalKind;
import p.studio.compiler.models.ProjectDescriptor;
import p.studio.compiler.models.SourceHandle;
import p.studio.compiler.models.SourceKind;
import p.studio.compiler.pbs.PbsHostAdmissionErrors; import p.studio.compiler.pbs.PbsHostAdmissionErrors;
import p.studio.compiler.pbs.linking.PbsLinkErrors; import p.studio.compiler.pbs.linking.PbsLinkErrors;
import p.studio.compiler.pbs.semantics.PbsSemanticsErrors; import p.studio.compiler.pbs.semantics.PbsSemanticsErrors;
@ -78,6 +74,7 @@ class PBSFrontendPhaseServiceTest {
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1, 1,
AppMode.Game,
p.studio.compiler.messages.HostAdmissionContext.permissiveDefault(), p.studio.compiler.messages.HostAdmissionContext.permissiveDefault(),
new FESurfaceContext(ReadOnlyList.from(new Addressable("assets.ui.panel", 91)))); new FESurfaceContext(ReadOnlyList.from(new Addressable("assets.ui.panel", 91))));
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
@ -134,7 +131,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -185,7 +183,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -238,7 +237,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -308,7 +308,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -372,7 +373,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -416,7 +418,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
new PBSFrontendPhaseService().compile( new PBSFrontendPhaseService().compile(
@ -469,7 +472,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -557,7 +561,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -607,7 +612,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -664,7 +670,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -728,7 +735,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
7); 7,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = frontendService.compile( final var irBackend = frontendService.compile(
@ -779,7 +787,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
7); 7,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = frontendService.compile( final var irBackend = frontendService.compile(
@ -826,7 +835,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -879,7 +889,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -932,7 +943,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -991,7 +1003,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -1050,7 +1063,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -1121,7 +1135,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -1193,7 +1208,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -1256,7 +1272,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = frontendService.compile( final var irBackend = frontendService.compile(
@ -1320,7 +1337,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = frontendService.compile( final var irBackend = frontendService.compile(
@ -1401,7 +1419,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -1473,7 +1492,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
9); 9,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = frontendService.compile( final var irBackend = frontendService.compile(
@ -1527,7 +1547,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -1557,7 +1578,7 @@ class PBSFrontendPhaseServiceTest {
final var callableCalls = frameExecutable.instructions().stream() final var callableCalls = frameExecutable.instructions().stream()
.filter(instruction -> .filter(instruction ->
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC) instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC)
.map(instruction -> instruction.calleeCallableName()) .map(IRBackendExecutableFunction.Instruction::calleeCallableName)
.toList(); .toList();
final var intrinsicCalls = frameExecutable.instructions().stream() final var intrinsicCalls = frameExecutable.instructions().stream()
.filter(instruction -> .filter(instruction ->
@ -1624,7 +1645,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -1643,7 +1665,7 @@ class PBSFrontendPhaseServiceTest {
final var callableCalls = frameExecutable.instructions().stream() final var callableCalls = frameExecutable.instructions().stream()
.filter(instruction -> .filter(instruction ->
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC) instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC)
.map(instruction -> instruction.calleeCallableName()) .map(IRBackendExecutableFunction.Instruction::calleeCallableName)
.toList(); .toList();
final var intrinsicCalls = frameExecutable.instructions().stream() final var intrinsicCalls = frameExecutable.instructions().stream()
.filter(instruction -> .filter(instruction ->
@ -1717,7 +1739,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1); 1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile( final var irBackend = new PBSFrontendPhaseService().compile(
@ -1736,7 +1759,7 @@ class PBSFrontendPhaseServiceTest {
final var callableCalls = frameExecutable.instructions().stream() final var callableCalls = frameExecutable.instructions().stream()
.filter(instruction -> .filter(instruction ->
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC) instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC)
.map(instruction -> instruction.calleeCallableName()) .map(IRBackendExecutableFunction.Instruction::calleeCallableName)
.toList(); .toList();
final var intrinsicCalls = frameExecutable.instructions().stream() final var intrinsicCalls = frameExecutable.instructions().stream()
.filter(instruction -> .filter(instruction ->
@ -1804,7 +1827,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
new PBSFrontendPhaseService().compile( new PBSFrontendPhaseService().compile(
@ -1861,7 +1885,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
new PBSFrontendPhaseService().compile( new PBSFrontendPhaseService().compile(
@ -1932,7 +1957,8 @@ class PBSFrontendPhaseServiceTest {
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))), new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
11); 11,
AppMode.Game);
final var deniedDiagnostics = DiagnosticSink.empty(); final var deniedDiagnostics = DiagnosticSink.empty();
deniedFrontendService.compile( deniedFrontendService.compile(
@ -1998,7 +2024,8 @@ class PBSFrontendPhaseServiceTest {
allowedProjectTable, allowedProjectTable,
allowedFileTable, allowedFileTable,
new BuildStack(ReadOnlyList.wrap(List.of(allowedProjectId))), new BuildStack(ReadOnlyList.wrap(List.of(allowedProjectId))),
12); 12,
AppMode.Game);
final var allowedDiagnostics = DiagnosticSink.empty(); final var allowedDiagnostics = DiagnosticSink.empty();
allowedFrontendService.compile( allowedFrontendService.compile(
@ -2056,7 +2083,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var inlineHintsByFile = PBSFrontendPhaseService.inlineHintsByFile( final var inlineHintsByFile = PBSFrontendPhaseService.inlineHintsByFile(
@ -2113,7 +2141,8 @@ class PBSFrontendPhaseServiceTest {
final var ctx = new FrontendPhaseContext( final var ctx = new FrontendPhaseContext(
projectTable, projectTable,
fileTable, fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId)))); new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
AppMode.Game);
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var inlineHints = PBSFrontendPhaseService.inlineHintsByFile( final var inlineHints = PBSFrontendPhaseService.inlineHintsByFile(
@ -2148,7 +2177,7 @@ class PBSFrontendPhaseServiceTest {
for (final var module : modules) { for (final var module : modules) {
byModuleKey.put(moduleKey(module.project(), module.pathSegments()), module); byModuleKey.put(moduleKey(module.project(), module.pathSegments()), module);
} }
return stdlib -> { return (stdlib, target) -> {
if (stdlib != acceptedStdlib) { if (stdlib != acceptedStdlib) {
return (project, pathSegments) -> Optional.empty(); return (project, pathSegments) -> Optional.empty();
} }

View File

@ -5,8 +5,8 @@ import p.studio.compiler.FrontendRegistryService;
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.BuilderPipelineContext; import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.compiler.workspaces.AssetSurfaceContextLoader;
import p.studio.compiler.source.diagnostics.DiagnosticSink; import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.compiler.workspaces.AssetSurfaceContextLoader;
import p.studio.compiler.workspaces.PipelineStage; import p.studio.compiler.workspaces.PipelineStage;
import p.studio.utilities.logs.LogAggregator; import p.studio.utilities.logs.LogAggregator;
@ -31,6 +31,7 @@ public class FrontendPhasePipelineStage implements PipelineStage {
fileTable, fileTable,
ctx.resolvedWorkspace.stack(), ctx.resolvedWorkspace.stack(),
ctx.resolvedWorkspace.stdlib(), ctx.resolvedWorkspace.stdlib(),
ctx.resolvedWorkspace.target(),
p.studio.compiler.messages.HostAdmissionContext.permissiveDefault(), p.studio.compiler.messages.HostAdmissionContext.permissiveDefault(),
assetSurfaceContextLoader.load(ctx.resolvedWorkspace.mainProject().getRootPath())); assetSurfaceContextLoader.load(ctx.resolvedWorkspace.mainProject().getRootPath()));
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();

View File

@ -2,6 +2,7 @@ package p.studio.compiler.models;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import p.studio.AppMode;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
import java.nio.file.Path; import java.nio.file.Path;
@ -12,6 +13,7 @@ public final class ProjectDescriptor {
private final Path rootPath; // canon root path private final Path rootPath; // canon root path
private final String name; // project name private final String name; // project name
private final String version; // project version private final String version; // project version
private final AppMode target; // project target (Game or System)
private final ReadOnlyList<Path> sourceRoots; // source roots canon paths for the project private final ReadOnlyList<Path> sourceRoots; // source roots canon paths for the project
@Builder.Default @Builder.Default
private final SourceKind sourceKind = SourceKind.PROJECT; private final SourceKind sourceKind = SourceKind.PROJECT;

View File

@ -10,6 +10,7 @@ public record PrometeuManifestDTO(
String version, String version,
String language, String language,
String stdlib, String stdlib,
String target,
List<DependencyDeclaration> dependencies) { List<DependencyDeclaration> dependencies) {
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION) @JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)

View File

@ -1,5 +1,6 @@
package p.studio.compiler.models; package p.studio.compiler.models;
import p.studio.AppMode;
import p.studio.compiler.exceptions.BuildException; import p.studio.compiler.exceptions.BuildException;
import p.studio.compiler.messages.DependencyConfig; import p.studio.compiler.messages.DependencyConfig;
import p.studio.compiler.source.identifiers.ProjectId; import p.studio.compiler.source.identifiers.ProjectId;
@ -23,6 +24,7 @@ public final class DependencyContext {
public Path mainProjectRootPathCanon; public Path mainProjectRootPathCanon;
public FrontendSpec frontendSpec; public FrontendSpec frontendSpec;
public Integer rootStdlib; public Integer rootStdlib;
public AppMode target;
public ProjectId rootProjectId; public ProjectId rootProjectId;
public BuildStack stack; public BuildStack stack;
@ -51,7 +53,7 @@ public final class DependencyContext {
} }
final var dependenciesByProject = buildDependenciesByProject(); final var dependenciesByProject = buildDependenciesByProject();
final var workspaceGraph = new WorkspaceGraph(projectTable, dependenciesByProject); final var workspaceGraph = new WorkspaceGraph(projectTable, dependenciesByProject);
return new ResolvedWorkspace(rootProjectId, frontendSpec, rootStdlib, workspaceGraph, stack); return new ResolvedWorkspace(rootProjectId, frontendSpec, rootStdlib, target, workspaceGraph, stack);
} }

View File

@ -1,5 +1,6 @@
package p.studio.compiler.models; package p.studio.compiler.models;
import p.studio.AppMode;
import p.studio.compiler.workspaces.DependencyReference; import p.studio.compiler.workspaces.DependencyReference;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
@ -8,5 +9,6 @@ public record PrometeuManifest(
String version, String version,
String language, String language,
int stdlib, int stdlib,
AppMode target,
ReadOnlyList<DependencyReference> dependencies) { ReadOnlyList<DependencyReference> dependencies) {
} }

View File

@ -1,11 +1,13 @@
package p.studio.compiler.models; package p.studio.compiler.models;
import p.studio.AppMode;
import p.studio.compiler.source.identifiers.ProjectId; import p.studio.compiler.source.identifiers.ProjectId;
public record ResolvedWorkspace( public record ResolvedWorkspace(
ProjectId mainProjectId, ProjectId mainProjectId,
FrontendSpec frontendSpec, FrontendSpec frontendSpec,
int stdlib, int stdlib,
AppMode target,
WorkspaceGraph graph, WorkspaceGraph graph,
BuildStack stack) { BuildStack stack) {
public ProjectDescriptor mainProject() { public ProjectDescriptor mainProject() {

View File

@ -2,7 +2,9 @@ package p.studio.compiler.utilities;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import p.studio.AppMode;
import p.studio.compiler.FrontendRegistryService; import p.studio.compiler.FrontendRegistryService;
import p.studio.compiler.dtos.PrometeuManifestDTO; import p.studio.compiler.dtos.PrometeuManifestDTO;
import p.studio.compiler.messages.BuildingIssueSink; import p.studio.compiler.messages.BuildingIssueSink;
@ -45,7 +47,18 @@ public final class PrometeuManifestUtils {
.error(true) .error(true)
.message("[DEPS]: manifest missing 'version': " + manifestPathCanon)); .message("[DEPS]: manifest missing 'version': " + manifestPathCanon));
} }
if (StringUtils.isBlank(dto.target())) {
issuesLocal.report(builder -> builder
.error(true)
.message("[DEPS]: manifest missing 'target': " + manifestPathCanon));
}
final var stdlibMaybe = parseStdlib(dto.stdlib(), manifestPathCanon, issuesLocal); final var stdlibMaybe = parseStdlib(dto.stdlib(), manifestPathCanon, issuesLocal);
final var target = EnumUtils.getEnum(AppMode.class, dto.target());
if (target == null) {
issuesLocal.report(builder -> builder
.error(true)
.message("[DEPS]: invalid 'target' \"" + dto.target() + "\": " + manifestPathCanon));
}
final var language = StringUtils.isBlank(dto.language()) final var language = StringUtils.isBlank(dto.language())
? FrontendRegistryService.getDefaultFrontendSpec().getLanguageId() ? FrontendRegistryService.getDefaultFrontendSpec().getLanguageId()
: dto.language(); : dto.language();
@ -54,7 +67,7 @@ public final class PrometeuManifestUtils {
issues.merge(issuesLocal); issues.merge(issuesLocal);
return Optional.empty(); return Optional.empty();
} }
return Optional.of(new PrometeuManifest(dto.name(), dto.version(), language, stdlibMaybe.getAsInt(), ReadOnlyList.wrap(dependencies))); return Optional.of(new PrometeuManifest(dto.name(), dto.version(), language, stdlibMaybe.getAsInt(), target, ReadOnlyList.wrap(dependencies)));
} }
private static OptionalInt parseStdlib( private static OptionalInt parseStdlib(

View File

@ -53,6 +53,7 @@ public class DiscoverPhase implements DependencyPhase {
} }
if (rootPathCanon.equals(ctx.mainProjectRootPathCanon)) { if (rootPathCanon.equals(ctx.mainProjectRootPathCanon)) {
ctx.rootStdlib = manifest.get().stdlib(); ctx.rootStdlib = manifest.get().stdlib();
ctx.target = manifest.get().target();
} }
final var frontendSpec = FrontendRegistryService.getFrontendSpec(manifest.get().language()); final var frontendSpec = FrontendRegistryService.getFrontendSpec(manifest.get().language());
// Returns empty when language is unknown // Returns empty when language is unknown

View File

@ -89,6 +89,7 @@ public final class WireProjectsPhase implements DependencyPhase {
.rootPath(projectInfo.rootDirectory) .rootPath(projectInfo.rootDirectory)
.name(projectInfo.manifest.name()) .name(projectInfo.manifest.name())
.version(projectInfo.manifest.version()) .version(projectInfo.manifest.version())
.target(projectInfo.manifest.target())
.sourceRoots(ReadOnlyList.wrap(sourceRoots)) .sourceRoots(ReadOnlyList.wrap(sourceRoots))
.build(); .build();
} }

View File

@ -23,6 +23,7 @@ class PrometeuManifestUtilsTest {
"version": "1.0.0", "version": "1.0.0",
"language": "pbs", "language": "pbs",
"stdlib": "1", "stdlib": "1",
"target": "Game",
"dependencies": [] "dependencies": []
} }
"""); """);
@ -74,6 +75,47 @@ class PrometeuManifestUtilsTest {
assertTrue(issues.asCollection().stream().anyMatch(issue -> issue.getMessage().contains("invalid 'stdlib'"))); assertTrue(issues.asCollection().stream().anyMatch(issue -> issue.getMessage().contains("invalid 'stdlib'")));
} }
@Test
void buildManifestRejectsNoTarget() throws IOException {
final var manifestPath = writeManifest("""
{
"name": "main",
"version": "1.0.0",
"language": "pbs",
"stdlib": "1",
"dependencies": []
}
""");
final var issues = BuildingIssueSink.empty();
final var manifest = PrometeuManifestUtils.buildManifest(tempDir, manifestPath, issues);
assertTrue(manifest.isEmpty());
assertTrue(issues.hasErrors());
assertTrue(issues.asCollection().stream().anyMatch(issue -> issue.getMessage().contains("missing 'target'")));
}
@Test
void buildManifestRejectsInvalidTarget() throws IOException {
final var manifestPath = writeManifest("""
{
"name": "main",
"version": "1.0.0",
"language": "pbs",
"stdlib": "1",
"target": "UnknownTarget",
"dependencies": []
}
""");
final var issues = BuildingIssueSink.empty();
final var manifest = PrometeuManifestUtils.buildManifest(tempDir, manifestPath, issues);
assertTrue(manifest.isEmpty());
assertTrue(issues.hasErrors());
assertTrue(issues.asCollection().stream().anyMatch(issue -> issue.getMessage().contains("invalid 'target'")));
}
private Path writeManifest(final String content) throws IOException { private Path writeManifest(final String content) throws IOException {
final var manifestPath = tempDir.resolve("prometeu.json"); final var manifestPath = tempDir.resolve("prometeu.json");
Files.writeString(manifestPath, content); Files.writeString(manifestPath, content);

View File

@ -2,6 +2,7 @@ package p.studio.compiler.workspaces.phases;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.studio.AppMode;
import p.studio.compiler.messages.DependencyConfig; import p.studio.compiler.messages.DependencyConfig;
import p.studio.compiler.models.DependencyContext; import p.studio.compiler.models.DependencyContext;
import p.studio.compiler.models.ProjectDescriptor; import p.studio.compiler.models.ProjectDescriptor;
@ -66,7 +67,7 @@ class StackPhaseTest {
ctx.projectInfoTable.register(ProjectInfo.builder() ctx.projectInfoTable.register(ProjectInfo.builder()
.rootDirectory(root) .rootDirectory(root)
.manifestPath(root.resolve("prometeu.json")) .manifestPath(root.resolve("prometeu.json"))
.manifest(new PrometeuManifest(name, "1.0.0", "pbs", 1, ReadOnlyList.wrap(List.of()))) .manifest(new PrometeuManifest(name, "1.0.0", "pbs", 1, AppMode.Game, ReadOnlyList.wrap(List.of())))
.build()); .build());
} }
} }

View File

@ -2,6 +2,7 @@ package p.studio.compiler.workspaces.phases;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.studio.AppMode;
import p.studio.compiler.messages.DependencyConfig; import p.studio.compiler.messages.DependencyConfig;
import p.studio.compiler.models.DependencyContext; import p.studio.compiler.models.DependencyContext;
import p.studio.compiler.models.ProjectDescriptor; import p.studio.compiler.models.ProjectDescriptor;
@ -42,16 +43,17 @@ class ValidatePhaseTest {
ctx.projectInfoTable.register(ProjectInfo.builder() ctx.projectInfoTable.register(ProjectInfo.builder()
.rootDirectory(rootPath) .rootDirectory(rootPath)
.manifestPath(rootPath.resolve("prometeu.json")) .manifestPath(rootPath.resolve("prometeu.json"))
.manifest(new PrometeuManifest("root", "1.0.0", "pbs", 1, ReadOnlyList.wrap(List.of()))) .manifest(new PrometeuManifest("root", "1.0.0", "pbs", 1, AppMode.Game, ReadOnlyList.wrap(List.of())))
.build()); .build());
ctx.projectInfoTable.register(ProjectInfo.builder() ctx.projectInfoTable.register(ProjectInfo.builder()
.rootDirectory(depPath) .rootDirectory(depPath)
.manifestPath(depPath.resolve("prometeu.json")) .manifestPath(depPath.resolve("prometeu.json"))
.manifest(new PrometeuManifest("dep", "1.0.0", "pbs", 2, ReadOnlyList.wrap(List.of()))) .manifest(new PrometeuManifest("dep", "1.0.0", "pbs", 2, AppMode.Game, ReadOnlyList.wrap(List.of())))
.build()); .build());
ctx.rootProjectId = rootProjectId; ctx.rootProjectId = rootProjectId;
ctx.rootStdlib = 1; ctx.rootStdlib = 1;
ctx.target = AppMode.Game;
ctx.dependenciesByProject.add(List.of()); ctx.dependenciesByProject.add(List.of());
ctx.dependenciesByProject.add(List.of()); ctx.dependenciesByProject.add(List.of());
ctx.projectNameAndVersions.put("root", new java.util.HashSet<>(List.of("1.0.0"))); ctx.projectNameAndVersions.put("root", new java.util.HashSet<>(List.of("1.0.0")));
@ -85,16 +87,17 @@ class ValidatePhaseTest {
ctx.projectInfoTable.register(ProjectInfo.builder() ctx.projectInfoTable.register(ProjectInfo.builder()
.rootDirectory(rootPath) .rootDirectory(rootPath)
.manifestPath(rootPath.resolve("prometeu.json")) .manifestPath(rootPath.resolve("prometeu.json"))
.manifest(new PrometeuManifest("root", "1.0.0", "pbs", 2, ReadOnlyList.wrap(List.of()))) .manifest(new PrometeuManifest("root", "1.0.0", "pbs", 2, AppMode.Game, ReadOnlyList.wrap(List.of())))
.build()); .build());
ctx.projectInfoTable.register(ProjectInfo.builder() ctx.projectInfoTable.register(ProjectInfo.builder()
.rootDirectory(depPath) .rootDirectory(depPath)
.manifestPath(depPath.resolve("prometeu.json")) .manifestPath(depPath.resolve("prometeu.json"))
.manifest(new PrometeuManifest("dep", "1.0.0", "pbs", 1, ReadOnlyList.wrap(List.of()))) .manifest(new PrometeuManifest("dep", "1.0.0", "pbs", 1, AppMode.Game, ReadOnlyList.wrap(List.of())))
.build()); .build());
ctx.rootProjectId = rootProjectId; ctx.rootProjectId = rootProjectId;
ctx.rootStdlib = 2; ctx.rootStdlib = 2;
ctx.target = AppMode.Game;
ctx.dependenciesByProject.add(List.of()); ctx.dependenciesByProject.add(List.of());
ctx.dependenciesByProject.add(List.of()); ctx.dependenciesByProject.add(List.of());
ctx.projectNameAndVersions.put("root", new java.util.HashSet<>(List.of("1.0.0"))); ctx.projectNameAndVersions.put("root", new java.util.HashSet<>(List.of("1.0.0")));

View File

@ -1,5 +1,6 @@
package p.studio.compiler.messages; package p.studio.compiler.messages;
import p.studio.AppMode;
import p.studio.compiler.models.BuildStack; import p.studio.compiler.models.BuildStack;
import p.studio.compiler.models.SourceKind; import p.studio.compiler.models.SourceKind;
import p.studio.compiler.source.identifiers.ProjectId; import p.studio.compiler.source.identifiers.ProjectId;
@ -13,22 +14,16 @@ public class FrontendPhaseContext {
public final BuildStack stack; public final BuildStack stack;
private final NameTable nameTable; private final NameTable nameTable;
private final int stdlibVersion; private final int stdlibVersion;
private final AppMode target;
private final HostAdmissionContext hostAdmissionContext; private final HostAdmissionContext hostAdmissionContext;
private final FESurfaceContext feSurfaceContext; private final FESurfaceContext feSurfaceContext;
public FrontendPhaseContext(
final ProjectTableReader projectTable,
final FileTableReader fileTable,
final BuildStack stack) {
this(projectTable, fileTable, stack, 1, HostAdmissionContext.permissiveDefault(), FESurfaceContext.empty());
}
public FrontendPhaseContext( public FrontendPhaseContext(
final ProjectTableReader projectTable, final ProjectTableReader projectTable,
final FileTableReader fileTable, final FileTableReader fileTable,
final BuildStack stack, final BuildStack stack,
final int stdlibVersion) { final AppMode target) {
this(projectTable, fileTable, stack, stdlibVersion, HostAdmissionContext.permissiveDefault(), FESurfaceContext.empty()); this(projectTable, fileTable, stack, 1, target, HostAdmissionContext.permissiveDefault(), FESurfaceContext.empty());
} }
public FrontendPhaseContext( public FrontendPhaseContext(
@ -36,8 +31,18 @@ public class FrontendPhaseContext {
final FileTableReader fileTable, final FileTableReader fileTable,
final BuildStack stack, final BuildStack stack,
final int stdlibVersion, final int stdlibVersion,
final AppMode target) {
this(projectTable, fileTable, stack, stdlibVersion, target, HostAdmissionContext.permissiveDefault(), FESurfaceContext.empty());
}
public FrontendPhaseContext(
final ProjectTableReader projectTable,
final FileTableReader fileTable,
final BuildStack stack,
final int stdlibVersion,
final AppMode target,
final HostAdmissionContext hostAdmissionContext) { final HostAdmissionContext hostAdmissionContext) {
this(projectTable, fileTable, stack, stdlibVersion, hostAdmissionContext, FESurfaceContext.empty()); this(projectTable, fileTable, stack, stdlibVersion, target, hostAdmissionContext, FESurfaceContext.empty());
} }
public FrontendPhaseContext( public FrontendPhaseContext(
@ -45,6 +50,7 @@ public class FrontendPhaseContext {
final FileTableReader fileTable, final FileTableReader fileTable,
final BuildStack stack, final BuildStack stack,
final int stdlibVersion, final int stdlibVersion,
final AppMode target,
final HostAdmissionContext hostAdmissionContext, final HostAdmissionContext hostAdmissionContext,
final FESurfaceContext feSurfaceContext) { final FESurfaceContext feSurfaceContext) {
this.projectTable = projectTable; this.projectTable = projectTable;
@ -52,6 +58,7 @@ public class FrontendPhaseContext {
this.stack = stack; this.stack = stack;
this.nameTable = new NameTable(); this.nameTable = new NameTable();
this.stdlibVersion = stdlibVersion; this.stdlibVersion = stdlibVersion;
this.target = target;
this.hostAdmissionContext = hostAdmissionContext == null this.hostAdmissionContext = hostAdmissionContext == null
? HostAdmissionContext.permissiveDefault() ? HostAdmissionContext.permissiveDefault()
: hostAdmissionContext; : hostAdmissionContext;
@ -68,6 +75,10 @@ public class FrontendPhaseContext {
return stdlibVersion; return stdlibVersion;
} }
public AppMode target() {
return target;
}
public HostAdmissionContext hostAdmissionContext() { public HostAdmissionContext hostAdmissionContext() {
return hostAdmissionContext; return hostAdmissionContext;
} }

View File

@ -0,0 +1,17 @@
package p.studio;
public enum AppMode {
Game("Game"),
System("System"),
;
private final String reference;
AppMode(final String reference) {
this.reference = reference;
}
public String exportReferenceName() {
return reference;
}
}

View File

@ -2,30 +2,14 @@ package p.studio.lsp.services.compiler;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import p.studio.compiler.FrontendRegistryService; import p.studio.compiler.FrontendRegistryService;
import p.studio.compiler.messages.BuilderPipelineConfig; import p.studio.compiler.messages.*;
import p.studio.compiler.messages.BuildingIssueSink; import p.studio.compiler.models.*;
import p.studio.compiler.messages.FrontendPhaseContext; import p.studio.compiler.pbs.semantics.*;
import p.studio.compiler.messages.BuildingIssue;
import p.studio.compiler.messages.HostAdmissionContext;
import p.studio.compiler.models.AnalysisSnapshot;
import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.compiler.models.FrontendEditorPaletteSpec;
import p.studio.compiler.models.FrontendHostProjectionEntrySpec;
import p.studio.compiler.models.FrontendHostProjectionSpec;
import p.studio.compiler.models.FrontendSemanticPresentationSpec;
import p.studio.compiler.models.FrontendSemanticToken;
import p.studio.compiler.models.FrontendTokenStyleSpec;
import p.studio.compiler.models.FrontendVisualThemeSpec;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.services.PBSFrontendPhaseService; import p.studio.compiler.services.PBSFrontendPhaseService;
import p.studio.compiler.workspaces.AssetSurfaceContextLoader; import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.utilities.SourceProviderFactory; import p.studio.compiler.utilities.SourceProviderFactory;
import p.studio.compiler.workspaces.AssetSurfaceContextLoader;
import p.studio.compiler.workspaces.BuilderPipelineService; import p.studio.compiler.workspaces.BuilderPipelineService;
import p.studio.compiler.pbs.semantics.PbsEditorialCompletionCandidate;
import p.studio.compiler.pbs.semantics.PbsEditorialResolvedSymbol;
import p.studio.compiler.pbs.semantics.PbsEditorialSignature;
import p.studio.compiler.pbs.semantics.PbsEditorialSymbolKind;
import p.studio.compiler.pbs.semantics.PbsEditorialSupportService;
import p.studio.lsp.messages.*; import p.studio.lsp.messages.*;
import p.studio.lsp.services.LanguageServiceBridge; import p.studio.lsp.services.LanguageServiceBridge;
import p.studio.utilities.logs.LogAggregator; import p.studio.utilities.logs.LogAggregator;
@ -33,12 +17,7 @@ import p.studio.utilities.structures.ReadOnlyList;
import java.net.URI; import java.net.URI;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
public final class CompilerLanguageServiceBridge implements LanguageServiceBridge { public final class CompilerLanguageServiceBridge implements LanguageServiceBridge {
private final AssetSurfaceContextLoader assetSurfaceContextLoader = new AssetSurfaceContextLoader(); private final AssetSurfaceContextLoader assetSurfaceContextLoader = new AssetSurfaceContextLoader();
@ -218,6 +197,7 @@ public final class CompilerLanguageServiceBridge implements LanguageServiceBridg
pipelineContext.fileTable, pipelineContext.fileTable,
pipelineContext.resolvedWorkspace.stack(), pipelineContext.resolvedWorkspace.stack(),
pipelineContext.resolvedWorkspace.stdlib(), pipelineContext.resolvedWorkspace.stdlib(),
pipelineContext.resolvedWorkspace.target(),
HostAdmissionContext.permissiveDefault(), HostAdmissionContext.permissiveDefault(),
assetSurfaceContextLoader.load(pipelineContext.resolvedWorkspace.mainProject().getRootPath())); assetSurfaceContextLoader.load(pipelineContext.resolvedWorkspace.mainProject().getRootPath()));
final var semanticReadSurface = PBSFrontendPhaseService.semanticReadSurface( final var semanticReadSurface = PBSFrontendPhaseService.semanticReadSurface(

View File

@ -2,6 +2,8 @@ package p.studio.projects;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.EnumUtils;
import p.studio.AppMode;
import p.studio.projectstate.ProjectLocalStudioSetup; import p.studio.projectstate.ProjectLocalStudioSetup;
import p.studio.projectstate.ProjectLocalStudioSetupService; import p.studio.projectstate.ProjectLocalStudioSetupService;
@ -70,11 +72,11 @@ public final class ProjectCatalogService {
} }
public ProjectReference createProject(String projectName) { public ProjectReference createProject(String projectName) {
return createProject(new ProjectCreationRequest(projectName, projectsRoot, "pbs", 1, "src", 4, null)); return createProject(new ProjectCreationRequest(projectName, projectsRoot, "pbs", 1, AppMode.Game, "src", 4, null));
} }
public ProjectReference createProject(String projectName, Path parentLocation) { public ProjectReference createProject(String projectName, Path parentLocation) {
return createProject(new ProjectCreationRequest(projectName, parentLocation, "pbs", 1, "src", 4, null)); return createProject(new ProjectCreationRequest(projectName, parentLocation, "pbs", 1, AppMode.Game, "src", 4, null));
} }
public ProjectReference createProject(ProjectCreationRequest request) { public ProjectReference createProject(ProjectCreationRequest request) {
@ -90,6 +92,9 @@ public final class ProjectCatalogService {
if (request.stdlib() <= 0) { if (request.stdlib() <= 0) {
throw new IllegalArgumentException("project stdlib major must be positive"); throw new IllegalArgumentException("project stdlib major must be positive");
} }
if (request.target() == null) {
throw new IllegalArgumentException("project target must not be null");
}
if (request.indentationWidth() <= 0) { if (request.indentationWidth() <= 0) {
throw new IllegalArgumentException("project indentation width must be positive"); throw new IllegalArgumentException("project indentation width must be positive");
} }
@ -115,13 +120,14 @@ public final class ProjectCatalogService {
"1.0.0", "1.0.0",
languageId, languageId,
request.stdlib(), request.stdlib(),
request.target(),
projectRoot); projectRoot);
Files.createDirectories(ProjectStudioPaths.studioRoot(projectReference)); Files.createDirectories(ProjectStudioPaths.studioRoot(projectReference));
Files.createDirectories(projectRoot.resolve(sourceRoot)); Files.createDirectories(projectRoot.resolve(sourceRoot));
Files.createDirectories(projectRoot.resolve("assets")); Files.createDirectories(projectRoot.resolve("assets"));
Files.createDirectories(projectRoot.resolve("build")); Files.createDirectories(projectRoot.resolve("build"));
Files.createDirectories(projectRoot.resolve("cartridge")); Files.createDirectories(projectRoot.resolve("cartridge"));
Files.writeString(manifestPath(projectRoot), defaultManifest(displayName, languageId, request.stdlib())); Files.writeString(manifestPath(projectRoot), defaultManifest(displayName, languageId, request.stdlib(), request.target()));
Files.writeString(projectRoot.resolve(".gitignore"), defaultGitIgnore()); Files.writeString(projectRoot.resolve(".gitignore"), defaultGitIgnore());
projectLocalStudioSetupService.save( projectLocalStudioSetupService.save(
projectReference, projectReference,
@ -151,6 +157,9 @@ public final class ProjectCatalogService {
if (manifest.version() == null || manifest.version().isBlank()) { if (manifest.version() == null || manifest.version().isBlank()) {
throw new IllegalArgumentException("project manifest missing version: " + manifestPath); throw new IllegalArgumentException("project manifest missing version: " + manifestPath);
} }
if (manifest.target() == null || manifest.target().isBlank()) {
throw new IllegalArgumentException("project manifest missing target: " + manifestPath);
}
if (manifest.language() == null || manifest.language().isBlank()) { if (manifest.language() == null || manifest.language().isBlank()) {
throw new IllegalArgumentException("project manifest missing language: " + manifestPath); throw new IllegalArgumentException("project manifest missing language: " + manifestPath);
} }
@ -160,11 +169,16 @@ public final class ProjectCatalogService {
} catch (RuntimeException runtimeException) { } catch (RuntimeException runtimeException) {
throw new IllegalArgumentException("project manifest invalid stdlib: " + manifestPath, runtimeException); throw new IllegalArgumentException("project manifest invalid stdlib: " + manifestPath, runtimeException);
} }
final AppMode target = EnumUtils.getEnum(AppMode.class, manifest.target());
if (target == null) {
throw new IllegalArgumentException("project manifest invalid target: " + manifestPath);
}
return new ProjectReference( return new ProjectReference(
manifest.name().trim(), manifest.name().trim(),
manifest.version().trim(), manifest.version().trim(),
manifest.language().trim(), manifest.language().trim(),
stdlibMajor, stdlibMajor,
target,
normalizedRoot); normalizedRoot);
} }
@ -188,17 +202,22 @@ public final class ProjectCatalogService {
return normalized; return normalized;
} }
private String defaultManifest(String projectName, String languageId, int stdlibMajor) { private String defaultManifest(
final String projectName,
final String languageId,
final int stdlibMajor,
final AppMode target) {
return """ return """
{ {
"name": "%s", "name": "%s",
"version": "1.0.0", "version": "1.0.0",
"language": "%s", "language": "%s",
"stdlib": "%d", "stdlib": "%d",
"target": "%s",
"dependencies": [ "dependencies": [
] ]
} }
""".formatted(projectName, languageId, stdlibMajor); """.formatted(projectName, languageId, stdlibMajor, target.exportReferenceName());
} }
private String defaultGitIgnore() { private String defaultGitIgnore() {
@ -223,7 +242,7 @@ public final class ProjectCatalogService {
} }
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
private record ProjectManifestSummary(String name, String version, String language, String stdlib) { private record ProjectManifestSummary(String name, String version, String language, String stdlib, String target) {
} }
private String sanitizeProjectName(String rawName) { private String sanitizeProjectName(String rawName) {

View File

@ -1,5 +1,7 @@
package p.studio.projects; package p.studio.projects;
import p.studio.AppMode;
import java.nio.file.Path; import java.nio.file.Path;
public record ProjectCreationRequest( public record ProjectCreationRequest(
@ -7,6 +9,7 @@ public record ProjectCreationRequest(
Path parentLocation, Path parentLocation,
String languageId, String languageId,
int stdlib, int stdlib,
AppMode target,
String sourceRoot, String sourceRoot,
int indentationWidth, int indentationWidth,
String runtimePath) { String runtimePath) {

View File

@ -2,6 +2,7 @@ package p.studio.projects;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import p.packer.messages.PackerProjectContext; import p.packer.messages.PackerProjectContext;
import p.studio.AppMode;
import p.studio.lsp.messages.LspProjectContext; import p.studio.lsp.messages.LspProjectContext;
import java.nio.file.Path; import java.nio.file.Path;
@ -11,6 +12,7 @@ public record ProjectReference(
String version, String version,
String languageId, String languageId,
int stdlibVersion, int stdlibVersion,
AppMode target,
Path rootPath) { Path rootPath) {
@Override @Override
public String toString() { public String toString() {

View File

@ -181,7 +181,7 @@ public final class StudioShipperService {
manifest.put("app_id", stableAppId(projectReference)); manifest.put("app_id", stableAppId(projectReference));
manifest.put("title", projectReference.name()); manifest.put("title", projectReference.name());
manifest.put("app_version", projectReference.version()); manifest.put("app_version", projectReference.version());
manifest.put("app_mode", "Game"); manifest.put("app_mode", projectReference.target().exportReferenceName());
manifest.set("capabilities", capabilitiesNode(buildResult)); manifest.set("capabilities", capabilitiesNode(buildResult));
manifest.set("asset_table", readArrayOrEmpty(projectReference.rootPath().resolve(BUILD_DIR).resolve(ASSET_TABLE_FILE))); manifest.set("asset_table", readArrayOrEmpty(projectReference.rootPath().resolve(BUILD_DIR).resolve(ASSET_TABLE_FILE)));
manifest.set("preload", readArrayOrEmpty(projectReference.rootPath().resolve(BUILD_DIR).resolve(PRELOAD_FILE))); manifest.set("preload", readArrayOrEmpty(projectReference.rootPath().resolve(BUILD_DIR).resolve(PRELOAD_FILE)));

View File

@ -14,6 +14,7 @@ import javafx.stage.DirectoryChooser;
import javafx.stage.Modality; import javafx.stage.Modality;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.Window; import javafx.stage.Window;
import p.studio.AppMode;
import p.studio.Container; import p.studio.Container;
import p.studio.projects.*; import p.studio.projects.*;
import p.studio.utilities.i18n.I18n; import p.studio.utilities.i18n.I18n;
@ -298,6 +299,7 @@ public final class NewProjectWizard {
Path.of(locationField.getText().trim()), Path.of(locationField.getText().trim()),
selectedLanguageId(), selectedLanguageId(),
selectedStdlib().version(), selectedStdlib().version(),
AppMode.Game, // hardcoded for now, we can add a separate step for this if needed
selectedSourceRoot(), selectedSourceRoot(),
selectedIndentationWidth(), selectedIndentationWidth(),
selectedRuntimePath()))); selectedRuntimePath())));

View File

@ -2,6 +2,7 @@ package p.studio.controls.shell;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.studio.AppMode;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.projects.ProjectStudioPaths; import p.studio.projects.ProjectStudioPaths;
@ -64,6 +65,6 @@ final class StudioActivityStorageServiceTest {
private ProjectReference project(String name) { private ProjectReference project(String name) {
final Path projectRoot = tempDir.resolve(name); final Path projectRoot = tempDir.resolve(name);
return new ProjectReference("Main", "1.0.0", "pbs", 1, projectRoot); return new ProjectReference("Main", "1.0.0", "pbs", 1, AppMode.Game, projectRoot);
} }
} }

View File

@ -1,6 +1,7 @@
package p.studio.execution; package p.studio.execution;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import p.studio.AppMode;
import p.studio.StudioBackgroundTasks; import p.studio.StudioBackgroundTasks;
import p.studio.debug.runtime.StudioRuntimeDebugConnectionSettings; import p.studio.debug.runtime.StudioRuntimeDebugConnectionSettings;
import p.studio.debug.runtime.StudioRuntimeHandshakeClient; import p.studio.debug.runtime.StudioRuntimeHandshakeClient;
@ -183,7 +184,7 @@ final class StudioPlayStopCoordinatorTest {
} }
private ProjectReference projectReference() { private ProjectReference projectReference() {
return new ProjectReference("Main", "1.0.0", "pbs", 1, Path.of("/tmp/prometeu-play-stop")); return new ProjectReference("Main", "1.0.0", "pbs", 1, AppMode.Game, Path.of("/tmp/prometeu-play-stop"));
} }
private static final class RecordingHandshakeClient implements StudioRuntimeHandshakeClient { private static final class RecordingHandshakeClient implements StudioRuntimeHandshakeClient {

View File

@ -2,6 +2,7 @@ package p.studio.projects;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.studio.AppMode;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -34,7 +35,7 @@ final class KnownProjectsServiceTest {
final Path projectsRoot = tempDir.resolve("projects"); final Path projectsRoot = tempDir.resolve("projects");
Files.createDirectories(projectsRoot.resolve("alpha")); Files.createDirectories(projectsRoot.resolve("alpha"));
Files.writeString(projectsRoot.resolve("alpha").resolve("prometeu.json"), manifest("Alpha Project")); Files.writeString(projectsRoot.resolve("alpha").resolve("prometeu.json"), manifest("Alpha Project"));
final ProjectReference alpha = new ProjectReference("Alpha Project", "1.0.0", "pbs", 1, projectsRoot.resolve("alpha")); final ProjectReference alpha = new ProjectReference("Alpha Project", "1.0.0", "pbs", 1, AppMode.Game, projectsRoot.resolve("alpha"));
final KnownProjectsService service = new KnownProjectsService( final KnownProjectsService service = new KnownProjectsService(
tempDir.resolve("known-projects.txt"), tempDir.resolve("known-projects.txt"),
@ -52,7 +53,7 @@ final class KnownProjectsServiceTest {
final Path projectsRoot = tempDir.resolve("projects"); final Path projectsRoot = tempDir.resolve("projects");
Files.createDirectories(projectsRoot.resolve("alpha")); Files.createDirectories(projectsRoot.resolve("alpha"));
Files.writeString(projectsRoot.resolve("alpha").resolve("prometeu.json"), manifest("Alpha Project")); Files.writeString(projectsRoot.resolve("alpha").resolve("prometeu.json"), manifest("Alpha Project"));
final ProjectReference alpha = new ProjectReference("Alpha Project", "1.0.0", "pbs", 1, projectsRoot.resolve("alpha")); final ProjectReference alpha = new ProjectReference("Alpha Project", "1.0.0", "pbs", 1, AppMode.Game, projectsRoot.resolve("alpha"));
final KnownProjectsService service = new KnownProjectsService( final KnownProjectsService service = new KnownProjectsService(
tempDir.resolve("known-projects.txt"), tempDir.resolve("known-projects.txt"),
@ -74,6 +75,7 @@ final class KnownProjectsServiceTest {
"version": "1.0.0", "version": "1.0.0",
"language": "pbs", "language": "pbs",
"stdlib": "1", "stdlib": "1",
"target": "Game",
"dependencies": [] "dependencies": []
} }
""".formatted(name); """.formatted(name);

View File

@ -2,6 +2,7 @@ package p.studio.projects;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.studio.AppMode;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -38,6 +39,7 @@ final class ProjectCatalogServiceTest {
assertEquals("1.0.0", project.version()); assertEquals("1.0.0", project.version());
assertEquals("pbs", project.languageId()); assertEquals("pbs", project.languageId());
assertEquals(1, project.stdlibVersion()); assertEquals(1, project.stdlibVersion());
assertEquals(AppMode.Game, project.target());
assertTrue(Files.isDirectory(project.rootPath())); assertTrue(Files.isDirectory(project.rootPath()));
assertTrue(Files.isRegularFile(project.rootPath().resolve("prometeu.json"))); assertTrue(Files.isRegularFile(project.rootPath().resolve("prometeu.json")));
assertTrue(Files.isRegularFile(project.rootPath().resolve(".gitignore"))); assertTrue(Files.isRegularFile(project.rootPath().resolve(".gitignore")));
@ -84,6 +86,7 @@ final class ProjectCatalogServiceTest {
tempDir, tempDir,
"pbs", "pbs",
7, 7,
AppMode.Game,
"code", "code",
8, 8,
"/opt/prometeu/runtime")); "/opt/prometeu/runtime"));
@ -135,6 +138,7 @@ final class ProjectCatalogServiceTest {
"version": "1.0.0", "version": "1.0.0",
"language": "pbs", "language": "pbs",
"stdlib": "1", "stdlib": "1",
"target": "Game",
"dependencies": [] "dependencies": []
} }
""".formatted(name); """.formatted(name);

View File

@ -1,6 +1,7 @@
package p.studio.projectsessions; package p.studio.projectsessions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import p.studio.AppMode;
import p.studio.lsp.api.LspServerLifecycle; import p.studio.lsp.api.LspServerLifecycle;
import p.studio.lsp.messages.LspProjectContext; import p.studio.lsp.messages.LspProjectContext;
import p.studio.lsp.messages.LspServerConfiguration; import p.studio.lsp.messages.LspServerConfiguration;
@ -29,6 +30,7 @@ final class StudioProjectSessionFactoryTest {
"1.0.0", "1.0.0",
"pbs", "pbs",
1, 1,
AppMode.Game,
Path.of("/tmp/example")); Path.of("/tmp/example"));
final StudioProjectSession session = sessionFactory.open(projectReference); final StudioProjectSession session = sessionFactory.open(projectReference);
@ -58,6 +60,7 @@ final class StudioProjectSessionFactoryTest {
"1.0.0", "1.0.0",
"pbs", "pbs",
1, 1,
AppMode.Game,
Path.of("/tmp/example")))); Path.of("/tmp/example"))));
assertEquals("boom", failure.getMessage()); assertEquals("boom", failure.getMessage());

View File

@ -1,6 +1,7 @@
package p.studio.projectsessions; package p.studio.projectsessions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import p.studio.AppMode;
import p.studio.execution.StudioExecutionSessionService; import p.studio.execution.StudioExecutionSessionService;
import p.studio.lsp.api.LspServerLifecycle; import p.studio.lsp.api.LspServerLifecycle;
import p.studio.lsp.messages.LspProjectContext; import p.studio.lsp.messages.LspProjectContext;
@ -72,7 +73,7 @@ final class StudioProjectSessionTest {
} }
private ProjectReference projectReference() { private ProjectReference projectReference() {
return new ProjectReference("Example", "1.0.0", "pbs", 1, Path.of("/tmp/example")); return new ProjectReference("Example", "1.0.0", "pbs", 1, AppMode.Game, Path.of("/tmp/example"));
} }
private static final class RecordingProjectLocalStudioStateService extends ProjectLocalStudioStateService { private static final class RecordingProjectLocalStudioStateService extends ProjectLocalStudioStateService {

View File

@ -2,6 +2,7 @@ package p.studio.projectstate;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.studio.AppMode;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.projects.ProjectStudioPaths; import p.studio.projects.ProjectStudioPaths;
@ -75,6 +76,6 @@ final class ProjectLocalStudioSetupServiceTest {
private ProjectReference project(final String name) { private ProjectReference project(final String name) {
final Path projectRoot = tempDir.resolve(name); final Path projectRoot = tempDir.resolve(name);
return new ProjectReference("Main", "1.0.0", "pbs", 1, projectRoot); return new ProjectReference("Main", "1.0.0", "pbs", 1, AppMode.Game, projectRoot);
} }
} }

View File

@ -2,6 +2,7 @@ package p.studio.projectstate;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import p.studio.AppMode;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.projects.ProjectStudioPaths; import p.studio.projects.ProjectStudioPaths;
@ -97,6 +98,6 @@ final class ProjectLocalStudioStateServiceTest {
private ProjectReference project(final String name) { private ProjectReference project(final String name) {
final Path projectRoot = tempDir.resolve(name); final Path projectRoot = tempDir.resolve(name);
return new ProjectReference("Main", "1.0.0", "pbs", 1, projectRoot); return new ProjectReference("Main", "1.0.0", "pbs", 1, AppMode.Game, projectRoot);
} }
} }

View File

@ -10,6 +10,7 @@ import p.packer.messages.assets.AssetFamilyCatalog;
import p.packer.messages.assets.OutputCodecCatalog; import p.packer.messages.assets.OutputCodecCatalog;
import p.packer.messages.assets.OutputFormatCatalog; import p.packer.messages.assets.OutputFormatCatalog;
import p.packer.messages.assets.PackerCodecConfigurationFieldType; import p.packer.messages.assets.PackerCodecConfigurationFieldType;
import p.studio.AppMode;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.workspaces.assets.metadata.AssetStudioGlyphSpecialization; import p.studio.workspaces.assets.metadata.AssetStudioGlyphSpecialization;
import p.studio.workspaces.assets.metadata.AssetStudioSceneBankMetadata; import p.studio.workspaces.assets.metadata.AssetStudioSceneBankMetadata;
@ -118,7 +119,7 @@ final class SceneBankWorkflowServiceTest {
} }
private ProjectReference projectReference() { private ProjectReference projectReference() {
return new ProjectReference("main", "1", "pbs", 1, tempDir.resolve("project")); return new ProjectReference("main", "1", "pbs", 1, AppMode.Game, tempDir.resolve("project"));
} }
private AssetWorkspaceAssetDetails createValidScene(ProjectReference project) throws Exception { private AssetWorkspaceAssetDetails createValidScene(ProjectReference project) throws Exception {

View File

@ -8,13 +8,10 @@ import p.packer.messages.assets.AssetFamilyCatalog;
import p.packer.messages.assets.OutputCodecCatalog; import p.packer.messages.assets.OutputCodecCatalog;
import p.packer.messages.assets.OutputFormatCatalog; import p.packer.messages.assets.OutputFormatCatalog;
import p.packer.messages.assets.PackerCodecConfigurationFieldType; import p.packer.messages.assets.PackerCodecConfigurationFieldType;
import p.studio.AppMode;
import p.studio.projects.ProjectReference; import p.studio.projects.ProjectReference;
import p.studio.workspaces.assets.metadata.AssetStudioGlyphSpecialization;
import p.studio.workspaces.assets.metadata.AssetStudioMetadataService;
import p.studio.workspaces.assets.metadata.AssetStudioSceneBankMetadata;
import p.studio.workspaces.assets.metadata.AssetStudioSceneLayerBinding;
import p.studio.workspaces.assets.metadata.AssetStudioSceneTile;
import p.studio.workspaces.assets.messages.*; import p.studio.workspaces.assets.messages.*;
import p.studio.workspaces.assets.metadata.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -45,8 +42,8 @@ final class TiledAssetGenerationServiceTest {
assertTrue(Files.isRegularFile(tsxPath)); assertTrue(Files.isRegularFile(tsxPath));
final TiledTilesetDocument tileset = codec.readTileset(tsxPath); final TiledTilesetDocument tileset = codec.readTileset(tsxPath);
assertEquals(2, tileset.tiles().size()); assertEquals(2, tileset.tiles().size());
assertEquals("a.png", tileset.tiles().get(0).imageSource()); assertEquals("a.png", tileset.tiles().getFirst().imageSource());
assertEquals("glyph_id", tileset.tiles().get(0).properties().getFirst().name()); assertEquals("glyph_id", tileset.tiles().getFirst().properties().getFirst().name());
} }
@Test @Test
@ -70,7 +67,7 @@ final class TiledAssetGenerationServiceTest {
final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld"); final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld");
Files.createDirectories(sceneRoot); Files.createDirectories(sceneRoot);
final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot); final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot);
final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, projectRoot); final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, AppMode.Game, projectRoot);
final TiledAssetGenerationResult result = service.exportSceneBankTmx(projectReference, details); final TiledAssetGenerationResult result = service.exportSceneBankTmx(projectReference, details);
@ -105,7 +102,7 @@ final class TiledAssetGenerationServiceTest {
final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld"); final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld");
Files.createDirectories(sceneRoot); Files.createDirectories(sceneRoot);
final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot); final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot);
final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, projectRoot); final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, AppMode.Game, projectRoot);
final Path tmxPath = sceneRoot.resolve("scene.tmx"); final Path tmxPath = sceneRoot.resolve("scene.tmx");
Files.writeString(tmxPath, "legacy"); Files.writeString(tmxPath, "legacy");
@ -145,7 +142,7 @@ final class TiledAssetGenerationServiceTest {
final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld"); final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld");
Files.createDirectories(sceneRoot); Files.createDirectories(sceneRoot);
final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot); final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot);
final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, projectRoot); final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, AppMode.Game, projectRoot);
assertTrue(service.exportSceneBankTmx(projectReference, details).success()); assertTrue(service.exportSceneBankTmx(projectReference, details).success());
final Path tmxPath = sceneRoot.resolve("scene.tmx"); final Path tmxPath = sceneRoot.resolve("scene.tmx");
@ -183,7 +180,7 @@ final class TiledAssetGenerationServiceTest {
final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld"); final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld");
Files.createDirectories(sceneRoot); Files.createDirectories(sceneRoot);
final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot); final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot);
final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, projectRoot); final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, AppMode.Game, projectRoot);
assertTrue(service.exportSceneBankTmx(projectReference, details).success()); assertTrue(service.exportSceneBankTmx(projectReference, details).success());
final Path tsxPath = tilesetRoot.resolve(TiledAssetGenerationService.GENERATED_TSX_FILE); final Path tsxPath = tilesetRoot.resolve(TiledAssetGenerationService.GENERATED_TSX_FILE);
@ -224,7 +221,7 @@ final class TiledAssetGenerationServiceTest {
final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld"); final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld");
Files.createDirectories(sceneRoot); Files.createDirectories(sceneRoot);
final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot); final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot);
final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, projectRoot); final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, AppMode.Game, projectRoot);
assertTrue(service.exportSceneBankTmx(projectReference, details).success()); assertTrue(service.exportSceneBankTmx(projectReference, details).success());
final Path tmxPath = sceneRoot.resolve("scene.tmx"); final Path tmxPath = sceneRoot.resolve("scene.tmx");
@ -290,7 +287,7 @@ final class TiledAssetGenerationServiceTest {
final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld"); final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld");
Files.createDirectories(sceneRoot); Files.createDirectories(sceneRoot);
final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot); final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot);
final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, projectRoot); final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, AppMode.Game, projectRoot);
assertTrue(service.exportSceneBankTmx(projectReference, details).success()); assertTrue(service.exportSceneBankTmx(projectReference, details).success());
final Path tmxPath = sceneRoot.resolve("scene.tmx"); final Path tmxPath = sceneRoot.resolve("scene.tmx");
@ -361,7 +358,7 @@ final class TiledAssetGenerationServiceTest {
final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld"); final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld");
Files.createDirectories(sceneRoot); Files.createDirectories(sceneRoot);
final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot); final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot);
final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, projectRoot); final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, AppMode.Game, projectRoot);
final Path tmxPath = sceneRoot.resolve("scene.tmx"); final Path tmxPath = sceneRoot.resolve("scene.tmx");
Files.writeString(tmxPath, """ Files.writeString(tmxPath, """
@ -398,7 +395,7 @@ final class TiledAssetGenerationServiceTest {
final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld"); final Path sceneRoot = projectRoot.resolve("assets/scenes/overworld");
Files.createDirectories(sceneRoot); Files.createDirectories(sceneRoot);
final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot); final AssetWorkspaceAssetDetails details = sceneDetails(sceneRoot);
final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, projectRoot); final ProjectReference projectReference = new ProjectReference("main", "1", "pbs", 1, AppMode.Game, projectRoot);
final Path tmxPath = sceneRoot.resolve("scene.tmx"); final Path tmxPath = sceneRoot.resolve("scene.tmx");
Files.writeString(tmxPath, """ Files.writeString(tmxPath, """

View File

@ -3,6 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"language": "pbs", "language": "pbs",
"stdlib": "1", "stdlib": "1",
"target": "Game",
"dependencies": [ "dependencies": [
] ]
} }

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"language": "pbs", "language": "pbs",
"stdlib": "1", "stdlib": "1",
"target": "Game",
"dependencies": [ "dependencies": [
] ]
} }