如何以编程方式检查scala解释器中发生的错误

如何以编程方式检查scala解释器中发生的错误,scala,interpreter,Scala,Interpreter,我正在使用scala.tools.nsc.Interpreter执行scala代码段 当代码片段正确时,一切都很好,但当它有缺陷时,我的代码无法发现并愉快地继续。我希望得到一个异常或方法来调用,以获取解释器上次求值期间发生的任何错误 我的代码: import scala.tools.nsc.Interpreter import scala.tools.nsc.Settings object RuntimeEval { def main(args: Array[String]): Unit =

我正在使用scala.tools.nsc.Interpreter执行scala代码段 当代码片段正确时,一切都很好,但当它有缺陷时,我的代码无法发现并愉快地继续。我希望得到一个异常或方法来调用,以获取解释器上次求值期间发生的任何错误

我的代码:

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")
    }
  }
}
导入scala.tools.nsc.解释器
导入scala.tools.nsc.Settings
对象运行时评估{
def main(参数:数组[字符串]):单位={
var msg=“失败”
val eval=新的运行时评估
msg=eval.eval(msg,“success\”)
println(msg)
var anInt=0
while(true){
println(“输入整数”)
val userInput=Console.readLine
anInt=eval.eval(anInt,用户输入)
println(“-->”+anInt)
普林顿
}
}
}
类重新容器(变量值:Any)
类运行时评估{
val设置=新设置
settings.classpath.value=System.getProperty(“java.class.path”)
val interp=新的解释器(设置)
def eval[A“预期类型:\n”+x.getClass.getCanonicalName+“\n”
案例u=>“预期的类型不是AnyRef\n”
}
res.值匹配{
案例x:A=>x
案例x:AnyRef=>错误(“意外的结果类型,+info+”结果类型:\n“+x.getClass.getCanonicalName)
case=>错误(“意外的结果类型,+info+”结果类型不是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
成功
输入一个整数
9/12
-->0
输入一个整数
9/0
java.lang.arithmetricException:/by零
在。(:6)
在
请求时结果$(:5)
请求时结果$()
请求时结果$scala_repl_result()
在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处
位于sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)中
位于java.lang.reflect.Method.invoke(Method.java:597)
在scala.tools.nsc.transparer$Request$$anonfun$loadand run$1$$anonfun$apply$17.apply(transparer.scala:988)
在scala.tools.nsc.transparer$Request$$anonfun$loadand run$1$$anonfun$apply$17.apply(transparer.scala:988)
在scala.util.control.Exception$Catch.apply处(Exception.scala:79)
在scala…-->0
输入一个整数
9/4
-->2
输入一个整数
算术异常发生在解释器内部,然后它似乎什么也没有返回,所以我的代码得到了与上一个操作相同的结果,0。
如何捕获此信息?

解释器的
exploration
方法返回一个结果值,该值指示是否可以成功解释代码。因此:

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
}
还有两件事:您不需要为每个
eval
绑定
“res”
,只要初始化解释器就足够了。另外,请注意还有一个方法
mostRecentVar
,因此您可以完全取消结果绑定。下面是Scala 2.9的一个示例(与2.8相同,但您使用的不是
解释器
,而是
IMain
):

测试:

scala> val x = eval( "1 + 2" )
res0: Int = 3
x: AnyRef = 3

非常感谢,Scala 2.9版本工作得很好,而且更方便。接下来的问题:如何获取原始错误消息(“/by 0”而不是“Failed”),我认为您可以将表达式包装在
try-catch
块中,比如
exploration(“try{expression+”}catch{case=>e}”)
。这样你就可以测试结果是否是一个可丢弃的
?这很好,谢谢。不幸的是,它似乎已经与scala-2.9.1发生了冲突。特别是,interp.valueOfTerm()似乎总是不给()
scala> val x = eval( "1 + 2" )
res0: Int = 3
x: AnyRef = 3