我有一个抽象类和case类的树状结构,表示一种小语言的抽象语法树。
对于顶级抽象类,我实现了一个方法map
:
abstract class AST {
...
def map(f: (AST => AST)): AST = {
val b1 = this match {
case s: STRUCTURAL => s.smap(f) // structural node for example IF(expr,truebranch,falsebranch)
case _ => this // leaf, // leaf, like ASSIGN(x,2)
}
f(b1)
}
...
smap的定义如下:
override def smap(f: AST => AST) = {
this.copy(trueb = trueb.map(f), falseb = falseb.map(f))
}
现在我正在编写不同的“转换”来插入,删除和更改AST中的节点。
例如,从块中删除相邻的NOP节点:
def handle_list(l:List[AST]) = l match {
case (NOP::NOP::tl) => handle_list(tl)
case h::tl => h::handle_list(tl)
case Nil => Nil
}
ast.map {
case BLOCK(listofstatements) => handle_list(listofstatements)
}
如果我这样写,我最终得到MatchError
,我可以通过将上面的地图更改为“修复它”:
ast.map {
case BLOCK(listofstatements) => handle_list(listofstatements)
case a => a
}
我应该与所有case a => a
人住在一起,还是可以通过某种方式改进我的map
方法(或其他部分)?
答案 0 :(得分:4)
如果树转换不仅仅是项目的一个次要方面,我强烈建议您使用Kiama的重写器模块来实现它们。它实现了类似Stratego的策略驱动的转换。它有一套非常丰富的策略和策略组合器,允许完全分离遍历逻辑(对于绝大多数情况,可以从提供的策略和组合器中“从现有的”获取)来自(本地)转换(这是特别是你的AST和你提供的,当然)。
答案 1 :(得分:4)
将参数设为map
一个PartialFunction
:
def map(f: PartialFunction[AST, AST]): AST = {
val idAST: PartialFunction[AST, AST] = {case a => a}
val g = f.orElse(idAST)
val b1 = this match {
case s: STRUCTURAL => s.smap(g)
case _ => this
}
g(b1)
}