summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorburaq <buraq@epfl.ch>2004-02-16 10:13:40 +0000
committerburaq <buraq@epfl.ch>2004-02-16 10:13:40 +0000
commit07f96aac397e7eff4ed59884b968722b48895b1b (patch)
tree5461e4b4b5d2ad441452219efa1f2408900625c1
parentb549b7bc7bd426db4a0fe18c20727e8b80057107 (diff)
downloadscala-07f96aac397e7eff4ed59884b968722b48895b1b.tar.gz
scala-07f96aac397e7eff4ed59884b968722b48895b1b.tar.bz2
scala-07f96aac397e7eff4ed59884b968722b48895b1b.zip
added support for XML patterns
-rw-r--r--sources/scala/tools/scalac/ast/parser/Parser.scala301
-rw-r--r--sources/scala/tools/scalac/ast/parser/Scanner.scala16
2 files changed, 205 insertions, 112 deletions
diff --git a/sources/scala/tools/scalac/ast/parser/Parser.scala b/sources/scala/tools/scalac/ast/parser/Parser.scala
index 68d2f09724..3e7342eb9a 100644
--- a/sources/scala/tools/scalac/ast/parser/Parser.scala
+++ b/sources/scala/tools/scalac/ast/parser/Parser.scala
@@ -360,17 +360,25 @@ class Parser(unit: Unit) {
make.LabelDef(pos, lname, new Array[Tree$Ident](0), rhs)
}
- def makeXML(pos:int, isPattern:boolean, t:Tree, args:Array[Tree]):Tree = {
- var symt = scalaDot(s.pos, Names.Symbol);
- if( isPattern ) symt = convertToTypeId(symt);
- val ts = new myTreeList();
- ts.append(t);
- ts.append(args);
- make.Apply(pos, symt, ts.toArray());
+ def mkXML(pos:int, isPattern:boolean, t:Tree, args:Array[Tree]):Tree = {
+ var symt = scalaDot(s.pos, Names.Symbol);
+ if( isPattern ) symt = convertToTypeId(symt);
+ val ts = new myTreeList();
+ ts.append(t);
+ ts.append(args);
+ make.Apply(pos, symt, ts.toArray());
}
+ def makeXMLpat(pos:int, n:Name, args:Array[Tree]):Tree =
+ mkXML(pos, true, gen.mkStringLit( pos, n.toString() ), args);
+
def makeXML(pos:int, n:Name, args:Array[Tree]):Tree =
- makeXML(pos, false, gen.mkStringLit( pos, n.toString() ), args);
+ mkXML(pos, false, gen.mkStringLit( pos, n.toString() ), args);
+
+ def makeXMLseq( pos:int, args:Array[Tree] ) = {
+ var symt = scalaDot(s.pos, Names.List);
+ make.Apply(pos, symt, args);
+ }
def makeXML(pos:int, n:Name, args:Array[Tree], attrMap:ListMap[Name,String]):Tree = {
val t = makeXML( pos, n, args );
@@ -383,7 +391,7 @@ class Parser(unit: Unit) {
x(0) = gen.mkStringLit( pos, key.toString() );
x(1) = gen.mkStringLit( pos, value.toString() );
x }
- ));
+ ));
i = i + 1;
};
make.Apply(pos,
@@ -392,7 +400,7 @@ class Parser(unit: Unit) {
x( 0 ) = make.Apply(pos,
scalaDot(s.pos, Names.List),
attrs);
- x })
+ x })
}
@@ -642,9 +650,9 @@ class Parser(unit: Unit) {
if (isSymLit) {
val pos = s.pos;
if (s.token == LPAREN || s.token == LBRACE)
- makeXML( pos, isPattern, t, argumentExprs() );
+ mkXML( pos, isPattern, t, argumentExprs() );
else
- makeXML( pos, isPattern, t, Tree.EMPTY_ARRAY );
+ mkXML( pos, isPattern, t, Tree.EMPTY_ARRAY );
} else {
t
}
@@ -985,9 +993,7 @@ class Parser(unit: Unit) {
t = literal(false);
case IDENTIFIER | THIS | SUPER =>
t = if( s.name == LT ) {
- val tt = xmlExpr(); /* top-level xml expression */
- s.nextToken();
- tt
+ xmlExprTop(); /* top-level xml expression */
} else {
stableRef(true, false);
}
@@ -1041,104 +1047,25 @@ class Parser(unit: Unit) {
null;//dummy
}
- /** '<' xmlExpr ::= STag { xmlExpr | '{' simpleExpr '}' } ETag
- ** '<' xmlExpr ::= EmptyElemTag
- */
- def xmlExpr():Tree = {
+ /** top level xml expression, resynchronizes after succesful parse
+ * see xmlExpr
+ */
+ def xmlExprTop():Tree = {
val pos = s.pos;
- var empty = false;
-
- /* [40] STag ::= '<' Name (S Attribute)* S? '>'
- * [41] Attribute ::= Name Eq AttValue
- * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
- */
- val elemName = s.xmlName();
- s.xmlSpaceOpt();
- var attrMap = ListMap.Empty[Name,String];
- while(( s.ch != '>' )&&( !empty )) {
- if( s.ch == '/' ) {
- s.nextch();
- empty = true;
- } else if( s.xml_isNameStart() ) {
- val attrName:Name = s.xmlName();
- s.xmlSpaceOpt();
- s.xmlToken('=');
- s.xmlSpaceOpt();
- var attrValue:String = "";
- val endch:char = s.ch.asInstanceOf[char];
- endch match {
- case '"' | '\'' => {
- s.nextch();
- attrValue = s.xmlValue( endch );
- s.xmlToken( endch.asInstanceOf[char] );
- s.xmlSpaceOpt();
- }
- case _ => s.xml_syntaxError("' or \" delimited value expected here");
- }
- if( attrMap.contains( attrName )) {
- s.xml_syntaxError("attribute "+attrName+" may only be defined once");
- }
- attrMap = attrMap.update( attrName, attrValue );
- } else {
- s.xml_syntaxError("attribute, > or /> expected in element declaration");
- }
- }
- s.xmlToken('>');
- /* Console.println("startTag of:"+elemName);*/
- s.xmlSpaceOpt();
- if( empty ) {
- makeXML( pos, elemName, Tree.EMPTY_ARRAY );
- } else { /* possible XML content: */
-
+ var t = xmlExpr();
+ s.nextToken();
+ if(( s.token == IDENTIFIER ) && ( s.name == LT )) {
val ts = new myTreeList();
- var exit = false;
- while( !exit ) {
- /* Console.println("read '"+s.ch.asInstanceOf[char]+"'"); */
- s.ch match {
- case '<' => { /* tag */
- s.nextch();
- if( s.ch != '/' ) { /* search end tag */
- ts.append( xmlExpr() );
- } else {
- exit = true
- }
- }
- case '{' => { /* Scala block */
- while( s.ch == '{' ) {
- s.nextToken();
- /* Console.println("{"); */
- s.nextToken();
- val bs = new myTreeList();
- val b = block( s.pos );
- if( s.token != RBRACE ) {
- s.xml_syntaxError(" expected end of Scala block");
- }
- /* Console.println("}"); */
- ts.append( b );
- }
- }
- case _ => { /* text */
- val pos = s.pos;
- val str = s.xmlText();/* text node */
- ts.append( gen.mkStringLit( pos, str ));
- }
-
- }
- }
-
- /* [42] ETag ::= '</' Name S? '>' */
- s.xmlToken('/');
- if( elemName != s.xmlName() )
- s.xml_syntaxError("expected closing tag of "+elemName);
- else {
- s.xmlSpaceOpt();
- s.xmlToken('>')
+ ts.append( t );
+ while(( s.token == IDENTIFIER ) && ( s.name == LT )) {
+ ts.append( xmlExpr() );
+ s.nextToken();
}
- /* Console.println("endTag of:"+elemName); */
- s.xmlSpaceOpt();
- makeXML( pos, elemName, ts.toArray(), attrMap );
+ t = makeXMLseq( pos, ts.toArray() );
}
+ t
}
+
/** ArgumentExprs ::= `(' [Exprs] `)'
* | BlockExpr
*/
@@ -1382,9 +1309,10 @@ class Parser(unit: Unit) {
reduceStack(false, base, top, 0, true)
}
- /** SimplePattern ::= varid
+ /** simplePattern ::= varid
* | `_'
* | literal
+ * | `<' xmlPatternTop
* | StableId [ `(' [Patterns] `)' ]
* | `(' [Patterns] `)'
* | (word: empty - nothing)
@@ -1395,6 +1323,8 @@ class Parser(unit: Unit) {
case IDENTIFIER | THIS =>
if (s.name == BAR) {
make.Sequence(s.pos, Tree.EMPTY_ARRAY); // ((nothing))
+ } else if (s.name == LT) {
+ xmlPatternTop()
} else {
var t = stableId();
while (s.token == LPAREN) {
@@ -1428,6 +1358,159 @@ class Parser(unit: Unit) {
syntaxError("illegal start of pattern", true)
}
+ def xmlTag():Tuple2[Name, ListMap[Name,String]] = {
+ var empty = false;
+
+ /* [40] STag ::= '<' Name (S Attribute)* S?
+ * [41] Attribute ::= Name Eq AttValue
+ * [44] EmptyElemTag ::= '<' Name (S Attribute)* S?
+ */
+ val elemName = s.xmlName();
+ s.xmlSpaceOpt();
+ var attrMap = ListMap.Empty[Name,String];
+ while( s.xml_isNameStart() ) {
+ val attrName:Name = s.xmlName();
+ s.xmlSpaceOpt();
+ s.xmlToken('=');
+ s.xmlSpaceOpt();
+ var attrValue:String = "";
+ val endch:char = s.ch.asInstanceOf[char];
+ endch match {
+ case '"' | '\'' => {
+ s.nextch();
+ attrValue = s.xmlValue( endch );
+ s.xmlToken( endch.asInstanceOf[char] );
+ s.xmlSpaceOpt();
+ }
+ case _ => s.xml_syntaxError("' or \" delimited value expected here");
+ }
+ if( attrMap.contains( attrName )) {
+ s.xml_syntaxError("attribute "+attrName+" may only be defined once");
+ }
+ attrMap = attrMap.update( attrName, attrValue );
+ }
+ Tuple2( elemName, attrMap );
+ }
+
+ /* [42] '<' xmlEndTag ::= '<' '/' Name S? '>' */
+ def xmlEndTag(n:Name) = {
+ s.xmlToken('/');
+ if( n != s.xmlName() ) s.xml_syntaxError("expected closing tag of "+n);
+ s.xmlSpaceOpt();
+ s.xmlToken('>')
+ }
+
+ /** '<' xmlExpr ::= xmlTag1 '>' { xmlExpr | '{' simpleExpr '}' } ETag
+ ** | xmlTag1 '\' '>'
+ */
+ def xmlExpr():Tree = {
+ val pos = s.pos;
+ val Tuple2(elemName, attrMap) = xmlTag();
+ if( s.ch == '/' ) {
+ s.xmlToken('/');
+ s.xmlToken('>');
+ makeXML( pos, elemName, Tree.EMPTY_ARRAY );
+ } else {
+ s.xmlToken('>'); /* handle XML content: */
+ s.xmlSpaceOpt();
+ val ts = new myTreeList();
+ var exit = false;
+ while( !exit ) {
+ /* Console.println("read '"+s.ch.asInstanceOf[char]+"'"); */
+ s.ch match {
+ case '<' => { /* tag */
+ s.nextch();
+ if( s.ch != '/' ) { /* search end tag */
+ ts.append( xmlExpr() );
+ s.xmlSpaceOpt();
+ } else {
+ exit = true
+ }
+ }
+ case '{' => { /* Scala block */
+ while( s.ch == '{' ) {
+ s.nextToken();
+ s.nextToken();
+ val bs = new myTreeList();
+ val b = block( s.pos );
+ if( s.token != RBRACE ) {
+ s.xml_syntaxError(" expected end of Scala block");
+ }
+ s.xmlSpaceOpt();
+ ts.append( b );
+ }
+ }
+ case _ => { /* text ? */
+ val pos = s.pos;
+ ts.append( gen.mkStringLit( pos, s.xmlText() ));
+ }
+ }
+ }
+ xmlEndTag( elemName );
+ s.xmlSpaceOpt();
+ if( attrMap.isEmpty )
+ makeXML( pos, elemName, ts.toArray() );
+ else
+ makeXML( pos, elemName, ts.toArray(), attrMap );
+ }
+ }
+
+ /** top level xml pattern, resynchronizes after succesful parse
+ * see xmlPattern
+ */
+ def xmlPatternTop():Tree = {
+ val t = xmlPattern();
+ s.nextToken();
+ t
+ }
+
+ /** '<' xmlPattern ::= Name [S] { xmlPattern | '{' pattern3 '}' } ETag
+ * | Name [S] '\' '>'
+ */
+ def xmlPattern():Tree = {
+ val pos = s.pos;
+ val elemName = s.xmlName();
+ s.xmlSpaceOpt();
+ if( s.ch == '/' ) {
+ s.xmlToken('/');
+ s.xmlToken('>');
+ makeXMLpat( pos, elemName, Tree.EMPTY_ARRAY );
+ } else { /* handle XML content: */
+ s.xmlToken('>');
+ val ts = new myTreeList();
+ var exit = false;
+ while( !exit ) {
+ //Console.print("["+s.ch.asInstanceOf[char]+"]");
+ s.ch match {
+ case '<' => { /* tag */
+ s.nextch();
+ if( s.ch != '/' ) { /* search end tag */
+ ts.append( xmlPattern() );
+ } else {
+ exit = true
+ }
+ }
+ case '{' => { /* Scala patterns */
+ while( s.ch == '{' ) {
+ s.nextToken();
+ s.nextToken();
+ val ps = patterns();
+ if( s.token != RBRACE ) {
+ s.xml_syntaxError(" expected end of Scala block");
+ }
+ ts.append( ps );
+ }
+ }
+ case _ => { /* text */
+ val pos = s.pos;
+ ts.append( gen.mkStringLit( pos, s.xmlText() ));
+ }
+ }
+ }
+ xmlEndTag( elemName );
+ makeXMLpat( pos, elemName, ts.toArray() );
+ }
+ }
////////// MODIFIERS ////////////////////////////////////////////////////////////
/** Modifiers ::= {Modifier}
diff --git a/sources/scala/tools/scalac/ast/parser/Scanner.scala b/sources/scala/tools/scalac/ast/parser/Scanner.scala
index 454ad6683b..27dd6c2725 100644
--- a/sources/scala/tools/scalac/ast/parser/Scanner.scala
+++ b/sources/scala/tools/scalac/ast/parser/Scanner.scala
@@ -668,7 +668,15 @@ class Scanner(_unit: Unit) extends TokenData {
* production
*/
def xml_nextch() = {
- nextch();
+ try {
+ nextch();
+ } catch {
+ case e:ArrayIndexOutOfBoundsException => {
+ token = EOF;
+ syntaxError(lastpos, "unclosed XML literal");
+ throw new ApplicationError("unclosed XML literal");
+ }
+ }
ch match {
case '\r' => {
cline = cline + 1;
@@ -753,11 +761,13 @@ class Scanner(_unit: Unit) extends TokenData {
}
def xmlValue(endch:char):String = {
- pos = Position.encode(cline, ccol);
+ lastpos = pos;
val index = bp;
while ( ch != endch ) {
- if(( ch == '<' )||( ch == '&' ))
+ if(( ch == '<' )||( ch == '&' )) {
+ pos = Position.encode(cline, ccol);
xml_syntaxError(ch.asInstanceOf[char]+" not allowed here");
+ }
xml_nextch();
};
pos = Position.encode(cline, ccol);