transmatcher.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 259 行

SCALA
259
字号
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * Copyright 2007 Google Inc. All Rights Reserved. * Author: bqe@google.com (Burak Emir) */// $Id: TransMatcher.scala 14561 2008-04-09 09:57:10Z odersky $package scala.tools.nsc.matching/** Translation of pattern matching * *  @author Burak Emir */trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with ParallelMatching with CodeFactory =>   import global._  import definitions._  import posAssigner.atPos  import symtab.Flags  import typer.typed  import collection.mutable.ListBuffer  var cunit: CompilationUnit = _ // memory leak?  def fresh = cunit.fresh  var nPatterns = 0  var resultType: Type = _  // cache these  final val settings_debug       = settings.debug.value  final val settings_squeeze     = settings.Xsqueeze.value == "on"  final val settings_casetags    = settings.Xcasetags.value == "on"  final def hasRegularPattern(pats1: List[Tree]): Boolean = {    var pats = pats1; while(pats ne Nil) {      if(isRegularPattern(pats.head)) { return true; } else { pats = pats.tail }    }    return false  }  final def isRegularPattern(pat: Tree): Boolean = {    pat match {      case Alternative(trees)    => hasRegularPattern(trees)      case Star(t)               => true      case Ident(_)              => false      case Bind(n, pat1)         => isRegularPattern(pat1)      case Sequence(trees)       => true // cause there are ArrayValues now      case ArrayValue(tt, trees) => hasRegularPattern(trees)      case Apply(fn, trees)      => hasRegularPattern(trees)      case Literal(_)            => false      case Select(_, _)          => false      case Typed(_, _)           => false      case UnApply(_,trees)      => hasRegularPattern(trees)    }  }  // @todo: this should be isNotRegular :-/ premature opt src of all evil  // check special case Seq(p1,...,pk,_*) where pi not regular  protected def isRightIgnoring(p: ArrayValue): Boolean = {    def isDefaultStar(p: Tree): Boolean = p match {      case Bind(_, q)                 => isDefaultStar(q)      case Star(Ident(nme.WILDCARD))  => true      case _                          => false    }    p match {      case ArrayValue(s, trees) =>        var ts = trees	var c: Tree = null	while ((ts ne Nil) && {c = ts.head; ts = ts.tail; !isRegularPattern(c)}) {}	(ts eq Nil) && isDefaultStar(c)    }  }  /** a casedef with sequence subpatterns like    *   *  case ..x @ ().. => body   *   * should be replaced straight away with    *   *  case    .. () .. => val x = Nil; body   */  def isRegular(pats: List[CaseDef]): (List[CaseDef],Boolean) = {    var existsReg = false    var isReg = false    var nilVars: List[Symbol] = null    def isRegular1(pat: Tree): Tree = pat match {      case Alternative(trees) =>        copy.Alternative(pat, trees map { isRegular1 })            case Star(t) =>        isReg = true; copy.Star(pat, isRegular1(t))           case Ident(_) =>        pat            case Bind(id, empt @ Sequence(List())) =>        nilVars = pat.symbol :: nilVars        empt            case Bind(n, pat1) =>        copy.Bind(pat, n, isRegular1(pat1))            case Sequence(trees) =>        isReg = true        copy.Sequence(pat, trees map { isRegular1 })            case UnApply(fn, args) => copy.UnApply(pat, fn, args map { isRegular1 })          case app @ Apply(fn, List(pat2@ ArrayValue( tt, List(b @ Bind(id, Star(wc @ Ident(nme.WILDCARD))))))) if (app.tpe.typeSymbol.flags & Flags.CASE) == 0 =>        val tpe1:Type = pat2.tpe.widen.baseType( definitions.SeqClass ).typeArgs(0)	val tpe = appliedType(definitions.SeqClass.typeConstructor, List(tpe1))	b.symbol.setInfo(tpe)	b.setType(tpe)        copy.Bind(b, id, wc)          case app @ Apply(fn, List(pat2@ ArrayValue( tt, List(b @ Bind(id, Star(wc @ Ident(nme.WILDCARD))))))) =>  // a pattern of the form MyCaseConstructor(foo@_*)        val tpe1:Type = pat2.tpe.widen.baseType( definitions.SeqClass ).typeArgs(0)	val tpe = appliedType(definitions.SeqClass.typeConstructor, List(tpe1))	b.symbol.setInfo(tpe)	b.setType(tpe)        copy.Apply(pat, fn, List(copy.Bind(b, id, wc)))      case av @ ArrayValue(s, trees) =>        if (isRightIgnoring(av)) pat        else copy.ArrayValue(pat, s, (trees map { isRegular1 }))              case Apply(fn, List(Sequence(List()))) =>        pat      case Apply(fn, trees) =>        copy.Apply(pat, fn, (trees map { isRegular1 }))            case Literal(_) =>        pat            case Select(_, _) =>        pat            case Typed(_, _) =>        pat            case This(_) =>        val stpe = mkThisType(pat.tpe.typeSymbol)        Typed(Ident(nme.WILDCARD) setType stpe, TypeTree(stpe))    }        var res = new ListBuffer[CaseDef]    val it = pats.elements; while (it.hasNext) {      nilVars = Nil      val cdef = it.next      val newt = isRegular1(cdef.pat)      existsReg = existsReg || isReg            val nbody = if (nilVars.isEmpty) cdef.body else        atPos(cdef.body.pos)(          Block(nilVars map {            x => ValDef(x, Ident(definitions.NilModule))          }, cdef.body)        )            res += copy.CaseDef(cdef, newt, cdef.guard, nbody)    }    (res.toList, existsReg)  }                      /** handles all translation of pattern matching   */  def handlePattern(selector: Tree, ocases: List[CaseDef], doCheckExhaustive: Boolean, owner: Symbol, handleOuter: Tree => Tree): Tree = {    val (cases, containsReg) = isRegular(ocases)    // @todo: remove unused variables    if (containsReg) {      cunit.error(selector.pos, "regular expressions not yet implemented")      //sel      EmptyTree    } else {      implicit val theOwner = owner      if (settings_debug) {        Console.println("****")        Console.println("**** initalize, selector = "+selector+" selector.tpe = "+selector.tpe)        Console.println("****    doCheckExhaustive == "+doCheckExhaustive)      }            implicit val rep = new RepFactory(handleOuter)      try {        val tmps = new ListBuffer[Symbol]        val vds  = new ListBuffer[Tree]        var root:Symbol = newVar(selector.pos, selector.tpe)        if (!doCheckExhaustive)          root.setFlag(symtab.Flags.TRANS_FLAG)                var vdef:Tree        = typed{ValDef(root, selector)}        var theFailTree:Tree = ThrowMatchError(selector.pos, mkIdent(root))	        if (definitions.isTupleType(selector.tpe)) selector match {          case app @ Apply(fn, args)           if (fn.symbol eq selector.tpe.decls.lookup(nme.CONSTRUCTOR)) &&          (cases forall { x => x match {            case CaseDef(Apply(fn, pargs),_,_) => true ;            case CaseDef(Ident(nme.WILDCARD),_,_) => true  ;            case _ => false          }}) =>            var i = 0            var as = args            while(as ne Nil) {              val ti = as.head              val v = newVar(ti.pos, cunit.fresh.newName("tp"), selector.tpe.typeArgs(i))              if (!doCheckExhaustive)                v.setFlag(symtab.Flags.TRANS_FLAG)              vds  += typedValDef(v, ti)              tmps += v              i = i + 1              as = as.tail            }          theFailTree = ThrowMatchError(selector.pos, copy.Apply(app, fn, tmps.toList map mkIdent))          case _ =>            tmps += root            vds  += vdef        } else {          tmps += root          vds  += vdef        }        val irep = initRep(tmps.toList, cases, rep)                implicit val fail: Tree = theFailTree	        val mch  = typed{ repToTree(irep)}        var dfatree = typed{Block(vds.toList, mch)}        // cannot use squeezedBlock because of side-effects, see t275             //DEBUG("**** finished\n"+dfatree.toString)        var bx = 0; var cs = cases; while(cs ne Nil) {          if (!rep.isReached(bx)) {            cunit.error(cs.head.asInstanceOf[CaseDef].body.pos, "unreachable code")          }          cs = cs.tail          bx += 1        }        dfatree = rep.cleanup(dfatree)        resetTrav.traverse(dfatree)        return dfatree      } catch {        case e => e.printStackTrace(); throw new FatalError(e.getMessage())      }    }  }                      object resetTrav extends Traverser {    override def traverse(x: Tree): Unit = x match {      case vd @ ValDef(_, _, _, _) =>        if (vd.symbol hasFlag symtab.Flags.SYNTHETIC) {          vd.symbol resetFlag symtab.Flags.TRANS_FLAG          vd.symbol resetFlag symtab.Flags.MUTABLE        }      case _ =>        super.traverse(x)    }  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?