+ @FunctionalInterface
+ private static interface ResourceFunctionGenerator {
+ SCLValue createValue(Name name, Resource resource);
+ }
+
+ private static class RelatedValueMacroRule implements MacroRule {
+ private final Resource relation;
+ private final SCLRelationInfo relationInfo;
+ private final boolean optionalValue;
+
+ public RelatedValueMacroRule(Resource relation, SCLRelationInfo relationInfo, boolean optionalValue) {
+ this.relation = relation;
+ this.relationInfo = relationInfo;
+ this.optionalValue = optionalValue;
+ }
+
+ private Expression applyWithSubject(SimplificationContext context, Type subjectType, Expression evidence, Expression subject) {
+ if(Types.equals(subjectType, RESOURCE))
+ return new EApply(
+ Locations.NO_LOCATION,
+ Types.READ_GRAPH,
+ context.getConstant(Name.create(DB_MODULE, optionalValue ? "possibleRelatedValue2" : "relatedValue2"), relationInfo.rangeType),
+ subject,
+ new EExternalConstant(relation, RESOURCE));
+ else if(Types.equals(subjectType, VARIABLE))
+ return new EApply(
+ Locations.NO_LOCATION,
+ Types.READ_GRAPH,
+ context.getConstant(Name.create(DB_MODULE, optionalValue ? "untypedPossiblePropertyValue" : "untypedPropertyValue"), relationInfo.rangeType),
+ subject,
+ new ELiteral(new StringConstant(relationInfo.name)));
+ else
+ return new EApply(
+ Locations.NO_LOCATION,
+ Types.READ_GRAPH,
+ context.getConstant(Name.create(DB_MODULE, optionalValue ? "genericPossibleRelatedValue" : "genericRelatedValue"), subjectType, relationInfo.rangeType),
+ evidence,
+ subject,
+ new EExternalConstant(relation, RESOURCE));
+ }
+
+ @Override
+ public Expression apply(SimplificationContext context, Type[] typeParameters, EApply apply) {
+ Type subjectType = typeParameters[0];
+ if(apply.parameters.length == 1) {
+ Variable subject = new Variable("subject", subjectType);
+ return new ESimpleLambda(subject, applyWithSubject(context, subjectType, apply.parameters[0], new EVariable(subject)));
+ }
+ else if(apply.parameters.length >= 2) {
+ Expression valueReplacement = applyWithSubject(context, subjectType, apply.parameters[0], apply.parameters[1]);
+ if(apply.parameters.length == 2)
+ return valueReplacement;
+ else {
+ apply.set(valueReplacement, Arrays.copyOfRange(apply.parameters, 2, apply.parameters.length));
+ return apply;
+ }
+ }
+ else {
+ LOGGER.error("Application of relation following functions should have at least one parameter (the evidence of Browsable).");
+ return null;
+ }
+ }
+ }
+
+ private final static HashMap<String, ResourceFunctionGenerator> VALUE_GENERATOR_MAP = new HashMap<>();
+ static {
+ TVar A = Types.var(Kinds.STAR);
+ VALUE_GENERATOR_MAP.put("value", (name, resource) -> {
+ SCLRelationInfo relationInfo = SCLRelationInfoRequest.getRelationInfo(resource);
+ if(relationInfo == null)
+ return null;
+
+ SCLValue value = new SCLValue(name);
+ value.setType(Types.forAll(A, Types.function(Types.pred(BROWSABLE, A), Types.functionE(A, Types.READ_GRAPH, relationInfo.rangeType))));
+ value.setMacroRule(new RelatedValueMacroRule(resource, relationInfo, false));
+ return value;
+ });
+ VALUE_GENERATOR_MAP.put("possibleValue", (name, resource) -> {
+ SCLRelationInfo relationInfo = SCLRelationInfoRequest.getRelationInfo(resource);
+ if(relationInfo == null)
+ return null;
+
+ SCLValue value = new SCLValue(name);
+ value.setType(Types.forAll(A, Types.function(Types.pred(BROWSABLE, A), Types.functionE(A, Types.READ_GRAPH, Types.apply(Types.MAYBE, relationInfo.rangeType)))));
+ value.setMacroRule(new RelatedValueMacroRule(resource, relationInfo, true));
+ return value;
+ });
+ }
+