我正在尝试替换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)
是Expression
,data Type = void()
是Type
或data TypeSymbol = void()
,它是TypeSymbol
,所以重写不是类型保留的,如果Rascal编译器检测不到这一点,则会做错误的事情。大多数情况下,它可能不适用于您,因为您的示例代码不包含这种特定类型的表达式。我怀疑它可能是int.class
和Integer.class
之类的抽象符号。
那么这个是"有趣的":
case type => void()
原则上,如果\type没有绑定在当前作用域中,那么它实际上匹配任何内容。但可能有一个名为\type的函数、一个变量或其他什么东西,因此这个模式测试范围内的其他东西是否相等。非常讨厌!我想这与任何事情都不匹配。顺便说一句,我们正在计划一个语言更改的"Rascal Amendement Proposal",以避免模式范围内的事物意外绑定。
后来,我从通信中了解到,目标是用void()
替换AST中Type
的所有实例,以帮助克隆检测模类型名称。具体操作如下:
case Type _ => void()
我们使用变量名为_
的[TypedVariable]模式来匹配代数类型为Type
的任何节点,而忽略绑定。然后,该节点将被void()
替换。
在没有用于模式匹配的内容辅助工具的情况下,我的工作方式如下:
- 找到想要匹配的东西的完整AST示例,比如
Int a = 1;
- 将其复制到Rascal源文件中
- 通过引入变量或
_
删除要从中提取的部分 - 对原始示例的测试
- 通过打印出匹配的
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)