Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion Wurstpack/wurstscript/grill
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ if [[ ! -x "$RUNTIME" ]]; then
exit 3
fi

exec "$RUNTIME" -Dfile.encoding=UTF-8 -jar "$JAR" "$@"
exec "$RUNTIME" -Dfile.encoding=UTF-8 --enable-native-access=ALL-UNNAMED -jar "$JAR" "$@"
2 changes: 1 addition & 1 deletion Wurstpack/wurstscript/grill.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ if not exist "%JAVA%" (
goto :restore
)

"%JAVA%" -Dfile.encoding=UTF-8 -jar "%GRILL_JAR%" %*
"%JAVA%" -Dfile.encoding=UTF-8 --enable-native-access=ALL-UNNAMED -jar "%GRILL_JAR%" %*

:restore
rem Restore previous code page if we captured it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public ILconstTuple createObjectDefinition(ILconstString fileType, ILconstInt ne
String objIdString = ObjectHelper.objectIdIntToString(newUnitId.getVal());
boolean isMeleeOverride = newUnitId.getVal() == deriveFrom.getVal();

if (!isMeleeOverride && dataStore.getObjs().containsKey(ObjId.valueOf(objIdString))) {
globalState.compilationError("Object definition with id " + objIdString + " already exists.");
if (!isMeleeOverride && !globalState.registerCreatedObjectDefinition(fileType.getVal(), objIdString)) {
globalState.compilationError("Object definition with id " + objIdString + " is defined more than once.");
}
ObjMod.Obj objDef = newDefFromFiletype(dataStore, deriveFrom.getVal(), newUnitId.getVal(), isMeleeOverride);
if (!isMeleeOverride) {
Expand All @@ -59,10 +59,15 @@ private ObjMod.Obj newDefFromFiletype(ObjMod<? extends ObjMod.Obj> dataStore, in
if (isMeleeOverride) {
ObjId id = ObjId.valueOf(ObjectHelper.objectIdIntToString(newId));
// same id => modify melee/original definition table
ObjMod.Obj existing = dataStore.getObjs().get(id);
if (existing != null) {
return existing;
}
return dataStore.addObj(id, null);
}
ObjId baseIdS = ObjId.valueOf(ObjectHelper.objectIdIntToString(base));
ObjId newIdS = ObjId.valueOf(ObjectHelper.objectIdIntToString(newId));
dataStore.removeObj(newIdS);
return dataStore.addObj(newIdS, baseIdS);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class ProgramStateIO extends ProgramState {
private @Nullable final MpqEditor mpqEditor;
private final Map<ObjectFileType, ObjMod<? extends ObjMod.Obj>> dataStoreMap = Maps.newLinkedHashMap();
private final Map<ObjectFileType, String> dataStoreHashes = Maps.newLinkedHashMap();
private final Map<String, Set<String>> createdObjectDefinitionIds = Maps.newLinkedHashMap();
private int id = 0;
private final Map<String, ObjMod.Obj> objDefinitions = Maps.newLinkedHashMap();
private PrintStream outStream = System.err;
Expand Down Expand Up @@ -368,6 +369,11 @@ ObjMod.Obj getObjectDefinition(String key) {
return objDefinitions.get(key);
}

boolean registerCreatedObjectDefinition(String fileExtension, String objId) {
Set<String> ids = createdObjectDefinitionIds.computeIfAbsent(fileExtension, k -> new LinkedHashSet<>());
return ids.add(objId);
}

/**
* Calculate hash of an object file's contents
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import de.peeeq.wurstscript.attributes.ErrorHandler;
import de.peeeq.wurstscript.attributes.names.DesugarArrayLength;
import de.peeeq.wurstscript.gui.WurstGui;
import de.peeeq.wurstscript.validation.GlobalCaches;
import de.peeeq.wurstscript.validation.TRVEHelper;
import de.peeeq.wurstscript.validation.WurstValidator;

Expand Down Expand Up @@ -34,6 +35,7 @@ public void checkProg(WurstModel root, Collection<CompilationUnit> toCheck) {
if (errorHandler.getErrorCount() > 0) return;

attachErrorHandler(root);
clearGlobalCaches(root, toCheck);

expandModules(root);

Expand All @@ -50,6 +52,14 @@ public void checkProg(WurstModel root, Collection<CompilationUnit> toCheck) {
validator.validate(toCheck);
}

private void clearGlobalCaches(WurstModel root, Collection<CompilationUnit> toCheck) {
if (toCheck == root || toCheck.size() >= root.size()) {
GlobalCaches.clearAll();
} else {
GlobalCaches.clearLookupCacheFor(toCheck);
}
}

private void attachErrorHandler(WurstModel root) {
for (CompilationUnit cu : root) {
cu.getCuInfo().setCuErrorHandler(errorHandler);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public static ImmutableMultimap<String, TypeLink> exportedTypeNameLinks(WPackage
return result.build();
}


private static void addExportedTypeNameLinks(Builder<String, TypeLink> result, WPackage p, Set<WPackage> alreadyImported) {
if (alreadyImported.contains(p)) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ public static ImmutableMultimap<String, DefLink> calculate(WPackage p) {
return result.build();
}


public static ImmutableMultimap<String, DefLink> calculate(WEntities wEntities) {
ImmutableMultimap.Builder<String, DefLink> result = ImmutableSetMultimap.builder();
for (WEntity e : wEntities) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
import de.peeeq.wurstscript.intermediatelang.interpreter.LocalState;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;

import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

// Expose static fields only if you already have them there; otherwise, just clear via dedicated methods.
Expand Down Expand Up @@ -146,6 +150,28 @@ public static void clearAll() {
HasAnnotation.clearCaches();
}

/**
* Clears lookup entries whose query element belongs to one of the changed roots.
* This keeps editor validation from throwing away hot lookup data for unchanged files.
*/
public static void clearLookupCacheFor(Collection<? extends Element> roots) {
if (roots.isEmpty()) {
return;
}
Set<Element> affected = java.util.Collections.newSetFromMap(new IdentityHashMap<>());
ArrayDeque<Element> todo = new ArrayDeque<>(roots);
while (!todo.isEmpty()) {
Element e = todo.removeLast();
if (!affected.add(e)) {
continue;
}
for (int i = 0; i < e.size(); i++) {
todo.add(e.get(i));
}
}
lookupCache.keySet().removeIf(key -> affected.contains(key.element));
Comment thread
Frotty marked this conversation as resolved.
}

public enum LookupType {
FUNC, VAR, TYPE, PACKAGE, MEMBER_FUNC, MEMBER_VAR
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,10 @@ public WurstValidator(WurstModel root) {

public void validate(Collection<CompilationUnit> toCheck) {
try {
functionCount = countFunctions();
functionCount = countFunctions(toCheck);
visitedFunctions = 0;
heavyFunctions.clear();
heavyBlocks.clear();
GlobalCaches.clearAll();

lightValidation(toCheck);

Expand Down Expand Up @@ -123,11 +122,6 @@ private void lightValidation(Collection<CompilationUnit> toCheck) {
for (CompilationUnit cu : toCheck) {
walkTree(cu);
}

// Build CFG once for heavy phase (enables reachability/prev/next attrs)
for (CompilationUnit cu : toCheck) {
computeFlowAttributes(cu);
}
}

/** Visit only statements under root and run checkReachability where applicable. */
Expand Down Expand Up @@ -1174,16 +1168,19 @@ private void checkIntVal(ExprIntVal e) {
// check range? ...
}

private int countFunctions() {
private int countFunctions(Collection<CompilationUnit> toCheck) {
final int[] functionCount = new int[1];
prog.accept(new WurstModel.DefaultVisitor() {
Element.DefaultVisitor visitor = new Element.DefaultVisitor() {

@Override
public void visit(FuncDef f) {
super.visit(f);
functionCount[0]++;
}
});
};
for (CompilationUnit cu : toCheck) {
cu.accept(visitor);
}
return functionCount[0];
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
package tests.wurstscript.tests;

import de.peeeq.wurstio.intermediateLang.interpreter.CompiletimeNatives;
import de.peeeq.wurstio.intermediateLang.interpreter.ProgramStateIO;
import de.peeeq.wurstio.objectreader.ObjectHelper;
import de.peeeq.wurstscript.ast.Ast;
import de.peeeq.wurstscript.ast.Element;
import de.peeeq.wurstscript.gui.WurstGuiLogger;
import de.peeeq.wurstscript.intermediatelang.ILconstInt;
import de.peeeq.wurstscript.intermediatelang.ILconstString;
import de.peeeq.wurstscript.jassIm.ImProg;
import de.peeeq.wurstscript.jassIm.JassIm;
import net.moonlightflower.wc3libs.bin.ObjMod;
import net.moonlightflower.wc3libs.bin.app.objMod.W3A;
import net.moonlightflower.wc3libs.bin.app.objMod.W3U;
import net.moonlightflower.wc3libs.dataTypes.DataType;
import net.moonlightflower.wc3libs.dataTypes.app.War3String;
import net.moonlightflower.wc3libs.dataTypes.app.War3Real;
import net.moonlightflower.wc3libs.misc.MetaFieldId;
import net.moonlightflower.wc3libs.misc.ObjId;
import org.testng.annotations.Test;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;

public class CompiletimeNativesTest {
Expand Down Expand Up @@ -104,4 +115,97 @@ public void differentIdsObjectDefinitionUsesCustomTable() throws Exception {
assertEquals(w3u.getOrigObjs().size(), 0);
assertEquals(w3u.getCustomObjs().size(), 1);
}

@Test
public void differentIdsObjectDefinitionOverwritesExistingMapObject() throws Exception {
CompiletimeNatives natives = new CompiletimeNatives(null, null, false);
W3U w3u = new W3U();
int hfoo = ObjectHelper.objectIdStringToInt("hfoo");
int hf01 = ObjectHelper.objectIdStringToInt("hf01");
W3U.Obj existing = w3u.addObj(ObjId.valueOf("hf01"), ObjId.valueOf("hpea"));
existing.addMod(new ObjMod.Obj.Mod(MetaFieldId.valueOf("unam"), ObjMod.ValType.STRING, War3String.valueOf("old map object")));

Method newDefFromFiletype = CompiletimeNatives.class.getDeclaredMethod(
"newDefFromFiletype",
ObjMod.class,
int.class,
int.class,
boolean.class
);
newDefFromFiletype.setAccessible(true);

ObjMod.Obj obj = (ObjMod.Obj) newDefFromFiletype.invoke(natives, w3u, hfoo, hf01, false);

assertEquals(w3u.getCustomObjs().size(), 1, "Existing map object should be replaced instead of duplicated");
assertEquals(obj.getId().getVal(), "hf01");
assertEquals(obj.getBaseId().getVal(), "hfoo");
assertEquals(obj.getMods().size(), 0, "Overwritten map object mods should not leak into the Wurst-created object");
}

@Test
public void duplicateCodeObjectDefinitionsReportError() {
WurstGuiLogger gui = new WurstGuiLogger();
ProgramStateIO state = new ProgramStateIO(Optional.empty(), null, gui, emptyProg(), true);
CompiletimeNatives natives = new CompiletimeNatives(state, null, false);
int hfoo = ObjectHelper.objectIdStringToInt("hfoo");
int hf01 = ObjectHelper.objectIdStringToInt("hf01");

natives.createObjectDefinition(new ILconstString("w3u"), new ILconstInt(hf01), new ILconstInt(hfoo));
natives.createObjectDefinition(new ILconstString("w3u"), new ILconstInt(hf01), new ILconstInt(hfoo));

assertEquals(gui.getErrorCount(), 1);
assertTrue(gui.getErrors().contains("Object definition with id hf01 is defined more than once."));
}

@Test
public void createObjectDefinitionDoesNotReportExistingMapObjectAsError() throws Exception {
WurstGuiLogger gui = new WurstGuiLogger();
ProgramStateIO state = new ProgramStateIO(Optional.empty(), null, gui, emptyProg(), true);
CompiletimeNatives natives = new CompiletimeNatives(state, null, false);
int hfoo = ObjectHelper.objectIdStringToInt("hfoo");
int hf01 = ObjectHelper.objectIdStringToInt("hf01");

Method getDataStore = ProgramStateIO.class.getDeclaredMethod("getDataStore", String.class);
getDataStore.setAccessible(true);
W3U w3u = (W3U) getDataStore.invoke(state, "w3u");
W3U.Obj existing = w3u.addObj(ObjId.valueOf("hf01"), ObjId.valueOf("hpea"));
existing.addMod(new ObjMod.Obj.Mod(MetaFieldId.valueOf("unam"), ObjMod.ValType.STRING, War3String.valueOf("old map object")));

natives.createObjectDefinition(new ILconstString("w3u"), new ILconstInt(hf01), new ILconstInt(hfoo));

assertEquals(gui.getErrorCount(), 0);
assertEquals(w3u.getCustomObjs().size(), 1);
ObjMod.Obj obj = w3u.getCustomObjs().get(0);
assertEquals(obj.getId().getVal(), "hf01");
assertEquals(obj.getBaseId().getVal(), "hfoo");
assertFalse(obj.getMods().stream().anyMatch(m -> m.getId().getVal().equals("unam")));
}

@Test
public void sameIdObjectDefinitionsMergeModsWithoutDuplicateError() throws Exception {
WurstGuiLogger gui = new WurstGuiLogger();
ProgramStateIO state = new ProgramStateIO(Optional.empty(), null, gui, emptyProg(), true);
CompiletimeNatives natives = new CompiletimeNatives(state, null, false);
int hfoo = ObjectHelper.objectIdStringToInt("hfoo");

var first = natives.createObjectDefinition(new ILconstString("w3u"), new ILconstInt(hfoo), new ILconstInt(hfoo));
natives.ObjectDefinition_setString(first, new ILconstString("unam"), new ILconstString("first"));
var second = natives.createObjectDefinition(new ILconstString("w3u"), new ILconstInt(hfoo), new ILconstInt(hfoo));
natives.ObjectDefinition_setString(second, new ILconstString("utip"), new ILconstString("second"));

Method getDataStore = ProgramStateIO.class.getDeclaredMethod("getDataStore", String.class);
getDataStore.setAccessible(true);
W3U w3u = (W3U) getDataStore.invoke(state, "w3u");

assertEquals(gui.getErrorCount(), 0);
assertEquals(w3u.getOrigObjs().size(), 1);
ObjMod.Obj obj = w3u.getOrigObjs().get(0);
assertTrue(obj.getMods().stream().anyMatch(m -> m.getId().getVal().equals("unam")));
assertTrue(obj.getMods().stream().anyMatch(m -> m.getId().getVal().equals("utip")));
}

private ImProg emptyProg() {
Element trace = Ast.NoExpr();
return JassIm.ImProg(trace, JassIm.ImVars(), JassIm.ImFunctions(), JassIm.ImMethods(), JassIm.ImClasses(), JassIm.ImTypeClassFuncs(), new HashMap<>());
}
}
Loading