替换 AST rascal 中的类型

Replacing types in AST rascal

我正在尝试替换 AST 中的所有类型。 使用 m3 模型分析 Java 语言; definitions from here

如果我们采用这段代码:

Int a = 1;

例如,我可以将 1 的类型更新为 void。 但是我无法更改变量本身的类型。

我包含了一些示例行。 有人能指出行中的错误吗?

case \method(Type \return, str name, list[Declaration] parameters, list[Expression] exceptions)
    => \method(\int(), "funcHolder", parameters, exceptions)

case \type(Type \type) => \void()
case \type => \void

好的,很好的问题。首先是您的代码及其可能存在的错误:

这看起来不错:

case \method(Type \return, str name, list[Declaration] parameters, list[Expression] exceptions)
    => \method(\int(), "funcHolder", parameters, exceptions) 

定义是:data Declaration = \method(Type \return, str name, list[Declaration] parameters, list[Expression] exceptions, Statement impl);(参见here),您的代码完全遵循定义。您解析的 AST 中的每个 abstract 方法声明都将与此匹配,因为对于带有附加参数的主体的方法还有另一个 \method 声明。

可能是您的示例代码中没有抽象方法体,在这种情况下这什么都不做。

更简单的版本也可以正常工作:

case \method(_, _, parameters, exceptions) => \method(\int(), "funcHolder", parameters, exceptions)

下一个有问题:

case \type(Type \type) => \void() 

因为data Expression = \type(Type \type)是一个Expressiondata Type = \void()是一个Type或者data TypeSymbol = \void()是一个TypeSymbol重写不是类型保留的,如果 Rascal 编译器检测不到这一点,它就会做错事。大多数情况下它可能对您不起作用,因为您的示例代码不包含这种特定类型的表达式。我怀疑它可能是 int.classInteger.class.

等事物的抽象符号

那么这个是"interesting":

case \type => \void() 

原则上,如果 \type 没有绑定在当前范围内,那么这实际上匹配任何内容。但可能有一个名为 \type 的函数或一个变量或某处的东西,因此这个模式测试与范围内的其他东西是否相等。非常讨厌!它不会与我猜测的任何东西相匹配。顺便说一句,我们正计划对语言进行 "Rascal Amendement Proposal" 更改,以避免在模式范围内发生此类意外绑定。

后来从评论中我了解到目标是用 void() 替换 AST 中 Type 的所有实例,以帮助克隆检测模类型名称。这是按如下方式完成的:

case Type _ => \void() 

我们使用 [TypedVariable] 模式,变量名 _ 来匹配任何代数类型的节点 Type 而忘记绑定。然后该节点将被替换为 void().

在没有用于模式匹配的内容辅助工具的情况下,我的工作方式如下:

  1. 找到你想要匹配的东西的完整一个 AST 例子,比如 Int a = 1;
  2. 将其复制到 Rascal 源文件中
  3. 通过引入变量或_
  4. 移除你想要抽象的部分
  5. 在原始示例上测试
  6. 通过打印出匹配的 loc 并单击位置将您带到代码并查看它是否不是误报来测试系统的其余部分。

比如我想把Int重写成void,我在一个AST里找了一个Int的例子粘贴过来:

visit (ast) {
   case simpleType(simpleName("Int")) => Type::\void()  // I added Type:: to be sure to disambiguate with TypeSymbol::void()
}

附上一些调试代码以打印出所有匹配项:

visit (ast) {
   case e:simpleType(simpleName("Int")) => Type::\void()  
     when bprintln("found a type at <e.src?|unknown:///|>");
}

也许你发现匹配太多了,你必须变得更具体,所以我们只改变声明Int _ = ....;,我们先举个例子:

\variables(simpleType(simpleName("Int")), [...lots of stuff here...])

然后我们简化它:

\variables(simpleType(simpleName("Int")), names)

然后将其包含在访问中:

visit (ast) {
   case \variables(simpleType(simpleName("Int")), names) => \variables(Type::\void(), names) 
}

最后一点,如您所见,您可以根据需要嵌套任何深度的模式,因此任何组合都可以。一个 "complex" 例子:

\variables(/"Int", names)

此模式查找在某处使用名称 "Int" 作为类型声明的一部分的任何变量声明。这比我们原来的更宽松,可能会比您讨价还价的多。它只是为了显示您可能想要执行的组合。

最后一个示例:查找所有类型名称以 "Int" 开头但可以以其他任何内容结尾的变量声明,例如 "Integer" 或 "IntFractal",等等:

\variables(simpleType(simpleName(/^Int/)), names)