Skip to content

Commit

Permalink
WIP: Started fixing check for incomplete implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
kindlich committed Sep 15, 2024
1 parent c2fd879 commit 4c34600
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.openzen.zenscript.codemodel.OperatorType;
import org.openzen.zenscript.codemodel.identifiers.MethodID;
import org.openzen.zenscript.codemodel.identifiers.instances.MethodInstance;
import org.openzen.zenscript.codemodel.member.IDefinitionMember;
import org.openzen.zenscript.codemodel.type.BasicTypeID;
import org.openzen.zenscript.codemodel.type.TypeID;

Expand Down Expand Up @@ -575,4 +576,22 @@ public static CompileError invalidLambdaHeader(FunctionHeader header) {
public static CompileError unreachableStatement() {
return new CompileError(CompileExceptionCode.UNREACHABLE_STATEMENT, "Unreachable statement");
}

public static CompileError definitionNotAllowedHere(String text) {
return new CompileError(CompileExceptionCode.DEFINITION_NOT_ALLOWED_HERE, text);
}

public static CompileError incompleteImplementation(List<IDefinitionMember> unimplementedMembers) {

String text;
if(unimplementedMembers.size() == 1) {
text = unimplementedMembers.get(0).describe() + " is not implemented";
} else {
text = unimplementedMembers.stream()
.map(IDefinitionMember::describe)
.collect(Collectors.joining("\n - ", "Implementation incomplete: " + unimplementedMembers.size() + " members not yet implemented:\n", ""));
}

return new CompileError(CompileExceptionCode.INCOMPLETE_IMPLEMENTATION, text);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#error: 7:INCOMPLETE_IMPLEMENTATION
#error: 8:INCOMPLETE_IMPLEMENTATION

interface Test {
print(): void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,5 @@ public enum CompileExceptionCode {
INVALID_PROPERTY_GETTER,
INVALID_PROPERTY_SETTER,
INVALID_PROPERTY_PAIR,
DEFINITION_NOT_ALLOWED_HERE,
}
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,14 @@ public Void visitImplementation(ImplementationMember implementation) {
}

private void checkImplementationComplete(ImplementationMember implementation) {
// TODO
ImplementationCheckValidator implementationCheckValidator = new ImplementationCheckValidator(validator, implementation);
implementation.members.forEach(member -> member.accept(implementationCheckValidator));

List<IDefinitionMember> unimplementedMembers = implementationCheckValidator.getUnimplementedMembers();
if (!unimplementedMembers.isEmpty()) {
validator.logError(implementation.position, CompileErrors.incompleteImplementation(unimplementedMembers));
}

/*Set<IDefinitionMember> implemented = new HashSet<>();
for (IDefinitionMember member : implementation.members)
if (member.getOverrides() != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package org.openzen.zenscript.validator.visitors;

import org.openzen.zenscript.codemodel.HighLevelDefinition;
import org.openzen.zenscript.codemodel.compilation.CompileErrors;
import org.openzen.zenscript.codemodel.definition.InterfaceDefinition;
import org.openzen.zenscript.codemodel.identifiers.MethodSymbol;
import org.openzen.zenscript.codemodel.member.*;
import org.openzen.zenscript.codemodel.type.DefinitionTypeID;
import org.openzen.zenscript.codemodel.type.TypeID;
import org.openzen.zenscript.validator.Validator;

import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.Collectors;

public class ImplementationCheckValidator implements MemberVisitor<Void> {

private final Validator validator;
private final ImplementationMember implementationMember;
private final Set<MethodSymbol> implementedMethods = new HashSet<>();
private final InterfaceDefinition interfaceDefinition;

public ImplementationCheckValidator(Validator validator, ImplementationMember implementationMember) {
this.validator = validator;
this.implementationMember = implementationMember;

this.interfaceDefinition = implementationMember.asImplementation()
.flatMap(TypeID::asDefinition)
.map(d -> d.definition)
.filter(InterfaceDefinition.class::isInstance)
.map(InterfaceDefinition.class::cast)
.orElseThrow(() -> new NoSuchElementException("Must be an implementation!"));
}

@Override
public Void visitField(FieldMember member) {
validator.logError(member.position, CompileErrors.definitionNotAllowedHere("Field members not allowed inside an interface implementation"));
return null;
}

@Override
public Void visitConstructor(ConstructorMember member) {
validator.logError(member.position, CompileErrors.definitionNotAllowedHere("Constructor members not allowed inside an interface implementation"));
return null;
}

@Override
public Void visitMethod(MethodMember member) {
visitFunctional(member);
return null;
}

@Override
public Void visitGetter(GetterMember member) {
visitFunctional(member);
return null;
}

@Override
public Void visitSetter(SetterMember member) {
visitFunctional(member);
return null;
}

@Override
public Void visitOperator(OperatorMember member) {
visitFunctional(member);
return null;
}

@Override
public Void visitCaster(CasterMember member) {
visitFunctional(member);
return null;
}

@Override
public Void visitCustomIterator(IteratorMember member) {
visitFunctional(member);
return null;
}

private void visitFunctional(FunctionalMember member) {
member.getOverrides().ifPresent(e -> {
if (interfaceDefinition.equals(e.method.getDefiningType())) {
if (implementedMethods.contains(e.method)) {
validator.logError(member.position, CompileErrors.duplicateMember(member.toString()));
return;
}

implementedMethods.add(e.method);
} else {
validator.logError(member.position, CompileErrors.invalidOverride("override not part of interface"));
}
});
}

@Override
public Void visitImplementation(ImplementationMember member) {
validator.logError(member.position, CompileErrors.cannotNestImplementations());
return null;
}

@Override
public Void visitInnerDefinition(InnerDefinitionMember member) {
validator.logError(member.position, CompileErrors.definitionNotAllowedHere("Inner definitions are not allowed inside an interface implementation"));
return null;
}

@Override
public Void visitStaticInitializer(StaticInitializerMember member) {
validator.logError(member.position, CompileErrors.definitionNotAllowedHere("Static initializer members not allowed inside an interface implementation"));
return null;
}

public List<IDefinitionMember> getUnimplementedMembers() {
return interfaceDefinition.members.stream()
.filter(IDefinitionMember::isAbstract)
.filter(o -> !implementedMethods.contains(o))
.collect(Collectors.toList());
}

}

0 comments on commit 4c34600

Please sign in to comment.