package org.simantics.modeling.scl.ontologymodule; import org.simantics.db.Resource; import org.simantics.scl.compiler.common.names.Name; import org.simantics.scl.compiler.common.names.Names; import org.simantics.scl.compiler.compilation.CompilationContext; import org.simantics.scl.compiler.elaboration.chr.plan.PlanContext; import org.simantics.scl.compiler.elaboration.expressions.EApply; import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant; 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.query.compilation.EnforcingContext; import org.simantics.scl.compiler.elaboration.query.compilation.QueryCompilationContext; import org.simantics.scl.compiler.elaboration.relations.SCLRelation; import org.simantics.scl.compiler.environment.Environment; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; import org.simantics.scl.compiler.types.TPred; import org.simantics.scl.compiler.types.TVar; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; public class GraphPropertyRelation implements SCLRelation { Resource propertyRelation; Type valueType; Type[] parameterTypes; private static final Type RESOURCE = Types.con("Simantics/DB", "Resource"); public GraphPropertyRelation(Resource propertyRelation, Type valueType) { this.propertyRelation = propertyRelation; this.valueType = valueType; this.parameterTypes = new Type[] { RESOURCE, valueType }; } @Override public TVar[] getTypeVariables() { return TVar.EMPTY_ARRAY; } @Override public TPred[] getTypeConstraints() { return new TPred[] {Types.pred(Types.SERIALIZABLE, valueType)}; } @Override public Type[] getParameterTypes() { return parameterTypes; } @Override public double getSelectivity(int boundVariables) { switch(boundVariables) { case FF: case FB: return Double.POSITIVE_INFINITY; case BF: return 1.0; case BB: return 0.01; default: throw new IllegalArgumentException(); } } @Override public int getRequiredVariablesMask() { return BF; } private static final Name POSSIBLE_RELATED_VALUE = Name.create("Simantics/DB", "possibleRelatedValue"); @Override public void generate(long location, QueryCompilationContext context, Type[] typeParameters, Variable[] parameters, int boundVariables) { Expression possibleValue = new EApply( Locations.NO_LOCATION, Types.READ_GRAPH, context.getCompilationContext().getConstant(POSSIBLE_RELATED_VALUE, valueType), context.getEvidence(location, Types.pred(Types.SERIALIZABLE, valueType)), new EVariable(parameters[0]), new EExternalConstant(propertyRelation, RESOURCE) ); switch(boundVariables) { case BB: { Variable temp = new Variable("temp", valueType); context.condition(new EApply( context.getCompilationContext().getConstant(Names.Builtin_equals, valueType), new Expression[] { new EVariable(temp), new EVariable(parameters[1]) } )); context.iterateMaybe(temp, possibleValue); } break; case BF: context.iterateMaybe(parameters[1], possibleValue); break; default: throw new IllegalArgumentException(); } } private static final Name CLAIM_RELATED_VALUE = Name.create("Simantics/DB", "claimRelatedValue"); @Override public Expression generateEnforce(long location, EnforcingContext context, Type[] typeParameters, Variable[] parameters) { return new EApply( Locations.NO_LOCATION, Types.WRITE_GRAPH, context.getCompilationContext().getConstant(CLAIM_RELATED_VALUE, valueType), context.getEvidence(location, Types.pred(Types.SERIALIZABLE, valueType)), new EVariable(parameters[0]), new EExternalConstant(propertyRelation, RESOURCE), new EVariable(parameters[1]) ); } @Override public int getPhase() { return 0; } @Override public void generateIterate(PlanContext context, CodeWriter w, long location, int boundMask, Variable[] variables, Expression[] expressions, Expression[] typeConstraintEvidenceParameters) { CompilationContext compilationContext = context.context; switch(boundMask) { case BF: context.iterateMaybe(location, w, variables[1], w.apply(location, compilationContext.environment.getValue(POSSIBLE_RELATED_VALUE).getValue().createSpecialization(valueType), typeConstraintEvidenceParameters[0].toVal(compilationContext, w), expressions[0].toVal(compilationContext, w), w.getModuleWriter().getExternalConstant(propertyRelation, Types.RESOURCE))); break; case BB: context.checkEqualsJust(location, w, expressions[1].toVal(compilationContext, w), w.apply(location, compilationContext.environment.getValue(POSSIBLE_RELATED_VALUE).getValue().createSpecialization(valueType), typeConstraintEvidenceParameters[0].toVal(compilationContext, w), expressions[0].toVal(compilationContext, w), w.getModuleWriter().getExternalConstant(propertyRelation, Types.RESOURCE))); break; default: throw new IllegalArgumentException(); } } @Override public void generateEnforce(PlanContext context, CodeWriter w, long location, Expression[] parameters, Expression[] typeConstraintEvidenceParameters) { CompilationContext compilationContext = context.context; w.apply(location, compilationContext.environment.getValue(CLAIM_RELATED_VALUE).getValue().createSpecialization(valueType), typeConstraintEvidenceParameters[0].toVal(compilationContext, w), parameters[0].toVal(compilationContext, w), w.getModuleWriter().getExternalConstant(propertyRelation, Types.RESOURCE), parameters[1].toVal(compilationContext, w)); } @Override public Type getEnforceEffect() { return Types.WRITE_GRAPH; } @Override public Type getQueryEffect() { return Types.READ_GRAPH; } }