diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/util')
6 files changed, 246 insertions, 120 deletions
diff --git a/src/compiler/scala/tools/nsc/util/CharArrayReader.scala b/src/compiler/scala/tools/nsc/util/CharArrayReader.scala index ba67c6e3ea..4f99ecc221 100644 --- a/src/compiler/scala/tools/nsc/util/CharArrayReader.scala +++ b/src/compiler/scala/tools/nsc/util/CharArrayReader.scala @@ -8,10 +8,10 @@ package scala.tools.nsc.util import scala.tools.nsc.util.SourceFile.{LF, FF, CR, SU} -class CharArrayReader(buf: Array[Char], start: Int, /* startline: Int, startcol: Int, */ - decodeUni: Boolean, error: String => Unit) extends Iterator[Char] { +class CharArrayReader(buf: RandomAccessSeq[Char], start: Int, /* startline: int, startcol: int, */ + decodeUni: Boolean, error: String => unit) extends Iterator[Char] { - def this(buf: Array[Char], decodeUni: Boolean, error: String => Unit) = + def this(buf: RandomAccessSeq[Char], decodeUni: Boolean, error: String => unit) = this(buf, 0, /* 1, 1, */ decodeUni, error) /** layout constant @@ -46,17 +46,21 @@ class CharArrayReader(buf: Array[Char], start: Int, /* startline: Int, startcol: //nextcol = 1 } - def hasNext: Boolean = bp < buf.length + def hasNext: Boolean = if (bp < buf.length) true + else { + assert(true) + false + } def last: Char = if (bp > start + 2) buf(bp - 2) else ' ' // XML literals def next: Char = { //cline = nextline //ccol = nextcol + val buf = this.buf.asInstanceOf[runtime.BoxedCharArray].value if(!hasNext) { - // there is an endless stream of SU's at the end ch = SU - return SU + return SU // there is an endless stream of SU's at the end } oldBp = bp oldCh = ch diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 6ac66ae968..cb67f55c60 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -81,7 +81,9 @@ class ClassPath(onlyPresentation: Boolean) { // assert(location != null, "cannot find classpath location") // assert(location.getFile() != null, "cannot find classpath location " + " " + location + " " + location.getClass()) def source: Source - override def toString() = location.toString() + override def toString() = + (if (location == null) "<none>" else location.toString) + + (if (source == null) "" else " source=" + source) } class Output(location0: AbstractFile, val sourceFile: AbstractFile) extends Entry(location0) { @@ -100,7 +102,7 @@ class ClassPath(onlyPresentation: Boolean) { if (entries.isEmpty) new Context(Nil) else { val ret = find0(entries.tail) - val head = entries.head + val head = entries.head; val name0 = name + (if (!isDir) ".class" else "") val clazz = if (head.location eq null) null else head.location.lookupPath(name0, isDir) @@ -124,7 +126,9 @@ class ClassPath(onlyPresentation: Boolean) { } try { //Console.err.println("this=" + this + "\nclazz=" + clazz + "\nsource0=" + source0 + "\n") - new Context(entry :: ret.entries) + + if (!isDir) new Context(entry :: Nil) + else new Context(entry :: ret.entries) } catch { case e: Error => throw e @@ -192,7 +196,7 @@ class ClassPath(onlyPresentation: Boolean) { val sourcePath0 = sourcePath if (sourcePath0 ne null) { if (!sourcePath0.isDirectory) { - Console.err.println(""+sourcePath0 + " cannot be a directory") + Console.err.println(""+sourcePath0 + " should be a directory") assert(false) } } @@ -248,15 +252,35 @@ class ClassPath(onlyPresentation: Boolean) { } /** - * @param classes ... - * @param sources ... + * @param classes where the class files come from and are written to + * @param sources where the source files come from + */ + def output(classes : String, sources : String) = { + assert(classes ne null) + assert(sources ne null) + val location = AbstractFile.getDirectory(classes) + val sources0 = AbstractFile.getDirectory(sources) + class Output0 extends Output(location, sources0) + entries += new Output0() + } + /** + * @param classes where the class files come from + * @param sources optional source file attachment, otherwise null */ def library(classes: String, sources: String) { assert(classes ne null) val location = AbstractFile.getDirectory(classes) - val sourceFile0 = + var sourceFile0 = if (sources ne null) AbstractFile.getDirectory(sources) else null + if (sourceFile0 ne null) { + val file00 = sourceFile0.lookupPath("src", true) + if ((file00 ne null) && file00.isDirectory) { + assert(true) + sourceFile0 = file00 + } + } + class Library0 extends Library(location) { override def sourceFile = sourceFile0 } diff --git a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala index d3e79969af..a4c257a996 100644 --- a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala +++ b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala @@ -8,7 +8,13 @@ package scala.tools.nsc.util import scala.collection.mutable.HashMap -class FreshNameCreator { +trait FreshNameCreator { + def newName(prefix : String) : String + def newName() : String + def newName(pos : util.Position, prefix : String) : String +} +object FreshNameCreator { + class Default extends FreshNameCreator { protected var counter = 0 protected val counters = new HashMap[String, Int] @@ -26,9 +32,11 @@ class FreshNameCreator { counters.update(prefix, count) prefix + count } + def newName(pos : util.Position, prefix : String) = newName(prefix) def newName(): String = { counter = counter + 1 "$" + counter + "$" } } +}
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/util/NewCharArrayReader.scala b/src/compiler/scala/tools/nsc/util/NewCharArrayReader.scala new file mode 100644 index 0000000000..3f889587ed --- /dev/null +++ b/src/compiler/scala/tools/nsc/util/NewCharArrayReader.scala @@ -0,0 +1,74 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2006 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: CharArrayReader.scala 11142 2007-05-22 10:23:00Z mcdirmid $ + +package scala.tools.nsc.util + +import scala.tools.nsc.util.SourceFile.{LF, FF, CR, SU} + +class NewCharArrayReader(val buf: RandomAccessSeq[Char], // should not change + decodeUni: Boolean, error: (Int,String) => unit) extends Iterator[Char] { + private var idx : Int = 0 + private var isUnicode0 = false + def isUnicode = isUnicode0 + + private val bufLength = buf.length + def seek(offset : Int) = { + assert(offset <= bufLength) + idx = offset + } + def offset = idx + def withOffset = new Iterator[(Int,Char)] { + def hasNext = NewCharArrayReader.this.hasNext + def next = (offset, NewCharArrayReader.this.next) + } + override def hasNext = { // could be padded + if (idx == bufLength - 1) buf(idx) != SU + else idx < bufLength + } + override def next : Char = { + isUnicode0 = false + if (!hasNext) return SU + var ch = buf(idx) + idx = idx + 1 + ch match { + case CR if buf.safeIs(idx + 1, LF) => + idx += 1; ch = LF + case LF | FF => + case '\\' => + def evenSlashPrefix: Boolean = { + var p = idx - 2 + while (p >= 0 && buf(p) == '\\') p = p - 1; + (idx - p) % 2 == 0 + } + def udigit: Int = { + val d = digit2int(buf(idx), 16) + if (d >= 0) { idx = idx + 1 } + else if (error != null) error(idx, "error in unicode escape"); + d + } + if (idx < bufLength && buf(idx) == 'u' && decodeUni && evenSlashPrefix) { + do { + idx = idx + 1; // nextcol = nextcol + 1; + } while (idx < bufLength && buf(idx) == 'u'); + val code = udigit << 12 | udigit << 8 | udigit << 4 | udigit + isUnicode0 = true + ch = code.asInstanceOf[Char] + } + case _ => + } + ch + } + 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 + } +} diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala index 144809ff6a..ae4cd55086 100644 --- a/src/compiler/scala/tools/nsc/util/Position.scala +++ b/src/compiler/scala/tools/nsc/util/Position.scala @@ -8,14 +8,19 @@ // $Id$ package scala.tools.nsc.util - +object Position { + // a static field + private val tabInc = 8 +} trait Position { + import Position.tabInc def offset : Option[Int] = None - private val tabInc = 8 + def source : Option[SourceFile] = None + def line : Option[Int] = - if (source.isEmpty || offset.isEmpty) None else Some(source.get.offsetToLine(offset.get) + 1) + if (offset.isEmpty || source.isEmpty) None else Some(source.get.offsetToLine(offset.get) + 1) def column : Option[Int] = { - if (source.isEmpty || offset.isEmpty) return None + if (offset.isEmpty || source.isEmpty) return None var column = 1 // find beginning offset for line val line = source.get.offsetToLine(offset.get) @@ -23,33 +28,39 @@ trait Position { var continue = true while (continue) { if (coffset == offset.get(-1)) continue = false - else if (source.get.content(coffset) == '\t') column = ((column - 1) / tabInc * tabInc) + tabInc + 1 + else if (source.get.asInstanceOf[BatchSourceFile].content(coffset) == '\t') + column = ((column - 1) / tabInc * tabInc) + tabInc + 1 else column = column + 1 coffset = coffset + 1 } Some(column) } - def source : Option[SourceFile] = None - def lineContent: String = - if (!line.isEmpty && !source.isEmpty) source.get.lineToString(line.get - 1) + def lineContent: String = { + val line = this.line + if (!line.isEmpty) source.get.lineToString(line.get - 1) else "NO_LINE" + } + + /** Map this position to a position in an original source * file. If the SourceFile is a normal SourceFile, simply * return this. */ - def inUltimateSource = if (!source.isEmpty) source.get.positionInUltimateSource(this) - else this + def inUltimateSource(source : SourceFile) = + if (source == null) this else source.positionInUltimateSource(this) def dbgString = { (if (source.isEmpty) "" else "source-" + source.get.path) + (if (line.isEmpty) "" else "line-" + line.get) + - (if (offset.isEmpty || source.isEmpty) "" - else if (offset.get >= source.get.content.length) "out-of-bounds-" + offset.get + (if (offset.isEmpty) "" + else if (offset.get >= source.get.length) "out-of-bounds-" + offset.get else { val ret = "offset=" + offset.get; var add = ""; - while (offset.get + add.length < source.get.content.length && + /* + while (offset.get + add.length < source.get.length && add.length < 10) add = add + source.get.content(offset.get + add.length()); + */ ret + " c[0..9]=\"" + add + "\""; }) } @@ -59,14 +70,14 @@ trait Position { object NoPosition extends Position; case class FakePos(msg : String) extends Position; -case class LinePosition(line0 : Int, override val source : Option[SourceFile]) extends Position { - def this(line0 : Int) = this(line0, None) +case class LinePosition(source0 : SourceFile, line0 : Int) extends Position { assert(line0 >= 1) override def offset = None override def column = None override def line = Some(line0) + override def source = Some(source0) } case class OffsetPosition(source0 : SourceFile, offset0 : Int) extends Position { override def source = Some(source0) override def offset = Some(offset0) -}
\ No newline at end of file +} diff --git a/src/compiler/scala/tools/nsc/util/SourceFile.scala b/src/compiler/scala/tools/nsc/util/SourceFile.scala index f810fe96f0..4f4694b6b7 100644 --- a/src/compiler/scala/tools/nsc/util/SourceFile.scala +++ b/src/compiler/scala/tools/nsc/util/SourceFile.scala @@ -6,72 +6,115 @@ // $Id$ package scala.tools.nsc.util - import scala.tools.nsc.io.{AbstractFile, VirtualFile} -/** Uses positions that are offsets rather than line/column pairs. - * - */ object SourceFile { val LF: Char = 0x0A val FF: Char = 0x0C val CR: Char = 0x0D val SU: Char = 0x1A - def isLineBreak(c: Char) = c == LF || c == FF || c == CR || c == SU + def isLineBreak(c: Int) = c match { + case LF|FF|CR|SU => true + case _ => false + } } - -/** Uses positions that are offsets rather than line/column pairs. - * - * @author Sean McDirmid - * @version 1.0 - */ -class SourceFile(val file: AbstractFile, _content: Array[Char]) { +/** abstract base class of a source file used in the compiler */ +abstract class SourceFile { import SourceFile._ + //def content : Seq[Char] // normalized, must end in SU + def file : AbstractFile + def isLineBreak(idx : Int) : Boolean + def length : Int + def position(offset: Int) : Position = { + assert(offset < length) + new OffsetPosition(this, offset) + } + def position(line: Int, column: Int) : Position = new OffsetPosition(this, lineToOffset(line) + column) + def offsetToLine(offset: Int): Int + def lineToOffset(index : Int): Int + /** Map a position to a position in the underlying source file. + * For regular source files, simply return the argument. + */ + def positionInUltimateSource(position: Position) = position + override def toString(): String = file.name /* + ":" + content.length */ + def dbg(offset: Int) = (new OffsetPosition(this, offset)).dbgString + def path = file.path - def this(_file: AbstractFile) = this(_file, _file.toCharArray) + def beginsWith(offset: Int, text: String): Boolean + def skipWhitespace(offset: Int): Int + def lineToString(index: Int): String + + def identifier(pos : Position, compiler : scala.tools.nsc.Global) : Option[String] = None +} +/** a file whose contents do not change over time */ +class BatchSourceFile(val file : AbstractFile, _content : Array[Char]) extends SourceFile { + import SourceFile._ + def this(_file: AbstractFile) = this(_file, _file.toCharArray) def this(sourceName: String, content: Array[Char]) = this(new VirtualFile(sourceName), content) + override def equals(that : Any) = that match { + case that : BatchSourceFile => file == that.file + case _ => false + } + override def hashCode = file.hashCode + + val content = _content // don't sweat it... + override val length = content.length + override def identifier(pos : Position, compiler : scala.tools.nsc.Global) = pos match { + case OffsetPosition(source,offset) if source == this => + import java.lang.Character + var i = offset + 1 + while (i < content.length && + (compiler.syntaxAnalyzer.isOperatorPart(content(i)) || + compiler.syntaxAnalyzer.isIdentifierPart(content(i)))) i = i + 1 + + assert(i > offset) + Some(new String(content, offset, i - offset)) + case _ => super.identifier(pos, compiler) + } - val content = normalize(_content) - - def getContent() = content - def getFile() = file def isLineBreak(idx: Int) = - if (!SourceFile.isLineBreak(content(idx))) false - else if (content(idx) == CR && idx + 1 < content.length && content(idx + 1) == LF) false + if (idx >= content.length) false + else if (!SourceFile.isLineBreak(content(idx))) false + else if (content(idx) == CR && content(idx + 1) == LF) false else true - def position(offset: Int) = new OffsetPosition(this, offset) - def position(line: Int, column: Int) = new OffsetPosition(this, lineToOffset(line) + column) - - /** Map a position to a position in the underlying source file. - * For regular source files, simply return the argument. - */ - def positionInUltimateSource(position: Position) = position - - // constants - - // NOTE: all indexes are based on zero!!!! - override def toString(): String = file.name /* + ":" + content.length */ - - def dbg(offset: Int) = (new OffsetPosition(this, offset)).dbgString + def beginsWith(offset: Int, text: String): Boolean = { + var idx = 0 + while (idx < text.length()) { + if (offset + idx >= content.length) return false + if (content(offset + idx) != text.charAt(idx)) return false + idx += 1 + } + return true + } + def skipWhitespace(offset: Int): Int = + if (content(offset).isWhitespace) skipWhitespace(offset + 1) + else offset + def lineToString(index: Int): String = { + var offset = lineToOffset(index) + val buf = new StringBuilder() + while (!isLineBreak(offset) && offset < content.length) { + buf.append(content(offset)) + offset += 1 + } + buf.toString() + } object line { var index = 0 var offset = 0 def find(toFind: Int, isIndex: Boolean): Int = { if (toFind == 0) return 0 - - //if (!isIndex) assert(toFind != -1) - //if ( isIndex) assert(toFind > 0) - - if (!isIndex && (toFind >= content.length)) + if (!isIndex && (toFind >= content.length)) { + assert(true) throw new Error(toFind + " not valid offset in " + file.name + ":" + content.length) + } def get(isIndex : Boolean) = if (isIndex) index else offset @@ -79,11 +122,7 @@ class SourceFile(val file: AbstractFile, _content: Array[Char]) { val increment = if (isBackward) -1 else + 1 val oneIfBackward = if (isBackward) +1 else 0 - // System.err.println("FIND-0: " + toFind + " " + isIndex); - while (true) { - // System.err.println("FIND-1: " + offset + " " + index); - if (!isIndex && offset == toFind) return index; if (isBackward && offset <= 0) throw new Error(offset + " " + index + " " + toFind + " " + isIndex); @@ -102,52 +141,19 @@ class SourceFile(val file: AbstractFile, _content: Array[Char]) { def offsetToLine(offset: Int): Int = line.find(offset, false) def lineToOffset(index : Int): Int = line.find(index , true) - def beginsWith(offset: Int, text: String): Boolean = { - var idx = 0 - while (idx < text.length()) { - if (offset + idx >= content.length) return false - if (content(offset + idx) != text.charAt(idx)) return false - idx += 1 - } - return true - } - def path = getFile().path +} - def skipWhitespace(offset: Int): Int = - if (content(offset).isWhitespace) skipWhitespace(offset + 1) - else offset - def lineToString(index: Int): String = { - var offset = lineToOffset(index) - val buf = new StringBuilder() - while (!isLineBreak(offset) && offset < content.length) { - buf.append(content(offset)) - offset += 1 - } - buf.toString() - } - - private def normalize(input : Array[Char]): Array[Char] = - if (input.length > 0 && input(input.length - 1) == SU) - input - else { - val content = new Array[Char](input.length + 1) - Array.copy(input, 0, content, 0, input.length) - content(input.length) = SU - content - } -} /** A source file composed of multiple other source files. * - * @author Sean McDirmid * @version 1.0 */ class CompoundSourceFile( name: String, - components: List[SourceFile], + components: List[BatchSourceFile], contents: Array[Char]) -extends SourceFile(name, contents) +extends BatchSourceFile(name, contents) { /** The usual constructor. Specify a name for the compound file and * a list of component sources. @@ -155,18 +161,18 @@ extends SourceFile(name, contents) * @param name ... * @param components ... */ - def this(name: String, components: SourceFile*) = { + def this(name: String, components: BatchSourceFile*) = { /* Note that the contents leaves off the final SU character * of all components */ this( name, components.toList, Array.concat(components.toList.map(comp => - comp.content.subArray(0, comp.content.length-1)):_*)) + comp.content.slice(0, comp.content.length-1).toArray):_*)) } /** Create an instance with the specified components and a generic name. */ - def this(components: SourceFile*) = + def this(components: BatchSourceFile*) = this("(virtual file)", components.toList:_*) override def positionInUltimateSource(position: Position) = { @@ -178,7 +184,7 @@ extends SourceFile(name, contents) off = off - compsLeft.head.content.length + 1 compsLeft = compsLeft.tail } - compsLeft.head.positionInUltimateSource(new OffsetPosition(compsLeft.head, off)) + compsLeft.head.positionInUltimateSource(new OffsetPosition(this, off)) } } } @@ -190,21 +196,20 @@ extends SourceFile(name, contents) */ class SourceFileFragment( name: String, - underlyingFile: SourceFile, + underlyingFile: BatchSourceFile, start: Int, stop: Int, contents: Array[Char]) -extends SourceFile(name, contents) -{ - def this(name: String, underlyingFile: SourceFile, start: Int, stop: Int) = +extends BatchSourceFile(name, contents) { + def this(name: String, underlyingFile: BatchSourceFile, start: Int, stop: Int) = this( name, underlyingFile, start, stop, - underlyingFile.content.subArray(start, stop)) + underlyingFile.content.slice(start, stop).toArray) - def this(underlyingFile: SourceFile, start: Int, stop: Int) = + def this(underlyingFile: BatchSourceFile, start: Int, stop: Int) = this( "(fragment of " + underlyingFile.file.name + ")", underlyingFile, @@ -214,7 +219,7 @@ extends SourceFile(name, contents) override def positionInUltimateSource(position: Position) = { if (position.offset.isEmpty) super.positionInUltimateSource(position) - else underlyingFile.positionInUltimateSource( - new OffsetPosition(underlyingFile, position.offset.get + start)) + else positionInUltimateSource( + new OffsetPosition(this, position.offset.get + start)) } } |