Package hampi.parser

Source Code of hampi.parser.HConstraintPreparer

package hampi.parser;

import hampi.*;
import hampi.constraints.*;
import hampi.grammars.*;
import hampi.grammars.apps.GrammarStringBounder;
import hampi.utils.*;

import java.util.*;

import jpaul.Graphs.*;

/**
* Converts the AST form the parser into a Hampi (core string) constraint.
*/
public final class HConstraintPreparer{

  private final Hampi hampi;
  private final int varSize;

  public HConstraintPreparer(Hampi hampi, int varSize){
    this.hampi = hampi;
    this.varSize = varSize;
  }

  /**
   * Converts ast to constraint. Assume ast is well-formed.
   */
  public Constraint prepare(HProgram ast){
    List<HStatement> asserts = ast.getStatements(HGrammarElementKind.STMT_ASSERT);

    List<Constraint> conjuncts = new ArrayList<Constraint>(asserts.size());
    for (HStatement assertStmt : asserts){
      Constraint p = prepare((HAssertStatement) assertStmt, ast);
      assert p != null : assertStmt;
      conjuncts.add(p);
    }
    return hampi.andConstraint(conjuncts);
  }

  private Constraint prepare(HAssertStatement asrt, HProgram ast){
    HBooleanExpression boolExpr = asrt.getBooleanExpression();
    switch (boolExpr.getKind()){
    case BEXPR_CONTAINS:
      return prepareContains((HContainsExpression) boolExpr, ast);
    case BEXPR_IN:
      return prepareIn((HInExpression) boolExpr, ast);
    case BEXPR_EQUALS:
      return prepareEquals((HEqualsExpression) boolExpr, ast);
    default:
      throw new IllegalStateException("invalid kind:" + asrt);
    }
  }

  private Constraint prepareEquals(HEqualsExpression equalExpr, HProgram ast){
    String leftId = equalExpr.getId1();
    String rightId = equalExpr.getId2();
    return hampi.equalsConstraint(getExpandedExpression(leftId, ast), equalExpr.equals(), getExpandedExpression(rightId, ast));
  }

  private Constraint prepareContains(HContainsExpression containsExpr, HProgram ast){
    String varName = containsExpr.getVariableName();
    String string = containsExpr.getString();
    Regexp sigma = getAlphabet(ast);
    Regexp sigmaStar = hampi.starRegexp(sigma);
    Regexp contains = hampi.concatRegexp(sigmaStar, hampi.constRegexp(string), sigmaStar);
    Expression varExpr = getExpandedExpression(varName, ast);
    return hampi.regexpConstraint(varExpr, containsExpr.contains(), contains);
  }

  /**
   * Creates an expression by inlining all var definitions (assumption is that
   * there are no cycles there.)
   */
  private Expression getExpandedExpression(String varName, HProgram ast){
    HStatement decl = ast.getDecl(varName);
    switch (decl.getKind()){
    case STMT_VALDECL: {
      HValDeclStatement val = (HValDeclStatement) decl;
      HExpression expression = val.getExpression();
      return getExpression(expression, ast);
    }
    case STMT_VARDECL: {
      HVarDeclStatement v = (HVarDeclStatement) decl;
      return hampi.varExpr(v.getVarName());
    }
    default:
      throw new IllegalStateException("invalid usage of variable reference " + varName + " \n" + ast);
    }
  }

  private Expression getExpression(HExpression expression, HProgram ast){
    switch (expression.getKind()){
    case EXPR_CONCAT: {
      HConcatExpression ce = (HConcatExpression) expression;
      List<Expression> exprs = new ArrayList<Expression>();
      for (HExpression subExpr : ce.getSubExpressions()){
        exprs.add(getExpression(subExpr, ast));
      }
      return hampi.concatExpr(exprs);
    }
    case EXPR_SUBSEQUENCE: {
      HSubsequenceExpression ce = (HSubsequenceExpression) expression;
      HStatement decl = ast.getDecl(ce.getName());
      switch (decl.getKind()){
      case STMT_VARDECL: {
        HVarDeclStatement v = (HVarDeclStatement) decl;
        return hampi.subsequenceExpr(hampi.varExpr(v.getVarName()), ce.getStartIndex(), ce.getLength());
      }
      default:
        throw new IllegalStateException("subsequence can only be used on var declaration " + ce.getName() + " \n" + ast);
      }
    }
    case EXPR_VAR: {
      HVarReferenceExpression var = (HVarReferenceExpression) expression;
      return getExpandedExpression(var.getName(), ast);
    }
    case EXPR_CONST: {
      HConstantExpression constEx = (HConstantExpression) expression;
      return hampi.constExpr(constEx.getValue());
    }
    default:
      throw new IllegalStateException("invalid expression in variable declaration: " + expression);
    }
  }

