替换AST流氓中的类型



我正在尝试替换AST中的所有类型。用m3模型分析Java语言;此处的定义

如果我们采用这个代码:

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);(请参见此处(,您的代码完全遵循该定义。您解析的AST中的每个抽象方法声明都将与此匹配,因为对于带有附加参数的实体的方法,还有另一个method声明。

可能是您的示例代码中没有抽象的方法体,在这种情况下,这不会起到任何作用。

一个更简单的版本也可以:

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

下一个有问题:

case type(Type type) => void() 

因为data Expression = type(Type type)Expressiondata Type = void()Typedata TypeSymbol = void(),它是TypeSymbol,所以重写不是类型保留的,如果Rascal编译器检测不到这一点,则会做错误的事情。大多数情况下,它可能不适用于您,因为您的示例代码不包含这种特定类型的表达式。我怀疑它可能是int.classInteger.class之类的抽象符号。

那么这个是"有趣的":

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. 通过打印出匹配的loc并点击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)

最新更新