Passer dans l'interpréteur lors de l'emplacement arbitraire du code scala

84

Je viens d'un fond Python, où à tout moment dans mon code je peux ajouter

import pdb; pdb.set_trace()

et au moment de l'exécution, je serai déposé dans un interprète interactif à cet endroit. Existe-t-il un équivalent pour scala, ou n'est-ce pas possible au moment de l'exécution?

Lars Yencken
la source
7
Dans l'esprit de «vérité dans la publicité», Scala n'a pas d'interprète. Son REPL est «compile-and-go». Cela dit, le code REPL (y compris le compilateur) peut être incorporé dans votre application, si vous le souhaitez (comme indiqué ci-dessous)
Randall Schulz
1
Mais le REPL se lancera sans aucune connaissance de votre contexte d'exécution, sauf pour ce que vous liez explicitement et laborieusement dans votre code de lancement de REPL. Voir ci-dessous. Je pense qu'en python vous atterrissez dans le contexte de fonctionnement, ce qui est bien meilleur. de toute façon, stackoverflow.com/questions/24674288/... est plus à jour.
matanster le

Réponses:

78

Oui, vous pouvez, sur Scala 2.8. Notez que, pour que cela fonctionne, vous devez inclure le scala-compiler.jar dans votre chemin de classe. Si vous invoquez votre programme scala avec scala, cela se fera automatiquement (du moins il semble dans les tests que j'ai effectués).

Vous pouvez ensuite l'utiliser comme ceci:

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)
    }
  }
}

Vous pouvez passer plusieurs DebugParamarguments. Lorsque le REPL apparaît, la valeur à droite sera liée à un val dont vous avez fourni le nom à gauche. Par exemple, si je change cette ligne comme ceci:

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

Ensuite, l'exécution se déroulera comme ceci:

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

scala> j
res0: Int = 5

Vous continuez l'exécution en tapant :quit.

Vous pouvez également passer inconditionnellement dans REPL en invoquant break, qui reçoit un Listof DebugParamau lieu d'un vararg. Voici un exemple complet, code et exécution:

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)
    }
  }
}

Puis:

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
la source
3
Cela peut conduire à une erreur scala.tools.nsc.MissingRequirementError: object scala not found.dans Scala 2.8. Vous devrez peut - être passer explicitement le classpath du processus hôte aux paramètres de Scalac, mais breaket breakIfne pas le faire. Voici une version corrigée de breakcela: gist.github.com/290632
retronym
@retronym Drôle, ça a marché ici. Envoyez-le à paulp. Il a mentionné que cette chose allait être changée de toute façon.
Daniel C.Sobral
Je l'ai essayé à partir d'un test JUnit, exécuté par IntelliJ. IntelliJ a lancé le processus avec java -classpath .... Je suppose que si vous utilisez à la scala -classpathplace, cela fonctionnerait bien.
retronym
4
C'était une dépendance du module, et donc dans le classpath. 2.8 ne transmet pas le contenu du java -classpathprocessus hôte aux paramètres de scalac: old.nabble.com
...
1
@Huur Voir la réponse de Răzvan Panda .
Daniel C.Sobral
24

Pour ajouter à la réponse de Daniel, à partir de Scala 2.9, les méthodes breaket breakIfsont contenues dans scala.tools.nsc.interpreter.ILoop. Aussi, DebugParamest maintenant NamedParam.

Kipton Barros
la source
Vous devrez ajouter jline en tant que dépendance.
schmmd
8
pouvez-vous s'il vous plaît écrire un exemple avec la nouvelle utilisation?
Volonté le
24

IntelliJ IDEA:

  1. Exécuter en mode débogage ou attacher un débogueur distant
  2. Définissez un point d'arrêt et exécutez jusqu'à ce que vous l'atteigniez
  3. Ouvrez la fenêtre Evaluate Expression( Alt+ F8, dans le menu: Exécuter -> Evaluer l'expression) pour exécuter du code Scala arbitraire.
  4. Tapez le fragment de code ou l'expression que vous souhaitez exécuter et cliquez sur Évaluer
  5. Tapez Alt+ Vou cliquez sur Evaluer pour exécuter le fragment de code.

Éclipse:

Depuis Scala 2.10, les deux breaket breakIfont été supprimés de ILoop.

Pour entrer par effraction, vous devrez travailler ILoopdirectement avec .

Ajoutez d'abord une scala compilerbibliothèque. Pour Eclipse Scala, faites un clic droit sur project => Build Path=> Add Libraries...=> Scala Compiler.

Et puis vous pouvez utiliser ce qui suit où vous souhaitez démarrer l'interpréteur:

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()

Dans Eclipse Scala, l'interpréteur peut être utilisé depuis la Consolevue:

Răzvan Flavius ​​Panda
la source
18
C'est horrible. :(
Daniel C. Sobral
@Daniel Pourquoi est-ce horrible?
Hakkar
14
Parce qu'il ajoute beaucoup de détails techniques qui n'ont aucun rapport avec l'objectif de débogage à un moment donné du programme, et, à la place, liés aux mécanismes de mise en route du REPL.
Daniel C.Sobral
1
@Daniel y a-t-il un meilleur moyen dans scala 2.10?
roterl
@roterl Quel est le problème avec ce qui précède?
Daniel C.Sobral