Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
matrix: ${{ fromJson(needs.setup.outputs.matrix) }}
runs-on: ${{ matrix.os }}
permissions:
checks: write
contents: read
env:
JAVA_TOOL_OPTIONS: >-
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ WurstSetup/proguard.map
de.peeeq.wurstscript/output.txt
/HelperScripts/gamedata
/HelperScripts/.gradle
/.gradle-user-home
/gradle-home-temp
43 changes: 42 additions & 1 deletion de.peeeq.wurstscript/deploy.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def jreImageDir = layout.buildDirectory.dir("jre-wurst-25")

def distRoot = layout.buildDirectory.dir("dist/slim-${plat}")
def releasesDir = layout.buildDirectory.dir("releases")
def appCdsArchive = distRoot.map { it.file("wurst-runtime/wurst-lsp.jsa") }

// ----------------------- Toolchain / tool paths (providers) -------------------------
def toolchainSvc = extensions.getByType(JavaToolchainService)
Expand Down Expand Up @@ -223,11 +224,51 @@ tasks.named("assembleSlimCompilerDist", Copy) { t ->
}
}

tasks.register("generateAppCdsArchive", Exec) {
description = "Best-effort AppCDS archive generation for language-server startup."
group = "distribution"
dependsOn("assembleSlimCompilerDist")

inputs.file(fatJar)
inputs.dir(distRoot)
outputs.file(appCdsArchive)
ignoreExitValue = true

doFirst {
def distDir = distRoot.get().asFile
def archiveFile = appCdsArchive.get().asFile
def runtimeJava = new File(distDir, "wurst-runtime/bin/java${os.isWindows() ? '.exe' : ''}")
def compilerJar = new File(distDir, "wurst-compiler/${fatJar.get().asFile.name}")

archiveFile.parentFile.mkdirs()
if (archiveFile.exists()) {
archiveFile.delete()
}

executable = runtimeJava.absolutePath
args "-Xshare:off",
Comment thread
Frotty marked this conversation as resolved.
Outdated
"-XX:ArchiveClassesAtExit=${archiveFile.absolutePath}",
Comment thread
Frotty marked this conversation as resolved.
"-jar", compilerJar.absolutePath,
"-languageServerAppCdsTrain"

logger.lifecycle("[appcds] Training LS startup with ${runtimeJava.absolutePath}")
}

doLast {
def archiveFile = appCdsArchive.get().asFile
if (executionResult.get().exitValue != 0 || !archiveFile.exists()) {
logger.warn("[appcds] Archive generation did not succeed on ${plat}; continuing without shipped AppCDS archive.")
} else {
logger.lifecycle("[appcds] Wrote ${archiveFile.absolutePath}")
}
}
}

