Skip to content

Commit 7e0e4ad

Browse files
authored
Add constructor chaining (#1159)
1 parent 5dd97a2 commit 7e0e4ad

11 files changed

Lines changed: 559 additions & 23 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ argumentList:
398398
;
399399

400400
exprFunctionCall:
401-
funcName=ID typeArgs argumentList
401+
funcName=(ID|THIS) typeArgs argumentList
402402
;
403403

404404
exprNewObject:'new' className=ID typeArgs argumentList?;

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ public static FuncLink calculate(final ExprFuncRef node) {
166166

167167

168168
public static @Nullable FuncLink calculate(final ExprFunctionCall node) {
169+
if (isConstructorThisCall(node)) {
170+
return null;
171+
}
169172
FuncLink result = searchFunction(node.getFuncName(), node, argumentTypes(node));
170173

171174
if (result == null) {
@@ -181,6 +184,20 @@ public static FuncLink calculate(final ExprFuncRef node) {
181184
return result;
182185
}
183186

187+
private static boolean isConstructorThisCall(ExprFunctionCall node) {
188+
if (!node.getFuncName().equals("this")) {
189+
return false;
190+
}
191+
Element current = node;
192+
while (current != null) {
193+
if (current instanceof ConstructorDef) {
194+
return true;
195+
}
196+
current = current.getParent();
197+
}
198+
return false;
199+
}
200+
184201
private static @Nullable FuncLink getExtensionFunction(Expr left, Expr right, WurstOperator op) {
185202
String funcName = op.getOverloadingFuncName();
186203
if (funcName == null || nativeOperator(op, left.attrTyp(), right.attrTyp(), left)) {

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ private static FunctionSignature filterSigs(
6464
Collection<FunctionSignature> sigs,
6565
List<WurstType> argTypes, StmtCall location) {
6666
if (sigs.isEmpty()) {
67+
if (location instanceof ExprFunctionCall && isConstructorThisCall((ExprFunctionCall) location)) {
68+
return FunctionSignature.empty;
69+
}
6770
if (!isInitTrigFunc(location)) {
6871
if (location instanceof ExprMemberMethodDot) {
6972
ExprMemberMethodDot emmd = (ExprMemberMethodDot) location;
@@ -117,6 +120,20 @@ private static FunctionSignature filterSigs(
117120
return candidates.get(0);
118121
}
119122

123+
private static boolean isConstructorThisCall(ExprFunctionCall call) {
124+
if (!call.getFuncName().equals("this")) {
125+
return false;
126+
}
127+
Element current = call;
128+
while (current != null) {
129+
if (current instanceof ConstructorDef) {
130+
return true;
131+
}
132+
current = current.getParent();
133+
}
134+
return false;
135+
}
136+
120137
private static List<FunctionSignature> filterByIfNotDefinedAnnotation(List<FunctionSignature> candidates) {
121138
List<FunctionSignature> list = new ArrayList<>();
122139
for (FunctionSignature sig : candidates) {

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,5 +196,35 @@ void handleError(List<String> hints) {
196196
}.resolve(constructors, node).orElse(null);
197197
}
198198

199+
public static @Nullable ConstructorDef resolveThisCall(List<ConstructorDef> constructors, final FunctionCall node) {
200+
return new OverloadingResolver<ConstructorDef, FunctionCall>() {
201+
202+
@Override
203+
int getParameterCount(ConstructorDef f) {
204+
return f.getParameters().size();
205+
}
206+
207+
@Override
208+
WurstType getParameterType(ConstructorDef f, int i) {
209+
return f.getParameters().get(i).attrTyp();
210+
}
211+
212+
@Override
213+
int getArgumentCount(FunctionCall c) {
214+
return c.getArgs().size();
215+
}
216+
217+
@Override
218+
WurstType getArgumentType(FunctionCall c, int i) {
219+
return c.getArgs().get(i).attrTyp();
220+
}
221+
222+
@Override
223+
void handleError(List<String> hints) {
224+
node.addError("No suitable constructor found. \n" + Utils.join(hints, ", \n"));
225+
}
226+
}.resolve(constructors, node).orElse(null);
227+
}
228+
199229

200230
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,26 @@ public static ImmutableCollection<FuncLink> calculate(final ExprMemberMethod nod
5050
}
5151

5252
public static ImmutableCollection<FuncLink> calculate(final ExprFunctionCall node) {
53+
if (isConstructorThisCall(node)) {
54+
return ImmutableList.of();
55+
}
5356
return searchFunction(node.getFuncName(), node);
5457
}
5558

59+
private static boolean isConstructorThisCall(ExprFunctionCall node) {
60+
if (!node.getFuncName().equals("this")) {
61+
return false;
62+
}
63+
Element current = node;
64+
while (current != null) {
65+
if (current instanceof ConstructorDef) {
66+
return true;
67+
}
68+
current = current.getParent();
69+
}
70+
return false;
71+
}
72+
5673
private static ImmutableCollection<FuncLink> getExtensionFunction(Expr left, Expr right, WurstOperator op) {
5774
String funcName = op.getOverloadingFuncName();
5875
if (funcName == null || nativeOperator(left.attrTyp(), right.attrTyp(), left)) {

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/gui/WurstGui.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,22 @@ public abstract class WurstGui {
2121
public abstract void showInfoMessage(String message);
2222

2323
public void sendError(CompileError err) {
24+
if (shouldSuppressWarning(err)) {
25+
return;
26+
}
2427
errors.add(err);
2528
}
2629

30+
private boolean shouldSuppressWarning(CompileError err) {
31+
if (err.getErrorType() != ErrorType.WARNING) {
32+
return false;
33+
}
34+
String file = err.getSource().getFile();
35+
String normalized = file.replace('\\', '/').toLowerCase();
36+
return normalized.contains("/_build/dependencies/")
37+
|| normalized.startsWith("_build/dependencies/");
38+
}
39+
2740
public void clearErrors() {
2841
errors.clear();
2942
}

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

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import de.peeeq.wurstscript.ast.*;
44
import de.peeeq.wurstscript.ast.Element;
5+
import de.peeeq.wurstscript.attributes.OverloadingResolver;
56
import de.peeeq.wurstscript.jassIm.Element.DefaultVisitor;
67
import de.peeeq.wurstscript.jassIm.*;
78
import de.peeeq.wurstscript.types.*;
@@ -382,36 +383,75 @@ private void createConstructFunc(ConstructorDef constr) {
382383
ConstructorDef trace = constr;
383384
ImFunction f = translator.getConstructFunc(constr);
384385
ImVar thisVar = translator.getThisVar(constr);
385-
ConstructorDef superConstr = constr.attrSuperConstructor();
386-
if (superConstr != null) {
387-
// call super constructor
388-
ImFunction superConstrFunc = translator.getConstructFunc(superConstr);
389-
ImExprs arguments = ImExprs(ImVarAccess(thisVar));
390-
for (Expr a : superArgs(constr)) {
391-
arguments.add(a.imTranslateExpr(translator, f));
386+
int firstRelevantIndex = firstRelevantStatementIndex(constr);
387+
ExprFunctionCall thisCall = null;
388+
if (firstRelevantIndex >= 0 && constr.getBody().get(firstRelevantIndex) instanceof ExprFunctionCall) {
389+
ExprFunctionCall first = (ExprFunctionCall) constr.getBody().get(firstRelevantIndex);
390+
if (first.getFuncName().equals("this")) {
391+
thisCall = first;
392392
}
393-
ImTypeArguments typeArgs = ImTypeArguments();
394-
ClassDef classDef = constr.attrNearestClassDef();
395-
assert classDef != null;
396-
WurstType extendedType = classDef.getExtendedClass().attrTyp();
397-
if (extendedType instanceof WurstTypeClass) {
398-
WurstTypeClass extendedTypeC = (WurstTypeClass) extendedType;
399-
for (WurstTypeBoundTypeParam bt : extendedTypeC.getTypeParameters()) {
400-
if (bt.isTemplateTypeParameter()) {
401-
typeArgs.add(bt.imTranslateToTypeArgument(translator));
393+
}
394+
int bodyStartIndex = 0;
395+
if (thisCall != null) {
396+
ConstructorDef calledConstr = OverloadingResolver.resolveThisCall(
397+
constr.attrNearestClassOrModule().getConstructors(),
398+
thisCall
399+
);
400+
if (calledConstr != null && calledConstr != constr) {
401+
ImFunction calledConstrFunc = translator.getConstructFunc(calledConstr);
402+
ImExprs arguments = ImExprs(ImVarAccess(thisVar));
403+
for (Expr a : thisCall.getArgs()) {
404+
arguments.add(a.imTranslateExpr(translator, f));
405+
}
406+
f.getBody().add(ImFunctionCall(trace, calledConstrFunc, classTypeArgs(), arguments, false, CallType.NORMAL));
407+
bodyStartIndex = firstRelevantIndex + 1;
408+
}
409+
} else {
410+
ConstructorDef superConstr = constr.attrSuperConstructor();
411+
if (superConstr != null) {
412+
// call super constructor
413+
ImFunction superConstrFunc = translator.getConstructFunc(superConstr);
414+
ImExprs arguments = ImExprs(ImVarAccess(thisVar));
415+
for (Expr a : superArgs(constr)) {
416+
arguments.add(a.imTranslateExpr(translator, f));
417+
}
418+
ImTypeArguments typeArgs = ImTypeArguments();
419+
ClassDef classDef = constr.attrNearestClassDef();
420+
assert classDef != null;
421+
WurstType extendedType = classDef.getExtendedClass().attrTyp();
422+
if (extendedType instanceof WurstTypeClass) {
423+
WurstTypeClass extendedTypeC = (WurstTypeClass) extendedType;
424+
for (WurstTypeBoundTypeParam bt : extendedTypeC.getTypeParameters()) {
425+
if (bt.isTemplateTypeParameter()) {
426+
typeArgs.add(bt.imTranslateToTypeArgument(translator));
427+
}
402428
}
403429
}
430+
f.getBody().add(ImFunctionCall(trace, superConstrFunc, typeArgs, arguments, false, CallType.NORMAL));
404431
}
405-
f.getBody().add(ImFunctionCall(trace, superConstrFunc, typeArgs, arguments, false, CallType.NORMAL));
432+
// call classInitFunc:
433+
f.getBody().add(ImFunctionCall(trace, classInitFunc, classTypeArgs(), JassIm.ImExprs(JassIm.ImVarAccess(thisVar)), false, CallType.NORMAL));
406434
}
407-
// call classInitFunc:
435+
// constructor user code
436+
f.getBody().addAll(translator.translateStatements(f, constr.getBody().subList(bodyStartIndex, constr.getBody().size())));
437+
}
438+
439+
private int firstRelevantStatementIndex(ConstructorDef constr) {
440+
for (int i = 0; i < constr.getBody().size(); i++) {
441+
WStatement s = constr.getBody().get(i);
442+
if (!(s instanceof StartFunctionStatement) && !(s instanceof EndFunctionStatement)) {
443+
return i;
444+
}
445+
}
446+
return -1;
447+
}
448+
449+
private ImTypeArguments classTypeArgs() {
408450
ImTypeArguments typeArguments = JassIm.ImTypeArguments();
409451
for (ImTypeVar tv : imClass.getTypeVariables()) {
410452
typeArguments.add(JassIm.ImTypeArgument(JassIm.ImTypeVarRef(tv), Collections.emptyMap()));
411453
}
412-
f.getBody().add(ImFunctionCall(trace, classInitFunc, typeArguments, JassIm.ImExprs(JassIm.ImVarAccess(thisVar)), false, CallType.NORMAL));
413-
// constructor user code
414-
f.getBody().addAll(translator.translateStatements(f, constr.getBody()));
454+
return typeArguments;
415455
}
416456

417457
private void translateClassInitFunc() {

0 commit comments

Comments
 (0)