Skip to content

Commit 24c4f76

Browse files
committed
fixes
1 parent f64497b commit 24c4f76

7 files changed

Lines changed: 172 additions & 24 deletions

File tree

de.peeeq.wurstscript/src/main/antlr/de/peeeq/wurstscript/antlr/Wurst.g4

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jassGlobalsBlock:
2525
;
2626

2727
jassGlobalDecl:
28-
constant='constant'? typeExpr name=ID ('=' initial=expr)? NL
28+
constant='constant'? typeExpr name=(ID|CONTINUE|SKIP_|BREAK) ('=' initial=expr)? NL
2929
;
3030

3131
jassFuncDef:
@@ -35,7 +35,7 @@ jassFuncDef:
3535
'endfunction' NL
3636
;
3737

38-
jassLocal: 'local' typeExpr name=ID ('=' initial=expr)? NL;
38+
jassLocal: 'local' typeExpr name=(ID|CONTINUE|SKIP_|BREAK) ('=' initial=expr)? NL;
3939

4040
jassStatements: stmts+=jassStatement*;
4141

@@ -224,7 +224,7 @@ funcSignature:
224224
formalParameters: '(' (params+=formalParameter (',' params+=formalParameter)*)? ')';
225225

226226
formalParameter:
227-
vararg=VARARG? typeExpr name=ID
227+
vararg=VARARG? typeExpr name=(ID|CONTINUE|SKIP_|BREAK)
228228
;
229229

230230
typeExpr:
@@ -238,7 +238,7 @@ typeExpr:
238238
varDef:
239239
modifiersWithDoc
240240
('var'|constant='constant' varType=typeExpr?|constant='let'|varType=typeExpr)
241-
name=ID ('=' variableInit)? NL
241+
name=(ID|CONTINUE|SKIP_|BREAK) ('=' variableInit)? NL
242242
;
243243

244244
variableInit: (arrayInit | initial=expr);
@@ -312,12 +312,12 @@ stmtWhile:
312312

313313
localVarDef:
314314
(var='var'|let='let'|type=typeExpr)
315-
name=ID ('=' variableInit)?
315+
name=(ID|CONTINUE|SKIP_|BREAK) ('=' variableInit)?
316316
;
317317

318318

319319
localVarDefInline:
320-
typeExpr? name=ID
320+
typeExpr? name=(ID|CONTINUE|SKIP_|BREAK)
321321
;
322322

323323
stmtSet:
@@ -335,12 +335,12 @@ exprAssignable:
335335
;
336336

337337
exprMemberVar:
338-
expr dots=('.'|'..') varname=ID? indexes?
338+
expr dots=('.'|'..') varname=(ID|CONTINUE|SKIP_|BREAK)? indexes?
339339
;
340340

341341

342342
exprVarAccess:
343-
varname=(ID|IT) indexes?
343+
varname=(ID|CONTINUE|SKIP_|BREAK|IT) indexes?
344344
;
345345

346346

