访问 Rascal 节点的_all_下游注解

Accessing _all_ downstream annotations of a node in Rascal

我在尝试做类似的事情时阅读了 。那里给出的答案没有解决我的问题。

我想用访问语句来确定每个子树的'mass',所以对于每个节点我想对所有后代的质量求和。例如,一个访问步骤遇到了这个节点表达式,里面有一个列表:

\anode([\bnode()[@mass=1], \bnode()[@mass=2]], \cnode()[@mass=5])

应该产生这个:

\anode([\bnode()[@mass=1], \bnode()[@mass=2]], \cnode()[@mass=5])[@mass=8]

所以我不只是想过滤掉非节点,而是实际遍历它们。在我的访问语句中包含列表的案例不起作用(至少不明显),因为列表不能有注释。

有没有一种自然的方法可以将完整的注释信息传播到树上?

如果具有容器子节点的节点数不是很大,那么第一个解决方案是精确且有用的:

x = \anode([\bnode()[@mass=1], \bnode()[@mass=2]], \cnode()[@mass=5]);

visit(x) {
  case n:\anode(l) => n[@mass=(0 | it + e@mass | e <- l)]
}

(您可能还会在本地函数中抽象 reducer 表达式)

第二种解决方案是从节点类型中抽象出来,以防你有很多这样的情况:

visit(x) {
  case n:str _(l) => n[@mass=(0 | it + e@mass | e <- l)]
}

第三种解决方案在注释嵌套得更深的情况下效果最好,例如在列表的列表等中,并且您有许多不同类型的节点:

import Node;
int computeMass(list[value] x) {
  mass = 0;
  top-down-break visit(x) {
    case node x : mass += (x@mass?) ? x@mass : 0;
  }
  return mass;
}

visit(x) {
  case node n => n[@mass=computeMass(getChildren(n))]
}

我更喜欢第一个解决方案,因为它最精确。

请注意,我们将在不久的将来用 "keyword parameters" 替换注释功能;具有几乎相同的语义,不同的语法,例如 \cnode(mass=2) 对应 \code()[@mass=2]。使用新的关键字参数,您还可以为 mass 字段提供延迟计算的默认值,如下所示:

data N() 
  = anode(list[N] children, int mass=(0 | it + c.mass | c <- children)) 
  | cnode(int mass=0)
  ;

anode([cnode(mass=1),cnode(mass=2)]).mass == 3