├── .github └── FUNDING.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── _example └── scripts │ ├── anonymous-call.ank │ ├── chan.ank │ ├── env.ank │ ├── example.ank │ ├── exec.ank │ ├── fib-for.ank │ ├── fib-recursion.ank │ ├── for-break-continue.ank │ ├── http.ank │ ├── module.ank │ ├── regexp.ank │ ├── server.ank │ ├── signal.ank │ ├── slice.ank │ ├── socket.ank │ ├── toType.ank │ ├── try-catch.ank │ ├── url.ank │ └── z-combinator.ank ├── anko.go ├── anko.png ├── anko_test.go ├── ast ├── ast.go ├── astutil │ ├── walk.go │ └── walk_test.go ├── doc.go ├── expr.go ├── operator.go ├── pos.go └── stmt.go ├── cmd └── anko-package-gen │ └── main.go ├── core ├── core.go ├── testdata │ ├── broken.ank │ ├── chan.ank │ ├── core_test.go │ ├── error.ank │ ├── for.ank │ ├── func.ank │ ├── if.ank │ ├── len.ank │ ├── let.ank │ ├── op.ank │ ├── sort.ank │ ├── switch.ank │ ├── test.ank │ ├── testing.ank │ ├── toBytes.ank │ ├── toRunes.ank │ ├── toString.ank │ └── toX_test.go └── toX.go ├── env ├── env.go ├── envExternalLookup_test.go ├── envTypes.go ├── envTypes_test.go ├── envValues.go ├── envValues_test.go └── env_test.go ├── go.mod ├── misc ├── vim │ ├── ftdetect │ │ └── ank.vim │ ├── ftplugin │ │ └── anko │ │ │ ├── comment.vim │ │ │ └── play.vim │ └── syntax │ │ └── anko.vim └── wasm │ ├── anko.go │ ├── index.html │ └── wasm_exec.js ├── packages ├── bytes.go ├── bytesGo17.go ├── bytesNotGo17.go ├── encoding.json.go ├── errors.go ├── flag.go ├── fmt.go ├── io.go ├── io.ioutil.go ├── log.go ├── math.big.go ├── math.go ├── math.rand.go ├── net.go ├── net.http.cookiejar.go ├── net.http.go ├── net.url.go ├── os.exec.go ├── os.go ├── os.signal.go ├── osAppEngine.go ├── osNotAppEngine.go ├── path.filepath.go ├── path.go ├── regexp.go ├── runtime.go ├── sort.go ├── sortGo18.go ├── sortNotGo18.go ├── strconv.go ├── strings.go ├── stringsGo110.go ├── stringsNotGo110.go ├── sync.go ├── syncGo19.go ├── syncNotGo19.go ├── time.go ├── timeGo110.go ├── timeGo18.go ├── timeNotGo110.go └── timeNotGo18.go ├── parser ├── Makefile ├── lexer.go ├── parser.go └── parser.go.y └── vm ├── doc.go ├── example_containers_test.go ├── example_functions_test.go ├── example_operators_test.go ├── example_packages_test.go ├── example_test.go ├── main_test.go ├── packagesGo110_test.go ├── packages_test.go ├── vm.go ├── vmContainers_test.go ├── vmConvertToX.go ├── vmConvertToXGo112.go ├── vmConvertToXNotGo112.go ├── vmExpr.go ├── vmExprFunction.go ├── vmFunctions_test.go ├── vmLetExpr.go ├── vmOperator.go ├── vmOperators_test.go ├── vmStmt.go ├── vmToX.go ├── vm_Go19_test.go ├── vm_NotGo19_test.go └── vm_test.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: mattn # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: mattn # Replace with a single Patreon username 5 | open_collective: mattn # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | custom: # Replace with a single custom sponsorship URL 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | anko 2 | anko.exe 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.8.x 5 | - 1.9.x 6 | - 1.10.x 7 | - 1.11.x 8 | - 1.12.x 9 | - 1.13.x 10 | - 1.14.x 11 | 12 | env: 13 | secure: "ELC4rD8nn2l5T48WYbTfcbwGGBmNxl7LAu05hgx5AB9/KA+oD3oBKIJkZqD512gJ31Gtyla/hG9QOgU7LikfWdpGuJjVILy01ZqtgP5SSKsrTdlln1D5pK1ZyHJNrEPevb3W5PYn9ahHnjKGtpobXj4/E0sCXfRPH67jv9hffYs=" 14 | 15 | before_install: 16 | - go get -u github.com/haya14busa/goverage 17 | 18 | script: 19 | - goverage -v -coverprofile=coverage.txt -covermode=count ./vm ./env . ./ast/astutil 20 | 21 | after_success: 22 | - bash <(curl -s https://codecov.io/bash) 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2018 Yasuhiro Matsumoto, http://mattn.kaoriya.net 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Anko 2 | 3 | [![GoDoc Reference](https://godoc.org/github.com/mattn/anko/vm?status.svg)](http://godoc.org/github.com/mattn/anko/vm) 4 | [![Build Status](https://travis-ci.org/mattn/anko.svg?branch=master)](https://travis-ci.org/mattn/anko) 5 | [![Financial Contributors on Open Collective](https://opencollective.com/mattn-anko/all/badge.svg?label=financial+contributors)](https://opencollective.com/mattn-anko) [![Coverage](https://codecov.io/gh/mattn/anko/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/anko) 6 | [![Go Report Card](https://goreportcard.com/badge/github.com/mattn/anko)](https://goreportcard.com/report/github.com/mattn/anko) 7 | 8 | Anko is a scriptable interpreter written in Go. 9 | 10 | ![](https://raw.githubusercontent.com/mattn/anko/master/anko.png) 11 | 12 | (Picture licensed under CC BY-SA 3.0, photo by Ocdp) 13 | 14 | 15 | ## Usage Example - Embedded 16 | 17 | ```go 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "log" 23 | 24 | "github.com/mattn/anko/env" 25 | "github.com/mattn/anko/vm" 26 | ) 27 | 28 | func main() { 29 | e := env.NewEnv() 30 | 31 | err := e.Define("println", fmt.Println) 32 | if err != nil { 33 | log.Fatalf("Define error: %v\n", err) 34 | } 35 | 36 | script := ` 37 | println("Hello World :)") 38 | ` 39 | 40 | _, err = vm.Execute(e, nil, script) 41 | if err != nil { 42 | log.Fatalf("Execute error: %v\n", err) 43 | } 44 | 45 | // output: Hello World :) 46 | } 47 | ``` 48 | 49 | More examples are located in the GoDoc: 50 | 51 | https://godoc.org/github.com/mattn/anko/vm 52 | 53 | 54 | ## Usage Example - Command Line 55 | 56 | ### Building 57 | ``` 58 | go get github.com/mattn/anko 59 | go install github.com/mattn/anko 60 | ``` 61 | 62 | ### Running an Anko script file named script.ank 63 | ``` 64 | ./anko script.ank 65 | ``` 66 | 67 | ## Anko Script Quick Start 68 | ``` 69 | // declare variables 70 | x = 1 71 | y = x + 1 72 | 73 | // print using outside the script defined println function 74 | println(x + y) // 3 75 | 76 | // if else statement 77 | if x < 1 || y < 1 { 78 | println(x) 79 | } else if x < 1 && y < 1 { 80 | println(y) 81 | } else { 82 | println(x + y) 83 | } 84 | 85 | // slice 86 | a = []interface{1, 2, 3} 87 | println(a) // [1 2 3] 88 | println(a[0]) // 1 89 | 90 | // map 91 | a = map[interface]interface{"x": 1} 92 | println(a) // map[x:1] 93 | a.b = 2 94 | a["c"] = 3 95 | println(a["b"]) // 2 96 | println(a.c) // 3 97 | 98 | // struct 99 | a = make(struct { 100 | A int64, 101 | B float64 102 | }) 103 | a.A = 4 104 | a.B = 5.5 105 | println(a.A) // 4 106 | println(a.B) // 5.5 107 | 108 | // function 109 | func a (x) { 110 | println(x + 1) 111 | } 112 | a(5) // 6 113 | ``` 114 | 115 | 116 | ## Please note that the master branch is not stable 117 | 118 | The master branch language and API may change at any time. 119 | 120 | To mitigate breaking changes, please use tagged branches. New tagged branches will be created for breaking changes. 121 | 122 | 123 | ## Author 124 | 125 | Yasuhiro Matsumoto (a.k.a mattn) 126 | 127 | ## Contributors 128 | 129 | ### Code Contributors 130 | 131 | This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. 132 | 133 | 134 | ### Financial Contributors 135 | 136 | Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/mattn-anko/contribute)] 137 | 138 | #### Individuals 139 | 140 | 141 | 142 | #### Organizations 143 | 144 | Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/mattn-anko/contribute)] 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /_example/scripts/anonymous-call.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | func(x) { 4 | return func(y) { 5 | x(y) 6 | } 7 | }(func(z) { 8 | println("Yay!", z) 9 | })("hello world") 10 | -------------------------------------------------------------------------------- /_example/scripts/chan.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | c = make(chan int64) 4 | 5 | go func() { 6 | c <- 1 7 | c <- 2 8 | c <- 3 9 | }() 10 | 11 | println(<-c) 12 | println(<-c) 13 | println(<-c) 14 | -------------------------------------------------------------------------------- /_example/scripts/env.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | var os, runtime = import("os"), import("runtime") 4 | 5 | if runtime.GOOS == "windows" { 6 | println(os.Getenv("USERPROFILE")) 7 | } else { 8 | println(os.Getenv("HOME")) 9 | } 10 | -------------------------------------------------------------------------------- /_example/scripts/example.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | # declare function 4 | func foo(x){ 5 | return x + 1 6 | } 7 | 8 | func bar(x ...){ 9 | return len(x) 10 | } 11 | 12 | # declare variables 13 | x = 1 14 | y = x + 1 15 | 16 | # print values 17 | println(x * (y + 2 * x + foo(x) / 2)) 18 | 19 | # if/else condition 20 | if foo(y) >= 1 { 21 | println("こんにちわ世界") 22 | } else { 23 | println("Hello, World") 24 | } 25 | 26 | # array type 27 | a = [1,2,3] 28 | println(a) 29 | println(a[2]) 30 | println(len(a)) 31 | 32 | # map type 33 | m = {"foo": "bar", "bar": "baz"} 34 | for k in keys(m) { 35 | println(m[k]) 36 | } 37 | 38 | f = func(a) { 39 | println(a) 40 | } 41 | 42 | f("あんこ") 43 | 44 | f = func(a ...) { 45 | println(a) 46 | } 47 | 48 | f("あんこ", "だいすき") 49 | 50 | println(1 && 2) 51 | 52 | println(bar(1,2,3)) 53 | println("foo") 54 | println(toByteSlice("あいう")) 55 | println(toRuneSlice("あいう")) 56 | 57 | a = 1 58 | func foo() { 59 | a = 2 60 | } 61 | foo() 62 | println(a) 63 | 64 | module Foo { 65 | func bar1() { 66 | println("Foo.bar1") 67 | } 68 | } 69 | 70 | println(Foo.bar1()) 71 | -------------------------------------------------------------------------------- /_example/scripts/exec.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | var os, exec = import("os"), import("os/exec") 4 | 5 | cmd = exec.Command("ls", "-la") 6 | cmd.Stdout = os.Stdout 7 | cmd.Run() 8 | -------------------------------------------------------------------------------- /_example/scripts/fib-for.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | func fib(n) { 4 | a, b = 1, 1 5 | f = [] 6 | for i in range(n) { 7 | f += a 8 | b += a 9 | a = b - a 10 | } 11 | return f 12 | } 13 | 14 | 15 | println(fib(20)) 16 | -------------------------------------------------------------------------------- /_example/scripts/fib-recursion.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | func fib(n) { 4 | if n == 1 { 5 | return [1] 6 | } else if n == 2 { 7 | return [1,1] 8 | } else { 9 | t = fib(n-1) 10 | return t + (t[len(t)-1] + t[len(t)-2]) 11 | } 12 | } 13 | 14 | println(fib(20)) 15 | -------------------------------------------------------------------------------- /_example/scripts/for-break-continue.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | for i in [1,2,3,4,5] { 4 | if i == 2 { 5 | continue 6 | } 7 | println(i) 8 | if i > 3 { 9 | break 10 | } 11 | println("foo") 12 | } 13 | -------------------------------------------------------------------------------- /_example/scripts/http.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | var http, ioutil = import("net/http"), import("io/ioutil") 4 | 5 | r = http.DefaultClient.Get("http://golang.org/") 6 | b, _ = ioutil.ReadAll(r[0].Body) 7 | printf("%s", toString(b)) 8 | r[0].Body.Close() 9 | -------------------------------------------------------------------------------- /_example/scripts/module.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | module Foo { 4 | func bar1() { 5 | println("Foo.bar1") 6 | return 1 7 | } 8 | } 9 | 10 | println(Foo.bar1()) 11 | -------------------------------------------------------------------------------- /_example/scripts/regexp.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | var regexp = import("regexp") 4 | 5 | for s in regexp.MustCompile(`[\s_]`).Split("foo_bar_baz", -1) { 6 | println(s) 7 | } 8 | 9 | -------------------------------------------------------------------------------- /_example/scripts/server.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | var http = import("net/http") 4 | 5 | http.HandleFunc("/", func(w, r) { 6 | w.Write(toByteSlice("hello world")) 7 | }) 8 | http.ListenAndServe(":8080", nil) 9 | -------------------------------------------------------------------------------- /_example/scripts/signal.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | var os, signal, time = import("os"), import("os/signal"), import("time") 4 | 5 | c = make(chan os.Signal, 1) 6 | signal.Notify(c, os.Interrupt) 7 | go func() { 8 | <-c 9 | println("CTRL-C") 10 | os.Exit(0) 11 | }() 12 | 13 | d, _ = time.ParseDuration("10s") 14 | time.Sleep(d) 15 | -------------------------------------------------------------------------------- /_example/scripts/slice.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | a = make([]int64, 5) 4 | 5 | for i = 0; i < len(a); i++ { 6 | a[i] = i 7 | } 8 | for i in a { 9 | println(i) 10 | } 11 | -------------------------------------------------------------------------------- /_example/scripts/socket.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | var os, net, url, ioutil = import("os"), import("net"), import("net/url"), import("io/ioutil"); 4 | 5 | func connect(uri) { 6 | proxy = os.Getenv("http_proxy") 7 | if proxy != "" { 8 | u, e = url.Parse(proxy) 9 | if e != nil { 10 | return nil, e 11 | } 12 | return net.Dial("tcp", u.Host) 13 | } 14 | return net.Dial("tcp", uri) 15 | } 16 | 17 | c, e = connect("www.google.com:80") 18 | if e != nil { 19 | throw e 20 | } 21 | c.Write(toByteSlice("GET http://www.google.com/ HTTP/1.0\r\n\r\n")) 22 | b, e = ioutil.ReadAll(c) 23 | if e != nil { 24 | throw e 25 | } 26 | printf("%s", b) 27 | -------------------------------------------------------------------------------- /_example/scripts/toType.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | # toInt with ints, floats, strings, bools 4 | println("\ntoInt examples:\n===============") 5 | i = 1<<63 - 1 6 | println("int", i, "toInt:", toInt(i)) 7 | 8 | i = -1 << 63 9 | println("int", i, "toInt:", toInt(i)) 10 | 11 | f = 3.141592653589793 12 | println("float", f, "toInt:", toInt(f)) 13 | 14 | f = 1.797693134862315708145274237317043567981e18 15 | println("float", f, "toInt:", toInt(f)) 16 | 17 | f = -1.797693134862315708145274237317043567981e18 18 | println("float", f, "toInt:", toInt(f)) 19 | 20 | s = "4611686018427387904" 21 | println("string", s, "toInt:", toInt(s)) 22 | 23 | s = "-9223372036854775808" 24 | println("string", s, "toInt:", toInt(s)) 25 | 26 | s = "3.141592653589793" 27 | println("string", s, "toInt:", toInt(s)) 28 | 29 | s = "1.797693134862315708145274237317043567981e18" 30 | println("string", s, "toInt:", toInt(s)) 31 | 32 | s = "-1.797693134862315708145274237317043567981e18" 33 | println("string", s, "toInt:", toInt(s)) 34 | 35 | s = "1.797693134862315708145274237317043567981e-18" 36 | println("string", s, "toInt:", toInt(s)) 37 | 38 | b = true 39 | println("bool", b, "toInt:", toInt(b)) 40 | 41 | b = false 42 | println("bool", b, "toInt:", toInt(b)) 43 | 44 | println("\ntoFloat examples:\n=================") 45 | i = 1<<63 - 1 46 | println("int", i, "toFloat:", toFloat(i)) 47 | 48 | i = -1 << 63 49 | println("int", i, "toFloat:", toFloat(i)) 50 | 51 | s = "4611686018427387904" 52 | println("string", s, "toFloat:", toFloat(s)) 53 | 54 | s = "-9223372036854775808" 55 | println("string", s, "toFloat:", toFloat(s)) 56 | 57 | s = "3.141592653589793" 58 | println("string", s, "toFloat:", toFloat(s)) 59 | 60 | s = "1.797693134862315708145274237317043567981e18" 61 | println("string", s, "toFloat:", toFloat(s)) 62 | 63 | s = "-1.797693134862315708145274237317043567981e18" 64 | println("string", s, "toFloat:", toFloat(s)) 65 | 66 | s = "1.797693134862315708145274237317043567981e-18" 67 | println("string", s, "toFloat:", toFloat(s)) 68 | 69 | b = true 70 | println("bool", b, "toFloat:", toFloat(b)) 71 | 72 | b = false 73 | println("bool", b, "toFloat:", toFloat(b)) 74 | 75 | println("\ntoBool examples:\n================") 76 | i = 1 77 | println("int", i, "toBool:", toBool(i)) 78 | 79 | i = 0 80 | println("int", i, "toBool:", toBool(i)) 81 | 82 | i = -1 83 | println("int", i, "toBool:", toBool(i)) 84 | 85 | f = 1.0 86 | println("float", f, "toBool:", toBool(f)) 87 | 88 | f = 0.000000000001 89 | println("float", f, "toBool:", toBool(f)) 90 | 91 | f = 0.0 92 | println("float", f, "toBool:", toBool(f)) 93 | 94 | f = -0.0 95 | println("float", f, "toBool:", toBool(f)) 96 | 97 | s = "y" 98 | println("string", s, "toBool:", toBool(s)) 99 | 100 | s = "yEs" 101 | println("string", s, "toBool:", toBool(s)) 102 | 103 | s = "t" 104 | println("string", s, "toBool:", toBool(s)) 105 | 106 | s = "TrUe" 107 | println("string", s, "toBool:", toBool(s)) 108 | 109 | s = "1" 110 | println("string", s, "toBool:", toBool(s)) 111 | 112 | s = "0" 113 | println("string", s, "toBool:", toBool(s)) 114 | 115 | s = "f" 116 | println("string", s, "toBool:", toBool(s)) 117 | 118 | s = "FaLsE" 119 | println("string", s, "toBool:", toBool(s)) 120 | 121 | s = "foobar" 122 | println("string", s, "toBool:", toBool(s)) 123 | 124 | -------------------------------------------------------------------------------- /_example/scripts/try-catch.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | var http = import("net/http") 4 | 5 | try { 6 | http.Do() 7 | } catch { 8 | println("catch!") 9 | } finally { 10 | println("finally!") 11 | } 12 | 13 | try { 14 | http.Do() 15 | } catch e { 16 | println("catch!", e) 17 | } finally { 18 | println("finally!") 19 | } 20 | -------------------------------------------------------------------------------- /_example/scripts/url.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | var url = import("net/url") 4 | 5 | u, _ = url.Parse("http://www.google.com/search?q=こんにちわ世界") 6 | println(u.Path) 7 | println(u.Host) 8 | -------------------------------------------------------------------------------- /_example/scripts/z-combinator.ank: -------------------------------------------------------------------------------- 1 | #!anko 2 | 3 | func Z(f) { 4 | return (func(x) { 5 | return f(func(y) { 6 | return x(x)(y) 7 | }) 8 | })(func(x) { 9 | return f(func(y) { 10 | return x(x)(y) 11 | }) 12 | }) 13 | } 14 | 15 | println(Z(func(f) { return func(n) { return n == 0 ? 1 : n * f(n - 1) } })(5) == 120) 16 | -------------------------------------------------------------------------------- /anko.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package main 4 | 5 | import ( 6 | "bufio" 7 | "flag" 8 | "fmt" 9 | "io" 10 | "io/ioutil" 11 | "os" 12 | "strings" 13 | 14 | "github.com/mattn/anko/core" 15 | "github.com/mattn/anko/env" 16 | _ "github.com/mattn/anko/packages" 17 | "github.com/mattn/anko/parser" 18 | "github.com/mattn/anko/vm" 19 | ) 20 | 21 | const version = "0.1.8" 22 | 23 | var ( 24 | flagExecute string 25 | file string 26 | args []string 27 | e *env.Env 28 | ) 29 | 30 | func main() { 31 | var exitCode int 32 | 33 | parseFlags() 34 | setupEnv() 35 | if flagExecute != "" || flag.NArg() > 0 { 36 | exitCode = runNonInteractive() 37 | } else { 38 | exitCode = runInteractive() 39 | } 40 | 41 | os.Exit(exitCode) 42 | } 43 | 44 | func parseFlags() { 45 | flagVersion := flag.Bool("v", false, "prints out the version and then exits") 46 | flag.StringVar(&flagExecute, "e", "", "execute the Anko code") 47 | flag.Parse() 48 | 49 | if *flagVersion { 50 | fmt.Println(version) 51 | os.Exit(0) 52 | } 53 | 54 | if flagExecute != "" || flag.NArg() < 1 { 55 | args = flag.Args() 56 | return 57 | } 58 | 59 | file = flag.Arg(0) 60 | args = flag.Args()[1:] 61 | } 62 | 63 | func setupEnv() { 64 | e = env.NewEnv() 65 | e.Define("args", args) 66 | core.Import(e) 67 | } 68 | 69 | func runNonInteractive() int { 70 | var source string 71 | if flagExecute != "" { 72 | source = flagExecute 73 | } else { 74 | sourceBytes, err := ioutil.ReadFile(file) 75 | if err != nil { 76 | fmt.Println("ReadFile error:", err) 77 | return 2 78 | } 79 | source = string(sourceBytes) 80 | } 81 | 82 | _, err := vm.Execute(e, nil, source) 83 | if err != nil { 84 | fmt.Println("Execute error:", err) 85 | return 4 86 | } 87 | 88 | return 0 89 | } 90 | 91 | func runInteractive() int { 92 | var following bool 93 | var source string 94 | scanner := bufio.NewScanner(os.Stdin) 95 | 96 | parser.EnableErrorVerbose() 97 | 98 | for { 99 | if following { 100 | source += "\n" 101 | fmt.Print(" ") 102 | } else { 103 | fmt.Print("> ") 104 | } 105 | 106 | if !scanner.Scan() { 107 | break 108 | } 109 | source += scanner.Text() 110 | if source == "" { 111 | continue 112 | } 113 | if source == "quit()" { 114 | break 115 | } 116 | 117 | stmts, err := parser.ParseSrc(source) 118 | 119 | if e, ok := err.(*parser.Error); ok { 120 | es := e.Error() 121 | if strings.HasPrefix(es, "syntax error: unexpected") { 122 | if strings.HasPrefix(es, "syntax error: unexpected $end,") { 123 | following = true 124 | continue 125 | } 126 | } else { 127 | if e.Pos.Column == len(source) && !e.Fatal { 128 | fmt.Fprintln(os.Stderr, e) 129 | following = true 130 | continue 131 | } 132 | if e.Error() == "unexpected EOF" { 133 | following = true 134 | continue 135 | } 136 | } 137 | } 138 | 139 | following = false 140 | source = "" 141 | var v interface{} 142 | 143 | if err == nil { 144 | v, err = vm.Run(e, nil, stmts) 145 | } 146 | if err != nil { 147 | if e, ok := err.(*vm.Error); ok { 148 | fmt.Fprintf(os.Stderr, "%d:%d %s\n", e.Pos.Line, e.Pos.Column, err) 149 | } else if e, ok := err.(*parser.Error); ok { 150 | fmt.Fprintf(os.Stderr, "%d:%d %s\n", e.Pos.Line, e.Pos.Column, err) 151 | } else { 152 | fmt.Fprintln(os.Stderr, err) 153 | } 154 | continue 155 | } 156 | 157 | fmt.Printf("%#v\n", v) 158 | } 159 | 160 | if err := scanner.Err(); err != nil { 161 | if err != io.EOF { 162 | fmt.Fprintln(os.Stderr, "ReadString error:", err) 163 | return 12 164 | } 165 | } 166 | 167 | return 0 168 | } 169 | -------------------------------------------------------------------------------- /anko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattn/anko/3f269a72ff69398b1250c584171f32d12c0d8085/anko.png -------------------------------------------------------------------------------- /anko_test.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package main 4 | 5 | import ( 6 | "bufio" 7 | "io" 8 | "log" 9 | "os" 10 | "os/exec" 11 | "path/filepath" 12 | "runtime" 13 | "strings" 14 | "testing" 15 | "time" 16 | ) 17 | 18 | var logger *log.Logger 19 | 20 | func TestMain(m *testing.M) { 21 | parseFlags() 22 | code := m.Run() 23 | os.Exit(code) 24 | } 25 | 26 | func TestRunNonInteractiveFile(t *testing.T) { 27 | _, filename, _, _ := runtime.Caller(0) 28 | testDir := filepath.Join(filepath.Dir(filename), "core", "testdata") 29 | setupEnv() 30 | 31 | file = filepath.Join(testDir, "not-found.ank") 32 | exitCode := runNonInteractive() 33 | if exitCode != 2 { 34 | t.Fatalf("exitCode - received: %v - expected: %v", exitCode, 2) 35 | } 36 | 37 | file = filepath.Join(testDir, "broken.ank") 38 | exitCode = runNonInteractive() 39 | os.Args = []string{os.Args[0]} 40 | if exitCode != 4 { 41 | t.Fatalf("exitCode - received: %v - expected: %v", exitCode, 4) 42 | } 43 | 44 | file = filepath.Join(testDir, "test.ank") 45 | exitCode = runNonInteractive() 46 | os.Args = []string{os.Args[0]} 47 | if exitCode != 0 { 48 | t.Fatalf("exitCode - received: %v - expected: %v", exitCode, 0) 49 | } 50 | 51 | file = "" 52 | } 53 | 54 | func TestRunNonInteractiveExecute(t *testing.T) { 55 | setupEnv() 56 | 57 | flagExecute = "1 + 1" 58 | exitCode := runNonInteractive() 59 | if exitCode != 0 { 60 | t.Fatalf("exitCode - received: %v - expected: %v", exitCode, 0) 61 | } 62 | 63 | flagExecute = "1++" 64 | exitCode = runNonInteractive() 65 | if exitCode != 4 { 66 | t.Fatalf("exitCode - received: %v - expected: %v", exitCode, 4) 67 | } 68 | 69 | flagExecute = "" 70 | } 71 | 72 | type testInteractive struct { 73 | runLines []string 74 | runOutputs []string 75 | runError string 76 | } 77 | 78 | func TestRunInteractive(t *testing.T) { 79 | // empty strings in runOutputs will ignore read timeouts 80 | tests := []testInteractive{ 81 | {runLines: []string{".."}, runError: "1:1 syntax error on '.' at 1:1"}, 82 | {runLines: []string{"1++"}, runError: "1:1 invalid operation"}, 83 | {runLines: []string{"var , b = 1, 2"}, runError: "1:7 syntax error: unexpected ','"}, 84 | 85 | {runLines: []string{"", "1"}, runOutputs: []string{"", "1"}}, 86 | {runLines: []string{"1 + 1"}, runOutputs: []string{"2"}}, 87 | {runLines: []string{"a = 1", "b = 2", "a + b"}, runOutputs: []string{"1", "2", "3"}}, 88 | {runLines: []string{"a = 1", "if a == 1 {", "b = 1", "b = 2", "}", "a"}, runOutputs: []string{"1", "", "", "", "2", "1"}}, 89 | {runLines: []string{"a = 1", "for i = 0; i < 2; i++ {", "a++", "}", "a"}, runOutputs: []string{"1", "", "", "", "3"}}, 90 | {runLines: []string{"1 + 1", "// comment 1", "2 + 2 // comment 2", "// 3 + 3"}, runOutputs: []string{"2", "", "4", ""}}, 91 | } 92 | runInteractiveTests(t, tests) 93 | } 94 | 95 | func runInteractiveTests(t *testing.T, tests []testInteractive) { 96 | // create logger 97 | // Note: logger is used for debugging since real stdout cannot be used 98 | logger = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.LUTC|log.Llongfile) 99 | gopath := os.Getenv("GOPATH") 100 | if gopath == "" { 101 | b, err := exec.Command("go", "env", "GOPATH").CombinedOutput() 102 | if err != nil { 103 | t.Fatal(err) 104 | } 105 | gopath = strings.TrimSpace(string(b)) 106 | } 107 | filehandle, err := os.OpenFile(filepath.Join(gopath, "bin", "anko_test.log"), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) 108 | if err != nil { 109 | t.Fatal("OpenFile error:", err) 110 | } 111 | defer filehandle.Close() 112 | logger.SetOutput(filehandle) 113 | logger.Print("logger file created") 114 | 115 | // defer sending std back to real 116 | realStdin := os.Stdin 117 | realStderr := os.Stderr 118 | realStdout := os.Stdout 119 | defer setStd(realStdin, realStderr, realStdout) 120 | 121 | // create pipes 122 | readFromIn, writeToIn, err := os.Pipe() 123 | if err != nil { 124 | t.Fatal("Pipe error:", err) 125 | } 126 | os.Stdin = readFromIn 127 | logger.Print("pipe in created") 128 | readFromErr, writeToErr, err := os.Pipe() 129 | if err != nil { 130 | t.Fatal("Pipe error:", err) 131 | } 132 | os.Stderr = writeToErr 133 | logger.Print("pipe err created") 134 | readFromOut, writeToOut, err := os.Pipe() 135 | if err != nil { 136 | t.Fatal("Pipe error:", err) 137 | } 138 | os.Stdout = writeToOut 139 | logger.Print("pipe out created") 140 | 141 | // setup reader 142 | readerErr := bufio.NewReaderSize(readFromErr, 256) 143 | readerOut := bufio.NewReaderSize(readFromOut, 256) 144 | chanQuit := make(chan struct{}, 1) 145 | chanErr := make(chan string, 3) 146 | chanOut := make(chan string, 3) 147 | readTimeout := 10 * time.Millisecond 148 | var dataErr string 149 | var dataOut string 150 | 151 | go readerToChan(t, chanQuit, readerErr, chanErr) 152 | go readerToChan(t, chanQuit, readerOut, chanOut) 153 | 154 | go runInteractive() 155 | 156 | time.Sleep(readTimeout) 157 | 158 | // basic read and write to make sure things are working 159 | _, err = writeToIn.WriteString("1\n") 160 | if err != nil { 161 | t.Fatal("Stdin WriteString error:", err) 162 | } 163 | select { 164 | case dataOut = <-chanOut: 165 | if len(dataOut) > 0 && dataOut[0] == '>' { 166 | dataOut = dataOut[1:] 167 | dataOut = strings.TrimSpace(dataOut) 168 | } 169 | if dataOut != "1" { 170 | t.Fatalf("Stdout - received: %v - expected: %v - basic test", dataOut, "1") 171 | } 172 | case dataErr = <-chanErr: 173 | dataErr = strings.TrimSpace(dataErr) 174 | if dataErr != "" { 175 | t.Fatalf("Stderr - received: %v - expected: %v - basic test", dataErr, "") 176 | } 177 | case <-time.After(readTimeout): 178 | t.Fatal("read timeout for basic test") 179 | } 180 | 181 | // run tests 182 | logger.Print("running tests start") 183 | for _, test := range tests { 184 | 185 | for i, runLine := range test.runLines { 186 | 187 | _, err = writeToIn.WriteString(runLine + "\n") 188 | if err != nil { 189 | t.Fatal("Stdin WriteString error:", err) 190 | } 191 | 192 | select { 193 | case <-time.After(readTimeout): 194 | if test.runOutputs[i] != "" { 195 | t.Fatalf("read timeout for i: %v - runLines: %v", i, test.runLines) 196 | } 197 | case dataOut = <-chanOut: 198 | for len(dataOut) > 0 && dataOut[0] == '>' { 199 | dataOut = dataOut[1:] 200 | dataOut = strings.TrimSpace(dataOut) 201 | } 202 | if dataOut != test.runOutputs[i] { 203 | t.Fatalf("Stdout - received: %v - expected: %v - i: %v - runLines: %v", dataOut, test.runOutputs[i], i, test.runLines) 204 | } 205 | case dataErr = <-chanErr: 206 | dataErr = strings.TrimSpace(dataErr) 207 | if dataErr != test.runError { 208 | t.Fatalf("Stderr - received: %v - expected: %v - i: %v - runLines: %v", dataErr, test.runError, i, test.runLines) 209 | } 210 | 211 | // to clean output from error 212 | _, err = writeToIn.WriteString("1\n") 213 | if err != nil { 214 | t.Fatal("Stdin WriteString error:", err) 215 | } 216 | 217 | select { 218 | case dataOut = <-chanOut: 219 | for len(dataOut) > 0 && dataOut[0] == '>' { 220 | dataOut = dataOut[1:] 221 | dataOut = strings.TrimSpace(dataOut) 222 | } 223 | if dataOut != "1" { 224 | t.Fatalf("Stdout - received: %v - expected: %v - i: %v - runLines: %v", dataOut, test.runOutputs[i], i, test.runLines) 225 | } 226 | case <-time.After(readTimeout): 227 | t.Fatalf("read timeout for i: %v - runLines: %v", i, test.runLines) 228 | } 229 | 230 | } 231 | 232 | } 233 | 234 | } 235 | logger.Print("running tests end") 236 | 237 | // quit 238 | _, err = writeToIn.WriteString("quit()\n") 239 | if err != nil { 240 | t.Fatal("Stdin WriteString error:", err) 241 | } 242 | logger.Print("quit() sent") 243 | 244 | close(chanQuit) 245 | logger.Print("chanQuit closed") 246 | 247 | writeToErr.Close() 248 | writeToOut.Close() 249 | logger.Print("pipes closed") 250 | } 251 | 252 | func readerToChan(t *testing.T, chanQuit chan struct{}, reader *bufio.Reader, chanOut chan string) { 253 | logger.Print("readerToChan start") 254 | for { 255 | data, err := reader.ReadString('\n') 256 | if err != nil && err != io.EOF { 257 | t.Fatal("readerToChan ReadString error:", err) 258 | } 259 | select { 260 | case <-chanQuit: 261 | logger.Print("readerToChan end") 262 | return 263 | default: 264 | } 265 | chanOut <- data 266 | } 267 | } 268 | 269 | func setStd(stdin *os.File, stderr *os.File, stdout *os.File) { 270 | os.Stdin = stdin 271 | os.Stderr = stderr 272 | os.Stdout = stdout 273 | } 274 | -------------------------------------------------------------------------------- /ast/ast.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | // Token is used in the lexer to split characters into a string called a token 4 | type Token struct { 5 | PosImpl 6 | Tok int 7 | Lit string 8 | } 9 | 10 | // TypeKind is the kinds of types 11 | type TypeKind int 12 | 13 | const ( 14 | // TypeDefault default type 15 | TypeDefault TypeKind = iota 16 | // TypePtr ptr type 17 | TypePtr 18 | // TypeSlice slice type 19 | TypeSlice 20 | // TypeMap map type 21 | TypeMap 22 | // TypeChan chan type 23 | TypeChan 24 | // TypeStructType struct type 25 | TypeStructType 26 | ) 27 | 28 | // TypeStruct is the type and sub-types 29 | type TypeStruct struct { 30 | Kind TypeKind 31 | Env []string 32 | Name string 33 | Dimensions int 34 | SubType *TypeStruct 35 | Key *TypeStruct 36 | StructNames []string 37 | StructTypes []*TypeStruct 38 | } 39 | -------------------------------------------------------------------------------- /ast/astutil/walk.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package astutil 4 | 5 | import ( 6 | "fmt" 7 | "reflect" 8 | 9 | "github.com/mattn/anko/ast" 10 | ) 11 | 12 | // WalkFunc is used in Walk to walk the AST 13 | type WalkFunc func(interface{}) error 14 | 15 | // Walk walks the ASTs associated with a statement list generated by parser.ParseSrc 16 | // each expression and/or statement is passed to the WalkFunc function. 17 | // If the WalkFunc returns an error the walk is aborted and the error is returned 18 | func Walk(stmt ast.Stmt, f WalkFunc) error { 19 | return walkStmt(stmt, f) 20 | } 21 | 22 | func walkStmts(stmts []ast.Stmt, f WalkFunc) error { 23 | for _, stmt := range stmts { 24 | if err := walkStmt(stmt, f); err != nil { 25 | return err 26 | } 27 | } 28 | return nil 29 | } 30 | 31 | func walkExprs(exprs []ast.Expr, f WalkFunc) error { 32 | for _, exp := range exprs { 33 | if err := walkExpr(exp, f); err != nil { 34 | return err 35 | } 36 | } 37 | return nil 38 | } 39 | 40 | func walkStmt(stmt ast.Stmt, f WalkFunc) error { 41 | //short circuit out if there are no functions 42 | if stmt == nil || f == nil { 43 | return nil 44 | } 45 | if err := callFunc(stmt, f); err != nil { 46 | return err 47 | } 48 | switch stmt := stmt.(type) { 49 | case *ast.StmtsStmt: 50 | if err := walkStmts(stmt.Stmts, f); err != nil { 51 | return err 52 | } 53 | case *ast.BreakStmt: 54 | case *ast.ContinueStmt: 55 | case *ast.LetMapItemStmt: 56 | if err := walkExpr(stmt.RHS, f); err != nil { 57 | return err 58 | } 59 | return walkExprs(stmt.LHSS, f) 60 | case *ast.ReturnStmt: 61 | return walkExprs(stmt.Exprs, f) 62 | case *ast.ExprStmt: 63 | return walkExpr(stmt.Expr, f) 64 | case *ast.VarStmt: 65 | return walkExprs(stmt.Exprs, f) 66 | case *ast.LetsStmt: 67 | if err := walkExprs(stmt.RHSS, f); err != nil { 68 | return err 69 | } 70 | return walkExprs(stmt.LHSS, f) 71 | case *ast.IfStmt: 72 | if err := walkExpr(stmt.If, f); err != nil { 73 | return err 74 | } 75 | if err := walkStmt(stmt.Then, f); err != nil { 76 | return err 77 | } 78 | if err := walkStmts(stmt.ElseIf, f); err != nil { 79 | return err 80 | } 81 | if err := walkStmt(stmt.Else, f); err != nil { 82 | return err 83 | } 84 | case *ast.TryStmt: 85 | if err := walkStmt(stmt.Try, f); err != nil { 86 | return err 87 | } 88 | if err := walkStmt(stmt.Catch, f); err != nil { 89 | return err 90 | } 91 | if err := walkStmt(stmt.Finally, f); err != nil { 92 | return err 93 | } 94 | case *ast.LoopStmt: 95 | if err := walkExpr(stmt.Expr, f); err != nil { 96 | return err 97 | } 98 | if err := walkStmt(stmt.Stmt, f); err != nil { 99 | return err 100 | } 101 | case *ast.ForStmt: 102 | if err := walkExpr(stmt.Value, f); err != nil { 103 | return err 104 | } 105 | if err := walkStmt(stmt.Stmt, f); err != nil { 106 | return err 107 | } 108 | case *ast.CForStmt: 109 | if err := walkStmt(stmt.Stmt1, f); err != nil { 110 | return err 111 | } 112 | if err := walkExpr(stmt.Expr2, f); err != nil { 113 | return err 114 | } 115 | if err := walkExpr(stmt.Expr3, f); err != nil { 116 | return err 117 | } 118 | if err := walkStmt(stmt.Stmt, f); err != nil { 119 | return err 120 | } 121 | case *ast.ThrowStmt: 122 | if err := walkExpr(stmt.Expr, f); err != nil { 123 | return err 124 | } 125 | case *ast.ModuleStmt: 126 | if err := walkStmt(stmt.Stmt, f); err != nil { 127 | return err 128 | } 129 | case *ast.SwitchStmt: 130 | if err := walkExpr(stmt.Expr, f); err != nil { 131 | return err 132 | } 133 | for _, switchCaseStmt := range stmt.Cases { 134 | caseStmt := switchCaseStmt.(*ast.SwitchCaseStmt) 135 | if err := walkStmt(caseStmt.Stmt, f); err != nil { 136 | return err 137 | } 138 | } 139 | if err := walkStmt(stmt.Default, f); err != nil { 140 | return err 141 | } 142 | case *ast.GoroutineStmt: 143 | return walkExpr(stmt.Expr, f) 144 | default: 145 | return fmt.Errorf("unknown statement %v", reflect.TypeOf(stmt)) 146 | } 147 | return nil 148 | } 149 | 150 | func walkExpr(expr ast.Expr, f WalkFunc) error { 151 | //short circuit out if there are no functions 152 | if expr == nil || f == nil { 153 | return nil 154 | } 155 | if err := callFunc(expr, f); err != nil { 156 | return err 157 | } 158 | switch expr := expr.(type) { 159 | case *ast.OpExpr: 160 | return walkOperator(expr.Op, f) 161 | case *ast.LenExpr: 162 | case *ast.LiteralExpr: 163 | case *ast.IdentExpr: 164 | case *ast.MemberExpr: 165 | return walkExpr(expr.Expr, f) 166 | case *ast.ItemExpr: 167 | if err := walkExpr(expr.Item, f); err != nil { 168 | return err 169 | } 170 | return walkExpr(expr.Index, f) 171 | case *ast.SliceExpr: 172 | if err := walkExpr(expr.Item, f); err != nil { 173 | return err 174 | } 175 | if err := walkExpr(expr.Begin, f); err != nil { 176 | return err 177 | } 178 | return walkExpr(expr.End, f) 179 | case *ast.ArrayExpr: 180 | return walkExprs(expr.Exprs, f) 181 | case *ast.MapExpr: 182 | for i := range expr.Keys { 183 | if err := walkExpr(expr.Keys[i], f); err != nil { 184 | return err 185 | } 186 | if err := walkExpr(expr.Values[i], f); err != nil { 187 | return err 188 | } 189 | } 190 | case *ast.DerefExpr: 191 | return walkExpr(expr.Expr, f) 192 | case *ast.AddrExpr: 193 | return walkExpr(expr.Expr, f) 194 | case *ast.UnaryExpr: 195 | return walkExpr(expr.Expr, f) 196 | case *ast.ParenExpr: 197 | return walkExpr(expr.SubExpr, f) 198 | case *ast.FuncExpr: 199 | return walkStmt(expr.Stmt, f) 200 | case *ast.LetsExpr: 201 | if err := walkExprs(expr.LHSS, f); err != nil { 202 | return err 203 | } 204 | return walkExprs(expr.RHSS, f) 205 | case *ast.AnonCallExpr: 206 | if err := walkExpr(expr.Expr, f); err != nil { 207 | return err 208 | } 209 | return walkExpr(&ast.CallExpr{Func: reflect.Value{}, SubExprs: expr.SubExprs, VarArg: expr.VarArg, Go: expr.Go}, f) 210 | case *ast.CallExpr: 211 | return walkExprs(expr.SubExprs, f) 212 | case *ast.TernaryOpExpr: 213 | if err := walkExpr(expr.Expr, f); err != nil { 214 | return err 215 | } 216 | if err := walkExpr(expr.LHS, f); err != nil { 217 | return err 218 | } 219 | return walkExpr(expr.RHS, f) 220 | case *ast.ImportExpr: 221 | return walkExpr(expr.Name, f) 222 | case *ast.MakeExpr: 223 | if err := walkExpr(expr.LenExpr, f); err != nil { 224 | return err 225 | } 226 | return walkExpr(expr.CapExpr, f) 227 | case *ast.ChanExpr: 228 | if err := walkExpr(expr.RHS, f); err != nil { 229 | return err 230 | } 231 | return walkExpr(expr.LHS, f) 232 | case *ast.IncludeExpr: 233 | if err := walkExpr(expr.ItemExpr, f); err != nil { 234 | return err 235 | } 236 | return walkExpr(expr.ListExpr, f) 237 | default: 238 | return fmt.Errorf("unknown expression %v", reflect.TypeOf(expr)) 239 | } 240 | return nil 241 | } 242 | 243 | func walkOperator(op ast.Operator, f WalkFunc) error { 244 | //short circuit out if there are no functions 245 | if op == nil || f == nil { 246 | return nil 247 | } 248 | if err := callFunc(op, f); err != nil { 249 | return err 250 | } 251 | switch op := op.(type) { 252 | case *ast.BinaryOperator: 253 | if err := walkExpr(op.LHS, f); err != nil { 254 | return err 255 | } 256 | return walkExpr(op.RHS, f) 257 | case *ast.ComparisonOperator: 258 | if err := walkExpr(op.LHS, f); err != nil { 259 | return err 260 | } 261 | return walkExpr(op.RHS, f) 262 | case *ast.AddOperator: 263 | if err := walkExpr(op.LHS, f); err != nil { 264 | return err 265 | } 266 | return walkExpr(op.RHS, f) 267 | case *ast.MultiplyOperator: 268 | if err := walkExpr(op.LHS, f); err != nil { 269 | return err 270 | } 271 | return walkExpr(op.RHS, f) 272 | } 273 | return nil 274 | } 275 | 276 | func callFunc(x interface{}, f WalkFunc) error { 277 | if x == nil || f == nil { 278 | return nil 279 | } 280 | return f(x) 281 | } 282 | -------------------------------------------------------------------------------- /ast/astutil/walk_test.go: -------------------------------------------------------------------------------- 1 | package astutil 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/mattn/anko/ast" 9 | "github.com/mattn/anko/parser" 10 | ) 11 | 12 | const ( 13 | goodSrc string = ` 14 | var fmt = import("fmt") 15 | 16 | a = "1" 17 | b = 2 18 | m = {} 19 | func testA(arg1, arg2, arg3) { 20 | v, ok = m["foo"] 21 | return "A" + arg1 + arg2 + arg3 22 | } 23 | 24 | func Main(arg1) { 25 | fmt.Println("enter Main") 26 | b = testA(1, 2, 3) + Tester() 27 | 28 | if b == 0 { 29 | fmt.Println("b is 0") 30 | } else if b == 1 { 31 | fmt.Println("b is 1") 32 | } else { 33 | fmt.Println("b is other") 34 | } 35 | 36 | switch arg1 { 37 | case 0: 38 | fmt.Println("arg0 is 0") 39 | case 1: 40 | fmt.Println("arg0 is 1") 41 | default: 42 | fmt.Println("arg0 is other") 43 | } 44 | 45 | try { 46 | throw "WTF!" 47 | } catch e { 48 | fmt.Println(e) 49 | } 50 | 51 | for n = 0; n < 3; n++ { 52 | if n < 2 { 53 | continue 54 | } 55 | fmt.Println(n) 56 | } 57 | 58 | for n in [1, 2, 3, 4, 5] { 59 | fmt.Println(n) 60 | if n > 3 { 61 | break 62 | } 63 | } 64 | 65 | n = 0 66 | for n < 3 { 67 | n++ 68 | } 69 | 70 | a = {"foo": "bar"} 71 | a.foo = "baz" 72 | if a["foo"] == "zoo" { 73 | fmt.Println("foo is zoo") 74 | } 75 | fmt.Println(a["foo"] == "zoo" ? "zoo" : "baz") 76 | 77 | c = make(chan int64) 78 | 79 | go func() { 80 | c <- 1 81 | c <- 2 82 | c <- 3 83 | }() 84 | 85 | println(<-c) 86 | println(<-c) 87 | println(<-c) 88 | 89 | v = make([]int, 3) 90 | fmt.Println("sizeof v is ", len(v)) 91 | 92 | x = 1 93 | y = (&x) 94 | *y = 2 95 | fmt.Println(x) 96 | 97 | x, y = !x, 2 98 | fmt.Println(x, y) 99 | 100 | x = new(string) 101 | fmt.Println(x) 102 | 103 | var f = func() { 104 | return "foo" 105 | } 106 | x = f()[0:1] 107 | y = f()[0] 108 | fmt.Println(x == y ? true : false) 109 | } 110 | 111 | func Tester() { 112 | return "YES" 113 | } 114 | 115 | func testLen() { 116 | return len("test") 117 | } 118 | 119 | fmt.Println(Main(1)) 120 | ` 121 | ) 122 | 123 | func TestWalk(t *testing.T) { 124 | stmts, err := parser.ParseSrc(goodSrc) 125 | if err != nil { 126 | t.Fatal(err) 127 | } 128 | var mainFound bool 129 | var lenFound bool 130 | err = Walk(stmts, func(e interface{}) error { 131 | switch exp := e.(type) { 132 | case *ast.CallExpr: 133 | switch exp.Name { 134 | case `testA`: 135 | if len(exp.SubExprs) != 3 { 136 | return errors.New("invalid parameter count") 137 | } 138 | case `Main`: 139 | if len(exp.SubExprs) != 1 { 140 | return errors.New("invalid parameter count") 141 | } 142 | case `Tester`: 143 | if len(exp.SubExprs) != 0 { 144 | return errors.New("invalid parameter count") 145 | } 146 | } 147 | case *ast.FuncExpr: 148 | if !mainFound && exp.Name == `Main` { 149 | mainFound = true 150 | } else if mainFound && exp.Name == `Main` { 151 | return errors.New("Main redefined") 152 | } 153 | case *ast.LenExpr: 154 | lenFound = true 155 | } 156 | return nil 157 | }) 158 | if err != nil { 159 | t.Fatal(err) 160 | } 161 | if !mainFound { 162 | t.Fatal("Main not found") 163 | } 164 | if !lenFound { 165 | t.Fatal("len not found") 166 | } 167 | } 168 | 169 | func Example_astWalk() { 170 | src := ` 171 | var fmt = import("fmt") 172 | 173 | func TestFunc(arg1, arg2, arg3) { 174 | return (arg1 + arg2) * arg3 175 | } 176 | 177 | func Main() { 178 | return TestFunc(1, 2, 3) + BuiltinFuncX(1, 2, 3) 179 | } 180 | 181 | fmt.Println(Main()) 182 | ` 183 | stmts, err := parser.ParseSrc(src) 184 | if err != nil { 185 | fmt.Println("ERROR: ", err) 186 | return 187 | } 188 | var mainFound bool 189 | err = Walk(stmts, func(e interface{}) error { 190 | switch e := e.(type) { 191 | case *ast.CallExpr: 192 | //check if the BuiltinFuncX is getting the right number of args 193 | if e.Name == `BuiltinFuncX` && len(e.SubExprs) != 3 { 194 | return errors.New("invalid number of arguments to BuiltinFuncX") 195 | } 196 | case *ast.FuncExpr: 197 | if !mainFound && e.Name == `Main` { 198 | if len(e.Params) != 0 { 199 | return errors.New("Too many args to main") 200 | } 201 | mainFound = true 202 | } else if mainFound && e.Name == `Main` { 203 | return errors.New("Main redefined") 204 | } 205 | } 206 | return nil 207 | }) 208 | if err != nil { 209 | fmt.Println("ERROR: ", err) 210 | return 211 | } 212 | if !mainFound { 213 | fmt.Println("ERROR: Main not found") 214 | } 215 | } 216 | 217 | func TestBadCode(t *testing.T) { 218 | var codes = []string{ 219 | `const 1 = 2`, 220 | `a["foo"] = 2, 3`, 221 | `if a, 2 {}`, 222 | `if break {}`, 223 | `if a { else }`, 224 | `if a { } else foo { }`, 225 | `try a { } else { }`, 226 | `try { } catch 1, 2 { }`, 227 | `throw 1, 2`, 228 | `for.true`, 229 | `switch { var }`, 230 | `case { var }`, 231 | `v, ok = { "foo": "bar" }[const 1]`, 232 | } 233 | for _, code := range codes { 234 | _, err := parser.ParseSrc(code) 235 | if err == nil { 236 | t.Fatalf("code %q should fail", code) 237 | } 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /ast/doc.go: -------------------------------------------------------------------------------- 1 | // Package ast implements abstruct-syntax-tree for anko. 2 | package ast 3 | -------------------------------------------------------------------------------- /ast/expr.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // Expr provides all of interfaces for expression. 8 | type Expr interface { 9 | Pos 10 | } 11 | 12 | // ExprImpl provide commonly implementations for Expr. 13 | type ExprImpl struct { 14 | PosImpl // PosImpl provide Pos() function. 15 | } 16 | 17 | // OpExpr provide operator expression. 18 | type OpExpr struct { 19 | ExprImpl 20 | Op Operator 21 | } 22 | 23 | // LiteralExpr provide literal expression. 24 | type LiteralExpr struct { 25 | ExprImpl 26 | Literal reflect.Value 27 | } 28 | 29 | // ArrayExpr provide Array expression. 30 | type ArrayExpr struct { 31 | ExprImpl 32 | Exprs []Expr 33 | TypeData *TypeStruct 34 | } 35 | 36 | // MapExpr provide Map expression. 37 | type MapExpr struct { 38 | ExprImpl 39 | Keys []Expr 40 | Values []Expr 41 | TypeData *TypeStruct 42 | } 43 | 44 | // IdentExpr provide identity expression. 45 | type IdentExpr struct { 46 | ExprImpl 47 | Lit string 48 | } 49 | 50 | // UnaryExpr provide unary minus expression. ex: -1, ^1, ~1. 51 | type UnaryExpr struct { 52 | ExprImpl 53 | Operator string 54 | Expr Expr 55 | } 56 | 57 | // AddrExpr provide referencing address expression. 58 | type AddrExpr struct { 59 | ExprImpl 60 | Expr Expr 61 | } 62 | 63 | // DerefExpr provide dereferencing address expression. 64 | type DerefExpr struct { 65 | ExprImpl 66 | Expr Expr 67 | } 68 | 69 | // ParenExpr provide parent block expression. 70 | type ParenExpr struct { 71 | ExprImpl 72 | SubExpr Expr 73 | } 74 | 75 | // NilCoalescingOpExpr provide if invalid operator expression. 76 | type NilCoalescingOpExpr struct { 77 | ExprImpl 78 | LHS Expr 79 | RHS Expr 80 | } 81 | 82 | // TernaryOpExpr provide ternary operator expression. 83 | type TernaryOpExpr struct { 84 | ExprImpl 85 | Expr Expr 86 | LHS Expr 87 | RHS Expr 88 | } 89 | 90 | // CallExpr provide calling expression. 91 | type CallExpr struct { 92 | ExprImpl 93 | Func reflect.Value 94 | Name string 95 | SubExprs []Expr 96 | VarArg bool 97 | Go bool 98 | } 99 | 100 | // AnonCallExpr provide anonymous calling expression. ex: func(){}(). 101 | type AnonCallExpr struct { 102 | ExprImpl 103 | Expr Expr 104 | SubExprs []Expr 105 | VarArg bool 106 | Go bool 107 | } 108 | 109 | // MemberExpr provide expression to refer member. 110 | type MemberExpr struct { 111 | ExprImpl 112 | Expr Expr 113 | Name string 114 | } 115 | 116 | // ItemExpr provide expression to refer Map/Array item. 117 | type ItemExpr struct { 118 | ExprImpl 119 | Item Expr 120 | Index Expr 121 | } 122 | 123 | // SliceExpr provide expression to refer slice of Array. 124 | type SliceExpr struct { 125 | ExprImpl 126 | Item Expr 127 | Begin Expr 128 | End Expr 129 | Cap Expr 130 | } 131 | 132 | // FuncExpr provide function expression. 133 | type FuncExpr struct { 134 | ExprImpl 135 | Name string 136 | Stmt Stmt 137 | Params []string 138 | VarArg bool 139 | } 140 | 141 | // LetsExpr provide multiple expression of let. 142 | type LetsExpr struct { 143 | ExprImpl 144 | LHSS []Expr 145 | RHSS []Expr 146 | } 147 | 148 | // ChanExpr provide chan expression. 149 | type ChanExpr struct { 150 | ExprImpl 151 | LHS Expr 152 | RHS Expr 153 | } 154 | 155 | // ImportExpr provide expression to import packages. 156 | type ImportExpr struct { 157 | ExprImpl 158 | Name Expr 159 | } 160 | 161 | // MakeExpr provide expression to make instance. 162 | type MakeExpr struct { 163 | ExprImpl 164 | TypeData *TypeStruct 165 | LenExpr Expr 166 | CapExpr Expr 167 | } 168 | 169 | // MakeTypeExpr provide expression to make type. 170 | type MakeTypeExpr struct { 171 | ExprImpl 172 | Name string 173 | Type Expr 174 | } 175 | 176 | // LenExpr provide expression to get length of array, map, etc. 177 | type LenExpr struct { 178 | ExprImpl 179 | Expr Expr 180 | } 181 | 182 | // IncludeExpr provide in expression 183 | type IncludeExpr struct { 184 | ExprImpl 185 | ItemExpr Expr 186 | ListExpr Expr 187 | } 188 | -------------------------------------------------------------------------------- /ast/operator.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | // Operator provides interfaces for operators. 4 | type Operator interface { 5 | Pos 6 | } 7 | 8 | // OperatorImpl provides common implementations for Operator. 9 | type OperatorImpl struct { 10 | PosImpl // PosImpl provide Pos() function. 11 | } 12 | 13 | // BinaryOperator provides binary operation. 14 | type BinaryOperator struct { 15 | OperatorImpl 16 | LHS Expr 17 | Operator string 18 | RHS Expr 19 | } 20 | 21 | // ComparisonOperator provides comparison operation. 22 | type ComparisonOperator struct { 23 | OperatorImpl 24 | LHS Expr 25 | Operator string 26 | RHS Expr 27 | } 28 | 29 | // AddOperator provides add operation. 30 | type AddOperator struct { 31 | OperatorImpl 32 | LHS Expr 33 | Operator string 34 | RHS Expr 35 | } 36 | 37 | // MultiplyOperator provides multiply operation. 38 | type MultiplyOperator struct { 39 | OperatorImpl 40 | LHS Expr 41 | Operator string 42 | RHS Expr 43 | } 44 | -------------------------------------------------------------------------------- /ast/pos.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | // Position provides interface to store code locations. 4 | type Position struct { 5 | Line int 6 | Column int 7 | } 8 | 9 | // Pos interface provides two functions to get/set the position for expression or statement. 10 | type Pos interface { 11 | Position() Position 12 | SetPosition(Position) 13 | } 14 | 15 | // PosImpl provides commonly implementations for Pos. 16 | type PosImpl struct { 17 | pos Position 18 | } 19 | 20 | // Position return the position of the expression or statement. 21 | func (x *PosImpl) Position() Position { 22 | return x.pos 23 | } 24 | 25 | // SetPosition is a function to specify position of the expression or statement. 26 | func (x *PosImpl) SetPosition(pos Position) { 27 | x.pos = pos 28 | } 29 | -------------------------------------------------------------------------------- /ast/stmt.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | // Stmt provides all of interfaces for statement. 4 | type Stmt interface { 5 | Pos 6 | } 7 | 8 | // StmtImpl provide commonly implementations for Stmt.. 9 | type StmtImpl struct { 10 | PosImpl // PosImpl provide Pos() function. 11 | } 12 | 13 | // StmtsStmt provides statements. 14 | type StmtsStmt struct { 15 | StmtImpl 16 | Stmts []Stmt 17 | } 18 | 19 | // ExprStmt provide expression statement. 20 | type ExprStmt struct { 21 | StmtImpl 22 | Expr Expr 23 | } 24 | 25 | // IfStmt provide "if/else" statement. 26 | type IfStmt struct { 27 | StmtImpl 28 | If Expr 29 | Then Stmt 30 | ElseIf []Stmt // This is array of IfStmt 31 | Else Stmt 32 | } 33 | 34 | // TryStmt provide "try/catch/finally" statement. 35 | type TryStmt struct { 36 | StmtImpl 37 | Try Stmt 38 | Var string 39 | Catch Stmt 40 | Finally Stmt 41 | } 42 | 43 | // ForStmt provide "for in" expression statement. 44 | type ForStmt struct { 45 | StmtImpl 46 | Vars []string 47 | Value Expr 48 | Stmt Stmt 49 | } 50 | 51 | // CForStmt provide C-style "for (;;)" expression statement. 52 | type CForStmt struct { 53 | StmtImpl 54 | Stmt1 Stmt 55 | Expr2 Expr 56 | Expr3 Expr 57 | Stmt Stmt 58 | } 59 | 60 | // LoopStmt provide "for expr" expression statement. 61 | type LoopStmt struct { 62 | StmtImpl 63 | Expr Expr 64 | Stmt Stmt 65 | } 66 | 67 | // BreakStmt provide "break" expression statement. 68 | type BreakStmt struct { 69 | StmtImpl 70 | } 71 | 72 | // ContinueStmt provide "continue" expression statement. 73 | type ContinueStmt struct { 74 | StmtImpl 75 | } 76 | 77 | // ReturnStmt provide "return" expression statement. 78 | type ReturnStmt struct { 79 | StmtImpl 80 | Exprs []Expr 81 | } 82 | 83 | // ThrowStmt provide "throw" expression statement. 84 | type ThrowStmt struct { 85 | StmtImpl 86 | Expr Expr 87 | } 88 | 89 | // ModuleStmt provide "module" expression statement. 90 | type ModuleStmt struct { 91 | StmtImpl 92 | Name string 93 | Stmt Stmt 94 | } 95 | 96 | // SwitchStmt provide switch statement. 97 | type SwitchStmt struct { 98 | StmtImpl 99 | Expr Expr 100 | Cases []Stmt 101 | Default Stmt 102 | } 103 | 104 | // SwitchCaseStmt provide switch case statement. 105 | type SwitchCaseStmt struct { 106 | StmtImpl 107 | Exprs []Expr 108 | Stmt Stmt 109 | } 110 | 111 | // VarStmt provide statement to let variables in current scope. 112 | type VarStmt struct { 113 | StmtImpl 114 | Names []string 115 | Exprs []Expr 116 | } 117 | 118 | // LetsStmt provide multiple statement of let. 119 | type LetsStmt struct { 120 | StmtImpl 121 | LHSS []Expr 122 | RHSS []Expr 123 | } 124 | 125 | // LetMapItemStmt provide statement of let for map item. 126 | type LetMapItemStmt struct { 127 | StmtImpl 128 | LHSS []Expr 129 | RHS Expr 130 | } 131 | 132 | // GoroutineStmt provide statement of groutine. 133 | type GoroutineStmt struct { 134 | StmtImpl 135 | Expr Expr 136 | } 137 | 138 | // DeleteStmt provides statement of delete. 139 | type DeleteStmt struct { 140 | ExprImpl 141 | Item Expr 142 | Key Expr 143 | } 144 | 145 | // CloseStmt provides statement of close. 146 | type CloseStmt struct { 147 | StmtImpl 148 | Expr Expr 149 | } 150 | 151 | // ChanStmt provide chan lets statement. 152 | type ChanStmt struct { 153 | ExprImpl 154 | LHS Expr 155 | OkExpr Expr 156 | RHS Expr 157 | } 158 | -------------------------------------------------------------------------------- /cmd/anko-package-gen/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | "go/parser" 7 | "go/token" 8 | "log" 9 | "os" 10 | "os/exec" 11 | "path/filepath" 12 | "sort" 13 | "strings" 14 | ) 15 | 16 | func pkgName(f string) string { 17 | file, err := parser.ParseFile(token.NewFileSet(), f, nil, parser.PackageClauseOnly) 18 | if err != nil || file == nil { 19 | return "" 20 | } 21 | return file.Name.Name 22 | } 23 | 24 | func isGoFile(dir os.FileInfo) bool { 25 | return !dir.IsDir() && 26 | !strings.HasPrefix(dir.Name(), ".") && // ignore .files 27 | filepath.Ext(dir.Name()) == ".go" 28 | } 29 | 30 | func isPkgFile(dir os.FileInfo) bool { 31 | return isGoFile(dir) && !strings.HasSuffix(dir.Name(), "_test.go") // ignore test files 32 | } 33 | 34 | func parseDir(p string) (map[string]*ast.Package, error) { 35 | isGoFile := func(d os.FileInfo) bool { 36 | return !d.IsDir() && !strings.HasSuffix(d.Name(), "_test.go") && !strings.HasPrefix(d.Name(), "example_") 37 | } 38 | 39 | pkgs, err := parser.ParseDir(token.NewFileSet(), p, isGoFile, parser.ParseComments) 40 | if err != nil { 41 | return nil, err 42 | } 43 | return pkgs, nil 44 | } 45 | 46 | func main() { 47 | pkg := "flag" 48 | if len(os.Args) == 2 { 49 | pkg = os.Args[1] 50 | } 51 | b, err := exec.Command("go", "env", "GOROOT").CombinedOutput() 52 | if err != nil { 53 | log.Fatal(err) 54 | } 55 | paths := []string{filepath.Join(strings.TrimSpace(string(b)), "src")} 56 | b, err = exec.Command("go", "env", "GOPATH").CombinedOutput() 57 | if err != nil { 58 | log.Fatal(err) 59 | } 60 | for _, p := range strings.Split(strings.TrimSpace(string(b)), string(filepath.ListSeparator)) { 61 | paths = append(paths, filepath.Join(p, "src")) 62 | } 63 | for _, p := range paths { 64 | pp := filepath.Join(p, pkg) 65 | pkgs, err := parseDir(pp) 66 | if err != nil || len(pkgs) == 0 { 67 | continue 68 | } 69 | names := map[string]bool{} 70 | pn := pkg 71 | for _, pp := range pkgs { 72 | pn = pp.Name 73 | for _, f := range pp.Files { 74 | for _, d := range f.Decls { 75 | switch decl := d.(type) { 76 | case *ast.GenDecl: 77 | for _, spec := range decl.Specs { 78 | if vspec, ok := spec.(*ast.ValueSpec); ok { 79 | for _, n := range vspec.Names { 80 | c := n.Name[0] 81 | if c < 'A' || c > 'Z' { 82 | continue 83 | } 84 | names[n.Name] = true 85 | } 86 | } 87 | } 88 | case *ast.FuncDecl: 89 | if decl.Recv != nil { 90 | continue 91 | } 92 | c := decl.Name.Name[0] 93 | if c < 'A' || c > 'Z' { 94 | continue 95 | } 96 | names[decl.Name.Name] = true 97 | } 98 | } 99 | } 100 | } 101 | keys := []string{} 102 | for k := range names { 103 | keys = append(keys, k) 104 | } 105 | sort.Strings(keys) 106 | fmt.Printf(`// Package %s implements %s interface for anko script. 107 | package %s 108 | 109 | import ( 110 | "%s" 111 | ) 112 | 113 | func init() { 114 | Packages["%s"] = map[string]interface{}{ 115 | `, pn, pkg, pn, pkg, pn) 116 | for _, k := range keys { 117 | fmt.Printf(` "%s": %s.%s,`+"\n", k, pn, k) 118 | } 119 | fmt.Println(` } 120 | }`) 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /core/core.go: -------------------------------------------------------------------------------- 1 | // Package core implements core interface for anko script. 2 | package core 3 | 4 | import ( 5 | "fmt" 6 | "io/ioutil" 7 | "reflect" 8 | 9 | "github.com/mattn/anko/env" 10 | "github.com/mattn/anko/parser" 11 | "github.com/mattn/anko/vm" 12 | ) 13 | 14 | // Import defines core language builtins - keys, range, println, etc. 15 | func Import(e *env.Env) *env.Env { 16 | e.Define("keys", func(v interface{}) []interface{} { 17 | rv := reflect.ValueOf(v) 18 | if rv.Kind() == reflect.Interface { 19 | rv = rv.Elem() 20 | } 21 | mapKeysValue := rv.MapKeys() 22 | mapKeys := make([]interface{}, len(mapKeysValue)) 23 | for i := 0; i < len(mapKeysValue); i++ { 24 | mapKeys[i] = mapKeysValue[i].Interface() 25 | } 26 | return mapKeys 27 | }) 28 | 29 | e.Define("range", func(args ...int64) []int64 { 30 | var start, stop int64 31 | var step int64 = 1 32 | 33 | switch len(args) { 34 | case 0: 35 | panic("range expected at least 1 argument, got 0") 36 | case 1: 37 | stop = args[0] 38 | case 2: 39 | start = args[0] 40 | stop = args[1] 41 | case 3: 42 | start = args[0] 43 | stop = args[1] 44 | step = args[2] 45 | if step == 0 { 46 | panic("range argument 3 must not be zero") 47 | } 48 | default: 49 | panic(fmt.Sprintf("range expected at most 3 arguments, got %d", len(args))) 50 | } 51 | 52 | arr := []int64{} 53 | for i := start; (step > 0 && i < stop) || (step < 0 && i > stop); i += step { 54 | arr = append(arr, i) 55 | } 56 | return arr 57 | }) 58 | 59 | e.Define("typeOf", func(v interface{}) string { 60 | return reflect.TypeOf(v).String() 61 | }) 62 | 63 | e.Define("kindOf", func(v interface{}) string { 64 | typeOf := reflect.TypeOf(v) 65 | if typeOf == nil { 66 | return "nil" 67 | } 68 | return typeOf.Kind().String() 69 | }) 70 | 71 | e.Define("defined", func(s string) bool { 72 | _, err := e.Get(s) 73 | return err == nil 74 | }) 75 | 76 | e.Define("load", func(s string) interface{} { 77 | body, err := ioutil.ReadFile(s) 78 | if err != nil { 79 | panic(err) 80 | } 81 | scanner := new(parser.Scanner) 82 | scanner.Init(string(body)) 83 | stmts, err := parser.Parse(scanner) 84 | if err != nil { 85 | if pe, ok := err.(*parser.Error); ok { 86 | pe.Filename = s 87 | panic(pe) 88 | } 89 | panic(err) 90 | } 91 | rv, err := vm.Run(e, nil, stmts) 92 | if err != nil { 93 | panic(err) 94 | } 95 | return rv 96 | }) 97 | 98 | e.Define("print", fmt.Print) 99 | e.Define("println", fmt.Println) 100 | e.Define("printf", fmt.Printf) 101 | 102 | ImportToX(e) 103 | 104 | return e 105 | } 106 | -------------------------------------------------------------------------------- /core/testdata/broken.ank: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 2 | 3 | use strict; 4 | use warnings; 5 | 6 | die "Hey! I'm anko"; 7 | -------------------------------------------------------------------------------- /core/testdata/chan.ank: -------------------------------------------------------------------------------- 1 | 2 | c = make(chan int64) 3 | r = [] 4 | 5 | go func() { 6 | c <- 1 7 | c <- 2 8 | c <- 3 9 | close(c) 10 | }() 11 | 12 | for a in c { 13 | r += a 14 | } 15 | is([1,2,3], r, "chan") 16 | 17 | nil 18 | -------------------------------------------------------------------------------- /core/testdata/core_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "reflect" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/mattn/anko/packages" 11 | "github.com/mattn/anko/vm" 12 | ) 13 | 14 | var testCoreEnvSetupFunc = func(t *testing.T, env corelib.Env) { Import(env.(*vm.Env)) } 15 | 16 | func init() { 17 | corelib.NewEnv = func() corelib.Env { 18 | return vm.NewEnv() 19 | } 20 | } 21 | 22 | func TestKeys(t *testing.T) { 23 | os.Setenv("ANKO_DEBUG", "1") 24 | tests := []testlib.Test{ 25 | {Script: `a = {}; b = keys(a)`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, 26 | {Script: `a = {"a": nil}; b = keys(a)`, RunOutput: []interface{}{"a"}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"a": nil}}}, 27 | {Script: `a = {"a": 1}; b = keys(a)`, RunOutput: []interface{}{"a"}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"a": int64(1)}}}, 28 | } 29 | testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) 30 | } 31 | 32 | func TestKindOf(t *testing.T) { 33 | os.Setenv("ANKO_DEBUG", "1") 34 | tests := []testlib.Test{ 35 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": reflect.Value{}}, RunOutput: "struct", Output: map[string]interface{}{"a": reflect.Value{}}}, 36 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": nil}, RunOutput: "nil", Output: map[string]interface{}{"a": nil}}, 37 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": true}, RunOutput: "bool", Output: map[string]interface{}{"a": true}}, 38 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": int32(1)}, RunOutput: "int32", Output: map[string]interface{}{"a": int32(1)}}, 39 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: "int64", Output: map[string]interface{}{"a": int64(1)}}, 40 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": float32(1.1)}, RunOutput: "float32", Output: map[string]interface{}{"a": float32(1.1)}}, 41 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: "float64", Output: map[string]interface{}{"a": float64(1.1)}}, 42 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": "a"}, RunOutput: "string", Output: map[string]interface{}{"a": "a"}}, 43 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": 'a'}, RunOutput: "int32", Output: map[string]interface{}{"a": 'a'}}, 44 | 45 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(nil)}, RunOutput: "nil", Output: map[string]interface{}{"a": interface{}(nil)}}, 46 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(true)}, RunOutput: "bool", Output: map[string]interface{}{"a": interface{}(true)}}, 47 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(int32(1))}, RunOutput: "int32", Output: map[string]interface{}{"a": interface{}(int32(1))}}, 48 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(int64(1))}, RunOutput: "int64", Output: map[string]interface{}{"a": interface{}(int64(1))}}, 49 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(float32(1))}, RunOutput: "float32", Output: map[string]interface{}{"a": interface{}(float32(1))}}, 50 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(float64(1))}, RunOutput: "float64", Output: map[string]interface{}{"a": interface{}(float64(1))}}, 51 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}("a")}, RunOutput: "string", Output: map[string]interface{}{"a": interface{}("a")}}, 52 | 53 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": []interface{}{}}, RunOutput: "slice", Output: map[string]interface{}{"a": []interface{}{}}}, 54 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": []interface{}{nil}}, RunOutput: "slice", Output: map[string]interface{}{"a": []interface{}{nil}}}, 55 | 56 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: "map", Output: map[string]interface{}{"a": map[string]interface{}{}}}, 57 | {Script: `kindOf(a)`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}, RunOutput: "map", Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}}, 58 | 59 | {Script: `a = make(interface); kindOf(a)`, RunOutput: "nil", Output: map[string]interface{}{"a": interface{}(nil)}}, 60 | } 61 | testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) 62 | } 63 | 64 | func TestRange(t *testing.T) { 65 | os.Setenv("ANKO_DEBUG", "") 66 | tests := []testlib.Test{ 67 | // 0 arguments 68 | {Script: `range()`, RunError: fmt.Errorf("range expected at least 1 argument, got 0")}, 69 | // 1 arguments(step == 1, start == 0) 70 | {Script: `range(-1)`, RunOutput: []int64{}}, 71 | {Script: `range(0)`, RunOutput: []int64{}}, 72 | {Script: `range(1)`, RunOutput: []int64{0}}, 73 | {Script: `range(2)`, RunOutput: []int64{0, 1}}, 74 | {Script: `range(10)`, RunOutput: []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}, 75 | // 2 arguments(step == 1) 76 | {Script: `range(-5,-1)`, RunOutput: []int64{-5, -4, -3, -2}}, 77 | {Script: `range(-1,1)`, RunOutput: []int64{-1, 0}}, 78 | {Script: `range(1,5)`, RunOutput: []int64{1, 2, 3, 4}}, 79 | // 3 arguments 80 | // step == 2 81 | {Script: `range(-5,-1,2)`, RunOutput: []int64{-5, -3}}, 82 | {Script: `range(1,5,2)`, RunOutput: []int64{1, 3}}, 83 | {Script: `range(-1,5,2)`, RunOutput: []int64{-1, 1, 3}}, 84 | // step < 0 and from small to large 85 | {Script: `range(-5,-1,-1)`, RunOutput: []int64{}}, 86 | {Script: `range(1,5,-1)`, RunOutput: []int64{}}, 87 | {Script: `range(-1,5,-1)`, RunOutput: []int64{}}, 88 | // step < 0 and from large to small 89 | {Script: `range(-1,-5,-1)`, RunOutput: []int64{-1, -2, -3, -4}}, 90 | {Script: `range(5,1,-1)`, RunOutput: []int64{5, 4, 3, 2}}, 91 | {Script: `range(5,-1,-1)`, RunOutput: []int64{5, 4, 3, 2, 1, 0}}, 92 | // 4,5 arguments 93 | {Script: `range(1,5,1,1)`, RunError: fmt.Errorf("range expected at most 3 arguments, got 4")}, 94 | {Script: `range(1,5,1,1,1)`, RunError: fmt.Errorf("range expected at most 3 arguments, got 5")}, 95 | // more 0 test 96 | {Script: `range(0,1,2)`, RunOutput: []int64{0}}, 97 | {Script: `range(1,0,2)`, RunOutput: []int64{}}, 98 | {Script: `range(1,2,0)`, RunError: fmt.Errorf("range argument 3 must not be zero")}, 99 | } 100 | testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) 101 | } 102 | 103 | func TestLoad(t *testing.T) { 104 | os.Setenv("ANKO_DEBUG", "") 105 | notFoundRunErrorFunc := func(t *testing.T, err error) { 106 | if err == nil || !strings.HasPrefix(err.Error(), "open testdata/not-found.ank:") { 107 | t.Errorf("load not-found.ank failed - received: %v", err) 108 | } 109 | } 110 | tests := []testlib.Test{ 111 | {Script: `load('testdata/test.ank'); X(1)`, RunOutput: int64(2)}, 112 | {Script: `load('testdata/not-found.ank'); X(1)`, RunErrorFunc: ¬FoundRunErrorFunc}, 113 | {Script: `load('testdata/broken.ank'); X(1)`, RunError: fmt.Errorf("syntax error")}, 114 | } 115 | testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) 116 | } 117 | 118 | func TestAnk(t *testing.T) { 119 | os.Setenv("ANKO_DEBUG", "") 120 | var testEnvSetupFunc = func(t *testing.T, env corelib.Env) { 121 | e := env.(*vm.Env) 122 | Import(e) 123 | packages.DefineImport(e) 124 | } 125 | tests := []testlib.Test{ 126 | {Script: `load('testdata/testing.ank'); load('testdata/let.ank')`}, 127 | {Script: `load('testdata/testing.ank'); load('testdata/toString.ank')`}, 128 | {Script: `load('testdata/testing.ank'); load('testdata/op.ank')`}, 129 | {Script: `load('testdata/testing.ank'); load('testdata/func.ank')`}, 130 | {Script: `load('testdata/testing.ank'); load('testdata/len.ank')`}, 131 | {Script: `load('testdata/testing.ank'); load('testdata/for.ank')`}, 132 | {Script: `load('testdata/testing.ank'); load('testdata/switch.ank')`}, 133 | {Script: `load('testdata/testing.ank'); load('testdata/if.ank')`}, 134 | {Script: `load('testdata/testing.ank'); load('testdata/toBytes.ank')`}, 135 | {Script: `load('testdata/testing.ank'); load('testdata/toRunes.ank')`}, 136 | {Script: `load('testdata/testing.ank'); load('testdata/chan.ank')`}, 137 | } 138 | testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testEnvSetupFunc}) 139 | } 140 | 141 | func TestDefined(t *testing.T) { 142 | os.Setenv("ANKO_DEBUG", "") 143 | tests := []testlib.Test{ 144 | {Script: `var a = 1; defined("a")`, RunOutput: true}, 145 | {Script: `defined("a")`, RunOutput: false}, 146 | {Script: `func(){ var a = 1 }(); defined("a")`, RunOutput: false}, 147 | } 148 | testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) 149 | } 150 | -------------------------------------------------------------------------------- /core/testdata/error.ank: -------------------------------------------------------------------------------- 1 | func X(a) { 2 | a.notfound = 1 3 | } 4 | -------------------------------------------------------------------------------- /core/testdata/for.ank: -------------------------------------------------------------------------------- 1 | 2 | x = 0 3 | for a in [1,2,3] { 4 | x += 1 5 | } 6 | is(3, x, "for a in range [1,2,3]") 7 | 8 | x = 0 9 | 10 | for { 11 | x += 1 12 | if (x > 3) { 13 | break 14 | } 15 | } 16 | is(4, x, "for loop") 17 | 18 | func loop_with_return_stmt() { 19 | y = 0 20 | for { 21 | if y == 5 { 22 | return y 23 | } 24 | y++ 25 | } 26 | return 1 27 | } 28 | is(5, loop_with_return_stmt(), "loop with return stmt") 29 | 30 | func for_with_return_stmt() { 31 | y = 0 32 | for k in range(0, 10) { 33 | if k == 5 { 34 | return y 35 | } 36 | y++ 37 | } 38 | return 1 39 | } 40 | is(5, for_with_return_stmt(), "for loop with return stmt") 41 | 42 | x = 0 43 | for a = 0; a < 10; a++ { 44 | x++ 45 | } 46 | is(10, x, "C-style for loop") 47 | 48 | func cstylefor_with_return_stmt() { 49 | y = 0 50 | for i = 0; i < 10; i++ { 51 | if i == 5 { 52 | return y 53 | } 54 | y++ 55 | } 56 | 57 | return 1 58 | } 59 | 60 | is(5, cstylefor_with_return_stmt(), "C-style for loop with return statement") 61 | 62 | resp = { 63 | "items": [{ 64 | "someData": 2, 65 | }] 66 | } 67 | 68 | x = 0 69 | for item in resp.items { 70 | x += item.someData 71 | } 72 | 73 | is(2, x, "dereference slice element") 74 | 75 | nil 76 | -------------------------------------------------------------------------------- /core/testdata/func.ank: -------------------------------------------------------------------------------- 1 | 2 | func a() { return 2 } 3 | is(2, a(), "func a() { return 2 }") 4 | 5 | func b(x) { return x + 1 } 6 | is(3, b(2), "func b(x) { return x + 1 }") 7 | 8 | func c(x) { return x, x + 1 } 9 | is([2,3], c(2), "func c(x) { return x, x + 1 }") 10 | 11 | func d(x) { return func() { return x + 1 } } 12 | is(3, d(2)(), "func d(x) { return func() { return x + 1 } }") 13 | 14 | var x = func(x) { 15 | return func(y) { 16 | x(y) 17 | } 18 | }(func(z) { 19 | return "Yay! " + z 20 | })("hello world") 21 | 22 | is("Yay! hello world", x, "...") 23 | 24 | nil 25 | -------------------------------------------------------------------------------- /core/testdata/if.ank: -------------------------------------------------------------------------------- 1 | 2 | r = -1 3 | if (false) { 4 | r = 1 5 | } else if (false) { 6 | r = 2 7 | } else if (false) { 8 | r = 3 9 | } else { 10 | r = 4 11 | } 12 | is(4, r, "if") 13 | 14 | nil 15 | -------------------------------------------------------------------------------- /core/testdata/len.ank: -------------------------------------------------------------------------------- 1 | 2 | is(3, len("foo"), "len(\"foo\")") 3 | is(0, len(""), "len(\"\")") 4 | is(4, len([1,2,true,["foo"]]), "len([1,2,true,[\"foo\"]])") 5 | 6 | nil 7 | -------------------------------------------------------------------------------- /core/testdata/let.ank: -------------------------------------------------------------------------------- 1 | 2 | a = nil 3 | is(nil, a, "let nil") 4 | 5 | a = 1 6 | is(1, a, "let int") 7 | 8 | a = 1.2 9 | is(1.2, a, "let float") 10 | 11 | a = "foo" 12 | is("foo", a, "let string") 13 | 14 | a = nil 15 | is(nil, a, "let nil") 16 | 17 | a = true 18 | is(true, a, "let true") 19 | 20 | a = false 21 | is(false, a, "let false") 22 | 23 | a = [1,2,3] 24 | is([1,2,3], a, "let array") 25 | 26 | a = {"foo": "bar", "bar": "baz"} 27 | is({"bar": "baz", "foo": "bar"}, a, "let map") 28 | 29 | a = {"foo": "bar", "bar": {"blah": true, "blah!": [1.3e3, true]}} 30 | is({"foo": "bar", "bar": {"blah": true, "blah!": [1.3e3, true]}}, a, "let map deep") 31 | 32 | nil 33 | -------------------------------------------------------------------------------- /core/testdata/op.ank: -------------------------------------------------------------------------------- 1 | 2 | ok(1 > 0, "1 > 0") 3 | ok(1 == 1.0, "1 == 1.0") 4 | is(1 != "1", false, "1 != \"1\"") 5 | ok(1 == 1, "1 == 1") 6 | ok(1.1 == 1.1, "1.1 == 1.1") 7 | ok("1" == "1", "\"1\" == \"1\"") 8 | 9 | ok(false != "1", "false != \"1\"") 10 | ok(false != true, "false != true") 11 | ok(false == false, "false == false") 12 | ok(true == true, "true == true") 13 | ok(false == false, "false == false") 14 | ok(nil == nil, "nil == nil") 15 | 16 | ok(1 <= 1, "1 <= 1") 17 | ok(1.0 <= 1.0, "1.0 <= 1.0") 18 | 19 | is(true, 1 <= 2 ? true : false, "1 == 1 ? true : false") 20 | 21 | a = 1; a += 1 22 | is(2, a, "+=") 23 | 24 | a = 2; a -= 1 25 | is(1, a, "-=") 26 | 27 | a = 2; a *= 2 28 | is(4, a, "*=") 29 | 30 | a = 3; a /= 2 31 | is(1.5, a, "/=") 32 | 33 | a = 2; a++ 34 | is(3, a, "++") 35 | 36 | a = 2; a-- 37 | is(1, a, "--") 38 | 39 | a = 1; a &= 2 40 | is(0, a, "&=") 41 | 42 | a = 1; a |= 2 43 | is(3, a, "|=") 44 | 45 | a = !3 46 | is(false, a, "!3") 47 | 48 | a = !true 49 | is(false, a, "!true") 50 | 51 | a = !false 52 | is(true, a, "!false") 53 | 54 | a = ^3 55 | is(-4, a, "^3") 56 | 57 | a = 3 << 2 58 | is(12, a, "3 << 2") 59 | 60 | a = 11 >> 2 61 | is(2, a, "11 >> 2") 62 | 63 | nil 64 | -------------------------------------------------------------------------------- /core/testdata/sort.ank: -------------------------------------------------------------------------------- 1 | sort = import("sort") 2 | 3 | a = make([]int) 4 | b = make([]int) 5 | a += [1, 2, 3] 6 | b += [3, 1, 2] 7 | sort.Ints(b) 8 | is(a, b, "sort.Ints") 9 | 10 | a = make([]float64) 11 | b = make([]float64) 12 | a += [1.1, 2.2, 3.3] 13 | b += [3.3, 1.1, 2.2] 14 | sort.Float64s(b) 15 | is(a, b, "sort.Float64s") 16 | 17 | a = make([]string) 18 | b = make([]string) 19 | a += ["a", "b", "c", "d"] 20 | b += ["b", "d", "a", "c"] 21 | sort.Strings(b) 22 | is(a, b, "sort.Strings") 23 | 24 | if go18later() { 25 | a = [1, 3, 2] 26 | sort.Slice(a, func(i, j) { 27 | return a[i] < a[j] 28 | }) 29 | is([1,2,3], a, "sort.Slice") 30 | } 31 | 32 | nil 33 | -------------------------------------------------------------------------------- /core/testdata/switch.ank: -------------------------------------------------------------------------------- 1 | 2 | x = 0 3 | r = -1 4 | switch x { 5 | case 0: 6 | r = 0 7 | case 1: 8 | r = 1 9 | case 2: 10 | r = 2 11 | } 12 | is(0, r, "switch/case") 13 | 14 | x = 3 15 | r = -1 16 | switch x { 17 | case 0: 18 | r = 0 19 | case 1: 20 | r = 1 21 | case 2: 22 | r = 2 23 | } 24 | is(-1, r, "switch/case") 25 | 26 | x = 3 27 | r = -1 28 | switch x { 29 | case 0: 30 | r = 0 31 | case 1: 32 | r = 1 33 | case 2: 34 | r = 2 35 | default: 36 | r = 3 37 | } 38 | is(3, r, "switch/default") 39 | 40 | nil 41 | -------------------------------------------------------------------------------- /core/testdata/test.ank: -------------------------------------------------------------------------------- 1 | func X(a) { 2 | return a + 1 3 | } 4 | -------------------------------------------------------------------------------- /core/testdata/testing.ank: -------------------------------------------------------------------------------- 1 | 2 | var runtime = import("runtime") 3 | var regexp = import("regexp") 4 | 5 | func is(expect, got, name) { 6 | if expect != got { 7 | panic("is - received: " + toString(got) + " - expected: " + toString(expect) + " - for: " + toString(name)) 8 | } 9 | } 10 | 11 | func ok(expect, name) { 12 | if !expect { 13 | panic("ok - received: " + toString(expect) + " - for: " + toString(name)) 14 | } 15 | } 16 | 17 | func go18later() { 18 | return regexp.MustCompile("^go1\\.(1[0-9]|[8-9])\\.[0-9]$").MatchString(runtime.Version()) 19 | } 20 | -------------------------------------------------------------------------------- /core/testdata/toBytes.ank: -------------------------------------------------------------------------------- 1 | 2 | a = toByteSlice("あいうえお") 3 | b = [227, 129, 130, 227, 129, 132, 227, 129, 134, 227, 129, 136, 227, 129, 138] 4 | x = 0 5 | for i = 0; i < len(a); i++ { 6 | if (a[i] == b[i]) { 7 | x++ 8 | } 9 | } 10 | is(x, len(a), "toByteSlice(str)") 11 | 12 | nil 13 | -------------------------------------------------------------------------------- /core/testdata/toRunes.ank: -------------------------------------------------------------------------------- 1 | 2 | a = toRuneSlice("あいうえお") 3 | b = [12354, 12356, 12358, 12360, 12362] 4 | x = 0 5 | for i = 0; i < len(a); i++ { 6 | if (a[i] == b[i]) { 7 | x++ 8 | } 9 | } 10 | is(x, len(a), "toRuneSlice(str)") 11 | 12 | nil 13 | -------------------------------------------------------------------------------- /core/testdata/toString.ank: -------------------------------------------------------------------------------- 1 | 2 | is("1", toString(1), "toString(int)") 3 | is("1.2", toString(1.2), "toString(float)") 4 | is("true", toString(true), "toString(true)") 5 | is("false", toString(false), "toString(false)") 6 | is("foo", toString("foo"), "toString(\"foo\")") 7 | 8 | nil 9 | -------------------------------------------------------------------------------- /core/testdata/toX_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | "time" 8 | 9 | "github.com/mattn/anko/internal/testlib" 10 | ) 11 | 12 | func TestToX(t *testing.T) { 13 | os.Setenv("ANKO_DEBUG", "1") 14 | tests := []testlib.Test{ 15 | {Script: `toBool(-2)`, RunOutput: false}, 16 | {Script: `toBool(-1.5)`, RunOutput: false}, 17 | {Script: `toBool(-1)`, RunOutput: false}, 18 | {Script: `toBool(-0.4)`, RunOutput: false}, 19 | {Script: `toBool(0)`, RunOutput: false}, 20 | {Script: `toBool(0.4)`, RunOutput: true}, 21 | {Script: `toBool(1)`, RunOutput: true}, 22 | {Script: `toBool(1.5)`, RunOutput: true}, 23 | {Script: `toBool(2)`, RunOutput: true}, 24 | {Script: `toBool(true)`, RunOutput: true}, 25 | {Script: `toBool(false)`, RunOutput: false}, 26 | {Script: `toBool("true")`, RunOutput: true}, 27 | {Script: `toBool("false")`, RunOutput: false}, 28 | {Script: `toBool("yes")`, RunOutput: true}, 29 | {Script: `toBool("ye")`, RunOutput: false}, 30 | {Script: `toBool("y")`, RunOutput: true}, 31 | {Script: `toBool("false")`, RunOutput: false}, 32 | {Script: `toBool("f")`, RunOutput: false}, 33 | {Script: `toBool("")`, RunOutput: false}, 34 | {Script: `toBool(nil)`, RunOutput: false}, 35 | {Script: `toBool({})`, RunOutput: false}, 36 | {Script: `toBool([])`, RunOutput: false}, 37 | {Script: `toBool([true])`, RunOutput: false}, 38 | {Script: `toBool({"true": "true"})`, RunOutput: false}, 39 | {Script: `toString(nil)`, RunOutput: ""}, 40 | {Script: `toString("")`, RunOutput: ""}, 41 | {Script: `toString(1)`, RunOutput: "1"}, 42 | {Script: `toString(1.2)`, RunOutput: "1.2"}, 43 | {Script: `toString(1/3)`, RunOutput: "0.3333333333333333"}, 44 | {Script: `toString(false)`, RunOutput: "false"}, 45 | {Script: `toString(true)`, RunOutput: "true"}, 46 | {Script: `toString({})`, RunOutput: "map[]"}, 47 | {Script: `toString({"foo": "bar"})`, RunOutput: "map[foo:bar]"}, 48 | {Script: `toString([true,nil])`, RunOutput: "[true ]"}, 49 | {Script: `toString(toByteSlice("foo"))`, RunOutput: "foo"}, 50 | {Script: `toInt(nil)`, RunOutput: int64(0)}, 51 | {Script: `toInt(-2)`, RunOutput: int64(-2)}, 52 | {Script: `toInt(-1.4)`, RunOutput: int64(-1)}, 53 | {Script: `toInt(-1)`, RunOutput: int64(-1)}, 54 | {Script: `toInt(0)`, RunOutput: int64(0)}, 55 | {Script: `toInt(1)`, RunOutput: int64(1)}, 56 | {Script: `toInt(1.4)`, RunOutput: int64(1)}, 57 | {Script: `toInt(1.5)`, RunOutput: int64(1)}, 58 | {Script: `toInt(1.9)`, RunOutput: int64(1)}, 59 | {Script: `toInt(2)`, RunOutput: int64(2)}, 60 | {Script: `toInt(2.1)`, RunOutput: int64(2)}, 61 | {Script: `toInt("2")`, RunOutput: int64(2)}, 62 | {Script: `toInt("2.1")`, RunOutput: int64(2)}, 63 | {Script: `toInt(true)`, RunOutput: int64(1)}, 64 | {Script: `toInt(false)`, RunOutput: int64(0)}, 65 | {Script: `toInt({})`, RunOutput: int64(0)}, 66 | {Script: `toInt([])`, RunOutput: int64(0)}, 67 | {Script: `toFloat(nil)`, RunOutput: float64(0.0)}, 68 | {Script: `toFloat(-2)`, RunOutput: float64(-2.0)}, 69 | {Script: `toFloat(-1.4)`, RunOutput: float64(-1.4)}, 70 | {Script: `toFloat(-1)`, RunOutput: float64(-1.0)}, 71 | {Script: `toFloat(0)`, RunOutput: float64(0.0)}, 72 | {Script: `toFloat(1)`, RunOutput: float64(1.0)}, 73 | {Script: `toFloat(1.4)`, RunOutput: float64(1.4)}, 74 | {Script: `toFloat(1.5)`, RunOutput: float64(1.5)}, 75 | {Script: `toFloat(1.9)`, RunOutput: float64(1.9)}, 76 | {Script: `toFloat(2)`, RunOutput: float64(2.0)}, 77 | {Script: `toFloat(2.1)`, RunOutput: float64(2.1)}, 78 | {Script: `toFloat("2")`, RunOutput: float64(2.0)}, 79 | {Script: `toFloat("2.1")`, RunOutput: float64(2.1)}, 80 | {Script: `toFloat(true)`, RunOutput: float64(1.0)}, 81 | {Script: `toFloat(false)`, RunOutput: float64(0.0)}, 82 | {Script: `toFloat({})`, RunOutput: float64(0.0)}, 83 | {Script: `toFloat([])`, RunOutput: float64(0.0)}, 84 | {Script: `toChar(0x1F431)`, RunOutput: "🐱"}, 85 | {Script: `toChar(0)`, RunOutput: "\x00"}, 86 | {Script: `toRune("")`, RunOutput: rune(0)}, 87 | {Script: `toRune("🐱")`, RunOutput: rune(0x1F431)}, 88 | {Script: `toBoolSlice(nil)`, RunOutput: []bool{}}, 89 | {Script: `toBoolSlice(1)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type int64")}, 90 | {Script: `toBoolSlice(1.2)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type float64")}, 91 | {Script: `toBoolSlice(false)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type bool")}, 92 | {Script: `toBoolSlice({})`, RunError: fmt.Errorf("function wants argument type []interface {} but received type map[interface {}]interface {}")}, 93 | {Script: `toBoolSlice([])`, RunOutput: []bool{}}, 94 | {Script: `toBoolSlice([nil])`, RunOutput: []bool{false}}, 95 | {Script: `toBoolSlice([1])`, RunOutput: []bool{false}}, 96 | {Script: `toBoolSlice([1.1])`, RunOutput: []bool{false}}, 97 | {Script: `toBoolSlice([true])`, RunOutput: []bool{true}}, 98 | {Script: `toBoolSlice([[]])`, RunOutput: []bool{false}}, 99 | {Script: `toBoolSlice([{}])`, RunOutput: []bool{false}}, 100 | {Script: `toIntSlice(nil)`, RunOutput: []int64{}}, 101 | {Script: `toIntSlice(1)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type int64")}, 102 | {Script: `toIntSlice(1.2)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type float64")}, 103 | {Script: `toIntSlice(false)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type bool")}, 104 | {Script: `toIntSlice({})`, RunError: fmt.Errorf("function wants argument type []interface {} but received type map[interface {}]interface {}")}, 105 | {Script: `toIntSlice([])`, RunOutput: []int64{}}, 106 | {Script: `toIntSlice([nil])`, RunOutput: []int64{0}}, 107 | {Script: `toIntSlice([1])`, RunOutput: []int64{1}}, 108 | {Script: `toIntSlice([1.1])`, RunOutput: []int64{1}}, 109 | {Script: `toIntSlice([true])`, RunOutput: []int64{0}}, 110 | {Script: `toIntSlice([[]])`, RunOutput: []int64{0}}, 111 | {Script: `toIntSlice([{}])`, RunOutput: []int64{0}}, 112 | {Script: `toFloatSlice(nil)`, RunOutput: []float64{}}, 113 | {Script: `toFloatSlice(1)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type int64")}, 114 | {Script: `toFloatSlice(1.2)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type float64")}, 115 | {Script: `toFloatSlice(false)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type bool")}, 116 | {Script: `toFloatSlice({})`, RunError: fmt.Errorf("function wants argument type []interface {} but received type map[interface {}]interface {}")}, 117 | {Script: `toFloatSlice([])`, RunOutput: []float64{}}, 118 | {Script: `toFloatSlice([nil])`, RunOutput: []float64{0.0}}, 119 | {Script: `toFloatSlice([1])`, RunOutput: []float64{1.0}}, 120 | {Script: `toFloatSlice([1.1])`, RunOutput: []float64{1.1}}, 121 | {Script: `toFloatSlice([true])`, RunOutput: []float64{0.0}}, 122 | {Script: `toFloatSlice([[]])`, RunOutput: []float64{0.0}}, 123 | {Script: `toFloatSlice([{}])`, RunOutput: []float64{0.0}}, 124 | {Script: `toByteSlice(nil)`, RunOutput: []byte{}}, 125 | {Script: `toByteSlice([])`, RunError: fmt.Errorf("function wants argument type string but received type []interface {}")}, 126 | {Script: `toByteSlice(1)`, RunOutput: []byte{0x01}}, // FIXME? 127 | {Script: `toByteSlice(1.1)`, RunError: fmt.Errorf("function wants argument type string but received type float64")}, 128 | {Script: `toByteSlice(true)`, RunError: fmt.Errorf("function wants argument type string but received type bool")}, 129 | {Script: `toByteSlice("foo")`, RunOutput: []byte{'f', 'o', 'o'}}, 130 | {Script: `toByteSlice("世界")`, RunOutput: []byte{0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c}}, 131 | {Script: `toRuneSlice(nil)`, RunOutput: []rune{}}, 132 | {Script: `toRuneSlice([])`, RunError: fmt.Errorf("function wants argument type string but received type []interface {}")}, 133 | {Script: `toRuneSlice(1)`, RunOutput: []rune{0x01}}, // FIXME? 134 | {Script: `toRuneSlice(1.1)`, RunError: fmt.Errorf("function wants argument type string but received type float64")}, 135 | {Script: `toRuneSlice(true)`, RunError: fmt.Errorf("function wants argument type string but received type bool")}, 136 | {Script: `toRuneSlice("foo")`, RunOutput: []rune{'f', 'o', 'o'}}, 137 | {Script: `toRuneSlice("世界")`, RunOutput: []rune{'世', '界'}}, 138 | {Script: `toStringSlice([true,false,1])`, RunOutput: []string{"", "", "\x01"}}, // FIXME? 139 | {Script: `toDuration(nil)`, RunOutput: time.Duration(0)}, 140 | {Script: `toDuration(0)`, RunOutput: time.Duration(0)}, 141 | {Script: `toDuration(true)`, RunError: fmt.Errorf("function wants argument type int64 but received type bool")}, 142 | {Script: `toDuration([])`, RunError: fmt.Errorf("function wants argument type int64 but received type []interface {}")}, 143 | {Script: `toDuration({})`, RunError: fmt.Errorf("function wants argument type int64 but received type map[interface {}]interface {}")}, 144 | {Script: `toDuration("")`, RunError: fmt.Errorf("function wants argument type int64 but received type string")}, 145 | {Script: `toDuration("1s")`, RunError: fmt.Errorf("function wants argument type int64 but received type string")}, // TODO 146 | {Script: `toDuration(a)`, Input: map[string]interface{}{"a": int64(time.Duration(123 * time.Minute))}, RunOutput: time.Duration(123 * time.Minute)}, 147 | {Script: `toDuration(a)`, Input: map[string]interface{}{"a": float64(time.Duration(123 * time.Minute))}, RunOutput: time.Duration(123 * time.Minute)}, 148 | {Script: `toDuration(a)`, Input: map[string]interface{}{"a": time.Duration(123 * time.Minute)}, RunOutput: time.Duration(123 * time.Minute)}, 149 | } 150 | testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) 151 | } 152 | -------------------------------------------------------------------------------- /core/toX.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strconv" 7 | "strings" 8 | "time" 9 | 10 | "github.com/mattn/anko/env" 11 | ) 12 | 13 | // ImportToX adds all the toX to the env given 14 | func ImportToX(e *env.Env) { 15 | 16 | e.Define("toBool", func(v interface{}) bool { 17 | rv := reflect.ValueOf(v) 18 | if !rv.IsValid() { 19 | return false 20 | } 21 | nt := reflect.TypeOf(true) 22 | if rv.Type().ConvertibleTo(nt) { 23 | return rv.Convert(nt).Bool() 24 | } 25 | if rv.Type().ConvertibleTo(reflect.TypeOf(1.0)) && rv.Convert(reflect.TypeOf(1.0)).Float() > 0.0 { 26 | return true 27 | } 28 | if rv.Kind() == reflect.String { 29 | s := strings.ToLower(v.(string)) 30 | if s == "y" || s == "yes" { 31 | return true 32 | } 33 | b, err := strconv.ParseBool(s) 34 | if err == nil { 35 | return b 36 | } 37 | } 38 | return false 39 | }) 40 | 41 | e.Define("toString", func(v interface{}) string { 42 | if b, ok := v.([]byte); ok { 43 | return string(b) 44 | } 45 | return fmt.Sprint(v) 46 | }) 47 | 48 | e.Define("toInt", func(v interface{}) int64 { 49 | rv := reflect.ValueOf(v) 50 | if !rv.IsValid() { 51 | return 0 52 | } 53 | nt := reflect.TypeOf(1) 54 | if rv.Type().ConvertibleTo(nt) { 55 | return rv.Convert(nt).Int() 56 | } 57 | if rv.Kind() == reflect.String { 58 | i, err := strconv.ParseInt(v.(string), 10, 64) 59 | if err == nil { 60 | return i 61 | } 62 | f, err := strconv.ParseFloat(v.(string), 64) 63 | if err == nil { 64 | return int64(f) 65 | } 66 | } 67 | if rv.Kind() == reflect.Bool { 68 | if v.(bool) { 69 | return 1 70 | } 71 | } 72 | return 0 73 | }) 74 | 75 | e.Define("toFloat", func(v interface{}) float64 { 76 | rv := reflect.ValueOf(v) 77 | if !rv.IsValid() { 78 | return 0 79 | } 80 | nt := reflect.TypeOf(1.0) 81 | if rv.Type().ConvertibleTo(nt) { 82 | return rv.Convert(nt).Float() 83 | } 84 | if rv.Kind() == reflect.String { 85 | f, err := strconv.ParseFloat(v.(string), 64) 86 | if err == nil { 87 | return f 88 | } 89 | } 90 | if rv.Kind() == reflect.Bool { 91 | if v.(bool) { 92 | return 1.0 93 | } 94 | } 95 | return 0.0 96 | }) 97 | 98 | e.Define("toChar", func(s rune) string { 99 | return string(s) 100 | }) 101 | 102 | e.Define("toRune", func(s string) rune { 103 | if len(s) == 0 { 104 | return 0 105 | } 106 | return []rune(s)[0] 107 | }) 108 | 109 | e.Define("toBoolSlice", func(v []interface{}) []bool { 110 | var result []bool 111 | toSlice(v, &result) 112 | return result 113 | }) 114 | 115 | e.Define("toStringSlice", func(v []interface{}) []string { 116 | var result []string 117 | toSlice(v, &result) 118 | return result 119 | }) 120 | 121 | e.Define("toIntSlice", func(v []interface{}) []int64 { 122 | var result []int64 123 | toSlice(v, &result) 124 | return result 125 | }) 126 | 127 | e.Define("toFloatSlice", func(v []interface{}) []float64 { 128 | var result []float64 129 | toSlice(v, &result) 130 | return result 131 | }) 132 | 133 | e.Define("toByteSlice", func(s string) []byte { 134 | return []byte(s) 135 | }) 136 | 137 | e.Define("toRuneSlice", func(s string) []rune { 138 | return []rune(s) 139 | }) 140 | 141 | e.Define("toDuration", func(v int64) time.Duration { 142 | return time.Duration(v) 143 | }) 144 | 145 | } 146 | 147 | // toSlice takes in a "generic" slice and converts and copies 148 | // it's elements into the typed slice pointed at by ptr. 149 | // Note that this is a costly operation. 150 | func toSlice(from []interface{}, ptr interface{}) { 151 | // Value of the pointer to the target 152 | obj := reflect.Indirect(reflect.ValueOf(ptr)) 153 | // We can't just convert from interface{} to whatever the target is (diff memory layout), 154 | // so we need to create a New slice of the proper type and copy the values individually 155 | t := reflect.TypeOf(ptr).Elem() 156 | tt := t.Elem() 157 | slice := reflect.MakeSlice(t, len(from), len(from)) 158 | // Copying the data, val is an addressable Pointer of the actual target type 159 | val := reflect.Indirect(reflect.New(tt)) 160 | for i := 0; i < len(from); i++ { 161 | v := reflect.ValueOf(from[i]) 162 | if v.IsValid() && v.Type().ConvertibleTo(tt) { 163 | val.Set(v.Convert(tt)) 164 | } else { 165 | val.Set(reflect.Zero(tt)) 166 | } 167 | slice.Index(i).Set(val) 168 | } 169 | // Ok now assign our slice to the target pointer 170 | obj.Set(slice) 171 | } 172 | -------------------------------------------------------------------------------- /env/env.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | "sync" 9 | ) 10 | 11 | type ( 12 | // ExternalLookup for Env external lookup of values and types. 13 | ExternalLookup interface { 14 | Get(string) (reflect.Value, error) 15 | Type(string) (reflect.Type, error) 16 | } 17 | 18 | // Env is the environment needed for a VM to run in. 19 | Env struct { 20 | rwMutex *sync.RWMutex 21 | parent *Env 22 | values map[string]reflect.Value 23 | types map[string]reflect.Type 24 | externalLookup ExternalLookup 25 | } 26 | ) 27 | 28 | var ( 29 | // Packages is a where packages can be stored so VM import command can be used to import them. 30 | // reflect.Value must be valid or VM may crash. 31 | // For nil must use NilValue. 32 | Packages = make(map[string]map[string]reflect.Value) 33 | // PackageTypes is a where package types can be stored so VM import command can be used to import them 34 | // reflect.Type must be valid or VM may crash. 35 | // For nil type must use NilType. 36 | PackageTypes = make(map[string]map[string]reflect.Type) 37 | 38 | // NilType is the reflect.type of nil 39 | NilType = reflect.TypeOf(nil) 40 | // NilValue is the reflect.value of nil 41 | NilValue = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem() 42 | 43 | basicTypes = map[string]reflect.Type{ 44 | "interface": reflect.ValueOf([]interface{}{int64(1)}).Index(0).Type(), 45 | "bool": reflect.TypeOf(true), 46 | "string": reflect.TypeOf("a"), 47 | "int": reflect.TypeOf(int(1)), 48 | "int32": reflect.TypeOf(int32(1)), 49 | "int64": reflect.TypeOf(int64(1)), 50 | "uint": reflect.TypeOf(uint(1)), 51 | "uint32": reflect.TypeOf(uint32(1)), 52 | "uint64": reflect.TypeOf(uint64(1)), 53 | "byte": reflect.TypeOf(byte(1)), 54 | "rune": reflect.TypeOf('a'), 55 | "float32": reflect.TypeOf(float32(1)), 56 | "float64": reflect.TypeOf(float64(1)), 57 | } 58 | 59 | // ErrSymbolContainsDot symbol contains . 60 | ErrSymbolContainsDot = errors.New("symbol contains '.'") 61 | ) 62 | 63 | // NewEnv creates new global scope. 64 | func NewEnv() *Env { 65 | return &Env{ 66 | rwMutex: &sync.RWMutex{}, 67 | values: make(map[string]reflect.Value), 68 | } 69 | } 70 | 71 | // NewEnv creates new child scope. 72 | func (e *Env) NewEnv() *Env { 73 | return &Env{ 74 | rwMutex: &sync.RWMutex{}, 75 | parent: e, 76 | values: make(map[string]reflect.Value), 77 | } 78 | } 79 | 80 | // NewModule creates new child scope and define it as a symbol. 81 | // This is a shortcut for calling e.NewEnv then Define that new Env. 82 | func (e *Env) NewModule(symbol string) (*Env, error) { 83 | module := &Env{ 84 | rwMutex: &sync.RWMutex{}, 85 | parent: e, 86 | values: make(map[string]reflect.Value), 87 | } 88 | return module, e.Define(symbol, module) 89 | } 90 | 91 | // SetExternalLookup sets an external lookup 92 | func (e *Env) SetExternalLookup(externalLookup ExternalLookup) { 93 | e.externalLookup = externalLookup 94 | } 95 | 96 | // String returns string of values and types in current scope. 97 | func (e *Env) String() string { 98 | var buffer bytes.Buffer 99 | e.rwMutex.RLock() 100 | 101 | if e.parent == nil { 102 | buffer.WriteString("No parent\n") 103 | } else { 104 | buffer.WriteString("Has parent\n") 105 | } 106 | 107 | for symbol, value := range e.values { 108 | buffer.WriteString(fmt.Sprintf("%v = %#v\n", symbol, value)) 109 | } 110 | 111 | for symbol, aType := range e.types { 112 | buffer.WriteString(fmt.Sprintf("%v = %v\n", symbol, aType)) 113 | } 114 | 115 | e.rwMutex.RUnlock() 116 | return buffer.String() 117 | } 118 | 119 | // GetEnvFromPath returns Env from path 120 | func (e *Env) GetEnvFromPath(path []string) (*Env, error) { 121 | if len(path) < 1 { 122 | return e, nil 123 | } 124 | 125 | var value reflect.Value 126 | var ok bool 127 | for { 128 | // find starting env 129 | value, ok = e.values[path[0]] 130 | if ok { 131 | e, ok = value.Interface().(*Env) 132 | if ok { 133 | break 134 | } 135 | } 136 | if e.parent == nil { 137 | return nil, fmt.Errorf("no namespace called: %v", path[0]) 138 | } 139 | e = e.parent 140 | } 141 | 142 | for i := 1; i < len(path); i++ { 143 | // find child env 144 | value, ok = e.values[path[i]] 145 | if ok { 146 | e, ok = value.Interface().(*Env) 147 | if ok { 148 | continue 149 | } 150 | } 151 | return nil, fmt.Errorf("no namespace called: %v", path[i]) 152 | } 153 | 154 | return e, nil 155 | } 156 | 157 | // Copy the Env for current scope 158 | func (e *Env) Copy() *Env { 159 | e.rwMutex.RLock() 160 | copy := Env{ 161 | rwMutex: &sync.RWMutex{}, 162 | parent: e.parent, 163 | values: make(map[string]reflect.Value, len(e.values)), 164 | externalLookup: e.externalLookup, 165 | } 166 | for name, value := range e.values { 167 | copy.values[name] = value 168 | } 169 | if e.types != nil { 170 | copy.types = make(map[string]reflect.Type, len(e.types)) 171 | for name, t := range e.types { 172 | copy.types[name] = t 173 | } 174 | } 175 | e.rwMutex.RUnlock() 176 | return © 177 | } 178 | 179 | // DeepCopy the Env for current scope and parent scopes. 180 | // Note that each scope is a consistent snapshot but not the whole. 181 | func (e *Env) DeepCopy() *Env { 182 | e = e.Copy() 183 | if e.parent != nil { 184 | e.parent = e.parent.DeepCopy() 185 | } 186 | return e 187 | } 188 | -------------------------------------------------------------------------------- /env/envExternalLookup_test.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | "testing" 8 | ) 9 | 10 | type TestExternalLookup struct { 11 | values map[string]reflect.Value 12 | types map[string]reflect.Type 13 | } 14 | 15 | func NewTestExternalLookup() *TestExternalLookup { 16 | return &TestExternalLookup{ 17 | values: make(map[string]reflect.Value), 18 | types: make(map[string]reflect.Type), 19 | } 20 | } 21 | 22 | func (testExternalLookup *TestExternalLookup) SetValue(symbol string, value interface{}) error { 23 | if strings.Contains(symbol, ".") { 24 | return ErrSymbolContainsDot 25 | } 26 | 27 | if value == nil { 28 | testExternalLookup.values[symbol] = NilValue 29 | } else { 30 | testExternalLookup.values[symbol] = reflect.ValueOf(value) 31 | } 32 | 33 | return nil 34 | } 35 | 36 | func (testExternalLookup *TestExternalLookup) Get(symbol string) (reflect.Value, error) { 37 | if value, ok := testExternalLookup.values[symbol]; ok { 38 | return value, nil 39 | } 40 | return NilValue, fmt.Errorf("undefined symbol '%s'", symbol) 41 | } 42 | 43 | func (testExternalLookup *TestExternalLookup) DefineType(symbol string, aType interface{}) error { 44 | if strings.Contains(symbol, ".") { 45 | return ErrSymbolContainsDot 46 | } 47 | 48 | var reflectType reflect.Type 49 | if aType == nil { 50 | reflectType = NilType 51 | } else { 52 | var ok bool 53 | reflectType, ok = reflectType.(reflect.Type) 54 | if !ok { 55 | reflectType = reflect.TypeOf(aType) 56 | } 57 | } 58 | 59 | testExternalLookup.types[symbol] = reflectType 60 | return nil 61 | } 62 | 63 | func (testExternalLookup *TestExternalLookup) Type(symbol string) (reflect.Type, error) { 64 | if value, ok := testExternalLookup.types[symbol]; ok { 65 | return value, nil 66 | } 67 | return NilType, fmt.Errorf("undefined symbol '%s'", symbol) 68 | } 69 | 70 | func TestExternalLookupValueAndGet(t *testing.T) { 71 | var err error 72 | var value interface{} 73 | tests := []struct { 74 | testInfo string 75 | varName string 76 | varDefineValue interface{} 77 | varGetValue interface{} 78 | varKind reflect.Kind 79 | defineError error 80 | getError error 81 | }{ 82 | {testInfo: "nil", varName: "a", varDefineValue: nil, varGetValue: nil, varKind: reflect.Interface}, 83 | {testInfo: "bool", varName: "a", varDefineValue: true, varGetValue: true, varKind: reflect.Bool}, 84 | {testInfo: "int16", varName: "a", varDefineValue: int16(1), varGetValue: int16(1), varKind: reflect.Int16}, 85 | {testInfo: "int32", varName: "a", varDefineValue: int32(1), varGetValue: int32(1), varKind: reflect.Int32}, 86 | {testInfo: "int64", varName: "a", varDefineValue: int64(1), varGetValue: int64(1), varKind: reflect.Int64}, 87 | {testInfo: "uint32", varName: "a", varDefineValue: uint32(1), varGetValue: uint32(1), varKind: reflect.Uint32}, 88 | {testInfo: "uint64", varName: "a", varDefineValue: uint64(1), varGetValue: uint64(1), varKind: reflect.Uint64}, 89 | {testInfo: "float32", varName: "a", varDefineValue: float32(1), varGetValue: float32(1), varKind: reflect.Float32}, 90 | {testInfo: "float64", varName: "a", varDefineValue: float64(1), varGetValue: float64(1), varKind: reflect.Float64}, 91 | {testInfo: "string", varName: "a", varDefineValue: "a", varGetValue: "a", varKind: reflect.String}, 92 | 93 | {testInfo: "string with dot", varName: "a.a", varDefineValue: "a", varGetValue: nil, varKind: reflect.String, defineError: ErrSymbolContainsDot, getError: fmt.Errorf("undefined symbol 'a.a'")}, 94 | {testInfo: "string with quotes", varName: "a", varDefineValue: `"a"`, varGetValue: `"a"`, varKind: reflect.String}, 95 | } 96 | 97 | // ExternalLookup set And get 98 | for _, test := range tests { 99 | testExternalLookup := NewTestExternalLookup() 100 | env := NewEnv() 101 | env.SetExternalLookup(testExternalLookup) 102 | 103 | err = testExternalLookup.SetValue(test.varName, test.varDefineValue) 104 | if err != nil && test.defineError != nil { 105 | if err.Error() != test.defineError.Error() { 106 | t.Errorf("TestExternalLookupValueAndGet %v - SetValue error - received: %v - expected: %v", test.testInfo, err, test.defineError) 107 | continue 108 | } 109 | } else if err != test.defineError { 110 | t.Errorf("TestExternalLookupValueAndGet %v - SetValue error - received: %v - expected: %v", test.testInfo, err, test.defineError) 111 | continue 112 | } 113 | value, err = env.Get(test.varName) 114 | if err != nil && test.getError != nil { 115 | if err.Error() != test.getError.Error() { 116 | t.Errorf("TestExternalLookupValueAndGet %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) 117 | continue 118 | } 119 | } else if err != test.getError { 120 | t.Errorf("TestExternalLookupValueAndGet %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) 121 | continue 122 | } 123 | if value != test.varGetValue { 124 | t.Errorf("TestExternalLookupValueAndGet %v - value check - received %#v expected: %#v", test.testInfo, value, test.varGetValue) 125 | } 126 | } 127 | } 128 | 129 | func TestExternalLookupTypeAndGet(t *testing.T) { 130 | var err error 131 | var valueType reflect.Type 132 | tests := []struct { 133 | testInfo string 134 | varName string 135 | varDefineValue interface{} 136 | defineError error 137 | typeError error 138 | }{ 139 | {testInfo: "nil", varName: "a", varDefineValue: nil}, 140 | {testInfo: "bool", varName: "a", varDefineValue: true}, 141 | {testInfo: "int16", varName: "a", varDefineValue: int16(1)}, 142 | {testInfo: "int32", varName: "a", varDefineValue: int32(1)}, 143 | {testInfo: "int64", varName: "a", varDefineValue: int64(1)}, 144 | {testInfo: "uint32", varName: "a", varDefineValue: uint32(1)}, 145 | {testInfo: "uint64", varName: "a", varDefineValue: uint64(1)}, 146 | {testInfo: "float32", varName: "a", varDefineValue: float32(1)}, 147 | {testInfo: "float64", varName: "a", varDefineValue: float64(1)}, 148 | {testInfo: "string", varName: "a", varDefineValue: "a"}, 149 | 150 | {testInfo: "string with dot", varName: "a.a", varDefineValue: nil, defineError: ErrSymbolContainsDot, typeError: fmt.Errorf("undefined type 'a.a'")}, 151 | } 152 | 153 | // DefineType 154 | for _, test := range tests { 155 | testExternalLookup := NewTestExternalLookup() 156 | env := NewEnv() 157 | env.SetExternalLookup(testExternalLookup) 158 | 159 | err = testExternalLookup.DefineType(test.varName, test.varDefineValue) 160 | if err != nil && test.defineError != nil { 161 | if err.Error() != test.defineError.Error() { 162 | t.Errorf("TestExternalLookupTypeAndGet %v - DefineType error - received: %v - expected: %v", test.testInfo, err, test.defineError) 163 | continue 164 | } 165 | } else if err != test.defineError { 166 | t.Errorf("TestExternalLookupTypeAndGet %v - DefineType error - received: %v - expected: %v", test.testInfo, err, test.defineError) 167 | continue 168 | } 169 | 170 | valueType, err = env.Type(test.varName) 171 | if err != nil && test.typeError != nil { 172 | if err.Error() != test.typeError.Error() { 173 | t.Errorf("TestExternalLookupTypeAndGet %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) 174 | continue 175 | } 176 | } else if err != test.typeError { 177 | t.Errorf("TestExternalLookupTypeAndGet %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) 178 | continue 179 | } 180 | if valueType == nil || test.varDefineValue == nil { 181 | if valueType != reflect.TypeOf(test.varDefineValue) { 182 | t.Errorf("TestExternalLookupTypeAndGet %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) 183 | } 184 | } else if valueType.String() != reflect.TypeOf(test.varDefineValue).String() { 185 | t.Errorf("TestExternalLookupTypeAndGet %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) 186 | } 187 | } 188 | 189 | } 190 | 191 | func TestExternalLookupAddr(t *testing.T) { 192 | var err error 193 | tests := []struct { 194 | testInfo string 195 | varName string 196 | varDefineValue interface{} 197 | defineError error 198 | addrError error 199 | }{ 200 | {testInfo: "nil", varName: "a", varDefineValue: nil, addrError: nil}, 201 | {testInfo: "bool", varName: "a", varDefineValue: true, addrError: fmt.Errorf("unaddressable")}, 202 | {testInfo: "int64", varName: "a", varDefineValue: int64(1), addrError: fmt.Errorf("unaddressable")}, 203 | {testInfo: "float64", varName: "a", varDefineValue: float64(1), addrError: fmt.Errorf("unaddressable")}, 204 | {testInfo: "string", varName: "a", varDefineValue: "a", addrError: fmt.Errorf("unaddressable")}, 205 | } 206 | 207 | for _, test := range tests { 208 | envParent := NewEnv() 209 | testExternalLookup := NewTestExternalLookup() 210 | envParent.SetExternalLookup(testExternalLookup) 211 | envChild := envParent.NewEnv() 212 | 213 | err = testExternalLookup.SetValue(test.varName, test.varDefineValue) 214 | if err != nil && test.defineError != nil { 215 | if err.Error() != test.defineError.Error() { 216 | t.Errorf("TestExternalLookupAddr %v - SetValue error - received: %v - expected: %v", test.testInfo, err, test.defineError) 217 | continue 218 | } 219 | } else if err != test.defineError { 220 | t.Errorf("TestExternalLookupAddr %v - SetValue error - received: %v - expected: %v", test.testInfo, err, test.defineError) 221 | continue 222 | } 223 | 224 | _, err = envChild.Addr(test.varName) 225 | if err != nil && test.addrError != nil { 226 | if err.Error() != test.addrError.Error() { 227 | t.Errorf("TestExternalLookupAddr %v - Addr error - received: %v - expected: %v", test.testInfo, err, test.addrError) 228 | continue 229 | } 230 | } else if err != test.addrError { 231 | t.Errorf("TestExternalLookupAddr %v - Addr error - received: %v - expected: %v", test.testInfo, err, test.addrError) 232 | continue 233 | } 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /env/envTypes.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | ) 8 | 9 | // DefineType defines type in current scope. 10 | func (e *Env) DefineType(symbol string, aType interface{}) error { 11 | var reflectType reflect.Type 12 | if aType == nil { 13 | reflectType = NilType 14 | } else { 15 | var ok bool 16 | reflectType, ok = aType.(reflect.Type) 17 | if !ok { 18 | reflectType = reflect.TypeOf(aType) 19 | } 20 | } 21 | 22 | return e.DefineReflectType(symbol, reflectType) 23 | } 24 | 25 | // DefineReflectType defines type in current scope. 26 | func (e *Env) DefineReflectType(symbol string, reflectType reflect.Type) error { 27 | if strings.Contains(symbol, ".") { 28 | return ErrSymbolContainsDot 29 | } 30 | 31 | e.rwMutex.Lock() 32 | if e.types == nil { 33 | e.types = make(map[string]reflect.Type) 34 | } 35 | e.types[symbol] = reflectType 36 | e.rwMutex.Unlock() 37 | 38 | return nil 39 | } 40 | 41 | // DefineGlobalType defines type in global scope. 42 | func (e *Env) DefineGlobalType(symbol string, aType interface{}) error { 43 | for e.parent != nil { 44 | e = e.parent 45 | } 46 | return e.DefineType(symbol, aType) 47 | } 48 | 49 | // DefineGlobalReflectType defines type in global scope. 50 | func (e *Env) DefineGlobalReflectType(symbol string, reflectType reflect.Type) error { 51 | for e.parent != nil { 52 | e = e.parent 53 | } 54 | return e.DefineReflectType(symbol, reflectType) 55 | } 56 | 57 | // Type returns reflect type from the scope where symbol is frist found. 58 | func (e *Env) Type(symbol string) (reflect.Type, error) { 59 | e.rwMutex.RLock() 60 | reflectType, ok := e.types[symbol] 61 | e.rwMutex.RUnlock() 62 | if ok { 63 | return reflectType, nil 64 | } 65 | 66 | if e.externalLookup != nil { 67 | var err error 68 | reflectType, err = e.externalLookup.Type(symbol) 69 | if err == nil { 70 | return reflectType, nil 71 | } 72 | } 73 | 74 | if e.parent == nil { 75 | reflectType, ok = basicTypes[symbol] 76 | if ok { 77 | return reflectType, nil 78 | } 79 | return NilType, fmt.Errorf("undefined type '%s'", symbol) 80 | } 81 | 82 | return e.parent.Type(symbol) 83 | } 84 | 85 | 86 | // GetValueSymbols returns all value symbol in the current scope. 87 | func (e *Env) GetTypeSymbols() []string { 88 | symbols := make([]string, 0, len(e.values)) 89 | e.rwMutex.RLock() 90 | for symbol := range e.types { 91 | symbols = append(symbols, symbol) 92 | } 93 | e.rwMutex.RUnlock() 94 | return symbols 95 | } 96 | -------------------------------------------------------------------------------- /env/envValues.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | ) 8 | 9 | // define 10 | 11 | // Define defines/sets interface value to symbol in current scope. 12 | func (e *Env) Define(symbol string, value interface{}) error { 13 | if value == nil { 14 | return e.DefineValue(symbol, NilValue) 15 | } 16 | return e.DefineValue(symbol, reflect.ValueOf(value)) 17 | } 18 | 19 | // DefineValue defines/sets reflect value to symbol in current scope. 20 | func (e *Env) DefineValue(symbol string, value reflect.Value) error { 21 | if strings.Contains(symbol, ".") { 22 | return ErrSymbolContainsDot 23 | } 24 | e.rwMutex.Lock() 25 | e.values[symbol] = value 26 | e.rwMutex.Unlock() 27 | 28 | return nil 29 | } 30 | 31 | // DefineGlobal defines/sets interface value to symbol in global scope. 32 | func (e *Env) DefineGlobal(symbol string, value interface{}) error { 33 | for e.parent != nil { 34 | e = e.parent 35 | } 36 | return e.Define(symbol, value) 37 | } 38 | 39 | // DefineGlobalValue defines/sets reflect value to symbol in global scope. 40 | func (e *Env) DefineGlobalValue(symbol string, value reflect.Value) error { 41 | for e.parent != nil { 42 | e = e.parent 43 | } 44 | return e.DefineValue(symbol, value) 45 | } 46 | 47 | // set 48 | 49 | // Set interface value to the scope where symbol is frist found. 50 | func (e *Env) Set(symbol string, value interface{}) error { 51 | if value == nil { 52 | return e.SetValue(symbol, NilValue) 53 | } 54 | return e.SetValue(symbol, reflect.ValueOf(value)) 55 | } 56 | 57 | // SetValue reflect value to the scope where symbol is frist found. 58 | func (e *Env) SetValue(symbol string, value reflect.Value) error { 59 | e.rwMutex.RLock() 60 | _, ok := e.values[symbol] 61 | e.rwMutex.RUnlock() 62 | if ok { 63 | e.rwMutex.Lock() 64 | e.values[symbol] = value 65 | e.rwMutex.Unlock() 66 | return nil 67 | } 68 | 69 | if e.parent == nil { 70 | return fmt.Errorf("undefined symbol '%s'", symbol) 71 | } 72 | return e.parent.SetValue(symbol, value) 73 | } 74 | 75 | // get 76 | 77 | // Get returns interface value from the scope where symbol is frist found. 78 | func (e *Env) Get(symbol string) (interface{}, error) { 79 | rv, err := e.GetValue(symbol) 80 | return rv.Interface(), err 81 | } 82 | 83 | // GetValue returns reflect value from the scope where symbol is frist found. 84 | func (e *Env) GetValue(symbol string) (reflect.Value, error) { 85 | e.rwMutex.RLock() 86 | value, ok := e.values[symbol] 87 | e.rwMutex.RUnlock() 88 | if ok { 89 | return value, nil 90 | } 91 | 92 | if e.externalLookup != nil { 93 | var err error 94 | value, err = e.externalLookup.Get(symbol) 95 | if err == nil { 96 | return value, nil 97 | } 98 | } 99 | 100 | if e.parent == nil { 101 | return NilValue, fmt.Errorf("undefined symbol '%s'", symbol) 102 | } 103 | 104 | return e.parent.GetValue(symbol) 105 | } 106 | 107 | // GetValueSymbols returns all value symbol in the current scope. 108 | func (e *Env) GetValueSymbols() []string { 109 | symbols := make([]string, 0, len(e.values)) 110 | e.rwMutex.RLock() 111 | for symbol := range e.values { 112 | symbols = append(symbols, symbol) 113 | } 114 | e.rwMutex.RUnlock() 115 | return symbols 116 | } 117 | 118 | // delete 119 | 120 | // Delete deletes symbol in current scope. 121 | func (e *Env) Delete(symbol string) { 122 | e.rwMutex.Lock() 123 | delete(e.values, symbol) 124 | e.rwMutex.Unlock() 125 | } 126 | 127 | // DeleteGlobal deletes the first matching symbol found in current or parent scope. 128 | func (e *Env) DeleteGlobal(symbol string) { 129 | if e.parent == nil { 130 | e.Delete(symbol) 131 | return 132 | } 133 | 134 | e.rwMutex.RLock() 135 | _, ok := e.values[symbol] 136 | e.rwMutex.RUnlock() 137 | 138 | if ok { 139 | e.Delete(symbol) 140 | return 141 | } 142 | 143 | e.parent.DeleteGlobal(symbol) 144 | } 145 | 146 | // Addr 147 | 148 | // Addr returns reflect.Addr of value for first matching symbol found in current or parent scope. 149 | func (e *Env) Addr(symbol string) (reflect.Value, error) { 150 | e.rwMutex.RLock() 151 | defer e.rwMutex.RUnlock() 152 | 153 | if v, ok := e.values[symbol]; ok { 154 | if v.CanAddr() { 155 | return v.Addr(), nil 156 | } 157 | return NilValue, fmt.Errorf("unaddressable") 158 | } 159 | if e.externalLookup != nil { 160 | v, err := e.externalLookup.Get(symbol) 161 | if err == nil { 162 | if v.CanAddr() { 163 | return v.Addr(), nil 164 | } 165 | return NilValue, fmt.Errorf("unaddressable") 166 | } 167 | } 168 | if e.parent == nil { 169 | return NilValue, fmt.Errorf("undefined symbol '%s'", symbol) 170 | } 171 | return e.parent.Addr(symbol) 172 | } 173 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mattn/anko 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /misc/vim/ftdetect/ank.vim: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead *.ank setlocal filetype=anko 2 | -------------------------------------------------------------------------------- /misc/vim/ftplugin/anko/comment.vim: -------------------------------------------------------------------------------- 1 | if exists("b:did_ftplugin") 2 | finish 3 | endif 4 | let b:did_ftplugin = 1 5 | 6 | setlocal comments=s1:# 7 | setlocal commentstring=#\ %s 8 | 9 | let b:undo_ftplugin = "setl com< cms<" 10 | 11 | " vim:ts=4:sw=4:et 12 | -------------------------------------------------------------------------------- /misc/vim/ftplugin/anko/play.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | function! s:play() 4 | let code = join(getline(1, '$'), "\n") 5 | let res = webapi#http#post("http://play-anko.appspot.com/api/play", {"code": code}) 6 | if res.status == "200" 7 | echo iconv(res.content, "utf-8", &encoding) 8 | else 9 | for line in split(res.content, "\n") 10 | echohl Error | echomsg iconv(line, "utf-8", &encoding) | echohl None 11 | endfor 12 | endif 13 | endfunction 14 | 15 | command! -buffer PlayAnko call s:play() 16 | -------------------------------------------------------------------------------- /misc/vim/syntax/anko.vim: -------------------------------------------------------------------------------- 1 | if exists("b:current_syntax") 2 | finish 3 | endif 4 | 5 | syn case match 6 | 7 | syn keyword ankoDirective module 8 | syn keyword ankoDeclaration var 9 | 10 | hi def link ankoDirective Statement 11 | hi def link ankoDeclaration Type 12 | 13 | syn keyword ankoStatement return break continue throw 14 | syn keyword ankoConditional if else switch try catch finally 15 | syn keyword ankoLabel case default 16 | syn keyword ankoRepeat for range 17 | 18 | hi def link ankoStatement Statement 19 | hi def link ankoConditional Conditional 20 | hi def link ankoLabel Label 21 | hi def link ankoRepeat Repeat 22 | 23 | syn match ankoDeclaration /\/ 24 | syn match ankoDeclaration /^func\>/ 25 | 26 | syn keyword ankoCast bytes runes string 27 | 28 | hi def link ankoCast Type 29 | 30 | syn keyword ankoBuiltins keys len 31 | syn keyword ankoBuiltins println printf print 32 | syn keyword ankoConstants true false nil 33 | 34 | hi def link ankoBuiltins Keyword 35 | hi def link ankoConstants Keyword 36 | 37 | " Comments; their contents 38 | syn keyword ankoTodo contained TODO FIXME XXX BUG 39 | syn cluster ankoCommentGroup contains=ankoTodo 40 | syn region ankoComment start="#" end="$" contains=@ankoCommentGroup,@Spell 41 | 42 | hi def link ankoComment Comment 43 | hi def link ankoTodo Todo 44 | 45 | " anko escapes 46 | syn match ankoEscapeOctal display contained "\\[0-7]\{3}" 47 | syn match ankoEscapeC display contained +\\[abfnrtv\\'"]+ 48 | syn match ankoEscapeX display contained "\\x\x\{2}" 49 | syn match ankoEscapeU display contained "\\u\x\{4}" 50 | syn match ankoEscapeBigU display contained "\\U\x\{8}" 51 | syn match ankoEscapeError display contained +\\[^0-7xuUabfnrtv\\'"]+ 52 | 53 | hi def link ankoEscapeOctal ankoSpecialString 54 | hi def link ankoEscapeC ankoSpecialString 55 | hi def link ankoEscapeX ankoSpecialString 56 | hi def link ankoEscapeU ankoSpecialString 57 | hi def link ankoEscapeBigU ankoSpecialString 58 | hi def link ankoSpecialString Special 59 | hi def link ankoEscapeError Error 60 | 61 | " Strings and their contents 62 | syn cluster ankoStringGroup contains=ankoEscapeOctal,ankoEscapeC,ankoEscapeX,ankoEscapeU,ankoEscapeBigU,ankoEscapeError 63 | syn region ankoString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@ankoStringGroup 64 | syn region ankoRawString start=+`+ end=+`+ 65 | 66 | hi def link ankoString String 67 | hi def link ankoRawString String 68 | 69 | " Characters; their contents 70 | syn cluster ankoCharacterGroup contains=ankoEscapeOctal,ankoEscapeC,ankoEscapeX,ankoEscapeU,ankoEscapeBigU 71 | syn region ankoCharacter start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=@ankoCharacterGroup 72 | 73 | hi def link ankoCharacter Character 74 | 75 | " Regions 76 | syn region ankoBlock start="{" end="}" transparent fold 77 | syn region ankoParen start='(' end=')' transparent 78 | 79 | " Integers 80 | syn match ankoDecimalInt "\<\d\+\([Ee]\d\+\)\?\>" 81 | syn match ankoHexadecimalInt "\<0x\x\+\>" 82 | syn match ankoOctalInt "\<0\o\+\>" 83 | syn match ankoOctalError "\<0\o*[89]\d*\>" 84 | 85 | hi def link ankoDecimalInt Integer 86 | hi def link ankoHexadecimalInt Integer 87 | hi def link ankoOctalInt Integer 88 | hi def link Integer Number 89 | 90 | " Floating point 91 | syn match ankoFloat "\<\d\+\.\d*\([Ee][-+]\d\+\)\?\>" 92 | syn match ankoFloat "\<\.\d\+\([Ee][-+]\d\+\)\?\>" 93 | syn match ankoFloat "\<\d\+[Ee][-+]\d\+\>" 94 | 95 | hi def link ankoFloat Float 96 | hi def link ankoImaginary Number 97 | 98 | syn sync minlines=500 99 | 100 | let b:current_syntax = "anko" 101 | -------------------------------------------------------------------------------- /misc/wasm/anko.go: -------------------------------------------------------------------------------- 1 | // +build js,wasm 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "html" 8 | "strings" 9 | "syscall/js" 10 | 11 | "github.com/mattn/anko/core" 12 | "github.com/mattn/anko/packages" 13 | "github.com/mattn/anko/parser" 14 | "github.com/mattn/anko/vm" 15 | ) 16 | 17 | var ( 18 | result = js.Global.Get("document").Call("getElementById", "result") 19 | input = js.Global.Get("document").Call("getElementById", "input") 20 | ) 21 | 22 | func writeCommand(s string) { 23 | result.Set("innerHTML", result.Get("innerHTML").String()+"

