Package org.rascalmpl.interpreter.utils

Source Code of org.rascalmpl.interpreter.utils.Cases$DefaultBlock

/*******************************************************************************
* Copyright (c) 2011-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:

*   * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
*   * Michael Steindorfer  - michael.steindorfer@cwi.nl - CWI
*******************************************************************************/
package org.rascalmpl.interpreter.utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.imp.pdb.facts.IConstructor;
import org.eclipse.imp.pdb.facts.INode;
import org.eclipse.imp.pdb.facts.IValue;
import org.eclipse.imp.pdb.facts.type.Type;
import org.eclipse.imp.pdb.facts.type.TypeFactory;
import org.rascalmpl.ast.Case;
import org.rascalmpl.ast.Expression;
import org.rascalmpl.ast.PatternWithAction;
import org.rascalmpl.ast.Replacement;
import org.rascalmpl.ast.Statement;
import org.rascalmpl.ast.StringConstant;
import org.rascalmpl.interpreter.IEvaluator;
import org.rascalmpl.interpreter.control_exceptions.Failure;
import org.rascalmpl.interpreter.control_exceptions.Insert;
import org.rascalmpl.interpreter.control_exceptions.InterruptException;
import org.rascalmpl.interpreter.env.Environment;
import org.rascalmpl.interpreter.matching.IBooleanResult;
import org.rascalmpl.interpreter.matching.IMatchingResult;
import org.rascalmpl.interpreter.result.Result;
import org.rascalmpl.interpreter.result.ResultFactory;
import org.rascalmpl.interpreter.types.NonTerminalType;
import org.rascalmpl.semantics.dynamic.QualifiedName;
import org.rascalmpl.semantics.dynamic.Tree;
import org.rascalmpl.values.uptr.Factory;
import org.rascalmpl.values.uptr.TreeAdapter;

public class Cases  {
  public static final List<String> IUPTR_NAMES = Arrays.asList("appl", "cycle", "amb", "char");
 
  private static final TypeFactory TF = TypeFactory.getInstance();
 
  public static List<CaseBlock> precompute(List<Case> cases) {
    ArrayList<CaseBlock> blocks = new ArrayList<CaseBlock>(cases.size());
   
    for (int i = 0; i < cases.size(); i++) {
      Case c = cases.get(i);
      if (isConcreteSyntaxPattern(c)) {
        ConcreteBlock b = new ConcreteBlock();
        b.add(c);
        for (int j = i + 1; j < cases.size(); j++) {
          Case d = cases.get(j);
          if (isConcreteSyntaxPattern(d) && !isIUPTRPattern(d)) {
            b.add(d);
            i++;
          } else {
            break;
          }
        }
        blocks.add(b);
      } else if (isIUPTRPattern(c)) {
        blocks.add(new DefaultBlock(c));
      } else if (isConstantTreePattern(c)) {
        NodeCaseBlock b = new NodeCaseBlock();
        b.add(c);
        for (int j = i + 1; j < cases.size(); j++) {
          Case d = cases.get(j);
          if (isConstantTreePattern(d) && !isIUPTRPattern(d)) {
            b.add(d);
            i++;
          } else {
            break;
          }
        }
        blocks.add(b);
      } else {
        blocks.add(new DefaultBlock(c));
      }
    }
   
    return blocks;
  }
 
  private static boolean isConcreteSyntaxPattern(Case d) {
    if (d.isDefault()) {
      return false;
    }

    org.rascalmpl.ast.Expression pattern = d.getPatternWithAction()
        .getPattern();
   
    if (pattern.isVariableBecomes() || pattern.isTypedVariableBecomes()) {
      pattern = pattern.getPattern();
    }
   
    if (pattern._getType() != null
        && pattern._getType() instanceof NonTerminalType) {
      return true;
    }

    return false;
  }
 
  private static boolean isIUPTRPattern(Case d) {
    if (d.isDefault()) {
      return false;
    }

    org.rascalmpl.ast.Expression pattern = d.getPatternWithAction().getPattern();
   
    if (pattern.isVariableBecomes() || pattern.isTypedVariableBecomes()) {
      pattern = pattern.getPattern();
    }
   
    if (pattern.isCallOrTree()) {
      Expression func =  pattern.getExpression();
      if (func.isQualifiedName() && IUPTR_NAMES.contains(Names.fullName(func.getQualifiedName()))) {
        return true;
      }
    }

    return false;

  }


  private static boolean isConstantTreePattern(Case c) {
    if (c.isDefault()) {
      return false;
    }
   
   
    org.rascalmpl.ast.Expression pattern = c.getPatternWithAction()
        .getPattern();
    if (pattern.isVariableBecomes() || pattern.isTypedVariableBecomes()) {
      pattern = pattern.getPattern();
    }
   
    if (pattern.isCallOrTree()) {
      if (pattern.getExpression().isQualifiedName()) {
        return true;
      }
      if (pattern.getExpression().isLiteral()) {
        return true;
      }
    }

    return false;
  }
 
