gpt4 book ai didi

scala - 如何从编译器插件中找到 Scala 程序中的语句?

转载 作者:行者123 更新时间:2023-12-05 00:00:19 25 4
gpt4 key购买 nike

我正在编写 Scala 编译器插件,并且已经开始编写“apply(unit:CompilationUnit”方法。但是,该方法中的语法超出了我的范围。以下代码来自 http://www.scala-lang.org/node/140

    for ( tree @ Apply(Select(rcvr, nme.DIV), List(Literal(Constant(0)))) <- unit.body;
if rcvr.tpe <:< definitions.IntClass.tpe) {
unit.error(tree.pos, "definitely division by zero")
}

此表达式查找所有除以零的结果。我不知道如何做类似的事情来查找所有可执行语句(TermTrees ??)。

最佳答案

好的,假设文件 TwoStatements.scala以下:

class TwoStatements {
def f {
println("first statement")
println("second statement")
}
}

试试这些命令:
scalac -Yshow-trees -Xprint:typer TwoStatements.scala 
scalac -Yshow-trees-compact -Xprint:typer TwoStatements.scala
scalac -Yshow-trees-stringified -Xprint:typer TwoStatements.scala
scalac -Ybrowse:typer TwoStatements.scala

请注意 typer是产生输出的阶段。因此,根据您自己的插件运行的阶段选择适当的阶段。
-Yshow-trees-compact是产生与您将在自己的代码中使用的内容完全(或非常接近)的输出的输出,但很难阅读。

其他的更容易阅读,但转换成您自己的代码可能会令人困惑。 -Yshow-trees-stringified可能比 -Yshow-trees 有用,因为它显示的信息最多。另一方面, -Ybrowse:typer是交互式的,并显示所选树节点的代码,这可能会有所帮助,尤其是当您查看较大的程序时。

如果您尝试 -Yshow-trees-compact使用链接博客中的示例,您将看到以下代码段:
 Apply(
Select(
Select(This(newTypeName("Test")), newTermName("five")), // assigned to rcvr
newTermName("$div") // compared to nme.DIV
),
List(Literal(Constant(0)))) // as is
)

所以我的建议是,您在插件工作的阶段查看您要处理的代码如何翻译,然后抓取代码片段,并用变量替换任何不感兴趣的部分。

你会注意到每个 DefDef以 body 为第六元素。可能是 BlockList在多个语句中,它可能是一个方法调用 ( Apply )、一个 getter ( Select )、一个赋值 ( Assign )、一个 if 语句 ( If ) 等等。其他类型的声明,如 ValDef ,也有与之相关的代码。

如果您正在寻找类似 tree @ Statement(...) 的内容, 它不存在。您可以使用 TermTree (或者,更好的是,方法 isTerm )来识别代表代码的东西,但这不会让你从表达式的一部分或完整的块中区分语句。

查看实际代码的 AST,并了解它是如何工作的。

编辑

