From b84faf92525a44149bc466cc48ab28251a08d161 Mon Sep 17 00:00:00 2001 From: buraq Date: Wed, 21 Jul 2004 15:30:36 +0000 Subject: independent of API --- .../tools/scalac/ast/parser/MarkupParser.scala | 366 ++++++++++++++++++++- .../scalac/ast/parser/SymbolicXMLBuilder.scala | 2 +- 2 files changed, 355 insertions(+), 13 deletions(-) diff --git a/sources/scala/tools/scalac/ast/parser/MarkupParser.scala b/sources/scala/tools/scalac/ast/parser/MarkupParser.scala index 75ec7aba04..c3108fb3ac 100644 --- a/sources/scala/tools/scalac/ast/parser/MarkupParser.scala +++ b/sources/scala/tools/scalac/ast/parser/MarkupParser.scala @@ -21,7 +21,7 @@ import scala.xml.{Text,TextBuffer}; import scala.xml.parsing.AttribValue ; package scala.tools.scalac.ast.parser { -class MarkupParser(unit: CompilationUnit, s: Scanner, p: Parser, presWS: boolean ) with scala.xml.parsing.MarkupParser[Tree,Tree] { +class MarkupParser(unit: CompilationUnit, s: Scanner, p: Parser, presWS: boolean ) /*with scala.xml.parsing.MarkupParser[Tree,Tree] */{ import Tokens.{EMPTY, LBRACE, RBRACE} ; import scala.tools.scalac.ast.{TreeList => myTreeList} @@ -31,8 +31,359 @@ class MarkupParser(unit: CompilationUnit, s: Scanner, p: Parser, presWS: boolean /** the XML tree factory */ val handle: SymbolicXMLBuilder = new SymbolicXMLBuilder( unit.global.make, unit.global.treeGen, p, presWS ); - //override type MarkupType = handle.MarkupType; - //override type AVType = handle.AVType; + /** holds the position in the source file */ + /*[Duplicate]*/ var pos: Int = _; + + /** holds temporary values of pos */ + /*[Duplicate]*/ var tmppos: Int = _; + + /** holds the next character */ + /*[Duplicate]*/ var ch: Char = _; + + /** character buffer, for names */ + /*[Duplicate]*/ protected val cbuf = new StringBuffer(); + + /** append Unicode character to name buffer*/ + /*[Duplicate]*/ protected def putChar(c: char) = cbuf.append( c ); + + /*[Duplicate]*/ var xEmbeddedBlock = false; + + /** munch expected XML token, report syntax error for unexpected */ + /*[Duplicate]*/ def xToken(that: Char): Unit = { + if( ch == that ) + nextch; + else + reportSyntaxError("'" + that + "' expected instead of '" + ch + "'"); + } + + /** checks whether next character starts a Scala block, if yes, skip it. + * @return true if next character starts a scala block + */ + /*[Duplicate]*/ def xCheckEmbeddedBlock:Boolean = { + xEmbeddedBlock = + enableEmbeddedExpressions && ( ch == '{' ) && { nextch;( ch != '{' ) }; + return xEmbeddedBlock; + } + + /** parse attribute and add it to listmap + * [41] Attributes ::= { S Name Eq AttValue } + * AttValue ::= `'` { _ } `'` + * | `"` { _ } `"` + * | `{` scalablock `}` + */ + /*[Duplicate]*/ def xAttributes = { + var aMap = new mutable.HashMap[String, AttribValue[Tree]]; + while( xml.Parsing.isNameStart( ch )) { + val key = xName; + xEQ; + val delim = ch; + val pos1 = pos; + val value:AttribValue[Tree] = ch match { + case '"' | '\'' => + nextch; + val tmp = xAttributeValue( delim ); + nextch; + handle.attributeCDataValue( pos1, tmp ); + case '{' if enableEmbeddedExpressions => + nextch; + handle.attributeEmbedded(pos1, xEmbeddedExpr); + case _ => + reportSyntaxError( "' or \" delimited attribute value or '{' scala-expr '}' expected" ); + handle.attributeCDataValue( pos1, "" ) + }; + // well-formedness constraint: unique attribute names + if( aMap.contains( key )) + reportSyntaxError( "attribute "+key+" may only be defined once" ); + aMap.update( key, value ); + if(( ch != '/' )&&( ch != '>' )) + xSpace; + }; + aMap + } + + /** attribute value, terminated by either ' or ". value may not contain <. + * @param endch either ' or " + */ + /*[Duplicate]*/ def xAttributeValue( endch:char ):String = { + while ( ch != endch ) { + putChar( ch ); + nextch; + }; + val str = cbuf.toString(); + cbuf.setLength( 0 ); + // @todo: normalize attribute value + // well-formedness constraint + if( str.indexOf('<') != -1 ) { + reportSyntaxError( "'<' not allowed in attrib value" ); "" + } else { + str + } + } + + /** parse a start or empty tag. + * [40] STag ::= '<' Name { S Attribute } [S] + * [44] EmptyElemTag ::= '<' Name { S Attribute } [S] + */ + /*[Duplicate]*/ def xTag: Pair[String, mutable.Map[String,AttribValue[Tree]]] = { + val elemName = xName; + xSpaceOpt; + val aMap = if(xml.Parsing.isNameStart( ch )) { + xAttributes; + } else { + new mutable.HashMap[String,AttribValue[Tree]](); + } + Tuple2( elemName, aMap ); + } + + /* [42] '<' xmlEndTag ::= '<' '/' Name S? '>' */ + /*[Duplicate]*/ def xEndTag(n: String) = { + xToken('/'); + val m = xName; + if(n != m) reportSyntaxError( "expected closing tag of " + n/* +", not "+m*/); + xSpaceOpt; + xToken('>') + } + + /** '"{char} ) ']]>' + * + * see [15] + */ + /*[Duplicate]*/ def xCharData: Tree = { + xToken('['); + xToken('C'); + xToken('D'); + xToken('A'); + xToken('T'); + xToken('A'); + xToken('['); + val pos1 = pos; + val sb:StringBuffer = new StringBuffer(); + while (true) { + if( ch==']' && + { sb.append( ch ); nextch; ch == ']' } && + { sb.append( ch ); nextch; ch == '>' } ) { + sb.setLength( sb.length() - 2 ); + nextch; + return handle.charData( pos1, sb.toString() ); + } else sb.append( ch ); + nextch; + } + throw new ApplicationError("this cannot happen"); + }; + + /** CharRef ::= "&#" '0'..'9' {'0'..'9'} ";" + * | "&#x" '0'..'9'|'A'..'F'|'a'..'f' { hexdigit } ";" + * + * see [66] + */ + /*[Duplicate]*/ def xCharRef:String = { + val hex = ( ch == 'x' ) && { nextch; true }; + val base = if (hex) 16 else 10; + var i = 0; + while( ch != ';' ) { + ch match { + case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => + i = i * base + Character.digit( ch, base ); + case 'a' | 'b' | 'c' | 'd' | 'e' | 'f' + | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' => + if( !hex ) + reportSyntaxError("hex char not allowed in decimal char ref\n" + +"Did you mean to write &#x ?"); + else + i = i * base + Character.digit( ch, base ); + case _ => + reportSyntaxError("character '"+ch+" not allowed in char ref\n"); + } + nextch; + } + new String( Predef.Array[char]( i.asInstanceOf[char] )) + } +/** Comment ::= '' + * + * see [15] + */ + /*[Duplicate]*/ def xComment: Tree = { + val sb:StringBuffer = new StringBuffer(); + xToken('-'); + xToken('-'); + while (true) { + if( ch=='-' && { sb.append( ch ); nextch; ch == '-' } ) { + sb.setLength( sb.length() - 1 ); + nextch; + xToken('>'); + return handle.comment( pos, sb.toString() ); + } else sb.append( ch ); + nextch; + } + throw new ApplicationError("this cannot happen"); + }; + + /*[Duplicate]*/ def appendText(pos: int, ts:mutable.Buffer[Tree], txt:String):Unit = { + if( !preserveWS ) + for( val t <- TextBuffer.fromString( txt ).toText ) { + ts.append( handle.text( pos, t.text ) ); + } + else + ts.append( handle.text( pos, txt )); + } + + /*[Duplicate]*/ def content: mutable.Buffer[Tree] = { + var ts = new mutable.ArrayBuffer[Tree]; + var exit = false; + while( !exit ) { + if( xEmbeddedBlock ) { + ts.append( xEmbeddedExpr ); + } else { + tmppos = pos; + ch match { + case '<' => // another tag + nextch; + ch match { + case '/' => + exit = true; // end tag + case '!' => + nextch; + if( '[' == ch ) // CDATA + ts.append( xCharData ); + else // comment + ts.append( xComment ); + case '?' => // PI + nextch; + ts.append( xProcInstr ); + case _ => + ts.append( element ); // child + } + + case '{' => + if( xCheckEmbeddedBlock ) { + ts.append(xEmbeddedExpr); + } else { + val str = new StringBuffer("{"); + str.append( xText ); + appendText(tmppos, ts, str.toString()); + } + // postcond: xEmbeddedBlock == false! + case '&' => // EntityRef or CharRef + nextch; + ch match { + case '#' => // CharacterRef + nextch; + val theChar = handle.text( tmppos, xCharRef ); + xToken(';'); + ts.append( theChar ); + case _ => // EntityRef + val n = xName ; + xToken(';'); + ts.append( handle.entityRef( tmppos, n ) ); + } + case _ => // text content + appendText(tmppos, ts, xText); + // here xEmbeddedBlock might be true + } + } + } + ts + } /* end content */ + + /** '<' element ::= xmlTag1 '>' { xmlExpr | '{' simpleExpr '}' } ETag + * | xmlTag1 '/' '>' + */ + /*[Duplicate]*/ def element: Tree = { + var pos1 = pos; + val Tuple2(qname, attrMap) = xTag; + if(ch == '/') { // empty element + xToken('/'); + xToken('>'); + handle.element( pos1, qname, attrMap, new mutable.ListBuffer[Tree] ); + } else { // handle content + xToken('>'); + val ts = content; + xEndTag( qname ); + handle.element( pos1, qname, attrMap, ts ); + } + } + + + /** Name ::= (Letter | '_' | ':') (NameChar)* + * + * see [5] of XML 1.0 specification + */ + /*[Duplicate]*/ def xName: String = { + if( xml.Parsing.isNameStart( ch ) ) { + do { + putChar( ch ); + nextch; + } while( xml.Parsing.isNameChar( ch ) ); + val n = cbuf.toString().intern(); + cbuf.setLength( 0 ); + n + } else { + reportSyntaxError( "name expected" ); + new String(); + } + } + + + /** scan [S] '=' [S]*/ + /*[Duplicate]*/ def xEQ = { xSpaceOpt; xToken('='); xSpaceOpt } + + /** skip optional space S? */ + /*[Duplicate]*/ def xSpaceOpt = { while( xml.Parsing.isSpace( ch ) ) { nextch; }} + + /** scan [3] S ::= (#x20 | #x9 | #xD | #xA)+ */ + /*[Duplicate]*/ def xSpace = { + if( xml.Parsing.isSpace( ch ) ) { + nextch; xSpaceOpt + } else { + reportSyntaxError("whitespace expected"); + } + } + +/** '?' {Char})]'?>' + * + * see [15] + */ + /*[Duplicate]*/ def xProcInstr: Tree = { + val sb:StringBuffer = new StringBuffer(); + val n = xName; + if( xml.Parsing.isSpace( ch ) ) { + xSpace; + while( true ) { + if( ch=='?' && { sb.append( ch ); nextch; ch == '>' } ) { + sb.setLength( sb.length() - 1 ); + nextch; + return handle.procInstr(tmppos, n.toString(), sb.toString()); + } else + sb.append( ch ); + nextch; + } + }; + xToken('?'); + xToken('>'); + return handle.procInstr(tmppos, n.toString(), sb.toString()); + } + + /** parse character data. + * precondition: xEmbeddedBlock == false (we are not in a scala block) + */ + /*[Duplicate]*/ def xText: String = { + if( xEmbeddedBlock ) throw new ApplicationError("internal error: encountered embedded block"); // assert + + if( xCheckEmbeddedBlock ) + return "" + else { + var exit = false; + while( !exit ) { + putChar( ch ); + exit = { nextch; xCheckEmbeddedBlock }||( ch == '<' ) || ( ch == '&' ); + } + val str = cbuf.toString(); + cbuf.setLength( 0 ); + str + } + } + //override type Tree = handle.Tree; + //override type Tree = handle.Tree; /** the XML tree builder */ val gen = unit.global.treeGen ; @@ -224,14 +575,5 @@ class MarkupParser(unit: CompilationUnit, s: Scanner, p: Parser, presWS: boolean handle.makeXMLpat( pos1, qname, ts ); } - - override def appendText(pos: int, ts:mutable.Buffer[Tree], txt:String):Unit = { - if( !preserveWS ) - for( val t <- TextBuffer.fromString( txt ).toText ) { - ts.append( handle.text( pos, t.text ) ); - } - else - ts.append( handle.text( pos, txt )); - } } /* class MarkupParser */ } diff --git a/sources/scala/tools/scalac/ast/parser/SymbolicXMLBuilder.scala b/sources/scala/tools/scalac/ast/parser/SymbolicXMLBuilder.scala index 71f634efb1..1f5164f3cf 100644 --- a/sources/scala/tools/scalac/ast/parser/SymbolicXMLBuilder.scala +++ b/sources/scala/tools/scalac/ast/parser/SymbolicXMLBuilder.scala @@ -23,7 +23,7 @@ import scalac.util.{ Name, Names, TypeNames } ; package scala.tools.scalac.ast.parser { /** this class builds instance of Tree that represent XML */ -class SymbolicXMLBuilder(make: TreeFactory, gen: TreeGen, p: Parser, preserveWS: Boolean ) extends MarkupHandler[Tree,Tree] { +class SymbolicXMLBuilder(make: TreeFactory, gen: TreeGen, p: Parser, preserveWS: Boolean ) /*extends MarkupHandler[Tree,Tree]*/ { import scala.tools.scalac.ast.{TreeList => myTreeList} -- cgit v1.2.3