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 Show documentation
Show all versions of snap 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.Constraint;
import org.snapscript.core.convert.ConstraintMatcher;
import org.snapscript.core.convert.FunctionComparator;
import org.snapscript.core.convert.Score;
import org.snapscript.core.function.Function;
import org.snapscript.core.function.Parameter;
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;
import org.snapscript.tree.ModifierValidator;
public class FunctionValidator {
private final FunctionComparator comparator;
private final ModifierValidator validator;
private final FunctionIndexer indexer;
private final TypeExtractor extractor;
public FunctionValidator(ConstraintMatcher matcher, TypeExtractor extractor, FunctionIndexer indexer) {
this.comparator = new FunctionComparator(matcher);
this.validator = new ModifierValidator();
this.extractor = extractor;
this.indexer = indexer;
}
public void validate(Function function) throws Exception {
Type type = function.getType();
if(type == null) {
throw new ValidateException("Function '" + function + "' does not have a type");
}
validateModifiers(function);
validateDuplicates(function);
}
private void validateModifiers(Function function) throws Exception {
Type parent = function.getType();
Scope scope = parent.getScope();
int modifiers = function.getModifiers();
if(ModifierType.isOverride(modifiers)) {
Set types = extractor.getTypes(parent);
String name = function.getName();
int matches = 0;
for(Type type : types) {
if(type != parent) {
List functions = type.getFunctions();
for(Function available : functions) {
String match = available.getName();
if(name.equals(match)) {
Score compare = comparator.compare(scope, available, function);
if(compare.isSimilar()) {
validateModifiers(available, function);
matches++;
}
}
}
}
}
if(matches == 0) {
throw new ValidateException("Function '" + function + "' is not an override");
}
}
validator.validate(parent, function, modifiers);
}
private void validateModifiers(Function actual, Function require) throws Exception {
Signature signature = actual.getSignature();
List parameters = signature.getParameters();
Type parent = require.getType();
Scope scope = parent.getScope();
String name = actual.getName();
int length = parameters.size();
if(length >0) {
Type[] types = new Type[length];
for(int i = 0; i < length; i++){
Parameter parameter = parameters.get(i);
Constraint constraint = parameter.getConstraint();
Type type = constraint.getType(scope);
types[i] = type;
}
FunctionPointer match = indexer.index(parent, name, types);
if(match == null) {
throw new ValidateException("Function '" + require +"' does not match override");
}
Function function = match.getFunction();
if(function != require) {
throw new ValidateException("Function '" + require +"' does not match override");
}
}
}
private void validateDuplicates(Function actual) throws Exception {
Type parent = actual.getType();
int modifiers = actual.getModifiers();
if(!ModifierType.isAbstract(modifiers)) {
Signature signature = actual.getSignature();
List parameters = signature.getParameters();
Scope scope = parent.getScope();
String name = actual.getName();
int length = parameters.size();
if(length >0) {
Type[] types = new Type[length];
for(int i = 0; i < length; i++){
Parameter parameter = parameters.get(i);
Constraint constraint = parameter.getConstraint();
Type type = constraint.getType(scope);
types[i] = type;
}
FunctionPointer resolved = indexer.index(parent, name, types);
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 + "'");
}
}
}
}
}