diff options
author | Miles Sabin <miles@milessabin.com> | 2009-05-18 10:54:00 +0000 |
---|---|---|
committer | Miles Sabin <miles@milessabin.com> | 2009-05-18 10:54:00 +0000 |
commit | 8fb4f2c37d579545674fc9d1fe3f66c80880dcbf (patch) | |
tree | 8ab19cb948b6968a7adff2862050784cc8915c99 /src/compiler | |
parent | b2e928c6d1f67230f18a33aad295fe67de9f6cd7 (diff) | |
download | scala-8fb4f2c37d579545674fc9d1fe3f66c80880dcbf.tar.gz scala-8fb4f2c37d579545674fc9d1fe3f66c80880dcbf.tar.bz2 scala-8fb4f2c37d579545674fc9d1fe3f66c80880dcbf.zip |
Switch over to new scanner/parser.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala | 94 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/MarkupParsers1.scala | 705 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/NewScanners.scala | 922 | ||||
-rwxr-xr-x[-rw-r--r--] | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 62 | ||||
-rwxr-xr-x | src/compiler/scala/tools/nsc/ast/parser/Parsers1.scala | 2607 | ||||
-rwxr-xr-x[-rw-r--r--] | src/compiler/scala/tools/nsc/ast/parser/Scanners.scala | 1364 | ||||
-rwxr-xr-x | src/compiler/scala/tools/nsc/ast/parser/Scanners1.scala | 971 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder1.scala | 368 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer1.scala | 29 |
12 files changed, 724 insertions, 6406 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 3ebe015fd5..73b2f6aff7 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -277,7 +277,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable val global: Global.this.type = Global.this val runsAfter = List[String]() val runsRightAfter = None - } with SyntaxAnalyzer1 + } with SyntaxAnalyzer // factory method for // phaseName = "namer" diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index 55695f725a..87955b9e31 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -2,12 +2,12 @@ * Copyright 2005-2009 LAMP/EPFL * @author Burak Emir */ -// $Id$ +// $Id: MarkupParsers.scala 17315 2009-03-16 17:46:58Z extempore $ package scala.tools.nsc.ast.parser import scala.collection.mutable -import scala.tools.nsc.util.{Position,NoPosition,SourceFile} +import scala.tools.nsc.util.{Position,NoPosition,SourceFile,CharArrayReader1} import scala.xml.{Text, TextBuffer} import SourceFile.{SU,LF} import scala.annotation.switch @@ -36,20 +36,19 @@ trait MarkupParsers {self: Parsers => 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 = _ + var input : CharArrayReader1 = _ - import parser.{symbXMLBuilder => handle} + import parser.{symbXMLBuilder => handle, i2p} - def pos : Int = input.offset + def pos : Int = input.charOffset var tmppos : Position = NoPosition - def ch = input.head + def ch = input.ch /** 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 } + def nextch = { val result = input.ch; input.nextChar(); result } // { s.in.next; /*s.xNext;*/ ch = s.in.ch ; pos = s.in.cpos } - /*[Duplicate]*/ var xEmbeddedBlock = false + var xEmbeddedBlock = false /** munch expected XML token, report syntax error for unexpected. * @@ -58,7 +57,7 @@ trait MarkupParsers {self: Parsers => /*[Duplicate]*/ def xToken(that: Char) { if (ch == that) nextch else if (ch == SU) - throw TruncatedXML + throw TruncatedXML else reportSyntaxError("'" + that + "' expected instead of '" + ch + "'") } @@ -130,7 +129,8 @@ trait MarkupParsers {self: Parsers => while (ch != endCh) { if (ch == SU) throw TruncatedXML - buf append nextch + buf append ch + nextch } val str = buf.toString() @@ -417,13 +417,14 @@ trait MarkupParsers {self: Parsers => */ /*[Duplicate]*/ def xName: String = { if (ch == SU) { - throw TruncatedXML + throw TruncatedXML + } else if ( !xml.Parsing.isNameStart(ch)) { reportSyntaxError("name expected, but char '"+ch+"' cannot start a name") return "" } val buf = new StringBuilder do { - buf append nextch + buf append ch; nextch } while (xml.Parsing.isNameChar(ch)) if (':' == buf.last) { reportSyntaxError( "name cannot end in ':'" ) @@ -513,14 +514,15 @@ trait MarkupParsers {self: Parsers => * precondition: s.xStartsXML == true */ def xLiteral: Tree = try { - input = parser.in.flush + input = parser.in handle.isPattern = false //val pos = s.currentPos 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 - assert(nextch == '<') +// assert(ch == '<') +// nextch content_LT(ts) //Console.println("xLiteral:ts = "+ts.toList) //lastend = s.in.bp @@ -528,19 +530,20 @@ trait MarkupParsers {self: Parsers => //if (settings.debug.value) { // Console.println("DEBUG 1: I am getting char '"+ch+"' at lastend "+lastend+" pos = "+pos); // DEBUG //} - val save = input.offset + input = input.lookaheadReader xSpaceOpt // parse more XML ? if (ch == '<') { + input = parser.in + xSpaceOpt while (ch == '<') { nextch ts.append(element) xSpaceOpt } tree = handle.makeXMLseq((pos), ts) - parser.in.resume(Tokens.XMLSTART) } else { - parser.in.seek(save, Tokens.XMLSTART) + input = parser.in assert(ts.length == 1) tree = ts(0) } @@ -548,21 +551,20 @@ trait MarkupParsers {self: Parsers => } catch { case c @ TruncatedXML => parser.incompleteInputError(c.getMessage) - parser.in.resume(Tokens.XMLSTART) EmptyTree case c @ (MissingEndTagException | ConfusedAboutBracesException) => parser.syntaxError((debugLastStartElement.top._1):Int, c.getMessage + debugLastStartElement.top._2+">") - parser.in.resume(Tokens.XMLSTART) EmptyTree case _:ArrayIndexOutOfBoundsException => parser.syntaxError((debugLastStartElement.top._1), "missing end tag in XML literal for <" +debugLastStartElement.top._2+">"); - parser.in.resume(Tokens.XMLSTART) EmptyTree + } finally { + parser.in.resume(Tokens.XMLSTART) } /** @see xmlPattern. resynchronizes after successful parse @@ -570,19 +572,17 @@ trait MarkupParsers {self: Parsers => * precondition: s.xStartsXML == true */ def xLiteralPattern: Tree = try { - input = parser.in.flush + input = parser.in val oldMode = handle.isPattern; handle.isPattern = true - assert(nextch == '<') +// assert(ch == '<') +// nextch var tree = xPattern; xSpaceOpt; handle.isPattern = oldMode; - parser.in.resume(Tokens.XMLSTART) tree } catch { case c @ TruncatedXML => parser.syntaxError(pos - 1, c.getMessage) - //s.nextToken - parser.in.resume(Tokens.XMLSTART) EmptyTree case c @ (MissingEndTagException | ConfusedAboutBracesException) => @@ -595,44 +595,30 @@ trait MarkupParsers {self: Parsers => "missing end tag in XML literal for <" +debugLastStartElement.top._2+">") EmptyTree + } finally { + parser.in.resume(Tokens.XMLSTART) } - def xEmbeddedExpr: Tree = { + def escapeToScala[A](op: => A, kind: String) = { xEmbeddedBlock = false + val savedSepRegions = parser.in.sepRegions parser.in.resume(LBRACE) - parser.in.sepRegions = RBRACE :: parser.in.sepRegions - val b = parser.block() //p.expr(true,false); - parser.in.sepRegions = parser.in.sepRegions.tail - if (parser.in.token != RBRACE) { - input = parser.in.flush - reportSyntaxError(" expected end of Scala block") - } else { - input = parser.in.flush - assert(nextch == '}') + try { + op //p.expr(true,false); + } finally { + parser.in.sepRegions = savedSepRegions // parser.in.sepRegions.tail + if (parser.in.token != RBRACE) { + reportSyntaxError(" expected end of Scala "+kind) + } } - b } + def xEmbeddedExpr: Tree = escapeToScala(parser.block(), "block") + /** xScalaPatterns ::= patterns */ - def xScalaPatterns: List[Tree] = { - xEmbeddedBlock = false - parser.in.resume(LBRACE) - val b = parser.patterns(true) - if (parser.in.token != RBRACE) { - input = parser.in.flush - reportSyntaxError(" expected end of Scala pattern") - } else { - input = parser.in.flush - assert(nextch == '}') - } - b - } - - //var ch: Char = _; - + def xScalaPatterns: List[Tree] = escapeToScala(parser.patterns(true), "pattern") - //def lookahead = { s.xLookahead } var scannerState: List[List[Int]] = Nil /* diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers1.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers1.scala deleted file mode 100644 index bba76c748c..0000000000 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers1.scala +++ /dev/null @@ -1,705 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2009 LAMP/EPFL - * @author Burak Emir - */ -// $Id: MarkupParsers.scala 17315 2009-03-16 17:46:58Z extempore $ - -package scala.tools.nsc.ast.parser - -import scala.collection.mutable -import scala.tools.nsc.util.{Position,NoPosition,SourceFile,CharArrayReader1} -import scala.xml.{Text, TextBuffer} -import SourceFile.{SU,LF} -import scala.annotation.switch - -/** This trait ... - * - * @author Burak Emir - * @version 1.0 - */ -trait MarkupParsers1 {self: Parsers1 => - 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} - - final val preserveWS = presWS - var input : CharArrayReader1 = _ - - import parser.{symbXMLBuilder => handle, i2p} - - def pos : Int = input.charOffset - var tmppos : Position = NoPosition - def ch = input.ch - /** this method assign the next character to ch and advances in input */ - def nextch = { val result = input.ch; input.nextChar(); result } // { s.in.next; /*s.xNext;*/ ch = s.in.ch ; pos = s.in.cpos } - - 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 ch - 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: @switch) 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) - 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 SU => - exit = true - 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) - } - } - } - - /** 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 (ch == SU) { - throw TruncatedXML - } else if ( !xml.Parsing.isNameStart(ch)) { - reportSyntaxError("name expected, but char '"+ch+"' cannot start a name") - return "" - } - val buf = new StringBuilder - do { - buf append ch; nextch - } while (xml.Parsing.isNameChar(ch)) - if (':' == buf.last) { - reportSyntaxError( "name cannot end in ':'" ) - buf.setLength(buf.length - 1) - } - val n = buf.toString().intern() - //cbuf.length = 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 if (ch == SU) - throw TruncatedXML - else reportSyntaxError("whitespace expected") - - /** '<?' ProcInstr ::= Name [S ({Char} - ({Char}'>?' {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.length = sb.length - 1 - nextch - return handle.procInstr(tmppos, n, sb.toString) - } else - sb.append(ch); - nextch - } - } - xToken('?') - xToken('>') - handle.procInstr(tmppos, n, 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 - val buf = new StringBuilder - while (!exit && (ch!=SU)) { - buf append 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 = buf.toString() - //cbuf.length = 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 { - input = parser.in - handle.isPattern = false - - //val pos = s.currentPos - 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 -// assert(ch == '<') -// nextch - 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 - //} - input = input.lookaheadReader - xSpaceOpt - // parse more XML ? - if (ch == '<') { - input = parser.in - xSpaceOpt - while (ch == '<') { - nextch - ts.append(element) - xSpaceOpt - } - tree = handle.makeXMLseq((pos), ts) - } else { - input = parser.in - assert(ts.length == 1) - tree = ts(0) - } - tree - } catch { - case c @ TruncatedXML => - parser.incompleteInputError(c.getMessage) - EmptyTree - - case c @ (MissingEndTagException | ConfusedAboutBracesException) => - parser.syntaxError((debugLastStartElement.top._1):Int, - c.getMessage + debugLastStartElement.top._2+">") - EmptyTree - - case _:ArrayIndexOutOfBoundsException => - parser.syntaxError((debugLastStartElement.top._1), - "missing end tag in XML literal for <" - +debugLastStartElement.top._2+">"); - EmptyTree - } finally { - parser.in.resume(Tokens.XMLSTART) - } - - /** @see xmlPattern. resynchronizes after successful parse - * @return this xml pattern - * precondition: s.xStartsXML == true - */ - def xLiteralPattern: Tree = try { - input = parser.in - val oldMode = handle.isPattern; - handle.isPattern = true -// assert(ch == '<') -// nextch - var tree = xPattern; xSpaceOpt; - handle.isPattern = oldMode; - tree - } catch { - case c @ TruncatedXML => - parser.syntaxError(pos - 1, c.getMessage) - EmptyTree - - case c @ (MissingEndTagException | ConfusedAboutBracesException) => - parser.syntaxError((debugLastStartElement.top._1), - c.getMessage + debugLastStartElement.top._2+">") - EmptyTree - - case _:ArrayIndexOutOfBoundsException => - parser.syntaxError((debugLastStartElement.top._1), - "missing end tag in XML literal for <" - +debugLastStartElement.top._2+">") - EmptyTree - } finally { - parser.in.resume(Tokens.XMLSTART) - } - - def escapeToScala[A](op: => A, kind: String) = { - xEmbeddedBlock = false - val savedSepRegions = parser.in.sepRegions - parser.in.resume(LBRACE) - try { - op //p.expr(true,false); - } finally { - parser.in.sepRegions = savedSepRegions // parser.in.sepRegions.tail - if (parser.in.token != RBRACE) { - reportSyntaxError(" expected end of Scala "+kind) - } - } - } - - def xEmbeddedExpr: Tree = escapeToScala(parser.block(), "block") - - /** xScalaPatterns ::= patterns - */ - def xScalaPatterns: List[Tree] = escapeToScala(parser.patterns(true), "pattern") - - 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) = { - parser.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)) - 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 == '{') { - nextch - ts ++= xScalaPatterns - } - // postcond: xEmbeddedBlock = false; - if (xEmbeddedBlock) Predef.error("problem with embedded block"); // assert - - case SU => - throw TruncatedXML - - 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 */ -} diff --git a/src/compiler/scala/tools/nsc/ast/parser/NewScanners.scala b/src/compiler/scala/tools/nsc/ast/parser/NewScanners.scala deleted file mode 100644 index d170d0257e..0000000000 --- a/src/compiler/scala/tools/nsc/ast/parser/NewScanners.scala +++ /dev/null @@ -1,922 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2009 LAMP/EPFL - * @author Sean McDirmid - */ -// $Id$ - -package scala.tools.nsc.ast.parser - -import scala.tools.nsc.util.SourceFile._ -import scala.tools.nsc.util._ -import scala.annotation.switch - -trait NewScanners { - val global : Global - import global._ - import Tokens._ - trait CoreScannerInput extends BufferedIterator[Char] { - private[NewScanners] val scratch = new StringBuilder - - /** iterates over and applies <code>f</code> to the next element - * if this iterator has a next element that <code>f</code> is defined for. - */ - def readIf[T](f : PartialFunction[Char,T]) : Option[T] = - if (hasNext && f.isDefinedAt(head)) - Some(f(next)) - else None - - /** iterates over elements as long as <code>f</code> is true - * for each element, returns whether anything was read - */ - def readWhile(f : Char => Boolean) : Boolean = { - var read = false - while (hasNext && f(head)) { - next - read = true - } - read - } - - def readIfStartsWith(c : Char) : Boolean = - if (head == c) { next; true } else false - def readIfStartsWith(c0 : Char, c1 : Char) : Boolean = - if (head == c0 && peek(1) == c1) { - next; next; true - } else false - def startsWith(c0: Char, c1 : Char) : Boolean = head == c0 && peek(1) == c1 - def isUnicode : Boolean - - def peek(idx : Int) : Char - - def offset : Int - def error(offset : Int, msg : String) : Unit - def incompleteError(offset : Int, msg : String) : Unit = error(offset, msg) - def textFor(from : Int, until : Int) : RandomAccessSeq[Char] - } - trait ScannerInput extends CoreScannerInput { - def seek(offset : Int) : Unit - } - class DefaultInput(in : NewCharArrayReader) extends ScannerInput { - import scala.collection.mutable._ - def seek(offset : Int) = in.seek(offset) - def offset = in.offset - def head = peek(0) - def next = in.next - def isUnicode : Boolean = in.isUnicode - def hasNext = in.hasNext - def peek(idx : Int) = { - val offset = in.offset - var jdx = idx - var result = in.next - while (jdx > 0) { - jdx = jdx - 1 - result =in.next - } - in.seek(offset) // jump back to old position - result - } - def error(offset : Int, msg : String) : Unit = {} - def textFor(from : Int, until : Int) = in.buf.slice(from, until).mkString - } - - abstract class ParserScanner extends BaseScanner { - def init = nextToken - - private var doc : String = "" - var sepRegions : List[Int] = Nil - private val current = new TokenHolder - private val next = new TokenHolder - implicit def in : ScannerInput - - def assertEmpty(th: TokenHolder) = - if (th.code != EMPTY) in.error(th.offset, "unexpected token") - def assertNotEmpty(th: TokenHolder) = - if (th.code == EMPTY) in.incompleteError(th.offset, "expected token not present") - - var lastCode = EMPTY - next.code = EMPTY - current.code = EMPTY - def hasNext = in.hasNext || (next.code != EMPTY && next.code != EOF) - def flush : ScannerInput = { - assertNotEmpty(current) - in.seek(unadjust(current.offset)) - current.code = EMPTY - next.code = EMPTY - in - } - def seek(offset : Int, lastCode : Int) = { - assertEmpty(current) - in.seek(unadjust(offset)) - this.lastCode = lastCode - nextToken - } - def resume(lastCode : Int) = { - assertEmpty(current) - this.lastCode = lastCode - nextToken - } - /** read next token and return last position - */ - def skipToken: Int = { - val p = current.offset; nextToken - // XXX: account for off by one error //??? - p - } - def currentPos = { - assertNotEmpty(current) - current.offset - } - def fillNext : Boolean = { - assertEmpty(next) - var hasNewline = false - do { - fill(next) - } while (next.code match { - case NEWLINE|NEWLINES|WHITESPACE|COMMENT => - assert((next.code != COMMENT) == (xmlOk)) - hasNewline = hasNewline || next.code == NEWLINE || next.code == NEWLINES - if (next.code == COMMENT) - doc = next.value.asInstanceOf[Option[String]].getOrElse("") - true - case _ => false - }) - hasNewline - } - - def flushDoc = { - val ret = doc - doc = "" - ret - } - - def nextToken : Unit = { - if (current.code == EOF) return // nothing more. - var lastIsComment = false - lastCode = current.code match { - case WHITESPACE|EMPTY => lastCode - case COMMENT => lastIsComment = true; lastCode - case code => code - } - // push on braces - val pushOn = (current.code) match { - case LBRACE => RBRACE - case LPAREN => RPAREN - case LBRACKET => RBRACKET - case CASE => - ARROW - case RBRACE => - while (!sepRegions.isEmpty && sepRegions.head != RBRACE) - sepRegions = sepRegions.tail - if (!sepRegions.isEmpty) - sepRegions = sepRegions.tail - EMPTY - case code @ (ARROW) if (!sepRegions.isEmpty && sepRegions.head == code) => - sepRegions = sepRegions.tail - EMPTY - case ARROW => - EMPTY - case code @ (RPAREN|RBRACKET) => - if (!sepRegions.isEmpty && sepRegions.head == code) - sepRegions = sepRegions.tail - EMPTY - case _ => EMPTY - } - if (pushOn != EMPTY) sepRegions = pushOn :: sepRegions - - if (next.code != EMPTY) { - current.copy(next) - next.code = EMPTY - } else fill(current) - - def currentIsNext : Unit = { - assertNotEmpty(next) - return nextToken - } - current.code match { - case CASE|SEMI => - fillNext - (current.code,next.code) match { - case (CASE,OBJECT) => - current.code = CASEOBJECT; next.code = EMPTY - case (CASE, CLASS) => current.code = CASECLASS ; next.code = EMPTY - case (SEMI, ELSE ) => currentIsNext - case _ => - } - case WHITESPACE|COMMENT => - if (current.code == COMMENT) - doc = current.value.asInstanceOf[Option[String]].getOrElse("") - nextToken - case NEWLINE | NEWLINES => - if (!xmlOk) in.error(current.offset, "XML mode not legal here") - val headIsRBRACE = if (sepRegions.isEmpty) true else sepRegions.head == RBRACE - val hasNewline = fillNext - - /** don't check for next.code == EOF else repl line continuation won't work */ - if (headIsRBRACE && (inLastOfStat(lastCode) && inFirstOfStat(next.code))) { } - else currentIsNext - - case _ => - } - } - - def token = { - assertNotEmpty(current) - current.code - } - - def nextTokenCode = { - if (next.code == EMPTY) fillNext - next.code - } - - def name = current.value.get.asInstanceOf[Name] - - def charVal = current.value.get.asInstanceOf[Char] - - def intVal(negated : Boolean) : Long = { - val base = current.value.asInstanceOf[Option[Int]].getOrElse(10) - intVal(current.offset, current.code, current.nLit(this), negated, base) - } - def intVal : Long = intVal(false) - - def floatVal(negated: Boolean): Double = { - floatVal(current.offset, current.code, current.nLit(this), negated) - } - def floatVal : Double = floatVal(false) - - def stringVal = current.value.get.asInstanceOf[String] - } - - class TokenHolder { - var offset : Int = 0 - var code : Int = 0 - var length : Int = 0 - var value : Option[Any] = None - def copy(from : TokenHolder) = { - this.offset = from.offset - this.code = from.code - this.length = from.length - this.value = from.value - } - def set(offset : Int, length : Int, code : Int) = { - this.offset = offset; this.length = length; this.code = code; this.value = None - } - def set(offset : Int, length : Int, code : Int, value : Any) = { - this.offset = offset; this.length = length; this.code = code; this.value = Some(value) - } - def nLit(implicit in : BaseScanner) = (in.in.textFor(in.unadjust(offset), in.unadjust(offset + length))) - - } - - trait BaseScanner { - implicit def in : CoreScannerInput - ScannerConfiguration.hashCode // forces initialization - import ScannerConfiguration._ - var xmlOk = true - - def iterator = new Iterator[(Int,Int,Int)] { // offset,length,code - val current = new TokenHolder - def hasNext = in.hasNext - def next = { - fill(current) - (current.offset, current.length, current.code) - } - } - // IDE hooks - def adjust(offset : Int) = offset - def unadjust(offset : Int) = offset - def identifier(name : Name) = name - - protected def fill(current : TokenHolder) : Unit = { - if (!in.hasNext) { - current.offset = adjust(in.offset) - current.code = EOF - return - } - val oldXmlOk = xmlOk - xmlOk = false - val offset = in.offset // call "after" next - def escapeCode(offset : Int) : Char = in.next match { - case c if simpleEscape.isDefinedAt(c) => simpleEscape(c) - case c if isDigit(c) => - val length = in.scratch.length - try { - in.scratch append c - while (isDigit(in.head)) in.scratch append in.next - val n = Integer.parseInt(in.scratch.drop(length).mkString, 8) - if (n > 0377) { - in.error(offset, "malformed octal character code"); 0.toChar - } else n.toChar - } catch { - case ex : Exception => in.error(offset, "malformed octal character code"); 0.toChar - } finally { - in.scratch.setLength(length) - } - case c => in.error(offset, "unrecognized escape code \'" + c + "\'"); c - } - def getIdentRest : Unit = in.readIf{ - case '_' => - in.scratch append '_' - val c = in.head - if (isOperatorPart(c)) getOperatorRest else getIdentRest - case c if isIdentifierPart(c) => - in.scratch append c; getIdentRest - } - - val next = in.next - // called after everything is read. - def length = in.offset - offset - - def value(code : Int, value : Any) : Int = { - current.value = Some(value) - code - } - def doOperator(c : Char) = { - in.scratch.setLength(0) - in.scratch append(c) - getOperatorRest - val name : Name = global.newTermName(in.scratch.toString) - value(name2token(name), (name)) - } - current.offset = adjust(offset) - current.value = None - current.code = next match { - case ';' => (SEMI) - case ',' => (COMMA) - case '(' => xmlOk = true; (LPAREN) - case ')' => (RPAREN) - case '{' => xmlOk = true; (LBRACE) - case '}' => (RBRACE) - case '[' => (LBRACKET) - case ']' => (RBRACKET) - case SU => EOF - case '\u21D2' => (ARROW) - case '\u2190' => (LARROW) - case '<' => - if (oldXmlOk && (in.head match { - case ('!' | '?') => true - case c if xml.Parsing.isNameStart(c) => true - case _ => false - })) { in.next; XMLSTART } - else doOperator('<') - case ' ' | '\t' => in.readWhile(isSpace); xmlOk = true; (WHITESPACE) - case '/' => - if (in.readIfStartsWith('/')) { - while (in.hasNext && !isNewLine(in.head)) in.next - (COMMENT) - } else if (in.readIfStartsWith('*')) { - val emptyOrDoc = in.readIfStartsWith('*') - val empty = emptyOrDoc && in.readIfStartsWith('/') - val isDoc = emptyOrDoc && !empty - - if (isDoc) - in.scratch setLength 0 - - var count = 0 - if (!empty) while (count != -1) in.next match { - case SU => in.incompleteError(offset, "unterminated comment"); count = -1 - case '*' if in.readIfStartsWith('/') => count -= 1 - case '/' if in.readIfStartsWith('*') => count += 1 - case c => - if (isDoc) in.scratch append c - } - if (!isDoc) (COMMENT) else value(COMMENT, in.scratch.toString) - } else doOperator('/') - case c @ ('~' | '!' | '@' | '#' | '%' | - '^' | '*' | '+' | '-' | /* '<' | | '/' */ - '>' | '?' | ':' | '=' | '&' | - '|' | '\\') => doOperator(c) - case c @ - ('A' | 'B' | 'C' | 'D' | 'E' | - 'F' | 'G' | 'H' | 'I' | 'J' | - 'K' | 'L' | 'M' | 'N' | 'O' | - 'P' | 'Q' | 'R' | 'S' | 'T' | - 'U' | 'V' | 'W' | 'X' | 'Y' | - 'Z' | '$' | '_' | - 'a' | 'b' | 'c' | 'd' | 'e' | - 'f' | 'g' | 'h' | 'i' | 'j' | - 'k' | 'l' | 'm' | 'n' | 'o' | - 'p' | 'q' | 'r' | 's' | 't' | - 'u' | 'v' | 'w' | 'x' | 'y' | - 'z') => - in.scratch.setLength(0) - in.scratch.append(c : Char) - getIdentRest - val name = global.newTermName(in.scratch.toString) - in.scratch.setLength(0) - val code = name2token(name) - if (code == IDENTIFIER) value(code, identifier(name)) - else value(code, (name)) - case '0' => - if (in.head match { - case 'x' | 'X' => true - case _ => false - }) { in.next; value(getNumber(offset, 16, "0x"), 16) } - else value(getNumber(offset, 8, "0"), 8) - case '1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' => getNumber(offset, 10, "") - case '.' => - val frac = getFraction(false) - val code = (frac getOrElse DOT) - code - case '\'' => - def endQ(cvalue : Char) : Int = { - if (!in.readIfStartsWith('\'')) { - in.error(offset, "missing terminating quote") - } - value(CHARLIT, cvalue) - } - in.next match { - case CR|LF|FF|SU|EOF if !in.isUnicode => - in.error(offset, "unterminated character literal") - value(CHARLIT, 0.toChar) - case '\'' => - in.error(offset, "empty character literal") - value(CHARLIT, 0.toChar) - case '\\' => endQ(escapeCode(offset)) - case c if (Character.isUnicodeIdentifierStart(c)) && in.head != '\'' => - in.scratch.setLength(0) - in.scratch append c - getIdentRest - if (in.readIfStartsWith('\'')) in.error(offset, "unexpected quote after symbol") - value(SYMBOLLIT, in.scratch.toString) - case c if isSpecial(c) && in.head != '\'' => - in.scratch.setLength(0) - in.scratch append(c) - getOperatorRest - if (in.readIfStartsWith('\'')) in.error(offset, "unexpected quote after symbol") - value(SYMBOLLIT, in.scratch.toString) - case c => endQ(c) - } - case '\"' => - if (in.readIfStartsWith('\"')) { - if (in.readIfStartsWith('\"')) { - // multiline - in.scratch setLength 0 - while (in.next match { - case SU if !in.isUnicode => in.incompleteError(offset, "unterminated multi-line string"); false - case '\"' if in.readIfStartsWith('\"') => - if (in.readIfStartsWith('\"')) false - else { - in.scratch append "\"\""; true - } - case c => in.scratch append c; true - }) {} - val ret = value(STRINGLIT, in.scratch.toString) - in.scratch setLength 0 - ret - } else value(STRINGLIT, "") - } else { - in.scratch setLength 0 - while (in.next match { - case '\"' => false - case CR|LF|FF|SU if !in.isUnicode => - in.error(offset, "unterminated string"); false - case '\\' => - in.scratch append escapeCode(in.offset - 1); true - case c => in.scratch.append(c); true - }) {} - val ret = value(STRINGLIT, in.scratch.toString) - in.scratch setLength 0 - ret - } - case '`' => - in.scratch setLength 0 - if (in.head == '`') in.error(offset, "empty quoted identifier") - while (in.head match { - case '`' => in.next; false - case CR | LF | FF | SU | EOF => - in.error(offset, "unterminated quoted identifier") - false - case _ => true - }) in.scratch append in.next - val name = global.newTermName(in.scratch.toString) - value(BACKQUOTED_IDENT, (name)) - case c if (c == CR | c == LF | c == FF) => - var multiple = false - in.readWhile{ - case d if isNewLine(d) => - multiple = multiple || d == c; true - case ' ' | '\t' => true // eat the whitespace after newlines. - case _ => false - } - xmlOk = true - (if (multiple) NEWLINES else NEWLINE) - case c => - if (Character.isUnicodeIdentifierStart(c)) { - in.scratch.setLength(0) - in.scratch append c - getIdentRest - val name = global.newTermName(in.scratch.toString) - in.scratch.setLength(0) - val code = name2token(name) - value(code, (name)) - } else if (isSpecial(c)) { - in.scratch.setLength(0) - in.scratch append c - getOperatorRest - val name = global.newTermName(in.scratch.toString) - in.scratch.setLength(0) - val code = name2token(name) - value(code, (name)) - } else { - in.error(offset, "illegal character: \'" + c + "\'") - (ERROR) - } - } - current.length = length - } - def intVal(offset : Int, token : Int, name0 : RandomAccessSeq[Char], negated: Boolean, base : Int): Long = { - if (name0.length == 1 && name0(0) == '0') return 0 - - var name = name0 - if (name.length > 2 && name(0) == '0' && (name(1) match { - case 'x'|'X' => true - case _ => false - })) name = name.drop(2) - - while (name.last match { - case 'l'|'L' => true - case _ => false - }) name = name.take(name.length - 1) - - if (token == CHARLIT && !negated) { - if (name.length > 0) name(0) else 0 - } else { - var value: Long = 0 - val divider = if (base == 10) 1 else 2 - val limit: Long = - if (token == LONGLIT) Math.MAX_LONG else Math.MAX_INT - var i = 0 - val len = name.length - while (i < len) { - val d = digit2int(name(i), base) - if (d < 0) { - in.error(offset, "malformed integer number") - return 0 - } - if (value < 0 || - limit / (base / divider) < value || - limit - (d / divider) < value * (base / divider) && - !(negated && limit == value * base - 1 + d)) { - in.error(offset, "integer number too large") - return 0 - } - value = value * base + d - i += 1 - } - if (negated) -value else value - } - } - - - /** convert name, base to double value - */ - def floatVal(offset : Int, token : Int, name0 : RandomAccessSeq[Char], negated: Boolean): Double = { - var name = name0 - while (name.last match { - case 'f'|'F'|'d'|'D' => true - case _ => false - }) name = name.take(name.length - 1) - - val limit: Double = - if (token == DOUBLELIT) Math.MAX_DOUBLE else Math.MAX_FLOAT - try { - val value: Double = java.lang.Double.valueOf(name.mkString).doubleValue() - if (value > limit) - in.error(offset, "floating point number too large") - if (negated) -value else value - } catch { - case _: NumberFormatException => - in.error(offset, "malformed floating point number") - 0.0 - } - } - } - - - // utility functions - def isSpecial(c : Char) : Boolean = { - val chtp = Character.getType(c) - chtp == Character.MATH_SYMBOL || chtp == Character.OTHER_SYMBOL - } - def isDigit(c : Char) : Boolean = digit2int(c, 10) >= 0 - - def isIdentifierStart(c: Char): Boolean = (c: @switch) match { - case 'A' | 'B' | 'C' | 'D' | 'E' | - 'F' | 'G' | 'H' | 'I' | 'J' | - 'K' | 'L' | 'M' | 'N' | 'O' | - 'P' | 'Q' | 'R' | 'S' | 'T' | - 'U' | 'V' | 'W' | 'X' | 'Y' | - 'Z' | '$' | '_' | - 'a' | 'b' | 'c' | 'd' | 'e' | - 'f' | 'g' | 'h' | 'i' | 'j' | - 'k' | 'l' | 'm' | 'n' | 'o' | - 'p' | 'q' | 'r' | 's' | 't' | - 'u' | 'v' | 'w' | 'x' | 'y' | // scala-mode: need to understand multi-line case patterns - 'z' => true - case _ => false - } - def isIdentifierPart(c: Char) : Boolean = (c: @switch) match { - case ('A' | 'B' | 'C' | 'D' | 'E' | - 'F' | 'G' | 'H' | 'I' | 'J' | - 'K' | 'L' | 'M' | 'N' | 'O' | - 'P' | 'Q' | 'R' | 'S' | 'T' | - 'U' | 'V' | 'W' | 'X' | 'Y' | - 'Z' | '$' | '_' | - 'a' | 'b' | 'c' | 'd' | 'e' | - 'f' | 'g' | 'h' | 'i' | 'j' | - 'k' | 'l' | 'm' | 'n' | 'o' | - 'p' | 'q' | 'r' | 's' | 't' | - 'u' | 'v' | 'w' | 'x' | 'y' | - 'z') => true - case '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' => true - case c => Character.isUnicodeIdentifierPart(c) - } - //isIdentifierStart(c) || isDigit(c) || isUnicodeIdentifierPart(c) - def isOperatorPart(c : Char) : Boolean = (c: @switch) match { - case '~' | '!' | '@' | '#' | '%' | - '^' | '*' | '+' | '-' | '<' | - '>' | '?' | ':' | '=' | '&' | - '|' | '/' | '\\' => true - case c => isSpecial(c) - } - - private def getOperatorRest(implicit in : CoreScannerInput) : Unit = { - in.readWhile{ - case ('/') if in.startsWith('/','*') || in.startsWith('/','/') => false - case ('*') if in.startsWith('*','/') => false - case (c) if isOperatorPart(c) => in.scratch append c; true - case _ => false - } - } - private def isFraction(c0 : Char, c1 : Char) = - isDigit(c0) || (c0 match { - case 'd'|'D'|'f'|'F' if !isIdentifierPart(c1) => true - case 'e'|'E' if isDigit(c1) => true - case _ => false - }) - private def getFraction(hasWhole : Boolean)(implicit in : CoreScannerInput) : Option[Int] = { - val hasDigits = in.readWhile(isDigit) - if (!hasDigits && !hasWhole) return None - - def end(code : Int) : Option[Int] = { - if (!hasDigits && isIdentifierPart(in.peek(1))) None - else in.next; Some(code) - } - in.head match { - case 'f'|'F' => return end(FLOATLIT) - case 'd'|'D' => return end(DOUBLELIT) - case 'e'|'E' if { - val peek = in.peek(1) - peek == '-' || peek == '+' || isDigit(peek) - } => - in.next // eat the e. - var hasDigit = isDigit(in.next) // eat +/-/digit - hasDigit = in.readWhile(isDigit) || hasDigit - in.readIf{ // eat an optional f or d - case 'f'|'F' => FLOATLIT - case 'd'|'D' => DOUBLELIT - } orElse Some(DOUBLELIT) - case _ if hasDigits => Some(DOUBLELIT) - case _ => None // we didn't read anything - } - } - private def getNumber(offset : Int, base : Int, prefix : String)(implicit in : CoreScannerInput) : Int = { - val hasBody = in.readWhile{ - case at if at >= '0' && at <= '9' => true - case at if base == 16 && ((at >= 'a' && at <= 'f') || (at >= 'A' && at <= 'F')) => true - case _ => false - } - if (!hasBody) base match { - // because Java does this - case 16 => - in.error(offset, "Invalid hex literal number") - return INTLIT - case _ => - } - val code = if (in.head == '.') { - in.peek(1) match { - case c if isDigit(c) => in.next; getFraction(true).get - case 'f'|'F'|'d'|'D' if !isIdentifierPart(in.peek(2)) => in.next; getFraction(true).get - case 'e'|'E' if { - val peek = in.peek(2) - isDigit(peek) || peek == '-' || peek == '+' - } => - in.next // consume the dot - in.next // consume the e - in.next // consume the +/-/digit - in.readWhile(isDigit) // consume remaining digits - in.readIf{ - case 'f'|'F' => FLOATLIT - case 'd'|'D' => DOUBLELIT - } getOrElse DOUBLELIT - case c if isIdentifierStart(c) => INTLIT - case _ => in.next; DOUBLELIT - } - } else (in.readIf{ - case 'l'|'L' => LONGLIT - case 'f'|'F' => FLOATLIT - case 'd'|'D' => DOUBLELIT - } getOrElse { - if (in.head == 'e' || in.head == 'E') { - in.next - if (in.head == '-' || in.head == '+') in.next - in.readWhile(isDigit) - in.readIf{ - case 'f'|'F' => FLOATLIT - case 'd'|'D' => DOUBLELIT - } getOrElse DOUBLELIT - } else INTLIT - }) - if (in.readWhile(isIdentifierPart)) - in.error(offset, "Invalid literal number") - code - } - // todo: add LBRACKET - def inFirstOfStat(token: Int) = (token: @switch) match { - case EOF | CATCH | ELSE | EXTENDS | FINALLY | MATCH | REQUIRES | WITH | YIELD | - COMMA | SEMI | NEWLINE | NEWLINES | DOT | COLON | EQUALS | ARROW | LARROW | - SUBTYPE | VIEWBOUND | SUPERTYPE | HASH | RPAREN | RBRACKET | RBRACE => false - case _ => true - } - def inLastOfStat(token: Int) = (token: @switch) match { - case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | - IDENTIFIER | BACKQUOTED_IDENT | THIS | NULL | TRUE | FALSE | RETURN | USCORE | - TYPE | XMLSTART | RPAREN | RBRACKET | RBRACE => true - case _ => false - } - - def digit(c : Char, radix : Int) = c match { - case c if c >= '0' && c <= '7' => c - '0' - case c if c >= '8' && c <= '9' && radix >= 10 => c - '0' - case c if c >= '8' && c <= '9' && radix == 8 => throw new NumberFormatException("Malformed octal number") - case c if c >= 'a' && c <= 'f' && radix == 16 => c - 'a' + 9 - case c if c >= 'A' && c <= 'F' && radix == 16 => c - 'A' + 9 - } - private val simpleEscape : PartialFunction[Char,Char] = { - case 'b' => '\b' - case 't' => '\t' - case 'n' => '\n' - case 'f' => '\f' - case 'r' => '\r' - case '\"' => '\"' - case '\'' => '\'' - case '\\' => '\\' - } - - def digit2int(ch: Char, base: Int): Int = { - if ('0' <= ch && ch <= '9' && ch < '0' + base) - ch - '0' - else if ('A' <= ch && ch < 'A' + base - 10) - ch - 'A' + 10 - else if ('a' <= ch && ch < 'a' + base - 10) - ch - 'a' + 10 - else - -1 - } - - object ScannerConfiguration { - private var key: Array[Byte] = _ - private var maxKey = 0 - private var tokenName = new Array[global.Name](128); - { - var tokenCount = 0 - // Enter keywords - def enterKeyword(n: global.Name, tokenId: Int) { - while (tokenId >= tokenName.length) { - val newTokName = new Array[global.Name](tokenName.length * 2) - Array.copy(tokenName, 0, newTokName, 0, newTokName.length) - tokenName = newTokName - } - tokenName(tokenId) = n - if (n.start > maxKey) maxKey = n.start - if (tokenId >= tokenCount) tokenCount = tokenId + 1 - } - import global.nme - - enterKeyword(nme.ABSTRACTkw, ABSTRACT) - enterKeyword(nme.CASEkw, CASE) - enterKeyword(nme.CATCHkw, CATCH) - enterKeyword(nme.CLASSkw, CLASS) - enterKeyword(nme.DEFkw, DEF) - enterKeyword(nme.DOkw, DO) - enterKeyword(nme.ELSEkw, ELSE) - enterKeyword(nme.EXTENDSkw, EXTENDS) - enterKeyword(nme.FALSEkw, FALSE) - enterKeyword(nme.FINALkw, FINAL) - enterKeyword(nme.FINALLYkw, FINALLY) - enterKeyword(nme.FORkw, FOR) - enterKeyword(nme.FORSOMEkw, FORSOME) - enterKeyword(nme.IFkw, IF) - enterKeyword(nme.IMPLICITkw, IMPLICIT) - enterKeyword(nme.IMPORTkw, IMPORT) - enterKeyword(nme.LAZYkw, LAZY) - enterKeyword(nme.MATCHkw, MATCH) - enterKeyword(nme.NEWkw, NEW) - enterKeyword(nme.NULLkw, NULL) - enterKeyword(nme.OBJECTkw, OBJECT) - enterKeyword(nme.OVERRIDEkw, OVERRIDE) - enterKeyword(nme.PACKAGEkw, PACKAGE) - enterKeyword(nme.PRIVATEkw, PRIVATE) - enterKeyword(nme.PROTECTEDkw, PROTECTED) - enterKeyword(nme.REQUIRESkw, REQUIRES) - enterKeyword(nme.RETURNkw, RETURN) - enterKeyword(nme.SEALEDkw, SEALED) - enterKeyword(nme.SUPERkw, SUPER) - enterKeyword(nme.THISkw, THIS) - enterKeyword(nme.THROWkw, THROW) - enterKeyword(nme.TRAITkw, TRAIT) - enterKeyword(nme.TRUEkw, TRUE) - enterKeyword(nme.TRYkw, TRY) - enterKeyword(nme.TYPEkw, TYPE) - enterKeyword(nme.VALkw, VAL) - enterKeyword(nme.VARkw, VAR) - enterKeyword(nme.WHILEkw, WHILE) - enterKeyword(nme.WITHkw, WITH) - enterKeyword(nme.YIELDkw, YIELD) - enterKeyword(nme.DOTkw, DOT) - enterKeyword(nme.USCOREkw, USCORE) - enterKeyword(nme.COLONkw, COLON) - enterKeyword(nme.EQUALSkw, EQUALS) - enterKeyword(nme.ARROWkw, ARROW) - enterKeyword(nme.LARROWkw, LARROW) - enterKeyword(nme.SUBTYPEkw, SUBTYPE) - enterKeyword(nme.VIEWBOUNDkw, VIEWBOUND) - enterKeyword(nme.SUPERTYPEkw, SUPERTYPE) - enterKeyword(nme.HASHkw, HASH) - enterKeyword(nme.ATkw, AT) - - // Build keyword array - key = new Array[Byte](maxKey + 1) - for (i <- 0 to maxKey) - key(i) = IDENTIFIER - for (j <- 0 until tokenCount) - if (tokenName(j) ne null) - key(tokenName(j).start) = j.asInstanceOf[Byte] - - } -//Token representation ----------------------------------------------------- - - /** Convert name to token */ - def name2token(name: global.Name): Int = - if (name.start <= maxKey) key(name.start) else IDENTIFIER - - def isKeyword(code : Int) = code match { - case code if code >= IF && code <= REQUIRES => true - case _ => false - } - - /** Returns the string representation of given token. */ - def token2string(token: Int): String = token match { - case IDENTIFIER | BACKQUOTED_IDENT => "identifier" - case CHARLIT => "character literal" - case INTLIT => "integer literal" - case LONGLIT => "long literal" - case FLOATLIT => "float literal" - case DOUBLELIT => "double literal" - case STRINGLIT => "string literal" - case SYMBOLLIT => "symbol literal" - case LPAREN => "'('" - case RPAREN => "')'" - case LBRACE => "'{'" - case RBRACE => "'}'" - case LBRACKET => "'['" - case RBRACKET => "']'" - case EOF => "eof" - case ERROR => "something" - case SEMI => "';'" - case NEWLINE => "';'" - case NEWLINES => "';'" - case COMMA => "','" - case CASECLASS => - "case class" - case CASEOBJECT => - "case object" - case XMLSTART => - "$XMLSTART$<" - case COMMENT => "cmnt" - case WHITESPACE => "ws" - case IGNORE => "ig" - case _ => - try { - "'" + tokenName(token) + "'" - } catch { - case _: ArrayIndexOutOfBoundsException => - "'<" + token + ">'" - case _: NullPointerException => - "'<(" + token + ")>'" - } - } - } - - class UnitScanner(unit: CompilationUnit) extends ParserScanner { - implicit val in = - new DefaultInput(new NewCharArrayReader(unit.source.content, !settings.nouescape.value, error)) { - override def error(offset : Int, msg : String) : Unit = UnitScanner.this.error(offset, msg) - override def incompleteError(offset : Int, msg : String) = - unit.incompleteInputError(new OffsetPosition(unit.source, offset), msg) - } - init - private def error(offset : Int, msg : String) : Unit = unit.error(new OffsetPosition(unit.source,offset), msg) - } -} diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index ec739fa6e0..1fc1382ee8 100644..100755 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2,7 +2,7 @@ * Copyright 2005-2009 LAMP/EPFL * @author Martin Odersky */ -// $Id$ +// $Id: Parsers.scala 17415 2009-03-31 13:38:18Z imaier $ //todo: allow infix type patterns @@ -50,7 +50,8 @@ import Tokens._ * </li> * </ol> */ -trait Parsers extends NewScanners with MarkupParsers { +trait Parsers extends Scanners with MarkupParsers { +self => val global : Global import global._ @@ -59,12 +60,9 @@ trait Parsers extends NewScanners with MarkupParsers { case class OpInfo(operand: Tree, operator: Name, pos: Int) - /** ... - * - * @author Sean McDirmid - */ class UnitParser(val unit: global.CompilationUnit) extends Parser { val in = new UnitScanner(unit) + in.init() def freshName(pos: Position, prefix: String): Name = unit.fresh.newName(pos, prefix) @@ -82,19 +80,23 @@ trait Parsers extends NewScanners with MarkupParsers { def syntaxError(pos: Int, msg: String) { unit.error(pos, msg) } /** the markup parser */ - def xmlp = { - if (xmlp0 == null) - xmlp0 = new MarkupParser(this, true) - xmlp0 - } + lazy val xmlp = new MarkupParser(this, true) + object symbXMLBuilder extends SymbolicXMLBuilder(treeBuilder, this, true) { // DEBUG choices - val global: Parsers.this.global.type = Parsers.this.global + val global: self.global.type = self.global def freshName(prefix: String): Name = UnitParser.this.freshName(NoPosition, prefix) } - private var xmlp0: MarkupParser = null def xmlLiteral : Tree = xmlp.xLiteral def xmlLiteralPattern : Tree = xmlp.xLiteralPattern } + + class ScanOnly(unit: global.CompilationUnit) extends UnitParser(unit) { + override def parse(): Tree = { + while (in.token != EOF) in.nextToken + null + } + } + // parser constants, here so they don't pollute parser debug listing private object ParserConfiguration { final val Local = 0 @@ -114,34 +116,34 @@ trait Parsers extends NewScanners with MarkupParsers { abstract class Parser { ParserConfiguration.hashCode import ParserConfiguration._ - val in: ParserScanner + val in: Scanner //val unit : CompilationUnit //import in.ScanPosition protected def freshName(pos: Position, prefix: String): Name - protected def posToReport: Int = in.currentPos + protected def posToReport: Int = in.offset protected implicit def i2p(offset: Int): Position //private implicit def p2i(pos: Position) = pos.offset.get private def inToken = in.token - private def inSkipToken = in.skipToken - private def inNextToken = in.nextToken - private def inCurrentPos = in.currentPos - private def inNextTokenCode : Int = in.nextTokenCode + private def inSkipToken = in.skipToken() + private def inNextToken = in.nextToken() + private def inCurrentPos = in.offset + private def inNextTokenCode : Int = in.next.token private def inName = in.name private def charVal = in.charVal private def intVal(isNegated: Boolean) = in.intVal(isNegated).asInstanceOf[Int] private def longVal(isNegated: Boolean) = in.intVal(isNegated) private def floatVal(isNegated: Boolean) = in.floatVal(isNegated).asInstanceOf[Float] private def doubleVal(isNegated: Boolean) = in.floatVal(isNegated) - private def stringVal = in.stringVal + private def stringVal = in.strVal /** whether a non-continuable syntax error has been seen */ //private var syntaxErrorSeen = false private var lastErrorPos : Int = -1 object treeBuilder extends TreeBuilder { - val global: Parsers.this.global.type = Parsers.this.global + val global: self.global.type = self.global def freshName(pos : Position, prefix: String): Name = Parser.this.freshName(pos, prefix) } @@ -298,8 +300,7 @@ trait Parsers extends NewScanners with MarkupParsers { //else inCurrentPos val msg = - ScannerConfiguration.token2string(token) + " expected but " + - ScannerConfiguration.token2string(inToken) + " found." + token2string(token) + " expected but " +token2string(inToken) + " found." if (inToken == EOF) incompleteInputError(msg) @@ -680,7 +681,7 @@ trait Parsers extends NewScanners with MarkupParsers { */ def requiresTypeOpt(): Tree = if (inToken == REQUIRES) { - deprecationWarning(in.currentPos, "`requires T' has been deprecated; use `{ self: T => ...' instead") + deprecationWarning(inCurrentPos, "`requires T' has been deprecated; use `{ self: T => ...' instead") inNextToken; annotType(false) } else TypeTree() @@ -836,7 +837,7 @@ trait Parsers extends NewScanners with MarkupParsers { accept(RPAREN) atPos(pos) { makeTupleType(ts, true) } } else if (inToken == USCORE) { - wildcardType(in.skipToken) + wildcardType(inSkipToken) } else { val r = path(false, true) r match { @@ -931,7 +932,7 @@ trait Parsers extends NewScanners with MarkupParsers { def exprs(): List[Tree] = { val ts = new ListBuffer[Tree] + expr() while (inToken == COMMA) { - val pos = in.currentPos + val pos = inCurrentPos inNextToken if (inToken == RPAREN) { deprecationWarning(pos, "Trailing commas have been deprecated") @@ -1039,7 +1040,7 @@ trait Parsers extends NewScanners with MarkupParsers { Throw(expr()) } case DOT => - deprecationWarning(in.currentPos, "`.f' has been deprecated; use `_.f' instead") + deprecationWarning(inCurrentPos, "`.f' has been deprecated; use `_.f' instead") atPos(inSkipToken) { if (isIdent) { makeDotClosure(stripParens(simpleExpr())) @@ -1158,7 +1159,7 @@ trait Parsers extends NewScanners with MarkupParsers { val name = unaryOp() atPos(pos) { Select(stripParens(simpleExpr()), name) } } else if (isIdent && inName == AMP) { - deprecationWarning(in.currentPos, "`&f' has been deprecated; use `f _' instead") + deprecationWarning(inCurrentPos, "`&f' has been deprecated; use `f _' instead") val pos = inCurrentPos val name = ident() atPos(pos) { Typed(stripParens(simpleExpr()), Function(List(), EmptyTree)) } @@ -1284,8 +1285,9 @@ trait Parsers extends NewScanners with MarkupParsers { /** Block ::= BlockStatSeq */ - def block(): Tree = + def block(): Tree = { makeBlock(blockStatSeq(new ListBuffer[Tree])) + } /** CaseClauses ::= CaseClause {CaseClause} */ @@ -1742,7 +1744,7 @@ trait Parsers extends NewScanners with MarkupParsers { val pos = inCurrentPos newLineOptWhenFollowedBy(LPAREN) if (ofCaseClass && inToken != LPAREN) - deprecationWarning(in.currentPos, "case classes without a parameter list have been deprecated;\n"+ + deprecationWarning(inCurrentPos, "case classes without a parameter list have been deprecated;\n"+ "use either case objects or case classes with `()' as parameter list.") while (implicitmod == 0 && inToken == LPAREN) { inNextToken diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers1.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers1.scala deleted file mode 100755 index 8e181d8f4a..0000000000 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers1.scala +++ /dev/null @@ -1,2607 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2009 LAMP/EPFL - * @author Martin Odersky - */ -// $Id: Parsers.scala 17415 2009-03-31 13:38:18Z imaier $ -//todo: allow infix type patterns - - -package scala.tools.nsc.ast.parser - -import scala.collection.mutable.ListBuffer -import scala.tools.nsc.util.{Position, OffsetPosition, NoPosition, BatchSourceFile} -import symtab.Flags -import Tokens._ - -//todo verify when stableId's should be just plain qualified type ids - -/** <p>Performs the following context-free rewritings:</p> - * <ol> - * <li> - * Places all pattern variables in Bind nodes. In a pattern, for - * identifiers <code>x</code>:<pre> - * x => x @ _ - * x:T => x @ (_ : T)</pre> - * </li> - * <li>Removes pattern definitions (PatDef's) as follows: - * If pattern is a simple (typed) identifier:<pre> - * <b>val</b> x = e ==> <b>val</b> x = e - * <b>val</b> x: T = e ==> <b>val</b> x: T = e</pre> - * - * if there are no variables in pattern<pre> - * <b>val</b> p = e ==> e match (case p => ())</pre> - * - * if there is exactly one variable in pattern<pre> - * <b>val</b> x_1 = e <b>match</b> (case p => (x_1))</pre> - * - * if there is more than one variable in pattern<pre> - * <b>val</b> p = e ==> <b>private synthetic val</b> t$ = e <b>match</b> (case p => (x_1, ..., x_N)) - * <b>val</b> x_1 = t$._1 - * ... - * <b>val</b> x_N = t$._N</pre> - * </li> - * <li> - * Removes function types as follows:<pre> - * (argtpes) => restpe ==> scala.Function_n[argtpes, restpe]</pre> - * </li> - * <li> - * Wraps naked case definitions in a match as follows:<pre> - * { cases } ==> (x => x.match {cases})<span style="font-family:normal;">, except when already argument to match</span></pre> - * </li> - * </ol> - */ -trait Parsers1 extends Scanners1 with MarkupParsers1 { -self => - val global : Global - import global._ - - private val glob: global.type = global - import global.posAssigner.atPos - - case class OpInfo(operand: Tree, operator: Name, pos: Int) - - class UnitParser(val unit: global.CompilationUnit) extends Parser { - val in = new UnitScanner(unit) - in.init() - - def freshName(pos: Position, prefix: String): Name = - unit.fresh.newName(pos, prefix) - - implicit def i2p(offset: Int): Position = new OffsetPosition(unit.source,offset) - - def warning(pos: Int, msg: String) { unit.warning(pos, msg) } - - def incompleteInputError(msg: String) { - unit.incompleteInputError(unit.source.asInstanceOf[BatchSourceFile].content.length - 1, msg) - } - def deprecationWarning(pos: Int, msg: String) { - unit.deprecationWarning(pos, msg) - } - def syntaxError(pos: Int, msg: String) { unit.error(pos, msg) } - - /** the markup parser */ - lazy val xmlp = new MarkupParser(this, true) - - object symbXMLBuilder extends SymbolicXMLBuilder1(treeBuilder, this, true) { // DEBUG choices - val global: self.global.type = self.global - def freshName(prefix: String): Name = UnitParser.this.freshName(NoPosition, prefix) - } - def xmlLiteral : Tree = xmlp.xLiteral - def xmlLiteralPattern : Tree = xmlp.xLiteralPattern - } - - class ScanOnly(unit: global.CompilationUnit) extends UnitParser(unit) { - override def parse(): Tree = { - while (in.token != EOF) in.nextToken - null - } - } - - // parser constants, here so they don't pollute parser debug listing - private object ParserConfiguration { - final val Local = 0 - final val InBlock = 1 - final val InTemplate = 2 - final val MINUS: Name = "-" - final val PLUS : Name = "+" - final val BANG : Name = "!" - final val TILDE: Name = "~" - final val AMP : Name = "&" - final val SLASH: Name = "/" - final val STAR : Name = "*" - final val BAR : Name = "|" - final val LT : Name = "<" - } - - abstract class Parser { - ParserConfiguration.hashCode - import ParserConfiguration._ - val in: Scanner - //val unit : CompilationUnit - //import in.ScanPosition - protected def freshName(pos: Position, prefix: String): Name - protected def posToReport: Int = in.offset - - protected implicit def i2p(offset: Int): Position - //private implicit def p2i(pos: Position) = pos.offset.get - - private def inToken = in.token - private def inSkipToken = in.skipToken() - private def inNextToken = in.nextToken() - private def inCurrentPos = in.offset - private def inNextTokenCode : Int = in.next.token - private def inName = in.name - private def charVal = in.charVal - private def intVal(isNegated: Boolean) = in.intVal(isNegated).asInstanceOf[Int] - private def longVal(isNegated: Boolean) = in.intVal(isNegated) - private def floatVal(isNegated: Boolean) = in.floatVal(isNegated).asInstanceOf[Float] - private def doubleVal(isNegated: Boolean) = in.floatVal(isNegated) - private def stringVal = in.strVal - - /** whether a non-continuable syntax error has been seen */ - //private var syntaxErrorSeen = false - private var lastErrorPos : Int = -1 - - object treeBuilder extends TreeBuilder { - val global: self.global.type = self.global - def freshName(pos : Position, prefix: String): Name = - Parser.this.freshName(pos, prefix) - } - import treeBuilder._ - - /** The implicit view parameters of the surrounding class */ - var implicitClassViews: List[Tree] = Nil - - /** this is the general parse method - */ - def parse(): Tree = { - val t = compilationUnit() - accept(EOF) - t - } - -/* --------------- PLACEHOLDERS ------------------------------------------- */ - - /** The implicit parameters introduced by `_' in the current expression. - * Parameters appear in reverse order - */ - var placeholderParams: List[ValDef] = Nil - - /** The placeholderTypes introduced by `_' in the current type. - * Parameters appear in reverse order - */ - var placeholderTypes: List[TypeDef] = Nil - - def checkNoEscapingPlaceholders[T](op: => T): T = { - val savedPlaceholderParams = placeholderParams - val savedPlaceholderTypes = placeholderTypes - placeholderParams = List() - placeholderTypes = List() - - val res = op - - placeholderParams match { - case vd :: _ => - syntaxError(vd.pos, "unbound placeholder parameter", false) - placeholderParams = List() - case _ => - } - placeholderTypes match { - case td :: _ => - syntaxError(td.pos, "unbound wildcard type", false) - placeholderTypes = List() - case _ => - } - placeholderParams = savedPlaceholderParams - placeholderTypes = savedPlaceholderTypes - - res - } - - def placeholderTypeBoundary(op: => Tree): Tree = { - val savedPlaceholderTypes = placeholderTypes - placeholderTypes = List() - var t = op - if (!placeholderTypes.isEmpty && t.isInstanceOf[AppliedTypeTree]) { - t = ExistentialTypeTree(t, placeholderTypes.reverse) - placeholderTypes = List() - } - placeholderTypes = placeholderTypes ::: savedPlaceholderTypes - t - } - -/* ------------- ERROR HANDLING ------------------------------------------- */ - - protected def skip() { - var nparens = 0 - var nbraces = 0 - while (true) { - inToken match { - case EOF => - return - case SEMI => - if (nparens == 0 && nbraces == 0) return - case NEWLINE => - if (nparens == 0 && nbraces == 0) return - case NEWLINES => - if (nparens == 0 && nbraces == 0) return - case RPAREN => - nparens -= 1 - case RBRACE => - if (nbraces == 0) return - nbraces -= 1 - case LPAREN => - nparens += 1 - case LBRACE => - nbraces += 1 - case _ => - } - inNextToken - } - } - def warning(pos: Int, msg: String): Unit - def incompleteInputError(msg: String): Unit - def deprecationWarning(pos: Int, msg: String): Unit - private def syntaxError(pos: Position, msg: String, skipIt: Boolean) { - pos.offset match { - case None => syntaxError(msg,skipIt) - case Some(offset) => syntaxError(offset, msg, skipIt) - } - } - def syntaxError(pos: Int, msg: String): Unit - def syntaxError(msg: String, skipIt: Boolean) { - syntaxError(inCurrentPos, msg, skipIt) - } - - def syntaxError(pos: Int, msg: String, skipIt: Boolean) { - if (pos > lastErrorPos) { - syntaxError(pos, msg) - // no more errors on this token. - lastErrorPos = inCurrentPos - } - if (skipIt) - skip() - } - - def warning(msg: String) { warning(inCurrentPos, msg) } - - def syntaxErrorOrIncomplete(msg: String, skipIt: Boolean) { - val inToken = this.inToken - if (inToken == EOF) - incompleteInputError(msg) - else - syntaxError(inCurrentPos, msg, skipIt) - } - // unused. - /* Commented out because the comment says it is unused. - Probably eliminate eventually. GAW 2008.05.01 - def mismatch(expected: Int, found: Int) { - val posToReport = this.posToReport - val msg = - ScannerConfiguration.token2string(expected) + " expected but " + - ScannerConfiguration.token2string(found) + " found." - - if (found == EOF) - incompleteInputError(msg) - else - syntaxError(posToReport, msg, true) - } - */ - - /** Consume one token of the specified type, or - * signal an error if it is not there. - */ - def accept(token: Int): Int = { - val pos = inCurrentPos - if (inToken != token) { - val posToReport = - //if (inCurrentPos.line(unit.source).get(0) > in.lastPos.line(unit.source).get(0)) - // in.lastPos - //else - inCurrentPos - val msg = - token2string(token) + " expected but " +token2string(inToken) + " found." - - if (inToken == EOF) - incompleteInputError(msg) - else - syntaxError(posToReport, msg, true) - } - if (inToken == token) inNextToken - pos - } - def surround[T](open: Int, close: Int)(f: => T, orElse: T): T = { - val wasOpened = inToken == open - accept(open) - if (wasOpened) { - val ret = f - accept(close) - ret - } else orElse - } - - /** semi = nl {nl} | `;' - * nl = `\n' // where allowed - */ - def acceptStatSep(): Boolean = - if (inToken == NEWLINE || inToken == NEWLINES) { inNextToken; true } - else { - val ret = inToken == SEMI - accept(SEMI) - ret - } - - def errorTypeTree = TypeTree().setType(ErrorType).setPos((inCurrentPos)) - def errorTermTree = Literal(Constant(null)).setPos((inCurrentPos)) - def errorPatternTree = Ident(nme.WILDCARD).setPos((inCurrentPos)) - -/* -------------- TOKEN CLASSES ------------------------------------------- */ - - def isModifier: Boolean = inToken match { - case ABSTRACT | FINAL | SEALED | PRIVATE | - PROTECTED | OVERRIDE | IMPLICIT | LAZY => true - case _ => false - } - - def isLocalModifier: Boolean = inToken match { - case ABSTRACT | FINAL | SEALED | IMPLICIT | LAZY => true - case _ => false - } - - def isDefIntro: Boolean = inToken match { - case VAL | VAR | DEF | TYPE | OBJECT | - CASEOBJECT | CLASS | CASECLASS | TRAIT => true - case _ => false - } - - def isDclIntro: Boolean = inToken match { - case VAL | VAR | DEF | TYPE => true - case _ => false - } - - def isIdent = inToken == IDENTIFIER || inToken == BACKQUOTED_IDENT - - def isExprIntroToken(token: Int): Boolean = token match { - case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | - STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL | IDENTIFIER | BACKQUOTED_IDENT | - THIS | SUPER | IF | FOR | NEW | USCORE | TRY | WHILE | - DO | RETURN | THROW | LPAREN | LBRACE | XMLSTART => true - case _ => false - } - - def isExprIntro: Boolean = isExprIntroToken(inToken) - - def isTypeIntroToken(token: Int): Boolean = token match { - case IDENTIFIER | BACKQUOTED_IDENT | THIS | - SUPER | USCORE | LPAREN | AT => true - case _ => false - } - - def isTypeIntro: Boolean = isTypeIntroToken(inToken) - - def isStatSep(token: Int): Boolean = - token == NEWLINE || token == NEWLINES || token == SEMI - - def isStatSep: Boolean = isStatSep(inToken) - - -/* --------- COMMENT AND ATTRIBUTE COLLECTION ----------------------------- */ - - /** Join the comment associated with a definition - */ - def joinComment(trees: => List[Tree]): List[Tree] = { - val buf = in.flushDoc - if ((buf ne null) && buf.length > 0) trees map (t => DocDef(buf, t) setPos t.pos) - else trees - } - -/* ---------- TREE CONSTRUCTION ------------------------------------------- */ - - /** Convert tree to formal parameter list - */ - def convertToParams(tree: Tree): List[ValDef] = tree match { - case Parens(ts) => - ts map convertToParam - case _ => - List(convertToParam(tree)) - } - - /** Convert tree to formal parameter - */ - def convertToParam(tree: Tree): ValDef = - atPos(tree.pos) { - def removeAsPlaceholder(name: Name) { - placeholderParams = placeholderParams filter (_.name != name) - } - tree match { - case Ident(name) => - removeAsPlaceholder(name) - ValDef(Modifiers(Flags.PARAM), name, TypeTree(), EmptyTree) - case Typed(tree @ Ident(name), tpe) if (tpe.isType) => // get the ident! - removeAsPlaceholder(name) - ValDef(Modifiers(Flags.PARAM), name, tpe, EmptyTree).setPos(tree.pos) - case _ => - syntaxError(tree.pos, "not a legal formal parameter", false) - ValDef(Modifiers(Flags.PARAM), nme.ERROR, errorTypeTree, EmptyTree) - } - } - - /** Convert (qual)ident to type identifier - */ - def convertToTypeId(tree: Tree): Tree = tree match { - case Ident(name) => - Ident(name.toTypeName).setPos(tree.pos) - case Select(qual, name) => - Select(qual, name.toTypeName).setPos(tree.pos) - case _ => - syntaxError(tree.pos, "identifier expected", false) - errorTypeTree - } - - /** make closure from tree staring with a `.' */ - def makeDotClosure(tree: Tree): Tree = { - val pname = freshName(tree.pos, "x$") - def insertParam(tree: Tree): Tree = atPos(tree.pos) { - tree match { - case Ident(name) => - Select(Ident(pname), name) - case Select(qual, name) => - Select(insertParam(qual), name) - case Apply(fn, args) => - Apply(insertParam(fn), args) - case TypeApply(fn, args) => - TypeApply(insertParam(fn), args) - case _ => - syntaxError(tree.pos, "cannot convert to closure", false) - errorTermTree - } - } - Function(List(makeSyntheticParam(pname)), insertParam(tree)) - } - -/* --------- OPERAND/OPERATOR STACK --------------------------------------- */ - - var opstack: List[OpInfo] = Nil - - def precedence(operator: Name): Int = - if (operator eq nme.ERROR) -1 - else { - val firstCh = operator(0) - if (((firstCh >= 'A') && (firstCh <= 'Z')) || - ((firstCh >= 'a') && (firstCh <= 'z'))) - 1 - else if (nme.isOpAssignmentName(operator)) - 0 - else - firstCh match { - case '|' => 2 - case '^' => 3 - case '&' => 4 - case '=' | '!' => 5 - case '<' | '>' => 6 - case ':' => 7 - case '+' | '-' => 8 - case '*' | '/' | '%' => 9 - case _ => 10 - } - } - - def checkSize(kind: String, size: Int, max: Int) { - if (size > max) syntaxError("too many "+kind+", maximum = "+max, false) - } - - def checkAssoc(pos: Int, op: Name, leftAssoc: Boolean) = - if (treeInfo.isLeftAssoc(op) != leftAssoc) - syntaxError( - pos, "left- and right-associative operators with same precedence may not be mixed", false) - - def reduceStack(isExpr: Boolean, base: List[OpInfo], top0: Tree, - prec: Int, leftAssoc: Boolean): Tree = { - var top = top0 - if (opstack != base && precedence(opstack.head.operator) == prec) - checkAssoc(opstack.head.pos, opstack.head.operator, leftAssoc) - while (opstack != base && - (prec < precedence(opstack.head.operator) || - (leftAssoc && prec == precedence(opstack.head.operator)))) { - top = atPos(opstack.head.pos) { - makeBinop(isExpr, opstack.head.operand, opstack.head.operator, top) - } - opstack = opstack.tail - } - top - } - -/* -------- IDENTIFIERS AND LITERALS ------------------------------------------- */ - - def ident(): Name = - if (inToken == IDENTIFIER || inToken == BACKQUOTED_IDENT) { - val name = inName.encode - inNextToken - name - } else { - accept(IDENTIFIER) - nme.ERROR - } - - def selector(t: Tree): Tree = - atPos(inCurrentPos)(Select(t, ident())) - - /** Path ::= StableId - * | [Ident `.'] this - * AnnotType ::= Path [`.' type] - */ - def path(thisOK: Boolean, typeOK: Boolean): Tree = { - var t: Tree = null - if (inToken == THIS) { - t = atPos(inSkipToken) { This(nme.EMPTY.toTypeName) } - if (!thisOK || inToken == DOT) { - t = selectors(t, typeOK, accept(DOT)) - } - } else if (inToken == SUPER) { - // val pos = inCurrentPos - val pos = inSkipToken - val (mix,usePos) = mixinQualifierOpt(pos) - t = atPos(usePos) { - Super(nme.EMPTY.toTypeName, mix) - } - t = atPos(accept(DOT)) { selector(t) } - if (inToken == DOT) - t = selectors(t, typeOK, inSkipToken) - } else { - val i = atPos(inCurrentPos) { - if (inToken == BACKQUOTED_IDENT) new BackQuotedIdent(ident()) - else Ident(ident()) - } - t = i - if (inToken == DOT) { - val pos = inSkipToken - if (inToken == THIS) { - inNextToken - t = atPos(i.pos) { This(i.name.toTypeName) } - if (!thisOK || inToken == DOT) - t = selectors(t, typeOK, accept(DOT)) - } else if (inToken == SUPER) { - inNextToken - val (mix,pos) = mixinQualifierOpt(i.pos) - t = atPos(pos) { Super(i.name.toTypeName, mix) } - t = atPos(accept(DOT)) {selector(t)} - if (inToken == DOT) - t = selectors(t, typeOK, inSkipToken) - } else { - t = selectors(t, typeOK, pos) - } - } - } - t - } - - def selectors(t: Tree, typeOK: Boolean, pos : Int): Tree = - if (typeOK && inToken == TYPE) { - inNextToken - atPos(pos) { SingletonTypeTree(t) } - } else { - val t1 = atPos(pos) { selector(t); } - if (inToken == DOT) { selectors(t1, typeOK, inSkipToken) } - else t1 - } - - /** MixinQualifier ::= `[' Id `]' - */ - def mixinQualifierOpt(pos: Position): (Name, Position) = - if (inToken == LBRACKET) { - inNextToken - val pos = inCurrentPos - val name = ident().toTypeName - accept(RBRACKET) - (name, pos) - } else { - (nme.EMPTY.toTypeName, pos) - } - - /** StableId ::= Id - * | Path `.' Id - * | [id '.'] super [`[' id `]']`.' id - */ - def stableId(): Tree = - path(false, false) - - /** QualId ::= Id {`.' Id} - */ - def qualId(): Tree = { - val id = atPos(inCurrentPos) { Ident(ident()) } - if (inToken == DOT) { selectors(id, false, inSkipToken) } - else id - } - - /** SimpleExpr ::= literal - * | symbol - * | null - */ - - def literal(isPattern: Boolean, isNegated: Boolean): Tree = { - def litToTree() = atPos(inCurrentPos) { - Literal( - inToken match { - case CHARLIT => Constant(charVal) - case INTLIT => Constant(intVal(isNegated)) - case LONGLIT => Constant(longVal(isNegated)) - case FLOATLIT => Constant(floatVal(isNegated)) - case DOUBLELIT => Constant(doubleVal(isNegated)) - case STRINGLIT | SYMBOLLIT => Constant(stringVal) - case TRUE => Constant(true) - case FALSE => Constant(false) - case NULL => Constant(null) - case _ => - syntaxErrorOrIncomplete("illegal literal", true) - null - }) - } - - val isSymLit = inToken == SYMBOLLIT - val t = litToTree() - val pos = inSkipToken - if (isSymLit) { - atPos(pos) { - var symid = scalaDot(nme.Symbol) - Apply(symid, List(t)) - } - } else { - t - } - } - - def newLineOpt() { - if (inToken == NEWLINE) inNextToken - } - - def newLinesOpt() { - if (inToken == NEWLINE || inToken == NEWLINES) - inNextToken - } - - def newLineOptWhenFollowedBy(token: Int) { - // note: next is defined here because current == NEWLINE - if (inToken == NEWLINE && inNextTokenCode == token) newLineOpt() - } - - def newLineOptWhenFollowing(p: Int => Boolean) { - // note: next is defined here because current == NEWLINE - if (inToken == NEWLINE && p(inNextTokenCode)) newLineOpt() - } - -/* ------------- TYPES ---------------------------------------------------- */ - - /** TypedOpt ::= [`:' Type] - */ - def typedOpt(): Tree = - if (inToken == COLON) { inNextToken; typ() } - else TypeTree() - - /** RequiresTypedOpt ::= [requires AnnotType] - */ - def requiresTypeOpt(): Tree = - if (inToken == REQUIRES) { - deprecationWarning(inCurrentPos, "`requires T' has been deprecated; use `{ self: T => ...' instead") - inNextToken; annotType(false) - } else TypeTree() - - /** Types ::= Type {`,' Type} - * (also eats trailing comma if it finds one) - */ - def types(isPattern: Boolean, isTypeApply: Boolean, isFuncArg: Boolean): List[Tree] = { - val ts = new ListBuffer[Tree] + argType(isPattern, isTypeApply, isFuncArg) - while (inToken == COMMA) { - val pos = inCurrentPos - inNextToken - if (inToken == RPAREN) { - deprecationWarning(pos, "Trailing commas have been deprecated") - return ts.toList - } else { - ts += argType(isPattern, isTypeApply, isFuncArg) - } - } - ts.toList - } - - /** modes for infix types */ - object InfixMode extends Enumeration { - val FirstOp, LeftOp, RightOp = Value - } - - /** Type ::= InfixType `=>' Type - * | `(' [`=>' Type] `)' `=>' Type - * | InfixType [ExistentialClause] - * ExistentialClause ::= forSome `{' ExistentialDcl {semi ExistentialDcl}} `}' - * ExistentialDcl ::= type TypeDcl | val ValDcl - */ - def typ(): Tree = typ(false) - - def typ(isPattern: Boolean): Tree = placeholderTypeBoundary { - val t = - if (inToken == LPAREN) { - val pos = inSkipToken - if (inToken == RPAREN) { - inNextToken - atPos(accept(ARROW)) { makeFunctionTypeTree(List(), typ(isPattern)) } - } else { - val ts = types(isPattern, false, true) - accept(RPAREN) - if (inToken == ARROW) atPos(inSkipToken) { - makeFunctionTypeTree(ts, typ(isPattern)) - } - else { - for (t <- ts) t match { - case AppliedTypeTree(Select(_, n), _) - if (n == nme.BYNAME_PARAM_CLASS_NAME.toTypeName) => - syntaxError(t.pos, "no by-name parameter type allowed here", false) - case _ => - } - infixTypeRest(pos, annotTypeRest(pos, isPattern, makeTupleType(ts, true)), false, InfixMode.FirstOp) - } - } - } else { - infixType(isPattern, InfixMode.FirstOp) - } - if (inToken == ARROW) - atPos(inSkipToken) { - makeFunctionTypeTree(List(t), typ(isPattern)) - } - else if (inToken == FORSOME) - atPos(inSkipToken) { - val whereClauses = refinement() - for (wc <- whereClauses) { - wc match { - case TypeDef(_, _, _, TypeBoundsTree(_, _)) | - ValDef(_, _, _, EmptyTree) | EmptyTree => - ; - case _ => - syntaxError(wc.pos, "not a legal existential clause", false) - } - } - ExistentialTypeTree(t, whereClauses) - } - else t - } - - /** InfixType ::= CompoundType {id [nl] CompoundType} - */ - def infixType(isPattern: Boolean, mode: InfixMode.Value): Tree = placeholderTypeBoundary { - infixTypeRest(inCurrentPos, infixTypeFirst(isPattern), isPattern, mode) - } - - def infixTypeFirst(isPattern: Boolean): Tree = - if (inToken == LBRACE) scalaAnyRefConstr else annotType(isPattern) - - def infixTypeRest(pos: Int, t0: Tree, isPattern: Boolean, mode: InfixMode.Value): Tree = { - val t = compoundTypeRest(pos, t0, isPattern) - if (isIdent && inName != nme.STAR) { - val opPos = inCurrentPos - val leftAssoc = treeInfo.isLeftAssoc(inName) - if (mode == InfixMode.LeftOp) checkAssoc(opPos, inName, true) - else if (mode == InfixMode.RightOp) checkAssoc(opPos, inName, false) - val op = ident() - newLineOptWhenFollowing(isTypeIntroToken) - def mkOp(t1: Tree) = atPos(opPos) { AppliedTypeTree(Ident(op.toTypeName), List(t, t1)) } - if (leftAssoc) - infixTypeRest(inCurrentPos, mkOp(compoundType(isPattern)), isPattern, InfixMode.LeftOp) - else - mkOp(infixType(isPattern, InfixMode.RightOp)) - } else t - } - - /** CompoundType ::= AnnotType {with AnnotType} [Refinement] - * | Refinement - */ - def compoundType(isPattern: Boolean): Tree = - compoundTypeRest(inCurrentPos, infixTypeFirst(isPattern), isPattern) - - def compoundTypeRest(pos: Int, t: Tree, isPattern: Boolean): Tree = { - var ts = new ListBuffer[Tree] + t - while (inToken == WITH) { - inNextToken; ts += annotType(isPattern) - } - newLineOptWhenFollowedBy(LBRACE) - atPos(pos) { - if (inToken == LBRACE) { - // Warn if they are attempting to refine Unit; we can't be certain it's - // scala.Unit they're refining because at this point all we have is an - // identifier, but at a later stage we lose the ability to tell an empty - // refinement from no refinement at all. See bug #284. - for (Ident(name) <- ts) name.toString match { - case "Unit" | "scala.Unit" => - warning("Detected apparent refinement of Unit; are you missing an '=' sign?") - case _ => - } - CompoundTypeTree(Template(ts.toList, emptyValDef, refinement())) - } - else - makeIntersectionTypeTree(ts.toList) - } - } - - /** AnnotType ::= SimpleType {Annotation} - * SimpleType ::= SimpleType TypeArgs - * | SimpleType `#' Id - * | StableId - * | Path `.' type - * | `(' Types [`,'] `)' - * | WildcardType - */ - def annotType(isPattern: Boolean): Tree = placeholderTypeBoundary { - val pos = inCurrentPos - - val t: Tree = annotTypeRest(pos, isPattern, - if (inToken == LPAREN) { - inNextToken - val ts = types(isPattern, false, false) - accept(RPAREN) - atPos(pos) { makeTupleType(ts, true) } - } else if (inToken == USCORE) { - wildcardType(inSkipToken) - } else { - val r = path(false, true) - r match { - case SingletonTypeTree(_) => r - case _ => convertToTypeId(r) - } - }) - (t /: annotations(false)) (makeAnnotated) - } - - def annotTypeRest(pos: Int, isPattern: Boolean, t: Tree): Tree = - if (inToken == HASH) { - inSkipToken - val posId = inCurrentPos - val id = ident - annotTypeRest(pos, isPattern, atPos(posId) { SelectFromTypeTree(t, id.toTypeName) }) - } else if (inToken == LBRACKET) { - val usePos = if (t.pos != NoPosition) t.pos else i2p(pos) - annotTypeRest(pos, isPattern, atPos(usePos) { AppliedTypeTree(t, typeArgs(isPattern, false)) }) - } - else - t - - /** WildcardType ::= `_' TypeBounds - */ - def wildcardType(pos: Int) = { - val pname = freshName(pos, "_$").toTypeName - val param = atPos(pos) { makeSyntheticTypeParam(pname, typeBounds()) } - placeholderTypes = param :: placeholderTypes - Ident(pname) setPos pos - } - - /** TypeArgs ::= `[' ArgType {`,' ArgType} `]' - */ - def typeArgs(isPattern: Boolean, isTypeApply: Boolean): List[Tree] = { - accept(LBRACKET) - val ts = types(isPattern, isTypeApply, false) - accept(RBRACKET) - ts - } - - /** ArgType ::= Type - */ - def argType(isPattern: Boolean, isTypeApply: Boolean, isFuncArg: Boolean): Tree = - if (isPattern) { - if (inToken == USCORE) - if (inToken == SUBTYPE || inToken == SUPERTYPE) wildcardType(inSkipToken) - else atPos(inSkipToken) { Bind(nme.WILDCARD.toTypeName, EmptyTree) } - else if (inToken == IDENTIFIER && treeInfo.isVariableName(inName.toTypeName)) - atPos(inCurrentPos) { - Bind(ident().toTypeName, EmptyTree) - } - else { - typ(true) - } - } else if (isFuncArg) { - // copy-paste (with change) from def paramType - if (inToken == ARROW) - atPos(inSkipToken) { - AppliedTypeTree( - rootScalaDot(nme.BYNAME_PARAM_CLASS_NAME.toTypeName), List(typ())) - } - else { - val t = typ() - if (isIdent && inName == STAR) { - inNextToken - atPos(t.pos) { - AppliedTypeTree( - rootScalaDot(nme.REPEATED_PARAM_CLASS_NAME.toTypeName), List(t)) - } - } else t - } - } else if (isTypeApply) { - typ() - } else { - typ() - } - -/* ----------- EXPRESSIONS ------------------------------------------------ */ - - /** EqualsExpr ::= `=' Expr - */ - def equalsExpr(): Tree = { - accept(EQUALS) - expr() - } - - /** Exprs ::= Expr {`,' Expr} - * - * (also eats trailing comma if it finds one) - */ - def exprs(): List[Tree] = { - val ts = new ListBuffer[Tree] + expr() - while (inToken == COMMA) { - val pos = inCurrentPos - inNextToken - if (inToken == RPAREN) { - deprecationWarning(pos, "Trailing commas have been deprecated") - return ts.toList - } else { - ts += expr() - } - } - ts.toList - } - - - /** Expr ::= (Bindings | Id | `_') `=>' Expr - * | Expr1 - * ResultExpr ::= (Bindings | Id `:' CompoundType) `=>' Block - * | Expr1 - * Expr1 ::= if `(' Expr `)' {nl} Expr [[semi] else Expr] - * | try (`{' Block `}' | Expr) [catch `{' CaseClauses `}'] [finally Expr] - * | while `(' Expr `)' {nl} Expr - * | do Expr [semi] while `(' Expr `)' - * | for (`(' Enumerators `)' | '{' Enumerators '}') {nl} [yield] Expr - * | throw Expr - * | return [Expr] - * | [SimpleExpr `.'] Id `=' Expr - * | SimpleExpr1 ArgumentExprs `=' Expr - * | PostfixExpr Ascription - * | PostfixExpr match `{' CaseClauses `}' - * Bindings ::= `(' [Binding {`,' Binding}] `)' - * Binding ::= (Id | `_') [`:' Type] - * Ascription ::= `:' CompoundType - * | `:' Annotation {Annotation} - * | `:' `_' `*' - */ - def expr(): Tree = expr(Local) - /* hook for IDE, unlike expression can be stubbed - * don't use for any tree that can be inspected in the parser! - */ - def statement(location: Int): Tree = expr(location) - def expr(location: Int): Tree = { - def isWildcard(t: Tree): Boolean = t match { - case Ident(name1) if !placeholderParams.isEmpty && name1 == placeholderParams.head.name => true - case Typed(t1, _) => isWildcard(t1) - case Annotated(t1, _) => isWildcard(t1) - case _ => false - } - var savedPlaceholderParams = placeholderParams - placeholderParams = List() - var res = inToken match { - case IF => - val pos = inSkipToken - val cond = surround(LPAREN,RPAREN)(expr(),Literal(true)) - newLinesOpt() - val thenp = expr() - val elsep = if (inToken == ELSE) { inNextToken; expr() } - else Literal(()) - atPos(pos) { If(cond, thenp, elsep) } - case TRY => - atPos(inSkipToken) { - val body = - if (inToken == LBRACE) surround(LBRACE, RBRACE)(block(), Literal(())) - else if (inToken == LPAREN) surround(LPAREN, RPAREN)(expr(), Literal(())) - else expr() - val catches = - if (inToken == CATCH) { - inNextToken - val cases = surround(LBRACE,RBRACE)(caseClauses(), Nil) - cases - } else Nil - val finalizer = - if (inToken == FINALLY) { inNextToken; expr() } - else EmptyTree - Try(body, catches, finalizer) - } - case WHILE => - val pos = inSkipToken - val lname: Name = freshName(pos, "while$") - val cond = surround(LPAREN,RPAREN)(expr(),Literal(true)) - newLinesOpt() - val body = expr() - atPos(pos) { makeWhile(lname, cond, body) } - case DO => - val pos = inSkipToken - val lname: Name = freshName(pos, "doWhile$") - val body = expr() - if (isStatSep) inNextToken - accept(WHILE) - val cond = surround(LPAREN,RPAREN)(expr(), Literal(true)) - atPos(pos) { makeDoWhile(lname, body, cond) } - case FOR => - atPos(inSkipToken) { - val startToken = inToken - val (open,close) = if (startToken == LBRACE) (LBRACE,RBRACE) else (LPAREN,RPAREN) - val enums = surround(open,close)(enumerators(), Nil) - newLinesOpt() - if (inToken == YIELD) { - inNextToken; makeForYield(enums, expr()) - } else makeFor(enums, expr()) - } - case RETURN => - atPos(inSkipToken) { - Return(if (isExprIntro) expr() else Literal(())) - } - case THROW => - atPos(inSkipToken) { - Throw(expr()) - } - case DOT => - deprecationWarning(inCurrentPos, "`.f' has been deprecated; use `_.f' instead") - atPos(inSkipToken) { - if (isIdent) { - makeDotClosure(stripParens(simpleExpr())) - } else { - syntaxErrorOrIncomplete("identifier expected", true) - errorTermTree - } - } - case _ => - var t = postfixExpr() - if (inToken == EQUALS) { - t match { - case Ident(_) | Select(_, _) | Apply(_, _) => - t = atPos(inSkipToken) { makeAssign(t, expr()) } - case _ => - } - } else if (inToken == COLON) { - t = stripParens(t) - val pos = inSkipToken - if (inToken == USCORE) { - //todo: need to handle case where USCORE is a wildcard in a type - val pos1 = inSkipToken - if (isIdent && inName == nme.STAR) { - inNextToken - t = atPos(pos) { - Typed(t, atPos(pos1) { Ident(nme.WILDCARD_STAR.toTypeName) }) - } - } else { - syntaxErrorOrIncomplete("`*' expected", true) - } - } else if (in.token == AT) { - t = (t /: annotations(false)) (makeAnnotated) - } else { - t = atPos(pos) { - val tpt = - if (location != Local) infixType(false, InfixMode.FirstOp) - else typ() - if (isWildcard(t)) - (placeholderParams: @unchecked) match { - case (vd @ ValDef(mods, name, _, _)) :: rest => - placeholderParams = copy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest - } - // this does not correspond to syntax, but is necessary to - // accept closures. We might restrict closures to be between {...} only! - Typed(t, tpt) - } - } - } else if (inToken == MATCH) { - t = atPos(inSkipToken) { - val cases = surround(LBRACE,RBRACE)(caseClauses(), Nil) - Match(stripParens(t), cases) - } - } - // in order to allow anonymous functions as statements (as opposed to expressions) inside - // templates, we have to disambiguate them from self type declarations - bug #1565 - // The case still missed is unparenthesized single argument, like "x: Int => x + 1", which - // may be impossible to distinguish from a self-type and so remains an error. (See #1564) - def lhsIsTypedParamList() = t match { - case Parens(xs) if xs forall (_.isInstanceOf[Typed]) => true - case _ => false - } - if (inToken == ARROW && (location != InTemplate || lhsIsTypedParamList)) { - t = atPos(inSkipToken) { - Function(convertToParams(t), if (location != InBlock) expr() else block()) - } - } - stripParens(t) - } - if (!placeholderParams.isEmpty && !isWildcard(res)) { - res = atPos(res.pos){ Function(placeholderParams.reverse, res) } - placeholderParams = List() - } - placeholderParams = placeholderParams ::: savedPlaceholderParams - res - } - - /** PostfixExpr ::= InfixExpr [Id [nl]] - * InfixExpr ::= PrefixExpr - * | InfixExpr Id [nl] InfixExpr - */ - def postfixExpr(): Tree = { - val base = opstack - var top = prefixExpr() - while (isIdent) { - top = reduceStack( - true, base, top, precedence(inName), treeInfo.isLeftAssoc(inName)) - val op = inName - opstack = OpInfo(top, op, inCurrentPos) :: opstack - ident() - newLineOptWhenFollowing(isExprIntroToken) - if (isExprIntro) { - top = prefixExpr() - } else { - val topinfo = opstack.head - opstack = opstack.tail - return Select( - stripParens(reduceStack(true, base, topinfo.operand, 0, true)), - topinfo.operator.encode).setPos(topinfo.pos) - } - } - reduceStack(true, base, top, 0, true) - } - - /** PrefixExpr ::= [`-' | `+' | `~' | `!' | `&'] SimpleExpr - */ - def prefixExpr(): Tree = { - def unaryOp(): Name = "unary_" + ident() - if (isIdent && inName == MINUS) { - val name = unaryOp() - inToken match { - case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => literal(false, true) - case _ => atPos(inCurrentPos) { Select(stripParens(simpleExpr()), name) } - } - } else if (isIdent && (inName == PLUS || inName == TILDE || inName == BANG)) { - val pos = inCurrentPos - val name = unaryOp() - atPos(pos) { Select(stripParens(simpleExpr()), name) } - } else if (isIdent && inName == AMP) { - deprecationWarning(inCurrentPos, "`&f' has been deprecated; use `f _' instead") - val pos = inCurrentPos - val name = ident() - atPos(pos) { Typed(stripParens(simpleExpr()), Function(List(), EmptyTree)) } -/* XX-LIFTING - } else if (settings.Xexperimental.value && isIdent && inName == SLASH) { - val pos = inSkipToken - val name = freshName() - liftedGenerators += ValFrom(pos, Bind(name, Ident(nme.WILDCARD)), simpleExpr()) - Ident(name) setPos pos -*/ - } else { - simpleExpr() - } - } - def xmlLiteral(): Tree - - /* SimpleExpr ::= new (ClassTemplate | TemplateBody) - * | BlockExpr - * | SimpleExpr1 [`_'] - * SimpleExpr1 ::= literal - * | xLiteral - * | Path - * | `(' [Exprs [`,']] `)' - * | SimpleExpr `.' Id - * | SimpleExpr TypeArgs - * | SimpleExpr1 ArgumentExprs - */ - def simpleExpr(): Tree = { - var t: Tree = null - var canApply = true - inToken match { - case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | - SYMBOLLIT | TRUE | FALSE | NULL => - t = literal(false, false) - case XMLSTART => t = xmlLiteral() - case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER => - t = path(true, false) - case USCORE => - val pos = inSkipToken - val pname = freshName(pos, "x$") - val param = atPos(pos){ makeSyntheticParam(pname) } - placeholderParams = param :: placeholderParams - t = atPos(pos) { Ident(pname) } - case LPAREN => - val pos = inSkipToken - val ts = if (inToken == RPAREN) List() else exprs() - accept(RPAREN) - t = Parens(ts) setPos (pos) - case LBRACE => - t = blockExpr() - canApply = false - case NEW => - t = atPos(inSkipToken) { - val (parents, argss, self, stats) = template(false) - makeNew(parents, self, stats, argss) - } - canApply = false - case _ => - syntaxErrorOrIncomplete("illegal start of simple expression", true) - t = errorTermTree - } - simpleExprRest(t, canApply) - } - - def simpleExprRest(t: Tree, canApply: Boolean): Tree = { - if (canApply) newLineOptWhenFollowedBy(LBRACE) - inToken match { - case DOT => - simpleExprRest(atPos(inSkipToken) { selector(stripParens(t)) }, true) - case LBRACKET => - val t1 = stripParens(t) - t1 match { - case Ident(_) | Select(_, _) => - val pos = if (t1.pos == NoPosition) i2p(inCurrentPos) else t1.pos - simpleExprRest(atPos(pos) { TypeApply(t1, typeArgs(false, true)) }, true) - case _ => - t1 - } - case LPAREN | LBRACE if (canApply) => - // again, position should be on idetifier, not ( - var pos = if (t.pos == NoPosition) i2p(inCurrentPos) else t.pos - simpleExprRest(atPos(pos) { - // look for anonymous function application like (f _)(x) and - // translate to (f _).apply(x), bug #460 - val sel = t match { - case Parens(List(Typed(_, _: Function))) => - Select(stripParens(t), nme.apply) - case _ => - stripParens(t) - } - Apply(sel, argumentExprs()) - }, true) - case USCORE => - atPos(inSkipToken) { Typed(stripParens(t), Function(List(), EmptyTree)) } - case _ => - t - } - } - - /** ArgumentExprs ::= `(' [Exprs [`,']] `)' - * | [nl] BlockExpr - */ - def argumentExprs(): List[Tree] = { - if (inToken == LBRACE) { - List(blockExpr()) - } else { - val ts = surround(LPAREN,RPAREN)(if (inToken == RPAREN) List() else exprs(), List()) - ts - } - } - - /** BlockExpr ::= `{' (CaseClauses | Block) `}' - */ - def blockExpr(): Tree = { - assert(inToken == LBRACE) - val res = atPos(accept(LBRACE)) { // no need to surround - if (inToken == CASE) Match(EmptyTree, caseClauses()) - else block() - } - accept(RBRACE) - res - } - - /** Block ::= BlockStatSeq - */ - def block(): Tree = { - makeBlock(blockStatSeq(new ListBuffer[Tree])) - } - - /** CaseClauses ::= CaseClause {CaseClause} - */ - def caseClauses(): List[CaseDef] = { - val ts = new ListBuffer[CaseDef] - do { ts += caseClause() - } while (inToken == CASE) - ts.toList - } - - /** CaseClause ::= case Pattern [Guard] `=>' Block - */ - def caseClause(): CaseDef = - atPos(accept(CASE)) { - val pat = pattern() - val gd = guard() - makeCaseDef(pat, gd, caseBlock()) - } - // IDE HOOK (so we can memoize case blocks) - def caseBlock(): Tree = - atPos(accept(ARROW))(block()) - - /** Guard ::= if PostfixExpr - */ - def guard(): Tree = - if (inToken == IF) { inNextToken; stripParens(postfixExpr()) } - else EmptyTree - - /** Enumerators ::= Generator {semi Enumerator} - * Enumerator ::= Generator - * | Guard - * | val Pattern1 `=' Expr - */ - def enumerators(): List[Enumerator] = { - val newStyle = inToken != VAL // todo: deprecate old style - //if (!newStyle) - // deprecationWarning(inCurrentPos, "for (val x <- ... ) has been deprecated; use for (x <- ... ) instead") - val enums = new ListBuffer[Enumerator] - generator(enums, false) - while (isStatSep) { - inNextToken - if (newStyle) { - if (inToken == IF) enums += Filter(guard()) - else generator(enums, true) - } else { - if (inToken == VAL) generator(enums, true) - else enums += Filter(expr()) - } - } - enums.toList - } - - /** Generator ::= Pattern1 (`<-' | '=') Expr [Guard] - */ - def generator(enums: ListBuffer[Enumerator], eqOK: Boolean) { - if (inToken == VAL) inNextToken - val pos = inCurrentPos; - val pat = pattern1(false) - val tok = inToken - if (tok == EQUALS && eqOK) inNextToken - else accept(LARROW) - enums += makeGenerator(pos, pat, tok == EQUALS, expr) - if (inToken == IF) enums += Filter(guard()) - } - //def p2i(pos : ScanPosition) : Int; - -/* -------- PATTERNS ------------------------------------------- */ - - /** Patterns ::= Pattern { `,' Pattern } - * SeqPatterns ::= SeqPattern { `,' SeqPattern } - * - * (also eats trailing comma if it finds one) - */ - def patterns(seqOK: Boolean): List[Tree] = { - val ts = new ListBuffer[Tree] + pattern(seqOK) - while (inToken == COMMA) { - val pos = inCurrentPos - inNextToken - if (inToken == RPAREN) { - deprecationWarning(pos, "Trailing commas have been deprecated") - return ts.toList - } else { - ts += pattern(seqOK) - } - } - ts.toList - } - - /** Pattern ::= Pattern1 { `|' Pattern1 } - * SeqPattern ::= SeqPattern1 { `|' SeqPattern1 } - */ - def pattern(seqOK: Boolean): Tree = { - val pos = inCurrentPos - val t = pattern1(seqOK) - if (isIdent && inName == BAR) { - val ts = new ListBuffer[Tree] + t - while (isIdent && inName == BAR) { - inNextToken; ts += pattern1(seqOK) - } - atPos(pos) { makeAlternative(ts.toList) } - } else t - } - - def pattern(): Tree = pattern(false) - - /** Pattern1 ::= varid `:' TypePat - * | `_' `:' TypePat - * | Pattern2 - * SeqPattern1 ::= varid `:' TypePat - * | `_' `:' TypePat - * | [SeqPattern2] - */ - def pattern1(seqOK: Boolean): Tree = { - //if (false && /*disabled, no regexp matching*/ seqOK && !isExprIntro) { - //atPos(inCurrentPos) { Sequence(List()) } - //} else { - val p = pattern2(seqOK) - p match { - case Ident(name) if (treeInfo.isVarPattern(p) && inToken == COLON) => - atPos(inSkipToken) { Typed(p, compoundType(true)) } - case _ => - p - } - //} - } - - /* Pattern2 ::= varid [ @ Pattern3 ] - * | Pattern3 - * SeqPattern2 ::= varid [ @ SeqPattern3 ] - * | SeqPattern3 - */ - def pattern2(seqOK: Boolean): Tree = { - val p = pattern3(seqOK) - if (inToken == AT) { - p match { - case Ident(name) => - if (name == nme.WILDCARD) { - inNextToken; pattern3(seqOK) - } else if (treeInfo.isVarPattern(p)) { - inNextToken - atPos(p.pos) { Bind(name, pattern3(seqOK)) } - } else { - p - } - case _ => - p - } - } else p - } - - /* Pattern3 ::= SimplePattern - * | SimplePattern {Id [nl] SimplePattern} - * SeqPattern3 ::= SeqSimplePattern [ '*' | '?' | '+' ] - * | SeqSimplePattern {Id [nl] SeqSimplePattern} - */ - def pattern3(seqOK: Boolean): Tree = { - val base = opstack - var top = simplePattern(seqOK) - if (seqOK && isIdent && inName == STAR) - return atPos(inSkipToken)(Star(stripParens(top))) - - while (isIdent && inName != BAR) { - top = reduceStack( - false, base, top, precedence(inName), treeInfo.isLeftAssoc(inName)) - val op = inName - opstack = OpInfo(top, op, inCurrentPos) :: opstack - ident() - top = simplePattern(seqOK) - } - stripParens(reduceStack(false, base, top, 0, true)) - } - - def xmlLiteralPattern(): Tree - - /** SimplePattern ::= varid - * | `_' - * | literal - * | XmlPattern - * | StableId [TypeArgs] [`(' [SeqPatterns [`,']] `)'] - * | `(' [Patterns [`,']] `)' - * SimpleSeqPattern ::= varid - * | `_' - * | literal - * | XmlPattern - * | `<' xLiteralPattern - * | StableId [TypeArgs] [`(' [SeqPatterns [`,']] `)'] - * | `(' [SeqPatterns [`,']] `)' - * - * XXX: Hook for IDE - */ - def simplePattern(seqOK: Boolean): Tree = inToken match { - case IDENTIFIER | BACKQUOTED_IDENT | THIS => - var t = stableId() - inToken match { - case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => - t match { - case Ident(name) if name == nme.MINUS => - return literal(true, true) - case _ => - } - case _ => - } -/* not yet - if (inToken == LBRACKET) - atPos(inCurrentPos) { - val ts = typeArgs(true, false) - accept(LPAREN) - val ps = if (inToken == RPAREN) List() else patterns(true, false) - accept(RPAREN) - Apply(TypeApply(convertToTypeId(t), ts), ps) - } - else */ - if (inToken == LPAREN) { - atPos(t.pos) { Apply(t, argumentPatterns()) } - } else t - case USCORE => - atPos(inSkipToken) { Ident(nme.WILDCARD) } - case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | - STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => - literal(true, false) - case LPAREN => - val pos = inSkipToken - val ps = if (inToken == RPAREN) List() else patterns(false) - accept(RPAREN) - Parens(ps) setPos (pos) - case XMLSTART => - xmlLiteralPattern() - case _ => - syntaxErrorOrIncomplete("illegal start of simple pattern", true) - errorPatternTree - } - - def argumentPatterns(): List[Tree] = { - accept(LPAREN) - val ps = if (inToken == RPAREN) List() else patterns(true) - accept(RPAREN) - ps - } - -/* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */ - - private def normalize(mods: Modifiers): Modifiers = - if ((mods hasFlag Flags.PRIVATE) && mods.privateWithin != nme.EMPTY.toTypeName) - mods &~ Flags.PRIVATE - else if ((mods hasFlag Flags.ABSTRACT) && (mods hasFlag Flags.OVERRIDE)) - mods &~ (Flags.ABSTRACT | Flags.OVERRIDE) | Flags.ABSOVERRIDE - else - mods - - private def addMod(mods: Modifiers, mod: Long): Modifiers = { - if (mods hasFlag mod) syntaxError(inCurrentPos, "repeated modifier", false) - inNextToken - mods | mod - } - - /** AccessQualifier ::= "[" (Id | this) "]" - */ - def accessQualifierOpt(mods: Modifiers): Modifiers = { - var result = mods - if (inToken == LBRACKET) { - inNextToken - if (mods.privateWithin != nme.EMPTY.toTypeName) - syntaxError("duplicate private/protected qualifier", false) - result = if (inToken == THIS) { inNextToken; mods | Flags.LOCAL } - else Modifiers(mods.flags, ident().toTypeName) - accept(RBRACKET) - } - result - } - - /** AccessModifier ::= (private | protected) [AccessQualifier] - */ - def accessModifierOpt(): Modifiers = normalize { - inToken match { - case PRIVATE => inNextToken; accessQualifierOpt(Modifiers(Flags.PRIVATE)) - case PROTECTED => inNextToken; accessQualifierOpt(Modifiers(Flags.PROTECTED)) - case _ => NoMods - } - } - - /** Modifiers ::= {Modifier} - * Modifier ::= LocalModifier - * | AccessModifier - * | override - */ - def modifiers(): Modifiers = normalize { - def loop(mods: Modifiers): Modifiers = inToken match { - case ABSTRACT => - loop(addMod(mods, Flags.ABSTRACT)) - case FINAL => - loop(addMod(mods, Flags.FINAL)) - case SEALED => - loop(addMod(mods, Flags.SEALED)) - case PRIVATE => - loop(accessQualifierOpt(addMod(mods, Flags.PRIVATE))) - case PROTECTED => - loop(accessQualifierOpt(addMod(mods, Flags.PROTECTED))) - case OVERRIDE => - loop(addMod(mods, Flags.OVERRIDE)) - case IMPLICIT => - loop(addMod(mods, Flags.IMPLICIT)) - case LAZY => - loop(addMod(mods, Flags.LAZY)) - case NEWLINE => - inNextToken - loop(mods) - case _ => - mods - } - loop(NoMods) - } - - /** LocalModifiers ::= {LocalModifier} - * LocalModifier ::= abstract | final | sealed | implicit | lazy - */ - def localModifiers(): Modifiers = { - def loop(mods: Modifiers): Modifiers = inToken match { - case ABSTRACT => - loop(addMod(mods, Flags.ABSTRACT)) - case FINAL => - loop(addMod(mods, Flags.FINAL)) - case SEALED => - loop(addMod(mods, Flags.SEALED)) - case IMPLICIT => - loop(addMod(mods, Flags.IMPLICIT)) - case LAZY => - loop(addMod(mods, Flags.LAZY)) - case _ => - mods - } - loop(NoMods) - } - - /** Annotations ::= {Annotation [nl]} - * Annotation ::= `@' AnnotationExpr - */ - def annotations(skipNewLines: Boolean): List[Annotation] = { - var annots = new ListBuffer[Annotation] - while (inToken == AT) { - inNextToken - annots += annotationExpr() - if (skipNewLines) newLineOpt() - } - annots.toList - } - - /** AnnotationExpr ::= StableId [TypeArgs] [`(' [Exprs] `)'] [[nl] `{' {NameValuePair} `}'] - * NameValuePair ::= val id `=' PrefixExpr - */ - def annotationExpr(): Annotation = { - def nameValuePair(): Tree = { - var pos = inCurrentPos - accept(VAL) - val aname = ident() - accept(EQUALS) - val rhs = stripParens(prefixExpr()) - atPos(pos) { ValDef(NoMods, aname, TypeTree(), rhs) } - } - val pos = inCurrentPos - var t: Tree = convertToTypeId(stableId()) - if (inToken == LBRACKET) - t = atPos(inCurrentPos)(AppliedTypeTree(t, typeArgs(false, false))) - val args = if (inToken == LPAREN) argumentExprs() else List() - newLineOptWhenFollowedBy(LBRACE) - val nameValuePairs: List[Tree] = if (inToken == LBRACE) { - inNextToken - val nvps = new ListBuffer[Tree] + nameValuePair() - while (inToken == COMMA) { - inNextToken - nvps += nameValuePair() - } - accept(RBRACE) - nvps.toList - } else List() - val constr = atPos(pos) { New(t, List(args)) } - Annotation(constr, nameValuePairs) setPos pos - } - -/* -------- PARAMETERS ------------------------------------------- */ - - /** ParamClauses ::= {ParamClause} [[nl] `(' implicit Params `)'] - * ParamClause ::= [nl] `(' [Params] ')' - * Params ::= Param {`,' Param} - * Param ::= {Annotation} Id [`:' ParamType] - * ClassParamClauses ::= {ClassParamClause} [[nl] `(' implicit ClassParams `)'] - * ClassParamClause ::= [nl] `(' [ClassParams] ')' - * ClassParams ::= ClassParam {`,' ClassParam} - * ClassParam ::= {Annotation} [{Modifier} (`val' | `var')] Id [`:' ParamType] - */ - def paramClauses(owner: Name, implicitViews: List[Tree], ofCaseClass: Boolean): List[List[ValDef]] = { - var implicitmod = 0 - var caseParam = ofCaseClass - def param(): ValDef = { - var pos = inCurrentPos - - { - val annots = annotations(false) - var mods = Modifiers(Flags.PARAM) - if (owner.isTypeName) { - mods = modifiers() | Flags.PARAMACCESSOR - if (mods.hasFlag(Flags.LAZY)) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", false) - if (inToken == VAL) { - inNextToken - } else if (inToken == VAR) { - mods = mods | Flags.MUTABLE - inNextToken - } else { - if (mods.flags != Flags.PARAMACCESSOR) accept(VAL) - if (!(caseParam)) mods = mods | Flags.PRIVATE | Flags.LOCAL - } - if (caseParam) mods = mods | Flags.CASEACCESSOR - } - val namePos = inCurrentPos - val name = ident() - if (name != nme.ERROR) pos = namePos - var bynamemod = 0 - val tpt = - if (settings.Xexperimental.value && !owner.isTypeName && inToken != COLON) { - TypeTree() - } else { // XX-METHOD-INFER - accept(COLON) - if (inToken == ARROW) { - if (owner.isTypeName && !mods.hasFlag(Flags.LOCAL)) - syntaxError( - inCurrentPos, - (if (mods.hasFlag(Flags.MUTABLE)) "`var'" else "`val'") + - " parameters may not be call-by-name", false) - else bynamemod = Flags.BYNAMEPARAM - } - paramType() - } - atPos(pos){ - ValDef((mods | implicitmod | bynamemod) withAnnotations annots, name, tpt, EmptyTree) - } - } - } - def paramClause(): List[ValDef] = { - val params = new ListBuffer[ValDef] - if (inToken != RPAREN) { - if (inToken == IMPLICIT) { - if (!implicitViews.isEmpty) - syntaxError("cannot have both view bounds `<%' and implicit parameters", false) - inNextToken - implicitmod = Flags.IMPLICIT - } - params += param() - while (inToken == COMMA) { - inNextToken; params += param() - } - } - params.toList - } - val vds = new ListBuffer[List[ValDef]] - val pos = inCurrentPos - newLineOptWhenFollowedBy(LPAREN) - if (ofCaseClass && inToken != LPAREN) - deprecationWarning(inCurrentPos, "case classes without a parameter list have been deprecated;\n"+ - "use either case objects or case classes with `()' as parameter list.") - while (implicitmod == 0 && inToken == LPAREN) { - inNextToken - vds += paramClause() - accept(RPAREN) - caseParam = false - newLineOptWhenFollowedBy(LPAREN) - } - val result = vds.toList - if (owner == nme.CONSTRUCTOR && - (result.isEmpty || - (!result.head.isEmpty && result.head.head.mods.hasFlag(Flags.IMPLICIT)))) - if (inToken == LBRACKET) - syntaxError(pos, "no type parameters allowed here", false) - else if(inToken == EOF) - incompleteInputError("auxiliary constructor needs non-implicit parameter list") - else - syntaxError(pos, "auxiliary constructor needs non-implicit parameter list", false) - addImplicitViews(owner, result, implicitViews) - } - - /** ParamType ::= Type | `=>' Type | Type `*' - */ - def paramType(): Tree = - if (inToken == ARROW) - atPos(inSkipToken) { - AppliedTypeTree( - rootScalaDot(nme.BYNAME_PARAM_CLASS_NAME.toTypeName), List(typ())) - } - else { - val t = typ() - if (isIdent && inName == STAR) { - inNextToken - atPos(t.pos) { - AppliedTypeTree( - rootScalaDot(nme.REPEATED_PARAM_CLASS_NAME.toTypeName), List(t)) - } - } else t - } - - /** TypeParamClauseOpt ::= [TypeParamClause] - * TypeParamClause ::= `[' VariantTypeParam {`,' VariantTypeParam} `]'] - * VariantTypeParam ::= [`+' | `-'] TypeParam - * FunTypeParamClauseOpt ::= [FunTypeParamClause] - * FunTypeParamClause ::= `[' TypeParam {`,' TypeParam} `]'] - * TypeParam ::= Id TypeParamClauseOpt TypeBounds [<% Type] - */ - def typeParamClauseOpt(owner: Name, implicitViewBuf: ListBuffer[Tree]): List[TypeDef] = { - def typeParam(): TypeDef = { - var mods = Modifiers(Flags.PARAM) - if (owner.isTypeName && isIdent) { - if (inName == PLUS) { - inNextToken - mods = mods | Flags.COVARIANT - } else if (inName == MINUS) { - inNextToken - mods = mods | Flags.CONTRAVARIANT - } - } - val pos = inCurrentPos - val pname = - (if (inToken == USCORE) { // @M! also allow underscore - inNextToken - nme.WILDCARD - } else ident()).toTypeName - - val tparams = typeParamClauseOpt(pname, null) // @M TODO null --> no higher-order view bounds for now - val param = atPos(pos) { TypeDef(mods, pname, tparams, typeBounds()) } - if (inToken == VIEWBOUND && (implicitViewBuf ne null)) - implicitViewBuf += atPos(inSkipToken) { - makeFunctionTypeTree(List(Ident(pname)), typ()) - } - param - } - val params = new ListBuffer[TypeDef] - newLineOptWhenFollowedBy(LBRACKET) - if (inToken == LBRACKET) { - inNextToken - params += typeParam() - while (inToken == COMMA) { - inNextToken - params += typeParam() - } - accept(RBRACKET) - } - params.toList - } - - /** TypeBounds ::= [`>:' Type] [`<:' Type] - */ - def typeBounds(): TypeBoundsTree = - TypeBoundsTree( - bound(SUPERTYPE, nme.Nothing), - bound(SUBTYPE, nme.Any)) - - def bound(tok: Int, default: Name): Tree = - if (inToken == tok) { inNextToken; typ() } - else rootScalaDot(default.toTypeName) - -/* -------- DEFS ------------------------------------------- */ - - - /** Import ::= import ImportExpr {`,' ImportExpr} - */ - def importClause(): List[Tree] = { - accept(IMPORT) - val ts = new ListBuffer[Tree] + importExpr() - while (inToken == COMMA) { - inNextToken; ts += importExpr() - } - ts.toList - } - - /** ImportExpr ::= StableId `.' (Id | `_' | ImportSelectors) - * XXX: Hook for IDE - */ - def importExpr(): Tree = - atPos(inCurrentPos) { - var t: Tree = null - //var pos : ScanPosition = null.asInstanceOf[ScanPosition] - var pos : Int = -1 - if (inToken == THIS) { - t = atPos(inCurrentPos) { This(nme.EMPTY.toTypeName) } - t = atPos(accept(DOT)) { selector(t) } - pos = accept(DOT) - } else { - val i = atPos(inCurrentPos) { Ident(ident()) } - pos = accept(DOT) - if (inToken == THIS) { - inNextToken - t = atPos(i.pos) { This(i.name.toTypeName) } - t = atPos(accept(DOT)) { selector(t) } - pos = accept(DOT) - } else { - t = i - } - } - def loop: Tree = - if (inToken == USCORE) { - inNextToken - Import(t, List((nme.WILDCARD, null))) - } else if (inToken == LBRACE) { - Import(t, importSelectors()) - } else { - val identPos = inCurrentPos - val name = ident() // @S: use position of identifier, not dot! - pos = if (name == nme.ERROR) pos else identPos - if (inToken == DOT) { - t = atPos(pos) { Select(t, name) } - pos = accept(DOT) - loop - } else { - Import(t, List((name, name))) - } - } - loop - } - - /** ImportSelectors ::= `{' {ImportSelector `,'} (ImportSelector | `_') `}' - */ - def importSelectors(): List[(Name, Name)] = { - val names = new ListBuffer[(Name, Name)] - accept(LBRACE) - var isLast = importSelector(names) - while (!isLast && inToken == COMMA) { - inNextToken - isLast = importSelector(names) - } - accept(RBRACE) - names.toList - } - - /** ImportSelector ::= Id [`=>' Id | `=>' `_'] - */ - def importSelector(names: ListBuffer[(Name, Name)]): Boolean = - if (inToken == USCORE) { - inNextToken; names += ((nme.WILDCARD, null)); true - } else { - val name = ident() - names += (( - name, - if (inToken == ARROW) { - inNextToken - if (inToken == USCORE) { inNextToken; nme.WILDCARD } else ident() - } else { - name - })) - false - } - - /** Def ::= val PatDef - * | var VarDef - * | def FunDef - * | type [nl] TypeDef - * | TmplDef - * Dcl ::= val ValDcl - * | var ValDcl - * | def FunDcl - * | type [nl] TypeDcl - */ - def defOrDcl(mods: Modifiers): List[Tree] = { - if ((mods hasFlag Flags.LAZY) && in.token != VAL) - syntaxError("lazy not allowed here. Only vals can be lazy", false) - inToken match { - case VAL => - patDefOrDcl(mods) - case VAR => - patDefOrDcl(mods | Flags.MUTABLE) - case DEF => - List(funDefOrDcl(mods)) - case TYPE => - inNextToken - newLinesOpt() - List(typeDefOrDcl(mods)) - case _ => - List(tmplDef(mods)) - } - } - /** IDE hook: for non-local defs or dcls with modifiers and annotations */ - def nonLocalDefOrDcl : List[Tree] = { - val annots = annotations(true) - defOrDcl(modifiers() withAnnotations annots) - } - /** not hooked by the IDE, will not undergo stubbing. Used for early initialization blocks. */ - def preNonLocalDefOrDcl : List[Tree] = { - val annots = annotations(true) - defOrDcl(modifiers() withAnnotations annots) - } - - - /** PatDef ::= Pattern2 {`,' Pattern2} [`:' Type] `=' Expr - * ValDcl ::= Id {`,' Id} `:' Type - * VarDef ::= PatDef | Id {`,' Id} `:' Type `=' `_' - */ - def patDefOrDcl(mods: Modifiers): List[Tree] = { - var newmods = mods - val lhsBuf = new ListBuffer[Tree] - do { - inNextToken - val p = pattern2(false) - lhsBuf += stripParens(p) - } while (inToken == COMMA) - val lhs = lhsBuf.toList - val tp = typedOpt() - val rhs = - if (tp.isEmpty || inToken == EQUALS) { - accept(EQUALS) - if (!tp.isEmpty && newmods.hasFlag(Flags.MUTABLE) && - (lhs.toList forall (_.isInstanceOf[Ident])) && inToken == USCORE) { - inNextToken - newmods = newmods | Flags.DEFAULTINIT - EmptyTree - } else { - expr() - } - } else { - newmods = newmods | Flags.DEFERRED - EmptyTree - } - var originalUsed = false - def mkDefs(p: Tree): List[Tree] = { - //Console.println("DEBUG: p = "+p.toString()); // DEBUG - val trees = - makePatDef(newmods, - if (tp.isEmpty) - p - else - Typed(p, tp), - if (inIDE && !originalUsed) { - // because duplicates have weaker status than originals - // need an original. - originalUsed = true - rhs - } else rhs.duplicate) map atPos(p.pos) - if (newmods.hasFlag(Flags.DEFERRED)) { - trees match { - case List(ValDef(_, _, _, EmptyTree)) => - if (mods.hasFlag(Flags.LAZY)) - syntaxError(p.pos, "lazy values may not be abstract", false) - case _ => syntaxError(p.pos, "pattern definition may not be abstract", false) - } - } - trees - } - for (p <- lhs.toList; d <- mkDefs(p)) yield d - } - - /** VarDef ::= PatDef - * | Id {`,' Id} `:' Type `=' `_' - * VarDcl ::= Id {`,' Id} `:' Type - def varDefOrDcl(mods: Modifiers): List[Tree] = { - var newmods = mods | Flags.MUTABLE - val lhs = new ListBuffer[(Int, Name)] - do { - inNextToken - lhs += (inCurrentPos, ident()) - } while (inToken == COMMA) - val tp = typedOpt() - val rhs = if (tp.isEmpty || inToken == EQUALS) { - accept(EQUALS) - if (!tp.isEmpty && inToken == USCORE) { - inNextToken - EmptyTree - } else { - expr() - } - } else { - newmods = newmods | Flags.DEFERRED - EmptyTree - } - var originalUsed = false - for ((pos, name) <- lhs.toList) yield atPos(pos) { - if (inIDE && !originalUsed) { - originalUsed = true - ValDef(newmods, name, tp, rhs) - } else ValDef(newmods, name, tp.duplicate, rhs.duplicate) - } - } - */ - - /** FunDef ::= FunSig `:' Type `=' Expr - * | FunSig [nl] `{' Block `}' - * | this ParamClause ParamClauses (`=' ConstrExpr | [nl] ConstrBlock) - * FunDcl ::= FunSig [`:' Type] - * FunSig ::= id [FunTypeParamClause] ParamClauses - */ - def funDefOrDcl(mods: Modifiers): Tree = { - var pos = inSkipToken // position of `def' - if (inToken == THIS) { - atPos(inCurrentPos) { - inNextToken - val vparamss = paramClauses(nme.CONSTRUCTOR, implicitClassViews map (_.duplicate), false) - newLineOptWhenFollowedBy(LBRACE) - val rhs = if (inToken == LBRACE) constrBlock(vparamss) - else { accept(EQUALS); constrExpr(vparamss) } - DefDef(mods, nme.CONSTRUCTOR, List(), vparamss, TypeTree(), rhs) - } - } else { - var newmods = mods - val namePos = inCurrentPos - val name = ident() - if (name != nme.ERROR) pos = namePos - atPos(pos) { - // implicitViewBuf is for view bounded type parameters of the form - // [T <% B]; it contains the equivalent implicit parameter, i.e. (implicit p: T => B) - val implicitViewBuf = new ListBuffer[Tree] - val tparams = typeParamClauseOpt(name, implicitViewBuf) - val vparamss = paramClauses(name, implicitViewBuf.toList, false) - newLineOptWhenFollowedBy(LBRACE) - var restype = typedOpt() - val rhs = - if (isStatSep || inToken == RBRACE) { - if (restype.isEmpty) restype = scalaUnitConstr - newmods = newmods | Flags.DEFERRED - EmptyTree - } else if (restype.isEmpty && inToken == LBRACE) { - restype = scalaUnitConstr - blockExpr() - } else equalsExpr() - DefDef(newmods, name, tparams, vparamss, restype, rhs) - } - } - } - - - /** ConstrExpr ::= SelfInvocation - * | ConstrBlock - */ - def constrExpr(vparamss: List[List[ValDef]]): Tree = - if (inToken == LBRACE) constrBlock(vparamss) - else Block(List(selfInvocation(vparamss)), Literal(())) - - /** SelfInvocation ::= this ArgumentExprs {ArgumentExprs} - */ - def selfInvocation(vparamss: List[List[ValDef]]): Tree = - atPos(accept(THIS)) { - newLineOptWhenFollowedBy(LBRACE) - var t = Apply(Ident(nme.CONSTRUCTOR), argumentExprs()) - while (inToken == LPAREN || inToken == LBRACE) { - t = Apply(t, argumentExprs()) - newLineOptWhenFollowedBy(LBRACE) - } - if (implicitClassViews.isEmpty) t - else Apply(t, vparamss.last.map(vp => Ident(vp.name))) - } - - /** ConstrBlock ::= `{' SelfInvocation {semi BlockStat} `}' - */ - def constrBlock(vparamss: List[List[ValDef]]): Tree = - atPos(inSkipToken) { - val statlist = new ListBuffer[Tree] - statlist += selfInvocation(vparamss) - val stats = if (isStatSep) { inNextToken; blockStatSeq(statlist) } - else statlist.toList - accept(RBRACE) - Block(stats, Literal(())) - } - - /** TypeDef ::= Id [TypeParamClause] `=' Type - * TypeDcl ::= Id [TypeParamClause] TypeBounds - */ - def typeDefOrDcl(mods: Modifiers): Tree = - atPos(inCurrentPos) { - val name = ident().toTypeName - - // @M! a type alias as well as an abstract type may declare type parameters - val tparams = inToken match { - case LBRACKET => - typeParamClauseOpt(name, null) - case _ => - Nil - } - - inToken match { - case EQUALS => - inNextToken - TypeDef(mods, name, tparams, typ()) - case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE => - TypeDef(mods | Flags.DEFERRED, name, tparams, typeBounds()) - case _ => - syntaxErrorOrIncomplete("`=', `>:', or `<:' expected", true) - EmptyTree - } - } - - /** Hook for IDE, for top-level classes/objects */ - def topLevelTmplDef: Tree = { - val annots = annotations(true) - val mods = modifiers() withAnnotations annots - tmplDef(mods) - } - - /** TmplDef ::= [case] class ClassDef - * | [case] object ObjectDef - * | [override] trait TraitDef - */ - def tmplDef(mods: Modifiers): Tree = { - if (mods.hasFlag(Flags.LAZY)) syntaxError("classes cannot be lazy", false) - inToken match { - case TRAIT => - classDef(mods | Flags.TRAIT | Flags.ABSTRACT) - case CLASS => - classDef(mods) - case CASECLASS => - classDef(mods | Flags.CASE) - case OBJECT => - objectDef(mods) - case CASEOBJECT => - objectDef(mods | Flags.CASE) - case _ => - syntaxErrorOrIncomplete("expected start of definition", true) - EmptyTree - } - } - - /** ClassDef ::= Id [TypeParamClause] {Annotation} - [AccessModifier] ClassParamClauses RequiresTypeOpt ClassTemplateOpt - * TraitDef ::= Id [TypeParamClause] RequiresTypeOpt TraitTemplateOpt - */ - def classDef(mods: Modifiers): ClassDef = { - var pos = inSkipToken - var namePos = inCurrentPos - val name = ident().toTypeName - if (name != nme.ERROR) pos = namePos - atPos(pos) { - val savedViews = implicitClassViews - val implicitViewBuf = new ListBuffer[Tree] - val tparams = typeParamClauseOpt(name, implicitViewBuf) - implicitClassViews = implicitViewBuf.toList - if (!implicitClassViews.isEmpty && mods.hasFlag(Flags.TRAIT)) { - syntaxError("traits cannot have type parameters with <% bounds", false) - implicitClassViews = List() - } - val constrAnnots = annotations(false) - val (constrMods, vparamss) = - if (mods.hasFlag(Flags.TRAIT)) (Modifiers(Flags.TRAIT), List()) - else (accessModifierOpt(), paramClauses(name, implicitClassViews, mods.hasFlag(Flags.CASE))) - val thistpe = requiresTypeOpt() - var mods1 = - if (mods hasFlag Flags.TRAIT) - if (inToken == SUBTYPE) mods | Flags.DEFERRED - else mods - else if (inToken == SUBTYPE) { - syntaxError("classes are not allowed to be virtual", false) - mods - } - else - mods - var template = templateOpt(mods1, name, constrMods withAnnotations constrAnnots, vparamss) - if (!thistpe.isEmpty) { - if (template.self.isEmpty) { - template = copy.Template( - template, template.parents, makeSelfDef(nme.WILDCARD, thistpe), template.body) - } else syntaxError("`requires' cannot be combined with explicit self type", false) - } - if (isInterface(mods1, template.body)) mods1 |= Flags.INTERFACE - val result = ClassDef(mods1, name, tparams, template) - implicitClassViews = savedViews - result - } - } - - /** ObjectDef ::= Id ClassTemplateOpt - */ - def objectDef(mods: Modifiers): ModuleDef = { - var pos = inSkipToken - var namePos = inCurrentPos - val name = ident().toTermName - if (name != nme.ERROR) pos = namePos - atPos(pos) { - val mods1 = if (inToken == SUBTYPE) mods | Flags.DEFERRED else mods - val template = templateOpt(mods1, name, NoMods, List()) - ModuleDef(mods1, name, template) - } - } - - - /** ClassParents ::= AnnotType {`(' [Exprs [`,']] `)'} {with AnnotType} - * TraitParents ::= AnnotType {with AnnotType} - */ - def templateParents(isTrait: Boolean): (List[Tree], List[List[Tree]]) = { - val parents = new ListBuffer[Tree] + annotType(false) - val argss = new ListBuffer[List[Tree]] - if (inToken == LPAREN && !isTrait) - do { argss += argumentExprs() } while (inToken == LPAREN) - else argss += List() - while (inToken == WITH) { - inNextToken - parents += annotType(false) - } - (parents.toList, argss.toList) - } - - /** ClassTemplate ::= [EarlyDefs with] ClassParents [TemplateBody] - * TraitTemplate ::= [EarlyDefs with] TraitParents [TemplateBody] - * EarlyDefs ::= `{' [EarlyDef {semi EarlyDef}] `}' - * EarlyDef ::= Annotations Modifiers PatDef - */ - def template(isTrait: Boolean): (List[Tree], List[List[Tree]], ValDef, List[Tree]) = { - newLineOptWhenFollowedBy(LBRACE) - if (inToken == LBRACE) { - // @S: pre template body cannot stub like post body can! - val (self, body) = templateBody(true) - if (inToken == WITH && self.isEmpty) { - val earlyDefs: List[Tree] = body flatMap { - case vdef @ ValDef(mods, name, tpt, rhs) if !(mods hasFlag Flags.DEFERRED) => - List(copy.ValDef(vdef, mods | Flags.PRESUPER, name, tpt, rhs)) - case tdef @ TypeDef(mods, name, tparams, rhs) => - List(copy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs)) - case stat if !stat.isEmpty => - syntaxError(stat.pos, "only type definitions and concrete field definitions allowed in early object initialization section", false) - List() - case _ => List() - } - inNextToken - val (parents, argss) = templateParents(isTrait) - val (self1, body1) = templateBodyOpt(isTrait) - (parents, argss, self1, earlyDefs ::: body1) - } else { - (List(), List(List()), self, body) - } - } else { - val (parents, argss) = templateParents(isTrait) - val (self, body) = templateBodyOpt(isTrait) - (parents, argss, self, body) - } - } - - def isInterface(mods: Modifiers, body: List[Tree]): Boolean = - (mods hasFlag Flags.TRAIT) && (body forall treeInfo.isInterfaceMember) - - /** ClassTemplateOpt ::= 'extends' ClassTemplate | [['extends'] TemplateBody] - * TraitTemplateOpt ::= TraitExtends TraitTemplate | [['extends'] TemplateBody] | '<:' TemplateBody - * TraitExtends ::= 'extends' | `<:' - */ - def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, - vparamss: List[List[ValDef]]): Template = { - val pos = inCurrentPos; - val (parents0, argss, self, body) = - if (inToken == EXTENDS || settings.Xexperimental.value && (mods hasFlag Flags.TRAIT) && inToken == SUBTYPE) { - inNextToken - template(mods hasFlag Flags.TRAIT) - } else if ((inToken == SUBTYPE) && (mods hasFlag Flags.TRAIT)) { - inNextToken - template(true) - } else { - newLineOptWhenFollowedBy(LBRACE) - val (self, body) = templateBodyOpt(false) - (List(), List(List()), self, body) - } - var parents = parents0 - if (name != nme.ScalaObject.toTypeName && !isInterface(mods, body)) - parents = parents ::: List(scalaScalaObjectConstr) - if (parents.isEmpty) - parents = List(scalaAnyRefConstr) - if (mods.hasFlag(Flags.CASE)) parents = parents ::: List(productConstr) - val tree = Template(parents, self, constrMods, vparamss, argss, body) - // @S: if nothing parsed, don't use next position! - // @S: if primary constructor does not always have the same position, then the IDE gets confused. - // @S: since build compiler is used to generate IDE files, don't set position here! - tree - // if (pos == inCurrentPos || inIDE) tree else atPos(pos) {tree} - } - -/* -------- TEMPLATES ------------------------------------------- */ - - /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' - * @param isPre specifies whether in early initializer (true) or not (false) - */ - def templateBody(isPre: Boolean) = { - accept(LBRACE) - val result @ (self, stats) = templateStatSeq(isPre) - accept(RBRACE) - if (stats.isEmpty) (self, List(EmptyTree)) else result - } - def templateBodyOpt(traitParentSeen: Boolean): (ValDef, List[Tree]) = { - newLineOptWhenFollowedBy(LBRACE) - if (inToken == LBRACE) { - templateBody(false) - } else { - if (inToken == LPAREN) - syntaxError((if (traitParentSeen) "parents of traits" else "traits or objects")+ - " may not have parameters", true) - (emptyValDef, List()) - } - } - - /** Refinement ::= [nl] `{' RefineStat {semi RefineStat} `}' - */ - def refinement(): List[Tree] = { - accept(LBRACE) - val body = refineStatSeq() - accept(RBRACE) - body - } - -/* -------- STATSEQS ------------------------------------------- */ - - /** Packaging ::= package QualId [nl] `{' TopStatSeq `}' - */ - def packaging(pkgPos: Int): Tree = { - val pkg = qualId() - val pos = if (pkg.pos != NoPosition) pkg.pos else i2p(pkgPos) - atPos(pos) { - newLineOptWhenFollowedBy(LBRACE) - accept(LBRACE) - val stats = topStatSeq() - accept(RBRACE) - makePackaging(pkg, stats) - } - } - - /** TopStatSeq ::= TopStat {semi TopStat} - * TopStat ::= Annotations Modifiers TmplDef - * | Packaging - * | package object objectDef - * | Import - * | - */ - def topStatSeq(): List[Tree] = { - val stats = new ListBuffer[Tree] - while (inToken != RBRACE && inToken != EOF) { - if (inToken == PACKAGE) { - val pkgPos = accept(PACKAGE) - stats += { - if (inToken == OBJECT) - atPos(pkgPos) { makePackageObject(objectDef(NoMods)) } - else packaging(pkgPos) - } - } else if (inToken == IMPORT) { - stats ++= importClause() - // XXX: IDE hook this all. - } else if (inToken == CLASS || - inToken == CASECLASS || - inToken == TRAIT || - inToken == OBJECT || - inToken == CASEOBJECT || - inToken == LBRACKET || //todo: remove - inToken == AT || - isModifier) { - stats ++ joinComment(List(topLevelTmplDef)) - } else if (!isStatSep) { - syntaxErrorOrIncomplete("expected class or object definition", true) - } - if (inToken != RBRACE && inToken != EOF) acceptStatSep() - } - stats.toList - } - - /** TemplateStatSeq ::= [id [`:' Type] `=>'] TemplateStat {semi TemplateStat} - * TemplateStat ::= Import - * | Annotations Modifiers Def - * | Annotations Modifiers Dcl - * | Expr1 - * | super ArgumentExprs {ArgumentExprs} - * | - * @param isPre specifies whether in early initializer (true) or not (false) - */ - def templateStatSeq(isPre : Boolean) = checkNoEscapingPlaceholders { - var self: ValDef = emptyValDef - val stats = new ListBuffer[Tree] - if (isExprIntro) { - val first = expr(InTemplate) // @S: first statement is potentially converted so cannot be stubbed. - if (inToken == ARROW) { - first match { - case Typed(tree @ This(name), tpt) if (name == nme.EMPTY.toTypeName) => - self = makeSelfDef(nme.WILDCARD, tpt).setPos(tree.pos) - case _ => - convertToParam(first) match { - case tree @ ValDef(_, name, tpt, EmptyTree) if (name != nme.ERROR) => - self = makeSelfDef(name, tpt).setPos(tree.pos) - case _ => - } - } - inNextToken - } else { - stats += first - if (in.token != RBRACE && in.token != EOF/* !isStatSep(in.token)*/) acceptStatSep() - } - } - while (inToken != RBRACE && inToken != EOF) { - if (inToken == IMPORT) { - stats ++= importClause() - } else if (isExprIntro) { - stats += statement(InTemplate) - } else if (isDefIntro || isModifier || inToken == LBRACKET /*todo: remove */ || inToken == AT) { - if (isPre) // @S: avoid caching by calling a different method that does the same thing (except in the IDE) - stats ++= joinComment(preNonLocalDefOrDcl) - else stats ++= joinComment(nonLocalDefOrDcl) - } else if (!isStatSep) { - syntaxErrorOrIncomplete("illegal start of definition", true) - } - if (inToken != RBRACE && inToken != EOF) acceptStatSep() - } - (self, stats.toList) - } - - - - /** RefineStatSeq ::= RefineStat {semi RefineStat} - * RefineStat ::= Dcl - * | type TypeDef - * | - */ - def refineStatSeq(): List[Tree] = checkNoEscapingPlaceholders { - val stats = new ListBuffer[Tree] - while (inToken != RBRACE && inToken != EOF) { - if (isDclIntro) { // don't IDE hook - stats ++= joinComment(defOrDcl(NoMods)) - } else if (!isStatSep) { - syntaxErrorOrIncomplete("illegal start of declaration", true) - } - if (inToken != RBRACE) acceptStatSep() - } - stats.toList - } - - /** overridable IDE hook for local definitions of blockStatSeq - * Here's an idea how to fill in start and end positions. - def localDef : List[Tree] = { - atEndPos { - atStartPos(inCurrentPos) { - val annots = annotations(true) - val mods = localModifiers() withAnnotations annots - if (!(mods hasFlag ~(Flags.IMPLICIT | Flags.LAZY))) defOrDcl(mods) - else List(tmplDef(mods)) - } - } (inCurrentPos) - } - */ - - def localDef : List[Tree] = { - val annots = annotations(true) - val mods = localModifiers() withAnnotations annots - if (!(mods hasFlag ~(Flags.IMPLICIT | Flags.LAZY))) defOrDcl(mods) - else List(tmplDef(mods)) - } - - /** BlockStatSeq ::= { BlockStat semi } [ResultExpr] - * BlockStat ::= Import - * | Annotations [implicit] [lazy] Def - * | Annotations LocalModifiers TmplDef - * | Expr1 - * | - */ - def blockStatSeq(stats: ListBuffer[Tree]): List[Tree] = checkNoEscapingPlaceholders { - var keepGoing = true - var hasError = false - while ((inToken != RBRACE) && (inToken != EOF) && (inToken != CASE) && keepGoing) { - var hasError0 = hasError - hasError = false - if (inToken == IMPORT) { - stats ++= importClause() - acceptStatSep() - } else if (isExprIntro) { - stats += statement(InBlock) - if (inToken != RBRACE && inToken != CASE) acceptStatSep() - } else if (isDefIntro || isLocalModifier || in.token == AT) { - stats ++= localDef - if (inToken == RBRACE || inToken == CASE) { - syntaxError("block must end in result expression, not in definition", false) - stats += Literal(()).setPos(inCurrentPos) - } else acceptStatSep() - } else if (isStatSep) { - inNextToken - } else { - syntaxErrorOrIncomplete("illegal start of statement", true) - if (hasError0) keepGoing = false else hasError = true - } - } - stats.toList - } - - /** CompilationUnit ::= [package QualId semi] TopStatSeq - */ - def compilationUnit(): Tree = checkNoEscapingPlaceholders { - var pos = inCurrentPos; - { - val ts = new ListBuffer[Tree] - // @S: the IDE can insert phantom semi-colons before package during editing - // @S: just eat them (doesn't really change the grammar) - while (inToken == SEMI) inNextToken - if (inToken == PACKAGE) { - pos = inSkipToken - if (in.token == OBJECT) { - ts += makePackageObject(objectDef(NoMods)) - if (inToken != EOF) { - acceptStatSep() - ts ++= topStatSeq() - } - } else { - val pkg = qualId() - newLineOptWhenFollowedBy(LBRACE) - if (inToken == EOF) { - ts += makePackaging(pkg, List()) - } else if (isStatSep) { - inNextToken - ts += makePackaging(pkg, topStatSeq()) - } else { - accept(LBRACE) - ts += makePackaging(pkg, topStatSeq()) - accept(RBRACE) - ts ++= topStatSeq() - } - } - } else { - ts ++= topStatSeq() - } - val stats = ts.toList - val usePos = - if (stats.isEmpty || stats.head.pos == NoPosition) i2p(pos) - else stats.head.pos - atPos(usePos) { stats match { - case List(stat @ PackageDef(_, _)) => stat - case _ => makePackaging(Ident(nme.EMPTY_PACKAGE_NAME), stats) - }} - } - } - } -} diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index a2e114afca..85695b4e85 100644..100755 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -2,258 +2,107 @@ * Copyright 2005-2009 LAMP/EPFL * @author Martin Odersky */ -// $Id$ +// $Id: Scanners.scala 17274 2009-03-10 11:39:04Z michelou $ package scala.tools.nsc.ast.parser import scala.tools.nsc.util._ import SourceFile.{LF, FF, CR, SU} import Tokens._ +import scala.annotation.switch trait Scanners { val global : Global import global._ - abstract class AbstractTokenData { - def token: Int - type ScanPosition - val NoPos: ScanPosition - def pos: ScanPosition - def currentPos: ScanPosition - def name: Name - } - /** A class for representing a token's data. */ - trait TokenData extends AbstractTokenData { - type ScanPosition = Int + /** Offset into source character array */ + type Offset = Int + + /** An undefined offset */ + val NoOffset: Offset = -1 + + trait TokenData { - val NoPos: Int = -1 /** the next token */ var token: Int = EMPTY - /** the token's position */ - var pos: Int = 0 - override def currentPos: Int = pos - 1 - /** the first character position after the previous token */ - var lastPos: Int = 0 + /** the offset of the first character of the current token */ + var offset: Offset = 0 - /** the name of an identifier or token */ + /** the offset of the character following the token preceding this one */ + var lastOffset: Offset = 0 + + /** the name of an identifier */ var name: Name = null + /** the string value of a literal */ + var strVal: String = null + /** the base of a number */ var base: Int = 0 def copyFrom(td: TokenData) = { this.token = td.token - this.pos = td.pos - this.lastPos = td.lastPos + this.offset = td.offset + this.lastOffset = td.lastOffset this.name = td.name + this.strVal = td.strVal this.base = td.base } } - /** ... - */ - abstract class AbstractScanner extends AbstractTokenData { - implicit def p2g(pos: Position): ScanPosition - implicit def g2p(pos: ScanPosition): Position - def warning(pos: ScanPosition, msg: String): Unit - def error (pos: ScanPosition, msg: String): Unit - def incompleteInputError(pos: ScanPosition, msg: String): Unit - def deprecationWarning(pos: ScanPosition, msg: String): Unit - /** the last error position - */ - var errpos: ScanPosition - var lastPos: ScanPosition - def skipToken: ScanPosition - def nextToken: Unit - def next: AbstractTokenData - def intVal(negated: Boolean): Long - def floatVal(negated: Boolean): Double - def intVal: Long = intVal(false) - def floatVal: Double = floatVal(false) - //def token2string(token: Int): String = configuration.token2string(token) - /** return recent scala doc, if any */ - def flushDoc: String - } - - object ScannerConfiguration { -// Keywords ----------------------------------------------------------------- - /** Keyword array; maps from name indices to tokens */ - private var key: Array[Byte] = _ - private var maxKey = 0 - private var tokenName = new Array[Name](128) + abstract class Scanner extends CharArrayReader1 with TokenData { - { - var tokenCount = 0 + def flush = { charOffset = offset; nextChar(); this } - // Enter keywords - - def enterKeyword(n: Name, tokenId: Int) { - while (tokenId >= tokenName.length) { - val newTokName = new Array[Name](tokenName.length * 2) - Array.copy(tokenName, 0, newTokName, 0, newTokName.length) - tokenName = newTokName - } - tokenName(tokenId) = n - if (n.start > maxKey) maxKey = n.start - if (tokenId >= tokenCount) tokenCount = tokenId + 1 - } - - enterKeyword(nme.ABSTRACTkw, ABSTRACT) - enterKeyword(nme.CASEkw, CASE) - enterKeyword(nme.CATCHkw, CATCH) - enterKeyword(nme.CLASSkw, CLASS) - enterKeyword(nme.DEFkw, DEF) - enterKeyword(nme.DOkw, DO) - enterKeyword(nme.ELSEkw, ELSE) - enterKeyword(nme.EXTENDSkw, EXTENDS) - enterKeyword(nme.FALSEkw, FALSE) - enterKeyword(nme.FINALkw, FINAL) - enterKeyword(nme.FINALLYkw, FINALLY) - enterKeyword(nme.FORkw, FOR) - enterKeyword(nme.FORSOMEkw, FORSOME) - enterKeyword(nme.IFkw, IF) - enterKeyword(nme.IMPLICITkw, IMPLICIT) - enterKeyword(nme.IMPORTkw, IMPORT) - enterKeyword(nme.LAZYkw, LAZY) - enterKeyword(nme.MATCHkw, MATCH) - enterKeyword(nme.NEWkw, NEW) - enterKeyword(nme.NULLkw, NULL) - enterKeyword(nme.OBJECTkw, OBJECT) - enterKeyword(nme.OVERRIDEkw, OVERRIDE) - enterKeyword(nme.PACKAGEkw, PACKAGE) - enterKeyword(nme.PRIVATEkw, PRIVATE) - enterKeyword(nme.PROTECTEDkw, PROTECTED) - enterKeyword(nme.REQUIRESkw, REQUIRES) - enterKeyword(nme.RETURNkw, RETURN) - enterKeyword(nme.SEALEDkw, SEALED) - enterKeyword(nme.SUPERkw, SUPER) - enterKeyword(nme.THISkw, THIS) - enterKeyword(nme.THROWkw, THROW) - enterKeyword(nme.TRAITkw, TRAIT) - enterKeyword(nme.TRUEkw, TRUE) - enterKeyword(nme.TRYkw, TRY) - enterKeyword(nme.TYPEkw, TYPE) - enterKeyword(nme.VALkw, VAL) - enterKeyword(nme.VARkw, VAR) - enterKeyword(nme.WHILEkw, WHILE) - enterKeyword(nme.WITHkw, WITH) - enterKeyword(nme.YIELDkw, YIELD) - enterKeyword(nme.DOTkw, DOT) - enterKeyword(nme.USCOREkw, USCORE) - enterKeyword(nme.COLONkw, COLON) - enterKeyword(nme.EQUALSkw, EQUALS) - enterKeyword(nme.ARROWkw, ARROW) - enterKeyword(nme.LARROWkw, LARROW) - enterKeyword(nme.SUBTYPEkw, SUBTYPE) - enterKeyword(nme.VIEWBOUNDkw, VIEWBOUND) - enterKeyword(nme.SUPERTYPEkw, SUPERTYPE) - enterKeyword(nme.HASHkw, HASH) - enterKeyword(nme.ATkw, AT) - - // Build keyword array - key = Array.make(maxKey + 1, IDENTIFIER) - for (j <- 0 until tokenCount if tokenName(j) ne null) - key(tokenName(j).start) = j.toByte + def resume(lastCode: Int) = { + token = lastCode + assert(next.token == EMPTY) + nextToken() } -//Token representation ----------------------------------------------------- + // things to fill in, in addition to buf, decodeUni + def warning(off: Offset, msg: String): Unit + def error (off: Offset, msg: String): Unit + def incompleteInputError(off: Offset, msg: String): Unit + def deprecationWarning(off: Offset, msg: String): Unit - /** Convert name to token */ - def name2token(name: Name): Int = - if (name.start <= maxKey) key(name.start) else IDENTIFIER - - /** Returns the string representation of given token. */ - def token2string(token: Int): String = token match { - case IDENTIFIER | BACKQUOTED_IDENT => - "identifier"/* + \""+name+"\""*/ - case CHARLIT => - "character literal" - case INTLIT => - "integer literal" - case LONGLIT => - "long literal" - case FLOATLIT => - "float literal" - case DOUBLELIT => - "double literal" - case STRINGLIT => - "string literal" - case SYMBOLLIT => - "symbol literal" - case LPAREN => - "'('" - case RPAREN => - "')'" - case LBRACE => - "'{'" - case RBRACE => - "'}'" - case LBRACKET => - "'['" - case RBRACKET => - "']'" - case EOF => - "eof" - case ERROR => - "something" - case SEMI => - "';'" - case NEWLINE => - "';'" - case NEWLINES => - "';'" - case COMMA => - "','" - case CASECLASS => - "case class" - case CASEOBJECT => - "case object" - case XMLSTART => - "$XMLSTART$<" - case _ => - try { - "'" + tokenName(token) + "'" - } catch { - case _: ArrayIndexOutOfBoundsException => - "'<" + token + ">'" - case _: NullPointerException => - "'<(" + token + ")>'" - } - } - } - - - /** A scanner for the programming language Scala. - * - * @author Matthias Zenger, Martin Odersky, Burak Emir - * @version 1.1 - */ - abstract class Scanner extends AbstractScanner with TokenData { - override def intVal = super.intVal - override def floatVal = super.floatVal - override var errpos: Int = NoPos + /** the last error offset + */ + var errOffset: Offset = NoOffset - val in: CharArrayReader + /** A character buffer for literals + */ + val cbuf = new StringBuilder - /** character buffer for literals + /** append Unicode character to "cbuf" buffer */ - val cbuf = new StringBuilder() + protected def putChar(c: Char) { +// assert(cbuf.size < 10000, cbuf) + cbuf.append(c) + } - /** append Unicode character to "lit" buffer - */ - protected def putChar(c: Char) { cbuf.append(c) } + /** Clear buffer and set name and token */ + private def finishNamed() { + name = newTermName(cbuf.toString) + token = name2token(name) + cbuf.clear() + } - /** Clear buffer and set name */ - private def setName { - name = newTermName(cbuf.toString()) - cbuf.setLength(0) + /** Clear buffer and set string */ + private def setStrVal() { + strVal = cbuf.toString + cbuf.clear() } + /** Should doc comments be built? */ + def buildDocs: Boolean = onlyPresentation + /** buffer for the documentation comment */ var docBuffer: StringBuilder = null + /** Return current docBuffer and set docBuffer to null */ def flushDoc = { val ret = if (docBuffer != null) docBuffer.toString else null docBuffer = null @@ -268,71 +117,81 @@ trait Scanners { private class TokenData0 extends TokenData - /** we need one token lookahead + /** we need one token lookahead and one token history */ val next : TokenData = new TokenData0 val prev : TokenData = new TokenData0 - /** a stack which indicates whether line-ends can be statement separators + /** a stack of tokens which indicates whether line-ends can be statement separators */ var sepRegions: List[Int] = List() - /** A new line was inserted where in version 1.0 it would not be. - * Only significant if settings.migrate.value is set - */ - var newNewLine = false - - /** Parser is currently skipping ahead because of an error. - * Only significant if settings.migrate.value is set - */ - var skipping = false - // Get next token ------------------------------------------------------------ - /** read next token and return last position + /** read next token and return last offset */ - def skipToken: Int = { - val p = pos; nextToken - // XXX: account for off by one error //??? - (p - 1) + def skipToken(): Offset = { + val off = offset + nextToken() + off } - def nextToken { - if (token == LPAREN) { - sepRegions = RPAREN :: sepRegions - } else if (token == LBRACKET) { - sepRegions = RBRACKET :: sepRegions - } else if (token == LBRACE) { - sepRegions = RBRACE :: sepRegions - } else if (token == CASE) { - sepRegions = ARROW :: sepRegions - } else if (token == RBRACE) { - while (!sepRegions.isEmpty && sepRegions.head != RBRACE) - sepRegions = sepRegions.tail - if (!sepRegions.isEmpty) - sepRegions = sepRegions.tail - } else if (token == RBRACKET || token == RPAREN || token == ARROW) { - if (!sepRegions.isEmpty && sepRegions.head == token) - sepRegions = sepRegions.tail + /** Produce next token, filling TokenData fields of Scanner. + */ + def nextToken() { + val lastToken = token + // Adapt sepRegions according to last token + (lastToken: @switch) match { + case LPAREN => + sepRegions = RPAREN :: sepRegions + case LBRACKET => + sepRegions = RBRACKET :: sepRegions + case LBRACE => + sepRegions = RBRACE :: sepRegions + case CASE => + sepRegions = ARROW :: sepRegions + case RBRACE => + sepRegions = sepRegions dropWhile (_ != RBRACE) + if (!sepRegions.isEmpty) sepRegions = sepRegions.tail + case RBRACKET | RPAREN | ARROW => + if (!sepRegions.isEmpty && sepRegions.head == lastToken) + sepRegions = sepRegions.tail + case _ => } - val lastToken = token + // Read a token or copy it from `next` tokenData if (next.token == EMPTY) { + lastOffset = charOffset - 1 fetchToken() } else { this copyFrom next next.token = EMPTY } + + /** Insert NEWLINE or NEWLINES if + * - we are after a newline + * - we are within a { ... } or on toplevel (wrt sepRegions) + * - the current token can start a statement and the one before can end it + * insert NEWLINES if we are past a blank line, NEWLINE otherwise + */ + if (afterLineEnd() && inLastOfStat(lastToken) && inFirstOfStat(token) && + (sepRegions.isEmpty || sepRegions.head == RBRACE)) { + next copyFrom this + offset = if (lineStartOffset <= offset) lineStartOffset else lastLineStartOffset + token = if (pastBlankLine()) NEWLINES else NEWLINE + } + + // Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE if (token == CASE) { prev copyFrom this + val nextLastOffset = charOffset - 1 fetchToken() if (token == CLASS) { token = CASECLASS - lastPos = prev.lastPos } else if (token == OBJECT) { token = CASEOBJECT - lastPos = prev.lastPos } else { + lastOffset = nextLastOffset next copyFrom this this copyFrom prev } @@ -343,274 +202,224 @@ trait Scanners { next copyFrom this this copyFrom prev } - } else if (token == IDENTIFIER && name == nme.MIXINkw) { //todo: remove eventually - prev.copyFrom(this) - fetchToken() - if (token == CLASS) - warning(prev.pos, "`mixin' is no longer a reserved word; you should use `trait' instead of `mixin class'"); - next.copyFrom(this) - this.copyFrom(prev) } - if (afterLineEnd() && inLastOfStat(lastToken) && inFirstOfStat(token) && - (sepRegions.isEmpty || sepRegions.head == RBRACE)) { - next copyFrom this - pos = in.lineStartPos - token = if (in.lastBlankLinePos > lastPos) NEWLINES else NEWLINE - } +// print("["+this+"]") } - private def afterLineEnd() = ( - lastPos < in.lineStartPos && - (in.lineStartPos <= pos || - lastPos < in.lastLineStartPos && in.lastLineStartPos <= pos) - ) + /** Is current token first one after a newline? */ + private def afterLineEnd(): Boolean = + lastOffset < lineStartOffset && + (lineStartOffset <= offset || + lastOffset < lastLineStartOffset && lastLineStartOffset <= offset) - /** read next token + /** Is there a blank line between the current token and the last one? + * @pre afterLineEnd(). */ - private def fetchToken() { - if (token == EOF) return - lastPos = in.cpos - 1 // Position.encode(in.cline, in.ccol) - //var index = bp - while (true) { - in.ch match { - case ' ' | '\t' | CR | LF | FF => - in.next - case _ => - pos = in.cpos // Position.encode(in.cline, in.ccol) - in.ch match { - case '\u21D2' => - in.next; token = ARROW - return - case '\u2190' => - in.next; token = LARROW - return - case 'A' | 'B' | 'C' | 'D' | 'E' | - 'F' | 'G' | 'H' | 'I' | 'J' | - 'K' | 'L' | 'M' | 'N' | 'O' | - 'P' | 'Q' | 'R' | 'S' | 'T' | - 'U' | 'V' | 'W' | 'X' | 'Y' | - 'Z' | '$' | '_' | - 'a' | 'b' | 'c' | 'd' | 'e' | - 'f' | 'g' | 'h' | 'i' | 'j' | - 'k' | 'l' | 'm' | 'n' | 'o' | - 'p' | 'q' | 'r' | 's' | 't' | - 'u' | 'v' | 'w' | 'x' | 'y' | // scala-mode: need to understand multi-line case patterns - 'z' => - putChar(in.ch) - in.next - getIdentRest // scala-mode: wrong indent for multi-line case blocks - return - - case '<' => // is XMLSTART? - val last = in.last - in.next - last match { - case ' '|'\t'|'\n'|'{'|'('|'>' if xml.Parsing.isNameStart(in.ch) || in.ch == '!' || in.ch == '?' => - token = XMLSTART - case _ => - // Console.println("found '<', but last is '"+in.last+"'"); // DEBUG - putChar('<') - getOperatorRest - } - return - - case '~' | '!' | '@' | '#' | '%' | - '^' | '*' | '+' | '-' | /*'<' | */ - '>' | '?' | ':' | '=' | '&' | - '|' | '\\' => - putChar(in.ch) - in.next - getOperatorRest; // XXX - return - case '/' => - in.next - if (!skipComment()) { - putChar('/') - getOperatorRest - return - } - case '0' => - putChar(in.ch) - in.next - if (in.ch == 'x' || in.ch == 'X') { - in.next - base = 16 - } else { - base = 8 - } - getNumber - return - case '1' | '2' | '3' | '4' | - '5' | '6' | '7' | '8' | '9' => - base = 10 - getNumber - return - case '`' => - in.next - getStringLit('`', BACKQUOTED_IDENT) - return - case '\"' => - in.next - if (in.ch == '\"') { - in.next - if (in.ch == '\"') { - in.next - val saved = in.lineStartPos - getMultiLineStringLit - if (in.lineStartPos != saved) // ignore linestarts within a mulit-line string - in.lastLineStartPos = saved - } else { - token = STRINGLIT - name = nme.EMPTY - } - } else { - getStringLit('\"', STRINGLIT) - } - return - case '\'' => - in.next - in.ch match { - case 'A' | 'B' | 'C' | 'D' | 'E' | - 'F' | 'G' | 'H' | 'I' | 'J' | - 'K' | 'L' | 'M' | 'N' | 'O' | - 'P' | 'Q' | 'R' | 'S' | 'T' | - 'U' | 'V' | 'W' | 'X' | 'Y' | - 'Z' | '$' | '_' | - 'a' | 'b' | 'c' | 'd' | 'e' | - 'f' | 'g' | 'h' | 'i' | 'j' | - 'k' | 'l' | 'm' | 'n' | 'o' | - 'p' | 'q' | 'r' | 's' | 't' | - 'u' | 'v' | 'w' | 'x' | 'y' | - 'z' | - '0' | '1' | '2' | '3' | '4' | - '5' | '6' | '7' | '8' | '9' => - putChar(in.ch) - in.next - if (in.ch != '\'') { - getIdentRest - token = SYMBOLLIT - return - } - case _ => - if (Character.isUnicodeIdentifierStart(in.ch)) { - putChar(in.ch) - in.next - if (in.ch != '\'') { - getIdentRest - token = SYMBOLLIT - return - } - } else if (isSpecial(in.ch)) { - putChar(in.ch) - in.next - if (in.ch != '\'') { - getOperatorRest - token = SYMBOLLIT - return - } - } else { - getlitch() - } - } - if (in.ch == '\'') { - in.next - token = CHARLIT - setName - } else { - syntaxError("unclosed character literal") - } - return - case '.' => - in.next - if ('0' <= in.ch && in.ch <= '9') { - putChar('.'); getFraction - } else { - token = DOT - } - return - case ';' => - in.next; token = SEMI - return - case ',' => - in.next; token = COMMA - return - case '(' => //scala-mode: need to understand character quotes - in.next; token = LPAREN - return - case '{' => - in.next; token = LBRACE - return - case ')' => - in.next; token = RPAREN - return - case '}' => - in.next; - token = RBRACE - return - case '[' => - in.next; token = LBRACKET - return - case ']' => - in.next; token = RBRACKET - return - case SU => - if (!in.hasNext) token = EOF - else { - syntaxError("illegal character") - in.next - } - return - case _ => - if (Character.isUnicodeIdentifierStart(in.ch)) { - putChar(in.ch) - in.next - getIdentRest - } else if (isSpecial(in.ch)) { - putChar(in.ch) - getOperatorRest - } else { - syntaxError("illegal character") - in.next - } - return + private def pastBlankLine(): Boolean = { + var idx = lastOffset + var ch = buf(idx) + val end = offset + while (idx < end) { + if (ch == LF || ch == FF) { + do { + idx += 1; ch = buf(idx) + if (ch == LF || ch == FF) { +// println("blank line found at "+lastOffset+":"+(lastOffset to idx).map(buf(_)).toList) + return true } + } while (idx < end && ch <= ' ') } + idx += 1; ch = buf(idx) + } + false + } + + /** read next token, filling TokenData fields of Scanner. + */ + private final def fetchToken() { + offset = charOffset - 1 + (ch: @switch) match { + case ' ' | '\t' | CR | LF | FF => + nextChar() + fetchToken() + case 'A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | '_' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | // scala-mode: need to understand multi-line case patterns + 'z' => + putChar(ch) + nextChar() + getIdentRest() // scala-mode: wrong indent for multi-line case blocks + case '<' => // is XMLSTART? + val last = if (charOffset >= 2) buf(charOffset - 2) else ' ' + nextChar() + last match { + case ' '|'\t'|'\n'|'{'|'('|'>' if xml.Parsing.isNameStart(ch) || ch == '!' || ch == '?' => + token = XMLSTART + case _ => + // Console.println("found '<', but last is '"+in.last+"'"); // DEBUG + putChar('<') + getOperatorRest() + } + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | /*'<' | */ + '>' | '?' | ':' | '=' | '&' | + '|' | '\\' => + putChar(ch) + nextChar() + getOperatorRest() + case '/' => + nextChar() + if (skipComment()) { + fetchToken() + } else { + putChar('/') + getOperatorRest() + } + case '0' => + putChar(ch) + nextChar() + if (ch == 'x' || ch == 'X') { + nextChar() + base = 16 + } else { + base = 8 + } + getNumber() + case '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => + base = 10 + getNumber() + case '`' => + nextChar() + if (getStringLit('`')) { + finishNamed(); + if (name.length == 0) syntaxError("empty quoted identifier") + token = BACKQUOTED_IDENT + } + else syntaxError("unclosed quoted identifier") + case '\"' => + nextChar() + if (ch == '\"') { + nextChar() + if (ch == '\"') { + nextChar() + val saved = lineStartOffset + getMultiLineStringLit() + if (lineStartOffset != saved) // ignore linestarts within a multi-line string + lastLineStartOffset = saved + } else { + token = STRINGLIT + strVal = "" + } + } else if (getStringLit('\"')) { + setStrVal() + token = STRINGLIT + } else { + syntaxError("unclosed string literal") + } + case '\'' => + nextChar() + if (isIdentifierStart(ch) || '0' <= ch && ch <= '9') + charLitOr(getIdentRest) + else if (isSpecial(ch)) + charLitOr(getOperatorRest) + else { + getLitChar() + if (ch == '\'') { + nextChar() + token = CHARLIT + setStrVal() + } else { + syntaxError("unclosed character literal") + } + } + case '.' => + nextChar() + if ('0' <= ch && ch <= '9') { + putChar('.'); getFraction() + } else { + token = DOT + } + case ';' => + nextChar(); token = SEMI + case ',' => + nextChar(); token = COMMA + case '(' => + nextChar(); token = LPAREN + case '{' => + nextChar(); token = LBRACE + case ')' => + nextChar(); token = RPAREN + case '}' => + nextChar(); token = RBRACE + case '[' => + nextChar(); token = LBRACKET + case ']' => + nextChar(); token = RBRACKET + case SU => + if (charOffset >= buf.length) token = EOF + else { + syntaxError("illegal character") + nextChar() + } + case _ => + if (ch == '\u21D2') { + nextChar(); token = ARROW + } else if (ch == '\u2190') { + nextChar(); token = LARROW + } else if (Character.isUnicodeIdentifierStart(ch)) { + putChar(ch) + nextChar() + getIdentRest() + } else if (isSpecial(ch)) { + putChar(ch) + getOperatorRest() + } else { + syntaxError("illegal character") + nextChar() + } } } private def skipComment(): Boolean = { - if (in.ch == '/') { + if (ch == '/') { do { - in.next - } while ((in.ch != CR) && (in.ch != LF) && (in.ch != SU)) + nextChar() + } while ((ch != CR) && (ch != LF) && (ch != SU)) true - } else if (in.ch == '*') { + } else if (ch == '*') { docBuffer = null var openComments = 1 - in.next - val scalaDoc = ("/**", "*/") - if (in.ch == '*' && onlyPresentation) - docBuffer = new StringBuilder(scalaDoc._1) + nextChar() + if (ch == '*' && buildDocs) + docBuffer = new StringBuilder("/**") while (openComments > 0) { do { do { - if (in.ch == '/') { - in.next; putDocChar(in.ch) - if (in.ch == '*') { - in.next; putDocChar(in.ch) - openComments = openComments + 1 + if (ch == '/') { + nextChar(); putDocChar(ch) + if (ch == '*') { + nextChar(); putDocChar(ch) + openComments += 1 } } - if (in.ch != '*' && in.ch != SU) { - in.next; putDocChar(in.ch) + if (ch != '*' && ch != SU) { + nextChar(); putDocChar(ch) } - } while (in.ch != '*' && in.ch != SU) - while (in.ch == '*') { - in.next; putDocChar(in.ch) + } while (ch != '*' && ch != SU) + while (ch == '*') { + nextChar(); putDocChar(ch) } - } while (in.ch != '/' && in.ch != SU) - if (in.ch == '/') in.next + } while (ch != '/' && ch != SU) + if (ch == '/') nextChar() else incompleteInputError("unclosed comment") openComments -= 1 } @@ -620,16 +429,17 @@ trait Scanners { } } + /** Can token start a statement? */ def inFirstOfStat(token: Int) = token match { - case EOF | CASE | CATCH | ELSE | EXTENDS | FINALLY | FORSOME | MATCH | - REQUIRES | WITH | YIELD | COMMA | SEMI | NEWLINE | NEWLINES | DOT | - USCORE | COLON | EQUALS | ARROW | LARROW | SUBTYPE | VIEWBOUND | - SUPERTYPE | HASH | RPAREN | RBRACKET | RBRACE => // todo: add LBRACKET + case EOF | CATCH | ELSE | EXTENDS | FINALLY | FORSOME | MATCH | WITH | YIELD | + COMMA | SEMI | NEWLINE | NEWLINES | DOT | COLON | EQUALS | ARROW | LARROW | + SUBTYPE | VIEWBOUND | SUPERTYPE | HASH | RPAREN | RBRACKET | RBRACE | LBRACKET => false case _ => true } + /** Can token end a statement? */ def inLastOfStat(token: Int) = token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | IDENTIFIER | BACKQUOTED_IDENT | THIS | NULL | TRUE | FALSE | RETURN | USCORE | @@ -641,152 +451,102 @@ trait Scanners { // Identifiers --------------------------------------------------------------- - def isIdentStart(c: Char): Boolean = ( - ('A' <= c && c <= 'Z') || - ('a' <= c && c <= 'a') || - (c == '_') || (c == '$') || - Character.isUnicodeIdentifierStart(c) - ) - - def isIdentPart(c: Char) = ( - isIdentStart(c) || - ('0' <= c && c <= '9') || - Character.isUnicodeIdentifierPart(c) - ) - - def isSpecial(c: Char) = { - val chtp = Character.getType(c) - chtp == Character.MATH_SYMBOL || chtp == Character.OTHER_SYMBOL - } - - private def getIdentRest { - while (true) { - in.ch match { - case 'A' | 'B' | 'C' | 'D' | 'E' | - 'F' | 'G' | 'H' | 'I' | 'J' | - 'K' | 'L' | 'M' | 'N' | 'O' | - 'P' | 'Q' | 'R' | 'S' | 'T' | - 'U' | 'V' | 'W' | 'X' | 'Y' | - 'Z' | '$' | - 'a' | 'b' | 'c' | 'd' | 'e' | - 'f' | 'g' | 'h' | 'i' | 'j' | - 'k' | 'l' | 'm' | 'n' | 'o' | - 'p' | 'q' | 'r' | 's' | 't' | - 'u' | 'v' | 'w' | 'x' | 'y' | - 'z' | - '0' | '1' | '2' | '3' | '4' | - '5' | '6' | '7' | '8' | '9' => - putChar(in.ch) - in.next - - case '_' => - putChar(in.ch) - in.next - getIdentOrOperatorRest - return - case SU => - setName - token = ScannerConfiguration.name2token(name) - return - case _ => - if (Character.isUnicodeIdentifierPart(in.ch)) { - putChar(in.ch) - in.next - } else { - setName - token = ScannerConfiguration.name2token(name) - return - } + private def getIdentRest(): Unit = (ch: @switch) match { + case 'A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | + 'z' | + '0' | '1' | '2' | '3' | '4' | + '5' | '6' | '7' | '8' | '9' => + putChar(ch) + nextChar() + getIdentRest() + case '_' => + putChar(ch) + nextChar() + getIdentOrOperatorRest() + case SU => // strangely enough, Character.isUnicodeIdentifierPart(SU) returns true! + finishNamed() + case _ => + if (Character.isUnicodeIdentifierPart(ch)) { + putChar(ch) + nextChar() + getIdentRest() + } else { + finishNamed() } - } } - private def getOperatorRest { - while (true) { - in.ch match { - case '~' | '!' | '@' | '#' | '%' | - '^' | '*' | '+' | '-' | '<' | - '>' | '?' | ':' | '=' | '&' | - '|' | '\\' => - putChar(in.ch) - in.next - case '/' => - in.next - if (skipComment) { - setName - token = ScannerConfiguration.name2token(name) - return - } else putChar('/') - case _ => - if (isSpecial(in.ch)) { - putChar(in.ch) - in.next - } else { - setName - token = ScannerConfiguration.name2token(name) - return - } - } - } + private def getOperatorRest(): Unit = (ch: @switch) match { + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | '=' | '&' | + '|' | '\\' => + putChar(ch); nextChar(); getOperatorRest() + case '/' => + nextChar() + if (skipComment()) finishNamed() + else { putChar('/'); getOperatorRest() } + case _ => + if (isSpecial(ch)) { putChar(ch); nextChar(); getOperatorRest() } + else finishNamed() } - private def getIdentOrOperatorRest { - if (isIdentPart(in.ch)) - getIdentRest - else in.ch match { + private def getIdentOrOperatorRest() { + if (isIdentifierPart(ch)) + getIdentRest() + else ch match { case '~' | '!' | '@' | '#' | '%' | '^' | '*' | '+' | '-' | '<' | '>' | '?' | ':' | '=' | '&' | '|' | '\\' | '/' => - getOperatorRest + getOperatorRest() case _ => - if (isSpecial(in.ch)) getOperatorRest - else { - setName - token = ScannerConfiguration.name2token(name) - } + if (isSpecial(ch)) getOperatorRest() + else finishNamed() } } - private def getStringLit(delimiter: Char, litType: Int) { - //assert((litType==STRINGLIT) || (litType==IDENTIFIER)) - while (in.ch != delimiter && (in.isUnicode || in.ch != CR && in.ch != LF && in.ch != SU)) { - getlitch() - } - if (in.ch == delimiter) { - token = litType - setName - in.next - } else { - val typeDesc = if(litType == STRINGLIT) "string literal" else "quoted identifier" - syntaxError("unclosed " + typeDesc) + private def getStringLit(delimiter: Char): Boolean = { + while (ch != delimiter && (isUnicodeEscape || ch != CR && ch != LF && ch != SU)) { + getLitChar() } + if (ch == delimiter) { nextChar(); true } + else false } - private def getMultiLineStringLit { - if (in.ch == '\"') { - in.next - if (in.ch == '\"') { - in.next - if (in.ch == '\"') { - in.next + private def getMultiLineStringLit() { + if (ch == '\"') { + nextChar() + if (ch == '\"') { + nextChar() + if (ch == '\"') { + nextChar() token = STRINGLIT - setName + setStrVal() } else { putChar('\"') putChar('\"') - getMultiLineStringLit + getMultiLineStringLit() } } else { putChar('\"') - getMultiLineStringLit + getMultiLineStringLit() } - } else if (in.ch == SU) { + } else if (ch == SU) { incompleteInputError("unclosed multi-line string literal") } else { - putChar(in.ch) - in.next - getMultiLineStringLit + putChar(ch) + nextChar() + getMultiLineStringLit() } } @@ -794,24 +554,24 @@ trait Scanners { /** read next character in character or string literal: */ - protected def getlitch() = - if (in.ch == '\\') { - in.next - if ('0' <= in.ch && in.ch <= '7') { - val leadch: Char = in.ch - var oct: Int = in.digit2int(in.ch, 8) - in.next - if ('0' <= in.ch && in.ch <= '7') { - oct = oct * 8 + in.digit2int(in.ch, 8) - in.next - if (leadch <= '3' && '0' <= in.ch && in.ch <= '7') { - oct = oct * 8 + in.digit2int(in.ch, 8) - in.next + protected def getLitChar() = + if (ch == '\\') { + nextChar() + if ('0' <= ch && ch <= '7') { + val leadch: Char = ch + var oct: Int = digit2int(ch, 8) + nextChar() + if ('0' <= ch && ch <= '7') { + oct = oct * 8 + digit2int(ch, 8) + nextChar() + if (leadch <= '3' && '0' <= ch && ch <= '7') { + oct = oct * 8 + digit2int(ch, 8) + nextChar() } } - putChar(oct.asInstanceOf[Char]) + putChar(oct.toChar) } else { - in.ch match { + ch match { case 'b' => putChar('\b') case 't' => putChar('\t') case 'n' => putChar('\n') @@ -821,71 +581,77 @@ trait Scanners { case '\'' => putChar('\'') case '\\' => putChar('\\') case _ => - syntaxError(in.cpos - 1, "invalid escape character") - putChar(in.ch) + syntaxError(charOffset - 1, "invalid escape character") + putChar(ch) } - in.next + nextChar() } } else { - putChar(in.ch) - in.next + putChar(ch) + nextChar() } /** read fractional part and exponent of floating point number * if one is present. */ - protected def getFraction { + protected def getFraction() { token = DOUBLELIT - while ('0' <= in.ch && in.ch <= '9') { - putChar(in.ch) - in.next + while ('0' <= ch && ch <= '9') { + putChar(ch) + nextChar() } - if (in.ch == 'e' || in.ch == 'E') { - val lookahead = in.copy - lookahead.next + if (ch == 'e' || ch == 'E') { + val lookahead = lookaheadReader + lookahead.nextChar() if (lookahead.ch == '+' || lookahead.ch == '-') { - lookahead.next + lookahead.nextChar() } if ('0' <= lookahead.ch && lookahead.ch <= '9') { - putChar(in.ch) - in.next - if (in.ch == '+' || in.ch == '-') { - putChar(in.ch) - in.next + putChar(ch) + nextChar() + if (ch == '+' || ch == '-') { + putChar(ch) + nextChar() } - while ('0' <= in.ch && in.ch <= '9') { - putChar(in.ch) - in.next + while ('0' <= ch && ch <= '9') { + putChar(ch) + nextChar() } } token = DOUBLELIT } - if (in.ch == 'd' || in.ch == 'D') { - putChar(in.ch) - in.next + if (ch == 'd' || ch == 'D') { + putChar(ch) + nextChar() token = DOUBLELIT - } else if (in.ch == 'f' || in.ch == 'F') { - putChar(in.ch) - in.next + } else if (ch == 'f' || ch == 'F') { + putChar(ch) + nextChar() token = FLOATLIT } - setName + checkNoLetter() + setStrVal() } - /** convert name to long value + /** Convert current strVal to char value + */ + def charVal: Char = if (strVal.length > 0) strVal.charAt(0) else 0 + + /** Convert current strVal, base to long value + * This is tricky because of max negative value. */ def intVal(negated: Boolean): Long = { if (token == CHARLIT && !negated) { - if (name.length > 0) name(0) else 0 + charVal } else { var value: Long = 0 val divider = if (base == 10) 1 else 2 val limit: Long = if (token == LONGLIT) Math.MAX_LONG else Math.MAX_INT var i = 0 - val len = name.length + val len = strVal.length while (i < len) { - val d = in.digit2int(name(i), base) + val d = digit2int(strVal charAt i, base) if (d < 0) { syntaxError("malformed integer number") return 0 @@ -904,14 +670,15 @@ trait Scanners { } } + def intVal: Long = intVal(false) - /** convert name, base to double value + /** Convert current strVal, base to double value */ def floatVal(negated: Boolean): Double = { val limit: Double = if (token == DOUBLELIT) Math.MAX_DOUBLE else Math.MAX_FLOAT try { - val value: Double = java.lang.Double.valueOf(name.toString()).doubleValue() + val value: Double = java.lang.Double.valueOf(strVal).doubleValue() if (value > limit) syntaxError("floating point number too large") if (negated) -value else value @@ -921,70 +688,90 @@ trait Scanners { 0.0 } } - /** read a number into name and set base + + def floatVal: Double = floatVal(false) + + def checkNoLetter() { + if (isIdentifierPart(ch) && ch >= ' ') + syntaxError("Invalid literal number") + } + + /** Read a number into strVal and set base */ - protected def getNumber { - while (in.digit2int(in.ch, if (base < 10) 10 else base) >= 0) { - putChar(in.ch) - in.next + protected def getNumber() { + val base1 = if (base < 10) 10 else base + // read 8,9's even if format is octal, produce a malformed number error afterwards. + while (digit2int(ch, base1) >= 0) { + putChar(ch) + nextChar() } token = INTLIT - if (base <= 10 && in.ch == '.') { - val lookahead = in.copy - lookahead.next + if (base <= 10 && ch == '.') { + val lookahead = lookaheadReader + lookahead.nextChar() lookahead.ch match { case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'd' | 'D' | 'e' | 'E' | 'f' | 'F' => - putChar(in.ch) - in.next - return getFraction + putChar(ch) + nextChar() + return getFraction() case _ => - if (!isIdentStart(lookahead.ch)) { - putChar(in.ch) - in.next - return getFraction + if (!isIdentifierStart(lookahead.ch)) { + putChar(ch) + nextChar() + return getFraction() } } } if (base <= 10 && - (in.ch == 'e' || in.ch == 'E' || - in.ch == 'f' || in.ch == 'F' || - in.ch == 'd' || in.ch == 'D')) { - return getFraction + (ch == 'e' || ch == 'E' || + ch == 'f' || ch == 'F' || + ch == 'd' || ch == 'D')) { + return getFraction() } - setName - if (in.ch == 'l' || in.ch == 'L') { - in.next + setStrVal() + if (ch == 'l' || ch == 'L') { + nextChar() token = LONGLIT - } + } else checkNoLetter() } -// XML lexing---------------------------------------------------------------- - def xSync = { - token = NEWLINE // avoid getting NEWLINE from nextToken if last was RBRACE - //in.next - nextToken + /** Parse character literal if current character is followed by \', + * or follow with given op and return a symol literal token + */ + def charLitOr(op: () => Unit) { + putChar(ch) + nextChar() + if (ch == '\'') { + nextChar() + token = CHARLIT + setStrVal() + } else { + op() + token = SYMBOLLIT + strVal = name.toString + } } // Errors ----------------------------------------------------------------- - /** generate an error at the given position + /** generate an error at the given offset */ - def syntaxError(pos: Int, msg: String) { - error(pos, msg) + def syntaxError(off: Offset, msg: String) { + error(off, msg) token = ERROR - errpos = pos + errOffset = off } - /** generate an error at the current token position + /** generate an error at the current token offset */ - def syntaxError(msg: String) { syntaxError(pos, msg) } + def syntaxError(msg: String): Unit = syntaxError(offset, msg) /** signal an error where the input ended in the middle of a token */ def incompleteInputError(msg: String) { - incompleteInputError(pos, msg) + incompleteInputError(offset, msg) token = EOF - errpos = pos + errOffset = offset } override def toString() = token match { @@ -1001,7 +788,7 @@ trait Scanners { case DOUBLELIT => "double(" + floatVal + ")" case STRINGLIT => - "string(" + name + ")" + "string(" + strVal + ")" case SEMI => ";" case NEWLINE => @@ -1011,29 +798,174 @@ trait Scanners { case COMMA => "," case _ => - ScannerConfiguration.token2string(token) + token2string(token) } - /** INIT: read lookahead character and token. + /** Initialization method: read first char, then first token */ - def init { - in.next - nextToken + def init() { + nextChar() + nextToken() + } + } // end Scanner + + // ------------- character classification -------------------------------- + + def isIdentifierStart(c: Char): Boolean = ( + ('A' <= c && c <= 'Z') || + ('a' <= c && c <= 'a') || + (c == '_') || (c == '$') || + Character.isUnicodeIdentifierStart(c) + ) + + def isIdentifierPart(c: Char) = ( + isIdentifierStart(c) || + ('0' <= c && c <= '9') || + Character.isUnicodeIdentifierPart(c) + ) + + def isSpecial(c: Char) = { + val chtp = Character.getType(c) + chtp == Character.MATH_SYMBOL || chtp == Character.OTHER_SYMBOL + } + + def isOperatorPart(c : Char) : Boolean = (c: @switch) match { + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | '=' | '&' | + '|' | '/' | '\\' => true + case c => isSpecial(c) } + + // ------------- keyword configuration ----------------------------------- + + /** Keyword array; maps from name indices to tokens */ + private var keyCode: Array[Byte] = _ + /** The highest name index of a keyword token */ + private var maxKey = 0 + /** An array of all keyword token names */ + private var keyName = new Array[Name](128) + /** The highest keyword token plus one */ + private var tokenCount = 0 + + /** Enter keyword with given name and token id */ + protected def enterKeyword(n: Name, tokenId: Int) { + while (tokenId >= keyName.length) { + val newTokName = new Array[Name](keyName.length * 2) + Array.copy(keyName, 0, newTokName, 0, newTokName.length) + keyName = newTokName + } + keyName(tokenId) = n + if (n.start > maxKey) maxKey = n.start + if (tokenId >= tokenCount) tokenCount = tokenId + 1 } - /** ... + /** Enter all keywords */ + protected def enterKeywords() { + enterKeyword(nme.ABSTRACTkw, ABSTRACT) + enterKeyword(nme.CASEkw, CASE) + enterKeyword(nme.CATCHkw, CATCH) + enterKeyword(nme.CLASSkw, CLASS) + enterKeyword(nme.DEFkw, DEF) + enterKeyword(nme.DOkw, DO) + enterKeyword(nme.ELSEkw, ELSE) + enterKeyword(nme.EXTENDSkw, EXTENDS) + enterKeyword(nme.FALSEkw, FALSE) + enterKeyword(nme.FINALkw, FINAL) + enterKeyword(nme.FINALLYkw, FINALLY) + enterKeyword(nme.FORkw, FOR) + enterKeyword(nme.FORSOMEkw, FORSOME) + enterKeyword(nme.IFkw, IF) + enterKeyword(nme.IMPLICITkw, IMPLICIT) + enterKeyword(nme.IMPORTkw, IMPORT) + enterKeyword(nme.LAZYkw, LAZY) + enterKeyword(nme.MATCHkw, MATCH) + enterKeyword(nme.NEWkw, NEW) + enterKeyword(nme.NULLkw, NULL) + enterKeyword(nme.OBJECTkw, OBJECT) + enterKeyword(nme.OVERRIDEkw, OVERRIDE) + enterKeyword(nme.PACKAGEkw, PACKAGE) + enterKeyword(nme.PRIVATEkw, PRIVATE) + enterKeyword(nme.PROTECTEDkw, PROTECTED) + enterKeyword(nme.RETURNkw, RETURN) + enterKeyword(nme.SEALEDkw, SEALED) + enterKeyword(nme.SUPERkw, SUPER) + enterKeyword(nme.THISkw, THIS) + enterKeyword(nme.THROWkw, THROW) + enterKeyword(nme.TRAITkw, TRAIT) + enterKeyword(nme.TRUEkw, TRUE) + enterKeyword(nme.TRYkw, TRY) + enterKeyword(nme.TYPEkw, TYPE) + enterKeyword(nme.VALkw, VAL) + enterKeyword(nme.VARkw, VAR) + enterKeyword(nme.WHILEkw, WHILE) + enterKeyword(nme.WITHkw, WITH) + enterKeyword(nme.YIELDkw, YIELD) + enterKeyword(nme.DOTkw, DOT) + enterKeyword(nme.USCOREkw, USCORE) + enterKeyword(nme.COLONkw, COLON) + enterKeyword(nme.EQUALSkw, EQUALS) + enterKeyword(nme.ARROWkw, ARROW) + enterKeyword(nme.LARROWkw, LARROW) + enterKeyword(nme.SUBTYPEkw, SUBTYPE) + enterKeyword(nme.VIEWBOUNDkw, VIEWBOUND) + enterKeyword(nme.SUPERTYPEkw, SUPERTYPE) + enterKeyword(nme.HASHkw, HASH) + enterKeyword(nme.ATkw, AT) + } + + { // initialization + enterKeywords() + // Build keyword array + keyCode = Array.make(maxKey + 1, IDENTIFIER) + for (j <- 0 until tokenCount if keyName(j) ne null) + keyCode(keyName(j).start) = j.toByte + } + + /** Convert name to token */ + def name2token(name: Name): Int = + if (name.start <= maxKey) keyCode(name.start) else IDENTIFIER + +// Token representation ---------------------------------------------------- + + /** Returns the string representation of given token. */ + def token2string(token: Int): String = (token: @switch) match { + case IDENTIFIER | BACKQUOTED_IDENT => "identifier" + case CHARLIT => "character literal" + case INTLIT => "integer literal" + case LONGLIT => "long literal" + case FLOATLIT => "float literal" + case DOUBLELIT => "double literal" + case STRINGLIT => "string literal" + case SYMBOLLIT => "symbol literal" + case LPAREN => "'('" + case RPAREN => "')'" + case LBRACE => "'{'" + case RBRACE => "'}'" + case LBRACKET => "'['" + case RBRACKET => "']'" + case EOF => "eof" + case ERROR => "something" + case SEMI => "';'" + case NEWLINE => "';'" + case NEWLINES => "';'" + case COMMA => "','" + case CASECLASS => "case class" + case CASEOBJECT => "case object" + case XMLSTART => "$XMLSTART$<" + case _ => + if (token <= maxKey) "'" + keyName(token) + "'" + else "'<" + token + ">'" + } + + /** A scanner over a given compilation unit */ class UnitScanner(unit: CompilationUnit) extends Scanner { - val in = new CharArrayReader( - unit.source.asInstanceOf[BatchSourceFile].content, - !settings.nouescape.value, syntaxError - ) - def warning(pos: Int, msg: String) = unit.warning(pos, msg) - def error (pos: Int, msg: String) = unit.error(pos, msg) - def incompleteInputError(pos: Int, msg: String) = unit.incompleteInputError(pos, msg) - def deprecationWarning(pos: Int, msg: String) = unit.deprecationWarning(pos, msg) - implicit def p2g(pos: Position): Int = pos.offset.getOrElse(-1) - implicit def g2p(pos: Int): Position = new OffsetPosition(unit.source, pos) + val buf = unit.source.asInstanceOf[BatchSourceFile].content + val decodeUnit = !settings.nouescape.value + def warning(off: Offset, msg: String) = unit.warning(unit.position(off), msg) + def error (off: Offset, msg: String) = unit.error(unit.position(off), msg) + def incompleteInputError(off: Offset, msg: String) = unit.incompleteInputError(unit.position(off), msg) + def deprecationWarning(off: Offset, msg: String) = unit.deprecationWarning(unit.position(off), msg) } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners1.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners1.scala deleted file mode 100755 index c0e425e494..0000000000 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners1.scala +++ /dev/null @@ -1,971 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2009 LAMP/EPFL - * @author Martin Odersky - */ -// $Id: Scanners.scala 17274 2009-03-10 11:39:04Z michelou $ - -package scala.tools.nsc.ast.parser - -import scala.tools.nsc.util._ -import SourceFile.{LF, FF, CR, SU} -import Tokens._ -import scala.annotation.switch - -trait Scanners1 { - val global : Global - import global._ - - /** Offset into source character array */ - type Offset = Int - - /** An undefined offset */ - val NoOffset: Offset = -1 - - trait TokenData { - - /** the next token */ - var token: Int = EMPTY - - /** the offset of the first character of the current token */ - var offset: Offset = 0 - - /** the offset of the character following the token preceding this one */ - var lastOffset: Offset = 0 - - /** the name of an identifier */ - var name: Name = null - - /** the string value of a literal */ - var strVal: String = null - - /** the base of a number */ - var base: Int = 0 - - def copyFrom(td: TokenData) = { - this.token = td.token - this.offset = td.offset - this.lastOffset = td.lastOffset - this.name = td.name - this.strVal = td.strVal - this.base = td.base - } - } - - abstract class Scanner extends CharArrayReader1 with TokenData { - - def flush = { charOffset = offset; nextChar(); this } - - def resume(lastCode: Int) = { - token = lastCode - assert(next.token == EMPTY) - nextToken() - } - - // things to fill in, in addition to buf, decodeUni - def warning(off: Offset, msg: String): Unit - def error (off: Offset, msg: String): Unit - def incompleteInputError(off: Offset, msg: String): Unit - def deprecationWarning(off: Offset, msg: String): Unit - - /** the last error offset - */ - var errOffset: Offset = NoOffset - - /** A character buffer for literals - */ - val cbuf = new StringBuilder - - /** append Unicode character to "cbuf" buffer - */ - protected def putChar(c: Char) { -// assert(cbuf.size < 10000, cbuf) - cbuf.append(c) - } - - /** Clear buffer and set name and token */ - private def finishNamed() { - name = newTermName(cbuf.toString) - token = name2token(name) - cbuf.clear() - } - - /** Clear buffer and set string */ - private def setStrVal() { - strVal = cbuf.toString - cbuf.clear() - } - - /** Should doc comments be built? */ - def buildDocs: Boolean = onlyPresentation - - /** buffer for the documentation comment - */ - var docBuffer: StringBuilder = null - - /** Return current docBuffer and set docBuffer to null */ - def flushDoc = { - val ret = if (docBuffer != null) docBuffer.toString else null - docBuffer = null - ret - } - - /** add the given character to the documentation buffer - */ - protected def putDocChar(c: Char) { - if (docBuffer ne null) docBuffer.append(c) - } - - private class TokenData0 extends TokenData - - /** we need one token lookahead and one token history - */ - val next : TokenData = new TokenData0 - val prev : TokenData = new TokenData0 - - /** a stack of tokens which indicates whether line-ends can be statement separators - */ - var sepRegions: List[Int] = List() - -// Get next token ------------------------------------------------------------ - - /** read next token and return last offset - */ - def skipToken(): Offset = { - val off = offset - nextToken() - off - } - - /** Produce next token, filling TokenData fields of Scanner. - */ - def nextToken() { - val lastToken = token - // Adapt sepRegions according to last token - (lastToken: @switch) match { - case LPAREN => - sepRegions = RPAREN :: sepRegions - case LBRACKET => - sepRegions = RBRACKET :: sepRegions - case LBRACE => - sepRegions = RBRACE :: sepRegions - case CASE => - sepRegions = ARROW :: sepRegions - case RBRACE => - sepRegions = sepRegions dropWhile (_ != RBRACE) - if (!sepRegions.isEmpty) sepRegions = sepRegions.tail - case RBRACKET | RPAREN | ARROW => - if (!sepRegions.isEmpty && sepRegions.head == lastToken) - sepRegions = sepRegions.tail - case _ => - } - - // Read a token or copy it from `next` tokenData - if (next.token == EMPTY) { - lastOffset = charOffset - 1 - fetchToken() - } else { - this copyFrom next - next.token = EMPTY - } - - /** Insert NEWLINE or NEWLINES if - * - we are after a newline - * - we are within a { ... } or on toplevel (wrt sepRegions) - * - the current token can start a statement and the one before can end it - * insert NEWLINES if we are past a blank line, NEWLINE otherwise - */ - if (afterLineEnd() && inLastOfStat(lastToken) && inFirstOfStat(token) && - (sepRegions.isEmpty || sepRegions.head == RBRACE)) { - next copyFrom this - offset = if (lineStartOffset <= offset) lineStartOffset else lastLineStartOffset - token = if (pastBlankLine()) NEWLINES else NEWLINE - } - - // Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE - if (token == CASE) { - prev copyFrom this - val nextLastOffset = charOffset - 1 - fetchToken() - if (token == CLASS) { - token = CASECLASS - } else if (token == OBJECT) { - token = CASEOBJECT - } else { - lastOffset = nextLastOffset - next copyFrom this - this copyFrom prev - } - } else if (token == SEMI) { - prev copyFrom this - fetchToken() - if (token != ELSE) { - next copyFrom this - this copyFrom prev - } - } - -// print("["+this+"]") - } - - /** Is current token first one after a newline? */ - private def afterLineEnd(): Boolean = - lastOffset < lineStartOffset && - (lineStartOffset <= offset || - lastOffset < lastLineStartOffset && lastLineStartOffset <= offset) - - /** Is there a blank line between the current token and the last one? - * @pre afterLineEnd(). - */ - private def pastBlankLine(): Boolean = { - var idx = lastOffset - var ch = buf(idx) - val end = offset - while (idx < end) { - if (ch == LF || ch == FF) { - do { - idx += 1; ch = buf(idx) - if (ch == LF || ch == FF) { -// println("blank line found at "+lastOffset+":"+(lastOffset to idx).map(buf(_)).toList) - return true - } - } while (idx < end && ch <= ' ') - } - idx += 1; ch = buf(idx) - } - false - } - - /** read next token, filling TokenData fields of Scanner. - */ - private final def fetchToken() { - offset = charOffset - 1 - (ch: @switch) match { - case ' ' | '\t' | CR | LF | FF => - nextChar() - fetchToken() - case 'A' | 'B' | 'C' | 'D' | 'E' | - 'F' | 'G' | 'H' | 'I' | 'J' | - 'K' | 'L' | 'M' | 'N' | 'O' | - 'P' | 'Q' | 'R' | 'S' | 'T' | - 'U' | 'V' | 'W' | 'X' | 'Y' | - 'Z' | '$' | '_' | - 'a' | 'b' | 'c' | 'd' | 'e' | - 'f' | 'g' | 'h' | 'i' | 'j' | - 'k' | 'l' | 'm' | 'n' | 'o' | - 'p' | 'q' | 'r' | 's' | 't' | - 'u' | 'v' | 'w' | 'x' | 'y' | // scala-mode: need to understand multi-line case patterns - 'z' => - putChar(ch) - nextChar() - getIdentRest() // scala-mode: wrong indent for multi-line case blocks - case '<' => // is XMLSTART? - val last = if (charOffset >= 2) buf(charOffset - 2) else ' ' - nextChar() - last match { - case ' '|'\t'|'\n'|'{'|'('|'>' if xml.Parsing.isNameStart(ch) || ch == '!' || ch == '?' => - token = XMLSTART - case _ => - // Console.println("found '<', but last is '"+in.last+"'"); // DEBUG - putChar('<') - getOperatorRest() - } - case '~' | '!' | '@' | '#' | '%' | - '^' | '*' | '+' | '-' | /*'<' | */ - '>' | '?' | ':' | '=' | '&' | - '|' | '\\' => - putChar(ch) - nextChar() - getOperatorRest() - case '/' => - nextChar() - if (skipComment()) { - fetchToken() - } else { - putChar('/') - getOperatorRest() - } - case '0' => - putChar(ch) - nextChar() - if (ch == 'x' || ch == 'X') { - nextChar() - base = 16 - } else { - base = 8 - } - getNumber() - case '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => - base = 10 - getNumber() - case '`' => - nextChar() - if (getStringLit('`')) { - finishNamed(); - if (name.length == 0) syntaxError("empty quoted identifier") - token = BACKQUOTED_IDENT - } - else syntaxError("unclosed quoted identifier") - case '\"' => - nextChar() - if (ch == '\"') { - nextChar() - if (ch == '\"') { - nextChar() - val saved = lineStartOffset - getMultiLineStringLit() - if (lineStartOffset != saved) // ignore linestarts within a multi-line string - lastLineStartOffset = saved - } else { - token = STRINGLIT - strVal = "" - } - } else if (getStringLit('\"')) { - setStrVal() - token = STRINGLIT - } else { - syntaxError("unclosed string literal") - } - case '\'' => - nextChar() - if (isIdentifierStart(ch) || '0' <= ch && ch <= '9') - charLitOr(getIdentRest) - else if (isSpecial(ch)) - charLitOr(getOperatorRest) - else { - getLitChar() - if (ch == '\'') { - nextChar() - token = CHARLIT - setStrVal() - } else { - syntaxError("unclosed character literal") - } - } - case '.' => - nextChar() - if ('0' <= ch && ch <= '9') { - putChar('.'); getFraction() - } else { - token = DOT - } - case ';' => - nextChar(); token = SEMI - case ',' => - nextChar(); token = COMMA - case '(' => - nextChar(); token = LPAREN - case '{' => - nextChar(); token = LBRACE - case ')' => - nextChar(); token = RPAREN - case '}' => - nextChar(); token = RBRACE - case '[' => - nextChar(); token = LBRACKET - case ']' => - nextChar(); token = RBRACKET - case SU => - if (charOffset >= buf.length) token = EOF - else { - syntaxError("illegal character") - nextChar() - } - case _ => - if (ch == '\u21D2') { - nextChar(); token = ARROW - } else if (ch == '\u2190') { - nextChar(); token = LARROW - } else if (Character.isUnicodeIdentifierStart(ch)) { - putChar(ch) - nextChar() - getIdentRest() - } else if (isSpecial(ch)) { - putChar(ch) - getOperatorRest() - } else { - syntaxError("illegal character") - nextChar() - } - } - } - - private def skipComment(): Boolean = { - if (ch == '/') { - do { - nextChar() - } while ((ch != CR) && (ch != LF) && (ch != SU)) - true - } else if (ch == '*') { - docBuffer = null - var openComments = 1 - nextChar() - if (ch == '*' && buildDocs) - docBuffer = new StringBuilder("/**") - while (openComments > 0) { - do { - do { - if (ch == '/') { - nextChar(); putDocChar(ch) - if (ch == '*') { - nextChar(); putDocChar(ch) - openComments += 1 - } - } - if (ch != '*' && ch != SU) { - nextChar(); putDocChar(ch) - } - } while (ch != '*' && ch != SU) - while (ch == '*') { - nextChar(); putDocChar(ch) - } - } while (ch != '/' && ch != SU) - if (ch == '/') nextChar() - else incompleteInputError("unclosed comment") - openComments -= 1 - } - true - } else { - false - } - } - - /** Can token start a statement? */ - def inFirstOfStat(token: Int) = token match { - case EOF | CATCH | ELSE | EXTENDS | FINALLY | FORSOME | MATCH | WITH | YIELD | - COMMA | SEMI | NEWLINE | NEWLINES | DOT | COLON | EQUALS | ARROW | LARROW | - SUBTYPE | VIEWBOUND | SUPERTYPE | HASH | RPAREN | RBRACKET | RBRACE | LBRACKET => - false - case _ => - true - } - - /** Can token end a statement? */ - def inLastOfStat(token: Int) = token match { - case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | - IDENTIFIER | BACKQUOTED_IDENT | THIS | NULL | TRUE | FALSE | RETURN | USCORE | - TYPE | XMLSTART | RPAREN | RBRACKET | RBRACE => - true - case _ => - false - } - -// Identifiers --------------------------------------------------------------- - - private def getIdentRest(): Unit = (ch: @switch) match { - case 'A' | 'B' | 'C' | 'D' | 'E' | - 'F' | 'G' | 'H' | 'I' | 'J' | - 'K' | 'L' | 'M' | 'N' | 'O' | - 'P' | 'Q' | 'R' | 'S' | 'T' | - 'U' | 'V' | 'W' | 'X' | 'Y' | - 'Z' | '$' | - 'a' | 'b' | 'c' | 'd' | 'e' | - 'f' | 'g' | 'h' | 'i' | 'j' | - 'k' | 'l' | 'm' | 'n' | 'o' | - 'p' | 'q' | 'r' | 's' | 't' | - 'u' | 'v' | 'w' | 'x' | 'y' | - 'z' | - '0' | '1' | '2' | '3' | '4' | - '5' | '6' | '7' | '8' | '9' => - putChar(ch) - nextChar() - getIdentRest() - case '_' => - putChar(ch) - nextChar() - getIdentOrOperatorRest() - case SU => // strangely enough, Character.isUnicodeIdentifierPart(SU) returns true! - finishNamed() - case _ => - if (Character.isUnicodeIdentifierPart(ch)) { - putChar(ch) - nextChar() - getIdentRest() - } else { - finishNamed() - } - } - - private def getOperatorRest(): Unit = (ch: @switch) match { - case '~' | '!' | '@' | '#' | '%' | - '^' | '*' | '+' | '-' | '<' | - '>' | '?' | ':' | '=' | '&' | - '|' | '\\' => - putChar(ch); nextChar(); getOperatorRest() - case '/' => - nextChar() - if (skipComment()) finishNamed() - else { putChar('/'); getOperatorRest() } - case _ => - if (isSpecial(ch)) { putChar(ch); nextChar(); getOperatorRest() } - else finishNamed() - } - - private def getIdentOrOperatorRest() { - if (isIdentifierPart(ch)) - getIdentRest() - else ch match { - case '~' | '!' | '@' | '#' | '%' | - '^' | '*' | '+' | '-' | '<' | - '>' | '?' | ':' | '=' | '&' | - '|' | '\\' | '/' => - getOperatorRest() - case _ => - if (isSpecial(ch)) getOperatorRest() - else finishNamed() - } - } - - private def getStringLit(delimiter: Char): Boolean = { - while (ch != delimiter && (isUnicodeEscape || ch != CR && ch != LF && ch != SU)) { - getLitChar() - } - if (ch == delimiter) { nextChar(); true } - else false - } - - private def getMultiLineStringLit() { - if (ch == '\"') { - nextChar() - if (ch == '\"') { - nextChar() - if (ch == '\"') { - nextChar() - token = STRINGLIT - setStrVal() - } else { - putChar('\"') - putChar('\"') - getMultiLineStringLit() - } - } else { - putChar('\"') - getMultiLineStringLit() - } - } else if (ch == SU) { - incompleteInputError("unclosed multi-line string literal") - } else { - putChar(ch) - nextChar() - getMultiLineStringLit() - } - } - -// Literals ----------------------------------------------------------------- - - /** read next character in character or string literal: - */ - protected def getLitChar() = - if (ch == '\\') { - nextChar() - if ('0' <= ch && ch <= '7') { - val leadch: Char = ch - var oct: Int = digit2int(ch, 8) - nextChar() - if ('0' <= ch && ch <= '7') { - oct = oct * 8 + digit2int(ch, 8) - nextChar() - if (leadch <= '3' && '0' <= ch && ch <= '7') { - oct = oct * 8 + digit2int(ch, 8) - nextChar() - } - } - putChar(oct.toChar) - } else { - ch match { - case 'b' => putChar('\b') - case 't' => putChar('\t') - case 'n' => putChar('\n') - case 'f' => putChar('\f') - case 'r' => putChar('\r') - case '\"' => putChar('\"') - case '\'' => putChar('\'') - case '\\' => putChar('\\') - case _ => - syntaxError(charOffset - 1, "invalid escape character") - putChar(ch) - } - nextChar() - } - } else { - putChar(ch) - nextChar() - } - - /** read fractional part and exponent of floating point number - * if one is present. - */ - protected def getFraction() { - token = DOUBLELIT - while ('0' <= ch && ch <= '9') { - putChar(ch) - nextChar() - } - if (ch == 'e' || ch == 'E') { - val lookahead = lookaheadReader - lookahead.nextChar() - if (lookahead.ch == '+' || lookahead.ch == '-') { - lookahead.nextChar() - } - if ('0' <= lookahead.ch && lookahead.ch <= '9') { - putChar(ch) - nextChar() - if (ch == '+' || ch == '-') { - putChar(ch) - nextChar() - } - while ('0' <= ch && ch <= '9') { - putChar(ch) - nextChar() - } - } - token = DOUBLELIT - } - if (ch == 'd' || ch == 'D') { - putChar(ch) - nextChar() - token = DOUBLELIT - } else if (ch == 'f' || ch == 'F') { - putChar(ch) - nextChar() - token = FLOATLIT - } - checkNoLetter() - setStrVal() - } - - /** Convert current strVal to char value - */ - def charVal: Char = if (strVal.length > 0) strVal.charAt(0) else 0 - - /** Convert current strVal, base to long value - * This is tricky because of max negative value. - */ - def intVal(negated: Boolean): Long = { - if (token == CHARLIT && !negated) { - charVal - } else { - var value: Long = 0 - val divider = if (base == 10) 1 else 2 - val limit: Long = - if (token == LONGLIT) Math.MAX_LONG else Math.MAX_INT - var i = 0 - val len = strVal.length - while (i < len) { - val d = digit2int(strVal charAt i, base) - if (d < 0) { - syntaxError("malformed integer number") - return 0 - } - if (value < 0 || - limit / (base / divider) < value || - limit - (d / divider) < value * (base / divider) && - !(negated && limit == value * base - 1 + d)) { - syntaxError("integer number too large") - return 0 - } - value = value * base + d - i += 1 - } - if (negated) -value else value - } - } - - def intVal: Long = intVal(false) - - /** Convert current strVal, base to double value - */ - def floatVal(negated: Boolean): Double = { - val limit: Double = - if (token == DOUBLELIT) Math.MAX_DOUBLE else Math.MAX_FLOAT - try { - val value: Double = java.lang.Double.valueOf(strVal).doubleValue() - if (value > limit) - syntaxError("floating point number too large") - if (negated) -value else value - } catch { - case _: NumberFormatException => - syntaxError("malformed floating point number") - 0.0 - } - } - - def floatVal: Double = floatVal(false) - - def checkNoLetter() { - if (isIdentifierPart(ch) && ch >= ' ') - syntaxError("Invalid literal number") - } - - /** Read a number into strVal and set base - */ - protected def getNumber() { - val base1 = if (base < 10) 10 else base - // read 8,9's even if format is octal, produce a malformed number error afterwards. - while (digit2int(ch, base1) >= 0) { - putChar(ch) - nextChar() - } - token = INTLIT - if (base <= 10 && ch == '.') { - val lookahead = lookaheadReader - lookahead.nextChar() - lookahead.ch match { - case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | - '8' | '9' | 'd' | 'D' | 'e' | 'E' | 'f' | 'F' => - putChar(ch) - nextChar() - return getFraction() - case _ => - if (!isIdentifierStart(lookahead.ch)) { - putChar(ch) - nextChar() - return getFraction() - } - } - } - if (base <= 10 && - (ch == 'e' || ch == 'E' || - ch == 'f' || ch == 'F' || - ch == 'd' || ch == 'D')) { - return getFraction() - } - setStrVal() - if (ch == 'l' || ch == 'L') { - nextChar() - token = LONGLIT - } else checkNoLetter() - } - - /** Parse character literal if current character is followed by \', - * or follow with given op and return a symol literal token - */ - def charLitOr(op: () => Unit) { - putChar(ch) - nextChar() - if (ch == '\'') { - nextChar() - token = CHARLIT - setStrVal() - } else { - op() - token = SYMBOLLIT - strVal = name.toString - } - } - -// Errors ----------------------------------------------------------------- - - /** generate an error at the given offset - */ - def syntaxError(off: Offset, msg: String) { - error(off, msg) - token = ERROR - errOffset = off - } - - /** generate an error at the current token offset - */ - def syntaxError(msg: String): Unit = syntaxError(offset, msg) - - /** signal an error where the input ended in the middle of a token */ - def incompleteInputError(msg: String) { - incompleteInputError(offset, msg) - token = EOF - errOffset = offset - } - - override def toString() = token match { - case IDENTIFIER | BACKQUOTED_IDENT => - "id(" + name + ")" - case CHARLIT => - "char(" + intVal + ")" - case INTLIT => - "int(" + intVal + ")" - case LONGLIT => - "long(" + intVal + ")" - case FLOATLIT => - "float(" + floatVal + ")" - case DOUBLELIT => - "double(" + floatVal + ")" - case STRINGLIT => - "string(" + strVal + ")" - case SEMI => - ";" - case NEWLINE => - ";" - case NEWLINES => - ";;" - case COMMA => - "," - case _ => - token2string(token) - } - - /** Initialization method: read first char, then first token - */ - def init() { - nextChar() - nextToken() - } - } // end Scanner - - // ------------- character classification -------------------------------- - - def isIdentifierStart(c: Char): Boolean = ( - ('A' <= c && c <= 'Z') || - ('a' <= c && c <= 'a') || - (c == '_') || (c == '$') || - Character.isUnicodeIdentifierStart(c) - ) - - def isIdentifierPart(c: Char) = ( - isIdentifierStart(c) || - ('0' <= c && c <= '9') || - Character.isUnicodeIdentifierPart(c) - ) - - def isSpecial(c: Char) = { - val chtp = Character.getType(c) - chtp == Character.MATH_SYMBOL || chtp == Character.OTHER_SYMBOL - } - - def isOperatorPart(c : Char) : Boolean = (c: @switch) match { - case '~' | '!' | '@' | '#' | '%' | - '^' | '*' | '+' | '-' | '<' | - '>' | '?' | ':' | '=' | '&' | - '|' | '/' | '\\' => true - case c => isSpecial(c) - } - - // ------------- keyword configuration ----------------------------------- - - /** Keyword array; maps from name indices to tokens */ - private var keyCode: Array[Byte] = _ - /** The highest name index of a keyword token */ - private var maxKey = 0 - /** An array of all keyword token names */ - private var keyName = new Array[Name](128) - /** The highest keyword token plus one */ - private var tokenCount = 0 - - /** Enter keyword with given name and token id */ - protected def enterKeyword(n: Name, tokenId: Int) { - while (tokenId >= keyName.length) { - val newTokName = new Array[Name](keyName.length * 2) - Array.copy(keyName, 0, newTokName, 0, newTokName.length) - keyName = newTokName - } - keyName(tokenId) = n - if (n.start > maxKey) maxKey = n.start - if (tokenId >= tokenCount) tokenCount = tokenId + 1 - } - - /** Enter all keywords */ - protected def enterKeywords() { - enterKeyword(nme.ABSTRACTkw, ABSTRACT) - enterKeyword(nme.CASEkw, CASE) - enterKeyword(nme.CATCHkw, CATCH) - enterKeyword(nme.CLASSkw, CLASS) - enterKeyword(nme.DEFkw, DEF) - enterKeyword(nme.DOkw, DO) - enterKeyword(nme.ELSEkw, ELSE) - enterKeyword(nme.EXTENDSkw, EXTENDS) - enterKeyword(nme.FALSEkw, FALSE) - enterKeyword(nme.FINALkw, FINAL) - enterKeyword(nme.FINALLYkw, FINALLY) - enterKeyword(nme.FORkw, FOR) - enterKeyword(nme.FORSOMEkw, FORSOME) - enterKeyword(nme.IFkw, IF) - enterKeyword(nme.IMPLICITkw, IMPLICIT) - enterKeyword(nme.IMPORTkw, IMPORT) - enterKeyword(nme.LAZYkw, LAZY) - enterKeyword(nme.MATCHkw, MATCH) - enterKeyword(nme.NEWkw, NEW) - enterKeyword(nme.NULLkw, NULL) - enterKeyword(nme.OBJECTkw, OBJECT) - enterKeyword(nme.OVERRIDEkw, OVERRIDE) - enterKeyword(nme.PACKAGEkw, PACKAGE) - enterKeyword(nme.PRIVATEkw, PRIVATE) - enterKeyword(nme.PROTECTEDkw, PROTECTED) - enterKeyword(nme.RETURNkw, RETURN) - enterKeyword(nme.SEALEDkw, SEALED) - enterKeyword(nme.SUPERkw, SUPER) - enterKeyword(nme.THISkw, THIS) - enterKeyword(nme.THROWkw, THROW) - enterKeyword(nme.TRAITkw, TRAIT) - enterKeyword(nme.TRUEkw, TRUE) - enterKeyword(nme.TRYkw, TRY) - enterKeyword(nme.TYPEkw, TYPE) - enterKeyword(nme.VALkw, VAL) - enterKeyword(nme.VARkw, VAR) - enterKeyword(nme.WHILEkw, WHILE) - enterKeyword(nme.WITHkw, WITH) - enterKeyword(nme.YIELDkw, YIELD) - enterKeyword(nme.DOTkw, DOT) - enterKeyword(nme.USCOREkw, USCORE) - enterKeyword(nme.COLONkw, COLON) - enterKeyword(nme.EQUALSkw, EQUALS) - enterKeyword(nme.ARROWkw, ARROW) - enterKeyword(nme.LARROWkw, LARROW) - enterKeyword(nme.SUBTYPEkw, SUBTYPE) - enterKeyword(nme.VIEWBOUNDkw, VIEWBOUND) - enterKeyword(nme.SUPERTYPEkw, SUPERTYPE) - enterKeyword(nme.HASHkw, HASH) - enterKeyword(nme.ATkw, AT) - } - - { // initialization - enterKeywords() - // Build keyword array - keyCode = Array.make(maxKey + 1, IDENTIFIER) - for (j <- 0 until tokenCount if keyName(j) ne null) - keyCode(keyName(j).start) = j.toByte - } - - /** Convert name to token */ - def name2token(name: Name): Int = - if (name.start <= maxKey) keyCode(name.start) else IDENTIFIER - -// Token representation ---------------------------------------------------- - - /** Returns the string representation of given token. */ - def token2string(token: Int): String = (token: @switch) match { - case IDENTIFIER | BACKQUOTED_IDENT => "identifier" - case CHARLIT => "character literal" - case INTLIT => "integer literal" - case LONGLIT => "long literal" - case FLOATLIT => "float literal" - case DOUBLELIT => "double literal" - case STRINGLIT => "string literal" - case SYMBOLLIT => "symbol literal" - case LPAREN => "'('" - case RPAREN => "')'" - case LBRACE => "'{'" - case RBRACE => "'}'" - case LBRACKET => "'['" - case RBRACKET => "']'" - case EOF => "eof" - case ERROR => "something" - case SEMI => "';'" - case NEWLINE => "';'" - case NEWLINES => "';'" - case COMMA => "','" - case CASECLASS => "case class" - case CASEOBJECT => "case object" - case XMLSTART => "$XMLSTART$<" - case _ => - if (token <= maxKey) "'" + keyName(token) + "'" - else "'<" + token + ">'" - } - - /** A scanner over a given compilation unit - */ - class UnitScanner(unit: CompilationUnit) extends Scanner { - val buf = unit.source.asInstanceOf[BatchSourceFile].content - val decodeUnit = !settings.nouescape.value - def warning(off: Offset, msg: String) = unit.warning(unit.position(off), msg) - def error (off: Offset, msg: String) = unit.error(unit.position(off), msg) - def incompleteInputError(off: Offset, msg: String) = unit.incompleteInputError(unit.position(off), msg) - def deprecationWarning(off: Offset, msg: String) = unit.deprecationWarning(unit.position(off), msg) - } -} diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala index 7b2f894e6b..2630bf374d 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala @@ -2,7 +2,7 @@ * Copyright 2005-2009 LAMP/EPFL * @author Burak Emir */ -// $Id$ +// $Id: SymbolicXMLBuilder.scala 16884 2009-01-09 16:52:09Z cunei $ package scala.tools.nsc.ast.parser diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder1.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder1.scala deleted file mode 100644 index c4eef84be6..0000000000 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder1.scala +++ /dev/null @@ -1,368 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2009 LAMP/EPFL - * @author Burak Emir - */ -// $Id: SymbolicXMLBuilder.scala 16884 2009-01-09 16:52:09Z cunei $ - -package scala.tools.nsc.ast.parser - -import scala.collection.mutable.{Buffer, HashMap, ListBuffer, Map} -import scala.tools.nsc.util.Position -import scala.xml.{EntityRef, Text} -import symtab.Flags.MUTABLE - -/** This class builds instance of <code>Tree</code> that represent XML. - * - * @author Burak Emir - * @version 1.0 - */ -abstract class SymbolicXMLBuilder1(make: TreeBuilder, p: Parsers1 # Parser, preserveWS: Boolean) { - - val global: Global - import global._ - import global.posAssigner.atPos - - var isPattern: Boolean = _ - - def _Attribute = global.newTypeName("Attribute") - def _MetaData = global.newTypeName("MetaData") - def _NamespaceBinding = global.newTypeName("NamespaceBinding") - def _NodeBuffer = global.newTypeName("NodeBuffer") - def _Null = global.newTermName("Null") - - def _PrefixedAttribute = global.newTypeName("PrefixedAttribute") - def _UnprefixedAttribute = global.newTypeName("UnprefixedAttribute") - def _Elem = global.newTypeName("Elem") - def __Elem = global.newTermName("Elem") - def _Group = global.newTypeName("Group") - def _Unparsed = global.newTypeName("Unparsed") - def _Seq = global.newTypeName("Seq") - def _immutable = global.newTermName("immutable") - def _mutable = global.newTermName("mutable") - def _append = global.newTermName("append") - def _plus = global.newTermName("$amp$plus") - def _collection = global.newTermName("collection") - def _toList = global.newTermName("toList") - def _xml = global.newTermName("xml") - def _Comment = global.newTypeName("Comment") - def _Node = global.newTypeName("Node") - def _None = global.newTermName("None") - def _Some = global.newTypeName("Some") - def _ProcInstr = global.newTypeName("ProcInstr") - def _Text = global.newTypeName("Text") - def __Text = global.newTermName("Text") - def _EntityRef = global.newTypeName("EntityRef") - - final def _buf = global.newTermName("$buf") - final def _md = global.newTermName("$md") - final def _scope = global.newTermName("$scope") - final def _tmpscope = global.newTermName("$tmpscope") - - // convenience methods - private def LL[A](x: A*): List[List[A]] = List(List(x:_*)) - - private def _scala(name: Name) = - Select(Select(Ident(nme.ROOTPKG), nme.scala_), name) - - private def _scala_Seq = _scala(_Seq) - private def _scala_xml(name: Name) = Select(_scala(_xml), name) - - private def _scala_xml_MetaData = _scala_xml(_MetaData) - private def _scala_xml_NamespaceBinding = _scala_xml(_NamespaceBinding) - private def _scala_xml_Null = _scala_xml(_Null) - private def _scala_xml_PrefixedAttribute = _scala_xml(_PrefixedAttribute) - private def _scala_xml_UnprefixedAttribute= _scala_xml(_UnprefixedAttribute) - private def _scala_xml_Node = _scala_xml(_Node) - private def _scala_xml_NodeBuffer = _scala_xml(_NodeBuffer) - private def _scala_xml_EntityRef = _scala_xml(_EntityRef) - private def _scala_xml_Comment = _scala_xml(_Comment) - private def _scala_xml_ProcInstr = _scala_xml(_ProcInstr) - private def _scala_xml_Text = _scala_xml(_Text) - private def _scala_xml__Text = _scala_xml(__Text) - private def _scala_xml_Elem = _scala_xml(_Elem) - private def _scala_xml__Elem = _scala_xml(__Elem) - private def _scala_xml_Attribute = _scala_xml(_Attribute) - private def _scala_xml_Group = _scala_xml(_Group) - private def _scala_xml_Unparsed = _scala_xml(_Unparsed) - - // create scala xml tree - - /** - * @arg namespace: a Tree of type defs.STRING_TYPE - * @arg label: a Tree of type defs.STRING_TYPE - * @todo map: a map of attributes !!! - */ - - protected def mkXML(pos: Position, isPattern: Boolean, pre: Tree, label: Tree, attrs: /*Array[*/Tree/*]*/ , scope:Tree, children: Buffer[Tree]): Tree = { - if (isPattern) { - convertToTextPat(children) - atPos (pos) { //@todo maybe matching on attributes, scope? - Apply( _scala_xml__Elem, List( - pre, label, Ident(nme.WILDCARD) /* md */ , Ident(nme.WILDCARD)) /* scope */ ::: children.toList ) - } - } else { - var ab = List(pre, label, attrs, scope) - if (children.length > 0) - ab = ab ::: List(Typed(makeXMLseq(pos, children), Ident(nme.WILDCARD_STAR.toTypeName))); - atPos(pos) { New( _scala_xml_Elem, List(ab) )} - } - } - - final def entityRef(pos: Position, n: String) = { - atPos(pos) { New( _scala_xml_EntityRef, LL(Literal(Constant( n )))) } - - }; - // create scala.xml.Text here <: scala.xml.Node - final def text(pos: Position, txt:String): Tree = { - //makeText( isPattern, gen.mkStringLit( txt )) - val txt1 = Literal(Constant(txt)) - atPos(pos) { - if (isPattern) - makeTextPat(txt1) - else - makeText1(txt1) - } - } - - // create scala.xml.Text here <: scala.xml.Node - def makeTextPat(txt: Tree) = Apply(_scala_xml__Text, List(txt)) - - def makeText1(txt: Tree) = - New(_scala_xml_Text, LL(txt)) - - // create - def comment(pos: Position, text: String): Tree = - atPos(pos) { Comment( Literal(Constant(text))) } - - // create - def charData(pos: Position, txt: String): Tree = - atPos(pos) { makeText1(Literal(Constant(txt))) }; //{ CharData( Literal(Constant(txt))) }; - - // create scala.xml.Text here <: scala.xml.Node - def procInstr( pos: Position, target: String, txt: String ) = - atPos(pos) { ProcInstr(Literal(Constant(target)), Literal(Constant(txt))) } - - protected def Comment(txt: Tree) = New(_scala_xml_Comment, LL(txt)) - - protected def ProcInstr(target: Tree, txt: Tree) = - New(_scala_xml_ProcInstr, LL(target, txt)) - - /** @todo: attributes */ - def makeXMLpat(pos: Position, n: String, args: Buffer[Tree]): Tree = { - val (prepat, labpat) = n.indexOf(':') match { - case -1 => (Ident(nme.WILDCARD), Literal(Constant(n))) - //case 0 => // is erroneous, but cannot happen - case i => //if(i+1<n.length) // we ensure i+1<n.length in method xName - (Literal(Constant(n.substring(0,i))), Literal(Constant(n.substring(i+1,n.length)))) - //else { p.syntaxError(pos,"nonsensical qualified name in XML"); return Ident(nme.WILDCARD).setPos(pos)} - } - mkXML(pos, - true, - prepat, //Ident( nme.WILDCARD ), - labpat, //Literal(Constant(n)), - null, //Array[Tree](), - null, - args); - } - - protected def convertToTextPat(t: Tree): Tree = t match { - case _:Literal => makeTextPat(t) - case _ => t - } - - def parseAttribute(pos: Position, s: String): Tree = { - val ns = xml.Utility.parseAttributeValue(s) - val ts: ListBuffer[Tree] = new ListBuffer - val it = ns.elements - while (it.hasNext) it.next match { - case Text(s) => ts += text(pos, s) // makeText1(Literal(Constant(s))) - case EntityRef(s) => ts += entityRef(pos, s) - } - ts.length match { - case 0 => gen.mkNil - case 1 => val t = ts(0); ts.clear; t - case _ => makeXMLseq(pos, ts) - } - } - - protected def convertToTextPat(buf: Buffer[Tree]) { - var i = 0; while (i < buf.length) { - val t1 = buf(i) - val t2 = convertToTextPat(t1) - if (!t1.eq(t2)) { - buf.remove(i) - buf.insert(i, t2) - } - i += 1 - } - } - - def freshName(prefix: String): Name - - def isEmptyText(t: Tree) = t match { - case Literal(Constant("")) => true - case _ => false - } - - // could optimize if args.length == 0, args.length == 1 AND args(0) is <: Node. - def makeXMLseq(pos: Position, args: Buffer[Tree] ) = { - //var _buffer = New( _scala_xml_NodeBuffer, List(Nil)) - - var as:List[Tree] = ValDef(NoMods, _buf, TypeTree(), New( _scala_xml_NodeBuffer, List(Nil)))::Nil - val it = args.elements - while (it.hasNext) { - val t = it.next - if (!isEmptyText(t)) { - //_buffer = Apply(Select(_buffer, _plus), List(t)) - as = Apply(Select(Ident(_buf), _plus), List(t))::as - } - } - //atPos(pos) { Select(_buffer, _toList) } - - atPos(pos) { - Block(as.reverse, Ident(_buf)) - } - } - /** returns Some(prefix) if pre:name, None otherwise */ - def getPrefix(name: String): Option[String] = { - val i = name.indexOf(':') - if (i != -1) Some(name.substring(0, i)) else None - } - - def group(pos: Position, args: Buffer[Tree]): Tree = { - atPos(pos) { New( _scala_xml_Group, LL( makeXMLseq(pos, args))) } - } - - /** code that constructs an unparsed node - */ - def unparsed(pos: Position, str: String): Tree = { - atPos(pos) { New( _scala_xml_Unparsed, LL( Literal(Constant(str)))) } - } - - /** makes an element */ - def element(pos: Position, qname: String, attrMap: Map[String,Tree], args: Buffer[Tree]): Tree = { - //Console.println("SymbolicXMLBuilder::element("+pos+","+qname+","+attrMap+","+args+")"); - var setNS = new HashMap[String, Tree] - - var tlist: List[Tree] = List() - - /* pre can be null */ - def handleNamespaceBinding(pre: String , uri1: Tree) { - def mkAssign(t: Tree): Tree = - Assign(Ident(_tmpscope), New( _scala_xml_NamespaceBinding, - LL(Literal(Constant(pre)), t, Ident( _tmpscope)))) - uri1 match { - case Apply(_, List(uri @ Literal(Constant(_)))) => //text - tlist = mkAssign(uri) :: tlist - case Select(_, nme.Nil) => // allow for xmlns="" -- bug #1626 - tlist = mkAssign(Literal(Constant(null))) :: tlist - case _ => - tlist = mkAssign(uri1) :: tlist - //println("SymbolicXMLBuilder::handleNamespaceBinding:") - //println(t.toString()) - } - } - - /* DEBUG */ - val attrIt = attrMap.keys - while (attrIt.hasNext) { - val z = attrIt.next - if (z startsWith "xmlns") { // handle namespace - val i = z indexOf ':' - if (i == -1) - handleNamespaceBinding(null, attrMap(z)) - //setNS.update("default", attrMap(z)) - else { - val zz = z.substring(i+1, z.length()) - //setNS.update( zz, attrMap( z ) ); - handleNamespaceBinding(zz, attrMap(z)) - } - attrMap -= z - } - } - - val moreNamespaces = (0 < tlist.length) - val i = qname indexOf ':' - var newlabel = qname - val pre = getPrefix(qname) match { - case Some(p) => - newlabel = qname.substring(p.length()+1, qname.length()) - p - case None => - null - } - var tlist2: List[Tree] = List() - - // make attributes - - def handlePrefixedAttribute(pre:String, key:String, value:Tree) { - val t = atPos(pos) { - Assign(Ident(_md), New( _scala_xml_PrefixedAttribute, - LL( - Literal(Constant(pre)), - Literal(Constant(key)), - value, - Ident(_md) - )))}; - tlist2 = t :: tlist2; - // Console.println("SymbolicXMLBuilder::handlePrefixed :"); - // Console.println(t.toString()); - } - - def handleUnprefixedAttribute(key: String, value:Tree) { - val t = atPos(pos) { - Assign(Ident(_md), New(_scala_xml_UnprefixedAttribute, - LL(Literal(Constant(key)),value,Ident(_md)) - ))}; - tlist2 = t :: tlist2 - } - - var it = attrMap.elements - while (it.hasNext) { - val ansk = it.next - getPrefix(ansk._1) match { - case Some(pre) => - val key = ansk._1.substring(pre.length()+1, ansk._1.length()) - handlePrefixedAttribute(pre, key, ansk._2) - case None => - handleUnprefixedAttribute(ansk._1, ansk._2) - } - } - // attrs - - val moreAttributes = (0 < tlist2.length) - - var ts: List[Tree] = tlist - var ts2: List[Tree] = List() - - if (moreAttributes) { - ts2 = atPos(pos) {ValDef(Modifiers(MUTABLE), - _md, - _scala_xml_MetaData, - _scala_xml_Null)} :: tlist2; - } - if (moreNamespaces) { - ts = atPos(pos) { - ValDef(Modifiers(MUTABLE), - _tmpscope, - _scala_xml_NamespaceBinding, - Ident(_scope))} :: ts; - - ts2 = ValDef(NoMods, _scope, _scala_xml_NamespaceBinding, Ident(_tmpscope)) :: ts2 - } - - val makeSymbolicAttrs = - if (moreAttributes) Ident(_md) else _scala_xml_Null - - var t = mkXML(pos, - false, - Literal(Constant(pre)) /* can be null */ , - Literal(Constant(newlabel)): Tree, - makeSymbolicAttrs, - Ident(_scope), - args); - - atPos(pos) { Block(ts, Block(ts2, t)) } - } -} - diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index 4aa29e3f8c..3b402bdd36 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala @@ -2,7 +2,7 @@ * Copyright 2005-2009 LAMP/EPFL * @author Martin Odersky */ -// $Id$ +// $Id: SyntaxAnalyzer.scala 16893 2009-01-13 13:09:22Z cunei $ package scala.tools.nsc.ast.parser @@ -10,7 +10,7 @@ import javac._ /** An nsc sub-component. */ -abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParsers with NewScanners with JavaParsers with JavaScanners { +abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParsers with Scanners with JavaParsers with JavaScanners { val phaseName = "parser" diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer1.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer1.scala deleted file mode 100644 index 4fe9db2036..0000000000 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer1.scala +++ /dev/null @@ -1,29 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2009 LAMP/EPFL - * @author Martin Odersky - */ -// $Id: SyntaxAnalyzer.scala 16893 2009-01-13 13:09:22Z cunei $ - -package scala.tools.nsc.ast.parser - -import javac._ - -/** An nsc sub-component. - */ -abstract class SyntaxAnalyzer1 extends SubComponent with Parsers1 with MarkupParsers1 with Scanners1 with JavaParsers with JavaScanners { - - val phaseName = "parser" - - def newPhase(prev: Phase): StdPhase = new ParserPhase(prev) - - class ParserPhase(prev: scala.tools.nsc.Phase) extends StdPhase(prev) { - override val checkable = false - def apply(unit: global.CompilationUnit) { - global.informProgress("parsing " + unit) - unit.body = - if (unit.source.file.name.endsWith(".java")) new JavaUnitParser(unit).parse() - else new UnitParser(unit).parse() - } - } -} - |