package org.simantics.scl.compiler.elaboration.chr.ast; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import org.simantics.scl.compiler.common.names.Name; import org.simantics.scl.compiler.elaboration.chr.CHRLiteral; 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.EConstant; 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.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.types.Types; public class CHRAstAtom extends CHRAstQuery { public Expression expression; public boolean remove; public CHRAstAtom(Expression expression, boolean remove) { this.expression = expression; this.remove = remove; } @Override public void accept(CHRAstQueryVisitor visitor) { visitor.visit(this); } public static CHRAstQuery atom(Expression expression) { boolean remove = false; if(expression instanceof EVar) { EVar var = (EVar)expression; if(var.name.equals("True")) { CHRAstConjunction query = new CHRAstConjunction(Collections.emptyList()); query.location = expression.location; return query; } } else if(expression instanceof EBinary) { EBinary binary = (EBinary)expression; if(binary.negation != null && binary.rights.isEmpty()) { remove = true; expression = binary.left; } // If query is marked for removal, it must be an atom } else if(expression instanceof EApply) { EApply apply = (EApply)expression; if(apply.function instanceof EVar && ((EVar)apply.function).name.equals("not")) { Expression subExpression; if(apply.parameters.length == 1) subExpression = apply.parameters[0]; else subExpression = 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)); CHRAstNegation query = new CHRAstNegation(atom(subExpression)); query.location = expression.location; return query; } else if(apply.function instanceof EConstant) { Name valueName = ((EConstant)apply.function).getValue().getName(); if(valueName.module.equals(Types.BUILTIN) && valueName.name.startsWith("(")) { CHRAstQuery[] conjuncts = new CHRAstQuery[apply.parameters.length]; for(int i=0;i literals) { literals.add( isConstraint(context, expression) ? convertConstraint(remove, expression) : convertExpression(isHead, expression)); } 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; } } 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, 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, false); literal.fields = fields; return literal; } }