|
|
@@ -0,0 +1,115 @@
|
|
|
+package jsre
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "github.com/obscuren/otto"
|
|
|
+ "io/ioutil"
|
|
|
+
|
|
|
+ "github.com/ethereum/go-ethereum/ethutil"
|
|
|
+)
|
|
|
+
|
|
|
+/*
|
|
|
+JSRE is a generic JS runtime environment embedding the otto JS interpreter.
|
|
|
+It provides some helper functions to
|
|
|
+- load code from files
|
|
|
+- run code snippets
|
|
|
+- require libraries
|
|
|
+- bind native go objects
|
|
|
+*/
|
|
|
+type JSRE struct {
|
|
|
+ assetPath string
|
|
|
+ vm *otto.Otto
|
|
|
+}
|
|
|
+
|
|
|
+func New(assetPath string) *JSRE {
|
|
|
+ re := &JSRE{
|
|
|
+ assetPath,
|
|
|
+ otto.New(),
|
|
|
+ }
|
|
|
+
|
|
|
+ // load prettyprint func definition
|
|
|
+ re.vm.Run(pp_js)
|
|
|
+ re.vm.Set("loadScript", re.loadScript)
|
|
|
+
|
|
|
+ return re
|
|
|
+}
|
|
|
+
|
|
|
+// Exec(file) loads and runs the contents of a file
|
|
|
+// if a relative path is given, the jsre's assetPath is used
|
|
|
+func (self *JSRE) Exec(file string) error {
|
|
|
+ return self.exec(ethutil.AbsolutePath(self.assetPath, file))
|
|
|
+}
|
|
|
+
|
|
|
+func (self *JSRE) exec(path string) error {
|
|
|
+ code, err := ioutil.ReadFile(path)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ _, err = self.vm.Run(code)
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+func (self *JSRE) Bind(name string, v interface{}) (err error) {
|
|
|
+ self.vm.Set(name, v)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func (self *JSRE) Run(code string) (otto.Value, error) {
|
|
|
+ return self.vm.Run(code)
|
|
|
+}
|
|
|
+
|
|
|
+func (self *JSRE) Get(ns string) (otto.Value, error) {
|
|
|
+ return self.vm.Get(ns)
|
|
|
+}
|
|
|
+
|
|
|
+func (self *JSRE) Set(ns string, v interface{}) error {
|
|
|
+ return self.vm.Set(ns, v)
|
|
|
+}
|
|
|
+
|
|
|
+func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value {
|
|
|
+ file, err := call.Argument(0).ToString()
|
|
|
+ if err != nil {
|
|
|
+ return otto.FalseValue()
|
|
|
+ }
|
|
|
+ if err := self.Exec(file); err != nil {
|
|
|
+ fmt.Println("err:", err)
|
|
|
+ return otto.FalseValue()
|
|
|
+ }
|
|
|
+
|
|
|
+ return otto.TrueValue()
|
|
|
+}
|
|
|
+
|
|
|
+func (self *JSRE) PrettyPrint(v interface{}) (val otto.Value, err error) {
|
|
|
+ var method otto.Value
|
|
|
+ v, err = self.vm.ToValue(v)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ method, err = self.vm.Get("prettyPrint")
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return method.Call(method, v)
|
|
|
+}
|
|
|
+
|
|
|
+func (self *JSRE) ToVal(v interface{}) otto.Value {
|
|
|
+ result, err := self.vm.ToValue(v)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("Value unknown:", err)
|
|
|
+ return otto.UndefinedValue()
|
|
|
+ }
|
|
|
+ return result
|
|
|
+}
|
|
|
+
|
|
|
+func (self *JSRE) Eval(code string) (s string, err error) {
|
|
|
+ var val otto.Value
|
|
|
+ val, err = self.Run(code)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ val, err = self.PrettyPrint(val)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return fmt.Sprintf("%v", val), nil
|
|
|
+}
|