summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorburaq <buraq@epfl.ch>2004-05-28 17:50:04 +0000
committerburaq <buraq@epfl.ch>2004-05-28 17:50:04 +0000
commit2cdb40e1efefe9209edda0c058b9c88c18d118fc (patch)
treedacfc271e6b7271939be0af1427df367b02d0ea9
parent828b051bf427565fbc559d068219b6914ece6ef1 (diff)
downloadscala-2cdb40e1efefe9209edda0c058b9c88c18d118fc.tar.gz
scala-2cdb40e1efefe9209edda0c058b9c88c18d118fc.tar.bz2
scala-2cdb40e1efefe9209edda0c058b9c88c18d118fc.zip
library update, validation in dtd2scala
-rw-r--r--config/list/library.lst4
-rw-r--r--sources/scala/tools/dtd2scala/DeclToScala.scala91
-rw-r--r--sources/scala/tools/dtd2scala/Main.scala29
-rw-r--r--sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml24
-rw-r--r--sources/scala/xml/Elem.scala2
-rw-r--r--sources/scala/xml/FactoryAdapter.scala116
-rw-r--r--sources/scala/xml/Node.scala4
-rw-r--r--sources/scala/xml/dtd/Decl.scala11
-rw-r--r--sources/scala/xml/dtd/Parser.scala128
-rw-r--r--sources/scala/xml/dtd/RegExp.scala61
-rw-r--r--sources/scala/xml/dtd/Scanner.scala79
-rw-r--r--sources/scala/xml/dtd/Tokens.scala34
-rw-r--r--sources/scalac/transformer/matching/BindingBerrySethi.java1
-rw-r--r--sources/scalac/transformer/matching/TestRegTraverser.java18
14 files changed, 512 insertions, 90 deletions
diff --git a/config/list/library.lst b/config/list/library.lst
index 0bc4c3cf8f..26d51fc5e2 100644
--- a/config/list/library.lst
+++ b/config/list/library.lst
@@ -169,6 +169,10 @@ xml/Text.scala
xml/Utility.scala
xml/dtd/Decl.scala
+xml/dtd/Parser.scala
+xml/dtd/RegExp.scala
+xml/dtd/Scanner.scala
+xml/dtd/Tokens.scala
xml/nobinding/NoBindingFactoryAdapter.scala
xml/nobinding/XML.scala
diff --git a/sources/scala/tools/dtd2scala/DeclToScala.scala b/sources/scala/tools/dtd2scala/DeclToScala.scala
index cae0cc82c5..88f0f7ae4e 100644
--- a/sources/scala/tools/dtd2scala/DeclToScala.scala
+++ b/sources/scala/tools/dtd2scala/DeclToScala.scala
@@ -10,7 +10,7 @@ import scala.collection.Map ;
import scala.collection.mutable.HashMap ;
import scala.xml._ ;
-import scala.xml.dtd.AttrDecl;
+import scala.xml.dtd.{AttrDecl,RegExp,ANY_,PCDATA_,Eps,Star,RNode,Sequ,Alt};
import scala.xml.nobinding.XML ;
/** transforms a set of DTD declaraion to a scala source file.
@@ -29,7 +29,88 @@ class DeclToScala(fOut:PrintWriter,
val lookup : HashMap[String,String] = new HashMap[String,String]();
var curAttribs: Map[String,AttrDecl] = null ; /* of current elem */
+ var curModel : RegExp = null;
+
+ def shallowValidate( r:RegExp ):String = {
+
+ def shallowContentModel1(rs:List[RegExp],sep:Char):String = {
+ val it = rs.elements;
+ val sb = new StringBuffer();
+ sb.append('(');
+ sb.append( shallowContentModel( it.next ) );
+ for( val z <- it ) {
+ sb.append( sep );
+ sb.append( shallowContentModel( z ) );
+ }
+ sb.append( ')' );
+ sb.toString()
+ }
+
+ def shallowContentModel(r:RegExp):String = {
+ //Console.println("sCM:"+ r.getClass() + " r:"+r );
+ r match {
+ case Eps => ""
+ case RNode(name) => "$TagOf" + cookedCap( name );
+ case Star(r) => "("+shallowContentModel( r ) +") *"
+ case Alt( rs @ _* ) => shallowContentModel1( rs, '|' )
+ case Sequ( rs @ _* ) => shallowContentModel1( rs, ',' )
+ case _ => error("unexpected regexp:"+r);
+ }
+ }
+
+ //Console.println("shallowValid:"+ r.getClass() + " r:"+r );
+ r match {
+ case ANY_ => "true";
+ case Eps => "ch.length == 0"
+ case PCDATA_ | Sequ( PCDATA_ ) =>
+ val sb = new StringBuffer("ch.elements.forall( x:scala.xml.Node => x match {\n");
+ sb.append(" case _:scala.xml.Text => true \n");
+ sb.append(" case _:scala.xml.EntityRef => true \n");
+ sb.append(" case _:scala.xml.CharData => true \n");
+ sb.append(" case _:scala.xml.Comment => true \n");
+ sb.append(" case _:scala.xml.ProcInstr => true \n");
+ sb.append("case _ => false })");
+ sb.toString();
+ case Star(Alt(PCDATA_, alts @ _*)) => {
+ val sb = new StringBuffer("ch.elements.forall( x:scala.xml.Node => x match {\n");
+ sb.append(" case _:scala.xml.Text => true \n");
+ sb.append(" case _:scala.xml.EntityRef => true \n");
+ sb.append(" case _:scala.xml.CharData => true \n");
+ sb.append(" case _:scala.xml.Comment => true \n");
+ sb.append(" case _:scala.xml.ProcInstr => true \n");
+ // classes created with mixin composition... types won't work
+ sb.append(" case _ => x.typeTag$ match {\n");
+ // no type tag -> is scala.xml.Elem
+ sb.append(" case 0 => x.label match {");
+ for( val alt <- alts.elements ) {
+ sb.append(" case \"");
+ alt match { case RNode( name ) => sb.append( name );}
+ sb.append("\" => true \n");
+ }
+ sb.append("case _ => Console.println(\"ELEM\"); for( val z <- ch ) { Console.println( z.getClass() ); Console.println( z.label ); Console.println( z.toString() )}; false}\n");
+ for( val alt <- alts.elements ) {
+ sb.append(" case $TagOf");
+ alt match { case RNode( name ) => sb.append( cookedCap( name ));}
+ sb.append(" => true \n");
+ }
+ sb.append("case _ => Console.println(ch.toList); for( val z <- ch ) { Console.println( z.getClass() ); Console.println( z.label ); Console.println( z.toString() )}; false }})");
+ sb.toString();
+ }
+ case _ => val sb = new StringBuffer("(ch.elements.foldLeft (Nil:List[Int]) { (e:List[Int],x:scala.xml.Node) => val i = x.typeTag$; if( i!=0 ) i::e else e }).reverse match {");
+ sb.append(" case Seq( ");
+ sb.append( shallowContentModel( r ) );
+ sb.append( ") => true ");
+ sb.append( "case _ => Console.println(\"reg match fails for \"+ch.elements.foldLeft (Nil:List[Int]) { (e:List[Int],x:scala.xml.Node) => val i = x.typeTag$; if( i!=0 ) i::e else e }); false}");
+ sb.toString();
+ }
+ }
+ var tagCounter = 0;
+ def newTag = {
+ val i = tagCounter;
+ tagCounter = tagCounter + 1;
+ i
+ }
def write:Unit = {
def writeNode( x:Node ):Unit = {
//Console.println("visiting "+x);
@@ -43,14 +124,22 @@ class DeclToScala(fOut:PrintWriter,
lookup.update("compressDefault", compress.toString());
n.child.elements.foreach { n => writeNode(n) }
}
+ case "shallowContentRegExp" =>
+ fOut.print( shallowValidate( curModel ) );
+ case "elementTag" =>
+ fOut.print( newTag.toString() );
case "elementBinding" => {
for( val decl <- elemMap.values ) {
lookup += "elementName" -> decl.name;
lookup += "elementContainsText" -> decl.containsText.toString();
lookup += "elementContentModel" -> decl.contentModel;
+ //Console.println("elemName="+decl.name);
+ curModel = decl.parsedContentModel ;
+ //Console.println("curModel="+curModel);
curAttribs = decl.attribs;
n.child.elements.foreach{ n => writeNode( n ) }
}
+ curModel = null;
curAttribs = null;
lookup -= "elementName";
lookup -= "elementContainsText";
diff --git a/sources/scala/tools/dtd2scala/Main.scala b/sources/scala/tools/dtd2scala/Main.scala
index 73d89df435..5daa917d8a 100644
--- a/sources/scala/tools/dtd2scala/Main.scala
+++ b/sources/scala/tools/dtd2scala/Main.scala
@@ -1,17 +1,27 @@
package scala.tools.dtd2scala ;
import org.xml.sax.{InputSource,SAXException,SAXParseException,XMLReader}
-import org.xml.sax.helpers.XMLReaderFactory;
+//import org.xml.sax.helpers.XMLReaderFactory;
import java.io.{File,FileWriter,PrintWriter,StringReader};
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+
object Main {
// included in JDK1.4, but cannot resolve relative sysIDs
- final val DEFAULT_PARSER_NAME = "org.apache.crimson.parser.XMLReaderImpl" ;
- // better "org.apache.xerces.parsers.SAXParser" ;
+ //final val DEFAULT_PARSER_NAME = "org.apache.crimson.parser.XMLReaderImpl" ;
+ //final val DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser" ;
+
+ /** Default namespaces support (true). */
+ final val DEFAULT_NAMESPACES = false;
final val DECL_HANDLER = "http://xml.org/sax/properties/declaration-handler";
+ final val NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces";
+
+
def printUsage:Unit = {
Console.println("usage: dtd2scala [ -d <dir> ] <sysID> <object name>");
Console.println(" binds a DTD to class definitions");
@@ -68,13 +78,18 @@ object Main {
}
private def parse( sysID:String, myH:MainHandler ) = {
- val parser:XMLReader =
- XMLReaderFactory.createXMLReader( DEFAULT_PARSER_NAME );
+ val parser:SAXParser = SAXParserFactory.newInstance().newSAXParser();
+ /*
+ try {parser.setFeature( NAMESPACES_FEATURE_ID,
+ DEFAULT_NAMESPACES );}
+ catch {
+ case e:SAXException =>
+ }
+*/
try { parser.setProperty( DECL_HANDLER, myH ); }
catch { case e:SAXException => e.printStackTrace(System.err); }
-
- try { parser.parse( inputsrc( sysID )); }
+ try { parser.parse( inputsrc( sysID ), myH ); }
catch {
case e:SAXParseException =>
System.err.println("SaxParseEx");e.printStackTrace( System.err );
diff --git a/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml b/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml
index a1f05a9050..97891442cf 100644
--- a/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml
+++ b/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml
@@ -31,28 +31,40 @@
type cT = scala.Seq[scala.xml.Node];
type aT = Map[String,String];
+ abstract class <string ref="objectName"/>Node$ extends scala.xml.Node;
+
<elementBinding>
+ val $TagOf&ccElementName;:int = <elementTag/>;
def constr_&ccElementName;( ch:cT, attrs:aT ) = new &ccElementName;(ch:_*) {
override var hmap = attrs;
override val attribHashCode = attrs.toList.hashCode() ;
};
+
+ def shallowValidate&ccElementName;Children( ch:Seq[scala.xml.Node] ) =
+ <shallowContentRegExp/>;
+
- case class &ccElementName;( ch:scala.xml.Node* ) extends scala.xml.Node {
-
+ case class &ccElementName;( ch:scala.xml.Node* ) extends <string ref="objectName"/>Node$ {
+
+ final override def typeTag$ = $TagOf&ccElementName;;
+
+ if( !shallowValidate&ccElementName;Children( ch ) )
+ error("trying to construct invalid &elementName;");
+
def label = &qElementName;;
def child = ch;
- protected var hmap:aT = new immutable.TreeMap[String,String]();
+ protected var hmap:aT = scala.xml.Node.NoAttributes;
final def attribute:aT = hmap;
<attributeBinding>
- def &cAttributeName; : scala.Option[String] = hmap.get(&qAttributeName;);
+ final def &cAttributeName; : scala.Option[String] = hmap.get(&qAttributeName;);
</attributeBinding>
val attribHashCode: int = hmap.toList.hashCode() ;
/** returns a new &ccElementName; with updated attributes */
final def %(attrs: Seq[Pair[String, String]]) = {
- var newmap = new immutable.TreeMap[String,String]();
+ var newmap = scala.xml.Node.NoAttributes;
for( val p &lt;- attribute.elements ) {
newmap = newmap.update( p._1, p._2 )
}
@@ -64,7 +76,7 @@
/** returns a new &ccElementName; with updated attribute */
final def %(attr: Pair[String, String]) = {
- var newmap = new immutable.TreeMap[String,String]();
+ var newmap = scala.xml.Node.NoAttributes;
for( val p &lt;- attribute.elements ) {
newmap = newmap.update( p._1, p._2 );
};
diff --git a/sources/scala/xml/Elem.scala b/sources/scala/xml/Elem.scala
index 7f9519c50d..8e68b242f8 100644
--- a/sources/scala/xml/Elem.scala
+++ b/sources/scala/xml/Elem.scala
@@ -19,6 +19,8 @@ import scala.collection.immutable;
*/
case class Elem( label: String, attribute:immutable.Map[String,String], child: Node*) extends Node {
+ final override def typeTag$:Int = 0;
+
def this(label: String, child: Node*) = this(label,immutable.ListMap.Empty[String,String],child:_*);
/** Return a new element with updated attributes
diff --git a/sources/scala/xml/FactoryAdapter.scala b/sources/scala/xml/FactoryAdapter.scala
index a0837cff55..c2cf22efb7 100644
--- a/sources/scala/xml/FactoryAdapter.scala
+++ b/sources/scala/xml/FactoryAdapter.scala
@@ -23,31 +23,20 @@ import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.SAXParseException;
-import org.xml.sax.XMLReader;
+//import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.ParserAdapter;
-import org.xml.sax.helpers.XMLReaderFactory;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
-/** SAX adapter class, for use with Java SAX parser
-**/
-abstract class FactoryAdapter
- extends DefaultHandler()
- // with ContentHandler
- // with ErrorHandler // SAX2
-{
- // default settings
-
- /** Default parser name - included in JDK1.4 */
- val DEFAULT_PARSER_NAME = "org.apache.crimson.parser.XMLReaderImpl";
- //val DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
- /** Namespaces feature id (http://xml.org/sax/features/namespaces). */
- val NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces";
+//import org.xml.sax.helpers.XMLReaderFactory;
- //
- // Constructors
- //
+/** SAX adapter class, for use with Java SAX parser
+**/
+abstract class FactoryAdapter extends DefaultHandler() {
val buffer = new StringBuffer();
val attribStack = new Stack[HashMap[String,String]];
@@ -271,61 +260,40 @@ abstract class FactoryAdapter
*/
def loadXML( source:InputSource ):Node = {
- // variables
- //PrintWriter out = new PrintWriter(System.out);
- var parser:XMLReader = null;
-
- // use default parser
- // create parser
- try {
- parser = XMLReaderFactory.createXMLReader(DEFAULT_PARSER_NAME);
- } catch {
- case ( e:Exception ) => {
- System.err.println("error: Unable to instantiate parser (" +
- DEFAULT_PARSER_NAME + ")");
- System.exit(-1);
- }
- }
-
- // set parser features
- try {
- parser.setFeature(NAMESPACES_FEATURE_ID, true);
- } catch {
- case ( e:SAXException ) => {
- System.err.println("warning: Parser does not support feature (" +
- NAMESPACES_FEATURE_ID + ")");
- }
- }
- // set handlers
- parser.setErrorHandler( this /*FA_ErrorHandler*/ );
-
- if (parser.isInstanceOf[ XMLReader ]) {
- parser.setContentHandler(this);
+ // variables
+ var parser:SAXParser = null;
+
+ // create parser
+ try {
+ val f = SAXParserFactory.newInstance();
+ f.setNamespaceAware( true );
+ parser = f.newSAXParser();
+ } catch {
+ case ( e:Exception ) => {
+ System.err.println("error: Unable to instantiate parser");
+ System.exit(-1);
}
- else {
- System.err.println("wrong parser");
- System.exit(-1);
+ }
+
+ // parse file
+ try {
+ //System.err.println("[parsing \"" + source + "\"]");
+ parser.parse( source, this );
+ } catch {
+ case ( e:SAXParseException ) => {
+ // ignore
}
-
- // parse file
- try {
- //System.err.println("[parsing \"" + source + "\"]");
- parser.parse( source );
- } catch {
- case ( e:SAXParseException ) => {
- // ignore
- }
- case ( e:Exception ) => {
- System.err.println("error: Parse error occurred - " + e.getMessage());
- if (e.isInstanceOf[ SAXException ]) {
- (e.asInstanceOf[ SAXException ])
- .getException()
- .printStackTrace( System.err );
- } else {
- e.printStackTrace(System.err);
- }
- }
- } // catch
+ case ( e:Exception ) => {
+ System.err.println("error: Parse error occurred - " + e.getMessage());
+ if (e.isInstanceOf[ SAXException ]) {
+ (e.asInstanceOf[ SAXException ])
+ .getException()
+ .printStackTrace( System.err );
+ } else {
+ e.printStackTrace(System.err);
+ }
+ }
+ } // catch
//System.err.println("[FactoryAdapter: total #elements = "+elemCount+"]");
rootElem
@@ -335,12 +303,12 @@ abstract class FactoryAdapter
/** loads XML from given file */
def loadFile( file:File ):Node = loadXML( new InputSource(
- new FileInputStream( file )
+ new FileInputStream( file )
));
/** loads XML from given file descriptor */
def loadFile( fileDesc:FileDescriptor ):Node = loadXML( new InputSource(
- new FileInputStream( fileDesc )
+ new FileInputStream( fileDesc )
));
/** loads XML from given file */
diff --git a/sources/scala/xml/Node.scala b/sources/scala/xml/Node.scala
index c7d83ca9e8..f116214e57 100644
--- a/sources/scala/xml/Node.scala
+++ b/sources/scala/xml/Node.scala
@@ -15,7 +15,7 @@ import scala.collection.immutable ;
object Node {
/** the constant empty attribute map */
- val NoAttributes: Map[String,String] =
+ val NoAttributes: immutable.TreeMap[String,String] =
immutable.TreeMap.Empty[String,String];
}
@@ -24,6 +24,8 @@ object Node {
*/
trait Node {
+ def typeTag$:Int = 0;
+
/** QName (the label of this node). I.e. "foo" for &lt;foo/&gt;) */
def label: String;
diff --git a/sources/scala/xml/dtd/Decl.scala b/sources/scala/xml/dtd/Decl.scala
index 48e5aae819..a409c8805c 100644
--- a/sources/scala/xml/dtd/Decl.scala
+++ b/sources/scala/xml/dtd/Decl.scala
@@ -11,7 +11,16 @@ case class ElemDecl( name:String ,
attribs:Map[String,AttrDecl] )
extends MarkupDecl {
- //final val parsedContentModel = RegExp.parse( contentModel );
+ final val parsedContentModel:RegExp = {
+ try {
+ RegExp.parse( contentModel );
+ } catch {
+ case _:Error =>
+ Console.println( "error parsing declaration of " + name );
+ Console.println( "content model was:\n" + contentModel );
+ null
+ }
+ }
def containsText = contentModel.indexOf("#PCDATA") != -1 ;
};
diff --git a/sources/scala/xml/dtd/Parser.scala b/sources/scala/xml/dtd/Parser.scala
new file mode 100644
index 0000000000..b0e9e369ec
--- /dev/null
+++ b/sources/scala/xml/dtd/Parser.scala
@@ -0,0 +1,128 @@
+package scala.xml.dtd ;
+
+/** Parser for regexps (content models in DTD element declarations) */
+
+object Parser with Scanner { // a bit too permissive concerning #PCDATA
+
+ /** parses the argument to a regexp */
+ def parse(s:String):RegExp = { initScanner( s ); contentspec }
+
+ // zzz parser methods zzz
+ def accept( tok:int ) = {
+ if( token != tok ) {
+ if(( tok == STAR )&&( token == END )) // common mistake
+ error("in DTDs, \n"+
+ "mixed content models must be like (#PCDATA|Name|Name|...)*");
+ else
+ error("expected "+token2string(tok)+
+ ", got unexpected token:"+token2string(token));
+ }
+ nextToken
+ }
+
+ // s [ '+' | '*' | '?' ]
+ def maybeSuffix(s:RegExp) = token match {
+ case STAR => nextToken; Star( s )
+ case PLUS => nextToken; Sequ( s, Star( s ))
+ case OPT => nextToken; Alt( Eps, s )
+ case _ => s
+ }
+
+ // contentspec ::= EMPTY|ANY|mixed|regexp
+ def contentspec:RegExp = token match {
+
+ case NAME =>
+ if( value.equals( "ANY" ) )
+ ANY_
+ else if( value.equals( "EMPTY" ) )
+ Eps
+ else
+ error("unexpected name:" + value );
+
+ case LPAREN =>
+ nextToken;
+ sOpt;
+ if( token == TOKEN_PCDATA )
+ mixed;
+ else
+ regexp;
+ case _ => error("unexpected token:" + token2string(token) );
+ }
+
+ // sopt ::= S?
+ def sOpt = if( token == S ) nextToken;
+
+ // (' S? mixed ::= '#PCDATA' S? ')'
+ // | '#PCDATA' (S? '|' S? atom)* S? ')*'
+ def mixed = {
+ accept( TOKEN_PCDATA );
+ sOpt;
+ if( token == RPAREN )
+ PCDATA_
+ else {
+ val t = choiceRest( PCDATA_ );
+ if( !t.mixed )
+ error("mixed content models must be like (#PCDATA.|.|.|.)*");
+ accept( RPAREN );
+ // lax: (workaround for buggy Java XML parser in JDK1.4.2)
+ if( token == STAR ) accept( STAR );
+ // strict:
+ // accept( STAR );
+ Star( t )
+ }
+ }
+
+ // '(' S? regexp ::= cp S? [seqRest|choiceRest] ')' [ '+' | '*' | '?' ]
+ def regexp:RegExp = {
+ //Console.println("regexp, token = "+token2string(token));
+ val p = particle;
+ sOpt;
+ maybeSuffix( token match {
+ case RPAREN => nextToken; p
+ case CHOICE => val q = choiceRest( p );accept( RPAREN ); q
+ case COMMA => val q = seqRest( p ); accept( RPAREN ); q
+ })
+ }
+
+
+ // seqRest ::= (',' S? cp S?)+
+ def seqRest( p:RegExp ) = {
+ var k = List( p );
+ while( token == COMMA ) {
+ nextToken;
+ sOpt;
+ k = particle::k;
+ sOpt;
+ }
+ Sequ( k.reverse:_* )
+ }
+
+ // choiceRest ::= ('|' S? cp S?)+
+ def choiceRest( p:RegExp ) = {
+ var k = List( p );
+ while( token == CHOICE ) {
+ nextToken;
+ sOpt;
+ k = particle::k;
+ sOpt;
+ }
+ Alt( k.reverse:_* )
+ }
+
+ // particle ::= '(' S? regexp
+ // | name [ '+' | '*' | '?' ]
+ def particle = {
+ //Console.println("particle, token="+token2string(token));
+ token match {
+ case LPAREN => nextToken; sOpt; regexp;
+ case NAME => val a = RNode( value ); nextToken; maybeSuffix( a )
+ case _ => error("expected '(' or Name, got:"+token2string( token ));
+ }
+ }
+
+ // atom ::= name
+ def atom = token match {
+ case NAME => val a = RNode( value ); nextToken; a
+ case _ => error("expected Name, got:"+token2string( token ));
+ }
+}
diff --git a/sources/scala/xml/dtd/RegExp.scala b/sources/scala/xml/dtd/RegExp.scala
new file mode 100644
index 0000000000..c1b5956ba6
--- /dev/null
+++ b/sources/scala/xml/dtd/RegExp.scala
@@ -0,0 +1,61 @@
+package scala.xml.dtd ;
+
+/** contains parse method to parse regexp from content model */
+object RegExp {
+ /** parse a regular expression from a DTD content model */
+ def parse(s:String):RegExp = Parser.parse( s );
+}
+
+/** abstract super class of regular expressions for DTD content models */
+abstract class RegExp ;
+
+
+case class RNode( name:String ) extends RegExp {
+ override def toString() = name;
+};
+case object PCDATA_ extends RegExp {
+ override def toString() = "#PCDATA";
+}
+case object ANY_ extends RegExp {
+ override def toString() = "ANY";
+}
+case object Eps extends RegExp {
+ override def toString() = "()";
+}
+case class Star(r:RegExp) extends RegExp {
+ override def toString() = r.toString()+"*";
+}
+/** rs should be not empty */
+case class Sequ(rs:RegExp*) extends RegExp {
+ override def toString() = {
+ val it = rs.elements;
+ val sb = new StringBuffer();
+ sb.append('(');
+ sb.append( it.next.toString() );
+ for( val z <- it ) {
+ sb.append( ',' );
+ sb.append( z.toString() );
+ }
+ sb.append( ')' );
+ sb.toString();
+ }
+}
+/** rs should be not empty */
+case class Alt(rs:RegExp*) extends RegExp {
+ final def mixed:boolean = {
+ val it = rs.elements;
+ ( it.next == PCDATA_ ) && it.forall { x:RegExp => x.isInstanceOf[RNode] }
+ }
+ override def toString() = {
+ val it = rs.elements;
+ val sb = new StringBuffer();
+ sb.append('(');
+ sb.append( it.next.toString() );
+ for( val z <- it ) {
+ sb.append( '|' );
+ sb.append( z.toString() );
+ }
+ sb.append(')');
+ sb.toString();
+ }
+}
diff --git a/sources/scala/xml/dtd/Scanner.scala b/sources/scala/xml/dtd/Scanner.scala
new file mode 100644
index 0000000000..1755975b52
--- /dev/null
+++ b/sources/scala/xml/dtd/Scanner.scala
@@ -0,0 +1,79 @@
+package scala.xml.dtd ;
+
+/** Scanner for regexps (content models in DTD element declarations) */
+class Scanner with Tokens {
+
+ // zzz constants zzz
+ final val ENDCH = '\u0000';
+
+ // zzz fields zzz
+ var token:Int = END;
+ var value:String = _;
+
+ private var it:Iterator[Char] = null;
+ private var c:Char = 'z';
+
+
+ /** initializes the scanner on input s */
+ final def initScanner( s:String ) = {
+ //Console.println("[scanner init on \""+s+"\"]");
+ value = "";
+ it = Iterator.fromString( s );
+ token = 1+END;
+ next;
+ nextToken;
+ }
+
+ /** scans the next token */
+ final def nextToken:Unit = {
+ if( token != END ) token = readToken;
+ //Console.println("["+token2string( token )+"]");
+ }
+
+ // zzz scanner methods zzz
+
+ // todo: see XML specification... probably isLetter,isDigit is fine
+ final def isIdentChar = { ('a' <= c && c <= 'z')
+ || ('A' <= c && c <= 'Z')};
+
+ final def next = if( it.hasNext ) c = it.next else c = ENDCH;
+
+ final def acc( d:char ):Unit =
+ if( c == d ) next; else error("expected '"+d+"' found '"+c+"' !");
+
+ final def accS( ds:Seq[Char] ):Unit = {
+ val jt = ds.elements; while( jt.hasNext ) { acc( jt.next ) }
+ }
+
+ final def isSpace = c match {
+ case '\u0020' | '\u0009' | '\u000D' | '\u000A' => true
+ case _ => false;
+ }
+
+ final def readToken:int = if( isSpace ) {
+ while( isSpace ) { it.next }; S
+ } else c match {
+ case '(' => next; LPAREN
+ case ')' => next; RPAREN
+ case ',' => next; COMMA
+ case '*' => next; STAR
+ case '+' => next; PLUS
+ case '?' => next; OPT
+ case '|' => next; CHOICE
+ case '#' => next; accS( "PCDATA" ); TOKEN_PCDATA
+ case ENDCH => END;
+ case _ =>
+ if( Utility.isNameStart( c ) ) name; // NAME
+ else {
+ error("unexpected character:"+c); END
+ }
+ }
+
+ final def name = {
+ val sb = new StringBuffer();
+ do { sb.append( c ); next } while ( Utility.isNameChar( c ) ) ;
+ value = sb.toString();
+ NAME
+ }
+
+}
diff --git a/sources/scala/xml/dtd/Tokens.scala b/sources/scala/xml/dtd/Tokens.scala
new file mode 100644
index 0000000000..458a1b37e4
--- /dev/null
+++ b/sources/scala/xml/dtd/Tokens.scala
@@ -0,0 +1,34 @@
+package scala.xml.dtd ;
+
+class Tokens {
+
+ // Tokens
+
+ final val TOKEN_PCDATA = 0;
+ final val NAME = 1;
+ final val EMPTY = 2;
+ final val LPAREN = 3;
+ final val RPAREN = 4;
+ final val COMMA = 5;
+ final val STAR = 6;
+ final val PLUS = 7;
+ final val OPT = 8;
+ final val CHOICE = 9;
+ final val END = 10;
+ final val S = 13;
+
+ final def token2string( i:int ):String = i.match {
+ case 0 => "#PCDATA";
+ case 1 => "NAME";
+ case 2 => "EMPTY";
+ case 3 => "(";
+ case 4 => ")";
+ case 5 => ",";
+ case 6 => "*";
+ case 7 => "+";
+ case 8 => "?";
+ case 9 => "|";
+ case 10 => "END";
+ case 13 => " ";
+ }
+}
diff --git a/sources/scalac/transformer/matching/BindingBerrySethi.java b/sources/scalac/transformer/matching/BindingBerrySethi.java
index eb31ddaf58..b2a8301516 100644
--- a/sources/scalac/transformer/matching/BindingBerrySethi.java
+++ b/sources/scalac/transformer/matching/BindingBerrySethi.java
@@ -55,6 +55,7 @@ public class BindingBerrySethi extends BerrySethi {
switch( pat ) {
case Apply(_, _):
case Literal( _ ):
+ case Select(_, _):
case Typed(_,_):
this.varAt.put( i, activeBinders.clone() ); // below @ ?
break;
diff --git a/sources/scalac/transformer/matching/TestRegTraverser.java b/sources/scalac/transformer/matching/TestRegTraverser.java
index ac00c3a366..bd01786734 100644
--- a/sources/scalac/transformer/matching/TestRegTraverser.java
+++ b/sources/scalac/transformer/matching/TestRegTraverser.java
@@ -53,6 +53,24 @@ public class TestRegTraverser extends Traverser {
//result = true;
break;
+ // Matthias PatternMatcher cannot handle this case
+ case Apply( Tree fn, Tree[] trees ):
+ if( trees.length == 1 ) {
+ switch (trees[ 0 ]) {
+ case Sequence( Tree[] trees2 ):
+ if( trees2.length == 1 ) {
+ switch (trees2[ 0 ]) {
+ case Sequence( _ ):
+ result = true;
+ break;
+ };
+ //System.out.println( fn );
+ //System.out.println( tree.type() );
+ }
+ }
+ }
+ super.traverse( tree );
+ break;
default:
super.traverse( tree );
}