summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorMiles Sabin <miles@milessabin.com>2009-05-18 10:54:00 +0000
committerMiles Sabin <miles@milessabin.com>2009-05-18 10:54:00 +0000
commit8fb4f2c37d579545674fc9d1fe3f66c80880dcbf (patch)
tree8ab19cb948b6968a7adff2862050784cc8915c99 /src/compiler/scala/tools
parentb2e928c6d1f67230f18a33aad295fe67de9f6cd7 (diff)
downloadscala-8fb4f2c37d579545674fc9d1fe3f66c80880dcbf.tar.gz
scala-8fb4f2c37d579545674fc9d1fe3f66c80880dcbf.tar.bz2
scala-8fb4f2c37d579545674fc9d1fe3f66c80880dcbf.zip
Switch over to new scanner/parser.
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala94
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/MarkupParsers1.scala705
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/NewScanners.scala922
-rwxr-xr-x[-rw-r--r--]src/compiler/scala/tools/nsc/ast/parser/Parsers.scala62
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/Parsers1.scala2607
-rwxr-xr-x[-rw-r--r--]src/compiler/scala/tools/nsc/ast/parser/Scanners.scala1364
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/Scanners1.scala971
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder1.scala368
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer1.scala29
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 == '&amp;'
- */
- def content_AMP(ts: mutable.ArrayBuffer[Tree]) {
- nextch
- ch match {
- case '#' => // CharacterRef
- nextch
- val theChar = handle.text(tmppos, xCharRef)
- xToken(';')
- ts.append(theChar)
- case _ => // EntityRef
- val n = xName
- xToken(';')
- ts.append(handle.entityRef(tmppos, n))
- }
- }
-
- /**
- * @precond ch == '{'
- * @postcond: xEmbeddedBlock == false!
- */
- def content_BRACE(p: Position, ts:mutable.ArrayBuffer[Tree]) {
- if (xCheckEmbeddedBlock)
- ts.append(xEmbeddedExpr)
- else {
- appendText(p, ts, xText)/*
- val str = new StringBuilder("{")
- str.append(xText)
- nextch
- appendText(p, ts, str.toString())*/
- }
- }
-
- /** Returns true if it encounters an end tag (without consuming it),
- * appends trees to ts as side-effect.
- *
- * @param ts ...
- * @return ...
- */
- private def content_LT(ts: mutable.ArrayBuffer[Tree]): Boolean = {
- ch match {
- case '/' =>
- return true // end tag
- case '!' =>
- nextch // CDATA or Comment
- ts.append(if ('[' == ch) xCharData else xComment)
- case '?' => // PI
- nextch
- ts.append(xProcInstr)
- case _ =>
- ts.append(element) // child node
- }
- false
- }
-
- /*[Duplicate]*/ def content: mutable.Buffer[Tree] = {
- var ts = new mutable.ArrayBuffer[Tree]
- var exit = false
- while (!exit) {
- if (xEmbeddedBlock)
- ts.append(xEmbeddedExpr)
- 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()
- }
- }
-}
-