github.com/igggame/nebulas-go@v2.1.0+incompatible/cmd/console/jsvm.go (about) 1 // Copyright (C) 2017 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // the go-nebulas library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with the go-nebulas library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 19 package console 20 21 import ( 22 "sort" 23 "strings" 24 25 "github.com/robertkrimen/otto" 26 ) 27 28 // JSVM javascript runtime environment 29 type JSVM struct { 30 31 // the representation of the JavaScript runtime 32 vm *otto.Otto 33 } 34 35 func newJSVM() *JSVM { 36 vm := &JSVM{} 37 vm.vm = otto.New() 38 return vm 39 } 40 41 // Run will run the given source (parsing it first if necessary), returning the resulting value and error (if any) 42 func (v *JSVM) Run(src string) (otto.Value, error) { 43 return v.vm.Run(src) 44 } 45 46 // Get returns the value of a variable in the JS environment. 47 func (v *JSVM) Get(name string) (otto.Value, error) { 48 return v.vm.Get(name) 49 } 50 51 // Set assigns value v to a variable in the JS environment. 52 func (v *JSVM) Set(name string, value interface{}) error { 53 return v.vm.Set(name, value) 54 } 55 56 // Compile compiles and then runs JS code. 57 func (v *JSVM) Compile(filename string, src interface{}) error { 58 script, err := v.vm.Compile(filename, src) 59 if err != nil { 60 return err 61 } 62 _, err = v.vm.Run(script) 63 return err 64 } 65 66 // JSONString convert value to json string 67 func (v *JSVM) JSONString(val otto.Value) (string, error) { 68 JSON, _ := v.vm.Object("JSON") 69 jsonVal, err := JSON.Call("stringify", val) 70 if err != nil { 71 return "", err 72 } 73 return jsonVal.String(), nil 74 } 75 76 // CompleteKeywords returns potential continuations for the given line. 77 func (v *JSVM) CompleteKeywords(line string) []string { 78 parts := strings.Split(line, ".") 79 objRef := "this" 80 prefix := line 81 if len(parts) > 1 { 82 objRef = strings.Join(parts[0:len(parts)-1], ".") 83 prefix = parts[len(parts)-1] 84 } 85 86 obj, _ := v.vm.Object(objRef) 87 if obj == nil { 88 return nil 89 } 90 properties := v.getObjectKeys(obj, objRef, prefix) 91 // only not golbal prototype should be use 92 if objRef != "this" { 93 if c, _ := obj.Get("constructor"); c.Object() != nil { 94 if p, _ := c.Object().Get("prototype"); p.Object() != nil { 95 keys := v.getObjectKeys(p.Object(), objRef, prefix) 96 // remove the duplicate property 97 set := make(map[string]bool) 98 for _, key := range keys { 99 set[key] = true 100 } 101 for _, key := range properties { 102 set[key] = true 103 } 104 properties = make([]string, 0, len(set)) 105 for k := range set { 106 properties = append(properties, k) 107 } 108 } 109 } 110 } 111 tmp := make([]string, len(properties)) 112 copy(tmp, properties) 113 for _, v := range tmp { 114 tmps := strings.Split(v, ".") 115 f := tmps[len(tmps)-1] 116 // only out property use,remove request func 117 if f == "request" || f == "constructor" || strings.HasPrefix(f, "_") { 118 properties = sliceRemove(properties, v) 119 } 120 } 121 // Append opening parenthesis (for functions) or dot (for objects) 122 // if the line itself is the only completion. 123 if len(properties) == 1 && properties[0] == line { 124 obj, _ := v.vm.Object(line) 125 if obj != nil { 126 if obj.Class() == "Function" { 127 properties[0] += "()" 128 } else { 129 properties[0] += "." 130 } 131 } 132 } 133 sort.Strings(properties) 134 return properties 135 } 136 137 func (v *JSVM) getObjectKeys(obj *otto.Object, objRef, prefix string) (properties []string) { 138 Object, _ := v.vm.Object("Object") 139 rv, _ := Object.Call("getOwnPropertyNames", obj.Value()) 140 gv, _ := rv.Export() 141 switch gv := gv.(type) { 142 case []string: 143 properties = parseOwnKeys(objRef, prefix, gv) 144 } 145 return properties 146 } 147 148 func parseOwnKeys(objRef, prefix string, properties []string) []string { 149 //fmt.Println("parse keys:", properties) 150 var results []string 151 for _, property := range properties { 152 //fmt.Println("property is:", property) 153 if len(prefix) == 0 || strings.HasPrefix(property, prefix) { 154 if objRef == "this" { 155 results = append(results, property) 156 } else { 157 results = append(results, objRef+"."+property) 158 } 159 } 160 } 161 return results 162 } 163 164 func sliceRemove(slices []string, value string) []string { 165 for i, v := range slices { 166 if v == value { 167 slices = append(slices[:i], slices[i+1:]...) 168 break 169 } 170 } 171 return slices 172 }