summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.config2
-rw-r--r--config/list/library.lst1
-rw-r--r--sources/scala/tools/dtd2scala/DeclToScala.scala7
-rw-r--r--sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml9
-rw-r--r--sources/scala/tools/scalac/ast/parser/SymbolicXMLBuilder.scala9
-rw-r--r--sources/scala/xml/dtd/RegExp.scala75
-rw-r--r--sources/scala/xml/dtd/Validation.scala68
-rw-r--r--sources/scala/xml/dtd/ValidationException.scala23
-rw-r--r--test/files/xml/lnk.check1
-rw-r--r--test/files/xml/lnk.scala22
10 files changed, 183 insertions, 34 deletions
diff --git a/Makefile.config b/Makefile.config
index 52872f2971..15b4443881 100644
--- a/Makefile.config
+++ b/Makefile.config
@@ -105,7 +105,7 @@ PICO_FLAGS ?= -make -source 1.4
##############################################################################
# Bootstrap compiler
-BOOTSTRAP_SCALAC ?= /home/linuxsoft/apps/scala/bin/scalac
+BOOTSTRAP_SCALAC ?= scalac
##############################################################################
# Convert tool (ImageMagick)
diff --git a/config/list/library.lst b/config/list/library.lst
index b4000ffc06..f13fcb3280 100644
--- a/config/list/library.lst
+++ b/config/list/library.lst
@@ -181,6 +181,7 @@ xml/dtd/RegExp.scala
xml/dtd/Scanner.scala
xml/dtd/Tokens.scala
xml/dtd/Validation.scala
+xml/dtd/ValidationException.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 62a724187f..12b92e2fbf 100644
--- a/sources/scala/tools/dtd2scala/DeclToScala.scala
+++ b/sources/scala/tools/dtd2scala/DeclToScala.scala
@@ -12,7 +12,7 @@ import scala.collection.Map ;
import scala.collection.mutable.HashMap ;
import scala.xml._ ;
-import scala.xml.dtd.{AttrDecl,RegExp,ANY_,PCDATA_,Eps,Star,RNode,Sequ,Alt}
+import scala.xml.dtd.{AttrDecl,ElemDecl,RegExp,ANY_,PCDATA_,Eps,Star,RNode,Sequ,Alt}
import scala.xml.dtd.{REQUIRED,IMPLIED,DEFAULT};
import scala.xml.nobinding.XML ;
@@ -29,7 +29,7 @@ class DeclToScala(fOut: PrintWriter, objectName: String, namespace: String, elem
val lookup : HashMap[String,String] = new HashMap[String,String]();
var curAttribs: Map[String,AttrDecl] = null ; /* of current elem */
- var curModel : RegExp = null;
+ var curModel: RegExp = null;
/** 1.populate with special "<R" and default
**/
@@ -174,6 +174,9 @@ class DeclToScala(fOut: PrintWriter, objectName: String, namespace: String, elem
}
fOut.print(sb.toString());
+ case "elemDecl" =>
+ fOut.print(curModel.toString());
+
case "template" => {
lookup.update("objectName", objectName);
lookup.update("namespace", namespace);
diff --git a/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml b/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml
index 07449413d4..994b2411ae 100644
--- a/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml
+++ b/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml
@@ -73,13 +73,20 @@
new AttributeValidator(
<qstring ref="namespace"/>, <attributeDecls/>);
}
+
+ private val &ccElementName;Validator = {
+ import scala.xml.dtd._;
+ new ElementValidator(<qstring ref="namespace"/>, <elemDecl/>);
+ }
+
case class &ccElementName;( attrs:scala.xml.AttributeSeq, ch:scala.xml.Node* ) extends <string ref="objectName"/>Node$ {
+ &ccElementName;Validator.validate( ch );
final override def typeTag$ = <refTag/>;
final def label = &qElementName;;
- final def child = ch;
+ final def child = ch;
final def attributes = theAttrs;
val theAttrs = &ccElementName;AttribValidator.validate( attrs );
diff --git a/sources/scala/tools/scalac/ast/parser/SymbolicXMLBuilder.scala b/sources/scala/tools/scalac/ast/parser/SymbolicXMLBuilder.scala
index ca799d2fa2..b398aac51e 100644
--- a/sources/scala/tools/scalac/ast/parser/SymbolicXMLBuilder.scala
+++ b/sources/scala/tools/scalac/ast/parser/SymbolicXMLBuilder.scala
@@ -159,7 +159,7 @@ class SymbolicXMLBuilder(make: TreeFactory, gen: TreeGen, p: Parser, preserveWS:
* @todo map: a map of attributes !!!
*/
- def mkXML(pos:int, isPattern:boolean, namespace:Tree, label:Tree, attrs:Array[Tree], children:Array[Tree]):Tree = {
+ protected def mkXML(pos: int, isPattern: boolean, namespace: Tree, label: Tree, attrs: Array[Tree], children: Array[Tree]): Tree = {
if( isPattern ) {
val ts = new myTreeList();
ts.append( namespace );
@@ -386,7 +386,7 @@ class SymbolicXMLBuilder(make: TreeFactory, gen: TreeGen, p: Parser, preserveWS:
def qualified( pos:Int, name:String ):Pair[String,String] =
getPrefix( name ).match {
case Some( pref ) =>
- val newLabel = name.substring( pref.length(), name.length() );
+ val newLabel = name.substring( pref.length()+1, name.length() );
// if( newLabel.indexOf(':') != -1 ) syntaxError
Pair( "namespace$"+pref, newLabel );
case None =>
@@ -394,10 +394,10 @@ class SymbolicXMLBuilder(make: TreeFactory, gen: TreeGen, p: Parser, preserveWS:
}
/** makes an element */
- def makeXML(pos: int, labeln: Name, attrMap: ListMap[String,Tree], args: Array[Tree]): Tree={
+ def makeXML(pos: int, labeln: Name, attrMap1: ListMap[String,Tree], args: Array[Tree]): Tree={
var label = labeln.toString();
var setNS = ListMap.Empty[String, Tree];
-
+ var attrMap = attrMap1;
for( val z <- attrMap.keys; z.startsWith("xmlns") ) {
val i = z.indexOf(':');
@@ -407,6 +407,7 @@ class SymbolicXMLBuilder(make: TreeFactory, gen: TreeGen, p: Parser, preserveWS:
val zz = z.substring( i+1, z.length() );
setNS = setNS.update( zz, attrMap( z ));
}
+ attrMap = attrMap - z;
}
val i = label.indexOf(':');
val Pair( namespace, newlabel ) = qualified( pos, label );
diff --git a/sources/scala/xml/dtd/RegExp.scala b/sources/scala/xml/dtd/RegExp.scala
index c1b5956ba6..6ad414e73b 100644
--- a/sources/scala/xml/dtd/RegExp.scala
+++ b/sources/scala/xml/dtd/RegExp.scala
@@ -7,30 +7,71 @@ object RegExp {
}
/** abstract super class of regular expressions for DTD content models */
-abstract class RegExp ;
+abstract class RegExp {
+ def toRegExp(): String;
+ def getLabels: scala.collection.Set[String] = {
+ val s = new scala.collection.mutable.HashSet[String]();
+ def traverse1(xs: Seq[RegExp]): Unit = {
+ val it = xs.elements;
+ while( it.hasNext )
+ traverse( it.next );
+ }
+ def traverse(r: RegExp): Unit = {
+ r match {
+ case RNode( name ) => s += name;
+ case Star( x @ _ ) => traverse( x ); // bug if x@_*
+ case Sequ( xs @ _* ) => traverse1(xs);
+ case Alt( xs @ _* ) => traverse1(xs);
+ }
+ }
+ traverse( this );
+ return s
+ }
+}
case class RNode( name:String ) extends RegExp {
- override def toString() = name;
+ final def toRegExp() = name;
+ final override def toString() = {
+ val sb = new StringBuffer("RNode(\"");
+ sb.append(name);
+ sb.append('"');
+ sb.append(')');
+ sb.toString()
+ }
};
case object PCDATA_ extends RegExp {
- override def toString() = "#PCDATA";
+ final def toRegExp() = "#PCDATA";
+ override def toString() = "PCDATA_";
}
case object ANY_ extends RegExp {
- override def toString() = "ANY";
+ final def toRegExp() = "ANY";
+ override def toString() = "ANY_";
}
case object Eps extends RegExp {
- override def toString() = "()";
+ final def toRegExp() = "()";
+ override def toString() = "Eps";
}
case class Star(r:RegExp) extends RegExp {
- override def toString() = r.toString()+"*";
+ final def toRegExp() = r.toRegExp()+"*";
}
/** rs should be not empty */
case class Sequ(rs:RegExp*) extends RegExp {
- override def toString() = {
+ final def toRegExp() = {
val it = rs.elements;
val sb = new StringBuffer();
sb.append('(');
+ sb.append( it.next.toRegExp() );
+ for( val z <- it ) {
+ sb.append( ',' );
+ sb.append( z.toRegExp() );
+ }
+ sb.append( ')' );
+ sb.toString();
+ }
+ final override def toString() = {
+ val it = rs.elements;
+ val sb = new StringBuffer("Alt(");
sb.append( it.next.toString() );
for( val z <- it ) {
sb.append( ',' );
@@ -38,24 +79,34 @@ case class Sequ(rs:RegExp*) extends RegExp {
}
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() = {
+ final def toRegExp() = {
val it = rs.elements;
val sb = new StringBuffer();
sb.append('(');
- sb.append( it.next.toString() );
+ sb.append( it.next.toRegExp() );
for( val z <- it ) {
sb.append( '|' );
- sb.append( z.toString() );
+ sb.append( z.toRegExp() );
}
sb.append(')');
sb.toString();
}
+ final override def toString() = {
+ val it = rs.elements;
+ val sb = new StringBuffer("Alt(");
+ 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/Validation.scala b/sources/scala/xml/dtd/Validation.scala
index b9e9fbcaba..6073b5aaa8 100644
--- a/sources/scala/xml/dtd/Validation.scala
+++ b/sources/scala/xml/dtd/Validation.scala
@@ -4,20 +4,62 @@ import scala.collection.mutable;
import scala.collection.Set;
import scala.collection.Map;
-class ValidationException( e:String ) extends Exception( e );
-object ValidationException {
- def fromFixedAttribute( k: String, value: String, actual: String ) =
- new ValidationException("value of attribute " + k + " FIXED to \""+value+"\", but document tries \""+actual+"\"");
+class ElementValidator(namespace$$: String, elemSpec: RegExp) {
+ final val namespace = namespace$$.intern();
+
+ var autom:Autom = _;
+
+ trait Autom {
+ def run(s:Seq[Node]):Unit;
+ }
+
+ object TrivialAutom extends Autom {
+ def run(s:Seq[Node]):Unit = {};
+ }
+
+ object EmptyAutom extends Autom {
+ /** "not even entity references, PIs, etc" */
+ def run(s:Seq[Node]):Unit =
+ if( s.length != 0 )
+ throw MakeValidationException.fromNonEmptyElement();
+
+ }
+
+ object TextAutom extends Autom {
+ /** only text nodes, entity references, PIs, comments, etc" */
+ def run(s:Seq[Node]):Unit = {
+ val it = s.elements;
+ while( it.hasNext ) {
+ val n = it.next;
+ if( n.typeTag$ >= 0 )
+ throw MakeValidationException.fromUndefinedElement( n.label );
+ }
+ }
+ }
- def fromUndefinedAttribute( key:String ) =
- new ValidationException("undefined attribute " + key );
+ class MixedModeAutom(set:scala.collection.Set[String]) extends Autom {
+ def run(s:Seq[Node]):Unit = {
+ val it = s.elements;
+ while( it.hasNext ) {
+ val n = it.next;
+ if(( n.namespace == namespace )&& !set.contains( n.label ))
+ throw MakeValidationException.fromUndefinedElement( n.label );
+ }
+ }
+ }
- def fromMissingAttribute( allKeys:Set[String] ) = {
- new ValidationException("missing value for REQUIRED attribute"+
- { if( allKeys.size > 1 ) "s" else "" }+
- allKeys );
+ autom = elemSpec match {
+ case ANY_ => TrivialAutom;
+ case Eps => EmptyAutom;
+ case PCDATA_ | Sequ( PCDATA_ ) => TextAutom
+ case Star(z:Alt) if(( z.rs.length == 1 )&& (z.rs(0) match {
+ case PCDATA_ => true
+ case _ => false
+ })) => new MixedModeAutom( elemSpec.getLabels );
+ case _ => TrivialAutom;
}
+ def validate( nodes:Seq[Node] ):Unit = autom.run( nodes );
}
/** only CDATA attributes, ignores attributes that have different namespace
@@ -66,7 +108,7 @@ class AttributeValidator( namespace$$:String, attrSpec1: Seq[dtd.AttrDecl]) {
case Some( AttrDecl( key, tpe, df )) => df match {
case DEFAULT( true, attValue ) =>
if( b.value != attValue )
- ValidationException.fromFixedAttribute( key, attValue, b.value );
+ MakeValidationException.fromFixedAttribute( key, attValue, b.value );
else
add( attribs, b )
case REQUIRED =>
@@ -76,7 +118,7 @@ class AttributeValidator( namespace$$:String, attrSpec1: Seq[dtd.AttrDecl]) {
attribs = add( attribs, b )
}
case _ =>
- ValidationException.fromUndefinedAttribute( b.key )
+ MakeValidationException.fromUndefinedAttribute( b.key )
}
}
if( req - actualReq > 0 ) {
@@ -85,7 +127,7 @@ class AttributeValidator( namespace$$:String, attrSpec1: Seq[dtd.AttrDecl]) {
allKeys += key;
for( val a <- attribs )
allKeys -= a.key;
- ValidationException.fromMissingAttribute( allKeys )
+ MakeValidationException.fromMissingAttribute( allKeys )
}
new AttributeSeq( (attribsTemplate:::attribs):_* )
}
diff --git a/sources/scala/xml/dtd/ValidationException.scala b/sources/scala/xml/dtd/ValidationException.scala
new file mode 100644
index 0000000000..295c7ce929
--- /dev/null
+++ b/sources/scala/xml/dtd/ValidationException.scala
@@ -0,0 +1,23 @@
+package scala.xml.dtd ;
+
+case class ValidationException( e:String ) extends Exception( e );
+
+object MakeValidationException {
+ def fromFixedAttribute( k: String, value: String, actual: String ) =
+ ValidationException("value of attribute " + k + " FIXED to \""+value+"\", but document tries \""+actual+"\"");
+
+ def fromNonEmptyElement() = {
+ new ValidationException("element should be *empty*");
+ }
+ def fromUndefinedElement( label:String ) =
+ new ValidationException("element \""+ label +"\" not allowed here");
+
+ def fromUndefinedAttribute( key:String ) =
+ new ValidationException("attribute " + key +" not allowed here" );
+
+ def fromMissingAttribute( allKeys:scala.collection.Set[String] ) = {
+ new ValidationException("missing value for REQUIRED attribute"+
+ { if( allKeys.size > 1 ) "s" else "" }+
+ allKeys );
+ }
+}
diff --git a/test/files/xml/lnk.check b/test/files/xml/lnk.check
index e7dca84cc8..23312a819c 100644
--- a/test/files/xml/lnk.check
+++ b/test/files/xml/lnk.check
@@ -1,3 +1,4 @@
+validator throws exception: element "link" not allowed here
<link target="http://www.scala.org" xmlns="http://scala.epfl.ch/testSuite/links"><name>hello-link</name></link>
<lnkDB xmlns="http://scala.epfl.ch/testSuite/links"><linkgroup><groupname>LDAP Links</groupname><link target="http://www.openldap.org/doc/"><name>OpenLDAP Administration Guide</name><description>contains very readable section &quot;What is LDAP&quot;</description></link><linkgroup><groupname>LDAP RFCs</groupname><link target="ftp://ftp.isi.edu/in-notes/rfc2251.txt"><name>RFC2251 Lightweight Directory Access Protocol (v3)</name></link><link target="ftp://ftp.isi.edu/in-notes/rfc2252.txt"><name>Lightweight Directory Access Protocol (v3):
Attribute Syntax Definitions</name></link><link target="ftp://ftp.isi.edu/in-notes/rfc2253.txt"><name>Lightweight Directory Access Protocol (v3):
diff --git a/test/files/xml/lnk.scala b/test/files/xml/lnk.scala
index 8d81eae609..7d4c927efe 100644
--- a/test/files/xml/lnk.scala
+++ b/test/files/xml/lnk.scala
@@ -13,13 +13,33 @@ object Test {
//val b: Node = dtd._factory.get("link").match { case Some(x) => x(Nil,null)}; // safe
// !!! System.out.println(b.toXML);
- // construct data using constructor
+ // construct data using constructor (valid)
val c = Link(
new AttributeSeq(
Attribute("","target","http://www.scala.org")
),
Name(n, scala.xml.Text("hello-link"))
);
+
+ try {
+ val c2 = Name(
+ n,
+ Link( n )
+ );
+ Console.println("eh ?");
+ } catch {
+ case scala.xml.dtd.ValidationException(msg) => {
+ Console.print("validator throws exception: ");
+ Console.println( msg );
+ }
+ case z => // ignore
+ Console.println("whut??? "+z.getClass);
+
+ }
+
+
+
+
//c.getAttribs.update("target", "http://www.scala.org");
System.out.println( c );