Rule.java :  » JVM » mandarax » org » mandarax » dsl » Java Open Source

Java Open Source » JVM » mandarax 
mandarax » org » mandarax » dsl » Rule.java
/*
 * Copyright 2010 Jens Dietrich Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE, Version 3
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * http://www.gnu.org/licenses/agpl.html Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

package org.mandarax.dsl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.google.common.base.Function;
import static org.mandarax.dsl.Utils.*;

/**
 * Represents a rule.
 * @author jens dietrich
 */
public class Rule extends RelationshipDefinitionPart {
  
  private List<Expression> body = null;
  private FunctionInvocation head = null;
  // variable renamings in the rule head, will be set by relationship definition e.g., in 
  // rel Father(MalePerson father,Person child) extends Parent queries getFather(child),isFather(father,child) {
  // rule1: Son(c,f) -> Father(f,c);}
  // has a mapping {c->child,f->father} 
  private Map<String,String> variableMappingsInHead = null;


  public Rule(Position position, Context context,String id,Expression body,FunctionInvocation head) {
    super(position, context,id);
    this.body = flatten(body);
    this.head = head;
    
    // check whether head is flat
//    for (Expression term:head.getParameters()) {
//      if (!term.isFlat()) {
//        throw new InternalScriptException("Only flat terms (variables and terms) are allowed in rule heads, but this rule is violated by " + term + " " + term.getPosition());
//      }
//    }
    
  }
  
  public Rule(Position position, Context context,String id,List<Expression> body,FunctionInvocation head) {
    super(position, context,id);
    this.body = body;
    this.head = head;
    
  }


  /**
   * Flatten a conjunction.
   * @param expr
   * @return
   */
  private List<Expression> flatten(Expression expr) {
    if (expr==null) {
      return new ArrayList<Expression>(0);
    }
    else if (expr instanceof BinaryExpression && ((BinaryExpression)expr).getOperator()==BinOp.AND) {
      BinaryExpression bexpr = (BinaryExpression)expr;
      List<Expression> list = new ArrayList<Expression>();
      list.addAll(flatten(bexpr.getLeft()));
      list.addAll(flatten(bexpr.getRight()));
      return list;
    }
    else {
      List<Expression> list = new ArrayList<Expression>(1);
      list.add(expr);
      return list;
    }
  }

  public void accept(ASTVisitor visitor) {
    if (visitor.visit(this)) {
      head.accept(visitor);
      for (Expression e:this.body) e.accept(visitor);
    }
    visitor.endVisit(this);
  }

  public List<Expression> getBody() {
    return body;
  }

  public FunctionInvocation getHead() {
    return head;
  }
  
  @Override
  public String toString() {
    StringBuffer b = new StringBuffer();
    b.append(id);
    b.append(": ");
    this.appendList(body, b,false," & ") ; 
    b.append(" -> ");
    b.append(head);
    b.append(';');
    return b.toString();
  }
  
  public boolean isFact() {
    return this.body==null || this.body.isEmpty();
  }

  public Map<String, String> getVariableMappingsInHead() {
    return variableMappingsInHead;
  }

  public void setVariableMappingsInHead(Map<String, String> variableMappingsInHead) {
    this.variableMappingsInHead = variableMappingsInHead;
  }
  
  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((body == null) ? 0 : body.hashCode());
    result = prime * result + ((head == null) ? 0 : head.hashCode());
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    Rule other = (Rule) obj;
    if (body == null) {
      if (other.body != null)
        return false;
    } else if (!body.equals(other.body))
      return false;
    if (head == null) {
      if (other.head != null)
        return false;
    } else if (!head.equals(other.head))
      return false;
    if (id == null) {
      if (other.id != null)
        return false;
    } else if (!id.equals(other.id))
      return false;
    return true;
  }
  
  @Override
  public Rule clone() {
    Rule r = new Rule(getPosition(),getContext(),id,transformList(body,new Function<Expression,Expression>() {
      @Override
      public Expression apply(Expression x) {
        return x.substitute(NO_SUBTITUTIONS);
      }}),
    (FunctionInvocation)head.substitute(NO_SUBTITUTIONS));
    r.copyPropertiesTo(this);
    return r;
  }
  
  public Rule substitute(final Map<Expression,? extends Expression> substitutions) {
    Rule r = new Rule(getPosition(),getContext(),id,transformList(body,new Function<Expression,Expression>() {
      @Override
      public Expression apply(Expression x) {
        return x.substitute(substitutions);
      }}),
    (FunctionInvocation)head.substitute(substitutions));
    this.copyPropertiesTo(r);
    return r;
  }

  public void addToBody(Expression expression) {
    // clone returns unmodifiable list!
    List<Expression> newBody = new ArrayList<Expression>(body.size()+1);
    newBody.addAll(body);
    newBody.add(expression);
    body=newBody;
    
  }
  
  
  /**
   * Clone the rule, and flatten NAF expressions in the body.
   * If an expression is a unary expression using negation, and its part is a function invocation referencing a relationship,
   * it will be replaced by just the function invocation with NAF set to true.
   * @return
   */  
  public Rule normaliseNAF () {
    Rule r = new Rule(getPosition(),getContext(),id,transformList(body,new Function<Expression,Expression>() {
      @Override
      public Expression apply(Expression x) {
        if (x instanceof UnaryExpression && ((UnaryExpression)x).getOperator()==UnOp.NOT) {
          Expression part = ((UnaryExpression)x).getPart();
          if (part instanceof FunctionInvocation && ((FunctionInvocation)part).isDefinedByRelationship()) {
            FunctionInvocation newPart = (FunctionInvocation)part.clone();
            newPart.setNaf(true);
            return newPart;
          }
        }
        return x;
      }}),
    (FunctionInvocation)head.substitute(NO_SUBTITUTIONS));
    r.copyPropertiesTo(this);
    return r;
  }
  
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.