  //XXX hardwire
  private Regexp getAlphabet(HProgram ast){
    return hampi.rangeRegexp(ASCIITable.lowestChar, ASCIITable.highestChar);
  }

  /*
   * Processes expressions 'x in A'.
   * A must be either a regular variable,
   * or a context-free variable.
   * In the latter case, bound inference is required.
   */
  private Constraint prepareIn(HInExpression inExpr, HProgram ast){
    Expression exp = getExpandedExpression(inExpr.getVarName(), ast);
    String varName = inExpr.getRegVarName();
    HRegDeclStatement regDecl = ast.getRegDecl(varName);
    if (regDecl != null){
      //regular case
      Regexp reg = prepareRegForVar(varName, ast);
      assert reg != null : "null reg for " + inExpr.getRegVarName();
      return hampi.regexpConstraint(exp, inExpr.isIn(), reg);
    }else{
      //context-free case
      CFGStatement cfg = ast.getCFGDecl(varName);
      assert cfg != null : "null cfg for " + inExpr.getRegVarName();
      int boundSize = computeExpressionSize(exp, varSize);
      Regexp reg = prepareSizeFixRegexp(varName, boundSize, ast);
      return hampi.regexpConstraint(exp, inExpr.isIn(), reg);
    }
  }

  /*
   * Compute the length of the expression given the size of the string variable.
   */
  private int computeExpressionSize(Expression exp, int varSize){
    assert exp.getVariables().size() <= 1 : exp.getVariables().toString();//expect at most 1 var
    Solution solution= Solution.createSAT();
    if (!exp.getVariables().isEmpty()) {
      solution.setValue(exp.getVariables().iterator().next(), Utils.spaces(varSize));
    }
    return exp.getValue(solution).length();
  }

  private Regexp prepareRegForVar(String varName, HProgram ast){
    HRegDeclStatement regDecl = ast.getRegDecl(varName);
    HRegDefinition regexp = regDecl.getRegexp();
    return prepareRegexp(regexp, ast);
  }

  private Regexp prepareRegexp(HRegDefinition regexp, HProgram ast){
    switch (regexp.getKind()){
    case REG_CONST: {
      HConstRegexp cr = (HConstRegexp) regexp;
      return hampi.constRegexp(cr.getString());
    }
    case REG_FIX: {
      HSizeFixRegDefinition fix = (HSizeFixRegDefinition) regexp;
      return prepareSizeFixRegexp(fix, ast);
    }
    case REG_STAR: {
      HStarRegexp sr = (HStarRegexp) regexp;
      HRegDefinition subRegexp = sr.getSubRegexp();
      return hampi.starRegexp(prepareRegexp(subRegexp, ast));
    }
    case REG_RANGE: {
      HRangeRegexp range = (HRangeRegexp) regexp;
      return hampi.rangeRegexp(range.getLow(), range.getHigh());
    }
    case REG_CONCAT: {
      HConcatRegexp concat = (HConcatRegexp) regexp;
      return hampi.concatRegexp(prepareRegexps(concat.getExpressions(), ast));
    }
    case REG_OR: {
      HOrRegexp or = (HOrRegexp) regexp;
      return hampi.orRegexp(prepareRegexps(or.getExpressions(), ast));
    }
    case REG_VAR: {
      HRegVarRef var = (HRegVarRef) regexp;
      return prepareRegForVar(var.getName(), ast);
    }
    default:
      throw new IllegalStateException(regexp.toString());
    }
  }

  private List<Regexp> prepareRegexps(List<HRegDefinition> expressions, HProgram ast){
    List<Regexp> res = new ArrayList<Regexp>(expressions.size());
    for (HRegDefinition regDefinition : expressions){
      res.add(prepareRegexp(regDefinition, ast));
    }
    return res;
  }

  /*
   * Creates the regular expression that describes
   * all strings of given size in the CFG.
   */
  private Regexp prepareSizeFixRegexp(HSizeFixRegDefinition fix, HProgram ast){
    return prepareSizeFixRegexp(fix.getNonterminal(), fix.getSize(), ast);
  }

  /*
   * Creates the regular expression that describes
   * all strings of given size in the CFG.
   */
  private Regexp prepareSizeFixRegexp(String cfg, int size, HProgram ast){
    Grammar g = extractGrammar(cfg, ast);
    StopWatch w = new StopWatch("grammar bounding for " + cfg);
    w.start();
    GrammarStringBounder gsb = new GrammarStringBounder();
    Regexp boundedRegexp = gsb.getBoundedRegexp(g, cfg, size, false);
    w.stop();
    System.out.println(w);
    if (boundedRegexp == null)
      throw HampiResultException.unsat();
    return boundedRegexp;
  }

