func main() { env := vm.NewEnv() env.Define("foo", reflect.ValueOf(1)) scanner := new(parser.Scanner) scanner.Init(`foo + 1`) stmts, err := parser.Parse(scanner) if err != nil { log.Fatal(err) } v, err := vm.Run(stmts, env) if err != nil { log.Fatal(err) } fmt.Println(v.Interface()) }
func main() { fs.Parse(os.Args[1:]) if *v { fmt.Println(version) os.Exit(0) } env := vm.NewEnv() var code string var b []byte var reader *bufio.Reader var following bool var source string repl := fs.NArg() == 0 && *e == "" env.Define("args", reflect.ValueOf(fs.Args())) if repl { reader = bufio.NewReader(os.Stdin) source = "typein" os.Args = append([]string{os.Args[0]}, fs.Args()...) } else { if *e != "" { b = []byte(*e) source = "argument" } else { var err error b, err = ioutil.ReadFile(fs.Arg(0)) if err != nil { colortext(ct.Red, false, func() { fmt.Fprintln(os.Stderr, err) }) os.Exit(1) } env.Define("args", reflect.ValueOf(fs.Args()[1:])) source = filepath.Clean(fs.Arg(0)) } os.Args = fs.Args() } anko_core.Import(env) tbl := map[string]func(env *vm.Env) *vm.Env{ "encoding/json": anko_encoding_json.Import, "flag": anko_flag.Import, "fmt": anko_fmt.Import, "io": anko_io.Import, "io/ioutil": anko_io_ioutil.Import, "math": anko_math.Import, "net": anko_net.Import, "net/http": anko_net_http.Import, "net/url": anko_net_url.Import, "os": anko_os.Import, "os/exec": anko_os_exec.Import, "path": anko_path.Import, "path/filepath": anko_path_filepath.Import, "regexp": anko_regexp.Import, "sort": anko_sort.Import, "strings": anko_strings.Import, "github.com/daviddengcn/go-colortext": anko_colortext.Import, } env.Define("import", reflect.ValueOf(func(s string) interface{} { if loader, ok := tbl[s]; ok { return loader(env) } panic(fmt.Sprintf("package '%s' not found", s)) })) for { if repl { colortext(ct.Green, true, func() { if following { fmt.Print(" ") } else { fmt.Print("> ") } }) var err error b, _, err = reader.ReadLine() if err != nil { break } if len(b) == 0 { continue } if code != "" { code += "\n" } code += string(b) } else { code = string(b) } scanner := new(parser.Scanner) scanner.Init(code) stmts, err := parser.Parse(scanner) v := vm.NilValue if repl { if e, ok := err.(*parser.Error); ok { if e.Pos.Column == len(b) && !e.Fatal { following = true continue } if e.Error() == "unexpected EOF" { following = true continue } } } following = false code = "" if err == nil { v, err = vm.Run(stmts, env) } if err != nil { colortext(ct.Red, false, func() { if e, ok := err.(*vm.Error); ok { fmt.Fprintf(os.Stderr, "%s:%d: %s\n", source, e.Pos.Line, err) } else if e, ok := err.(*parser.Error); ok { if e.Filename != "" { source = e.Filename } fmt.Fprintf(os.Stderr, "%s:%d: %s\n", source, e.Pos.Line, err) } else { fmt.Fprintln(os.Stderr, err) } }) if repl { continue } else { os.Exit(1) } } else { if repl { colortext(ct.Black, true, func() { if v == vm.NilValue || !v.IsValid() { fmt.Println("nil") } else { s, ok := v.Interface().(fmt.Stringer) if v.Kind() != reflect.String && ok { fmt.Println(s) } else { fmt.Printf("%#v\n", v.Interface()) } } }) } else { break } } } }
func runREPL() { fmt.Fprintf(os.Stderr, `# For more info about .ank scripts, see https://github.com/mattn/anko. # In filtering script, DCPL defines variable 'event' which has following structure: # # type Event struct { # Type string # Key string # Value []byte # } # # This REPL has preloaded event in 'event' variable, where Value is JSON encoded object. So that # the simples filtering script might look like this: # # json = import("json") # time = import("time") # # func filter(event) { # if event.Type != "mutation" { # return false # } # releaseDate, err = time.Parse(time.RFC3339, "2015-08-15T01:01:42+08:00") # if err != nil { # return false # } # val, err = json.Unmarshal(event.Value) # if err != nil { # return false # } # documentDate, err = time.Parse(time.RFC3339, toString(val.LastViewDate)) # if err != nil { # return false # } # return val.Type == "ad-view" && documentDate.After(releaseDate) # } # # filter(event) `) var ( code string following bool ) event := Event{ Type: "mutation", Key: "foo", Value: []byte(`{ "Type": "ad-view", "ObjectId": 43827, "ProfileId": 39524, "Count": 5, "Referrers": ["http://example.com", "http://google.com/search"], "LastViewDate": "2015-09-27T12:01:31+03:00" }`), } env := NewAnkEnv() env.Define("event", reflect.ValueOf(event)) reader := bufio.NewReader(os.Stdin) for { if following { fmt.Print(" ") } else { fmt.Print("> ") } b, _, err := reader.ReadLine() if err != nil { break } if len(b) == 0 { continue } if code != "" { code += "\n" } code += string(b) scanner := new(parser.Scanner) scanner.Init(code) stmts, err := parser.Parse(scanner) if e, ok := err.(*parser.Error); ok { if e.Pos.Column == len(b) && !e.Fatal { following = true continue } if e.Error() == "unexpected EOF" || strings.Contains(e.Error(), "unexpected $end") { following = true continue } } following = false code = "" v := vm.NilValue if err == nil { v, err = vm.Run(stmts, env) } if err != nil { if e, ok := err.(*vm.Error); ok { fmt.Fprintf(os.Stderr, "VM error at %d: %s\n", e.Pos.Line, err) } else if e, ok := err.(*parser.Error); ok { fmt.Fprintf(os.Stderr, "Parser error at %d: %s\n", e.Pos.Line, err) } else { fmt.Fprintln(os.Stderr, err) } } else { if v == vm.NilValue || !v.IsValid() { fmt.Println("nil") } else { s, ok := v.Interface().(fmt.Stringer) if v.Kind() != reflect.String && ok { fmt.Println(s) } else { fmt.Printf("%#v\n", v.Interface()) } } } } }
func serveApiPlay(w http.ResponseWriter, r *http.Request) { code := r.FormValue("code") scanner := new(parser.Scanner) scanner.Init(code) stmts, err := parser.Parse(scanner) if e, ok := err.(*parser.Error); ok { w.WriteHeader(500) fmt.Fprintf(w, "%d: %s\n", e.Pos.Line, err) return } w.Header().Set("Content-Type", "text/plain; charset=utf-8") env := vm.NewEnv() anko_core.Import(env) tbl := map[string]func(env *vm.Env) *vm.Env{ "encoding/json": anko_encoding_json.Import, "flag": anko_flag.Import, "fmt": anko_fmt.Import, "io": anko_io.Import, "io/ioutil": anko_io_ioutil.Import, "math": anko_math.Import, "net": anko_net.Import, "net/http": anko_net_http.Import, "net/url": anko_net_url.Import, "os": anko_os.Import, "os/exec": anko_os_exec.Import, "path": anko_path.Import, "path/filepath": anko_path_filepath.Import, "regexp": anko_regexp.Import, "sort": anko_sort.Import, "strings": anko_strings.Import, "github.com/daviddengcn/go-colortext": anko_colortext.Import, } env.Define("import", reflect.ValueOf(func(s string) interface{} { if loader, ok := tbl[s]; ok { return loader(env) } panic(fmt.Sprintf("package '%s' not found", s)) })) env.Define("println", reflect.ValueOf(func(a ...interface{}) { fmt.Fprint(w, fmt.Sprintln(a...)) })) env.Define("print", reflect.ValueOf(func(a ...interface{}) { fmt.Fprint(w, fmt.Sprint(a...)) })) env.Define("panic", reflect.ValueOf(func(a ...interface{}) { w.WriteHeader(500) fmt.Fprintf(w, "Can't use panic()") return })) env.Define("load", reflect.ValueOf(func(a ...interface{}) { w.WriteHeader(500) fmt.Fprintf(w, "Can't use load()") return })) defer env.Destroy() _, err = vm.Run(stmts, env) if err != nil { w.WriteHeader(500) if e, ok := err.(*vm.Error); ok { fmt.Fprintf(w, "%d: %s\n", e.Pos.Line, err) } else if e, ok := err.(*parser.Error); ok { fmt.Fprintf(w, "%d: %s\n", e.Pos.Line, err) } else { fmt.Fprintln(w, e.Error()) } } }
func ankoCmd(filename string) error { fmt.Println("ANKO " + filename) if len(filename) == 0 { err := errors.New("Please specify an Anko script file") printError(err) return err } file, err := os.Open(filename) if err != nil { printError(err) return err } env := vm.NewEnv() anko_core.Import(env) anko_flag.Import(env) anko_net.Import(env) anko_encoding.Import(env) anko_os.Import(env) anko_io.Import(env) anko_math.Import(env) anko_path.Import(env) anko_regexp.Import(env) anko_sort.Import(env) anko_strings.Import(env) anko_term.Import(env) var ln, code string lnScanner := bufio.NewScanner(file) for lnScanner.Scan() { ln = lnScanner.Text() code = code + ln + "\n" if err != nil { break printError(err) return err } } scanner := new(parser.Scanner) scanner.Init(code) stmts, err := parser.Parse(scanner) if err != nil { printError(err) return err } _, err = vm.Run(stmts, env) if err != nil { printError(err) return err } file.Close() return err }
func main() { flag.IntVar(&batchSize, "batch-size", 0, "the maximum size of websockets frame (0 - disable batching)") flag.StringVar(&clusterURI, "cluster-uri", "couchbase://localhost/", "URI of Couchbase cluster") flag.StringVar(&address, "address", "localhost:12345", "interface and port to bind the server") flag.StringVar(&filterScriptPath, "filter-script", "", ".ank script to filter values (bypass all event by default)") flag.BoolVar(&debug, "debug", false, "export pprof and expvars") flag.BoolVar(&repl, "repl", false, "run REPL to test and debug .ank scripts") flag.Parse() if repl { runREPL() return } log.Printf("GOMAXPROCS=%d\n", runtime.GOMAXPROCS(-1)) if filterScriptPath != "" { filterScriptPath = path.Clean(filterScriptPath) file, err := os.Open(filterScriptPath) if err != nil { log.Fatal(err) } content, err := ioutil.ReadAll(file) if err != nil && err != io.EOF { log.Fatal(err) } scanner := new(parser.Scanner) scanner.Init(string(content)) filterScript, err = parser.Parse(scanner) if err != nil { if e, ok := err.(*parser.Error); ok { log.Fatalf("%s:%d:%d: %s\n", filterScriptPath, e.Pos.Line, e.Pos.Column, err) } else { log.Fatal(err) } } log.Printf("filter script: %v\n", filterScriptPath) } log.Printf("cluster URI: %v\n", clusterURI) log.Printf("batch size: %v bytes\n", batchSize) server := websocket.Server{ Handler: onConnected, Handshake: checkAuth, } mux := http.NewServeMux() mux.Handle("/ws/", server) mux.HandleFunc("/http/", httpHandler) log.Printf("GET /ws/ # websockets endpoint") log.Printf("GET /http/ # HTTP endpoint with chunked encoding") if debug { initDebug(mux) log.Printf("GET /debug/pprof/ # pprof reports") log.Printf("GET /debug/vars/ # expvar metrics") } log.Printf("listening at %s", address) err := http.ListenAndServe(address, mux) if err != nil { log.Fatal(err) } }
func Import(env *vm.Env) *vm.Env { env.Define("len", reflect.ValueOf(func(v interface{}) int64 { rv := reflect.ValueOf(v) if rv.Kind() == reflect.Interface { rv = rv.Elem() } if rv.Kind() == reflect.String { return int64(len([]byte(rv.String()))) } if rv.Kind() != reflect.Array && rv.Kind() != reflect.Slice { panic("Argument #1 should be array") } return int64(rv.Len()) })) env.Define("keys", reflect.ValueOf(func(v interface{}) []string { rv := reflect.ValueOf(v) if rv.Kind() == reflect.Interface { rv = rv.Elem() } if rv.Kind() != reflect.Map { panic("Argument #1 should be map") } keys := []string{} mk := rv.MapKeys() for _, key := range mk { keys = append(keys, key.String()) } return keys })) env.Define("range", reflect.ValueOf(func(args ...int64) []int64 { if len(args) < 1 { panic("Missing arguments") } if len(args) > 2 { panic("Too many arguments") } var min, max int64 if len(args) == 1 { min = 0 max = args[0] - 1 } else { min = args[0] max = args[1] } arr := []int64{} for i := min; i <= max; i++ { arr = append(arr, i) } return arr })) env.Define("toBytes", reflect.ValueOf(func(s string) []byte { return []byte(s) })) env.Define("toRunes", reflect.ValueOf(func(s string) []rune { return []rune(s) })) env.Define("toString", reflect.ValueOf(func(v interface{}) string { return fmt.Sprint(v) })) env.Define("toInt", reflect.ValueOf(func(v interface{}) int64 { nt := reflect.TypeOf(1) rv := reflect.ValueOf(v) if rv.Type().ConvertibleTo(nt) { return 0 } return rv.Convert(nt).Int() })) env.Define("toFloat", reflect.ValueOf(func(v interface{}) float64 { nt := reflect.TypeOf(1.0) rv := reflect.ValueOf(v) if rv.Type().ConvertibleTo(nt) { return 0.0 } return rv.Convert(nt).Float() })) env.Define("toBool", reflect.ValueOf(func(v interface{}) bool { nt := reflect.TypeOf(true) rv := reflect.ValueOf(v) if rv.Type().ConvertibleTo(nt) { return false } return rv.Convert(nt).Bool() })) env.Define("toChar", reflect.ValueOf(func(s rune) string { return string(s) })) env.Define("toRune", reflect.ValueOf(func(s string) rune { if len(s) == 0 { return 0 } return []rune(s)[0] })) env.Define("string", reflect.ValueOf(func(b []byte) string { return string(b) })) env.Define("typeof", reflect.ValueOf(func(v interface{}) string { return reflect.TypeOf(v).String() })) env.Define("defined", reflect.ValueOf(func(s string) bool { _, err := env.Get(s) return err == nil })) env.Define("load", reflect.ValueOf(func(s string) interface{} { body, err := ioutil.ReadFile(s) if err != nil { panic(err) } scanner := new(parser.Scanner) scanner.Init(string(body)) stmts, err := parser.Parse(scanner) if err != nil { if pe, ok := err.(*parser.Error); ok { pe.Filename = s panic(pe) } panic(err) } rv, err := vm.Run(stmts, env) if err != nil { panic(err) } if rv.IsValid() && rv.CanInterface() { return rv.Interface() } return nil })) env.Define("panic", reflect.ValueOf(func(e interface{}) { os.Setenv("ANKO_DEBUG", "1") panic(e) })) env.Define("print", reflect.ValueOf(fmt.Print)) env.Define("println", reflect.ValueOf(fmt.Println)) env.Define("printf", reflect.ValueOf(fmt.Printf)) return env }