Skip to content

Commit 50f07d5

Browse files
committed
import Scala.scala from original implementation of semanticdb
1 parent 7b8ffd7 commit 50f07d5

File tree

2 files changed

+339
-27
lines changed

2 files changed

+339
-27
lines changed
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
package dotty.semanticdb
2+
3+
import scala.compat.Platform.EOL
4+
import dotty.semanticdb.Scala.{Descriptor => d}
5+
import dotty.semanticdb.Scala.{Names => n}
6+
7+
object Scala {
8+
object Symbols {
9+
val None: String = ""
10+
val RootPackage: String = "_root_/"
11+
val EmptyPackage: String = "_empty_/"
12+
def Global(owner: String, desc: Descriptor): String =
13+
if (owner != RootPackage) owner + desc.toString
14+
else desc.toString
15+
def Local(suffix: String): String = {
16+
if (suffix.indexOf("/") == -1 && suffix.indexOf(";") == -1) "local" + suffix
17+
else throw new IllegalArgumentException(suffix)
18+
}
19+
def Multi(symbols: List[String]): String = {
20+
symbols.distinct match {
21+
case List(symbol) =>
22+
symbol
23+
case symbols =>
24+
val sb = new StringBuilder
25+
symbols.foreach { symbol =>
26+
if (!symbol.isMulti) {
27+
sb.append(';')
28+
}
29+
sb.append(symbol)
30+
}
31+
sb.toString()
32+
}
33+
}
34+
}
35+
36+
implicit class ScalaSymbolOps(symbol: String) {
37+
def isNone: Boolean =
38+
symbol == Symbols.None
39+
def isRootPackage: Boolean =
40+
symbol == Symbols.RootPackage
41+
def isEmptyPackage: Boolean =
42+
symbol == Symbols.EmptyPackage
43+
def isGlobal: Boolean =
44+
!isNone && !isMulti && (symbol.last match {
45+
case '.' | '#' | '/' | ')' | ']' => true
46+
case _ => false
47+
})
48+
def isLocal: Boolean =
49+
symbol.startsWith("local")
50+
def isMulti: Boolean =
51+
symbol.startsWith(";")
52+
def asMulti: List[String] = {
53+
if (!isMulti) symbol :: Nil
54+
else {
55+
val buf = List.newBuilder[String]
56+
def loop(begin: Int, i: Int): Unit =
57+
if (i >= symbol.length) {
58+
buf += symbol.substring(begin, symbol.length)
59+
} else {
60+
symbol.charAt(i) match {
61+
case ';' =>
62+
buf += symbol.substring(begin, i)
63+
loop(i + 1, i + 1)
64+
case '`' =>
65+
var j = i + 1
66+
while (symbol.charAt(j) != '`') j += 1
67+
loop(begin, j + 1)
68+
case _ =>
69+
loop(begin, i + 1)
70+
}
71+
}
72+
loop(1, 1)
73+
buf.result()
74+
}
75+
}
76+
def isTerm: Boolean =
77+
!isNone && !isMulti && symbol.last == '.'
78+
def isType: Boolean =
79+
!isNone && !isMulti && symbol.last == '#'
80+
def isPackage: Boolean =
81+
!isNone && !isMulti && symbol.last == '/'
82+
def isParameter: Boolean =
83+
!isNone && !isMulti && symbol.last == ')'
84+
def isTypeParameter: Boolean =
85+
!isNone && !isMulti && symbol.last == ']'
86+
def ownerChain: List[String] = {
87+
val buf = List.newBuilder[String]
88+
def loop(symbol: String): Unit = {
89+
if (!symbol.isNone) {
90+
loop(symbol.owner)
91+
buf += symbol
92+
}
93+
}
94+
loop(symbol)
95+
buf.result
96+
}
97+
def owner: String = {
98+
if (isGlobal) {
99+
if (isRootPackage) Symbols.None
100+
else {
101+
val rest = DescriptorParser(symbol)._2
102+
if (rest.nonEmpty) rest
103+
else Symbols.RootPackage
104+
}
105+
} else {
106+
Symbols.None
107+
}
108+
}
109+
def desc: Descriptor = {
110+
if (isGlobal) {
111+
DescriptorParser(symbol)._1
112+
} else {
113+
d.None
114+
}
115+
}
116+
}
117+
118+
sealed trait Descriptor {
119+
def isNone: Boolean = this == d.None
120+
def isTerm: Boolean = this.isInstanceOf[d.Term]
121+
def isMethod: Boolean = this.isInstanceOf[d.Method]
122+
def isType: Boolean = this.isInstanceOf[d.Type]
123+
def isPackage: Boolean = this.isInstanceOf[d.Package]
124+
def isParameter: Boolean = this.isInstanceOf[d.Parameter]
125+
def isTypeParameter: Boolean = this.isInstanceOf[d.TypeParameter]
126+
def value: String
127+
def name: n.Name = {
128+
this match {
129+
case d.None => n.TermName(value)
130+
case d.Term(value) => n.TermName(value)
131+
case d.Method(value, disambiguator) => n.TermName(value)
132+
case d.Type(value) => n.TypeName(value)
133+
case d.Package(value) => n.TermName(value)
134+
case d.Parameter(value) => n.TermName(value)
135+
case d.TypeParameter(value) => n.TypeName(value)
136+
}
137+
}
138+
override def toString: String = {
139+
this match {
140+
case d.None => sys.error("unsupported descriptor")
141+
case d.Term(value) => s"${n.encode(value)}."
142+
case d.Method(value, disambiguator) => s"${n.encode(value)}${disambiguator}."
143+
case d.Type(value) => s"${n.encode(value)}#"
144+
case d.Package(value) => s"${n.encode(value)}/"
145+
case d.Parameter(value) => s"(${n.encode(value)})"
146+
case d.TypeParameter(value) => s"[${n.encode(value)}]"
147+
}
148+
}
149+
}
150+
object Descriptor {
151+
final case object None extends Descriptor { def value: String = "" }
152+
final case class Term(value: String) extends Descriptor
153+
final case class Method(value: String, disambiguator: String) extends Descriptor
154+
final case class Type(value: String) extends Descriptor
155+
final case class Package(value: String) extends Descriptor
156+
final case class Parameter(value: String) extends Descriptor
157+
final case class TypeParameter(value: String) extends Descriptor
158+
}
159+
160+
object Names {
161+
// NOTE: This trait is defined inside Names to support the idiom of importing
162+
// scala.meta.internal.semanticdb.Scala._ and not being afraid of name conflicts.
163+
sealed trait Name {
164+
def value: String
165+
override def toString: String = value
166+
}
167+
final case class TermName(value: String) extends Name
168+
final case class TypeName(value: String) extends Name
169+
170+
val RootPackage: TermName = TermName("_root_")
171+
val EmptyPackage: TermName = TermName("_empty_")
172+
val PackageObject: TermName = TermName("package")
173+
val Constructor: TermName = TermName("<init>")
174+
175+
private[semanticdb] def encode(value: String): String = {
176+
if (value == "") {
177+
"``"
178+
} else {
179+
val (start, parts) = (value.head, value.tail)
180+
val isStartOk = Character.isJavaIdentifierStart(start)
181+
val isPartsOk = parts.forall(Character.isJavaIdentifierPart)
182+
if (isStartOk && isPartsOk) value
183+
else "`" + value + "`"
184+
}
185+
}
186+
}
187+
188+
object DisplayNames {
189+
val RootPackage: String = "_root_"
190+
val EmptyPackage: String = "_empty_"
191+
val Constructor: String = "<init>"
192+
val Anonymous: String = "_"
193+
}
194+
195+
private class DescriptorParser(s: String) {
196+
var i = s.length
197+
def fail() = {
198+
val message = "invalid symbol format"
199+
val caret = " " * i + "^"
200+
sys.error(s"$message$EOL$s$EOL$caret")
201+
}
202+
203+
val BOF = '\u0000'
204+
val EOF = '\u001A'
205+
var currChar = EOF
206+
def readChar(): Char = {
207+
if (i <= 0) {
208+
if (i == 0) {
209+
i -= 1
210+
currChar = BOF
211+
currChar
212+
} else {
213+
fail()
214+
}
215+
} else {
216+
i -= 1
217+
currChar = s(i)
218+
currChar
219+
}
220+
}
221+
222+
def parseValue(): String = {
223+
if (currChar == '`') {
224+
val end = i
225+
while (readChar() != '`') {}
226+
readChar()
227+
s.substring(i + 2, end)
228+
} else {
229+
val end = i + 1
230+
if (!Character.isJavaIdentifierPart(currChar)) fail()
231+
while (Character.isJavaIdentifierPart(readChar()) && currChar != BOF) {}
232+
s.substring(i + 1, end)
233+
}
234+
}
235+
236+
def parseDisambiguator(): String = {
237+
val end = i + 1
238+
if (currChar != ')') fail()
239+
while (readChar() != '(') {}
240+
readChar()
241+
s.substring(i + 1, end)
242+
}
243+
244+
def parseDescriptor(): Descriptor = {
245+
if (currChar == '.') {
246+
readChar()
247+
if (currChar == ')') {
248+
val disambiguator = parseDisambiguator()
249+
val value = parseValue()
250+
d.Method(value, disambiguator)
251+
} else {
252+
d.Term(parseValue())
253+
}
254+
} else if (currChar == '#') {
255+
readChar()
256+
d.Type(parseValue())
257+
} else if (currChar == '/') {
258+
readChar()
259+
d.Package(parseValue())
260+
} else if (currChar == ')') {
261+
readChar()
262+
val value = parseValue()
263+
if (currChar != '(') fail()
264+
else readChar()
265+
d.Parameter(value)
266+
} else if (currChar == ']') {
267+
readChar()
268+
val value = parseValue()
269+
if (currChar != '[') fail()
270+
else readChar()
271+
d.TypeParameter(value)
272+
} else {
273+
fail()
274+
}
275+
}
276+
277+
def entryPoint(): (Descriptor, String) = {
278+
readChar()
279+
val desc = parseDescriptor()
280+
(desc, s.substring(0, i + 1))
281+
}
282+
}
283+
284+
private[semanticdb] object DescriptorParser {
285+
def apply(symbol: String): (Descriptor, String) = {
286+
val parser = new DescriptorParser(symbol)
287+
parser.entryPoint()
288+
}
289+
}
290+
}

0 commit comments

Comments
 (0)