diff options
-rw-r--r-- | docs/examples/xml/phonebook/phonebook3.scala | 98 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/ParallelMatching.scala | 41 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/PatternMatchers.scala | 24 | ||||
-rw-r--r-- | src/library/scala/xml/Node.scala | 14 | ||||
-rw-r--r-- | src/library/scala/xml/Utility.scala | 10 |
5 files changed, 86 insertions, 101 deletions
diff --git a/docs/examples/xml/phonebook/phonebook3.scala b/docs/examples/xml/phonebook/phonebook3.scala index 0965b16558..76cc00f227 100644 --- a/docs/examples/xml/phonebook/phonebook3.scala +++ b/docs/examples/xml/phonebook/phonebook3.scala @@ -1,77 +1,63 @@ -/* examples/xml/phonebook/phonebook3.scala */ -package phonebook +package phonebook; object phonebook3 { - import scala.xml.{Elem, Node, Text} - import scala.xml.Utility.view - import scala.xml.PrettyPrinter - import Node.NoAttributes + import scala.xml.{Elem, Node, Text} ; + import scala.xml.PrettyPrinter ; + import Node.NoAttributes ; - /* finds entry for Name, Where, changes it, or adds if not present */ - def change ( phonebook: Node, Name: String, Where: String, newPhone: String ) = { + /* this method "changes" (returns an updated copy) of the phonebook when the + * entry for Name exists. If it has an attribute "where" whose value is equal to the + * parameter Where, it is changed, otherwise, it is added. + */ + def change ( phonebook:Node, Name:String, Where:String, newPhone:String ) = { - /** returns true if this element's first child is the right 'name' - * x is treated a if it was a singleton sequence here. - */ - def hasName ( x: Seq[Node] ) = x(0).child.elements.exists { - case <name>{Text(Name)}</name> => true - case _ => false - } + /** this nested function walks through tree, and returns an updated copy of it */ + def copyOrChange ( ch: Iterator[Node] ) = { - /** returns true if this element has the right 'where' attribute - * y is treated a if it was a singleton sequence here. - * n.attribute(s) is the same as n.attributes.get(s) - */ - def hasWhere ( y: Node ) = y.attribute("where") match { - case Some(Text(Where)) => true - case None => false - } + import xml.Utility.{trim,trimProper} //removes whitespace nodes, which are annoying in matches - /** returns true if this element has the right 'where' attribute - * the apply method of MetaData (n.attributes) returns raw a - * sequence of nodes. - */ - def hasWhere2 ( y: Node ) = y.attributes("where") match { - case null => false - case Text(Where) => true - case _ => false - } + for( val c <- ch ) yield + trimProper(c) match { + + // if the node is the particular entry we are looking for, return an updated copy + + case x @ <entry><name>{ Text(Name) }</name>{ ch1 @ _* }</entry> => + + var updated = false; + val ch2 = for(val c <- ch1) yield c match { // does it have the phone number? + case y @ <phone>{ _* }</phone> if y.attribute("where") == Where => + updated = true + <phone where={ Where }>{ newPhone }</phone> - /** walks through tree, returns changed/copied updated tree */ - def copyOrChange ( ch: Iterator[Node] ):List[Node] = { - for(c <- ch ) yield c match { + case y => y - case x @ <entry>{ ch1 @ _* }</entry> if hasName(x) => - val it = ch1.elements; - val nameElem:Seq[Node] = it.next; // grab 'name' element - val ch2 = nameElem ++ copyOrChange( it ); // concat with updated seq + } + if( !updated ) { // no, so we add as first entry - if( ch1 == ch2 ) // not present: add as first entry + <entry> + <name>{ Name }</name> + <phone where={ Where }>{ newPhone }</phone> + { ch1 } + </entry> - <entry> - <name>{ Name }</name> - <phone where={ Where }>{ newPhone }</phone> - { ch1 } - </entry> + } else { // yes, and we changed it as we should - else // was present and changed + <entry> + { ch2 } + </entry> - <entry> - { ch2 } - </entry> + } + // end case x @ <entry>... - case y @ <phone>{ _* }</phone> if hasWhere( y ) => - Console.println("phone: "+c); - <phone where={ Where }>{ newPhone }</phone> + // other entries are copied without changing them - case _ => - Console.println("default "+c); - c + case x => + x } - }.toList ; // for ... yield ... returns Iterator, convert to list + } ; // for ... yield ... returns an Iterator[Node] // decompose phonebook, apply updates phonebook match { diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 59a4523c3f..8af380d447 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -17,7 +17,7 @@ trait ParallelMatching { import global._ - final def DEBUG(x:String) = {if (settings.debug.value) Console.println(x)} + //final def DEBUG(x:String) = {if (settings.debug.value) Console.println(x)} // ---------------------------------- data sealed trait RuleApplication @@ -91,10 +91,9 @@ trait ParallelMatching { [locker] at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:809) [locker] at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadQualifier(GenICode.scala:996) [locker] at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:785) - (pat.symbol != NoSymbol) && pat.symbol.tpe.prefix.isStable && */ - (patternType =:= singleType(pat.symbol.tpe.prefix, pat.symbol)) => + (patternType =:= singleType(pat.symbol.tpe.prefix, pat.symbol)) => (EmptyTree::ms, (j,dummies)::ss, rs); // matching an object case _ if (pat.tpe <:< patternType) => ({if(pat.tpe =:= patternType) EmptyTree else pat}::ms, (j,subpatterns(pat))::ss, rs); // subsumed (same or more specific) pattern; @@ -113,7 +112,7 @@ trait ParallelMatching { } def getTransition(implicit theOwner: Symbol): (Symbol, Rep, Option[Rep]) = { - DEBUG("*** getTransition! of "+this.toString) + //DEBUG("*** getTransition! of "+this.toString) // the following works for type tests... what fudge is necessary for value comparisons? // type test casted = if(scrutinee.tpe =:= patternType) scrutinee else newVar(scrutinee.pos, patternType) @@ -137,12 +136,12 @@ trait ParallelMatching { ntemps = ntemps ::: rest.temp val ntriples = subtests map { case (j,pats) => - val (vs:List[Symbol],_) = strip(column(j)); - val (opats,osubst:List[(Symbol,Symbol)],og,ob) = rest.row(j); - val subst1:List[(Symbol,Symbol)] = vs map { v => (v,casted) } + val (vs,_) = strip(column(j)); + val (opats,osubst,og,ob) = rest.row(j); + val subst1 = vs map { v => (v,casted) } - DEBUG("getTransition, vs = "+vs) - DEBUG("getTransition, subst1 = "+subst1) + //DEBUG("getTransition, vs = "+vs) + //DEBUG("getTransition, subst1 = "+subst1) // def doSubst(vs:List[Symbol], exp:Tree) = { new TreeSymSubstituter(vs,vs map {x=> casted}).traverse(exp); exp } @@ -153,8 +152,8 @@ trait ParallelMatching { } Rep(ntemps, ntriples) setParent this } - DEBUG("nmatrix for type "+patternType) - DEBUG(nmatrix.toString) + //DEBUG("nmatrix for type "+patternType) + //DEBUG(nmatrix.toString) // and then more or this... Console.println(nmatrix.applyRule) // CONTINUE HERE: epsilon transitions, which ensure that transitions are tested in the right order. @@ -169,10 +168,10 @@ trait ParallelMatching { 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) + //DEBUG("nmatrix for failing type test "+patternType) + //DEBUG(nmatrixFail.get.toString) } else { - DEBUG("pattern type "+patternType+" cannot fail for "+scrutinee) + //DEBUG("pattern type "+patternType+" cannot fail for "+scrutinee) } (casted, nmatrix, nmatrixFail) } // end getTransitions @@ -200,7 +199,7 @@ trait ParallelMatching { // make new value parameter for each vsym in subst // (**) approach 2 //val pdefsyms = subst map { case (v,tmp) => theLabel.newValueParameter(v.pos, v.name+"_!") . setInfo (v.tpe). setFlag(symtab.Flags.MUTABLE) } - DEBUG("subst of "+b.hashCode+"! in case VariableRule (new) "+subst) + //DEBUG("subst of "+b.hashCode+"! in case VariableRule (new) "+subst) val vdefs = subst map { case (v,t) => ValDef(v, {v.setFlag(symtab.Flags.TRANS_FLAG); if(v.tpe =:= t.tpe) typed{Ident(t)} else typed{gen.mkAsInstanceOf(Ident(t),v.tpe)}}) } // this weird thing should only be done for shared states. @@ -350,9 +349,9 @@ trait ParallelMatching { } if(!sealedCols.isEmpty) { - DEBUG("cols"+sealedCols) - DEBUG("comb") - for (com <- sealedComb) DEBUG(com.toString) + //DEBUG("cols"+sealedCols) + //DEBUG("comb") + //for (com <- sealedComb) DEBUG(com.toString) val allcomb = combine(sealedCols zip sealedComb) //Console.println("all comb!" + allcomb) @@ -399,7 +398,7 @@ trait ParallelMatching { case (pats,subst,g,b)::xs => if(pats forall isDefaultPattern) { val subst1 = pats.zip(temp) flatMap { case (p,tmp) => val (vs,_) = strip(p); vs.zipAll(Nil,null,tmp)} - DEBUG("applyRule! subst1="+subst1) + //DEBUG("applyRule! subst1="+subst1) VariableRule (subst:::subst1, g, b) } else { val i = pats findIndexOf {x => !isDefaultPattern(x)} @@ -554,7 +553,7 @@ trait ParallelMatching { */ def condition(tpe: Type, scrut: Symbol): Tree = { val res = condition1(tpe, scrut) - DEBUG("condition, tpe = "+tpe+", scrut.tpe = "+scrut.tpe+", res = "+res) + //DEBUG("condition, tpe = "+tpe+", scrut.tpe = "+scrut.tpe+", res = "+res) res } def condition1(tpe: Type, scrut: Symbol): Tree = { @@ -607,7 +606,7 @@ trait ParallelMatching { def outerAlwaysEqual(left: Type, right: Type): Option[Boolean] = (left.normalize,right.normalize) match { case (TypeRef(lprefix, _,_), TypeRef(rprefix,_,_)) => if(!(lprefix =:= rprefix)) { - DEBUG("DEBUG(outerAlwaysEqual) Some(f) for"+(left,right)) + //DEBUG("DEBUG(outerAlwaysEqual) Some(f) for"+(left,right)) } Some(lprefix =:= rprefix) case _ => None diff --git a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala index cb17975243..409b939ad8 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternMatchers.scala @@ -128,17 +128,17 @@ trait PatternMatchers requires (transform.ExplicitOuter with PatternNodes with P x match { case _:UnApply => throw CantHandleUnapply case Ident(n) if n!= nme.WILDCARD => - DEBUG("I can't handle IDENT pattern:"+x) - DEBUG("x.tpe.symbols:"+x.tpe.symbol) + //DEBUG("I can't handle IDENT pattern:"+x) + //DEBUG("x.tpe.symbols:"+x.tpe.symbol) throw CantHandleIdent case p:Select => //case p:Select => - // DEBUG("I can't handle SELECT pattern:"+p) - // DEBUG("p.tpe.symbols:"+p.tpe.symbol) + // //DEBUG("I can't handle SELECT pattern:"+p) + // //DEBUG("p.tpe.symbols:"+p.tpe.symbol) //throw CantHandleUnapply case p@Apply(_,_) if !p.tpe.symbol.hasFlag(symtab.Flags.CASE) => - DEBUG("I can't handle APPLY pattern:"+p) - DEBUG("p.tpe.symbols:"+p.tpe.symbol) + //DEBUG("I can't handle APPLY pattern:"+p) + //DEBUG("p.tpe.symbols:"+p.tpe.symbol) throw CantHandleApply //case p@Apply(_,_) if !p.tpe.symbol.hasFlag(symtab.Flags.CASE) => throw CantHandleUnapply //@todo @@ -160,12 +160,12 @@ trait PatternMatchers requires (transform.ExplicitOuter with PatternNodes with P val mch = typed{repToTree(irep, typed, handleOuter)} dfatree = typed{squeezedBlock(List(vdef), mch)} - DEBUG("**** finished\n"+dfatree.toString) + //DEBUG("**** finished\n"+dfatree.toString) val i = cases.findIndexOf { case CaseDef(_,_,b) => bodies.get(b).isEmpty} if(i != -1) { val CaseDef(_,_,b) = cases(i) - DEBUG("*** damn, unreachable!") + //DEBUG("*** damn, unreachable!") //for (b <- bodies) { // Console.println(b) //} @@ -192,9 +192,9 @@ trait PatternMatchers requires (transform.ExplicitOuter with PatternNodes with P } else throw CantHandleGuard } catch { case e: CantHandle => // fall back - DEBUG("****") - DEBUG("**** falling back, "+e.getClass) - DEBUG("****") + //DEBUG("****") + //DEBUG("**** falling back, "+e.getClass) + //DEBUG("****") case CantHandleGuard => // fall back (actually already fell back before) case e => @@ -1113,7 +1113,7 @@ print() protected def toTree_refined(node: PatternNode, selector:Tree, ignoreSelectorType: Boolean): Tree = { //Console.println("pm.toTree("+node+","+selector+") selector.tpe = "+selector.tpe+")") if (selector.tpe eq null) - scala.Predef.error("cannot go on") + scala.Predef.error("cannot go on due to internal error (type attribute set to null)") if (node eq null) return Literal(Constant(false)); else diff --git a/src/library/scala/xml/Node.scala b/src/library/scala/xml/Node.scala index 9a32667a79..c49cd93517 100644 --- a/src/library/scala/xml/Node.scala +++ b/src/library/scala/xml/Node.scala @@ -139,17 +139,11 @@ abstract class Node extends NodeSeq { } /** <p> - * Returns a hashcode. A standard implementation of hashcodes is obtained - * by calling <code>Utility.hashCode(pre, label, attributes.hashCode(), child)</code>. + * Returns a hashcode. The default implementation here calls only + * super.hashcode (which is the same as for objects). A more useful + * implementation can be invoked by calling + * <code>Utility.hashCode(pre, label, attributes.hashCode(), child)</code>. * </p> - * <p> - * Martin to Burak: to do: if you make this method abstract, the compiler - * will now complain if there's no implementation in a subclass. Is this - * what we want? Note that this would break <code>doc/DocGenator</code> and - * doc/ModelToXML, with an error message like: - * </p><pre> - * doc/ModelToXML.scala:95: error: object creation impossible, since there is a deferred declaration of method hashCode in class Node of type ()Int which is not implemented in a subclass - * new SpecialNode {<pre> */ override def hashCode(): Int = super.hashCode diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala index f3cb5f4964..d257ea2faf 100644 --- a/src/library/scala/xml/Utility.scala +++ b/src/library/scala/xml/Utility.scala @@ -22,7 +22,12 @@ import collection.mutable.{Set, HashSet} object Utility extends AnyRef with parsing.TokenTests { - /** precondition: node is not a text node (it might be trimmed) + /** trims an element - call this method, when you know that it is an element (and not a text node) + * so you know that it will not be trimmed away. With this assumption, the function can + * return a Node, rather than a Seq[Node]. If you don't know, call trimProper and account for + * the fact that you may get back an empty sequence of nodes + * + * precondition: node is not a text node (it might be trimmed) */ def trim(x:Node): Node = x match { @@ -30,7 +35,8 @@ object Utility extends AnyRef with parsing.TokenTests { Elem(pre,lab,md,scp, (child flatMap trimProper):_*) } - /** attribute values and Atom nodes that are not Text nodes are unaffected */ + /** trim a child of an element. Attribute values and Atom nodes that are not Text nodes are unaffected + */ def trimProper(x:Node): Seq[Node] = x match { case Elem(pre,lab,md,scp,child@_*) => Elem(pre,lab,md,scp, (child flatMap trimProper):_*) |