]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling/src/org/simantics/modeling/scl/ontologymodule/OntologyModule.java
Property following functions value and possibleValue to ontology modules
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / scl / ontologymodule / OntologyModule.java
similarity index 58%
rename from bundles/org.simantics.modeling/src/org/simantics/modeling/scl/OntologyModule.java
rename to bundles/org.simantics.modeling/src/org/simantics/modeling/scl/ontologymodule/OntologyModule.java
index 39cf2f76555387e85091512c0f4844e6cdecb38f..ec698e670514984fa42128d3211238d503a93a35 100644 (file)
@@ -1,8 +1,9 @@
-package org.simantics.modeling.scl;
+package org.simantics.modeling.scl.ontologymodule;
 
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
@@ -16,29 +17,48 @@ import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.request.Read;
 import org.simantics.layer0.Layer0;
 import org.simantics.scl.compiler.common.names.Name;
+import org.simantics.scl.compiler.constants.StringConstant;
+import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
+import org.simantics.scl.compiler.elaboration.expressions.EApply;
 import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
+import org.simantics.scl.compiler.elaboration.expressions.ESimpleLambda;
+import org.simantics.scl.compiler.elaboration.expressions.EVariable;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.elaboration.macros.MacroRule;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.relations.SCLEntityType;
 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
 import org.simantics.scl.compiler.environment.filter.NamespaceFilter;
+import org.simantics.scl.compiler.errors.Locations;
 import org.simantics.scl.compiler.module.ImportDeclaration;
 import org.simantics.scl.compiler.module.LazyModule;
 import org.simantics.scl.compiler.types.TCon;
+import org.simantics.scl.compiler.types.TVar;
 import org.simantics.scl.compiler.types.Type;
 import org.simantics.scl.compiler.types.Types;
 import org.simantics.scl.compiler.types.exceptions.SCLTypeParseException;
+import org.simantics.scl.compiler.types.kinds.Kinds;
 import org.simantics.scl.runtime.SCLContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import gnu.trove.map.hash.THashMap;
 import gnu.trove.procedure.TObjectProcedure;
 
 public class OntologyModule extends LazyModule {
-
+    private static final Logger LOGGER = LoggerFactory.getLogger(OntologyModule.class);
+    
     private static final String DB_MODULE = "Simantics/DB";
+    private static final String VARIABLE_MODULE = "Simantics/Variable";
     private static final Collection<ImportDeclaration> DEPENDENCIES = Arrays.asList(
-            new ImportDeclaration(DB_MODULE, null)
+            new ImportDeclaration(DB_MODULE, null),
+            new ImportDeclaration(VARIABLE_MODULE, null)
             );
     private static final TCon RESOURCE = Types.con(DB_MODULE, "Resource");
+    private static final TCon BROWSABLE = Types.con(DB_MODULE, "Browsable");
+    private static final TCon VARIABLE = Types.con(VARIABLE_MODULE, "Variable");
     
     Resource ontology;
     String defaultLocalName;
@@ -69,26 +89,55 @@ public class OntologyModule extends LazyModule {
         return Collections.emptyList();
     }
     
-    private Resource getResource(String name) {
+    private static interface ResourceSearchResult {}
+    private static class JustResource implements ResourceSearchResult {
+        public final Resource resource;
+        public JustResource(Resource resource) {
+            this.resource = resource;
+        }   
+    }
+    private static class ResourceAndSuffix implements ResourceSearchResult {
+        public final Resource resource;
+        public final String suffix;
+        public ResourceAndSuffix(Resource resource, String suffix) {
+            this.resource = resource;
+            this.suffix = suffix;
+        }  
+    }
+    
+    private ResourceSearchResult getResourceOrSuffixedResource(String name) {
         Map<String,Resource> localMap = childMaps.get(ontology); 
         if(localMap == null)
             return null;
+        Resource parent = ontology;
         while(true) {
             int p = name.indexOf('.');
             if(p < 0)
                 break;
             String localName = name.substring(0, p);
-            Resource newParent = localMap.get(localName);
-            if(newParent == null)
+            parent = localMap.get(localName);
+            if(parent == null)
                 return null;
             name = name.substring(p+1);
             
             // Get new local map
-            localMap = getLocalMap(newParent);
+            localMap = getLocalMap(parent);
             if(localMap == null)
                 return null;
         }
-        return localMap.get(name);
+        Resource child = localMap.get(name);
+        if(child != null)
+            return new JustResource(child);
+        else
+            return new ResourceAndSuffix(parent, name);
+    }
+    
+    private Resource getResource(String name) {
+        ResourceSearchResult searchResult = getResourceOrSuffixedResource(name);
+        if(searchResult instanceof JustResource)
+            return ((JustResource)searchResult).resource;
+        else
+            return null;
     }
     
     private Map<String, Resource> getLocalMap(Resource parent) {
@@ -129,16 +178,116 @@ public class OntologyModule extends LazyModule {
         }
     }
     
+    @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;
+        });
+    }
+   
     @Override
     protected SCLValue createValue(String name) {
-        Resource resource = getResource(name);
-        if(resource == null)
-            return null;        
-        SCLValue value = new SCLValue(Name.create(getName(), name));
-        value.setType(RESOURCE);
-        value.setExpression(new EExternalConstant(resource, RESOURCE));
-        value.setInlineInSimplification(true);
-        return value;
+        ResourceSearchResult searchResult = getResourceOrSuffixedResource(name);
+        if(searchResult instanceof JustResource) {
+            Resource resource = ((JustResource)searchResult).resource;
+            SCLValue value = new SCLValue(Name.create(getName(), name));
+            value.setType(RESOURCE);
+            value.setExpression(new EExternalConstant(resource, RESOURCE));
+            value.setInlineInSimplification(true);
+            return value;        
+        }
+        else if(searchResult instanceof ResourceAndSuffix){
+            ResourceAndSuffix resourceAndSuffix = (ResourceAndSuffix)searchResult;
+            ResourceFunctionGenerator generator = VALUE_GENERATOR_MAP.get(resourceAndSuffix.suffix);
+            if(generator == null)
+                return null;
+            else
+                return generator.createValue(Name.create(getName(), name), resourceAndSuffix.resource);
+        }
+        else
+            return null;
     }
     
     @Override