1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
/* NSC -- new Scala compiler
* Copyright 2006-2011 LAMP/EPFL
* @author Martin Odersky
*/
// $Id$
package scala.tools.nsc
package util
import java.io.File
import java.net.URL
import java.util.StringTokenizer
import scala.util.Sorting
import scala.collection.mutable.{ ListBuffer, HashSet => MutHashSet }
import scala.tools.nsc.io.AbstractFile
import ch.epfl.lamp.compiler.msil.{ Type => MSILType, Assembly }
import ClassPath.{ ClassPathContext, isTraitImplementation }
/** Keeping the MSIL classpath code in its own file is important to make sure
* we don't accidentally introduce a dependency on msil.jar in the jvm.
*/
object MsilClassPath {
def collectTypes(assemFile: AbstractFile) = {
var res: Array[MSILType] = MSILType.EmptyTypes
val assem = Assembly.LoadFrom(assemFile.path)
if (assem != null) {
// DeclaringType == null: true for non-inner classes
res = assem.GetTypes() filter (_.DeclaringType == null)
Sorting.stableSort(res, (t1: MSILType, t2: MSILType) => (t1.FullName compareTo t2.FullName) < 0)
}
res
}
/** On the java side this logic is in PathResolver, but as I'm not really
* up to folding MSIL into that, I am encapsulating it here.
*/
def fromSettings(settings: Settings): MsilClassPath = {
val context =
if (settings.inline.value) new MsilContext
else new MsilContext { override def isValidName(name: String) = !isTraitImplementation(name) }
import settings._
new MsilClassPath(assemextdirs.value, assemrefs.value, sourcepath.value, context)
}
class MsilContext extends ClassPathContext[MSILType] {
def toBinaryName(rep: MSILType) = rep.Name
def newClassPath(assemFile: AbstractFile) = new AssemblyClassPath(MsilClassPath collectTypes assemFile, "", this)
}
private def assembleEntries(ext: String, user: String, source: String, context: MsilContext): List[ClassPath[MSILType]] = {
import ClassPath._
val etr = new ListBuffer[ClassPath[MSILType]]
val names = new MutHashSet[String]
// 1. Assemblies from -Xassem-extdirs
for (dirName <- expandPath(ext, expandStar = false)) {
val dir = AbstractFile.getDirectory(dirName)
if (dir ne null) {
for (file <- dir) {
val name = file.name.toLowerCase
if (name.endsWith(".dll") || name.endsWith(".exe")) {
names += name
etr += context.newClassPath(file)
}
}
}
}
// 2. Assemblies from -Xassem-path
for (fileName <- expandPath(user, expandStar = false)) {
val file = AbstractFile.getFile(fileName)
if (file ne null) {
val name = file.name.toLowerCase
if (name.endsWith(".dll") || name.endsWith(".exe")) {
names += name
etr += context.newClassPath(file)
}
}
}
def check(n: String) {
if (!names.contains(n))
throw new AssertionError("Cannot find assembly "+ n +
". Use -Xassem-extdirs or -Xassem-path to specify its location")
}
check("mscorlib.dll")
check("scalaruntime.dll")
// 3. Source path
for (dirName <- expandPath(source, expandStar = false)) {
val file = AbstractFile.getDirectory(dirName)
if (file ne null) etr += new SourcePath[MSILType](file, context)
}
etr.toList
}
}
import MsilClassPath._
/**
* A assembly file (dll / exe) containing classes and namespaces
*/
class AssemblyClassPath(types: Array[MSILType], namespace: String, val context: MsilContext) extends ClassPath[MSILType] {
def name = {
val i = namespace.lastIndexOf('.')
if (i < 0) namespace
else namespace drop (i + 1)
}
def asURLs = List(new java.net.URL(name))
def asClasspathString = sys.error("Unknown") // I don't know what if anything makes sense here?
private lazy val first: Int = {
var m = 0
var n = types.length - 1
while (m < n) {
val l = (m + n) / 2
val res = types(l).FullName.compareTo(namespace)
if (res < 0) m = l + 1
else n = l
}
if (types(m).FullName.startsWith(namespace)) m else types.length
}
lazy val classes = {
val cls = new ListBuffer[ClassRep]
var i = first
while (i < types.length && types(i).Namespace.startsWith(namespace)) {
// CLRTypes used to exclude java.lang.Object and java.lang.String (no idea why..)
if (types(i).Namespace == namespace)
cls += ClassRep(Some(types(i)), None)
i += 1
}
cls.toIndexedSeq
}
lazy val packages = {
val nsSet = new MutHashSet[String]
var i = first
while (i < types.length && types(i).Namespace.startsWith(namespace)) {
val subns = types(i).Namespace
if (subns.length > namespace.length) {
// example: namespace = "System", subns = "System.Reflection.Emit"
// => find second "." and "System.Reflection" to nsSet.
val end = subns.indexOf('.', namespace.length + 1)
nsSet += (if (end < 0) subns
else subns.substring(0, end))
}
i += 1
}
val xs = for (ns <- nsSet.toList)
yield new AssemblyClassPath(types, ns, context)
xs.toIndexedSeq
}
val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq()
override def toString() = "assembly classpath "+ namespace
}
/**
* The classpath when compiling with target:msil. Binary files are represented as
* MSILType values.
*/
class MsilClassPath(ext: String, user: String, source: String, context: MsilContext)
extends MergedClassPath[MSILType](MsilClassPath.assembleEntries(ext, user, source, context), context) { }
|