"+html.EscapeString(s)+"

") 24 | result.Set("scrollTop", result.Get("scrollHeight").Int()) 25 | } 26 | 27 | func writeStdout(s string) { 28 | result.Set("innerHTML", result.Get("innerHTML").String()+"

"+html.EscapeString(s)+"

") 29 | result.Set("scrollTop", result.Get("scrollHeight").Int()) 30 | } 31 | 32 | func writeStderr(s string) { 33 | result.Set("innerHTML", result.Get("innerHTML").String()+"

"+html.EscapeString(s)+"

") 34 | result.Set("scrollTop", result.Get("scrollHeight").Int()) 35 | } 36 | 37 | func main() { 38 | env := vm.NewEnv() 39 | core.Import(env) 40 | packages.DefineImport(env) 41 | 42 | env.Define("print", func(a ...interface{}) { 43 | writeStdout(fmt.Sprint(a...)) 44 | }) 45 | env.Define("printf", func(a string, b ...interface{}) { 46 | writeStdout(fmt.Sprintf(a, b...)) 47 | }) 48 | 49 | var following bool 50 | var source string 51 | 52 | parser.EnableErrorVerbose() 53 | 54 | ch := make(chan string) 55 | 56 | input.Call("addEventListener", "keypress", js.NewCallback(func(args []js.Value) { 57 | e := args[0] 58 | if e.Get("keyCode").Int() != 13 { 59 | return 60 | } 61 | s := e.Get("target").Get("value").String() 62 | e.Get("target").Set("value", "") 63 | writeCommand(s) 64 | ch <- s 65 | })) 66 | input.Set("disabled", false) 67 | result.Set("innerHTML", "") 68 | 69 | go func() { 70 | for { 71 | text, ok := <-ch 72 | if !ok { 73 | break 74 | } 75 | source += text 76 | if source == "" { 77 | continue 78 | } 79 | if source == "quit()" { 80 | break 81 | } 82 | 83 | stmts, err := parser.ParseSrc(source) 84 | 85 | if e, ok := err.(*parser.Error); ok { 86 | es := e.Error() 87 | if strings.HasPrefix(es, "syntax error: unexpected") { 88 | if strings.HasPrefix(es, "syntax error: unexpected $end,") { 89 | following = true 90 | continue 91 | } 92 | } else { 93 | if e.Pos.Column == len(source) && !e.Fatal { 94 | writeStderr(e.Error()) 95 | following = true 96 | continue 97 | } 98 | if e.Error() == "unexpected EOF" { 99 | following = true 100 | continue 101 | } 102 | } 103 | } 104 | 105 | following = false 106 | source = "" 107 | var v interface{} 108 | 109 | if err == nil { 110 | v, err = vm.Run(stmts, env) 111 | } 112 | if err != nil { 113 | if e, ok := err.(*vm.Error); ok { 114 | writeStderr(fmt.Sprintf("%d:%d %s\n", e.Pos.Line, e.Pos.Column, err)) 115 | } else if e, ok := err.(*parser.Error); ok { 116 | writeStderr(fmt.Sprintf("%d:%d %s\n", e.Pos.Line, e.Pos.Column, err)) 117 | } else { 118 | writeStderr(err.Error()) 119 | } 120 | continue 121 | } 122 | 123 | writeStdout(fmt.Sprintf("%#v\n", v)) 124 | } 125 | }() 126 | 127 | select {} 128 | 129 | } 130 | -------------------------------------------------------------------------------- /misc/wasm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Anko WebAssembly 4 | 5 | 23 | 30 | 31 | 32 |
loading...
33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /packages/bytes.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "bytes" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["bytes"] = map[string]reflect.Value{ 12 | "Compare": reflect.ValueOf(bytes.Compare), 13 | "Contains": reflect.ValueOf(bytes.Contains), 14 | "Count": reflect.ValueOf(bytes.Count), 15 | "Equal": reflect.ValueOf(bytes.Equal), 16 | "EqualFold": reflect.ValueOf(bytes.EqualFold), 17 | "Fields": reflect.ValueOf(bytes.Fields), 18 | "FieldsFunc": reflect.ValueOf(bytes.FieldsFunc), 19 | "HasPrefix": reflect.ValueOf(bytes.HasPrefix), 20 | "HasSuffix": reflect.ValueOf(bytes.HasSuffix), 21 | "Index": reflect.ValueOf(bytes.Index), 22 | "IndexAny": reflect.ValueOf(bytes.IndexAny), 23 | "IndexByte": reflect.ValueOf(bytes.IndexByte), 24 | "IndexFunc": reflect.ValueOf(bytes.IndexFunc), 25 | "IndexRune": reflect.ValueOf(bytes.IndexRune), 26 | "Join": reflect.ValueOf(bytes.Join), 27 | "LastIndex": reflect.ValueOf(bytes.LastIndex), 28 | "LastIndexAny": reflect.ValueOf(bytes.LastIndexAny), 29 | "LastIndexByte": reflect.ValueOf(bytes.LastIndexByte), 30 | "LastIndexFunc": reflect.ValueOf(bytes.LastIndexFunc), 31 | "Map": reflect.ValueOf(bytes.Map), 32 | "NewBuffer": reflect.ValueOf(bytes.NewBuffer), 33 | "NewBufferString": reflect.ValueOf(bytes.NewBufferString), 34 | "NewReader": reflect.ValueOf(bytes.NewReader), 35 | "Repeat": reflect.ValueOf(bytes.Repeat), 36 | "Replace": reflect.ValueOf(bytes.Replace), 37 | "Runes": reflect.ValueOf(bytes.Runes), 38 | "Split": reflect.ValueOf(bytes.Split), 39 | "SplitAfter": reflect.ValueOf(bytes.SplitAfter), 40 | "SplitAfterN": reflect.ValueOf(bytes.SplitAfterN), 41 | "SplitN": reflect.ValueOf(bytes.SplitN), 42 | "Title": reflect.ValueOf(bytes.Title), 43 | "ToLower": reflect.ValueOf(bytes.ToLower), 44 | "ToLowerSpecial": reflect.ValueOf(bytes.ToLowerSpecial), 45 | "ToTitle": reflect.ValueOf(bytes.ToTitle), 46 | "ToTitleSpecial": reflect.ValueOf(bytes.ToTitleSpecial), 47 | "ToUpper": reflect.ValueOf(bytes.ToUpper), 48 | "ToUpperSpecial": reflect.ValueOf(bytes.ToUpperSpecial), 49 | "Trim": reflect.ValueOf(bytes.Trim), 50 | "TrimFunc": reflect.ValueOf(bytes.TrimFunc), 51 | "TrimLeft": reflect.ValueOf(bytes.TrimLeft), 52 | "TrimLeftFunc": reflect.ValueOf(bytes.TrimLeftFunc), 53 | "TrimPrefix": reflect.ValueOf(bytes.TrimPrefix), 54 | "TrimRight": reflect.ValueOf(bytes.TrimRight), 55 | "TrimRightFunc": reflect.ValueOf(bytes.TrimRightFunc), 56 | "TrimSpace": reflect.ValueOf(bytes.TrimSpace), 57 | "TrimSuffix": reflect.ValueOf(bytes.TrimSuffix), 58 | } 59 | env.PackageTypes["bytes"] = map[string]reflect.Type{ 60 | "Buffer": reflect.TypeOf(bytes.Buffer{}), 61 | "Reader": reflect.TypeOf(bytes.Reader{}), 62 | } 63 | bytesGo17() 64 | } 65 | -------------------------------------------------------------------------------- /packages/bytesGo17.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package packages 4 | 5 | import ( 6 | "bytes" 7 | "reflect" 8 | 9 | "github.com/mattn/anko/env" 10 | ) 11 | 12 | func bytesGo17() { 13 | env.Packages["bytes"]["ContainsRune"] = reflect.ValueOf(bytes.ContainsRune) 14 | } 15 | -------------------------------------------------------------------------------- /packages/bytesNotGo17.go: -------------------------------------------------------------------------------- 1 | // +build !go1.7 2 | 3 | package packages 4 | 5 | func bytesGo17() {} 6 | -------------------------------------------------------------------------------- /packages/encoding.json.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "encoding/json" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["encoding/json"] = map[string]reflect.Value{ 12 | "Marshal": reflect.ValueOf(json.Marshal), 13 | "Unmarshal": reflect.ValueOf(json.Unmarshal), 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/errors.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["errors"] = map[string]reflect.Value{ 12 | "New": reflect.ValueOf(errors.New), 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/flag.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "flag" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["flag"] = map[string]reflect.Value{ 12 | "Arg": reflect.ValueOf(flag.Arg), 13 | "Args": reflect.ValueOf(flag.Args), 14 | "Bool": reflect.ValueOf(flag.Bool), 15 | "BoolVar": reflect.ValueOf(flag.BoolVar), 16 | "CommandLine": reflect.ValueOf(flag.CommandLine), 17 | "ContinueOnError": reflect.ValueOf(flag.ContinueOnError), 18 | "Duration": reflect.ValueOf(flag.Duration), 19 | "DurationVar": reflect.ValueOf(flag.DurationVar), 20 | "ErrHelp": reflect.ValueOf(flag.ErrHelp), 21 | "ExitOnError": reflect.ValueOf(flag.ExitOnError), 22 | "Float64": reflect.ValueOf(flag.Float64), 23 | "Float64Var": reflect.ValueOf(flag.Float64Var), 24 | "Int": reflect.ValueOf(flag.Int), 25 | "Int64": reflect.ValueOf(flag.Int64), 26 | "Int64Var": reflect.ValueOf(flag.Int64Var), 27 | "IntVar": reflect.ValueOf(flag.IntVar), 28 | "Lookup": reflect.ValueOf(flag.Lookup), 29 | "NArg": reflect.ValueOf(flag.NArg), 30 | "NFlag": reflect.ValueOf(flag.NFlag), 31 | "NewFlagSet": reflect.ValueOf(flag.NewFlagSet), 32 | "PanicOnError": reflect.ValueOf(flag.PanicOnError), 33 | "Parse": reflect.ValueOf(flag.Parse), 34 | "Parsed": reflect.ValueOf(flag.Parsed), 35 | "PrintDefaults": reflect.ValueOf(flag.PrintDefaults), 36 | "Set": reflect.ValueOf(flag.Set), 37 | "String": reflect.ValueOf(flag.String), 38 | "StringVar": reflect.ValueOf(flag.StringVar), 39 | "Uint": reflect.ValueOf(flag.Uint), 40 | "Uint64": reflect.ValueOf(flag.Uint64), 41 | "Uint64Var": reflect.ValueOf(flag.Uint64Var), 42 | "UintVar": reflect.ValueOf(flag.UintVar), 43 | "Usage": reflect.ValueOf(flag.Usage), 44 | "Var": reflect.ValueOf(flag.Var), 45 | "Visit": reflect.ValueOf(flag.Visit), 46 | "VisitAll": reflect.ValueOf(flag.VisitAll), 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/fmt.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["fmt"] = map[string]reflect.Value{ 12 | "Errorf": reflect.ValueOf(fmt.Errorf), 13 | "Fprint": reflect.ValueOf(fmt.Fprint), 14 | "Fprintf": reflect.ValueOf(fmt.Fprintf), 15 | "Fprintln": reflect.ValueOf(fmt.Fprintln), 16 | "Fscan": reflect.ValueOf(fmt.Fscan), 17 | "Fscanf": reflect.ValueOf(fmt.Fscanf), 18 | "Fscanln": reflect.ValueOf(fmt.Fscanln), 19 | "Print": reflect.ValueOf(fmt.Print), 20 | "Printf": reflect.ValueOf(fmt.Printf), 21 | "Println": reflect.ValueOf(fmt.Println), 22 | "Scan": reflect.ValueOf(fmt.Scan), 23 | "Scanf": reflect.ValueOf(fmt.Scanf), 24 | "Scanln": reflect.ValueOf(fmt.Scanln), 25 | "Sprint": reflect.ValueOf(fmt.Sprint), 26 | "Sprintf": reflect.ValueOf(fmt.Sprintf), 27 | "Sprintln": reflect.ValueOf(fmt.Sprintln), 28 | "Sscan": reflect.ValueOf(fmt.Sscan), 29 | "Sscanf": reflect.ValueOf(fmt.Sscanf), 30 | "Sscanln": reflect.ValueOf(fmt.Sscanln), 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/io.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "io" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["io"] = map[string]reflect.Value{ 12 | "Copy": reflect.ValueOf(io.Copy), 13 | "CopyN": reflect.ValueOf(io.CopyN), 14 | "EOF": reflect.ValueOf(io.EOF), 15 | "ErrClosedPipe": reflect.ValueOf(io.ErrClosedPipe), 16 | "ErrNoProgress": reflect.ValueOf(io.ErrNoProgress), 17 | "ErrShortBuffer": reflect.ValueOf(io.ErrShortBuffer), 18 | "ErrShortWrite": reflect.ValueOf(io.ErrShortWrite), 19 | "ErrUnexpectedEOF": reflect.ValueOf(io.ErrUnexpectedEOF), 20 | "LimitReader": reflect.ValueOf(io.LimitReader), 21 | "MultiReader": reflect.ValueOf(io.MultiReader), 22 | "MultiWriter": reflect.ValueOf(io.MultiWriter), 23 | "NewSectionReader": reflect.ValueOf(io.NewSectionReader), 24 | "Pipe": reflect.ValueOf(io.Pipe), 25 | "ReadAtLeast": reflect.ValueOf(io.ReadAtLeast), 26 | "ReadFull": reflect.ValueOf(io.ReadFull), 27 | "TeeReader": reflect.ValueOf(io.TeeReader), 28 | "WriteString": reflect.ValueOf(io.WriteString), 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/io.ioutil.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "io/ioutil" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["io/ioutil"] = map[string]reflect.Value{ 12 | "ReadAll": reflect.ValueOf(ioutil.ReadAll), 13 | "ReadDir": reflect.ValueOf(ioutil.ReadDir), 14 | "ReadFile": reflect.ValueOf(ioutil.ReadFile), 15 | "WriteFile": reflect.ValueOf(ioutil.WriteFile), 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/log.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "log" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["log"] = map[string]reflect.Value{ 12 | "Fatal": reflect.ValueOf(log.Fatal), 13 | "Fatalf": reflect.ValueOf(log.Fatalf), 14 | "Fatalln": reflect.ValueOf(log.Fatalln), 15 | "Flags": reflect.ValueOf(log.Flags), 16 | "New": reflect.ValueOf(log.New), 17 | "Output": reflect.ValueOf(log.Output), 18 | "Panic": reflect.ValueOf(log.Panic), 19 | "Panicf": reflect.ValueOf(log.Panicf), 20 | "Panicln": reflect.ValueOf(log.Panicln), 21 | "Prefix": reflect.ValueOf(log.Prefix), 22 | "Print": reflect.ValueOf(log.Print), 23 | "Printf": reflect.ValueOf(log.Printf), 24 | "Println": reflect.ValueOf(log.Println), 25 | "SetFlags": reflect.ValueOf(log.SetFlags), 26 | "SetOutput": reflect.ValueOf(log.SetOutput), 27 | "SetPrefix": reflect.ValueOf(log.SetPrefix), 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/math.big.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "math/big" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["math/big"] = map[string]reflect.Value{ 12 | "Above": reflect.ValueOf(big.Above), 13 | "AwayFromZero": reflect.ValueOf(big.AwayFromZero), 14 | "Below": reflect.ValueOf(big.Below), 15 | "Exact": reflect.ValueOf(big.Exact), 16 | "Jacobi": reflect.ValueOf(big.Jacobi), 17 | "MaxBase": reflect.ValueOf(big.MaxBase), 18 | "MaxExp": reflect.ValueOf(big.MaxExp), 19 | // TODO: https://github.com/mattn/anko/issues/49 20 | // "MaxPrec": reflect.ValueOf(big.MaxPrec), 21 | "MinExp": reflect.ValueOf(big.MinExp), 22 | "NewFloat": reflect.ValueOf(big.NewFloat), 23 | "NewInt": reflect.ValueOf(big.NewInt), 24 | "NewRat": reflect.ValueOf(big.NewRat), 25 | "ParseFloat": reflect.ValueOf(big.ParseFloat), 26 | "ToNearestAway": reflect.ValueOf(big.ToNearestAway), 27 | "ToNearestEven": reflect.ValueOf(big.ToNearestEven), 28 | "ToNegativeInf": reflect.ValueOf(big.ToNegativeInf), 29 | "ToPositiveInf": reflect.ValueOf(big.ToPositiveInf), 30 | "ToZero": reflect.ValueOf(big.ToZero), 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/math.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "math" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["math"] = map[string]reflect.Value{ 12 | "Abs": reflect.ValueOf(math.Abs), 13 | "Acos": reflect.ValueOf(math.Acos), 14 | "Acosh": reflect.ValueOf(math.Acosh), 15 | "Asin": reflect.ValueOf(math.Asin), 16 | "Asinh": reflect.ValueOf(math.Asinh), 17 | "Atan": reflect.ValueOf(math.Atan), 18 | "Atan2": reflect.ValueOf(math.Atan2), 19 | "Atanh": reflect.ValueOf(math.Atanh), 20 | "Cbrt": reflect.ValueOf(math.Cbrt), 21 | "Ceil": reflect.ValueOf(math.Ceil), 22 | "Copysign": reflect.ValueOf(math.Copysign), 23 | "Cos": reflect.ValueOf(math.Cos), 24 | "Cosh": reflect.ValueOf(math.Cosh), 25 | "Dim": reflect.ValueOf(math.Dim), 26 | "Erf": reflect.ValueOf(math.Erf), 27 | "Erfc": reflect.ValueOf(math.Erfc), 28 | "Exp": reflect.ValueOf(math.Exp), 29 | "Exp2": reflect.ValueOf(math.Exp2), 30 | "Expm1": reflect.ValueOf(math.Expm1), 31 | "Float32bits": reflect.ValueOf(math.Float32bits), 32 | "Float32frombits": reflect.ValueOf(math.Float32frombits), 33 | "Float64bits": reflect.ValueOf(math.Float64bits), 34 | "Float64frombits": reflect.ValueOf(math.Float64frombits), 35 | "Floor": reflect.ValueOf(math.Floor), 36 | "Frexp": reflect.ValueOf(math.Frexp), 37 | "Gamma": reflect.ValueOf(math.Gamma), 38 | "Hypot": reflect.ValueOf(math.Hypot), 39 | "Ilogb": reflect.ValueOf(math.Ilogb), 40 | "Inf": reflect.ValueOf(math.Inf), 41 | "IsInf": reflect.ValueOf(math.IsInf), 42 | "IsNaN": reflect.ValueOf(math.IsNaN), 43 | "J0": reflect.ValueOf(math.J0), 44 | "J1": reflect.ValueOf(math.J1), 45 | "Jn": reflect.ValueOf(math.Jn), 46 | "Ldexp": reflect.ValueOf(math.Ldexp), 47 | "Lgamma": reflect.ValueOf(math.Lgamma), 48 | "Log": reflect.ValueOf(math.Log), 49 | "Log10": reflect.ValueOf(math.Log10), 50 | "Log1p": reflect.ValueOf(math.Log1p), 51 | "Log2": reflect.ValueOf(math.Log2), 52 | "Logb": reflect.ValueOf(math.Logb), 53 | "Max": reflect.ValueOf(math.Max), 54 | "Min": reflect.ValueOf(math.Min), 55 | "Mod": reflect.ValueOf(math.Mod), 56 | "Modf": reflect.ValueOf(math.Modf), 57 | "NaN": reflect.ValueOf(math.NaN), 58 | "Nextafter": reflect.ValueOf(math.Nextafter), 59 | "Pow": reflect.ValueOf(math.Pow), 60 | "Pow10": reflect.ValueOf(math.Pow10), 61 | "Remainder": reflect.ValueOf(math.Remainder), 62 | "Signbit": reflect.ValueOf(math.Signbit), 63 | "Sin": reflect.ValueOf(math.Sin), 64 | "Sincos": reflect.ValueOf(math.Sincos), 65 | "Sinh": reflect.ValueOf(math.Sinh), 66 | "Sqrt": reflect.ValueOf(math.Sqrt), 67 | "Tan": reflect.ValueOf(math.Tan), 68 | "Tanh": reflect.ValueOf(math.Tanh), 69 | "Trunc": reflect.ValueOf(math.Trunc), 70 | "Y0": reflect.ValueOf(math.Y0), 71 | "Y1": reflect.ValueOf(math.Y1), 72 | "Yn": reflect.ValueOf(math.Yn), 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /packages/math.rand.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "math/rand" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["math/rand"] = map[string]reflect.Value{ 12 | "ExpFloat64": reflect.ValueOf(rand.ExpFloat64), 13 | "Float32": reflect.ValueOf(rand.Float32), 14 | "Float64": reflect.ValueOf(rand.Float64), 15 | "Int": reflect.ValueOf(rand.Int), 16 | "Int31": reflect.ValueOf(rand.Int31), 17 | "Int31n": reflect.ValueOf(rand.Int31n), 18 | "Int63": reflect.ValueOf(rand.Int63), 19 | "Int63n": reflect.ValueOf(rand.Int63n), 20 | "Intn": reflect.ValueOf(rand.Intn), 21 | "NormFloat64": reflect.ValueOf(rand.NormFloat64), 22 | "Perm": reflect.ValueOf(rand.Perm), 23 | "Seed": reflect.ValueOf(rand.Seed), 24 | "Uint32": reflect.ValueOf(rand.Uint32), 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/net.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package packages 4 | 5 | import ( 6 | "net" 7 | "reflect" 8 | 9 | "github.com/mattn/anko/env" 10 | ) 11 | 12 | func init() { 13 | env.Packages["net"] = map[string]reflect.Value{ 14 | "CIDRMask": reflect.ValueOf(net.CIDRMask), 15 | "Dial": reflect.ValueOf(net.Dial), 16 | "DialIP": reflect.ValueOf(net.DialIP), 17 | "DialTCP": reflect.ValueOf(net.DialTCP), 18 | "DialTimeout": reflect.ValueOf(net.DialTimeout), 19 | "DialUDP": reflect.ValueOf(net.DialUDP), 20 | "DialUnix": reflect.ValueOf(net.DialUnix), 21 | "ErrWriteToConnected": reflect.ValueOf(net.ErrWriteToConnected), 22 | "FileConn": reflect.ValueOf(net.FileConn), 23 | "FileListener": reflect.ValueOf(net.FileListener), 24 | "FilePacketConn": reflect.ValueOf(net.FilePacketConn), 25 | "FlagBroadcast": reflect.ValueOf(net.FlagBroadcast), 26 | "FlagLoopback": reflect.ValueOf(net.FlagLoopback), 27 | "FlagMulticast": reflect.ValueOf(net.FlagMulticast), 28 | "FlagPointToPoint": reflect.ValueOf(net.FlagPointToPoint), 29 | "FlagUp": reflect.ValueOf(net.FlagUp), 30 | "IPv4": reflect.ValueOf(net.IPv4), 31 | "IPv4Mask": reflect.ValueOf(net.IPv4Mask), 32 | "IPv4allrouter": reflect.ValueOf(net.IPv4allrouter), 33 | "IPv4allsys": reflect.ValueOf(net.IPv4allsys), 34 | "IPv4bcast": reflect.ValueOf(net.IPv4bcast), 35 | "IPv4len": reflect.ValueOf(net.IPv4len), 36 | "IPv4zero": reflect.ValueOf(net.IPv4zero), 37 | "IPv6interfacelocalallnodes": reflect.ValueOf(net.IPv6interfacelocalallnodes), 38 | "IPv6len": reflect.ValueOf(net.IPv6len), 39 | "IPv6linklocalallnodes": reflect.ValueOf(net.IPv6linklocalallnodes), 40 | "IPv6linklocalallrouters": reflect.ValueOf(net.IPv6linklocalallrouters), 41 | "IPv6loopback": reflect.ValueOf(net.IPv6loopback), 42 | "IPv6unspecified": reflect.ValueOf(net.IPv6unspecified), 43 | "IPv6zero": reflect.ValueOf(net.IPv6zero), 44 | "InterfaceAddrs": reflect.ValueOf(net.InterfaceAddrs), 45 | "InterfaceByIndex": reflect.ValueOf(net.InterfaceByIndex), 46 | "InterfaceByName": reflect.ValueOf(net.InterfaceByName), 47 | "Interfaces": reflect.ValueOf(net.Interfaces), 48 | "JoinHostPort": reflect.ValueOf(net.JoinHostPort), 49 | "Listen": reflect.ValueOf(net.Listen), 50 | "ListenIP": reflect.ValueOf(net.ListenIP), 51 | "ListenMulticastUDP": reflect.ValueOf(net.ListenMulticastUDP), 52 | "ListenPacket": reflect.ValueOf(net.ListenPacket), 53 | "ListenTCP": reflect.ValueOf(net.ListenTCP), 54 | "ListenUDP": reflect.ValueOf(net.ListenUDP), 55 | "ListenUnix": reflect.ValueOf(net.ListenUnix), 56 | "ListenUnixgram": reflect.ValueOf(net.ListenUnixgram), 57 | "LookupAddr": reflect.ValueOf(net.LookupAddr), 58 | "LookupCNAME": reflect.ValueOf(net.LookupCNAME), 59 | "LookupHost": reflect.ValueOf(net.LookupHost), 60 | "LookupIP": reflect.ValueOf(net.LookupIP), 61 | "LookupMX": reflect.ValueOf(net.LookupMX), 62 | "LookupNS": reflect.ValueOf(net.LookupNS), 63 | "LookupPort": reflect.ValueOf(net.LookupPort), 64 | "LookupSRV": reflect.ValueOf(net.LookupSRV), 65 | "LookupTXT": reflect.ValueOf(net.LookupTXT), 66 | "ParseCIDR": reflect.ValueOf(net.ParseCIDR), 67 | "ParseIP": reflect.ValueOf(net.ParseIP), 68 | "ParseMAC": reflect.ValueOf(net.ParseMAC), 69 | "Pipe": reflect.ValueOf(net.Pipe), 70 | "ResolveIPAddr": reflect.ValueOf(net.ResolveIPAddr), 71 | "ResolveTCPAddr": reflect.ValueOf(net.ResolveTCPAddr), 72 | "ResolveUDPAddr": reflect.ValueOf(net.ResolveUDPAddr), 73 | "ResolveUnixAddr": reflect.ValueOf(net.ResolveUnixAddr), 74 | "SplitHostPort": reflect.ValueOf(net.SplitHostPort), 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /packages/net.http.cookiejar.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "net/http/cookiejar" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["net/http/cookiejar"] = map[string]reflect.Value{ 12 | "New": reflect.ValueOf(cookiejar.New), 13 | } 14 | env.PackageTypes["net/http/cookiejar"] = map[string]reflect.Type{ 15 | "Options": reflect.TypeOf(cookiejar.Options{}), 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/net.http.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package packages 4 | 5 | import ( 6 | "net/http" 7 | "reflect" 8 | 9 | "github.com/mattn/anko/env" 10 | ) 11 | 12 | func init() { 13 | env.Packages["net/http"] = map[string]reflect.Value{ 14 | "DefaultClient": reflect.ValueOf(http.DefaultClient), 15 | "DefaultServeMux": reflect.ValueOf(http.DefaultServeMux), 16 | "DefaultTransport": reflect.ValueOf(http.DefaultTransport), 17 | "Handle": reflect.ValueOf(http.Handle), 18 | "HandleFunc": reflect.ValueOf(http.HandleFunc), 19 | "ListenAndServe": reflect.ValueOf(http.ListenAndServe), 20 | "ListenAndServeTLS": reflect.ValueOf(http.ListenAndServeTLS), 21 | "NewRequest": reflect.ValueOf(http.NewRequest), 22 | "NewServeMux": reflect.ValueOf(http.NewServeMux), 23 | "Serve": reflect.ValueOf(http.Serve), 24 | "SetCookie": reflect.ValueOf(http.SetCookie), 25 | } 26 | env.PackageTypes["net/http"] = map[string]reflect.Type{ 27 | "Client": reflect.TypeOf(http.Client{}), 28 | "Cookie": reflect.TypeOf(http.Cookie{}), 29 | "Request": reflect.TypeOf(http.Request{}), 30 | "Response": reflect.TypeOf(http.Response{}), 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/net.url.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package packages 4 | 5 | import ( 6 | "net/url" 7 | "reflect" 8 | 9 | "github.com/mattn/anko/env" 10 | ) 11 | 12 | func init() { 13 | env.Packages["net/url"] = map[string]reflect.Value{ 14 | "QueryEscape": reflect.ValueOf(url.QueryEscape), 15 | "QueryUnescape": reflect.ValueOf(url.QueryUnescape), 16 | "Parse": reflect.ValueOf(url.Parse), 17 | "ParseRequestURI": reflect.ValueOf(url.ParseRequestURI), 18 | "User": reflect.ValueOf(url.User), 19 | "UserPassword": reflect.ValueOf(url.UserPassword), 20 | "ParseQuery": reflect.ValueOf(url.ParseQuery), 21 | } 22 | env.PackageTypes["net/url"] = map[string]reflect.Type{ 23 | "Error": reflect.TypeOf(url.Error{}), 24 | "URL": reflect.TypeOf(url.URL{}), 25 | "Values": reflect.TypeOf(url.Values{}), 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/os.exec.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "os/exec" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["os/exec"] = map[string]reflect.Value{ 12 | "ErrNotFound": reflect.ValueOf(exec.ErrNotFound), 13 | "LookPath": reflect.ValueOf(exec.LookPath), 14 | "Command": reflect.ValueOf(exec.Command), 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/os.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "os" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["os"] = map[string]reflect.Value{ 12 | "Args": reflect.ValueOf(os.Args), 13 | "Chdir": reflect.ValueOf(os.Chdir), 14 | "Chmod": reflect.ValueOf(os.Chmod), 15 | "Chown": reflect.ValueOf(os.Chown), 16 | "Chtimes": reflect.ValueOf(os.Chtimes), 17 | "Clearenv": reflect.ValueOf(os.Clearenv), 18 | "Create": reflect.ValueOf(os.Create), 19 | "DevNull": reflect.ValueOf(os.DevNull), 20 | "Environ": reflect.ValueOf(os.Environ), 21 | "ErrExist": reflect.ValueOf(os.ErrExist), 22 | "ErrInvalid": reflect.ValueOf(os.ErrInvalid), 23 | "ErrNotExist": reflect.ValueOf(os.ErrNotExist), 24 | "ErrPermission": reflect.ValueOf(os.ErrPermission), 25 | "Exit": reflect.ValueOf(os.Exit), 26 | "Expand": reflect.ValueOf(os.Expand), 27 | "ExpandEnv": reflect.ValueOf(os.ExpandEnv), 28 | "FindProcess": reflect.ValueOf(os.FindProcess), 29 | "Getegid": reflect.ValueOf(os.Getegid), 30 | "Getenv": reflect.ValueOf(os.Getenv), 31 | "Geteuid": reflect.ValueOf(os.Geteuid), 32 | "Getgid": reflect.ValueOf(os.Getgid), 33 | "Getgroups": reflect.ValueOf(os.Getgroups), 34 | "Getpagesize": reflect.ValueOf(os.Getpagesize), 35 | "Getpid": reflect.ValueOf(os.Getpid), 36 | "Getuid": reflect.ValueOf(os.Getuid), 37 | "Getwd": reflect.ValueOf(os.Getwd), 38 | "Hostname": reflect.ValueOf(os.Hostname), 39 | "Interrupt": reflect.ValueOf(os.Interrupt), 40 | "IsExist": reflect.ValueOf(os.IsExist), 41 | "IsNotExist": reflect.ValueOf(os.IsNotExist), 42 | "IsPathSeparator": reflect.ValueOf(os.IsPathSeparator), 43 | "IsPermission": reflect.ValueOf(os.IsPermission), 44 | "Kill": reflect.ValueOf(os.Kill), 45 | "Lchown": reflect.ValueOf(os.Lchown), 46 | "Link": reflect.ValueOf(os.Link), 47 | "Lstat": reflect.ValueOf(os.Lstat), 48 | "Mkdir": reflect.ValueOf(os.Mkdir), 49 | "MkdirAll": reflect.ValueOf(os.MkdirAll), 50 | "ModeAppend": reflect.ValueOf(os.ModeAppend), 51 | "ModeCharDevice": reflect.ValueOf(os.ModeCharDevice), 52 | "ModeDevice": reflect.ValueOf(os.ModeDevice), 53 | "ModeDir": reflect.ValueOf(os.ModeDir), 54 | "ModeExclusive": reflect.ValueOf(os.ModeExclusive), 55 | "ModeNamedPipe": reflect.ValueOf(os.ModeNamedPipe), 56 | "ModePerm": reflect.ValueOf(os.ModePerm), 57 | "ModeSetgid": reflect.ValueOf(os.ModeSetgid), 58 | "ModeSetuid": reflect.ValueOf(os.ModeSetuid), 59 | "ModeSocket": reflect.ValueOf(os.ModeSocket), 60 | "ModeSticky": reflect.ValueOf(os.ModeSticky), 61 | "ModeSymlink": reflect.ValueOf(os.ModeSymlink), 62 | "ModeTemporary": reflect.ValueOf(os.ModeTemporary), 63 | "ModeType": reflect.ValueOf(os.ModeType), 64 | "NewFile": reflect.ValueOf(os.NewFile), 65 | "NewSyscallError": reflect.ValueOf(os.NewSyscallError), 66 | "O_APPEND": reflect.ValueOf(os.O_APPEND), 67 | "O_CREATE": reflect.ValueOf(os.O_CREATE), 68 | "O_EXCL": reflect.ValueOf(os.O_EXCL), 69 | "O_RDONLY": reflect.ValueOf(os.O_RDONLY), 70 | "O_RDWR": reflect.ValueOf(os.O_RDWR), 71 | "O_SYNC": reflect.ValueOf(os.O_SYNC), 72 | "O_TRUNC": reflect.ValueOf(os.O_TRUNC), 73 | "O_WRONLY": reflect.ValueOf(os.O_WRONLY), 74 | "Open": reflect.ValueOf(os.Open), 75 | "OpenFile": reflect.ValueOf(os.OpenFile), 76 | "PathListSeparator": reflect.ValueOf(os.PathListSeparator), 77 | "PathSeparator": reflect.ValueOf(os.PathSeparator), 78 | "Pipe": reflect.ValueOf(os.Pipe), 79 | "Readlink": reflect.ValueOf(os.Readlink), 80 | "Remove": reflect.ValueOf(os.Remove), 81 | "RemoveAll": reflect.ValueOf(os.RemoveAll), 82 | "Rename": reflect.ValueOf(os.Rename), 83 | "SEEK_CUR": reflect.ValueOf(os.SEEK_CUR), 84 | "SEEK_END": reflect.ValueOf(os.SEEK_END), 85 | "SEEK_SET": reflect.ValueOf(os.SEEK_SET), 86 | "SameFile": reflect.ValueOf(os.SameFile), 87 | "Setenv": reflect.ValueOf(os.Setenv), 88 | "StartProcess": reflect.ValueOf(os.StartProcess), 89 | "Stat": reflect.ValueOf(os.Stat), 90 | "Stderr": reflect.ValueOf(os.Stderr), 91 | "Stdin": reflect.ValueOf(os.Stdin), 92 | "Stdout": reflect.ValueOf(os.Stdout), 93 | "Symlink": reflect.ValueOf(os.Symlink), 94 | "TempDir": reflect.ValueOf(os.TempDir), 95 | "Truncate": reflect.ValueOf(os.Truncate), 96 | } 97 | var signal os.Signal 98 | env.PackageTypes["os"] = map[string]reflect.Type{ 99 | "Signal": reflect.TypeOf(&signal).Elem(), 100 | } 101 | osNotAppEngine() 102 | } 103 | -------------------------------------------------------------------------------- /packages/os.signal.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "os/signal" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["os/signal"] = map[string]reflect.Value{ 12 | "Notify": reflect.ValueOf(signal.Notify), 13 | "Stop": reflect.ValueOf(signal.Stop), 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/osAppEngine.go: -------------------------------------------------------------------------------- 1 | // +build appengine 2 | 3 | package packages 4 | 5 | func osNotAppEngine() {} 6 | -------------------------------------------------------------------------------- /packages/osNotAppEngine.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package packages 4 | 5 | import ( 6 | "os" 7 | "reflect" 8 | 9 | "github.com/mattn/anko/env" 10 | ) 11 | 12 | func osNotAppEngine() { 13 | env.Packages["os"]["Getppid"] = reflect.ValueOf(os.Getppid) 14 | } 15 | -------------------------------------------------------------------------------- /packages/path.filepath.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "path/filepath" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["path/filepath"] = map[string]reflect.Value{ 12 | "Abs": reflect.ValueOf(filepath.Abs), 13 | "Base": reflect.ValueOf(filepath.Base), 14 | "Clean": reflect.ValueOf(filepath.Clean), 15 | "Dir": reflect.ValueOf(filepath.Dir), 16 | "EvalSymlinks": reflect.ValueOf(filepath.EvalSymlinks), 17 | "Ext": reflect.ValueOf(filepath.Ext), 18 | "FromSlash": reflect.ValueOf(filepath.FromSlash), 19 | "Glob": reflect.ValueOf(filepath.Glob), 20 | "HasPrefix": reflect.ValueOf(filepath.HasPrefix), 21 | "IsAbs": reflect.ValueOf(filepath.IsAbs), 22 | "Join": reflect.ValueOf(filepath.Join), 23 | "Match": reflect.ValueOf(filepath.Match), 24 | "Rel": reflect.ValueOf(filepath.Rel), 25 | "Split": reflect.ValueOf(filepath.Split), 26 | "SplitList": reflect.ValueOf(filepath.SplitList), 27 | "ToSlash": reflect.ValueOf(filepath.ToSlash), 28 | "VolumeName": reflect.ValueOf(filepath.VolumeName), 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/path.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "path" 5 | "reflect" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["path"] = map[string]reflect.Value{ 12 | "Base": reflect.ValueOf(path.Base), 13 | "Clean": reflect.ValueOf(path.Clean), 14 | "Dir": reflect.ValueOf(path.Dir), 15 | "ErrBadPattern": reflect.ValueOf(path.ErrBadPattern), 16 | "Ext": reflect.ValueOf(path.Ext), 17 | "IsAbs": reflect.ValueOf(path.IsAbs), 18 | "Join": reflect.ValueOf(path.Join), 19 | "Match": reflect.ValueOf(path.Match), 20 | "Split": reflect.ValueOf(path.Split), 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/regexp.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "reflect" 5 | "regexp" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["regexp"] = map[string]reflect.Value{ 12 | "Match": reflect.ValueOf(regexp.Match), 13 | "MatchReader": reflect.ValueOf(regexp.MatchReader), 14 | "MatchString": reflect.ValueOf(regexp.MatchString), 15 | "QuoteMeta": reflect.ValueOf(regexp.QuoteMeta), 16 | "Compile": reflect.ValueOf(regexp.Compile), 17 | "CompilePOSIX": reflect.ValueOf(regexp.CompilePOSIX), 18 | "MustCompile": reflect.ValueOf(regexp.MustCompile), 19 | "MustCompilePOSIX": reflect.ValueOf(regexp.MustCompilePOSIX), 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/runtime.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "reflect" 5 | "runtime" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["runtime"] = map[string]reflect.Value{ 12 | "GC": reflect.ValueOf(runtime.GC), 13 | "GOARCH": reflect.ValueOf(runtime.GOARCH), 14 | "GOMAXPROCS": reflect.ValueOf(runtime.GOMAXPROCS), 15 | "GOOS": reflect.ValueOf(runtime.GOOS), 16 | "GOROOT": reflect.ValueOf(runtime.GOROOT), 17 | "Version": reflect.ValueOf(runtime.Version), 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/sort.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "reflect" 5 | "sort" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | // SortFuncsStruct provides functions to be used with Sort 11 | type SortFuncsStruct struct { 12 | LenFunc func() int 13 | LessFunc func(i, j int) bool 14 | SwapFunc func(i, j int) 15 | } 16 | 17 | func (s SortFuncsStruct) Len() int { return s.LenFunc() } 18 | func (s SortFuncsStruct) Less(i, j int) bool { return s.LessFunc(i, j) } 19 | func (s SortFuncsStruct) Swap(i, j int) { s.SwapFunc(i, j) } 20 | 21 | func init() { 22 | env.Packages["sort"] = map[string]reflect.Value{ 23 | "Float64s": reflect.ValueOf(sort.Float64s), 24 | "Float64sAreSorted": reflect.ValueOf(sort.Float64sAreSorted), 25 | "Ints": reflect.ValueOf(sort.Ints), 26 | "IntsAreSorted": reflect.ValueOf(sort.IntsAreSorted), 27 | "IsSorted": reflect.ValueOf(sort.IsSorted), 28 | "Search": reflect.ValueOf(sort.Search), 29 | "SearchFloat64s": reflect.ValueOf(sort.SearchFloat64s), 30 | "SearchInts": reflect.ValueOf(sort.SearchInts), 31 | "SearchStrings": reflect.ValueOf(sort.SearchStrings), 32 | "Sort": reflect.ValueOf(sort.Sort), 33 | "Stable": reflect.ValueOf(sort.Stable), 34 | "Strings": reflect.ValueOf(sort.Strings), 35 | "StringsAreSorted": reflect.ValueOf(sort.StringsAreSorted), 36 | } 37 | env.PackageTypes["sort"] = map[string]reflect.Type{ 38 | "Float64Slice": reflect.TypeOf(sort.Float64Slice{}), 39 | "IntSlice": reflect.TypeOf(sort.IntSlice{}), 40 | "StringSlice": reflect.TypeOf(sort.StringSlice{}), 41 | "SortFuncsStruct": reflect.TypeOf(&SortFuncsStruct{}), 42 | } 43 | sortGo18() 44 | } 45 | -------------------------------------------------------------------------------- /packages/sortGo18.go: -------------------------------------------------------------------------------- 1 | // +build go1.8 2 | 3 | package packages 4 | 5 | import ( 6 | "reflect" 7 | "sort" 8 | 9 | "github.com/mattn/anko/env" 10 | ) 11 | 12 | func sortGo18() { 13 | env.Packages["sort"]["Slice"] = reflect.ValueOf(sort.Slice) 14 | env.Packages["sort"]["SliceIsSorted"] = reflect.ValueOf(sort.SliceIsSorted) 15 | env.Packages["sort"]["SliceStable"] = reflect.ValueOf(sort.SliceStable) 16 | } 17 | -------------------------------------------------------------------------------- /packages/sortNotGo18.go: -------------------------------------------------------------------------------- 1 | // +build !go1.8 2 | 3 | package packages 4 | 5 | func sortGo18() {} 6 | -------------------------------------------------------------------------------- /packages/strconv.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "reflect" 5 | "strconv" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["strconv"] = map[string]reflect.Value{ 12 | "FormatBool": reflect.ValueOf(strconv.FormatBool), 13 | "FormatFloat": reflect.ValueOf(strconv.FormatFloat), 14 | "FormatInt": reflect.ValueOf(strconv.FormatInt), 15 | "FormatUint": reflect.ValueOf(strconv.FormatUint), 16 | "ParseBool": reflect.ValueOf(strconv.ParseBool), 17 | "ParseFloat": reflect.ValueOf(strconv.ParseFloat), 18 | "ParseInt": reflect.ValueOf(strconv.ParseInt), 19 | "ParseUint": reflect.ValueOf(strconv.ParseUint), 20 | "Atoi": reflect.ValueOf(strconv.Atoi), 21 | "Itoa": reflect.ValueOf(strconv.Itoa), 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/strings.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "reflect" 5 | "strings" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["strings"] = map[string]reflect.Value{ 12 | "Contains": reflect.ValueOf(strings.Contains), 13 | "ContainsAny": reflect.ValueOf(strings.ContainsAny), 14 | "ContainsRune": reflect.ValueOf(strings.ContainsRune), 15 | "Count": reflect.ValueOf(strings.Count), 16 | "EqualFold": reflect.ValueOf(strings.EqualFold), 17 | "Fields": reflect.ValueOf(strings.Fields), 18 | "FieldsFunc": reflect.ValueOf(strings.FieldsFunc), 19 | "HasPrefix": reflect.ValueOf(strings.HasPrefix), 20 | "HasSuffix": reflect.ValueOf(strings.HasSuffix), 21 | "Index": reflect.ValueOf(strings.Index), 22 | "IndexAny": reflect.ValueOf(strings.IndexAny), 23 | "IndexByte": reflect.ValueOf(strings.IndexByte), 24 | "IndexFunc": reflect.ValueOf(strings.IndexFunc), 25 | "IndexRune": reflect.ValueOf(strings.IndexRune), 26 | "Join": reflect.ValueOf(strings.Join), 27 | "LastIndex": reflect.ValueOf(strings.LastIndex), 28 | "LastIndexAny": reflect.ValueOf(strings.LastIndexAny), 29 | "LastIndexFunc": reflect.ValueOf(strings.LastIndexFunc), 30 | "Map": reflect.ValueOf(strings.Map), 31 | "NewReader": reflect.ValueOf(strings.NewReader), 32 | "NewReplacer": reflect.ValueOf(strings.NewReplacer), 33 | "Repeat": reflect.ValueOf(strings.Repeat), 34 | "Replace": reflect.ValueOf(strings.Replace), 35 | "Split": reflect.ValueOf(strings.Split), 36 | "SplitAfter": reflect.ValueOf(strings.SplitAfter), 37 | "SplitAfterN": reflect.ValueOf(strings.SplitAfterN), 38 | "SplitN": reflect.ValueOf(strings.SplitN), 39 | "Title": reflect.ValueOf(strings.Title), 40 | "ToLower": reflect.ValueOf(strings.ToLower), 41 | "ToLowerSpecial": reflect.ValueOf(strings.ToLowerSpecial), 42 | "ToTitle": reflect.ValueOf(strings.ToTitle), 43 | "ToTitleSpecial": reflect.ValueOf(strings.ToTitleSpecial), 44 | "ToUpper": reflect.ValueOf(strings.ToUpper), 45 | "ToUpperSpecial": reflect.ValueOf(strings.ToUpperSpecial), 46 | "Trim": reflect.ValueOf(strings.Trim), 47 | "TrimFunc": reflect.ValueOf(strings.TrimFunc), 48 | "TrimLeft": reflect.ValueOf(strings.TrimLeft), 49 | "TrimLeftFunc": reflect.ValueOf(strings.TrimLeftFunc), 50 | "TrimPrefix": reflect.ValueOf(strings.TrimPrefix), 51 | "TrimRight": reflect.ValueOf(strings.TrimRight), 52 | "TrimRightFunc": reflect.ValueOf(strings.TrimRightFunc), 53 | "TrimSpace": reflect.ValueOf(strings.TrimSpace), 54 | "TrimSuffix": reflect.ValueOf(strings.TrimSuffix), 55 | } 56 | stringsGo110() 57 | } 58 | -------------------------------------------------------------------------------- /packages/stringsGo110.go: -------------------------------------------------------------------------------- 1 | // +build go1.10 2 | 3 | package packages 4 | 5 | import ( 6 | "reflect" 7 | "strings" 8 | 9 | "github.com/mattn/anko/env" 10 | ) 11 | 12 | func stringsGo110() { 13 | env.PackageTypes["strings"] = map[string]reflect.Type{ 14 | "Builder": reflect.TypeOf(strings.Builder{}), 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/stringsNotGo110.go: -------------------------------------------------------------------------------- 1 | // +build !go1.10 2 | 3 | package packages 4 | 5 | func stringsGo110() {} 6 | -------------------------------------------------------------------------------- /packages/sync.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "reflect" 5 | "sync" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["sync"] = map[string]reflect.Value{ 12 | "NewCond": reflect.ValueOf(sync.NewCond), 13 | } 14 | env.PackageTypes["sync"] = map[string]reflect.Type{ 15 | "Cond": reflect.TypeOf(sync.Cond{}), 16 | "Mutex": reflect.TypeOf(sync.Mutex{}), 17 | "Once": reflect.TypeOf(sync.Once{}), 18 | "Pool": reflect.TypeOf(sync.Pool{}), 19 | "RWMutex": reflect.TypeOf(sync.RWMutex{}), 20 | "WaitGroup": reflect.TypeOf(sync.WaitGroup{}), 21 | } 22 | syncGo19() 23 | } 24 | -------------------------------------------------------------------------------- /packages/syncGo19.go: -------------------------------------------------------------------------------- 1 | // +build go1.9 2 | 3 | package packages 4 | 5 | import ( 6 | "reflect" 7 | "sync" 8 | 9 | "github.com/mattn/anko/env" 10 | ) 11 | 12 | func syncGo19() { 13 | env.PackageTypes["sync"]["Map"] = reflect.TypeOf(sync.Map{}) 14 | } 15 | -------------------------------------------------------------------------------- /packages/syncNotGo19.go: -------------------------------------------------------------------------------- 1 | // +build !go1.9 2 | 3 | package packages 4 | 5 | func syncGo19() {} 6 | -------------------------------------------------------------------------------- /packages/time.go: -------------------------------------------------------------------------------- 1 | package packages 2 | 3 | import ( 4 | "reflect" 5 | "time" 6 | 7 | "github.com/mattn/anko/env" 8 | ) 9 | 10 | func init() { 11 | env.Packages["time"] = map[string]reflect.Value{ 12 | "ANSIC": reflect.ValueOf(time.ANSIC), 13 | "After": reflect.ValueOf(time.After), 14 | "AfterFunc": reflect.ValueOf(time.AfterFunc), 15 | "April": reflect.ValueOf(time.April), 16 | "August": reflect.ValueOf(time.August), 17 | "Date": reflect.ValueOf(time.Date), 18 | "December": reflect.ValueOf(time.December), 19 | "February": reflect.ValueOf(time.February), 20 | "FixedZone": reflect.ValueOf(time.FixedZone), 21 | "Friday": reflect.ValueOf(time.Friday), 22 | "Hour": reflect.ValueOf(time.Hour), 23 | "January": reflect.ValueOf(time.January), 24 | "July": reflect.ValueOf(time.July), 25 | "June": reflect.ValueOf(time.June), 26 | "Kitchen": reflect.ValueOf(time.Kitchen), 27 | "LoadLocation": reflect.ValueOf(time.LoadLocation), 28 | "March": reflect.ValueOf(time.March), 29 | "May": reflect.ValueOf(time.May), 30 | "Microsecond": reflect.ValueOf(time.Microsecond), 31 | "Millisecond": reflect.ValueOf(time.Millisecond), 32 | "Minute": reflect.ValueOf(time.Minute), 33 | "Monday": reflect.ValueOf(time.Monday), 34 | "Nanosecond": reflect.ValueOf(time.Nanosecond), 35 | "NewTicker": reflect.ValueOf(time.NewTicker), 36 | "NewTimer": reflect.ValueOf(time.NewTimer), 37 | "November": reflect.ValueOf(time.November), 38 | "Now": reflect.ValueOf(time.Now), 39 | "October": reflect.ValueOf(time.October), 40 | "Parse": reflect.ValueOf(time.Parse), 41 | "ParseDuration": reflect.ValueOf(time.ParseDuration), 42 | "ParseInLocation": reflect.ValueOf(time.ParseInLocation), 43 | "RFC1123": reflect.ValueOf(time.RFC1123), 44 | "RFC1123Z": reflect.ValueOf(time.RFC1123Z), 45 | "RFC3339": reflect.ValueOf(time.RFC3339), 46 | "RFC3339Nano": reflect.ValueOf(time.RFC3339Nano), 47 | "RFC822": reflect.ValueOf(time.RFC822), 48 | "RFC822Z": reflect.ValueOf(time.RFC822Z), 49 | "RFC850": reflect.ValueOf(time.RFC850), 50 | "RubyDate": reflect.ValueOf(time.RubyDate), 51 | "Saturday": reflect.ValueOf(time.Saturday), 52 | "Second": reflect.ValueOf(time.Second), 53 | "September": reflect.ValueOf(time.September), 54 | "Since": reflect.ValueOf(time.Since), 55 | "Sleep": reflect.ValueOf(time.Sleep), 56 | "Stamp": reflect.ValueOf(time.Stamp), 57 | "StampMicro": reflect.ValueOf(time.StampMicro), 58 | "StampMilli": reflect.ValueOf(time.StampMilli), 59 | "StampNano": reflect.ValueOf(time.StampNano), 60 | "Sunday": reflect.ValueOf(time.Sunday), 61 | "Thursday": reflect.ValueOf(time.Thursday), 62 | "Tick": reflect.ValueOf(time.Tick), 63 | "Tuesday": reflect.ValueOf(time.Tuesday), 64 | "Unix": reflect.ValueOf(time.Unix), 65 | "UnixDate": reflect.ValueOf(time.UnixDate), 66 | "Wednesday": reflect.ValueOf(time.Wednesday), 67 | } 68 | env.PackageTypes["time"] = map[string]reflect.Type{ 69 | "Duration": reflect.TypeOf(time.Duration(0)), 70 | "Ticker": reflect.TypeOf(time.Ticker{}), 71 | "Time": reflect.TypeOf(time.Time{}), 72 | } 73 | timeGo18() 74 | timeGo110() 75 | } 76 | -------------------------------------------------------------------------------- /packages/timeGo110.go: -------------------------------------------------------------------------------- 1 | // +build go1.10 2 | 3 | package packages 4 | 5 | import ( 6 | "reflect" 7 | "time" 8 | 9 | "github.com/mattn/anko/env" 10 | ) 11 | 12 | func timeGo110() { 13 | env.Packages["time"]["LoadLocationFromTZData"] = reflect.ValueOf(time.LoadLocationFromTZData) 14 | } 15 | -------------------------------------------------------------------------------- /packages/timeGo18.go: -------------------------------------------------------------------------------- 1 | // +build go1.8 2 | 3 | package packages 4 | 5 | import ( 6 | "reflect" 7 | "time" 8 | 9 | "github.com/mattn/anko/env" 10 | ) 11 | 12 | func timeGo18() { 13 | env.Packages["time"]["Until"] = reflect.ValueOf(time.Until) 14 | } 15 | -------------------------------------------------------------------------------- /packages/timeNotGo110.go: -------------------------------------------------------------------------------- 1 | // +build !go1.10 2 | 3 | package packages 4 | 5 | func timeGo110() {} 6 | -------------------------------------------------------------------------------- /packages/timeNotGo18.go: -------------------------------------------------------------------------------- 1 | // +build !go1.8 2 | 3 | package packages 4 | 5 | func timeGo18() {} 6 | -------------------------------------------------------------------------------- /parser/Makefile: -------------------------------------------------------------------------------- 1 | all : parser.go 2 | 3 | parser.go : parser.go.y 4 | goyacc -o $@ parser.go.y 5 | gofmt -s -w . 6 | -------------------------------------------------------------------------------- /vm/doc.go: -------------------------------------------------------------------------------- 1 | // Package vm implements virtual-machine for anko. 2 | package vm 3 | -------------------------------------------------------------------------------- /vm/example_containers_test.go: -------------------------------------------------------------------------------- 1 | package vm_test 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/mattn/anko/env" 8 | "github.com/mattn/anko/vm" 9 | ) 10 | 11 | func Example_vmArrays() { 12 | e := env.NewEnv() 13 | 14 | err := e.Define("println", fmt.Println) 15 | if err != nil { 16 | log.Fatalf("define error: %v\n", err) 17 | } 18 | 19 | script := ` 20 | a = []interface{1, 2} 21 | println(a) 22 | 23 | a += 3 24 | println(a) 25 | 26 | a = []interface{} 27 | // this automatically appends to array 28 | a[0] = 1 29 | println(a) 30 | 31 | println("") 32 | 33 | a = []interface{} 34 | // this would give an index out of range error 35 | // a[1] = 1 36 | 37 | a = []interface{1, 2} 38 | b = []interface{3, 4} 39 | c = a + b 40 | println(c) 41 | 42 | c = []interface{1, 2} + []interface{3, 4} 43 | println(c) 44 | 45 | println("") 46 | 47 | c = []interface{a} + b 48 | println(c) 49 | 50 | c = []interface{a} + []interface{b} 51 | println(c) 52 | 53 | c = []interface{[]interface{1, 2}} + []interface{[]interface{3, 4}} 54 | println(c) 55 | 56 | println("") 57 | 58 | a = []interface{1, 2} 59 | 60 | println(len(a)) 61 | 62 | println(a[1]) 63 | 64 | a = [1, 2] 65 | println(a) 66 | ` 67 | 68 | _, err = vm.Execute(e, nil, script) 69 | if err != nil { 70 | log.Fatalf("execute error: %v\n", err) 71 | } 72 | 73 | // output: 74 | // [1 2] 75 | // [1 2 3] 76 | // [1] 77 | // 78 | // [1 2 3 4] 79 | // [1 2 3 4] 80 | // 81 | // [[1 2] 3 4] 82 | // [[1 2] [3 4]] 83 | // [[1 2] [3 4]] 84 | // 85 | // 2 86 | // 2 87 | // [1 2] 88 | } 89 | 90 | func Example_vmMaps() { 91 | e := env.NewEnv() 92 | 93 | err := e.Define("println", fmt.Println) 94 | if err != nil { 95 | log.Fatalf("define error: %v\n", err) 96 | } 97 | 98 | script := ` 99 | a = map[interface]interface{} 100 | println(a) 101 | 102 | a.b = 1 103 | println(a) 104 | println(a.b) 105 | 106 | a["b"] = 2 107 | println(a["b"]) 108 | 109 | println(len(a)) 110 | 111 | println("") 112 | 113 | b, ok = a["b"] 114 | println(b) 115 | println(ok) 116 | 117 | delete(a, "b") 118 | 119 | _, ok = a["b"] 120 | println(ok) 121 | 122 | println("") 123 | 124 | a = {} 125 | println(a) 126 | 127 | a.b = 1 128 | println(a) 129 | println(a.b) 130 | 131 | a["b"] = 2 132 | println(a["b"]) 133 | 134 | ` 135 | 136 | _, err = vm.Execute(e, nil, script) 137 | if err != nil { 138 | log.Fatalf("execute error: %v\n", err) 139 | } 140 | 141 | // output: 142 | // map[] 143 | // map[b:1] 144 | // 1 145 | // 2 146 | // 1 147 | // 148 | // 2 149 | // true 150 | // false 151 | // 152 | // map[] 153 | // map[b:1] 154 | // 1 155 | // 2 156 | } 157 | 158 | func Example_vmStructs() { 159 | e := env.NewEnv() 160 | 161 | err := e.Define("println", fmt.Println) 162 | if err != nil { 163 | log.Fatalf("define error: %v\n", err) 164 | } 165 | 166 | script := ` 167 | a = make(struct { 168 | A int64, 169 | B float64 170 | }) 171 | println(a) 172 | 173 | a.A = 1 174 | println(a) 175 | println(a.A) 176 | 177 | a.B = 2.5 178 | println(a) 179 | println(a.B) 180 | ` 181 | 182 | _, err = vm.Execute(e, nil, script) 183 | if err != nil { 184 | log.Fatalf("execute error: %v\n", err) 185 | } 186 | 187 | // output: 188 | // {0 0} 189 | // {1 0} 190 | // 1 191 | // {1 2.5} 192 | // 2.5 193 | } 194 | 195 | func Example_vmModules() { 196 | 197 | e := env.NewEnv() 198 | 199 | err := e.Define("println", fmt.Println) 200 | if err != nil { 201 | log.Fatalf("define error: %v\n", err) 202 | } 203 | 204 | script := ` 205 | module rectangle { 206 | _length = 1 207 | _width = 1 208 | 209 | func setLength (length) { 210 | if length <= 0 { 211 | return 212 | } 213 | _length = length 214 | } 215 | 216 | func setWidth (width) { 217 | if width <= 0 { 218 | return 219 | } 220 | _width = width 221 | } 222 | 223 | func area () { 224 | return _length * _width 225 | } 226 | 227 | func perimeter () { 228 | return 2 * (_length + _width) 229 | } 230 | } 231 | 232 | rectangle1 = rectangle 233 | 234 | rectangle1.setLength(4) 235 | rectangle1.setWidth(5) 236 | 237 | println(rectangle1.area()) 238 | println(rectangle1.perimeter()) 239 | 240 | rectangle2 = rectangle 241 | 242 | rectangle2.setLength(2) 243 | rectangle2.setWidth(4) 244 | 245 | println(rectangle2.area()) 246 | println(rectangle2.perimeter()) 247 | ` 248 | 249 | _, err = vm.Execute(e, nil, script) 250 | if err != nil { 251 | log.Fatalf("execute error: %v\n", err) 252 | } 253 | 254 | // output: 255 | // 20 256 | // 18 257 | // 8 258 | // 12 259 | } 260 | -------------------------------------------------------------------------------- /vm/example_functions_test.go: -------------------------------------------------------------------------------- 1 | package vm_test 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/mattn/anko/env" 8 | "github.com/mattn/anko/vm" 9 | ) 10 | 11 | func Example_vmFunctions() { 12 | e := env.NewEnv() 13 | 14 | err := e.Define("println", fmt.Println) 15 | if err != nil { 16 | log.Fatalf("define error: %v\n", err) 17 | } 18 | 19 | script := ` 20 | func a(b) { 21 | println(b) 22 | } 23 | a("b") 24 | 25 | a = func(b) { 26 | println(b) 27 | } 28 | a("b") 29 | 30 | func(b) { 31 | println(b) 32 | }("b") 33 | 34 | func a() { 35 | return "a" 36 | } 37 | println(a()) 38 | 39 | println("") 40 | 41 | 42 | func fib(n) { 43 | if (n <= 1) { 44 | return n 45 | } 46 | return fib(n - 1) + fib(n - 2) 47 | } 48 | 49 | println(fib(8)) 50 | 51 | func sum(n...) { 52 | t = 0 53 | for a in n { 54 | t += a 55 | } 56 | return t 57 | } 58 | println(sum(1, 2, 3, 4)) 59 | 60 | func add(a, b) { 61 | return a + b 62 | } 63 | println(add([1, 2]...)) 64 | ` 65 | 66 | _, err = vm.Execute(e, nil, script) 67 | if err != nil { 68 | log.Fatalf("execute error: %v\n", err) 69 | } 70 | 71 | // output: 72 | // b 73 | // b 74 | // b 75 | // a 76 | // 77 | // 21 78 | // 10 79 | // 3 80 | 81 | } 82 | 83 | func Example_vmFunctionsScope() { 84 | e := env.NewEnv() 85 | 86 | err := e.Define("println", fmt.Println) 87 | if err != nil { 88 | log.Fatalf("define error: %v\n", err) 89 | } 90 | 91 | script := ` 92 | a = 1 93 | func () { 94 | a = 2 95 | }() 96 | println(a) 97 | 98 | var a = 1 99 | func () { 100 | a = 2 101 | }() 102 | println(a) 103 | 104 | a = 1 105 | func () { 106 | var a = 2 107 | }() 108 | println(a) 109 | 110 | var a = 1 111 | func () { 112 | var a = 2 113 | }() 114 | println(a) 115 | ` 116 | 117 | _, err = vm.Execute(e, nil, script) 118 | if err != nil { 119 | log.Fatalf("execute error: %v\n", err) 120 | } 121 | 122 | // output: 123 | // 2 124 | // 2 125 | // 1 126 | // 1 127 | 128 | } 129 | 130 | func testFunc1(a interface{}) int { 131 | b, ok := a.([]interface{}) 132 | if ok { 133 | return len(b) 134 | } 135 | return 0 136 | } 137 | 138 | func Example_vmFunctionsOutside() { 139 | 140 | /* 141 | // the following function would be uncommented 142 | func testFunc1(a interface{}) int { 143 | b, ok := a.([]interface{}) 144 | if ok { 145 | return len(b) 146 | } 147 | return 0 148 | } 149 | */ 150 | 151 | e := env.NewEnv() 152 | 153 | err := e.Define("println", fmt.Println) 154 | if err != nil { 155 | log.Fatalf("define error: %v\n", err) 156 | } 157 | err = e.Define("addString", func(a string, b string) string { return a + b }) 158 | if err != nil { 159 | log.Fatalf("define error: %v\n", err) 160 | } 161 | // uses the function that would be declared above 162 | err = e.Define("aFunc", testFunc1) 163 | if err != nil { 164 | log.Fatalf("define error: %v\n", err) 165 | } 166 | 167 | script := ` 168 | a = addString("a", "b") 169 | println(a) 170 | 171 | a = aFunc([1, 2, 3]) 172 | println(a) 173 | ` 174 | 175 | _, err = vm.Execute(e, nil, script) 176 | if err != nil { 177 | log.Fatalf("execute error: %v\n", err) 178 | } 179 | 180 | // output: 181 | // ab 182 | // 3 183 | 184 | } 185 | -------------------------------------------------------------------------------- /vm/example_operators_test.go: -------------------------------------------------------------------------------- 1 | package vm_test 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/mattn/anko/env" 8 | "github.com/mattn/anko/vm" 9 | ) 10 | 11 | func Example_vmBasicOperators() { 12 | e := env.NewEnv() 13 | 14 | err := e.Define("println", fmt.Println) 15 | if err != nil { 16 | log.Fatalf("define error: %v\n", err) 17 | } 18 | 19 | script := ` 20 | a = nil 21 | println(a) 22 | a = true 23 | println(a) 24 | 25 | println("") 26 | 27 | a = 2 + 1 28 | println(a) 29 | a = 2 - 1 30 | println(a) 31 | a = 2 * 1 32 | println(a) 33 | a = 4 / 2 34 | println(a) 35 | 36 | println("") 37 | 38 | a = 1 39 | a++ 40 | println(a) 41 | a-- 42 | println(a) 43 | 44 | println("") 45 | 46 | a = 1 47 | a += 1 48 | println(a) 49 | a -= 1 50 | println(a) 51 | a *= 4 52 | println(a) 53 | a /= 2 54 | println(a) 55 | 56 | println("") 57 | 58 | a = 1 & 3 59 | println(a) 60 | a = 1 | 2 61 | println(a) 62 | 63 | println("") 64 | 65 | a = 2 << 3 66 | println(a) 67 | a = 8 >> 2 68 | println(a) 69 | a = 7 % 3 70 | println(a) 71 | 72 | println("") 73 | 74 | a = 2 - (-2) 75 | println(a) 76 | a = ^2 77 | println(a) 78 | a = "a" * 4 79 | println(a) 80 | a = !true 81 | println(a) 82 | 83 | ` 84 | 85 | _, err = vm.Execute(e, nil, script) 86 | if err != nil { 87 | log.Fatalf("execute error: %v\n", err) 88 | } 89 | 90 | // output: 91 | // 92 | // true 93 | // 94 | // 3 95 | // 1 96 | // 2 97 | // 2 98 | // 99 | // 2 100 | // 1 101 | // 102 | // 2 103 | // 1 104 | // 4 105 | // 2 106 | // 107 | // 1 108 | // 3 109 | // 110 | // 16 111 | // 2 112 | // 1 113 | // 114 | // 4 115 | // -3 116 | // aaaa 117 | // false 118 | 119 | } 120 | 121 | func Example_vmComparisonOperators() { 122 | e := env.NewEnv() 123 | 124 | err := e.Define("println", fmt.Println) 125 | if err != nil { 126 | log.Fatalf("define error: %v\n", err) 127 | } 128 | 129 | script := ` 130 | a = nil == nil 131 | println(a) 132 | a = "a" != "a" 133 | println(a) 134 | a = 1 == 1.0 135 | println(a) 136 | a = !true 137 | println(a) 138 | 139 | println("") 140 | 141 | a = 1 < 2 142 | println(a) 143 | a = 1 > 3 144 | println(a) 145 | a = 2 <= 2 146 | println(a) 147 | a = 2 >= 3 148 | println(a) 149 | 150 | println("") 151 | a = 1 == 2 && 1 == 1 152 | println(a) 153 | a = 1 == 2 || 1 == 1 154 | println(a) 155 | ` 156 | 157 | _, err = vm.Execute(e, nil, script) 158 | if err != nil { 159 | log.Fatalf("execute error: %v\n", err) 160 | } 161 | 162 | // output: 163 | // true 164 | // false 165 | // true 166 | // false 167 | // 168 | // true 169 | // false 170 | // true 171 | // false 172 | // 173 | // false 174 | // true 175 | 176 | } 177 | 178 | func Example_vmIfOperators() { 179 | e := env.NewEnv() 180 | 181 | err := e.Define("println", fmt.Println) 182 | if err != nil { 183 | log.Fatalf("define error: %v\n", err) 184 | } 185 | 186 | script := ` 187 | a = 1 188 | b = 2 189 | 190 | if a == 1 { 191 | println(a) 192 | } 193 | 194 | if b == 1 { 195 | println(a) 196 | } else { 197 | println(b) 198 | } 199 | 200 | if a == 3 { 201 | println(a) 202 | } else if b == 3 { 203 | println(b) 204 | } else { 205 | println(a + b) 206 | } 207 | 208 | println("") 209 | 210 | if a == 2 || b == 2 { 211 | println(4) 212 | } 213 | 214 | if a == 1 && b == 2 { 215 | println(5) 216 | } 217 | ` 218 | 219 | _, err = vm.Execute(e, nil, script) 220 | if err != nil { 221 | log.Fatalf("execute error: %v\n", err) 222 | } 223 | 224 | // output: 225 | // 1 226 | // 2 227 | // 3 228 | // 229 | // 4 230 | // 5 231 | 232 | } 233 | 234 | func Example_vmForLoops() { 235 | e := env.NewEnv() 236 | 237 | err := e.Define("println", fmt.Println) 238 | if err != nil { 239 | log.Fatalf("define error: %v\n", err) 240 | } 241 | 242 | script := ` 243 | i = 0 244 | for { 245 | println(i) 246 | i++ 247 | if i > 1 { 248 | break 249 | } 250 | } 251 | 252 | println("") 253 | 254 | for i in [0, 1] { 255 | println(i) 256 | } 257 | 258 | println("") 259 | 260 | for key, value in {"a": "b"} { 261 | println(key, value) 262 | } 263 | 264 | println("") 265 | 266 | i = 0 267 | for i < 2 { 268 | println(i) 269 | i++ 270 | } 271 | 272 | println("") 273 | 274 | for i = 0; i < 2; i++ { 275 | println(i) 276 | } 277 | 278 | println("") 279 | 280 | 281 | for i = 0; i < 10; i++ { 282 | println(i) 283 | if i < 1 { 284 | continue 285 | } 286 | break 287 | } 288 | 289 | ` 290 | 291 | _, err = vm.Execute(e, nil, script) 292 | if err != nil { 293 | log.Fatalf("execute error: %v\n", err) 294 | } 295 | 296 | // output: 297 | // 0 298 | // 1 299 | // 300 | // 0 301 | // 1 302 | // 303 | // a b 304 | // 305 | // 0 306 | // 1 307 | // 308 | // 0 309 | // 1 310 | // 311 | // 0 312 | // 1 313 | 314 | } 315 | 316 | func Example_vmSlices() { 317 | e := env.NewEnv() 318 | 319 | err := e.Define("println", fmt.Println) 320 | if err != nil { 321 | log.Fatalf("define error: %v\n", err) 322 | } 323 | 324 | script := ` 325 | a = "abc" 326 | println(a[1:]) 327 | println(a[:2]) 328 | println(a[1:2]) 329 | 330 | println("") 331 | 332 | a = [1, 2, 3] 333 | println(a[1:]) 334 | println(a[:2]) 335 | println(a[1:2]) 336 | ` 337 | 338 | _, err = vm.Execute(e, nil, script) 339 | if err != nil { 340 | log.Fatalf("execute error: %v\n", err) 341 | } 342 | 343 | // output: 344 | // bc 345 | // ab 346 | // b 347 | // 348 | // [2 3] 349 | // [1 2] 350 | // [2] 351 | 352 | } 353 | 354 | func Example_vmChannels() { 355 | e := env.NewEnv() 356 | 357 | err := e.Define("println", fmt.Println) 358 | if err != nil { 359 | log.Fatalf("define error: %v\n", err) 360 | } 361 | 362 | script := ` 363 | a = make(chan string, 1) 364 | a <- "a" 365 | println(<- a) 366 | 367 | a = make(chan string) 368 | go func() { 369 | a <- "a" 370 | }() 371 | println(<- a) 372 | 373 | 374 | ` 375 | 376 | _, err = vm.Execute(e, nil, script) 377 | if err != nil { 378 | log.Fatalf("execute error: %v\n", err) 379 | } 380 | 381 | // output: 382 | // a 383 | // a 384 | 385 | } 386 | -------------------------------------------------------------------------------- /vm/example_packages_test.go: -------------------------------------------------------------------------------- 1 | package vm_test 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/mattn/anko/env" 7 | _ "github.com/mattn/anko/packages" 8 | "github.com/mattn/anko/vm" 9 | ) 10 | 11 | func Example_vmSort() { 12 | // _ "github.com/mattn/anko/packages" 13 | 14 | e := env.NewEnv() 15 | 16 | script := ` 17 | fmt = import("fmt") 18 | sort = import("sort") 19 | a = [5, 1.1, 3, "f", "2", "4.4"] 20 | sortFuncs = make(sort.SortFuncsStruct) 21 | sortFuncs.LenFunc = func() { return len(a) } 22 | sortFuncs.LessFunc = func(i, j) { return a[i] < a[j] } 23 | sortFuncs.SwapFunc = func(i, j) { temp = a[i]; a[i] = a[j]; a[j] = temp } 24 | sort.Sort(sortFuncs) 25 | fmt.Println(a) 26 | ` 27 | 28 | _, err := vm.Execute(e, nil, script) 29 | if err != nil { 30 | log.Fatalf("execute error: %v\n", err) 31 | } 32 | 33 | // output: 34 | // [f 1.1 2 3 4.4 5] 35 | } 36 | 37 | func Example_vmRegexp() { 38 | // _ "github.com/mattn/anko/packages" 39 | 40 | e := env.NewEnv() 41 | 42 | script := ` 43 | fmt = import("fmt") 44 | regexp = import("regexp") 45 | 46 | re = regexp.MustCompile("^simple$") 47 | result = re.MatchString("simple") 48 | fmt.Println(result) 49 | fmt.Println("") 50 | 51 | re = regexp.MustCompile("simple") 52 | result = re.FindString("This is a simple sentence") 53 | fmt.Println(result) 54 | fmt.Println("") 55 | 56 | re = regexp.MustCompile(",") 57 | result = re.Split("a,b,c", -1) 58 | fmt.Println(result) 59 | fmt.Println("") 60 | 61 | re = regexp.MustCompile("foo") 62 | result = re.ReplaceAllString("foo", "bar") 63 | fmt.Println(result) 64 | ` 65 | 66 | _, err := vm.Execute(e, nil, script) 67 | if err != nil { 68 | log.Fatalf("execute error: %v\n", err) 69 | } 70 | 71 | // output: 72 | // true 73 | // 74 | // simple 75 | // 76 | // [a b c] 77 | // 78 | // bar 79 | } 80 | 81 | func Example_vmHttp() { 82 | // _ "github.com/mattn/anko/packages" 83 | 84 | e := env.NewEnv() 85 | 86 | script := ` 87 | fmt = import("fmt") 88 | io = import("io") 89 | ioutil = import("io/ioutil") 90 | net = import("net") 91 | http = import("net/http") 92 | time = import("time") 93 | 94 | func handlerRoot(responseWriter, request) { 95 | io.WriteString(responseWriter, "Hello World :)") 96 | } 97 | 98 | serveMux = http.NewServeMux() 99 | serveMux.HandleFunc("/", handlerRoot) 100 | listener, err = net.Listen("tcp", ":8080") 101 | if err != nil { 102 | fmt.Println(err) 103 | return 104 | } 105 | go http.Serve(listener, serveMux) 106 | 107 | client = http.DefaultClient 108 | 109 | response, err = client.Get("http://localhost:8080/") 110 | if err != nil { 111 | fmt.Println(err) 112 | return 113 | } 114 | 115 | body, err = ioutil.ReadAll(response.Body) 116 | if err != nil { 117 | fmt.Println(err) 118 | } 119 | response.Body.Close() 120 | 121 | fmt.Printf("%s\n", body) 122 | ` 123 | 124 | _, err := vm.Execute(e, nil, script) 125 | if err != nil { 126 | log.Fatalf("execute error: %v\n", err) 127 | } 128 | 129 | // output: 130 | // Hello World :) 131 | } 132 | -------------------------------------------------------------------------------- /vm/example_test.go: -------------------------------------------------------------------------------- 1 | package vm_test 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "sync" 8 | "time" 9 | 10 | "github.com/mattn/anko/env" 11 | "github.com/mattn/anko/vm" 12 | ) 13 | 14 | func Example_vmExecuteContext() { 15 | var waitGroup sync.WaitGroup 16 | waitGroup.Add(1) 17 | waitChan := make(chan struct{}, 1) 18 | 19 | e := env.NewEnv() 20 | sleepMillisecond := func() { time.Sleep(time.Millisecond) } 21 | 22 | err := e.Define("println", fmt.Println) 23 | if err != nil { 24 | log.Fatalf("define error: %v\n", err) 25 | } 26 | err = e.Define("sleep", sleepMillisecond) 27 | if err != nil { 28 | log.Fatalf("define error: %v\n", err) 29 | } 30 | 31 | script := ` 32 | # sleep for 10 seconds 33 | for i = 0; i < 10000; i++ { 34 | sleep() 35 | } 36 | # the context should cancel before printing the next line 37 | println("this line should not be printed") 38 | ` 39 | 40 | ctx, cancel := context.WithCancel(context.Background()) 41 | go func() { 42 | close(waitChan) 43 | v, err := vm.ExecuteContext(ctx, e, nil, script) 44 | fmt.Println(v, err) 45 | waitGroup.Done() 46 | }() 47 | 48 | <-waitChan 49 | cancel() 50 | 51 | waitGroup.Wait() 52 | 53 | // output: execution interrupted 54 | } 55 | 56 | func Example_vmEnvDefine() { 57 | // "github.com/mattn/anko/env" 58 | 59 | e := env.NewEnv() 60 | 61 | err := e.Define("println", fmt.Println) 62 | if err != nil { 63 | log.Fatalf("define error: %v\n", err) 64 | } 65 | 66 | err = e.Define("a", true) 67 | if err != nil { 68 | log.Fatalf("define error: %v\n", err) 69 | } 70 | err = e.Define("b", int64(1)) 71 | if err != nil { 72 | log.Fatalf("define error: %v\n", err) 73 | } 74 | err = e.Define("c", float64(1.1)) 75 | if err != nil { 76 | log.Fatalf("define error: %v\n", err) 77 | } 78 | err = e.Define("d", "d") 79 | if err != nil { 80 | log.Fatalf("define error: %v\n", err) 81 | } 82 | err = e.Define("e", []interface{}{true, int64(1), float64(1.1), "d"}) 83 | if err != nil { 84 | log.Fatalf("define error: %v\n", err) 85 | } 86 | err = e.Define("f", map[string]interface{}{"a": true}) 87 | if err != nil { 88 | log.Fatalf("define error: %v\n", err) 89 | } 90 | 91 | script := ` 92 | println(a) 93 | println(b) 94 | println(c) 95 | println(d) 96 | println(e) 97 | println(f) 98 | ` 99 | 100 | _, err = vm.Execute(e, nil, script) 101 | if err != nil { 102 | log.Fatalf("execute error: %v\n", err) 103 | } 104 | 105 | // output: 106 | // true 107 | // 1 108 | // 1.1 109 | // d 110 | // [true 1 1.1 d] 111 | // map[a:true] 112 | } 113 | 114 | func Example_vmEnv() { 115 | // "github.com/mattn/anko/env" 116 | 117 | e := env.NewEnv() 118 | 119 | err := e.Define("a", "a") 120 | if err != nil { 121 | log.Fatalf("define error: %v\n", err) 122 | } 123 | 124 | _, err = e.Get("a") 125 | if err != nil { 126 | log.Fatalf("get error: %v\n", err) 127 | } 128 | 129 | fmt.Println(e) 130 | 131 | // output: 132 | // No parent 133 | // a = "a" 134 | } 135 | 136 | func Example_vmHelloWorld() { 137 | // "github.com/mattn/anko/env" 138 | 139 | e := env.NewEnv() 140 | 141 | err := e.Define("println", fmt.Println) 142 | if err != nil { 143 | log.Fatalf("define error: %v\n", err) 144 | } 145 | 146 | script := ` 147 | println("Hello World :)") 148 | ` 149 | 150 | _, err = vm.Execute(e, nil, script) 151 | if err != nil { 152 | log.Fatalf("execute error: %v\n", err) 153 | } 154 | 155 | // output: Hello World :) 156 | } 157 | 158 | func Example_vmQuickStart() { 159 | // "github.com/mattn/anko/env" 160 | 161 | e := env.NewEnv() 162 | 163 | err := e.Define("println", fmt.Println) 164 | if err != nil { 165 | log.Fatalf("define error: %v\n", err) 166 | } 167 | 168 | script := ` 169 | // declare variables 170 | x = 1 171 | y = x + 1 172 | 173 | // print using outside the script defined println function 174 | println(x + y) // 3 175 | 176 | // if else statement 177 | if x < 1 || y < 1 { 178 | println(x) 179 | } else if x < 1 && y < 1 { 180 | println(y) 181 | } else { 182 | println(x + y) 183 | } 184 | 185 | // slice 186 | a = []interface{1, 2, 3} 187 | println(a) // [1 2 3] 188 | println(a[0]) // 1 189 | 190 | // map 191 | a = map[interface]interface{"x": 1} 192 | println(a) // map[x:1] 193 | a.b = 2 194 | a["c"] = 3 195 | println(a["b"]) // 2 196 | println(a.c) // 3 197 | 198 | // struct 199 | a = make(struct { 200 | A int64, 201 | B float64 202 | }) 203 | a.A = 4 204 | a.B = 5.5 205 | println(a.A) // 4 206 | println(a.B) // 5.5 207 | 208 | // function 209 | func a (x) { 210 | println(x + 1) 211 | } 212 | a(5) // 6 213 | ` 214 | 215 | _, err = vm.Execute(e, nil, script) 216 | if err != nil { 217 | log.Fatalf("execute error: %v\n", err) 218 | } 219 | 220 | // output: 221 | // 3 222 | // 3 223 | // [1 2 3] 224 | // 1 225 | // map[x:1] 226 | // 2 227 | // 3 228 | // 4 229 | // 5.5 230 | // 6 231 | } 232 | -------------------------------------------------------------------------------- /vm/main_test.go: -------------------------------------------------------------------------------- 1 | package vm 2 | 3 | import ( 4 | "context" 5 | "reflect" 6 | "testing" 7 | "time" 8 | 9 | "github.com/mattn/anko/env" 10 | "github.com/mattn/anko/parser" 11 | ) 12 | 13 | type ( 14 | testStruct1 struct { 15 | aInterface interface{} 16 | aBool bool 17 | aInt32 int32 18 | aInt64 int64 19 | aFloat32 float32 20 | aFloat64 float32 21 | aString string 22 | aFunc func() 23 | 24 | aPtrInterface *interface{} 25 | aPtrBool *bool 26 | aPtrInt32 *int32 27 | aPtrInt64 *int64 28 | aPtrFloat32 *float32 29 | aPtrFloat64 *float32 30 | aPtrString *string 31 | aPtrSliceInterface *[]interface{} 32 | aPtrSliceBool *[]bool 33 | aPtrSliceInt32 *[]int32 34 | aPtrSliceInt64 *[]int64 35 | aPtrSliceFloat32 *[]float32 36 | aPtrSliceFloat64 *[]float32 37 | aPtrSliceString *[]string 38 | 39 | aSliceInterface []interface{} 40 | aSliceBool []bool 41 | aSliceInt32 []int32 42 | aSliceInt64 []int64 43 | aSliceFloat32 []float32 44 | aSliceFloat64 []float32 45 | aSliceString []string 46 | aSlicePtrInterface []*interface{} 47 | aSlicePtrBool []*bool 48 | aSlicePtrInt32 []*int32 49 | aSlicePtrInt64 []*int64 50 | aSlicePtrFloat32 []*float32 51 | aSlicePtrFloat64 []*float32 52 | aSlicePtrString []*string 53 | 54 | aMapInterface map[string]interface{} 55 | aMapBool map[string]bool 56 | aMapInt32 map[string]int32 57 | aMapInt64 map[string]int64 58 | aMapFloat32 map[string]float32 59 | aMapFloat64 map[string]float32 60 | aMapString map[string]string 61 | aMapPtrInterface map[string]*interface{} 62 | aMapPtrBool map[string]*bool 63 | aMapPtrInt32 map[string]*int32 64 | aMapPtrInt64 map[string]*int64 65 | aMapPtrFloat32 map[string]*float32 66 | aMapPtrFloat64 map[string]*float32 67 | aMapPtrString map[string]*string 68 | 69 | aChanInterface chan interface{} 70 | aChanBool chan bool 71 | aChanInt32 chan int32 72 | aChanInt64 chan int64 73 | aChanFloat32 chan float32 74 | aChanFloat64 chan float32 75 | aChanString chan string 76 | aChanPtrInterface chan *interface{} 77 | aChanPtrBool chan *bool 78 | aChanPtrInt32 chan *int32 79 | aChanPtrInt64 chan *int64 80 | aChanPtrFloat32 chan *float32 81 | aChanPtrFloat64 chan *float32 82 | aChanPtrString chan *string 83 | 84 | aPtrStruct *testStruct1 85 | } 86 | testStruct2 struct { 87 | aStruct testStruct1 88 | } 89 | ) 90 | 91 | var ( 92 | testVarValue = reflect.Value{} 93 | testVarValueP = &reflect.Value{} 94 | testVarBool = true 95 | testVarBoolP = &testVarBool 96 | testVarInt32 = int32(1) 97 | testVarInt32P = &testVarInt32 98 | testVarInt64 = int64(1) 99 | testVarInt64P = &testVarInt64 100 | testVarFloat32 = float32(1) 101 | testVarFloat32P = &testVarFloat32 102 | testVarFloat64 = float64(1) 103 | testVarFloat64P = &testVarFloat64 104 | testVarString = "a" 105 | testVarStringP = &testVarString 106 | testVarFunc = func() int64 { return 1 } 107 | testVarFuncP = &testVarFunc 108 | 109 | testVarValueBool = reflect.ValueOf(true) 110 | testVarValueInt32 = reflect.ValueOf(int32(1)) 111 | testVarValueInt64 = reflect.ValueOf(int64(1)) 112 | testVarValueFloat32 = reflect.ValueOf(float32(1.1)) 113 | testVarValueFloat64 = reflect.ValueOf(float64(1.1)) 114 | testVarValueString = reflect.ValueOf("a") 115 | 116 | testSliceEmpty []interface{} 117 | testSlice = []interface{}{nil, true, int64(1), float64(1.1), "a"} 118 | testMapEmpty map[interface{}]interface{} 119 | testMap = map[interface{}]interface{}{"a": nil, "b": true, "c": int64(1), "d": float64(1.1), "e": "e"} 120 | ) 121 | 122 | // Test is utility struct to make tests easy. 123 | type Test struct { 124 | Script string 125 | ParseError error 126 | ParseErrorFunc *func(*testing.T, error) 127 | EnvSetupFunc *func(*testing.T, *env.Env) 128 | Types map[string]interface{} 129 | Input map[string]interface{} 130 | RunError error 131 | RunErrorFunc *func(*testing.T, error) 132 | RunOutput interface{} 133 | Output map[string]interface{} 134 | } 135 | 136 | // TestOptions is utility struct to pass options to the test. 137 | type TestOptions struct { 138 | EnvSetupFunc *func(*testing.T, *env.Env) 139 | Timeout time.Duration 140 | } 141 | 142 | // runTests runs VM tests 143 | func runTests(t *testing.T, tests []Test, testOptions *TestOptions, options *Options) { 144 | for _, test := range tests { 145 | runTest(t, test, testOptions, options) 146 | } 147 | } 148 | 149 | // runTest runs VM test 150 | func runTest(t *testing.T, test Test, testOptions *TestOptions, options *Options) { 151 | timeout := 60 * time.Second 152 | 153 | // parser.EnableErrorVerbose() 154 | // parser.EnableDebug(8) 155 | 156 | stmt, err := parser.ParseSrc(test.Script) 157 | if test.ParseErrorFunc != nil { 158 | (*test.ParseErrorFunc)(t, err) 159 | } else if err != nil && test.ParseError != nil { 160 | if err.Error() != test.ParseError.Error() { 161 | t.Errorf("ParseSrc error - received: %v - expected: %v - script: %v", err, test.ParseError, test.Script) 162 | return 163 | } 164 | } else if err != test.ParseError { 165 | t.Errorf("ParseSrc error - received: %v - expected: %v - script: %v", err, test.ParseError, test.Script) 166 | return 167 | } 168 | // Note: Still want to run the code even after a parse error to see what happens 169 | 170 | envTest := env.NewEnv() 171 | if testOptions != nil { 172 | if testOptions.EnvSetupFunc != nil { 173 | (*testOptions.EnvSetupFunc)(t, envTest) 174 | } 175 | if testOptions.Timeout != 0 { 176 | timeout = testOptions.Timeout 177 | } 178 | } 179 | if test.EnvSetupFunc != nil { 180 | (*test.EnvSetupFunc)(t, envTest) 181 | } 182 | 183 | for typeName, typeValue := range test.Types { 184 | err = envTest.DefineType(typeName, typeValue) 185 | if err != nil { 186 | t.Errorf("DefineType error: %v - typeName: %v - script: %v", err, typeName, test.Script) 187 | return 188 | } 189 | } 190 | 191 | for inputName, inputValue := range test.Input { 192 | err = envTest.Define(inputName, inputValue) 193 | if err != nil { 194 | t.Errorf("Define error: %v - inputName: %v - script: %v", err, inputName, test.Script) 195 | return 196 | } 197 | } 198 | 199 | var value interface{} 200 | ctx, cancel := context.WithTimeout(context.Background(), timeout) 201 | value, err = RunContext(ctx, envTest, options, stmt) 202 | cancel() 203 | if test.RunErrorFunc != nil { 204 | (*test.RunErrorFunc)(t, err) 205 | } else if err != nil && test.RunError != nil { 206 | if err.Error() != test.RunError.Error() { 207 | t.Errorf("Run error - received: %v - expected: %v - script: %v", err, test.RunError, test.Script) 208 | return 209 | } 210 | } else if err != test.RunError { 211 | t.Errorf("Run error - received: %v - expected: %v - script: %v", err, test.RunError, test.Script) 212 | return 213 | } 214 | 215 | if !valueEqual(value, test.RunOutput) { 216 | t.Errorf("Run output - received: %#v - expected: %#v - script: %v", value, test.RunOutput, test.Script) 217 | t.Errorf("received type: %T - expected: %T", value, test.RunOutput) 218 | return 219 | } 220 | 221 | for outputName, outputValue := range test.Output { 222 | value, err = envTest.Get(outputName) 223 | if err != nil { 224 | t.Errorf("Get error: %v - outputName: %v - script: %v", err, outputName, test.Script) 225 | return 226 | } 227 | 228 | if !valueEqual(value, outputValue) { 229 | t.Errorf("outputName %v - received: %#v - expected: %#v - script: %v", outputName, value, outputValue, test.Script) 230 | t.Errorf("received type: %T - expected: %T", value, outputValue) 231 | continue 232 | } 233 | } 234 | } 235 | 236 | // valueEqual return true if v1 and v2 is same value. If passed function, does 237 | // extra checks otherwise just doing reflect.DeepEqual 238 | func valueEqual(v1 interface{}, v2 interface{}) bool { 239 | v1RV := reflect.ValueOf(v1) 240 | switch v1RV.Kind() { 241 | case reflect.Func: 242 | // This is best effort to check if functions match, but it could be wrong 243 | v2RV := reflect.ValueOf(v2) 244 | if !v1RV.IsValid() || !v2RV.IsValid() { 245 | if v1RV.IsValid() != !v2RV.IsValid() { 246 | return false 247 | } 248 | return true 249 | } else if v1RV.Kind() != v2RV.Kind() { 250 | return false 251 | } else if v1RV.Type() != v2RV.Type() { 252 | return false 253 | } else if v1RV.Pointer() != v2RV.Pointer() { 254 | // From reflect: If v's Kind is Func, the returned pointer is an underlying code pointer, but not necessarily enough to identify a single function uniquely. 255 | return false 256 | } 257 | return true 258 | } 259 | switch value1 := v1.(type) { 260 | case error: 261 | switch value2 := v2.(type) { 262 | case error: 263 | return value1.Error() == value2.Error() 264 | } 265 | } 266 | 267 | return reflect.DeepEqual(v1, v2) 268 | } 269 | -------------------------------------------------------------------------------- /vm/packagesGo110_test.go: -------------------------------------------------------------------------------- 1 | // +build go1.10 2 | 3 | package vm 4 | 5 | import ( 6 | "testing" 7 | 8 | _ "github.com/mattn/anko/packages" 9 | ) 10 | 11 | func TestPackagesStringsGo110(t *testing.T) { 12 | t.Parallel() 13 | 14 | tests := []Test{ 15 | {Script: `strings = import("strings"); a = make(strings.Builder); _, err = a.WriteString("a"); if err != nil { return err.Error() }; _, err = a.WriteString("b"); if err != nil { return err.Error() }; _, err = a.WriteString("c"); if err != nil { return err.Error() }; a.String()`, RunOutput: "abc"}, 16 | } 17 | runTests(t, tests, nil, &Options{Debug: true}) 18 | } 19 | -------------------------------------------------------------------------------- /vm/vmConvertToX.go: -------------------------------------------------------------------------------- 1 | package vm 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | // reflectValueSlicetoInterfaceSlice convert from a slice of reflect.Value to a interface slice 10 | // returned in normal reflect.Value form 11 | func reflectValueSlicetoInterfaceSlice(valueSlice []reflect.Value) reflect.Value { 12 | interfaceSlice := make([]interface{}, 0, len(valueSlice)) 13 | for _, value := range valueSlice { 14 | if value.Kind() == reflect.Interface && !value.IsNil() { 15 | value = value.Elem() 16 | } 17 | if value.CanInterface() { 18 | interfaceSlice = append(interfaceSlice, value.Interface()) 19 | } else { 20 | interfaceSlice = append(interfaceSlice, nil) 21 | } 22 | } 23 | return reflect.ValueOf(interfaceSlice) 24 | } 25 | 26 | // convertReflectValueToType trys to covert the reflect.Value to the reflect.Type 27 | // if it can not, it returns the original rv and an error 28 | func convertReflectValueToType(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { 29 | if rt == interfaceType || rv.Type() == rt { 30 | // if reflect.Type is interface or the types match, return the provided reflect.Value 31 | return rv, nil 32 | } 33 | if rv.Type().ConvertibleTo(rt) { 34 | // if reflect can covert, do that conversion and return 35 | return rv.Convert(rt), nil 36 | } 37 | if (rv.Kind() == reflect.Slice || rv.Kind() == reflect.Array) && 38 | (rt.Kind() == reflect.Slice || rt.Kind() == reflect.Array) { 39 | // covert slice or array 40 | return convertSliceOrArray(rv, rt) 41 | } 42 | if rv.Kind() == rt.Kind() { 43 | // kind matches 44 | switch rv.Kind() { 45 | case reflect.Map: 46 | // convert map 47 | return convertMap(rv, rt) 48 | case reflect.Func: 49 | // for runVMFunction conversions, call convertVMFunctionToType 50 | return convertVMFunctionToType(rv, rt) 51 | case reflect.Ptr: 52 | // both rv and rt are pointers, convert what they are pointing to 53 | value, err := convertReflectValueToType(rv.Elem(), rt.Elem()) 54 | if err != nil { 55 | return rv, err 56 | } 57 | // need to make a new value to be able to set it 58 | ptrV, err := makeValue(rt) 59 | if err != nil { 60 | return rv, err 61 | } 62 | // set value and return new pointer 63 | ptrV.Elem().Set(value) 64 | return ptrV, nil 65 | } 66 | } 67 | if rv.Type() == interfaceType { 68 | if rv.IsNil() { 69 | // return nil of correct type 70 | return reflect.Zero(rt), nil 71 | } 72 | // try to convert the element 73 | return convertReflectValueToType(rv.Elem(), rt) 74 | } 75 | 76 | if rv.Type() == stringType { 77 | if rt == byteType { 78 | aString := rv.String() 79 | if len(aString) < 1 { 80 | return reflect.Zero(rt), nil 81 | } 82 | if len(aString) > 1 { 83 | return rv, errInvalidTypeConversion 84 | } 85 | return reflect.ValueOf(aString[0]), nil 86 | } 87 | if rt == runeType { 88 | aString := rv.String() 89 | if len(aString) < 1 { 90 | return reflect.Zero(rt), nil 91 | } 92 | if len(aString) > 1 { 93 | return rv, errInvalidTypeConversion 94 | } 95 | return reflect.ValueOf(rune(aString[0])), nil 96 | } 97 | } 98 | 99 | // TODO: need to handle the case where either rv or rt are a pointer but not both 100 | 101 | return rv, errInvalidTypeConversion 102 | } 103 | 104 | // convertSliceOrArray trys to covert the reflect.Value slice or array to the slice or array reflect.Type 105 | func convertSliceOrArray(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { 106 | rtElemType := rt.Elem() 107 | 108 | // try to covert elements to new slice/array 109 | var value reflect.Value 110 | if rt.Kind() == reflect.Slice { 111 | // make slice 112 | value = reflect.MakeSlice(rt, rv.Len(), rv.Len()) 113 | } else { 114 | // make array 115 | value = reflect.New(rt).Elem() 116 | } 117 | 118 | var err error 119 | var v reflect.Value 120 | for i := 0; i < rv.Len(); i++ { 121 | v, err = convertReflectValueToType(rv.Index(i), rtElemType) 122 | if err != nil { 123 | return rv, err 124 | } 125 | value.Index(i).Set(v) 126 | } 127 | 128 | // return new converted slice or array 129 | return value, nil 130 | } 131 | 132 | // convertVMFunctionToType is for translating a runVMFunction into the correct type 133 | // so it can be passed to a Go function argument with the correct static types 134 | // it creates a translate function runVMConvertFunction 135 | func convertVMFunctionToType(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { 136 | // only translates runVMFunction type 137 | if !checkIfRunVMFunction(rv.Type()) { 138 | return rv, errInvalidTypeConversion 139 | } 140 | 141 | // create runVMConvertFunction to match reflect.Type 142 | // this function is being called by the Go function 143 | runVMConvertFunction := func(in []reflect.Value) []reflect.Value { 144 | // note: this function is being called by another reflect Call 145 | // only way to pass along any errors is by panic 146 | 147 | // make the reflect.Value slice of each of the VM reflect.Value 148 | args := make([]reflect.Value, 0, rt.NumIn()+1) 149 | // for runVMFunction first arg is always context 150 | // TOFIX: use normal context 151 | args = append(args, reflect.ValueOf(context.Background())) 152 | for i := 0; i < rt.NumIn(); i++ { 153 | // have to do the double reflect.ValueOf that runVMFunction expects 154 | args = append(args, reflect.ValueOf(in[i])) 155 | } 156 | 157 | // Call runVMFunction 158 | rvs := rv.Call(args) 159 | 160 | // call processCallReturnValues to process runVMFunction return values 161 | // returns normal VM reflect.Value form 162 | rv, err := processCallReturnValues(rvs, true, false) 163 | if err != nil { 164 | panic(err) 165 | } 166 | 167 | if rt.NumOut() < 1 { 168 | // Go function does not want any return values, so give it none 169 | return []reflect.Value{} 170 | } 171 | if rt.NumOut() < 2 { 172 | // Go function wants one return value 173 | // will try to covert to reflect.Value correct type and return 174 | rv, err = convertReflectValueToType(rv, rt.Out(0)) 175 | if err != nil { 176 | panic("function wants return type " + rt.Out(0).String() + " but received type " + rv.Type().String()) 177 | } 178 | return []reflect.Value{rv} 179 | } 180 | 181 | // Go function wants more than one return value 182 | // make sure we have a slice/array with enought values 183 | 184 | if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array { 185 | panic(fmt.Sprintf("function wants %v return values but received %v", rt.NumOut(), rv.Kind().String())) 186 | } 187 | if rv.Len() < rt.NumOut() { 188 | panic(fmt.Sprintf("function wants %v return values but received %v values", rt.NumOut(), rv.Len())) 189 | } 190 | 191 | // try to covert each value in slice to wanted type and put into a reflect.Value slice 192 | rvs = make([]reflect.Value, rt.NumOut()) 193 | for i := 0; i < rv.Len(); i++ { 194 | rvs[i], err = convertReflectValueToType(rv.Index(i), rt.Out(i)) 195 | if err != nil { 196 | panic("function wants return type " + rt.Out(i).String() + " but received type " + rvs[i].Type().String()) 197 | } 198 | } 199 | 200 | // return created reflect.Value slice 201 | return rvs 202 | } 203 | 204 | // make the reflect.Value function that calls runVMConvertFunction 205 | return reflect.MakeFunc(rt, runVMConvertFunction), nil 206 | } 207 | -------------------------------------------------------------------------------- /vm/vmConvertToXGo112.go: -------------------------------------------------------------------------------- 1 | // +build go1.12 2 | 3 | package vm 4 | 5 | import ( 6 | "reflect" 7 | ) 8 | 9 | // convertMap trys to covert the reflect.Value map to the map reflect.Type 10 | func convertMap(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { 11 | rtKey := rt.Key() 12 | rtElem := rt.Elem() 13 | 14 | // create new map 15 | // note creating slice as work around to create map 16 | // just doing MakeMap can give incorrect type for defined types 17 | newMap := reflect.MakeSlice(reflect.SliceOf(rt), 0, 1) 18 | newMap = reflect.Append(newMap, reflect.MakeMap(reflect.MapOf(rtKey, rtElem))).Index(0) 19 | 20 | // copy keys to new map 21 | // For Go 1.12 and after can use MapRange 22 | mapIter := rv.MapRange() 23 | var value reflect.Value 24 | for mapIter.Next() { 25 | newKey, err := convertReflectValueToType(mapIter.Key(), rtKey) 26 | if err != nil { 27 | return rv, err 28 | } 29 | value, err = convertReflectValueToType(mapIter.Value(), rtElem) 30 | if err != nil { 31 | return rv, err 32 | } 33 | newMap.SetMapIndex(newKey, value) 34 | } 35 | 36 | return newMap, nil 37 | } 38 | -------------------------------------------------------------------------------- /vm/vmConvertToXNotGo112.go: -------------------------------------------------------------------------------- 1 | // +build !go1.12 2 | 3 | package vm 4 | 5 | import ( 6 | "reflect" 7 | ) 8 | 9 | // convertMap trys to covert the reflect.Value map to the map reflect.Type 10 | func convertMap(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { 11 | rtKey := rt.Key() 12 | rtElem := rt.Elem() 13 | 14 | // create new map 15 | // note creating slice as work around to create map 16 | // just doing MakeMap can give incorrect type for defined types 17 | newMap := reflect.MakeSlice(reflect.SliceOf(rt), 0, 1) 18 | newMap = reflect.Append(newMap, reflect.MakeMap(reflect.MapOf(rtKey, rtElem))).Index(0) 19 | 20 | // copy keys to new map 21 | // Before Go 1.12 the only way to do this is to get all the keys. 22 | // Note this is costly for large maps. 23 | mapKeys := rv.MapKeys() 24 | for i := 0; i < len(mapKeys); i++ { 25 | newKey, err := convertReflectValueToType(mapKeys[i], rtKey) 26 | if err != nil { 27 | return rv, err 28 | } 29 | value := rv.MapIndex(mapKeys[i]) 30 | value, err = convertReflectValueToType(value, rtElem) 31 | if err != nil { 32 | return rv, err 33 | } 34 | newMap.SetMapIndex(newKey, value) 35 | } 36 | 37 | return newMap, nil 38 | } 39 | -------------------------------------------------------------------------------- /vm/vmOperator.go: -------------------------------------------------------------------------------- 1 | package vm 2 | 3 | import ( 4 | "reflect" 5 | "strings" 6 | 7 | "github.com/mattn/anko/ast" 8 | ) 9 | 10 | // invokeOperator evaluates one Operator. 11 | func (runInfo *runInfoStruct) invokeOperator() { 12 | switch operator := runInfo.operator.(type) { 13 | 14 | // BinaryOperator 15 | case *ast.BinaryOperator: 16 | runInfo.expr = operator.LHS 17 | runInfo.invokeExpr() 18 | if runInfo.err != nil { 19 | return 20 | } 21 | if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { 22 | runInfo.rv = runInfo.rv.Elem() 23 | } 24 | 25 | switch operator.Operator { 26 | case "||": 27 | if toBool(runInfo.rv) { 28 | runInfo.rv = trueValue 29 | return 30 | } 31 | case "&&": 32 | if !toBool(runInfo.rv) { 33 | runInfo.rv = falseValue 34 | return 35 | } 36 | default: 37 | runInfo.err = newStringError(operator, "unknown operator") 38 | runInfo.rv = nilValue 39 | return 40 | } 41 | 42 | runInfo.expr = operator.RHS 43 | runInfo.invokeExpr() 44 | if runInfo.err != nil { 45 | return 46 | } 47 | if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { 48 | runInfo.rv = runInfo.rv.Elem() 49 | } 50 | 51 | if toBool(runInfo.rv) { 52 | runInfo.rv = trueValue 53 | } else { 54 | runInfo.rv = falseValue 55 | } 56 | 57 | // ComparisonOperator 58 | case *ast.ComparisonOperator: 59 | runInfo.expr = operator.LHS 60 | runInfo.invokeExpr() 61 | if runInfo.err != nil { 62 | return 63 | } 64 | if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { 65 | runInfo.rv = runInfo.rv.Elem() 66 | } 67 | lhsV := runInfo.rv 68 | 69 | runInfo.expr = operator.RHS 70 | runInfo.invokeExpr() 71 | if runInfo.err != nil { 72 | return 73 | } 74 | if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { 75 | runInfo.rv = runInfo.rv.Elem() 76 | } 77 | 78 | switch operator.Operator { 79 | case "==": 80 | runInfo.rv = reflect.ValueOf(equal(lhsV, runInfo.rv)) 81 | case "!=": 82 | runInfo.rv = reflect.ValueOf(!equal(lhsV, runInfo.rv)) 83 | case "<": 84 | runInfo.rv = reflect.ValueOf(toFloat64(lhsV) < toFloat64(runInfo.rv)) 85 | case "<=": 86 | runInfo.rv = reflect.ValueOf(toFloat64(lhsV) <= toFloat64(runInfo.rv)) 87 | case ">": 88 | runInfo.rv = reflect.ValueOf(toFloat64(lhsV) > toFloat64(runInfo.rv)) 89 | case ">=": 90 | runInfo.rv = reflect.ValueOf(toFloat64(lhsV) >= toFloat64(runInfo.rv)) 91 | default: 92 | runInfo.err = newStringError(operator, "unknown operator") 93 | runInfo.rv = nilValue 94 | } 95 | 96 | // AddOperator 97 | case *ast.AddOperator: 98 | runInfo.expr = operator.LHS 99 | runInfo.invokeExpr() 100 | if runInfo.err != nil { 101 | return 102 | } 103 | if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { 104 | runInfo.rv = runInfo.rv.Elem() 105 | } 106 | lhsV := runInfo.rv 107 | 108 | runInfo.expr = operator.RHS 109 | runInfo.invokeExpr() 110 | if runInfo.err != nil { 111 | return 112 | } 113 | if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { 114 | runInfo.rv = runInfo.rv.Elem() 115 | } 116 | 117 | switch operator.Operator { 118 | case "+": 119 | lhsKind := lhsV.Kind() 120 | rhsKind := runInfo.rv.Kind() 121 | 122 | if lhsKind == reflect.Slice || lhsKind == reflect.Array { 123 | if rhsKind == reflect.Slice || rhsKind == reflect.Array { 124 | // append slice to slice 125 | runInfo.rv, runInfo.err = appendSlice(operator, lhsV, runInfo.rv) 126 | return 127 | } 128 | // try to append rhs non-slice to lhs slice 129 | runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, lhsV.Type().Elem()) 130 | if runInfo.err != nil { 131 | runInfo.err = newStringError(operator, "invalid type conversion") 132 | runInfo.rv = nilValue 133 | return 134 | } 135 | runInfo.rv = reflect.Append(lhsV, runInfo.rv) 136 | return 137 | } 138 | if rhsKind == reflect.Slice || rhsKind == reflect.Array { 139 | // can not append rhs slice to lhs non-slice 140 | runInfo.err = newStringError(operator, "invalid type conversion") 141 | runInfo.rv = nilValue 142 | return 143 | } 144 | 145 | kind := precedenceOfKinds(lhsKind, rhsKind) 146 | switch kind { 147 | case reflect.String: 148 | runInfo.rv = reflect.ValueOf(toString(lhsV) + toString(runInfo.rv)) 149 | case reflect.Float64, reflect.Float32: 150 | runInfo.rv = reflect.ValueOf(toFloat64(lhsV) + toFloat64(runInfo.rv)) 151 | default: 152 | runInfo.rv = reflect.ValueOf(toInt64(lhsV) + toInt64(runInfo.rv)) 153 | } 154 | 155 | case "-": 156 | switch lhsV.Kind() { 157 | case reflect.Float64, reflect.Float32: 158 | runInfo.rv = reflect.ValueOf(toFloat64(lhsV) - toFloat64(runInfo.rv)) 159 | return 160 | } 161 | switch runInfo.rv.Kind() { 162 | case reflect.Float64, reflect.Float32: 163 | runInfo.rv = reflect.ValueOf(toFloat64(lhsV) - toFloat64(runInfo.rv)) 164 | default: 165 | runInfo.rv = reflect.ValueOf(toInt64(lhsV) - toInt64(runInfo.rv)) 166 | } 167 | 168 | case "|": 169 | runInfo.rv = reflect.ValueOf(toInt64(lhsV) | toInt64(runInfo.rv)) 170 | default: 171 | runInfo.err = newStringError(operator, "unknown operator") 172 | runInfo.rv = nilValue 173 | } 174 | 175 | // MultiplyOperator 176 | case *ast.MultiplyOperator: 177 | runInfo.expr = operator.LHS 178 | runInfo.invokeExpr() 179 | if runInfo.err != nil { 180 | return 181 | } 182 | if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { 183 | runInfo.rv = runInfo.rv.Elem() 184 | } 185 | lhsV := runInfo.rv 186 | 187 | runInfo.expr = operator.RHS 188 | runInfo.invokeExpr() 189 | if runInfo.err != nil { 190 | return 191 | } 192 | if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { 193 | runInfo.rv = runInfo.rv.Elem() 194 | } 195 | 196 | switch operator.Operator { 197 | case "*": 198 | if lhsV.Kind() == reflect.String && (runInfo.rv.Kind() == reflect.Int || runInfo.rv.Kind() == reflect.Int32 || runInfo.rv.Kind() == reflect.Int64) { 199 | runInfo.rv = reflect.ValueOf(strings.Repeat(toString(lhsV), int(toInt64(runInfo.rv)))) 200 | return 201 | } 202 | if lhsV.Kind() == reflect.Float64 || runInfo.rv.Kind() == reflect.Float64 { 203 | runInfo.rv = reflect.ValueOf(toFloat64(lhsV) * toFloat64(runInfo.rv)) 204 | return 205 | } 206 | runInfo.rv = reflect.ValueOf(toInt64(lhsV) * toInt64(runInfo.rv)) 207 | case "/": 208 | runInfo.rv = reflect.ValueOf(toFloat64(lhsV) / toFloat64(runInfo.rv)) 209 | case "%": 210 | runInfo.rv = reflect.ValueOf(toInt64(lhsV) % toInt64(runInfo.rv)) 211 | case ">>": 212 | runInfo.rv = reflect.ValueOf(toInt64(lhsV) >> uint64(toInt64(runInfo.rv))) 213 | case "<<": 214 | runInfo.rv = reflect.ValueOf(toInt64(lhsV) << uint64(toInt64(runInfo.rv))) 215 | case "&": 216 | runInfo.rv = reflect.ValueOf(toInt64(lhsV) & toInt64(runInfo.rv)) 217 | 218 | default: 219 | runInfo.err = newStringError(operator, "unknown operator") 220 | runInfo.rv = nilValue 221 | } 222 | 223 | default: 224 | runInfo.err = newStringError(operator, "unknown operator") 225 | runInfo.rv = nilValue 226 | 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /vm/vmToX.go: -------------------------------------------------------------------------------- 1 | package vm 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // toString converts all reflect.Value-s into string. 12 | func toString(v reflect.Value) string { 13 | if v.Kind() == reflect.Interface && !v.IsNil() { 14 | v = v.Elem() 15 | } 16 | if v.Kind() == reflect.Ptr { 17 | v = v.Elem() 18 | } 19 | if v.Kind() == reflect.String { 20 | return v.String() 21 | } 22 | return fmt.Sprint(v.Interface()) 23 | } 24 | 25 | // toBool converts all reflect.Value-s into bool. 26 | func toBool(v reflect.Value) bool { 27 | b, _ := tryToBool(v) 28 | return b 29 | } 30 | 31 | // tryToBool attempts to convert the value 'v' to a boolean, returning 32 | // an error if it cannot. When converting a string, the function returns 33 | // true if the string nonempty and does not satisfy the condition for false 34 | // with parseBool https://golang.org/pkg/strconv/#ParseBool 35 | // and is not 0.0 36 | func tryToBool(v reflect.Value) (bool, error) { 37 | if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { 38 | v = v.Elem() 39 | } 40 | switch v.Kind() { 41 | case reflect.Float64, reflect.Float32: 42 | return v.Float() != 0, nil 43 | case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: 44 | return v.Int() != 0, nil 45 | case reflect.Bool: 46 | return v.Bool(), nil 47 | case reflect.String: 48 | if v.Len() == 0 { 49 | return false, nil 50 | } 51 | 52 | s := v.String() 53 | if b, err := strconv.ParseBool(s); err == nil && !b { 54 | return false, nil 55 | } 56 | 57 | if f, err := tryToFloat64(v); err == nil && f == 0 { 58 | return false, nil 59 | } 60 | return true, nil 61 | case reflect.Slice, reflect.Map: 62 | if v.Len() > 0 { 63 | return true, nil 64 | } 65 | return false, nil 66 | } 67 | return false, errors.New("unknown type") 68 | } 69 | 70 | // toFloat64 converts all reflect.Value-s into float64. 71 | func toFloat64(v reflect.Value) float64 { 72 | f, _ := tryToFloat64(v) 73 | return f 74 | } 75 | 76 | // tryToFloat64 attempts to convert a value to a float64. 77 | // If it cannot (in the case of a non-numeric string, a struct, etc.) 78 | // it returns 0.0 and an error. 79 | func tryToFloat64(v reflect.Value) (float64, error) { 80 | if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { 81 | v = v.Elem() 82 | } 83 | switch v.Kind() { 84 | case reflect.Float64, reflect.Float32: 85 | return v.Float(), nil 86 | case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: 87 | return float64(v.Int()), nil 88 | case reflect.Bool: 89 | if v.Bool() { 90 | return 1, nil 91 | } 92 | return 0, nil 93 | case reflect.String: 94 | f, err := strconv.ParseFloat(v.String(), 64) 95 | if err == nil { 96 | return f, nil 97 | } 98 | } 99 | return 0.0, errors.New("couldn't convert to a float64") 100 | } 101 | 102 | // toInt64 converts all reflect.Value-s into int64. 103 | func toInt64(v reflect.Value) int64 { 104 | i, _ := tryToInt64(v) 105 | return i 106 | } 107 | 108 | // tryToInt64 attempts to convert a value to an int64. 109 | // If it cannot (in the case of a non-numeric string, a struct, etc.) 110 | // it returns 0 and an error. 111 | func tryToInt64(v reflect.Value) (int64, error) { 112 | if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { 113 | v = v.Elem() 114 | } 115 | switch v.Kind() { 116 | case reflect.Float64, reflect.Float32: 117 | return int64(v.Float()), nil 118 | case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: 119 | return v.Int(), nil 120 | case reflect.Bool: 121 | if v.Bool() { 122 | return 1, nil 123 | } 124 | return 0, nil 125 | case reflect.String: 126 | s := v.String() 127 | var i int64 128 | var err error 129 | if strings.HasPrefix(s, "0x") { 130 | i, err = strconv.ParseInt(s, 16, 64) 131 | } else { 132 | i, err = strconv.ParseInt(s, 10, 64) 133 | } 134 | if err == nil { 135 | return i, nil 136 | } 137 | } 138 | return 0, errors.New("couldn't convert to integer") 139 | } 140 | 141 | // toInt converts all reflect.Value-s into int. 142 | func toInt(v reflect.Value) int { 143 | i, _ := tryToInt(v) 144 | return i 145 | } 146 | 147 | // tryToInt attempts to convert a value to an int. 148 | // If it cannot (in the case of a non-numeric string, a struct, etc.) 149 | // it returns 0 and an error. 150 | func tryToInt(v reflect.Value) (int, error) { 151 | if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { 152 | v = v.Elem() 153 | } 154 | switch v.Kind() { 155 | case reflect.Float64, reflect.Float32: 156 | return int(v.Float()), nil 157 | case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: 158 | return int(v.Int()), nil 159 | case reflect.Bool: 160 | if v.Bool() { 161 | return 1, nil 162 | } 163 | return 0, nil 164 | case reflect.String: 165 | s := v.String() 166 | var i int64 167 | var err error 168 | if strings.HasPrefix(s, "0x") { 169 | i, err = strconv.ParseInt(s, 16, 64) 170 | } else { 171 | i, err = strconv.ParseInt(s, 10, 64) 172 | } 173 | if err == nil { 174 | return int(i), nil 175 | } 176 | } 177 | return 0, errors.New("couldn't convert to integer") 178 | } 179 | -------------------------------------------------------------------------------- /vm/vm_Go19_test.go: -------------------------------------------------------------------------------- 1 | // +build go1.9 2 | 3 | package vm 4 | 5 | import ( 6 | "fmt" 7 | "testing" 8 | ) 9 | 10 | func TestMakeGo19(t *testing.T) { 11 | t.Parallel() 12 | 13 | tests := []Test{ 14 | {Script: `make(struct { a int64 })`, RunError: fmt.Errorf("reflect.StructOf: field \"a\" is unexported but missing PkgPath")}, 15 | } 16 | runTests(t, tests, nil, &Options{Debug: false}) 17 | } 18 | -------------------------------------------------------------------------------- /vm/vm_NotGo19_test.go: -------------------------------------------------------------------------------- 1 | // +build !go1.9 2 | 3 | package vm 4 | 5 | import ( 6 | "fmt" 7 | "testing" 8 | ) 9 | 10 | func TestMakeNotGo19(t *testing.T) { 11 | t.Parallel() 12 | 13 | tests := []Test{ 14 | {Script: `make(struct { a int64 })`, RunError: fmt.Errorf("reflect.StructOf: field \"a\" is unexported but has no PkgPath")}, 15 | } 16 | runTests(t, tests, nil, &Options{Debug: false}) 17 | } 18 | --------------------------------------------------------------------------------