-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;
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;
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) {
}
}
+ @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
--- /dev/null
+package org.simantics.modeling.scl.ontologymodule;
+
+import java.util.Collection;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.request.UnaryRead;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.layer0.Layer0;
+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.db.SCLCompilationRequestProcessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SCLRelationInfoRequest extends UnaryRead<Resource,SCLRelationInfo> {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SCLRelationInfoRequest.class);
+
+ private SCLRelationInfoRequest(Resource resource) {
+ super(resource);
+ }
+
+ @Override
+ public SCLRelationInfo perform(ReadGraph graph) throws DatabaseException {
+ Layer0 L0 = Layer0.getInstance(graph);
+ if(!graph.isSubrelationOf(parameter, L0.HasProperty))
+ return null;
+
+ String name = graph.getPossibleRelatedValue(parameter, L0.HasName);
+ if(name == null)
+ return null;
+
+ String valueType = graph.getPossibleRelatedValue(parameter, L0.RequiresValueType);
+ if(valueType == null) {
+ Collection<Resource> rangeTypes = graph.getObjects(parameter, L0.HasRange);
+ if(rangeTypes.size() != 1) {
+ LOGGER.warn("Couldn't find SCLtype for {} because it has multiple range types.", graph.getURI(parameter));
+ return null;
+ }
+
+ Resource range = rangeTypes.iterator().next();
+ Collection<Resource> assertedValueTypes = graph.getAssertedObjects(range, L0.HasValueType);
+ if(assertedValueTypes.size() != 1) {
+ LOGGER.warn("Couldn't find SCL type for {} because its range {} has multiple asserted value types.", graph.getURI(parameter), graph.getURI(range));
+ return null;
+ }
+
+ Resource assertedValueType = assertedValueTypes.iterator().next();
+ valueType = graph.getPossibleValue(assertedValueType, Bindings.STRING);
+ if(valueType == null) {
+ LOGGER.warn("Couldn't find SCL type for {} because value type assertion of {} is missing a value.", graph.getURI(parameter), graph.getURI(range));
+ return null;
+ }
+ }
+
+ Type type;
+ try {
+ type = Types.parseType(valueType);
+ } catch (SCLTypeParseException e) {
+ LOGGER.warn("Couldn't parse the value type of relation {}. Definition was '{}'.", graph.getURI(parameter), valueType);
+ return null;
+ }
+
+ return new SCLRelationInfo(type, name);
+ }
+
+ public static SCLRelationInfo getRelationInfo(Resource resource) {
+ try {
+ return SCLCompilationRequestProcessor.getRequestProcessor().syncRequest(new SCLRelationInfoRequest(resource), TransientCacheListener.instance());
+ } catch(DatabaseException e) {
+ LOGGER.error("SCLRelationInfoRequest failed.", e);
+ return null;
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.modeling.scl.ontologymodule;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.ResourceRead;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.service.CollectionSupport;
+import org.simantics.layer0.Layer0;
+import org.simantics.scl.compiler.common.names.SCLReservedWords;
+import org.simantics.utils.Development;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SCLReservedWordsEscapingChildMapOfResource extends ResourceRead<Map<String, Resource>> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SCLReservedWordsEscapingChildMapOfResource.class);
+
+ public SCLReservedWordsEscapingChildMapOfResource(Resource resource) {
+ super(resource);
+ }
+
+ @Override
+ public Map<String, Resource> perform(ReadGraph graph) throws DatabaseException {
+ Layer0 L0 = Layer0.getInstance(graph);
+ Collection<Resource> objects = graph.getObjects(resource, L0.ConsistsOf);
+ CollectionSupport cs = graph.getService(CollectionSupport.class);
+ Map<String,Resource> result = cs.createObjectResourceMap(String.class, objects.size());
+ for(Resource r : objects) {
+ String name = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING);
+ if(name != null) {
+ if(SCLReservedWords.RESERVED_WORDS_SET.contains(name))
+ name = name + "_";
+ Resource old = result.put(name, r);
+ if (old != null)
+ LOGGER.error("The database contains siblings with the same name " + name + " (resource=$" + resource.getResourceId() + ", child=$" + r.getResourceId() + ", previous child=$" + old.getResourceId() + ").");
+ } else {
+ if(Development.DEVELOPMENT)
+ LOGGER.error("The database contains a child with no unique name (resource=$" + resource.getResourceId() + ", child=$" + r.getResourceId() + ").");
+ }
+ }
+ return result;
+ }
+
+}