Как скомпилировать / оценить выражение Scala во время выполнения?

Новое в Scala и поиск указателей на идиоматическое решение, если оно есть.

Я хотел бы, чтобы к некоторым данным применялись произвольные пользовательские функции Scala (которые могут ссылаться на функции / классы, которые я определил в моем коде).

Например: у меня естьfoo(s: String): String а такжеbar(s: String): String функции, определенные в моемmyprog.scala, Пользователь запускает мою программу так:

$ scala myprog data.txt --func='(s: Str) => foo(bar(s)).reverse'

Это будет проходить строка за строкой через файл данных и выдаст результат применения указанной пользователем функции к этой строке.

Могу ли я убедиться, что в дополнительной функции нет никаких побочных эффектов в определяемой пользователем функции? Если нет, могу ли я ограничить использование функциитолько ограниченный набор функций (которые я могу гарантировать, чтобы быть безопасным)?

 Reactormonk11 июн. 2016 г., 00:48
Я бы посмотрел, как пишется lambdabot на freenode, ваши проблемы звучат похоже.

Ответы на вопрос(2)

@kenjiyoshida имеет хорошийсуть это показывает, как оценить код Scala. Обратите внимание, что при использованииEval Исходя из этого, отсутствие указания возвращаемого значения приведет к сбою во время выполнения, когда Scala по умолчанию выводитNothing.

scala> Eval("println(\"Hello\")")
Hello
java.lang.ClassCastException: scala.runtime.BoxedUnit cannot be cast to scala.runtime.Nothing$
  ... 42 elided

против

scala> Eval[Unit]("println(\"Hello\")")
Hello

Он также прекрасно справляется с любой задачей.

 object Thing {
   val thing: Int = 5
 }

 object Eval {

   def apply[A](string: String): A = {
     val toolbox = currentMirror.mkToolBox()
     val tree = toolbox.parse(string)
     toolbox.eval(tree).asInstanceOf[A]
   }

   def fromFile[A](file: File): A =
     apply(scala.io.Source.fromFile(file).mkString(""))

   def fromFileName[A](file: String): A =
     fromFile(new File(file))

 }

 object Thing2 {
   val thing2 = Eval[Int]("Thing.thing") // 5
 }

щебетатьutil пакет раньше имелutil-eval, но это, кажется, уже устарело (а также вызывает ошибку компилятора при компиляции).

Что касается второй части вашего вопроса, ответ, кажется, нет. Даже если вы отключите по умолчаниюPredef и импортируя себя, пользователь всегда может получить доступ к этим функциям с полным именем пакета. Вы могли бы использовать Скалаscala.tools.reflect.ToolBox сначала проанализировать вашу строку, а затем сравнить с белым списком, прежде чем перейти кeval, но в этот момент все может стать довольно проблематично, так как вы будете вручную писать код для дезинфекции Scala AST (или, по крайней мере, отклонять опасные данные). Это определенно не кажется «идиоматическим решением».

Это должно быть возможно при использовании стандартного Java JSR 223 Scripting Engine.

увидетьhttps://issues.scala-lang.org/browse/SI-874

(также упоминается использование scala.tools.nsc.Interpreter, но не уверен, что он по-прежнему доступен)

import javax.script.*;
ScriptEngine e = new ScriptEngineManager().getEngineByName("scala");
e.getContext().setAttribute("label", new Integer(4), ScriptContext.ENGINE_SCOPE);
try {
    engine.eval("println(2+label)");
} catch (ScriptException ex) {
    ex.printStackTrace();
}

Ваш ответ на вопрос