как проверить ошибки, происходящие внутри интерпретатора Scala программно - PullRequest
3 голосов
/ 24 июля 2011

Я выполняю фрагменты кода 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. Как это отловить?

1 Ответ

7 голосов
/ 24 июля 2011

Метод интерпретатора 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
...