org.snapscript.compile.validate.FunctionValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of snap-all Show documentation
Show all versions of snap-all Show documentation
Dynamic scripting for the JVM
package org.snapscript.compile.validate;
import java.util.List;
import java.util.Set;
import org.snapscript.core.ModifierType;
import org.snapscript.core.constraint.transform.ConstraintTransformer;
import org.snapscript.core.convert.ConstraintMatcher;
import org.snapscript.core.convert.FunctionOverrideMatcher;
import org.snapscript.core.function.Function;
import org.snapscript.core.function.Origin;
import org.snapscript.core.function.Signature;
import org.snapscript.core.function.index.FunctionIndexer;
import org.snapscript.core.function.index.FunctionPointer;
import org.snapscript.core.scope.Scope;
import org.snapscript.core.type.Type;
import org.snapscript.core.type.TypeExtractor;
public class FunctionValidator {
private final FunctionOverrideMatcher matcher;
private final FunctionIndexer indexer;
private final TypeExtractor extractor;
public FunctionValidator(ConstraintMatcher matcher, ConstraintTransformer transformer, TypeExtractor extractor, FunctionIndexer indexer) {
this.matcher = new FunctionOverrideMatcher(matcher, transformer);
this.extractor = extractor;
this.indexer = indexer;
}
public void validate(Function function) throws Exception {
Type source = function.getSource();
if(source == null) {
throw new ValidateException("Function '" + function + "' does not have a declaring type");
}
validateModifiers(function);
validateDuplicates(function);
}
public void validate(Function function, Type type) throws Exception {
Type source = function.getSource();
if(source == type) {
throw new ValidateException("Function '" + function + "' is abstract but '" + type + "' is not");
}
if(source == null) {
throw new ValidateException("Function '" + function + "' does not have a declaring type");
}
validateImplemented(function, type);
}
private void validateImplemented(Function function, Type type) throws Exception {
Scope scope = type.getScope();
int modifiers = function.getModifiers();
if(ModifierType.isAbstract(modifiers)) {
Signature signature = function.getSignature();
Origin origin = signature.getOrigin();
String name = function.getName();
if(!origin.isSystem()) {
Type[] parameters = matcher.matchTypes(scope, function, type);
FunctionPointer resolved = indexer.index(type, name, parameters);
if(resolved == null) {
throw new ValidateException("Type '" + type + "' must implement '" + function + "'");
}
Function match = resolved.getFunction();
int mask = match.getModifiers();
if(ModifierType.isAbstract(mask)) {
throw new ValidateException("Type '" + type + "' must implement '" + function + "'");
}
}
}
}
private void validateModifiers(Function function) throws Exception {
Type source = function.getSource();
Scope scope = source.getScope();
int modifiers = function.getModifiers();
if(ModifierType.isOverride(modifiers)) {
Set types = extractor.getTypes(source);
String name = function.getName();
int matches = 0;
for(Type type : types) {
if(type != source) {
List functions = type.getFunctions();
for(Function available : functions) {
String match = available.getName();
if(name.equals(match)) {
Type[] parameters = matcher.matchTypes(scope, function, available);
if(parameters != null) {
validateModifiers(function, parameters);
matches++;
}
}
}
}
}
if(matches == 0) {
throw new ValidateException("Function '" + function + "' is not an override");
}
}
}
private void validateModifiers(Function override, Type[] parameters) throws Exception {
Signature signature = override.getSignature();
Origin origin = signature.getOrigin();
Type source = override.getSource();
String name = override.getName();
if(!origin.isSystem()) {
FunctionPointer match = indexer.index(source, name, parameters);
if(match == null) {
throw new ValidateException("Function '" + override +"' is not an override");
}
Function function = match.getFunction();
if(function != override) {
throw new ValidateException("Function '" + override +"' is not an override");
}
}
}
private void validateDuplicates(Function actual) throws Exception {
Type source = actual.getSource();
int modifiers = actual.getModifiers();
if(!ModifierType.isAbstract(modifiers)) {
Signature signature = actual.getSignature();
Origin origin = signature.getOrigin();
Scope scope = source.getScope();
String name = actual.getName();
if(!origin.isSystem()) {
Type[] parameters = matcher.matchTypes(scope, actual, source);
FunctionPointer resolved = indexer.index(source, name, parameters);
if(resolved == actual) {
throw new ValidateException("Function '" + actual +"' has a duplicate '" + resolved + "'");
}
Function function = resolved.getFunction();
if(function != actual) {
throw new ValidateException("Function '" + actual +"' has a duplicate '" + resolved + "'");
}
}
}
}
}