  private static boolean isNonTerminalType(Type t) {
    return t instanceof NonTerminalType;
  }
 
  public static abstract class CaseBlock {
    public boolean hasRegExp = false;
    public boolean allConcrete = false;
    public abstract boolean matchAndEval(IEvaluator<Result<IValue>> eval, Result<IValue> subject);
   
    protected void computePredicates(Case c) {
      if (c.hasPatternWithAction()) {
        Expression pattern = c.getPatternWithAction().getPattern();
        hasRegExp |= pattern.isLiteral() && pattern.getLiteral().isRegExp();

        Type type = pattern._getType();
        allConcrete &= isNonTerminalType(type);
      }
    }
  }

  public static class ConcreteBlock extends CaseBlock {
    private final Hashtable<IConstructor, List<DefaultBlock>> table = new Hashtable<IConstructor, List<DefaultBlock>>();

    public ConcreteBlock() {
      allConcrete = true;
      hasRegExp = false;
    }
   
    void add(Case c) {
      Expression pattern = c.getPatternWithAction().getPattern();
      if (pattern.isVariableBecomes() || pattern.isTypedVariableBecomes()) {
        pattern = pattern.getPattern();
      }

      IConstructor key = ((Tree.Appl) pattern).getProduction();
      List<DefaultBlock> same = table.get(key);
      if (same == null) {
        same = new LinkedList<DefaultBlock>();
        table.put(key, same);
      }
      same.add(new DefaultBlock(c));
    }

    @Override
    public boolean matchAndEval(IEvaluator<Result<IValue>> eval, Result<IValue> subject) {
      IValue value = subject.getValue();
      org.eclipse.imp.pdb.facts.type.Type subjectType = value
          .getType();

      if (subjectType.isSubtypeOf(Factory.Tree) && TreeAdapter.isAppl((IConstructor) value)) {
        List<DefaultBlock> alts = table.get(TreeAdapter.getProduction((IConstructor) value));
        if (alts != null) {
          for (CaseBlock c : alts) {
            if (c.matchAndEval(eval, subject)) {
              return true;
            }
          }
        }
      }

      return false;
    }
  }

  private static class DefaultBlock extends CaseBlock {
    private final Case theCase;
    private final PatternWithAction pattern;
    private final Replacement replacement;
    private final List<Expression> conditions;
    private final Expression insert;

    public DefaultBlock(Case c) {
      this.theCase = c;
      this.pattern = c.hasPatternWithAction() ? c.getPatternWithAction() : null;
      this.replacement = pattern != null && pattern.hasReplacement() ? pattern.getReplacement() : null;
      this.conditions = replacement != null && replacement.hasConditions() ? replacement.getConditions() : Collections.<Expression>emptyList();
      this.insert = replacement != null ? replacement.getReplacementExpression() : null;
     
      computePredicates(c);
    }

    @Override
    public boolean matchAndEval(IEvaluator<Result<IValue>> eval, Result<IValue> subject) {
      if (theCase.isDefault()) {
        theCase.getStatement().interpret(eval);
        return true;
      }
     
      PatternWithAction rule = theCase.getPatternWithAction();
     
      if (rule.hasStatement()) {
        return Cases.matchAndEval(subject, rule.getPattern(), pattern.getStatement(), eval);
      }
      else {
        return matchEvalAndReplace(subject, rule.getPattern(), conditions, insert, eval);
      }
    }
    
    public static boolean matchEvalAndReplace(Result<IValue> subject, Expression pat, List<Expression> conditions, Expression replacementExpr, IEvaluator<Result<IValue>> eval) {
      Environment old = eval.getCurrentEnvt();
      try {
        IMatchingResult mp = pat.getMatcher(eval);
        mp.initMatch(subject);

        while (mp.hasNext()) {
          if (eval.isInterrupted())
            throw new InterruptException(eval.getStackTrace(), eval.getCurrentAST().getLocation());
          if (mp.next()) {
            int size = conditions.size();
           
            if (size == 0) {
               throw new Insert(replacementExpr.interpret(eval), mp, mp.getType(eval.getCurrentEnvt(), null));
            }
           
            IBooleanResult[] gens = new IBooleanResult[size];
            Environment[] olds = new Environment[size];
            Environment old2 = eval.getCurrentEnvt();

            int i = 0;
            try {
              olds[0] = eval.getCurrentEnvt();
              eval.pushEnv();
              gens[0] = conditions.get(0).getBacktracker(eval);
              gens[0].init();

              while (i >= 0 && i < size) {

                if (eval.isInterrupted()) {
                  throw new InterruptException(eval.getStackTrace(), eval.getCurrentAST().getLocation());
                }
                if (gens[i].hasNext() && gens[i].next()) {
                  if (i == size - 1) {
                    // in IfThen the body is executed, here we insert the expression
                    // NB: replaceMentExpr sees the latest bindings of the when clause
                    throw new Insert(replacementExpr.interpret(eval), mp, mp.getType(eval.getCurrentEnvt(), null));
                  }

                  i++;
                  gens[i] = conditions.get(i).getBacktracker(eval);
                  gens[i].init();
                  olds[i] = eval.getCurrentEnvt();
                  eval.pushEnv();
                } else {
                  eval.unwind(olds[i]);
                  eval.pushEnv();
                  i--;
                }
              }
            } finally {
              eval.unwind(old2);
            }
          }
        }
      } finally {
        eval.unwind(old);
      }
      return false;
    }
  }
 

