markupparsers.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 719 行 · 第 1/2 页
SCALA
719 行
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author Burak Emir */// $Id: MarkupParsers.scala 14257 2008-03-04 16:17:21Z washburn $package scala.tools.nsc.ast.parserimport scala.collection.mutableimport scala.tools.nsc.util.{Position,NoPosition,SourceFile}import scala.xml.{Text, TextBuffer}import SourceFile.{SU,LF}/** This trait ... * * @author Burak Emir * @version 1.0 */trait MarkupParsers {self: Parsers => 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 TruncatedXML extends RuntimeException { override def getMessage = "input ended while parsing XML" } import global._ //import posAssigner.atPos class MarkupParser(parser: UnitParser, presWS: Boolean) /*with scala.xml.parsing.MarkupParser[Tree,Tree] */{ import Tokens.{EMPTY, LBRACE, RBRACE} import parser.i2p final val preserveWS = presWS var input : ScannerInput = _ import parser.{symbXMLBuilder => handle} def pos : Int = input.offset var tmppos : Position = NoPosition def ch = input.head /** this method assign the next character to ch and advances in input */ def nextch = input.next // { s.in.next; /*s.xNext;*/ ch = s.in.ch ; pos = s.in.cpos } /*[Duplicate]*/ var xEmbeddedBlock = false /** munch expected XML token, report syntax error for unexpected. * * @param that ... */ /*[Duplicate]*/ def xToken(that: Char) { if (ch == that) nextch else if (ch == SU) throw TruncatedXML else reportSyntaxError("'" + that + "' expected instead of '" + ch + "'") } var debugLastStartElement = new mutable.Stack[(Int, String)] /** 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") parser.errorTermTree } case '{' => nextch xEmbeddedExpr case SU => throw TruncatedXML case _ => reportSyntaxError("' or \" delimited attribute value" + " or '{' scala-expr '}' expected" ) Literal(Constant("<syntax-error>")) } // 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 = { val buf = new StringBuilder while (ch != endCh) { if (ch == SU) throw TruncatedXML buf append nextch } val str = buf.toString() // @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('>') } /** '<! CharData ::= [CDATA[ ( {char} - {char}"]]>"{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.length = sb.length - 2 nextch return handle.charData(pos1, sb.toString()) } else if (ch == SU) throw TruncatedXML else sb.append(ch) nextch } 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.length = sb.length - "</xml:unparsed".length nextch return handle.unparsed(pos1, sb.toString()) } else if (ch == SU) { throw TruncatedXML } else sb.append(ch) nextch } Predef.error("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 + 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 i = i * base + ch.asDigit case SU => throw TruncatedXML case _ => reportSyntaxError("character '"+ch+"' not allowed in char ref") } nextch } new String(Array(i.asInstanceOf[Char])) } /** Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' * * see [15] */ /*[Duplicate]*/ def xComment: Tree = { val sb: StringBuilder = new StringBuilder() xToken('-') xToken('-') while (true) { if (ch=='-' && { sb.append(ch); nextch; ch == '-' }) { sb.length = sb.length - 1 nextch xToken('>') return handle.comment(pos, sb.toString()) } else if (ch == SU) { throw TruncatedXML } 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) { 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)) } } /** * @precond ch == '{' * @postcond: xEmbeddedBlock == false! */ def content_BRACE(p: Position, ts:mutable.ArrayBuffer[Tree]) { 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 ... */ 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)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?