2016-06-10 18 views
5

स्कैला के लिए नया और एक मुहावरेदार समाधान के लिए पॉइंटर्स की तलाश में, यदि कोई है तो।रनटाइम पर स्कैला अभिव्यक्ति को संकलित/eval कैसे करें?

मैं कुछ डेटा पर लागू मनमाने ढंग से उपयोगकर्ता द्वारा आपूर्ति किए गए स्कैला फ़ंक्शन (जिन्हें मेरे कोड में परिभाषित कार्यों/कक्षाओं को संदर्भित करने की अनुमति है) रखना चाहते हैं।

उदाहरण के लिए: मेरे पास और bar(s: String): String मेरे myprog.scala में परिभाषित फ़ंक्शन हैं। उपयोगकर्ता इस तरह मेरी कार्यक्रम चलाता है:

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

इस डेटा फ़ाइल के माध्यम से लाइन द्वारा लाइन चलाने के लिए और है कि लाइन के लिए उपयोगकर्ता द्वारा निर्दिष्ट समारोह को लागू करने के परिणाम का उत्सर्जन होता है।

अतिरिक्त अंक के लिए, क्या मैं यह सुनिश्चित कर सकता हूं कि उपयोगकर्ता द्वारा परिभाषित फ़ंक्शन में कोई दुष्प्रभाव नहीं हैं? यदि नहीं, तो क्या मैं फ़ंक्शन को केवल फ़ंक्शंस का प्रतिबंधित सबसेट (जिसे मैं सुरक्षित होने का आश्वासन देता हूं) का उपयोग करने के लिए प्रतिबंधित कर सकता हूं?

+0

मैं देखता हूं कि कैसे freenode पर lambdabot लिखा है, आपकी समस्याएं समान लगती हैं। – Reactormonk

उत्तर

2

@kenjiyoshida का अच्छा gist है जो दिखाता है कि स्कैला कोड कैसे निकाला जाए। ध्यान दें कि उस ग्रिस्ट से Eval का उपयोग करते समय, रिटर्न वैल्यू निर्दिष्ट नहीं करने पर परिणामस्वरूप रनटाइम विफलता होगी जब स्कैला 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 
} 

ट्विटर की utilutil-eval किया करते थे पैकेज है, लेकिन वह अब पदावनत किया गया है (और यह भी एक संकलक बग जब संकलित चलाता है) लगता है।

आपके प्रश्न के दूसरे भाग के लिए, उत्तर नहीं लगता है। यहां तक ​​कि यदि आप डिफ़ॉल्ट Predef अक्षम करते हैं और स्वयं आयात करते हैं, तो उपयोगकर्ता हमेशा उन कार्यों को पूरी तरह से योग्य पैकेज नाम के साथ प्राप्त कर सकता है। आप शायद अपनी स्ट्रिंग को पार्स करने के लिए स्कैला के scala.tools.reflect.ToolBox का उपयोग कर सकते हैं और फिर eval पर जाने से पहले श्वेतसूची के खिलाफ तुलना कर सकते हैं, लेकिन उस समय चीजें बहुत बालों वाली हो सकती हैं क्योंकि आप स्काला एएसटी को स्वच्छ करने के लिए मैन्युअल रूप से कोड लिखेंगे (या बहुत खतरनाक इनपुट को कम से कम अस्वीकार करें)। यह निश्चित रूप से एक "मूर्खतापूर्ण समाधान" प्रतीत नहीं होता है।

0

यह मानक जावा JSR 223 स्क्रिप्टिंग इंजन का उपयोग करके संभव हो जाना चाहिए

https://issues.scala-lang.org/browse/SI-874

देख

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(); 
} 
(भी scala.tools.nsc.Interpreter लेकिन यकीन नहीं यह अभी भी उपलब्ध है का उपयोग करते हुए उल्लेख है)
संबंधित मुद्दे