From 993ae3423712e393b64888efa943ee1a2a3481ba Mon Sep 17 00:00:00 2001 From: michelou Date: Tue, 15 May 2007 09:11:48 +0000 Subject: [PATCH] merged Burak's destructive rev11032 with rev11031 git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@11034 5e8d7ff9-d8ef-0310-90f0-a4852d11357a --- build.xml | 2 +- .../scala/tools/nsc/ast/NodePrinters.scala | 2 +- .../tools/nsc/ast/parser/MarkupParsers.scala | 1257 ++++++++--------- 3 files changed, 625 insertions(+), 636 deletions(-) diff --git a/build.xml b/build.xml index 00de75755..48e364927 100644 --- a/build.xml +++ b/build.xml @@ -1049,7 +1049,7 @@ GENERATES A DISTRIBUTION - + diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index 0cce3aec5..f114426d3 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -191,7 +191,7 @@ abstract class NodePrinters { case Super(qual, mix) => printcln("Super(\"" + qual + "\", \"" + mix + "\")" + nodeinfo2(tree)) case Template(parents, self, body) => - println("Template(," + nodeinfo(tree)) + println("Template(" + nodeinfo(tree)) println(" " + parents.map(p => p.tpe.symbol) + ", // parents") if (body.isEmpty) println(" List() // no body") diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index 0c068a766..9e62e0e3e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -6,7 +6,6 @@ package scala.tools.nsc.ast.parser -import scala.collection.immutable.ListMap import scala.collection.mutable import scala.tools.nsc.util.Position import scala.xml.{Text, TextBuffer} @@ -19,682 +18,672 @@ import scala.xml.{Text, TextBuffer} trait MarkupParsers { self: SyntaxAnalyzer => - case object MissingEndTagException extends RuntimeException { - override def getMessage = "start tag was here: " - } + case object MissingEndTagException extends RuntimeException { + override def getMessage = "start tag was here: " + } - case object ConfusedAboutBracesException extends RuntimeException { - override def getMessage = " I encountered a '}' where I didn't expect one, maybe this tag isn't closed <" - } + case object ConfusedAboutBracesException extends RuntimeException { + override def getMessage = " I encountered a '}' where I didn't expect one, maybe this tag isn't closed <" + } import global._ //import posAssigner.atPos -class MarkupParser(p: UnitParser, presWS: boolean) /*with scala.xml.parsing.MarkupParser[Tree,Tree] */{ + class MarkupParser(p: UnitParser, presWS: boolean) /*with scala.xml.parsing.MarkupParser[Tree,Tree] */{ - import Tokens.{EMPTY, LBRACE, RBRACE} + import Tokens.{EMPTY, LBRACE, RBRACE} - final val preserveWS = presWS + final val preserveWS = presWS - import p.{symbXMLBuilder => handle} - def s = p.in - import p.in.g2p - import p.in.p2g - import p.in.token + import p.{symbXMLBuilder => handle} + def s = p.in + import p.in.g2p + import p.in.p2g + import p.in.token - /** holds the position in the source file */ - /*[Duplicate]*/ var pos: Position = _ + /** holds the position in the source file */ + /*[Duplicate]*/ var pos: Position = _ - /** holds temporary values of pos */ - /*[Duplicate]*/ var tmppos: Position = _ + /** holds temporary values of pos */ + /*[Duplicate]*/ var tmppos: Position = _ - /** holds the next character */ - /*[Duplicate]*/ var ch: Char = _ + /** holds the next character */ + /*[Duplicate]*/ var ch: Char = _ - /** character buffer, for names */ - /*[Duplicate]*/ protected val cbuf = new StringBuilder() + /** character buffer, for names */ + /*[Duplicate]*/ protected val cbuf = new StringBuilder() - /** append Unicode character to name buffer*/ - /*[Duplicate]*/ protected def putChar(c: char) = cbuf.append(c) + /** append Unicode character to name buffer*/ + /*[Duplicate]*/ protected def putChar(c: char) = cbuf.append(c) - /*[Duplicate]*/ var xEmbeddedBlock = false + /*[Duplicate]*/ var xEmbeddedBlock = false - /** munch expected XML token, report syntax error for unexpected. - * - * @param that ... - */ - /*[Duplicate]*/ def xToken(that: Char): Unit = { - if (ch == that) - nextch - else - reportSyntaxError("'" + that + "' expected instead of '" + ch + "'") - } - var debugLastStartElement = new mutable.Stack[(Position, String)] + /** munch expected XML token, report syntax error for unexpected. + * + * @param that ... + */ + /*[Duplicate]*/ def xToken(that: Char) { + 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 = { - // attentions, side-effect, used in xText - xEmbeddedBlock = ( ch == '{' ) && { nextch;( ch != '{' ) } - //Console.println("pos = "+pos+" xEmbeddedBlock returns "+xEmbeddedBlock) - return xEmbeddedBlock; - } + var debugLastStartElement = new mutable.Stack[(Position, String)] - /** parse attribute and add it to listmap - * [41] Attributes ::= { S Name Eq AttValue } - * AttValue ::= `'` { _ } `'` - * | `"` { _ } `"` - * | `{` scalablock `}` - */ - /*[Duplicate]*/ def xAttributes = { - var aMap = new mutable.HashMap[String, 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 - try { - handle.parseAttribute(pos1, tmp) - } catch { - case e => - reportSyntaxError("error parsing attribute value") - p.errorTermTree - } + /** 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 = { + // attentions, side-effect, used in xText + xEmbeddedBlock = (ch == '{') && { nextch; (ch != '{') } + //Console.println("pos = "+pos+" xEmbeddedBlock returns "+xEmbeddedBlock) + 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, 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 + try { + handle.parseAttribute(pos1, tmp) + } catch { + case e => + reportSyntaxError("error parsing attribute value") + p.errorTermTree + } - case '{' => + case '{' => + nextch + xEmbeddedExpr + case _ => + reportSyntaxError("' or \" delimited attribute value" + + " or '{' scala-expr '}' expected" ) + Literal(Constant("")) + } + // 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: (String, mutable.Map[String, Tree]) = { + val elemName = xName + xSpaceOpt + val aMap = + if (xml.Parsing.isNameStart(ch)) xAttributes + else new mutable.HashMap[String, Tree]() + (elemName, aMap) + } + + /** [42] '<' xmlEndTag ::= '<' '/' Name S? '>' + */ + /*[Duplicate]*/ def xEndTag(startName: String) { + xToken('/') + val endName = xName + if (endName != startName) { + reportSyntaxError("expected closing tag of " + startName) + throw MissingEndTagException + } + 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: StringBuilder = new StringBuilder() + while (true) { + if (ch==']' && + { sb.append(ch); nextch; ch == ']' } && + { sb.append(ch); nextch; ch == '>' }) { + sb.setLength(sb.length() - 2) nextch - xEmbeddedExpr - case _ => - reportSyntaxError("' or \" delimited attribute value" + - " or '{' scala-expr '}' expected" ) - Literal(Constant("")) - } - // 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: (String, mutable.Map[String, Tree]) = { - val elemName = xName - xSpaceOpt - val aMap = - if (xml.Parsing.isNameStart(ch)) xAttributes - else new mutable.HashMap[String, 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*/); - throw MissingEndTagException - } - 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: StringBuilder = new StringBuilder() - while (true) { - if (ch==']' && - { sb.append(ch); nextch; ch == ']' } && - { sb.append(ch); nextch; ch == '>' }) { - sb.setLength(sb.length() - 2) + return handle.charData(pos1, sb.toString()) + } else + sb.append(ch) nextch - return handle.charData(pos1, sb.toString()) - } else sb.append(ch) - nextch + } + Predef.error("this cannot happen") } - Predef.error("this cannot happen") - } - def xUnparsed: Tree = { - val pos1 = pos - val sb: StringBuilder = new StringBuilder() - while (true) { - if (ch=='<' && - { sb.append(ch); nextch; ch == '/' } && - { sb.append(ch); nextch; ch == 'x' } && - { sb.append(ch); nextch; ch == 'm' } && - { sb.append(ch); nextch; ch == 'l' } && - { sb.append(ch); nextch; ch == ':' } && - { sb.append(ch); nextch; ch == 'u' } && - { sb.append(ch); nextch; ch == 'n' } && - { sb.append(ch); nextch; ch == 'p' } && - { sb.append(ch); nextch; ch == 'a' } && - { sb.append(ch); nextch; ch == 'r' } && - { sb.append(ch); nextch; ch == 's' } && - { sb.append(ch); nextch; ch == 'e' } && - { sb.append(ch); nextch; ch == 'd' } && - { sb.append(ch); nextch; ch == '>' }) { - sb.setLength(sb.length - "' }) { + sb.setLength(sb.length - " - i = i * base + ch.asDigit - 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 + /** 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 + ch.asDigit - case _ => - reportSyntaxError("character '"+ch+" not allowed in char ref\n") - } - nextch - } - new String(Array(i.asInstanceOf[char])) - } - - /** Comment ::= '' - * - * see [15] - */ - /*[Duplicate]*/ def xComment: Tree = { - val sb: StringBuilder = new StringBuilder() - xToken('-') - xToken('-') - while (true) { - if( ch=='-' && { sb.append(ch); nextch; ch == '-' } ) { - sb.setLength(sb.length() - 1) + 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 + ch.asDigit + case _ => + reportSyntaxError("character '"+ch+" not allowed in char ref\n") + } nextch - xToken('>') - return handle.comment(pos, sb.toString()) - } else sb.append(ch) - nextch + } + new String(Array(i.asInstanceOf[char])) } - Predef.error("this cannot happen") - } - /** - * @param pos ... - * @param ts ... - * @param txt ... - */ - /*[Duplicate]*/ def appendText(pos: Position, ts: mutable.Buffer[Tree], - txt: String): Unit = - if (!preserveWS) { - for (t <- TextBuffer.fromString(txt).toText) { - ts.append(handle.text(pos, t.text)) + /** Comment ::= '' + * + * see [15] + */ + /*[Duplicate]*/ def xComment: Tree = { + val sb: StringBuilder = new StringBuilder() + 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 + } + Predef.error("this cannot happen") + } + + /** + * @param pos ... + * @param ts ... + * @param txt ... + */ + /*[Duplicate]*/ def appendText(pos: Position, ts: mutable.Buffer[Tree], + txt: String): Unit = + if (!preserveWS) { + for (t <- TextBuffer.fromString(txt).toText) { + ts.append(handle.text(pos, t.text)) + } + } + else + ts.append( handle.text(pos, txt)) + + /** adds entity/character to to ts as side-effect + * @precond ch == '&' + */ + def content_AMP(ts: mutable.ArrayBuffer[Tree]) { + 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)) } } - else - ts.append( handle.text(pos, txt)) - /** adds entity/character to to ts as side-effect - * @precond ch == '&' - */ - def content_AMP(ts: mutable.ArrayBuffer[Tree]): Unit = { - 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)) - } - } - - /** - * @precond ch == '{' - * @postcond: xEmbeddedBlock == false! - */ - def content_BRACE(p: Position, ts:mutable.ArrayBuffer[Tree]): Unit = { - if (xCheckEmbeddedBlock) - ts.append(xEmbeddedExpr) - else { - appendText(p, ts, xText)/* - val str = new StringBuilder("{") - str.append(xText) - nextch - appendText(p, ts, str.toString())*/ - } - } - - /** Returns true if it encounters an end tag (without consuming it), - * appends trees to ts as side-effect. - * - * @param ts ... - * @return ... - */ - def content_LT(ts: mutable.ArrayBuffer[Tree]): Boolean = { - ch match { - case '/' => - return true // end tag - case '!' => - nextch // CDATA or Comment - ts.append(if ('[' == ch) xCharData else xComment) - case '?' => // PI - nextch - ts.append(xProcInstr) - case _ => - ts.append(element) // child node - } - false - } - - /*[Duplicate]*/ def content: mutable.Buffer[Tree] = { - var ts = new mutable.ArrayBuffer[Tree] - var exit = false - while (!exit) { - if (xEmbeddedBlock) + /** + * @precond ch == '{' + * @postcond: xEmbeddedBlock == false! + */ + def content_BRACE(p: Position, ts:mutable.ArrayBuffer[Tree]) { + if (xCheckEmbeddedBlock) ts.append(xEmbeddedExpr) else { - tmppos = pos; - ch match { - case '<' => // end tag, cdata, comment, pi or child node - nextch - exit = content_LT(ts) - case '{' => // either the character '{' or an embedded scala block - content_BRACE(tmppos, ts) - case '&' => // EntityRef or CharRef - content_AMP(ts) - case _ => // text content - appendText(tmppos, ts, xText) - // here xEmbeddedBlock might be true + appendText(p, ts, xText)/* + val str = new StringBuilder("{") + str.append(xText) + nextch + appendText(p, ts, str.toString())*/ + } + } + + /** Returns true if it encounters an end tag (without consuming it), + * appends trees to ts as side-effect. + * + * @param ts ... + * @return ... + */ + private def content_LT(ts: mutable.ArrayBuffer[Tree]): Boolean = { + ch match { + case '/' => + return true // end tag + case '!' => + nextch // CDATA or Comment + ts.append(if ('[' == ch) xCharData else xComment) + case '?' => // PI + nextch + ts.append(xProcInstr) + case _ => + ts.append(element) // child node + } + false + } + + /*[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 '<' => // end tag, cdata, comment, pi or child node + nextch + exit = content_LT(ts) + case '{' => // either the character '{' or an embedded scala block + content_BRACE(tmppos, ts) + case '&' => // EntityRef or CharRef + content_AMP(ts) + case _ => // text content + appendText(tmppos, ts, xText) + // here xEmbeddedBlock might be true + } + } + } + ts + } + + /** '<' element ::= xmlTag1 '>' { xmlExpr | '{' simpleExpr '}' } ETag + * | xmlTag1 '/' '>' + */ + /*[Duplicate]*/ def element: Tree = { + val pos1 = pos + val (qname, attrMap) = xTag + if (ch == '/') { // empty element + xToken('/') + xToken('>') + handle.element(pos1, qname, attrMap, new mutable.ListBuffer[Tree]) + } + else { // handle content + xToken('>') + if (qname == "xml:unparsed") + return xUnparsed + + debugLastStartElement.push((pos1, qname)) + val ts = content + xEndTag(qname) + debugLastStartElement.pop + qname match { + case "xml:group" => handle.group(pos1, ts) + case _ => handle.element(pos1, qname, attrMap, ts) } } } - ts - } /* end content */ - /** '<' element ::= xmlTag1 '>' { xmlExpr | '{' simpleExpr '}' } ETag - * | xmlTag1 '/' '>' - */ - /*[Duplicate]*/ def element: Tree = { - val pos1 = pos - val Tuple2(qname, attrMap) = xTag - //Console.println("MarkupParser::element("+qname+","+attrMap+")"); - if (ch == '/') { // empty element - xToken('/') - xToken('>') - handle.element(pos1, qname, attrMap, new mutable.ListBuffer[Tree]) + /** actually, Name ::= (Letter | '_' | ':') (NameChar)* but starting with ':' cannot happen + * Name ::= (Letter | '_') (NameChar)* + * + * see [5] of XML 1.0 specification + * + * pre-condition: ch != ':' // assured by definition of XMLSTART token + * post-condition: name does neither start, nor end in ':' + */ + /*[Duplicate]*/ def xName: String = { + if ( !xml.Parsing.isNameStart(ch)) { + reportSyntaxError("name expected, but char '"+ch+"' cannot start a name") + return "" + } + do { + putChar(ch) + nextch + } while (xml.Parsing.isNameChar(ch)) + if (':' == cbuf.charAt(cbuf.length-1)) { + reportSyntaxError( "name cannot end in ':'" ) + cbuf.setLength(cbuf.length-1) + } + val n = cbuf.toString().intern() + cbuf.setLength(0) + n } - else { // handle content - xToken('>') - if(qname == "xml:unparsed") - return xUnparsed + /** 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: StringBuilder = new StringBuilder() + 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('>') + 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) Predef.error("internal error: encountered embedded block"); // assert + //Console.println("xText ch now "+ch) + //if( xCheckEmbeddedBlock ) { + // return "" + //} else { + var exit = false + while (!exit) { + putChar(ch) + val expectRBRACE = ch == '}' + // TODO check for "}}" + nextch + if (expectRBRACE) { + if (ch == '}') + nextch + else + reportSyntaxError("in XML content, please use '}}' to express '}'") + throw ConfusedAboutBracesException + } + exit = xCheckEmbeddedBlock ||(ch == '<') || (ch == '&') + } + val str = cbuf.toString() + cbuf.setLength(0) + str + //} + } + + //val cbuf = new StringBuilder() + + /** append Unicode character to name buffer*/ + //private def putChar(c: char) = cbuf.append(c) + + /** xLiteral = element { element } + * @return Scala representation of this xml literal + * precondition: s.xStartsXML == true + */ + def xLiteral: Tree = try { + init; pushScannerState + handle.isPattern = false + val pos = s.currentPos + var lastend = 0 + var lastch = ch + var tree:Tree = null + val ts = new mutable.ArrayBuffer[Tree]() + tmppos = pos // Iuli: added this line, as it seems content_LT uses tmppos when creating trees + content_LT(ts) + //Console.println("xLiteral:ts = "+ts.toList) + lastend = s.in.bp + lastch = s.in.ch + //if (settings.debug.value) { + // Console.println("DEBUG 1: I am getting char '"+ch+"' at lastend "+lastend+" pos = "+pos); // DEBUG + //} + xSpaceOpt + // parse more XML ? + if (ch == '<') { + //val ts = new mutable.ArrayBuffer[Tree](); + //ts.append( tree ); + while (ch == '<') { + nextch + ts.append(element) + lastend = s.in.bp + lastch = s.in.ch + xSpaceOpt + } + tree = handle.makeXMLseq((pos), ts) + } else { + assert(ts.length == 1) + tree = ts(0) + } + s.in.bp = lastend // ugly hack + s.in.ch = lastch + //if (settings.debug.value) { + // Console.println("DEBUG 2: restoring char '"+lastch+"' at lastend "+lastend+" pos = "+pos); // DEBUG + //} + //Console.println("out of xLiteral, parsed:"+tree.toString()); + s.next.token = Tokens.EMPTY; + s.nextToken + popScannerState + tree + } + catch { + case c @ (MissingEndTagException | ConfusedAboutBracesException) => + s.syntaxError((debugLastStartElement.top._1), + c.getMessage + debugLastStartElement.top._2+">") + EmptyTree + + case _:ArrayIndexOutOfBoundsException => + s.syntaxError((debugLastStartElement.top._1), + "missing end tag in XML literal for <" + +debugLastStartElement.top._2+">"); + EmptyTree + } + + /** @see xmlPattern. resynchronizes after successful parse + * @return this xml pattern + * precondition: s.xStartsXML == true + */ + def xLiteralPattern: Tree = try { + init; pushScannerState + val oldMode = handle.isPattern; + handle.isPattern = true + var tree = xPattern; xSpaceOpt; + handle.isPattern = oldMode; + s.next.token = Tokens.EMPTY; + s.nextToken + popScannerState + tree + } catch { + case c @ (MissingEndTagException | ConfusedAboutBracesException) => + s.syntaxError((debugLastStartElement.top._1), + c.getMessage + debugLastStartElement.top._2+">") + EmptyTree + + case _:ArrayIndexOutOfBoundsException => + s.syntaxError((debugLastStartElement.top._1), + "missing end tag in XML literal for <" + +debugLastStartElement.top._2+">") + EmptyTree + } + + def xEmbeddedExpr: Tree = { + sync + val b = p.block() //p.expr(true,false); + if (/*s.*/token != RBRACE) { + reportSyntaxError(" expected end of Scala block") + } + init + b + } + + /** xScalaPatterns ::= patterns + */ + def xScalaPatterns: List[Tree] = { + sync + val b = p.patterns(true) + if (/*s.*/token != RBRACE) { + reportSyntaxError(" expected end of Scala patterns") + } + init + b + } + + //var ch: Char = _; + + /** this method assign the next character to ch and advances in input */ + def nextch { s.in.next; /*s.xNext;*/ ch = s.in.ch ; pos = s.in.cpos } + + //def lookahead = { s.xLookahead } + var scannerState: List[List[Int]] = Nil + + private def pushScannerState { + scannerState = s.sepRegions :: scannerState + s.sepRegions = Nil + } + + private def popScannerState { + s.sepRegions = scannerState.head + scannerState = scannerState.tail + } + + private def init { + ch = s.in.ch + pos = s.in.cpos + } + + def reportSyntaxError(str: String) = { + s.syntaxError(pos-1, "in XML literal: " + str) + nextch + } + + private def sync { + xEmbeddedBlock = false + s.xSync + } + + /** '<' xPattern ::= Name [S] { xmlPattern | '{' pattern3 '}' } ETag + * | Name [S] '/' '>' + */ + def xPattern: Tree = { + val pos1 = pos + val qname = xName debugLastStartElement.push((pos1, qname)) - val ts = content + xSpaceOpt + if (ch == '/') { // empty tag + nextch + xToken('>') + return handle.makeXMLpat(pos1, qname, new mutable.ArrayBuffer[Tree]()) + } + + // else: tag with content + xToken('>') + var ts = new mutable.ArrayBuffer[Tree] + var exit = false + while (! exit) { + val pos2 = pos + if (xEmbeddedBlock) { + ts ++ xScalaPatterns + } else + ch match { + case '<' => // tag + nextch + if (ch != '/') { //child + ts.append(xPattern) + } else { + exit = true + } + case '{' => // embedded Scala patterns + while (ch == '{') { + s.in.next + ts ++ xScalaPatterns + } + // postcond: xEmbeddedBlock = false; + if (xEmbeddedBlock) Predef.error("problem with embedded block"); // assert + case _ => // teMaxt + appendText(pos2, ts, xText) + // here xEmbeddedBlock might be true; + //if( xEmbeddedBlock ) throw new ApplicationError("after:"+text); // assert + } + } xEndTag(qname) debugLastStartElement.pop - qname match { - case "xml:group" => handle.group(pos1, ts) - case _ => handle.element(pos1, qname, attrMap, ts) - } - } - } - - - /** actually, Name ::= (Letter | '_' | ':') (NameChar)* but starting with ':' cannot happen - ** Name ::= (Letter | '_') (NameChar)* - * - * see [5] of XML 1.0 specification - * - * pre-condition: ch != ':' // assured by definition of XMLSTART token - * post-condition: name does neither start, nor end in ':' - */ - /*[Duplicate]*/ def xName: String = { - if( !xml.Parsing.isNameStart( ch ) ) { - reportSyntaxError( "name expected, but char '"+ch+"' cannot start a name" ) - return "" - } - do { - putChar( ch ) - nextch - } while( xml.Parsing.isNameChar( ch ) ) - if(':' == cbuf.charAt(cbuf.length-1)) { - reportSyntaxError( "name cannot end in ':'" ) - cbuf.setLength(cbuf.length-1) - } - val n = cbuf.toString().intern() - cbuf.setLength( 0 ) - n - } - - - /** 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:StringBuilder = new StringBuilder(); - 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 ) Predef.error("internal error: encountered embedded block"); // assert - //Console.println("xText ch now "+ch) - //if( xCheckEmbeddedBlock ) { - // return "" - //} else { - var exit = false; - while( !exit ) { - putChar( ch ); - val expectRBRACE = ch == '}' - // TODO check for "}}" - nextch - if(expectRBRACE) { - if(ch == '}') - nextch - else { - reportSyntaxError("in XML content, please use '}}' to express '}'") - throw ConfusedAboutBracesException - } - } - exit = xCheckEmbeddedBlock ||( ch == '<' ) || ( ch == '&' ); - } - val str = cbuf.toString(); - cbuf.setLength( 0 ); - str - //} - } - - //val cbuf = new StringBuilder(); - - /** append Unicode character to name buffer*/ - //private def putChar(c: char) = cbuf.append( c ); - - /** xLiteral = element { element } - * @return Scala representation of this xml literal - * precondition: s.xStartsXML == true - */ - def xLiteral: Tree = try { - //Console.println("entering xLiteral!!") - init; pushScannerState - handle.isPattern = false - val pos = s.currentPos - var lastend = 0 - var lastch = ch - //var tree = element; - var tree:Tree = null - val ts = new mutable.ArrayBuffer[Tree]() - tmppos = pos // Iuli: added this line, as it seems content_LT uses tmppos when creating trees - content_LT(ts) - //Console.println("xLiteral:ts = "+ts.toList) - lastend = s.in.bp - lastch = s.in.ch - //if (settings.debug.value) { - // Console.println("DEBUG 1: I am getting char '"+ch+"' at lastend "+lastend+" pos = "+pos); // DEBUG - //} - xSpaceOpt - // parse more XML ? - if (ch == '<') { - //val ts = new mutable.ArrayBuffer[Tree](); - //ts.append( tree ); - while( ch == '<' ) { - nextch - ts.append( element ) - lastend = s.in.bp - lastch = s.in.ch - xSpaceOpt - } - tree = handle.makeXMLseq((pos), ts ) - } else { - assert(ts.length == 1) - tree = ts(0) - } - s.in.bp = lastend // ugly hack - s.in.ch = lastch - //if (settings.debug.value) { - // Console.println("DEBUG 2: restoring char '"+lastch+"' at lastend "+lastend+" pos = "+pos); // DEBUG - //} - //Console.println("out of xLiteral, parsed:"+tree.toString()); - s.next.token = Tokens.EMPTY; - s.nextToken - popScannerState - tree - } - catch { - case c @ (MissingEndTagException | ConfusedAboutBracesException) => - s.syntaxError((debugLastStartElement.top._1), c.getMessage + debugLastStartElement.top._2+">") - EmptyTree; - - case _:ArrayIndexOutOfBoundsException => - s.syntaxError((debugLastStartElement.top._1), - "missing end tag in XML literal for <"+debugLastStartElement.top._2+">") - EmptyTree; - } - - /** @see xmlPattern. resynchronizes after succesful parse - * @return this xml pattern - * precondition: s.xStartsXML == true - */ - def xLiteralPattern:Tree = try { - init; pushScannerState - val oldMode = handle.isPattern; - handle.isPattern = true - var tree = xPattern; xSpaceOpt; - handle.isPattern = oldMode; - s.next.token = Tokens.EMPTY; - s.nextToken - popScannerState - tree - } catch { - case c @ (MissingEndTagException | ConfusedAboutBracesException) => - s.syntaxError((debugLastStartElement.top._1), c.getMessage + debugLastStartElement.top._2+">"); - EmptyTree; - - case _:ArrayIndexOutOfBoundsException => - s.syntaxError((debugLastStartElement.top._1), - "missing end tag in XML literal for <" - +debugLastStartElement.top._2+">"); - EmptyTree; - - } - - def xEmbeddedExpr: Tree = { - sync - val b = p.block() //p.expr(true,false); - if(/*s.*/token != RBRACE) { - reportSyntaxError(" expected end of Scala block") - } - init - return b - } - - /** xScalaPatterns ::= patterns - */ - def xScalaPatterns: List[Tree] = { - sync; - val b = p.patterns(true); - if (/*s.*/token != RBRACE) { - reportSyntaxError(" expected end of Scala patterns") - } - init - return b - } - - //var ch: Char = _; - - /** this method assign the next character to ch and advances in input */ - def nextch: Unit = { s.in.next; /*s.xNext;*/ ch = s.in.ch ; pos = s.in.cpos; } - - //def lookahead = { s.xLookahead } - var scannerState: List[List[Int]] = Nil - - def pushScannerState { - scannerState = s.sepRegions::scannerState - s.sepRegions = Nil - } - def popScannerState { - s.sepRegions = scannerState.head; - scannerState = scannerState.tail - } - - def init: Unit = { - ch = s.in.ch; - pos = s.in.cpos; - //Console.println("\ninit! ch = "+ch); - } - - def reportSyntaxError(str: String) = { - s.syntaxError(pos-1, "in XML literal: " + str) - nextch - } - - def sync: Unit = { - xEmbeddedBlock = false - s.xSync - } - - /** '<' xPattern ::= Name [S] { xmlPattern | '{' pattern3 '}' } ETag - * | Name [S] '/' '>' - */ - def xPattern:Tree = { - //Console.println("xPattern") - val pos1 = pos - val qname = xName - debugLastStartElement.push((pos1, qname)) - xSpaceOpt - if (ch == '/') { // empty tag - nextch - xToken('>') - return handle.makeXMLpat(pos1, qname, new mutable.ArrayBuffer[Tree]()) + handle.makeXMLpat(pos1, qname, ts) } - // else: tag with content - xToken('>') - var ts = new mutable.ArrayBuffer[Tree] - var exit = false - while (! exit) { - val pos2 = pos - if (xEmbeddedBlock) { - ts ++ xScalaPatterns - } else - ch match { - case '<' => { // tag - nextch - if (ch != '/') { //child - ts.append(xPattern) - } else { - exit = true - } - } - case '{' => // embedded Scala patterns - while( ch == '{' ) { - s.in.next; - ts ++ xScalaPatterns; - } - // postcond: xEmbeddedBlock = false; - if (xEmbeddedBlock) Predef.error("problem with embedded block"); // assert - case _ => // teMaxt - appendText( pos2, ts, xText ); - // here xEmbeddedBlock might be true; - //if( xEmbeddedBlock ) throw new ApplicationError("after:"+text); // assert - } - } - xEndTag(qname) - debugLastStartElement.pop - handle.makeXMLpat(pos1, qname, ts) - } - -} /* class MarkupParser */ + } /* class MarkupParser */ }