|
| 1 | +package de.peeeq.wurstscript.attributes; |
| 2 | + |
| 3 | +import de.peeeq.wurstscript.ast.*; |
| 4 | +import de.peeeq.wurstscript.attributes.names.DefLink; |
| 5 | +import de.peeeq.wurstscript.types.VariableBinding; |
| 6 | +import de.peeeq.wurstscript.types.WurstType; |
| 7 | +import de.peeeq.wurstscript.types.WurstTypeBoundTypeParam; |
| 8 | +import org.eclipse.jdt.annotation.Nullable; |
| 9 | + |
| 10 | +/** Exact ABI matching for package functions replaced through {@code @config}. */ |
| 11 | +public final class ConfigFunctionMatcher { |
| 12 | + |
| 13 | + private ConfigFunctionMatcher() { |
| 14 | + } |
| 15 | + |
| 16 | + public static @Nullable FunctionDefinition findMatchingFunction(WPackage pack, FunctionDefinition function) { |
| 17 | + return findMatchingFunction(pack, function, false); |
| 18 | + } |
| 19 | + |
| 20 | + public static @Nullable FunctionDefinition findMatchingFunction(WPackage pack, FunctionDefinition function, |
| 21 | + boolean requireConfigAnnotation) { |
| 22 | + for (DefLink link : pack.getElements().attrNameLinks().get(function.getName())) { |
| 23 | + if (link.getDef() instanceof FunctionDefinition candidate |
| 24 | + && isPackageFunction(candidate, pack) |
| 25 | + && (!requireConfigAnnotation || candidate.hasAnnotation("@config")) |
| 26 | + && matches(function, candidate)) { |
| 27 | + return candidate; |
| 28 | + } |
| 29 | + } |
| 30 | + return null; |
| 31 | + } |
| 32 | + |
| 33 | + private static boolean isPackageFunction(FunctionDefinition function, WPackage pack) { |
| 34 | + return function.attrNearestPackage() == pack |
| 35 | + && (!(function instanceof FuncDef) || function.attrNearestStructureDef() == null); |
| 36 | + } |
| 37 | + |
| 38 | + public static boolean matches(FunctionDefinition first, FunctionDefinition second) { |
| 39 | + if (!first.getName().equals(second.getName())) { |
| 40 | + return false; |
| 41 | + } |
| 42 | + if ((first instanceof ExtensionFuncDef) != (second instanceof ExtensionFuncDef)) { |
| 43 | + return false; |
| 44 | + } |
| 45 | + if (!(first instanceof AstElementWithTypeParameters firstGeneric) |
| 46 | + || !(second instanceof AstElementWithTypeParameters secondGeneric)) { |
| 47 | + return false; |
| 48 | + } |
| 49 | + TypeParamDefs firstTypeParams = firstGeneric.getTypeParameters(); |
| 50 | + TypeParamDefs secondTypeParams = secondGeneric.getTypeParameters(); |
| 51 | + if (firstTypeParams.size() != secondTypeParams.size()) { |
| 52 | + return false; |
| 53 | + } |
| 54 | + |
| 55 | + VariableBinding alphaMapping = VariableBinding.emptyMapping(); |
| 56 | + for (int i = 0; i < firstTypeParams.size(); i++) { |
| 57 | + TypeParamDef firstTypeParam = firstTypeParams.get(i); |
| 58 | + TypeParamDef secondTypeParam = secondTypeParams.get(i); |
| 59 | + alphaMapping = alphaMapping.set(firstTypeParam, |
| 60 | + new WurstTypeBoundTypeParam(firstTypeParam, secondTypeParam.attrTyp(), first)); |
| 61 | + } |
| 62 | + for (int i = 0; i < firstTypeParams.size(); i++) { |
| 63 | + TypeParamDef firstTypeParam = firstTypeParams.get(i); |
| 64 | + TypeParamDef secondTypeParam = secondTypeParams.get(i); |
| 65 | + if (!equalConstraints(firstTypeParam, secondTypeParam, alphaMapping, first)) { |
| 66 | + return false; |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + if (first instanceof ExtensionFuncDef firstExtension) { |
| 71 | + ExtensionFuncDef secondExtension = (ExtensionFuncDef) second; |
| 72 | + if (!equalType(firstExtension.getExtendedType().attrTyp(), |
| 73 | + secondExtension.getExtendedType().attrTyp(), alphaMapping, first)) { |
| 74 | + return false; |
| 75 | + } |
| 76 | + } |
| 77 | + if (first.getParameters().size() != second.getParameters().size()) { |
| 78 | + return false; |
| 79 | + } |
| 80 | + for (int i = 0; i < first.getParameters().size(); i++) { |
| 81 | + if (!equalType(first.getParameters().get(i).attrTyp(), second.getParameters().get(i).attrTyp(), |
| 82 | + alphaMapping, first)) { |
| 83 | + return false; |
| 84 | + } |
| 85 | + } |
| 86 | + return equalType(first.attrReturnTyp(), second.attrReturnTyp(), alphaMapping, first); |
| 87 | + } |
| 88 | + |
| 89 | + private static boolean equalConstraints(TypeParamDef first, TypeParamDef second, |
| 90 | + VariableBinding alphaMapping, Element location) { |
| 91 | + if ((first.getTypeParamConstraints() instanceof TypeExprList) |
| 92 | + != (second.getTypeParamConstraints() instanceof TypeExprList)) { |
| 93 | + return false; |
| 94 | + } |
| 95 | + if (!(first.getTypeParamConstraints() instanceof TypeExprList firstConstraints)) { |
| 96 | + return true; |
| 97 | + } |
| 98 | + TypeExprList secondConstraints = (TypeExprList) second.getTypeParamConstraints(); |
| 99 | + if (firstConstraints.size() != secondConstraints.size()) { |
| 100 | + return false; |
| 101 | + } |
| 102 | + for (int i = 0; i < firstConstraints.size(); i++) { |
| 103 | + if (!equalType(firstConstraints.get(i).attrTyp(), secondConstraints.get(i).attrTyp(), |
| 104 | + alphaMapping, location)) { |
| 105 | + return false; |
| 106 | + } |
| 107 | + } |
| 108 | + return true; |
| 109 | + } |
| 110 | + |
| 111 | + private static boolean equalType(WurstType first, WurstType second, |
| 112 | + VariableBinding alphaMapping, Element location) { |
| 113 | + return first.setTypeArgs(alphaMapping).equalsType(second, location); |
| 114 | + } |
| 115 | +} |
0 commit comments