parallelmatching.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,405 行 · 第 1/4 页
SCALA
1,405 行
// `typeRef(definitions.ScalaPackageClass.tpe, definitions.EqualsPatternClass, List(stpe))' // and force an equality check. However, exhaustivity checking would not work anymore. // so first, extend exhaustivity check to equalspattern } val p = Ident(nme.WILDCARD) setType tpe val q = Typed(p, TypeTree(tpe)) setType tpe pats = (makeBind( vs, q) setType tpe) :: pats case o @ Select(stor,_) => DBG("Select") val stpe = if (!o.symbol.isValue) { singleType(o.tpe.prefix, o.symbol) } else { singleType(NoPrefix, o.symbol) // equals-check } val p = Ident(nme.WILDCARD) setType stpe val q = makeBind(vs,Typed(p, TypeTree(stpe)) setType stpe) setType stpe pats = q::pats case UnApply(Apply(TypeApply(sel @ Select(stor, nme.unapplySeq),List(tptArg)),_),ArrayValue(_,xs)::Nil) if (stor.symbol eq definitions.ListModule) => DBG("Unapply(...TypeApply...)") //@pre: is not right-ignoring (no star pattern) // no exhaustivity check, please temp(j).setFlag(symtab.Flags.TRANS_FLAG) val listType = typeRef(mkThisType(definitions.ScalaPackage), definitions.ListClass, List(tptArg.tpe)) val nmlzdPat = normalizedListPattern(xs, tptArg.tpe) pats = makeBind(vs, nmlzdPat) :: pats //@todo: rewrite, using __UnApply instead of UnApply like so: //case ua @ __UnApply(_,argtpe,_) => //val ua = prepat // val npat = (if (temp(j).tpe <:< argtpe) ua else Typed(ua,TypeTree(argtpe)).setType(argtpe)) // pats = (makeBind(vs, npat) setType argtpe)::pats case ua @ UnApply(Apply(fn, _), _) => DBG("Unapply(Apply())") fn.tpe match { case MethodType(List(argtpe,_*),_) => val npat = (if (temp(j).tpe <:< argtpe) ua else Typed(ua,TypeTree(argtpe)).setType(argtpe)) pats = (makeBind(vs, npat) setType argtpe)::pats } case o @ Apply(fn, List()) if !isCaseClass(o.tpe) || /*see t301*/ !Apply_Value.unapply(o).isEmpty => DBG("Apply !isCaseClass") val stpe: Type = fn match { case _ if (o.symbol.isModule) => singleType(o.tpe.prefix, o.symbol) case _ if (o.tpe.termSymbol.isModule) => singleType(o.tpe.prefix, o.symbol) case Select(path,sym) => path.tpe match { case ThisType(sym) => singleType(path.tpe, o.symbol) case _ => // e.g. `case Some(p._2)' in scala.collection.jcl.Map if (path.isInstanceOf[Apply]) new PseudoType(o) // outer-matching, see test/files/pos/t154.scala else singleType(singleType(path.tpe.prefix, path.symbol), o.symbol) // old } case o @ Ident(_) => if (!o.symbol.isValue) singleType(o.tpe.prefix, o.symbol) else singleType(NoPrefix, o.symbol) } val ttst = typeRef(NoPrefix, definitions.EqualsPatternClass, List(stpe)) val p = Ident(nme.WILDCARD) setType ttst val q = makeBind(vs,Typed(p, TypeTree(stpe)) setType ttst) pats = q::pats case Apply_Value(pre, sym) => DBG("Apply_Value") val tpe = typeRef(NoPrefix, definitions.EqualsPatternClass, singleType(pre, sym)::Nil) val q = makeBind(vs,Typed(EmptyTree, TypeTree(tpe)) setType tpe) pats = q :: pats case Apply_CaseClass_NoArgs(tpe) => // no-args case class pattern DBG("Apply_CaseClass_NoArgs") val q = makeBind(vs, Typed(EmptyTree, TypeTree(tpe)) setType tpe) pats = q :: pats case Apply_CaseClass_WithArgs() => // case class pattern with args DBG("Apply_CaseClass_WithArgs") pats = opat :: pats case ArrayValue(_,xs) => DBG("ArrayValue") pats = opat :: pats } opats = opats.tail j += 1 } pats = pats.reverse if (indexOfAlternative == -1) { val res = List(Row(pats, subst, g, bx)) DBG("finished: result "+res) res } else { val prefix = pats.take( indexOfAlternative ) val alts = getAlternativeBranches(pats( indexOfAlternative )) val suffix = pats.drop(indexOfAlternative + 1) val intermediary_result = alts map { p => Row(prefix ::: p :: suffix, subst, g, bx) } DBG("not finished: intermediary_result = "+intermediary_result) intermediary_result } } if (unchanged) { val ri = RepImpl(temp,row).init ri } else { this.make(temp,row) // recursive call } }} abstract class Rep { val temp:List[Symbol] val row:List[Row] var sealedCols = List[Int]() var sealedComb = List[Set[Symbol]]() final def init: this.type = { temp.zipWithIndex.foreach { case (sym,i) => if (sym.hasFlag(symtab.Flags.MUTABLE) && // indicates that have not yet checked exhaustivity !sym.hasFlag(symtab.Flags.TRANS_FLAG) && // indicates @unchecked sym.tpe.typeSymbol.hasFlag(symtab.Flags.SEALED)) { sym.resetFlag(symtab.Flags.MUTABLE) sealedCols = i::sealedCols // this should enumerate all cases... however, also the superclass is taken if it is not abstract def candidates(tpesym: Symbol): SymSet = if (!tpesym.hasFlag(symtab.Flags.SEALED)) emptySymbolSet else tpesym.children.flatMap { x => val z = candidates(x) if (x.hasFlag(symtab.Flags.ABSTRACT)) z else z + x } val cases = candidates(sym.tpe.typeSymbol) sealedComb = cases::sealedComb } } // computes cartesian product, keeps indices available def combine(colcom: List[(Int,Set[Symbol])]): List[List[(Int,Symbol)]] = colcom match { case Nil => Nil case (i,syms)::Nil => syms.toList.map { sym => List((i,sym)) } case (i,syms)::cs => for (s <- syms.toList; rest <- combine(cs)) yield (i,s) :: rest } if (!sealedCols.isEmpty) { val allcomb = combine(sealedCols zip sealedComb) /** returns true if pattern vector pats covers a type symbols "combination" * @param pats pattern vector * @param comb pairs of (column index, type symbol) */ def covers(pats: List[Tree], comb:List[(Int,Symbol)]) = comb forall { case (i,sym) => val p = strip2(pats(i)); val res = isDefaultPattern(p) || p.isInstanceOf[UnApply] || p.isInstanceOf[ArrayValue] || { val ptpe = patternType_wrtEquals(p.tpe) val symtpe = if (sym.hasFlag(symtab.Flags.MODULE) && (sym.linkedModuleOfClass ne NoSymbol)) { singleType(sym.tpe.prefix, sym.linkedModuleOfClass) // e.g. None, Nil } else sym.tpe (ptpe.typeSymbol == sym) || (symtpe <:< ptpe) || (symtpe.parents.exists(_.typeSymbol eq ptpe.typeSymbol)) || // e.g. Some[Int] <: Option[&b] /* outer, see scala.util.parsing.combinator.lexical.Scanner */ (ptpe.prefix.memberType(sym) <:< ptpe) } res } val coversAll = allcomb forall { combination => row exists { r => (r.guard eq EmptyTree) && covers(r.pat, combination)}} if (!coversAll) { val sb = new StringBuilder() sb.append("match is not exhaustive!\n") for (open <- allcomb if !(row exists { r => covers(r.pat, open)})) { sb.append("missing combination ") val NPAD = 15 def pad(s:String) = { 1.until(NPAD - s.length).foreach { x => sb.append(" ") }; sb.append(s) } List.range(0, temp.length) foreach { i => open.find { case (j,sym) => j==i } match { case None => pad("*") case Some((_,sym)) => pad(sym.name.toString) } } sb.append('\n') } cunit.warning(temp.head.pos, sb.toString) } } return this } /* internal representation is (temp:List[Symbol], row:List[Row]) * * tmp1 tmp_m */ final def applyRule(implicit theOwner: Symbol, rep: RepFactory): RuleApplication = row match { case Nil => ErrorRule() case Row(pats, subst, g, bx)::xs => var px = 0; var rpats = pats; var bnd = subst; var temps = temp; while((bnd ne null) && (rpats ne Nil)) { val (vs,p) = strip(rpats.head); if (!isDefaultPattern(p)) { /*break*/ bnd = null; } else { bnd = bnd.add(vs.elements,temps.head) rpats = rpats.tail temps = temps.tail px += 1 // pattern index } } /* Row( _ ... _ g_1 b_1 ) :: rows it's all default patterns */ if (bnd ne null) { // all default patterns val rest = if (g eq EmptyTree) null else rep.make(temp, xs) DBG("\n---\nmixture rule is = VariableRule") return VariableRule (bnd, g, rest, bx) } /* Row( _ ... _ p_1i ... p_1n g_m b_m ) :: rows */ // cut out column px that contains the non-default pattern val column = rpats.head :: (row.tail map { case Row(pats,_,_,_) => pats(px) }) val restTemp = temp.take(px) ::: temp.drop(px+1) val restRows = row map { case Row(pats, subst, g, bx) => Row(pats.take(px) ::: pats.drop(px+1), subst, g, bx) } val mr = MixtureRule(temps.head, column, rep.make(restTemp,restRows)) DBG("\n---\nmixture rule is = "+mr.getClass.toString) mr } // a fancy toString method for debugging override final def toString = { val sb = new StringBuilder val NPAD = 15 def pad(s:String) = { 1.until(NPAD - s.length).foreach { x => sb.append(" ") }; sb.append(s) } for (tmp <- temp) pad(tmp.name.toString) sb.append('\n') for ((r,i) <- row.zipWithIndex) { for (c <- r.pat ::: List(r.subst, r.guard, r.bx)) { pad(c.toString) } sb.append('\n') } sb.toString } /* def toString */ } /* class Rep */ /** creates initial clause matrix */ final def initRep(roots: List[Symbol], cases: List[Tree], rep:RepFactory)(implicit theOwner: Symbol) = { // communicate whether exhaustiveness-checking is enabled via some flag var bx = 0; val targets = new ListBuffer[Tree] val vss = new ListBuffer[SymList] val row = new ListBuffer[Row] var cs = cases; while (cs ne Nil) cs.head match { // stash away pvars and bodies for later case CaseDef(pat,g,b) => vss += definedVars(pat) targets += b if (roots.length > 1) pat match { case Apply(fn, pargs) => row += Row(pargs, NoBinding, g, bx) case Ident(nme.WILDCARD) => row += Row(getDummies(roots.length), NoBinding, g, bx) } else row += Row(List(pat), NoBinding, g, bx) bx += 1 cs = cs.tail } rep.make(roots, row.toList, targets.toList, vss.toList) } final def newVar(pos: Position, name: Name, tpe: Type)(implicit theOwner: Symbol): Symbol = { if (tpe eq null) assert(tpe ne null, "newVar("+name+", null)") val sym = theOwner.newVariable(pos, name) // careful: pos has special meaning sym setInfo tpe sym } final def newVar(pos: Position, tpe: Type)(implicit theOwner: Symbol): Symbol = newVar(pos, cunit.fresh.newName("temp"), tpe) setFlag symtab.Flags.SYNTHETIC /** returns the condition in "if (cond) k1 else k2" */ final def condition(tpe: Type, scrut: Symbol): Tree = { assert(scrut ne NoSymbol) condition(tpe, mkIdent(scrut)) } final def condition(tpe: Type, scrutineeTree: Tree): Tree = { assert(tpe ne NoType) assert(scrutineeTree.tpe ne NoType) if (tpe.isInstanceOf[SingletonType] && !tpe.isInstanceOf[ConstantType]) { if (tpe.termSymbol.isModule) {// object //if (scrutineeTree.tpe <:< definitions.AnyRefClass.tpe) // Eq(gen.mkAttributedRef(tpe.termSymbol), scrutineeTree) // object //else Equals(gen.mkAttributedRef(tpe.termSymbol), scrutineeTree) // object } else { val x = if (tpe.prefix ne NoPrefix) gen.mkIsInstanceOf(scrutineeTree, tpe) else Equals(gen.mkAttributedRef(tpe.termSymbol), scrutineeTree) typed { x } } } else if (tpe.isInstanceOf[ConstantType]) { val value = tpe.asInstanceOf[ConstantType].value if (value == Constant(null) && scrutineeTree.tpe <:< definitions.AnyRefClass.tpe) Eq(scrutineeTree, Literal(value)) // constant else Equals(scrutineeTree, Literal(value)) // constant } else if (scrutineeTree.tpe <:< tpe && tpe <:< definitions.AnyRefClass.tpe) { NotNull(scrutineeTree) } else { gen.mkIsInstanceOf(scrutineeTree, tpe) } } /** adds a test comparing the dynamic outer to the static outer */ final def addOuterCondition(cond:Tree, tpe2test: Type, scrutinee: Tree, handleOuter: Tree=>Tree) = { val TypeRef(prefix,_,_) = tpe2test assert(prefix ne NoPrefix) var theRef = prefix match { case ThisType(clazz) => gen.mkAttributedThis(clazz) case _ => gen.mkAttributedRef(prefix.prefix, prefix.termSymbol) } // needs explicitouter treatment theRef = handleOuter(theRef) val outerAcc = outerAccessor(tpe2test.typeSymbol) if (outerAcc == NoSymbol) { if (settings_debug) cunit.warning(scrutinee.pos, "no outer acc for "+tpe2test.typeSymbol) cond } else And(cond, Eq(Apply(Select( gen.mkAsInstanceOf(scrutinee, tpe2test, true), outerAcc),List()), theRef)) } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?