From 0fdee8b11ce7451f63e7825e2b4886c66bc982f4 Mon Sep 17 00:00:00 2001 From: Burak Emir Date: Tue, 14 Aug 2007 09:23:15 +0000 Subject: restructuring pattern translation (rewrite rule... restructuring pattern translation (rewrite rule result to tree), small opts --- .../tools/nsc/matching/ParallelMatching.scala | 524 +++++++++------------ .../scala/tools/nsc/matching/PatternMatchers.scala | 9 +- .../scala/tools/nsc/matching/PatternNodes.scala | 41 +- 3 files changed, 263 insertions(+), 311 deletions(-) diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 4d3e984266..8de2ce2e27 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -22,65 +22,27 @@ trait ParallelMatching { import typer.typed import symtab.Flags - def isCaseClass(tpe: Type) = - tpe match { - case TypeRef(_, sym, _) => - if(!sym.isAliasType) - sym.hasFlag(symtab.Flags.CASE) - else - tpe.normalize.typeSymbol.hasFlag(symtab.Flags.CASE) - case _ => false - } - - def isEqualsPattern(tpe: Type) = - tpe match { - case TypeRef(_, sym, _) => sym eq definitions.EqualsPatternClass - case _ => false - } - - // ---------------------------------- data - - sealed trait RuleApplication { - def scrutinee:Symbol - } - case class ErrorRule extends RuleApplication { - def scrutinee:Symbol = throw new RuntimeException("this never happens") - } - case class VariableRule(subst:Binding, guard: Tree, guardedRest:Rep, bx: Int) extends RuleApplication { - def scrutinee:Symbol = throw new RuntimeException("this never happens") - } - /** here, we distinguish which rewrite rule to apply */ def MixtureRule(scrutinee:Symbol, column:List[Tree], rest:Rep): RuleApplication = { def isSimpleIntSwitch: Boolean = { (isSameType(scrutinee.tpe.widen, definitions.IntClass.tpe)/*|| isSameType(scrutinee.tpe.widen, definitions.CharClass.tpe)*/) && { - var xs = column - while(!xs.isEmpty) { // forall + var xs = column; while(!xs.isEmpty) { // forall val h = xs.head if(h.isInstanceOf[Literal] || isDefaultPattern(h)) { xs = xs.tail } else return false } - return true - }} + return true + }} // an unapply for which we don't need a type test def isUnapplyHead: Boolean = { def isUnapply(x:Tree): Boolean = x match { case Bind(_,p) => isUnapply(p) case UnApply(Apply(fn,_),arg) => fn.tpe match { - case MethodType(List(argtpe,_*),_) => - //Console.println("scrutinee.tpe "+scrutinee.tpe) - //Console.println("argtpe "+argtpe) - val r = scrutinee.tpe <:< argtpe - //Console.println("<: ???"+r) - r - case _ => - //Console.println("wrong tpe") - false + case MethodType(List(argtpe,_*),_) => scrutinee.tpe <:< argtpe + case _ => /* Console.println("wrong tpe, needs type test"); */ false } - case x => - //Console.println("is something else"+x+" "+x.getClass) - false + case x => /*Console.println("is something else"+x+" "+x.getClass) */ false } isUnapply(column.head) } @@ -109,43 +71,63 @@ trait ParallelMatching { false } } - //def containsUnapply = column exists { _.isInstanceOf[UnApply] } /* - if(settings_debug) { - Console.println("/// MixtureRule("+scrutinee.name+":"+scrutinee.tpe+","+column+", rep = ") - Console.println(rest) - Console.println(")///") - } - */ - if(isEqualsPattern(column.head.tpe)) { - if(settings_debug) { Console.println("\n%%% MixEquals") } + DBG("/// MixtureRule("+scrutinee.name+":"+scrutinee.tpe+","+column+", rep = ") + DBG(rest) + DBG(")///") + */ + if(isEqualsPattern(column.head.tpe)) { DBG("\n%%% MixEquals"); return new MixEquals(scrutinee, column, rest) } - - if(isSimpleIntSwitch) { - if(settings_debug) { Console.println("\n%%% MixLiterals") } + if(column.head.isInstanceOf[ArrayValue]) { DBG("\n%%% MixArrayValue"); + Console.println("STOP"); System.exit(-1); // EXPERIMENTAL + //return new MixArrayValue(scrutinee, column, rest) + } + if(isSimpleIntSwitch) { DBG("\n%%% MixLiterals") return new MixLiterals(scrutinee, column, rest) } if(settings_casetags && (column.length > 1) && isFlatCases(column)) { - if(settings_debug) { - Console.println("flat cases!"+column) - Console.println(scrutinee.tpe.typeSymbol.children) - Console.println(scrutinee.tpe.member(nme.tag)) - //Console.println(column.map { x => x.tpe./*?type?*/symbol.tag }) - } - if(settings_debug) { Console.println("\n%%% MixCases") } + DBG("flat cases!"+column+"\n"+scrutinee.tpe.typeSymbol.children+"\n"+scrutinee.tpe.member(nme.tag)) + DBG("\n%%% MixCases") return new MixCases(scrutinee, column, rest) // if(scrutinee.tpe./*?type?*/symbol.hasFlag(symtab.Flags.SEALED)) new MixCasesSealed(scrutinee, column, rest) // else new MixCases(scrutinee, column, rest) } - //Console.println("isUnapplyHead") - if(isUnapplyHead) { - if(settings_debug) { Console.println("\n%%% MixUnapply") } + if(isUnapplyHead) { DBG("\n%%% MixUnapply") return new MixUnapply(scrutinee, column, rest) } - if(settings_debug) { Console.println("\n%%% MixTypes") } + DBG("\n%%% MixTypes") return new MixTypes(scrutinee, column, rest) // todo: handle type tests in unapply + } /* def MixtureRule(scrutinee:Symbol, column:List[Tree], rest:Rep): RuleApplication */ + + // ---------------------------------- data + + sealed trait RuleApplication { + def scrutinee:Symbol + /** translate outcome of the rule application into code (possible involving recursive application of rewriting) */ + def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree): Tree + } + + case class ErrorRule extends RuleApplication { + def scrutinee:Symbol = throw new RuntimeException("this never happens") + final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = failTree + } + + case class VariableRule(subst:Binding, guard: Tree, guardedRest:Rep, bx: Int) extends RuleApplication { + def scrutinee:Symbol = throw new RuntimeException("this never happens") + final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree): Tree = { + val body = typed { Rep.requestBody(bx, subst) } + if(guard eq EmptyTree) + return body + + val vdefs = targetParams(subst) + val typedElse = repToTree(guardedRest, handleOuter) + val untypedIf = makeIf(guard, body, typedElse) + val r = atPhase(phase.prev) { typed { squeezedBlock(vdefs, untypedIf) }} + //Console.println("genBody-guard:"+r) + r + } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */ } @@ -208,13 +190,9 @@ trait ParallelMatching { trs } - protected def defaultsToRep = { - Rep(rest.temp, getDefaultRows) - } + protected def defaultsToRep = Rep(rest.temp, getDefaultRows) - protected def insertTagIndexPair(tag: Int, index: Int) { - tagIndexPairs = TagIndexPair.insert(tagIndexPairs, tag, index) - } + protected def insertTagIndexPair(tag: Int, index: Int) { tagIndexPairs = TagIndexPair.insert(tagIndexPairs, tag, index) } /** returns * @return list of continuations, @@ -223,7 +201,7 @@ trait ParallelMatching { **/ def getTransition(implicit theOwner: Symbol): (List[(Int,Rep)],Set[Symbol],Option[Rep]) = (tagIndicesToReps, defaultV, {if(haveDefault) Some(defaultsToRep) else None}) - } + } /* CaseRuleApplication */ /** * mixture rule for flat case class (using tags) @@ -234,9 +212,7 @@ trait ParallelMatching { /** insert row indices using in to list of tagindexpairs */ { - var xs = column - var i = 0 - while(xs ne Nil) { // forall + var xs = column; var i = 0; while(xs ne Nil) { // forall val p = strip2(xs.head) if(isDefaultPattern(p)) insertDefault(i,strip1(xs.head)) @@ -254,7 +230,46 @@ trait ParallelMatching { Row(column(tagIndexPairs.index)::pats, nbindings, g, bx) } - } + final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = { + val (branches, defaultV, default) = getTransition // tag body pairs + DBG("[[mix cases transition: branches \n"+(branches.mkString("","\n","")+"\ndefaults:"+defaultV+" "+default+"]]")) + + var ndefault = if(default.isEmpty) failTree else repToTree(default.get, handleOuter) + var cases = branches map { + case (tag, rep) => + CaseDef(Literal(tag), + EmptyTree, + { + val pat = this.column(this.tagIndexPairs.find(tag)); + val ptpe = pat.tpe + if(this.scrutinee.tpe.typeSymbol.hasFlag(symtab.Flags.SEALED) && strip2(pat).isInstanceOf[Apply]) { + //cast + val vtmp = newVar(pat.pos, ptpe) + squeezedBlock( + List(typedValDef(vtmp, gen.mkAsInstanceOf(Ident(this.scrutinee),ptpe))), + repToTree(Rep(vtmp::rep.temp.tail, rep.row),handleOuter) + ) + } else repToTree(rep, handleOuter) + } + )} + + renamingBind(defaultV, this.scrutinee, ndefault) // each v in defaultV gets bound to scrutinee + + // make first case a default case. + if(this.scrutinee.tpe.typeSymbol.hasFlag(symtab.Flags.SEALED) && defaultV.isEmpty) { + ndefault = cases.head.body + cases = cases.tail + } + + cases.length match { + case 0 => ndefault + case 1 => val CaseDef(lit,_,body) = cases.head + makeIf(Equals(Select(Ident(this.scrutinee),nme.tag),lit), body, ndefault) + case _ => val defCase = CaseDef(mk_(definitions.IntClass.tpe), EmptyTree, ndefault) + Match(Select(Ident(this.scrutinee),nme.tag), cases ::: defCase :: Nil) + } + } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */ + } /* MixCases */ /** * mixture rule for flat case class (using tags) @@ -276,8 +291,7 @@ trait ParallelMatching { private var defaultIndexSet: Set64 = if(column.length < 64) new Set64 else null override def insertDefault(tag: Int, vs: Set[Symbol]): Unit = - if(defaultIndexSet eq null) - super.insertDefault(tag,vs) + if(defaultIndexSet eq null) super.insertDefault(tag,vs) else { defaultIndexSet |= tag defaultV = defaultV ++ vs @@ -324,7 +338,25 @@ trait ParallelMatching { } } - } + final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = { + val (branches, defaultV, defaultRepOpt) = this.getTransition // tag body pairs + DBG("[[mix literal transition: branches \n"+(branches.mkString("","\n",""))+"\ndefaults:"+defaultV+"\n"+defaultRepOpt+"\n]]") + val cases = branches map { case (tag, rep) => CaseDef(Literal(tag), EmptyTree, repToTree(rep, handleOuter)) } + var ndefault = if(defaultRepOpt.isEmpty) failTree else repToTree(defaultRepOpt.get, handleOuter) + + renamingBind(defaultV, this.scrutinee, ndefault) // each v in defaultV gets bound to scrutinee + if(cases.length == 1) { + val CaseDef(lit,_,body) = cases.head + makeIf(Equals(Ident(this.scrutinee),lit), body, ndefault) + } else { + val defCase = CaseDef(mk_(definitions.IntClass.tpe), EmptyTree, ndefault) + var selector:Tree = Ident(this.scrutinee) + if(isSameType(this.scrutinee.tpe.widen, definitions.CharClass.tpe)) + selector = gen.mkAsInstanceOf(selector, definitions.IntClass.tpe) + Match(selector, cases ::: defCase :: Nil) + } + } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */ + } /* MixLiterals */ /** * mixture rule for unapply pattern @@ -413,8 +445,21 @@ trait ParallelMatching { }} (uacall, rootvdefs:::vdefs.reverse, Rep(ntemps, nrows), nrepFail) }} - } - } + } /* def getTransition(...) */ + + final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = { + val (uacall/*:ValDef*/ , vdefs,srep,frep) = this.getTransition // uacall is a Valdef + //Console.println("getTransition"+(uacall,vdefs,srep,frep)) + val succ = repToTree(srep, handleOuter) + val fail = if(frep.isEmpty) failTree else repToTree(frep.get, handleOuter) + val cond = + if(uacall.symbol.tpe.typeSymbol eq definitions.BooleanClass) + typed{ Ident(uacall.symbol) } + else + emptynessCheck(uacall.symbol) + typed { squeezedBlock(List(handleOuter(uacall)), makeIf(cond,squeezedBlock(vdefs,succ),fail)) } + } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */ + } /* MixUnapply */ class MixEquals(val scrutinee:Symbol, val column:List[Tree], val rest:Rep) extends RuleApplication { final def getTransition(implicit theOwner: Symbol): (Tree, Rep, Rep) = { @@ -437,7 +482,33 @@ trait ParallelMatching { val nfail = Rep(scrutinee::rest.temp, nfailrow.toList) return (typed{ Equals(Ident(scrutinee) setType scrutinee.tpe, vlue) }, rest, nfail) } - } + + final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = { + handleOuter(Ident("GAGA")) + val (cond,srep,frep) = this.getTransition + val cond2 = try{ + typed { handleOuter(cond) } + } catch { + case e => + Console.println("failed to type-check cond2") + Console.println("cond: "+cond) + Console.println("cond2: "+handleOuter(cond)) + throw e + } + + val succ = repToTree(srep, handleOuter) + val fail = repToTree(frep, handleOuter) + try { + typed{ If(cond2, succ, fail) } + } catch { + case e => + Console.println("failed to type-check If") + Console.println("cond2: "+cond2) + throw e + } + } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */ + } /* MixEquals */ + /** * mixture rule for type tests **/ @@ -568,8 +639,6 @@ trait ParallelMatching { casted.setFlag(symtab.Flags.CAPTURED) // succeeding => transition to translate(subsumed) (taking into account more specific) val nmatrix = { - //Console.println("casted:"+casted) - //Console.println("casted.case:"+casted.tpe./*?type?*/symbol.hasFlag(symtab.Flags.CASE)) var ntemps = if(isCaseClass(casted.tpe)) casted.caseFieldAccessors map { meth => val ctemp = newVar(scrutinee.pos, casted.tpe.memberType(meth).resultType) @@ -579,238 +648,88 @@ trait ParallelMatching { } else Nil // (***) var subtests = subsumed -//var moreSpecificIndices:Option[List[Int]] = None - - //Console.println("subtests BEFORE "+subtests) if(moreSpecific.exists { x => x != EmptyTree }) { - //moreSpecificIndices = Some(Nil) ntemps = casted::ntemps // (***) subtests = moreSpecific.zip(subsumed) map { - case (mspat, (j,pats)) => - //moreSpecificIndices = Some(j::moreSpecificIndices) - (j,mspat::pats) + case (mspat, (j,pats)) => (j,mspat::pats) } - //Console.println("more specific, subtests "+subtests) } ntemps = ntemps ::: rest.temp val ntriples = subtests map { case (j,pats) => val (vs,thePat) = strip(column(j)) val Row(opats, osubst, og, bx) = rest.row(j) - val subst1 = //if(!moreSpecificIndices.isEmpty && moreSpecificIndices.contains(j)) Nil /*morespecific?*/ else - vs.toList map { v => (v,casted) } - //Console.println("j = "+j) - //Console.println("pats:"+pats) - //Console.println("opats:"+pats) - //debug - // don't substitute eagerly here, problems with bodies that can - // be reached with several routes... impossible to find one-fits-all ordering. - + val subst1 = vs.toList map { v => (v,casted) } Row(pats ::: opats, subst1 ::: osubst, og, bx) - - // BTW duplicating body/guard, gets you "defined twice" error cause hashing breaks - } - if(settings_debug) { - Console.println("ntemps = "+ntemps.mkString("[["," , ","]]")) - Console.println("ntriples = "+ntriples.mkString("[[\n","\n, ","\n]]")) } + DBG("ntemps = "+ntemps.mkString("[["," , ","]]")) + DBG("ntriples = "+ntriples.mkString("[[\n","\n, ","\n]]")) Rep(ntemps, ntriples) /*setParent this*/ } // fails => transition to translate(remaining) val nmatrixFail: Option[Rep] = { val ntemps = scrutinee :: rest.temp - //Console.println("nmatrixfail ntemps:"+ntemps) val ntriples = remaining map { case (j, pat) => val r = rest.row(j); Row(pat :: r.pat, r.subst, r.guard, r.bx) } - //Console.println("nmatrixfail triples:"+ntriples) - if(ntriples.isEmpty) None else Some(Rep(ntemps, ntriples) /*setParent this*/) - } - if(!nmatrixFail.isEmpty) { - //DEBUG("nmatrix for failing type test "+patternType) - //DEBUG(nmatrixFail.get.toString) - } else { - //DEBUG("pattern type "+patternType+" cannot fail for "+scrutinee) + if(ntriples.isEmpty) None else Some(Rep(ntemps, ntriples)) } (casted, nmatrix, nmatrixFail) - } // end getTransitions - } + } /* getTransition(implicit theOwner: Symbol): (Symbol, Rep, Option[Rep]) */ + final def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) = { + val (casted,srep,frep) = this.getTransition + val condUntyped = condition(casted.tpe, this.scrutinee) + var cond = handleOuter(typed { condUntyped }) // <- throws exceptions in some situations? + if(needsOuterTest(casted.tpe, this.scrutinee.tpe)) // @todo merge into def condition + cond = addOuterCondition(cond, casted.tpe, typed{Ident(this.scrutinee)}, handleOuter) - final def genBody(subst: Binding, guard:Tree, rest:Tree, bx:Int)(implicit theOwner: Symbol): Tree = { - //Rep.markReached(bx) // for unreachable-code-detection + val succ = repToTree(srep, handleOuter) - val rbody = typed { Rep.requestBody( bx, subst ) } - val vdefs = targetParams(subst) + val fail = if(frep.isEmpty) failTree else repToTree(frep.get, handleOuter) - val typedThen = rbody // origbody//typed{origbody.duplicate} + // dig out case field accessors that were buried in (***) + val cfa = casted.caseFieldAccessors + val caseTemps = (if(!srep.temp.isEmpty && srep.temp.head == casted) srep.temp.tail else srep.temp).zip(cfa) - //Console.println("typedThen = "+typedThen); - val typedElse = rest//typed{rest} - //Console.println("typedElse = "+typedElse); - val untypedIf = makeIf(guard, typedThen, typedElse) - //Console.println("typedIf = "+typedIf); - //val typedBlock = typed{ squeezedBlock(vdefs, typedIf) } - //Console.println("typedBlock= "+typedBlock); - //typedBlock - val r = atPhase(phase.prev) { typed { squeezedBlock(vdefs, untypedIf) }} - //Console.println("genBody-guard:"+r) - r - } + //DEBUG("case temps"+caseTemps.toString) + var vdefs = caseTemps map { + case (tmp,meth) => + val typedAccess = typed { Apply(Select(typed{Ident(casted)}, meth),List()) } + typedValDef(tmp, typedAccess) + } - final def genBody(subst: Binding, bx:Int)(implicit theOwner: Symbol): Tree = { - typed{ Rep.requestBody(bx, subst) } - } + if(casted ne this.scrutinee) { + vdefs = ValDef(casted, gen.mkAsInstanceOf(typed{Ident(this.scrutinee)}, casted.tpe)) :: vdefs + } + typed { makeIf(cond, squeezedBlock(vdefs,succ), fail) } + } /* def tree(implicit handleOuter: Tree=>Tree, theOwner: Symbol, failTree: Tree) */ + } /* class MixTypes */ /** converts given rep to a tree - performs recursive call to translation in the process to get sub reps */ final def repToTree(rep:Rep, handleOuter: Tree => Tree)(implicit theOwner: Symbol, failTree: Tree): Tree = { + implicit val HandleOuter = handleOuter + rep.applyRule.tree + /* rep.applyRule match { - case ErrorRule() => failTree - case VariableRule(subst, EmptyTree, _, bx) => - genBody(subst, bx) - - case VariableRule(subst, g, restRep, bx) => - genBody(subst, g, repToTree(restRep, handleOuter),bx) - - case mc: MixCases => - val (branches, defaultV, default) = mc.getTransition // tag body pairs - if (settings_debug) { - Console.println("[[mix cases transition: branches \n"+(branches.mkString("","\n",""))) - Console.println("defaults:"+defaultV) - Console.println(default) - Console.println("]]") - } + case r : ErrorRule => r.tree - var ndefault = if(default.isEmpty) failTree else repToTree(default.get, handleOuter) - - var cases = branches map { - case (tag, rep) => - CaseDef(Literal(tag), - EmptyTree, - { - val pat = mc.column(mc.tagIndexPairs.find(tag)); - val ptpe = pat.tpe - if(mc.scrutinee.tpe.typeSymbol.hasFlag(symtab.Flags.SEALED) && strip2(pat).isInstanceOf[Apply]) { - //cast - val vtmp = newVar(pat.pos, ptpe) - squeezedBlock( - List(typedValDef(vtmp, gen.mkAsInstanceOf(Ident(mc.scrutinee),ptpe))), - repToTree(Rep(vtmp::rep.temp.tail, rep.row),handleOuter) - ) - } else repToTree(rep, handleOuter) - } - )} - - renamingBind(defaultV, mc.scrutinee, ndefault) // each v in defaultV gets bound to scrutinee - - // make first case a default case. - if(mc.scrutinee.tpe.typeSymbol.hasFlag(symtab.Flags.SEALED) && defaultV.isEmpty) { - ndefault = cases.head.body - cases = cases.tail - } + case vr: VariableRule => vr.tree - if(cases.length == 0) { - ndefault - } else if(cases.length == 1) { - val CaseDef(lit,_,body) = cases.head - makeIf(Equals(Select(Ident(mc.scrutinee),nme.tag),lit), body, ndefault) // * - } else { - val defCase = CaseDef(mk_(definitions.IntClass.tpe), EmptyTree, ndefault) - Match(Select(Ident(mc.scrutinee),nme.tag), cases ::: defCase :: Nil) // * - } + case mc: MixCases => mc.tree - case ml: MixLiterals => - val (branches, defaultV, defaultRepOpt) = ml.getTransition // tag body pairs - if(settings_debug) { - Console.println("[[mix literal transition: branches \n"+(branches.mkString("","\n",""))) - Console.println("defaults:"+defaultV) - Console.println(defaultRepOpt) - Console.println("]]") - } - val cases = branches map { case (tag, rep) => CaseDef(Literal(tag), EmptyTree, repToTree(rep, handleOuter)) } - var ndefault = if(defaultRepOpt.isEmpty) failTree else repToTree(defaultRepOpt.get, handleOuter) - - renamingBind(defaultV, ml.scrutinee, ndefault) // each v in defaultV gets bound to scrutinee - if(cases.length == 1) { - val CaseDef(lit,_,body) = cases.head - makeIf(Equals(Ident(ml.scrutinee),lit), body, ndefault) - } else { - val defCase = CaseDef(mk_(definitions.IntClass.tpe), EmptyTree, ndefault) - var selector:Tree = Ident(ml.scrutinee) - if(isSameType(ml.scrutinee.tpe.widen, definitions.CharClass.tpe)) - selector = gen.mkAsInstanceOf(selector, definitions.IntClass.tpe) - Match(selector, cases ::: defCase :: Nil) - } + case ml: MixLiterals => ml.tree - case me:MixEquals => - val (cond,srep,frep) = me.getTransition - val cond2 = try{ - typed { handleOuter(cond) } - } catch { - case e => - Console.println("failed to type-check cond2") - Console.println("cond: "+cond) - Console.println("cond2: "+handleOuter(cond)) - throw e - } + case me: MixEquals => me.tree - val succ = repToTree(srep, handleOuter) - val fail = repToTree(frep, handleOuter) - try { - typed{ If(cond2, succ, fail) } - } catch { - case e => - Console.println("failed to type-check If") - Console.println("cond2: "+cond2) - throw e - } + case mm: MixTypes => mm.tree - case mm:MixTypes => - val (casted,srep,frep) = mm.getTransition - //Console.println("--- mixture \n succ \n"+srep.toString+"\n fail\n"+frep.toString) - //val cond = typed{gen.mkIsInstanceOf(Ident(mm.scrutinee), casted.tpe)} - //Console.println("casted.tpe="+casted.tpe) - val condUntyped = condition(casted.tpe, mm.scrutinee) - //Console.println("condUntyped:" + condUntyped) - var cond = handleOuter(typed { condUntyped }) // this thing throws exceptions in some obscure situations - if(needsOuterTest(casted.tpe, mm.scrutinee.tpe)) // @todo merrge into def condition - cond = addOuterCondition(cond, casted.tpe, typed{Ident(mm.scrutinee)}, handleOuter) - - val succ = repToTree(srep, handleOuter) - - val fail = if(frep.isEmpty) failTree else repToTree(frep.get, handleOuter) - - // dig out case field accessors that were buried in (***) - val cfa = casted.caseFieldAccessors - //DEBUG("case field accessors, casted = "+casted.toString) - //DEBUG("case field accessors, the things themselves = "+cfa.toString) - val caseTemps = (if(!srep.temp.isEmpty && srep.temp.head == casted) srep.temp.tail else srep.temp).zip(cfa) - - //DEBUG("case temps"+caseTemps.toString) - var vdefs = caseTemps map { - case (tmp,meth) => - val typedAccess = typed { Apply(Select(typed{Ident(casted)}, meth),List()) } - typedValDef(tmp, typedAccess) - } + case mu: MixUnapply => mu.tree - if(casted ne mm.scrutinee) { - vdefs = ValDef(casted, gen.mkAsInstanceOf(typed{Ident(mm.scrutinee)}, casted.tpe)) :: vdefs - } - typed { makeIf(cond, squeezedBlock(vdefs,succ), fail) } - - case mu: MixUnapply => - val (uacall/*:ValDef*/ , vdefs,srep,frep) = mu.getTransition // uacall is a Valdef - //Console.println("getTransition"+(uacall,vdefs,srep,frep)) - val succ = repToTree(srep, handleOuter) - val fail = if(frep.isEmpty) failTree else repToTree(frep.get, handleOuter) - val cond = if(uacall.symbol.tpe.typeSymbol eq definitions.BooleanClass) - typed{ Ident(uacall.symbol) } - else - emptynessCheck(uacall.symbol) - typed { squeezedBlock(List(handleOuter(uacall)), makeIf(cond,squeezedBlock(vdefs,succ),fail)) } } + */ } /** subst: the bindings so far */ @@ -1062,6 +981,10 @@ object Rep { val q = Typed(EmptyTree, TypeTree(o.tpe)) setType o.tpe pats = q :: pats + case p @ ArrayValue(_,xs) => + Console.println("hello from array val!") + pats = p :: pats + case p => pats = p :: pats } @@ -1178,37 +1101,34 @@ object Rep { } //if(settings_debug) Console.println("init done, rep = "+this.toString) return this - } // end init + } /* def init */ -/* - final def applyRule: RuleApplication = { - Console.println("entering applyRule!") - val res = applyRule1 - Console.println("leaving applyRule!") - res - } -*/ final def applyRule: RuleApplication = row match { case Nil => ErrorRule case Row(pats, subst, g, bx)::xs => - if(pats forall isDefaultPattern) { - val subst1 = pats.zip(temp) flatMap { - case (p,tmp) => - strip1(p).toList.zipAll(Nil,null,tmp) // == vars map { (v,tmp) } + 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 } - VariableRule (subst1 ::: subst, g, Rep(temp, xs), bx) - } else { - val i = pats findIndexOf {x => !isDefaultPattern(x)} - - val column = row map { case Row(pats,_,_,_) => pats(i) } - - val restTemp = temp.take(i) ::: temp.drop(i+1) - val restRows = row map { case Row(pats, subst, g, bx) => Row(pats.take(i) ::: pats.drop(i+1), subst, g, bx) } - - MixtureRule(temp(i), column, Rep(restTemp,restRows)) } - } // applyRule + if(bnd ne null) { // all default patterns + val rest = if(g eq EmptyTree) null else Rep(temp, xs) + return VariableRule (bnd, g, rest, bx) + } + + // cut out column px that contains the non-default pattern + // assert(px == pats findIndexOf {x => !isDefaultPattern(x)}) + val column = rpats.head :: (row.tail map { case Row(pats,_,_,_) => pats(px) }) + // assert(column == row 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) } + return MixtureRule(temps.head, column, Rep(restTemp,restRows)) + } /* applyRule */ // a fancy toString method for debugging override final def toString = { @@ -1224,8 +1144,8 @@ object Rep { sb.append('\n') } sb.toString - } - } + } /* def toString */ + } /* class Rep */ /** creates initial clause matrix */ diff --git a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala index dee4b32bfe..5538799b5e 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala @@ -270,14 +270,19 @@ trait PatternMatchers { self: transform.ExplicitOuter with PatternNodes with Par isImplemented(xs) } case p @ Ident(n) => null // if(n!= nme.WILDCARD && p.symbol.) CantHandleIdent else null - case _:ArrayValue => CantHandleSeq case UnApply(fn,xs) => isImplemented(xs) case Bind(n, p) => isImplemented(p) case Alternative(xs) => isImplemented(xs) case p:Literal => null case p:Select => null case p:Typed => null - //case Star(t) =>can't happen/ excluded by Transmatcher:isregular + + + case ArrayValue(_,xs) => CantHandleSeq + + //@todo + //case ArrayValue(_,xs) => isImplemented(xs) //CantHandleSeq // DEBUG + //case Star(t) => isImplemented(t) //can't happen/ excluded by Transmatcher:isregular //case Sequence(trees) =>can't happen/ only appear below ArrayValue } } diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala index e23ec59d94..033b9fb6cd 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala @@ -17,6 +17,8 @@ trait PatternNodes { self: transform.ExplicitOuter => // --- misc methods + final def DBG(x:String) { if(settings_debug) Console.println(x) } + /** returns all variables that are binding the given pattern * @param x a pattern * @return vs variables bound, p pattern proper @@ -35,24 +37,41 @@ trait PatternNodes { self: transform.ExplicitOuter => case z => z } - // this method obtains tag method in a defensive way - final def getCaseTag(x:Type): Int = { x.typeSymbol.tag } + final def isCaseClass(tpe: Type): Boolean = + tpe match { + case TypeRef(_, sym, _) => + if(!sym.isAliasType) + sym.hasFlag(symtab.Flags.CASE) + else + tpe.normalize.typeSymbol.hasFlag(symtab.Flags.CASE) + case _ => false + } + + final def isEqualsPattern(tpe: Type): Boolean = + tpe match { + case TypeRef(_, sym, _) => sym eq definitions.EqualsPatternClass + case _ => false + } - case class FinalState(label:Symbol,body:Tree) - // misc methods END --- + // this method obtains tag method in a defensive way + final def getCaseTag(x:Type): Int = { x.typeSymbol.tag } final def definedVars(x:Tree): SymList = { var vs = new collection.mutable.ListBuffer[Symbol] def definedVars1(x:Tree): Unit = x match { - case Alternative(bs) => definedVars2(bs) + case Alternative(bs) => ; // must not have any variables case Apply(_, args) => definedVars2(args) case b @ Bind(_,p) => vs += b.symbol; definedVars1(p) case Ident(_) => ; case Literal(_) => ; case Select(_,_) => ; - case Typed(p,_) => definedVars1(p) + case Typed(p,_) => ; // definedVars1(p) //shouldn't have, because x @ (_:T) case UnApply(_,args) => definedVars2(args) + + // regexp specific + case ArrayValue(_,xs)=> definedVars2(xs) + case Star(p) => ; // must not have variables } def definedVars2(args:List[Tree]): Unit = { var xs = args; while(xs ne Nil) { definedVars1(xs.head); xs = xs.tail }; @@ -83,6 +102,12 @@ trait PatternNodes { self: transform.ExplicitOuter => case (v,tmp)::bs => Binding(v, tmp, bs ::: this); case Nil => this } + def add(vs:Iterator[Symbol], temp:Symbol): Binding = { + var b = this; while(vs.hasNext){ + b = Binding(vs.next, temp, b) + } + return b + } def apply(v:Symbol): Ident = { //Console.println(this.toString()+" apply ("+v+"), eq?"+(v eq pvar)) if(v eq pvar) {Ident(temp).setType(v.tpe)} else next(v) @@ -92,7 +117,9 @@ trait PatternNodes { self: transform.ExplicitOuter => override def apply(v:Symbol) = null // not found, means bound elsewhere (x @ unapply-call) override def toString = "." } - // + + // misc methods END --- + type SymSet = collection.immutable.Set[Symbol] type SymList = List[Symbol] -- cgit v1.2.3