Skip to content

Commit 4cf4a89

Browse files
authored
implement "it" as closure self reference & lua robustness (#1162)
1 parent c7bb6c0 commit 4cf4a89

17 files changed

Lines changed: 226 additions & 45 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ exprMemberVar:
340340

341341

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

346346

@@ -375,7 +375,7 @@ exprPrimary:
375375
| exprClosure
376376
| exprStatementsBlock
377377
| exprDestroy
378-
| varname=ID indexes?
378+
| varname=(ID|IT) indexes?
379379
| atom=(INT
380380
| REAL
381381
| STRING

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.google.common.collect.ImmutableMultimap.Builder;
55
import de.peeeq.wurstscript.ast.*;
66
import de.peeeq.wurstscript.attributes.names.NameLink;
7+
import de.peeeq.wurstscript.attributes.names.OtherLink;
78
import de.peeeq.wurstscript.types.WurstTypeArray;
89

910
import java.util.Map.Entry;
@@ -33,6 +34,10 @@ private static void collect(Builder<Element, VarDef> result, ExprClosure closure
3334
if (e instanceof NameRef) {
3435
NameRef nr = (NameRef) e;
3536
NameLink def = nr.attrNameLink();
37+
if (def instanceof OtherLink) {
38+
// Synthetic links (e.g. implicit closure-self) are not captured locals.
39+
return;
40+
}
3641

3742
if (def != null && isLocalVariable(def.getDef())) {
3843
VarDef v = (VarDef) def.getDef();

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import de.peeeq.wurstscript.WurstOperator;
44
import de.peeeq.wurstscript.ast.*;
55
import de.peeeq.wurstscript.attributes.names.NameLink;
6+
import de.peeeq.wurstscript.attributes.names.OtherLink;
67
import de.peeeq.wurstscript.intermediatelang.ILconst;
78
import de.peeeq.wurstscript.intermediatelang.ILconstInt;
89

@@ -31,6 +32,9 @@ public static ILconst calculate(ExprIntVal e) {
3132

3233
public static ILconst calculate(ExprVarAccess e) {
3334
NameLink v = e.attrNameLink();
35+
if (v instanceof OtherLink) {
36+
throw new ConstantValueCalculationException(e.toString());
37+
}
3438
if (v != null && v.getDef() instanceof GlobalVarDef) {
3539
GlobalVarDef g = (GlobalVarDef) v.getDef();
3640
if (g.attrIsConstant() && g.getInitialExpr() instanceof Expr) {

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import de.peeeq.wurstscript.ast.*;
66
import de.peeeq.wurstscript.attributes.names.FuncLink;
77
import de.peeeq.wurstscript.attributes.names.NameLink;
8+
import de.peeeq.wurstscript.attributes.names.OtherLink;
89
import de.peeeq.wurstscript.types.*;
910
import de.peeeq.wurstscript.utils.Utils;
1011
import org.eclipse.jdt.annotation.Nullable;
@@ -68,13 +69,13 @@ public static WurstType calculate(ExprVarAccess term) {
6869

6970
return WurstTypeUnknown.instance();
7071
}
71-
if (varDef.getDef() instanceof VarDef) {
72+
if (!(varDef instanceof OtherLink) && varDef.getDef() instanceof VarDef) {
7273
if (Utils.getParentVarDef(Optional.of(term)) == Optional.of((VarDef) varDef.getDef())) {
7374
term.addError("Recursive variable definition is not allowed.");
7475
return WurstTypeUnknown.instance();
7576
}
7677
}
77-
if (varDef.getDef() instanceof FunctionDefinition) {
78+
if (!(varDef instanceof OtherLink) && varDef.getDef() instanceof FunctionDefinition) {
7879
term.addError("Missing parantheses for function call");
7980
}
8081
return varDef.getTyp();
@@ -388,10 +389,10 @@ public static WurstType calculate(ExprMemberVarDot term) {
388389
if (varDef == null) {
389390
return WurstTypeUnknown.instance();
390391
}
391-
if (varDef.getDef() instanceof FunctionDefinition) {
392+
if (!(varDef instanceof OtherLink) && varDef.getDef() instanceof FunctionDefinition) {
392393
term.addError("Missing parantheses for function call");
393394
}
394-
if (varDef.getDef().attrIsStatic() && !term.getLeft().attrTyp().isStaticRef()) {
395+
if (!(varDef instanceof OtherLink) && varDef.getDef().attrIsStatic() && !term.getLeft().attrTyp().isStaticRef()) {
395396
term.addError("Cannot access static variable " + term.getVarName() + " via a dynamic reference.");
396397
}
397398
return varDef.getTyp(); // TODO .setTypeArgs(term.getLeft().attrTyp().getTypeArgBinding());
@@ -403,7 +404,7 @@ public static WurstType calculate(ExprMemberArrayVarDot term) {
403404
if (varDef == null) {
404405
return WurstTypeUnknown.instance();
405406
}
406-
if (varDef.getDef().attrIsStatic() && !term.getLeft().attrTyp().isStaticRef()) {
407+
if (!(varDef instanceof OtherLink) && varDef.getDef().attrIsStatic() && !term.getLeft().attrTyp().isStaticRef()) {
407408
term.addError("Cannot access static array variable " + term.getVarName() + " via a dynamic reference.");
408409
}
409410
WurstType typ = varDef.getTyp();

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import de.peeeq.wurstscript.ast.*;
44
import de.peeeq.wurstscript.attributes.names.FuncLink;
55
import de.peeeq.wurstscript.attributes.names.NameLink;
6+
import de.peeeq.wurstscript.attributes.names.OtherLink;
67
import de.peeeq.wurstscript.types.WurstType;
78
import org.eclipse.jdt.annotation.Nullable;
89

@@ -108,6 +109,9 @@ static OptExpr getFunctionCallImplicitParameter(FunctionCall e, FuncLink calledF
108109

109110
private static OptExpr getImplicitParamterCaseNormalVar(NameRef e) {
110111
NameLink def = e.attrNameLink();
112+
if (def instanceof OtherLink) {
113+
return Ast.NoExpr();
114+
}
111115
if (def != null && def.getDef() instanceof VarDef) {
112116
VarDef varDef = (VarDef) def.getDef();
113117
if (varDef.attrIsDynamicClassMember()) {

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

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import de.peeeq.wurstscript.ast.*;
44
import de.peeeq.wurstscript.attributes.names.FuncLink;
55
import de.peeeq.wurstscript.attributes.names.NameLink;
6+
import de.peeeq.wurstscript.attributes.names.OtherLink;
7+
import de.peeeq.wurstscript.attributes.names.Visibility;
68
import de.peeeq.wurstscript.types.WurstType;
9+
import de.peeeq.wurstscript.types.WurstTypeClassOrInterface;
10+
import de.peeeq.wurstscript.types.WurstTypeUnknown;
711
import de.peeeq.wurstscript.types.WurstTypeEnum;
812
import de.peeeq.wurstscript.types.WurstTypeModule;
913
import org.eclipse.jdt.annotation.Nullable;
@@ -74,8 +78,52 @@ public static NameLink calculate(ExprMemberVar term) {
7478

7579
protected static NameLink searchNameInScope(String varName, NameRef node) {
7680
boolean showErrors = !varName.startsWith("gg_");
77-
NameLink result = node.lookupVar(varName, showErrors);
78-
return result;
81+
if (!"it".equals(varName)) {
82+
return node.lookupVar(varName, showErrors);
83+
}
84+
85+
// Normal lexical lookup wins, so user-defined names can shadow implicit closure-self.
86+
NameLink result = node.lookupVar(varName, false);
87+
if (result != null) {
88+
return result;
89+
}
90+
91+
NameLink implicitClosureSelf = lookupImplicitClosureSelf(node, showErrors);
92+
if (implicitClosureSelf != null) {
93+
return implicitClosureSelf;
94+
}
95+
if (node.attrNearestExprClosure() != null) {
96+
// keep diagnostics focused on closure typing instead of "unknown variable it"
97+
return null;
98+
}
99+
100+
if (!showErrors) {
101+
return null;
102+
}
103+
104+
// Fallback to default diagnostics when no implicit closure-self is available.
105+
return node.lookupVar(varName, true);
106+
}
107+
108+
private static @Nullable NameLink lookupImplicitClosureSelf(NameRef node, boolean showErrors) {
109+
ExprClosure closure = node.attrNearestExprClosure();
110+
if (closure == null) {
111+
return null;
112+
}
113+
WurstType expectedTyp = closure.attrExpectedTypAfterOverloading();
114+
if (!(expectedTyp instanceof WurstTypeClassOrInterface)) {
115+
if (showErrors && (expectedTyp instanceof WurstTypeUnknown)) {
116+
node.addError("Cannot use implicit closure self 'it' because the closure target type is unknown.");
117+
}
118+
return null;
119+
}
120+
121+
return new OtherLink(Visibility.LOCAL, "it", expectedTyp) {
122+
@Override
123+
public de.peeeq.wurstscript.jassIm.ImExpr translate(NameRef e, de.peeeq.wurstscript.translation.imtranslation.ImTranslator t, de.peeeq.wurstscript.jassIm.ImFunction f) {
124+
return de.peeeq.wurstscript.jassIm.JassIm.ImVarAccess(t.getThisVar(closure));
125+
}
126+
};
79127
}
80128

81129
private static boolean isWriteAccess(final NameRef node) {
@@ -110,7 +158,7 @@ private static boolean isWriteAccess(final NameRef node) {
110158

111159
public static @Nullable NameDef tryGetNameDef(NameRef e) {
112160
NameLink link = e.attrNameLink();
113-
if (link == null) {
161+
if (link == null || link instanceof OtherLink) {
114162
return null;
115163
}
116164
return link.getDef();
@@ -139,6 +187,9 @@ private static boolean isWriteAccess(final NameRef node) {
139187

140188
public static NameDef calculateDef(NameRef nameRef) {
141189
NameLink l = nameRef.attrNameLink();
190+
if (l instanceof OtherLink) {
191+
return null;
192+
}
142193
return l == null ? null : l.getDef();
143194
}
144195
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import de.peeeq.wurstscript.ast.*;
55
import de.peeeq.wurstscript.attributes.names.FuncLink;
66
import de.peeeq.wurstscript.attributes.names.NameLink;
7+
import de.peeeq.wurstscript.attributes.names.OtherLink;
78
import de.peeeq.wurstscript.types.WurstType;
89
import de.peeeq.wurstscript.utils.Utils;
910
import org.eclipse.jdt.annotation.Nullable;
@@ -160,6 +161,9 @@ public static String description(NameRef nr) {
160161
if (nameDef == null) {
161162
return nr.getVarName() + " is not defined yet.";
162163
}
164+
if (nameDef instanceof OtherLink) {
165+
return nr.getVarName() + " has type " + htmlType(nameDef.getTyp());
166+
}
163167
return nameDef.getDef().descriptionHtml();
164168
}
165169

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ private static ImmutableList<NameDef> generic(Element e) {
3333
}
3434

3535
public static ImmutableList<NameDef> calculate(ExprVarAccess e) {
36-
if (e.attrNameLink() != null) {
36+
if (e.attrNameLink() != null && e.attrNameDef() != null) {
3737
return ImmutableList.of(e.attrNameDef());
3838
} else {
3939
return ImmutableList.emptyList();
@@ -42,7 +42,7 @@ public static ImmutableList<NameDef> calculate(ExprVarAccess e) {
4242

4343
public static ImmutableList<NameDef> calculate(ExprVarArrayAccess e) {
4444
ImmutableList<NameDef> r = ImmutableList.emptyList();
45-
if (e.attrNameLink() != null) {
45+
if (e.attrNameLink() != null && e.attrNameDef() != null) {
4646
r = ImmutableList.of(e.attrNameDef());
4747
}
4848
r = r.cons(generic(e.getIndexes()));
@@ -51,7 +51,7 @@ public static ImmutableList<NameDef> calculate(ExprVarArrayAccess e) {
5151

5252
public static ImmutableList<NameDef> calculate(ExprMemberArrayVar e) {
5353
ImmutableList<NameDef> r = ImmutableList.emptyList();
54-
if (e.attrNameLink() != null) {
54+
if (e.attrNameLink() != null && e.attrNameDef() != null) {
5555
r = ImmutableList.of(e.attrNameDef());
5656
}
5757
r = r.cons(e.getLeft().attrReadVariables());

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import de.peeeq.wurstscript.ast.*;
66
import de.peeeq.wurstscript.attributes.names.FuncLink;
77
import de.peeeq.wurstscript.attributes.names.NameLink;
8+
import de.peeeq.wurstscript.attributes.names.OtherLink;
89
import de.peeeq.wurstscript.types.WurstType;
910
import de.peeeq.wurstscript.types.WurstTypeClass;
1011

@@ -36,7 +37,7 @@ public static ImmutableList<VarDef> getUsedGlobals(ExprOrStatements e) {
3637
} else if (e instanceof NameRef) {
3738
NameRef nameRef = (NameRef) e;
3839
NameLink def = nameRef.attrNameLink();
39-
if (def.getDef() instanceof GlobalVarDef) {
40+
if (def != null && !(def instanceof OtherLink) && def.getDef() instanceof GlobalVarDef) {
4041
GlobalVarDef varDef = (GlobalVarDef) def.getDef();
4142
result.add(varDef);
4243
}
@@ -103,7 +104,7 @@ private static void collectReadGlobals(Element e, Builder<VarDef> result) {
103104
// write access
104105
} else {
105106
NameLink def = nameRef.attrNameLink();
106-
if (def.getDef() instanceof GlobalVarDef) {
107+
if (def != null && !(def instanceof OtherLink) && def.getDef() instanceof GlobalVarDef) {
107108
GlobalVarDef varDef = (GlobalVarDef) def.getDef();
108109
result.add(varDef);
109110
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import de.peeeq.wurstscript.ast.VarDef;
99
import de.peeeq.wurstscript.ast.WPackage;
1010
import de.peeeq.wurstscript.attributes.names.NameLink;
11+
import de.peeeq.wurstscript.attributes.names.OtherLink;
1112

1213
public class UsedPackages {
1314

@@ -34,7 +35,7 @@ private static void processChildren(Element e,
3435
public static ImmutableCollection<WPackage> usedPackages(NameRef e) {
3536
ImmutableSet.Builder<WPackage> result = ImmutableSet.builder();
3637
NameLink def = e.attrNameLink();
37-
if (def.getDef() instanceof VarDef) {
38+
if (def != null && !(def instanceof OtherLink) && def.getDef() instanceof VarDef) {
3839
if (def.getDef().attrNearestPackage() instanceof WPackage) {
3940
result.add((WPackage) e.attrNearestPackage());
4041
}

0 commit comments

Comments
 (0)