更换+副作用

时间:2017-04-12 23:53:15

标签: rascal

在访问编译单元---并给定一定条件时 - 我想应用转换(使用=>运算符)并计算对给定编译单元应用相同转换的次数。

我能够使用一种"全局模块变量"来执行该操作,但我确信可以在单个访问表达式中组合替换和操作。那可能吗?

module MultiCatch

import lang::java::\syntax::Java18;
import ParseTree; 
import IO;
import Map;
import Type; 
import List;

// sure, I don't like global variables. 
//
// However I could not find a way to perform both 
// a replacement and count the number of times 
// it was applied in the same compilation unit. 
int numberOfOccurences = 0; 

/**
 * Refactor a try-catch statement to use the 
 * MultiCatch construct of Java 7. 
 */
public tuple[int, CompilationUnit]  refactorMultiCatch(CompilationUnit unit) { 
  numberOfOccurences = 0;  
  CompilationUnit cu =  visit(unit) {
   case (TryStatement)`try <Block b1> <Catches c1>` => (TryStatement)`try <Block b1> <Catches mc>`
     when mc := computeMultiCatches(c1)
  };
  return <numberOfOccurences, cu>;
}

/*
 * Based on a simple notion of similarity, 
 * this function calculates the possible 
 * occurences of MultiCatch. 
 */ 
private Catches computeMultiCatches(cs){
   map [Block, tuple[list[CatchType], VariableDeclaratorId, Block] ] mCatches =();
   visit(cs){
      case(CatchClause)`catch (<CatchType t> <VariableDeclaratorId vId>) <Block b>` :{
         if (b in mCatches){
            <ts, vId, blk> = mCatches[b];
            ts += t;
            mCatches[b] = <ts, vId, blk>;
            numberOfOccurences += 1;
         }
         else{
            mCatches[b] = <[t], vId, b>;
         }
      }
   }
   return generateMultiCatches([mCatches[b] | b <- mCatches]); 
}

/*
 * Creates a syntactic catch clause (either a simple one or 
 * a multicatch). 
 * 
 * This is a recursive definition. The base case expects only 
 * one tuple, and than it returns a single catch clause. In the 
 * recursive definition, at least two tuples must be passed as 
 * arguments, and thus it returns at least two catches clauses 
 * (actually, one catch clause for each element in the list)
 */
private Catches generateMultiCatches([<ts, vId, b>]) = {
  types = parse(#CatchType, intercalate("| ", ts));
  return (Catches)`catch(<CatchType types>  <VariableDeclaratorId vId>) <Block b>`; 
};
private Catches generateMultiCatches([<ts, vId, b>, C*]) = {
  catches = generateMultiCatches(C);
  types = parse(#CatchType, intercalate("| ", ts));
  return (Catches)`catch(<CatchType types> <VariableDeclaratorId vId>) <Block b> <CatchClause+ catches>`;
};

1 个答案:

答案 0 :(得分:2)

一种方法是使用本地变量和带insert的块:

module MultiCatch

import lang::java::\syntax::Java18;
import ParseTree; 
import IO;
import Map;
import Type; 
import List;

/**
 * Refactor a try-catch statement to use the 
 * MultiCatch construct of Java 7. 
 */
public tuple[int, CompilationUnit]  refactorMultiCatch(CompilationUnit unit) { 
  int numberOfOccurences = 0;  /* the type is superfluous */
  CompilationUnit cu =  visit(unit) {
   case (TryStatement)`try <Block b1> <Catches c1>` : {
      numberOfOccurences += 1;
      mc = computeMultiCatches(c1)
      insert (TryStatement)`try <Block b1> <Catches mc>`;
   }
  };

  return <numberOfOccurences, cu>;
}
  • {...}块允许在匹配后执行多个语句;
  • 局部变量现在只出现在refactorMultiCatch;
  • 的框架中
  • insert语句与之前的=>箭头具有相同的效果;
  • 由于匹配:=总是成功,我将when条款更改为简单的分配

还有其他更复杂的方法可以在Rascal中共享状态,但我个人更喜欢让状态无法逃避函数的词法范围。