Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 72 additions & 11 deletions cli/src/main/scala/scala/scalanative/cli/ScalaNativeP.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import scala.scalanative.cli.options._
import scala.scalanative.nir.Global
import scala.scalanative.build.Config
import scala.scalanative.linker.ClassLoader
import java.nio.file.Path
import scala.scalanative.io.VirtualDirectory
import scala.scalanative.nir.serialization.deserializeBinary
import scala.scalanative.nir.Defn
import scala.annotation.tailrec
import java.nio.ByteBuffer

object ScalaNativeP extends CaseApp[POptions] {

Expand All @@ -19,7 +25,10 @@ object ScalaNativeP extends CaseApp[POptions] {
}

if (args.all.isEmpty) {
System.err.println("Required NIR file not specified.")
if (options.fromPath)
System.err.println("Required NIR file not specified.")
else
System.err.println("Required class/object not specified.")
exit(1)
}

Expand All @@ -32,29 +41,81 @@ object ScalaNativeP extends CaseApp[POptions] {
System.err.println(s"Ignoring non existing path: $path")
}

if (options.fromPath) printFromFiles(classpath, args.all)
else printFromNames(classpath, args.all)
}

private def printFromNames(
classpath: List[Path],
args: Seq[String]
): Unit = {
Scope { implicit scope =>
val classLoader =
ClassLoader.fromDisk {
Config.empty.withClassPath(classpath)
}

for {
fileName <- args.all
className <- args
} {
classLoader.load(Global.Top(fileName)) match {
case Some(defns) =>
defns
.sortBy(_.name.mangle)
.foreach { d =>
println(d.show)
println()
}
case None => fail(s"Not found class/object with name `${fileName}`")
classLoader.load(Global.Top(className)) match {
case Some(defns) => printNIR(defns)
case None => fail(s"Not found class/object with name `${className}`")
}
}
}
}

private def printFromFiles(
classpath: List[Path],
args: Seq[String]
): Unit = {

Scope { implicit scope =>
val cp = classpath.toStream.map(VirtualDirectory.real(_))
def virtualDirPathMatches(
virtualPath: Path,
regularPath: Path
): Boolean = {
// Paths in jars are always using Unix path denotation
val relativeInJar = virtualPath.toString().stripPrefix("/")
relativeInJar == regularPath.toString()
}
@tailrec
def findAndRead(
classpath: Stream[VirtualDirectory],
path: Path
): Option[ByteBuffer] = {
classpath match {
case Stream.Empty => None
case dir #:: tail =>
val found = dir.files
.find(virtualDirPathMatches(_, path))
.map(dir.read(_))
if (found.isEmpty) findAndRead(tail, path)
else found
}
}
for {
fileName <- args
path = Paths.get(fileName).normalize()
content <- findAndRead(cp, path)
.orElse(fail(s"Not found file with name `${fileName}`"))
} {
val defns = deserializeBinary(content, fileName)
printNIR(defns)
}
}
}

private def printNIR(defns: Seq[Defn]) =
defns
.sortBy(_.name.mangle)
.foreach { d =>
println(d.show)
println()
}

private def fail(msg: String): Nothing = {
Console.err.println(msg)
exit(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ case class POptions(
@ExtraName("cp")
@ValueDescription("<path>")
classpath: List[String] = "." :: Nil,
@HelpMessage(
"Instead of passing class/object names, pass NIR file paths."
)
fromPath: Boolean = false,
@Recurse
misc: MiscOptions
)
7 changes: 7 additions & 0 deletions cli/src/sbt-test/integration/standalone/test
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ $ exists Foo$.nir

-> runScript scala-native-p not.existing.Class

> runScript scala-native-p --from-path Foo.nir
-> runScript scala-native-p --from-path notExisting.nir

> runExec jar cf inside.jar Foo.class Foo.nir Foo$.class Foo$.nir
> runScript scala-native-p --cp inside.jar --from-path Foo.nir Foo$.nir
-> runScript scala-native-p --cp inside.jar --from-path Main$.nir

> runScript scala-native-ld --main Main . -o scala-native-out.exe -v -v
$ exists scala-native-out.exe
> runExec ./scala-native-out.exe