观看 a presentation刚刚在 scala/reflecti/api/Trees.scala 的末尾提示了我这条评论文件:
// A standard pattern match
case EmptyTree =>
case PackageDef(pid, stats) =>
// package pid { stats }
case ClassDef(mods, name, tparams, impl) =>
// mods class name [tparams] impl where impl = extends parents { defs }
case ModuleDef(mods, name, impl) => (eliminated by refcheck)
// mods object name impl where impl = extends parents { defs }
case ValDef(mods, name, tpt, rhs) =>
// mods val name: tpt = rhs
// note missing type information is expressed by tpt = TypeTree()
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
// mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs
// note missing type information is expressed by tpt = TypeTree()
case TypeDef(mods, name, tparams, rhs) => (eliminated by erasure)
// mods type name[tparams] = rhs
// mods type name[tparams] >: lo <: hi, where lo, hi are in a TypeBoundsTree,
and DEFERRED is set in mods
case LabelDef(name, params, rhs) =>
// used for tailcalls and like
// while/do are desugared to label defs as follows:
// while (cond) body ==> LabelDef($L, List(), if (cond) { body; L$() } else ())
// do body while (cond) ==> LabelDef($L, List(), body; if (cond) L$() else ())
case Import(expr, selectors) => (eliminated by typecheck)
// import expr.{selectors}
// Selectors are a list of pairs of names (from, to).
// The last (and maybe only name) may be a nme.WILDCARD
// for instance
// import qual.{x, y => z, _} would be represented as
// Import(qual, List(("x", "x"), ("y", "z"), (WILDCARD, null)))
case Template(parents, self, body) =>
// extends parents { self => body }
// if self is missing it is represented as emptyValDef
case Block(stats, expr) =>
// { stats; expr }
case CaseDef(pat, guard, body) => (eliminated by transmatch/explicitouter)
// case pat if guard => body
case Alternative(trees) => (eliminated by transmatch/explicitouter)
// pat1 | ... | patn
case Star(elem) => (eliminated by transmatch/explicitouter)
// pat*
case Bind(name, body) => (eliminated by transmatch/explicitouter)
// name @ pat
case UnApply(fun: Tree, args) (introduced by typer, eliminated by transmatch/explicitouter)
// used for unapply's
case ArrayValue(elemtpt, trees) => (introduced by uncurry)
// used to pass arguments to vararg arguments
// for instance, printf("%s%d", foo, 42) is translated to after uncurry to:
// Apply(
// Ident("printf"),
// Literal("%s%d"),
// ArrayValue(<Any>, List(Ident("foo"), Literal(42))))
case Function(vparams, body) => (eliminated by lambdaLift)
// vparams => body where vparams:List[ValDef]
case Assign(lhs, rhs) =>
// lhs = rhs
case AssignOrNamedArg(lhs, rhs) => (eliminated by typer, resurrected by reifier)
// @annotation(lhs = rhs)
case If(cond, thenp, elsep) =>
// if (cond) thenp else elsep
case Match(selector, cases) =>
// selector match { cases }
case Return(expr) =>
// return expr
case Try(block, catches, finalizer) =>
// try block catch { catches } finally finalizer where catches: List[CaseDef]
case Throw(expr) =>
// throw expr
case New(tpt) =>
// new tpt always in the context: (new tpt).<init>[targs](args)
case Typed(expr, tpt) => (eliminated by erasure)
// expr: tpt
case TypeApply(fun, args) =>
// fun[args]
case Apply(fun, args) =>
// fun(args)
// for instance fun[targs](args) is expressed as Apply(TypeApply(fun, targs), args)
case ApplyDynamic(qual, args) (introduced by erasure, eliminated by cleanup)
// fun(args)
case Super(qual, mix) =>
// qual.super[mix] qual is always This(something), if mix is empty, it is tpnme.EMPTY
case This(qual) =>
// qual.this
case Select(qualifier, selector) =>
// qualifier.selector
case Ident(name) =>
// name
// note: type checker converts idents that refer to enclosing fields or methods
// to selects; name ==> this.name
case ReferenceToBoxed(ident) => (created by typer, eliminated by lambdalift)
// synthetic node emitted by macros to reference capture vars directly without going through ``elem''
// var x = ...; fun { x } will emit Ident(x), which gets transformed to Select(Ident(x), "elem")
// if ReferenceToBoxed were used instead of Ident, no transformation would be performed
case Literal(value) =>
// value
case TypeTree() => (introduced by refcheck)
// a type that's not written out, but given in the tpe attribute
case Annotated(annot, arg) => (eliminated by typer)
// arg @annot for types, arg: @annot for exprs
case SingletonTypeTree(ref) => (eliminated by uncurry)
// ref.type
case SelectFromTypeTree(qualifier, selector) => (eliminated by uncurry)
// qualifier # selector, a path-dependent type p.T is expressed as p.type # T
case CompoundTypeTree(templ: Template) => (eliminated by uncurry)
// parent1 with ... with parentN { refinement }
case AppliedTypeTree(tpt, args) => (eliminated by uncurry)
// tpt[args]
case TypeBoundsTree(lo, hi) => (eliminated by uncurry)
// >: lo <: hi
case ExistentialTypeTree(tpt, whereClauses) => (eliminated by uncurry)
// tpt forSome { whereClauses }

关于scala - 如何从编译器插件中找到 Scala 程序中的语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10419101/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com