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 == '&amp;'     */    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 + -
显示快捷键?