// 4) Package ZIP on all platforms
tasks.register("packageSlimCompilerDistZip", Zip) {
description = "Packages slim dist as a ZIP archive (all platforms)."
group = "distribution"
dependsOn("assembleSlimCompilerDist")
dependsOn("generateAppCdsArchive")

from(distRoot)
destinationDirectory.set(releasesDir)
Expand Down
5 changes: 5 additions & 0 deletions de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ public static void main(String[] args) {
return;
}

if (runArgs.isLanguageServerAppCdsTrain()) {
LanguageServerStarter.trainForAppCds();
return;
}

if (runArgs.isLanguageServer()) {
LanguageServerStarter.start();
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -616,9 +616,11 @@ public static void exportToWurst(List<? extends ObjMod.Obj> customObjs, ObjectFi
* <p>Fields that have no known wrapper method are emitted as commented-out raw
* calls so the output is still useful even when coverage is incomplete.
*
* <p>Returns {@code false} only when there is no wrapper class at all for this
* <p>Returns {@code false} when there is no wrapper class at all for this
* object type / base ID (e.g. doodads, upgrades, or an unknown ability base ID),
* in which case the caller should fall back to the fully raw format.
* or when a mapped wrapper setter exists but its parameter type is not yet
* supported for source re-emission. In those cases the caller should fall back
* to the fully raw format so no object data is lost on re-export.
*/
private static boolean tryExportWithWrapper(Appendable out, ObjectFileType fileType,
String newId, String oldId,
Expand Down Expand Up @@ -677,11 +679,8 @@ private static boolean tryExportWithWrapper(Appendable out, ObjectFileType fileT
return false;
}

for (ObjMod.Obj.Mod m : mods) {
StdlibObjectMappings.FieldMethodInfo info = fieldMethods.get(fieldKey(m, fileType));
if (info != null && !canUseWrapperForMod(m, info)) {
return false;
}
if (hasUnsupportedMappedWrapperField(mods, fieldMethods, fileType)) {
return false;
}

out.append("@compiletime function create_").append(fileType.getExt()).append("_").append(newId)
Expand All @@ -690,7 +689,7 @@ private static boolean tryExportWithWrapper(Appendable out, ObjectFileType fileT

for (ObjMod.Obj.Mod m : mods) {
StdlibObjectMappings.FieldMethodInfo info = fieldMethods.get(fieldKey(m, fileType));
if (info != null) {
if (info != null && canUseWrapperForMod(m, info)) {
Comment thread
Frotty marked this conversation as resolved.
out.append("\t..").append(info.methodName()).append("(");
if (info.hasLevel() && m instanceof ObjMod.Obj.ExtendedMod) {
out.append(String.valueOf(((ObjMod.Obj.ExtendedMod) m).getLevel())).append(", ");
Expand All @@ -707,6 +706,21 @@ private static boolean tryExportWithWrapper(Appendable out, ObjectFileType fileT
return true;
}

private static boolean hasUnsupportedMappedWrapperField(List<ObjMod.Obj.Mod> mods,
Map<String, StdlibObjectMappings.FieldMethodInfo> fieldMethods,
ObjectFileType fileType) {
for (ObjMod.Obj.Mod mod : mods) {
StdlibObjectMappings.FieldMethodInfo info = fieldMethods.get(fieldKey(mod, fileType));
if (info == null) {
continue;
}
if (!canUseWrapperForMod(mod, info)) {
return true;
}
}
return false;
}

/**
* Returns the lookup key used to match a mod to a {@link StdlibObjectMappings.FieldMethodInfo}.
* Uses the mod's actual dataPtr when it is an {@link ObjMod.Obj.ExtendedMod}, regardless of
Expand All @@ -724,8 +738,7 @@ static String fieldKey(ObjMod.Obj.Mod m, ObjectFileType fileType) {
}

private static boolean canUseWrapperForMod(ObjMod.Obj.Mod m, StdlibObjectMappings.FieldMethodInfo info) {
if (!info.parameterType().isEmpty() && !isPrimitiveParameter(info.parameterType())
&& !isEnumParameter(info.parameterType())) {
if (!supportsWrapperParameterType(info.parameterType())) {
return false;
}
if (isEnumParameter(info.parameterType())) {
Expand All @@ -734,6 +747,12 @@ private static boolean canUseWrapperForMod(ObjMod.Obj.Mod m, StdlibObjectMapping
return true;
}

private static boolean supportsWrapperParameterType(String parameterType) {
return parameterType.isEmpty()
|| isPrimitiveParameter(parameterType)
|| isEnumParameter(parameterType);
}

private static boolean isEnumParameter(String parameterType) {
return ENUM_OBJECT_STRING_TO_CONSTANT.containsKey(parameterType);
}
Expand Down Expand Up @@ -848,6 +867,7 @@ private static Map<String, String> enumConstants(String... valueConstantPairs) {
"mline", "MissileLine"
),
"WeaponSound", enumConstants(
"", "Nothing",
Comment thread
Frotty marked this conversation as resolved.
"Nothing", "Nothing",
"AxeMediumChop", "AxeMediumChop",
"MetalHeavyBash", "MetalHeavyBash",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,15 @@ public static void start() {
server.setRemoteEndpoint(launcher.getRemoteEndpoint());
}

public static void trainForAppCds() {
WurstLanguageServer server = new WurstLanguageServer();
try {
server.getTextDocumentService();
server.getWorkspaceService();
} finally {
server.shutdown().join();
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public void setRootPath(WFile rootPath) {
lock.notify();
}
});
private boolean initialBuildPending = false;
private final BufferManager bufferManager = new BufferManager();
private LanguageClient languageClient;

Expand Down Expand Up @@ -200,9 +201,6 @@ private Workitem getNextWorkItem() {
changesToReconcile = ModelManager.Changes.empty();
reconcileNowRequested = false;
return new Workitem("reconcile files (save)", () -> modelManager.reconcile(changes));
} else if (!userRequests.isEmpty()) {
UserRequest<?> req = userRequests.remove();
return new Workitem(req.toString(), () -> req.run(modelManager));
} else if (!changes.isEmpty()) {
// TODO this can be done more efficiently than doing one at a time
PendingChange change = removeFirst(changes);
Expand Down Expand Up @@ -246,6 +244,12 @@ private Workitem getNextWorkItem() {
return new Workitem("reconcile files", () -> {
modelManager.reconcile(changes);
});
} else if (initialBuildPending) {
initialBuildPending = false;
return new Workitem("initial full build", () -> doInitialBuild());
Comment thread
Frotty marked this conversation as resolved.
} else if (!userRequests.isEmpty()) {
UserRequest<?> req = userRequests.remove();
return new Workitem(req.toString(), () -> req.run(modelManager));
}
return null;
}
Expand All @@ -271,11 +275,20 @@ private void doInit(WFile rootPath) {
log("Handle init " + rootPath);
modelManager = new ModelManagerImpl(rootPath.getFile(), bufferManager);
modelManager.onCompilationResult(this::onCompilationResult);
initialBuildPending = true;
} catch (Exception e) {
WLogger.severe(e);
}
}

log("Start building " + rootPath);
private void doInitialBuild() {
try {
if (modelManager == null || rootPath == null) {
return;
}
log("Start background full build " + rootPath);
modelManager.buildProject();

log("Finished building " + rootPath);
log("Finished background full build " + rootPath);
} catch (Exception e) {
WLogger.severe(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -516,20 +516,11 @@ private void resolveImports(WurstGui gui) {
}

private void replaceCompilationUnit(WFile filename) {
File f;
try {
f = filename.getFile();
} catch (FileNotFoundException e) {
WLogger.info("Cannot replaceCompilationUnit for " + filename + "\n" + e);
return;
}
if (!f.exists()) {
removeCompilationUnit(filename);
return;
}
try {
String contents = Files.toString(f, Charsets.UTF_8);
bufferManager.updateFile(WFile.create(f), contents);
String contents = readCompilationUnitContents(filename, true);
if (contents == null) {
return;
}
replaceCompilationUnit(filename, contents, true);
} catch (IOException e) {
WLogger.severe(e);
Expand Down Expand Up @@ -582,13 +573,10 @@ public Changes syncCompilationUnit(WFile f) {
WLogger.debug("syncCompilationUnit File " + f);
String contents;
try {
File file = f.getFile();
if (!file.exists()) {
removeCompilationUnit(f);
contents = readCompilationUnitContents(f, true);
if (contents == null) {
return Changes.empty();
}
contents = Files.toString(file, Charsets.UTF_8);
bufferManager.updateFile(WFile.create(file), contents);
} catch (IOException e) {
WLogger.severe(e);
throw new ModelManagerException(e);
Expand All @@ -608,6 +596,28 @@ public Changes syncCompilationUnit(WFile f) {
return new Changes(io.vavr.collection.HashSet.of(f), oldPackages);
}

private @Nullable String readCompilationUnitContents(WFile filename, boolean preferOpenBuffer) throws IOException {
if (preferOpenBuffer && bufferManager.getTextDocumentVersion(filename) >= 0) {
return bufferManager.getBuffer(filename);
}
File file;
try {
file = filename.getFile();
} catch (FileNotFoundException e) {
WLogger.info("Cannot read compilation unit for " + filename + "\n" + e);
return null;
}
if (!file.exists()) {
removeCompilationUnit(filename);
return null;
}
String contents = Files.toString(file, Charsets.UTF_8);
if (bufferManager.getTextDocumentVersion(filename) < 0) {
bufferManager.updateFile(WFile.create(file), contents);
}
return contents;
}

private CompilationUnit replaceCompilationUnit(WFile filename, String contents, boolean reportErrors) {
if (!isInWurstFolder(filename) && !isAlreadyLoaded(filename)) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class RunArgs {
private final RunOption optionExtractImports;
private final RunOption optionStartServer;
private final RunOption optionLanguageServer;
private final RunOption optionLanguageServerAppCdsTrain;
private final RunOption optionNoExtractMapScript;
private final RunOption optionFixInstall;
private final RunOption optionCopyMap;
Expand Down Expand Up @@ -136,6 +137,7 @@ public RunArgs(String... args) {

optionLanguageServer = addOption("languageServer", "Starts a language server which can be used by editors to get services "
+ "like code completion, validations, and find declaration. The communication to the language server is via standard input output.");
optionLanguageServerAppCdsTrain = addOption("languageServerAppCdsTrain", "Starts and immediately stops a lightweight language-server startup path for AppCDS training.");

optionHelp = addOption("help", "Prints this help message.");
optionDisablePjass = addOption("noPJass", "Disables PJass checks for the generated code.");
Expand Down Expand Up @@ -352,6 +354,10 @@ public boolean isLanguageServer() {
return optionLanguageServer.isSet;
}

public boolean isLanguageServerAppCdsTrain() {
return optionLanguageServerAppCdsTrain.isSet;
}

public boolean isNoExtractMapScript() {
return optionNoExtractMapScript.isSet;
}
Expand Down
Loading
Loading