как программно проверять ошибки, происходящие внутри интерпретатора scala

Я выполняю фрагменты кода scala с помощью scala.tools.nsc.Interpreter. Когда фрагмент кода правильный, все в порядке, но когда он содержит ошибки, мой код не может это выяснить и счастливо продолжает работать. Я хотел бы получить исключение или метод для вызова любой ошибки, которая произошла во время последней оценки интерпретатором.

мой код:

import scala.tools.nsc.Interpreter
import scala.tools.nsc.Settings
object RuntimeEval {
  def main(args: Array[String]): Unit = {
    var msg = "fail"
    val eval = new RuntimeEval
    msg = eval.eval(msg,"\"success\"")
    println(msg)
    var anInt = 0
    while(true){
    println("Enter an integer")
      val userInput = Console.readLine
      anInt = eval.eval(anInt,userInput)
      println("-->"+anInt)
      println
    }
  }
}
class ResContainer(var value: Any)
class RuntimeEval {
  val settings = new Settings
  settings.classpath.value = System.getProperty("java.class.path")
  val interp = new Interpreter(settings)

  def eval[A <: Any](obj: A, expression: String): A={
    val res = new ResContainer(obj)
    interp.beQuietDuring {
      interp.bind("res", res.getClass.getCanonicalName, res)
      interp.interpret("res.value = "+expression)
    }
    val info = obj match{
      case x: AnyRef => "expected type: \n"+x.getClass.getCanonicalName+"\n"
      case _ => "expected type is not an AnyRef\n"
    }
    res.value match{
      case x: A => x
      case x: AnyRef => error("unexpected result type, "+info+"result type:\n"+x.getClass.getCanonicalName)
      case _ => error("unexpected result type, "+info+"result type is not an AnyRef")
    }
  }
}

пример проблемы:

success
Enter an integer
9/12
-->0

Enter an integer
9/0
java.lang.ArithmeticException: / by zero
    at .<init>(<console>:6)
    at .<clinit>(<console>)
    at RequestResult$.<init>(<console>:5)
    at RequestResult$.<clinit>(<console>)
    at RequestResult$scala_repl_result(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
    at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988)
    at scala.util.control.Exception$Catch.apply(Exception.scala:79)
    at scala...-->0

Enter an integer
9/4
-->2

Enter an integer

Исключение ArithmeticException произошло внутри интерпретатора, затем кажется, что он ничего не вернул, поэтому мой код получил тот же результат, что и предыдущая операция, 0. Как это поймать?


person acapola    schedule 24.07.2011    source источник


Ответы (1)


Метод interpret интерпретатора возвращает значение результата, которое указывает, может ли код быть успешно интерпретирован или нет. Таким образом:

interp.beQuietDuring {
  interp.bind("res", res.getClass.getCanonicalName, res)
  interp.interpret("res.value = "+expression)
} match {
   case Results.Error => error( ... )
   case Results.Incomplete => error( ... )
   case Results.Success => res.value
}

Еще две вещи: вам не нужно связывать "res" для каждого eval, этого должно быть достаточно после инициализации интерпретатора. Также обратите внимание, что существует метод mostRecentVar, так что вы можете вообще отказаться от привязки результата. Вот пример для Scala 2.9 (то же, что и 2.8, но вместо Interpreter используется IMain):

import tools.nsc.interpreter.{IMain, Results}
import sys.error
val interp = new IMain()
def eval( expression: String ) : AnyRef =
   interp.interpret( expression ) match {
      case Results.Error => error( "Failed" )
      case Results.Incomplete => error( "Incomplete" )
      case Results.Success => interp.valueOfTerm( interp.mostRecentVar )
        .getOrElse( error( "No result" ))
   }

Тестирование:

scala> val x = eval( "1 + 2" )
res0: Int = 3
x: AnyRef = 3
person 0__    schedule 24.07.2011
comment
большое спасибо, версия Scala 2.9 работает хорошо и удобнее. Последующий вопрос: как получить исходное сообщение об ошибке (/ на 0 вместо просто Failed) - person acapola; 24.07.2011
comment
Я думаю, вы можете обернуть свое выражение в блок try-catch, может быть? как 2_. Таким образом, вы могли бы проверить, является ли результат Throwable? - person 0__; 24.07.2011
comment
Это здорово, спасибо. К сожалению, похоже, он сломался со scala-2.9.1. В частности, кажется, что interp.valueOfTerm() всегда дает None(). :( issues.scala-lang.org/browse/SI-4899 - person wmacura; 17.10.2011
comment
@0__ Я застрял в проблеме, связанной с интерпретатором класс был загружен через другой загрузчик"> stackoverflow.com/questions/52965997/ пожалуйста, помогите мне решить эту проблему - person user811602; 24.10.2018