etaexpansion.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 130 行
SCALA
130 行
/* NSC -- new Scala compiler * Copyright 2005-2006 LAMP/EPFL * @author Martin Odersky */// $Id: EtaExpansion.scala 14543 2008-04-07 15:57:07Z odersky $package scala.tools.nsc.typecheckerimport scala.collection.mutable.ListBufferimport symtab.Flags._/** This trait ... * * @author Martin Odersky * @version 1.0 */trait EtaExpansion { self: Analyzer => import global._ import posAssigner.atPos object etaExpansion { def unapply(tree: Tree): Option[(List[ValDef], Tree, List[Tree])] = tree match { case Function(vparams, Apply(fn, args)) if (List.forall2(vparams, args) { case (vparam, Ident(name)) => vparam.name == name case _ => false }) => Some((vparams, fn, args)) case _ => None } } /** <p> * Expand partial function applications of type <code>type</code>. * </p><pre> * p.f(es_1)...(es_n) * ==> { * <b>private synthetic val</b> eta$f = p.f // if p is not stable * ... * <b>private synthetic val</b> eta$e_i = e_i // if e_i is not stable * ... * (ps_1 => ... => ps_m => eta$f([es_1])...([es_m])(ps_1)...(ps_m)) * }</pre> * <p> * tree is already attributed * </p> */ def etaExpand(unit : CompilationUnit, tree: Tree): Tree = { val tpe = tree.tpe val symbolHash = if (!inIDE) "" else Integer.toString(tree.symbol.hashCode, 10 + ('z' - 'a')) + "$" var cnt = 0 // for NoPosition def freshName(pos : util.Position, n : Int) = { cnt += 1 if (!inIDE) { newTermName(unit.fresh.newName(pos, "eta$" + (cnt - 1) + "$")) } else if (pos == util.NoPosition) { // nothing we can do, hope for no conflict! newTermName(("eta$" + symbolHash + (cnt - 1))) } else newTermName(unit.fresh.newName(pos, "eta$" + symbolHash + (cnt - 1) + "$")) // Martin to Sean: I removed the // else if (n == 0) branch and changed `n' in the line above to `(cnt - 1)' // this was necessary because otherwise curried eta-expansions would get the same // symbol. An example which failes test/files/run/Course-2002-02.scala // todo: review and get rid of the `n' argument (which is unused right now). } // { cnt = cnt + 1; newTermName("eta$" + cnt) } val defs = new ListBuffer[Tree] /** Append to <code>defs</code> value definitions for all non-stable * subexpressions of the function application <code>tree</code>. * * @param tree ... * @return ... */ def liftoutPrefix(tree: Tree): Tree = { def liftout(tree: Tree): Tree = if (treeInfo.isPureExpr(tree)) tree else { val vname: Name = freshName(tree.pos, 0) defs += atPos(tree.pos)(ValDef(Modifiers(SYNTHETIC), vname, TypeTree(), tree)) Ident(vname) setPos tree.pos } tree match { case Apply(fn, args) => copy.Apply(tree, liftoutPrefix(fn), List.mapConserve(args)(liftout)) setType null case TypeApply(fn, args) => copy.TypeApply(tree, liftoutPrefix(fn), args) setType null case Select(qual, name) => copy.Select(tree, liftout(qual), name) setSymbol NoSymbol setType null case Ident(name) => tree } } /** Eta-expand lifted tree. * * @param tree ... * @param tpe ... * @return ... */ def expand(tree: Tree, tpe: Type): Tree = tpe match { case mt: ImplicitMethodType => tree case MethodType(formals, restpe) => var cnt0 = 0 def cnt = { cnt0 += 1 cnt0 - 1 } val params = formals map (formal => ValDef(Modifiers(SYNTHETIC | PARAM), freshName(tree.pos, cnt), TypeTree() .setType(formal), EmptyTree)) val args = params map (param => Ident(param.name)) val applyArgs = if (isVarArgs(formals)) args.init ::: Typed(args.last, Ident(nme.WILDCARD_STAR.toTypeName)) :: Nil else args atPos(tree.pos)(Function(params, expand(Apply(tree, applyArgs), restpe))) //atPos(tree.pos)(Function(params, expand(Apply(tree, args), restpe))) case _ => tree } val tree1 = liftoutPrefix(tree) atPos(tree.pos)(Block(defs.toList, expand(tree1, tpe))) }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?