Mapping line numbers of user code in Scala REPL to generated code

86 views
Skip to first unread message

Chip Senkbeil

unread,
Mar 21, 2015, 5:13:55 AM3/21/15
to scala...@googlegroups.com
Is there any way in the Scala REPL (specifically the IMain class) to map the line numbers of the user-entered code to the generated code? This would be nice for several reasons including a better understanding of where compile errors happen (they give the line number relative to the generated code). I could try to grab the generated code and search for the original line, but the generated code will occasionally mutate the original line such as turning "val x = 3 + 4" into "val x = 3.+(4)".

Anyway, here is an example of what I'm talking about.

E.g. I enter "val x = 3" into the Scala REPL and it generates the code below (minus the package name for the specific line generated and maybe some other wrappers I'm missing). Not sure if the super.<init>; is something printed by the REPL as "pretty print" since I can't tell if that is something actually valid in the JVM.

class $read extends Serializable {
  def <init>() = {
    super.<init>;
    ()
  };
  class $iwC extends Serializable {
    def <init>() = {
      super.<init>;
      ()
    };
    class $iwC extends Serializable {
      def <init>() = {
        super.<init>;
        ()
      };
      val x = 3
    };
    val $iw = new $iwC.<init>
  };
  val $iw = new $iwC.<init>
}
object $read extends scala.AnyRef {
  def <init>() = {
    super.<init>;
    ()
  };
  val INSTANCE = new $read.<init>
}

Som Snytt

unread,
Mar 21, 2015, 3:46:08 PM3/21/15
to Chip Senkbeil, scala-user
Not sure about your exact use case -- it looks like you're talking about the spark shell.

I was just considering a repl feature to look up line numbers to relate normal compiler artifacts to code (such as anonfuns).

Right now, you get some help locating artifacts

scala> :javap -fun f
Compiled from "<console>"
public final class $anonfun$f$1 extends scala.runtime.AbstractFunction1$mcII$sp implements scala.Serializable {
  public static final long serialVersionUID;
  public final int apply(int);
  public int apply$mcII$sp(int);
  public final java.lang.Object apply(java.lang.Object);
  public $anonfun$f$1();
}


and you can add -v to trawl for line numbers.

In vanilla repl, the code templater isn't exposed, but is retained in the request list:

scala> import $intp._, tools.nsc.interpreter.IMain._
import $intp._
import tools.nsc.interpreter.IMain._


scala> $intp.prevRequestList(1)
res25: $intp.Request = Request(line=def f(is: List[Int]) = is map (_ + 1), 1 trees)

scala> val x = res25.asInstanceOf[ Request { def scala$tools$nsc$interpreter$IMain$Request$$ObjectSourceCode: CodeAssembler[Any] }]
x: $intp.Request{def ObjectSourceCode: tools.nsc.interpreter.IMain.CodeAssembler[Any]} = Request(line=def f(is: List[Int]) = is map (_ + 1), 1 trees)

scala> x.scala$tools$nsc$interpreter$IMain$Request$$ObjectSourceCode(x.handlers)
warning: there was one feature warning; re-run with -feature for details
res26: String =
"
object $read {
object $iw {
object $iw {
       def f(is: List[Int]) = is map (_ + 1)



}
}

}
"

scala> x.lineRep.packaged(res26)
res27: String =
"package $line4


object $read {
object $iw {
object $iw {
       def f(is: List[Int]) = is map (_ + 1)



}
}

}
"


So repeating the exercise, you can see that this code wound up on line 14:

scala> def f(is: List[Int]) = is map { i => ??? ; i + 1 }
f: (is: List[Int])List[Int]

scala> f(List(1))
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
  at $anonfun$f$1.apply$mcII$sp(<console>:14)
  at $anonfun$f$1.apply(<console>:14)
  at $anonfun$f$1.apply(<console>:14)
  at scala.collection.immutable.List.map(List.scala:273)
  at .f(<console>:14)
  ... 33 elided

scala> $intp.prevRequestList.dropRight(1).last
res29: $intp.Request = Request(line=def f(is: List[Int]) = is map { i => ??? ; i + 1 }, 1 trees)

scala> val x = res29.asInstanceOf[ Request { def scala$tools$nsc$interpreter$IMain$Request$$ObjectSourceCode: CodeAssembler[Any] }]
x: $intp.Request{def ObjectSourceCode: tools.nsc.interpreter.IMain.CodeAssembler[Any]} = Request(line=def f(is: List[Int]) = is map { i => ??? ; i + 1 }, 1 trees)

scala> x.scala$tools$nsc$interpreter$IMain$Request$$ObjectSourceCode(x.handlers)
warning: there was one feature warning; re-run with -feature for details
res30: String =
"
object $read {
object $iw {
import $intp
object $iw {
import $intp._
object $iw {
object $iw {
import tools.nsc.interpreter.IMain._
object $iw {
object $iw {
       def f(is: List[Int]) = is map { i => ??? ; i + 1 }



}
}
}
}
}
}

}
"

scala> x.lineRep.packaged(res30)
res31: String =
"package $line63


object $read {
object $iw {
import $intp
object $iw {
import $intp._
object $iw {
object $iw {
import tools.nsc.interpreter.IMain._
object $iw {
object $iw {
       def f(is: List[Int]) = is map { i => ??? ; i + 1 }



}
}
}
}
}
}

}
"








--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages