替换AST rascal中的类型

时间:2018-11-29 16:12:54

标签: abstract-syntax-tree rascal

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

如果我们采用以下代码:

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

1 个答案:

答案 0 :(得分:1)

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

这看起来不错:

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),即Expression,而data Type = \void()Typedata TypeSymbol = \void(),它是TypeSymbol,因此重写不是保留类型,如果Rascal编译器无法检测到该错误,则会执行错误的操作。通常,它可能对您不起作用,因为您的示例代码不包含这种特定类型的表达式。我怀疑这可能是int.classInteger.class之类的抽象符号。

然后这是“有趣的”:

case \type => \void() 

原则上,如果\ type不在当前范围内,则此匹配任何字面值。但是可能在某个地方有一个称为\ type的函数或一个变量或其他内容,因此此模式测试与范围内的其他内容是否相等。很讨厌!它不会与我猜到的任何东西匹配。顺便说一句,我们正在计划一项针对语言更改的“大规模修改提案”,以避免在模式范围内对事物进行此类意外绑定。

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

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) 
}

最后一句话,如您所见,您可以根据需要深度嵌套图案,因此任何组合都可以。一个“复杂”的例子:

\variables(/"Int", names)

此模式可找到任何在类型声明中使用名称“ Int”的变量声明。这比我们的原始版本更宽松,可能比您议价的要多。只是为了显示您可能想要的组合。

这的最后一个示例:查找所有类型名称以“ Int”开头但可以以“ Integer”或“ IntFractal”等结尾的变量名称的所有变量声明:

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