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

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

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

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

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

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

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

7 голосов | спросил Arkady 11 J0000006Europe/Moscow 2016, 01:21:31

2 ответа


0
У

@kenjiyoshida есть хороший gist , в котором показано, как оценить код 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 в Scala, чтобы сначала проанализировать вашу строку, а затем сравнить с белым списком, прежде чем переходить к eval, но в этот момент все может стать довольно проблематично, так как вы будете вручную писать код для дезинфекции Scala AST (или, по крайней мере, отклонять опасные данные). Это определенно не кажется «идиоматическим решением».

ответил badcook 11 J0000006Europe/Moscow 2016, 12:01:45
0

Это должно быть возможно при использовании стандартного 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();
}
ответил Somatik 11 J0000006Europe/Moscow 2016, 22:33:23

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132