@@ -354,7 +354,7 @@ expr:
354354
| left=expr 'castTo' castToType=typeExpr
355355
| left=expr 'instanceof' instaneofType=typeExpr
356356
| receiver=expr dotsCall=('.'|'..') funcName=ID? typeArgs argumentList
357-
| receiver=expr dotsVar=('.'|'..') varName=ID? indexes?
357+
| receiver=expr dotsVar=('.'|'..') varName=(ID|CONTINUE|SKIP_|BREAK)? indexes?
358358
| left=expr op=('*'|'/'|'%'|'div'|'mod') right=expr
359359
| op='-' right=expr // TODO move unary minus one up to be compatible with Java etc.
360360
// currently it is here to be backwards compatible with the old wurst parser
@@ -375,7 +375,7 @@ exprPrimary:
375375
| exprClosure
376376
| exprStatementsBlock
377377
| exprDestroy
378-
| varname=(ID|IT) indexes?
378+
| varname=(ID|CONTINUE|SKIP_|BREAK|IT) indexes?
379379
| atom=(INT
380380
| REAL
381381
| STRING
@@ -412,7 +412,7 @@ shortFormalParameters:
412412
| /* empty */
413413
;
414414

415-
shortFormalParameter: typeExpr? name=ID;
415+
shortFormalParameter: typeExpr? name=(ID|CONTINUE|SKIP_|BREAK);
416416

417417
typeParams: ('<' (params+=typeParam (',' params+=typeParam)*)? '>')?;
418418

@@ -447,6 +447,7 @@ exprList : exprs+=expr (',' exprs+=expr)*;
447447

448448

449449

450+
450451
nativeType: 'nativetype' name=ID ('extends' extended=ID)? NL;
451452
initBlock: 'init' NL statementsBlock;
452453
nativeDef: modifiersWithDoc 'native' funcSignature NL;

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/AttrFuncDef.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,38 @@ private static boolean isConstructorThisCall(ExprFunctionCall node) {
209209
}
210210

211211
public static @Nullable FuncLink getIndexGetOperator(Expr node, WurstType receiverType, WurstType indexType) {
212-
return searchMemberFunc(node, receiverType, overloadingIndexGet, Collections.singletonList(indexType));
212+
List<WurstType> argTypes = Collections.singletonList(indexType);
213+
FuncLink candidate = searchMemberFunc(node, receiverType, overloadingIndexGet, argTypes);
214+
if (candidate == null || !matchesArguments(node, candidate, argTypes)) {
215+
return null;
216+
}
217+
return candidate;
213218
}
214219

215220
public static @Nullable FuncLink getIndexSetOperator(Expr node, WurstType receiverType, WurstType indexType, WurstType valueType) {
216-
return searchMemberFunc(node, receiverType, overloadingIndexSet, Lists.newArrayList(indexType, valueType));
221+
List<WurstType> argTypes = Lists.newArrayList(indexType, valueType);
222+
FuncLink candidate = searchMemberFunc(node, receiverType, overloadingIndexSet, argTypes);
223+
if (candidate == null || !matchesArguments(node, candidate, argTypes)) {
224+
return null;
225+
}
226+
return candidate;
227+
}
228+
229+
private static boolean matchesArguments(Element node, FuncLink f, List<WurstType> argumentTypes) {
230+
if (f.getParameterTypes().size() != argumentTypes.size()) {
231+
return false;
232+
}
233+
VariableBinding mapping = f.getVariableBinding();
234+
for (int i = 0; i < argumentTypes.size(); i++) {
235+
WurstType at = argumentTypes.get(i);
236+
WurstType pt = f.getParameterType(i);
237+
VariableBinding m2 = at.matchAgainstSupertype(pt, node, mapping, VariablePosition.RIGHT);
238+
if (m2 == null) {
239+
return false;
240+
}
241+
mapping = m2;
242+
}
243+
return true;
217244
}
218245

219246

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/EliminateClasses.java

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,27 @@ private void createReflectionFunctions() {
8888
"instanceCount",
8989
TypesHelper.imInt(),
9090
JassIm.ImIntVal(0),
91-
c ->
92-
JassIm.ImOperatorCall(WurstOperator.MINUS,
91+
c -> {
92+
ClassManagementVars m = translator.getClassManagementVarsFor(c);
93+
if (m == null) {
94+
return JassIm.ImIntVal(0);
95+
}
96+
return JassIm.ImOperatorCall(WurstOperator.MINUS,
9397
JassIm.ImExprs(
94-
JassIm.ImVarAccess(translator.getClassManagementVarsFor(c).maxIndex),
95-
JassIm.ImVarAccess(translator.getClassManagementVarsFor(c).freeCount))));
98+
JassIm.ImVarAccess(m.maxIndex),
99+
JassIm.ImVarAccess(m.freeCount)));
100+
});
96101
maxInstanceCountFunc = accessClassManagementVar(
97102
"maxInstanceCount",
98103
TypesHelper.imInt(),
99104
JassIm.ImIntVal(0),
100-
c -> JassIm.ImVarAccess(translator.getClassManagementVarsFor(c).maxIndex));
105+
c -> {
106+
ClassManagementVars m = translator.getClassManagementVarsFor(c);
107+
if (m == null) {
108+
return JassIm.ImIntVal(0);
109+
}
110+
return JassIm.ImVarAccess(m.maxIndex);
111+
});
101112
maxTypeIdFunc = maxTypeIdFunc();
102113
}
103114

