Wpadnij do interpretera podczas dowolnej lokalizacji kodu scala

84

Pochodzę z języka Python, gdzie w dowolnym miejscu mogę dodać kod

import pdb; pdb.set_trace()

aw czasie wykonywania zostanę wpuszczony do interaktywnego tłumacza w tym miejscu. Czy istnieje odpowiednik dla scala, czy nie jest to możliwe w czasie wykonywania?

Lars Yencken
źródło
7
W duchu „prawdy w reklamie” Scala nie ma tłumacza. Jego REPL to „kompiluj i pracuj”. To powiedziawszy, kod REPL (w tym kompilator) może zostać włączony do twojej aplikacji, jeśli chcesz (jak pokazano poniżej)
Randall Schulz,
1
Ale REPL uruchomi się bez żadnej znajomości kontekstu działania, z wyjątkiem tego, co wyraźnie i mozolnie wiążesz w kodzie uruchamiającym REPL. Zobacz poniżej. Myślę, że w Pythonie trafisz do kontekstu biegowego, który jest znacznie lepszy. w każdym razie, stackoverflow.com/questions/24674288/ ... jest bardziej aktualny.
matanster

Odpowiedzi:

78

Tak, możesz na Scali 2.8. Zauważ, że aby to zadziałało, musisz dołączyć plik scala-compiler.jar do swojej ścieżki klas. Jeśli wywołasz swój program scala za pomocą scala, zostanie to zrobione automatycznie (a przynajmniej tak się wydaje w testach, które przeprowadziłem).

Następnie możesz go użyć w następujący sposób:

import scala.tools.nsc.Interpreter._

object TestDebugger {
  def main(args: Array[String]) {
    0 to 10 foreach { i =>
      breakIf(i == 5, DebugParam("i", i))
      println(i)
    }
  }
}

Możesz przekazać wiele DebugParamargumentów. Kiedy pojawi się REPL, wartość po prawej stronie zostanie powiązana z wartością, której nazwę podałeś po lewej stronie. Na przykład, jeśli zmienię tę linię w ten sposób:

      breakIf(i == 5, DebugParam("j", i))

Wtedy wykonanie nastąpi tak:

C:\Users\Daniel\Documents\Scala\Programas>scala TestDebugger
0
1
2
3
4
j: Int

scala> j
res0: Int = 5

Kontynuujesz wykonanie, wpisując :quit.

Możesz także bezwarunkowo przejść do REPL przez wywołanie break, które otrzymuje Listof DebugParamzamiast vararg. Oto pełny przykład, kod i wykonanie:

import scala.tools.nsc.Interpreter._

object TestDebugger {
  def main(args: Array[String]) {
    0 to 10 foreach { i =>
      breakIf(i == 5, DebugParam("j", i))
      println(i)
      if (i == 7) break(Nil)
    }
  }
}

I wtedy:

C:\Users\Daniel\Documents\Scala\Programas>scalac TestDebugger.scala

C:\Users\Daniel\Documents\Scala\Programas>scala TestDebugger
0
1
2
3
4
j: Int

scala> j
res0: Int = 5

scala> :quit
5
6
7

scala> j
<console>:5: error: not found: value j
       j
       ^

scala> :quit
8
9
10

C:\Users\Daniel\Documents\Scala\Programas>
Daniel C. Sobral
źródło
3
Może to doprowadzić do błędu scala.tools.nsc.MissingRequirementError: object scala not found.w Scali 2.8. Być może trzeba wyraźnie zdać ścieżkę klas procesu hosta z ustawieniami Scalac, ale breaki breakIfnie rób tego. Oto poprawiona wersja breaktego rozwiązania: gist.github.com/290632
retronym
@retronym Zabawne, po prostu tutaj zadziałało. Wyślij to do Paulp. Wspomniał, że to i tak zostanie zmienione.
Daniel C. Sobral
Wypróbowałem to z testu JUnit, uruchomionego przez IntelliJ. IntelliJ uruchomił proces z java -classpath .... Myślę, że jeśli użyjesz scala -classpathzamiast tego, będzie dobrze.
retronim
4
Była to zależność modułu, a więc w ścieżce klas. 2.8 nie przekazuje zawartości java -classpathprocesu hosta do ustawień dla skalaca: old.nabble.com/…
retronym
1
@Huur Patrz odpowiedź przez Răzvan Panda .
Daniel C. Sobral,
24

Aby dodać do odpowiedzi Daniela, od Scala 2.9, plik breakbreakIf metody i są zawarte w scala.tools.nsc.interpreter.ILoop. DebugParamTeraz też jest NamedParam.

Kipton Barros
źródło
Będziesz musiał dodać jline jako zależność.
schmmd
8
czy możesz napisać przykład z nowym użyciem?
Will
24

IntelliJ IDEA:

  1. Uruchom w trybie debugowania lub dołącz zdalny debuger
  2. Ustaw punkt przerwania i biegnij, aż do niego dotrzesz
  3. Otwórz Evaluate Expression( Alt+F8 , w menu: Uruchom -> Oceń wyrażenie), aby uruchomić dowolny kod Scala.
  4. Wpisz fragment kodu lub wyrażenie, które chcesz uruchomić i kliknij Oceń
  5. Wpisz Alt+ Vlub kliknij Oceń, aby uruchomić fragment kodu.

Zaćmienie:

Począwszy od Scala 2.10, zarówno breaki breakIfzostały usunięte z ILoop.

Aby włamać się do tłumacza, będziesz musiał pracować ILoopbezpośrednio.

Najpierw dodaj scala compilerbibliotekę. W przypadku Eclipse Scala kliknij prawym przyciskiem myszy projekt => Build Path=> Add Libraries...=> Scala Compiler.

A następnie możesz użyć następujących, w których chcesz uruchomić tłumacza:

import scala.tools.nsc.interpreter.ILoop
import scala.tools.nsc.interpreter.SimpleReader
import scala.tools.nsc.Settings

val repl = new ILoop
repl.settings = new Settings
repl.settings.Yreplsync.value = true
repl.in = SimpleReader()
repl.createInterpreter()

// bind any local variables that you want to have access to
repl.intp.bind("row", "Int", row)
repl.intp.bind("col", "Int", col)

// start the interpreter and then close it after you :quit
repl.loop()
repl.closeInterpreter()

W Eclipse Scala z interpretera można skorzystać z Consolewidoku:

Răzvan Flavius ​​Panda
źródło
18
To okropne. :(
Daniel C. Sobral,
@Daniel Dlaczego to jest okropne?
Hakkar
14
Ponieważ dodaje wiele kotłów, które są całkowicie niezwiązane z celem debugowania w punkcie programu, a zamiast tego są związane z mechaniką uruchamiania REPL.
Daniel C. Sobral
1
@Daniel czy jest lepszy sposób w scali 2.10?
roterl
@roterl Jaki jest problem z powyższym?
Daniel C. Sobral