package org.simantics.scl.compiler.elaboration.chr.translation; import java.util.ArrayList; import java.util.Arrays; import org.simantics.scl.compiler.elaboration.chr.CHRLiteral; import org.simantics.scl.compiler.elaboration.chr.CHRQuery; import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint; import org.simantics.scl.compiler.elaboration.chr.relations.SpecialCHRRelation; import org.simantics.scl.compiler.elaboration.chr.relations.UnresolvedCHRRelation; import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; import org.simantics.scl.compiler.elaboration.expressions.EApply; import org.simantics.scl.compiler.elaboration.expressions.EBinary; import org.simantics.scl.compiler.elaboration.expressions.ERecord; import org.simantics.scl.compiler.elaboration.expressions.EVar; import org.simantics.scl.compiler.elaboration.expressions.Expression; import org.simantics.scl.compiler.elaboration.expressions.block.ConstraintStatement; import org.simantics.scl.compiler.elaboration.expressions.list.ListAssignment; import org.simantics.scl.compiler.elaboration.expressions.list.ListGenerator; import org.simantics.scl.compiler.elaboration.expressions.list.ListGuard; import org.simantics.scl.compiler.elaboration.expressions.list.ListQualifier; import org.simantics.scl.compiler.elaboration.expressions.records.FieldAssignment; import org.simantics.scl.compiler.environment.AmbiguousNameException; import org.simantics.scl.compiler.environment.Environments; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.internal.parsing.declarations.DAnnotationAst; import org.simantics.scl.compiler.internal.parsing.types.TypeAst; public class CHRTranslation { private static CHRLiteral convertExpression(boolean isHead, Expression expression) { if(isHead) return new CHRLiteral(expression.location, SpecialCHRRelation.CHECK, new Expression[] {expression}, false, false); else return new CHRLiteral(expression.location, SpecialCHRRelation.EXECUTE, new Expression[] {expression}, false, false); } private static CHRLiteral convertConstraint(boolean remove, boolean negated, Expression expression) { long location = expression.location; Expression[] parameters; FieldAssignment[] fields = null; if(expression instanceof EApply) { EApply apply = (EApply)expression; parameters = apply.parameters; expression = apply.function; } else if(expression instanceof ERecord) { ERecord record = (ERecord)expression; parameters = null; fields = record.fields; expression = record.constructor; } else // if(expression instanceof EVar) parameters = Expression.EMPTY_ARRAY; EVar var = (EVar)expression; // this should succeed because of isConstraint test CHRLiteral literal = new CHRLiteral(location, new UnresolvedCHRRelation(var.location, var.name), parameters, remove, negated); literal.fields = fields; return literal; } private static CHRLiteral convertListQualifier(TranslationContext context, boolean isHead, ListQualifier qualifier) { if(qualifier instanceof ListGuard) { Expression originalExpression = ((ListGuard)qualifier).condition; if(originalExpression instanceof EVar && ((EVar)originalExpression).name.equals("True")) return null; Expression currentExpression = originalExpression; boolean remove = false; boolean negated = false; if(currentExpression instanceof EBinary) { EBinary binary = (EBinary)currentExpression; if(binary.negation==null || !binary.rights.isEmpty()) return convertExpression(isHead, originalExpression); currentExpression = binary.left; remove = true; } else if(currentExpression instanceof EApply) { EApply apply = (EApply)currentExpression; if(apply.function instanceof EVar && ((EVar)apply.function).name.equals("not")) { negated = true; if(apply.parameters.length == 1) currentExpression = apply.parameters[0]; else { currentExpression = new EApply( Locations.combine(apply.parameters[0].location, apply.parameters[apply.parameters.length-1].location), apply.parameters[0], Arrays.copyOfRange(apply.parameters, 1, apply.parameters.length)); } } } if(isConstraint(context, currentExpression)) return convertConstraint(remove, negated, currentExpression); else return convertExpression(isHead, originalExpression); } else if(qualifier instanceof ListAssignment) { ListAssignment assignment = (ListAssignment)qualifier; return new CHRLiteral(assignment.location, SpecialCHRRelation.EQUALS, new Expression[] { assignment.pattern, assignment.value }, false, false); } else if(qualifier instanceof ListGenerator) { ListGenerator generator = (ListGenerator)qualifier; return new CHRLiteral(generator.location, SpecialCHRRelation.MEMBER, new Expression[] { generator.pattern, generator.value }, false, false); } else { context.getErrorLog().log(qualifier.location, "Invalid CHR literal."); return null; } } private static boolean isConstraint(TranslationContext context, Expression expression) { if(expression instanceof EApply) expression = ((EApply)expression).function; else if(expression instanceof ERecord) expression = ((ERecord)expression).constructor; if(!(expression instanceof EVar)) return false; String name = ((EVar)expression).name; if(TranslationContext.isConstructorName(name)) return true; try { return Environments.getRelation(context.getEnvironment(), name) != null; } catch (AmbiguousNameException e) { return true; } } public static CHRQuery convertCHRQuery(TranslationContext context, boolean isHead, ListQualifier[] lqs) { long location = Locations.NO_LOCATION; ArrayList query = new ArrayList(lqs.length); for(ListQualifier qualifier : lqs) { location = Locations.combine(location, qualifier.location); CHRLiteral literal = convertListQualifier(context, isHead, qualifier); if(literal != null) query.add(literal); } return new CHRQuery(location, query.toArray(new CHRLiteral[query.size()])); } /*public static CHRRule convertCHRStatement(TranslationContext context, CHRStatement statement) { return new CHRRule(statement.location, convertCHRQuery(context, true, statement.head), convertCHRQuery(context, false, statement.body), null); }*/ public static CHRConstraint convertConstraintStatement(TranslationContext context, ConstraintStatement statement) { CHRConstraint constraint = new CHRConstraint(statement.location, statement.name.text, TypeAst.toTypes(context, statement.parameterTypes)); for(DAnnotationAst annotation : statement.annotations) applyConstraintAnnotation(context, constraint, annotation); constraint.fieldNames = statement.fieldNames; return constraint; } private static void applyConstraintAnnotation(TranslationContext context, CHRConstraint constraint, DAnnotationAst annotation) { context.getErrorLog().log(annotation.location, "Invalid constraint annotation"); } }