@@ -111,9 +122,13 @@ private ImFunction maxTypeIdFunc() {
111122
}
112123

113124
public static int calculateMaxTypeId(ImProg prog) {
125+
return calculateMaxTypeId(TypeId.calculate(prog));
126+
}
127+
128+
private static int calculateMaxTypeId(Map<ImClass, Integer> classId) {
114129
boolean seen = false;
115130
int best = 0;
116-
for (Integer x : prog.attrTypeId().values()) {
131+
for (Integer x : classId.values()) {
117132
int i = x;
118133
if (!seen || i > best) {
119134
seen = true;
@@ -129,8 +144,9 @@ private ImFunction accessClassManagementVar(String funcName, ImType returnType,
129144
ImVar typeId = JassIm.ImVar(trace, TypesHelper.imInt(), "typeId", false);
130145
ImVars parameters = JassIm.ImVars(typeId);
131146
ImVars locals = JassIm.ImVars();
132-
Map<ImClass, Integer> classId = prog.attrTypeId();
133-
int maxTypeId = calculateMaxTypeId(prog);
147+
// Use fresh IDs from current classes to avoid stale attrTypeId cache inconsistencies.
148+
Map<ImClass, Integer> classId = TypeId.calculate(prog);
149+
int maxTypeId = calculateMaxTypeId(classId);
134150
ImClass[] typeIdToClass = new ImClass[maxTypeId + 1];
135151
for (Map.Entry<ImClass, Integer> e : classId.entrySet()) {
136152
typeIdToClass[e.getValue()] = e.getKey();
@@ -149,7 +165,11 @@ private ImStmts generateBinarySearch(int lower, int upper, ImVar typeId, ImClass
149165
if (lower > upper) {
150166
return JassIm.ImStmts();
151167
} else if (lower == upper) {
152-
return JassIm.ImStmts(JassIm.ImReturn(prog.getTrace(), makeAccess.apply(typeIdToClass[lower])));
168+
ImClass c = typeIdToClass[lower];
169+
if (c == null) {
170+
return JassIm.ImStmts();
171+
}
172+
return JassIm.ImStmts(JassIm.ImReturn(prog.getTrace(), makeAccess.apply(c)));
153173
} else {
154174
int mid = lower + (upper - lower) / 2;
155175
return

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imtranslation/ImTranslator.java

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,7 +2024,25 @@ public ImMethod getMethodFor(FuncDef f) {
20242024
}
20252025

20262026
public ClassManagementVars getClassManagementVarsFor(ImClass c) {
2027-
return getClassManagementVars().get(c);
2027+
Map<ImClass, ClassManagementVars> vars = getClassManagementVars();
2028+
ClassManagementVars res = vars.get(c);
2029+
if (res != null) {
2030+
return res;
2031+
}
2032+
debugClassManagementMiss("first lookup miss", c, vars);
2033+
// Recover from stale/mutated key situations by rebuilding from current classes.
2034+
classManagementVars = null;
2035+
vars = getClassManagementVars();
2036+
res = vars.get(c);
2037+
if (res != null) {
2038+
return res;
2039+
}
2040+
debugClassManagementMiss("after rebuild miss", c, vars);
2041+
// Last-resort fallback: ensure compilation does not crash language-server requests.
2042+
WLogger.info("ClassManagementVars missing for class " + c.getName() + ", creating fallback mapping.");
2043+
ClassManagementVars fallback = new ClassManagementVars(c, this);
2044+
vars.put(c, fallback);
2045+
return fallback;
20282046
}
20292047

20302048

@@ -2046,7 +2064,7 @@ public Map<ImClass, ClassManagementVars> getClassManagementVars() {
20462064
}
20472065
}
20482066
// generate typeId variables
2049-
classManagementVars = Maps.newLinkedHashMap();
2067+
classManagementVars = new IdentityHashMap<>();
20502068
for (ImClass c : imProg.getClasses()) {
20512069
ImClass rep = p.getRep(c);
20522070
ClassManagementVars v = classManagementVars.computeIfAbsent(rep, r -> new ClassManagementVars(r, this));
@@ -2055,6 +2073,29 @@ public Map<ImClass, ClassManagementVars> getClassManagementVars() {
20552073
return classManagementVars;
20562074
}
20572075

2076+
private void debugClassManagementMiss(String stage, ImClass c, Map<ImClass, ClassManagementVars> vars) {
2077+
StringBuilder sb = new StringBuilder();
2078+
sb.append("[ClassMgmt] ").append(stage)
2079+
.append(" target=").append(c.getName())
2080+
.append("#").append(System.identityHashCode(c))
2081+
.append(" mapSize=").append(vars.size());
2082+
int sameName = 0;
2083+
int sameIdentity = 0;
2084+
for (ImClass k : vars.keySet()) {
2085+
if (k == c) sameIdentity++;
2086+
if (k.getName().equals(c.getName())) {
2087+
sameName++;
2088+
if (sameName <= 5) {
2089+
sb.append(" | sameNameKey=").append(k.getName())
2090+
.append("#").append(System.identityHashCode(k));
2091+
}
2092+
}
2093+
}
2094+
sb.append(" | sameNameCount=").append(sameName)
2095+
.append(" sameIdentityCount=").append(sameIdentity);
2096+
WLogger.info(sb.toString());
2097+
}
2098+
20582099

20592100
public ImFunction getGlobalInitFunc() {
20602101
return globalInitFunc;

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/validation/WurstValidator.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,13 @@ private void checkStmtSet(StmtSet s) {
12191219
+ targetType + ". The overloading function has to be named: " + AttrFuncDef.overloadingIndexSet);
12201220
return;
12211221
}
1222+
WurstType indexType = leftWithIndex.getIndexes().get(0).attrTyp();
1223+
WurstType expectedIndexType = setOverload.getParameterType(0);
1224+
if (!indexType.isSubtypeOf(expectedIndexType, s)) {
1225+
s.addError("Index expression has type " + indexType
1226+
+ " but overloaded [] assignment expects " + expectedIndexType + ".");
1227+
return;
1228+
}
12221229
checkAssignment(Utils.isJassCode(s), s, setOverload.getParameterType(1), rightType);
12231230
checkIfAssigningToConstant(s.getUpdatedExpr());
12241231
checkIfNoEffectAssignment(s);

de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/OpOverloading.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,5 +241,32 @@ public void testOverloading_indexWriteMissingSetter() {
241241
"endpackage");
242242
}
243243

244+
@Test
245+
public void testOverloading_indexReadWrongIndexType() {
246+
testAssertErrorsLines(true, "op_index",
247+
"package test",
248+
" class ListLike",
249+
" function op_index(int i) returns int",
250+
" return i",
251+
" init",
252+
" ListLike l = new ListLike()",
253+
" int x = l[\"x\"]",
254+
"endpackage");
255+
}
256+
257+
@Test
258+
public void testOverloading_indexWriteWrongIndexType() {
259+
testAssertErrorsLines(true, "op_indexAssign",
260+
"package test",
261+
" class ListLike",
262+
" function op_index(int i) returns int",
263+
" return i",
264+
" function op_indexAssign(int i, int v)",
265+
" init",
266+
" ListLike l = new ListLike()",
267+
" l[\"x\"] = 1",
268+
"endpackage");
269+
}
270+
244271

245272
}

de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/SimpleStatementTests.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,31 @@ public void testContinueOutsideLoop() {
103103
);
104104
}
105105

106+
@Test
107+
public void testContinueAsVariableName() {
108+
assertOk(true,
109+
"int continue = 5",
110+
"int x = continue",
111+
"if x == 5",
112+
" testSuccess()",
113+
"");
114+
}
115+
116+
@Test
117+
public void testContinueKeywordAndVariableNameTogether() {
118+
assertOk(true,
119+
"int continue = 0",
120+
"int sum = 0",
121+
"while continue < 5",
122+
" continue++",
123+
" if continue mod 2 == 0",
124+
" continue",
125+
" sum += continue",
126+
"if sum == 9",
127+
" testSuccess()",
128+
"");
129+
}
130+
106131
@Test
107132
public void testWhileContinue() {
108133
assertOk(true,

0 commit comments

Comments
 (0)