• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wurstscript / WurstScript / 228

29 Nov 2023 05:00PM UTC coverage: 62.48% (-0.09%) from 62.574%
228

push

circleci

web-flow
Show dialog for choosing game path, cleanup (#1083)

* show dialog for choosing game path

* cleanup code

* remove logs and refactor

* remove confusing mpq error, make some mpq loads readonly

17295 of 27681 relevant lines covered (62.48%)

0.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.27
de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/interpreter/ILInterpreter.java
1
package de.peeeq.wurstscript.intermediatelang.interpreter;
2

3
import de.peeeq.wurstio.jassinterpreter.DebugPrintError;
4
import de.peeeq.wurstio.jassinterpreter.InterpreterException;
5
import de.peeeq.wurstio.jassinterpreter.VarargArray;
6
import de.peeeq.wurstscript.ast.Annotation;
7
import de.peeeq.wurstscript.ast.HasModifier;
8
import de.peeeq.wurstscript.ast.Modifier;
9
import de.peeeq.wurstscript.gui.WurstGui;
10
import de.peeeq.wurstscript.intermediatelang.*;
11
import de.peeeq.wurstscript.jassIm.*;
12
import de.peeeq.wurstscript.jassinterpreter.ReturnException;
13
import de.peeeq.wurstscript.jassinterpreter.TestFailException;
14
import de.peeeq.wurstscript.jassinterpreter.TestSuccessException;
15
import de.peeeq.wurstscript.parser.WPos;
16
import de.peeeq.wurstscript.translation.imtranslation.FunctionFlagEnum;
17
import de.peeeq.wurstscript.translation.imtranslation.ImHelper;
18
import org.eclipse.jdt.annotation.Nullable;
19

20
import java.io.File;
21
import java.util.Arrays;
22
import java.util.LinkedHashMap;
23
import java.util.Objects;
24
import java.util.Optional;
25
import java.util.stream.Collectors;
26

27
import static de.peeeq.wurstscript.translation.imoptimizer.UselessFunctionCallsRemover.isFunctionPure;
28

29
public class ILInterpreter implements AbstractInterpreter {
30
    private ImProg prog;
31
    private static boolean cache = false;
1✔
32
    private final ProgramState globalState;
33
    private final TimerMockHandler timerMockHandler = new TimerMockHandler();
1✔
34

35
    public ILInterpreter(ImProg prog, WurstGui gui, Optional<File> mapFile, ProgramState globalState, boolean cache) {
1✔
36
        this.prog = prog;
1✔
37
        this.globalState = globalState;
1✔
38
        ILInterpreter.cache = cache;
1✔
39
        globalState.addNativeProvider(new BuiltinFuncs(globalState));
1✔
40
//        globalState.addNativeProvider(new NativeFunctions());
41
    }
1✔
42

43
    public ILInterpreter(ImProg prog, WurstGui gui, Optional<File> mapFile, boolean isCompiletime, boolean cache) {
44
        this(prog, gui, mapFile, new ProgramState(gui, prog, isCompiletime), cache);
1✔
45
    }
1✔
46

47
    public static LocalState runFunc(ProgramState globalState, ImFunction f, @Nullable Element caller,
48
                                     ILconst... args) {
49
        if (Thread.currentThread().isInterrupted()) {
1✔
50
            throw new InterpreterException(globalState, "Execution interrupted");
×
51
        }
52
        try {
53
            if (f.hasFlag(FunctionFlagEnum.IS_VARARG)) {
1✔
54
                // for vararg functions, rewrite args and put last argument
55
                ILconst[] newArgs = new ILconst[f.getParameters().size()];
1✔
56
                if (newArgs.length - 1 >= 0) System.arraycopy(args, 0, newArgs, 0, newArgs.length - 1);
1✔
57

58
                ILconst[] varargArray = new ILconst[1 + args.length - newArgs.length];
1✔
59
                for (int i = newArgs.length - 1, j = 0; i < args.length; i++, j++) {
1✔
60
                    varargArray[j] = args[i];
1✔
61
                }
62
                newArgs[newArgs.length - 1] = new VarargArray(varargArray);
1✔
63
                args = newArgs;
1✔
64
            }
65

66
            if (f.getParameters().size() != args.length) {
1✔
67
                throw new Error("wrong number of parameters when calling func " + f.getName() + "(" +
×
68
                    Arrays.stream(args).map(Object::toString).collect(Collectors.joining(", ")) + ")");
×
69
            }
70

71
            for (int i = 0; i < f.getParameters().size(); i++) {
1✔
72
                // TODO could do typecheck here
73
                args[i] = adjustTypeOfConstant(args[i], f.getParameters().get(i).getType());
1✔
74
            }
75

76
            if (isCompiletimeNative(f)) {
1✔
77
                return runBuiltinFunction(globalState, f, args);
1✔
78
            }
79

80
            if (f.isNative()) {
1✔
81
                return runBuiltinFunction(globalState, f, args);
1✔
82
            }
83

84
            LocalState localState = new LocalState();
1✔
85
            int i = 0;
1✔
86
            for (ImVar p : f.getParameters()) {
1✔
87
                localState.setVal(p, args[i]);
1✔
88
                i++;
1✔
89
            }
1✔
90

91
            if (f.getBody().isEmpty()) {
1✔
92
                return localState.setReturnVal(ILconstNull.instance());
1✔
93
            } else {
94
                globalState.setLastStatement(f.getBody().get(0));
1✔
95
            }
96

97
            globalState.pushStackframe(f, args, (caller == null ? f : caller).attrTrace().attrErrorPos());
1✔
98

99
            try {
100
                f.getBody().runStatements(globalState, localState);
1✔
101
                globalState.popStackframe();
1✔
102
            } catch (ReturnException e) {
1✔
103
                globalState.popStackframe();
1✔
104
                ILconst retVal = e.getVal();
1✔
105
                retVal = adjustTypeOfConstant(retVal, f.getReturnType());
1✔
106
                return localState.setReturnVal(retVal);
1✔
107
            }
1✔
108
            if (f.getReturnType() instanceof ImVoid) {
1✔
109
                return localState;
1✔
110
            }
111
            throw new InterpreterException("function " + f.getName() + " did not return any value...");
×
112
        } catch (InterpreterException e) {
1✔
113
            String msg = buildStacktrace(globalState, e);
1✔
114
            e.setStacktrace(msg);
1✔
115
            e.setTrace(getTrace(globalState, f));
1✔
116
            throw e;
1✔
117
        } catch (TestSuccessException | TestFailException | DebugPrintError e) {
1✔
118
            throw e;
1✔
119
        } catch (Throwable e) {
×
120
            String msg = buildStacktrace(globalState, e);
×
121
            de.peeeq.wurstscript.ast.Element trace = getTrace(globalState, f);
×
122
            throw new InterpreterException(trace, "You encountered a bug in the interpreter: " + e, e).setStacktrace(msg);
×
123
        }
124
    }
125

126
    public static de.peeeq.wurstscript.ast.Element getTrace(ProgramState globalState, ImFunction f) {
127
        Element lastStatement = globalState.getLastStatement();
1✔
128
        return lastStatement == null ? f.attrTrace() : lastStatement.attrTrace();
1✔
129
    }
130

131
    public static String buildStacktrace(ProgramState globalState, Throwable e) {
132
        StringBuilder err = new StringBuilder();
1✔
133
        try {
134
            WPos src = globalState.getLastStatement().attrTrace().attrSource();
1✔
135
            err.append("at : ").append(new File(src.getFile()).getName()).append(", line ").append(src.getLine()).append("\n");
1✔
136
        } catch (Exception _e) {
×
137
            // ignore
138
        }
1✔
139
        globalState.getStackFrames().appendTo(err);
1✔
140
        return err.toString();
1✔
141
    }
142

143
    @SuppressWarnings("null")
144
    private static ILconst adjustTypeOfConstant(@Nullable ILconst retVal, ImType expectedType) {
145
        if (retVal instanceof ILconstInt && isTypeReal(expectedType)) {
1✔
146
            ILconstInt retValI = (ILconstInt) retVal;
1✔
147
            retVal = new ILconstReal(retValI.getVal());
1✔
148
        }
149
        return retVal;
1✔
150
    }
151

152
    private static boolean isTypeReal(ImType t) {
153
        if (t instanceof ImSimpleType) {
1✔
154
            ImSimpleType st = (ImSimpleType) t;
1✔
155
            return st.getTypename().equals("real");
1✔
156
        }
157
        return false;
1✔
158
    }
159

160
    public static LinkedHashMap<ImFunction, LinkedHashMap<Integer, LocalState>> localStateCache = new LinkedHashMap<>();
1✔
161

162
    private static LocalState runBuiltinFunction(ProgramState globalState, ImFunction f, ILconst... args) {
163
        if (cache && isFunctionPure(f.getName())) {
1✔
164
            int combinedHash = Objects.hash((Object[]) args);
×
165
            if (localStateCache.containsKey(f) && localStateCache.get(f).containsKey(combinedHash)) {
×
166
                return localStateCache.get(f).get(combinedHash);
×
167
            }
168
        }
169
        StringBuilder errors = new StringBuilder();
1✔
170
        for (NativesProvider natives : globalState.getNativeProviders()) {
1✔
171
            try {
172
                LocalState localState = new LocalState(natives.invoke(f.getName(), args));
1✔
173
                if (cache && isFunctionPure(f.getName())) {
1✔
174
                    int combinedHash = Objects.hash((Object[]) args);
×
175
                    LinkedHashMap<Integer, LocalState> cached = localStateCache.getOrDefault(f, new LinkedHashMap<>());
×
176
                    cached.put(combinedHash, localState);
×
177
                    localStateCache.put(f, cached);
×
178
                }
179
                return localState;
1✔
180
            } catch (NoSuchNativeException e) {
1✔
181
                errors.append("\n").append(e.getMessage());
1✔
182
                // ignore
183
            }
184
        }
1✔
185
        globalState.compilationError("function " + f.getName() + " cannot be used from the Wurst interpreter.\n" + errors);
×
186
        if (f.getReturnType() instanceof ImVoid) {
×
187
            return new LocalState();
×
188
        }
189
        ILconst returnValue = ImHelper.defaultValueForComplexType(f.getReturnType()).evaluate(globalState, new LocalState());
×
190
        return new LocalState(returnValue);
×
191
    }
192

193
    private static boolean isCompiletimeNative(ImFunction f) {
194
        if (f.getTrace() instanceof HasModifier) {
1✔
195
            HasModifier f2 = (HasModifier) f.getTrace();
1✔
196
            for (Modifier m : f2.getModifiers()) {
1✔
197
                if (m instanceof Annotation) {
1✔
198
                    Annotation annotation = (Annotation) m;
1✔
199
                    if (annotation.getAnnotationType().equals("@compiletimenative")) {
1✔
200
                        return true;
1✔
201
                    }
202
                }
203
            }
1✔
204
        }
205
        return false;
1✔
206
    }
207

208
    public LocalState executeFunction(String funcName, @Nullable Element trace) {
209
        globalState.resetStackframes();
1✔
210
        for (ImFunction f : prog.getFunctions()) {
1✔
211
            if (f.getName().equals(funcName)) {
1✔
212
                return runFunc(globalState, f, trace);
×
213
            }
214
        }
1✔
215

216
        throw new Error("no function with name " + funcName + "was found.");
×
217
    }
218

219
    public void runVoidFunc(ImFunction f, @Nullable Element trace) {
220
        globalState.resetStackframes();
1✔
221
        ILconst[] args = {};
1✔
222
        if (!f.getParameters().isEmpty()) {
1✔
223
            // this should only happen because of added stacktrace parameter
224
            args = new ILconstString[]{new ILconstString("initial call")};
1✔
225
        }
226
        runFunc(globalState, f, trace, args);
1✔
227
    }
1✔
228

229
    public Element getLastStatement() {
230
        return globalState.getLastStatement();
×
231
    }
232

233
    public void writebackGlobalState(boolean injectObjects) {
234
        globalState.writeBack(injectObjects);
1✔
235

236
    }
1✔
237

238
    public ProgramState getGlobalState() {
239
        return globalState;
1✔
240
    }
241

242
    public void addNativeProvider(NativesProvider np) {
243
        globalState.addNativeProvider(np);
1✔
244
    }
1✔
245

246
    public void setProgram(ImProg imProg) {
247
        this.prog = imProg;
×
248
        this.getGlobalState().setProg(imProg);
×
249
        globalState.resetStackframes();
×
250
    }
×
251

252
    public ProgramState.StackTrace getStackFrames() {
253
        return globalState.getStackFrames();
×
254

255
    }
256

257
    @Override
258
    public void runFuncRef(ILconstFuncRef obj, @Nullable Element trace) {
259
        runVoidFunc(obj.getFunc(), trace);
1✔
260
    }
1✔
261

262
    @Override
263
    public TimerMockHandler getTimerMockHandler() {
264
        return timerMockHandler;
1✔
265
    }
266

267
    @Override
268
    public void completeTimers() {
269
        timerMockHandler.completeTimers();
1✔
270
    }
1✔
271

272
    @Override
273
    public ImProg getImProg() {
274
        return prog;
1✔
275
    }
276

277
    @Override
278
    public int getInstanceCount(int val) {
279
        return (int) globalState.getAllObjects()
1✔
280
            .stream()
1✔
281
            .filter(o -> o.getType().getClassDef().attrTypeId() == val)
1✔
282
            .filter(o -> !o.isDestroyed())
1✔
283
            .count();
1✔
284
    }
285

286
    @Override
287
    public int getMaxInstanceCount(int val) {
288
        return (int) globalState.getAllObjects()
1✔
289
            .stream()
1✔
290
            .filter(o -> o.getType().getClassDef().attrTypeId() == val)
1✔
291
            .count();
1✔
292
    }
293
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc