Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
25 changes: 20 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,27 @@ concurrency:
cancel-in-progress: true

jobs:
# Emit a wider matrix on master pushes (adds macOS), narrow on PRs (saves minutes)
setup:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- id: set-matrix
shell: bash
run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
echo 'matrix={"include":[{"os":"ubuntu-latest"},{"os":"windows-latest"},{"os":"macos-13"},{"os":"macos-14"}]}' >> "$GITHUB_OUTPUT"
else
echo 'matrix={"include":[{"os":"ubuntu-latest"},{"os":"windows-latest"}]}' >> "$GITHUB_OUTPUT"
fi

build:
name: Gradle build on ${{ matrix.os }}
needs: setup
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
matrix: ${{ fromJson(needs.setup.outputs.matrix) }}
runs-on: ${{ matrix.os }}
permissions:
contents: read
Expand Down Expand Up @@ -147,14 +162,14 @@ jobs:
mkdir -p upload
find artifacts -type f -name '*.zip' -print0 | xargs -0 -I{} cp "{}" upload/

- name: Verify we have both platform zips
- name: Verify we have all platform zips
shell: bash
run: |
shopt -s nullglob
zips=(upload/*.zip)
echo "Found ${#zips[@]} zip(s):"; ls -alh upload
if (( ${#zips[@]} < 2 )); then
echo "ERROR: expected at least Win + Linux zips."
if (( ${#zips[@]} < 4 )); then
echo "ERROR: expected Win + Linux + macOS x64 + macOS arm64 zips (got ${#zips[@]})."
exit 1
fi

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ Checksums/testmd5.txt
downloads/
WurstSetup/proguard.map
de.peeeq.wurstscript/output.txt
/HelperScripts/gamedata
/HelperScripts/.gradle
1 change: 0 additions & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
Wurstscript is a delicious programming language which compiles to Jass or Lua code that is used to power WarCraft III maps.

[![Build](https://github.com/wurstscript/WurstScript/actions/workflows/build.yml/badge.svg)](https://github.com/wurstscript/WurstScript/actions/workflows/build.yml)
[![Release](https://github.com/wurstscript/WurstScript/actions/workflows/release.yml/badge.svg)](https://github.com/wurstscript/WurstScript/actions/workflows/release.yml)
[![GitHub issues](https://img.shields.io/github/issues/wurstscript/WurstScript.svg)]()
[![GitHub pull requests](https://img.shields.io/github/issues-pr/wurstscript/WurstScript.svg)]()
[![Coverage Status](https://coveralls.io/repos/github/wurstscript/WurstScript/badge.svg?branch=master)](https://coveralls.io/github/wurstscript/WurstScript?branch=master)
Expand Down
16 changes: 10 additions & 6 deletions de.peeeq.wurstscript/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -292,17 +292,21 @@ shadowJar {
}

def fatJar = shadowJar.archiveFile.map { it.asFile }
def wurstUserDir = "${System.properties['user.home']}/.wurst"
def wurstCompilerDir = "${wurstUserDir}/wurst-compiler"

tasks.register('delete_legacy_userdir_compiler_jar', Delete) {
delete "${wurstUserDir}/wurstscript.jar"
}

tasks.register('make_for_userdir', Copy) {
dependsOn 'shadowJar', 'make_for_userdir_wurst_compiler'
dependsOn 'shadowJar', 'delete_legacy_userdir_compiler_jar'
from fatJar
into "${System.properties['user.home']}/.wurst/"
into wurstCompilerDir
}

tasks.register('make_for_userdir_wurst_compiler', Copy) {
dependsOn 'shadowJar'
from fatJar
into "${System.properties['user.home']}/.wurst/wurst-compiler/"
tasks.register('make_for_userdir_wurst_compiler') {
dependsOn 'make_for_userdir'
}

tasks.register('make_for_wurstpack', Copy) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ public JassProg transformProgToJass() {
// eliminate
beginPhase(2, "Eliminate generics");
new EliminateGenerics(imTranslator2, imProg2).transform();
imTranslator2.clearStaleClassManagementVars();
printDebugImProg("./test-output/im " + stage++ + "_genericsEliminated.im");
timeTaker.endPhase();
// eliminate classes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ Result<TS, P, T> run(
) throws IOException {

CharStream input = CharStreams.fromReader(reader);
if (input.LA(1) == '\uFEFF') {
input.consume();
}

TS tokenSource = tokenSourceFactory.create(input);
if (installLexerListener != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2102,6 +2102,23 @@ public Map<ImClass, ClassManagementVars> getClassManagementVars() {
return classManagementVars;
}

public void clearStaleClassManagementVars() {
if (classManagementVars == null) {
return;
}
if (classManagementVars.keySet().stream().anyMatch(c -> !imProg.getClasses().contains(c))
|| classManagementVars.values().stream().anyMatch(this::hasStaleClassManagementVars)) {
classManagementVars = null;
}
}

private boolean hasStaleClassManagementVars(ClassManagementVars vars) {
return !imProg.getGlobals().contains(vars.free)
|| !imProg.getGlobals().contains(vars.freeCount)
|| !imProg.getGlobals().contains(vars.maxIndex)
|| !imProg.getGlobals().contains(vars.typeId);
}

private Partitions<ImClass> buildClassPartitions() {
Partitions<ImClass> p = new Partitions<>();
for (ImClass c : imProg.getClasses()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,67 @@ public void classes_method() throws IOException {
testAssertOkFile(new File(TEST_DIR + "Classes_method.wurst"), true);
}

@Test
public void jassKeepsTypeIdGlobalsWhenDestroyGuardReadsThem() throws IOException {
testAssertOkLines(false,
"package test",
" class Reference<T>",
" T value",
"",
" init",
" let r = new Reference<int>",
" destroy r",
"endpackage"
);

String opt = Files.readString(new File(TEST_OUTPUT_PATH + "ClassesTests_jassKeepsTypeIdGlobalsWhenDestroyGuardReadsThem_opt.j").toPath(), StandardCharsets.UTF_8);
assertTrue(opt.contains("integer array Reference_nextFree"),
"Expected generated Jass to keep the Reference_nextFree global declaration.\n" + opt);
assertTrue(opt.contains("integer Reference_firstFree=0"),
"Expected generated Jass to keep the Reference_firstFree global declaration.\n" + opt);
assertTrue(opt.contains("integer Reference_maxIndex=0"),
"Expected generated Jass to keep the Reference_maxIndex global declaration.\n" + opt);
assertTrue(opt.contains("integer array Reference_typeId"),
"Expected generated Jass to keep the Reference_typeId global declaration.\n" + opt);
assertTrue(opt.contains("Reference_typeId[obj]"),
"Expected generated Jass to still reference Reference_typeId in destroy/dispatch logic.");
assertTrue(opt.contains("Reference_nextFree[Reference_firstFree]"),
"Expected generated Jass to still reference the recycle stack globals.");
}

@Test
public void jassNewGenericsRebuildsClassManagementVarsAfterCompiletime() throws IOException {
test()
.runCompiletimeFunctions(true)
.executeProg(false)
.lines(
"package test",
" class Reference<T:>",
" T val",
" construct(T val)",
" this.val = val",
"",
" class Box",
"",
" constant compiletimeRef = new Reference<int>(0)",
"",
" init",
" let r = new Reference<int>(1)",
" destroy r",
" let s = new Reference<bool>(true)",
" destroy s",
"endpackage"
);

String opt = Files.readString(new File(TEST_OUTPUT_PATH + "ClassesTests_jassNewGenericsRebuildsClassManagementVarsAfterCompiletime_opt.j").toPath(), StandardCharsets.UTF_8);
assertTrue(opt.contains("integer array Reference_integer__typeId"),
"Expected generated Jass to declare integer-specialized class-management globals.\n" + opt);
assertTrue(opt.contains("integer array Reference_boolean__typeId"),
"Expected generated Jass to declare boolean-specialized class-management globals.\n" + opt);
assertFalse(opt.contains("Reference_typeId["),
"Expected specialized generic lifecycle code not to reference undeclared raw Reference_typeId.");
}

@Test
public void dispatchNarrowingUsesStaticReceiverTypeInJass() throws IOException {
testAssertOkLines(true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,17 @@ public void testStringNullCheckStaysNull() throws IOException {
);
}

@Test
public void jassFileWithUtf8Bom() {
testJurstWithJass(false, false,
"\uFEFFglobals\nendglobals\n",
Utils.string(
"package test",
"endpackage",
"")
);
}

private void testJurstWithJass(boolean executeProg, boolean withStdLib, String jass, String jurst) {
Map<String, String> inputs = ImmutableMap.of(
"example.j", jass,
Expand Down
Loading