  /**
   * Converts the CFG from the front-end format to the internal format.<br>
   * TODO revisit whether this 2-format story could be simplified.
   */
  private Grammar extractGrammar(String nonterminal, HProgram ast){
    Set<String> reachableNonterminals = reachableNonterminals(nonterminal, ast);
    Set<CFGStatement> cfgDecl = ast.getCFGDecls(reachableNonterminals);
    Grammar grammar = new Grammar();
    for (CFGStatement stmt : cfgDecl){
      grammar.addRule(extractRule(stmt, ast, grammar));
    }
    return grammar;
  }

  private GrammarRule extractRule(CFGStatement stmt, HProgram ast, Grammar grammar){
    List<List<CFGProductionElement>> elemSets = stmt.getElementSets();
    GrammarRule rule = new GrammarRule();
    for (List<CFGProductionElement> elems : elemSets){
      rule.addProduction(extractProduction(rule, elems, ast, grammar));
    }
    rule.setNonterminal(new NonterminalElement(stmt.getVarName(), grammar));
    return rule;
  }

  private GrammarProduction extractProduction(GrammarRule rule, List<CFGProductionElement> elems, HProgram ast, Grammar grammar){
    GrammarProduction gp = new GrammarProduction(rule);
    for (CFGProductionElement elem : elems){
      GrammarProductionElement element = extractProductionElement(elem, ast, grammar);
      gp.addElement(element);
    }
    return gp;
  }

  private final Set<String> newNonterminals = new LinkedHashSet<String>();

  private GrammarProductionElement extractProductionElement(CFGProductionElement elem, HProgram ast, Grammar grammar){
    switch (elem.getKind()){
    case CFG_CHAR_RANGE: {
      //the other model does not have ranges or OR so we introduce a new nonterminal and expand the range
      CFGCharRange range = (CFGCharRange) elem;
      String name = "range" + range.getLow() + "_" + range.getHigh();
      NonterminalElement newNt = new NonterminalElement(name, grammar);
      if (!newNonterminals.contains(name)){
        newNonterminals.add(name);
        GrammarRule newRule = new GrammarRule();
        newRule.setNonterminal(newNt);
        for (char c : range.getChars()){
          GrammarProduction p = new GrammarProduction(newRule);
          p.addElement(new TerminalElement("\"" + String.valueOf(c) + "\"", grammar));
          newRule.addProduction(p);
        }
        grammar.addRule(newRule);
      }
      return newNt;
    }
    case CFG_NONTERMINAL: {
      CFGNonterminal nt = (CFGNonterminal) elem;
      return new NonterminalElement(nt.getName(), grammar);
    }
    case CFG_OPTION: {
      CFGOption opt = (CFGOption) elem;
      List<GrammarProductionElement> elems = new ArrayList<GrammarProductionElement>(1);
      elems.add(extractProductionElement(opt.getSubelement(), ast, grammar));
      return new OptionElement(elems, grammar);
    }
    case CFG_PLUS: {
      CFGPlus plus = (CFGPlus) elem;
      List<GrammarProductionElement> elems = new ArrayList<GrammarProductionElement>(1);
      elems.add(extractProductionElement(plus.getSubelement(), ast, grammar));
      return new PlusElement(elems, grammar);
    }
    case CFG_STAR: {
      CFGStar star = (CFGStar) elem;
      List<GrammarProductionElement> elems = new ArrayList<GrammarProductionElement>(1);
      elems.add(extractProductionElement(star.getSubelement(), ast, grammar));
      return new StarElement(elems, grammar);
    }
    case CFG_TERMINAL: {
      CFGTerminal term = (CFGTerminal) elem;
      return new TerminalElement(term.getText(), grammar);
    }
    default:
      throw new IllegalStateException("unknown kind " + elem);
    }
  }

  private Set<String> reachableNonterminals(String nonterminal, final HProgram ast){
    DiGraph<String> graph = new DiGraph<String>(){
      @Override
      public Collection<String> getRoots(){
        List<HStatement> statements = ast.getStatements(HGrammarElementKind.STMT_CFG);
        List<String> l = new ArrayList<String>(statements.size());
        for (HStatement statement : statements){
          l.add(((CFGStatement) statement).getVarName());
        }
        return l;
      }

      @Override
      public ForwardNavigator<String> getForwardNavigator(){
        return new ForwardNavigator<String>(){

          @Override
          public List<String> next(String vertex){
            CFGStatement decl = ast.getCFGDecls(Collections.singleton(vertex)).iterator().next();
            final List<String> res = new ArrayList<String>();
            for (List<CFGProductionElement> elemSet : decl.getElementSets()){
              for (CFGProductionElement elem : elemSet){
                elem.accept(new HGrammarVisitor(){
                  @Override
                  public void visitCFGNonterminal(CFGNonterminal nonterminal){
                    res.add(nonterminal.getName());
                  }
                });
              }
            }
            return res;
          }

        };
      }
    };
    return graph.transitiveSucc(nonterminal);
  }

}
TOP

Related Classes of hampi.parser.HConstraintPreparer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.