  private static class NodeCaseBlock extends CaseBlock {
    private final HashMap<String, List<DefaultBlock>> table = new HashMap<String, List<DefaultBlock>>();

    public NodeCaseBlock() {
      hasRegExp = false;
      allConcrete = false;
    }

    void add(Case c) {
      Expression pattern = c.getPatternWithAction().getPattern();
      org.rascalmpl.ast.Expression name;
      if (pattern.isVariableBecomes() || pattern.isTypedVariableBecomes()) {
        name = pattern.getPattern().getExpression();
      }
      else {
        name = pattern.getExpression();
      }
      String key = null;

      if (name.isQualifiedName()) {
        key = ((QualifiedName.Default) name.getQualifiedName()).lastName();
      } else if (name.isLiteral()) {
        StringConstant constant = name.getLiteral().getStringLiteral().getConstant();
        key = StringUtils.unescapeBase(StringUtils.unquote(((StringConstant.Lexical) constant).getString()));
      }

      List<DefaultBlock> same = table.get(key);
      if (same == null) {
        same = new LinkedList<DefaultBlock>();
        table.put(key, same);
      }
      same.add(new DefaultBlock(c));
    }

    @Override
    public boolean matchAndEval(IEvaluator<Result<IValue>> eval, Result<IValue> subject) {
      IValue value = subject.getValue();
      org.eclipse.imp.pdb.facts.type.Type subjectType = value
          .getType();

      if (subjectType.isSubtypeOf(TF.nodeType())) {
        boolean isTree = subjectType.isSubtypeOf(Factory.Tree)
            && ((IConstructor) subject.getValue()).getConstructorType() == Factory.Tree_Appl;

        if (isTree) { // matching abstract with concrete
          TreeAsNode wrap = new TreeAsNode((IConstructor) subject.getValue());
          Result<IValue> asTree = ResultFactory.makeResult(TF.nodeType(), wrap, eval);

          if (tryCases(eval, asTree)) {
            return true;
          }
        }
        else if (tryCases(eval, subject)) {
          return true;
        }
      }
      return false;
    }

    protected boolean tryCases(IEvaluator<Result<IValue>> eval, Result<IValue> subject) {
      List<DefaultBlock> alts = table.get(((INode) subject.getValue()).getName());

      if (alts != null) {
        for (DefaultBlock c : alts) {
          if (c.matchAndEval(eval, subject)) {
            return true;
          }
        }
      }

      return false;
    }
  }


  public static boolean matchAndEval(Result<IValue> subject, Expression pat, Statement stat, IEvaluator<Result<IValue>> eval) {
    boolean debug = false;
    Environment old = eval.getCurrentEnvt();
    eval.pushEnv();
 
    try {
      IMatchingResult mp = pat.getMatcher(eval);
      mp.initMatch(subject);
 
      while (mp.hasNext()) {
        eval.pushEnv();
       
        if (eval.isInterrupted()) {
          throw new InterruptException(eval.getStackTrace(), eval.getCurrentAST().getLocation());
        }
 
        if (mp.next()) {
          try {
            try {
              stat.interpret(eval);
            } catch (Insert e) {
              // Make sure that the match pattern is set
              if (e.getMatchPattern() == null) {
                e.setMatchPattern(mp);
              }
              e.setStaticType(mp.getType(eval.getCurrentEnvt(), null));
              throw e;
            }
            return true;
          } catch (Failure e) {
            // unwind(old); // can not clean up because you don't
            // know how far to roll back
          }
        }
      }
    } finally {
      if (debug) {
        System.err.println("Unwind to old env");
      }
      eval.unwind(old);
    }
    return false;
  }
}
TOP

Related Classes of org.rascalmpl.interpreter.utils.Cases$DefaultBlock

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.