Skip to content

Commit f325e2f

Browse files
committed
- Fix default constructors in classes + supported them for subclasses
- Implemented super calls
1 parent 768f1f8 commit f325e2f

File tree

34 files changed

+321
-24
lines changed

34 files changed

+321
-24
lines changed

CodeModel/src/main/java/org/openzen/zenscript/codemodel/HighLevelDefinition.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ public int getNumberOfGenericParameters() {
6464
return typeParameters == null ? 0 : typeParameters.length;
6565
}
6666

67+
public void addDefaultMembers() {}
68+
6769
public void setOuterDefinition(HighLevelDefinition outerDefinition) {
6870
this.outerDefinition = outerDefinition;
6971
}

CodeModel/src/main/java/org/openzen/zenscript/codemodel/SemanticModule.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ public SemanticModule normalize() {
7979
expansions.stream()
8080
).forEach(annotationProcessor::process);
8181

82-
8382
return new SemanticModule(
8483
module,
8584
dependencies,

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CompileErrors.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,10 @@ public static CompileError notStaticCallableMethod(MethodID id) {
390390
return new CompileError(CompileExceptionCode.CANNOT_CALL, "Cannot call this method statically: " + id + "(" + id.getKind() + ")");
391391
}
392392

393+
public static CompileError notSuperCallableMethod(MethodID id) {
394+
return new CompileError(CompileExceptionCode.CANNOT_CALL, "Cannot call this method on super: " + id + "(" + id.getKind() + ")");
395+
}
396+
393397
public static CompileError constructorForwardOutsideConstructor() {
394398
return new CompileError(CompileExceptionCode.CONSTRUCTOR_FORWARD_OUTSIDE_CONSTRUCTOR, "Can only forward constructors inside constructors");
395399
}
@@ -497,7 +501,7 @@ public static CompileError superclassNotVirtual(TypeID type) {
497501
}
498502

499503
public static CompileError typeNotDetermined(String display) {
500-
return new CompileError(CompileExceptionCode.INVALID_TYPE, display + " could not be inferred");
504+
return new CompileError(CompileExceptionCode.TYPE_NOT_INFERRED, display + " could not be inferred");
501505
}
502506

503507
public static CompileError invalidArrayDimension(int dimension) {

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/ExpressionBuilder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public interface ExpressionBuilder {
2525

2626
Expression callVirtual(MethodInstance method, Expression target, CallArguments arguments);
2727

28+
Expression callSuper(MethodInstance method, Expression target, CallArguments arguments);
29+
2830
Expression coalesce(Expression left, Expression right);
2931

3032
Expression constant(boolean value);

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/InstanceCallable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import java.util.stream.Stream;
1717

1818
public final class InstanceCallable {
19-
private final List<InstanceCallableMethod> overloads;
19+
public final List<InstanceCallableMethod> overloads;
2020

2121
public InstanceCallable(List<InstanceCallableMethod> overloads) {
2222
this.overloads = overloads;

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/MatchedCallArguments.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public Optional<CompileError> getError() {
106106
}
107107

108108
@FunctionalInterface
109-
interface CallEvaluator<T> {
109+
public interface CallEvaluator<T> {
110110
Expression eval(ExpressionBuilder builder, T method, CallArguments arguments);
111111
}
112112

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/StaticCallable.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ public Optional<FunctionHeader> getSingleHeader() {
6464
return overloads.size() == 1 ? Optional.of(overloads.get(0).getHeader()) : Optional.empty();
6565
}
6666

67+
public Optional<StaticCallableMethod> getSingleOverload() {
68+
return overloads.size() == 1 ? Optional.of(overloads.get(0)) : Optional.empty();
69+
}
70+
6771
private Expression call(ExpressionBuilder builder, StaticCallableMethod method, CallArguments arguments) {
6872
return method.call(builder, arguments);
6973
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.openzen.zenscript.codemodel.compilation.impl;
2+
3+
import org.openzen.zencode.shared.CodePosition;
4+
import org.openzen.zenscript.codemodel.compilation.*;
5+
import org.openzen.zenscript.codemodel.expression.Expression;
6+
import org.openzen.zenscript.codemodel.identifiers.instances.MethodInstance;
7+
import org.openzen.zenscript.codemodel.type.TypeID;
8+
9+
import java.math.MathContext;
10+
11+
public class BoundSuperCallable implements CompilingCallable {
12+
private final ExpressionCompiler compiler;
13+
private final InstanceCallable method;
14+
private final Expression target;
15+
private final TypeID[] typeArguments;
16+
17+
public BoundSuperCallable(ExpressionCompiler compiler, InstanceCallable method, Expression target, TypeID[] typeArguments) {
18+
this.compiler = compiler;
19+
this.method = method;
20+
this.target = target;
21+
this.typeArguments = typeArguments;
22+
}
23+
24+
@Override
25+
public Expression call(CodePosition position, CompilingExpression[] arguments) {
26+
MatchedCallArguments<InstanceCallableMethod> matched = MatchedCallArguments.match(compiler, position, method.overloads, null, typeArguments, arguments);
27+
return matched.eval(compiler.at(position), (builder, method, args) -> builder.callSuper((MethodInstance) method, target, args));
28+
}
29+
30+
@Override
31+
public CastedExpression casted(CodePosition position, CastedEval cast, CompilingExpression[] arguments) {
32+
MatchedCallArguments<InstanceCallableMethod> matched = MatchedCallArguments.match(compiler, position, method.overloads, cast.type, typeArguments, arguments);
33+
return matched.cast(compiler.at(position), cast, (builder, method, args) -> builder.callSuper((MethodInstance) method, target, args));
34+
}
35+
}

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/impl/compiler/ExpressionCompilerImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ public Expression callVirtual(MethodInstance method, Expression target, CallArgu
168168
return new CallExpression(position, target, method, arguments);
169169
}
170170

171+
@Override
172+
public Expression callSuper(MethodInstance method, Expression target, CallArguments arguments) {
173+
return new CallSuperExpression(position, target, method, arguments);
174+
}
175+
171176
@Override
172177
public Expression coalesce(Expression left, Expression right) {
173178
return new CoalesceExpression(position, left, right);

CodeModel/src/main/java/org/openzen/zenscript/codemodel/definition/ClassDefinition.java

Lines changed: 74 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,29 @@
22

33
import org.openzen.zencode.shared.CodePosition;
44
import org.openzen.zenscript.codemodel.*;
5+
import org.openzen.zenscript.codemodel.compilation.AnyMethod;
6+
import org.openzen.zenscript.codemodel.expression.*;
57
import org.openzen.zenscript.codemodel.identifiers.ModuleSymbol;
68
import org.openzen.zenscript.codemodel.identifiers.TypeSymbol;
9+
import org.openzen.zenscript.codemodel.identifiers.instances.FieldInstance;
710
import org.openzen.zenscript.codemodel.identifiers.instances.MethodInstance;
11+
import org.openzen.zenscript.codemodel.member.ConstructorMember;
812
import org.openzen.zenscript.codemodel.member.FieldMember;
13+
import org.openzen.zenscript.codemodel.member.IDefinitionMember;
14+
import org.openzen.zenscript.codemodel.statement.BlockStatement;
15+
import org.openzen.zenscript.codemodel.statement.ExpressionStatement;
16+
import org.openzen.zenscript.codemodel.statement.Statement;
17+
import org.openzen.zenscript.codemodel.type.DefinitionTypeID;
918
import org.openzen.zenscript.codemodel.type.TypeID;
10-
import org.openzen.zenscript.codemodel.type.builtin.BuiltinMethodSymbol;
11-
import org.openzen.zenscript.codemodel.type.member.MemberSet;
1219

20+
import java.util.ArrayList;
21+
import java.util.Arrays;
1322
import java.util.List;
14-
15-
import static org.openzen.zenscript.codemodel.type.BasicTypeID.VOID;
23+
import java.util.Optional;
24+
import java.util.stream.Collectors;
25+
import java.util.stream.Stream;
1626

1727
public class ClassDefinition extends HighLevelDefinition {
18-
public ClassDefinition(CodePosition position, ModuleSymbol module, ZSPackage pkg, String name, Modifiers modifiers) {
19-
this(position, module, pkg, name, modifiers, null);
20-
}
21-
2228
public ClassDefinition(CodePosition position, ModuleSymbol module, ZSPackage pkg, String name, Modifiers modifiers, TypeSymbol outerDefinition) {
2329
super(position, module, pkg, name, modifiers, outerDefinition);
2430
}
@@ -34,23 +40,73 @@ public <C, R> R accept(C context, DefinitionVisitorWithContext<C, R> visitor) {
3440
}
3541

3642
@Override
37-
protected void resolveAdditional(TypeID type, MemberSet.Builder members, GenericMapper mapper) {
38-
if (members.hasNoConstructor()) {
39-
List<FieldMember> fields = getFields();
40-
boolean noUninitializedFields = true;
41-
if (!fields.isEmpty()) {
42-
FunctionParameter[] parameters = new FunctionParameter[fields.size()];
43-
for (int i = 0; i < parameters.length; i++) {
43+
public void addDefaultMembers() {
44+
super.addDefaultMembers();
45+
46+
boolean hasNoConstructor = members.stream().noneMatch(IDefinitionMember::isConstructor);
47+
48+
Optional<MethodInstance> superConstructor = Optional.ofNullable(getSuperType())
49+
.flatMap(t -> t.resolve().getConstructor().getSingleOverload())
50+
.flatMap(AnyMethod::asMethod);
51+
52+
if (hasNoConstructor) {
53+
TypeID thisType = DefinitionTypeID.createThis(this);
54+
55+
List<FieldMember> fields = getFields().stream().filter(field -> !field.isStatic()).collect(Collectors.toList());
56+
boolean hasSuperParameters = superConstructor.map(c -> c.getHeader().parameters.length > 0).orElse(false);
57+
boolean noUninitializedFields = !hasSuperParameters;
58+
List<Statement> defaultInitializerStatements = new ArrayList<>();
59+
List<Statement> initializerStatements = new ArrayList<>();
60+
List<FunctionParameter> parameters = new ArrayList<>();
61+
62+
superConstructor.ifPresent(constructor -> {
63+
parameters.addAll(Arrays.asList(constructor.getHeader().parameters));
64+
65+
Expression[] superArgumentExpressions = Stream.of(constructor.getHeader().parameters)
66+
.map(parameter -> new GetFunctionParameterExpression(position, parameter))
67+
.toArray(Expression[]::new);
68+
CallArguments superArguments = new CallArguments(superArgumentExpressions);
69+
ExpressionStatement superCall = new ExpressionStatement(position, new ConstructorSuperCallExpression(position, thisType, constructor, superArguments));
70+
defaultInitializerStatements.add(superCall);
71+
initializerStatements.add(superCall);
72+
});
73+
74+
if (hasSuperParameters || !fields.isEmpty()) {
75+
for (int i = 0; i < fields.size(); i++) {
4476
FieldMember field = fields.get(i);
4577
noUninitializedFields &= field.initializer != null;
46-
parameters[i] = new FunctionParameter(field.getType(), field.name, field.initializer, false);
78+
FunctionParameter parameter = new FunctionParameter(field.getType(), field.name, field.initializer, false);
79+
parameters.add(parameter);
80+
81+
initializerStatements.add(new ExpressionStatement(
82+
position,
83+
new SetFieldExpression(
84+
position,
85+
new ThisExpression(position, thisType),
86+
new FieldInstance(field, field.getType()),
87+
new GetFunctionParameterExpression(position, parameter))));
88+
if (field.initializer != null) {
89+
defaultInitializerStatements.add(new ExpressionStatement(
90+
position,
91+
new SetFieldExpression(
92+
position,
93+
new ThisExpression(position, thisType),
94+
new FieldInstance(field, field.getType()),
95+
field.initializer)));
96+
}
4797
}
4898

49-
members.constructor(new MethodInstance(BuiltinMethodSymbol.CLASS_DEFAULT_CONSTRUCTOR, new FunctionHeader(VOID, parameters), type));
99+
ConstructorMember constructor = new ConstructorMember(position, this, Modifiers.PUBLIC, new FunctionHeader(thisType, parameters.toArray(FunctionParameter.NONE)));
100+
BlockStatement block = new BlockStatement(position, initializerStatements.toArray(new Statement[0]));
101+
constructor.setBody(block);
102+
members.add(constructor);
50103
}
51104

52105
if (noUninitializedFields) {
53-
members.constructor(new MethodInstance(BuiltinMethodSymbol.CLASS_DEFAULT_CONSTRUCTOR, new FunctionHeader(type), type));
106+
ConstructorMember constructor = new ConstructorMember(position, this, Modifiers.PUBLIC, new FunctionHeader(thisType));
107+
BlockStatement block = new BlockStatement(position, defaultInitializerStatements.toArray(new Statement[0]));
108+
constructor.setBody(block);
109+
members.add(constructor);
54110
}
55111
}
56112
}

0 commit comments

Comments
 (0)