From bbc84eabcd244179299ad435b6e9d7473e5ff892 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Mar 2017 19:18:20 +0100 Subject: Implement startsWith/encode/decode for derived names. --- compiler/src/dotty/tools/dotc/core/NameInfos.scala | 4 ++- compiler/src/dotty/tools/dotc/core/Names.scala | 39 +++++++++++++++------- compiler/src/dotty/tools/dotc/core/StdNames.scala | 2 +- .../src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- .../dotty/tools/dotc/util/NameTransformer.scala | 5 ++- 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameInfos.scala b/compiler/src/dotty/tools/dotc/core/NameInfos.scala index 650a0c0a4..031ca8f6e 100644 --- a/compiler/src/dotty/tools/dotc/core/NameInfos.scala +++ b/compiler/src/dotty/tools/dotc/core/NameInfos.scala @@ -9,6 +9,7 @@ import Names._ abstract class NameInfo extends util.DotClass { def kind: NameInfo.Kind def mkString(underlying: TermName): String + def map(f: SimpleTermName => SimpleTermName): NameInfo = this def contains(ch: Char): Boolean = false def ++(other: String): NameInfo = unsupported("++") } @@ -29,9 +30,10 @@ object NameInfo { def mkString(underlying: TermName) = underlying.toString // will cause an unsupported exception } - case class Qualified(name: TermName, separator: String) extends NameInfo { + case class Qualified(name: SimpleTermName, separator: String) extends NameInfo { def kind = QualifiedKind def mkString(underlying: TermName) = s"$underlying$separator$name" + override def map(f: SimpleTermName => SimpleTermName): NameInfo = Qualified(f(name), separator) override def contains(ch: Char): Boolean = name.contains(ch) override def ++(other: String): NameInfo = Qualified(name ++ other, separator) override def toString = s"Qualified($name, $separator)" diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 9ec9e73f2..e9dbd7f7c 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -75,13 +75,10 @@ object Names { def toText(printer: Printer): Text = printer.toText(this) /** Replace \$op_name's by corresponding operator symbols. */ - def decode: Name = - if (contains('$')) fromName(termName(NameTransformer.decode(toString))) - else this + def decode: Name /** Replace operator symbols by corresponding \$op_name's. */ - def encode: Name = - if (dontEncode(toTermName)) this else NameTransformer.encode(this) + def encode: Name /** A more efficient version of concatenation */ def ++ (other: Name): ThisName = ++ (other.toString) @@ -89,7 +86,8 @@ object Names { def replace(from: Char, to: Char): ThisName = fromName(toSimpleName.replace(from, to)) - def contains(ch: Char): Boolean + def startsWith(str: String): Boolean + def startsWith(name: Name): Boolean = startsWith(name.toString) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] } @@ -187,14 +185,20 @@ object Names { def apply(n: Int) = chrs(start + n) - def ++ (other: String): ThisName = termName(toString + other) + def ++ (other: String): SimpleTermName = termName(toString + other) - def contains(ch: Char): Boolean = { + private def contains(ch: Char): Boolean = { var i = 0 while (i < length && chrs(start + i) != ch) i += 1 i < length } + def startsWith(str: String): Boolean = { + var i = 0 + while (i < str.length && i < length && apply(i) == str(i)) i += 1 + i == str.length + } + override def replace(from: Char, to: Char): ThisName = { val cs = new Array[Char](length) Array.copy(chrs, start, cs, 0, length) @@ -204,6 +208,13 @@ object Names { fromName(termName(cs, 0, length)) } + def encode: SimpleTermName = + if (dontEncode(toTermName)) this else NameTransformer.encode(this) + + /** Replace \$op_name's by corresponding operator symbols. */ + def decode: SimpleTermName = + if (contains('$')) termName(NameTransformer.decode(toString)) else this + override def hashCode: Int = start override def toString = @@ -218,7 +229,10 @@ object Names { def ++ (other: String): ThisName = toTermName.++(other).toTypeName - def contains(ch: Char): Boolean = toTermName.contains(ch) + def startsWith(str: String): Boolean = toTermName.startsWith(str) + + def encode: Name = toTermName.encode + def decode: Name = toTermName.decode type ThisName = TypeName def isTypeName = true @@ -243,7 +257,9 @@ object Names { class DerivedTermName(override val underlying: TermName, override val info: NameInfo) extends TermName { def ++ (other: String): ThisName = derived(info ++ other) - def contains(ch: Char): Boolean = underlying.contains(ch) || info.contains(ch) + def startsWith(str: String): Boolean = underlying.startsWith(str) + def encode: Name = underlying.encode.derived(info.map(_.encode)) + def decode: Name = underlying.decode.derived(info.map(_.decode)) override def toString = info.mkString(underlying) override def debugString = s"${underlying.debugString}[$info]" } @@ -388,7 +404,7 @@ object Names { val STATIC_CONSTRUCTOR: TermName = termName("") val EMPTY_PACKAGE: TermName = termName("") - val dontEncode = Set[TermName](CONSTRUCTOR, EMPTY_PACKAGE) + val dontEncode = Set(CONSTRUCTOR, EMPTY_PACKAGE) def termNameBuilder: Builder[Char, TermName] = StringBuilder.newBuilder.mapResult(termName) @@ -404,7 +420,6 @@ object Names { def seq: WrappedString = new WrappedString(name.toString) override protected[this] def thisCollection: WrappedString = seq - def startsWith(name: Name): Boolean = startsWith(name.toString) def endsWith(name: Name): Boolean = endsWith(name.toString) def indexOfSlice(name: Name): Int = indexOfSlice(name.toString) def lastIndexOfSlice(name: Name): Int = lastIndexOfSlice(name.toString) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index e7928fd09..56f8ca189 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -92,7 +92,7 @@ object StdNames { val BITMAP_CHECKINIT: N = BITMAP_PREFIX + "init$" // initialization bitmap for checkinit values val BITMAP_CHECKINIT_TRANSIENT: N = BITMAP_PREFIX + "inittrans$" // initialization bitmap for transient checkinit values val DEFAULT_GETTER: N = "$default$" - val DEFAULT_GETTER_INIT: N = NameTransformer.encode("") + val DEFAULT_GETTER_INIT: N = "$lessinit$greater" val DO_WHILE_PREFIX: N = "doWhile$" val EMPTY: N = "" val EMPTY_PACKAGE: N = Names.EMPTY_PACKAGE.toString diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 0483e0ca1..070fdf345 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -415,7 +415,7 @@ object SymDenotations { if (sep == "$") // duplicate scalac's behavior: don't write a double '$$' for module class members. prefix = prefix.without(NameInfo.ModuleClassKind) - prefix.derived(NameInfo.Qualified(name.toTermName, sep)) + prefix.derived(NameInfo.Qualified(name.toSimpleName, sep)) } else { if (owner.is(ModuleClass, butNot = Package) && sep == "$") diff --git a/compiler/src/dotty/tools/dotc/util/NameTransformer.scala b/compiler/src/dotty/tools/dotc/util/NameTransformer.scala index 330d513fe..52f8e6ec0 100644 --- a/compiler/src/dotty/tools/dotc/util/NameTransformer.scala +++ b/compiler/src/dotty/tools/dotc/util/NameTransformer.scala @@ -60,7 +60,7 @@ object NameTransformer { * @param name the string to encode * @return the string with all recognized opchars replaced with their encoding */ - def encode[N <: Name](name: N): N = { + def encode(name: SimpleTermName): SimpleTermName = { var buf: StringBuilder = null val len = name.length var i = 0 @@ -87,8 +87,7 @@ object NameTransformer { i += 1 } if (buf eq null) name - else if (name.isTermName) buf.toString.toTermName.asInstanceOf[N] - else buf.toString.toTypeName.asInstanceOf[N] + else termName(buf.toString) } /** Replace `\$opname` by corresponding operator symbol. -- cgit v1.2.3