From 5251f0fbf4d197fd9dda759e5563a5276582c683 Mon Sep 17 00:00:00 2001 From: surdeus Date: Sun, 4 Jun 2023 18:59:42 +0300 Subject: [PATCH] Embedded anko as run. --- src/cmd/goblin/main.go | 6 + src/tool/run/.github/FUNDING.yml | 8 + src/tool/run/.travis.yml | 22 + src/tool/run/LICENSE | 21 + src/tool/run/README.md | 155 + .../run/_example/scripts/anonymous-call.ank | 9 + src/tool/run/_example/scripts/chan.ank | 13 + src/tool/run/_example/scripts/env.ank | 9 + src/tool/run/_example/scripts/example.ank | 70 + src/tool/run/_example/scripts/exec.ank | 7 + src/tool/run/_example/scripts/fib-for.ank | 15 + .../run/_example/scripts/fib-recursion.ank | 14 + .../_example/scripts/for-break-continue.ank | 12 + src/tool/run/_example/scripts/http.ank | 8 + src/tool/run/_example/scripts/module.ank | 10 + src/tool/run/_example/scripts/regexp.ank | 8 + src/tool/run/_example/scripts/server.ank | 8 + src/tool/run/_example/scripts/signal.ank | 14 + src/tool/run/_example/scripts/slice.ank | 10 + src/tool/run/_example/scripts/socket.ank | 26 + src/tool/run/_example/scripts/toType.ank | 123 + src/tool/run/_example/scripts/try-catch.ank | 19 + src/tool/run/_example/scripts/url.ank | 7 + .../run/_example/scripts/z-combinator.ank | 15 + src/tool/run/anko.go | 172 ++ src/tool/run/anko.png | Bin 0 -> 363243 bytes src/tool/run/anko_test.go | 273 ++ src/tool/run/ast/ast.go | 38 + src/tool/run/ast/astutil/walk.go | 281 ++ src/tool/run/ast/astutil/walk_test.go | 239 ++ src/tool/run/ast/doc.go | 2 + src/tool/run/ast/expr.go | 187 ++ src/tool/run/ast/operator.go | 43 + src/tool/run/ast/pos.go | 28 + src/tool/run/ast/stmt.go | 157 ++ src/tool/run/cmd/anko-package-gen/main.go | 122 + src/tool/run/core/core.go | 105 + src/tool/run/core/testdata/broken.ank | 6 + src/tool/run/core/testdata/chan.ank | 17 + src/tool/run/core/testdata/core_test.go | 149 + src/tool/run/core/testdata/error.ank | 3 + src/tool/run/core/testdata/for.ank | 75 + src/tool/run/core/testdata/func.ank | 24 + src/tool/run/core/testdata/if.ank | 14 + src/tool/run/core/testdata/len.ank | 6 + src/tool/run/core/testdata/let.ank | 32 + src/tool/run/core/testdata/op.ank | 63 + src/tool/run/core/testdata/sort.ank | 32 + src/tool/run/core/testdata/switch.ank | 40 + src/tool/run/core/testdata/test.ank | 3 + src/tool/run/core/testdata/testing.ank | 19 + src/tool/run/core/testdata/toBytes.ank | 12 + src/tool/run/core/testdata/toRunes.ank | 12 + src/tool/run/core/testdata/toString.ank | 8 + src/tool/run/core/testdata/toX_test.go | 151 + src/tool/run/core/toX.go | 171 ++ src/tool/run/env/env.go | 187 ++ src/tool/run/env/envExternalLookup_test.go | 235 ++ src/tool/run/env/envTypes.go | 83 + src/tool/run/env/envTypes_test.go | 313 +++ src/tool/run/env/envValues.go | 161 ++ src/tool/run/env/envValues_test.go | 787 ++++++ src/tool/run/env/env_test.go | 394 +++ src/tool/run/misc/vim/ftdetect/ank.vim | 1 + .../run/misc/vim/ftplugin/anko/comment.vim | 11 + src/tool/run/misc/vim/ftplugin/anko/play.vim | 15 + src/tool/run/misc/vim/syntax/anko.vim | 100 + src/tool/run/misc/wasm/anko.go | 129 + src/tool/run/misc/wasm/index.html | 35 + src/tool/run/misc/wasm/wasm_exec.js | 381 +++ src/tool/run/packages/bytes.go | 64 + src/tool/run/packages/bytesGo17.go | 14 + src/tool/run/packages/bytesNotGo17.go | 5 + src/tool/run/packages/encoding.json.go | 15 + src/tool/run/packages/errors.go | 14 + src/tool/run/packages/flag.go | 48 + src/tool/run/packages/fmt.go | 32 + src/tool/run/packages/io.go | 30 + src/tool/run/packages/io.ioutil.go | 17 + src/tool/run/packages/log.go | 29 + src/tool/run/packages/math.big.go | 32 + src/tool/run/packages/math.go | 74 + src/tool/run/packages/math.rand.go | 26 + src/tool/run/packages/net.go | 76 + src/tool/run/packages/net.http.cookiejar.go | 17 + src/tool/run/packages/net.http.go | 32 + src/tool/run/packages/net.url.go | 27 + src/tool/run/packages/os.exec.go | 16 + src/tool/run/packages/os.go | 102 + src/tool/run/packages/os.signal.go | 15 + src/tool/run/packages/osAppEngine.go | 5 + src/tool/run/packages/osNotAppEngine.go | 14 + src/tool/run/packages/path.filepath.go | 30 + src/tool/run/packages/path.go | 22 + src/tool/run/packages/regexp.go | 21 + src/tool/run/packages/runtime.go | 19 + src/tool/run/packages/sort.go | 44 + src/tool/run/packages/sortGo18.go | 16 + src/tool/run/packages/sortNotGo18.go | 5 + src/tool/run/packages/strconv.go | 23 + src/tool/run/packages/strings.go | 57 + src/tool/run/packages/stringsGo110.go | 16 + src/tool/run/packages/stringsNotGo110.go | 5 + src/tool/run/packages/sync.go | 23 + src/tool/run/packages/syncGo19.go | 14 + src/tool/run/packages/syncNotGo19.go | 5 + src/tool/run/packages/time.go | 75 + src/tool/run/packages/timeGo110.go | 14 + src/tool/run/packages/timeGo18.go | 14 + src/tool/run/packages/timeNotGo110.go | 5 + src/tool/run/packages/timeNotGo18.go | 5 + src/tool/run/parser/Makefile | 5 + src/tool/run/parser/lexer.go | 653 +++++ src/tool/run/parser/parser.go | 2483 +++++++++++++++++ src/tool/run/parser/parser.go.y | 1089 ++++++++ src/tool/run/vm/doc.go | 2 + src/tool/run/vm/example_containers_test.go | 259 ++ src/tool/run/vm/example_functions_test.go | 184 ++ src/tool/run/vm/example_operators_test.go | 385 +++ src/tool/run/vm/example_packages_test.go | 131 + src/tool/run/vm/example_test.go | 231 ++ src/tool/run/vm/main_test.go | 268 ++ src/tool/run/vm/packagesGo110_test.go | 18 + src/tool/run/vm/packages_test.go | 209 ++ src/tool/run/vm/vm.go | 458 +++ src/tool/run/vm/vmContainers_test.go | 1926 +++++++++++++ src/tool/run/vm/vmConvertToX.go | 206 ++ src/tool/run/vm/vmConvertToXGo112.go | 37 + src/tool/run/vm/vmConvertToXNotGo112.go | 38 + src/tool/run/vm/vmExpr.go | 761 +++++ src/tool/run/vm/vmExprFunction.go | 478 ++++ src/tool/run/vm/vmFunctions_test.go | 863 ++++++ src/tool/run/vm/vmLetExpr.go | 382 +++ src/tool/run/vm/vmOperator.go | 228 ++ src/tool/run/vm/vmOperators_test.go | 1073 +++++++ src/tool/run/vm/vmStmt.go | 803 ++++++ src/tool/run/vm/vmToX.go | 178 ++ src/tool/run/vm/vm_Go19_test.go | 17 + src/tool/run/vm/vm_NotGo19_test.go | 17 + src/tool/run/vm/vm_test.go | 1268 +++++++++ 140 files changed, 21692 insertions(+) create mode 100644 src/tool/run/.github/FUNDING.yml create mode 100644 src/tool/run/.travis.yml create mode 100644 src/tool/run/LICENSE create mode 100644 src/tool/run/README.md create mode 100644 src/tool/run/_example/scripts/anonymous-call.ank create mode 100644 src/tool/run/_example/scripts/chan.ank create mode 100644 src/tool/run/_example/scripts/env.ank create mode 100644 src/tool/run/_example/scripts/example.ank create mode 100644 src/tool/run/_example/scripts/exec.ank create mode 100644 src/tool/run/_example/scripts/fib-for.ank create mode 100644 src/tool/run/_example/scripts/fib-recursion.ank create mode 100644 src/tool/run/_example/scripts/for-break-continue.ank create mode 100644 src/tool/run/_example/scripts/http.ank create mode 100644 src/tool/run/_example/scripts/module.ank create mode 100644 src/tool/run/_example/scripts/regexp.ank create mode 100644 src/tool/run/_example/scripts/server.ank create mode 100644 src/tool/run/_example/scripts/signal.ank create mode 100644 src/tool/run/_example/scripts/slice.ank create mode 100644 src/tool/run/_example/scripts/socket.ank create mode 100644 src/tool/run/_example/scripts/toType.ank create mode 100644 src/tool/run/_example/scripts/try-catch.ank create mode 100644 src/tool/run/_example/scripts/url.ank create mode 100644 src/tool/run/_example/scripts/z-combinator.ank create mode 100644 src/tool/run/anko.go create mode 100644 src/tool/run/anko.png create mode 100644 src/tool/run/anko_test.go create mode 100644 src/tool/run/ast/ast.go create mode 100644 src/tool/run/ast/astutil/walk.go create mode 100644 src/tool/run/ast/astutil/walk_test.go create mode 100644 src/tool/run/ast/doc.go create mode 100644 src/tool/run/ast/expr.go create mode 100644 src/tool/run/ast/operator.go create mode 100644 src/tool/run/ast/pos.go create mode 100644 src/tool/run/ast/stmt.go create mode 100644 src/tool/run/cmd/anko-package-gen/main.go create mode 100644 src/tool/run/core/core.go create mode 100644 src/tool/run/core/testdata/broken.ank create mode 100644 src/tool/run/core/testdata/chan.ank create mode 100644 src/tool/run/core/testdata/core_test.go create mode 100644 src/tool/run/core/testdata/error.ank create mode 100644 src/tool/run/core/testdata/for.ank create mode 100644 src/tool/run/core/testdata/func.ank create mode 100644 src/tool/run/core/testdata/if.ank create mode 100644 src/tool/run/core/testdata/len.ank create mode 100644 src/tool/run/core/testdata/let.ank create mode 100644 src/tool/run/core/testdata/op.ank create mode 100644 src/tool/run/core/testdata/sort.ank create mode 100644 src/tool/run/core/testdata/switch.ank create mode 100644 src/tool/run/core/testdata/test.ank create mode 100644 src/tool/run/core/testdata/testing.ank create mode 100644 src/tool/run/core/testdata/toBytes.ank create mode 100644 src/tool/run/core/testdata/toRunes.ank create mode 100644 src/tool/run/core/testdata/toString.ank create mode 100644 src/tool/run/core/testdata/toX_test.go create mode 100644 src/tool/run/core/toX.go create mode 100644 src/tool/run/env/env.go create mode 100644 src/tool/run/env/envExternalLookup_test.go create mode 100644 src/tool/run/env/envTypes.go create mode 100644 src/tool/run/env/envTypes_test.go create mode 100644 src/tool/run/env/envValues.go create mode 100644 src/tool/run/env/envValues_test.go create mode 100644 src/tool/run/env/env_test.go create mode 100644 src/tool/run/misc/vim/ftdetect/ank.vim create mode 100644 src/tool/run/misc/vim/ftplugin/anko/comment.vim create mode 100644 src/tool/run/misc/vim/ftplugin/anko/play.vim create mode 100644 src/tool/run/misc/vim/syntax/anko.vim create mode 100644 src/tool/run/misc/wasm/anko.go create mode 100644 src/tool/run/misc/wasm/index.html create mode 100644 src/tool/run/misc/wasm/wasm_exec.js create mode 100644 src/tool/run/packages/bytes.go create mode 100644 src/tool/run/packages/bytesGo17.go create mode 100644 src/tool/run/packages/bytesNotGo17.go create mode 100644 src/tool/run/packages/encoding.json.go create mode 100644 src/tool/run/packages/errors.go create mode 100644 src/tool/run/packages/flag.go create mode 100644 src/tool/run/packages/fmt.go create mode 100644 src/tool/run/packages/io.go create mode 100644 src/tool/run/packages/io.ioutil.go create mode 100644 src/tool/run/packages/log.go create mode 100644 src/tool/run/packages/math.big.go create mode 100644 src/tool/run/packages/math.go create mode 100644 src/tool/run/packages/math.rand.go create mode 100644 src/tool/run/packages/net.go create mode 100644 src/tool/run/packages/net.http.cookiejar.go create mode 100644 src/tool/run/packages/net.http.go create mode 100644 src/tool/run/packages/net.url.go create mode 100644 src/tool/run/packages/os.exec.go create mode 100644 src/tool/run/packages/os.go create mode 100644 src/tool/run/packages/os.signal.go create mode 100644 src/tool/run/packages/osAppEngine.go create mode 100644 src/tool/run/packages/osNotAppEngine.go create mode 100644 src/tool/run/packages/path.filepath.go create mode 100644 src/tool/run/packages/path.go create mode 100644 src/tool/run/packages/regexp.go create mode 100644 src/tool/run/packages/runtime.go create mode 100644 src/tool/run/packages/sort.go create mode 100644 src/tool/run/packages/sortGo18.go create mode 100644 src/tool/run/packages/sortNotGo18.go create mode 100644 src/tool/run/packages/strconv.go create mode 100644 src/tool/run/packages/strings.go create mode 100644 src/tool/run/packages/stringsGo110.go create mode 100644 src/tool/run/packages/stringsNotGo110.go create mode 100644 src/tool/run/packages/sync.go create mode 100644 src/tool/run/packages/syncGo19.go create mode 100644 src/tool/run/packages/syncNotGo19.go create mode 100644 src/tool/run/packages/time.go create mode 100644 src/tool/run/packages/timeGo110.go create mode 100644 src/tool/run/packages/timeGo18.go create mode 100644 src/tool/run/packages/timeNotGo110.go create mode 100644 src/tool/run/packages/timeNotGo18.go create mode 100644 src/tool/run/parser/Makefile create mode 100644 src/tool/run/parser/lexer.go create mode 100644 src/tool/run/parser/parser.go create mode 100644 src/tool/run/parser/parser.go.y create mode 100644 src/tool/run/vm/doc.go create mode 100644 src/tool/run/vm/example_containers_test.go create mode 100644 src/tool/run/vm/example_functions_test.go create mode 100644 src/tool/run/vm/example_operators_test.go create mode 100644 src/tool/run/vm/example_packages_test.go create mode 100644 src/tool/run/vm/example_test.go create mode 100644 src/tool/run/vm/main_test.go create mode 100644 src/tool/run/vm/packagesGo110_test.go create mode 100644 src/tool/run/vm/packages_test.go create mode 100644 src/tool/run/vm/vm.go create mode 100644 src/tool/run/vm/vmContainers_test.go create mode 100644 src/tool/run/vm/vmConvertToX.go create mode 100644 src/tool/run/vm/vmConvertToXGo112.go create mode 100644 src/tool/run/vm/vmConvertToXNotGo112.go create mode 100644 src/tool/run/vm/vmExpr.go create mode 100644 src/tool/run/vm/vmExprFunction.go create mode 100644 src/tool/run/vm/vmFunctions_test.go create mode 100644 src/tool/run/vm/vmLetExpr.go create mode 100644 src/tool/run/vm/vmOperator.go create mode 100644 src/tool/run/vm/vmOperators_test.go create mode 100644 src/tool/run/vm/vmStmt.go create mode 100644 src/tool/run/vm/vmToX.go create mode 100644 src/tool/run/vm/vm_Go19_test.go create mode 100644 src/tool/run/vm/vm_NotGo19_test.go create mode 100644 src/tool/run/vm/vm_test.go diff --git a/src/cmd/goblin/main.go b/src/cmd/goblin/main.go index 258ab22..fc66c32 100644 --- a/src/cmd/goblin/main.go +++ b/src/cmd/goblin/main.go @@ -29,6 +29,7 @@ import ( "github.com/surdeus/goblin/src/tool/wc" "github.com/surdeus/goblin/src/tool/whoami" "github.com/surdeus/goblin/src/tool/yes" + "github.com/surdeus/goblin/src/tool/run" "github.com/surdeus/gomtool/src/mtool" ) @@ -74,6 +75,11 @@ func main() { "link files", "", }, + "run": mtool.Tool{ + run.Run, + "run anko script", + "", + }, } mtool.Main("goblin", tools) diff --git a/src/tool/run/.github/FUNDING.yml b/src/tool/run/.github/FUNDING.yml new file mode 100644 index 0000000..d0701d4 --- /dev/null +++ b/src/tool/run/.github/FUNDING.yml @@ -0,0 +1,8 @@ +# These are supported funding model platforms + +github: mattn # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: mattn # Replace with a single Patreon username +open_collective: mattn # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +custom: # Replace with a single custom sponsorship URL diff --git a/src/tool/run/.travis.yml b/src/tool/run/.travis.yml new file mode 100644 index 0000000..0e000e9 --- /dev/null +++ b/src/tool/run/.travis.yml @@ -0,0 +1,22 @@ +language: go + +go: + - 1.8.x + - 1.9.x + - 1.10.x + - 1.11.x + - 1.12.x + - 1.13.x + - 1.14.x + +env: + secure: "ELC4rD8nn2l5T48WYbTfcbwGGBmNxl7LAu05hgx5AB9/KA+oD3oBKIJkZqD512gJ31Gtyla/hG9QOgU7LikfWdpGuJjVILy01ZqtgP5SSKsrTdlln1D5pK1ZyHJNrEPevb3W5PYn9ahHnjKGtpobXj4/E0sCXfRPH67jv9hffYs=" + +before_install: + - go get -u github.com/haya14busa/goverage + +script: + - goverage -v -coverprofile=coverage.txt -covermode=count ./vm ./env . ./ast/astutil + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/src/tool/run/LICENSE b/src/tool/run/LICENSE new file mode 100644 index 0000000..252f04a --- /dev/null +++ b/src/tool/run/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2018 Yasuhiro Matsumoto, http://mattn.kaoriya.net + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/tool/run/README.md b/src/tool/run/README.md new file mode 100644 index 0000000..b785465 --- /dev/null +++ b/src/tool/run/README.md @@ -0,0 +1,155 @@ +# Anko + +[![GoDoc Reference](https://godoc.org/github.com/surdeus/goblin/src/tool/run/vm?status.svg)](http://godoc.org/github.com/surdeus/goblin/src/tool/run/vm) +[![Build Status](https://travis-ci.org/mattn/anko.svg?branch=master)](https://travis-ci.org/mattn/anko) +[![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) +[![Go Report Card](https://goreportcard.com/badge/github.com/surdeus/goblin/src/tool/run)](https://goreportcard.com/report/github.com/surdeus/goblin/src/tool/run) + +Anko is a scriptable interpreter written in Go. + +![](https://raw.githubusercontent.com/mattn/anko/master/anko.png) + +(Picture licensed under CC BY-SA 3.0, photo by Ocdp) + + +## Usage Example - Embedded + +```go +package main + +import ( + "fmt" + "log" + + "github.com/surdeus/goblin/src/tool/run/env" + "github.com/surdeus/goblin/src/tool/run/vm" +) + +func main() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("Define error: %v\n", err) + } + + script := ` +println("Hello World :)") +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("Execute error: %v\n", err) + } + + // output: Hello World :) +} +``` + +More examples are located in the GoDoc: + +https://godoc.org/github.com/surdeus/goblin/src/tool/run/vm + + +## Usage Example - Command Line + +### Building +``` +go get github.com/surdeus/goblin/src/tool/run +go install github.com/surdeus/goblin/src/tool/run +``` + +### Running an Anko script file named script.ank +``` +./anko script.ank +``` + +## Anko Script Quick Start +``` +// declare variables +x = 1 +y = x + 1 + +// print using outside the script defined println function +println(x + y) // 3 + +// if else statement +if x < 1 || y < 1 { + println(x) +} else if x < 1 && y < 1 { + println(y) +} else { + println(x + y) +} + +// slice +a = []interface{1, 2, 3} +println(a) // [1 2 3] +println(a[0]) // 1 + +// map +a = map[interface]interface{"x": 1} +println(a) // map[x:1] +a.b = 2 +a["c"] = 3 +println(a["b"]) // 2 +println(a.c) // 3 + +// struct +a = make(struct { + A int64, + B float64 +}) +a.A = 4 +a.B = 5.5 +println(a.A) // 4 +println(a.B) // 5.5 + +// function +func a (x) { + println(x + 1) +} +a(5) // 6 +``` + + +## Please note that the master branch is not stable + +The master branch language and API may change at any time. + +To mitigate breaking changes, please use tagged branches. New tagged branches will be created for breaking changes. + + +## Author + +Yasuhiro Matsumoto (a.k.a mattn) + +## Contributors + +### Code Contributors + +This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. + + +### Financial Contributors + +Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/mattn-anko/contribute)] + +#### Individuals + + + +#### Organizations + +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)] + + + + + + + + + + + diff --git a/src/tool/run/_example/scripts/anonymous-call.ank b/src/tool/run/_example/scripts/anonymous-call.ank new file mode 100644 index 0000000..df73133 --- /dev/null +++ b/src/tool/run/_example/scripts/anonymous-call.ank @@ -0,0 +1,9 @@ +#!anko + +func(x) { + return func(y) { + x(y) + } +}(func(z) { + println("Yay!", z) +})("hello world") diff --git a/src/tool/run/_example/scripts/chan.ank b/src/tool/run/_example/scripts/chan.ank new file mode 100644 index 0000000..18d6e78 --- /dev/null +++ b/src/tool/run/_example/scripts/chan.ank @@ -0,0 +1,13 @@ +#!anko + +c = make(chan int64) + +go func() { + c <- 1 + c <- 2 + c <- 3 +}() + +println(<-c) +println(<-c) +println(<-c) diff --git a/src/tool/run/_example/scripts/env.ank b/src/tool/run/_example/scripts/env.ank new file mode 100644 index 0000000..b98b7cc --- /dev/null +++ b/src/tool/run/_example/scripts/env.ank @@ -0,0 +1,9 @@ +#!anko + +var os, runtime = import("os"), import("runtime") + +if runtime.GOOS == "windows" { + println(os.Getenv("USERPROFILE")) +} else { + println(os.Getenv("HOME")) +} diff --git a/src/tool/run/_example/scripts/example.ank b/src/tool/run/_example/scripts/example.ank new file mode 100644 index 0000000..77faad9 --- /dev/null +++ b/src/tool/run/_example/scripts/example.ank @@ -0,0 +1,70 @@ +#!anko + +# declare function +func foo(x){ + return x + 1 +} + +func bar(x ...){ + return len(x) +} + +# declare variables +x = 1 +y = x + 1 + +# print values +println(x * (y + 2 * x + foo(x) / 2)) + +# if/else condition +if foo(y) >= 1 { + println("こんにちわ世界") +} else { + println("Hello, World") +} + +# array type +a = [1,2,3] +println(a) +println(a[2]) +println(len(a)) + +# map type +m = {"foo": "bar", "bar": "baz"} +for k in keys(m) { + println(m[k]) +} + +f = func(a) { + println(a) +} + +f("あんこ") + +f = func(a ...) { + println(a) +} + +f("あんこ", "だいすき") + +println(1 && 2) + +println(bar(1,2,3)) +println("foo") +println(toByteSlice("あいう")) +println(toRuneSlice("あいう")) + +a = 1 +func foo() { + a = 2 +} +foo() +println(a) + +module Foo { + func bar1() { + println("Foo.bar1") + } +} + +println(Foo.bar1()) diff --git a/src/tool/run/_example/scripts/exec.ank b/src/tool/run/_example/scripts/exec.ank new file mode 100644 index 0000000..45b3988 --- /dev/null +++ b/src/tool/run/_example/scripts/exec.ank @@ -0,0 +1,7 @@ +#!anko + +var os, exec = import("os"), import("os/exec") + +cmd = exec.Command("ls", "-la") +cmd.Stdout = os.Stdout +cmd.Run() diff --git a/src/tool/run/_example/scripts/fib-for.ank b/src/tool/run/_example/scripts/fib-for.ank new file mode 100644 index 0000000..e4d8b19 --- /dev/null +++ b/src/tool/run/_example/scripts/fib-for.ank @@ -0,0 +1,15 @@ +#!anko + +func fib(n) { + a, b = 1, 1 + f = [] + for i in range(n) { + f += a + b += a + a = b - a + } + return f +} + + +println(fib(20)) diff --git a/src/tool/run/_example/scripts/fib-recursion.ank b/src/tool/run/_example/scripts/fib-recursion.ank new file mode 100644 index 0000000..01cbab0 --- /dev/null +++ b/src/tool/run/_example/scripts/fib-recursion.ank @@ -0,0 +1,14 @@ +#!anko + +func fib(n) { + if n == 1 { + return [1] + } else if n == 2 { + return [1,1] + } else { + t = fib(n-1) + return t + (t[len(t)-1] + t[len(t)-2]) + } +} + +println(fib(20)) diff --git a/src/tool/run/_example/scripts/for-break-continue.ank b/src/tool/run/_example/scripts/for-break-continue.ank new file mode 100644 index 0000000..2f5185a --- /dev/null +++ b/src/tool/run/_example/scripts/for-break-continue.ank @@ -0,0 +1,12 @@ +#!anko + +for i in [1,2,3,4,5] { + if i == 2 { + continue + } + println(i) + if i > 3 { + break + } + println("foo") +} diff --git a/src/tool/run/_example/scripts/http.ank b/src/tool/run/_example/scripts/http.ank new file mode 100644 index 0000000..eaa62ad --- /dev/null +++ b/src/tool/run/_example/scripts/http.ank @@ -0,0 +1,8 @@ +#!anko + +var http, ioutil = import("net/http"), import("io/ioutil") + +r = http.DefaultClient.Get("http://golang.org/") +b, _ = ioutil.ReadAll(r[0].Body) +printf("%s", toString(b)) +r[0].Body.Close() diff --git a/src/tool/run/_example/scripts/module.ank b/src/tool/run/_example/scripts/module.ank new file mode 100644 index 0000000..2a17d90 --- /dev/null +++ b/src/tool/run/_example/scripts/module.ank @@ -0,0 +1,10 @@ +#!anko + +module Foo { + func bar1() { + println("Foo.bar1") + return 1 + } +} + +println(Foo.bar1()) diff --git a/src/tool/run/_example/scripts/regexp.ank b/src/tool/run/_example/scripts/regexp.ank new file mode 100644 index 0000000..27e2e65 --- /dev/null +++ b/src/tool/run/_example/scripts/regexp.ank @@ -0,0 +1,8 @@ +#!anko + +var regexp = import("regexp") + +for s in regexp.MustCompile(`[\s_]`).Split("foo_bar_baz", -1) { + println(s) +} + diff --git a/src/tool/run/_example/scripts/server.ank b/src/tool/run/_example/scripts/server.ank new file mode 100644 index 0000000..1a7cfc7 --- /dev/null +++ b/src/tool/run/_example/scripts/server.ank @@ -0,0 +1,8 @@ +#!anko + +var http = import("net/http") + +http.HandleFunc("/", func(w, r) { + w.Write(toByteSlice("hello world")) +}) +http.ListenAndServe(":8080", nil) diff --git a/src/tool/run/_example/scripts/signal.ank b/src/tool/run/_example/scripts/signal.ank new file mode 100644 index 0000000..ccd64c5 --- /dev/null +++ b/src/tool/run/_example/scripts/signal.ank @@ -0,0 +1,14 @@ +#!anko + +var os, signal, time = import("os"), import("os/signal"), import("time") + +c = make(chan os.Signal, 1) +signal.Notify(c, os.Interrupt) +go func() { + <-c + println("CTRL-C") + os.Exit(0) +}() + +d, _ = time.ParseDuration("10s") +time.Sleep(d) diff --git a/src/tool/run/_example/scripts/slice.ank b/src/tool/run/_example/scripts/slice.ank new file mode 100644 index 0000000..3216ffb --- /dev/null +++ b/src/tool/run/_example/scripts/slice.ank @@ -0,0 +1,10 @@ +#!anko + +a = make([]int64, 5) + +for i = 0; i < len(a); i++ { + a[i] = i +} +for i in a { + println(i) +} diff --git a/src/tool/run/_example/scripts/socket.ank b/src/tool/run/_example/scripts/socket.ank new file mode 100644 index 0000000..5e4c3f6 --- /dev/null +++ b/src/tool/run/_example/scripts/socket.ank @@ -0,0 +1,26 @@ +#!anko + +var os, net, url, ioutil = import("os"), import("net"), import("net/url"), import("io/ioutil"); + +func connect(uri) { + proxy = os.Getenv("http_proxy") + if proxy != "" { + u, e = url.Parse(proxy) + if e != nil { + return nil, e + } + return net.Dial("tcp", u.Host) + } + return net.Dial("tcp", uri) +} + +c, e = connect("www.google.com:80") +if e != nil { + throw e +} +c.Write(toByteSlice("GET http://www.google.com/ HTTP/1.0\r\n\r\n")) +b, e = ioutil.ReadAll(c) +if e != nil { + throw e +} +printf("%s", b) diff --git a/src/tool/run/_example/scripts/toType.ank b/src/tool/run/_example/scripts/toType.ank new file mode 100644 index 0000000..a3d0a60 --- /dev/null +++ b/src/tool/run/_example/scripts/toType.ank @@ -0,0 +1,123 @@ +#!anko + +# toInt with ints, floats, strings, bools +println("\ntoInt examples:\n===============") +i = 1<<63 - 1 +println("int", i, "toInt:", toInt(i)) + +i = -1 << 63 +println("int", i, "toInt:", toInt(i)) + +f = 3.141592653589793 +println("float", f, "toInt:", toInt(f)) + +f = 1.797693134862315708145274237317043567981e18 +println("float", f, "toInt:", toInt(f)) + +f = -1.797693134862315708145274237317043567981e18 +println("float", f, "toInt:", toInt(f)) + +s = "4611686018427387904" +println("string", s, "toInt:", toInt(s)) + +s = "-9223372036854775808" +println("string", s, "toInt:", toInt(s)) + +s = "3.141592653589793" +println("string", s, "toInt:", toInt(s)) + +s = "1.797693134862315708145274237317043567981e18" +println("string", s, "toInt:", toInt(s)) + +s = "-1.797693134862315708145274237317043567981e18" +println("string", s, "toInt:", toInt(s)) + +s = "1.797693134862315708145274237317043567981e-18" +println("string", s, "toInt:", toInt(s)) + +b = true +println("bool", b, "toInt:", toInt(b)) + +b = false +println("bool", b, "toInt:", toInt(b)) + +println("\ntoFloat examples:\n=================") +i = 1<<63 - 1 +println("int", i, "toFloat:", toFloat(i)) + +i = -1 << 63 +println("int", i, "toFloat:", toFloat(i)) + +s = "4611686018427387904" +println("string", s, "toFloat:", toFloat(s)) + +s = "-9223372036854775808" +println("string", s, "toFloat:", toFloat(s)) + +s = "3.141592653589793" +println("string", s, "toFloat:", toFloat(s)) + +s = "1.797693134862315708145274237317043567981e18" +println("string", s, "toFloat:", toFloat(s)) + +s = "-1.797693134862315708145274237317043567981e18" +println("string", s, "toFloat:", toFloat(s)) + +s = "1.797693134862315708145274237317043567981e-18" +println("string", s, "toFloat:", toFloat(s)) + +b = true +println("bool", b, "toFloat:", toFloat(b)) + +b = false +println("bool", b, "toFloat:", toFloat(b)) + +println("\ntoBool examples:\n================") +i = 1 +println("int", i, "toBool:", toBool(i)) + +i = 0 +println("int", i, "toBool:", toBool(i)) + +i = -1 +println("int", i, "toBool:", toBool(i)) + +f = 1.0 +println("float", f, "toBool:", toBool(f)) + +f = 0.000000000001 +println("float", f, "toBool:", toBool(f)) + +f = 0.0 +println("float", f, "toBool:", toBool(f)) + +f = -0.0 +println("float", f, "toBool:", toBool(f)) + +s = "y" +println("string", s, "toBool:", toBool(s)) + +s = "yEs" +println("string", s, "toBool:", toBool(s)) + +s = "t" +println("string", s, "toBool:", toBool(s)) + +s = "TrUe" +println("string", s, "toBool:", toBool(s)) + +s = "1" +println("string", s, "toBool:", toBool(s)) + +s = "0" +println("string", s, "toBool:", toBool(s)) + +s = "f" +println("string", s, "toBool:", toBool(s)) + +s = "FaLsE" +println("string", s, "toBool:", toBool(s)) + +s = "foobar" +println("string", s, "toBool:", toBool(s)) + diff --git a/src/tool/run/_example/scripts/try-catch.ank b/src/tool/run/_example/scripts/try-catch.ank new file mode 100644 index 0000000..80029b3 --- /dev/null +++ b/src/tool/run/_example/scripts/try-catch.ank @@ -0,0 +1,19 @@ +#!anko + +var http = import("net/http") + +try { + http.Do() +} catch { + println("catch!") +} finally { + println("finally!") +} + +try { + http.Do() +} catch e { + println("catch!", e) +} finally { + println("finally!") +} diff --git a/src/tool/run/_example/scripts/url.ank b/src/tool/run/_example/scripts/url.ank new file mode 100644 index 0000000..4454fc8 --- /dev/null +++ b/src/tool/run/_example/scripts/url.ank @@ -0,0 +1,7 @@ +#!anko + +var url = import("net/url") + +u, _ = url.Parse("http://www.google.com/search?q=こんにちわ世界") +println(u.Path) +println(u.Host) diff --git a/src/tool/run/_example/scripts/z-combinator.ank b/src/tool/run/_example/scripts/z-combinator.ank new file mode 100644 index 0000000..5d61304 --- /dev/null +++ b/src/tool/run/_example/scripts/z-combinator.ank @@ -0,0 +1,15 @@ +#!anko + +func Z(f) { + return (func(x) { + return f(func(y) { + return x(x)(y) + }) + })(func(x) { + return f(func(y) { + return x(x)(y) + }) + }) +} + +println(Z(func(f) { return func(n) { return n == 0 ? 1 : n * f(n - 1) } })(5) == 120) diff --git a/src/tool/run/anko.go b/src/tool/run/anko.go new file mode 100644 index 0000000..84fbebe --- /dev/null +++ b/src/tool/run/anko.go @@ -0,0 +1,172 @@ +// +build !appengine + +package run + +import ( + "bufio" + //"flag" + "fmt" + "io" + "io/ioutil" + "os" + "strings" + + "github.com/surdeus/goblin/src/tool/run/core" + "github.com/surdeus/goblin/src/tool/run/env" + _ "github.com/surdeus/goblin/src/tool/run/packages" + "github.com/surdeus/goblin/src/tool/run/parser" + "github.com/surdeus/goblin/src/tool/run/vm" + "github.com/surdeus/gomtool/src/mtool" +) + +const version = "0.1.8" + +var ( + flagExecute string + file string + args []string + e *env.Env + flag *mtool.Flags +) + +func Run(flagSet *mtool.Flags) { + var exitCode int + + flag = flagSet + + parseFlags() + setupEnv() + if flagExecute != "" || flag.NArg() > 0 { + exitCode = runNonInteractive() + } else { + exitCode = runInteractive() + } + + os.Exit(exitCode) +} + +func parseFlags() { + flagVersion := flag.Bool("v", false, "prints out the version and then exits") + flag.StringVar(&flagExecute, "e", "", "execute the Anko code") + flag.Parse() + + if *flagVersion { + fmt.Println(version) + os.Exit(0) + } + + if flagExecute != "" || flag.NArg() < 1 { + args = flag.Args() + return + } + + file = flag.Arg(0) + args = flag.Args()[1:] +} + +func setupEnv() { + e = env.NewEnv() + e.Define("args", args) + core.Import(e) +} + +func runNonInteractive() int { + var source string + if flagExecute != "" { + source = flagExecute + } else { + sourceBytes, err := ioutil.ReadFile(file) + if err != nil { + fmt.Println("ReadFile error:", err) + return 2 + } + source = string(sourceBytes) + } + + _, err := vm.Execute(e, nil, source) + if err != nil { + fmt.Println("Execute error:", err) + return 4 + } + + return 0 +} + +func runInteractive() int { + var following bool + var source string + scanner := bufio.NewScanner(os.Stdin) + + parser.EnableErrorVerbose() + + for { + if following { + source += "\n" + fmt.Print(" ") + } else { + fmt.Print("> ") + } + + if !scanner.Scan() { + break + } + source += scanner.Text() + if source == "" { + continue + } + if source == "quit()" { + break + } + + stmts, err := parser.ParseSrc(source) + + if e, ok := err.(*parser.Error); ok { + es := e.Error() + if strings.HasPrefix(es, "syntax error: unexpected") { + if strings.HasPrefix(es, "syntax error: unexpected $end,") { + following = true + continue + } + } else { + if e.Pos.Column == len(source) && !e.Fatal { + fmt.Fprintln(os.Stderr, e) + following = true + continue + } + if e.Error() == "unexpected EOF" { + following = true + continue + } + } + } + + following = false + source = "" + var v interface{} + + if err == nil { + v, err = vm.Run(e, nil, stmts) + } + if err != nil { + if e, ok := err.(*vm.Error); ok { + fmt.Fprintf(os.Stderr, "%d:%d %s\n", e.Pos.Line, e.Pos.Column, err) + } else if e, ok := err.(*parser.Error); ok { + fmt.Fprintf(os.Stderr, "%d:%d %s\n", e.Pos.Line, e.Pos.Column, err) + } else { + fmt.Fprintln(os.Stderr, err) + } + continue + } + + fmt.Printf("%#v\n", v) + } + + if err := scanner.Err(); err != nil { + if err != io.EOF { + fmt.Fprintln(os.Stderr, "ReadString error:", err) + return 12 + } + } + + return 0 +} diff --git a/src/tool/run/anko.png b/src/tool/run/anko.png new file mode 100644 index 0000000000000000000000000000000000000000..44052a85fce02919afd7326baf71167e6f864272 GIT binary patch literal 363243 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 z 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 z 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 literal 0 HcmV?d00001 diff --git a/src/tool/run/anko_test.go b/src/tool/run/anko_test.go new file mode 100644 index 0000000..9c7fe8a --- /dev/null +++ b/src/tool/run/anko_test.go @@ -0,0 +1,273 @@ +// +build !appengine + +package run + +import ( + "bufio" + "io" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + "time" +) + +var logger *log.Logger + +func TestMain(m *testing.M) { + parseFlags() + code := m.Run() + os.Exit(code) +} + +func TestRunNonInteractiveFile(t *testing.T) { + _, filename, _, _ := runtime.Caller(0) + testDir := filepath.Join(filepath.Dir(filename), "core", "testdata") + setupEnv() + + file = filepath.Join(testDir, "not-found.ank") + exitCode := runNonInteractive() + if exitCode != 2 { + t.Fatalf("exitCode - received: %v - expected: %v", exitCode, 2) + } + + file = filepath.Join(testDir, "broken.ank") + exitCode = runNonInteractive() + os.Args = []string{os.Args[0]} + if exitCode != 4 { + t.Fatalf("exitCode - received: %v - expected: %v", exitCode, 4) + } + + file = filepath.Join(testDir, "test.ank") + exitCode = runNonInteractive() + os.Args = []string{os.Args[0]} + if exitCode != 0 { + t.Fatalf("exitCode - received: %v - expected: %v", exitCode, 0) + } + + file = "" +} + +func TestRunNonInteractiveExecute(t *testing.T) { + setupEnv() + + flagExecute = "1 + 1" + exitCode := runNonInteractive() + if exitCode != 0 { + t.Fatalf("exitCode - received: %v - expected: %v", exitCode, 0) + } + + flagExecute = "1++" + exitCode = runNonInteractive() + if exitCode != 4 { + t.Fatalf("exitCode - received: %v - expected: %v", exitCode, 4) + } + + flagExecute = "" +} + +type testInteractive struct { + runLines []string + runOutputs []string + runError string +} + +func TestRunInteractive(t *testing.T) { + // empty strings in runOutputs will ignore read timeouts + tests := []testInteractive{ + {runLines: []string{".."}, runError: "1:1 syntax error on '.' at 1:1"}, + {runLines: []string{"1++"}, runError: "1:1 invalid operation"}, + {runLines: []string{"var , b = 1, 2"}, runError: "1:7 syntax error: unexpected ','"}, + + {runLines: []string{"", "1"}, runOutputs: []string{"", "1"}}, + {runLines: []string{"1 + 1"}, runOutputs: []string{"2"}}, + {runLines: []string{"a = 1", "b = 2", "a + b"}, runOutputs: []string{"1", "2", "3"}}, + {runLines: []string{"a = 1", "if a == 1 {", "b = 1", "b = 2", "}", "a"}, runOutputs: []string{"1", "", "", "", "2", "1"}}, + {runLines: []string{"a = 1", "for i = 0; i < 2; i++ {", "a++", "}", "a"}, runOutputs: []string{"1", "", "", "", "3"}}, + {runLines: []string{"1 + 1", "// comment 1", "2 + 2 // comment 2", "// 3 + 3"}, runOutputs: []string{"2", "", "4", ""}}, + } + runInteractiveTests(t, tests) +} + +func runInteractiveTests(t *testing.T, tests []testInteractive) { + // create logger + // Note: logger is used for debugging since real stdout cannot be used + logger = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.LUTC|log.Llongfile) + gopath := os.Getenv("GOPATH") + if gopath == "" { + b, err := exec.Command("go", "env", "GOPATH").CombinedOutput() + if err != nil { + t.Fatal(err) + } + gopath = strings.TrimSpace(string(b)) + } + filehandle, err := os.OpenFile(filepath.Join(gopath, "bin", "anko_test.log"), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + t.Fatal("OpenFile error:", err) + } + defer filehandle.Close() + logger.SetOutput(filehandle) + logger.Print("logger file created") + + // defer sending std back to real + realStdin := os.Stdin + realStderr := os.Stderr + realStdout := os.Stdout + defer setStd(realStdin, realStderr, realStdout) + + // create pipes + readFromIn, writeToIn, err := os.Pipe() + if err != nil { + t.Fatal("Pipe error:", err) + } + os.Stdin = readFromIn + logger.Print("pipe in created") + readFromErr, writeToErr, err := os.Pipe() + if err != nil { + t.Fatal("Pipe error:", err) + } + os.Stderr = writeToErr + logger.Print("pipe err created") + readFromOut, writeToOut, err := os.Pipe() + if err != nil { + t.Fatal("Pipe error:", err) + } + os.Stdout = writeToOut + logger.Print("pipe out created") + + // setup reader + readerErr := bufio.NewReaderSize(readFromErr, 256) + readerOut := bufio.NewReaderSize(readFromOut, 256) + chanQuit := make(chan struct{}, 1) + chanErr := make(chan string, 3) + chanOut := make(chan string, 3) + readTimeout := 10 * time.Millisecond + var dataErr string + var dataOut string + + go readerToChan(t, chanQuit, readerErr, chanErr) + go readerToChan(t, chanQuit, readerOut, chanOut) + + go runInteractive() + + time.Sleep(readTimeout) + + // basic read and write to make sure things are working + _, err = writeToIn.WriteString("1\n") + if err != nil { + t.Fatal("Stdin WriteString error:", err) + } + select { + case dataOut = <-chanOut: + if len(dataOut) > 0 && dataOut[0] == '>' { + dataOut = dataOut[1:] + dataOut = strings.TrimSpace(dataOut) + } + if dataOut != "1" { + t.Fatalf("Stdout - received: %v - expected: %v - basic test", dataOut, "1") + } + case dataErr = <-chanErr: + dataErr = strings.TrimSpace(dataErr) + if dataErr != "" { + t.Fatalf("Stderr - received: %v - expected: %v - basic test", dataErr, "") + } + case <-time.After(readTimeout): + t.Fatal("read timeout for basic test") + } + + // run tests + logger.Print("running tests start") + for _, test := range tests { + + for i, runLine := range test.runLines { + + _, err = writeToIn.WriteString(runLine + "\n") + if err != nil { + t.Fatal("Stdin WriteString error:", err) + } + + select { + case <-time.After(readTimeout): + if test.runOutputs[i] != "" { + t.Fatalf("read timeout for i: %v - runLines: %v", i, test.runLines) + } + case dataOut = <-chanOut: + for len(dataOut) > 0 && dataOut[0] == '>' { + dataOut = dataOut[1:] + dataOut = strings.TrimSpace(dataOut) + } + if dataOut != test.runOutputs[i] { + t.Fatalf("Stdout - received: %v - expected: %v - i: %v - runLines: %v", dataOut, test.runOutputs[i], i, test.runLines) + } + case dataErr = <-chanErr: + dataErr = strings.TrimSpace(dataErr) + if dataErr != test.runError { + t.Fatalf("Stderr - received: %v - expected: %v - i: %v - runLines: %v", dataErr, test.runError, i, test.runLines) + } + + // to clean output from error + _, err = writeToIn.WriteString("1\n") + if err != nil { + t.Fatal("Stdin WriteString error:", err) + } + + select { + case dataOut = <-chanOut: + for len(dataOut) > 0 && dataOut[0] == '>' { + dataOut = dataOut[1:] + dataOut = strings.TrimSpace(dataOut) + } + if dataOut != "1" { + t.Fatalf("Stdout - received: %v - expected: %v - i: %v - runLines: %v", dataOut, test.runOutputs[i], i, test.runLines) + } + case <-time.After(readTimeout): + t.Fatalf("read timeout for i: %v - runLines: %v", i, test.runLines) + } + + } + + } + + } + logger.Print("running tests end") + + // quit + _, err = writeToIn.WriteString("quit()\n") + if err != nil { + t.Fatal("Stdin WriteString error:", err) + } + logger.Print("quit() sent") + + close(chanQuit) + logger.Print("chanQuit closed") + + writeToErr.Close() + writeToOut.Close() + logger.Print("pipes closed") +} + +func readerToChan(t *testing.T, chanQuit chan struct{}, reader *bufio.Reader, chanOut chan string) { + logger.Print("readerToChan start") + for { + data, err := reader.ReadString('\n') + if err != nil && err != io.EOF { + t.Fatal("readerToChan ReadString error:", err) + } + select { + case <-chanQuit: + logger.Print("readerToChan end") + return + default: + } + chanOut <- data + } +} + +func setStd(stdin *os.File, stderr *os.File, stdout *os.File) { + os.Stdin = stdin + os.Stderr = stderr + os.Stdout = stdout +} diff --git a/src/tool/run/ast/ast.go b/src/tool/run/ast/ast.go new file mode 100644 index 0000000..c2f83f7 --- /dev/null +++ b/src/tool/run/ast/ast.go @@ -0,0 +1,38 @@ +package ast + +// Token is used in the lexer to split characters into a string called a token +type Token struct { + PosImpl + Tok int + Lit string +} + +// TypeKind is the kinds of types +type TypeKind int + +const ( + // TypeDefault default type + TypeDefault TypeKind = iota + // TypePtr ptr type + TypePtr + // TypeSlice slice type + TypeSlice + // TypeMap map type + TypeMap + // TypeChan chan type + TypeChan + // TypeStructType struct type + TypeStructType +) + +// TypeStruct is the type and sub-types +type TypeStruct struct { + Kind TypeKind + Env []string + Name string + Dimensions int + SubType *TypeStruct + Key *TypeStruct + StructNames []string + StructTypes []*TypeStruct +} diff --git a/src/tool/run/ast/astutil/walk.go b/src/tool/run/ast/astutil/walk.go new file mode 100644 index 0000000..00fa54e --- /dev/null +++ b/src/tool/run/ast/astutil/walk.go @@ -0,0 +1,281 @@ +// +build !appengine + +package astutil + +import ( + "fmt" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/ast" +) + +// WalkFunc is used in Walk to walk the AST +type WalkFunc func(interface{}) error + +// Walk walks the ASTs associated with a statement list generated by parser.ParseSrc +// each expression and/or statement is passed to the WalkFunc function. +// If the WalkFunc returns an error the walk is aborted and the error is returned +func Walk(stmt ast.Stmt, f WalkFunc) error { + return walkStmt(stmt, f) +} + +func walkStmts(stmts []ast.Stmt, f WalkFunc) error { + for _, stmt := range stmts { + if err := walkStmt(stmt, f); err != nil { + return err + } + } + return nil +} + +func walkExprs(exprs []ast.Expr, f WalkFunc) error { + for _, exp := range exprs { + if err := walkExpr(exp, f); err != nil { + return err + } + } + return nil +} + +func walkStmt(stmt ast.Stmt, f WalkFunc) error { + //short circuit out if there are no functions + if stmt == nil || f == nil { + return nil + } + if err := callFunc(stmt, f); err != nil { + return err + } + switch stmt := stmt.(type) { + case *ast.StmtsStmt: + if err := walkStmts(stmt.Stmts, f); err != nil { + return err + } + case *ast.BreakStmt: + case *ast.ContinueStmt: + case *ast.LetMapItemStmt: + if err := walkExpr(stmt.RHS, f); err != nil { + return err + } + return walkExprs(stmt.LHSS, f) + case *ast.ReturnStmt: + return walkExprs(stmt.Exprs, f) + case *ast.ExprStmt: + return walkExpr(stmt.Expr, f) + case *ast.VarStmt: + return walkExprs(stmt.Exprs, f) + case *ast.LetsStmt: + if err := walkExprs(stmt.RHSS, f); err != nil { + return err + } + return walkExprs(stmt.LHSS, f) + case *ast.IfStmt: + if err := walkExpr(stmt.If, f); err != nil { + return err + } + if err := walkStmt(stmt.Then, f); err != nil { + return err + } + if err := walkStmts(stmt.ElseIf, f); err != nil { + return err + } + if err := walkStmt(stmt.Else, f); err != nil { + return err + } + case *ast.TryStmt: + if err := walkStmt(stmt.Try, f); err != nil { + return err + } + if err := walkStmt(stmt.Catch, f); err != nil { + return err + } + if err := walkStmt(stmt.Finally, f); err != nil { + return err + } + case *ast.LoopStmt: + if err := walkExpr(stmt.Expr, f); err != nil { + return err + } + if err := walkStmt(stmt.Stmt, f); err != nil { + return err + } + case *ast.ForStmt: + if err := walkExpr(stmt.Value, f); err != nil { + return err + } + if err := walkStmt(stmt.Stmt, f); err != nil { + return err + } + case *ast.CForStmt: + if err := walkStmt(stmt.Stmt1, f); err != nil { + return err + } + if err := walkExpr(stmt.Expr2, f); err != nil { + return err + } + if err := walkExpr(stmt.Expr3, f); err != nil { + return err + } + if err := walkStmt(stmt.Stmt, f); err != nil { + return err + } + case *ast.ThrowStmt: + if err := walkExpr(stmt.Expr, f); err != nil { + return err + } + case *ast.ModuleStmt: + if err := walkStmt(stmt.Stmt, f); err != nil { + return err + } + case *ast.SwitchStmt: + if err := walkExpr(stmt.Expr, f); err != nil { + return err + } + for _, switchCaseStmt := range stmt.Cases { + caseStmt := switchCaseStmt.(*ast.SwitchCaseStmt) + if err := walkStmt(caseStmt.Stmt, f); err != nil { + return err + } + } + if err := walkStmt(stmt.Default, f); err != nil { + return err + } + case *ast.GoroutineStmt: + return walkExpr(stmt.Expr, f) + default: + return fmt.Errorf("unknown statement %v", reflect.TypeOf(stmt)) + } + return nil +} + +func walkExpr(expr ast.Expr, f WalkFunc) error { + //short circuit out if there are no functions + if expr == nil || f == nil { + return nil + } + if err := callFunc(expr, f); err != nil { + return err + } + switch expr := expr.(type) { + case *ast.OpExpr: + return walkOperator(expr.Op, f) + case *ast.LenExpr: + case *ast.LiteralExpr: + case *ast.IdentExpr: + case *ast.MemberExpr: + return walkExpr(expr.Expr, f) + case *ast.ItemExpr: + if err := walkExpr(expr.Item, f); err != nil { + return err + } + return walkExpr(expr.Index, f) + case *ast.SliceExpr: + if err := walkExpr(expr.Item, f); err != nil { + return err + } + if err := walkExpr(expr.Begin, f); err != nil { + return err + } + return walkExpr(expr.End, f) + case *ast.ArrayExpr: + return walkExprs(expr.Exprs, f) + case *ast.MapExpr: + for i := range expr.Keys { + if err := walkExpr(expr.Keys[i], f); err != nil { + return err + } + if err := walkExpr(expr.Values[i], f); err != nil { + return err + } + } + case *ast.DerefExpr: + return walkExpr(expr.Expr, f) + case *ast.AddrExpr: + return walkExpr(expr.Expr, f) + case *ast.UnaryExpr: + return walkExpr(expr.Expr, f) + case *ast.ParenExpr: + return walkExpr(expr.SubExpr, f) + case *ast.FuncExpr: + return walkStmt(expr.Stmt, f) + case *ast.LetsExpr: + if err := walkExprs(expr.LHSS, f); err != nil { + return err + } + return walkExprs(expr.RHSS, f) + case *ast.AnonCallExpr: + if err := walkExpr(expr.Expr, f); err != nil { + return err + } + return walkExpr(&ast.CallExpr{Func: reflect.Value{}, SubExprs: expr.SubExprs, VarArg: expr.VarArg, Go: expr.Go}, f) + case *ast.CallExpr: + return walkExprs(expr.SubExprs, f) + case *ast.TernaryOpExpr: + if err := walkExpr(expr.Expr, f); err != nil { + return err + } + if err := walkExpr(expr.LHS, f); err != nil { + return err + } + return walkExpr(expr.RHS, f) + case *ast.ImportExpr: + return walkExpr(expr.Name, f) + case *ast.MakeExpr: + if err := walkExpr(expr.LenExpr, f); err != nil { + return err + } + return walkExpr(expr.CapExpr, f) + case *ast.ChanExpr: + if err := walkExpr(expr.RHS, f); err != nil { + return err + } + return walkExpr(expr.LHS, f) + case *ast.IncludeExpr: + if err := walkExpr(expr.ItemExpr, f); err != nil { + return err + } + return walkExpr(expr.ListExpr, f) + default: + return fmt.Errorf("unknown expression %v", reflect.TypeOf(expr)) + } + return nil +} + +func walkOperator(op ast.Operator, f WalkFunc) error { + //short circuit out if there are no functions + if op == nil || f == nil { + return nil + } + if err := callFunc(op, f); err != nil { + return err + } + switch op := op.(type) { + case *ast.BinaryOperator: + if err := walkExpr(op.LHS, f); err != nil { + return err + } + return walkExpr(op.RHS, f) + case *ast.ComparisonOperator: + if err := walkExpr(op.LHS, f); err != nil { + return err + } + return walkExpr(op.RHS, f) + case *ast.AddOperator: + if err := walkExpr(op.LHS, f); err != nil { + return err + } + return walkExpr(op.RHS, f) + case *ast.MultiplyOperator: + if err := walkExpr(op.LHS, f); err != nil { + return err + } + return walkExpr(op.RHS, f) + } + return nil +} + +func callFunc(x interface{}, f WalkFunc) error { + if x == nil || f == nil { + return nil + } + return f(x) +} diff --git a/src/tool/run/ast/astutil/walk_test.go b/src/tool/run/ast/astutil/walk_test.go new file mode 100644 index 0000000..0b979de --- /dev/null +++ b/src/tool/run/ast/astutil/walk_test.go @@ -0,0 +1,239 @@ +package astutil + +import ( + "errors" + "fmt" + "testing" + + "github.com/surdeus/goblin/src/tool/run/ast" + "github.com/surdeus/goblin/src/tool/run/parser" +) + +const ( + goodSrc string = ` +var fmt = import("fmt") + +a = "1" +b = 2 +m = {} +func testA(arg1, arg2, arg3) { + v, ok = m["foo"] + return "A" + arg1 + arg2 + arg3 +} + +func Main(arg1) { + fmt.Println("enter Main") + b = testA(1, 2, 3) + Tester() + + if b == 0 { + fmt.Println("b is 0") + } else if b == 1 { + fmt.Println("b is 1") + } else { + fmt.Println("b is other") + } + + switch arg1 { + case 0: + fmt.Println("arg0 is 0") + case 1: + fmt.Println("arg0 is 1") + default: + fmt.Println("arg0 is other") + } + + try { + throw "WTF!" + } catch e { + fmt.Println(e) + } + + for n = 0; n < 3; n++ { + if n < 2 { + continue + } + fmt.Println(n) + } + + for n in [1, 2, 3, 4, 5] { + fmt.Println(n) + if n > 3 { + break + } + } + + n = 0 + for n < 3 { + n++ + } + + a = {"foo": "bar"} + a.foo = "baz" + if a["foo"] == "zoo" { + fmt.Println("foo is zoo") + } + fmt.Println(a["foo"] == "zoo" ? "zoo" : "baz") + + c = make(chan int64) + + go func() { + c <- 1 + c <- 2 + c <- 3 + }() + + println(<-c) + println(<-c) + println(<-c) + + v = make([]int, 3) + fmt.Println("sizeof v is ", len(v)) + + x = 1 + y = (&x) + *y = 2 + fmt.Println(x) + + x, y = !x, 2 + fmt.Println(x, y) + + x = new(string) + fmt.Println(x) + + var f = func() { + return "foo" + } + x = f()[0:1] + y = f()[0] + fmt.Println(x == y ? true : false) +} + +func Tester() { + return "YES" +} + +func testLen() { + return len("test") +} + +fmt.Println(Main(1)) +` +) + +func TestWalk(t *testing.T) { + stmts, err := parser.ParseSrc(goodSrc) + if err != nil { + t.Fatal(err) + } + var mainFound bool + var lenFound bool + err = Walk(stmts, func(e interface{}) error { + switch exp := e.(type) { + case *ast.CallExpr: + switch exp.Name { + case `testA`: + if len(exp.SubExprs) != 3 { + return errors.New("invalid parameter count") + } + case `Main`: + if len(exp.SubExprs) != 1 { + return errors.New("invalid parameter count") + } + case `Tester`: + if len(exp.SubExprs) != 0 { + return errors.New("invalid parameter count") + } + } + case *ast.FuncExpr: + if !mainFound && exp.Name == `Main` { + mainFound = true + } else if mainFound && exp.Name == `Main` { + return errors.New("Main redefined") + } + case *ast.LenExpr: + lenFound = true + } + return nil + }) + if err != nil { + t.Fatal(err) + } + if !mainFound { + t.Fatal("Main not found") + } + if !lenFound { + t.Fatal("len not found") + } +} + +func Example_astWalk() { + src := ` +var fmt = import("fmt") + +func TestFunc(arg1, arg2, arg3) { + return (arg1 + arg2) * arg3 +} + +func Main() { + return TestFunc(1, 2, 3) + BuiltinFuncX(1, 2, 3) +} + +fmt.Println(Main()) + ` + stmts, err := parser.ParseSrc(src) + if err != nil { + fmt.Println("ERROR: ", err) + return + } + var mainFound bool + err = Walk(stmts, func(e interface{}) error { + switch e := e.(type) { + case *ast.CallExpr: + //check if the BuiltinFuncX is getting the right number of args + if e.Name == `BuiltinFuncX` && len(e.SubExprs) != 3 { + return errors.New("invalid number of arguments to BuiltinFuncX") + } + case *ast.FuncExpr: + if !mainFound && e.Name == `Main` { + if len(e.Params) != 0 { + return errors.New("Too many args to main") + } + mainFound = true + } else if mainFound && e.Name == `Main` { + return errors.New("Main redefined") + } + } + return nil + }) + if err != nil { + fmt.Println("ERROR: ", err) + return + } + if !mainFound { + fmt.Println("ERROR: Main not found") + } +} + +func TestBadCode(t *testing.T) { + var codes = []string{ + `const 1 = 2`, + `a["foo"] = 2, 3`, + `if a, 2 {}`, + `if break {}`, + `if a { else }`, + `if a { } else foo { }`, + `try a { } else { }`, + `try { } catch 1, 2 { }`, + `throw 1, 2`, + `for.true`, + `switch { var }`, + `case { var }`, + `v, ok = { "foo": "bar" }[const 1]`, + } + for _, code := range codes { + _, err := parser.ParseSrc(code) + if err == nil { + t.Fatalf("code %q should fail", code) + } + } +} diff --git a/src/tool/run/ast/doc.go b/src/tool/run/ast/doc.go new file mode 100644 index 0000000..8781cfc --- /dev/null +++ b/src/tool/run/ast/doc.go @@ -0,0 +1,2 @@ +// Package ast implements abstruct-syntax-tree for anko. +package ast diff --git a/src/tool/run/ast/expr.go b/src/tool/run/ast/expr.go new file mode 100644 index 0000000..939ab8f --- /dev/null +++ b/src/tool/run/ast/expr.go @@ -0,0 +1,187 @@ +package ast + +import ( + "reflect" +) + +// Expr provides all of interfaces for expression. +type Expr interface { + Pos +} + +// ExprImpl provide commonly implementations for Expr. +type ExprImpl struct { + PosImpl // PosImpl provide Pos() function. +} + +// OpExpr provide operator expression. +type OpExpr struct { + ExprImpl + Op Operator +} + +// LiteralExpr provide literal expression. +type LiteralExpr struct { + ExprImpl + Literal reflect.Value +} + +// ArrayExpr provide Array expression. +type ArrayExpr struct { + ExprImpl + Exprs []Expr + TypeData *TypeStruct +} + +// MapExpr provide Map expression. +type MapExpr struct { + ExprImpl + Keys []Expr + Values []Expr + TypeData *TypeStruct +} + +// IdentExpr provide identity expression. +type IdentExpr struct { + ExprImpl + Lit string +} + +// UnaryExpr provide unary minus expression. ex: -1, ^1, ~1. +type UnaryExpr struct { + ExprImpl + Operator string + Expr Expr +} + +// AddrExpr provide referencing address expression. +type AddrExpr struct { + ExprImpl + Expr Expr +} + +// DerefExpr provide dereferencing address expression. +type DerefExpr struct { + ExprImpl + Expr Expr +} + +// ParenExpr provide parent block expression. +type ParenExpr struct { + ExprImpl + SubExpr Expr +} + +// NilCoalescingOpExpr provide if invalid operator expression. +type NilCoalescingOpExpr struct { + ExprImpl + LHS Expr + RHS Expr +} + +// TernaryOpExpr provide ternary operator expression. +type TernaryOpExpr struct { + ExprImpl + Expr Expr + LHS Expr + RHS Expr +} + +// CallExpr provide calling expression. +type CallExpr struct { + ExprImpl + Func reflect.Value + Name string + SubExprs []Expr + VarArg bool + Go bool +} + +// AnonCallExpr provide anonymous calling expression. ex: func(){}(). +type AnonCallExpr struct { + ExprImpl + Expr Expr + SubExprs []Expr + VarArg bool + Go bool +} + +// MemberExpr provide expression to refer member. +type MemberExpr struct { + ExprImpl + Expr Expr + Name string +} + +// ItemExpr provide expression to refer Map/Array item. +type ItemExpr struct { + ExprImpl + Item Expr + Index Expr +} + +// SliceExpr provide expression to refer slice of Array. +type SliceExpr struct { + ExprImpl + Item Expr + Begin Expr + End Expr + Cap Expr +} + +// FuncExpr provide function expression. +type FuncExpr struct { + ExprImpl + Name string + Stmt Stmt + Params []string + VarArg bool +} + +// LetsExpr provide multiple expression of let. +type LetsExpr struct { + ExprImpl + LHSS []Expr + RHSS []Expr +} + +// ChanExpr provide chan expression. +type ChanExpr struct { + ExprImpl + LHS Expr + RHS Expr +} + +// ImportExpr provide expression to import packages. +type ImportExpr struct { + ExprImpl + Name Expr +} + +// MakeExpr provide expression to make instance. +type MakeExpr struct { + ExprImpl + TypeData *TypeStruct + LenExpr Expr + CapExpr Expr +} + +// MakeTypeExpr provide expression to make type. +type MakeTypeExpr struct { + ExprImpl + Name string + Type Expr +} + +// LenExpr provide expression to get length of array, map, etc. +type LenExpr struct { + ExprImpl + Expr Expr +} + +// IncludeExpr provide in expression +type IncludeExpr struct { + ExprImpl + ItemExpr Expr + ListExpr Expr +} diff --git a/src/tool/run/ast/operator.go b/src/tool/run/ast/operator.go new file mode 100644 index 0000000..b370a68 --- /dev/null +++ b/src/tool/run/ast/operator.go @@ -0,0 +1,43 @@ +package ast + +// Operator provides interfaces for operators. +type Operator interface { + Pos +} + +// OperatorImpl provides common implementations for Operator. +type OperatorImpl struct { + PosImpl // PosImpl provide Pos() function. +} + +// BinaryOperator provides binary operation. +type BinaryOperator struct { + OperatorImpl + LHS Expr + Operator string + RHS Expr +} + +// ComparisonOperator provides comparison operation. +type ComparisonOperator struct { + OperatorImpl + LHS Expr + Operator string + RHS Expr +} + +// AddOperator provides add operation. +type AddOperator struct { + OperatorImpl + LHS Expr + Operator string + RHS Expr +} + +// MultiplyOperator provides multiply operation. +type MultiplyOperator struct { + OperatorImpl + LHS Expr + Operator string + RHS Expr +} diff --git a/src/tool/run/ast/pos.go b/src/tool/run/ast/pos.go new file mode 100644 index 0000000..076fdac --- /dev/null +++ b/src/tool/run/ast/pos.go @@ -0,0 +1,28 @@ +package ast + +// Position provides interface to store code locations. +type Position struct { + Line int + Column int +} + +// Pos interface provides two functions to get/set the position for expression or statement. +type Pos interface { + Position() Position + SetPosition(Position) +} + +// PosImpl provides commonly implementations for Pos. +type PosImpl struct { + pos Position +} + +// Position return the position of the expression or statement. +func (x *PosImpl) Position() Position { + return x.pos +} + +// SetPosition is a function to specify position of the expression or statement. +func (x *PosImpl) SetPosition(pos Position) { + x.pos = pos +} diff --git a/src/tool/run/ast/stmt.go b/src/tool/run/ast/stmt.go new file mode 100644 index 0000000..e7a15a8 --- /dev/null +++ b/src/tool/run/ast/stmt.go @@ -0,0 +1,157 @@ +package ast + +// Stmt provides all of interfaces for statement. +type Stmt interface { + Pos +} + +// StmtImpl provide commonly implementations for Stmt.. +type StmtImpl struct { + PosImpl // PosImpl provide Pos() function. +} + +// StmtsStmt provides statements. +type StmtsStmt struct { + StmtImpl + Stmts []Stmt +} + +// ExprStmt provide expression statement. +type ExprStmt struct { + StmtImpl + Expr Expr +} + +// IfStmt provide "if/else" statement. +type IfStmt struct { + StmtImpl + If Expr + Then Stmt + ElseIf []Stmt // This is array of IfStmt + Else Stmt +} + +// TryStmt provide "try/catch/finally" statement. +type TryStmt struct { + StmtImpl + Try Stmt + Var string + Catch Stmt + Finally Stmt +} + +// ForStmt provide "for in" expression statement. +type ForStmt struct { + StmtImpl + Vars []string + Value Expr + Stmt Stmt +} + +// CForStmt provide C-style "for (;;)" expression statement. +type CForStmt struct { + StmtImpl + Stmt1 Stmt + Expr2 Expr + Expr3 Expr + Stmt Stmt +} + +// LoopStmt provide "for expr" expression statement. +type LoopStmt struct { + StmtImpl + Expr Expr + Stmt Stmt +} + +// BreakStmt provide "break" expression statement. +type BreakStmt struct { + StmtImpl +} + +// ContinueStmt provide "continue" expression statement. +type ContinueStmt struct { + StmtImpl +} + +// ReturnStmt provide "return" expression statement. +type ReturnStmt struct { + StmtImpl + Exprs []Expr +} + +// ThrowStmt provide "throw" expression statement. +type ThrowStmt struct { + StmtImpl + Expr Expr +} + +// ModuleStmt provide "module" expression statement. +type ModuleStmt struct { + StmtImpl + Name string + Stmt Stmt +} + +// SwitchStmt provide switch statement. +type SwitchStmt struct { + StmtImpl + Expr Expr + Cases []Stmt + Default Stmt +} + +// SwitchCaseStmt provide switch case statement. +type SwitchCaseStmt struct { + StmtImpl + Exprs []Expr + Stmt Stmt +} + +// VarStmt provide statement to let variables in current scope. +type VarStmt struct { + StmtImpl + Names []string + Exprs []Expr +} + +// LetsStmt provide multiple statement of let. +type LetsStmt struct { + StmtImpl + LHSS []Expr + RHSS []Expr +} + +// LetMapItemStmt provide statement of let for map item. +type LetMapItemStmt struct { + StmtImpl + LHSS []Expr + RHS Expr +} + +// GoroutineStmt provide statement of groutine. +type GoroutineStmt struct { + StmtImpl + Expr Expr +} + +// DeleteStmt provides statement of delete. +type DeleteStmt struct { + ExprImpl + Item Expr + Key Expr +} + +// CloseStmt provides statement of close. +type CloseStmt struct { + StmtImpl + Expr Expr +} + +// ChanStmt provide chan lets statement. +type ChanStmt struct { + ExprImpl + LHS Expr + OkExpr Expr + RHS Expr +} diff --git a/src/tool/run/cmd/anko-package-gen/main.go b/src/tool/run/cmd/anko-package-gen/main.go new file mode 100644 index 0000000..daaf42f --- /dev/null +++ b/src/tool/run/cmd/anko-package-gen/main.go @@ -0,0 +1,122 @@ +package main + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "log" + "os" + "os/exec" + "path/filepath" + "sort" + "strings" +) + +func pkgName(f string) string { + file, err := parser.ParseFile(token.NewFileSet(), f, nil, parser.PackageClauseOnly) + if err != nil || file == nil { + return "" + } + return file.Name.Name +} + +func isGoFile(dir os.FileInfo) bool { + return !dir.IsDir() && + !strings.HasPrefix(dir.Name(), ".") && // ignore .files + filepath.Ext(dir.Name()) == ".go" +} + +func isPkgFile(dir os.FileInfo) bool { + return isGoFile(dir) && !strings.HasSuffix(dir.Name(), "_test.go") // ignore test files +} + +func parseDir(p string) (map[string]*ast.Package, error) { + isGoFile := func(d os.FileInfo) bool { + return !d.IsDir() && !strings.HasSuffix(d.Name(), "_test.go") && !strings.HasPrefix(d.Name(), "example_") + } + + pkgs, err := parser.ParseDir(token.NewFileSet(), p, isGoFile, parser.ParseComments) + if err != nil { + return nil, err + } + return pkgs, nil +} + +func main() { + pkg := "flag" + if len(os.Args) == 2 { + pkg = os.Args[1] + } + b, err := exec.Command("go", "env", "GOROOT").CombinedOutput() + if err != nil { + log.Fatal(err) + } + paths := []string{filepath.Join(strings.TrimSpace(string(b)), "src")} + b, err = exec.Command("go", "env", "GOPATH").CombinedOutput() + if err != nil { + log.Fatal(err) + } + for _, p := range strings.Split(strings.TrimSpace(string(b)), string(filepath.ListSeparator)) { + paths = append(paths, filepath.Join(p, "src")) + } + for _, p := range paths { + pp := filepath.Join(p, pkg) + pkgs, err := parseDir(pp) + if err != nil || len(pkgs) == 0 { + continue + } + names := map[string]bool{} + pn := pkg + for _, pp := range pkgs { + pn = pp.Name + for _, f := range pp.Files { + for _, d := range f.Decls { + switch decl := d.(type) { + case *ast.GenDecl: + for _, spec := range decl.Specs { + if vspec, ok := spec.(*ast.ValueSpec); ok { + for _, n := range vspec.Names { + c := n.Name[0] + if c < 'A' || c > 'Z' { + continue + } + names[n.Name] = true + } + } + } + case *ast.FuncDecl: + if decl.Recv != nil { + continue + } + c := decl.Name.Name[0] + if c < 'A' || c > 'Z' { + continue + } + names[decl.Name.Name] = true + } + } + } + } + keys := []string{} + for k := range names { + keys = append(keys, k) + } + sort.Strings(keys) + fmt.Printf(`// Package %s implements %s interface for anko script. +package %s + +import ( + "%s" +) + +func init() { + Packages["%s"] = map[string]interface{}{ +`, pn, pkg, pn, pkg, pn) + for _, k := range keys { + fmt.Printf(` "%s": %s.%s,`+"\n", k, pn, k) + } + fmt.Println(` } +}`) + } +} diff --git a/src/tool/run/core/core.go b/src/tool/run/core/core.go new file mode 100644 index 0000000..0c8a2aa --- /dev/null +++ b/src/tool/run/core/core.go @@ -0,0 +1,105 @@ +// Package core implements core interface for anko script. +package core + +import ( + "fmt" + "io/ioutil" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" + "github.com/surdeus/goblin/src/tool/run/parser" + "github.com/surdeus/goblin/src/tool/run/vm" +) + +// Import defines core language builtins - keys, range, println, etc. +func Import(e *env.Env) *env.Env { + e.Define("keys", func(v interface{}) []interface{} { + rv := reflect.ValueOf(v) + if rv.Kind() == reflect.Interface { + rv = rv.Elem() + } + mapKeysValue := rv.MapKeys() + mapKeys := make([]interface{}, len(mapKeysValue)) + for i := 0; i < len(mapKeysValue); i++ { + mapKeys[i] = mapKeysValue[i].Interface() + } + return mapKeys + }) + + e.Define("range", func(args ...int64) []int64 { + var start, stop int64 + var step int64 = 1 + + switch len(args) { + case 0: + panic("range expected at least 1 argument, got 0") + case 1: + stop = args[0] + case 2: + start = args[0] + stop = args[1] + case 3: + start = args[0] + stop = args[1] + step = args[2] + if step == 0 { + panic("range argument 3 must not be zero") + } + default: + panic(fmt.Sprintf("range expected at most 3 arguments, got %d", len(args))) + } + + arr := []int64{} + for i := start; (step > 0 && i < stop) || (step < 0 && i > stop); i += step { + arr = append(arr, i) + } + return arr + }) + + e.Define("typeOf", func(v interface{}) string { + return reflect.TypeOf(v).String() + }) + + e.Define("kindOf", func(v interface{}) string { + typeOf := reflect.TypeOf(v) + if typeOf == nil { + return "nil" + } + return typeOf.Kind().String() + }) + + e.Define("defined", func(s string) bool { + _, err := e.Get(s) + return err == nil + }) + + e.Define("load", func(s string) interface{} { + body, err := ioutil.ReadFile(s) + if err != nil { + panic(err) + } + scanner := new(parser.Scanner) + scanner.Init(string(body)) + stmts, err := parser.Parse(scanner) + if err != nil { + if pe, ok := err.(*parser.Error); ok { + pe.Filename = s + panic(pe) + } + panic(err) + } + rv, err := vm.Run(e, nil, stmts) + if err != nil { + panic(err) + } + return rv + }) + + e.Define("print", fmt.Print) + e.Define("println", fmt.Println) + e.Define("printf", fmt.Printf) + + ImportToX(e) + + return e +} diff --git a/src/tool/run/core/testdata/broken.ank b/src/tool/run/core/testdata/broken.ank new file mode 100644 index 0000000..a4f8fd0 --- /dev/null +++ b/src/tool/run/core/testdata/broken.ank @@ -0,0 +1,6 @@ +#!/usr/bin/env + +use strict; +use warnings; + +die "Hey! I'm anko"; diff --git a/src/tool/run/core/testdata/chan.ank b/src/tool/run/core/testdata/chan.ank new file mode 100644 index 0000000..5745440 --- /dev/null +++ b/src/tool/run/core/testdata/chan.ank @@ -0,0 +1,17 @@ + +c = make(chan int64) +r = [] + +go func() { + c <- 1 + c <- 2 + c <- 3 + close(c) +}() + +for a in c { + r += a +} +is([1,2,3], r, "chan") + +nil diff --git a/src/tool/run/core/testdata/core_test.go b/src/tool/run/core/testdata/core_test.go new file mode 100644 index 0000000..31210af --- /dev/null +++ b/src/tool/run/core/testdata/core_test.go @@ -0,0 +1,149 @@ +package core + +import ( + "fmt" + "os" + "reflect" + "strings" + "testing" + + "github.com/surdeus/goblin/src/tool/run/packages" + "github.com/surdeus/goblin/src/tool/run/vm" +) + +var testCoreEnvSetupFunc = func(t *testing.T, env corelib.Env) { Import(env.(*vm.Env)) } + +func init() { + corelib.NewEnv = func() corelib.Env { + return vm.NewEnv() + } +} + +func TestKeys(t *testing.T) { + os.Setenv("ANKO_DEBUG", "1") + tests := []testlib.Test{ + {Script: `a = {}; b = keys(a)`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = {"a": nil}; b = keys(a)`, RunOutput: []interface{}{"a"}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"a": nil}}}, + {Script: `a = {"a": 1}; b = keys(a)`, RunOutput: []interface{}{"a"}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"a": int64(1)}}}, + } + testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) +} + +func TestKindOf(t *testing.T) { + os.Setenv("ANKO_DEBUG", "1") + tests := []testlib.Test{ + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": reflect.Value{}}, RunOutput: "struct", Output: map[string]interface{}{"a": reflect.Value{}}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": nil}, RunOutput: "nil", Output: map[string]interface{}{"a": nil}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": true}, RunOutput: "bool", Output: map[string]interface{}{"a": true}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": int32(1)}, RunOutput: "int32", Output: map[string]interface{}{"a": int32(1)}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: "int64", Output: map[string]interface{}{"a": int64(1)}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": float32(1.1)}, RunOutput: "float32", Output: map[string]interface{}{"a": float32(1.1)}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: "float64", Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": "a"}, RunOutput: "string", Output: map[string]interface{}{"a": "a"}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": 'a'}, RunOutput: "int32", Output: map[string]interface{}{"a": 'a'}}, + + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(nil)}, RunOutput: "nil", Output: map[string]interface{}{"a": interface{}(nil)}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(true)}, RunOutput: "bool", Output: map[string]interface{}{"a": interface{}(true)}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(int32(1))}, RunOutput: "int32", Output: map[string]interface{}{"a": interface{}(int32(1))}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(int64(1))}, RunOutput: "int64", Output: map[string]interface{}{"a": interface{}(int64(1))}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(float32(1))}, RunOutput: "float32", Output: map[string]interface{}{"a": interface{}(float32(1))}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}(float64(1))}, RunOutput: "float64", Output: map[string]interface{}{"a": interface{}(float64(1))}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": interface{}("a")}, RunOutput: "string", Output: map[string]interface{}{"a": interface{}("a")}}, + + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": []interface{}{}}, RunOutput: "slice", Output: map[string]interface{}{"a": []interface{}{}}}, + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": []interface{}{nil}}, RunOutput: "slice", Output: map[string]interface{}{"a": []interface{}{nil}}}, + + {Script: `kindOf(a)`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: "map", Output: map[string]interface{}{"a": map[string]interface{}{}}}, + {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"}}}, + + {Script: `a = make(interface); kindOf(a)`, RunOutput: "nil", Output: map[string]interface{}{"a": interface{}(nil)}}, + } + testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) +} + +func TestRange(t *testing.T) { + os.Setenv("ANKO_DEBUG", "") + tests := []testlib.Test{ + // 0 arguments + {Script: `range()`, RunError: fmt.Errorf("range expected at least 1 argument, got 0")}, + // 1 arguments(step == 1, start == 0) + {Script: `range(-1)`, RunOutput: []int64{}}, + {Script: `range(0)`, RunOutput: []int64{}}, + {Script: `range(1)`, RunOutput: []int64{0}}, + {Script: `range(2)`, RunOutput: []int64{0, 1}}, + {Script: `range(10)`, RunOutput: []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}, + // 2 arguments(step == 1) + {Script: `range(-5,-1)`, RunOutput: []int64{-5, -4, -3, -2}}, + {Script: `range(-1,1)`, RunOutput: []int64{-1, 0}}, + {Script: `range(1,5)`, RunOutput: []int64{1, 2, 3, 4}}, + // 3 arguments + // step == 2 + {Script: `range(-5,-1,2)`, RunOutput: []int64{-5, -3}}, + {Script: `range(1,5,2)`, RunOutput: []int64{1, 3}}, + {Script: `range(-1,5,2)`, RunOutput: []int64{-1, 1, 3}}, + // step < 0 and from small to large + {Script: `range(-5,-1,-1)`, RunOutput: []int64{}}, + {Script: `range(1,5,-1)`, RunOutput: []int64{}}, + {Script: `range(-1,5,-1)`, RunOutput: []int64{}}, + // step < 0 and from large to small + {Script: `range(-1,-5,-1)`, RunOutput: []int64{-1, -2, -3, -4}}, + {Script: `range(5,1,-1)`, RunOutput: []int64{5, 4, 3, 2}}, + {Script: `range(5,-1,-1)`, RunOutput: []int64{5, 4, 3, 2, 1, 0}}, + // 4,5 arguments + {Script: `range(1,5,1,1)`, RunError: fmt.Errorf("range expected at most 3 arguments, got 4")}, + {Script: `range(1,5,1,1,1)`, RunError: fmt.Errorf("range expected at most 3 arguments, got 5")}, + // more 0 test + {Script: `range(0,1,2)`, RunOutput: []int64{0}}, + {Script: `range(1,0,2)`, RunOutput: []int64{}}, + {Script: `range(1,2,0)`, RunError: fmt.Errorf("range argument 3 must not be zero")}, + } + testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) +} + +func TestLoad(t *testing.T) { + os.Setenv("ANKO_DEBUG", "") + notFoundRunErrorFunc := func(t *testing.T, err error) { + if err == nil || !strings.HasPrefix(err.Error(), "open testdata/not-found.ank:") { + t.Errorf("load not-found.ank failed - received: %v", err) + } + } + tests := []testlib.Test{ + {Script: `load('testdata/test.ank'); X(1)`, RunOutput: int64(2)}, + {Script: `load('testdata/not-found.ank'); X(1)`, RunErrorFunc: ¬FoundRunErrorFunc}, + {Script: `load('testdata/broken.ank'); X(1)`, RunError: fmt.Errorf("syntax error")}, + } + testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) +} + +func TestAnk(t *testing.T) { + os.Setenv("ANKO_DEBUG", "") + var testEnvSetupFunc = func(t *testing.T, env corelib.Env) { + e := env.(*vm.Env) + Import(e) + packages.DefineImport(e) + } + tests := []testlib.Test{ + {Script: `load('testdata/testing.ank'); load('testdata/let.ank')`}, + {Script: `load('testdata/testing.ank'); load('testdata/toString.ank')`}, + {Script: `load('testdata/testing.ank'); load('testdata/op.ank')`}, + {Script: `load('testdata/testing.ank'); load('testdata/func.ank')`}, + {Script: `load('testdata/testing.ank'); load('testdata/len.ank')`}, + {Script: `load('testdata/testing.ank'); load('testdata/for.ank')`}, + {Script: `load('testdata/testing.ank'); load('testdata/switch.ank')`}, + {Script: `load('testdata/testing.ank'); load('testdata/if.ank')`}, + {Script: `load('testdata/testing.ank'); load('testdata/toBytes.ank')`}, + {Script: `load('testdata/testing.ank'); load('testdata/toRunes.ank')`}, + {Script: `load('testdata/testing.ank'); load('testdata/chan.ank')`}, + } + testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testEnvSetupFunc}) +} + +func TestDefined(t *testing.T) { + os.Setenv("ANKO_DEBUG", "") + tests := []testlib.Test{ + {Script: `var a = 1; defined("a")`, RunOutput: true}, + {Script: `defined("a")`, RunOutput: false}, + {Script: `func(){ var a = 1 }(); defined("a")`, RunOutput: false}, + } + testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) +} diff --git a/src/tool/run/core/testdata/error.ank b/src/tool/run/core/testdata/error.ank new file mode 100644 index 0000000..c222400 --- /dev/null +++ b/src/tool/run/core/testdata/error.ank @@ -0,0 +1,3 @@ +func X(a) { + a.notfound = 1 +} diff --git a/src/tool/run/core/testdata/for.ank b/src/tool/run/core/testdata/for.ank new file mode 100644 index 0000000..9470a6f --- /dev/null +++ b/src/tool/run/core/testdata/for.ank @@ -0,0 +1,75 @@ + +x = 0 +for a in [1,2,3] { + x += 1 +} +is(3, x, "for a in range [1,2,3]") + +x = 0 + +for { + x += 1 + if (x > 3) { + break + } +} +is(4, x, "for loop") + +func loop_with_return_stmt() { + y = 0 + for { + if y == 5 { + return y + } + y++ + } + return 1 +} +is(5, loop_with_return_stmt(), "loop with return stmt") + +func for_with_return_stmt() { + y = 0 + for k in range(0, 10) { + if k == 5 { + return y + } + y++ + } + return 1 +} +is(5, for_with_return_stmt(), "for loop with return stmt") + +x = 0 +for a = 0; a < 10; a++ { + x++ +} +is(10, x, "C-style for loop") + +func cstylefor_with_return_stmt() { + y = 0 + for i = 0; i < 10; i++ { + if i == 5 { + return y + } + y++ + } + + return 1 +} + +is(5, cstylefor_with_return_stmt(), "C-style for loop with return statement") + +resp = { + "items": [{ + "someData": 2, + }] +} + +x = 0 +for item in resp.items { + x += item.someData +} + +is(2, x, "dereference slice element") + +nil diff --git a/src/tool/run/core/testdata/func.ank b/src/tool/run/core/testdata/func.ank new file mode 100644 index 0000000..0d3760a --- /dev/null +++ b/src/tool/run/core/testdata/func.ank @@ -0,0 +1,24 @@ + +func a() { return 2 } +is(2, a(), "func a() { return 2 }") + +func b(x) { return x + 1 } +is(3, b(2), "func b(x) { return x + 1 }") + +func c(x) { return x, x + 1 } +is([2,3], c(2), "func c(x) { return x, x + 1 }") + +func d(x) { return func() { return x + 1 } } +is(3, d(2)(), "func d(x) { return func() { return x + 1 } }") + +var x = func(x) { + return func(y) { + x(y) + } +}(func(z) { + return "Yay! " + z +})("hello world") + +is("Yay! hello world", x, "...") + +nil diff --git a/src/tool/run/core/testdata/if.ank b/src/tool/run/core/testdata/if.ank new file mode 100644 index 0000000..3ae8e56 --- /dev/null +++ b/src/tool/run/core/testdata/if.ank @@ -0,0 +1,14 @@ + +r = -1 +if (false) { + r = 1 +} else if (false) { + r = 2 +} else if (false) { + r = 3 +} else { + r = 4 +} +is(4, r, "if") + +nil diff --git a/src/tool/run/core/testdata/len.ank b/src/tool/run/core/testdata/len.ank new file mode 100644 index 0000000..2d7a0f4 --- /dev/null +++ b/src/tool/run/core/testdata/len.ank @@ -0,0 +1,6 @@ + +is(3, len("foo"), "len(\"foo\")") +is(0, len(""), "len(\"\")") +is(4, len([1,2,true,["foo"]]), "len([1,2,true,[\"foo\"]])") + +nil diff --git a/src/tool/run/core/testdata/let.ank b/src/tool/run/core/testdata/let.ank new file mode 100644 index 0000000..7fee9cf --- /dev/null +++ b/src/tool/run/core/testdata/let.ank @@ -0,0 +1,32 @@ + +a = nil +is(nil, a, "let nil") + +a = 1 +is(1, a, "let int") + +a = 1.2 +is(1.2, a, "let float") + +a = "foo" +is("foo", a, "let string") + +a = nil +is(nil, a, "let nil") + +a = true +is(true, a, "let true") + +a = false +is(false, a, "let false") + +a = [1,2,3] +is([1,2,3], a, "let array") + +a = {"foo": "bar", "bar": "baz"} +is({"bar": "baz", "foo": "bar"}, a, "let map") + +a = {"foo": "bar", "bar": {"blah": true, "blah!": [1.3e3, true]}} +is({"foo": "bar", "bar": {"blah": true, "blah!": [1.3e3, true]}}, a, "let map deep") + +nil diff --git a/src/tool/run/core/testdata/op.ank b/src/tool/run/core/testdata/op.ank new file mode 100644 index 0000000..b59c978 --- /dev/null +++ b/src/tool/run/core/testdata/op.ank @@ -0,0 +1,63 @@ + +ok(1 > 0, "1 > 0") +ok(1 == 1.0, "1 == 1.0") +is(1 != "1", false, "1 != \"1\"") +ok(1 == 1, "1 == 1") +ok(1.1 == 1.1, "1.1 == 1.1") +ok("1" == "1", "\"1\" == \"1\"") + +ok(false != "1", "false != \"1\"") +ok(false != true, "false != true") +ok(false == false, "false == false") +ok(true == true, "true == true") +ok(false == false, "false == false") +ok(nil == nil, "nil == nil") + +ok(1 <= 1, "1 <= 1") +ok(1.0 <= 1.0, "1.0 <= 1.0") + +is(true, 1 <= 2 ? true : false, "1 == 1 ? true : false") + +a = 1; a += 1 +is(2, a, "+=") + +a = 2; a -= 1 +is(1, a, "-=") + +a = 2; a *= 2 +is(4, a, "*=") + +a = 3; a /= 2 +is(1.5, a, "/=") + +a = 2; a++ +is(3, a, "++") + +a = 2; a-- +is(1, a, "--") + +a = 1; a &= 2 +is(0, a, "&=") + +a = 1; a |= 2 +is(3, a, "|=") + +a = !3 +is(false, a, "!3") + +a = !true +is(false, a, "!true") + +a = !false +is(true, a, "!false") + +a = ^3 +is(-4, a, "^3") + +a = 3 << 2 +is(12, a, "3 << 2") + +a = 11 >> 2 +is(2, a, "11 >> 2") + +nil diff --git a/src/tool/run/core/testdata/sort.ank b/src/tool/run/core/testdata/sort.ank new file mode 100644 index 0000000..853f28b --- /dev/null +++ b/src/tool/run/core/testdata/sort.ank @@ -0,0 +1,32 @@ +sort = import("sort") + +a = make([]int) +b = make([]int) +a += [1, 2, 3] +b += [3, 1, 2] +sort.Ints(b) +is(a, b, "sort.Ints") + +a = make([]float64) +b = make([]float64) +a += [1.1, 2.2, 3.3] +b += [3.3, 1.1, 2.2] +sort.Float64s(b) +is(a, b, "sort.Float64s") + +a = make([]string) +b = make([]string) +a += ["a", "b", "c", "d"] +b += ["b", "d", "a", "c"] +sort.Strings(b) +is(a, b, "sort.Strings") + +if go18later() { + a = [1, 3, 2] + sort.Slice(a, func(i, j) { + return a[i] < a[j] + }) + is([1,2,3], a, "sort.Slice") +} + +nil diff --git a/src/tool/run/core/testdata/switch.ank b/src/tool/run/core/testdata/switch.ank new file mode 100644 index 0000000..08423ad --- /dev/null +++ b/src/tool/run/core/testdata/switch.ank @@ -0,0 +1,40 @@ + +x = 0 +r = -1 +switch x { +case 0: + r = 0 +case 1: + r = 1 +case 2: + r = 2 +} +is(0, r, "switch/case") + +x = 3 +r = -1 +switch x { +case 0: + r = 0 +case 1: + r = 1 +case 2: + r = 2 +} +is(-1, r, "switch/case") + +x = 3 +r = -1 +switch x { +case 0: + r = 0 +case 1: + r = 1 +case 2: + r = 2 +default: + r = 3 +} +is(3, r, "switch/default") + +nil diff --git a/src/tool/run/core/testdata/test.ank b/src/tool/run/core/testdata/test.ank new file mode 100644 index 0000000..f96b08d --- /dev/null +++ b/src/tool/run/core/testdata/test.ank @@ -0,0 +1,3 @@ +func X(a) { + return a + 1 +} diff --git a/src/tool/run/core/testdata/testing.ank b/src/tool/run/core/testdata/testing.ank new file mode 100644 index 0000000..cabbf4a --- /dev/null +++ b/src/tool/run/core/testdata/testing.ank @@ -0,0 +1,19 @@ + +var runtime = import("runtime") +var regexp = import("regexp") + +func is(expect, got, name) { + if expect != got { + panic("is - received: " + toString(got) + " - expected: " + toString(expect) + " - for: " + toString(name)) + } +} + +func ok(expect, name) { + if !expect { + panic("ok - received: " + toString(expect) + " - for: " + toString(name)) + } +} + +func go18later() { + return regexp.MustCompile("^go1\\.(1[0-9]|[8-9])\\.[0-9]$").MatchString(runtime.Version()) +} diff --git a/src/tool/run/core/testdata/toBytes.ank b/src/tool/run/core/testdata/toBytes.ank new file mode 100644 index 0000000..8dccfd6 --- /dev/null +++ b/src/tool/run/core/testdata/toBytes.ank @@ -0,0 +1,12 @@ + +a = toByteSlice("あいうえお") +b = [227, 129, 130, 227, 129, 132, 227, 129, 134, 227, 129, 136, 227, 129, 138] +x = 0 +for i = 0; i < len(a); i++ { + if (a[i] == b[i]) { + x++ + } +} +is(x, len(a), "toByteSlice(str)") + +nil diff --git a/src/tool/run/core/testdata/toRunes.ank b/src/tool/run/core/testdata/toRunes.ank new file mode 100644 index 0000000..88a43f8 --- /dev/null +++ b/src/tool/run/core/testdata/toRunes.ank @@ -0,0 +1,12 @@ + +a = toRuneSlice("あいうえお") +b = [12354, 12356, 12358, 12360, 12362] +x = 0 +for i = 0; i < len(a); i++ { + if (a[i] == b[i]) { + x++ + } +} +is(x, len(a), "toRuneSlice(str)") + +nil diff --git a/src/tool/run/core/testdata/toString.ank b/src/tool/run/core/testdata/toString.ank new file mode 100644 index 0000000..31aa217 --- /dev/null +++ b/src/tool/run/core/testdata/toString.ank @@ -0,0 +1,8 @@ + +is("1", toString(1), "toString(int)") +is("1.2", toString(1.2), "toString(float)") +is("true", toString(true), "toString(true)") +is("false", toString(false), "toString(false)") +is("foo", toString("foo"), "toString(\"foo\")") + +nil diff --git a/src/tool/run/core/testdata/toX_test.go b/src/tool/run/core/testdata/toX_test.go new file mode 100644 index 0000000..fd42a5c --- /dev/null +++ b/src/tool/run/core/testdata/toX_test.go @@ -0,0 +1,151 @@ +package core + +import ( + "fmt" + "os" + "testing" + "time" + + "github.com/surdeus/goblin/src/tool/run/internal/testlib" +) + +func TestToX(t *testing.T) { + os.Setenv("ANKO_DEBUG", "1") + tests := []testlib.Test{ + {Script: `toBool(-2)`, RunOutput: false}, + {Script: `toBool(-1.5)`, RunOutput: false}, + {Script: `toBool(-1)`, RunOutput: false}, + {Script: `toBool(-0.4)`, RunOutput: false}, + {Script: `toBool(0)`, RunOutput: false}, + {Script: `toBool(0.4)`, RunOutput: true}, + {Script: `toBool(1)`, RunOutput: true}, + {Script: `toBool(1.5)`, RunOutput: true}, + {Script: `toBool(2)`, RunOutput: true}, + {Script: `toBool(true)`, RunOutput: true}, + {Script: `toBool(false)`, RunOutput: false}, + {Script: `toBool("true")`, RunOutput: true}, + {Script: `toBool("false")`, RunOutput: false}, + {Script: `toBool("yes")`, RunOutput: true}, + {Script: `toBool("ye")`, RunOutput: false}, + {Script: `toBool("y")`, RunOutput: true}, + {Script: `toBool("false")`, RunOutput: false}, + {Script: `toBool("f")`, RunOutput: false}, + {Script: `toBool("")`, RunOutput: false}, + {Script: `toBool(nil)`, RunOutput: false}, + {Script: `toBool({})`, RunOutput: false}, + {Script: `toBool([])`, RunOutput: false}, + {Script: `toBool([true])`, RunOutput: false}, + {Script: `toBool({"true": "true"})`, RunOutput: false}, + {Script: `toString(nil)`, RunOutput: ""}, + {Script: `toString("")`, RunOutput: ""}, + {Script: `toString(1)`, RunOutput: "1"}, + {Script: `toString(1.2)`, RunOutput: "1.2"}, + {Script: `toString(1/3)`, RunOutput: "0.3333333333333333"}, + {Script: `toString(false)`, RunOutput: "false"}, + {Script: `toString(true)`, RunOutput: "true"}, + {Script: `toString({})`, RunOutput: "map[]"}, + {Script: `toString({"foo": "bar"})`, RunOutput: "map[foo:bar]"}, + {Script: `toString([true,nil])`, RunOutput: "[true ]"}, + {Script: `toString(toByteSlice("foo"))`, RunOutput: "foo"}, + {Script: `toInt(nil)`, RunOutput: int64(0)}, + {Script: `toInt(-2)`, RunOutput: int64(-2)}, + {Script: `toInt(-1.4)`, RunOutput: int64(-1)}, + {Script: `toInt(-1)`, RunOutput: int64(-1)}, + {Script: `toInt(0)`, RunOutput: int64(0)}, + {Script: `toInt(1)`, RunOutput: int64(1)}, + {Script: `toInt(1.4)`, RunOutput: int64(1)}, + {Script: `toInt(1.5)`, RunOutput: int64(1)}, + {Script: `toInt(1.9)`, RunOutput: int64(1)}, + {Script: `toInt(2)`, RunOutput: int64(2)}, + {Script: `toInt(2.1)`, RunOutput: int64(2)}, + {Script: `toInt("2")`, RunOutput: int64(2)}, + {Script: `toInt("2.1")`, RunOutput: int64(2)}, + {Script: `toInt(true)`, RunOutput: int64(1)}, + {Script: `toInt(false)`, RunOutput: int64(0)}, + {Script: `toInt({})`, RunOutput: int64(0)}, + {Script: `toInt([])`, RunOutput: int64(0)}, + {Script: `toFloat(nil)`, RunOutput: float64(0.0)}, + {Script: `toFloat(-2)`, RunOutput: float64(-2.0)}, + {Script: `toFloat(-1.4)`, RunOutput: float64(-1.4)}, + {Script: `toFloat(-1)`, RunOutput: float64(-1.0)}, + {Script: `toFloat(0)`, RunOutput: float64(0.0)}, + {Script: `toFloat(1)`, RunOutput: float64(1.0)}, + {Script: `toFloat(1.4)`, RunOutput: float64(1.4)}, + {Script: `toFloat(1.5)`, RunOutput: float64(1.5)}, + {Script: `toFloat(1.9)`, RunOutput: float64(1.9)}, + {Script: `toFloat(2)`, RunOutput: float64(2.0)}, + {Script: `toFloat(2.1)`, RunOutput: float64(2.1)}, + {Script: `toFloat("2")`, RunOutput: float64(2.0)}, + {Script: `toFloat("2.1")`, RunOutput: float64(2.1)}, + {Script: `toFloat(true)`, RunOutput: float64(1.0)}, + {Script: `toFloat(false)`, RunOutput: float64(0.0)}, + {Script: `toFloat({})`, RunOutput: float64(0.0)}, + {Script: `toFloat([])`, RunOutput: float64(0.0)}, + {Script: `toChar(0x1F431)`, RunOutput: "🐱"}, + {Script: `toChar(0)`, RunOutput: "\x00"}, + {Script: `toRune("")`, RunOutput: rune(0)}, + {Script: `toRune("🐱")`, RunOutput: rune(0x1F431)}, + {Script: `toBoolSlice(nil)`, RunOutput: []bool{}}, + {Script: `toBoolSlice(1)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type int64")}, + {Script: `toBoolSlice(1.2)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type float64")}, + {Script: `toBoolSlice(false)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type bool")}, + {Script: `toBoolSlice({})`, RunError: fmt.Errorf("function wants argument type []interface {} but received type map[interface {}]interface {}")}, + {Script: `toBoolSlice([])`, RunOutput: []bool{}}, + {Script: `toBoolSlice([nil])`, RunOutput: []bool{false}}, + {Script: `toBoolSlice([1])`, RunOutput: []bool{false}}, + {Script: `toBoolSlice([1.1])`, RunOutput: []bool{false}}, + {Script: `toBoolSlice([true])`, RunOutput: []bool{true}}, + {Script: `toBoolSlice([[]])`, RunOutput: []bool{false}}, + {Script: `toBoolSlice([{}])`, RunOutput: []bool{false}}, + {Script: `toIntSlice(nil)`, RunOutput: []int64{}}, + {Script: `toIntSlice(1)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type int64")}, + {Script: `toIntSlice(1.2)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type float64")}, + {Script: `toIntSlice(false)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type bool")}, + {Script: `toIntSlice({})`, RunError: fmt.Errorf("function wants argument type []interface {} but received type map[interface {}]interface {}")}, + {Script: `toIntSlice([])`, RunOutput: []int64{}}, + {Script: `toIntSlice([nil])`, RunOutput: []int64{0}}, + {Script: `toIntSlice([1])`, RunOutput: []int64{1}}, + {Script: `toIntSlice([1.1])`, RunOutput: []int64{1}}, + {Script: `toIntSlice([true])`, RunOutput: []int64{0}}, + {Script: `toIntSlice([[]])`, RunOutput: []int64{0}}, + {Script: `toIntSlice([{}])`, RunOutput: []int64{0}}, + {Script: `toFloatSlice(nil)`, RunOutput: []float64{}}, + {Script: `toFloatSlice(1)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type int64")}, + {Script: `toFloatSlice(1.2)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type float64")}, + {Script: `toFloatSlice(false)`, RunError: fmt.Errorf("function wants argument type []interface {} but received type bool")}, + {Script: `toFloatSlice({})`, RunError: fmt.Errorf("function wants argument type []interface {} but received type map[interface {}]interface {}")}, + {Script: `toFloatSlice([])`, RunOutput: []float64{}}, + {Script: `toFloatSlice([nil])`, RunOutput: []float64{0.0}}, + {Script: `toFloatSlice([1])`, RunOutput: []float64{1.0}}, + {Script: `toFloatSlice([1.1])`, RunOutput: []float64{1.1}}, + {Script: `toFloatSlice([true])`, RunOutput: []float64{0.0}}, + {Script: `toFloatSlice([[]])`, RunOutput: []float64{0.0}}, + {Script: `toFloatSlice([{}])`, RunOutput: []float64{0.0}}, + {Script: `toByteSlice(nil)`, RunOutput: []byte{}}, + {Script: `toByteSlice([])`, RunError: fmt.Errorf("function wants argument type string but received type []interface {}")}, + {Script: `toByteSlice(1)`, RunOutput: []byte{0x01}}, // FIXME? + {Script: `toByteSlice(1.1)`, RunError: fmt.Errorf("function wants argument type string but received type float64")}, + {Script: `toByteSlice(true)`, RunError: fmt.Errorf("function wants argument type string but received type bool")}, + {Script: `toByteSlice("foo")`, RunOutput: []byte{'f', 'o', 'o'}}, + {Script: `toByteSlice("世界")`, RunOutput: []byte{0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c}}, + {Script: `toRuneSlice(nil)`, RunOutput: []rune{}}, + {Script: `toRuneSlice([])`, RunError: fmt.Errorf("function wants argument type string but received type []interface {}")}, + {Script: `toRuneSlice(1)`, RunOutput: []rune{0x01}}, // FIXME? + {Script: `toRuneSlice(1.1)`, RunError: fmt.Errorf("function wants argument type string but received type float64")}, + {Script: `toRuneSlice(true)`, RunError: fmt.Errorf("function wants argument type string but received type bool")}, + {Script: `toRuneSlice("foo")`, RunOutput: []rune{'f', 'o', 'o'}}, + {Script: `toRuneSlice("世界")`, RunOutput: []rune{'世', '界'}}, + {Script: `toStringSlice([true,false,1])`, RunOutput: []string{"", "", "\x01"}}, // FIXME? + {Script: `toDuration(nil)`, RunOutput: time.Duration(0)}, + {Script: `toDuration(0)`, RunOutput: time.Duration(0)}, + {Script: `toDuration(true)`, RunError: fmt.Errorf("function wants argument type int64 but received type bool")}, + {Script: `toDuration([])`, RunError: fmt.Errorf("function wants argument type int64 but received type []interface {}")}, + {Script: `toDuration({})`, RunError: fmt.Errorf("function wants argument type int64 but received type map[interface {}]interface {}")}, + {Script: `toDuration("")`, RunError: fmt.Errorf("function wants argument type int64 but received type string")}, + {Script: `toDuration("1s")`, RunError: fmt.Errorf("function wants argument type int64 but received type string")}, // TODO + {Script: `toDuration(a)`, Input: map[string]interface{}{"a": int64(time.Duration(123 * time.Minute))}, RunOutput: time.Duration(123 * time.Minute)}, + {Script: `toDuration(a)`, Input: map[string]interface{}{"a": float64(time.Duration(123 * time.Minute))}, RunOutput: time.Duration(123 * time.Minute)}, + {Script: `toDuration(a)`, Input: map[string]interface{}{"a": time.Duration(123 * time.Minute)}, RunOutput: time.Duration(123 * time.Minute)}, + } + testlib.Run(t, tests, &testlib.Options{EnvSetupFunc: &testCoreEnvSetupFunc}) +} diff --git a/src/tool/run/core/toX.go b/src/tool/run/core/toX.go new file mode 100644 index 0000000..0147491 --- /dev/null +++ b/src/tool/run/core/toX.go @@ -0,0 +1,171 @@ +package core + +import ( + "fmt" + "reflect" + "strconv" + "strings" + "time" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +// ImportToX adds all the toX to the env given +func ImportToX(e *env.Env) { + + e.Define("toBool", func(v interface{}) bool { + rv := reflect.ValueOf(v) + if !rv.IsValid() { + return false + } + nt := reflect.TypeOf(true) + if rv.Type().ConvertibleTo(nt) { + return rv.Convert(nt).Bool() + } + if rv.Type().ConvertibleTo(reflect.TypeOf(1.0)) && rv.Convert(reflect.TypeOf(1.0)).Float() > 0.0 { + return true + } + if rv.Kind() == reflect.String { + s := strings.ToLower(v.(string)) + if s == "y" || s == "yes" { + return true + } + b, err := strconv.ParseBool(s) + if err == nil { + return b + } + } + return false + }) + + e.Define("toString", func(v interface{}) string { + if b, ok := v.([]byte); ok { + return string(b) + } + return fmt.Sprint(v) + }) + + e.Define("toInt", func(v interface{}) int64 { + rv := reflect.ValueOf(v) + if !rv.IsValid() { + return 0 + } + nt := reflect.TypeOf(1) + if rv.Type().ConvertibleTo(nt) { + return rv.Convert(nt).Int() + } + if rv.Kind() == reflect.String { + i, err := strconv.ParseInt(v.(string), 10, 64) + if err == nil { + return i + } + f, err := strconv.ParseFloat(v.(string), 64) + if err == nil { + return int64(f) + } + } + if rv.Kind() == reflect.Bool { + if v.(bool) { + return 1 + } + } + return 0 + }) + + e.Define("toFloat", func(v interface{}) float64 { + rv := reflect.ValueOf(v) + if !rv.IsValid() { + return 0 + } + nt := reflect.TypeOf(1.0) + if rv.Type().ConvertibleTo(nt) { + return rv.Convert(nt).Float() + } + if rv.Kind() == reflect.String { + f, err := strconv.ParseFloat(v.(string), 64) + if err == nil { + return f + } + } + if rv.Kind() == reflect.Bool { + if v.(bool) { + return 1.0 + } + } + return 0.0 + }) + + e.Define("toChar", func(s rune) string { + return string(s) + }) + + e.Define("toRune", func(s string) rune { + if len(s) == 0 { + return 0 + } + return []rune(s)[0] + }) + + e.Define("toBoolSlice", func(v []interface{}) []bool { + var result []bool + toSlice(v, &result) + return result + }) + + e.Define("toStringSlice", func(v []interface{}) []string { + var result []string + toSlice(v, &result) + return result + }) + + e.Define("toIntSlice", func(v []interface{}) []int64 { + var result []int64 + toSlice(v, &result) + return result + }) + + e.Define("toFloatSlice", func(v []interface{}) []float64 { + var result []float64 + toSlice(v, &result) + return result + }) + + e.Define("toByteSlice", func(s string) []byte { + return []byte(s) + }) + + e.Define("toRuneSlice", func(s string) []rune { + return []rune(s) + }) + + e.Define("toDuration", func(v int64) time.Duration { + return time.Duration(v) + }) + +} + +// toSlice takes in a "generic" slice and converts and copies +// it's elements into the typed slice pointed at by ptr. +// Note that this is a costly operation. +func toSlice(from []interface{}, ptr interface{}) { + // Value of the pointer to the target + obj := reflect.Indirect(reflect.ValueOf(ptr)) + // We can't just convert from interface{} to whatever the target is (diff memory layout), + // so we need to create a New slice of the proper type and copy the values individually + t := reflect.TypeOf(ptr).Elem() + tt := t.Elem() + slice := reflect.MakeSlice(t, len(from), len(from)) + // Copying the data, val is an addressable Pointer of the actual target type + val := reflect.Indirect(reflect.New(tt)) + for i := 0; i < len(from); i++ { + v := reflect.ValueOf(from[i]) + if v.IsValid() && v.Type().ConvertibleTo(tt) { + val.Set(v.Convert(tt)) + } else { + val.Set(reflect.Zero(tt)) + } + slice.Index(i).Set(val) + } + // Ok now assign our slice to the target pointer + obj.Set(slice) +} diff --git a/src/tool/run/env/env.go b/src/tool/run/env/env.go new file mode 100644 index 0000000..d8faa70 --- /dev/null +++ b/src/tool/run/env/env.go @@ -0,0 +1,187 @@ +package env + +import ( + "bytes" + "errors" + "fmt" + "reflect" + "sync" +) + +type ( + // ExternalLookup for Env external lookup of values and types. + ExternalLookup interface { + Get(string) (reflect.Value, error) + Type(string) (reflect.Type, error) + } + + // Env is the environment needed for a VM to run in. + Env struct { + rwMutex *sync.RWMutex + parent *Env + values map[string]reflect.Value + types map[string]reflect.Type + externalLookup ExternalLookup + } +) + +var ( + // Packages is a where packages can be stored so VM import command can be used to import them. + // reflect.Value must be valid or VM may crash. + // For nil must use NilValue. + Packages = make(map[string]map[string]reflect.Value) + // PackageTypes is a where package types can be stored so VM import command can be used to import them + // reflect.Type must be valid or VM may crash. + // For nil type must use NilType. + PackageTypes = make(map[string]map[string]reflect.Type) + + // NilType is the reflect.type of nil + NilType = reflect.TypeOf(nil) + // NilValue is the reflect.value of nil + NilValue = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem() + + basicTypes = map[string]reflect.Type{ + "interface": reflect.ValueOf([]interface{}{int64(1)}).Index(0).Type(), + "bool": reflect.TypeOf(true), + "string": reflect.TypeOf("a"), + "int": reflect.TypeOf(int(1)), + "int32": reflect.TypeOf(int32(1)), + "int64": reflect.TypeOf(int64(1)), + "uint": reflect.TypeOf(uint(1)), + "uint32": reflect.TypeOf(uint32(1)), + "uint64": reflect.TypeOf(uint64(1)), + "byte": reflect.TypeOf(byte(1)), + "rune": reflect.TypeOf('a'), + "float32": reflect.TypeOf(float32(1)), + "float64": reflect.TypeOf(float64(1)), + } + + // ErrSymbolContainsDot symbol contains . + ErrSymbolContainsDot = errors.New("symbol contains '.'") +) + +// NewEnv creates new global scope. +func NewEnv() *Env { + return &Env{ + rwMutex: &sync.RWMutex{}, + values: make(map[string]reflect.Value), + } +} + +// NewEnv creates new child scope. +func (e *Env) NewEnv() *Env { + return &Env{ + rwMutex: &sync.RWMutex{}, + parent: e, + values: make(map[string]reflect.Value), + } +} + +// NewModule creates new child scope and define it as a symbol. +// This is a shortcut for calling e.NewEnv then Define that new Env. +func (e *Env) NewModule(symbol string) (*Env, error) { + module := &Env{ + rwMutex: &sync.RWMutex{}, + parent: e, + values: make(map[string]reflect.Value), + } + return module, e.Define(symbol, module) +} + +// SetExternalLookup sets an external lookup +func (e *Env) SetExternalLookup(externalLookup ExternalLookup) { + e.externalLookup = externalLookup +} + +// String returns string of values and types in current scope. +func (e *Env) String() string { + var buffer bytes.Buffer + e.rwMutex.RLock() + + if e.parent == nil { + buffer.WriteString("No parent\n") + } else { + buffer.WriteString("Has parent\n") + } + + for symbol, value := range e.values { + buffer.WriteString(fmt.Sprintf("%v = %#v\n", symbol, value)) + } + + for symbol, aType := range e.types { + buffer.WriteString(fmt.Sprintf("%v = %v\n", symbol, aType)) + } + + e.rwMutex.RUnlock() + return buffer.String() +} + +// GetEnvFromPath returns Env from path +func (e *Env) GetEnvFromPath(path []string) (*Env, error) { + if len(path) < 1 { + return e, nil + } + + var value reflect.Value + var ok bool + for { + // find starting env + value, ok = e.values[path[0]] + if ok { + e, ok = value.Interface().(*Env) + if ok { + break + } + } + if e.parent == nil { + return nil, fmt.Errorf("no namespace called: %v", path[0]) + } + e = e.parent + } + + for i := 1; i < len(path); i++ { + // find child env + value, ok = e.values[path[i]] + if ok { + e, ok = value.Interface().(*Env) + if ok { + continue + } + } + return nil, fmt.Errorf("no namespace called: %v", path[i]) + } + + return e, nil +} + +// Copy the Env for current scope +func (e *Env) Copy() *Env { + e.rwMutex.RLock() + copy := Env{ + rwMutex: &sync.RWMutex{}, + parent: e.parent, + values: make(map[string]reflect.Value, len(e.values)), + externalLookup: e.externalLookup, + } + for name, value := range e.values { + copy.values[name] = value + } + if e.types != nil { + copy.types = make(map[string]reflect.Type, len(e.types)) + for name, t := range e.types { + copy.types[name] = t + } + } + e.rwMutex.RUnlock() + return © +} + +// DeepCopy the Env for current scope and parent scopes. +// Note that each scope is a consistent snapshot but not the whole. +func (e *Env) DeepCopy() *Env { + e = e.Copy() + if e.parent != nil { + e.parent = e.parent.DeepCopy() + } + return e +} diff --git a/src/tool/run/env/envExternalLookup_test.go b/src/tool/run/env/envExternalLookup_test.go new file mode 100644 index 0000000..f1f16db --- /dev/null +++ b/src/tool/run/env/envExternalLookup_test.go @@ -0,0 +1,235 @@ +package env + +import ( + "fmt" + "reflect" + "strings" + "testing" +) + +type TestExternalLookup struct { + values map[string]reflect.Value + types map[string]reflect.Type +} + +func NewTestExternalLookup() *TestExternalLookup { + return &TestExternalLookup{ + values: make(map[string]reflect.Value), + types: make(map[string]reflect.Type), + } +} + +func (testExternalLookup *TestExternalLookup) SetValue(symbol string, value interface{}) error { + if strings.Contains(symbol, ".") { + return ErrSymbolContainsDot + } + + if value == nil { + testExternalLookup.values[symbol] = NilValue + } else { + testExternalLookup.values[symbol] = reflect.ValueOf(value) + } + + return nil +} + +func (testExternalLookup *TestExternalLookup) Get(symbol string) (reflect.Value, error) { + if value, ok := testExternalLookup.values[symbol]; ok { + return value, nil + } + return NilValue, fmt.Errorf("undefined symbol '%s'", symbol) +} + +func (testExternalLookup *TestExternalLookup) DefineType(symbol string, aType interface{}) error { + if strings.Contains(symbol, ".") { + return ErrSymbolContainsDot + } + + var reflectType reflect.Type + if aType == nil { + reflectType = NilType + } else { + var ok bool + reflectType, ok = reflectType.(reflect.Type) + if !ok { + reflectType = reflect.TypeOf(aType) + } + } + + testExternalLookup.types[symbol] = reflectType + return nil +} + +func (testExternalLookup *TestExternalLookup) Type(symbol string) (reflect.Type, error) { + if value, ok := testExternalLookup.types[symbol]; ok { + return value, nil + } + return NilType, fmt.Errorf("undefined symbol '%s'", symbol) +} + +func TestExternalLookupValueAndGet(t *testing.T) { + var err error + var value interface{} + tests := []struct { + testInfo string + varName string + varDefineValue interface{} + varGetValue interface{} + varKind reflect.Kind + defineError error + getError error + }{ + {testInfo: "nil", varName: "a", varDefineValue: nil, varGetValue: nil, varKind: reflect.Interface}, + {testInfo: "bool", varName: "a", varDefineValue: true, varGetValue: true, varKind: reflect.Bool}, + {testInfo: "int16", varName: "a", varDefineValue: int16(1), varGetValue: int16(1), varKind: reflect.Int16}, + {testInfo: "int32", varName: "a", varDefineValue: int32(1), varGetValue: int32(1), varKind: reflect.Int32}, + {testInfo: "int64", varName: "a", varDefineValue: int64(1), varGetValue: int64(1), varKind: reflect.Int64}, + {testInfo: "uint32", varName: "a", varDefineValue: uint32(1), varGetValue: uint32(1), varKind: reflect.Uint32}, + {testInfo: "uint64", varName: "a", varDefineValue: uint64(1), varGetValue: uint64(1), varKind: reflect.Uint64}, + {testInfo: "float32", varName: "a", varDefineValue: float32(1), varGetValue: float32(1), varKind: reflect.Float32}, + {testInfo: "float64", varName: "a", varDefineValue: float64(1), varGetValue: float64(1), varKind: reflect.Float64}, + {testInfo: "string", varName: "a", varDefineValue: "a", varGetValue: "a", varKind: reflect.String}, + + {testInfo: "string with dot", varName: "a.a", varDefineValue: "a", varGetValue: nil, varKind: reflect.String, defineError: ErrSymbolContainsDot, getError: fmt.Errorf("undefined symbol 'a.a'")}, + {testInfo: "string with quotes", varName: "a", varDefineValue: `"a"`, varGetValue: `"a"`, varKind: reflect.String}, + } + + // ExternalLookup set And get + for _, test := range tests { + testExternalLookup := NewTestExternalLookup() + env := NewEnv() + env.SetExternalLookup(testExternalLookup) + + err = testExternalLookup.SetValue(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("TestExternalLookupValueAndGet %v - SetValue error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("TestExternalLookupValueAndGet %v - SetValue error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + value, err = env.Get(test.varName) + if err != nil && test.getError != nil { + if err.Error() != test.getError.Error() { + t.Errorf("TestExternalLookupValueAndGet %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + } else if err != test.getError { + t.Errorf("TestExternalLookupValueAndGet %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + if value != test.varGetValue { + t.Errorf("TestExternalLookupValueAndGet %v - value check - received %#v expected: %#v", test.testInfo, value, test.varGetValue) + } + } +} + +func TestExternalLookupTypeAndGet(t *testing.T) { + var err error + var valueType reflect.Type + tests := []struct { + testInfo string + varName string + varDefineValue interface{} + defineError error + typeError error + }{ + {testInfo: "nil", varName: "a", varDefineValue: nil}, + {testInfo: "bool", varName: "a", varDefineValue: true}, + {testInfo: "int16", varName: "a", varDefineValue: int16(1)}, + {testInfo: "int32", varName: "a", varDefineValue: int32(1)}, + {testInfo: "int64", varName: "a", varDefineValue: int64(1)}, + {testInfo: "uint32", varName: "a", varDefineValue: uint32(1)}, + {testInfo: "uint64", varName: "a", varDefineValue: uint64(1)}, + {testInfo: "float32", varName: "a", varDefineValue: float32(1)}, + {testInfo: "float64", varName: "a", varDefineValue: float64(1)}, + {testInfo: "string", varName: "a", varDefineValue: "a"}, + + {testInfo: "string with dot", varName: "a.a", varDefineValue: nil, defineError: ErrSymbolContainsDot, typeError: fmt.Errorf("undefined type 'a.a'")}, + } + + // DefineType + for _, test := range tests { + testExternalLookup := NewTestExternalLookup() + env := NewEnv() + env.SetExternalLookup(testExternalLookup) + + err = testExternalLookup.DefineType(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("TestExternalLookupTypeAndGet %v - DefineType error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("TestExternalLookupTypeAndGet %v - DefineType error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + valueType, err = env.Type(test.varName) + if err != nil && test.typeError != nil { + if err.Error() != test.typeError.Error() { + t.Errorf("TestExternalLookupTypeAndGet %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + } else if err != test.typeError { + t.Errorf("TestExternalLookupTypeAndGet %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + if valueType == nil || test.varDefineValue == nil { + if valueType != reflect.TypeOf(test.varDefineValue) { + t.Errorf("TestExternalLookupTypeAndGet %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } else if valueType.String() != reflect.TypeOf(test.varDefineValue).String() { + t.Errorf("TestExternalLookupTypeAndGet %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } + +} + +func TestExternalLookupAddr(t *testing.T) { + var err error + tests := []struct { + testInfo string + varName string + varDefineValue interface{} + defineError error + addrError error + }{ + {testInfo: "nil", varName: "a", varDefineValue: nil, addrError: nil}, + {testInfo: "bool", varName: "a", varDefineValue: true, addrError: fmt.Errorf("unaddressable")}, + {testInfo: "int64", varName: "a", varDefineValue: int64(1), addrError: fmt.Errorf("unaddressable")}, + {testInfo: "float64", varName: "a", varDefineValue: float64(1), addrError: fmt.Errorf("unaddressable")}, + {testInfo: "string", varName: "a", varDefineValue: "a", addrError: fmt.Errorf("unaddressable")}, + } + + for _, test := range tests { + envParent := NewEnv() + testExternalLookup := NewTestExternalLookup() + envParent.SetExternalLookup(testExternalLookup) + envChild := envParent.NewEnv() + + err = testExternalLookup.SetValue(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("TestExternalLookupAddr %v - SetValue error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("TestExternalLookupAddr %v - SetValue error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + _, err = envChild.Addr(test.varName) + if err != nil && test.addrError != nil { + if err.Error() != test.addrError.Error() { + t.Errorf("TestExternalLookupAddr %v - Addr error - received: %v - expected: %v", test.testInfo, err, test.addrError) + continue + } + } else if err != test.addrError { + t.Errorf("TestExternalLookupAddr %v - Addr error - received: %v - expected: %v", test.testInfo, err, test.addrError) + continue + } + } +} diff --git a/src/tool/run/env/envTypes.go b/src/tool/run/env/envTypes.go new file mode 100644 index 0000000..565b7f1 --- /dev/null +++ b/src/tool/run/env/envTypes.go @@ -0,0 +1,83 @@ +package env + +import ( + "fmt" + "reflect" + "strings" +) + +// DefineType defines type in current scope. +func (e *Env) DefineType(symbol string, aType interface{}) error { + var reflectType reflect.Type + if aType == nil { + reflectType = NilType + } else { + var ok bool + reflectType, ok = aType.(reflect.Type) + if !ok { + reflectType = reflect.TypeOf(aType) + } + } + + return e.DefineReflectType(symbol, reflectType) +} + +// DefineReflectType defines type in current scope. +func (e *Env) DefineReflectType(symbol string, reflectType reflect.Type) error { + if strings.Contains(symbol, ".") { + return ErrSymbolContainsDot + } + + e.rwMutex.Lock() + if e.types == nil { + e.types = make(map[string]reflect.Type) + } + e.types[symbol] = reflectType + e.rwMutex.Unlock() + + return nil +} + +// DefineGlobalType defines type in global scope. +func (e *Env) DefineGlobalType(symbol string, aType interface{}) error { + for e.parent != nil { + e = e.parent + } + return e.DefineType(symbol, aType) +} + +// DefineGlobalReflectType defines type in global scope. +func (e *Env) DefineGlobalReflectType(symbol string, reflectType reflect.Type) error { + for e.parent != nil { + e = e.parent + } + return e.DefineReflectType(symbol, reflectType) +} + +// Type returns reflect type from the scope where symbol is frist found. +func (e *Env) Type(symbol string) (reflect.Type, error) { + e.rwMutex.RLock() + reflectType, ok := e.types[symbol] + e.rwMutex.RUnlock() + if ok { + return reflectType, nil + } + + if e.externalLookup != nil { + var err error + reflectType, err = e.externalLookup.Type(symbol) + if err == nil { + return reflectType, nil + } + } + + if e.parent == nil { + reflectType, ok = basicTypes[symbol] + if ok { + return reflectType, nil + } + return NilType, fmt.Errorf("undefined type '%s'", symbol) + } + + return e.parent.Type(symbol) +} diff --git a/src/tool/run/env/envTypes_test.go b/src/tool/run/env/envTypes_test.go new file mode 100644 index 0000000..050de22 --- /dev/null +++ b/src/tool/run/env/envTypes_test.go @@ -0,0 +1,313 @@ +package env + +import ( + "fmt" + "reflect" + "testing" +) + +func TestBasicType(t *testing.T) { + env := NewEnv() + aType, err := env.Type("string") + if err != nil { + t.Fatalf("Type error - %v", err) + } + if aType != reflect.TypeOf("a") { + t.Errorf("Type - received: %v - expected: %v", aType, reflect.TypeOf("a")) + } + + aType, err = env.Type("int64") + if err != nil { + t.Fatal("Type error:", err) + } + if aType != reflect.TypeOf(int64(1)) { + t.Errorf("Type - received: %v - expected: %v", aType, reflect.TypeOf(int64(1))) + } +} + +func TestDefineType(t *testing.T) { + var err error + var valueType reflect.Type + tests := []struct { + testInfo string + varName string + varDefineValue interface{} + defineError error + typeError error + }{ + {testInfo: "nil", varName: "a", varDefineValue: nil}, + {testInfo: "bool", varName: "a", varDefineValue: true}, + {testInfo: "int16", varName: "a", varDefineValue: int16(1)}, + {testInfo: "int32", varName: "a", varDefineValue: int32(1)}, + {testInfo: "int64", varName: "a", varDefineValue: int64(1)}, + {testInfo: "uint32", varName: "a", varDefineValue: uint32(1)}, + {testInfo: "uint64", varName: "a", varDefineValue: uint64(1)}, + {testInfo: "float32", varName: "a", varDefineValue: float32(1)}, + {testInfo: "float64", varName: "a", varDefineValue: float64(1)}, + {testInfo: "string", varName: "a", varDefineValue: "a"}, + + {testInfo: "string with dot", varName: "a.a", varDefineValue: nil, defineError: ErrSymbolContainsDot, typeError: fmt.Errorf("undefined type 'a.a'")}, + } + + // DefineType + for _, test := range tests { + env := NewEnv() + + err = env.DefineType(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineType %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineType %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + valueType, err = env.Type(test.varName) + if err != nil && test.typeError != nil { + if err.Error() != test.typeError.Error() { + t.Errorf("DefineType %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + } else if err != test.typeError { + t.Errorf("DefineType %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + if valueType == nil || test.varDefineValue == nil { + if valueType != reflect.TypeOf(test.varDefineValue) { + t.Errorf("DefineType %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } else if valueType.String() != reflect.TypeOf(test.varDefineValue).String() { + t.Errorf("DefineType %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } + + // DefineType NewEnv + for _, test := range tests { + envParent := NewEnv() + envChild := envParent.NewEnv() + + err = envParent.DefineType(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineType NewEnv %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineType NewEnv %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + valueType, err = envChild.Type(test.varName) + if err != nil && test.typeError != nil { + if err.Error() != test.typeError.Error() { + t.Errorf("DefineType NewEnv %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + } else if err != test.typeError { + t.Errorf("DefineType NewEnv %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + if valueType == nil || test.varDefineValue == nil { + if valueType != reflect.TypeOf(test.varDefineValue) { + t.Errorf("DefineType NewEnv %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } else if valueType.String() != reflect.TypeOf(test.varDefineValue).String() { + t.Errorf("DefineType NewEnv %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } + + // DefineType NewModule + for _, test := range tests { + envParent := NewEnv() + envChild, err := envParent.NewModule("envChild") + if err != nil { + t.Fatalf("DefineType NewModule %v - NewModule error - received: %v - expected: %v", test.testInfo, err, nil) + } + + err = envParent.DefineType(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineType NewModule %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineType NewModule %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + valueType, err = envChild.Type(test.varName) + if err != nil && test.typeError != nil { + if err.Error() != test.typeError.Error() { + t.Errorf("DefineType NewModule %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + } else if err != test.typeError { + t.Errorf("DefineType NewModule %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + if valueType == nil || test.varDefineValue == nil { + if valueType != reflect.TypeOf(test.varDefineValue) { + t.Errorf("DefineType NewModule %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } else if valueType.String() != reflect.TypeOf(test.varDefineValue).String() { + t.Errorf("DefineType NewModule %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } + + // DefineGlobalType + for _, test := range tests { + envParent := NewEnv() + envChild := envParent.NewEnv() + + err = envChild.DefineGlobalType(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineGlobalType %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineGlobalType %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + valueType, err = envParent.Type(test.varName) + if err != nil && test.typeError != nil { + if err.Error() != test.typeError.Error() { + t.Errorf("DefineGlobalType %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + } else if err != test.typeError { + t.Errorf("DefineGlobalType %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + if valueType == nil || test.varDefineValue == nil { + if valueType != reflect.TypeOf(test.varDefineValue) { + t.Errorf("DefineGlobalType %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } else if valueType.String() != reflect.TypeOf(test.varDefineValue).String() { + t.Errorf("DefineGlobalType %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + + valueType, err = envChild.Type(test.varName) + if err != nil && test.typeError != nil { + if err.Error() != test.typeError.Error() { + t.Errorf("DefineGlobalType %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + } else if err != test.typeError { + t.Errorf("DefineGlobalType %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + if valueType == nil || test.varDefineValue == nil { + if valueType != reflect.TypeOf(test.varDefineValue) { + t.Errorf("DefineGlobalType %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } else if valueType.String() != reflect.TypeOf(test.varDefineValue).String() { + t.Errorf("DefineGlobalType %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } + + // DefineGlobalReflectType + for _, test := range tests { + envParent := NewEnv() + envChild := envParent.NewEnv() + + err = envChild.DefineGlobalReflectType(test.varName, reflect.TypeOf(test.varDefineValue)) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineGlobalReflectType %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineGlobalReflectType %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + valueType, err = envParent.Type(test.varName) + if err != nil && test.typeError != nil { + if err.Error() != test.typeError.Error() { + t.Errorf("DefineGlobalReflectType %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + } else if err != test.typeError { + t.Errorf("DefineGlobalReflectType %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + if valueType == nil || test.varDefineValue == nil { + if valueType != reflect.TypeOf(test.varDefineValue) { + t.Errorf("DefineGlobalReflectType %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } else if valueType.String() != reflect.TypeOf(test.varDefineValue).String() { + t.Errorf("DefineGlobalReflectType %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + + valueType, err = envChild.Type(test.varName) + if err != nil && test.typeError != nil { + if err.Error() != test.typeError.Error() { + t.Errorf("DefineGlobalReflectType %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + } else if err != test.typeError { + t.Errorf("DefineGlobalReflectType %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + if valueType == nil || test.varDefineValue == nil { + if valueType != reflect.TypeOf(test.varDefineValue) { + t.Errorf("DefineGlobalReflectType %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } else if valueType.String() != reflect.TypeOf(test.varDefineValue).String() { + t.Errorf("DefineGlobalReflectType %v - Type check - received: %v - expected: %v", test.testInfo, valueType, reflect.TypeOf(test.varDefineValue)) + } + } +} + +func TestDefineTypeFail(t *testing.T) { + var err error + tests := []struct { + testInfo string + varName string + varDefineValue interface{} + defineError error + typeError error + }{ + {testInfo: "nil", varName: "a", varDefineValue: nil, typeError: fmt.Errorf("undefined type 'a'")}, + {testInfo: "bool", varName: "a", varDefineValue: true, typeError: fmt.Errorf("undefined type 'a'")}, + {testInfo: "int16", varName: "a", varDefineValue: int16(1), typeError: fmt.Errorf("undefined type 'a'")}, + {testInfo: "int32", varName: "a", varDefineValue: int32(1), typeError: fmt.Errorf("undefined type 'a'")}, + {testInfo: "int64", varName: "a", varDefineValue: int64(1), typeError: fmt.Errorf("undefined type 'a'")}, + {testInfo: "uint32", varName: "a", varDefineValue: uint32(1), typeError: fmt.Errorf("undefined type 'a'")}, + {testInfo: "uint64", varName: "a", varDefineValue: uint64(1), typeError: fmt.Errorf("undefined type 'a'")}, + {testInfo: "float32", varName: "a", varDefineValue: float32(1), typeError: fmt.Errorf("undefined type 'a'")}, + {testInfo: "float64", varName: "a", varDefineValue: float64(1), typeError: fmt.Errorf("undefined type 'a'")}, + {testInfo: "string", varName: "a", varDefineValue: "a", typeError: fmt.Errorf("undefined type 'a'")}, + } + + // DefineTypeFail + for _, test := range tests { + envParent := NewEnv() + envChild := envParent.NewEnv() + + err = envChild.DefineType(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("TestDefineTypeFail %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("TestDefineTypeFail %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + _, err = envParent.Type(test.varName) + if err != nil && test.typeError != nil { + if err.Error() != test.typeError.Error() { + t.Errorf("TestDefineTypeFail %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + continue + } + } else if err != test.typeError { + t.Errorf("TestDefineTypeFail %v - Type error - received: %v - expected: %v", test.testInfo, err, test.typeError) + } + } +} diff --git a/src/tool/run/env/envValues.go b/src/tool/run/env/envValues.go new file mode 100644 index 0000000..a5da28f --- /dev/null +++ b/src/tool/run/env/envValues.go @@ -0,0 +1,161 @@ +package env + +import ( + "fmt" + "reflect" + "strings" +) + +// define + +// Define defines/sets interface value to symbol in current scope. +func (e *Env) Define(symbol string, value interface{}) error { + if value == nil { + return e.DefineValue(symbol, NilValue) + } + return e.DefineValue(symbol, reflect.ValueOf(value)) +} + +// DefineValue defines/sets reflect value to symbol in current scope. +func (e *Env) DefineValue(symbol string, value reflect.Value) error { + if strings.Contains(symbol, ".") { + return ErrSymbolContainsDot + } + e.rwMutex.Lock() + e.values[symbol] = value + e.rwMutex.Unlock() + + return nil +} + +// DefineGlobal defines/sets interface value to symbol in global scope. +func (e *Env) DefineGlobal(symbol string, value interface{}) error { + for e.parent != nil { + e = e.parent + } + return e.Define(symbol, value) +} + +// DefineGlobalValue defines/sets reflect value to symbol in global scope. +func (e *Env) DefineGlobalValue(symbol string, value reflect.Value) error { + for e.parent != nil { + e = e.parent + } + return e.DefineValue(symbol, value) +} + +// set + +// Set interface value to the scope where symbol is frist found. +func (e *Env) Set(symbol string, value interface{}) error { + if value == nil { + return e.SetValue(symbol, NilValue) + } + return e.SetValue(symbol, reflect.ValueOf(value)) +} + +// SetValue reflect value to the scope where symbol is frist found. +func (e *Env) SetValue(symbol string, value reflect.Value) error { + e.rwMutex.RLock() + _, ok := e.values[symbol] + e.rwMutex.RUnlock() + if ok { + e.rwMutex.Lock() + e.values[symbol] = value + e.rwMutex.Unlock() + return nil + } + + if e.parent == nil { + return fmt.Errorf("undefined symbol '%s'", symbol) + } + return e.parent.SetValue(symbol, value) +} + +// get + +// Get returns interface value from the scope where symbol is frist found. +func (e *Env) Get(symbol string) (interface{}, error) { + rv, err := e.GetValue(symbol) + return rv.Interface(), err +} + +// GetValue returns reflect value from the scope where symbol is frist found. +func (e *Env) GetValue(symbol string) (reflect.Value, error) { + e.rwMutex.RLock() + value, ok := e.values[symbol] + e.rwMutex.RUnlock() + if ok { + return value, nil + } + + if e.externalLookup != nil { + var err error + value, err = e.externalLookup.Get(symbol) + if err == nil { + return value, nil + } + } + + if e.parent == nil { + return NilValue, fmt.Errorf("undefined symbol '%s'", symbol) + } + + return e.parent.GetValue(symbol) +} + +// delete + +// Delete deletes symbol in current scope. +func (e *Env) Delete(symbol string) { + e.rwMutex.Lock() + delete(e.values, symbol) + e.rwMutex.Unlock() +} + +// DeleteGlobal deletes the first matching symbol found in current or parent scope. +func (e *Env) DeleteGlobal(symbol string) { + if e.parent == nil { + e.Delete(symbol) + return + } + + e.rwMutex.RLock() + _, ok := e.values[symbol] + e.rwMutex.RUnlock() + + if ok { + e.Delete(symbol) + return + } + + e.parent.DeleteGlobal(symbol) +} + +// Addr + +// Addr returns reflect.Addr of value for first matching symbol found in current or parent scope. +func (e *Env) Addr(symbol string) (reflect.Value, error) { + e.rwMutex.RLock() + defer e.rwMutex.RUnlock() + + if v, ok := e.values[symbol]; ok { + if v.CanAddr() { + return v.Addr(), nil + } + return NilValue, fmt.Errorf("unaddressable") + } + if e.externalLookup != nil { + v, err := e.externalLookup.Get(symbol) + if err == nil { + if v.CanAddr() { + return v.Addr(), nil + } + return NilValue, fmt.Errorf("unaddressable") + } + } + if e.parent == nil { + return NilValue, fmt.Errorf("undefined symbol '%s'", symbol) + } + return e.parent.Addr(symbol) +} diff --git a/src/tool/run/env/envValues_test.go b/src/tool/run/env/envValues_test.go new file mode 100644 index 0000000..81c9611 --- /dev/null +++ b/src/tool/run/env/envValues_test.go @@ -0,0 +1,787 @@ +package env + +import ( + "fmt" + "reflect" + "sync" + "testing" +) + +func TestSetError(t *testing.T) { + envParent := NewEnv() + envChild := envParent.NewEnv() + err := envChild.Set("a", "a") + if err == nil { + t.Errorf("Set error - received: %v - expected: %v", err, fmt.Errorf("undefined symbol 'a'")) + } else if err.Error() != "undefined symbol 'a'" { + t.Errorf("Set error - received: %v - expected: %v", err, fmt.Errorf("undefined symbol 'a'")) + } +} + +func TestAddrError(t *testing.T) { + envParent := NewEnv() + envChild := envParent.NewEnv() + _, err := envChild.Addr("a") + if err == nil { + t.Errorf("Addr error - received: %v - expected: %v", err, fmt.Errorf("undefined symbol 'a'")) + } else if err.Error() != "undefined symbol 'a'" { + t.Errorf("Addr error - received: %v - expected: %v", err, fmt.Errorf("undefined symbol 'a'")) + } +} + +func TestDefineGlobalValue(t *testing.T) { + envParent := NewEnv() + envChild := envParent.NewEnv() + err := envChild.DefineGlobalValue("a", reflect.ValueOf("a")) + if err != nil { + t.Fatal("DefineGlobalValue error:", err) + } + + var value interface{} + value, err = envParent.Get("a") + if err != nil { + t.Fatal("Get error:", err) + } + v, ok := value.(string) + if !ok { + t.Fatalf("value - received: %T - expected: %T", value, "a") + } + if v != "a" { + t.Fatalf("value - received: %v - expected: %v", v, "a") + } +} + +func TestDefineAndGet(t *testing.T) { + var err error + var value interface{} + tests := []struct { + testInfo string + varName string + varDefineValue interface{} + varGetValue interface{} + varKind reflect.Kind + defineError error + getError error + }{ + {testInfo: "nil", varName: "a", varDefineValue: reflect.Value{}, varGetValue: reflect.Value{}, varKind: reflect.Invalid}, + {testInfo: "nil", varName: "a", varDefineValue: nil, varGetValue: nil, varKind: reflect.Interface}, + {testInfo: "bool", varName: "a", varDefineValue: true, varGetValue: true, varKind: reflect.Bool}, + {testInfo: "int16", varName: "a", varDefineValue: int16(1), varGetValue: int16(1), varKind: reflect.Int16}, + {testInfo: "int32", varName: "a", varDefineValue: int32(1), varGetValue: int32(1), varKind: reflect.Int32}, + {testInfo: "int64", varName: "a", varDefineValue: int64(1), varGetValue: int64(1), varKind: reflect.Int64}, + {testInfo: "uint32", varName: "a", varDefineValue: uint32(1), varGetValue: uint32(1), varKind: reflect.Uint32}, + {testInfo: "uint64", varName: "a", varDefineValue: uint64(1), varGetValue: uint64(1), varKind: reflect.Uint64}, + {testInfo: "float32", varName: "a", varDefineValue: float32(1), varGetValue: float32(1), varKind: reflect.Float32}, + {testInfo: "float64", varName: "a", varDefineValue: float64(1), varGetValue: float64(1), varKind: reflect.Float64}, + {testInfo: "string", varName: "a", varDefineValue: "a", varGetValue: "a", varKind: reflect.String}, + + {testInfo: "string with dot", varName: "a.a", varDefineValue: "a", varGetValue: nil, varKind: reflect.Interface, defineError: ErrSymbolContainsDot, getError: fmt.Errorf("undefined symbol 'a.a'")}, + {testInfo: "string with quotes", varName: "a", varDefineValue: `"a"`, varGetValue: `"a"`, varKind: reflect.String}, + } + + // DefineAndGet + for _, test := range tests { + env := NewEnv() + + err = env.Define(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineAndGet %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineAndGet %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + value, err = env.Get(test.varName) + if err != nil && test.getError != nil { + if err.Error() != test.getError.Error() { + t.Errorf("DefineAndGet %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + } else if err != test.getError { + t.Errorf("DefineAndGet %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + if value != test.varGetValue { + t.Errorf("DefineAndGet %v - value check - received %#v expected: %#v", test.testInfo, value, test.varGetValue) + } + } + + // DefineAndGet NewEnv + for _, test := range tests { + envParent := NewEnv() + envChild := envParent.NewEnv() + + err = envParent.Define(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineAndGet NewEnv %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineAndGet NewEnv %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + value, err = envChild.Get(test.varName) + if err != nil && test.getError != nil { + if err.Error() != test.getError.Error() { + t.Errorf("DefineAndGet NewEnv %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + } else if err != test.getError { + t.Errorf("DefineAndGet NewEnv %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + if value != test.varGetValue { + t.Errorf("DefineAndGet NewEnv %v - value check - received %#v expected: %#v", test.testInfo, value, test.varGetValue) + } + } + + // DefineAndGet DefineGlobal + for _, test := range tests { + envParent := NewEnv() + envChild := envParent.NewEnv() + + err = envChild.DefineGlobal(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineAndGet DefineGlobal %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineAndGet DefineGlobal %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + value, err = envParent.Get(test.varName) + if err != nil && test.getError != nil { + if err.Error() != test.getError.Error() { + t.Errorf("DefineAndGet DefineGlobal %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + } else if err != test.getError { + t.Errorf("DefineAndGet DefineGlobal %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + if value != test.varGetValue { + t.Errorf("DefineAndGet DefineGlobal %v - value check - received %#v expected: %#v", test.testInfo, value, test.varGetValue) + } + } + +} + +func TestDefineModify(t *testing.T) { + var err error + var value interface{} + tests := []struct { + testInfo string + varName string + varDefineValue interface{} + varGetValue interface{} + varKind reflect.Kind + defineError error + getError error + }{ + {testInfo: "nil", varName: "a", varDefineValue: nil, varGetValue: nil, varKind: reflect.Interface}, + {testInfo: "bool", varName: "a", varDefineValue: true, varGetValue: true, varKind: reflect.Bool}, + {testInfo: "int64", varName: "a", varDefineValue: int64(1), varGetValue: int64(1), varKind: reflect.Int64}, + {testInfo: "float64", varName: "a", varDefineValue: float64(1), varGetValue: float64(1), varKind: reflect.Float64}, + {testInfo: "string", varName: "a", varDefineValue: "a", varGetValue: "a", varKind: reflect.String}, + } + changeTests := []struct { + varDefineValue interface{} + varGetValue interface{} + varKind reflect.Kind + defineError error + getError error + }{ + {varDefineValue: nil, varGetValue: nil, varKind: reflect.Interface}, + {varDefineValue: "a", varGetValue: "a", varKind: reflect.String}, + {varDefineValue: int64(1), varGetValue: int64(1), varKind: reflect.Int64}, + {varDefineValue: float64(1), varGetValue: float64(1), varKind: reflect.Float64}, + {varDefineValue: true, varGetValue: true, varKind: reflect.Bool}, + } + + // DefineModify + for _, test := range tests { + env := NewEnv() + + err = env.Define(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineModify %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineModify %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + value, err = env.Get(test.varName) + if err != nil && test.getError != nil { + if err.Error() != test.getError.Error() { + t.Errorf("DefineModify %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + } else if err != test.getError { + t.Errorf("DefineModify %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + if value != test.varGetValue { + t.Errorf("DefineModify %v - value check - received %#v expected: %#v", test.testInfo, value, test.varGetValue) + } + + // DefineModify changeTest + for _, changeTest := range changeTests { + err = env.Set(test.varName, changeTest.varDefineValue) + if err != nil && changeTest.defineError != nil { + if err.Error() != changeTest.defineError.Error() { + t.Errorf("DefineModify changeTest %v - Set error - received: %v - expected: %v", test.testInfo, err, changeTest.defineError) + continue + } + } else if err != changeTest.defineError { + t.Errorf("DefineModify changeTest %v - Set error - received: %v - expected: %v", test.testInfo, err, changeTest.defineError) + continue + } + + value, err = env.Get(test.varName) + if err != nil && changeTest.getError != nil { + if err.Error() != changeTest.getError.Error() { + t.Errorf("DefineModify changeTest %v - Get error - received: %v - expected: %v", test.testInfo, err, changeTest.getError) + continue + } + } else if err != changeTest.getError { + t.Errorf("DefineModify changeTest %v - Get error - received: %v - expected: %v", test.testInfo, err, changeTest.getError) + continue + } + if value != changeTest.varGetValue { + t.Errorf("DefineModify changeTest %v - value check - received %#v expected: %#v", test.testInfo, value, changeTest.varGetValue) + } + } + } + + // DefineModify envParent + for _, test := range tests { + envParent := NewEnv() + envChild := envParent.NewEnv() + + err = envParent.Define(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineModify envParent %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineModify envParent %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + value, err = envChild.Get(test.varName) + if err != nil && test.getError != nil { + if err.Error() != test.getError.Error() { + t.Errorf("DefineModify envParent %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + } else if err != test.getError { + t.Errorf("DefineModify envParent %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + if value != test.varGetValue { + t.Errorf("DefineModify envParent %v - value check - received %#v expected: %#v", test.testInfo, value, test.varGetValue) + } + + for _, changeTest := range changeTests { + err = envParent.Set(test.varName, changeTest.varDefineValue) + if err != nil && changeTest.defineError != nil { + if err.Error() != changeTest.defineError.Error() { + t.Errorf("DefineModify envParent changeTest %v - Set error - received: %v - expected: %v", test.testInfo, err, changeTest.defineError) + continue + } + } else if err != changeTest.defineError { + t.Errorf("DefineModify envParent changeTest %v - Set error - received: %v - expected: %v", test.testInfo, err, changeTest.defineError) + continue + } + + value, err = envChild.Get(test.varName) + if err != nil && changeTest.getError != nil { + if err.Error() != changeTest.getError.Error() { + t.Errorf("DefineModify envParent changeTest %v - Get error - received: %v - expected: %v", test.testInfo, err, changeTest.getError) + continue + } + } else if err != changeTest.getError { + t.Errorf("ChanDefineModify envParent changeTestgeTest %v - Get error - received: %v - expected: %v", test.testInfo, err, changeTest.getError) + continue + } + if value != changeTest.varGetValue { + t.Errorf("DefineModify envParent changeTest %v - value check - received %#v expected: %#v", test.testInfo, value, changeTest.varGetValue) + } + } + } + + // DefineModify envChild + for _, test := range tests { + envParent := NewEnv() + envChild := envParent.NewEnv() + + err = envParent.Define(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("DefineModify envChild %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("DefineModify envChild %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + value, err = envChild.Get(test.varName) + if err != nil && test.getError != nil { + if err.Error() != test.getError.Error() { + t.Errorf("DefineModify envChild %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + } else if err != test.getError { + t.Errorf("DefineModify envChild %v - Get error - received: %v - expected: %v", test.testInfo, err, test.getError) + continue + } + if value != test.varGetValue { + t.Errorf("DefineModify envChild %v - value check - received %#v expected: %#v", test.testInfo, value, test.varGetValue) + } + + for _, changeTest := range changeTests { + err = envChild.Set(test.varName, changeTest.varDefineValue) + if err != nil && changeTest.defineError != nil { + if err.Error() != changeTest.defineError.Error() { + t.Errorf("DefineModify envChild changeTest %v - Set error - received: %v - expected: %v", test.testInfo, err, changeTest.defineError) + continue + } + } else if err != changeTest.defineError { + t.Errorf("DefineModify envChild changeTest %v - Set error - received: %v - expected: %v", test.testInfo, err, changeTest.defineError) + continue + } + + value, err = envChild.Get(test.varName) + if err != nil && changeTest.getError != nil { + if err.Error() != changeTest.getError.Error() { + t.Errorf("DefineModify envChild changeTest %v - Get error - received: %v - expected: %v", test.testInfo, err, changeTest.getError) + continue + } + } else if err != changeTest.getError { + t.Errorf("ChanDefineModify envChild changeTestgeTest %v - Get error - received: %v - expected: %v", test.testInfo, err, changeTest.getError) + continue + } + if value != changeTest.varGetValue { + t.Errorf("DefineModify envChild changeTest %v - value check - received %#v expected: %#v", test.testInfo, value, changeTest.varGetValue) + } + } + } +} + +func TestAddr(t *testing.T) { + var err error + tests := []struct { + testInfo string + varName string + varDefineValue interface{} + defineError error + addrError error + }{ + {testInfo: "nil", varName: "a", varDefineValue: nil, addrError: nil}, + {testInfo: "string", varName: "a", varDefineValue: "a", addrError: fmt.Errorf("unaddressable")}, + {testInfo: "int64", varName: "a", varDefineValue: int64(1), addrError: fmt.Errorf("unaddressable")}, + {testInfo: "float64", varName: "a", varDefineValue: float64(1), addrError: fmt.Errorf("unaddressable")}, + {testInfo: "bool", varName: "a", varDefineValue: true, addrError: fmt.Errorf("unaddressable")}, + } + + // TestAddr + for _, test := range tests { + envParent := NewEnv() + envChild := envParent.NewEnv() + + err = envParent.Define(test.varName, test.varDefineValue) + if err != nil && test.defineError != nil { + if err.Error() != test.defineError.Error() { + t.Errorf("TestAddr %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + } else if err != test.defineError { + t.Errorf("TestAddr %v - Define error - received: %v - expected: %v", test.testInfo, err, test.defineError) + continue + } + + _, err = envChild.Addr(test.varName) + if err != nil && test.addrError != nil { + if err.Error() != test.addrError.Error() { + t.Errorf("TestAddr %v - Addr error - received: %v - expected: %v", test.testInfo, err, test.addrError) + continue + } + } else if err != test.addrError { + t.Errorf("TestAddr %v - Addr error - received: %v - expected: %v", test.testInfo, err, test.addrError) + continue + } + } +} + +func TestDelete(t *testing.T) { + // empty + env := NewEnv() + env.Delete("a") + + // add & delete a + env.Define("a", "a") + env.Delete("a") + + value, err := env.Get("a") + expectedError := "undefined symbol 'a'" + if err == nil || err.Error() != expectedError { + t.Errorf("Get error - received: %v - expected: %v", err, expectedError) + } + if value != nil { + t.Errorf("Get value - received: %#v - expected: %#v", value, nil) + } +} + +func TestDeleteGlobal(t *testing.T) { + // empty + env := NewEnv() + env.DeleteGlobal("a") + + // add & delete a + env.Define("a", "a") + env.DeleteGlobal("a") + + value, err := env.Get("a") + expectedError := "undefined symbol 'a'" + if err == nil || err.Error() != expectedError { + t.Errorf("Get error - received: %v - expected: %v", err, expectedError) + } + if value != nil { + t.Errorf("Get value - received: %#v - expected: %#v", value, nil) + } + + // parent & child, var in child, delete in parent + envChild := env.NewEnv() + envChild.Define("a", "a") + env.DeleteGlobal("a") + + value, err = envChild.Get("a") + if err != nil { + t.Errorf("Get error - received: %v - expected: %v", err, nil) + } + if value != "a" { + t.Errorf("Get value - received: %#v - expected: %#v", value, "a") + } + + // parent & child, var in child, delete in child + envChild.DeleteGlobal("a") + + value, err = envChild.Get("a") + if err == nil || err.Error() != expectedError { + t.Errorf("Get error - received: %v - expected: %v", err, expectedError) + } + if value != nil { + t.Errorf("Get value - received: %#v - expected: %#v", value, nil) + } + + // parent & child, var in parent, delete in child + env.Define("a", "a") + envChild.DeleteGlobal("a") + + value, err = envChild.Get("a") + if err == nil || err.Error() != expectedError { + t.Errorf("Get error - received: %v - expected: %v", err, expectedError) + } + if value != nil { + t.Errorf("Get value - received: %#v - expected: %#v", value, nil) + } + + // parent & child, var in parent, delete in parent + env.Define("a", "a") + env.DeleteGlobal("a") + + value, err = envChild.Get("a") + if err == nil || err.Error() != expectedError { + t.Errorf("Get error - received: %v - expected: %v", err, expectedError) + } + if value != nil { + t.Errorf("Get value - received: %#v - expected: %#v", value, nil) + } +} + +func TestRaceCreateSameVariable(t *testing.T) { + // Test creating same variable in parallel + + waitChan := make(chan struct{}, 1) + var waitGroup sync.WaitGroup + + env := NewEnv() + + for i := 0; i < 100; i++ { + waitGroup.Add(1) + go func(i int) { + <-waitChan + err := env.Define("a", i) + if err != nil { + t.Errorf("Define error: %v", err) + } + _, err = env.Get("a") + if err != nil { + t.Errorf("Get error: %v", err) + } + waitGroup.Done() + }(i) + } + + close(waitChan) + waitGroup.Wait() + + _, err := env.Get("a") + if err != nil { + t.Errorf("Get error: %v", err) + } +} + +func TestRaceCreateDifferentVariables(t *testing.T) { + // Test creating different variables in parallel + + waitChan := make(chan struct{}, 1) + var waitGroup sync.WaitGroup + + env := NewEnv() + + for i := 0; i < 100; i++ { + waitGroup.Add(1) + go func(i int) { + <-waitChan + err := env.Define(fmt.Sprint(i), i) + if err != nil { + t.Errorf("Define error: %v", err) + } + _, err = env.Get(fmt.Sprint(i)) + if err != nil { + t.Errorf("Get error: %v", err) + } + waitGroup.Done() + }(i) + } + + close(waitChan) + waitGroup.Wait() + + for i := 0; i < 100; i++ { + _, err := env.Get(fmt.Sprint(i)) + if err != nil { + t.Errorf("Get error: %v", err) + } + } +} + +func TestRaceReadDifferentVariables(t *testing.T) { + // Test reading different variables in parallel + + waitChan := make(chan struct{}, 1) + var waitGroup sync.WaitGroup + + env := NewEnv() + + for i := 0; i < 100; i++ { + err := env.Define(fmt.Sprint(i), i) + if err != nil { + t.Errorf("Define error: %v", err) + } + _, err = env.Get(fmt.Sprint(i)) + if err != nil { + t.Errorf("Get error: %v", err) + } + } + + for i := 0; i < 100; i++ { + waitGroup.Add(1) + go func(i int) { + <-waitChan + _, err := env.Get(fmt.Sprint(i)) + if err != nil { + t.Errorf("Get error: %v", err) + } + waitGroup.Done() + }(i) + } + + close(waitChan) + waitGroup.Wait() +} + +func TestRaceSetSameVariable(t *testing.T) { + // Test setting same variable in parallel + + waitChan := make(chan struct{}, 1) + var waitGroup sync.WaitGroup + + env := NewEnv() + + err := env.Define("a", 0) + if err != nil { + t.Errorf("Define error: %v", err) + } + _, err = env.Get("a") + if err != nil { + t.Errorf("Get error: %v", err) + } + + for i := 0; i < 100; i++ { + waitGroup.Add(1) + go func(i int) { + <-waitChan + err := env.Set("a", i) + if err != nil { + t.Errorf("Set error: %v", err) + } + waitGroup.Done() + }(i) + } + + close(waitChan) + waitGroup.Wait() + + _, err = env.Get("a") + if err != nil { + t.Errorf("Get error: %v", err) + } +} + +func TestRaceSetSameVariableNewEnv(t *testing.T) { + // Test setting same variable in parallel with NewEnv + + waitChan := make(chan struct{}, 1) + var waitGroup sync.WaitGroup + + env := NewEnv() + + err := env.Define("a", 0) + if err != nil { + t.Errorf("Define error: %v", err) + } + _, err = env.Get("a") + if err != nil { + t.Errorf("Get error: %v", err) + } + + for i := 0; i < 100; i++ { + waitGroup.Add(1) + go func(i int) { + <-waitChan + env = env.NewEnv().NewEnv() + err := env.Set("a", i) + if err != nil { + t.Errorf("Set error: %v", err) + } + waitGroup.Done() + }(i) + } +} + +func TestRaceDefineAndSetSameVariable(t *testing.T) { + // Test defining and setting same variable in parallel + for i := 0; i < 100; i++ { + raceDefineAndSetSameVariable(t) + } +} + +func raceDefineAndSetSameVariable(t *testing.T) { + waitChan := make(chan struct{}, 1) + var waitGroup sync.WaitGroup + + envParent := NewEnv() + envChild := envParent.NewEnv() + + for i := 0; i < 2; i++ { + waitGroup.Add(1) + go func() { + <-waitChan + err := envParent.Set("a", 1) + if err != nil && err.Error() != "undefined symbol 'a'" { + t.Errorf("Set error: %v", err) + } + waitGroup.Done() + }() + waitGroup.Add(1) + go func() { + <-waitChan + err := envParent.Define("a", 2) + if err != nil { + t.Errorf("Define error: %v", err) + } + waitGroup.Done() + }() + waitGroup.Add(1) + go func() { + <-waitChan + err := envChild.Set("a", 3) + if err != nil && err.Error() != "undefined symbol 'a'" { + t.Errorf("Set error: %v", err) + } + waitGroup.Done() + }() + waitGroup.Add(1) + go func() { + <-waitChan + err := envChild.Define("a", 4) + if err != nil { + t.Errorf("Define error: %v", err) + } + waitGroup.Done() + }() + } + + close(waitChan) + waitGroup.Wait() + + _, err := envParent.Get("a") // value of a could be 1, 2, or 3 + if err != nil { + t.Errorf("Get error: %v", err) + } + _, err = envChild.Get("a") // value of a could be 3 or 4 + if err != nil { + t.Errorf("Get error: %v", err) + } +} + +func BenchmarkDefine(b *testing.B) { + var err error + env := NewEnv() + b.ResetTimer() + for i := 0; i < b.N; i++ { + err := env.Define("a", 1) + if err != nil { + b.Errorf("Set error: %v", err) + } + } + b.StopTimer() + _, err = env.Get("a") + if err != nil { + b.Errorf("Get error: %v", err) + } +} + +func BenchmarkSet(b *testing.B) { + env := NewEnv() + err := env.Define("a", 1) + if err != nil { + b.Errorf("Define error: %v", err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + err = env.Set("a", 1) + if err != nil { + b.Errorf("Set error: %v", err) + } + } + b.StopTimer() + _, err = env.Get("a") + if err != nil { + b.Errorf("Get error: %v", err) + } +} diff --git a/src/tool/run/env/env_test.go b/src/tool/run/env/env_test.go new file mode 100644 index 0000000..bd7a682 --- /dev/null +++ b/src/tool/run/env/env_test.go @@ -0,0 +1,394 @@ +package env + +import ( + "reflect" + "testing" +) + +func TestString(t *testing.T) { + t.Parallel() + + env := NewEnv() + env.Define("a", "a") + output := env.String() + expected := `No parent +a = "a" +` + if output != expected { + t.Errorf("received: %v - expected: %v", output, expected) + } + + env = env.NewEnv() + env.Define("b", "b") + output = env.String() + expected = `Has parent +b = "b" +` + if output != expected { + t.Errorf("received: %v - expected: %v", output, expected) + } + + env = NewEnv() + env.Define("c", "c") + env.DefineType("string", "a") + output = env.String() + expected = `No parent +c = "c" +string = string +` + if output != expected { + t.Errorf("received: %v - expected: %v", output, expected) + } +} + +func TestGetEnvFromPath(t *testing.T) { + t.Parallel() + + env := NewEnv() + a, err := env.NewModule("a") + if err != nil { + t.Fatal("NewModule error:", err) + } + var b *Env + b, err = a.NewModule("b") + if err != nil { + t.Fatal("NewModule error:", err) + } + var c *Env + c, err = b.NewModule("c") + if err != nil { + t.Fatal("NewModule error:", err) + } + err = c.Define("d", "d") + if err != nil { + t.Fatal("Define error:", err) + } + + e, err := env.GetEnvFromPath(nil) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + + e, err = env.GetEnvFromPath([]string{}) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + + e, err = env.GetEnvFromPath([]string{"a", "c"}) + expected := "no namespace called: c" + if err == nil || err.Error() != expected { + t.Fatalf("GetEnvFromPath error - received: %v - expected: %v", err, expected) + } + if e != nil { + t.Fatal("GetEnvFromPath e not nil") + } + + // a.b.c + + e, err = env.GetEnvFromPath([]string{"a", "b", "c"}) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + var value interface{} + value, err = e.Get("d") + if err != nil { + t.Fatal("Get error:", err) + } + v, ok := value.(string) + if !ok { + t.Fatal("value not string") + } + if v != "d" { + t.Errorf("value - received: %v - expected: %v", v, "d") + } + + e, err = a.GetEnvFromPath([]string{"a", "b", "c"}) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + value, err = e.Get("d") + if err != nil { + t.Fatal("Get error:", err) + } + v, ok = value.(string) + if !ok { + t.Fatal("value not string") + } + if v != "d" { + t.Errorf("value - received: %v - expected: %v", v, "d") + } + + e, err = b.GetEnvFromPath([]string{"a", "b", "c"}) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + value, err = e.Get("d") + if err != nil { + t.Fatal("Get error:", err) + } + v, ok = value.(string) + if !ok { + t.Fatal("value not string") + } + if v != "d" { + t.Errorf("value - received: %v - expected: %v", v, "d") + } + + e, err = c.GetEnvFromPath([]string{"a", "b", "c"}) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + value, err = e.Get("d") + if err != nil { + t.Fatal("Get error:", err) + } + v, ok = value.(string) + if !ok { + t.Fatal("value not string") + } + if v != "d" { + t.Errorf("value - received: %v - expected: %v", v, "d") + } + + // b.c + + e, err = env.GetEnvFromPath([]string{"b", "c"}) + expected = "no namespace called: b" + if err == nil || err.Error() != expected { + t.Fatalf("GetEnvFromPath error - received: %v - expected: %v", err, expected) + } + if e != nil { + t.Fatal("GetEnvFromPath e not nil") + } + + e, err = a.GetEnvFromPath([]string{"b", "c"}) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + value, err = e.Get("d") + if err != nil { + t.Fatal("Get error:", err) + } + v, ok = value.(string) + if !ok { + t.Fatal("value not string") + } + if v != "d" { + t.Errorf("value - received: %v - expected: %v", v, "d") + } + + e, err = b.GetEnvFromPath([]string{"b", "c"}) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + value, err = e.Get("d") + if err != nil { + t.Fatal("Get error:", err) + } + v, ok = value.(string) + if !ok { + t.Fatal("value not string") + } + if v != "d" { + t.Errorf("value - received: %v - expected: %v", v, "d") + } + + e, err = c.GetEnvFromPath([]string{"b", "c"}) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + value, err = e.Get("d") + if err != nil { + t.Fatal("Get error:", err) + } + v, ok = value.(string) + if !ok { + t.Fatal("value not string") + } + if v != "d" { + t.Errorf("value - received: %v - expected: %v", v, "d") + } + + // c + + e, err = env.GetEnvFromPath([]string{"c"}) + expected = "no namespace called: c" + if err == nil || err.Error() != expected { + t.Fatalf("GetEnvFromPath error - received: %v - expected: %v", err, expected) + } + if e != nil { + t.Fatal("GetEnvFromPath e not nil") + } + + e, err = b.GetEnvFromPath([]string{"c"}) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + value, err = e.Get("d") + if err != nil { + t.Fatal("Get error:", err) + } + v, ok = value.(string) + if !ok { + t.Fatal("value not string") + } + if v != "d" { + t.Errorf("value - received: %v - expected: %v", v, "d") + } + + e, err = c.GetEnvFromPath(nil) + if err != nil { + t.Fatal("GetEnvFromPath error:", err) + } + if e == nil { + t.Fatal("GetEnvFromPath e nil") + } + value, err = e.Get("d") + if err != nil { + t.Fatal("Get error:", err) + } + v, ok = value.(string) + if !ok { + t.Fatal("value not string") + } + if v != "d" { + t.Errorf("value - received: %v - expected: %v", v, "d") + } +} + +func TestCopy(t *testing.T) { + t.Parallel() + + parent := NewEnv() + parent.Define("a", "a") + parent.DefineType("b", []bool{}) + child := parent.NewEnv() + child.Define("c", "c") + child.DefineType("d", []int64{}) + copy := child.Copy() + + if v, e := copy.Get("a"); e != nil || v != "a" { + t.Errorf("copy missing value") + } + if v, e := copy.Type("b"); e != nil || v != reflect.TypeOf([]bool{}) { + t.Errorf("copy missing type") + } + if v, e := copy.Get("c"); e != nil || v != "c" { + t.Errorf("copy missing value") + } + if v, e := copy.Type("d"); e != nil || v != reflect.TypeOf([]int64{}) { + t.Errorf("copy missing type") + } + + // TODO: add more get type tests + + copy.Set("a", "i") + if v, e := child.Get("a"); e != nil || v != "i" { + t.Errorf("parent was not modified") + } + if v, e := copy.Get("a"); e != nil || v != "i" { + t.Errorf("copy did not get parent value") + } + + copy.Set("c", "j") + if v, e := child.Get("c"); e != nil || v != "c" { + t.Errorf("child was not modified") + } + if v, e := copy.Get("c"); e != nil || v != "j" { + t.Errorf("copy child was not modified") + } + + child.Set("a", "x") + if v, e := child.Get("a"); e != nil || v != "x" { + t.Errorf("parent was not modified") + } + if v, e := copy.Get("a"); e != nil || v != "x" { + t.Errorf("copy did not get parent value") + } + + child.Set("c", "z") + if v, e := child.Get("c"); e != nil || v != "z" { + t.Errorf("child was not modified") + } + if v, e := copy.Get("c"); e != nil || v != "j" { + t.Errorf("copy child was modified") + } + + parent.Set("a", "m") + if v, e := child.Get("a"); e != nil || v != "m" { + t.Errorf("parent was not modified") + } + if v, e := copy.Get("a"); e != nil || v != "m" { + t.Errorf("copy did not get parent value") + } + + parent.Define("x", "n") + if v, e := child.Get("x"); e != nil || v != "n" { + t.Errorf("child did not get parent value") + } + if v, e := copy.Get("x"); e != nil || v != "n" { + t.Errorf("copy did not get parent value") + } +} + +func TestDeepCopy(t *testing.T) { + t.Parallel() + + parent := NewEnv() + parent.Define("a", "a") + env := parent.NewEnv() + copy := env.DeepCopy() + + // TODO: add more/better tests, like above + if v, e := copy.Get("a"); e != nil || v != "a" { + t.Errorf("copy doesn't retain original values") + } + parent.Set("a", "b") + if v, e := env.Get("a"); e != nil || v != "b" { + t.Errorf("son was not modified") + } + if v, e := copy.Get("a"); e != nil || v != "a" { + t.Errorf("copy got the new value") + } + parent.Set("a", "c") + if v, e := env.Get("a"); e != nil || v != "c" { + t.Errorf("original was not modified") + } + if v, e := copy.Get("a"); e != nil || v != "a" { + t.Errorf("copy was modified") + } + parent.Define("b", "b") + if _, e := copy.Get("b"); e == nil { + t.Errorf("copy parent was modified") + } +} diff --git a/src/tool/run/misc/vim/ftdetect/ank.vim b/src/tool/run/misc/vim/ftdetect/ank.vim new file mode 100644 index 0000000..13bd684 --- /dev/null +++ b/src/tool/run/misc/vim/ftdetect/ank.vim @@ -0,0 +1 @@ +au BufNewFile,BufRead *.ank setlocal filetype=anko diff --git a/src/tool/run/misc/vim/ftplugin/anko/comment.vim b/src/tool/run/misc/vim/ftplugin/anko/comment.vim new file mode 100644 index 0000000..35f52f9 --- /dev/null +++ b/src/tool/run/misc/vim/ftplugin/anko/comment.vim @@ -0,0 +1,11 @@ +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +setlocal comments=s1:# +setlocal commentstring=#\ %s + +let b:undo_ftplugin = "setl com< cms<" + +" vim:ts=4:sw=4:et diff --git a/src/tool/run/misc/vim/ftplugin/anko/play.vim b/src/tool/run/misc/vim/ftplugin/anko/play.vim new file mode 100644 index 0000000..6da8751 --- /dev/null +++ b/src/tool/run/misc/vim/ftplugin/anko/play.vim @@ -0,0 +1,15 @@ +scriptencoding utf-8 + +function! s:play() + let code = join(getline(1, '$'), "\n") + let res = webapi#http#post("http://play-anko.appspot.com/api/play", {"code": code}) + if res.status == "200" + echo iconv(res.content, "utf-8", &encoding) + else + for line in split(res.content, "\n") + echohl Error | echomsg iconv(line, "utf-8", &encoding) | echohl None + endfor + endif +endfunction + +command! -buffer PlayAnko call s:play() diff --git a/src/tool/run/misc/vim/syntax/anko.vim b/src/tool/run/misc/vim/syntax/anko.vim new file mode 100644 index 0000000..9be5c83 --- /dev/null +++ b/src/tool/run/misc/vim/syntax/anko.vim @@ -0,0 +1,100 @@ +if exists("b:current_syntax") + finish +endif + +syn case match + +syn keyword ankoDirective module +syn keyword ankoDeclaration var + +hi def link ankoDirective Statement +hi def link ankoDeclaration Type + +syn keyword ankoStatement return break continue throw +syn keyword ankoConditional if else switch try catch finally +syn keyword ankoLabel case default +syn keyword ankoRepeat for range + +hi def link ankoStatement Statement +hi def link ankoConditional Conditional +hi def link ankoLabel Label +hi def link ankoRepeat Repeat + +syn match ankoDeclaration /\/ +syn match ankoDeclaration /^func\>/ + +syn keyword ankoCast bytes runes string + +hi def link ankoCast Type + +syn keyword ankoBuiltins keys len +syn keyword ankoBuiltins println printf print +syn keyword ankoConstants true false nil + +hi def link ankoBuiltins Keyword +hi def link ankoConstants Keyword + +" Comments; their contents +syn keyword ankoTodo contained TODO FIXME XXX BUG +syn cluster ankoCommentGroup contains=ankoTodo +syn region ankoComment start="#" end="$" contains=@ankoCommentGroup,@Spell + +hi def link ankoComment Comment +hi def link ankoTodo Todo + +" anko escapes +syn match ankoEscapeOctal display contained "\\[0-7]\{3}" +syn match ankoEscapeC display contained +\\[abfnrtv\\'"]+ +syn match ankoEscapeX display contained "\\x\x\{2}" +syn match ankoEscapeU display contained "\\u\x\{4}" +syn match ankoEscapeBigU display contained "\\U\x\{8}" +syn match ankoEscapeError display contained +\\[^0-7xuUabfnrtv\\'"]+ + +hi def link ankoEscapeOctal ankoSpecialString +hi def link ankoEscapeC ankoSpecialString +hi def link ankoEscapeX ankoSpecialString +hi def link ankoEscapeU ankoSpecialString +hi def link ankoEscapeBigU ankoSpecialString +hi def link ankoSpecialString Special +hi def link ankoEscapeError Error + +" Strings and their contents +syn cluster ankoStringGroup contains=ankoEscapeOctal,ankoEscapeC,ankoEscapeX,ankoEscapeU,ankoEscapeBigU,ankoEscapeError +syn region ankoString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@ankoStringGroup +syn region ankoRawString start=+`+ end=+`+ + +hi def link ankoString String +hi def link ankoRawString String + +" Characters; their contents +syn cluster ankoCharacterGroup contains=ankoEscapeOctal,ankoEscapeC,ankoEscapeX,ankoEscapeU,ankoEscapeBigU +syn region ankoCharacter start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=@ankoCharacterGroup + +hi def link ankoCharacter Character + +" Regions +syn region ankoBlock start="{" end="}" transparent fold +syn region ankoParen start='(' end=')' transparent + +" Integers +syn match ankoDecimalInt "\<\d\+\([Ee]\d\+\)\?\>" +syn match ankoHexadecimalInt "\<0x\x\+\>" +syn match ankoOctalInt "\<0\o\+\>" +syn match ankoOctalError "\<0\o*[89]\d*\>" + +hi def link ankoDecimalInt Integer +hi def link ankoHexadecimalInt Integer +hi def link ankoOctalInt Integer +hi def link Integer Number + +" Floating point +syn match ankoFloat "\<\d\+\.\d*\([Ee][-+]\d\+\)\?\>" +syn match ankoFloat "\<\.\d\+\([Ee][-+]\d\+\)\?\>" +syn match ankoFloat "\<\d\+[Ee][-+]\d\+\>" + +hi def link ankoFloat Float +hi def link ankoImaginary Number + +syn sync minlines=500 + +let b:current_syntax = "anko" diff --git a/src/tool/run/misc/wasm/anko.go b/src/tool/run/misc/wasm/anko.go new file mode 100644 index 0000000..944d93a --- /dev/null +++ b/src/tool/run/misc/wasm/anko.go @@ -0,0 +1,129 @@ +// +build js,wasm + +package main + +import ( + "fmt" + "html" + "strings" + "syscall/js" + + "github.com/surdeus/goblin/src/tool/run/core" + "github.com/surdeus/goblin/src/tool/run/packages" + "github.com/surdeus/goblin/src/tool/run/parser" + "github.com/surdeus/goblin/src/tool/run/vm" +) + +var ( + result = js.Global.Get("document").Call("getElementById", "result") + input = js.Global.Get("document").Call("getElementById", "input") +) + +func writeCommand(s string) { + result.Set("innerHTML", result.Get("innerHTML").String()+"

"+html.EscapeString(s)+"

") + result.Set("scrollTop", result.Get("scrollHeight").Int()) +} + +func writeStdout(s string) { + result.Set("innerHTML", result.Get("innerHTML").String()+"

"+html.EscapeString(s)+"

") + result.Set("scrollTop", result.Get("scrollHeight").Int()) +} + +func writeStderr(s string) { + result.Set("innerHTML", result.Get("innerHTML").String()+"

"+html.EscapeString(s)+"

") + result.Set("scrollTop", result.Get("scrollHeight").Int()) +} + +func main() { + env := vm.NewEnv() + core.Import(env) + packages.DefineImport(env) + + env.Define("print", func(a ...interface{}) { + writeStdout(fmt.Sprint(a...)) + }) + env.Define("printf", func(a string, b ...interface{}) { + writeStdout(fmt.Sprintf(a, b...)) + }) + + var following bool + var source string + + parser.EnableErrorVerbose() + + ch := make(chan string) + + input.Call("addEventListener", "keypress", js.NewCallback(func(args []js.Value) { + e := args[0] + if e.Get("keyCode").Int() != 13 { + return + } + s := e.Get("target").Get("value").String() + e.Get("target").Set("value", "") + writeCommand(s) + ch <- s + })) + input.Set("disabled", false) + result.Set("innerHTML", "") + + go func() { + for { + text, ok := <-ch + if !ok { + break + } + source += text + if source == "" { + continue + } + if source == "quit()" { + break + } + + stmts, err := parser.ParseSrc(source) + + if e, ok := err.(*parser.Error); ok { + es := e.Error() + if strings.HasPrefix(es, "syntax error: unexpected") { + if strings.HasPrefix(es, "syntax error: unexpected $end,") { + following = true + continue + } + } else { + if e.Pos.Column == len(source) && !e.Fatal { + writeStderr(e.Error()) + following = true + continue + } + if e.Error() == "unexpected EOF" { + following = true + continue + } + } + } + + following = false + source = "" + var v interface{} + + if err == nil { + v, err = vm.Run(stmts, env) + } + if err != nil { + if e, ok := err.(*vm.Error); ok { + writeStderr(fmt.Sprintf("%d:%d %s\n", e.Pos.Line, e.Pos.Column, err)) + } else if e, ok := err.(*parser.Error); ok { + writeStderr(fmt.Sprintf("%d:%d %s\n", e.Pos.Line, e.Pos.Column, err)) + } else { + writeStderr(err.Error()) + } + continue + } + + writeStdout(fmt.Sprintf("%#v\n", v)) + } + }() + + select {} + +} diff --git a/src/tool/run/misc/wasm/index.html b/src/tool/run/misc/wasm/index.html new file mode 100644 index 0000000..87c08ac --- /dev/null +++ b/src/tool/run/misc/wasm/index.html @@ -0,0 +1,35 @@ + + + Anko WebAssembly + + + + + +
loading...
+
+ + diff --git a/src/tool/run/misc/wasm/wasm_exec.js b/src/tool/run/misc/wasm/wasm_exec.js new file mode 100644 index 0000000..fc995ec --- /dev/null +++ b/src/tool/run/misc/wasm/wasm_exec.js @@ -0,0 +1,381 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +(() => { + // Map web browser API and Node.js API to a single common API (preferring web standards over Node.js API). + const isNodeJS = typeof process !== "undefined"; + if (isNodeJS) { + global.require = require; + global.fs = require("fs"); + + const nodeCrypto = require("crypto"); + global.crypto = { + getRandomValues(b) { + nodeCrypto.randomFillSync(b); + }, + }; + + global.performance = { + now() { + const [sec, nsec] = process.hrtime(); + return sec * 1000 + nsec / 1000000; + }, + }; + + const util = require("util"); + global.TextEncoder = util.TextEncoder; + global.TextDecoder = util.TextDecoder; + } else { + window.global = window; + + let outputBuf = ""; + global.fs = { + constants: {}, + writeSync(fd, buf) { + outputBuf += decoder.decode(buf); + const nl = outputBuf.lastIndexOf("\n"); + if (nl != -1) { + console.log(outputBuf.substr(0, nl)); + outputBuf = outputBuf.substr(nl + 1); + } + return buf.length; + }, + openSync(path, flags, mode) { + const err = new Error("not implemented"); + err.code = "ENOSYS"; + throw err; + }, + }; + } + + const encoder = new TextEncoder("utf-8"); + const decoder = new TextDecoder("utf-8"); + + global.Go = class { + constructor() { + this.argv = ["js"]; + this.env = {}; + this.exit = (code) => { + if (code !== 0) { + console.warn("exit code:", code); + } + }; + this._callbackTimeouts = new Map(); + this._nextCallbackTimeoutID = 1; + + const mem = () => { + // The buffer may change when requesting more memory. + return new DataView(this._inst.exports.mem.buffer); + } + + const setInt64 = (addr, v) => { + mem().setUint32(addr + 0, v, true); + mem().setUint32(addr + 4, Math.floor(v / 4294967296), true); + } + + const getInt64 = (addr) => { + const low = mem().getUint32(addr + 0, true); + const high = mem().getInt32(addr + 4, true); + return low + high * 4294967296; + } + + const loadValue = (addr) => { + const id = mem().getUint32(addr, true); + return this._values[id]; + } + + const storeValue = (addr, v) => { + if (v === undefined) { + mem().setUint32(addr, 0, true); + return; + } + if (v === null) { + mem().setUint32(addr, 1, true); + return; + } + this._values.push(v); + mem().setUint32(addr, this._values.length - 1, true); + } + + const loadSlice = (addr) => { + const array = getInt64(addr + 0); + const len = getInt64(addr + 8); + return new Uint8Array(this._inst.exports.mem.buffer, array, len); + } + + const loadSliceOfValues = (addr) => { + const array = getInt64(addr + 0); + const len = getInt64(addr + 8); + const a = new Array(len); + for (let i = 0; i < len; i++) { + const id = mem().getUint32(array + i * 4, true); + a[i] = this._values[id]; + } + return a; + } + + const loadString = (addr) => { + const saddr = getInt64(addr + 0); + const len = getInt64(addr + 8); + return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len)); + } + + const timeOrigin = Date.now() - performance.now(); + this.importObject = { + go: { + // func wasmExit(code int32) + "runtime.wasmExit": (sp) => { + this.exited = true; + this.exit(mem().getInt32(sp + 8, true)); + }, + + // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32) + "runtime.wasmWrite": (sp) => { + const fd = getInt64(sp + 8); + const p = getInt64(sp + 16); + const n = mem().getInt32(sp + 24, true); + fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n)); + }, + + // func nanotime() int64 + "runtime.nanotime": (sp) => { + setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000); + }, + + // func walltime() (sec int64, nsec int32) + "runtime.walltime": (sp) => { + const msec = (new Date).getTime(); + setInt64(sp + 8, msec / 1000); + mem().setInt32(sp + 16, (msec % 1000) * 1000000, true); + }, + + // func scheduleCallback(delay int64) int32 + "runtime.scheduleCallback": (sp) => { + const id = this._nextCallbackTimeoutID; + this._nextCallbackTimeoutID++; + this._callbackTimeouts.set(id, setTimeout( + () => { this._resolveCallbackPromise(); }, + getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early + )); + mem().setInt32(sp + 16, id, true); + }, + + // func clearScheduledCallback(id int32) + "runtime.clearScheduledCallback": (sp) => { + const id = mem().getInt32(sp + 8, true); + clearTimeout(this._callbackTimeouts.get(id)); + this._callbackTimeouts.delete(id); + }, + + // func getRandomData(r []byte) + "runtime.getRandomData": (sp) => { + crypto.getRandomValues(loadSlice(sp + 8)); + }, + + // func boolVal(value bool) ref + "syscall/js.boolVal": (sp) => { + storeValue(sp + 16, mem().getUint8(sp + 8) !== 0); + }, + + // func intVal(value int) ref + "syscall/js.intVal": (sp) => { + storeValue(sp + 16, getInt64(sp + 8)); + }, + + // func floatVal(value float64) ref + "syscall/js.floatVal": (sp) => { + storeValue(sp + 16, mem().getFloat64(sp + 8, true)); + }, + + // func stringVal(value string) ref + "syscall/js.stringVal": (sp) => { + storeValue(sp + 24, loadString(sp + 8)); + }, + + // func valueGet(v ref, p string) ref + "syscall/js.valueGet": (sp) => { + storeValue(sp + 32, Reflect.get(loadValue(sp + 8), loadString(sp + 16))); + }, + + // func valueSet(v ref, p string, x ref) + "syscall/js.valueSet": (sp) => { + Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32)); + }, + + // func valueIndex(v ref, i int) ref + "syscall/js.valueIndex": (sp) => { + storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16))); + }, + + // valueSetIndex(v ref, i int, x ref) + "syscall/js.valueSetIndex": (sp) => { + Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24)); + }, + + // func valueCall(v ref, m string, args []ref) (ref, bool) + "syscall/js.valueCall": (sp) => { + try { + const v = loadValue(sp + 8); + const m = Reflect.get(v, loadString(sp + 16)); + const args = loadSliceOfValues(sp + 32); + storeValue(sp + 56, Reflect.apply(m, v, args)); + mem().setUint8(sp + 60, 1); + } catch (err) { + storeValue(sp + 56, err); + mem().setUint8(sp + 60, 0); + } + }, + + // func valueInvoke(v ref, args []ref) (ref, bool) + "syscall/js.valueInvoke": (sp) => { + try { + const v = loadValue(sp + 8); + const args = loadSliceOfValues(sp + 16); + storeValue(sp + 40, Reflect.apply(v, undefined, args)); + mem().setUint8(sp + 44, 1); + } catch (err) { + storeValue(sp + 40, err); + mem().setUint8(sp + 44, 0); + } + }, + + // func valueNew(v ref, args []ref) (ref, bool) + "syscall/js.valueNew": (sp) => { + try { + const v = loadValue(sp + 8); + const args = loadSliceOfValues(sp + 16); + storeValue(sp + 40, Reflect.construct(v, args)); + mem().setUint8(sp + 44, 1); + } catch (err) { + storeValue(sp + 40, err); + mem().setUint8(sp + 44, 0); + } + }, + + // func valueFloat(v ref) float64 + "syscall/js.valueFloat": (sp) => { + mem().setFloat64(sp + 16, parseFloat(loadValue(sp + 8)), true); + }, + + // func valueInt(v ref) int + "syscall/js.valueInt": (sp) => { + setInt64(sp + 16, parseInt(loadValue(sp + 8))); + }, + + // func valueBool(v ref) bool + "syscall/js.valueBool": (sp) => { + mem().setUint8(sp + 16, !!loadValue(sp + 8)); + }, + + // func valueLength(v ref) int + "syscall/js.valueLength": (sp) => { + setInt64(sp + 16, parseInt(loadValue(sp + 8).length)); + }, + + // valuePrepareString(v ref) (ref, int) + "syscall/js.valuePrepareString": (sp) => { + const str = encoder.encode(String(loadValue(sp + 8))); + storeValue(sp + 16, str); + setInt64(sp + 24, str.length); + }, + + // valueLoadString(v ref, b []byte) + "syscall/js.valueLoadString": (sp) => { + const str = loadValue(sp + 8); + loadSlice(sp + 16).set(str); + }, + + "debug": (value) => { + console.log(value); + }, + } + }; + } + + async run(instance) { + this._inst = instance; + this._values = [ // TODO: garbage collection + undefined, + null, + global, + this._inst.exports.mem, + () => { // resolveCallbackPromise + if (this.exited) { + throw new Error("bad callback: Go program has already exited"); + } + setTimeout(this._resolveCallbackPromise, 0); // make sure it is asynchronous + }, + ]; + this.exited = false; + + const mem = new DataView(this._inst.exports.mem.buffer) + + // Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory. + let offset = 4096; + + const strPtr = (str) => { + let ptr = offset; + new Uint8Array(mem.buffer, offset, str.length + 1).set(encoder.encode(str + "\0")); + offset += str.length + (8 - (str.length % 8)); + return ptr; + }; + + const argc = this.argv.length; + + const argvPtrs = []; + this.argv.forEach((arg) => { + argvPtrs.push(strPtr(arg)); + }); + + const keys = Object.keys(this.env).sort(); + argvPtrs.push(keys.length); + keys.forEach((key) => { + argvPtrs.push(strPtr(`${key}=${this.env[key]}`)); + }); + + const argv = offset; + argvPtrs.forEach((ptr) => { + mem.setUint32(offset, ptr, true); + mem.setUint32(offset + 4, 0, true); + offset += 8; + }); + + while (true) { + const callbackPromise = new Promise((resolve) => { + this._resolveCallbackPromise = resolve; + }); + this._inst.exports.run(argc, argv); + if (this.exited) { + break; + } + await callbackPromise; + } + } + } + + if (isNodeJS) { + if (process.argv.length < 3) { + process.stderr.write("usage: go_js_wasm_exec [wasm binary] [arguments]\n"); + process.exit(1); + } + + const go = new Go(); + go.argv = process.argv.slice(2); + go.env = process.env; + go.exit = process.exit; + WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => { + process.on("exit", () => { // Node.js exits if no callback is pending + if (!go.exited) { + console.error("error: all goroutines asleep and no JavaScript callback pending - deadlock!"); + process.exit(1); + } + }); + return go.run(result.instance); + }).catch((err) => { + console.error(err); + go.exited = true; + process.exit(1); + }); + } +})(); \ No newline at end of file diff --git a/src/tool/run/packages/bytes.go b/src/tool/run/packages/bytes.go new file mode 100644 index 0000000..650c208 --- /dev/null +++ b/src/tool/run/packages/bytes.go @@ -0,0 +1,64 @@ +package packages + +import ( + "bytes" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["bytes"] = map[string]reflect.Value{ + "Compare": reflect.ValueOf(bytes.Compare), + "Contains": reflect.ValueOf(bytes.Contains), + "Count": reflect.ValueOf(bytes.Count), + "Equal": reflect.ValueOf(bytes.Equal), + "EqualFold": reflect.ValueOf(bytes.EqualFold), + "Fields": reflect.ValueOf(bytes.Fields), + "FieldsFunc": reflect.ValueOf(bytes.FieldsFunc), + "HasPrefix": reflect.ValueOf(bytes.HasPrefix), + "HasSuffix": reflect.ValueOf(bytes.HasSuffix), + "Index": reflect.ValueOf(bytes.Index), + "IndexAny": reflect.ValueOf(bytes.IndexAny), + "IndexByte": reflect.ValueOf(bytes.IndexByte), + "IndexFunc": reflect.ValueOf(bytes.IndexFunc), + "IndexRune": reflect.ValueOf(bytes.IndexRune), + "Join": reflect.ValueOf(bytes.Join), + "LastIndex": reflect.ValueOf(bytes.LastIndex), + "LastIndexAny": reflect.ValueOf(bytes.LastIndexAny), + "LastIndexByte": reflect.ValueOf(bytes.LastIndexByte), + "LastIndexFunc": reflect.ValueOf(bytes.LastIndexFunc), + "Map": reflect.ValueOf(bytes.Map), + "NewBuffer": reflect.ValueOf(bytes.NewBuffer), + "NewBufferString": reflect.ValueOf(bytes.NewBufferString), + "NewReader": reflect.ValueOf(bytes.NewReader), + "Repeat": reflect.ValueOf(bytes.Repeat), + "Replace": reflect.ValueOf(bytes.Replace), + "Runes": reflect.ValueOf(bytes.Runes), + "Split": reflect.ValueOf(bytes.Split), + "SplitAfter": reflect.ValueOf(bytes.SplitAfter), + "SplitAfterN": reflect.ValueOf(bytes.SplitAfterN), + "SplitN": reflect.ValueOf(bytes.SplitN), + "Title": reflect.ValueOf(bytes.Title), + "ToLower": reflect.ValueOf(bytes.ToLower), + "ToLowerSpecial": reflect.ValueOf(bytes.ToLowerSpecial), + "ToTitle": reflect.ValueOf(bytes.ToTitle), + "ToTitleSpecial": reflect.ValueOf(bytes.ToTitleSpecial), + "ToUpper": reflect.ValueOf(bytes.ToUpper), + "ToUpperSpecial": reflect.ValueOf(bytes.ToUpperSpecial), + "Trim": reflect.ValueOf(bytes.Trim), + "TrimFunc": reflect.ValueOf(bytes.TrimFunc), + "TrimLeft": reflect.ValueOf(bytes.TrimLeft), + "TrimLeftFunc": reflect.ValueOf(bytes.TrimLeftFunc), + "TrimPrefix": reflect.ValueOf(bytes.TrimPrefix), + "TrimRight": reflect.ValueOf(bytes.TrimRight), + "TrimRightFunc": reflect.ValueOf(bytes.TrimRightFunc), + "TrimSpace": reflect.ValueOf(bytes.TrimSpace), + "TrimSuffix": reflect.ValueOf(bytes.TrimSuffix), + } + env.PackageTypes["bytes"] = map[string]reflect.Type{ + "Buffer": reflect.TypeOf(bytes.Buffer{}), + "Reader": reflect.TypeOf(bytes.Reader{}), + } + bytesGo17() +} diff --git a/src/tool/run/packages/bytesGo17.go b/src/tool/run/packages/bytesGo17.go new file mode 100644 index 0000000..4ef560f --- /dev/null +++ b/src/tool/run/packages/bytesGo17.go @@ -0,0 +1,14 @@ +// +build go1.7 + +package packages + +import ( + "bytes" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func bytesGo17() { + env.Packages["bytes"]["ContainsRune"] = reflect.ValueOf(bytes.ContainsRune) +} diff --git a/src/tool/run/packages/bytesNotGo17.go b/src/tool/run/packages/bytesNotGo17.go new file mode 100644 index 0000000..795edb6 --- /dev/null +++ b/src/tool/run/packages/bytesNotGo17.go @@ -0,0 +1,5 @@ +// +build !go1.7 + +package packages + +func bytesGo17() {} diff --git a/src/tool/run/packages/encoding.json.go b/src/tool/run/packages/encoding.json.go new file mode 100644 index 0000000..2fe2477 --- /dev/null +++ b/src/tool/run/packages/encoding.json.go @@ -0,0 +1,15 @@ +package packages + +import ( + "encoding/json" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["encoding/json"] = map[string]reflect.Value{ + "Marshal": reflect.ValueOf(json.Marshal), + "Unmarshal": reflect.ValueOf(json.Unmarshal), + } +} diff --git a/src/tool/run/packages/errors.go b/src/tool/run/packages/errors.go new file mode 100644 index 0000000..cf56660 --- /dev/null +++ b/src/tool/run/packages/errors.go @@ -0,0 +1,14 @@ +package packages + +import ( + "errors" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["errors"] = map[string]reflect.Value{ + "New": reflect.ValueOf(errors.New), + } +} diff --git a/src/tool/run/packages/flag.go b/src/tool/run/packages/flag.go new file mode 100644 index 0000000..538f975 --- /dev/null +++ b/src/tool/run/packages/flag.go @@ -0,0 +1,48 @@ +package packages + +import ( + "flag" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["flag"] = map[string]reflect.Value{ + "Arg": reflect.ValueOf(flag.Arg), + "Args": reflect.ValueOf(flag.Args), + "Bool": reflect.ValueOf(flag.Bool), + "BoolVar": reflect.ValueOf(flag.BoolVar), + "CommandLine": reflect.ValueOf(flag.CommandLine), + "ContinueOnError": reflect.ValueOf(flag.ContinueOnError), + "Duration": reflect.ValueOf(flag.Duration), + "DurationVar": reflect.ValueOf(flag.DurationVar), + "ErrHelp": reflect.ValueOf(flag.ErrHelp), + "ExitOnError": reflect.ValueOf(flag.ExitOnError), + "Float64": reflect.ValueOf(flag.Float64), + "Float64Var": reflect.ValueOf(flag.Float64Var), + "Int": reflect.ValueOf(flag.Int), + "Int64": reflect.ValueOf(flag.Int64), + "Int64Var": reflect.ValueOf(flag.Int64Var), + "IntVar": reflect.ValueOf(flag.IntVar), + "Lookup": reflect.ValueOf(flag.Lookup), + "NArg": reflect.ValueOf(flag.NArg), + "NFlag": reflect.ValueOf(flag.NFlag), + "NewFlagSet": reflect.ValueOf(flag.NewFlagSet), + "PanicOnError": reflect.ValueOf(flag.PanicOnError), + "Parse": reflect.ValueOf(flag.Parse), + "Parsed": reflect.ValueOf(flag.Parsed), + "PrintDefaults": reflect.ValueOf(flag.PrintDefaults), + "Set": reflect.ValueOf(flag.Set), + "String": reflect.ValueOf(flag.String), + "StringVar": reflect.ValueOf(flag.StringVar), + "Uint": reflect.ValueOf(flag.Uint), + "Uint64": reflect.ValueOf(flag.Uint64), + "Uint64Var": reflect.ValueOf(flag.Uint64Var), + "UintVar": reflect.ValueOf(flag.UintVar), + "Usage": reflect.ValueOf(flag.Usage), + "Var": reflect.ValueOf(flag.Var), + "Visit": reflect.ValueOf(flag.Visit), + "VisitAll": reflect.ValueOf(flag.VisitAll), + } +} diff --git a/src/tool/run/packages/fmt.go b/src/tool/run/packages/fmt.go new file mode 100644 index 0000000..d267740 --- /dev/null +++ b/src/tool/run/packages/fmt.go @@ -0,0 +1,32 @@ +package packages + +import ( + "fmt" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["fmt"] = map[string]reflect.Value{ + "Errorf": reflect.ValueOf(fmt.Errorf), + "Fprint": reflect.ValueOf(fmt.Fprint), + "Fprintf": reflect.ValueOf(fmt.Fprintf), + "Fprintln": reflect.ValueOf(fmt.Fprintln), + "Fscan": reflect.ValueOf(fmt.Fscan), + "Fscanf": reflect.ValueOf(fmt.Fscanf), + "Fscanln": reflect.ValueOf(fmt.Fscanln), + "Print": reflect.ValueOf(fmt.Print), + "Printf": reflect.ValueOf(fmt.Printf), + "Println": reflect.ValueOf(fmt.Println), + "Scan": reflect.ValueOf(fmt.Scan), + "Scanf": reflect.ValueOf(fmt.Scanf), + "Scanln": reflect.ValueOf(fmt.Scanln), + "Sprint": reflect.ValueOf(fmt.Sprint), + "Sprintf": reflect.ValueOf(fmt.Sprintf), + "Sprintln": reflect.ValueOf(fmt.Sprintln), + "Sscan": reflect.ValueOf(fmt.Sscan), + "Sscanf": reflect.ValueOf(fmt.Sscanf), + "Sscanln": reflect.ValueOf(fmt.Sscanln), + } +} diff --git a/src/tool/run/packages/io.go b/src/tool/run/packages/io.go new file mode 100644 index 0000000..eaa103b --- /dev/null +++ b/src/tool/run/packages/io.go @@ -0,0 +1,30 @@ +package packages + +import ( + "io" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["io"] = map[string]reflect.Value{ + "Copy": reflect.ValueOf(io.Copy), + "CopyN": reflect.ValueOf(io.CopyN), + "EOF": reflect.ValueOf(io.EOF), + "ErrClosedPipe": reflect.ValueOf(io.ErrClosedPipe), + "ErrNoProgress": reflect.ValueOf(io.ErrNoProgress), + "ErrShortBuffer": reflect.ValueOf(io.ErrShortBuffer), + "ErrShortWrite": reflect.ValueOf(io.ErrShortWrite), + "ErrUnexpectedEOF": reflect.ValueOf(io.ErrUnexpectedEOF), + "LimitReader": reflect.ValueOf(io.LimitReader), + "MultiReader": reflect.ValueOf(io.MultiReader), + "MultiWriter": reflect.ValueOf(io.MultiWriter), + "NewSectionReader": reflect.ValueOf(io.NewSectionReader), + "Pipe": reflect.ValueOf(io.Pipe), + "ReadAtLeast": reflect.ValueOf(io.ReadAtLeast), + "ReadFull": reflect.ValueOf(io.ReadFull), + "TeeReader": reflect.ValueOf(io.TeeReader), + "WriteString": reflect.ValueOf(io.WriteString), + } +} diff --git a/src/tool/run/packages/io.ioutil.go b/src/tool/run/packages/io.ioutil.go new file mode 100644 index 0000000..50cb0ba --- /dev/null +++ b/src/tool/run/packages/io.ioutil.go @@ -0,0 +1,17 @@ +package packages + +import ( + "io/ioutil" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["io/ioutil"] = map[string]reflect.Value{ + "ReadAll": reflect.ValueOf(ioutil.ReadAll), + "ReadDir": reflect.ValueOf(ioutil.ReadDir), + "ReadFile": reflect.ValueOf(ioutil.ReadFile), + "WriteFile": reflect.ValueOf(ioutil.WriteFile), + } +} diff --git a/src/tool/run/packages/log.go b/src/tool/run/packages/log.go new file mode 100644 index 0000000..e441792 --- /dev/null +++ b/src/tool/run/packages/log.go @@ -0,0 +1,29 @@ +package packages + +import ( + "log" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["log"] = map[string]reflect.Value{ + "Fatal": reflect.ValueOf(log.Fatal), + "Fatalf": reflect.ValueOf(log.Fatalf), + "Fatalln": reflect.ValueOf(log.Fatalln), + "Flags": reflect.ValueOf(log.Flags), + "New": reflect.ValueOf(log.New), + "Output": reflect.ValueOf(log.Output), + "Panic": reflect.ValueOf(log.Panic), + "Panicf": reflect.ValueOf(log.Panicf), + "Panicln": reflect.ValueOf(log.Panicln), + "Prefix": reflect.ValueOf(log.Prefix), + "Print": reflect.ValueOf(log.Print), + "Printf": reflect.ValueOf(log.Printf), + "Println": reflect.ValueOf(log.Println), + "SetFlags": reflect.ValueOf(log.SetFlags), + "SetOutput": reflect.ValueOf(log.SetOutput), + "SetPrefix": reflect.ValueOf(log.SetPrefix), + } +} diff --git a/src/tool/run/packages/math.big.go b/src/tool/run/packages/math.big.go new file mode 100644 index 0000000..8176e74 --- /dev/null +++ b/src/tool/run/packages/math.big.go @@ -0,0 +1,32 @@ +package packages + +import ( + "math/big" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["math/big"] = map[string]reflect.Value{ + "Above": reflect.ValueOf(big.Above), + "AwayFromZero": reflect.ValueOf(big.AwayFromZero), + "Below": reflect.ValueOf(big.Below), + "Exact": reflect.ValueOf(big.Exact), + "Jacobi": reflect.ValueOf(big.Jacobi), + "MaxBase": reflect.ValueOf(big.MaxBase), + "MaxExp": reflect.ValueOf(big.MaxExp), + // TODO: https://github.com/surdeus/goblin/src/tool/run/issues/49 + // "MaxPrec": reflect.ValueOf(big.MaxPrec), + "MinExp": reflect.ValueOf(big.MinExp), + "NewFloat": reflect.ValueOf(big.NewFloat), + "NewInt": reflect.ValueOf(big.NewInt), + "NewRat": reflect.ValueOf(big.NewRat), + "ParseFloat": reflect.ValueOf(big.ParseFloat), + "ToNearestAway": reflect.ValueOf(big.ToNearestAway), + "ToNearestEven": reflect.ValueOf(big.ToNearestEven), + "ToNegativeInf": reflect.ValueOf(big.ToNegativeInf), + "ToPositiveInf": reflect.ValueOf(big.ToPositiveInf), + "ToZero": reflect.ValueOf(big.ToZero), + } +} diff --git a/src/tool/run/packages/math.go b/src/tool/run/packages/math.go new file mode 100644 index 0000000..c20536c --- /dev/null +++ b/src/tool/run/packages/math.go @@ -0,0 +1,74 @@ +package packages + +import ( + "math" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["math"] = map[string]reflect.Value{ + "Abs": reflect.ValueOf(math.Abs), + "Acos": reflect.ValueOf(math.Acos), + "Acosh": reflect.ValueOf(math.Acosh), + "Asin": reflect.ValueOf(math.Asin), + "Asinh": reflect.ValueOf(math.Asinh), + "Atan": reflect.ValueOf(math.Atan), + "Atan2": reflect.ValueOf(math.Atan2), + "Atanh": reflect.ValueOf(math.Atanh), + "Cbrt": reflect.ValueOf(math.Cbrt), + "Ceil": reflect.ValueOf(math.Ceil), + "Copysign": reflect.ValueOf(math.Copysign), + "Cos": reflect.ValueOf(math.Cos), + "Cosh": reflect.ValueOf(math.Cosh), + "Dim": reflect.ValueOf(math.Dim), + "Erf": reflect.ValueOf(math.Erf), + "Erfc": reflect.ValueOf(math.Erfc), + "Exp": reflect.ValueOf(math.Exp), + "Exp2": reflect.ValueOf(math.Exp2), + "Expm1": reflect.ValueOf(math.Expm1), + "Float32bits": reflect.ValueOf(math.Float32bits), + "Float32frombits": reflect.ValueOf(math.Float32frombits), + "Float64bits": reflect.ValueOf(math.Float64bits), + "Float64frombits": reflect.ValueOf(math.Float64frombits), + "Floor": reflect.ValueOf(math.Floor), + "Frexp": reflect.ValueOf(math.Frexp), + "Gamma": reflect.ValueOf(math.Gamma), + "Hypot": reflect.ValueOf(math.Hypot), + "Ilogb": reflect.ValueOf(math.Ilogb), + "Inf": reflect.ValueOf(math.Inf), + "IsInf": reflect.ValueOf(math.IsInf), + "IsNaN": reflect.ValueOf(math.IsNaN), + "J0": reflect.ValueOf(math.J0), + "J1": reflect.ValueOf(math.J1), + "Jn": reflect.ValueOf(math.Jn), + "Ldexp": reflect.ValueOf(math.Ldexp), + "Lgamma": reflect.ValueOf(math.Lgamma), + "Log": reflect.ValueOf(math.Log), + "Log10": reflect.ValueOf(math.Log10), + "Log1p": reflect.ValueOf(math.Log1p), + "Log2": reflect.ValueOf(math.Log2), + "Logb": reflect.ValueOf(math.Logb), + "Max": reflect.ValueOf(math.Max), + "Min": reflect.ValueOf(math.Min), + "Mod": reflect.ValueOf(math.Mod), + "Modf": reflect.ValueOf(math.Modf), + "NaN": reflect.ValueOf(math.NaN), + "Nextafter": reflect.ValueOf(math.Nextafter), + "Pow": reflect.ValueOf(math.Pow), + "Pow10": reflect.ValueOf(math.Pow10), + "Remainder": reflect.ValueOf(math.Remainder), + "Signbit": reflect.ValueOf(math.Signbit), + "Sin": reflect.ValueOf(math.Sin), + "Sincos": reflect.ValueOf(math.Sincos), + "Sinh": reflect.ValueOf(math.Sinh), + "Sqrt": reflect.ValueOf(math.Sqrt), + "Tan": reflect.ValueOf(math.Tan), + "Tanh": reflect.ValueOf(math.Tanh), + "Trunc": reflect.ValueOf(math.Trunc), + "Y0": reflect.ValueOf(math.Y0), + "Y1": reflect.ValueOf(math.Y1), + "Yn": reflect.ValueOf(math.Yn), + } +} diff --git a/src/tool/run/packages/math.rand.go b/src/tool/run/packages/math.rand.go new file mode 100644 index 0000000..cf68ca6 --- /dev/null +++ b/src/tool/run/packages/math.rand.go @@ -0,0 +1,26 @@ +package packages + +import ( + "math/rand" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["math/rand"] = map[string]reflect.Value{ + "ExpFloat64": reflect.ValueOf(rand.ExpFloat64), + "Float32": reflect.ValueOf(rand.Float32), + "Float64": reflect.ValueOf(rand.Float64), + "Int": reflect.ValueOf(rand.Int), + "Int31": reflect.ValueOf(rand.Int31), + "Int31n": reflect.ValueOf(rand.Int31n), + "Int63": reflect.ValueOf(rand.Int63), + "Int63n": reflect.ValueOf(rand.Int63n), + "Intn": reflect.ValueOf(rand.Intn), + "NormFloat64": reflect.ValueOf(rand.NormFloat64), + "Perm": reflect.ValueOf(rand.Perm), + "Seed": reflect.ValueOf(rand.Seed), + "Uint32": reflect.ValueOf(rand.Uint32), + } +} diff --git a/src/tool/run/packages/net.go b/src/tool/run/packages/net.go new file mode 100644 index 0000000..a068ba1 --- /dev/null +++ b/src/tool/run/packages/net.go @@ -0,0 +1,76 @@ +// +build !appengine + +package packages + +import ( + "net" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["net"] = map[string]reflect.Value{ + "CIDRMask": reflect.ValueOf(net.CIDRMask), + "Dial": reflect.ValueOf(net.Dial), + "DialIP": reflect.ValueOf(net.DialIP), + "DialTCP": reflect.ValueOf(net.DialTCP), + "DialTimeout": reflect.ValueOf(net.DialTimeout), + "DialUDP": reflect.ValueOf(net.DialUDP), + "DialUnix": reflect.ValueOf(net.DialUnix), + "ErrWriteToConnected": reflect.ValueOf(net.ErrWriteToConnected), + "FileConn": reflect.ValueOf(net.FileConn), + "FileListener": reflect.ValueOf(net.FileListener), + "FilePacketConn": reflect.ValueOf(net.FilePacketConn), + "FlagBroadcast": reflect.ValueOf(net.FlagBroadcast), + "FlagLoopback": reflect.ValueOf(net.FlagLoopback), + "FlagMulticast": reflect.ValueOf(net.FlagMulticast), + "FlagPointToPoint": reflect.ValueOf(net.FlagPointToPoint), + "FlagUp": reflect.ValueOf(net.FlagUp), + "IPv4": reflect.ValueOf(net.IPv4), + "IPv4Mask": reflect.ValueOf(net.IPv4Mask), + "IPv4allrouter": reflect.ValueOf(net.IPv4allrouter), + "IPv4allsys": reflect.ValueOf(net.IPv4allsys), + "IPv4bcast": reflect.ValueOf(net.IPv4bcast), + "IPv4len": reflect.ValueOf(net.IPv4len), + "IPv4zero": reflect.ValueOf(net.IPv4zero), + "IPv6interfacelocalallnodes": reflect.ValueOf(net.IPv6interfacelocalallnodes), + "IPv6len": reflect.ValueOf(net.IPv6len), + "IPv6linklocalallnodes": reflect.ValueOf(net.IPv6linklocalallnodes), + "IPv6linklocalallrouters": reflect.ValueOf(net.IPv6linklocalallrouters), + "IPv6loopback": reflect.ValueOf(net.IPv6loopback), + "IPv6unspecified": reflect.ValueOf(net.IPv6unspecified), + "IPv6zero": reflect.ValueOf(net.IPv6zero), + "InterfaceAddrs": reflect.ValueOf(net.InterfaceAddrs), + "InterfaceByIndex": reflect.ValueOf(net.InterfaceByIndex), + "InterfaceByName": reflect.ValueOf(net.InterfaceByName), + "Interfaces": reflect.ValueOf(net.Interfaces), + "JoinHostPort": reflect.ValueOf(net.JoinHostPort), + "Listen": reflect.ValueOf(net.Listen), + "ListenIP": reflect.ValueOf(net.ListenIP), + "ListenMulticastUDP": reflect.ValueOf(net.ListenMulticastUDP), + "ListenPacket": reflect.ValueOf(net.ListenPacket), + "ListenTCP": reflect.ValueOf(net.ListenTCP), + "ListenUDP": reflect.ValueOf(net.ListenUDP), + "ListenUnix": reflect.ValueOf(net.ListenUnix), + "ListenUnixgram": reflect.ValueOf(net.ListenUnixgram), + "LookupAddr": reflect.ValueOf(net.LookupAddr), + "LookupCNAME": reflect.ValueOf(net.LookupCNAME), + "LookupHost": reflect.ValueOf(net.LookupHost), + "LookupIP": reflect.ValueOf(net.LookupIP), + "LookupMX": reflect.ValueOf(net.LookupMX), + "LookupNS": reflect.ValueOf(net.LookupNS), + "LookupPort": reflect.ValueOf(net.LookupPort), + "LookupSRV": reflect.ValueOf(net.LookupSRV), + "LookupTXT": reflect.ValueOf(net.LookupTXT), + "ParseCIDR": reflect.ValueOf(net.ParseCIDR), + "ParseIP": reflect.ValueOf(net.ParseIP), + "ParseMAC": reflect.ValueOf(net.ParseMAC), + "Pipe": reflect.ValueOf(net.Pipe), + "ResolveIPAddr": reflect.ValueOf(net.ResolveIPAddr), + "ResolveTCPAddr": reflect.ValueOf(net.ResolveTCPAddr), + "ResolveUDPAddr": reflect.ValueOf(net.ResolveUDPAddr), + "ResolveUnixAddr": reflect.ValueOf(net.ResolveUnixAddr), + "SplitHostPort": reflect.ValueOf(net.SplitHostPort), + } +} diff --git a/src/tool/run/packages/net.http.cookiejar.go b/src/tool/run/packages/net.http.cookiejar.go new file mode 100644 index 0000000..1fd0133 --- /dev/null +++ b/src/tool/run/packages/net.http.cookiejar.go @@ -0,0 +1,17 @@ +package packages + +import ( + "net/http/cookiejar" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["net/http/cookiejar"] = map[string]reflect.Value{ + "New": reflect.ValueOf(cookiejar.New), + } + env.PackageTypes["net/http/cookiejar"] = map[string]reflect.Type{ + "Options": reflect.TypeOf(cookiejar.Options{}), + } +} diff --git a/src/tool/run/packages/net.http.go b/src/tool/run/packages/net.http.go new file mode 100644 index 0000000..1fd5c1c --- /dev/null +++ b/src/tool/run/packages/net.http.go @@ -0,0 +1,32 @@ +// +build !appengine + +package packages + +import ( + "net/http" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["net/http"] = map[string]reflect.Value{ + "DefaultClient": reflect.ValueOf(http.DefaultClient), + "DefaultServeMux": reflect.ValueOf(http.DefaultServeMux), + "DefaultTransport": reflect.ValueOf(http.DefaultTransport), + "Handle": reflect.ValueOf(http.Handle), + "HandleFunc": reflect.ValueOf(http.HandleFunc), + "ListenAndServe": reflect.ValueOf(http.ListenAndServe), + "ListenAndServeTLS": reflect.ValueOf(http.ListenAndServeTLS), + "NewRequest": reflect.ValueOf(http.NewRequest), + "NewServeMux": reflect.ValueOf(http.NewServeMux), + "Serve": reflect.ValueOf(http.Serve), + "SetCookie": reflect.ValueOf(http.SetCookie), + } + env.PackageTypes["net/http"] = map[string]reflect.Type{ + "Client": reflect.TypeOf(http.Client{}), + "Cookie": reflect.TypeOf(http.Cookie{}), + "Request": reflect.TypeOf(http.Request{}), + "Response": reflect.TypeOf(http.Response{}), + } +} diff --git a/src/tool/run/packages/net.url.go b/src/tool/run/packages/net.url.go new file mode 100644 index 0000000..2c3b6d9 --- /dev/null +++ b/src/tool/run/packages/net.url.go @@ -0,0 +1,27 @@ +// +build !appengine + +package packages + +import ( + "net/url" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["net/url"] = map[string]reflect.Value{ + "QueryEscape": reflect.ValueOf(url.QueryEscape), + "QueryUnescape": reflect.ValueOf(url.QueryUnescape), + "Parse": reflect.ValueOf(url.Parse), + "ParseRequestURI": reflect.ValueOf(url.ParseRequestURI), + "User": reflect.ValueOf(url.User), + "UserPassword": reflect.ValueOf(url.UserPassword), + "ParseQuery": reflect.ValueOf(url.ParseQuery), + } + env.PackageTypes["net/url"] = map[string]reflect.Type{ + "Error": reflect.TypeOf(url.Error{}), + "URL": reflect.TypeOf(url.URL{}), + "Values": reflect.TypeOf(url.Values{}), + } +} diff --git a/src/tool/run/packages/os.exec.go b/src/tool/run/packages/os.exec.go new file mode 100644 index 0000000..9fe49ea --- /dev/null +++ b/src/tool/run/packages/os.exec.go @@ -0,0 +1,16 @@ +package packages + +import ( + "os/exec" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["os/exec"] = map[string]reflect.Value{ + "ErrNotFound": reflect.ValueOf(exec.ErrNotFound), + "LookPath": reflect.ValueOf(exec.LookPath), + "Command": reflect.ValueOf(exec.Command), + } +} diff --git a/src/tool/run/packages/os.go b/src/tool/run/packages/os.go new file mode 100644 index 0000000..ea01757 --- /dev/null +++ b/src/tool/run/packages/os.go @@ -0,0 +1,102 @@ +package packages + +import ( + "os" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["os"] = map[string]reflect.Value{ + "Args": reflect.ValueOf(os.Args), + "Chdir": reflect.ValueOf(os.Chdir), + "Chmod": reflect.ValueOf(os.Chmod), + "Chown": reflect.ValueOf(os.Chown), + "Chtimes": reflect.ValueOf(os.Chtimes), + "Clearenv": reflect.ValueOf(os.Clearenv), + "Create": reflect.ValueOf(os.Create), + "DevNull": reflect.ValueOf(os.DevNull), + "Environ": reflect.ValueOf(os.Environ), + "ErrExist": reflect.ValueOf(os.ErrExist), + "ErrInvalid": reflect.ValueOf(os.ErrInvalid), + "ErrNotExist": reflect.ValueOf(os.ErrNotExist), + "ErrPermission": reflect.ValueOf(os.ErrPermission), + "Exit": reflect.ValueOf(os.Exit), + "Expand": reflect.ValueOf(os.Expand), + "ExpandEnv": reflect.ValueOf(os.ExpandEnv), + "FindProcess": reflect.ValueOf(os.FindProcess), + "Getegid": reflect.ValueOf(os.Getegid), + "Getenv": reflect.ValueOf(os.Getenv), + "Geteuid": reflect.ValueOf(os.Geteuid), + "Getgid": reflect.ValueOf(os.Getgid), + "Getgroups": reflect.ValueOf(os.Getgroups), + "Getpagesize": reflect.ValueOf(os.Getpagesize), + "Getpid": reflect.ValueOf(os.Getpid), + "Getuid": reflect.ValueOf(os.Getuid), + "Getwd": reflect.ValueOf(os.Getwd), + "Hostname": reflect.ValueOf(os.Hostname), + "Interrupt": reflect.ValueOf(os.Interrupt), + "IsExist": reflect.ValueOf(os.IsExist), + "IsNotExist": reflect.ValueOf(os.IsNotExist), + "IsPathSeparator": reflect.ValueOf(os.IsPathSeparator), + "IsPermission": reflect.ValueOf(os.IsPermission), + "Kill": reflect.ValueOf(os.Kill), + "Lchown": reflect.ValueOf(os.Lchown), + "Link": reflect.ValueOf(os.Link), + "Lstat": reflect.ValueOf(os.Lstat), + "Mkdir": reflect.ValueOf(os.Mkdir), + "MkdirAll": reflect.ValueOf(os.MkdirAll), + "ModeAppend": reflect.ValueOf(os.ModeAppend), + "ModeCharDevice": reflect.ValueOf(os.ModeCharDevice), + "ModeDevice": reflect.ValueOf(os.ModeDevice), + "ModeDir": reflect.ValueOf(os.ModeDir), + "ModeExclusive": reflect.ValueOf(os.ModeExclusive), + "ModeNamedPipe": reflect.ValueOf(os.ModeNamedPipe), + "ModePerm": reflect.ValueOf(os.ModePerm), + "ModeSetgid": reflect.ValueOf(os.ModeSetgid), + "ModeSetuid": reflect.ValueOf(os.ModeSetuid), + "ModeSocket": reflect.ValueOf(os.ModeSocket), + "ModeSticky": reflect.ValueOf(os.ModeSticky), + "ModeSymlink": reflect.ValueOf(os.ModeSymlink), + "ModeTemporary": reflect.ValueOf(os.ModeTemporary), + "ModeType": reflect.ValueOf(os.ModeType), + "NewFile": reflect.ValueOf(os.NewFile), + "NewSyscallError": reflect.ValueOf(os.NewSyscallError), + "O_APPEND": reflect.ValueOf(os.O_APPEND), + "O_CREATE": reflect.ValueOf(os.O_CREATE), + "O_EXCL": reflect.ValueOf(os.O_EXCL), + "O_RDONLY": reflect.ValueOf(os.O_RDONLY), + "O_RDWR": reflect.ValueOf(os.O_RDWR), + "O_SYNC": reflect.ValueOf(os.O_SYNC), + "O_TRUNC": reflect.ValueOf(os.O_TRUNC), + "O_WRONLY": reflect.ValueOf(os.O_WRONLY), + "Open": reflect.ValueOf(os.Open), + "OpenFile": reflect.ValueOf(os.OpenFile), + "PathListSeparator": reflect.ValueOf(os.PathListSeparator), + "PathSeparator": reflect.ValueOf(os.PathSeparator), + "Pipe": reflect.ValueOf(os.Pipe), + "Readlink": reflect.ValueOf(os.Readlink), + "Remove": reflect.ValueOf(os.Remove), + "RemoveAll": reflect.ValueOf(os.RemoveAll), + "Rename": reflect.ValueOf(os.Rename), + "SEEK_CUR": reflect.ValueOf(os.SEEK_CUR), + "SEEK_END": reflect.ValueOf(os.SEEK_END), + "SEEK_SET": reflect.ValueOf(os.SEEK_SET), + "SameFile": reflect.ValueOf(os.SameFile), + "Setenv": reflect.ValueOf(os.Setenv), + "StartProcess": reflect.ValueOf(os.StartProcess), + "Stat": reflect.ValueOf(os.Stat), + "Stderr": reflect.ValueOf(os.Stderr), + "Stdin": reflect.ValueOf(os.Stdin), + "Stdout": reflect.ValueOf(os.Stdout), + "Symlink": reflect.ValueOf(os.Symlink), + "TempDir": reflect.ValueOf(os.TempDir), + "Truncate": reflect.ValueOf(os.Truncate), + } + var signal os.Signal + env.PackageTypes["os"] = map[string]reflect.Type{ + "Signal": reflect.TypeOf(&signal).Elem(), + } + osNotAppEngine() +} diff --git a/src/tool/run/packages/os.signal.go b/src/tool/run/packages/os.signal.go new file mode 100644 index 0000000..4603c77 --- /dev/null +++ b/src/tool/run/packages/os.signal.go @@ -0,0 +1,15 @@ +package packages + +import ( + "os/signal" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["os/signal"] = map[string]reflect.Value{ + "Notify": reflect.ValueOf(signal.Notify), + "Stop": reflect.ValueOf(signal.Stop), + } +} diff --git a/src/tool/run/packages/osAppEngine.go b/src/tool/run/packages/osAppEngine.go new file mode 100644 index 0000000..64892f8 --- /dev/null +++ b/src/tool/run/packages/osAppEngine.go @@ -0,0 +1,5 @@ +// +build appengine + +package packages + +func osNotAppEngine() {} diff --git a/src/tool/run/packages/osNotAppEngine.go b/src/tool/run/packages/osNotAppEngine.go new file mode 100644 index 0000000..5997ea2 --- /dev/null +++ b/src/tool/run/packages/osNotAppEngine.go @@ -0,0 +1,14 @@ +// +build !appengine + +package packages + +import ( + "os" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func osNotAppEngine() { + env.Packages["os"]["Getppid"] = reflect.ValueOf(os.Getppid) +} diff --git a/src/tool/run/packages/path.filepath.go b/src/tool/run/packages/path.filepath.go new file mode 100644 index 0000000..585c3a0 --- /dev/null +++ b/src/tool/run/packages/path.filepath.go @@ -0,0 +1,30 @@ +package packages + +import ( + "path/filepath" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["path/filepath"] = map[string]reflect.Value{ + "Abs": reflect.ValueOf(filepath.Abs), + "Base": reflect.ValueOf(filepath.Base), + "Clean": reflect.ValueOf(filepath.Clean), + "Dir": reflect.ValueOf(filepath.Dir), + "EvalSymlinks": reflect.ValueOf(filepath.EvalSymlinks), + "Ext": reflect.ValueOf(filepath.Ext), + "FromSlash": reflect.ValueOf(filepath.FromSlash), + "Glob": reflect.ValueOf(filepath.Glob), + "HasPrefix": reflect.ValueOf(filepath.HasPrefix), + "IsAbs": reflect.ValueOf(filepath.IsAbs), + "Join": reflect.ValueOf(filepath.Join), + "Match": reflect.ValueOf(filepath.Match), + "Rel": reflect.ValueOf(filepath.Rel), + "Split": reflect.ValueOf(filepath.Split), + "SplitList": reflect.ValueOf(filepath.SplitList), + "ToSlash": reflect.ValueOf(filepath.ToSlash), + "VolumeName": reflect.ValueOf(filepath.VolumeName), + } +} diff --git a/src/tool/run/packages/path.go b/src/tool/run/packages/path.go new file mode 100644 index 0000000..e615818 --- /dev/null +++ b/src/tool/run/packages/path.go @@ -0,0 +1,22 @@ +package packages + +import ( + "path" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["path"] = map[string]reflect.Value{ + "Base": reflect.ValueOf(path.Base), + "Clean": reflect.ValueOf(path.Clean), + "Dir": reflect.ValueOf(path.Dir), + "ErrBadPattern": reflect.ValueOf(path.ErrBadPattern), + "Ext": reflect.ValueOf(path.Ext), + "IsAbs": reflect.ValueOf(path.IsAbs), + "Join": reflect.ValueOf(path.Join), + "Match": reflect.ValueOf(path.Match), + "Split": reflect.ValueOf(path.Split), + } +} diff --git a/src/tool/run/packages/regexp.go b/src/tool/run/packages/regexp.go new file mode 100644 index 0000000..96294bb --- /dev/null +++ b/src/tool/run/packages/regexp.go @@ -0,0 +1,21 @@ +package packages + +import ( + "reflect" + "regexp" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["regexp"] = map[string]reflect.Value{ + "Match": reflect.ValueOf(regexp.Match), + "MatchReader": reflect.ValueOf(regexp.MatchReader), + "MatchString": reflect.ValueOf(regexp.MatchString), + "QuoteMeta": reflect.ValueOf(regexp.QuoteMeta), + "Compile": reflect.ValueOf(regexp.Compile), + "CompilePOSIX": reflect.ValueOf(regexp.CompilePOSIX), + "MustCompile": reflect.ValueOf(regexp.MustCompile), + "MustCompilePOSIX": reflect.ValueOf(regexp.MustCompilePOSIX), + } +} diff --git a/src/tool/run/packages/runtime.go b/src/tool/run/packages/runtime.go new file mode 100644 index 0000000..22e9534 --- /dev/null +++ b/src/tool/run/packages/runtime.go @@ -0,0 +1,19 @@ +package packages + +import ( + "reflect" + "runtime" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["runtime"] = map[string]reflect.Value{ + "GC": reflect.ValueOf(runtime.GC), + "GOARCH": reflect.ValueOf(runtime.GOARCH), + "GOMAXPROCS": reflect.ValueOf(runtime.GOMAXPROCS), + "GOOS": reflect.ValueOf(runtime.GOOS), + "GOROOT": reflect.ValueOf(runtime.GOROOT), + "Version": reflect.ValueOf(runtime.Version), + } +} diff --git a/src/tool/run/packages/sort.go b/src/tool/run/packages/sort.go new file mode 100644 index 0000000..c98d147 --- /dev/null +++ b/src/tool/run/packages/sort.go @@ -0,0 +1,44 @@ +package packages + +import ( + "reflect" + "sort" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +// SortFuncsStruct provides functions to be used with Sort +type SortFuncsStruct struct { + LenFunc func() int + LessFunc func(i, j int) bool + SwapFunc func(i, j int) +} + +func (s SortFuncsStruct) Len() int { return s.LenFunc() } +func (s SortFuncsStruct) Less(i, j int) bool { return s.LessFunc(i, j) } +func (s SortFuncsStruct) Swap(i, j int) { s.SwapFunc(i, j) } + +func init() { + env.Packages["sort"] = map[string]reflect.Value{ + "Float64s": reflect.ValueOf(sort.Float64s), + "Float64sAreSorted": reflect.ValueOf(sort.Float64sAreSorted), + "Ints": reflect.ValueOf(sort.Ints), + "IntsAreSorted": reflect.ValueOf(sort.IntsAreSorted), + "IsSorted": reflect.ValueOf(sort.IsSorted), + "Search": reflect.ValueOf(sort.Search), + "SearchFloat64s": reflect.ValueOf(sort.SearchFloat64s), + "SearchInts": reflect.ValueOf(sort.SearchInts), + "SearchStrings": reflect.ValueOf(sort.SearchStrings), + "Sort": reflect.ValueOf(sort.Sort), + "Stable": reflect.ValueOf(sort.Stable), + "Strings": reflect.ValueOf(sort.Strings), + "StringsAreSorted": reflect.ValueOf(sort.StringsAreSorted), + } + env.PackageTypes["sort"] = map[string]reflect.Type{ + "Float64Slice": reflect.TypeOf(sort.Float64Slice{}), + "IntSlice": reflect.TypeOf(sort.IntSlice{}), + "StringSlice": reflect.TypeOf(sort.StringSlice{}), + "SortFuncsStruct": reflect.TypeOf(&SortFuncsStruct{}), + } + sortGo18() +} diff --git a/src/tool/run/packages/sortGo18.go b/src/tool/run/packages/sortGo18.go new file mode 100644 index 0000000..d167c5f --- /dev/null +++ b/src/tool/run/packages/sortGo18.go @@ -0,0 +1,16 @@ +// +build go1.8 + +package packages + +import ( + "reflect" + "sort" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func sortGo18() { + env.Packages["sort"]["Slice"] = reflect.ValueOf(sort.Slice) + env.Packages["sort"]["SliceIsSorted"] = reflect.ValueOf(sort.SliceIsSorted) + env.Packages["sort"]["SliceStable"] = reflect.ValueOf(sort.SliceStable) +} diff --git a/src/tool/run/packages/sortNotGo18.go b/src/tool/run/packages/sortNotGo18.go new file mode 100644 index 0000000..0588911 --- /dev/null +++ b/src/tool/run/packages/sortNotGo18.go @@ -0,0 +1,5 @@ +// +build !go1.8 + +package packages + +func sortGo18() {} diff --git a/src/tool/run/packages/strconv.go b/src/tool/run/packages/strconv.go new file mode 100644 index 0000000..191abc4 --- /dev/null +++ b/src/tool/run/packages/strconv.go @@ -0,0 +1,23 @@ +package packages + +import ( + "reflect" + "strconv" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["strconv"] = map[string]reflect.Value{ + "FormatBool": reflect.ValueOf(strconv.FormatBool), + "FormatFloat": reflect.ValueOf(strconv.FormatFloat), + "FormatInt": reflect.ValueOf(strconv.FormatInt), + "FormatUint": reflect.ValueOf(strconv.FormatUint), + "ParseBool": reflect.ValueOf(strconv.ParseBool), + "ParseFloat": reflect.ValueOf(strconv.ParseFloat), + "ParseInt": reflect.ValueOf(strconv.ParseInt), + "ParseUint": reflect.ValueOf(strconv.ParseUint), + "Atoi": reflect.ValueOf(strconv.Atoi), + "Itoa": reflect.ValueOf(strconv.Itoa), + } +} diff --git a/src/tool/run/packages/strings.go b/src/tool/run/packages/strings.go new file mode 100644 index 0000000..9a1fae0 --- /dev/null +++ b/src/tool/run/packages/strings.go @@ -0,0 +1,57 @@ +package packages + +import ( + "reflect" + "strings" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["strings"] = map[string]reflect.Value{ + "Contains": reflect.ValueOf(strings.Contains), + "ContainsAny": reflect.ValueOf(strings.ContainsAny), + "ContainsRune": reflect.ValueOf(strings.ContainsRune), + "Count": reflect.ValueOf(strings.Count), + "EqualFold": reflect.ValueOf(strings.EqualFold), + "Fields": reflect.ValueOf(strings.Fields), + "FieldsFunc": reflect.ValueOf(strings.FieldsFunc), + "HasPrefix": reflect.ValueOf(strings.HasPrefix), + "HasSuffix": reflect.ValueOf(strings.HasSuffix), + "Index": reflect.ValueOf(strings.Index), + "IndexAny": reflect.ValueOf(strings.IndexAny), + "IndexByte": reflect.ValueOf(strings.IndexByte), + "IndexFunc": reflect.ValueOf(strings.IndexFunc), + "IndexRune": reflect.ValueOf(strings.IndexRune), + "Join": reflect.ValueOf(strings.Join), + "LastIndex": reflect.ValueOf(strings.LastIndex), + "LastIndexAny": reflect.ValueOf(strings.LastIndexAny), + "LastIndexFunc": reflect.ValueOf(strings.LastIndexFunc), + "Map": reflect.ValueOf(strings.Map), + "NewReader": reflect.ValueOf(strings.NewReader), + "NewReplacer": reflect.ValueOf(strings.NewReplacer), + "Repeat": reflect.ValueOf(strings.Repeat), + "Replace": reflect.ValueOf(strings.Replace), + "Split": reflect.ValueOf(strings.Split), + "SplitAfter": reflect.ValueOf(strings.SplitAfter), + "SplitAfterN": reflect.ValueOf(strings.SplitAfterN), + "SplitN": reflect.ValueOf(strings.SplitN), + "Title": reflect.ValueOf(strings.Title), + "ToLower": reflect.ValueOf(strings.ToLower), + "ToLowerSpecial": reflect.ValueOf(strings.ToLowerSpecial), + "ToTitle": reflect.ValueOf(strings.ToTitle), + "ToTitleSpecial": reflect.ValueOf(strings.ToTitleSpecial), + "ToUpper": reflect.ValueOf(strings.ToUpper), + "ToUpperSpecial": reflect.ValueOf(strings.ToUpperSpecial), + "Trim": reflect.ValueOf(strings.Trim), + "TrimFunc": reflect.ValueOf(strings.TrimFunc), + "TrimLeft": reflect.ValueOf(strings.TrimLeft), + "TrimLeftFunc": reflect.ValueOf(strings.TrimLeftFunc), + "TrimPrefix": reflect.ValueOf(strings.TrimPrefix), + "TrimRight": reflect.ValueOf(strings.TrimRight), + "TrimRightFunc": reflect.ValueOf(strings.TrimRightFunc), + "TrimSpace": reflect.ValueOf(strings.TrimSpace), + "TrimSuffix": reflect.ValueOf(strings.TrimSuffix), + } + stringsGo110() +} diff --git a/src/tool/run/packages/stringsGo110.go b/src/tool/run/packages/stringsGo110.go new file mode 100644 index 0000000..abc3eb9 --- /dev/null +++ b/src/tool/run/packages/stringsGo110.go @@ -0,0 +1,16 @@ +// +build go1.10 + +package packages + +import ( + "reflect" + "strings" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func stringsGo110() { + env.PackageTypes["strings"] = map[string]reflect.Type{ + "Builder": reflect.TypeOf(strings.Builder{}), + } +} diff --git a/src/tool/run/packages/stringsNotGo110.go b/src/tool/run/packages/stringsNotGo110.go new file mode 100644 index 0000000..97e6896 --- /dev/null +++ b/src/tool/run/packages/stringsNotGo110.go @@ -0,0 +1,5 @@ +// +build !go1.10 + +package packages + +func stringsGo110() {} diff --git a/src/tool/run/packages/sync.go b/src/tool/run/packages/sync.go new file mode 100644 index 0000000..7e5e744 --- /dev/null +++ b/src/tool/run/packages/sync.go @@ -0,0 +1,23 @@ +package packages + +import ( + "reflect" + "sync" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["sync"] = map[string]reflect.Value{ + "NewCond": reflect.ValueOf(sync.NewCond), + } + env.PackageTypes["sync"] = map[string]reflect.Type{ + "Cond": reflect.TypeOf(sync.Cond{}), + "Mutex": reflect.TypeOf(sync.Mutex{}), + "Once": reflect.TypeOf(sync.Once{}), + "Pool": reflect.TypeOf(sync.Pool{}), + "RWMutex": reflect.TypeOf(sync.RWMutex{}), + "WaitGroup": reflect.TypeOf(sync.WaitGroup{}), + } + syncGo19() +} diff --git a/src/tool/run/packages/syncGo19.go b/src/tool/run/packages/syncGo19.go new file mode 100644 index 0000000..27ba4d8 --- /dev/null +++ b/src/tool/run/packages/syncGo19.go @@ -0,0 +1,14 @@ +// +build go1.9 + +package packages + +import ( + "reflect" + "sync" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func syncGo19() { + env.PackageTypes["sync"]["Map"] = reflect.TypeOf(sync.Map{}) +} diff --git a/src/tool/run/packages/syncNotGo19.go b/src/tool/run/packages/syncNotGo19.go new file mode 100644 index 0000000..36f3839 --- /dev/null +++ b/src/tool/run/packages/syncNotGo19.go @@ -0,0 +1,5 @@ +// +build !go1.9 + +package packages + +func syncGo19() {} diff --git a/src/tool/run/packages/time.go b/src/tool/run/packages/time.go new file mode 100644 index 0000000..5db7292 --- /dev/null +++ b/src/tool/run/packages/time.go @@ -0,0 +1,75 @@ +package packages + +import ( + "reflect" + "time" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func init() { + env.Packages["time"] = map[string]reflect.Value{ + "ANSIC": reflect.ValueOf(time.ANSIC), + "After": reflect.ValueOf(time.After), + "AfterFunc": reflect.ValueOf(time.AfterFunc), + "April": reflect.ValueOf(time.April), + "August": reflect.ValueOf(time.August), + "Date": reflect.ValueOf(time.Date), + "December": reflect.ValueOf(time.December), + "February": reflect.ValueOf(time.February), + "FixedZone": reflect.ValueOf(time.FixedZone), + "Friday": reflect.ValueOf(time.Friday), + "Hour": reflect.ValueOf(time.Hour), + "January": reflect.ValueOf(time.January), + "July": reflect.ValueOf(time.July), + "June": reflect.ValueOf(time.June), + "Kitchen": reflect.ValueOf(time.Kitchen), + "LoadLocation": reflect.ValueOf(time.LoadLocation), + "March": reflect.ValueOf(time.March), + "May": reflect.ValueOf(time.May), + "Microsecond": reflect.ValueOf(time.Microsecond), + "Millisecond": reflect.ValueOf(time.Millisecond), + "Minute": reflect.ValueOf(time.Minute), + "Monday": reflect.ValueOf(time.Monday), + "Nanosecond": reflect.ValueOf(time.Nanosecond), + "NewTicker": reflect.ValueOf(time.NewTicker), + "NewTimer": reflect.ValueOf(time.NewTimer), + "November": reflect.ValueOf(time.November), + "Now": reflect.ValueOf(time.Now), + "October": reflect.ValueOf(time.October), + "Parse": reflect.ValueOf(time.Parse), + "ParseDuration": reflect.ValueOf(time.ParseDuration), + "ParseInLocation": reflect.ValueOf(time.ParseInLocation), + "RFC1123": reflect.ValueOf(time.RFC1123), + "RFC1123Z": reflect.ValueOf(time.RFC1123Z), + "RFC3339": reflect.ValueOf(time.RFC3339), + "RFC3339Nano": reflect.ValueOf(time.RFC3339Nano), + "RFC822": reflect.ValueOf(time.RFC822), + "RFC822Z": reflect.ValueOf(time.RFC822Z), + "RFC850": reflect.ValueOf(time.RFC850), + "RubyDate": reflect.ValueOf(time.RubyDate), + "Saturday": reflect.ValueOf(time.Saturday), + "Second": reflect.ValueOf(time.Second), + "September": reflect.ValueOf(time.September), + "Since": reflect.ValueOf(time.Since), + "Sleep": reflect.ValueOf(time.Sleep), + "Stamp": reflect.ValueOf(time.Stamp), + "StampMicro": reflect.ValueOf(time.StampMicro), + "StampMilli": reflect.ValueOf(time.StampMilli), + "StampNano": reflect.ValueOf(time.StampNano), + "Sunday": reflect.ValueOf(time.Sunday), + "Thursday": reflect.ValueOf(time.Thursday), + "Tick": reflect.ValueOf(time.Tick), + "Tuesday": reflect.ValueOf(time.Tuesday), + "Unix": reflect.ValueOf(time.Unix), + "UnixDate": reflect.ValueOf(time.UnixDate), + "Wednesday": reflect.ValueOf(time.Wednesday), + } + env.PackageTypes["time"] = map[string]reflect.Type{ + "Duration": reflect.TypeOf(time.Duration(0)), + "Ticker": reflect.TypeOf(time.Ticker{}), + "Time": reflect.TypeOf(time.Time{}), + } + timeGo18() + timeGo110() +} diff --git a/src/tool/run/packages/timeGo110.go b/src/tool/run/packages/timeGo110.go new file mode 100644 index 0000000..3893918 --- /dev/null +++ b/src/tool/run/packages/timeGo110.go @@ -0,0 +1,14 @@ +// +build go1.10 + +package packages + +import ( + "reflect" + "time" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func timeGo110() { + env.Packages["time"]["LoadLocationFromTZData"] = reflect.ValueOf(time.LoadLocationFromTZData) +} diff --git a/src/tool/run/packages/timeGo18.go b/src/tool/run/packages/timeGo18.go new file mode 100644 index 0000000..bb6749a --- /dev/null +++ b/src/tool/run/packages/timeGo18.go @@ -0,0 +1,14 @@ +// +build go1.8 + +package packages + +import ( + "reflect" + "time" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func timeGo18() { + env.Packages["time"]["Until"] = reflect.ValueOf(time.Until) +} diff --git a/src/tool/run/packages/timeNotGo110.go b/src/tool/run/packages/timeNotGo110.go new file mode 100644 index 0000000..bae9c13 --- /dev/null +++ b/src/tool/run/packages/timeNotGo110.go @@ -0,0 +1,5 @@ +// +build !go1.10 + +package packages + +func timeGo110() {} diff --git a/src/tool/run/packages/timeNotGo18.go b/src/tool/run/packages/timeNotGo18.go new file mode 100644 index 0000000..57cbc3e --- /dev/null +++ b/src/tool/run/packages/timeNotGo18.go @@ -0,0 +1,5 @@ +// +build !go1.8 + +package packages + +func timeGo18() {} diff --git a/src/tool/run/parser/Makefile b/src/tool/run/parser/Makefile new file mode 100644 index 0000000..72c8b09 --- /dev/null +++ b/src/tool/run/parser/Makefile @@ -0,0 +1,5 @@ +all : parser.go + +parser.go : parser.go.y + goyacc -o $@ parser.go.y + gofmt -s -w . diff --git a/src/tool/run/parser/lexer.go b/src/tool/run/parser/lexer.go new file mode 100644 index 0000000..6bf3869 --- /dev/null +++ b/src/tool/run/parser/lexer.go @@ -0,0 +1,653 @@ +// Package parser implements parser for anko. +package parser + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "unicode" + + "github.com/surdeus/goblin/src/tool/run/ast" +) + +const ( + // EOF is short for End of file. + EOF = -1 + // EOL is short for End of line. + EOL = '\n' +) + +// Error is a parse error. +type Error struct { + Message string + Pos ast.Position + Filename string + Fatal bool +} + +// Error returns the parse error message. +func (e *Error) Error() string { + return e.Message +} + +// Scanner stores informations for lexer. +type Scanner struct { + src []rune + offset int + lineHead int + line int +} + +// opName is correction of operation names. +var opName = map[string]int{ + "func": FUNC, + "return": RETURN, + "var": VAR, + "throw": THROW, + "if": IF, + "for": FOR, + "break": BREAK, + "continue": CONTINUE, + "in": IN, + "else": ELSE, + "new": NEW, + "true": TRUE, + "false": FALSE, + "nil": NIL, + "module": MODULE, + "try": TRY, + "catch": CATCH, + "finally": FINALLY, + "switch": SWITCH, + "case": CASE, + "default": DEFAULT, + "go": GO, + "chan": CHAN, + "struct": STRUCT, + "make": MAKE, + "type": TYPE, + "len": LEN, + "delete": DELETE, + "close": CLOSE, + "map": MAP, + "import": IMPORT, +} + +var ( + nilValue = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem() + trueValue = reflect.ValueOf(true) + falseValue = reflect.ValueOf(false) + oneLiteral = &ast.LiteralExpr{Literal: reflect.ValueOf(int64(1))} +) + +// Init resets code to scan. +func (s *Scanner) Init(src string) { + s.src = []rune(src) +} + +// Scan analyses token, and decide identify or literals. +func (s *Scanner) Scan() (tok int, lit string, pos ast.Position, err error) { +retry: + s.skipBlank() + pos = s.pos() + switch ch := s.peek(); { + case isLetter(ch): + lit, err = s.scanIdentifier() + if err != nil { + return + } + if name, ok := opName[lit]; ok { + tok = name + } else { + tok = IDENT + } + case isDigit(ch): + tok = NUMBER + lit, err = s.scanNumber() + if err != nil { + return + } + case ch == '"': + tok = STRING + lit, err = s.scanString('"') + if err != nil { + return + } + case ch == '\'': + tok = STRING + lit, err = s.scanString('\'') + if err != nil { + return + } + case ch == '`': + tok = STRING + lit, err = s.scanRawString('`') + if err != nil { + return + } + default: + switch ch { + case EOF: + tok = EOF + case '#': + for !isEOL(s.peek()) { + s.next() + } + goto retry + case '!': + s.next() + switch s.peek() { + case '=': + tok = NEQ + lit = "!=" + default: + s.back() + tok = int(ch) + lit = string(ch) + } + case '=': + s.next() + switch s.peek() { + case '=': + tok = EQEQ + lit = "==" + case ' ': + if s.peekPlus(1) == '<' && s.peekPlus(2) == '-' { + s.next() + s.next() + tok = EQOPCHAN + lit = "= <-" + } else { + s.back() + tok = int(ch) + lit = string(ch) + } + default: + s.back() + tok = int(ch) + lit = string(ch) + } + case '?': + s.next() + switch s.peek() { + case '?': + tok = NILCOALESCE + lit = "??" + default: + s.back() + tok = int(ch) + lit = string(ch) + } + case '+': + s.next() + switch s.peek() { + case '+': + tok = PLUSPLUS + lit = "++" + case '=': + tok = PLUSEQ + lit = "+=" + default: + s.back() + tok = int(ch) + lit = string(ch) + } + case '-': + s.next() + switch s.peek() { + case '-': + tok = MINUSMINUS + lit = "--" + case '=': + tok = MINUSEQ + lit = "-=" + default: + s.back() + tok = int(ch) + lit = "-" + } + case '*': + s.next() + switch s.peek() { + case '=': + tok = MULEQ + lit = "*=" + default: + s.back() + tok = int(ch) + lit = string(ch) + } + case '/': + s.next() + switch s.peek() { + case '=': + tok = DIVEQ + lit = "/=" + case '/': + for !isEOL(s.peek()) { + s.next() + } + goto retry + case '*': + for { + _, err = s.scanRawString('*') + if err != nil { + return + } + + if s.peek() == '/' { + s.next() + goto retry + } + + s.back() + } + default: + s.back() + tok = int(ch) + lit = string(ch) + } + case '>': + s.next() + switch s.peek() { + case '=': + tok = GE + lit = ">=" + case '>': + tok = SHIFTRIGHT + lit = ">>" + default: + s.back() + tok = int(ch) + lit = string(ch) + } + case '<': + s.next() + switch s.peek() { + case '-': + tok = OPCHAN + lit = "<-" + case '=': + tok = LE + lit = "<=" + case '<': + tok = SHIFTLEFT + lit = "<<" + default: + s.back() + tok = int(ch) + lit = string(ch) + } + case '|': + s.next() + switch s.peek() { + case '|': + tok = OROR + lit = "||" + case '=': + tok = OREQ + lit = "|=" + default: + s.back() + tok = int(ch) + lit = string(ch) + } + case '&': + s.next() + switch s.peek() { + case '&': + tok = ANDAND + lit = "&&" + case '=': + tok = ANDEQ + lit = "&=" + default: + s.back() + tok = int(ch) + lit = string(ch) + } + case '.': + s.next() + if s.peek() == '.' { + s.next() + if s.peek() == '.' { + tok = VARARG + } else { + err = fmt.Errorf("syntax error on '%v' at %v:%v", string(ch), pos.Line, pos.Column) + return + } + } else { + s.back() + tok = int(ch) + lit = string(ch) + } + case '\n', '(', ')', ':', ';', '%', '{', '}', '[', ']', ',', '^': + tok = int(ch) + lit = string(ch) + default: + err = fmt.Errorf("syntax error on '%v' at %v:%v", string(ch), pos.Line, pos.Column) + tok = int(ch) + lit = string(ch) + return + } + s.next() + } + return +} + +// isLetter returns true if the rune is a letter for identity. +func isLetter(ch rune) bool { + return unicode.IsLetter(ch) || ch == '_' +} + +// isDigit returns true if the rune is a number. +func isDigit(ch rune) bool { + return '0' <= ch && ch <= '9' +} + +// isHex returns true if the rune is a hex digits. +func isHex(ch rune) bool { + return ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') +} + +// isEOL returns true if the rune is at end-of-line or end-of-file. +func isEOL(ch rune) bool { + return ch == '\n' || ch == -1 +} + +// isBlank returns true if the rune is empty character.. +func isBlank(ch rune) bool { + return ch == ' ' || ch == '\t' || ch == '\r' +} + +// peek returns current rune in the code. +func (s *Scanner) peek() rune { + if s.reachEOF() { + return EOF + } + return s.src[s.offset] +} + +// peek returns current rune plus i in the code. +func (s *Scanner) peekPlus(i int) rune { + if len(s.src) <= s.offset+i { + return EOF + } + return s.src[s.offset+i] +} + +// next moves offset to next. +func (s *Scanner) next() { + if !s.reachEOF() { + if s.peek() == '\n' { + s.lineHead = s.offset + 1 + s.line++ + } + s.offset++ + } +} + +// current returns the current offset. +func (s *Scanner) current() int { + return s.offset +} + +// offset sets the offset value. +func (s *Scanner) set(o int) { + s.offset = o +} + +// back moves back offset once to top. +func (s *Scanner) back() { + s.offset-- +} + +// reachEOF returns true if offset is at end-of-file. +func (s *Scanner) reachEOF() bool { + return len(s.src) <= s.offset +} + +// pos returns the position of current. +func (s *Scanner) pos() ast.Position { + return ast.Position{Line: s.line + 1, Column: s.offset - s.lineHead + 1} +} + +// skipBlank moves position into non-black character. +func (s *Scanner) skipBlank() { + for isBlank(s.peek()) { + s.next() + } +} + +// scanIdentifier returns identifier beginning at current position. +func (s *Scanner) scanIdentifier() (string, error) { + var ret []rune + for { + if !isLetter(s.peek()) && !isDigit(s.peek()) { + break + } + ret = append(ret, s.peek()) + s.next() + } + return string(ret), nil +} + +// scanNumber returns number beginning at current position. +func (s *Scanner) scanNumber() (string, error) { + result := []rune{s.peek()} + s.next() + + if result[0] == '0' && (s.peek() == 'x' || s.peek() == 'X') { + // hex + result = append(result, 'x') + s.next() + for isHex(s.peek()) { + result = append(result, s.peek()) + s.next() + } + } else { + // non-hex + found := false + for { + if isDigit(s.peek()) { + // is digit + result = append(result, s.peek()) + s.next() + continue + } + + if s.peek() == '.' { + // is . + result = append(result, '.') + s.next() + continue + } + + if s.peek() == 'e' || s.peek() == 'E' { + // is e + if found { + return "", errors.New("unexpected " + string(s.peek())) + } + found = true + s.next() + + // check if + or - + if s.peek() == '+' || s.peek() == '-' { + // add e with + or - + result = append(result, 'e') + result = append(result, s.peek()) + s.next() + } else { + // add e, but next char not + or - + result = append(result, 'e') + } + continue + } + + // not digit, e, nor . + break + } + } + + if isLetter(s.peek()) { + return "", errors.New("identifier starts immediately after numeric literal") + } + + return string(result), nil +} + +// scanRawString returns raw-string starting at current position. +func (s *Scanner) scanRawString(l rune) (string, error) { + var ret []rune + for { + s.next() + if s.peek() == EOF { + return "", errors.New("unexpected EOF") + } + if s.peek() == l { + s.next() + break + } + ret = append(ret, s.peek()) + } + return string(ret), nil +} + +// scanString returns string starting at current position. +// This handles backslash escaping. +func (s *Scanner) scanString(l rune) (string, error) { + var ret []rune +eos: + for { + s.next() + switch s.peek() { + case EOL: + return "", errors.New("unexpected EOL") + case EOF: + return "", errors.New("unexpected EOF") + case l: + s.next() + break eos + case '\\': + s.next() + switch s.peek() { + case 'b': + ret = append(ret, '\b') + continue + case 'f': + ret = append(ret, '\f') + continue + case 'r': + ret = append(ret, '\r') + continue + case 'n': + ret = append(ret, '\n') + continue + case 't': + ret = append(ret, '\t') + continue + } + ret = append(ret, s.peek()) + continue + default: + ret = append(ret, s.peek()) + } + } + return string(ret), nil +} + +// Lexer provides interface to parse codes. +type Lexer struct { + s *Scanner + lit string + pos ast.Position + e error + stmt ast.Stmt +} + +// Lex scans the token and literals. +func (l *Lexer) Lex(lval *yySymType) int { + tok, lit, pos, err := l.s.Scan() + if err != nil { + l.e = &Error{Message: err.Error(), Pos: pos, Fatal: true} + } + lval.tok = ast.Token{Tok: tok, Lit: lit} + lval.tok.SetPosition(pos) + l.lit = lit + l.pos = pos + return tok +} + +// Error sets parse error. +func (l *Lexer) Error(msg string) { + l.e = &Error{Message: msg, Pos: l.pos, Fatal: false} +} + +// Parse provides way to parse the code using Scanner. +func Parse(s *Scanner) (ast.Stmt, error) { + l := Lexer{s: s} + if yyParse(&l) != 0 { + return nil, l.e + } + return l.stmt, l.e +} + +// EnableErrorVerbose enabled verbose errors from the parser +func EnableErrorVerbose() { + yyErrorVerbose = true +} + +// EnableDebug enabled debug from the parser +func EnableDebug(level int) { + yyDebug = level +} + +// ParseSrc provides way to parse the code from source. +func ParseSrc(src string) (ast.Stmt, error) { + scanner := &Scanner{ + src: []rune(src), + } + return Parse(scanner) +} + +func toNumber(numString string) (reflect.Value, error) { + // hex + if len(numString) > 2 && numString[0:2] == "0x" { + i, err := strconv.ParseInt(numString[2:], 16, 64) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(i), nil + } + + // hex + if len(numString) > 3 && numString[0:3] == "-0x" { + i, err := strconv.ParseInt("-"+numString[3:], 16, 64) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(i), nil + } + + // float + if strings.Contains(numString, ".") || strings.Contains(numString, "e") { + f, err := strconv.ParseFloat(numString, 64) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(f), nil + } + + // int + i, err := strconv.ParseInt(numString, 10, 64) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(i), nil +} + +func stringToValue(aString string) reflect.Value { + return reflect.ValueOf(aString) +} diff --git a/src/tool/run/parser/parser.go b/src/tool/run/parser/parser.go new file mode 100644 index 0000000..aecf8a2 --- /dev/null +++ b/src/tool/run/parser/parser.go @@ -0,0 +1,2483 @@ +// Code generated by goyacc -o parser.go parser.go.y. DO NOT EDIT. + +//line parser.go.y:2 +package parser + +import __yyfmt__ "fmt" + +//line parser.go.y:2 + +import ( + "github.com/surdeus/goblin/src/tool/run/ast" +) + +//line parser.go.y:45 +type yySymType struct { + yys int + tok ast.Token + + compstmt ast.Stmt + stmts ast.Stmt + stmt ast.Stmt + stmt_var_or_lets ast.Stmt + stmt_var ast.Stmt + stmt_lets ast.Stmt + stmt_if ast.Stmt + stmt_for ast.Stmt + stmt_switch ast.Stmt + stmt_switch_cases ast.Stmt + stmt_switch_case ast.Stmt + stmt_switch_default ast.Stmt + + exprs []ast.Expr + expr ast.Expr + expr_idents []string + type_data *ast.TypeStruct + type_data_struct *ast.TypeStruct + slice_count int + expr_member_or_ident ast.Expr + expr_member *ast.MemberExpr + expr_ident *ast.IdentExpr + expr_literals ast.Expr + expr_map *ast.MapExpr + expr_slice ast.Expr + expr_chan ast.Expr + expr_unary ast.Expr + expr_binary ast.Expr + expr_lets ast.Expr + + op_binary ast.Operator + op_comparison ast.Operator + op_add ast.Operator + op_multiply ast.Operator +} + +const IDENT = 57346 +const NUMBER = 57347 +const STRING = 57348 +const ARRAY = 57349 +const VARARG = 57350 +const FUNC = 57351 +const RETURN = 57352 +const VAR = 57353 +const THROW = 57354 +const IF = 57355 +const ELSE = 57356 +const FOR = 57357 +const IN = 57358 +const EQEQ = 57359 +const NEQ = 57360 +const GE = 57361 +const LE = 57362 +const OROR = 57363 +const ANDAND = 57364 +const NEW = 57365 +const TRUE = 57366 +const FALSE = 57367 +const NIL = 57368 +const NILCOALESCE = 57369 +const MODULE = 57370 +const TRY = 57371 +const CATCH = 57372 +const FINALLY = 57373 +const PLUSEQ = 57374 +const MINUSEQ = 57375 +const MULEQ = 57376 +const DIVEQ = 57377 +const ANDEQ = 57378 +const OREQ = 57379 +const BREAK = 57380 +const CONTINUE = 57381 +const PLUSPLUS = 57382 +const MINUSMINUS = 57383 +const SHIFTLEFT = 57384 +const SHIFTRIGHT = 57385 +const SWITCH = 57386 +const CASE = 57387 +const DEFAULT = 57388 +const GO = 57389 +const CHAN = 57390 +const STRUCT = 57391 +const MAKE = 57392 +const OPCHAN = 57393 +const EQOPCHAN = 57394 +const TYPE = 57395 +const LEN = 57396 +const DELETE = 57397 +const CLOSE = 57398 +const MAP = 57399 +const IMPORT = 57400 +const UNARY = 57401 + +var yyToknames = [...]string{ + "$end", + "error", + "$unk", + "IDENT", + "NUMBER", + "STRING", + "ARRAY", + "VARARG", + "FUNC", + "RETURN", + "VAR", + "THROW", + "IF", + "ELSE", + "FOR", + "IN", + "EQEQ", + "NEQ", + "GE", + "LE", + "OROR", + "ANDAND", + "NEW", + "TRUE", + "FALSE", + "NIL", + "NILCOALESCE", + "MODULE", + "TRY", + "CATCH", + "FINALLY", + "PLUSEQ", + "MINUSEQ", + "MULEQ", + "DIVEQ", + "ANDEQ", + "OREQ", + "BREAK", + "CONTINUE", + "PLUSPLUS", + "MINUSMINUS", + "SHIFTLEFT", + "SHIFTRIGHT", + "SWITCH", + "CASE", + "DEFAULT", + "GO", + "CHAN", + "STRUCT", + "MAKE", + "OPCHAN", + "EQOPCHAN", + "TYPE", + "LEN", + "DELETE", + "CLOSE", + "MAP", + "IMPORT", + "'='", + "':'", + "'?'", + "'<'", + "'>'", + "'+'", + "'-'", + "'|'", + "'^'", + "'*'", + "'/'", + "'%'", + "'&'", + "UNARY", + "'{'", + "'}'", + "'('", + "')'", + "','", + "';'", + "'['", + "']'", + "'.'", + "'!'", + "'\\n'", +} +var yyStatenames = [...]string{} + +const yyEofCode = 1 +const yyErrCode = 2 +const yyInitialStackSize = 16 + +//line parser.go.y:1089 + +//line yacctab:1 +var yyExca = [...]int{ + -1, 1, + 1, -1, + -2, 0, + -1, 2, + 52, 57, + 59, 57, + 77, 57, + 78, 5, + -2, 1, + -1, 23, + 77, 58, + -2, 26, + -1, 27, + 16, 95, + -2, 57, + -1, 67, + 52, 57, + 59, 57, + 77, 57, + -2, 5, + -1, 120, + 16, 96, + 77, 96, + -2, 112, + -1, 124, + 4, 107, + 48, 107, + 49, 107, + 57, 107, + -2, 69, + -1, 267, + 74, 181, + 80, 181, + -2, 173, + -1, 288, + 74, 181, + -2, 173, + -1, 292, + 1, 60, + 8, 60, + 45, 60, + 46, 60, + 52, 60, + 59, 60, + 60, 60, + 74, 60, + 76, 60, + 77, 60, + 78, 60, + 80, 60, + 83, 60, + -2, 110, + -1, 296, + 1, 17, + 45, 17, + 46, 17, + 74, 17, + 78, 17, + 83, 17, + -2, 74, + -1, 298, + 1, 19, + 45, 19, + 46, 19, + 74, 19, + 78, 19, + 83, 19, + -2, 76, + -1, 328, + 74, 179, + 80, 179, + -2, 174, + -1, 348, + 1, 16, + 45, 16, + 46, 16, + 74, 16, + 78, 16, + 83, 16, + -2, 73, + -1, 349, + 1, 18, + 45, 18, + 46, 18, + 74, 18, + 78, 18, + 83, 18, + -2, 75, +} + +const yyPrivate = 57344 + +const yyLast = 3907 + +var yyAct = [...]int{ + + 71, 268, 33, 23, 232, 320, 321, 36, 116, 323, + 322, 5, 8, 288, 377, 72, 8, 267, 76, 8, + 8, 124, 386, 8, 8, 127, 281, 114, 117, 121, + 214, 214, 282, 283, 84, 135, 130, 214, 85, 214, + 87, 1, 331, 214, 207, 286, 214, 8, 7, 329, + 220, 137, 151, 327, 134, 69, 49, 145, 152, 153, + 154, 155, 156, 213, 217, 202, 142, 373, 23, 149, + 70, 214, 143, 404, 340, 349, 348, 334, 162, 163, + 325, 166, 167, 168, 169, 297, 171, 173, 303, 175, + 149, 210, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 136, 159, 69, 295, 206, + 448, 326, 203, 148, 234, 160, 203, 211, 141, 274, + 147, 209, 130, 130, 140, 130, 86, 139, 223, 225, + 226, 170, 203, 130, 130, 233, 130, 265, 149, 236, + 123, 138, 447, 298, 149, 215, 216, 200, 218, 144, + 89, 90, 100, 101, 78, 245, 227, 228, 77, 231, + 443, 248, 438, 252, 437, 69, 435, 428, 427, 6, + 423, 422, 212, 128, 346, 68, 296, 149, 97, 98, + 99, 102, 125, 222, 367, 84, 421, 275, 149, 85, + 238, 87, 419, 255, 235, 86, 259, 246, 262, 410, + 128, 409, 126, 164, 405, 264, 203, 240, 241, 266, + 130, 122, 126, 211, 401, 278, 397, 132, 133, 89, + 90, 233, 229, 395, 287, 285, 131, 444, 291, 249, + 149, 253, 394, 272, 299, 292, 257, 129, 302, 393, + 69, 390, 304, 347, 132, 133, 385, 356, 134, 343, + 311, 315, 317, 131, 84, 308, 301, 293, 85, 254, + 87, 239, 442, 165, 129, 408, 388, 372, 335, 9, + 371, 324, 219, 158, 339, 134, 74, 341, 441, 130, + 345, 290, 323, 322, 436, 201, 294, 79, 430, 333, + 312, 310, 230, 10, 284, 271, 146, 174, 354, 237, + 73, 4, 342, 2, 62, 67, 63, 66, 69, 363, + 64, 65, 126, 47, 368, 366, 365, 330, 46, 126, + 45, 119, 374, 44, 130, 43, 130, 30, 50, 381, + 29, 384, 351, 332, 319, 387, 22, 157, 21, 20, + 25, 355, 24, 3, 391, 357, 358, 375, 360, 378, + 0, 0, 0, 256, 0, 0, 370, 0, 263, 0, + 0, 0, 0, 270, 0, 0, 0, 69, 0, 273, + 369, 412, 0, 126, 414, 0, 0, 0, 126, 389, + 0, 0, 269, 126, 0, 0, 0, 0, 0, 126, + 0, 396, 0, 398, 399, 0, 0, 0, 0, 402, + 0, 0, 269, 406, 407, 0, 0, 233, 434, 0, + 0, 433, 0, 0, 0, 0, 0, 237, 0, 0, + 418, 0, 0, 130, 0, 440, 0, 0, 201, 0, + 0, 0, 424, 0, 0, 425, 426, 328, 344, 0, + 429, 0, 0, 0, 0, 0, 439, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 328, 120, + 52, 53, 0, 0, 31, 0, 48, 0, 0, 364, + 0, 0, 0, 0, 445, 0, 446, 0, 39, 54, + 55, 56, 376, 0, 201, 0, 201, 0, 0, 126, + 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 269, 0, 126, 0, 0, 40, 57, 0, 0, 37, + 0, 0, 41, 38, 89, 90, 100, 101, 0, 0, + 51, 0, 59, 61, 0, 0, 60, 411, 115, 0, + 34, 0, 201, 118, 32, 0, 416, 58, 103, 104, + 105, 0, 97, 98, 99, 102, 0, 126, 0, 84, + 0, 0, 0, 85, 0, 87, 126, 0, 0, 86, + 106, 107, 111, 109, 113, 112, 0, 0, 0, 0, + 83, 0, 0, 0, 0, 91, 92, 94, 95, 96, + 93, 0, 0, 89, 90, 100, 101, 0, 0, 0, + 0, 0, 0, 0, 88, 81, 0, 0, 0, 0, + 0, 0, 80, 269, 82, 108, 110, 103, 104, 105, + 0, 97, 98, 99, 102, 0, 204, 0, 84, 0, + 0, 0, 85, 0, 87, 35, 52, 53, 0, 0, + 31, 13, 48, 14, 26, 0, 27, 0, 0, 0, + 0, 0, 0, 0, 39, 54, 55, 56, 0, 15, + 16, 0, 0, 0, 0, 0, 0, 0, 0, 11, + 12, 0, 0, 0, 0, 28, 0, 0, 17, 0, + 0, 40, 57, 0, 0, 37, 18, 19, 41, 38, + 0, 0, 0, 0, 0, 0, 51, 0, 59, 61, + 0, 0, 60, 0, 42, 0, 34, 0, 0, 0, + 32, 0, 0, 58, 86, 106, 107, 111, 109, 113, + 112, 0, 0, 0, 0, 83, 0, 0, 0, 0, + 91, 92, 94, 95, 96, 93, 0, 0, 89, 90, + 100, 101, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 108, 110, 103, 104, 105, 0, 97, 98, 99, 102, + 0, 0, 0, 84, 382, 383, 0, 85, 0, 87, + 86, 106, 107, 111, 109, 113, 112, 0, 0, 0, + 0, 83, 0, 0, 0, 0, 91, 92, 94, 95, + 96, 93, 0, 0, 89, 90, 100, 101, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 380, 82, 108, 110, 103, 104, + 105, 0, 97, 98, 99, 102, 0, 0, 0, 84, + 0, 0, 0, 85, 379, 87, 86, 106, 107, 111, + 109, 113, 112, 0, 0, 0, 0, 83, 0, 0, + 0, 0, 91, 92, 94, 95, 96, 93, 0, 0, + 89, 90, 100, 101, 0, 0, 0, 0, 0, 0, + 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 353, 82, 108, 110, 103, 104, 105, 0, 97, 98, + 99, 102, 0, 0, 0, 84, 0, 0, 0, 85, + 352, 87, 86, 106, 107, 111, 109, 113, 112, 0, + 0, 0, 0, 83, 0, 0, 0, 0, 91, 92, + 94, 95, 96, 93, 0, 0, 89, 90, 100, 101, + 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, + 0, 0, 0, 0, 0, 0, 338, 82, 108, 110, + 103, 104, 105, 0, 97, 98, 99, 102, 0, 0, + 0, 84, 0, 0, 0, 85, 337, 87, 86, 106, + 107, 111, 109, 113, 112, 0, 0, 0, 0, 83, + 0, 0, 0, 0, 91, 92, 94, 95, 96, 93, + 0, 0, 89, 90, 100, 101, 0, 0, 0, 0, + 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, + 0, 0, 307, 82, 108, 110, 103, 104, 105, 0, + 97, 98, 99, 102, 0, 0, 0, 84, 0, 0, + 0, 85, 306, 87, 86, 106, 107, 111, 109, 113, + 112, 0, 0, 0, 0, 83, 0, 0, 0, 0, + 91, 92, 94, 95, 96, 93, 0, 0, 89, 90, + 100, 101, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 277, 82, + 108, 110, 103, 104, 105, 0, 97, 98, 99, 102, + 0, 0, 0, 84, 0, 0, 0, 85, 276, 87, + 86, 106, 107, 111, 109, 113, 112, 0, 0, 0, + 0, 83, 0, 0, 0, 0, 91, 92, 94, 95, + 96, 93, 0, 0, 89, 90, 100, 101, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 251, 82, 108, 110, 103, 104, + 105, 0, 97, 98, 99, 102, 0, 0, 0, 84, + 0, 0, 0, 85, 250, 87, 86, 106, 107, 111, + 109, 113, 112, 0, 0, 0, 0, 83, 0, 0, + 0, 0, 91, 92, 94, 95, 96, 93, 0, 0, + 89, 90, 100, 101, 0, 0, 0, 0, 0, 0, + 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 82, 108, 110, 103, 104, 105, 0, 97, 98, + 99, 102, 0, 0, 0, 84, 242, 243, 0, 85, + 0, 87, 86, 106, 107, 111, 109, 113, 112, 0, + 0, 0, 0, 83, 0, 0, 0, 0, 91, 92, + 94, 95, 96, 93, 0, 0, 89, 90, 100, 101, + 0, 0, 0, 0, 0, 0, 0, 88, 81, 0, + 0, 0, 0, 0, 0, 80, 0, 82, 108, 110, + 103, 104, 105, 0, 97, 98, 99, 102, 0, 0, + 0, 84, 0, 0, 0, 85, 0, 87, 86, 106, + 107, 111, 109, 113, 112, 0, 0, 0, 0, 83, + 0, 0, 0, 0, 91, 92, 94, 95, 96, 93, + 0, 0, 89, 90, 100, 101, 0, 0, 0, 0, + 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 82, 108, 110, 103, 104, 105, 0, + 97, 98, 99, 102, 0, 0, 0, 84, 432, 0, + 0, 85, 0, 87, 86, 106, 107, 111, 109, 113, + 112, 0, 0, 0, 0, 83, 0, 0, 0, 0, + 91, 92, 94, 95, 96, 93, 0, 0, 89, 90, + 100, 101, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 108, 110, 103, 104, 105, 0, 97, 98, 99, 102, + 0, 0, 0, 84, 0, 0, 0, 85, 431, 87, + 86, 106, 107, 111, 109, 113, 112, 0, 0, 0, + 0, 83, 0, 0, 0, 0, 91, 92, 94, 95, + 96, 93, 0, 0, 89, 90, 100, 101, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, 108, 110, 103, 104, + 105, 0, 97, 98, 99, 102, 0, 0, 0, 84, + 0, 0, 0, 85, 420, 87, 86, 106, 107, 111, + 109, 113, 112, 0, 0, 0, 0, 83, 0, 0, + 0, 0, 91, 92, 94, 95, 96, 93, 0, 0, + 89, 90, 100, 101, 0, 0, 0, 0, 0, 0, + 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 417, 82, 108, 110, 103, 104, 105, 0, 97, 98, + 99, 102, 0, 0, 0, 84, 0, 0, 0, 85, + 0, 87, 86, 106, 107, 111, 109, 113, 112, 0, + 0, 0, 0, 83, 0, 0, 0, 0, 91, 92, + 94, 95, 96, 93, 0, 0, 89, 90, 100, 101, + 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 82, 108, 110, + 103, 104, 105, 0, 97, 98, 99, 102, 0, 0, + 0, 84, 415, 0, 0, 85, 0, 87, 86, 106, + 107, 111, 109, 113, 112, 0, 0, 0, 0, 83, + 0, 0, 0, 0, 91, 92, 94, 95, 96, 93, + 0, 0, 89, 90, 100, 101, 0, 0, 0, 0, + 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 82, 108, 110, 103, 104, 105, 0, + 97, 98, 99, 102, 0, 0, 0, 84, 0, 0, + 0, 85, 413, 87, 86, 106, 107, 111, 109, 113, + 112, 0, 0, 0, 0, 83, 0, 0, 0, 0, + 91, 92, 94, 95, 96, 93, 0, 0, 89, 90, + 100, 101, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 403, 82, + 108, 110, 103, 104, 105, 0, 97, 98, 99, 102, + 0, 0, 0, 84, 0, 0, 0, 85, 0, 87, + 86, 106, 107, 111, 109, 113, 112, 0, 0, 0, + 0, 83, 0, 0, 0, 0, 91, 92, 94, 95, + 96, 93, 0, 0, 89, 90, 100, 101, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, 108, 110, 103, 104, + 105, 0, 97, 98, 99, 102, 0, 400, 0, 84, + 0, 0, 0, 85, 0, 87, 86, 106, 107, 111, + 109, 113, 112, 0, 0, 0, 0, 83, 0, 0, + 0, 0, 91, 92, 94, 95, 96, 93, 0, 0, + 89, 90, 100, 101, 0, 0, 0, 0, 0, 0, + 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 82, 108, 110, 103, 104, 105, 0, 97, 98, + 99, 102, 0, 0, 0, 84, 0, 0, 0, 85, + 392, 87, 86, 106, 107, 111, 109, 113, 112, 0, + 0, 0, 0, 83, 0, 0, 0, 0, 91, 92, + 94, 95, 96, 93, 0, 0, 89, 90, 100, 101, + 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 82, 108, 110, + 103, 104, 105, 0, 97, 98, 99, 102, 0, 361, + 0, 84, 0, 0, 0, 85, 0, 87, 86, 106, + 107, 111, 109, 113, 112, 0, 0, 0, 0, 83, + 0, 0, 0, 0, 91, 92, 94, 95, 96, 93, + 0, 0, 89, 90, 100, 101, 0, 0, 0, 0, + 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 82, 108, 110, 103, 104, 105, 0, + 97, 98, 99, 102, 0, 359, 0, 84, 0, 0, + 0, 85, 0, 87, 86, 106, 107, 111, 109, 113, + 112, 0, 0, 0, 0, 83, 0, 0, 0, 0, + 91, 92, 94, 95, 96, 93, 0, 0, 89, 90, + 100, 101, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 108, 110, 103, 104, 105, 0, 97, 98, 99, 102, + 0, 0, 0, 84, 350, 0, 0, 85, 0, 87, + 86, 106, 107, 111, 109, 113, 112, 0, 0, 0, + 0, 83, 0, 0, 0, 0, 91, 92, 94, 95, + 96, 93, 0, 0, 89, 90, 100, 101, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, 108, 110, 103, 104, + 105, 0, 97, 98, 99, 102, 0, 0, 0, 84, + 0, 0, 318, 85, 0, 87, 86, 106, 107, 111, + 109, 113, 112, 0, 0, 0, 0, 83, 0, 0, + 0, 0, 91, 92, 94, 95, 96, 93, 0, 0, + 89, 90, 100, 101, 0, 0, 0, 0, 0, 0, + 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 82, 108, 110, 103, 104, 105, 0, 97, 98, + 99, 102, 0, 313, 0, 84, 0, 0, 0, 85, + 0, 87, 86, 106, 107, 111, 109, 113, 112, 0, + 0, 0, 0, 83, 0, 0, 0, 0, 91, 92, + 94, 95, 96, 93, 0, 0, 89, 90, 100, 101, + 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 82, 108, 110, + 103, 104, 105, 0, 97, 98, 99, 102, 0, 309, + 0, 84, 0, 0, 0, 85, 0, 87, 86, 106, + 107, 111, 109, 113, 112, 0, 0, 0, 0, 83, + 0, 0, 0, 0, 91, 92, 94, 95, 96, 93, + 0, 0, 89, 90, 100, 101, 0, 0, 0, 0, + 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 82, 108, 110, 103, 104, 105, 0, + 97, 98, 99, 102, 0, 300, 0, 84, 0, 0, + 0, 85, 0, 87, 86, 106, 107, 111, 109, 113, + 112, 0, 0, 0, 0, 83, 0, 0, 0, 0, + 91, 92, 94, 95, 96, 93, 0, 0, 89, 90, + 100, 101, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 289, 82, + 108, 110, 103, 104, 105, 0, 97, 98, 99, 102, + 0, 0, 0, 84, 0, 0, 0, 85, 0, 87, + 86, 106, 107, 111, 109, 113, 112, 0, 0, 0, + 0, 83, 0, 0, 0, 0, 91, 92, 94, 95, + 96, 93, 0, 0, 89, 90, 100, 101, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, 108, 110, 103, 104, + 105, 0, 97, 98, 99, 102, 0, 0, 0, 84, + 280, 0, 0, 85, 0, 87, 86, 106, 107, 111, + 109, 113, 112, 0, 0, 0, 0, 83, 0, 0, + 0, 0, 91, 92, 94, 95, 96, 93, 0, 0, + 89, 90, 100, 101, 0, 0, 0, 0, 0, 0, + 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 82, 108, 110, 103, 104, 105, 0, 97, 98, + 99, 102, 0, 0, 0, 84, 279, 0, 0, 85, + 0, 87, 86, 106, 107, 111, 109, 113, 112, 0, + 0, 0, 0, 83, 0, 0, 0, 0, 91, 92, + 94, 95, 96, 93, 0, 0, 89, 90, 100, 101, + 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 82, 108, 110, + 103, 104, 105, 0, 97, 98, 99, 102, 0, 0, + 0, 84, 0, 0, 260, 85, 0, 87, 86, 106, + 107, 111, 109, 113, 112, 0, 0, 0, 0, 83, + 0, 0, 0, 0, 91, 92, 94, 95, 96, 93, + 0, 0, 89, 90, 100, 101, 0, 0, 0, 0, + 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, + 0, 0, 247, 82, 108, 110, 103, 104, 105, 0, + 97, 98, 99, 102, 0, 0, 0, 84, 0, 0, + 0, 85, 0, 87, 86, 106, 107, 111, 109, 113, + 112, 0, 0, 0, 0, 83, 0, 0, 0, 0, + 91, 92, 94, 95, 96, 93, 0, 0, 89, 90, + 100, 101, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 108, 110, 103, 104, 105, 0, 97, 98, 99, 102, + 0, 0, 0, 84, 244, 0, 0, 85, 0, 87, + 86, 106, 107, 111, 109, 113, 112, 0, 0, 0, + 0, 83, 0, 0, 0, 0, 91, 92, 94, 95, + 96, 93, 0, 0, 89, 90, 100, 101, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, 108, 110, 103, 104, + 105, 0, 97, 98, 99, 102, 0, 0, 0, 84, + 221, 0, 0, 85, 0, 87, 86, 106, 107, 111, + 109, 113, 112, 0, 0, 0, 0, 83, 0, 0, + 0, 0, 91, 92, 94, 95, 96, 93, 0, 0, + 89, 90, 100, 101, 0, 0, 0, 0, 0, 0, + 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 82, 108, 110, 103, 104, 105, 0, 97, 98, + 99, 102, 0, 208, 0, 84, 0, 0, 0, 85, + 0, 87, 86, 106, 107, 111, 109, 113, 112, 0, + 0, 0, 0, 83, 0, 0, 0, 0, 91, 92, + 94, 95, 96, 93, 0, 0, 89, 90, 100, 101, + 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 82, 108, 110, + 103, 104, 105, 0, 97, 98, 99, 102, 0, 199, + 0, 84, 0, 0, 0, 85, 0, 87, 86, 106, + 107, 111, 109, 113, 112, 0, 0, 0, 0, 83, + 0, 0, 0, 0, 91, 92, 94, 95, 96, 93, + 0, 0, 89, 90, 100, 101, 0, 0, 0, 0, + 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 82, 108, 110, 103, 104, 105, 0, + 97, 98, 99, 102, 0, 0, 0, 84, 0, 0, + 0, 85, 0, 87, 86, 106, 107, 111, 109, 113, + 112, 0, 0, 0, 0, 83, 0, 0, 0, 0, + 91, 92, 94, 95, 96, 93, 0, 0, 89, 90, + 100, 101, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 108, 110, 103, 104, 105, 0, 97, 98, 99, 102, + 0, 0, 0, 161, 0, 0, 0, 85, 0, 87, + 86, 106, 107, 111, 109, 113, 112, 0, 0, 0, + 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 89, 90, 100, 101, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, 108, 110, 103, 104, + 105, 0, 97, 98, 99, 102, 0, 0, 0, 84, + 0, 0, 0, 85, 0, 87, 86, 106, 107, 111, + 109, 113, 112, 0, 0, 0, 0, 83, 0, 0, + 35, 52, 53, 0, 0, 31, 0, 0, 0, 0, + 89, 90, 100, 101, 0, 0, 0, 0, 0, 39, + 54, 55, 56, 0, 0, 0, 0, 0, 0, 0, + 0, 82, 108, 110, 103, 104, 105, 0, 97, 98, + 99, 102, 0, 0, 0, 84, 40, 57, 0, 85, + 37, 87, 0, 41, 38, 0, 0, 0, 0, 0, + 0, 51, 0, 59, 61, 0, 0, 60, 0, 42, + 0, 34, 35, 52, 53, 32, 336, 31, 58, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 39, 54, 55, 56, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 35, 52, + 53, 0, 0, 31, 0, 0, 0, 0, 40, 57, + 0, 0, 37, 0, 0, 41, 38, 39, 54, 55, + 56, 0, 0, 51, 0, 59, 61, 0, 0, 60, + 0, 42, 0, 34, 35, 52, 53, 32, 305, 31, + 58, 0, 0, 0, 40, 57, 0, 0, 37, 0, + 0, 41, 38, 39, 54, 55, 56, 0, 0, 51, + 0, 59, 61, 0, 0, 60, 0, 42, 0, 34, + 0, 0, 261, 32, 0, 0, 58, 0, 0, 0, + 40, 57, 0, 0, 37, 0, 0, 41, 38, 0, + 224, 0, 0, 0, 0, 51, 0, 59, 61, 0, + 0, 60, 0, 42, 0, 34, 35, 52, 53, 32, + 0, 31, 58, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 39, 54, 55, 56, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 35, 52, 53, 0, 0, 31, 0, 0, + 0, 0, 40, 57, 0, 0, 37, 0, 0, 41, + 38, 39, 54, 55, 56, 0, 0, 51, 0, 59, + 61, 0, 0, 60, 0, 42, 0, 34, 0, 0, + 205, 32, 0, 0, 58, 0, 0, 0, 40, 57, + 0, 0, 37, 0, 0, 41, 38, 0, 172, 0, + 0, 0, 0, 51, 0, 59, 61, 0, 0, 60, + 0, 42, 0, 34, 35, 52, 53, 32, 0, 31, + 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 39, 54, 55, 56, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 35, 52, 53, 0, 0, 31, 0, 0, 0, 0, + 40, 57, 0, 0, 37, 0, 0, 41, 38, 39, + 54, 55, 56, 0, 0, 51, 0, 59, 61, 0, + 0, 60, 0, 42, 0, 34, 35, 52, 53, 32, + 0, 31, 58, 0, 0, 0, 40, 57, 0, 0, + 37, 0, 0, 41, 38, 39, 54, 55, 56, 0, + 0, 51, 0, 59, 61, 0, 0, 60, 0, 362, + 0, 34, 35, 52, 53, 32, 0, 31, 58, 0, + 0, 0, 40, 57, 0, 0, 37, 0, 0, 41, + 38, 39, 54, 55, 56, 0, 0, 51, 0, 59, + 61, 0, 0, 60, 0, 316, 0, 34, 35, 52, + 53, 32, 0, 31, 58, 0, 0, 0, 40, 57, + 0, 0, 37, 0, 0, 41, 38, 39, 54, 55, + 56, 0, 0, 51, 0, 59, 61, 0, 0, 60, + 0, 314, 0, 34, 0, 0, 0, 32, 0, 0, + 58, 0, 0, 0, 40, 57, 0, 0, 37, 0, + 0, 41, 38, 0, 86, 106, 107, 111, 109, 51, + 112, 59, 61, 0, 0, 60, 0, 258, 0, 34, + 0, 0, 0, 32, 0, 0, 58, 0, 89, 90, + 100, 101, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 108, 110, 103, 104, 105, 0, 97, 98, 99, 102, + 35, 150, 53, 84, 0, 31, 0, 85, 0, 87, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, + 54, 55, 56, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 75, 52, 53, 0, + 0, 31, 0, 0, 0, 0, 40, 57, 0, 0, + 37, 0, 0, 41, 38, 39, 54, 55, 56, 0, + 0, 51, 0, 59, 61, 0, 0, 60, 0, 42, + 0, 34, 0, 0, 0, 32, 0, 0, 58, 0, + 0, 0, 40, 57, 0, 0, 37, 0, 0, 41, + 38, 86, 106, 107, 111, 109, 0, 51, 0, 59, + 61, 0, 0, 60, 0, 42, 0, 34, 0, 0, + 0, 32, 0, 0, 58, 89, 90, 100, 101, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 108, 110, 103, + 104, 105, 0, 97, 98, 99, 102, 0, 0, 0, + 84, 0, 0, 0, 85, 0, 87, +} +var yyPact = [...]int{ + + -67, -1000, 631, -67, -1000, -71, -71, -1000, -1000, -1000, + -1000, -1000, -1000, 3490, 3490, 306, 213, 3782, 93, 89, + 283, -1000, -1000, 1226, -1000, -1000, 3490, 465, 3490, -1000, + -1000, 146, -59, 206, 3490, 40, -28, 76, 62, 59, + 53, -7, -71, -1000, -1000, -1000, -1000, -1000, 302, 71, + -1000, 3746, -1000, -1000, -1000, -1000, -1000, 3490, 3490, 3490, + 3490, 3490, -1000, -1000, -1000, -1000, -1000, 631, -71, -1000, + -8, 2942, 2942, 210, -67, 50, 3008, 3490, 3490, 200, + 3490, 3490, 3490, 3490, 3490, 3418, 3490, 303, 3490, -1000, + -1000, 3490, 3490, 3490, 3490, 3490, 3490, 3490, 3490, 3490, + 3490, 3490, 3490, 3490, 3490, 3490, 3490, 3490, 3490, 3490, + 3490, 3490, 3490, 3490, 2876, -67, 49, 553, 3382, -34, + 40, 2810, 302, 16, -25, 3490, -71, -10, -1000, 206, + 206, -15, 206, 209, -30, 2744, 3490, 3310, 3490, 3490, + 206, 179, -71, 206, 3490, 65, -1000, 3490, 3490, -71, + -1000, -41, 3074, -41, -41, -41, -41, -1000, -67, 197, + 3490, 3490, 1160, 2678, 3490, -67, 2942, 2942, 2612, 3140, + 163, 1094, 3490, 189, -1000, 3074, 2942, 2942, 2942, 2942, + 2942, 2942, 189, 189, 189, 189, 189, 189, 120, 120, + 120, 484, 484, 484, 484, 484, 484, 3825, 3678, -67, + 195, -71, 3490, -71, -67, 3634, 2546, 3274, -71, 139, + 302, -1000, -60, -71, 301, -42, -42, 206, -42, -71, + -25, -1000, 121, 1028, 3490, 2480, 2414, -50, -44, 300, + 3490, -35, -64, 2348, 3490, -8, 2942, 3490, 193, 266, + 110, 77, -1000, 3490, -1000, 2282, 192, 3490, 12, -1000, + -1000, 3238, 962, 191, -1000, 2216, 297, 186, -67, 2150, + 3598, 3562, 2084, 247, 208, 4, 45, -71, -31, -71, + 3490, -1000, -38, 295, 1, -1000, -1000, 3166, 896, -1000, + -1000, -1000, -1000, 3490, -3, -64, 206, 185, -71, 3490, + -8, 2942, -28, -1000, 180, 0, -1000, -1, -1000, 2018, + -67, -1000, 3074, -1000, 830, -1000, -1000, 3490, -1000, -67, + -1000, -1000, 183, -67, -67, 1952, -67, 1886, 3526, -36, + -1000, -1000, 134, 3490, -67, 207, 204, -9, -71, -1000, + -60, 206, -63, 206, -1000, 764, -1000, -1000, 3490, 698, + 3490, 182, -51, -1000, 3490, 2942, 203, -67, -1000, -1000, + -1000, 177, -1000, 3490, 1820, 175, -1000, 168, 159, -67, + 152, -67, -67, 1754, 150, -1000, -1000, -67, 1688, 13, + 140, -67, -67, 202, 137, -42, 135, -71, -42, -1000, + 3490, 1622, -1000, 3490, 1556, -1000, -71, 1490, -67, 128, + -1000, 1424, -1000, -1000, -1000, -1000, 122, -1000, 107, 106, + -67, -1000, -1000, -67, -67, -1000, 104, 103, -67, -1000, + -1000, 294, 1358, -1000, 1292, -1000, 3490, 3490, 102, 263, + -1000, -1000, -1000, -1000, 100, -1000, -1000, -1000, -1000, 98, + 206, -1000, -1000, -64, 2942, 257, 199, -1000, -1000, -42, + 96, 164, -67, -1000, -67, 78, 46, -1000, -1000, +} +var yyPgo = [...]int{ + + 0, 41, 353, 279, 303, 352, 350, 349, 348, 346, + 344, 6, 5, 56, 0, 8, 25, 343, 2, 340, + 338, 7, 337, 4, 335, 333, 330, 328, 323, 321, + 320, 316, 314, 313, 311, 159, 1, 179, 48, +} +var yyR1 = [...]int{ + + 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, + 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 9, 10, + 10, 10, 10, 10, 11, 11, 12, 13, 13, 13, + 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 15, 15, 15, 16, 16, + 16, 16, 16, 16, 16, 17, 17, 18, 18, 19, + 19, 20, 21, 22, 22, 22, 22, 22, 22, 23, + 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 25, 25, 26, 26, 26, 26, 26, 27, + 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, + 28, 32, 32, 32, 32, 32, 32, 31, 31, 31, + 30, 30, 30, 30, 30, 30, 29, 29, 33, 33, + 34, 34, 34, 35, 35, 37, 37, 38, 36, 36, + 36, 36, +} +var yyR2 = [...]int{ + + 0, 1, 2, 2, 3, 0, 1, 1, 1, 2, + 2, 5, 13, 12, 9, 8, 6, 5, 6, 5, + 4, 6, 4, 1, 1, 1, 1, 1, 1, 4, + 3, 3, 3, 3, 5, 7, 5, 4, 7, 5, + 6, 7, 7, 8, 7, 8, 8, 9, 7, 0, + 1, 1, 2, 2, 4, 4, 3, 0, 1, 4, + 4, 1, 1, 5, 3, 7, 8, 8, 9, 2, + 5, 7, 3, 5, 4, 5, 4, 4, 4, 4, + 4, 4, 4, 6, 8, 7, 3, 6, 10, 5, + 1, 1, 1, 1, 1, 0, 1, 4, 1, 3, + 2, 2, 5, 2, 6, 2, 5, 2, 3, 1, + 1, 3, 1, 2, 1, 1, 1, 1, 1, 0, + 3, 6, 6, 5, 5, 7, 8, 6, 5, 5, + 7, 8, 3, 2, 2, 2, 2, 2, 2, 1, + 1, 1, 1, 2, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, + 2, 1, 1, 0, 1, 1, 2, 1, 0, 2, + 1, 1, +} +var yyChk = [...]int{ + + -1000, -1, -33, -2, -34, 78, -37, -38, 83, -3, + -4, 38, 39, 10, 12, 28, 29, 47, 55, 56, + -7, -8, -9, -14, -5, -6, 13, 15, 44, -19, + -22, 9, 79, -18, 75, 4, -21, 54, 58, 23, + 50, 57, 73, -24, -25, -26, -27, -28, 11, -13, + -20, 65, 5, 6, 24, 25, 26, 51, 82, 67, + 71, 68, -32, -31, -30, -29, -33, -34, -37, -38, + -13, -14, -14, 4, 73, 4, -14, 75, 75, 14, + 59, 52, 61, 27, 75, 79, 16, 81, 51, 40, + 41, 32, 33, 37, 34, 35, 36, 68, 69, 70, + 42, 43, 71, 64, 65, 66, 17, 18, 62, 20, + 63, 19, 22, 21, -14, 73, -15, -14, 78, -4, + 4, -14, 75, 4, 80, -35, -37, -16, 4, 68, + -18, 57, 48, 49, 79, -14, 75, 79, 75, 75, + 75, 75, 73, 79, -35, -15, 4, 59, 52, 77, + 5, -14, -14, -14, -14, -14, -14, -3, 73, -1, + 75, 75, -14, -14, 13, 73, -14, -14, -14, -14, + -13, -14, 60, -14, 4, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, 73, + -1, -37, 16, 77, 73, 78, -14, 78, 73, -15, + 75, -18, -13, 73, 81, -16, -16, 79, -16, 73, + 80, 76, -13, -14, 60, -14, -14, -16, -16, 53, + -35, -16, -23, -14, 59, -13, -14, -35, -1, 74, + -13, -13, 76, 77, 76, -14, -1, 60, 8, 76, + 80, 60, -14, -1, 74, -14, -35, -1, 73, -14, + 78, 78, -14, -35, 76, 8, -15, 77, -36, -37, + -35, 4, -16, -35, 8, 76, 80, 60, -14, 76, + 76, 76, 76, 77, 4, -23, 80, -36, 77, 60, + -13, -14, -21, 74, 30, 8, 76, 8, 76, -14, + 73, 74, -14, 76, -14, 80, 80, 60, 74, 73, + 4, 74, -1, 73, 73, -14, 73, -14, 78, -10, + -12, -11, 46, 45, 73, 76, 76, 8, -37, 80, + -13, 80, -17, 4, 76, -14, 80, 80, 60, -14, + 77, -36, -16, 74, -35, -14, 4, 73, 76, 76, + 76, -1, 80, 60, -14, -1, 74, -1, -1, 73, + -1, 73, 73, -14, -35, -11, -12, 60, -14, -13, + -1, 73, 73, 76, -36, -16, -35, 77, -16, 80, + 60, -14, 76, 77, -14, 74, 73, -14, 73, -1, + 74, -14, 80, 74, 74, 74, -1, 74, -1, -1, + 73, 74, -1, 60, 60, 74, -1, -1, 73, 74, + 74, -35, -14, 80, -14, 76, -35, 60, -1, 74, + 80, 74, 74, 74, -1, -1, -1, 74, 74, -1, + 4, 80, 76, -23, -14, 74, 31, 74, 74, -16, + -36, 31, 73, 74, 73, -1, -1, 74, 74, +} +var yyDef = [...]int{ + + 168, -2, -2, 168, 169, 172, 171, 175, 177, 3, + 6, 7, 8, 57, 0, 0, 0, 0, 0, 0, + 23, 24, 25, -2, 27, 28, 0, -2, 0, 61, + 62, 0, 173, 0, 0, 112, 110, 0, 0, 0, + 0, 0, 173, 90, 91, 92, 93, 94, 95, 0, + 109, 0, 114, 115, 116, 117, 118, 0, 0, 0, + 0, 0, 139, 140, 141, 142, 2, -2, 170, 176, + 9, 58, 10, 0, 168, 112, 0, 0, 0, 0, + 0, 0, 0, 0, 57, 0, 0, 0, 0, 143, + 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 168, 0, 58, 0, 0, + -2, 0, 95, 0, -2, 57, 174, 0, 98, 0, + 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, + 0, 0, 173, 0, 119, 0, 96, 57, 0, 173, + 113, 134, 133, 135, 136, 137, 138, 4, 168, 0, + 57, 57, 0, 0, 0, 168, 30, 32, 0, 64, + 0, 0, 0, 86, 111, 132, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 0, 171, 0, 173, 168, 0, 0, 0, 173, 0, + 95, 108, 178, 173, 0, 100, 101, 0, 103, 173, + 107, 72, 0, 0, 0, 0, 0, 0, 0, 0, + 119, 0, 178, 0, 57, 31, 33, 0, 0, 0, + 0, 0, 20, 0, 22, 0, 0, 0, 0, 76, + 78, 0, 0, 0, 37, 0, 0, 0, 168, 0, + 0, 0, 0, 49, 0, 0, 0, -2, 0, 180, + 57, 99, 0, 0, 0, 74, 77, 0, 0, 79, + 80, 81, 82, 0, 0, 178, 0, 0, -2, 0, + 29, 59, -2, 11, 0, 0, -2, 0, -2, 0, + 168, 36, 63, 75, 0, 128, 129, 0, 34, 168, + 97, 39, 0, 168, 168, 0, 168, 0, 0, 173, + 50, 51, 0, 57, 168, 0, 0, 0, -2, 70, + 178, 0, 173, 0, 73, 0, 123, 124, 0, 0, + 0, 0, 0, 89, 0, 120, 0, 168, -2, -2, + 21, 0, 127, 0, 0, 0, 40, 0, 0, 168, + 0, 168, 168, 0, 0, 52, 53, 168, 58, 0, + 0, 168, 168, 0, 0, 102, 0, 173, 105, 122, + 0, 0, 83, 0, 0, 87, 173, 0, 168, 0, + 35, 0, 130, 38, 41, 42, 0, 44, 0, 0, + 168, 48, 56, 168, 168, 65, 0, 0, 168, 71, + 104, 0, 0, 125, 0, 85, 119, 0, 0, 15, + 131, 43, 45, 46, 0, 54, 55, 66, 67, 0, + 0, 126, 84, 178, 121, 14, 0, 47, 68, 106, + 0, 0, 168, 88, 168, 0, 0, 13, 12, +} +var yyTok1 = [...]int{ + + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 83, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 82, 3, 3, 3, 70, 71, 3, + 75, 76, 68, 64, 77, 65, 81, 69, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 60, 78, + 62, 59, 63, 61, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 79, 3, 80, 67, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 73, 66, 74, +} +var yyTok2 = [...]int{ + + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 72, +} +var yyTok3 = [...]int{ + 0, +} + +var yyErrorMessages = [...]struct { + state int + token int + msg string +}{} + +//line yaccpar:1 + +/* parser for yacc output */ + +var ( + yyDebug = 0 + yyErrorVerbose = false +) + +type yyLexer interface { + Lex(lval *yySymType) int + Error(s string) +} + +type yyParser interface { + Parse(yyLexer) int + Lookahead() int +} + +type yyParserImpl struct { + lval yySymType + stack [yyInitialStackSize]yySymType + char int +} + +func (p *yyParserImpl) Lookahead() int { + return p.char +} + +func yyNewParser() yyParser { + return &yyParserImpl{} +} + +const yyFlag = -1000 + +func yyTokname(c int) string { + if c >= 1 && c-1 < len(yyToknames) { + if yyToknames[c-1] != "" { + return yyToknames[c-1] + } + } + return __yyfmt__.Sprintf("tok-%v", c) +} + +func yyStatname(s int) string { + if s >= 0 && s < len(yyStatenames) { + if yyStatenames[s] != "" { + return yyStatenames[s] + } + } + return __yyfmt__.Sprintf("state-%v", s) +} + +func yyErrorMessage(state, lookAhead int) string { + const TOKSTART = 4 + + if !yyErrorVerbose { + return "syntax error" + } + + for _, e := range yyErrorMessages { + if e.state == state && e.token == lookAhead { + return "syntax error: " + e.msg + } + } + + res := "syntax error: unexpected " + yyTokname(lookAhead) + + // To match Bison, suggest at most four expected tokens. + expected := make([]int, 0, 4) + + // Look for shiftable tokens. + base := yyPact[state] + for tok := TOKSTART; tok-1 < len(yyToknames); tok++ { + if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok { + if len(expected) == cap(expected) { + return res + } + expected = append(expected, tok) + } + } + + if yyDef[state] == -2 { + i := 0 + for yyExca[i] != -1 || yyExca[i+1] != state { + i += 2 + } + + // Look for tokens that we accept or reduce. + for i += 2; yyExca[i] >= 0; i += 2 { + tok := yyExca[i] + if tok < TOKSTART || yyExca[i+1] == 0 { + continue + } + if len(expected) == cap(expected) { + return res + } + expected = append(expected, tok) + } + + // If the default action is to accept or reduce, give up. + if yyExca[i+1] != 0 { + return res + } + } + + for i, tok := range expected { + if i == 0 { + res += ", expecting " + } else { + res += " or " + } + res += yyTokname(tok) + } + return res +} + +func yylex1(lex yyLexer, lval *yySymType) (char, token int) { + token = 0 + char = lex.Lex(lval) + if char <= 0 { + token = yyTok1[0] + goto out + } + if char < len(yyTok1) { + token = yyTok1[char] + goto out + } + if char >= yyPrivate { + if char < yyPrivate+len(yyTok2) { + token = yyTok2[char-yyPrivate] + goto out + } + } + for i := 0; i < len(yyTok3); i += 2 { + token = yyTok3[i+0] + if token == char { + token = yyTok3[i+1] + goto out + } + } + +out: + if token == 0 { + token = yyTok2[1] /* unknown char */ + } + if yyDebug >= 3 { + __yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char)) + } + return char, token +} + +func yyParse(yylex yyLexer) int { + return yyNewParser().Parse(yylex) +} + +func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int { + var yyn int + var yyVAL yySymType + var yyDollar []yySymType + _ = yyDollar // silence set and not used + yyS := yyrcvr.stack[:] + + Nerrs := 0 /* number of errors */ + Errflag := 0 /* error recovery flag */ + yystate := 0 + yyrcvr.char = -1 + yytoken := -1 // yyrcvr.char translated into internal numbering + defer func() { + // Make sure we report no lookahead when not parsing. + yystate = -1 + yyrcvr.char = -1 + yytoken = -1 + }() + yyp := -1 + goto yystack + +ret0: + return 0 + +ret1: + return 1 + +yystack: + /* put a state and value onto the stack */ + if yyDebug >= 4 { + __yyfmt__.Printf("char %v in %v\n", yyTokname(yytoken), yyStatname(yystate)) + } + + yyp++ + if yyp >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyS[yyp] = yyVAL + yyS[yyp].yys = yystate + +yynewstate: + yyn = yyPact[yystate] + if yyn <= yyFlag { + goto yydefault /* simple state */ + } + if yyrcvr.char < 0 { + yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval) + } + yyn += yytoken + if yyn < 0 || yyn >= yyLast { + goto yydefault + } + yyn = yyAct[yyn] + if yyChk[yyn] == yytoken { /* valid shift */ + yyrcvr.char = -1 + yytoken = -1 + yyVAL = yyrcvr.lval + yystate = yyn + if Errflag > 0 { + Errflag-- + } + goto yystack + } + +yydefault: + /* default state action */ + yyn = yyDef[yystate] + if yyn == -2 { + if yyrcvr.char < 0 { + yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval) + } + + /* look through exception table */ + xi := 0 + for { + if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { + break + } + xi += 2 + } + for xi += 2; ; xi += 2 { + yyn = yyExca[xi+0] + if yyn < 0 || yyn == yytoken { + break + } + } + yyn = yyExca[xi+1] + if yyn < 0 { + goto ret0 + } + } + if yyn == 0 { + /* error ... attempt to resume parsing */ + switch Errflag { + case 0: /* brand new error */ + yylex.Error(yyErrorMessage(yystate, yytoken)) + Nerrs++ + if yyDebug >= 1 { + __yyfmt__.Printf("%s", yyStatname(yystate)) + __yyfmt__.Printf(" saw %s\n", yyTokname(yytoken)) + } + fallthrough + + case 1, 2: /* incompletely recovered error ... try again */ + Errflag = 3 + + /* find a state where "error" is a legal shift action */ + for yyp >= 0 { + yyn = yyPact[yyS[yyp].yys] + yyErrCode + if yyn >= 0 && yyn < yyLast { + yystate = yyAct[yyn] /* simulate a shift of "error" */ + if yyChk[yystate] == yyErrCode { + goto yystack + } + } + + /* the current p has no shift on "error", pop stack */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) + } + yyp-- + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1 + + case 3: /* no shift yet; clobber input char */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yytoken)) + } + if yytoken == yyEofCode { + goto ret1 + } + yyrcvr.char = -1 + yytoken = -1 + goto yynewstate /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if yyDebug >= 2 { + __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) + } + + yynt := yyn + yypt := yyp + _ = yypt // guard against "declared and not used" + + yyp -= yyR2[yyn] + // yyp is now the index of $0. Perform the default action. Iff the + // reduced production is ε, $1 is possibly out of range. + if yyp+1 >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyVAL = yyS[yyp+1] + + /* consult goto table to find next state */ + yyn = yyR1[yyn] + yyg := yyPgo[yyn] + yyj := yyg + yyS[yyp].yys + 1 + + if yyj >= yyLast { + yystate = yyAct[yyg] + } else { + yystate = yyAct[yyj] + if yyChk[yystate] != -yyn { + yystate = yyAct[yyg] + } + } + // dummy call; replaced with literal code + switch yynt { + + case 1: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:108 + { + yyVAL.compstmt = nil + } + case 2: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:112 + { + yyVAL.compstmt = yyDollar[1].stmts + } + case 3: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:118 + { + if yyDollar[2].stmt != nil { + yyVAL.stmts = &ast.StmtsStmt{Stmts: []ast.Stmt{yyDollar[2].stmt}} + } + if l, ok := yylex.(*Lexer); ok { + l.stmt = yyVAL.stmts + } + } + case 4: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:127 + { + if yyDollar[3].stmt != nil { + if yyDollar[1].stmts == nil { + yyVAL.stmts = &ast.StmtsStmt{Stmts: []ast.Stmt{yyDollar[3].stmt}} + } else { + stmts := yyDollar[1].stmts.(*ast.StmtsStmt) + stmts.Stmts = append(stmts.Stmts, yyDollar[3].stmt) + } + if l, ok := yylex.(*Lexer); ok { + l.stmt = yyVAL.stmts + } + } + } + case 5: + yyDollar = yyS[yypt-0 : yypt+1] +//line parser.go.y:143 + { + yyVAL.stmt = nil + } + case 6: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:147 + { + yyVAL.stmt = yyDollar[1].stmt_var_or_lets + } + case 7: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:151 + { + yyVAL.stmt = &ast.BreakStmt{} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 8: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:156 + { + yyVAL.stmt = &ast.ContinueStmt{} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 9: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:161 + { + yyVAL.stmt = &ast.ReturnStmt{Exprs: yyDollar[2].exprs} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 10: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:166 + { + yyVAL.stmt = &ast.ThrowStmt{Expr: yyDollar[2].expr} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 11: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:171 + { + yyVAL.stmt = &ast.ModuleStmt{Name: yyDollar[2].tok.Lit, Stmt: yyDollar[4].compstmt} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 12: + yyDollar = yyS[yypt-13 : yypt+1] +//line parser.go.y:176 + { + yyVAL.stmt = &ast.TryStmt{Try: yyDollar[3].compstmt, Var: yyDollar[6].tok.Lit, Catch: yyDollar[8].compstmt, Finally: yyDollar[12].compstmt} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 13: + yyDollar = yyS[yypt-12 : yypt+1] +//line parser.go.y:181 + { + yyVAL.stmt = &ast.TryStmt{Try: yyDollar[3].compstmt, Catch: yyDollar[7].compstmt, Finally: yyDollar[11].compstmt} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 14: + yyDollar = yyS[yypt-9 : yypt+1] +//line parser.go.y:186 + { + yyVAL.stmt = &ast.TryStmt{Try: yyDollar[3].compstmt, Var: yyDollar[6].tok.Lit, Catch: yyDollar[8].compstmt} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 15: + yyDollar = yyS[yypt-8 : yypt+1] +//line parser.go.y:191 + { + yyVAL.stmt = &ast.TryStmt{Try: yyDollar[3].compstmt, Catch: yyDollar[7].compstmt} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 16: + yyDollar = yyS[yypt-6 : yypt+1] +//line parser.go.y:196 + { + yyVAL.stmt = &ast.GoroutineStmt{Expr: &ast.CallExpr{Name: yyDollar[2].tok.Lit, SubExprs: yyDollar[4].exprs, VarArg: true, Go: true}} + yyVAL.stmt.SetPosition(yyDollar[2].tok.Position()) + } + case 17: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:201 + { + yyVAL.stmt = &ast.GoroutineStmt{Expr: &ast.CallExpr{Name: yyDollar[2].tok.Lit, SubExprs: yyDollar[4].exprs, Go: true}} + yyVAL.stmt.SetPosition(yyDollar[2].tok.Position()) + } + case 18: + yyDollar = yyS[yypt-6 : yypt+1] +//line parser.go.y:206 + { + yyVAL.stmt = &ast.GoroutineStmt{Expr: &ast.AnonCallExpr{Expr: yyDollar[2].expr, SubExprs: yyDollar[4].exprs, VarArg: true, Go: true}} + yyVAL.stmt.SetPosition(yyDollar[2].expr.Position()) + } + case 19: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:211 + { + yyVAL.stmt = &ast.GoroutineStmt{Expr: &ast.AnonCallExpr{Expr: yyDollar[2].expr, SubExprs: yyDollar[4].exprs, Go: true}} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 20: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:216 + { + yyVAL.stmt = &ast.DeleteStmt{Item: yyDollar[3].expr} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 21: + yyDollar = yyS[yypt-6 : yypt+1] +//line parser.go.y:221 + { + yyVAL.stmt = &ast.DeleteStmt{Item: yyDollar[3].expr, Key: yyDollar[5].expr} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 22: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:226 + { + yyVAL.stmt = &ast.CloseStmt{Expr: yyDollar[3].expr} + yyVAL.stmt.SetPosition(yyDollar[1].tok.Position()) + } + case 23: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:231 + { + yyVAL.stmt = yyDollar[1].stmt_if + } + case 24: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:235 + { + yyVAL.stmt = yyDollar[1].stmt_for + } + case 25: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:239 + { + yyVAL.stmt = yyDollar[1].stmt_switch + } + case 26: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:243 + { + yyVAL.stmt = &ast.ExprStmt{Expr: yyDollar[1].expr} + yyVAL.stmt.SetPosition(yyDollar[1].expr.Position()) + } + case 27: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:250 + { + yyVAL.stmt_var_or_lets = yyDollar[1].stmt_var + } + case 28: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:254 + { + yyVAL.stmt_var_or_lets = yyDollar[1].stmt_lets + } + case 29: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:260 + { + yyVAL.stmt_var = &ast.VarStmt{Names: yyDollar[2].expr_idents, Exprs: yyDollar[4].exprs} + yyVAL.stmt_var.SetPosition(yyDollar[1].tok.Position()) + } + case 30: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:267 + { + yyVAL.stmt_lets = &ast.LetsStmt{LHSS: []ast.Expr{yyDollar[1].expr}, RHSS: []ast.Expr{yyDollar[3].expr}} + yyVAL.stmt_lets.SetPosition(yyDollar[1].expr.Position()) + } + case 31: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:272 + { + if len(yyDollar[1].exprs) == 2 && len(yyDollar[3].exprs) == 1 { + if _, ok := yyDollar[3].exprs[0].(*ast.ItemExpr); ok { + yyVAL.stmt_lets = &ast.LetMapItemStmt{LHSS: yyDollar[1].exprs, RHS: yyDollar[3].exprs[0]} + } else { + yyVAL.stmt_lets = &ast.LetsStmt{LHSS: yyDollar[1].exprs, RHSS: yyDollar[3].exprs} + } + } else { + yyVAL.stmt_lets = &ast.LetsStmt{LHSS: yyDollar[1].exprs, RHSS: yyDollar[3].exprs} + } + } + case 32: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:284 + { + yyVAL.stmt_lets = &ast.ChanStmt{LHS: yyDollar[1].expr, RHS: yyDollar[3].expr} + yyVAL.stmt_lets.SetPosition(yyDollar[1].expr.Position()) + } + case 33: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:289 + { + if len(yyDollar[1].exprs) == 2 { + chanStmt := &ast.ChanStmt{LHS: yyDollar[1].exprs[0].(ast.Expr), OkExpr: yyDollar[1].exprs[1].(ast.Expr), RHS: yyDollar[3].expr} + yyVAL.stmt_lets = chanStmt + yyVAL.stmt_lets.SetPosition(chanStmt.LHS.Position()) + } else if len(yyDollar[1].exprs) < 2 { + yylex.Error("missing expressions on left side of channel operator") + yyVAL.stmt_lets = &ast.ChanStmt{RHS: yyDollar[3].expr} + yyVAL.stmt_lets.SetPosition(yyDollar[2].tok.Position()) + } + } + case 34: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:303 + { + yyVAL.stmt_if = &ast.IfStmt{If: yyDollar[2].expr, Then: yyDollar[4].compstmt, Else: nil} + yyVAL.stmt_if.SetPosition(yyDollar[1].tok.Position()) + } + case 35: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:308 + { + ifStmt := yyDollar[1].stmt_if.(*ast.IfStmt) + ifStmt.ElseIf = append(ifStmt.ElseIf, &ast.IfStmt{If: yyDollar[4].expr, Then: yyDollar[6].compstmt}) + } + case 36: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:313 + { + ifStmt := yyDollar[1].stmt_if.(*ast.IfStmt) + if ifStmt.Else != nil { + yylex.Error("multiple else statement") + } + ifStmt.Else = yyDollar[4].compstmt + } + case 37: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:323 + { + yyVAL.stmt_for = &ast.LoopStmt{Stmt: yyDollar[3].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + case 38: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:328 + { + if len(yyDollar[2].expr_idents) < 1 { + yylex.Error("missing identifier") + } else if len(yyDollar[2].expr_idents) > 2 { + yylex.Error("too many identifiers") + } else { + yyVAL.stmt_for = &ast.ForStmt{Vars: yyDollar[2].expr_idents, Value: yyDollar[4].expr, Stmt: yyDollar[6].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + } + case 39: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:339 + { + yyVAL.stmt_for = &ast.LoopStmt{Expr: yyDollar[2].expr, Stmt: yyDollar[4].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + case 40: + yyDollar = yyS[yypt-6 : yypt+1] +//line parser.go.y:344 + { + yyVAL.stmt_for = &ast.CForStmt{Stmt: yyDollar[5].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + case 41: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:349 + { + yyVAL.stmt_for = &ast.CForStmt{Expr3: yyDollar[4].expr, Stmt: yyDollar[6].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + case 42: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:354 + { + yyVAL.stmt_for = &ast.CForStmt{Expr2: yyDollar[3].expr, Stmt: yyDollar[6].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + case 43: + yyDollar = yyS[yypt-8 : yypt+1] +//line parser.go.y:359 + { + yyVAL.stmt_for = &ast.CForStmt{Expr2: yyDollar[3].expr, Expr3: yyDollar[5].expr, Stmt: yyDollar[7].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + case 44: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:364 + { + yyVAL.stmt_for = &ast.CForStmt{Stmt1: yyDollar[2].stmt_var_or_lets, Stmt: yyDollar[6].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + case 45: + yyDollar = yyS[yypt-8 : yypt+1] +//line parser.go.y:369 + { + yyVAL.stmt_for = &ast.CForStmt{Stmt1: yyDollar[2].stmt_var_or_lets, Expr3: yyDollar[5].expr, Stmt: yyDollar[7].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + case 46: + yyDollar = yyS[yypt-8 : yypt+1] +//line parser.go.y:374 + { + yyVAL.stmt_for = &ast.CForStmt{Stmt1: yyDollar[2].stmt_var_or_lets, Expr2: yyDollar[4].expr, Stmt: yyDollar[7].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + case 47: + yyDollar = yyS[yypt-9 : yypt+1] +//line parser.go.y:379 + { + yyVAL.stmt_for = &ast.CForStmt{Stmt1: yyDollar[2].stmt_var_or_lets, Expr2: yyDollar[4].expr, Expr3: yyDollar[6].expr, Stmt: yyDollar[8].compstmt} + yyVAL.stmt_for.SetPosition(yyDollar[1].tok.Position()) + } + case 48: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:386 + { + switchStmt := yyDollar[5].stmt_switch_cases.(*ast.SwitchStmt) + switchStmt.Expr = yyDollar[2].expr + yyVAL.stmt_switch = switchStmt + yyVAL.stmt_switch.SetPosition(yyDollar[1].tok.Position()) + } + case 49: + yyDollar = yyS[yypt-0 : yypt+1] +//line parser.go.y:395 + { + yyVAL.stmt_switch_cases = &ast.SwitchStmt{} + } + case 50: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:399 + { + yyVAL.stmt_switch_cases = &ast.SwitchStmt{Default: yyDollar[1].stmt_switch_default} + } + case 51: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:403 + { + yyVAL.stmt_switch_cases = &ast.SwitchStmt{Cases: []ast.Stmt{yyDollar[1].stmt_switch_case}} + } + case 52: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:407 + { + switchStmt := yyDollar[1].stmt_switch_cases.(*ast.SwitchStmt) + switchStmt.Cases = append(switchStmt.Cases, yyDollar[2].stmt_switch_case) + yyVAL.stmt_switch_cases = switchStmt + } + case 53: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:413 + { + switchStmt := yyDollar[1].stmt_switch_cases.(*ast.SwitchStmt) + if switchStmt.Default != nil { + yylex.Error("multiple default statement") + } + switchStmt.Default = yyDollar[2].stmt_switch_default + } + case 54: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:423 + { + yyVAL.stmt_switch_case = &ast.SwitchCaseStmt{Exprs: []ast.Expr{yyDollar[2].expr}, Stmt: yyDollar[4].compstmt} + yyVAL.stmt_switch_case.SetPosition(yyDollar[1].tok.Position()) + } + case 55: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:428 + { + yyVAL.stmt_switch_case = &ast.SwitchCaseStmt{Exprs: yyDollar[2].exprs, Stmt: yyDollar[4].compstmt} + yyVAL.stmt_switch_case.SetPosition(yyDollar[1].tok.Position()) + } + case 56: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:435 + { + yyVAL.stmt_switch_default = yyDollar[3].compstmt + } + case 57: + yyDollar = yyS[yypt-0 : yypt+1] +//line parser.go.y:442 + { + yyVAL.exprs = nil + } + case 58: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:446 + { + yyVAL.exprs = []ast.Expr{yyDollar[1].expr} + } + case 59: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:450 + { + if len(yyDollar[1].exprs) == 0 { + yylex.Error("syntax error: unexpected ','") + } + yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[4].expr) + } + case 60: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:457 + { + if len(yyDollar[1].exprs) == 0 { + yylex.Error("syntax error: unexpected ','") + } + yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[4].expr_ident) + } + case 61: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:466 + { + yyVAL.expr = yyDollar[1].expr_member_or_ident + } + case 62: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:470 + { + yyVAL.expr = yyDollar[1].expr_literals + } + case 63: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:474 + { + yyVAL.expr = &ast.TernaryOpExpr{Expr: yyDollar[1].expr, LHS: yyDollar[3].expr, RHS: yyDollar[5].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 64: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:479 + { + yyVAL.expr = &ast.NilCoalescingOpExpr{LHS: yyDollar[1].expr, RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 65: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:484 + { + yyVAL.expr = &ast.FuncExpr{Params: yyDollar[3].expr_idents, Stmt: yyDollar[6].compstmt} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 66: + yyDollar = yyS[yypt-8 : yypt+1] +//line parser.go.y:489 + { + yyVAL.expr = &ast.FuncExpr{Params: yyDollar[3].expr_idents, Stmt: yyDollar[7].compstmt, VarArg: true} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 67: + yyDollar = yyS[yypt-8 : yypt+1] +//line parser.go.y:494 + { + yyVAL.expr = &ast.FuncExpr{Name: yyDollar[2].tok.Lit, Params: yyDollar[4].expr_idents, Stmt: yyDollar[7].compstmt} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 68: + yyDollar = yyS[yypt-9 : yypt+1] +//line parser.go.y:499 + { + yyVAL.expr = &ast.FuncExpr{Name: yyDollar[2].tok.Lit, Params: yyDollar[4].expr_idents, Stmt: yyDollar[8].compstmt, VarArg: true} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 69: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:504 + { + yyVAL.expr = &ast.ArrayExpr{} + if l, ok := yylex.(*Lexer); ok { + yyVAL.expr.SetPosition(l.pos) + } + } + case 70: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:509 + { + yyVAL.expr = &ast.ArrayExpr{Exprs: yyDollar[3].exprs} + if l, ok := yylex.(*Lexer); ok { + yyVAL.expr.SetPosition(l.pos) + } + } + case 71: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:514 + { + yyVAL.expr = &ast.ArrayExpr{Exprs: yyDollar[5].exprs, TypeData: &ast.TypeStruct{Kind: ast.TypeSlice, SubType: yyDollar[2].type_data, Dimensions: yyDollar[1].slice_count}} + if l, ok := yylex.(*Lexer); ok { + yyVAL.expr.SetPosition(l.pos) + } + } + case 72: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:519 + { + yyVAL.expr = &ast.ParenExpr{SubExpr: yyDollar[2].expr} + if l, ok := yylex.(*Lexer); ok { + yyVAL.expr.SetPosition(l.pos) + } + } + case 73: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:524 + { + yyVAL.expr = &ast.CallExpr{Name: yyDollar[1].tok.Lit, SubExprs: yyDollar[3].exprs, VarArg: true} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 74: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:529 + { + yyVAL.expr = &ast.CallExpr{Name: yyDollar[1].tok.Lit, SubExprs: yyDollar[3].exprs} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 75: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:534 + { + yyVAL.expr = &ast.AnonCallExpr{Expr: yyDollar[1].expr, SubExprs: yyDollar[3].exprs, VarArg: true} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 76: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:539 + { + yyVAL.expr = &ast.AnonCallExpr{Expr: yyDollar[1].expr, SubExprs: yyDollar[3].exprs} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 77: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:544 + { + yyVAL.expr = &ast.ItemExpr{Item: yyDollar[1].expr_ident, Index: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr_ident.Position()) + } + case 78: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:549 + { + yyVAL.expr = &ast.ItemExpr{Item: yyDollar[1].expr, Index: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 79: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:554 + { + yyVAL.expr = &ast.LenExpr{Expr: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 80: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:559 + { + yyVAL.expr = &ast.ImportExpr{Name: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 81: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:564 + { + if yyDollar[3].type_data.Kind == ast.TypeDefault { + yyDollar[3].type_data.Kind = ast.TypePtr + yyVAL.expr = &ast.MakeExpr{TypeData: yyDollar[3].type_data} + } else { + yyVAL.expr = &ast.MakeExpr{TypeData: &ast.TypeStruct{Kind: ast.TypePtr, SubType: yyDollar[3].type_data}} + } + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 82: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:574 + { + yyVAL.expr = &ast.MakeExpr{TypeData: yyDollar[3].type_data} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 83: + yyDollar = yyS[yypt-6 : yypt+1] +//line parser.go.y:579 + { + yyVAL.expr = &ast.MakeExpr{TypeData: yyDollar[3].type_data, LenExpr: yyDollar[5].expr} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 84: + yyDollar = yyS[yypt-8 : yypt+1] +//line parser.go.y:584 + { + yyVAL.expr = &ast.MakeExpr{TypeData: yyDollar[3].type_data, LenExpr: yyDollar[5].expr, CapExpr: yyDollar[7].expr} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 85: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:589 + { + yyVAL.expr = &ast.MakeTypeExpr{Name: yyDollar[4].tok.Lit, Type: yyDollar[6].expr} + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 86: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:594 + { + yyVAL.expr = &ast.IncludeExpr{ItemExpr: yyDollar[1].expr, ListExpr: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 87: + yyDollar = yyS[yypt-6 : yypt+1] +//line parser.go.y:599 + { + yyDollar[4].expr_map.TypeData = &ast.TypeStruct{Kind: ast.TypeMap, Key: &ast.TypeStruct{Name: "interface"}, SubType: &ast.TypeStruct{Name: "interface"}} + yyVAL.expr = yyDollar[4].expr_map + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 88: + yyDollar = yyS[yypt-10 : yypt+1] +//line parser.go.y:605 + { + yyDollar[8].expr_map.TypeData = &ast.TypeStruct{Kind: ast.TypeMap, Key: yyDollar[3].type_data, SubType: yyDollar[5].type_data} + yyVAL.expr = yyDollar[8].expr_map + yyVAL.expr.SetPosition(yyDollar[1].tok.Position()) + } + case 89: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:611 + { + yyVAL.expr = yyDollar[3].expr_map + yyVAL.expr.SetPosition(yyDollar[3].expr_map.Position()) + } + case 90: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:616 + { + yyVAL.expr = yyDollar[1].expr_slice + yyVAL.expr.SetPosition(yyDollar[1].expr_slice.Position()) + } + case 91: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:621 + { + yyVAL.expr = yyDollar[1].expr_chan + yyVAL.expr.SetPosition(yyDollar[1].expr_chan.Position()) + } + case 95: + yyDollar = yyS[yypt-0 : yypt+1] +//line parser.go.y:630 + { + yyVAL.expr_idents = []string{} + } + case 96: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:634 + { + yyVAL.expr_idents = []string{yyDollar[1].tok.Lit} + } + case 97: + yyDollar = yyS[yypt-4 : yypt+1] +//line parser.go.y:638 + { + if len(yyDollar[1].expr_idents) == 0 { + yylex.Error("syntax error: unexpected ','") + } + yyVAL.expr_idents = append(yyDollar[1].expr_idents, yyDollar[4].tok.Lit) + } + case 98: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:647 + { + yyVAL.type_data = &ast.TypeStruct{Name: yyDollar[1].tok.Lit} + } + case 99: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:651 + { + if yyDollar[1].type_data.Kind != ast.TypeDefault { + yylex.Error("not type default") + } else { + yyDollar[1].type_data.Env = append(yyDollar[1].type_data.Env, yyDollar[1].type_data.Name) + yyDollar[1].type_data.Name = yyDollar[3].tok.Lit + } + } + case 100: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:660 + { + if yyDollar[2].type_data.Kind == ast.TypeDefault { + yyDollar[2].type_data.Kind = ast.TypePtr + yyVAL.type_data = yyDollar[2].type_data + } else { + yyVAL.type_data = &ast.TypeStruct{Kind: ast.TypePtr, SubType: yyDollar[2].type_data} + } + } + case 101: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:669 + { + if yyDollar[2].type_data.Kind == ast.TypeDefault { + yyDollar[2].type_data.Kind = ast.TypeSlice + yyDollar[2].type_data.Dimensions = yyDollar[1].slice_count + yyVAL.type_data = yyDollar[2].type_data + } else { + yyVAL.type_data = &ast.TypeStruct{Kind: ast.TypeSlice, SubType: yyDollar[2].type_data, Dimensions: yyDollar[1].slice_count} + } + } + case 102: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:679 + { + yyVAL.type_data = &ast.TypeStruct{Kind: ast.TypeMap, Key: yyDollar[3].type_data, SubType: yyDollar[5].type_data} + } + case 103: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:683 + { + if yyDollar[2].type_data.Kind == ast.TypeDefault { + yyDollar[2].type_data.Kind = ast.TypeChan + yyVAL.type_data = yyDollar[2].type_data + } else { + yyVAL.type_data = &ast.TypeStruct{Kind: ast.TypeChan, SubType: yyDollar[2].type_data} + } + } + case 104: + yyDollar = yyS[yypt-6 : yypt+1] +//line parser.go.y:692 + { + yyVAL.type_data = yyDollar[4].type_data_struct + } + case 105: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:698 + { + yyVAL.type_data_struct = &ast.TypeStruct{Kind: ast.TypeStructType, StructNames: []string{yyDollar[1].tok.Lit}, StructTypes: []*ast.TypeStruct{yyDollar[2].type_data}} + } + case 106: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:702 + { + if yyDollar[1].type_data_struct == nil { + yylex.Error("syntax error: unexpected ','") + } + yyVAL.type_data_struct.StructNames = append(yyVAL.type_data_struct.StructNames, yyDollar[4].tok.Lit) + yyVAL.type_data_struct.StructTypes = append(yyVAL.type_data_struct.StructTypes, yyDollar[5].type_data) + } + case 107: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:712 + { + yyVAL.slice_count = 1 + } + case 108: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:716 + { + yyVAL.slice_count = yyDollar[3].slice_count + 1 + } + case 109: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:722 + { + yyVAL.expr_member_or_ident = yyDollar[1].expr_member + } + case 110: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:726 + { + yyVAL.expr_member_or_ident = yyDollar[1].expr_ident + } + case 111: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:732 + { + yyVAL.expr_member = &ast.MemberExpr{Expr: yyDollar[1].expr, Name: yyDollar[3].tok.Lit} + yyVAL.expr_member.SetPosition(yyDollar[1].expr.Position()) + } + case 112: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:739 + { + yyVAL.expr_ident = &ast.IdentExpr{Lit: yyDollar[1].tok.Lit} + yyVAL.expr_ident.SetPosition(yyDollar[1].tok.Position()) + } + case 113: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:746 + { + num, err := toNumber("-" + yyDollar[2].tok.Lit) + if err != nil { + yylex.Error("invalid number: -" + yyDollar[2].tok.Lit) + } + yyVAL.expr_literals = &ast.LiteralExpr{Literal: num} + yyVAL.expr_literals.SetPosition(yyDollar[2].tok.Position()) + } + case 114: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:755 + { + num, err := toNumber(yyDollar[1].tok.Lit) + if err != nil { + yylex.Error("invalid number: " + yyDollar[1].tok.Lit) + } + yyVAL.expr_literals = &ast.LiteralExpr{Literal: num} + yyVAL.expr_literals.SetPosition(yyDollar[1].tok.Position()) + } + case 115: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:764 + { + yyVAL.expr_literals = &ast.LiteralExpr{Literal: stringToValue(yyDollar[1].tok.Lit)} + yyVAL.expr_literals.SetPosition(yyDollar[1].tok.Position()) + } + case 116: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:769 + { + yyVAL.expr_literals = &ast.LiteralExpr{Literal: trueValue} + yyVAL.expr_literals.SetPosition(yyDollar[1].tok.Position()) + } + case 117: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:774 + { + yyVAL.expr_literals = &ast.LiteralExpr{Literal: falseValue} + yyVAL.expr_literals.SetPosition(yyDollar[1].tok.Position()) + } + case 118: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:779 + { + yyVAL.expr_literals = &ast.LiteralExpr{Literal: nilValue} + yyVAL.expr_literals.SetPosition(yyDollar[1].tok.Position()) + } + case 119: + yyDollar = yyS[yypt-0 : yypt+1] +//line parser.go.y:786 + { + yyVAL.expr_map = &ast.MapExpr{} + } + case 120: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:790 + { + yyVAL.expr_map = &ast.MapExpr{Keys: []ast.Expr{yyDollar[1].expr}, Values: []ast.Expr{yyDollar[3].expr}} + } + case 121: + yyDollar = yyS[yypt-6 : yypt+1] +//line parser.go.y:794 + { + if yyDollar[1].expr_map.Keys == nil { + yylex.Error("syntax error: unexpected ','") + } + yyVAL.expr_map.Keys = append(yyVAL.expr_map.Keys, yyDollar[4].expr) + yyVAL.expr_map.Values = append(yyVAL.expr_map.Values, yyDollar[6].expr) + } + case 122: + yyDollar = yyS[yypt-6 : yypt+1] +//line parser.go.y:804 + { + yyVAL.expr_slice = &ast.SliceExpr{Item: yyDollar[1].expr_ident, Begin: yyDollar[3].expr, End: yyDollar[5].expr} + } + case 123: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:808 + { + yyVAL.expr_slice = &ast.SliceExpr{Item: yyDollar[1].expr_ident, Begin: yyDollar[3].expr, End: nil} + } + case 124: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:812 + { + yyVAL.expr_slice = &ast.SliceExpr{Item: yyDollar[1].expr_ident, Begin: nil, End: yyDollar[4].expr} + } + case 125: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:816 + { + yyVAL.expr_slice = &ast.SliceExpr{Item: yyDollar[1].expr_ident, End: yyDollar[4].expr, Cap: yyDollar[6].expr} + } + case 126: + yyDollar = yyS[yypt-8 : yypt+1] +//line parser.go.y:820 + { + yyVAL.expr_slice = &ast.SliceExpr{Item: yyDollar[1].expr_ident, Begin: yyDollar[3].expr, End: yyDollar[5].expr, Cap: yyDollar[7].expr} + } + case 127: + yyDollar = yyS[yypt-6 : yypt+1] +//line parser.go.y:824 + { + yyVAL.expr_slice = &ast.SliceExpr{Item: yyDollar[1].expr, Begin: yyDollar[3].expr, End: yyDollar[5].expr} + } + case 128: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:828 + { + yyVAL.expr_slice = &ast.SliceExpr{Item: yyDollar[1].expr, Begin: yyDollar[3].expr, End: nil} + } + case 129: + yyDollar = yyS[yypt-5 : yypt+1] +//line parser.go.y:832 + { + yyVAL.expr_slice = &ast.SliceExpr{Item: yyDollar[1].expr, Begin: nil, End: yyDollar[4].expr} + } + case 130: + yyDollar = yyS[yypt-7 : yypt+1] +//line parser.go.y:836 + { + yyVAL.expr_slice = &ast.SliceExpr{Item: yyDollar[1].expr, End: yyDollar[4].expr, Cap: yyDollar[6].expr} + } + case 131: + yyDollar = yyS[yypt-8 : yypt+1] +//line parser.go.y:840 + { + yyVAL.expr_slice = &ast.SliceExpr{Item: yyDollar[1].expr, Begin: yyDollar[3].expr, End: yyDollar[5].expr, Cap: yyDollar[7].expr} + } + case 132: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:846 + { + yyVAL.expr_chan = &ast.ChanExpr{LHS: yyDollar[1].expr, RHS: yyDollar[3].expr} + } + case 133: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:850 + { + yyVAL.expr_chan = &ast.ChanExpr{RHS: yyDollar[2].expr} + } + case 134: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:856 + { + yyVAL.expr = &ast.UnaryExpr{Operator: "-", Expr: yyDollar[2].expr} + yyVAL.expr.SetPosition(yyDollar[2].expr.Position()) + } + case 135: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:861 + { + yyVAL.expr = &ast.UnaryExpr{Operator: "!", Expr: yyDollar[2].expr} + yyVAL.expr.SetPosition(yyDollar[2].expr.Position()) + } + case 136: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:866 + { + yyVAL.expr = &ast.UnaryExpr{Operator: "^", Expr: yyDollar[2].expr} + yyVAL.expr.SetPosition(yyDollar[2].expr.Position()) + } + case 137: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:871 + { + yyVAL.expr = &ast.AddrExpr{Expr: yyDollar[2].expr} + yyVAL.expr.SetPosition(yyDollar[2].expr.Position()) + } + case 138: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:876 + { + yyVAL.expr = &ast.DerefExpr{Expr: yyDollar[2].expr} + yyVAL.expr.SetPosition(yyDollar[2].expr.Position()) + } + case 139: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:883 + { + yyVAL.expr = &ast.OpExpr{Op: yyDollar[1].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 140: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:888 + { + yyVAL.expr = &ast.OpExpr{Op: yyDollar[1].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 141: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:893 + { + yyVAL.expr = &ast.OpExpr{Op: yyDollar[1].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 142: + yyDollar = yyS[yypt-1 : yypt+1] +//line parser.go.y:898 + { + yyVAL.expr = &ast.OpExpr{Op: yyDollar[1].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 143: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:905 + { + rhs := &ast.OpExpr{Op: &ast.AddOperator{LHS: yyDollar[1].expr, Operator: "+", RHS: oneLiteral}} + rhs.Op.SetPosition(yyDollar[1].expr.Position()) + rhs.SetPosition(yyDollar[1].expr.Position()) + yyVAL.expr = &ast.LetsExpr{LHSS: []ast.Expr{yyDollar[1].expr}, RHSS: []ast.Expr{rhs}} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 144: + yyDollar = yyS[yypt-2 : yypt+1] +//line parser.go.y:913 + { + rhs := &ast.OpExpr{Op: &ast.AddOperator{LHS: yyDollar[1].expr, Operator: "-", RHS: oneLiteral}} + rhs.Op.SetPosition(yyDollar[1].expr.Position()) + rhs.SetPosition(yyDollar[1].expr.Position()) + yyVAL.expr = &ast.LetsExpr{LHSS: []ast.Expr{yyDollar[1].expr}, RHSS: []ast.Expr{rhs}} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 145: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:921 + { + rhs := &ast.OpExpr{Op: &ast.AddOperator{LHS: yyDollar[1].expr, Operator: "+", RHS: yyDollar[3].expr}} + rhs.Op.SetPosition(yyDollar[1].expr.Position()) + rhs.SetPosition(yyDollar[1].expr.Position()) + yyVAL.expr = &ast.LetsExpr{LHSS: []ast.Expr{yyDollar[1].expr}, RHSS: []ast.Expr{rhs}} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 146: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:929 + { + rhs := &ast.OpExpr{Op: &ast.AddOperator{LHS: yyDollar[1].expr, Operator: "-", RHS: yyDollar[3].expr}} + rhs.Op.SetPosition(yyDollar[1].expr.Position()) + rhs.SetPosition(yyDollar[1].expr.Position()) + yyVAL.expr = &ast.LetsExpr{LHSS: []ast.Expr{yyDollar[1].expr}, RHSS: []ast.Expr{rhs}} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 147: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:937 + { + rhs := &ast.OpExpr{Op: &ast.AddOperator{LHS: yyDollar[1].expr, Operator: "|", RHS: yyDollar[3].expr}} + rhs.Op.SetPosition(yyDollar[1].expr.Position()) + rhs.SetPosition(yyDollar[1].expr.Position()) + yyVAL.expr = &ast.LetsExpr{LHSS: []ast.Expr{yyDollar[1].expr}, RHSS: []ast.Expr{rhs}} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 148: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:945 + { + rhs := &ast.OpExpr{Op: &ast.MultiplyOperator{LHS: yyDollar[1].expr, Operator: "*", RHS: yyDollar[3].expr}} + rhs.Op.SetPosition(yyDollar[1].expr.Position()) + rhs.SetPosition(yyDollar[1].expr.Position()) + yyVAL.expr = &ast.LetsExpr{LHSS: []ast.Expr{yyDollar[1].expr}, RHSS: []ast.Expr{rhs}} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 149: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:953 + { + rhs := &ast.OpExpr{Op: &ast.MultiplyOperator{LHS: yyDollar[1].expr, Operator: "/", RHS: yyDollar[3].expr}} + rhs.Op.SetPosition(yyDollar[1].expr.Position()) + rhs.SetPosition(yyDollar[1].expr.Position()) + yyVAL.expr = &ast.LetsExpr{LHSS: []ast.Expr{yyDollar[1].expr}, RHSS: []ast.Expr{rhs}} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 150: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:961 + { + rhs := &ast.OpExpr{Op: &ast.MultiplyOperator{LHS: yyDollar[1].expr, Operator: "&", RHS: yyDollar[3].expr}} + rhs.Op.SetPosition(yyDollar[1].expr.Position()) + rhs.SetPosition(yyDollar[1].expr.Position()) + yyVAL.expr = &ast.LetsExpr{LHSS: []ast.Expr{yyDollar[1].expr}, RHSS: []ast.Expr{rhs}} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 151: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:972 + { + yyVAL.expr = &ast.MultiplyOperator{LHS: yyDollar[1].expr, Operator: "*", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 152: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:977 + { + yyVAL.expr = &ast.MultiplyOperator{LHS: yyDollar[1].expr, Operator: "/", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 153: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:982 + { + yyVAL.expr = &ast.MultiplyOperator{LHS: yyDollar[1].expr, Operator: "%", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 154: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:987 + { + yyVAL.expr = &ast.MultiplyOperator{LHS: yyDollar[1].expr, Operator: "<<", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 155: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:992 + { + yyVAL.expr = &ast.MultiplyOperator{LHS: yyDollar[1].expr, Operator: ">>", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 156: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:997 + { + yyVAL.expr = &ast.MultiplyOperator{LHS: yyDollar[1].expr, Operator: "&", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 157: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1004 + { + yyVAL.expr = &ast.AddOperator{LHS: yyDollar[1].expr, Operator: "+", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 158: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1009 + { + yyVAL.expr = &ast.AddOperator{LHS: yyDollar[1].expr, Operator: "-", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 159: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1014 + { + yyVAL.expr = &ast.AddOperator{LHS: yyDollar[1].expr, Operator: "|", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 160: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1021 + { + yyVAL.expr = &ast.ComparisonOperator{LHS: yyDollar[1].expr, Operator: "==", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 161: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1026 + { + yyVAL.expr = &ast.ComparisonOperator{LHS: yyDollar[1].expr, Operator: "!=", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 162: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1031 + { + yyVAL.expr = &ast.ComparisonOperator{LHS: yyDollar[1].expr, Operator: "<", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 163: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1036 + { + yyVAL.expr = &ast.ComparisonOperator{LHS: yyDollar[1].expr, Operator: "<=", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 164: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1041 + { + yyVAL.expr = &ast.ComparisonOperator{LHS: yyDollar[1].expr, Operator: ">", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 165: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1046 + { + yyVAL.expr = &ast.ComparisonOperator{LHS: yyDollar[1].expr, Operator: ">=", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 166: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1053 + { + yyVAL.expr = &ast.BinaryOperator{LHS: yyDollar[1].expr, Operator: "&&", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + case 167: + yyDollar = yyS[yypt-3 : yypt+1] +//line parser.go.y:1058 + { + yyVAL.expr = &ast.BinaryOperator{LHS: yyDollar[1].expr, Operator: "||", RHS: yyDollar[3].expr} + yyVAL.expr.SetPosition(yyDollar[1].expr.Position()) + } + } + goto yystack /* stack new state and value */ +} diff --git a/src/tool/run/parser/parser.go.y b/src/tool/run/parser/parser.go.y new file mode 100644 index 0000000..c59d17a --- /dev/null +++ b/src/tool/run/parser/parser.go.y @@ -0,0 +1,1089 @@ +%{ +package parser + +import ( + "github.com/surdeus/goblin/src/tool/run/ast" +) + +%} + +%type compstmt +%type stmts +%type stmt +%type stmt_var_or_lets +%type stmt_var +%type stmt_lets +%type stmt_if +%type stmt_for +%type stmt_switch +%type stmt_switch_cases +%type stmt_switch_case +%type stmt_switch_default + +%type exprs +%type expr +%type expr_idents +%type type_data +%type type_data_struct +%type slice_count +%type expr_member_or_ident +%type expr_member +%type expr_ident +%type expr_literals +%type expr_map +%type expr_slice +%type expr_chan +%type expr_unary +%type expr_binary +%type expr_lets + +%type op_binary +%type op_comparison +%type op_add +%type op_multiply + +%union{ + tok ast.Token + + compstmt ast.Stmt + stmts ast.Stmt + stmt ast.Stmt + stmt_var_or_lets ast.Stmt + stmt_var ast.Stmt + stmt_lets ast.Stmt + stmt_if ast.Stmt + stmt_for ast.Stmt + stmt_switch ast.Stmt + stmt_switch_cases ast.Stmt + stmt_switch_case ast.Stmt + stmt_switch_default ast.Stmt + + exprs []ast.Expr + expr ast.Expr + expr_idents []string + type_data *ast.TypeStruct + type_data_struct *ast.TypeStruct + slice_count int + expr_member_or_ident ast.Expr + expr_member *ast.MemberExpr + expr_ident *ast.IdentExpr + expr_literals ast.Expr + expr_map *ast.MapExpr + expr_slice ast.Expr + expr_chan ast.Expr + expr_unary ast.Expr + expr_binary ast.Expr + expr_lets ast.Expr + + op_binary ast.Operator + op_comparison ast.Operator + op_add ast.Operator + op_multiply ast.Operator +} + +%token IDENT NUMBER STRING ARRAY VARARG FUNC RETURN VAR THROW IF ELSE FOR IN EQEQ NEQ GE LE OROR ANDAND NEW TRUE FALSE NIL NILCOALESCE MODULE TRY CATCH FINALLY PLUSEQ MINUSEQ MULEQ DIVEQ ANDEQ OREQ BREAK CONTINUE PLUSPLUS MINUSMINUS SHIFTLEFT SHIFTRIGHT SWITCH CASE DEFAULT GO CHAN STRUCT MAKE OPCHAN EQOPCHAN TYPE LEN DELETE CLOSE MAP IMPORT + +/* lowest precedence */ +%left , +%right '=' PLUSEQ MINUSEQ MULEQ DIVEQ ANDEQ OREQ EQOPCHAN +%right ':' +%right OPCHAN +%right '?' NILCOALESCE +%left OROR +%left ANDAND +%left EQEQ NEQ '<' LE '>' GE +%left '+' '-' '|' '^' +%left '*' '/' '%' SHIFTLEFT SHIFTRIGHT '&' +%right IN +%right PLUSPLUS MINUSMINUS +%right UNARY +/* highest precedence */ +/* https://golang.org/ref/spec#Expression */ + + +%% + +compstmt : + opt_term + { + $$ = nil + } + | stmts opt_term + { + $$ = $1 + } + +stmts : + opt_term stmt + { + if $2 != nil { + $$ = &ast.StmtsStmt{Stmts: []ast.Stmt{$2}} + } + if l, ok := yylex.(*Lexer); ok { + l.stmt = $$ + } + } + | stmts term stmt + { + if $3 != nil { + if $1 == nil { + $$ = &ast.StmtsStmt{Stmts: []ast.Stmt{$3}} + } else { + stmts := $1.(*ast.StmtsStmt) + stmts.Stmts = append(stmts.Stmts, $3) + } + if l, ok := yylex.(*Lexer); ok { + l.stmt = $$ + } + } + } + +stmt : + /* nothing */ + { + $$ = nil + } + | stmt_var_or_lets + { + $$ = $1 + } + | BREAK + { + $$ = &ast.BreakStmt{} + $$.SetPosition($1.Position()) + } + | CONTINUE + { + $$ = &ast.ContinueStmt{} + $$.SetPosition($1.Position()) + } + | RETURN exprs + { + $$ = &ast.ReturnStmt{Exprs: $2} + $$.SetPosition($1.Position()) + } + | THROW expr + { + $$ = &ast.ThrowStmt{Expr: $2} + $$.SetPosition($1.Position()) + } + | MODULE IDENT '{' compstmt '}' + { + $$ = &ast.ModuleStmt{Name: $2.Lit, Stmt: $4} + $$.SetPosition($1.Position()) + } + | TRY '{' compstmt '}' CATCH IDENT '{' compstmt '}' FINALLY '{' compstmt '}' + { + $$ = &ast.TryStmt{Try: $3, Var: $6.Lit, Catch: $8, Finally: $12} + $$.SetPosition($1.Position()) + } + | TRY '{' compstmt '}' CATCH '{' compstmt '}' FINALLY '{' compstmt '}' + { + $$ = &ast.TryStmt{Try: $3, Catch: $7, Finally: $11} + $$.SetPosition($1.Position()) + } + | TRY '{' compstmt '}' CATCH IDENT '{' compstmt '}' + { + $$ = &ast.TryStmt{Try: $3, Var: $6.Lit, Catch: $8} + $$.SetPosition($1.Position()) + } + | TRY '{' compstmt '}' CATCH '{' compstmt '}' + { + $$ = &ast.TryStmt{Try: $3, Catch: $7} + $$.SetPosition($1.Position()) + } + | GO IDENT '(' exprs VARARG ')' + { + $$ = &ast.GoroutineStmt{Expr: &ast.CallExpr{Name: $2.Lit, SubExprs: $4, VarArg: true, Go: true}} + $$.SetPosition($2.Position()) + } + | GO IDENT '(' exprs ')' + { + $$ = &ast.GoroutineStmt{Expr: &ast.CallExpr{Name: $2.Lit, SubExprs: $4, Go: true}} + $$.SetPosition($2.Position()) + } + | GO expr '(' exprs VARARG ')' + { + $$ = &ast.GoroutineStmt{Expr: &ast.AnonCallExpr{Expr: $2, SubExprs: $4, VarArg: true, Go: true}} + $$.SetPosition($2.Position()) + } + | GO expr '(' exprs ')' + { + $$ = &ast.GoroutineStmt{Expr: &ast.AnonCallExpr{Expr: $2, SubExprs: $4, Go: true}} + $$.SetPosition($1.Position()) + } + | DELETE '(' expr ')' + { + $$ = &ast.DeleteStmt{Item: $3} + $$.SetPosition($1.Position()) + } + | DELETE '(' expr ',' expr ')' + { + $$ = &ast.DeleteStmt{Item: $3, Key: $5} + $$.SetPosition($1.Position()) + } + | CLOSE '(' expr ')' + { + $$ = &ast.CloseStmt{Expr: $3} + $$.SetPosition($1.Position()) + } + | stmt_if + { + $$ = $1 + } + | stmt_for + { + $$ = $1 + } + | stmt_switch + { + $$ = $1 + } + | expr + { + $$ = &ast.ExprStmt{Expr: $1} + $$.SetPosition($1.Position()) + } + +stmt_var_or_lets : + stmt_var + { + $$ = $1 + } + | stmt_lets + { + $$ = $1 + } + +stmt_var : + VAR expr_idents '=' exprs + { + $$ = &ast.VarStmt{Names: $2, Exprs: $4} + $$.SetPosition($1.Position()) + } + +stmt_lets : + expr '=' expr + { + $$ = &ast.LetsStmt{LHSS: []ast.Expr{$1}, RHSS: []ast.Expr{$3}} + $$.SetPosition($1.Position()) + } + | exprs '=' exprs + { + if len($1) == 2 && len($3) == 1 { + if _, ok := $3[0].(*ast.ItemExpr); ok { + $$ = &ast.LetMapItemStmt{LHSS: $1, RHS: $3[0]} + } else { + $$ = &ast.LetsStmt{LHSS: $1, RHSS: $3} + } + } else { + $$ = &ast.LetsStmt{LHSS: $1, RHSS: $3} + } + } + | expr EQOPCHAN expr + { + $$ = &ast.ChanStmt{LHS: $1, RHS: $3} + $$.SetPosition($1.Position()) + } + | exprs EQOPCHAN expr + { + if len($1) == 2 { + chanStmt := &ast.ChanStmt{LHS: $1[0].(ast.Expr), OkExpr: $1[1].(ast.Expr), RHS: $3} + $$ = chanStmt + $$.SetPosition(chanStmt.LHS.Position()) + } else if len($1) < 2 { + yylex.Error("missing expressions on left side of channel operator") + $$ = &ast.ChanStmt{RHS: $3} + $$.SetPosition($2.Position()) + } + } + +stmt_if : + IF expr '{' compstmt '}' + { + $$ = &ast.IfStmt{If: $2, Then: $4, Else: nil} + $$.SetPosition($1.Position()) + } + | stmt_if ELSE IF expr '{' compstmt '}' + { + ifStmt := $1.(*ast.IfStmt) + ifStmt.ElseIf = append(ifStmt.ElseIf, &ast.IfStmt{If: $4, Then: $6}) + } + | stmt_if ELSE '{' compstmt '}' + { + ifStmt := $1.(*ast.IfStmt) + if ifStmt.Else != nil { + yylex.Error("multiple else statement") + } + ifStmt.Else = $4 + } + +stmt_for : + FOR '{' compstmt '}' + { + $$ = &ast.LoopStmt{Stmt: $3} + $$.SetPosition($1.Position()) + } + | FOR expr_idents IN expr '{' compstmt '}' + { + if len($2) < 1 { + yylex.Error("missing identifier") + } else if len($2) > 2 { + yylex.Error("too many identifiers") + } else { + $$ = &ast.ForStmt{Vars: $2, Value: $4, Stmt: $6} + $$.SetPosition($1.Position()) + } + } + | FOR expr '{' compstmt '}' + { + $$ = &ast.LoopStmt{Expr: $2, Stmt: $4} + $$.SetPosition($1.Position()) + } + | FOR ';' ';' '{' compstmt '}' + { + $$ = &ast.CForStmt{Stmt: $5} + $$.SetPosition($1.Position()) + } + | FOR ';' ';' expr '{' compstmt '}' + { + $$ = &ast.CForStmt{Expr3: $4, Stmt: $6} + $$.SetPosition($1.Position()) + } + | FOR ';' expr ';' '{' compstmt '}' + { + $$ = &ast.CForStmt{Expr2: $3, Stmt: $6} + $$.SetPosition($1.Position()) + } + | FOR ';' expr ';' expr '{' compstmt '}' + { + $$ = &ast.CForStmt{Expr2: $3, Expr3: $5, Stmt: $7} + $$.SetPosition($1.Position()) + } + | FOR stmt_var_or_lets ';' ';' '{' compstmt '}' + { + $$ = &ast.CForStmt{Stmt1: $2, Stmt: $6} + $$.SetPosition($1.Position()) + } + | FOR stmt_var_or_lets ';' ';' expr '{' compstmt '}' + { + $$ = &ast.CForStmt{Stmt1: $2, Expr3: $5, Stmt: $7} + $$.SetPosition($1.Position()) + } + | FOR stmt_var_or_lets ';' expr ';' '{' compstmt '}' + { + $$ = &ast.CForStmt{Stmt1: $2, Expr2: $4, Stmt: $7} + $$.SetPosition($1.Position()) + } + | FOR stmt_var_or_lets ';' expr ';' expr '{' compstmt '}' + { + $$ = &ast.CForStmt{Stmt1: $2, Expr2: $4, Expr3: $6, Stmt: $8} + $$.SetPosition($1.Position()) + } + +stmt_switch : + SWITCH expr '{' opt_newlines stmt_switch_cases opt_newlines '}' + { + switchStmt := $5.(*ast.SwitchStmt) + switchStmt.Expr = $2 + $$ = switchStmt + $$.SetPosition($1.Position()) + } + +stmt_switch_cases : + /* nothing */ + { + $$ = &ast.SwitchStmt{} + } + | stmt_switch_default + { + $$ = &ast.SwitchStmt{Default: $1} + } + | stmt_switch_case + { + $$ = &ast.SwitchStmt{Cases: []ast.Stmt{$1}} + } + | stmt_switch_cases stmt_switch_case + { + switchStmt := $1.(*ast.SwitchStmt) + switchStmt.Cases = append(switchStmt.Cases, $2) + $$ = switchStmt + } + | stmt_switch_cases stmt_switch_default + { + switchStmt := $1.(*ast.SwitchStmt) + if switchStmt.Default != nil { + yylex.Error("multiple default statement") + } + switchStmt.Default = $2 + } + +stmt_switch_case : + CASE expr ':' compstmt + { + $$ = &ast.SwitchCaseStmt{Exprs: []ast.Expr{$2}, Stmt: $4} + $$.SetPosition($1.Position()) + } + | CASE exprs ':' compstmt + { + $$ = &ast.SwitchCaseStmt{Exprs: $2, Stmt: $4} + $$.SetPosition($1.Position()) + } + +stmt_switch_default : + DEFAULT ':' compstmt + { + $$ = $3 + } + + +exprs : + /* nothing */ + { + $$ = nil + } + | expr + { + $$ = []ast.Expr{$1} + } + | exprs ',' opt_newlines expr + { + if len($1) == 0 { + yylex.Error("syntax error: unexpected ','") + } + $$ = append($1, $4) + } + | exprs ',' opt_newlines expr_ident + { + if len($1) == 0 { + yylex.Error("syntax error: unexpected ','") + } + $$ = append($1, $4) + } + +expr : + expr_member_or_ident + { + $$ = $1 + } + | expr_literals + { + $$ = $1 + } + | expr '?' expr ':' expr + { + $$ = &ast.TernaryOpExpr{Expr: $1, LHS: $3, RHS: $5} + $$.SetPosition($1.Position()) + } + | expr NILCOALESCE expr + { + $$ = &ast.NilCoalescingOpExpr{LHS: $1, RHS: $3} + $$.SetPosition($1.Position()) + } + | FUNC '(' expr_idents ')' '{' compstmt '}' + { + $$ = &ast.FuncExpr{Params: $3, Stmt: $6} + $$.SetPosition($1.Position()) + } + | FUNC '(' expr_idents VARARG ')' '{' compstmt '}' + { + $$ = &ast.FuncExpr{Params: $3, Stmt: $7, VarArg: true} + $$.SetPosition($1.Position()) + } + | FUNC IDENT '(' expr_idents ')' '{' compstmt '}' + { + $$ = &ast.FuncExpr{Name: $2.Lit, Params: $4, Stmt: $7} + $$.SetPosition($1.Position()) + } + | FUNC IDENT '(' expr_idents VARARG ')' '{' compstmt '}' + { + $$ = &ast.FuncExpr{Name: $2.Lit, Params: $4, Stmt: $8, VarArg: true} + $$.SetPosition($1.Position()) + } + | '[' ']' + { + $$ = &ast.ArrayExpr{} + if l, ok := yylex.(*Lexer); ok { $$.SetPosition(l.pos) } + } + | '[' opt_newlines exprs opt_comma_newlines ']' + { + $$ = &ast.ArrayExpr{Exprs: $3} + if l, ok := yylex.(*Lexer); ok { $$.SetPosition(l.pos) } + } + | slice_count type_data '{' opt_newlines exprs opt_comma_newlines '}' + { + $$ = &ast.ArrayExpr{Exprs: $5, TypeData: &ast.TypeStruct{Kind: ast.TypeSlice, SubType: $2, Dimensions: $1}} + if l, ok := yylex.(*Lexer); ok { $$.SetPosition(l.pos) } + } + | '(' expr ')' + { + $$ = &ast.ParenExpr{SubExpr: $2} + if l, ok := yylex.(*Lexer); ok { $$.SetPosition(l.pos) } + } + | IDENT '(' exprs VARARG ')' + { + $$ = &ast.CallExpr{Name: $1.Lit, SubExprs: $3, VarArg: true} + $$.SetPosition($1.Position()) + } + | IDENT '(' exprs ')' + { + $$ = &ast.CallExpr{Name: $1.Lit, SubExprs: $3} + $$.SetPosition($1.Position()) + } + | expr '(' exprs VARARG ')' + { + $$ = &ast.AnonCallExpr{Expr: $1, SubExprs: $3, VarArg: true} + $$.SetPosition($1.Position()) + } + | expr '(' exprs ')' + { + $$ = &ast.AnonCallExpr{Expr: $1, SubExprs: $3} + $$.SetPosition($1.Position()) + } + | expr_ident '[' expr ']' + { + $$ = &ast.ItemExpr{Item: $1, Index: $3} + $$.SetPosition($1.Position()) + } + | expr '[' expr ']' + { + $$ = &ast.ItemExpr{Item: $1, Index: $3} + $$.SetPosition($1.Position()) + } + | LEN '(' expr ')' + { + $$ = &ast.LenExpr{Expr: $3} + $$.SetPosition($1.Position()) + } + | IMPORT '(' expr ')' + { + $$ = &ast.ImportExpr{Name: $3} + $$.SetPosition($1.Position()) + } + | NEW '(' type_data ')' + { + if $3.Kind == ast.TypeDefault { + $3.Kind = ast.TypePtr + $$ = &ast.MakeExpr{TypeData: $3} + } else { + $$ = &ast.MakeExpr{TypeData: &ast.TypeStruct{Kind: ast.TypePtr, SubType: $3}} + } + $$.SetPosition($1.Position()) + } + | MAKE '(' type_data ')' + { + $$ = &ast.MakeExpr{TypeData: $3} + $$.SetPosition($1.Position()) + } + | MAKE '(' type_data ',' expr ')' + { + $$ = &ast.MakeExpr{TypeData: $3, LenExpr: $5} + $$.SetPosition($1.Position()) + } + | MAKE '(' type_data ',' expr ',' expr ')' + { + $$ = &ast.MakeExpr{TypeData: $3, LenExpr: $5, CapExpr: $7} + $$.SetPosition($1.Position()) + } + | MAKE '(' TYPE IDENT ',' expr ')' + { + $$ = &ast.MakeTypeExpr{Name: $4.Lit, Type: $6} + $$.SetPosition($1.Position()) + } + | expr IN expr + { + $$ = &ast.IncludeExpr{ItemExpr: $1, ListExpr: $3} + $$.SetPosition($1.Position()) + } + | MAP '{' opt_newlines expr_map opt_comma_newlines '}' + { + $4.TypeData = &ast.TypeStruct{Kind: ast.TypeMap, Key: &ast.TypeStruct{Name: "interface"}, SubType: &ast.TypeStruct{Name: "interface"}} + $$ = $4 + $$.SetPosition($1.Position()) + } + | MAP '[' type_data ']' type_data '{' opt_newlines expr_map opt_comma_newlines '}' + { + $8.TypeData = &ast.TypeStruct{Kind: ast.TypeMap, Key: $3, SubType: $5} + $$ = $8 + $$.SetPosition($1.Position()) + } + | '{' opt_newlines expr_map opt_comma_newlines '}' + { + $$ = $3 + $$.SetPosition($3.Position()) + } + | expr_slice + { + $$ = $1 + $$.SetPosition($1.Position()) + } + | expr_chan + { + $$ = $1 + $$.SetPosition($1.Position()) + } + | expr_unary + | expr_binary + | expr_lets + +expr_idents : + { + $$ = []string{} + } + | IDENT + { + $$ = []string{$1.Lit} + } + | expr_idents ',' opt_newlines IDENT + { + if len($1) == 0 { + yylex.Error("syntax error: unexpected ','") + } + $$ = append($1, $4.Lit) + } + +type_data : + IDENT + { + $$ = &ast.TypeStruct{Name: $1.Lit} + } + | type_data '.' IDENT + { + if $1.Kind != ast.TypeDefault { + yylex.Error("not type default") + } else { + $1.Env = append($1.Env, $1.Name) + $1.Name = $3.Lit + } + } + | '*' type_data + { + if $2.Kind == ast.TypeDefault { + $2.Kind = ast.TypePtr + $$ = $2 + } else { + $$ = &ast.TypeStruct{Kind: ast.TypePtr, SubType: $2} + } + } + | slice_count type_data + { + if $2.Kind == ast.TypeDefault { + $2.Kind = ast.TypeSlice + $2.Dimensions = $1 + $$ = $2 + } else { + $$ = &ast.TypeStruct{Kind: ast.TypeSlice, SubType: $2, Dimensions: $1} + } + } + | MAP '[' type_data ']' type_data + { + $$ = &ast.TypeStruct{Kind: ast.TypeMap, Key: $3, SubType: $5} + } + | CHAN type_data + { + if $2.Kind == ast.TypeDefault { + $2.Kind = ast.TypeChan + $$ = $2 + } else { + $$ = &ast.TypeStruct{Kind: ast.TypeChan, SubType: $2} + } + } + | STRUCT '{' opt_newlines type_data_struct opt_newlines '}' + { + $$ = $4 + } + +type_data_struct : + IDENT type_data + { + $$ = &ast.TypeStruct{Kind: ast.TypeStructType, StructNames: []string{$1.Lit}, StructTypes: []*ast.TypeStruct{$2}} + } + | type_data_struct ',' opt_newlines IDENT type_data + { + if $1 == nil { + yylex.Error("syntax error: unexpected ','") + } + $$.StructNames = append($$.StructNames, $4.Lit) + $$.StructTypes = append($$.StructTypes, $5) + } + +slice_count : + '[' ']' + { + $$ = 1 + } + | '[' ']' slice_count + { + $$ = $3 + 1 + } + +expr_member_or_ident : + expr_member + { + $$ = $1 + } + | expr_ident + { + $$ = $1 + } + +expr_member : + expr '.' IDENT + { + $$ = &ast.MemberExpr{Expr: $1, Name: $3.Lit} + $$.SetPosition($1.Position()) + } + +expr_ident : + IDENT + { + $$ = &ast.IdentExpr{Lit: $1.Lit} + $$.SetPosition($1.Position()) + } + +expr_literals : + '-' NUMBER + { + num, err := toNumber("-" + $2.Lit) + if err != nil { + yylex.Error("invalid number: -" + $2.Lit) + } + $$ = &ast.LiteralExpr{Literal: num} + $$.SetPosition($2.Position()) + } + | NUMBER + { + num, err := toNumber($1.Lit) + if err != nil { + yylex.Error("invalid number: " + $1.Lit) + } + $$ = &ast.LiteralExpr{Literal: num} + $$.SetPosition($1.Position()) + } + | STRING + { + $$ = &ast.LiteralExpr{Literal: stringToValue($1.Lit)} + $$.SetPosition($1.Position()) + } + | TRUE + { + $$ = &ast.LiteralExpr{Literal: trueValue} + $$.SetPosition($1.Position()) + } + | FALSE + { + $$ = &ast.LiteralExpr{Literal: falseValue} + $$.SetPosition($1.Position()) + } + | NIL + { + $$ = &ast.LiteralExpr{Literal: nilValue} + $$.SetPosition($1.Position()) + } + +expr_map : + /* nothing */ + { + $$ = &ast.MapExpr{} + } + | expr ':' expr + { + $$ = &ast.MapExpr{Keys: []ast.Expr{$1}, Values: []ast.Expr{$3}} + } + | expr_map ',' opt_newlines expr ':' expr + { + if $1.Keys == nil { + yylex.Error("syntax error: unexpected ','") + } + $$.Keys = append($$.Keys, $4) + $$.Values = append($$.Values, $6) + } + +expr_slice : + expr_ident '[' expr ':' expr ']' + { + $$ = &ast.SliceExpr{Item: $1, Begin: $3, End: $5} + } + | expr_ident '[' expr ':' ']' + { + $$ = &ast.SliceExpr{Item: $1, Begin: $3, End: nil} + } + | expr_ident '[' ':' expr ']' + { + $$ = &ast.SliceExpr{Item: $1, Begin: nil, End: $4} + } + | expr_ident '[' ':' expr ':' expr ']' + { + $$ = &ast.SliceExpr{Item: $1, End: $4, Cap: $6} + } + | expr_ident '[' expr ':' expr ':' expr ']' + { + $$ = &ast.SliceExpr{Item: $1, Begin: $3, End: $5, Cap: $7} + } + | expr '[' expr ':' expr ']' + { + $$ = &ast.SliceExpr{Item: $1, Begin: $3, End: $5} + } + | expr '[' expr ':' ']' + { + $$ = &ast.SliceExpr{Item: $1, Begin: $3, End: nil} + } + | expr '[' ':' expr ']' + { + $$ = &ast.SliceExpr{Item: $1, Begin: nil, End: $4} + } + | expr '[' ':' expr ':' expr ']' + { + $$ = &ast.SliceExpr{Item: $1, End: $4, Cap: $6} + } + | expr '[' expr ':' expr ':' expr ']' + { + $$ = &ast.SliceExpr{Item: $1, Begin: $3, End: $5, Cap: $7} + } + +expr_chan : + expr OPCHAN expr + { + $$ = &ast.ChanExpr{LHS: $1, RHS: $3} + } + | OPCHAN expr + { + $$ = &ast.ChanExpr{RHS: $2} + } + +expr_unary : + '-' expr %prec UNARY + { + $$ = &ast.UnaryExpr{Operator: "-", Expr: $2} + $$.SetPosition($2.Position()) + } + | '!' expr %prec UNARY + { + $$ = &ast.UnaryExpr{Operator: "!", Expr: $2} + $$.SetPosition($2.Position()) + } + | '^' expr %prec UNARY + { + $$ = &ast.UnaryExpr{Operator: "^", Expr: $2} + $$.SetPosition($2.Position()) + } + | '&' expr %prec UNARY + { + $$ = &ast.AddrExpr{Expr: $2} + $$.SetPosition($2.Position()) + } + | '*' expr %prec UNARY + { + $$ = &ast.DerefExpr{Expr: $2} + $$.SetPosition($2.Position()) + } + +expr_binary : + op_multiply + { + $$ = &ast.OpExpr{Op: $1} + $$.SetPosition($1.Position()) + } + | op_add + { + $$ = &ast.OpExpr{Op: $1} + $$.SetPosition($1.Position()) + } + | op_comparison + { + $$ = &ast.OpExpr{Op: $1} + $$.SetPosition($1.Position()) + } + | op_binary + { + $$ = &ast.OpExpr{Op: $1} + $$.SetPosition($1.Position()) + } + +expr_lets: + expr PLUSPLUS + { + rhs := &ast.OpExpr{Op: &ast.AddOperator{LHS: $1, Operator: "+", RHS: oneLiteral}} + rhs.Op.SetPosition($1.Position()) + rhs.SetPosition($1.Position()) + $$ = &ast.LetsExpr{LHSS: []ast.Expr{$1}, RHSS: []ast.Expr{rhs}} + $$.SetPosition($1.Position()) + } + | expr MINUSMINUS + { + rhs := &ast.OpExpr{Op: &ast.AddOperator{LHS: $1, Operator: "-", RHS: oneLiteral}} + rhs.Op.SetPosition($1.Position()) + rhs.SetPosition($1.Position()) + $$ = &ast.LetsExpr{LHSS: []ast.Expr{$1}, RHSS: []ast.Expr{rhs}} + $$.SetPosition($1.Position()) + } + | expr PLUSEQ expr + { + rhs := &ast.OpExpr{Op: &ast.AddOperator{LHS: $1, Operator: "+", RHS: $3}} + rhs.Op.SetPosition($1.Position()) + rhs.SetPosition($1.Position()) + $$ = &ast.LetsExpr{LHSS: []ast.Expr{$1}, RHSS: []ast.Expr{rhs}} + $$.SetPosition($1.Position()) + } + | expr MINUSEQ expr + { + rhs := &ast.OpExpr{Op: &ast.AddOperator{LHS: $1, Operator: "-", RHS: $3}} + rhs.Op.SetPosition($1.Position()) + rhs.SetPosition($1.Position()) + $$ = &ast.LetsExpr{LHSS: []ast.Expr{$1}, RHSS: []ast.Expr{rhs}} + $$.SetPosition($1.Position()) + } + | expr OREQ expr + { + rhs := &ast.OpExpr{Op: &ast.AddOperator{LHS: $1, Operator: "|", RHS: $3}} + rhs.Op.SetPosition($1.Position()) + rhs.SetPosition($1.Position()) + $$ = &ast.LetsExpr{LHSS: []ast.Expr{$1}, RHSS: []ast.Expr{rhs}} + $$.SetPosition($1.Position()) + } + | expr MULEQ expr + { + rhs := &ast.OpExpr{Op: &ast.MultiplyOperator{LHS: $1, Operator: "*", RHS: $3}} + rhs.Op.SetPosition($1.Position()) + rhs.SetPosition($1.Position()) + $$ = &ast.LetsExpr{LHSS: []ast.Expr{$1}, RHSS: []ast.Expr{rhs}} + $$.SetPosition($1.Position()) + } + | expr DIVEQ expr + { + rhs := &ast.OpExpr{Op: &ast.MultiplyOperator{LHS: $1, Operator: "/", RHS: $3}} + rhs.Op.SetPosition($1.Position()) + rhs.SetPosition($1.Position()) + $$ = &ast.LetsExpr{LHSS: []ast.Expr{$1}, RHSS: []ast.Expr{rhs}} + $$.SetPosition($1.Position()) + } + | expr ANDEQ expr + { + rhs := &ast.OpExpr{Op: &ast.MultiplyOperator{LHS: $1, Operator: "&", RHS: $3}} + rhs.Op.SetPosition($1.Position()) + rhs.SetPosition($1.Position()) + $$ = &ast.LetsExpr{LHSS: []ast.Expr{$1}, RHSS: []ast.Expr{rhs}} + $$.SetPosition($1.Position()) + } + + +op_multiply : + expr '*' expr + { + $$ = &ast.MultiplyOperator{LHS: $1, Operator: "*", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr '/' expr + { + $$ = &ast.MultiplyOperator{LHS: $1, Operator: "/", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr '%' expr + { + $$ = &ast.MultiplyOperator{LHS: $1, Operator: "%", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr SHIFTLEFT expr + { + $$ = &ast.MultiplyOperator{LHS: $1, Operator: "<<", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr SHIFTRIGHT expr + { + $$ = &ast.MultiplyOperator{LHS: $1, Operator: ">>", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr '&' expr + { + $$ = &ast.MultiplyOperator{LHS: $1, Operator: "&", RHS: $3} + $$.SetPosition($1.Position()) + } + +op_add : + expr '+' expr + { + $$ = &ast.AddOperator{LHS: $1, Operator: "+", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr '-' expr + { + $$ = &ast.AddOperator{LHS: $1, Operator: "-", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr '|' expr + { + $$ = &ast.AddOperator{LHS: $1, Operator: "|", RHS: $3} + $$.SetPosition($1.Position()) + } + +op_comparison : + expr EQEQ expr + { + $$ = &ast.ComparisonOperator{LHS: $1, Operator: "==", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr NEQ expr + { + $$ = &ast.ComparisonOperator{LHS: $1, Operator: "!=", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr '<' expr + { + $$ = &ast.ComparisonOperator{LHS: $1, Operator: "<", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr LE expr + { + $$ = &ast.ComparisonOperator{LHS: $1, Operator: "<=", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr '>' expr + { + $$ = &ast.ComparisonOperator{LHS: $1, Operator: ">", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr GE expr + { + $$ = &ast.ComparisonOperator{LHS: $1, Operator: ">=", RHS: $3} + $$.SetPosition($1.Position()) + } + +op_binary : + expr ANDAND expr + { + $$ = &ast.BinaryOperator{LHS: $1, Operator: "&&", RHS: $3} + $$.SetPosition($1.Position()) + } + | expr OROR expr + { + $$ = &ast.BinaryOperator{LHS: $1, Operator: "||", RHS: $3} + $$.SetPosition($1.Position()) + } + + +opt_term : + /* nothing */ + | term + +term : + ';' newlines + | newlines + | ';' + +opt_newlines : + /* nothing */ + | newlines + +newlines : + newline + | newlines newline + +newline : '\n' + +opt_comma_newlines : + /* nothing */ + | ',' newlines + | newlines + | ',' + +%% diff --git a/src/tool/run/vm/doc.go b/src/tool/run/vm/doc.go new file mode 100644 index 0000000..6bbb194 --- /dev/null +++ b/src/tool/run/vm/doc.go @@ -0,0 +1,2 @@ +// Package vm implements virtual-machine for anko. +package vm diff --git a/src/tool/run/vm/example_containers_test.go b/src/tool/run/vm/example_containers_test.go new file mode 100644 index 0000000..b1fa63e --- /dev/null +++ b/src/tool/run/vm/example_containers_test.go @@ -0,0 +1,259 @@ +package vm_test + +import ( + "fmt" + "log" + + "github.com/surdeus/goblin/src/tool/run/env" + "github.com/surdeus/goblin/src/tool/run/vm" +) + +func Example_vmArrays() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +a = []interface{1, 2} +println(a) + +a += 3 +println(a) + +a = []interface{} +// this automatically appends to array +a[0] = 1 +println(a) + +println("") + +a = []interface{} +// this would give an index out of range error +// a[1] = 1 + +a = []interface{1, 2} +b = []interface{3, 4} +c = a + b +println(c) + +c = []interface{1, 2} + []interface{3, 4} +println(c) + +println("") + +c = []interface{a} + b +println(c) + +c = []interface{a} + []interface{b} +println(c) + +c = []interface{[]interface{1, 2}} + []interface{[]interface{3, 4}} +println(c) + +println("") + +a = []interface{1, 2} + +println(len(a)) + +println(a[1]) + +a = [1, 2] +println(a) +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // [1 2] + // [1 2 3] + // [1] + // + // [1 2 3 4] + // [1 2 3 4] + // + // [[1 2] 3 4] + // [[1 2] [3 4]] + // [[1 2] [3 4]] + // + // 2 + // 2 + // [1 2] +} + +func Example_vmMaps() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +a = map[interface]interface{} +println(a) + +a.b = 1 +println(a) +println(a.b) + +a["b"] = 2 +println(a["b"]) + +println(len(a)) + +println("") + +b, ok = a["b"] +println(b) +println(ok) + +delete(a, "b") + +_, ok = a["b"] +println(ok) + +println("") + +a = {} +println(a) + +a.b = 1 +println(a) +println(a.b) + +a["b"] = 2 +println(a["b"]) + +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // map[] + // map[b:1] + // 1 + // 2 + // 1 + // + // 2 + // true + // false + // + // map[] + // map[b:1] + // 1 + // 2 +} + +func Example_vmStructs() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +a = make(struct { + A int64, + B float64 +}) +println(a) + +a.A = 1 +println(a) +println(a.A) + +a.B = 2.5 +println(a) +println(a.B) +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // {0 0} + // {1 0} + // 1 + // {1 2.5} + // 2.5 +} + +func Example_vmModules() { + + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +module rectangle { + _length = 1 + _width = 1 + + func setLength (length) { + if length <= 0 { + return + } + _length = length + } + + func setWidth (width) { + if width <= 0 { + return + } + _width = width + } + + func area () { + return _length * _width + } + + func perimeter () { + return 2 * (_length + _width) + } + } + +rectangle1 = rectangle + +rectangle1.setLength(4) +rectangle1.setWidth(5) + +println(rectangle1.area()) +println(rectangle1.perimeter()) + +rectangle2 = rectangle + +rectangle2.setLength(2) +rectangle2.setWidth(4) + +println(rectangle2.area()) +println(rectangle2.perimeter()) +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // 20 + // 18 + // 8 + // 12 +} diff --git a/src/tool/run/vm/example_functions_test.go b/src/tool/run/vm/example_functions_test.go new file mode 100644 index 0000000..82b10d6 --- /dev/null +++ b/src/tool/run/vm/example_functions_test.go @@ -0,0 +1,184 @@ +package vm_test + +import ( + "fmt" + "log" + + "github.com/surdeus/goblin/src/tool/run/env" + "github.com/surdeus/goblin/src/tool/run/vm" +) + +func Example_vmFunctions() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +func a(b) { + println(b) +} +a("b") + +a = func(b) { + println(b) +} +a("b") + +func(b) { + println(b) +}("b") + +func a() { + return "a" +} +println(a()) + +println("") + + +func fib(n) { + if (n <= 1) { + return n + } + return fib(n - 1) + fib(n - 2) +} + +println(fib(8)) + + func sum(n...) { + t = 0 + for a in n { + t += a + } + return t + } +println(sum(1, 2, 3, 4)) + +func add(a, b) { + return a + b +} +println(add([1, 2]...)) +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // b + // b + // b + // a + // + // 21 + // 10 + // 3 + +} + +func Example_vmFunctionsScope() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +a = 1 +func () { + a = 2 +}() +println(a) + +var a = 1 +func () { + a = 2 +}() +println(a) + +a = 1 +func () { + var a = 2 +}() +println(a) + +var a = 1 +func () { + var a = 2 +}() +println(a) +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // 2 + // 2 + // 1 + // 1 + +} + +func testFunc1(a interface{}) int { + b, ok := a.([]interface{}) + if ok { + return len(b) + } + return 0 +} + +func Example_vmFunctionsOutside() { + + /* + // the following function would be uncommented + func testFunc1(a interface{}) int { + b, ok := a.([]interface{}) + if ok { + return len(b) + } + return 0 + } + */ + + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + err = e.Define("addString", func(a string, b string) string { return a + b }) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + // uses the function that would be declared above + err = e.Define("aFunc", testFunc1) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +a = addString("a", "b") +println(a) + +a = aFunc([1, 2, 3]) +println(a) +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // ab + // 3 + +} diff --git a/src/tool/run/vm/example_operators_test.go b/src/tool/run/vm/example_operators_test.go new file mode 100644 index 0000000..a6d8f27 --- /dev/null +++ b/src/tool/run/vm/example_operators_test.go @@ -0,0 +1,385 @@ +package vm_test + +import ( + "fmt" + "log" + + "github.com/surdeus/goblin/src/tool/run/env" + "github.com/surdeus/goblin/src/tool/run/vm" +) + +func Example_vmBasicOperators() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +a = nil +println(a) +a = true +println(a) + +println("") + +a = 2 + 1 +println(a) +a = 2 - 1 +println(a) +a = 2 * 1 +println(a) +a = 4 / 2 +println(a) + +println("") + +a = 1 +a++ +println(a) +a-- +println(a) + +println("") + +a = 1 +a += 1 +println(a) +a -= 1 +println(a) +a *= 4 +println(a) +a /= 2 +println(a) + +println("") + +a = 1 & 3 +println(a) +a = 1 | 2 +println(a) + +println("") + +a = 2 << 3 +println(a) +a = 8 >> 2 +println(a) +a = 7 % 3 +println(a) + +println("") + +a = 2 - (-2) +println(a) +a = ^2 +println(a) +a = "a" * 4 +println(a) +a = !true +println(a) + +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // + // true + // + // 3 + // 1 + // 2 + // 2 + // + // 2 + // 1 + // + // 2 + // 1 + // 4 + // 2 + // + // 1 + // 3 + // + // 16 + // 2 + // 1 + // + // 4 + // -3 + // aaaa + // false + +} + +func Example_vmComparisonOperators() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +a = nil == nil +println(a) +a = "a" != "a" +println(a) +a = 1 == 1.0 +println(a) +a = !true +println(a) + +println("") + +a = 1 < 2 +println(a) +a = 1 > 3 +println(a) +a = 2 <= 2 +println(a) +a = 2 >= 3 +println(a) + +println("") +a = 1 == 2 && 1 == 1 +println(a) +a = 1 == 2 || 1 == 1 +println(a) +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // true + // false + // true + // false + // + // true + // false + // true + // false + // + // false + // true + +} + +func Example_vmIfOperators() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +a = 1 +b = 2 + +if a == 1 { + println(a) +} + +if b == 1 { + println(a) +} else { + println(b) +} + +if a == 3 { + println(a) +} else if b == 3 { + println(b) +} else { + println(a + b) +} + +println("") + +if a == 2 || b == 2 { + println(4) +} + +if a == 1 && b == 2 { + println(5) +} +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // 1 + // 2 + // 3 + // + // 4 + // 5 + +} + +func Example_vmForLoops() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +i = 0 +for { + println(i) + i++ + if i > 1 { + break + } +} + +println("") + +for i in [0, 1] { + println(i) +} + +println("") + +for key, value in {"a": "b"} { + println(key, value) +} + +println("") + +i = 0 +for i < 2 { + println(i) + i++ +} + +println("") + +for i = 0; i < 2; i++ { + println(i) +} + +println("") + + +for i = 0; i < 10; i++ { + println(i) + if i < 1 { + continue + } + break +} + +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // 0 + // 1 + // + // 0 + // 1 + // + // a b + // + // 0 + // 1 + // + // 0 + // 1 + // + // 0 + // 1 + +} + +func Example_vmSlices() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +a = "abc" +println(a[1:]) +println(a[:2]) +println(a[1:2]) + +println("") + +a = [1, 2, 3] +println(a[1:]) +println(a[:2]) +println(a[1:2]) +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // bc + // ab + // b + // + // [2 3] + // [1 2] + // [2] + +} + +func Example_vmChannels() { + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +a = make(chan string, 1) +a <- "a" +println(<- a) + +a = make(chan string) +go func() { + a <- "a" +}() +println(<- a) + + +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // a + // a + +} diff --git a/src/tool/run/vm/example_packages_test.go b/src/tool/run/vm/example_packages_test.go new file mode 100644 index 0000000..ce7e158 --- /dev/null +++ b/src/tool/run/vm/example_packages_test.go @@ -0,0 +1,131 @@ +package vm_test + +import ( + "log" + + "github.com/surdeus/goblin/src/tool/run/env" + _ "github.com/surdeus/goblin/src/tool/run/packages" + "github.com/surdeus/goblin/src/tool/run/vm" +) + +func Example_vmSort() { + // _ "github.com/surdeus/goblin/src/tool/run/packages" + + e := env.NewEnv() + + script := ` +fmt = import("fmt") +sort = import("sort") +a = [5, 1.1, 3, "f", "2", "4.4"] +sortFuncs = make(sort.SortFuncsStruct) +sortFuncs.LenFunc = func() { return len(a) } +sortFuncs.LessFunc = func(i, j) { return a[i] < a[j] } +sortFuncs.SwapFunc = func(i, j) { temp = a[i]; a[i] = a[j]; a[j] = temp } +sort.Sort(sortFuncs) +fmt.Println(a) +` + + _, err := vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // [f 1.1 2 3 4.4 5] +} + +func Example_vmRegexp() { + // _ "github.com/surdeus/goblin/src/tool/run/packages" + + e := env.NewEnv() + + script := ` +fmt = import("fmt") +regexp = import("regexp") + +re = regexp.MustCompile("^simple$") +result = re.MatchString("simple") +fmt.Println(result) +fmt.Println("") + +re = regexp.MustCompile("simple") +result = re.FindString("This is a simple sentence") +fmt.Println(result) +fmt.Println("") + +re = regexp.MustCompile(",") +result = re.Split("a,b,c", -1) +fmt.Println(result) +fmt.Println("") + +re = regexp.MustCompile("foo") +result = re.ReplaceAllString("foo", "bar") +fmt.Println(result) +` + + _, err := vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // true + // + // simple + // + // [a b c] + // + // bar +} + +func Example_vmHttp() { + // _ "github.com/surdeus/goblin/src/tool/run/packages" + + e := env.NewEnv() + + script := ` +fmt = import("fmt") +io = import("io") +ioutil = import("io/ioutil") +net = import("net") +http = import("net/http") +time = import("time") + +func handlerRoot(responseWriter, request) { + io.WriteString(responseWriter, "Hello World :)") +} + +serveMux = http.NewServeMux() +serveMux.HandleFunc("/", handlerRoot) +listener, err = net.Listen("tcp", ":8080") +if err != nil { + fmt.Println(err) + return +} +go http.Serve(listener, serveMux) + +client = http.DefaultClient + +response, err = client.Get("http://localhost:8080/") +if err != nil { + fmt.Println(err) + return +} + +body, err = ioutil.ReadAll(response.Body) +if err != nil { + fmt.Println(err) +} +response.Body.Close() + +fmt.Printf("%s\n", body) +` + + _, err := vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // Hello World :) +} diff --git a/src/tool/run/vm/example_test.go b/src/tool/run/vm/example_test.go new file mode 100644 index 0000000..7202b6b --- /dev/null +++ b/src/tool/run/vm/example_test.go @@ -0,0 +1,231 @@ +package vm_test + +import ( + "context" + "fmt" + "log" + "sync" + "time" + + "github.com/surdeus/goblin/src/tool/run/env" + "github.com/surdeus/goblin/src/tool/run/vm" +) + +func Example_vmExecuteContext() { + var waitGroup sync.WaitGroup + waitGroup.Add(1) + waitChan := make(chan struct{}, 1) + + e := env.NewEnv() + sleepMillisecond := func() { time.Sleep(time.Millisecond) } + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + err = e.Define("sleep", sleepMillisecond) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +# sleep for 10 seconds +for i = 0; i < 10000; i++ { + sleep() +} +# the context should cancel before printing the next line +println("this line should not be printed") +` + + ctx, cancel := context.WithCancel(context.Background()) + go func() { + close(waitChan) + v, err := vm.ExecuteContext(ctx, e, nil, script) + fmt.Println(v, err) + waitGroup.Done() + }() + + <-waitChan + cancel() + + waitGroup.Wait() + + // output: execution interrupted +} + +func Example_vmEnvDefine() { + // "github.com/surdeus/goblin/src/tool/run/env" + + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + err = e.Define("a", true) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + err = e.Define("b", int64(1)) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + err = e.Define("c", float64(1.1)) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + err = e.Define("d", "d") + if err != nil { + log.Fatalf("define error: %v\n", err) + } + err = e.Define("e", []interface{}{true, int64(1), float64(1.1), "d"}) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + err = e.Define("f", map[string]interface{}{"a": true}) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +println(a) +println(b) +println(c) +println(d) +println(e) +println(f) +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // true + // 1 + // 1.1 + // d + // [true 1 1.1 d] + // map[a:true] +} + +func Example_vmEnv() { + // "github.com/surdeus/goblin/src/tool/run/env" + + e := env.NewEnv() + + err := e.Define("a", "a") + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + _, err = e.Get("a") + if err != nil { + log.Fatalf("get error: %v\n", err) + } + + fmt.Println(e) + + // output: + // No parent + // a = "a" +} + +func Example_vmHelloWorld() { + // "github.com/surdeus/goblin/src/tool/run/env" + + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +println("Hello World :)") +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: Hello World :) +} + +func Example_vmQuickStart() { + // "github.com/surdeus/goblin/src/tool/run/env" + + e := env.NewEnv() + + err := e.Define("println", fmt.Println) + if err != nil { + log.Fatalf("define error: %v\n", err) + } + + script := ` +// declare variables +x = 1 +y = x + 1 + +// print using outside the script defined println function +println(x + y) // 3 + +// if else statement +if x < 1 || y < 1 { + println(x) +} else if x < 1 && y < 1 { + println(y) +} else { + println(x + y) +} + +// slice +a = []interface{1, 2, 3} +println(a) // [1 2 3] +println(a[0]) // 1 + +// map +a = map[interface]interface{"x": 1} +println(a) // map[x:1] +a.b = 2 +a["c"] = 3 +println(a["b"]) // 2 +println(a.c) // 3 + +// struct +a = make(struct { + A int64, + B float64 +}) +a.A = 4 +a.B = 5.5 +println(a.A) // 4 +println(a.B) // 5.5 + +// function +func a (x) { + println(x + 1) +} +a(5) // 6 +` + + _, err = vm.Execute(e, nil, script) + if err != nil { + log.Fatalf("execute error: %v\n", err) + } + + // output: + // 3 + // 3 + // [1 2 3] + // 1 + // map[x:1] + // 2 + // 3 + // 4 + // 5.5 + // 6 +} diff --git a/src/tool/run/vm/main_test.go b/src/tool/run/vm/main_test.go new file mode 100644 index 0000000..4aa145f --- /dev/null +++ b/src/tool/run/vm/main_test.go @@ -0,0 +1,268 @@ +package vm + +import ( + "context" + "reflect" + "testing" + "time" + + "github.com/surdeus/goblin/src/tool/run/env" + "github.com/surdeus/goblin/src/tool/run/parser" +) + +type ( + testStruct1 struct { + aInterface interface{} + aBool bool + aInt32 int32 + aInt64 int64 + aFloat32 float32 + aFloat64 float32 + aString string + aFunc func() + + aPtrInterface *interface{} + aPtrBool *bool + aPtrInt32 *int32 + aPtrInt64 *int64 + aPtrFloat32 *float32 + aPtrFloat64 *float32 + aPtrString *string + aPtrSliceInterface *[]interface{} + aPtrSliceBool *[]bool + aPtrSliceInt32 *[]int32 + aPtrSliceInt64 *[]int64 + aPtrSliceFloat32 *[]float32 + aPtrSliceFloat64 *[]float32 + aPtrSliceString *[]string + + aSliceInterface []interface{} + aSliceBool []bool + aSliceInt32 []int32 + aSliceInt64 []int64 + aSliceFloat32 []float32 + aSliceFloat64 []float32 + aSliceString []string + aSlicePtrInterface []*interface{} + aSlicePtrBool []*bool + aSlicePtrInt32 []*int32 + aSlicePtrInt64 []*int64 + aSlicePtrFloat32 []*float32 + aSlicePtrFloat64 []*float32 + aSlicePtrString []*string + + aMapInterface map[string]interface{} + aMapBool map[string]bool + aMapInt32 map[string]int32 + aMapInt64 map[string]int64 + aMapFloat32 map[string]float32 + aMapFloat64 map[string]float32 + aMapString map[string]string + aMapPtrInterface map[string]*interface{} + aMapPtrBool map[string]*bool + aMapPtrInt32 map[string]*int32 + aMapPtrInt64 map[string]*int64 + aMapPtrFloat32 map[string]*float32 + aMapPtrFloat64 map[string]*float32 + aMapPtrString map[string]*string + + aChanInterface chan interface{} + aChanBool chan bool + aChanInt32 chan int32 + aChanInt64 chan int64 + aChanFloat32 chan float32 + aChanFloat64 chan float32 + aChanString chan string + aChanPtrInterface chan *interface{} + aChanPtrBool chan *bool + aChanPtrInt32 chan *int32 + aChanPtrInt64 chan *int64 + aChanPtrFloat32 chan *float32 + aChanPtrFloat64 chan *float32 + aChanPtrString chan *string + + aPtrStruct *testStruct1 + } + testStruct2 struct { + aStruct testStruct1 + } +) + +var ( + testVarValue = reflect.Value{} + testVarValueP = &reflect.Value{} + testVarBool = true + testVarBoolP = &testVarBool + testVarInt32 = int32(1) + testVarInt32P = &testVarInt32 + testVarInt64 = int64(1) + testVarInt64P = &testVarInt64 + testVarFloat32 = float32(1) + testVarFloat32P = &testVarFloat32 + testVarFloat64 = float64(1) + testVarFloat64P = &testVarFloat64 + testVarString = "a" + testVarStringP = &testVarString + testVarFunc = func() int64 { return 1 } + testVarFuncP = &testVarFunc + + testVarValueBool = reflect.ValueOf(true) + testVarValueInt32 = reflect.ValueOf(int32(1)) + testVarValueInt64 = reflect.ValueOf(int64(1)) + testVarValueFloat32 = reflect.ValueOf(float32(1.1)) + testVarValueFloat64 = reflect.ValueOf(float64(1.1)) + testVarValueString = reflect.ValueOf("a") + + testSliceEmpty []interface{} + testSlice = []interface{}{nil, true, int64(1), float64(1.1), "a"} + testMapEmpty map[interface{}]interface{} + testMap = map[interface{}]interface{}{"a": nil, "b": true, "c": int64(1), "d": float64(1.1), "e": "e"} +) + +// Test is utility struct to make tests easy. +type Test struct { + Script string + ParseError error + ParseErrorFunc *func(*testing.T, error) + EnvSetupFunc *func(*testing.T, *env.Env) + Types map[string]interface{} + Input map[string]interface{} + RunError error + RunErrorFunc *func(*testing.T, error) + RunOutput interface{} + Output map[string]interface{} +} + +// TestOptions is utility struct to pass options to the test. +type TestOptions struct { + EnvSetupFunc *func(*testing.T, *env.Env) + Timeout time.Duration +} + +// runTests runs VM tests +func runTests(t *testing.T, tests []Test, testOptions *TestOptions, options *Options) { + for _, test := range tests { + runTest(t, test, testOptions, options) + } +} + +// runTest runs VM test +func runTest(t *testing.T, test Test, testOptions *TestOptions, options *Options) { + timeout := 60 * time.Second + + // parser.EnableErrorVerbose() + // parser.EnableDebug(8) + + stmt, err := parser.ParseSrc(test.Script) + if test.ParseErrorFunc != nil { + (*test.ParseErrorFunc)(t, err) + } else if err != nil && test.ParseError != nil { + if err.Error() != test.ParseError.Error() { + t.Errorf("ParseSrc error - received: %v - expected: %v - script: %v", err, test.ParseError, test.Script) + return + } + } else if err != test.ParseError { + t.Errorf("ParseSrc error - received: %v - expected: %v - script: %v", err, test.ParseError, test.Script) + return + } + // Note: Still want to run the code even after a parse error to see what happens + + envTest := env.NewEnv() + if testOptions != nil { + if testOptions.EnvSetupFunc != nil { + (*testOptions.EnvSetupFunc)(t, envTest) + } + if testOptions.Timeout != 0 { + timeout = testOptions.Timeout + } + } + if test.EnvSetupFunc != nil { + (*test.EnvSetupFunc)(t, envTest) + } + + for typeName, typeValue := range test.Types { + err = envTest.DefineType(typeName, typeValue) + if err != nil { + t.Errorf("DefineType error: %v - typeName: %v - script: %v", err, typeName, test.Script) + return + } + } + + for inputName, inputValue := range test.Input { + err = envTest.Define(inputName, inputValue) + if err != nil { + t.Errorf("Define error: %v - inputName: %v - script: %v", err, inputName, test.Script) + return + } + } + + var value interface{} + ctx, cancel := context.WithTimeout(context.Background(), timeout) + value, err = RunContext(ctx, envTest, options, stmt) + cancel() + if test.RunErrorFunc != nil { + (*test.RunErrorFunc)(t, err) + } else if err != nil && test.RunError != nil { + if err.Error() != test.RunError.Error() { + t.Errorf("Run error - received: %v - expected: %v - script: %v", err, test.RunError, test.Script) + return + } + } else if err != test.RunError { + t.Errorf("Run error - received: %v - expected: %v - script: %v", err, test.RunError, test.Script) + return + } + + if !valueEqual(value, test.RunOutput) { + t.Errorf("Run output - received: %#v - expected: %#v - script: %v", value, test.RunOutput, test.Script) + t.Errorf("received type: %T - expected: %T", value, test.RunOutput) + return + } + + for outputName, outputValue := range test.Output { + value, err = envTest.Get(outputName) + if err != nil { + t.Errorf("Get error: %v - outputName: %v - script: %v", err, outputName, test.Script) + return + } + + if !valueEqual(value, outputValue) { + t.Errorf("outputName %v - received: %#v - expected: %#v - script: %v", outputName, value, outputValue, test.Script) + t.Errorf("received type: %T - expected: %T", value, outputValue) + continue + } + } +} + +// valueEqual return true if v1 and v2 is same value. If passed function, does +// extra checks otherwise just doing reflect.DeepEqual +func valueEqual(v1 interface{}, v2 interface{}) bool { + v1RV := reflect.ValueOf(v1) + switch v1RV.Kind() { + case reflect.Func: + // This is best effort to check if functions match, but it could be wrong + v2RV := reflect.ValueOf(v2) + if !v1RV.IsValid() || !v2RV.IsValid() { + if v1RV.IsValid() != !v2RV.IsValid() { + return false + } + return true + } else if v1RV.Kind() != v2RV.Kind() { + return false + } else if v1RV.Type() != v2RV.Type() { + return false + } else if v1RV.Pointer() != v2RV.Pointer() { + // 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. + return false + } + return true + } + switch value1 := v1.(type) { + case error: + switch value2 := v2.(type) { + case error: + return value1.Error() == value2.Error() + } + } + + return reflect.DeepEqual(v1, v2) +} diff --git a/src/tool/run/vm/packagesGo110_test.go b/src/tool/run/vm/packagesGo110_test.go new file mode 100644 index 0000000..4b05743 --- /dev/null +++ b/src/tool/run/vm/packagesGo110_test.go @@ -0,0 +1,18 @@ +// +build go1.10 + +package vm + +import ( + "testing" + + _ "github.com/surdeus/goblin/src/tool/run/packages" +) + +func TestPackagesStringsGo110(t *testing.T) { + t.Parallel() + + tests := []Test{ + {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"}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} diff --git a/src/tool/run/vm/packages_test.go b/src/tool/run/vm/packages_test.go new file mode 100644 index 0000000..a13affe --- /dev/null +++ b/src/tool/run/vm/packages_test.go @@ -0,0 +1,209 @@ +package vm + +import ( + "fmt" + "reflect" + "testing" + + "github.com/surdeus/goblin/src/tool/run/env" + _ "github.com/surdeus/goblin/src/tool/run/packages" +) + +func TestImport(t *testing.T) { + tests := []Test{ + {Script: `a = import(1++)`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a = import(true)`, RunError: fmt.Errorf("invalid type conversion")}, + {Script: `a = import("foo")`, RunError: fmt.Errorf("package not found: foo")}, + } + runTests(t, tests, nil, &Options{Debug: true}) + + envPackages := env.Packages + envPackageTypes := env.PackageTypes + + env.Packages = map[string]map[string]reflect.Value{"testPackage": {"a.b": reflect.ValueOf(1)}} + tests = []Test{ + {Script: `a = import("testPackage")`, RunError: fmt.Errorf("import DefineValue error: symbol contains '.'")}, + } + runTests(t, tests, nil, &Options{Debug: true}) + + env.Packages = map[string]map[string]reflect.Value{"testPackage": {"a": reflect.ValueOf(1)}} + env.PackageTypes = map[string]map[string]reflect.Type{"testPackage": {"a.b": reflect.TypeOf(1)}} + tests = []Test{ + {Script: `a = import("testPackage")`, RunError: fmt.Errorf("import DefineReflectType error: symbol contains '.'")}, + } + runTests(t, tests, nil, &Options{Debug: true}) + + env.PackageTypes = envPackageTypes + env.Packages = envPackages +} + +func TestPackagesBytes(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `bytes = import("bytes"); a = make(bytes.Buffer); n, err = a.WriteString("a"); if err != nil { return err }; n`, RunOutput: 1}, + {Script: `bytes = import("bytes"); a = make(bytes.Buffer); n, err = a.WriteString("a"); if err != nil { return err }; a.String()`, RunOutput: "a"}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestPackagesJson(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `json = import("encoding/json"); a = make(map[string]interface); a["b"] = "b"; c, err = json.Marshal(a); err`, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": []byte(`{"b":"b"}`)}}, + {Script: `json = import("encoding/json"); b = 1; err = json.Unmarshal(a, &b); err`, Input: map[string]interface{}{"a": []byte(`{"b": "b"}`)}, Output: map[string]interface{}{"a": []byte(`{"b": "b"}`), "b": map[string]interface{}{"b": "b"}}}, + {Script: `json = import("encoding/json"); b = 1; err = json.Unmarshal(a, &b); err`, Input: map[string]interface{}{"a": `{"b": "b"}`}, Output: map[string]interface{}{"a": `{"b": "b"}`, "b": map[string]interface{}{"b": "b"}}}, + {Script: `json = import("encoding/json"); b = 1; err = json.Unmarshal(a, &b); err`, Input: map[string]interface{}{"a": `[["1", "2"],["3", "4"]]`}, Output: map[string]interface{}{"a": `[["1", "2"],["3", "4"]]`, "b": []interface{}{[]interface{}{"1", "2"}, []interface{}{"3", "4"}}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestPackagesRegexp(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `regexp = import("regexp"); re = regexp.MustCompile("^simple$"); re.MatchString("simple")`, RunOutput: true}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile("^simple$"); re.MatchString("no match")`, RunOutput: false}, + + {Script: `regexp = import("regexp"); re = regexp.MustCompile(a); re.MatchString(b)`, Input: map[string]interface{}{"a": "^simple$", "b": "simple"}, RunOutput: true, Output: map[string]interface{}{"a": "^simple$", "b": "simple"}}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile(a); re.MatchString(b)`, Input: map[string]interface{}{"a": "^simple$", "b": "no match"}, RunOutput: false, Output: map[string]interface{}{"a": "^simple$", "b": "no match"}}, + + {Script: `regexp = import("regexp"); re = regexp.MustCompile("^a\\.\\d+\\.b$"); re.String()`, RunOutput: "^a\\.\\d+\\.b$"}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile("^a\\.\\d+\\.b$"); re.MatchString("a.1.b")`, RunOutput: true}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile("^a\\.\\d+\\.b$"); re.MatchString("a.22.b")`, RunOutput: true}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile("^a\\.\\d+\\.b$"); re.MatchString("a.333.b")`, RunOutput: true}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile("^a\\.\\d+\\.b$"); re.MatchString("no match")`, RunOutput: false}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile("^a\\.\\d+\\.b$"); re.MatchString("a+1+b")`, RunOutput: false}, + + {Script: `regexp = import("regexp"); re = regexp.MustCompile(a); re.String()`, Input: map[string]interface{}{"a": "^a\\.\\d+\\.b$"}, RunOutput: "^a\\.\\d+\\.b$", Output: map[string]interface{}{"a": "^a\\.\\d+\\.b$"}}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile(a); re.MatchString(b)`, Input: map[string]interface{}{"a": "^a\\.\\d+\\.b$", "b": "a.1.b"}, RunOutput: true, Output: map[string]interface{}{"a": "^a\\.\\d+\\.b$", "b": "a.1.b"}}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile(a); re.MatchString(b)`, Input: map[string]interface{}{"a": "^a\\.\\d+\\.b$", "b": "a.22.b"}, RunOutput: true, Output: map[string]interface{}{"a": "^a\\.\\d+\\.b$", "b": "a.22.b"}}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile(a); re.MatchString(b)`, Input: map[string]interface{}{"a": "^a\\.\\d+\\.b$", "b": "a.333.b"}, RunOutput: true, Output: map[string]interface{}{"a": "^a\\.\\d+\\.b$", "b": "a.333.b"}}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile(a); re.MatchString(b)`, Input: map[string]interface{}{"a": "^a\\.\\d+\\.b$", "b": "no match"}, RunOutput: false, Output: map[string]interface{}{"a": "^a\\.\\d+\\.b$", "b": "no match"}}, + {Script: `regexp = import("regexp"); re = regexp.MustCompile(a); re.MatchString(b)`, Input: map[string]interface{}{"a": "^a\\.\\d+\\.b$", "b": "a+1+b"}, RunOutput: false, Output: map[string]interface{}{"a": "^a\\.\\d+\\.b$", "b": "a+1+b"}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestPackagesSort(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `sort = import("sort"); a = make([]int); a += [5, 3, 1, 4, 2]; sort.Ints(a); a`, RunOutput: []int{1, 2, 3, 4, 5}, Output: map[string]interface{}{"a": []int{1, 2, 3, 4, 5}}}, + {Script: `sort = import("sort"); a = make([]float64); a += [5.5, 3.3, 1.1, 4.4, 2.2]; sort.Float64s(a); a`, RunOutput: []float64{1.1, 2.2, 3.3, 4.4, 5.5}, Output: map[string]interface{}{"a": []float64{1.1, 2.2, 3.3, 4.4, 5.5}}}, + {Script: `sort = import("sort"); a = make([]string); a += ["e", "c", "a", "d", "b"]; sort.Strings(a); a`, RunOutput: []string{"a", "b", "c", "d", "e"}, Output: map[string]interface{}{"a": []string{"a", "b", "c", "d", "e"}}}, + {Script: ` +sort = import("sort") +a = [5, 1.1, 3, "f", "2", "4.4"] +sortFuncs = make(sort.SortFuncsStruct) +sortFuncs.LenFunc = func() { return len(a) } +sortFuncs.LessFunc = func(i, j) { return a[i] < a[j] } +sortFuncs.SwapFunc = func(i, j) { temp = a[i]; a[i] = a[j]; a[j] = temp } +sort.Sort(sortFuncs) +a +`, + RunOutput: []interface{}{"f", float64(1.1), "2", int64(3), "4.4", int64(5)}, Output: map[string]interface{}{"a": []interface{}{"f", float64(1.1), "2", int64(3), "4.4", int64(5)}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestPackagesStrconv(t *testing.T) { + t.Parallel() + + var toRune = func(s string) rune { + if len(s) == 0 { + return 0 + } + return []rune(s)[0] + } + var toString = func(v interface{}) string { + if b, ok := v.([]byte); ok { + return string(b) + } + return fmt.Sprint(v) + } + tests := []Test{ + {Script: `strconv = import("strconv"); a = true; b = strconv.FormatBool(a)`, RunOutput: "true", Output: map[string]interface{}{"a": true, "b": "true"}}, + {Script: `strconv = import("strconv"); a = 1.1; b = strconv.FormatFloat(a, toRune("f"), -1, 64)`, Input: map[string]interface{}{"toRune": toRune}, RunOutput: "1.1", Output: map[string]interface{}{"a": float64(1.1), "b": "1.1"}}, + {Script: `strconv = import("strconv"); a = 1; b = strconv.FormatInt(a, 10)`, RunOutput: "1", Output: map[string]interface{}{"a": int64(1), "b": "1"}}, + {Script: `strconv = import("strconv"); b = strconv.FormatInt(a, 10)`, Input: map[string]interface{}{"a": uint64(1)}, RunOutput: "1", Output: map[string]interface{}{"a": uint64(1), "b": "1"}}, + + {Script: `strconv = import("strconv"); a = "true"; b, err = strconv.ParseBool(a); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: "", Output: map[string]interface{}{"a": "true", "b": true, "err": ""}}, + {Script: `strconv = import("strconv"); a = "2"; b, err = strconv.ParseBool(a); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: `strconv.ParseBool: parsing "2": invalid syntax`, Output: map[string]interface{}{"a": "2", "b": false, "err": `strconv.ParseBool: parsing "2": invalid syntax`}}, + {Script: `strconv = import("strconv"); a = "1.1"; b, err = strconv.ParseFloat(a, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: "", Output: map[string]interface{}{"a": "1.1", "b": float64(1.1), "err": ""}}, + {Script: `strconv = import("strconv"); a = "a"; b, err = strconv.ParseFloat(a, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: `strconv.ParseFloat: parsing "a": invalid syntax`, Output: map[string]interface{}{"a": "a", "b": float64(0), "err": `strconv.ParseFloat: parsing "a": invalid syntax`}}, + {Script: `strconv = import("strconv"); a = "1"; b, err = strconv.ParseInt(a, 10, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: "", Output: map[string]interface{}{"a": "1", "b": int64(1), "err": ""}}, + {Script: `strconv = import("strconv"); a = "1.1"; b, err = strconv.ParseInt(a, 10, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: `strconv.ParseInt: parsing "1.1": invalid syntax`, Output: map[string]interface{}{"a": "1.1", "b": int64(0), "err": `strconv.ParseInt: parsing "1.1": invalid syntax`}}, + {Script: `strconv = import("strconv"); a = "a"; b, err = strconv.ParseInt(a, 10, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: `strconv.ParseInt: parsing "a": invalid syntax`, Output: map[string]interface{}{"a": "a", "b": int64(0), "err": `strconv.ParseInt: parsing "a": invalid syntax`}}, + {Script: `strconv = import("strconv"); a = "1"; b, err = strconv.ParseUint(a, 10, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: "", Output: map[string]interface{}{"a": "1", "b": uint64(1), "err": ""}}, + {Script: `strconv = import("strconv"); a = "a"; b, err = strconv.ParseUint(a, 10, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: `strconv.ParseUint: parsing "a": invalid syntax`, Output: map[string]interface{}{"a": "a", "b": uint64(0), "err": `strconv.ParseUint: parsing "a": invalid syntax`}}, + + {Script: `strconv = import("strconv"); a = "true"; var b, err = strconv.ParseBool(a); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: "", Output: map[string]interface{}{"a": "true", "b": true, "err": ""}}, + {Script: `strconv = import("strconv"); a = "2"; var b, err = strconv.ParseBool(a); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: `strconv.ParseBool: parsing "2": invalid syntax`, Output: map[string]interface{}{"a": "2", "b": false, "err": `strconv.ParseBool: parsing "2": invalid syntax`}}, + {Script: `strconv = import("strconv"); a = "1.1"; var b, err = strconv.ParseFloat(a, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: "", Output: map[string]interface{}{"a": "1.1", "b": float64(1.1), "err": ""}}, + {Script: `strconv = import("strconv"); a = "a"; var b, err = strconv.ParseFloat(a, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: `strconv.ParseFloat: parsing "a": invalid syntax`, Output: map[string]interface{}{"a": "a", "b": float64(0), "err": `strconv.ParseFloat: parsing "a": invalid syntax`}}, + {Script: `strconv = import("strconv"); a = "1"; var b, err = strconv.ParseInt(a, 10, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: "", Output: map[string]interface{}{"a": "1", "b": int64(1), "err": ""}}, + {Script: `strconv = import("strconv"); a = "1.1"; var b, err = strconv.ParseInt(a, 10, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: `strconv.ParseInt: parsing "1.1": invalid syntax`, Output: map[string]interface{}{"a": "1.1", "b": int64(0), "err": `strconv.ParseInt: parsing "1.1": invalid syntax`}}, + {Script: `strconv = import("strconv"); a = "a"; var b, err = strconv.ParseInt(a, 10, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: `strconv.ParseInt: parsing "a": invalid syntax`, Output: map[string]interface{}{"a": "a", "b": int64(0), "err": `strconv.ParseInt: parsing "a": invalid syntax`}}, + {Script: `strconv = import("strconv"); a = "1"; var b, err = strconv.ParseUint(a, 10, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: "", Output: map[string]interface{}{"a": "1", "b": uint64(1), "err": ""}}, + {Script: `strconv = import("strconv"); a = "a"; var b, err = strconv.ParseUint(a, 10, 64); err = toString(err)`, Input: map[string]interface{}{"toString": toString}, RunOutput: `strconv.ParseUint: parsing "a": invalid syntax`, Output: map[string]interface{}{"a": "a", "b": uint64(0), "err": `strconv.ParseUint: parsing "a": invalid syntax`}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestPackagesStrings(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `strings = import("strings"); a = " one two "; b = strings.TrimSpace(a)`, RunOutput: "one two", Output: map[string]interface{}{"a": " one two ", "b": "one two"}}, + {Script: `strings = import("strings"); a = "a b c d"; b = strings.Split(a, " ")`, RunOutput: []string{"a", "b", "c", "d"}, Output: map[string]interface{}{"a": "a b c d", "b": []string{"a", "b", "c", "d"}}}, + {Script: `strings = import("strings"); a = "a b c d"; b = strings.SplitN(a, " ", 3)`, RunOutput: []string{"a", "b", "c d"}, Output: map[string]interface{}{"a": "a b c d", "b": []string{"a", "b", "c d"}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestPackagesSync(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `sync = import("sync"); once = make(sync.Once); a = []; func add() { a += "a" }; once.Do(add); once.Do(add); a`, RunOutput: []interface{}{"a"}, Output: map[string]interface{}{"a": []interface{}{"a"}}}, + {Script: `sync = import("sync"); waitGroup = make(sync.WaitGroup); waitGroup.Add(2); func done() { waitGroup.Done() }; go done(); go done(); waitGroup.Wait(); "a"`, RunOutput: "a"}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestPackagesTime(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `time = import("time"); a = make(time.Time); a.IsZero()`, RunOutput: true}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestPackagesURL(t *testing.T) { + t.Parallel() + + e := env.NewEnv() + value, err := Execute(e, nil, ` +url = import("net/url") +v1 = make(url.Values) +v1.Set("a", "a") +if v1.Get("a") != "a" { + return "value a not set" +} +v2 = make(url.Values) +v2.Set("b", "b") +if v2.Get("b") != "b" { + return "value b not set" +} +v2.Get("a") +`) + if err != nil { + t.Errorf("execute error - received: %v expected: %v", err, nil) + } + if value != "" { + t.Errorf("execute value - received: %#v expected: %#v", value, "") + } +} diff --git a/src/tool/run/vm/vm.go b/src/tool/run/vm/vm.go new file mode 100644 index 0000000..e7aadfd --- /dev/null +++ b/src/tool/run/vm/vm.go @@ -0,0 +1,458 @@ +package vm + +import ( + "context" + "errors" + "fmt" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/ast" + "github.com/surdeus/goblin/src/tool/run/env" +) + +// Options provides options to run VM with +type Options struct { + Debug bool // run in Debug mode +} + +type ( + // Error is a VM run error. + Error struct { + Message string + Pos ast.Position + } + + // runInfo provides run incoming and outgoing information + runInfoStruct struct { + // incoming + ctx context.Context + env *env.Env + options *Options + stmt ast.Stmt + expr ast.Expr + operator ast.Operator + + // outgoing + rv reflect.Value + err error + } +) + +var ( + nilType = reflect.TypeOf(nil) + stringType = reflect.TypeOf("a") + byteType = reflect.TypeOf(byte('a')) + runeType = reflect.TypeOf('a') + interfaceType = reflect.ValueOf([]interface{}{int64(1)}).Index(0).Type() + interfaceSliceType = reflect.TypeOf([]interface{}{}) + reflectValueType = reflect.TypeOf(reflect.Value{}) + errorType = reflect.ValueOf([]error{nil}).Index(0).Type() + vmErrorType = reflect.TypeOf(&Error{}) + contextType = reflect.TypeOf((*context.Context)(nil)).Elem() + + nilValue = reflect.New(reflect.TypeOf((*interface{})(nil)).Elem()).Elem() + trueValue = reflect.ValueOf(true) + falseValue = reflect.ValueOf(false) + zeroValue = reflect.Value{} + reflectValueNilValue = reflect.ValueOf(nilValue) + reflectValueErrorNilValue = reflect.ValueOf(reflect.New(errorType).Elem()) + + errInvalidTypeConversion = fmt.Errorf("invalid type conversion") + + // ErrBreak when there is an unexpected break statement + ErrBreak = errors.New("unexpected break statement") + // ErrContinue when there is an unexpected continue statement + ErrContinue = errors.New("unexpected continue statement") + // ErrReturn when there is an unexpected return statement + ErrReturn = errors.New("unexpected return statement") + // ErrInterrupt when execution has been interrupted + ErrInterrupt = errors.New("execution interrupted") +) + +// Error returns the VM error message. +func (e *Error) Error() string { + return e.Message +} + +// newError makes VM error from error +func newError(pos ast.Pos, err error) error { + if err == nil { + return nil + } + if pos == nil { + return &Error{Message: err.Error(), Pos: ast.Position{Line: 1, Column: 1}} + } + return &Error{Message: err.Error(), Pos: pos.Position()} +} + +// newStringError makes VM error from string +func newStringError(pos ast.Pos, err string) error { + if err == "" { + return nil + } + if pos == nil { + return &Error{Message: err, Pos: ast.Position{Line: 1, Column: 1}} + } + return &Error{Message: err, Pos: pos.Position()} +} + +// recoverFunc generic recover function +func recoverFunc(runInfo *runInfoStruct) { + recoverInterface := recover() + if recoverInterface == nil { + return + } + switch value := recoverInterface.(type) { + case *Error: + runInfo.err = value + case error: + runInfo.err = value + default: + runInfo.err = fmt.Errorf("%v", recoverInterface) + } +} + +func isNil(v reflect.Value) bool { + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + // from reflect IsNil: + // Note that IsNil is not always equivalent to a regular comparison with nil in Go. + // For example, if v was created by calling ValueOf with an uninitialized interface variable i, + // i==nil will be true but v.IsNil will panic as v will be the zero Value. + return v.IsNil() + default: + return false + } +} + +func isNum(v reflect.Value) bool { + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Float32, reflect.Float64: + return true + } + return false +} + +// equal returns true when lhsV and rhsV is same value. +func equal(lhsV, rhsV reflect.Value) bool { + lhsIsNil, rhsIsNil := isNil(lhsV), isNil(rhsV) + if lhsIsNil && rhsIsNil { + return true + } + if (!lhsIsNil && rhsIsNil) || (lhsIsNil && !rhsIsNil) { + return false + } + if lhsV.Kind() == reflect.Interface || lhsV.Kind() == reflect.Ptr { + lhsV = lhsV.Elem() + } + if rhsV.Kind() == reflect.Interface || rhsV.Kind() == reflect.Ptr { + rhsV = rhsV.Elem() + } + + // Compare a string and a number. + // This will attempt to convert the string to a number, + // while leaving the other side alone. Code further + // down takes care of converting ints and floats as needed. + if isNum(lhsV) && rhsV.Kind() == reflect.String { + rhsF, err := tryToFloat64(rhsV) + if err != nil { + // Couldn't convert RHS to a float, they can't be compared. + return false + } + rhsV = reflect.ValueOf(rhsF) + } else if lhsV.Kind() == reflect.String && isNum(rhsV) { + // If the LHS is a string formatted as an int, try that before trying float + lhsI, err := tryToInt64(lhsV) + if err != nil { + // if LHS is a float, e.g. "1.2", we need to set lhsV to a float64 + lhsF, err := tryToFloat64(lhsV) + if err != nil { + return false + } + lhsV = reflect.ValueOf(lhsF) + } else { + lhsV = reflect.ValueOf(lhsI) + } + } + + if isNum(lhsV) && isNum(rhsV) { + return fmt.Sprintf("%v", lhsV) == fmt.Sprintf("%v", rhsV) + } + + // Try to compare bools to strings and numbers + if lhsV.Kind() == reflect.Bool || rhsV.Kind() == reflect.Bool { + lhsB, err := tryToBool(lhsV) + if err != nil { + return false + } + rhsB, err := tryToBool(rhsV) + if err != nil { + return false + } + return lhsB == rhsB + } + + return reflect.DeepEqual(lhsV.Interface(), rhsV.Interface()) +} + +func getMapIndex(key reflect.Value, aMap reflect.Value) reflect.Value { + if aMap.IsNil() { + return nilValue + } + + var err error + key, err = convertReflectValueToType(key, aMap.Type().Key()) + if err != nil { + return nilValue + } + + // From reflect MapIndex: + // It returns the zero Value if key is not found in the map or if v represents a nil map. + value := aMap.MapIndex(key) + if !value.IsValid() { + return nilValue + } + + if aMap.Type().Elem() == interfaceType && !value.IsNil() { + value = reflect.ValueOf(value.Interface()) + } + + return value +} + +// appendSlice appends rhs to lhs +// function assumes lhsV and rhsV are slice or array +func appendSlice(expr ast.Expr, lhsV reflect.Value, rhsV reflect.Value) (reflect.Value, error) { + lhsT := lhsV.Type().Elem() + rhsT := rhsV.Type().Elem() + + if lhsT == rhsT { + return reflect.AppendSlice(lhsV, rhsV), nil + } + + if rhsT.ConvertibleTo(lhsT) { + for i := 0; i < rhsV.Len(); i++ { + lhsV = reflect.Append(lhsV, rhsV.Index(i).Convert(lhsT)) + } + return lhsV, nil + } + + leftHasSubArray := lhsT.Kind() == reflect.Slice || lhsT.Kind() == reflect.Array + rightHasSubArray := rhsT.Kind() == reflect.Slice || rhsT.Kind() == reflect.Array + + if leftHasSubArray != rightHasSubArray && lhsT != interfaceType && rhsT != interfaceType { + return nilValue, newStringError(expr, "invalid type conversion") + } + + if !leftHasSubArray && !rightHasSubArray { + for i := 0; i < rhsV.Len(); i++ { + value := rhsV.Index(i) + if rhsT == interfaceType { + value = value.Elem() + } + if lhsT == value.Type() { + lhsV = reflect.Append(lhsV, value) + } else if value.Type().ConvertibleTo(lhsT) { + lhsV = reflect.Append(lhsV, value.Convert(lhsT)) + } else { + return nilValue, newStringError(expr, "invalid type conversion") + } + } + return lhsV, nil + } + + if (leftHasSubArray || lhsT == interfaceType) && (rightHasSubArray || rhsT == interfaceType) { + for i := 0; i < rhsV.Len(); i++ { + value := rhsV.Index(i) + if rhsT == interfaceType { + value = value.Elem() + if value.Kind() != reflect.Slice && value.Kind() != reflect.Array { + return nilValue, newStringError(expr, "invalid type conversion") + } + } + newSlice, err := appendSlice(expr, reflect.MakeSlice(lhsT, 0, value.Len()), value) + if err != nil { + return nilValue, err + } + lhsV = reflect.Append(lhsV, newSlice) + } + return lhsV, nil + } + + return nilValue, newStringError(expr, "invalid type conversion") +} + +func makeType(runInfo *runInfoStruct, typeStruct *ast.TypeStruct) reflect.Type { + switch typeStruct.Kind { + case ast.TypeDefault: + return getTypeFromEnv(runInfo, typeStruct) + case ast.TypePtr: + var t reflect.Type + if typeStruct.SubType != nil { + t = makeType(runInfo, typeStruct.SubType) + } else { + t = getTypeFromEnv(runInfo, typeStruct) + } + if runInfo.err != nil { + return nil + } + if t == nil { + return nil + } + return reflect.PtrTo(t) + case ast.TypeSlice: + var t reflect.Type + if typeStruct.SubType != nil { + t = makeType(runInfo, typeStruct.SubType) + } else { + t = getTypeFromEnv(runInfo, typeStruct) + } + if runInfo.err != nil { + return nil + } + if t == nil { + return nil + } + for i := 1; i < typeStruct.Dimensions; i++ { + t = reflect.SliceOf(t) + } + return reflect.SliceOf(t) + case ast.TypeMap: + key := makeType(runInfo, typeStruct.Key) + if runInfo.err != nil { + return nil + } + if key == nil { + return nil + } + t := makeType(runInfo, typeStruct.SubType) + if runInfo.err != nil { + return nil + } + if t == nil { + return nil + } + if !runInfo.options.Debug { + // captures panic + defer recoverFunc(runInfo) + } + t = reflect.MapOf(key, t) + return t + case ast.TypeChan: + var t reflect.Type + if typeStruct.SubType != nil { + t = makeType(runInfo, typeStruct.SubType) + } else { + t = getTypeFromEnv(runInfo, typeStruct) + } + if runInfo.err != nil { + return nil + } + if t == nil { + return nil + } + return reflect.ChanOf(reflect.BothDir, t) + case ast.TypeStructType: + var t reflect.Type + fields := make([]reflect.StructField, 0, len(typeStruct.StructNames)) + for i := 0; i < len(typeStruct.StructNames); i++ { + t = makeType(runInfo, typeStruct.StructTypes[i]) + if runInfo.err != nil { + return nil + } + if t == nil { + return nil + } + fields = append(fields, reflect.StructField{Name: typeStruct.StructNames[i], Type: t}) + } + if !runInfo.options.Debug { + // captures panic + defer recoverFunc(runInfo) + } + t = reflect.StructOf(fields) + return t + default: + runInfo.err = fmt.Errorf("unknown kind") + return nil + } +} + +func getTypeFromEnv(runInfo *runInfoStruct, typeStruct *ast.TypeStruct) reflect.Type { + var e *env.Env + e, runInfo.err = runInfo.env.GetEnvFromPath(typeStruct.Env) + if runInfo.err != nil { + return nil + } + + var t reflect.Type + t, runInfo.err = e.Type(typeStruct.Name) + return t +} + +func makeValue(t reflect.Type) (reflect.Value, error) { + switch t.Kind() { + case reflect.Chan: + return reflect.MakeChan(t, 0), nil + case reflect.Func: + return reflect.MakeFunc(t, nil), nil + case reflect.Map: + // note creating slice as work around to create map + // just doing MakeMap can give incorrect type for defined types + value := reflect.MakeSlice(reflect.SliceOf(t), 0, 1) + value = reflect.Append(value, reflect.MakeMap(reflect.MapOf(t.Key(), t.Elem()))) + return value.Index(0), nil + case reflect.Ptr: + ptrV := reflect.New(t.Elem()) + v, err := makeValue(t.Elem()) + if err != nil { + return nilValue, err + } + + ptrV.Elem().Set(v) + return ptrV, nil + case reflect.Slice: + return reflect.MakeSlice(t, 0, 0), nil + case reflect.Struct: + structV := reflect.New(t).Elem() + for i := 0; i < structV.NumField(); i++ { + if structV.Field(i).Kind() == reflect.Ptr { + continue + } + v, err := makeValue(structV.Field(i).Type()) + if err != nil { + return nilValue, err + } + if structV.Field(i).CanSet() { + structV.Field(i).Set(v) + } + } + return structV, nil + } + return reflect.New(t).Elem(), nil +} + +// precedenceOfKinds returns the greater of two kinds +// string > float > int +func precedenceOfKinds(kind1 reflect.Kind, kind2 reflect.Kind) reflect.Kind { + if kind1 == kind2 { + return kind1 + } + switch kind1 { + case reflect.String: + return kind1 + case reflect.Float64, reflect.Float32: + switch kind2 { + case reflect.String: + return kind2 + } + return kind1 + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch kind2 { + case reflect.String, reflect.Float64, reflect.Float32: + return kind2 + } + } + return kind1 +} diff --git a/src/tool/run/vm/vmContainers_test.go b/src/tool/run/vm/vmContainers_test.go new file mode 100644 index 0000000..a829f1e --- /dev/null +++ b/src/tool/run/vm/vmContainers_test.go @@ -0,0 +1,1926 @@ +package vm + +import ( + "fmt" + "net/url" + "reflect" + "testing" + + "github.com/surdeus/goblin/src/tool/run/env" + "github.com/surdeus/goblin/src/tool/run/parser" +) + +func TestSlices(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `[1++]`, RunError: fmt.Errorf("invalid operation")}, + {Script: `1++[0]`, RunError: fmt.Errorf("invalid operation")}, + + {Script: `[]`, RunOutput: []interface{}{}}, + {Script: `[nil]`, RunOutput: []interface{}{nil}}, + {Script: `[true]`, RunOutput: []interface{}{true}}, + {Script: `["a"]`, RunOutput: []interface{}{"a"}}, + {Script: `[1]`, RunOutput: []interface{}{int64(1)}}, + {Script: `[1.1]`, RunOutput: []interface{}{float64(1.1)}}, + + {Script: `a = []; a.b`, RunError: fmt.Errorf("type slice does not support member operation")}, + {Script: `a = []; a.b = 1`, RunError: fmt.Errorf("type slice does not support member operation")}, + + {Script: `a = []`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{}}}, + {Script: `a = [nil]`, RunOutput: []interface{}{interface{}(nil)}, Output: map[string]interface{}{"a": []interface{}{interface{}(nil)}}}, + {Script: `a = [true]`, RunOutput: []interface{}{true}, Output: map[string]interface{}{"a": []interface{}{true}}}, + {Script: `a = [1]`, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `a = [1.1]`, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": []interface{}{float64(1.1)}}}, + {Script: `a = ["a"]`, RunOutput: []interface{}{"a"}, Output: map[string]interface{}{"a": []interface{}{"a"}}}, + + {Script: `a = [[]]`, RunOutput: []interface{}{[]interface{}{}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{}}}}, + {Script: `a = [[nil]]`, RunOutput: []interface{}{[]interface{}{interface{}(nil)}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{interface{}(nil)}}}}, + {Script: `a = [[true]]`, RunOutput: []interface{}{[]interface{}{true}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{true}}}}, + {Script: `a = [[1]]`, RunOutput: []interface{}{[]interface{}{int64(1)}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1)}}}}, + {Script: `a = [[1.1]]`, RunOutput: []interface{}{[]interface{}{float64(1.1)}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{float64(1.1)}}}}, + {Script: `a = [["a"]]`, RunOutput: []interface{}{[]interface{}{"a"}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{"a"}}}}, + + {Script: `a = []; a += nil`, RunOutput: []interface{}{nil}, Output: map[string]interface{}{"a": []interface{}{nil}}}, + {Script: `a = []; a += true`, RunOutput: []interface{}{true}, Output: map[string]interface{}{"a": []interface{}{true}}}, + {Script: `a = []; a += 1`, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `a = []; a += 1.1`, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": []interface{}{float64(1.1)}}}, + {Script: `a = []; a += "a"`, RunOutput: []interface{}{"a"}, Output: map[string]interface{}{"a": []interface{}{"a"}}}, + + {Script: `a = []; a += []`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{}}}, + {Script: `a = []; a += [nil]`, RunOutput: []interface{}{nil}, Output: map[string]interface{}{"a": []interface{}{nil}}}, + {Script: `a = []; a += [true]`, RunOutput: []interface{}{true}, Output: map[string]interface{}{"a": []interface{}{true}}}, + {Script: `a = []; a += [1]`, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `a = []; a += [1.1]`, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": []interface{}{float64(1.1)}}}, + {Script: `a = []; a += ["a"]`, RunOutput: []interface{}{"a"}, Output: map[string]interface{}{"a": []interface{}{"a"}}}, + + {Script: `a = [0]; a[0]++`, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `a = [[0]]; a[0][0]++`, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1)}}}}, + + {Script: `a = [2]; a[0]--`, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `a = [[2]]; a[0][0]--`, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1)}}}}, + + {Script: `a`, Input: map[string]interface{}{"a": []bool{}}, RunOutput: []bool{}, Output: map[string]interface{}{"a": []bool{}}}, + {Script: `a`, Input: map[string]interface{}{"a": []int32{}}, RunOutput: []int32{}, Output: map[string]interface{}{"a": []int32{}}}, + {Script: `a`, Input: map[string]interface{}{"a": []int64{}}, RunOutput: []int64{}, Output: map[string]interface{}{"a": []int64{}}}, + {Script: `a`, Input: map[string]interface{}{"a": []float32{}}, RunOutput: []float32{}, Output: map[string]interface{}{"a": []float32{}}}, + {Script: `a`, Input: map[string]interface{}{"a": []float64{}}, RunOutput: []float64{}, Output: map[string]interface{}{"a": []float64{}}}, + {Script: `a`, Input: map[string]interface{}{"a": []string{}}, RunOutput: []string{}, Output: map[string]interface{}{"a": []string{}}}, + + {Script: `a`, Input: map[string]interface{}{"a": []bool{true, false}}, RunOutput: []bool{true, false}, Output: map[string]interface{}{"a": []bool{true, false}}}, + {Script: `a`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: []int32{1, 2}, Output: map[string]interface{}{"a": []int32{1, 2}}}, + {Script: `a`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: []int64{1, 2}, Output: map[string]interface{}{"a": []int64{1, 2}}}, + {Script: `a`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: []float32{1.1, 2.2}, Output: map[string]interface{}{"a": []float32{1.1, 2.2}}}, + {Script: `a`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: []float64{1.1, 2.2}, Output: map[string]interface{}{"a": []float64{1.1, 2.2}}}, + {Script: `a`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunOutput: []string{"a", "b"}, Output: map[string]interface{}{"a": []string{"a", "b"}}}, + + {Script: `a += true`, Input: map[string]interface{}{"a": []bool{}}, RunOutput: []bool{true}, Output: map[string]interface{}{"a": []bool{true}}}, + {Script: `a += 1`, Input: map[string]interface{}{"a": []int32{}}, RunOutput: []int32{1}, Output: map[string]interface{}{"a": []int32{1}}}, + {Script: `a += 1.1`, Input: map[string]interface{}{"a": []int32{}}, RunOutput: []int32{1}, Output: map[string]interface{}{"a": []int32{1}}}, + {Script: `a += 1`, Input: map[string]interface{}{"a": []int64{}}, RunOutput: []int64{1}, Output: map[string]interface{}{"a": []int64{1}}}, + {Script: `a += 1.1`, Input: map[string]interface{}{"a": []int64{}}, RunOutput: []int64{1}, Output: map[string]interface{}{"a": []int64{1}}}, + {Script: `a += 1`, Input: map[string]interface{}{"a": []float32{}}, RunOutput: []float32{1}, Output: map[string]interface{}{"a": []float32{1}}}, + {Script: `a += 1.1`, Input: map[string]interface{}{"a": []float32{}}, RunOutput: []float32{1.1}, Output: map[string]interface{}{"a": []float32{1.1}}}, + {Script: `a += 1`, Input: map[string]interface{}{"a": []float64{}}, RunOutput: []float64{1}, Output: map[string]interface{}{"a": []float64{1}}}, + {Script: `a += 1.1`, Input: map[string]interface{}{"a": []float64{}}, RunOutput: []float64{1.1}, Output: map[string]interface{}{"a": []float64{1.1}}}, + {Script: `a += "a"`, Input: map[string]interface{}{"a": []string{}}, RunOutput: []string{"a"}, Output: map[string]interface{}{"a": []string{"a"}}}, + {Script: `a += 97`, Input: map[string]interface{}{"a": []string{}}, RunOutput: []string{"a"}, Output: map[string]interface{}{"a": []string{"a"}}}, + + {Script: `a[0]`, Input: map[string]interface{}{"a": []bool{true, false}}, RunOutput: true, Output: map[string]interface{}{"a": []bool{true, false}}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: int32(1), Output: map[string]interface{}{"a": []int32{1, 2}}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: int64(1), Output: map[string]interface{}{"a": []int64{1, 2}}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": []float32{1.1, 2.2}}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": []float64{1.1, 2.2}}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunOutput: "a", Output: map[string]interface{}{"a": []string{"a", "b"}}}, + + {Script: `a[1]`, Input: map[string]interface{}{"a": []bool{true, false}}, RunOutput: false, Output: map[string]interface{}{"a": []bool{true, false}}}, + {Script: `a[1]`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: int32(2), Output: map[string]interface{}{"a": []int32{1, 2}}}, + {Script: `a[1]`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: int64(2), Output: map[string]interface{}{"a": []int64{1, 2}}}, + {Script: `a[1]`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: float32(2.2), Output: map[string]interface{}{"a": []float32{1.1, 2.2}}}, + {Script: `a[1]`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": []float64{1.1, 2.2}}}, + {Script: `a[1]`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunOutput: "b", Output: map[string]interface{}{"a": []string{"a", "b"}}}, + + {Script: `a[0]`, Input: map[string]interface{}{"a": []bool{}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []bool{}}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": []int32{}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []int32{}}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": []int64{}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []int64{}}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": []float32{}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []float32{}}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": []float64{}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []float64{}}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": []string{}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []string{}}}, + + {Script: `a[1] = true`, Input: map[string]interface{}{"a": []bool{true, false}}, RunOutput: true, Output: map[string]interface{}{"a": []bool{true, true}}}, + {Script: `a[1] = 3`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: int64(3), Output: map[string]interface{}{"a": []int32{1, 3}}}, + {Script: `a[1] = 3`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: int64(3), Output: map[string]interface{}{"a": []int64{1, 3}}}, + {Script: `a[1] = 3.3`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: float64(3.3), Output: map[string]interface{}{"a": []float32{1.1, 3.3}}}, + {Script: `a[1] = 3.3`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: float64(3.3), Output: map[string]interface{}{"a": []float64{1.1, 3.3}}}, + {Script: `a[1] = "c"`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunOutput: "c", Output: map[string]interface{}{"a": []string{"a", "c"}}}, + + {Script: `a = []; a[0]`, RunError: fmt.Errorf("index out of range")}, + {Script: `a = []; a[-1]`, RunError: fmt.Errorf("index out of range")}, + {Script: `a = []; a[1] = 1`, RunError: fmt.Errorf("index out of range")}, + {Script: `a = []; a[-1] = 1`, RunError: fmt.Errorf("index out of range")}, + + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": nil}, RunError: fmt.Errorf("index must be a number"), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": true}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": int(1)}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": int32(1)}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": float32(1.1)}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": "1"}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": "a"}, RunError: fmt.Errorf("index must be a number"), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": testVarBoolP}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": testVarInt32P}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": testVarInt64P}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": testVarFloat32P}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": testVarFloat64P}, RunOutput: int64(2), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a]`, Input: map[string]interface{}{"a": testVarStringP}, RunError: fmt.Errorf("index must be a number"), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + + {Script: `b = [1, 2]; b[a] = 3`, Input: map[string]interface{}{"a": nil}, RunError: fmt.Errorf("index must be a number"), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b[a] = 3`, Input: map[string]interface{}{"a": true}, RunOutput: int64(3), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(3)}}}, + {Script: `b = [1, 2]; b[a] = 3`, Input: map[string]interface{}{"a": int(1)}, RunOutput: int64(3), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(3)}}}, + {Script: `b = [1, 2]; b[a] = 3`, Input: map[string]interface{}{"a": int32(1)}, RunOutput: int64(3), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(3)}}}, + {Script: `b = [1, 2]; b[a] = 3`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: int64(3), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(3)}}}, + {Script: `b = [1, 2]; b[a] = 3`, Input: map[string]interface{}{"a": float32(1.1)}, RunOutput: int64(3), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(3)}}}, + {Script: `b = [1, 2]; b[a] = 3`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: int64(3), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(3)}}}, + {Script: `b = [1, 2]; b[a] = 3`, Input: map[string]interface{}{"a": "1"}, RunOutput: int64(3), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(3)}}}, + {Script: `b = [1, 2]; b[a] = 3`, Input: map[string]interface{}{"a": "a"}, RunError: fmt.Errorf("index must be a number"), Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2)}}}, + + {Script: `a`, Input: map[string]interface{}{"a": testSliceEmpty}, RunOutput: testSliceEmpty, Output: map[string]interface{}{"a": testSliceEmpty}}, + {Script: `a += []`, Input: map[string]interface{}{"a": testSliceEmpty}, RunOutput: []interface{}(nil), Output: map[string]interface{}{"a": testSliceEmpty}}, + + {Script: `a`, Input: map[string]interface{}{"a": testSlice}, RunOutput: testSlice, Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: nil, Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[0] = 1`, Input: map[string]interface{}{"a": testSlice}, RunOutput: int64(1), Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: int64(1), Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[0] = nil`, Input: map[string]interface{}{"a": testSlice}, RunOutput: nil, Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: nil, Output: map[string]interface{}{"a": testSlice}}, + + {Script: `a[1]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: true, Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[1] = false`, Input: map[string]interface{}{"a": testSlice}, RunOutput: false, Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[1]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: false, Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[1] = true`, Input: map[string]interface{}{"a": testSlice}, RunOutput: true, Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[1]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: true, Output: map[string]interface{}{"a": testSlice}}, + + {Script: `a[2]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: int64(1), Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[2] = 2`, Input: map[string]interface{}{"a": testSlice}, RunOutput: int64(2), Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[2]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: int64(2), Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[2] = 1`, Input: map[string]interface{}{"a": testSlice}, RunOutput: int64(1), Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[2]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: int64(1), Output: map[string]interface{}{"a": testSlice}}, + + {Script: `a[3]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[3] = 2.2`, Input: map[string]interface{}{"a": testSlice}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[3]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[3] = 1.1`, Input: map[string]interface{}{"a": testSlice}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[3]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": testSlice}}, + + {Script: `a[4]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: "a", Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[4] = "x"`, Input: map[string]interface{}{"a": testSlice}, RunOutput: "x", Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[4]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: "x", Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[4] = "a"`, Input: map[string]interface{}{"a": testSlice}, RunOutput: "a", Output: map[string]interface{}{"a": testSlice}}, + {Script: `a[4]`, Input: map[string]interface{}{"a": testSlice}, RunOutput: "a", Output: map[string]interface{}{"a": testSlice}}, + + {Script: `a[0][0] = true`, Input: map[string]interface{}{"a": []interface{}{[]string{"a"}}}, RunError: fmt.Errorf("type bool cannot be assigned to type string for slice index"), Output: map[string]interface{}{"a": []interface{}{[]string{"a"}}}}, + {Script: `a[0][0] = "a"`, Input: map[string]interface{}{"a": []interface{}{[]bool{true}}}, RunError: fmt.Errorf("type string cannot be assigned to type bool for slice index"), Output: map[string]interface{}{"a": []interface{}{[]bool{true}}}}, + + {Script: `a[0][0] = b[0][0]`, Input: map[string]interface{}{"a": []interface{}{[]bool{true}}, "b": []interface{}{[]string{"b"}}}, RunError: fmt.Errorf("type string cannot be assigned to type bool for slice index"), Output: map[string]interface{}{"a": []interface{}{[]bool{true}}}}, + {Script: `b[0][0] = a[0][0]`, Input: map[string]interface{}{"a": []interface{}{[]bool{true}}, "b": []interface{}{[]string{"b"}}}, RunError: fmt.Errorf("type bool cannot be assigned to type string for slice index"), Output: map[string]interface{}{"a": []interface{}{[]bool{true}}}}, + + {Script: `a = make([][]bool); a[0] = make([]bool); a[0] = [true, 1]`, RunError: fmt.Errorf("type []interface {} cannot be assigned to type []bool for slice index"), Output: map[string]interface{}{"a": [][]bool{{}}}}, + {Script: `a = make([][]bool); a[0] = make([]bool); a[0] = [true, false]`, RunOutput: []interface{}{true, false}, Output: map[string]interface{}{"a": [][]bool{{true, false}}}}, + + {Script: `a = make([][][]bool); a[0] = make([][]bool); a[0][0] = make([]bool); a[0] = [[true, 1]]`, RunError: fmt.Errorf("type []interface {} cannot be assigned to type [][]bool for slice index"), Output: map[string]interface{}{"a": [][][]bool{{{}}}}}, + {Script: `a = make([][][]bool); a[0] = make([][]bool); a[0][0] = make([]bool); a[0] = [[true, false]]`, RunOutput: []interface{}{[]interface{}{true, false}}, Output: map[string]interface{}{"a": [][][]bool{{{true, false}}}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestSlicesAutoAppend(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a[2]`, Input: map[string]interface{}{"a": []bool{true, false}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []bool{true, false}}}, + {Script: `a[2]`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []int32{1, 2}}}, + {Script: `a[2]`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []int64{1, 2}}}, + {Script: `a[2]`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []float32{1.1, 2.2}}}, + {Script: `a[2]`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []float64{1.1, 2.2}}}, + {Script: `a[2]`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []string{"a", "b"}}}, + + {Script: `a[2] = true`, Input: map[string]interface{}{"a": []bool{true, false}}, RunOutput: true, Output: map[string]interface{}{"a": []bool{true, false, true}}}, + {Script: `a[2] = 3`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: int64(3), Output: map[string]interface{}{"a": []int32{1, 2, 3}}}, + {Script: `a[2] = 3`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: int64(3), Output: map[string]interface{}{"a": []int64{1, 2, 3}}}, + {Script: `a[2] = 3.3`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: float64(3.3), Output: map[string]interface{}{"a": []float32{1.1, 2.2, 3.3}}}, + {Script: `a[2] = 3.3`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: float64(3.3), Output: map[string]interface{}{"a": []float64{1.1, 2.2, 3.3}}}, + {Script: `a[2] = "c"`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunOutput: "c", Output: map[string]interface{}{"a": []string{"a", "b", "c"}}}, + + {Script: `a[2] = 3.3`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: float64(3.3), Output: map[string]interface{}{"a": []int32{1, 2, 3}}}, + {Script: `a[2] = 3.3`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: float64(3.3), Output: map[string]interface{}{"a": []int64{1, 2, 3}}}, + + {Script: `a[3] = true`, Input: map[string]interface{}{"a": []bool{true, false}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []bool{true, false}}}, + {Script: `a[3] = 4`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []int32{1, 2}}}, + {Script: `a[3] = 4`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []int64{1, 2}}}, + {Script: `a[3] = 4.4`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []float32{1.1, 2.2}}}, + {Script: `a[3] = 4.4`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []float64{1.1, 2.2}}}, + {Script: `a[3] = "d"`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []string{"a", "b"}}}, + + {Script: `a[2] = nil`, Input: map[string]interface{}{"a": []bool{true, false}}, Output: map[string]interface{}{"a": []bool{true, false, false}}}, + {Script: `a[2] = nil`, Input: map[string]interface{}{"a": []int32{1, 2}}, Output: map[string]interface{}{"a": []int32{1, 2, 0}}}, + {Script: `a[2] = nil`, Input: map[string]interface{}{"a": []int64{1, 2}}, Output: map[string]interface{}{"a": []int64{1, 2, 0}}}, + {Script: `a[2] = nil`, Input: map[string]interface{}{"a": []float32{1.5, 2.5}}, Output: map[string]interface{}{"a": []float32{1.5, 2.5, 0}}}, + {Script: `a[2] = nil`, Input: map[string]interface{}{"a": []float64{1.5, 2.5}}, Output: map[string]interface{}{"a": []float64{1.5, 2.5, 0}}}, + {Script: `a[2] = nil`, Input: map[string]interface{}{"a": []string{"a", "b"}}, Output: map[string]interface{}{"a": []string{"a", "b", ""}}}, + + {Script: `a[2] = "a"`, Input: map[string]interface{}{"a": []int16{1, 2}}, RunError: fmt.Errorf("type string cannot be assigned to type int16 for slice index"), Output: map[string]interface{}{"a": []int16{1, 2}}}, + {Script: `a[2] = true`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunError: fmt.Errorf("type bool cannot be assigned to type int64 for slice index"), Output: map[string]interface{}{"a": []int64{1, 2}}}, + {Script: `a[2] = "a"`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunError: fmt.Errorf("type string cannot be assigned to type int64 for slice index"), Output: map[string]interface{}{"a": []int64{1, 2}}}, + {Script: `a[2] = true`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunError: fmt.Errorf("type bool cannot be assigned to type float32 for slice index"), Output: map[string]interface{}{"a": []float32{1.1, 2.2}}}, + {Script: `a[2] = "a"`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunError: fmt.Errorf("type string cannot be assigned to type float64 for slice index"), Output: map[string]interface{}{"a": []float64{1.1, 2.2}}}, + {Script: `a[2] = true`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunError: fmt.Errorf("type bool cannot be assigned to type string for slice index"), Output: map[string]interface{}{"a": []string{"a", "b"}}}, + {Script: `a[2] = 1.1`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunError: fmt.Errorf("type float64 cannot be assigned to type string for slice index"), Output: map[string]interface{}{"a": []string{"a", "b"}}}, + + {Script: `a`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: [][]interface{}{}, Output: map[string]interface{}{"a": [][]interface{}{}}}, + {Script: `a[0] = []`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": [][]interface{}{{}}}}, + {Script: `a[0] = [nil]`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: []interface{}{nil}, Output: map[string]interface{}{"a": [][]interface{}{{nil}}}}, + {Script: `a[0] = [true]`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: []interface{}{true}, Output: map[string]interface{}{"a": [][]interface{}{{true}}}}, + {Script: `a[0] = [1]`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": [][]interface{}{{int64(1)}}}}, + {Script: `a[0] = [1.1]`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": [][]interface{}{{float64(1.1)}}}}, + {Script: `a[0] = ["b"]`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: []interface{}{"b"}, Output: map[string]interface{}{"a": [][]interface{}{{"b"}}}}, + + {Script: `a[0] = [nil]; a[0][0]`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: nil, Output: map[string]interface{}{"a": [][]interface{}{{nil}}}}, + {Script: `a[0] = [true]; a[0][0]`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: true, Output: map[string]interface{}{"a": [][]interface{}{{true}}}}, + {Script: `a[0] = [1]; a[0][0]`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{int64(1)}}}}, + {Script: `a[0] = [1.1]; a[0][0]`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": [][]interface{}{{float64(1.1)}}}}, + {Script: `a[0] = ["b"]; a[0][0]`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: "b", Output: map[string]interface{}{"a": [][]interface{}{{"b"}}}}, + + {Script: `a = make([]bool); a[0] = 1`, RunError: fmt.Errorf("type int64 cannot be assigned to type bool for slice index"), Output: map[string]interface{}{"a": []bool{}}}, + {Script: `a = make([]bool); a[0] = true; a[1] = false`, RunOutput: false, Output: map[string]interface{}{"a": []bool{true, false}}}, + + {Script: `a = make([][]bool); a[0] = [true, 1]`, RunError: fmt.Errorf("type []interface {} cannot be assigned to type []bool for slice index"), Output: map[string]interface{}{"a": [][]bool{}}}, + {Script: `a = make([][]bool); a[0] = [true, false]`, RunOutput: []interface{}{true, false}, Output: map[string]interface{}{"a": [][]bool{{true, false}}}}, + + {Script: `a = make([][][]bool); a[0] = [[true, 1]]`, RunError: fmt.Errorf("type []interface {} cannot be assigned to type [][]bool for slice index"), Output: map[string]interface{}{"a": [][][]bool{}}}, + {Script: `a = make([][][]bool); a[0] = [[true, false]]`, RunOutput: []interface{}{[]interface{}{true, false}}, Output: map[string]interface{}{"a": [][][]bool{{{true, false}}}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestMakeSlices(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `make([]foo)`, RunError: fmt.Errorf("undefined type 'foo'")}, + + {Script: `make([]nilT)`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `make([][]nilT)`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `make([][][]nilT)`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + + {Script: `make([]bool, 1++)`, RunError: fmt.Errorf("invalid operation")}, + {Script: `make([]bool, 0, 1++)`, RunError: fmt.Errorf("invalid operation")}, + + // spaces and/or newlines + {Script: `[]`, RunOutput: []interface{}{}}, + {Script: `[ ]`, RunOutput: []interface{}{}}, + {Script: `[ +]`, RunOutput: []interface{}{}}, + {Script: `[ + ]`, RunOutput: []interface{}{}}, + + {Script: `make(slice2x)`, Types: map[string]interface{}{"slice2x": [][]interface{}{}}, RunOutput: [][]interface{}{}}, + + {Script: `make([]bool)`, RunOutput: []bool{}}, + {Script: `make([]int32)`, RunOutput: []int32{}}, + {Script: `make([]int64)`, RunOutput: []int64{}}, + {Script: `make([]float32)`, RunOutput: []float32{}}, + {Script: `make([]float64)`, RunOutput: []float64{}}, + {Script: `make([]string)`, RunOutput: []string{}}, + + {Script: `make([]bool, 0)`, RunOutput: []bool{}}, + {Script: `make([]int32, 0)`, RunOutput: []int32{}}, + {Script: `make([]int64, 0)`, RunOutput: []int64{}}, + {Script: `make([]float32, 0)`, RunOutput: []float32{}}, + {Script: `make([]float64, 0)`, RunOutput: []float64{}}, + {Script: `make([]string, 0)`, RunOutput: []string{}}, + + {Script: `make([]bool, 2)`, RunOutput: []bool{false, false}}, + {Script: `make([]int32, 2)`, RunOutput: []int32{int32(0), int32(0)}}, + {Script: `make([]int64, 2)`, RunOutput: []int64{int64(0), int64(0)}}, + {Script: `make([]float32, 2)`, RunOutput: []float32{float32(0), float32(0)}}, + {Script: `make([]float64, 2)`, RunOutput: []float64{float64(0), float64(0)}}, + {Script: `make([]string, 2)`, RunOutput: []string{"", ""}}, + + {Script: `make([]bool, 0, 2)`, RunOutput: []bool{}}, + {Script: `make([]int32, 0, 2)`, RunOutput: []int32{}}, + {Script: `make([]int64, 0, 2)`, RunOutput: []int64{}}, + {Script: `make([]float32, 0, 2)`, RunOutput: []float32{}}, + {Script: `make([]float64, 0, 2)`, RunOutput: []float64{}}, + {Script: `make([]string, 0, 2)`, RunOutput: []string{}}, + + {Script: `make([]bool, 2, 2)`, RunOutput: []bool{false, false}}, + {Script: `make([]int32, 2, 2)`, RunOutput: []int32{int32(0), int32(0)}}, + {Script: `make([]int64, 2, 2)`, RunOutput: []int64{int64(0), int64(0)}}, + {Script: `make([]float32, 2, 2)`, RunOutput: []float32{float32(0), float32(0)}}, + {Script: `make([]float64, 2, 2)`, RunOutput: []float64{float64(0), float64(0)}}, + {Script: `make([]string, 2, 2)`, RunOutput: []string{"", ""}}, + + {Script: `a = make([]bool, 0); a += true; a += false`, RunOutput: []bool{true, false}, Output: map[string]interface{}{"a": []bool{true, false}}}, + {Script: `a = make([]int32, 0); a += 1; a += 2`, RunOutput: []int32{int32(1), int32(2)}, Output: map[string]interface{}{"a": []int32{int32(1), int32(2)}}}, + {Script: `a = make([]int64, 0); a += 1; a += 2`, RunOutput: []int64{int64(1), int64(2)}, Output: map[string]interface{}{"a": []int64{int64(1), int64(2)}}}, + {Script: `a = make([]float32, 0); a += 1.1; a += 2.2`, RunOutput: []float32{float32(1.1), float32(2.2)}, Output: map[string]interface{}{"a": []float32{float32(1.1), float32(2.2)}}}, + {Script: `a = make([]float64, 0); a += 1.1; a += 2.2`, RunOutput: []float64{float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []float64{float64(1.1), float64(2.2)}}}, + {Script: `a = make([]string, 0); a += "a"; a += "b"`, RunOutput: []string{"a", "b"}, Output: map[string]interface{}{"a": []string{"a", "b"}}}, + + {Script: `a = make([]bool, 2); a[0] = true; a[1] = false`, RunOutput: false, Output: map[string]interface{}{"a": []bool{true, false}}}, + {Script: `a = make([]int32, 2); a[0] = 1; a[1] = 2`, RunOutput: int64(2), Output: map[string]interface{}{"a": []int32{int32(1), int32(2)}}}, + {Script: `a = make([]int64, 2); a[0] = 1; a[1] = 2`, RunOutput: int64(2), Output: map[string]interface{}{"a": []int64{int64(1), int64(2)}}}, + {Script: `a = make([]float32, 2); a[0] = 1.1; a[1] = 2.2`, RunOutput: float64(2.2), Output: map[string]interface{}{"a": []float32{float32(1.1), float32(2.2)}}}, + {Script: `a = make([]float64, 2); a[0] = 1.1; a[1] = 2.2`, RunOutput: float64(2.2), Output: map[string]interface{}{"a": []float64{float64(1.1), float64(2.2)}}}, + {Script: `a = make([]string, 2); a[0] = "a"; a[1] = "b"`, RunOutput: "b", Output: map[string]interface{}{"a": []string{"a", "b"}}}, + + {Script: `make([]boolA)`, Types: map[string]interface{}{"boolA": []bool{}}, RunOutput: [][]bool{}}, + {Script: `make([]int32A)`, Types: map[string]interface{}{"int32A": []int32{}}, RunOutput: [][]int32{}}, + {Script: `make([]int64A)`, Types: map[string]interface{}{"int64A": []int64{}}, RunOutput: [][]int64{}}, + {Script: `make([]float32A)`, Types: map[string]interface{}{"float32A": []float32{}}, RunOutput: [][]float32{}}, + {Script: `make([]float64A)`, Types: map[string]interface{}{"float64A": []float64{}}, RunOutput: [][]float64{}}, + {Script: `make([]stringA)`, Types: map[string]interface{}{"stringA": []string{}}, RunOutput: [][]string{}}, + + {Script: `make([]slice)`, Types: map[string]interface{}{"slice": []interface{}{}}, RunOutput: [][]interface{}{}}, + {Script: `a = make([]slice)`, Types: map[string]interface{}{"slice": []interface{}{}}, RunOutput: [][]interface{}{}, Output: map[string]interface{}{"a": [][]interface{}{}}}, + + {Script: `make([][]bool)`, RunOutput: [][]bool{}}, + {Script: `make([][]int32)`, RunOutput: [][]int32{}}, + {Script: `make([][]int64)`, RunOutput: [][]int64{}}, + {Script: `make([][]float32)`, RunOutput: [][]float32{}}, + {Script: `make([][]float64)`, RunOutput: [][]float64{}}, + {Script: `make([][]string)`, RunOutput: [][]string{}}, + + {Script: `make([][]bool)`, RunOutput: [][]bool{}}, + {Script: `make([][]int32)`, RunOutput: [][]int32{}}, + {Script: `make([][]int64)`, RunOutput: [][]int64{}}, + {Script: `make([][]float32)`, RunOutput: [][]float32{}}, + {Script: `make([][]float64)`, RunOutput: [][]float64{}}, + {Script: `make([][]string)`, RunOutput: [][]string{}}, + + {Script: `make([][][]bool)`, RunOutput: [][][]bool{}}, + {Script: `make([][][]int32)`, RunOutput: [][][]int32{}}, + {Script: `make([][][]int64)`, RunOutput: [][][]int64{}}, + {Script: `make([][][]float32)`, RunOutput: [][][]float32{}}, + {Script: `make([][][]float64)`, RunOutput: [][][]float64{}}, + {Script: `make([][][]string)`, RunOutput: [][][]string{}}, + + // slice type errors + {Script: `[]nilT{"a"}`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `[]int64{1++}`, RunError: fmt.Errorf("invalid operation")}, + {Script: `[]int64{"a"}`, RunError: fmt.Errorf("cannot use type string as type int64 as slice value")}, + + // slice type + {Script: `[]interface{nil}`, RunOutput: []interface{}{nil}}, + {Script: `[]bool{true, false}`, RunOutput: []bool{true, false}}, + {Script: `[]int32{1}`, RunOutput: []int32{int32(1)}}, + {Script: `[]int64{2}`, RunOutput: []int64{int64(2)}}, + {Script: `[]float32{3.5}`, RunOutput: []float32{float32(3.5)}}, + {Script: `[]float64{4.5}`, RunOutput: []float64{float64(4.5)}}, + {Script: `[]string{"a"}`, RunOutput: []string{"a"}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestSliceOfSlices(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a = [1, 2]; a[:]`, ParseError: fmt.Errorf("syntax error")}, + {Script: `(1++)[0:0]`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a = [1, 2]; a[1++:0]`, RunError: fmt.Errorf("invalid operation"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2)}}}, + {Script: `a = [1, 2]; a[0:1++]`, RunError: fmt.Errorf("invalid operation"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2)}}}, + {Script: `a = [1, 2]; a[:0]++`, RunError: fmt.Errorf("slice cannot be assigned"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2)}}}, + {Script: `a = [1, 2]; a[:0]--`, RunError: fmt.Errorf("slice cannot be assigned"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2)}}}, + + {Script: `a = [1, 2, 3]; a[nil:2]`, RunError: fmt.Errorf("index must be a number"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:nil]`, RunError: fmt.Errorf("index must be a number"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1, 2, 3]; a[-1:0]`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[0:0]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[0:1]`, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[0:2]`, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[0:3]`, RunOutput: []interface{}{int64(1), int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[0:4]`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1, 2, 3]; a[1:0]`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:1]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:2]`, RunOutput: []interface{}{int64(2)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:3]`, RunOutput: []interface{}{int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:4]`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1, 2, 3]; a[2:1]`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[2:2]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[2:3]`, RunOutput: []interface{}{int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[2:4]`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1, 2, 3]; a[3:2]`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[3:3]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[3:4]`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1, 2, 3]; a[4:4]`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1, 2, 3]; a[-1:]`, RunError: fmt.Errorf("index out of range"), RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[0:]`, RunOutput: []interface{}{int64(1), int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:]`, RunOutput: []interface{}{int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[2:]`, RunOutput: []interface{}{int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[3:]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[4:]`, RunError: fmt.Errorf("index out of range"), RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1, 2, 3]; a[:-1]`, RunError: fmt.Errorf("index out of range"), RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[:0]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[:1]`, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[:2]`, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[:3]`, RunOutput: []interface{}{int64(1), int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[:4]`, RunError: fmt.Errorf("index out of range"), RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `b[1:2] = 4`, RunError: fmt.Errorf("undefined symbol 'b'")}, + {Script: `a = [1, 2, 3]; a[1++:2] = 4`, RunError: fmt.Errorf("invalid operation"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:2++] = 4`, RunError: fmt.Errorf("invalid operation"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[nil:2] = 4`, RunError: fmt.Errorf("index must be a number"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:nil] = 4`, RunError: fmt.Errorf("index must be a number"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1, 2, 3]; a[0:0] = 4`, RunError: fmt.Errorf("slice cannot be assigned"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[0:1] = 4`, RunError: fmt.Errorf("slice cannot be assigned"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[0:4] = 4`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:0] = 4`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:4] = 4`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1, 2, 3]; a[-1:] = 4`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[0:] = 4`, RunError: fmt.Errorf("slice cannot be assigned"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[1:] = 4`, RunError: fmt.Errorf("slice cannot be assigned"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[4:] = 4`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1, 2, 3]; a[:-1] = 4`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[:0] = 4`, RunError: fmt.Errorf("slice cannot be assigned"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[:1] = 4`, RunError: fmt.Errorf("slice cannot be assigned"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = [1, 2, 3]; a[:4] = 4`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + // slice assigned elem + {Script: `a[0][0:0] = 4`, Input: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}}}, RunError: fmt.Errorf("slice cannot be assigned"), Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}}}}, + + {Script: `a = [{"b": "b"}, {"c": "c"}, {"d": "d"}]; a[0:2].a`, RunError: fmt.Errorf("type slice does not support member operation"), Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": "b"}, map[interface{}]interface{}{"c": "c"}, map[interface{}]interface{}{"d": "d"}}}}, + + {Script: `a = [{"b": "b"}, {"c": "c"}, {"d": "d"}]; a[0:2]`, RunOutput: []interface{}{map[interface{}]interface{}{"b": "b"}, map[interface{}]interface{}{"c": "c"}}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": "b"}, map[interface{}]interface{}{"c": "c"}, map[interface{}]interface{}{"d": "d"}}}}, + {Script: `a = [{"b": "b"}, {"c": "c"}, {"d": "d"}]; a[0:2][0].b`, RunOutput: "b", Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": "b"}, map[interface{}]interface{}{"c": "c"}, map[interface{}]interface{}{"d": "d"}}}}, + + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][0:3]`, RunOutput: []interface{}{int64(1), int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][1:3]`, RunOutput: []interface{}{int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][2:3]`, RunOutput: []interface{}{int64(3)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][3:3]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][0:]`, RunOutput: []interface{}{int64(1), int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][1:]`, RunOutput: []interface{}{int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][2:]`, RunOutput: []interface{}{int64(3)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][3:]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][0:0]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][0:1]`, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][0:2]`, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][0:3]`, RunOutput: []interface{}{int64(1), int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][:0]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][:1]`, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][:2]`, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[0][:3]`, RunOutput: []interface{}{int64(1), int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][0:3]`, RunOutput: []interface{}{int64(4), int64(5), int64(6)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][1:3]`, RunOutput: []interface{}{int64(5), int64(6)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][2:3]`, RunOutput: []interface{}{int64(6)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][3:3]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][0:]`, RunOutput: []interface{}{int64(4), int64(5), int64(6)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][1:]`, RunOutput: []interface{}{int64(5), int64(6)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][2:]`, RunOutput: []interface{}{int64(6)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][3:]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][0:0]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][0:1]`, RunOutput: []interface{}{int64(4)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][0:2]`, RunOutput: []interface{}{int64(4), int64(5)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][0:3]`, RunOutput: []interface{}{int64(4), int64(5), int64(6)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][:0]`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][:1]`, RunOutput: []interface{}{int64(4)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][:2]`, RunOutput: []interface{}{int64(4), int64(5)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + {Script: `a = [[1, 2, 3], [4, 5, 6]]; a[1][:3]`, RunOutput: []interface{}{int64(4), int64(5), int64(6)}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2), int64(3)}, []interface{}{int64(4), int64(5), int64(6)}}}}, + + {Script: `a = [["123"], ["456"]]; a[0][0][0:3]`, RunOutput: "123", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][1:3]`, RunOutput: "23", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][2:3]`, RunOutput: "3", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][3:3]`, RunOutput: "", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + + {Script: `a = [["123"], ["456"]]; a[0][0][0:]`, RunOutput: "123", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][1:]`, RunOutput: "23", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][2:]`, RunOutput: "3", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][3:]`, RunOutput: "", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + + {Script: `a = [["123"], ["456"]]; a[0][0][0:0]`, RunOutput: "", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][0:1]`, RunOutput: "1", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][0:2]`, RunOutput: "12", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][0:3]`, RunOutput: "123", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + + {Script: `a = [["123"], ["456"]]; a[0][0][:0]`, RunOutput: "", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][:1]`, RunOutput: "1", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][:2]`, RunOutput: "12", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[0][0][:3]`, RunOutput: "123", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + + {Script: `a = [["123"], ["456"]]; a[1][0][0:3]`, RunOutput: "456", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][1:3]`, RunOutput: "56", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][2:3]`, RunOutput: "6", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][3:3]`, RunOutput: "", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + + {Script: `a = [["123"], ["456"]]; a[1][0][0:]`, RunOutput: "456", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][1:]`, RunOutput: "56", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][2:]`, RunOutput: "6", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][3:]`, RunOutput: "", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + + {Script: `a = [["123"], ["456"]]; a[1][0][0:0]`, RunOutput: "", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][0:1]`, RunOutput: "4", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][0:2]`, RunOutput: "45", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][0:3]`, RunOutput: "456", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + + {Script: `a = [["123"], ["456"]]; a[1][0][:0]`, RunOutput: "", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][:1]`, RunOutput: "4", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][:2]`, RunOutput: "45", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + {Script: `a = [["123"], ["456"]]; a[1][0][:3]`, RunOutput: "456", Output: map[string]interface{}{"a": []interface{}{[]interface{}{"123"}, []interface{}{"456"}}}}, + + // cap errors + {Script: `a = "a"; a[0:1:1]`, RunError: fmt.Errorf("type string does not support cap")}, + {Script: `a = [1,2,3,4]; a[1:3:-1]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[1:3:0]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[1:3:2]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[1:3:5]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[:2:-1]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[:2:0]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[:2:1]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[:2:5]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[1:3:"a"]`, RunError: fmt.Errorf("cap must be a number")}, + {Script: `a = [1,2,3,4]; a[1:3:1++]`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a = "a"; b = a[0:1:1]`, RunError: fmt.Errorf("type string does not support cap")}, + {Script: `a = [1,2,3,4]; b = a[1:3:-1]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; b = a[1:3:0]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; b = a[1:3:2]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; b = a[1:3:5]`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; b = a[1:3:"a"]`, RunError: fmt.Errorf("cap must be a number")}, + {Script: `a = [1,2,3,4]; b = a[1:3:1++]`, RunError: fmt.Errorf("invalid operation")}, + + // cap assigned errors + {Script: `a = [1,2,3,4]; a[1:1:-1] = 3`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[1:1:0] = 3`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[1:1:5] = 3`, RunError: fmt.Errorf("cap out of range")}, + {Script: `a = [1,2,3,4]; a[1:1:"a"] = 3`, RunError: fmt.Errorf("cap must be a number")}, + {Script: `a = [1,2,3,4]; a[1:3:1++] = 3`, RunError: fmt.Errorf("invalid operation")}, + + // cap + {Script: `a = [1,2,3,4]; a[1:3:3]`, RunOutput: []interface{}{int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3), int64(4)}}}, + {Script: `a = [1,2,3,4]; a[1:3:4]`, RunOutput: []interface{}{int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3), int64(4)}}}, + {Script: `a = [1,2,3,4]; a[:2:3]`, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3), int64(4)}}}, + {Script: `a = [1,2,3,4]; a[:2:4]`, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3), int64(4)}}}, + {Script: `a = [1,2,3,4]; b = a[1:3:3]`, RunOutput: []interface{}{int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3), int64(4)}, "b": []interface{}{int64(2), int64(3)}}}, + {Script: `a = [1,2,3,4]; b = a[1:3:4]`, RunOutput: []interface{}{int64(2), int64(3)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3), int64(4)}, "b": []interface{}{int64(2), int64(3)}}}, + {Script: `a = [1,2,3,4]; b = a[:2:3]`, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3), int64(4)}, "b": []interface{}{int64(1), int64(2)}}}, + {Script: `a = [1,2,3,4]; b = a[:2:4]`, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3), int64(4)}, "b": []interface{}{int64(1), int64(2)}}}, + + // cap assigned + {Script: `a = [1,2,3,4]; a[1:1:1] = 3`, RunError: fmt.Errorf("slice cannot be assigned"), Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3), int64(4)}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestSliceAppendSlices(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a += 1`, Input: map[string]interface{}{"a": []bool{true}}, RunError: fmt.Errorf("invalid type conversion")}, + {Script: `a += 1.1`, Input: map[string]interface{}{"a": []bool{true}}, RunError: fmt.Errorf("invalid type conversion")}, + {Script: `a += "a"`, Input: map[string]interface{}{"a": []bool{true}}, RunError: fmt.Errorf("invalid type conversion")}, + {Script: `a += b`, Input: map[string]interface{}{"a": "a", "b": []bool{true}}, RunError: fmt.Errorf("invalid type conversion")}, + + {Script: `a += b`, Input: map[string]interface{}{"a": []bool{true}, "b": []string{"b"}}, RunError: fmt.Errorf("invalid type conversion")}, + {Script: `b += a`, Input: map[string]interface{}{"a": []bool{true}, "b": []string{"b"}}, RunError: fmt.Errorf("invalid type conversion")}, + + {Script: `a += nil`, Input: map[string]interface{}{"a": []bool{true}}, RunOutput: []bool{true, false}, Output: map[string]interface{}{"a": []bool{true, false}}}, + + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []bool{}}, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []bool{}, "b": []interface{}{}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []bool{true}}, RunOutput: []interface{}{true}, Output: map[string]interface{}{"a": []bool{true}, "b": []interface{}{true}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []bool{true, false}}, RunOutput: []interface{}{true, false}, Output: map[string]interface{}{"a": []bool{true, false}, "b": []interface{}{true, false}}}, + + {Script: `b = [true]; b += a`, Input: map[string]interface{}{"a": []bool{}}, RunOutput: []interface{}{true}, Output: map[string]interface{}{"a": []bool{}, "b": []interface{}{true}}}, + {Script: `b = [true]; b += a`, Input: map[string]interface{}{"a": []bool{true}}, RunOutput: []interface{}{true, true}, Output: map[string]interface{}{"a": []bool{true}, "b": []interface{}{true, true}}}, + {Script: `b = [true]; b += a`, Input: map[string]interface{}{"a": []bool{true, false}}, RunOutput: []interface{}{true, true, false}, Output: map[string]interface{}{"a": []bool{true, false}, "b": []interface{}{true, true, false}}}, + + {Script: `b = [true, false]; b += a`, Input: map[string]interface{}{"a": []bool{}}, RunOutput: []interface{}{true, false}, Output: map[string]interface{}{"a": []bool{}, "b": []interface{}{true, false}}}, + {Script: `b = [true, false]; b += a`, Input: map[string]interface{}{"a": []bool{true}}, RunOutput: []interface{}{true, false, true}, Output: map[string]interface{}{"a": []bool{true}, "b": []interface{}{true, false, true}}}, + {Script: `b = [true, false]; b += a`, Input: map[string]interface{}{"a": []bool{true, false}}, RunOutput: []interface{}{true, false, true, false}, Output: map[string]interface{}{"a": []bool{true, false}, "b": []interface{}{true, false, true, false}}}, + + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []int32{}}, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []int32{}, "b": []interface{}{}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []int32{1}}, RunOutput: []interface{}{int32(1)}, Output: map[string]interface{}{"a": []int32{1}, "b": []interface{}{int32(1)}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: []interface{}{int32(1), int32(2)}, Output: map[string]interface{}{"a": []int32{1, 2}, "b": []interface{}{int32(1), int32(2)}}}, + + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []int32{}}, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []int32{}, "b": []interface{}{int64(1)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []int32{1}}, RunOutput: []interface{}{int64(1), int32(1)}, Output: map[string]interface{}{"a": []int32{1}, "b": []interface{}{int64(1), int32(1)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: []interface{}{int64(1), int32(1), int32(2)}, Output: map[string]interface{}{"a": []int32{1, 2}, "b": []interface{}{int64(1), int32(1), int32(2)}}}, + + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []int32{}}, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []int32{}, "b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []int32{1}}, RunOutput: []interface{}{int64(1), int64(2), int32(1)}, Output: map[string]interface{}{"a": []int32{1}, "b": []interface{}{int64(1), int64(2), int32(1)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: []interface{}{int64(1), int64(2), int32(1), int32(2)}, Output: map[string]interface{}{"a": []int32{1, 2}, "b": []interface{}{int64(1), int64(2), int32(1), int32(2)}}}, + + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []int32{}}, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": []int32{}, "b": []interface{}{float64(1.1)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []int32{1}}, RunOutput: []interface{}{float64(1.1), int32(1)}, Output: map[string]interface{}{"a": []int32{1}, "b": []interface{}{float64(1.1), int32(1)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: []interface{}{float64(1.1), int32(1), int32(2)}, Output: map[string]interface{}{"a": []int32{1, 2}, "b": []interface{}{float64(1.1), int32(1), int32(2)}}}, + + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int32{}}, RunOutput: []interface{}{float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []int32{}, "b": []interface{}{float64(1.1), float64(2.2)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int32{1}}, RunOutput: []interface{}{float64(1.1), float64(2.2), int32(1)}, Output: map[string]interface{}{"a": []int32{1}, "b": []interface{}{float64(1.1), float64(2.2), int32(1)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: []interface{}{float64(1.1), float64(2.2), int32(1), int32(2)}, Output: map[string]interface{}{"a": []int32{1, 2}, "b": []interface{}{float64(1.1), float64(2.2), int32(1), int32(2)}}}, + + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int32{}}, RunOutput: []interface{}{int64(1), float64(2.2)}, Output: map[string]interface{}{"a": []int32{}, "b": []interface{}{int64(1), float64(2.2)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int32{1}}, RunOutput: []interface{}{int64(1), float64(2.2), int32(1)}, Output: map[string]interface{}{"a": []int32{1}, "b": []interface{}{int64(1), float64(2.2), int32(1)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: []interface{}{int64(1), float64(2.2), int32(1), int32(2)}, Output: map[string]interface{}{"a": []int32{1, 2}, "b": []interface{}{int64(1), float64(2.2), int32(1), int32(2)}}}, + + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []int32{}}, RunOutput: []interface{}{float64(1.1), int64(2)}, Output: map[string]interface{}{"a": []int32{}, "b": []interface{}{float64(1.1), int64(2)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []int32{1}}, RunOutput: []interface{}{float64(1.1), int64(2), int32(1)}, Output: map[string]interface{}{"a": []int32{1}, "b": []interface{}{float64(1.1), int64(2), int32(1)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []int32{1, 2}}, RunOutput: []interface{}{float64(1.1), int64(2), int32(1), int32(2)}, Output: map[string]interface{}{"a": []int32{1, 2}, "b": []interface{}{float64(1.1), int64(2), int32(1), int32(2)}}}, + + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []int64{}}, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []int64{}, "b": []interface{}{}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []int64{1}}, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []int64{1}, "b": []interface{}{int64(1)}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []int64{1, 2}, "b": []interface{}{int64(1), int64(2)}}}, + + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []int64{}}, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []int64{}, "b": []interface{}{int64(1)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []int64{1}}, RunOutput: []interface{}{int64(1), int64(1)}, Output: map[string]interface{}{"a": []int64{1}, "b": []interface{}{int64(1), int64(1)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: []interface{}{int64(1), int64(1), int64(2)}, Output: map[string]interface{}{"a": []int64{1, 2}, "b": []interface{}{int64(1), int64(1), int64(2)}}}, + + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []int64{}}, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []int64{}, "b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []int64{1}}, RunOutput: []interface{}{int64(1), int64(2), int64(1)}, Output: map[string]interface{}{"a": []int64{1}, "b": []interface{}{int64(1), int64(2), int64(1)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: []interface{}{int64(1), int64(2), int64(1), int64(2)}, Output: map[string]interface{}{"a": []int64{1, 2}, "b": []interface{}{int64(1), int64(2), int64(1), int64(2)}}}, + + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []int64{}}, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": []int64{}, "b": []interface{}{float64(1.1)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []int64{1}}, RunOutput: []interface{}{float64(1.1), int64(1)}, Output: map[string]interface{}{"a": []int64{1}, "b": []interface{}{float64(1.1), int64(1)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: []interface{}{float64(1.1), int64(1), int64(2)}, Output: map[string]interface{}{"a": []int64{1, 2}, "b": []interface{}{float64(1.1), int64(1), int64(2)}}}, + + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int64{}}, RunOutput: []interface{}{float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []int64{}, "b": []interface{}{float64(1.1), float64(2.2)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int64{1}}, RunOutput: []interface{}{float64(1.1), float64(2.2), int64(1)}, Output: map[string]interface{}{"a": []int64{1}, "b": []interface{}{float64(1.1), float64(2.2), int64(1)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: []interface{}{float64(1.1), float64(2.2), int64(1), int64(2)}, Output: map[string]interface{}{"a": []int64{1, 2}, "b": []interface{}{float64(1.1), float64(2.2), int64(1), int64(2)}}}, + + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int64{}}, RunOutput: []interface{}{int64(1), float64(2.2)}, Output: map[string]interface{}{"a": []int64{}, "b": []interface{}{int64(1), float64(2.2)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int64{1}}, RunOutput: []interface{}{int64(1), float64(2.2), int64(1)}, Output: map[string]interface{}{"a": []int64{1}, "b": []interface{}{int64(1), float64(2.2), int64(1)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: []interface{}{int64(1), float64(2.2), int64(1), int64(2)}, Output: map[string]interface{}{"a": []int64{1, 2}, "b": []interface{}{int64(1), float64(2.2), int64(1), int64(2)}}}, + + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []int64{}}, RunOutput: []interface{}{float64(1.1), int64(2)}, Output: map[string]interface{}{"a": []int64{}, "b": []interface{}{float64(1.1), int64(2)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []int64{1}}, RunOutput: []interface{}{float64(1.1), int64(2), int64(1)}, Output: map[string]interface{}{"a": []int64{1}, "b": []interface{}{float64(1.1), int64(2), int64(1)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []int64{1, 2}}, RunOutput: []interface{}{float64(1.1), int64(2), int64(1), int64(2)}, Output: map[string]interface{}{"a": []int64{1, 2}, "b": []interface{}{float64(1.1), int64(2), int64(1), int64(2)}}}, + + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []float32{}}, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []float32{}, "b": []interface{}{}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []float32{1}}, RunOutput: []interface{}{float32(1)}, Output: map[string]interface{}{"a": []float32{1}, "b": []interface{}{float32(1)}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []float32{1, 2}}, RunOutput: []interface{}{float32(1), float32(2)}, Output: map[string]interface{}{"a": []float32{1, 2}, "b": []interface{}{float32(1), float32(2)}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []float32{1.1}}, RunOutput: []interface{}{float32(1.1)}, Output: map[string]interface{}{"a": []float32{1.1}, "b": []interface{}{float32(1.1)}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: []interface{}{float32(1.1), float32(2.2)}, Output: map[string]interface{}{"a": []float32{1.1, 2.2}, "b": []interface{}{float32(1.1), float32(2.2)}}}, + + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []float32{}}, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []float32{}, "b": []interface{}{int64(1)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []float32{1}}, RunOutput: []interface{}{int64(1), float32(1)}, Output: map[string]interface{}{"a": []float32{1}, "b": []interface{}{int64(1), float32(1)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []float32{1, 2}}, RunOutput: []interface{}{int64(1), float32(1), float32(2)}, Output: map[string]interface{}{"a": []float32{1, 2}, "b": []interface{}{int64(1), float32(1), float32(2)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []float32{1.1}}, RunOutput: []interface{}{int64(1), float32(1.1)}, Output: map[string]interface{}{"a": []float32{1.1}, "b": []interface{}{int64(1), float32(1.1)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: []interface{}{int64(1), float32(1.1), float32(2.2)}, Output: map[string]interface{}{"a": []float32{1.1, 2.2}, "b": []interface{}{int64(1), float32(1.1), float32(2.2)}}}, + + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []float32{}}, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []float32{}, "b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []float32{1}}, RunOutput: []interface{}{int64(1), int64(2), float32(1)}, Output: map[string]interface{}{"a": []float32{1}, "b": []interface{}{int64(1), int64(2), float32(1)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []float32{1, 2}}, RunOutput: []interface{}{int64(1), int64(2), float32(1), float32(2)}, Output: map[string]interface{}{"a": []float32{1, 2}, "b": []interface{}{int64(1), int64(2), float32(1), float32(2)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []float32{1.1}}, RunOutput: []interface{}{int64(1), int64(2), float32(1.1)}, Output: map[string]interface{}{"a": []float32{1.1}, "b": []interface{}{int64(1), int64(2), float32(1.1)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: []interface{}{int64(1), int64(2), float32(1.1), float32(2.2)}, Output: map[string]interface{}{"a": []float32{1.1, 2.2}, "b": []interface{}{int64(1), int64(2), float32(1.1), float32(2.2)}}}, + + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []float32{}}, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": []float32{}, "b": []interface{}{float64(1.1)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []float32{1}}, RunOutput: []interface{}{float64(1.1), float32(1)}, Output: map[string]interface{}{"a": []float32{1}, "b": []interface{}{float64(1.1), float32(1)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []float32{1, 2}}, RunOutput: []interface{}{float64(1.1), float32(1), float32(2)}, Output: map[string]interface{}{"a": []float32{1, 2}, "b": []interface{}{float64(1.1), float32(1), float32(2)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []float32{1.1}}, RunOutput: []interface{}{float64(1.1), float32(1.1)}, Output: map[string]interface{}{"a": []float32{1.1}, "b": []interface{}{float64(1.1), float32(1.1)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: []interface{}{float64(1.1), float32(1.1), float32(2.2)}, Output: map[string]interface{}{"a": []float32{1.1, 2.2}, "b": []interface{}{float64(1.1), float32(1.1), float32(2.2)}}}, + + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float32{}}, RunOutput: []interface{}{float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []float32{}, "b": []interface{}{float64(1.1), float64(2.2)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float32{1}}, RunOutput: []interface{}{float64(1.1), float64(2.2), float32(1)}, Output: map[string]interface{}{"a": []float32{1}, "b": []interface{}{float64(1.1), float64(2.2), float32(1)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float32{1, 2}}, RunOutput: []interface{}{float64(1.1), float64(2.2), float32(1), float32(2)}, Output: map[string]interface{}{"a": []float32{1, 2}, "b": []interface{}{float64(1.1), float64(2.2), float32(1), float32(2)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float32{1.1}}, RunOutput: []interface{}{float64(1.1), float64(2.2), float32(1.1)}, Output: map[string]interface{}{"a": []float32{1.1}, "b": []interface{}{float64(1.1), float64(2.2), float32(1.1)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: []interface{}{float64(1.1), float64(2.2), float32(1.1), float32(2.2)}, Output: map[string]interface{}{"a": []float32{1.1, 2.2}, "b": []interface{}{float64(1.1), float64(2.2), float32(1.1), float32(2.2)}}}, + + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float32{}}, RunOutput: []interface{}{int64(1), float64(2.2)}, Output: map[string]interface{}{"a": []float32{}, "b": []interface{}{int64(1), float64(2.2)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float32{1}}, RunOutput: []interface{}{int64(1), float64(2.2), float32(1)}, Output: map[string]interface{}{"a": []float32{1}, "b": []interface{}{int64(1), float64(2.2), float32(1)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float32{1, 2}}, RunOutput: []interface{}{int64(1), float64(2.2), float32(1), float32(2)}, Output: map[string]interface{}{"a": []float32{1, 2}, "b": []interface{}{int64(1), float64(2.2), float32(1), float32(2)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float32{1.1}}, RunOutput: []interface{}{int64(1), float64(2.2), float32(1.1)}, Output: map[string]interface{}{"a": []float32{1.1}, "b": []interface{}{int64(1), float64(2.2), float32(1.1)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: []interface{}{int64(1), float64(2.2), float32(1.1), float32(2.2)}, Output: map[string]interface{}{"a": []float32{1.1, 2.2}, "b": []interface{}{int64(1), float64(2.2), float32(1.1), float32(2.2)}}}, + + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []float32{}}, RunOutput: []interface{}{float64(1.1), int64(2)}, Output: map[string]interface{}{"a": []float32{}, "b": []interface{}{float64(1.1), int64(2)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []float32{1}}, RunOutput: []interface{}{float64(1.1), int64(2), float32(1)}, Output: map[string]interface{}{"a": []float32{1}, "b": []interface{}{float64(1.1), int64(2), float32(1)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []float32{1, 2}}, RunOutput: []interface{}{float64(1.1), int64(2), float32(1), float32(2)}, Output: map[string]interface{}{"a": []float32{1, 2}, "b": []interface{}{float64(1.1), int64(2), float32(1), float32(2)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []float32{1.1}}, RunOutput: []interface{}{float64(1.1), int64(2), float32(1.1)}, Output: map[string]interface{}{"a": []float32{1.1}, "b": []interface{}{float64(1.1), int64(2), float32(1.1)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []float32{1.1, 2.2}}, RunOutput: []interface{}{float64(1.1), int64(2), float32(1.1), float32(2.2)}, Output: map[string]interface{}{"a": []float32{1.1, 2.2}, "b": []interface{}{float64(1.1), int64(2), float32(1.1), float32(2.2)}}}, + + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []float64{}}, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []float64{}, "b": []interface{}{}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []float64{1}}, RunOutput: []interface{}{float64(1)}, Output: map[string]interface{}{"a": []float64{1}, "b": []interface{}{float64(1)}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []float64{1, 2}}, RunOutput: []interface{}{float64(1), float64(2)}, Output: map[string]interface{}{"a": []float64{1, 2}, "b": []interface{}{float64(1), float64(2)}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []float64{1.1}}, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": []float64{1.1}, "b": []interface{}{float64(1.1)}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: []interface{}{float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []float64{1.1, 2.2}, "b": []interface{}{float64(1.1), float64(2.2)}}}, + + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []float64{}}, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": []float64{}, "b": []interface{}{int64(1)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []float64{1}}, RunOutput: []interface{}{int64(1), float64(1)}, Output: map[string]interface{}{"a": []float64{1}, "b": []interface{}{int64(1), float64(1)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []float64{1, 2}}, RunOutput: []interface{}{int64(1), float64(1), float64(2)}, Output: map[string]interface{}{"a": []float64{1, 2}, "b": []interface{}{int64(1), float64(1), float64(2)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []float64{1.1}}, RunOutput: []interface{}{int64(1), float64(1.1)}, Output: map[string]interface{}{"a": []float64{1.1}, "b": []interface{}{int64(1), float64(1.1)}}}, + {Script: `b = [1]; b += a`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: []interface{}{int64(1), float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []float64{1.1, 2.2}, "b": []interface{}{int64(1), float64(1.1), float64(2.2)}}}, + + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []float64{}}, RunOutput: []interface{}{int64(1), int64(2)}, Output: map[string]interface{}{"a": []float64{}, "b": []interface{}{int64(1), int64(2)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []float64{1}}, RunOutput: []interface{}{int64(1), int64(2), float64(1)}, Output: map[string]interface{}{"a": []float64{1}, "b": []interface{}{int64(1), int64(2), float64(1)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []float64{1, 2}}, RunOutput: []interface{}{int64(1), int64(2), float64(1), float64(2)}, Output: map[string]interface{}{"a": []float64{1, 2}, "b": []interface{}{int64(1), int64(2), float64(1), float64(2)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []float64{1.1}}, RunOutput: []interface{}{int64(1), int64(2), float64(1.1)}, Output: map[string]interface{}{"a": []float64{1.1}, "b": []interface{}{int64(1), int64(2), float64(1.1)}}}, + {Script: `b = [1, 2]; b += a`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: []interface{}{int64(1), int64(2), float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []float64{1.1, 2.2}, "b": []interface{}{int64(1), int64(2), float64(1.1), float64(2.2)}}}, + + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []float64{}}, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": []float64{}, "b": []interface{}{float64(1.1)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []float64{1}}, RunOutput: []interface{}{float64(1.1), float64(1)}, Output: map[string]interface{}{"a": []float64{1}, "b": []interface{}{float64(1.1), float64(1)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []float64{1, 2}}, RunOutput: []interface{}{float64(1.1), float64(1), float64(2)}, Output: map[string]interface{}{"a": []float64{1, 2}, "b": []interface{}{float64(1.1), float64(1), float64(2)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []float64{1.1}}, RunOutput: []interface{}{float64(1.1), float64(1.1)}, Output: map[string]interface{}{"a": []float64{1.1}, "b": []interface{}{float64(1.1), float64(1.1)}}}, + {Script: `b = [1.1]; b += a`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: []interface{}{float64(1.1), float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []float64{1.1, 2.2}, "b": []interface{}{float64(1.1), float64(1.1), float64(2.2)}}}, + + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float64{}}, RunOutput: []interface{}{float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []float64{}, "b": []interface{}{float64(1.1), float64(2.2)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float64{1}}, RunOutput: []interface{}{float64(1.1), float64(2.2), float64(1)}, Output: map[string]interface{}{"a": []float64{1}, "b": []interface{}{float64(1.1), float64(2.2), float64(1)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float64{1, 2}}, RunOutput: []interface{}{float64(1.1), float64(2.2), float64(1), float64(2)}, Output: map[string]interface{}{"a": []float64{1, 2}, "b": []interface{}{float64(1.1), float64(2.2), float64(1), float64(2)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float64{1.1}}, RunOutput: []interface{}{float64(1.1), float64(2.2), float64(1.1)}, Output: map[string]interface{}{"a": []float64{1.1}, "b": []interface{}{float64(1.1), float64(2.2), float64(1.1)}}}, + {Script: `b = [1.1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: []interface{}{float64(1.1), float64(2.2), float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []float64{1.1, 2.2}, "b": []interface{}{float64(1.1), float64(2.2), float64(1.1), float64(2.2)}}}, + + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float64{}}, RunOutput: []interface{}{int64(1), float64(2.2)}, Output: map[string]interface{}{"a": []float64{}, "b": []interface{}{int64(1), float64(2.2)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float64{1}}, RunOutput: []interface{}{int64(1), float64(2.2), float64(1)}, Output: map[string]interface{}{"a": []float64{1}, "b": []interface{}{int64(1), float64(2.2), float64(1)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float64{1, 2}}, RunOutput: []interface{}{int64(1), float64(2.2), float64(1), float64(2)}, Output: map[string]interface{}{"a": []float64{1, 2}, "b": []interface{}{int64(1), float64(2.2), float64(1), float64(2)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float64{1.1}}, RunOutput: []interface{}{int64(1), float64(2.2), float64(1.1)}, Output: map[string]interface{}{"a": []float64{1.1}, "b": []interface{}{int64(1), float64(2.2), float64(1.1)}}}, + {Script: `b = [1, 2.2]; b += a`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: []interface{}{int64(1), float64(2.2), float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []float64{1.1, 2.2}, "b": []interface{}{int64(1), float64(2.2), float64(1.1), float64(2.2)}}}, + + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []float64{}}, RunOutput: []interface{}{float64(1.1), int64(2)}, Output: map[string]interface{}{"a": []float64{}, "b": []interface{}{float64(1.1), int64(2)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []float64{1}}, RunOutput: []interface{}{float64(1.1), int64(2), float64(1)}, Output: map[string]interface{}{"a": []float64{1}, "b": []interface{}{float64(1.1), int64(2), float64(1)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []float64{1, 2}}, RunOutput: []interface{}{float64(1.1), int64(2), float64(1), float64(2)}, Output: map[string]interface{}{"a": []float64{1, 2}, "b": []interface{}{float64(1.1), int64(2), float64(1), float64(2)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []float64{1.1}}, RunOutput: []interface{}{float64(1.1), int64(2), float64(1.1)}, Output: map[string]interface{}{"a": []float64{1.1}, "b": []interface{}{float64(1.1), int64(2), float64(1.1)}}}, + {Script: `b = [1.1, 2]; b += a`, Input: map[string]interface{}{"a": []float64{1.1, 2.2}}, RunOutput: []interface{}{float64(1.1), int64(2), float64(1.1), float64(2.2)}, Output: map[string]interface{}{"a": []float64{1.1, 2.2}, "b": []interface{}{float64(1.1), int64(2), float64(1.1), float64(2.2)}}}, + + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []string{}}, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": []string{}, "b": []interface{}{}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []string{"a"}}, RunOutput: []interface{}{"a"}, Output: map[string]interface{}{"a": []string{"a"}, "b": []interface{}{"a"}}}, + {Script: `b = []; b += a`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunOutput: []interface{}{"a", "b"}, Output: map[string]interface{}{"a": []string{"a", "b"}, "b": []interface{}{"a", "b"}}}, + + {Script: `b = ["a"]; b += a`, Input: map[string]interface{}{"a": []string{}}, RunOutput: []interface{}{"a"}, Output: map[string]interface{}{"a": []string{}, "b": []interface{}{"a"}}}, + {Script: `b = ["a"]; b += a`, Input: map[string]interface{}{"a": []string{"a"}}, RunOutput: []interface{}{"a", "a"}, Output: map[string]interface{}{"a": []string{"a"}, "b": []interface{}{"a", "a"}}}, + {Script: `b = ["a"]; b += a`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunOutput: []interface{}{"a", "a", "b"}, Output: map[string]interface{}{"a": []string{"a", "b"}, "b": []interface{}{"a", "a", "b"}}}, + + {Script: `b = ["a", "b"]; b += a`, Input: map[string]interface{}{"a": []string{}}, RunOutput: []interface{}{"a", "b"}, Output: map[string]interface{}{"a": []string{}, "b": []interface{}{"a", "b"}}}, + {Script: `b = ["a", "b"]; b += a`, Input: map[string]interface{}{"a": []string{"a"}}, RunOutput: []interface{}{"a", "b", "a"}, Output: map[string]interface{}{"a": []string{"a"}, "b": []interface{}{"a", "b", "a"}}}, + {Script: `b = ["a", "b"]; b += a`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunOutput: []interface{}{"a", "b", "a", "b"}, Output: map[string]interface{}{"a": []string{"a", "b"}, "b": []interface{}{"a", "b", "a", "b"}}}, + + {Script: `b = [1, "a"]; b += a`, Input: map[string]interface{}{"a": []string{}}, RunOutput: []interface{}{int64(1), "a"}, Output: map[string]interface{}{"a": []string{}, "b": []interface{}{int64(1), "a"}}}, + {Script: `b = [1, "a"]; b += a`, Input: map[string]interface{}{"a": []string{"a"}}, RunOutput: []interface{}{int64(1), "a", "a"}, Output: map[string]interface{}{"a": []string{"a"}, "b": []interface{}{int64(1), "a", "a"}}}, + {Script: `b = [1, "a"]; b += a`, Input: map[string]interface{}{"a": []string{"a", "b"}}, RunOutput: []interface{}{int64(1), "a", "a", "b"}, Output: map[string]interface{}{"a": []string{"a", "b"}, "b": []interface{}{int64(1), "a", "a", "b"}}}, + + {Script: `a = []; a += [nil, nil]; a += [nil, nil]`, RunOutput: []interface{}{interface{}(nil), interface{}(nil), interface{}(nil), interface{}(nil)}, Output: map[string]interface{}{"a": []interface{}{interface{}(nil), interface{}(nil), interface{}(nil), interface{}(nil)}}}, + {Script: `a = []; a += [true, false]; a += [false, true]`, RunOutput: []interface{}{interface{}(true), interface{}(false), interface{}(false), interface{}(true)}, Output: map[string]interface{}{"a": []interface{}{interface{}(true), interface{}(false), interface{}(false), interface{}(true)}}}, + {Script: `a = []; a += [1, 2]; a += [3, 4]`, RunOutput: []interface{}{interface{}(int64(1)), interface{}(int64(2)), interface{}(int64(3)), interface{}(int64(4))}, Output: map[string]interface{}{"a": []interface{}{interface{}(int64(1)), interface{}(int64(2)), interface{}(int64(3)), interface{}(int64(4))}}}, + {Script: `a = []; a += [1.1, 2.2]; a += [3.3, 4.4]`, RunOutput: []interface{}{interface{}(float64(1.1)), interface{}(float64(2.2)), interface{}(float64(3.3)), interface{}(float64(4.4))}, Output: map[string]interface{}{"a": []interface{}{interface{}(float64(1.1)), interface{}(float64(2.2)), interface{}(float64(3.3)), interface{}(float64(4.4))}}}, + {Script: `a = []; a += ["a", "b"]; a += ["c", "d"]`, RunOutput: []interface{}{interface{}("a"), interface{}("b"), interface{}("c"), interface{}("d")}, Output: map[string]interface{}{"a": []interface{}{interface{}("a"), interface{}("b"), interface{}("c"), interface{}("d")}}}, + + {Script: `a = []; a += [[nil, nil]]; a += [[nil, nil]]`, RunOutput: []interface{}{[]interface{}{nil, nil}, []interface{}{nil, nil}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{nil, nil}, []interface{}{nil, nil}}}}, + {Script: `a = []; a += [[true, false]]; a += [[false, true]]`, RunOutput: []interface{}{[]interface{}{true, false}, []interface{}{false, true}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{true, false}, []interface{}{false, true}}}}, + {Script: `a = []; a += [[1, 2]]; a += [[3, 4]]`, RunOutput: []interface{}{[]interface{}{int64(1), int64(2)}, []interface{}{int64(3), int64(4)}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{int64(1), int64(2)}, []interface{}{int64(3), int64(4)}}}}, + {Script: `a = []; a += [[1.1, 2.2]]; a += [[3.3, 4.4]]`, RunOutput: []interface{}{[]interface{}{float64(1.1), float64(2.2)}, []interface{}{float64(3.3), float64(4.4)}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{float64(1.1), float64(2.2)}, []interface{}{float64(3.3), float64(4.4)}}}}, + {Script: `a = []; a += [["a", "b"]]; a += [["c", "d"]]`, RunOutput: []interface{}{[]interface{}{"a", "b"}, []interface{}{"c", "d"}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{"a", "b"}, []interface{}{"c", "d"}}}}, + + {Script: `a = make([]bool); a += 1`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": []bool{}}}, + {Script: `a = make([]bool); a += true; a += 1`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": []bool{true}}}, + {Script: `a = make([]bool); a += [1]`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": []bool{}}}, + {Script: `a = make([]bool); a += [true, 1]`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": []bool{}}}, + + {Script: `a = make([]bool); a += true; a += false`, RunOutput: []bool{true, false}, Output: map[string]interface{}{"a": []bool{true, false}}}, + {Script: `a = make([]bool); a += [true]; a += [false]`, RunOutput: []bool{true, false}, Output: map[string]interface{}{"a": []bool{true, false}}}, + {Script: `a = make([]bool); a += [true, false]`, RunOutput: []bool{true, false}, Output: map[string]interface{}{"a": []bool{true, false}}}, + + {Script: `a = make([]bool); a += true; a += b`, Input: map[string]interface{}{"b": int64(1)}, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": []bool{true}, "b": int64(1)}}, + {Script: `a = make([]bool); a += [true]; a += [b]`, Input: map[string]interface{}{"b": int64(1)}, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": []bool{true}, "b": int64(1)}}, + {Script: `a = make([]bool); a += [true, b]`, Input: map[string]interface{}{"b": int64(1)}, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": []bool{}, "b": int64(1)}}, + + {Script: `a = make([]bool); a += b; a += b`, Input: map[string]interface{}{"b": true}, RunOutput: []bool{true, true}, Output: map[string]interface{}{"a": []bool{true, true}, "b": true}}, + {Script: `a = make([]bool); a += [b]; a += [b]`, Input: map[string]interface{}{"b": true}, RunOutput: []bool{true, true}, Output: map[string]interface{}{"a": []bool{true, true}, "b": true}}, + {Script: `a = make([]bool); a += [b, b]`, Input: map[string]interface{}{"b": true}, RunOutput: []bool{true, true}, Output: map[string]interface{}{"a": []bool{true, true}, "b": true}}, + + {Script: `a = make([]bool); a += [true, false]; b = make([]int64); b += [1, 2]; a += b`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": []bool{true, false}, "b": []int64{int64(1), int64(2)}}}, + + {Script: `a = []; b = []; b += true; b += false; a += b`, RunOutput: []interface{}{true, false}, Output: map[string]interface{}{"a": []interface{}{true, false}, "b": []interface{}{true, false}}}, + {Script: `a = []; b = make([]bool); b += true; b += false; a += b`, RunOutput: []interface{}{true, false}, Output: map[string]interface{}{"a": []interface{}{true, false}, "b": []bool{true, false}}}, + {Script: `a = []; b = []; b += [true]; b += [false]; a += [b]`, RunOutput: []interface{}{[]interface{}{true, false}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{true, false}}, "b": []interface{}{true, false}}}, + {Script: `a = []; b = make([]bool); b += [true]; b += [false]; a += [b]`, RunOutput: []interface{}{[]bool{true, false}}, Output: map[string]interface{}{"a": []interface{}{[]bool{true, false}}, "b": []bool{true, false}}}, + + {Script: `a = [true, false]; b = [true, false]; a += b`, RunOutput: []interface{}{true, false, true, false}, Output: map[string]interface{}{"a": []interface{}{true, false, true, false}, "b": []interface{}{true, false}}}, + {Script: `a = make([]bool); a += [true, false]; b = make([]bool); b += [true, false]; a += b`, RunOutput: []bool{true, false, true, false}, Output: map[string]interface{}{"a": []bool{true, false, true, false}, "b": []bool{true, false}}}, + {Script: `a = make([]bool); a += [true, false]; b = [true, false]; a += b`, RunOutput: []bool{true, false, true, false}, Output: map[string]interface{}{"a": []bool{true, false, true, false}, "b": []interface{}{true, false}}}, + {Script: `a = [true, false]; b = make([]bool); b += [true, false]; a += b`, RunOutput: []interface{}{true, false, true, false}, Output: map[string]interface{}{"a": []interface{}{true, false, true, false}, "b": []bool{true, false}}}, + + {Script: `a = make([][]bool); b = make([][]bool); a += b`, RunOutput: [][]bool{}, Output: map[string]interface{}{"a": [][]bool{}, "b": [][]bool{}}}, + {Script: `a = make([][]bool); b = make([][]bool); b += [[]]; a += b`, RunOutput: [][]bool{{}}, Output: map[string]interface{}{"a": [][]bool{{}}, "b": [][]bool{{}}}}, + {Script: `a = make([][]bool); a += [[]]; b = make([][]bool); a += b`, RunOutput: [][]bool{{}}, Output: map[string]interface{}{"a": [][]bool{{}}, "b": [][]bool{}}}, + {Script: `a = make([][]bool); a += [[]]; b = make([][]bool); b += [[]]; a += b`, RunOutput: [][]bool{{}, {}}, Output: map[string]interface{}{"a": [][]bool{{}, {}}, "b": [][]bool{{}}}}, + + {Script: `a = make([]bool); a += []; b = make([]bool); b += []; a += b`, RunOutput: []bool{}, Output: map[string]interface{}{"a": []bool{}, "b": []bool{}}}, + {Script: `a = make([]bool); a += [true]; b = make([]bool); b += []; a += b`, RunOutput: []bool{true}, Output: map[string]interface{}{"a": []bool{true}, "b": []bool{}}}, + {Script: `a = make([]bool); a += []; b = make([]bool); b += [true]; a += b`, RunOutput: []bool{true}, Output: map[string]interface{}{"a": []bool{true}, "b": []bool{true}}}, + {Script: `a = make([]bool); a += [true]; b = make([]bool); b += [true]; a += b`, RunOutput: []bool{true, true}, Output: map[string]interface{}{"a": []bool{true, true}, "b": []bool{true}}}, + + {Script: `a = make([][]bool); a += [true, false];`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": [][]bool{}}}, + {Script: `a = make([][]bool); a += [[true, false]]; b = make([]bool); b += [true, false]; a += b`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": [][]bool{{true, false}}, "b": []bool{true, false}}}, + {Script: `a = make([][]bool); a += [[true, false]]; b = [[1.1]]; a += b`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": [][]bool{{true, false}}, "b": []interface{}{[]interface{}{1.1}}}}, + {Script: `a = make([]bool); a += [true, false]; b = make([][]bool); b += [[true, false]]; a += b`, RunError: fmt.Errorf("invalid type conversion"), Output: map[string]interface{}{"a": []bool{true, false}, "b": [][]bool{{true, false}}}}, + + {Script: `a = make([][]interface); a += [[1, 2]]`, RunOutput: [][]interface{}{{int64(1), int64(2)}}, Output: map[string]interface{}{"a": [][]interface{}{{int64(1), int64(2)}}}}, + {Script: `a = make([][]interface); b = [1, 2]; a += [b]`, RunOutput: [][]interface{}{{int64(1), int64(2)}}, Output: map[string]interface{}{"a": [][]interface{}{{int64(1), int64(2)}}, "b": []interface{}{int64(1), int64(2)}}}, + {Script: `a = make([][]interface); a += [[1, 2],[3, 4]]`, RunOutput: [][]interface{}{{int64(1), int64(2)}, {int64(3), int64(4)}}, Output: map[string]interface{}{"a": [][]interface{}{{int64(1), int64(2)}, {int64(3), int64(4)}}}}, + {Script: `a = make([][]interface); b = [1, 2]; a += [b]; b = [3, 4]; a += [b]`, RunOutput: [][]interface{}{{int64(1), int64(2)}, {int64(3), int64(4)}}, Output: map[string]interface{}{"a": [][]interface{}{{int64(1), int64(2)}, {int64(3), int64(4)}}, "b": []interface{}{int64(3), int64(4)}}}, + + {Script: `a = [["a", "b"], ["c", "d"]]; b = [["w", "x"], ["y", "z"]]; a += b`, RunOutput: []interface{}{[]interface{}{"a", "b"}, []interface{}{"c", "d"}, []interface{}{"w", "x"}, []interface{}{"y", "z"}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{"a", "b"}, []interface{}{"c", "d"}, []interface{}{"w", "x"}, []interface{}{"y", "z"}}, "b": []interface{}{[]interface{}{"w", "x"}, []interface{}{"y", "z"}}}}, + {Script: `a = make([][]string); a += [["a", "b"], ["c", "d"]]; b = make([][]string); b += [["w", "x"], ["y", "z"]]; a += b`, RunOutput: [][]string{{"a", "b"}, {"c", "d"}, {"w", "x"}, {"y", "z"}}, Output: map[string]interface{}{"a": [][]string{{"a", "b"}, {"c", "d"}, {"w", "x"}, {"y", "z"}}, "b": [][]string{{"w", "x"}, {"y", "z"}}}}, + {Script: `a = make([][]string); a += [["a", "b"], ["c", "d"]]; b = [["w", "x"], ["y", "z"]]; a += b`, RunOutput: [][]string{{"a", "b"}, {"c", "d"}, {"w", "x"}, {"y", "z"}}, Output: map[string]interface{}{"a": [][]string{{"a", "b"}, {"c", "d"}, {"w", "x"}, {"y", "z"}}, "b": []interface{}{[]interface{}{"w", "x"}, []interface{}{"y", "z"}}}}, + {Script: `a = [["a", "b"], ["c", "d"]]; b = make([][]string); b += [["w", "x"], ["y", "z"]]; a += b`, RunOutput: []interface{}{[]interface{}{"a", "b"}, []interface{}{"c", "d"}, []string{"w", "x"}, []string{"y", "z"}}, Output: map[string]interface{}{"a": []interface{}{[]interface{}{"a", "b"}, []interface{}{"c", "d"}, []string{"w", "x"}, []string{"y", "z"}}, "b": [][]string{{"w", "x"}, {"y", "z"}}}}, + + {Script: `a = make([][]int64); a += [[1, 2], [3, 4]]; b = make([][]int32); b += [[5, 6], [7, 8]]; a += b`, RunOutput: [][]int64{{int64(1), int64(2)}, {int64(3), int64(4)}, {int64(5), int64(6)}, {int64(7), int64(8)}}, Output: map[string]interface{}{"a": [][]int64{{int64(1), int64(2)}, {int64(3), int64(4)}, {int64(5), int64(6)}, {int64(7), int64(8)}}, "b": [][]int32{{int32(5), int32(6)}, {int32(7), int32(8)}}}}, + {Script: `a = make([][]int32); a += [[1, 2], [3, 4]]; b = make([][]int64); b += [[5, 6], [7, 8]]; a += b`, RunOutput: [][]int32{{int32(1), int32(2)}, {int32(3), int32(4)}, {int32(5), int32(6)}, {int32(7), int32(8)}}, Output: map[string]interface{}{"a": [][]int32{{int32(1), int32(2)}, {int32(3), int32(4)}, {int32(5), int32(6)}, {int32(7), int32(8)}}, "b": [][]int64{{int64(5), int64(6)}, {int64(7), int64(8)}}}}, + {Script: `a = make([][]int64); a += [[1, 2], [3, 4]]; b = make([][]float64); b += [[5, 6], [7, 8]]; a += b`, RunOutput: [][]int64{{int64(1), int64(2)}, {int64(3), int64(4)}, {int64(5), int64(6)}, {int64(7), int64(8)}}, Output: map[string]interface{}{"a": [][]int64{{int64(1), int64(2)}, {int64(3), int64(4)}, {int64(5), int64(6)}, {int64(7), int64(8)}}, "b": [][]float64{{float64(5), float64(6)}, {float64(7), float64(8)}}}}, + {Script: `a = make([][]float64); a += [[1, 2], [3, 4]]; b = make([][]int64); b += [[5, 6], [7, 8]]; a += b`, RunOutput: [][]float64{{float64(1), float64(2)}, {float64(3), float64(4)}, {float64(5), float64(6)}, {float64(7), float64(8)}}, Output: map[string]interface{}{"a": [][]float64{{float64(1), float64(2)}, {float64(3), float64(4)}, {float64(5), float64(6)}, {float64(7), float64(8)}}, "b": [][]int64{{int64(5), int64(6)}, {int64(7), int64(8)}}}}, + + {Script: `a = make([][][]interface); a += [[[1, 2]]]`, RunOutput: [][][]interface{}{{{int64(1), int64(2)}}}, Output: map[string]interface{}{"a": [][][]interface{}{{{int64(1), int64(2)}}}}}, + {Script: `a = make([][][]interface); b = [[1, 2]]; a += [b]`, RunOutput: [][][]interface{}{{{int64(1), int64(2)}}}, Output: map[string]interface{}{"a": [][][]interface{}{{{int64(1), int64(2)}}}, "b": []interface{}{[]interface{}{int64(1), int64(2)}}}}, + {Script: `a = make([][][]interface); b = [1, 2]; a += [[b]]`, RunOutput: [][][]interface{}{{{int64(1), int64(2)}}}, Output: map[string]interface{}{"a": [][][]interface{}{{{int64(1), int64(2)}}}, "b": []interface{}{int64(1), int64(2)}}}, + + {Script: `a = make([][][]interface); a += [[[1, 2],[3, 4]]]`, RunOutput: [][][]interface{}{{{int64(1), int64(2)}, {int64(3), int64(4)}}}, Output: map[string]interface{}{"a": [][][]interface{}{{{int64(1), int64(2)}, {int64(3), int64(4)}}}}}, + {Script: `a = make([][][]interface); b = [[1, 2],[3, 4]]; a += [b]`, RunOutput: [][][]interface{}{{{int64(1), int64(2)}, {int64(3), int64(4)}}}, Output: map[string]interface{}{"a": [][][]interface{}{{{int64(1), int64(2)}, {int64(3), int64(4)}}}, "b": []interface{}{[]interface{}{int64(1), int64(2)}, []interface{}{int64(3), int64(4)}}}}, + {Script: `a = make([][][]interface); b = [1, 2]; c = [b]; b = [3, 4]; c += [b]; a += [c]`, RunOutput: [][][]interface{}{{{int64(1), int64(2)}, {int64(3), int64(4)}}}, Output: map[string]interface{}{"a": [][][]interface{}{{{int64(1), int64(2)}, {int64(3), int64(4)}}}, "b": []interface{}{int64(3), int64(4)}, "c": []interface{}{[]interface{}{int64(1), int64(2)}, []interface{}{int64(3), int64(4)}}}}, + {Script: `a = make([][][]interface); b = [1, 2]; c = []; c += [b]; b = [3, 4]; c += [b]; a += [c]`, RunOutput: [][][]interface{}{{{int64(1), int64(2)}, {int64(3), int64(4)}}}, Output: map[string]interface{}{"a": [][][]interface{}{{{int64(1), int64(2)}, {int64(3), int64(4)}}}, "b": []interface{}{int64(3), int64(4)}, "c": []interface{}{[]interface{}{int64(1), int64(2)}, []interface{}{int64(3), int64(4)}}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestMaps(t *testing.T) { + t.Parallel() + + tests := []Test{ + // TOFIX: this should have a ParseError + {Script: `{ , }`, RunOutput: map[interface{}]interface{}{}}, + {Script: `{"a": }`, ParseError: fmt.Errorf("syntax error")}, + {Script: `{ :"a"}`, ParseError: fmt.Errorf("syntax error")}, + {Script: `{ , "b":"b"}`, ParseError: fmt.Errorf("syntax error: unexpected ','"), RunOutput: map[interface{}]interface{}{"b": "b"}}, + {Script: `{"a":"a", , "c":"c"}`, ParseError: fmt.Errorf("syntax error")}, + {Script: `{"b": 1++}`, RunError: fmt.Errorf("invalid operation")}, + {Script: `{1++: 1}`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a = {}; a.b.c`, RunError: fmt.Errorf("type interface does not support member operation")}, + {Script: `a = {}; a.b.c = 1`, RunError: fmt.Errorf("type interface does not support member operation")}, + {Script: `a = {}; a[1++]`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a = {}; a[1++] = 1`, RunError: fmt.Errorf("invalid operation")}, + {Script: `b[1]`, RunError: fmt.Errorf("undefined symbol 'b'")}, + {Script: `b[1] = 1`, RunError: fmt.Errorf("undefined symbol 'b'")}, + {Script: `z.y.x = 1`, RunError: fmt.Errorf("undefined symbol 'z'")}, + + {Script: `{}`, RunOutput: map[interface{}]interface{}{}}, + {Script: `{"b": nil}`, RunOutput: map[interface{}]interface{}{"b": nil}}, + {Script: `{"b": true}`, RunOutput: map[interface{}]interface{}{"b": true}}, + {Script: `{"b": 1}`, RunOutput: map[interface{}]interface{}{"b": int64(1)}}, + {Script: `{"b": 1.1}`, RunOutput: map[interface{}]interface{}{"b": float64(1.1)}}, + {Script: `{"b": "b"}`, RunOutput: map[interface{}]interface{}{"b": "b"}}, + + {Script: `{1: nil}`, RunOutput: map[interface{}]interface{}{int64(1): nil}}, + {Script: `{1: true}`, RunOutput: map[interface{}]interface{}{int64(1): true}}, + {Script: `{1: 2}`, RunOutput: map[interface{}]interface{}{int64(1): int64(2)}}, + {Script: `{1: 2.2}`, RunOutput: map[interface{}]interface{}{int64(1): float64(2.2)}}, + {Script: `{1: "b"}`, RunOutput: map[interface{}]interface{}{int64(1): "b"}}, + + {Script: `a = {}`, RunOutput: map[interface{}]interface{}{}, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = map{}`, RunOutput: map[interface{}]interface{}{}, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = map {}`, RunOutput: map[interface{}]interface{}{}, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = {"b": nil}`, RunOutput: map[interface{}]interface{}{"b": nil}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": nil}}}, + {Script: `a = {"b": true}`, RunOutput: map[interface{}]interface{}{"b": true}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": true}}}, + {Script: `a = {"b": 1}`, RunOutput: map[interface{}]interface{}{"b": int64(1)}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1)}}}, + {Script: `a = {"b": 1.1}`, RunOutput: map[interface{}]interface{}{"b": float64(1.1)}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": float64(1.1)}}}, + {Script: `a = {"b": "b"}`, RunOutput: map[interface{}]interface{}{"b": "b"}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b"}}}, + + {Script: `a = {"b": {}}`, RunOutput: map[interface{}]interface{}{"b": map[interface{}]interface{}{}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{}}}}, + {Script: `a = {"b": {"c": nil}}`, RunOutput: map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": nil}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": nil}}}}, + {Script: `a = {"b": {"c": true}}`, RunOutput: map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": true}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": true}}}}, + {Script: `a = {"b": {"c": 1}}`, RunOutput: map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": int64(1)}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": int64(1)}}}}, + {Script: `a = {"b": {"c": 1.1}}`, RunOutput: map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": float64(1.1)}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": float64(1.1)}}}}, + {Script: `a = {"b": {"c": "c"}}`, RunOutput: map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": "c"}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": "c"}}}}, + + {Script: `a = {"b": {}}; a.b`, RunOutput: map[interface{}]interface{}{}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{}}}}, + {Script: `a = {"b": {"c": nil}}; a.b`, RunOutput: map[interface{}]interface{}{"c": nil}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": nil}}}}, + {Script: `a = {"b": {"c": true}}; a.b`, RunOutput: map[interface{}]interface{}{"c": true}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": true}}}}, + {Script: `a = {"b": {"c": 1}}; a.b`, RunOutput: map[interface{}]interface{}{"c": int64(1)}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": int64(1)}}}}, + {Script: `a = {"b": {"c": 1.1}}; a.b`, RunOutput: map[interface{}]interface{}{"c": float64(1.1)}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": float64(1.1)}}}}, + {Script: `a = {"b": {"c": "c"}}; a.b`, RunOutput: map[interface{}]interface{}{"c": "c"}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": map[interface{}]interface{}{"c": "c"}}}}, + + {Script: `a = {"b": []}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{}}}}, + {Script: `a = {"b": [nil]}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{nil}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{nil}}}}, + {Script: `a = {"b": [true]}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{true}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{true}}}}, + {Script: `a = {"b": [1]}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{int64(1)}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{int64(1)}}}}, + {Script: `a = {"b": [1.1]}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{float64(1.1)}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{float64(1.1)}}}}, + {Script: `a = {"b": ["c"]}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{"c"}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{"c"}}}}, + + {Script: `a = {}; a.b`, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = {"b": nil}; a.b`, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": nil}}}, + {Script: `a = {"b": true}; a.b`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": true}}}, + {Script: `a = {"b": 1}; a.b`, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1)}}}, + {Script: `a = {"b": 1.1}; a.b`, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": float64(1.1)}}}, + {Script: `a = {"b": "b"}; a.b`, RunOutput: "b", Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b"}}}, + + {Script: `a = {}; a["b"]`, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = {"b": nil}; a["b"]`, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": nil}}}, + {Script: `a = {"b": true}; a["b"]`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": true}}}, + {Script: `a = {"b": 1}; a["b"]`, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1)}}}, + {Script: `a = {"b": 1.1}; a["b"]`, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": float64(1.1)}}}, + {Script: `a = {"b": "b"}; a["b"]`, RunOutput: "b", Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b"}}}, + + {Script: `a`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: map[string]interface{}{}, Output: map[string]interface{}{"a": map[string]interface{}{}}}, + {Script: `a`, Input: map[string]interface{}{"a": map[string]interface{}{"b": nil}}, RunOutput: map[string]interface{}{"b": nil}, Output: map[string]interface{}{"a": map[string]interface{}{"b": nil}}}, + {Script: `a`, Input: map[string]interface{}{"a": map[string]interface{}{"b": true}}, RunOutput: map[string]interface{}{"b": true}, Output: map[string]interface{}{"a": map[string]interface{}{"b": true}}}, + {Script: `a`, Input: map[string]interface{}{"a": map[string]interface{}{"b": int32(1)}}, RunOutput: map[string]interface{}{"b": int32(1)}, Output: map[string]interface{}{"a": map[string]interface{}{"b": int32(1)}}}, + {Script: `a`, Input: map[string]interface{}{"a": map[string]interface{}{"b": int64(1)}}, RunOutput: map[string]interface{}{"b": int64(1)}, Output: map[string]interface{}{"a": map[string]interface{}{"b": int64(1)}}}, + {Script: `a`, Input: map[string]interface{}{"a": map[string]interface{}{"b": float32(1.1)}}, RunOutput: map[string]interface{}{"b": float32(1.1)}, Output: map[string]interface{}{"a": map[string]interface{}{"b": float32(1.1)}}}, + {Script: `a`, Input: map[string]interface{}{"a": map[string]interface{}{"b": float64(1.1)}}, RunOutput: map[string]interface{}{"b": float64(1.1)}, Output: map[string]interface{}{"a": map[string]interface{}{"b": float64(1.1)}}}, + {Script: `a`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}, RunOutput: map[string]interface{}{"b": "b"}, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}}, + + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]interface{}{"b": nil}}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": nil}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]interface{}{"b": true}}, RunOutput: true, Output: map[string]interface{}{"a": map[string]interface{}{"b": true}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]interface{}{"b": int32(1)}}, RunOutput: int32(1), Output: map[string]interface{}{"a": map[string]interface{}{"b": int32(1)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]interface{}{"b": int64(1)}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[string]interface{}{"b": int64(1)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]interface{}{"b": float32(1.1)}}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": map[string]interface{}{"b": float32(1.1)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]interface{}{"b": float64(1.1)}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[string]interface{}{"b": float64(1.1)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}, RunOutput: "b", Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}}, + + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]bool{"a": false, "b": true}}, RunOutput: true, Output: map[string]interface{}{"a": map[string]bool{"a": false, "b": true}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]int32{"a": int32(1), "b": int32(2)}}, RunOutput: int32(2), Output: map[string]interface{}{"a": map[string]int32{"a": int32(1), "b": int32(2)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]int64{"a": int64(1), "b": int64(2)}}, RunOutput: int64(2), Output: map[string]interface{}{"a": map[string]int64{"a": int64(1), "b": int64(2)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]float32{"a": float32(1.1), "b": float32(2.2)}}, RunOutput: float32(2.2), Output: map[string]interface{}{"a": map[string]float32{"a": float32(1.1), "b": float32(2.2)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]float64{"a": float64(1.1), "b": float64(2.2)}}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": map[string]float64{"a": float64(1.1), "b": float64(2.2)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[string]string{"a": "a", "b": "b"}}, RunOutput: "b", Output: map[string]interface{}{"a": map[string]string{"a": "a", "b": "b"}}}, + + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": reflect.Value{}}}, RunOutput: reflect.Value{}, Output: map[string]interface{}{"a": map[string]interface{}{"b": reflect.Value{}}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": nil}}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": nil}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": true}}, RunOutput: true, Output: map[string]interface{}{"a": map[string]interface{}{"b": true}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": int32(1)}}, RunOutput: int32(1), Output: map[string]interface{}{"a": map[string]interface{}{"b": int32(1)}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": int64(1)}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[string]interface{}{"b": int64(1)}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": float32(1.1)}}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": map[string]interface{}{"b": float32(1.1)}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": float64(1.1)}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[string]interface{}{"b": float64(1.1)}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}, RunOutput: "b", Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}}, + + {Script: `a[0:1]`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunError: fmt.Errorf("type map does not support slice operation"), Output: map[string]interface{}{"a": map[string]interface{}{}}}, + {Script: `a[0:1]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": reflect.Value{}}}, RunError: fmt.Errorf("type map does not support slice operation"), Output: map[string]interface{}{"a": map[string]interface{}{"b": reflect.Value{}}}}, + {Script: `a[0:1]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": nil}}, RunError: fmt.Errorf("type map does not support slice operation"), Output: map[string]interface{}{"a": map[string]interface{}{"b": nil}}}, + {Script: `a[0:1]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": true}}, RunError: fmt.Errorf("type map does not support slice operation"), Output: map[string]interface{}{"a": map[string]interface{}{"b": true}}}, + {Script: `a[0:1]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": int32(1)}}, RunError: fmt.Errorf("type map does not support slice operation"), Output: map[string]interface{}{"a": map[string]interface{}{"b": int32(1)}}}, + {Script: `a[0:1]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": int64(1)}}, RunError: fmt.Errorf("type map does not support slice operation"), Output: map[string]interface{}{"a": map[string]interface{}{"b": int64(1)}}}, + {Script: `a[0:1]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": float32(1.1)}}, RunError: fmt.Errorf("type map does not support slice operation"), Output: map[string]interface{}{"a": map[string]interface{}{"b": float32(1.1)}}}, + {Script: `a[0:1]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": float64(1.1)}}, RunError: fmt.Errorf("type map does not support slice operation"), Output: map[string]interface{}{"a": map[string]interface{}{"b": float64(1.1)}}}, + {Script: `a[0:1]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}, RunError: fmt.Errorf("type map does not support slice operation"), Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}}, + + {Script: `a[c]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": nil}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": nil}}, + {Script: `a[c]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": true}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": true}}, + {Script: `a[c]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": int32(1)}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": int32(1)}}, + {Script: `a[c]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": int64(1)}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": int64(1)}}, + {Script: `a[c]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": float32(1.1)}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": float32(1.1)}}, + {Script: `a[c]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": float64(1.1)}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": float64(1.1)}}, + {Script: `a[c]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": "b"}, RunOutput: "b", Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": "b"}}, + {Script: `a[c]`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": "c"}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": "c"}}, + + {Script: `a.b = nil`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": nil}}}, + {Script: `a.b = true`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: true, Output: map[string]interface{}{"a": map[string]interface{}{"b": true}}}, + {Script: `a.b = 1`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[string]interface{}{"b": int64(1)}}}, + {Script: `a.b = 1.1`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[string]interface{}{"b": float64(1.1)}}}, + {Script: `a.b = "b"`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: "b", Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}}, + + {Script: `a.b = true`, Input: map[string]interface{}{"a": map[string]bool{"a": true, "b": false}}, RunOutput: true, Output: map[string]interface{}{"a": map[string]bool{"a": true, "b": true}}}, + {Script: `a.b = 3`, Input: map[string]interface{}{"a": map[string]int32{"a": int32(1), "b": int32(2)}}, RunOutput: int64(3), Output: map[string]interface{}{"a": map[string]int32{"a": int32(1), "b": int32(3)}}}, + {Script: `a.b = 3`, Input: map[string]interface{}{"a": map[string]int64{"a": int64(1), "b": int64(2)}}, RunOutput: int64(3), Output: map[string]interface{}{"a": map[string]int64{"a": int64(1), "b": int64(3)}}}, + {Script: `a.b = 3.3`, Input: map[string]interface{}{"a": map[string]float32{"a": float32(1.1), "b": float32(2.2)}}, RunOutput: float64(3.3), Output: map[string]interface{}{"a": map[string]float32{"a": float32(1.1), "b": float32(3.3)}}}, + {Script: `a.b = 3.3`, Input: map[string]interface{}{"a": map[string]float64{"a": float64(1.1), "b": float64(2.2)}}, RunOutput: float64(3.3), Output: map[string]interface{}{"a": map[string]float64{"a": float64(1.1), "b": float64(3.3)}}}, + {Script: `a.b = "c"`, Input: map[string]interface{}{"a": map[string]string{"a": "a", "b": "b"}}, RunOutput: "c", Output: map[string]interface{}{"a": map[string]string{"a": "a", "b": "c"}}}, + + {Script: `a["b"] = true`, Input: map[string]interface{}{"a": map[string]bool{"a": true, "b": false}}, RunOutput: true, Output: map[string]interface{}{"a": map[string]bool{"a": true, "b": true}}}, + {Script: `a["b"] = 3`, Input: map[string]interface{}{"a": map[string]int32{"a": int32(1), "b": int32(2)}}, RunOutput: int64(3), Output: map[string]interface{}{"a": map[string]int32{"a": int32(1), "b": int32(3)}}}, + {Script: `a["b"] = 3`, Input: map[string]interface{}{"a": map[string]int64{"a": int64(1), "b": int64(2)}}, RunOutput: int64(3), Output: map[string]interface{}{"a": map[string]int64{"a": int64(1), "b": int64(3)}}}, + {Script: `a["b"] = 3.3`, Input: map[string]interface{}{"a": map[string]float32{"a": float32(1.1), "b": float32(2.2)}}, RunOutput: float64(3.3), Output: map[string]interface{}{"a": map[string]float32{"a": float32(1.1), "b": float32(3.3)}}}, + {Script: `a["b"] = 3.3`, Input: map[string]interface{}{"a": map[string]float64{"a": float64(1.1), "b": float64(2.2)}}, RunOutput: float64(3.3), Output: map[string]interface{}{"a": map[string]float64{"a": float64(1.1), "b": float64(3.3)}}}, + {Script: `a["b"] = "c"`, Input: map[string]interface{}{"a": map[string]string{"a": "a", "b": "b"}}, RunOutput: "c", Output: map[string]interface{}{"a": map[string]string{"a": "a", "b": "c"}}}, + + {Script: `a[c] = "x"`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": true}, RunError: fmt.Errorf("index type bool cannot be used for map index type string"), RunOutput: nil, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}, "c": true}}, + {Script: `a[c] = "x"`, Input: map[string]interface{}{"a": map[bool]interface{}{true: "b"}, "c": true}, RunOutput: "x", Output: map[string]interface{}{"a": map[bool]interface{}{true: "x"}, "c": true}}, + + // note if passed an uninitialized map there does not seem to be a way to update that map + {Script: `a`, Input: map[string]interface{}{"a": testMapEmpty}, RunOutput: testMapEmpty, Output: map[string]interface{}{"a": testMapEmpty}}, + {Script: `a.b`, Input: map[string]interface{}{"a": testMapEmpty}, RunOutput: nil, Output: map[string]interface{}{"a": testMapEmpty}}, + {Script: `a.b = 1`, Input: map[string]interface{}{"a": testMapEmpty}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": testMapEmpty}, RunOutput: nil, Output: map[string]interface{}{"a": testMapEmpty}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": testMapEmpty}, RunOutput: nil, Output: map[string]interface{}{"a": testMapEmpty}}, + {Script: `a["b"] = 1`, Input: map[string]interface{}{"a": testMapEmpty}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1)}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": testMapEmpty}, RunOutput: nil, Output: map[string]interface{}{"a": testMapEmpty}}, + + {Script: `a`, Input: map[string]interface{}{"a": testMap}, RunOutput: testMap, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.a`, Input: map[string]interface{}{"a": testMap}, RunOutput: nil, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.a = true`, Input: map[string]interface{}{"a": testMap}, RunOutput: true, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.a`, Input: map[string]interface{}{"a": testMap}, RunOutput: true, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.a = nil`, Input: map[string]interface{}{"a": testMap}, RunOutput: nil, Output: map[string]interface{}{"a": testMap}}, + + {Script: `a`, Input: map[string]interface{}{"a": testMap}, RunOutput: testMap, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.b`, Input: map[string]interface{}{"a": testMap}, RunOutput: true, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.b = false`, Input: map[string]interface{}{"a": testMap}, RunOutput: false, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.b`, Input: map[string]interface{}{"a": testMap}, RunOutput: false, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.b = true`, Input: map[string]interface{}{"a": testMap}, RunOutput: true, Output: map[string]interface{}{"a": testMap}}, + + {Script: `a`, Input: map[string]interface{}{"a": testMap}, RunOutput: testMap, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.c`, Input: map[string]interface{}{"a": testMap}, RunOutput: int64(1), Output: map[string]interface{}{"a": testMap}}, + {Script: `a.c = 2`, Input: map[string]interface{}{"a": testMap}, RunOutput: int64(2), Output: map[string]interface{}{"a": testMap}}, + {Script: `a.c`, Input: map[string]interface{}{"a": testMap}, RunOutput: int64(2), Output: map[string]interface{}{"a": testMap}}, + {Script: `a.c = 1`, Input: map[string]interface{}{"a": testMap}, RunOutput: int64(1), Output: map[string]interface{}{"a": testMap}}, + + {Script: `a`, Input: map[string]interface{}{"a": testMap}, RunOutput: testMap, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.d`, Input: map[string]interface{}{"a": testMap}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": testMap}}, + {Script: `a.d = 2.2`, Input: map[string]interface{}{"a": testMap}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": testMap}}, + {Script: `a.d`, Input: map[string]interface{}{"a": testMap}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": testMap}}, + {Script: `a.d = 1.1`, Input: map[string]interface{}{"a": testMap}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": testMap}}, + + {Script: `a`, Input: map[string]interface{}{"a": testMap}, RunOutput: testMap, Output: map[string]interface{}{"a": testMap}}, + {Script: `a.e`, Input: map[string]interface{}{"a": testMap}, RunOutput: "e", Output: map[string]interface{}{"a": testMap}}, + {Script: `a.e = "x"`, Input: map[string]interface{}{"a": testMap}, RunOutput: "x", Output: map[string]interface{}{"a": testMap}}, + {Script: `a.e`, Input: map[string]interface{}{"a": testMap}, RunOutput: "x", Output: map[string]interface{}{"a": testMap}}, + {Script: `a.e = "e"`, Input: map[string]interface{}{"a": testMap}, RunOutput: "e", Output: map[string]interface{}{"a": testMap}}, + + {Script: `a = {"b": 1, "c": nil}`, RunOutput: map[interface{}]interface{}{"b": int64(1), "c": nil}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.b`, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.c`, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.d`, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + + {Script: `a = {"b": 1, "c": nil}; a == nil`, RunOutput: false, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a != nil`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.b == nil`, RunOutput: false, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.b != nil`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.c == nil`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.c != nil`, RunOutput: false, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.d == nil`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.d != nil`, RunOutput: false, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + + {Script: `a = {"b": 1, "c": nil}; a == 1`, RunOutput: false, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a != 1`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.b == 1`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.b != 1`, RunOutput: false, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.c == 1`, RunOutput: false, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.c != 1`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.d == 1`, RunOutput: false, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + {Script: `a = {"b": 1, "c": nil}; a.d != 1`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": int64(1), "c": nil}}}, + + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[interface{}]bool{"b": true}}, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]bool{"b": true}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[interface{}]int32{"b": int32(1)}}, RunOutput: int32(1), Output: map[string]interface{}{"a": map[interface{}]int32{"b": int32(1)}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[interface{}]int64{"b": int64(1)}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]int64{"b": int64(1)}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[interface{}]float32{"b": float32(1.1)}}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": map[interface{}]float32{"b": float32(1.1)}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[interface{}]float64{"b": float64(1.1)}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]float64{"b": float64(1.1)}}}, + {Script: `a["b"]`, Input: map[string]interface{}{"a": map[interface{}]string{"b": "b"}}, RunOutput: "b", Output: map[string]interface{}{"a": map[interface{}]string{"b": "b"}}}, + + {Script: `a.b`, Input: map[string]interface{}{"a": map[interface{}]bool{"b": true}}, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]bool{"b": true}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[interface{}]int32{"b": int32(1)}}, RunOutput: int32(1), Output: map[string]interface{}{"a": map[interface{}]int32{"b": int32(1)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[interface{}]int64{"b": int64(1)}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]int64{"b": int64(1)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[interface{}]float32{"b": float32(1.1)}}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": map[interface{}]float32{"b": float32(1.1)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[interface{}]float64{"b": float64(1.1)}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]float64{"b": float64(1.1)}}}, + {Script: `a.b`, Input: map[string]interface{}{"a": map[interface{}]string{"b": "b"}}, RunOutput: "b", Output: map[string]interface{}{"a": map[interface{}]string{"b": "b"}}}, + + {Script: `a = {}; a[true] = true`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{true: true}}}, + {Script: `a = {}; a[1] = 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{int64(1): int64(1)}}}, + {Script: `a = {}; a[1.1] = 1.1`, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]interface{}{float64(1.1): float64(1.1)}}}, + + {Script: `a = {}; a[true] = true; a[true]`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{true: true}}}, + {Script: `a = {}; a[1] = 1; a[1]`, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{int64(1): int64(1)}}}, + {Script: `a = {}; a[1.1] = 1.1; a[1.1]`, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]interface{}{float64(1.1): float64(1.1)}}}, + + {Script: `a = {}; a[b] = b`, Input: map[string]interface{}{"b": nil}, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{nil: nil}}}, + {Script: `a = {}; a[b] = b`, Input: map[string]interface{}{"b": int32(1)}, RunOutput: int32(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{int32(1): int32(1)}}}, + {Script: `a = {}; a[b] = b`, Input: map[string]interface{}{"b": int64(1)}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{int64(1): int64(1)}}}, + {Script: `a = {}; a[b] = b`, Input: map[string]interface{}{"b": float32(1.1)}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": map[interface{}]interface{}{float32(1.1): float32(1.1)}}}, + {Script: `a = {}; a[b] = b`, Input: map[string]interface{}{"b": float64(1.1)}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]interface{}{float64(1.1): float64(1.1)}}}, + {Script: `a = {}; a[b] = b`, Input: map[string]interface{}{"b": "b"}, RunOutput: "b", Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b"}}}, + + {Script: `a = {}; a[b] = b; a[b]`, Input: map[string]interface{}{"b": nil}, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{nil: nil}}}, + {Script: `a = {}; a[b] = b; a[b]`, Input: map[string]interface{}{"b": int32(1)}, RunOutput: int32(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{int32(1): int32(1)}}}, + {Script: `a = {}; a[b] = b; a[b]`, Input: map[string]interface{}{"b": int64(1)}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{int64(1): int64(1)}}}, + {Script: `a = {}; a[b] = b; a[b]`, Input: map[string]interface{}{"b": float32(1.1)}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": map[interface{}]interface{}{float32(1.1): float32(1.1)}}}, + {Script: `a = {}; a[b] = b; a[b]`, Input: map[string]interface{}{"b": float64(1.1)}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]interface{}{float64(1.1): float64(1.1)}}}, + {Script: `a = {}; a[b] = b; a[b]`, Input: map[string]interface{}{"b": "b"}, RunOutput: "b", Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b"}}}, + + // test equal nil when not found + {Script: `a = {"b":"b"}; if a.c == nil { return 1 }`, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b"}}}, + {Script: `a = {"b":"b"}; if a["c"] == nil { return 1 }`, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b"}}}, + + // test map create with spacing and comma + {Script: `{"b": "b",}`, RunOutput: map[interface{}]interface{}{"b": "b"}}, + {Script: `{"b": "b" +}`, RunOutput: map[interface{}]interface{}{"b": "b"}}, + {Script: `{"b": "b", +}`, RunOutput: map[interface{}]interface{}{"b": "b"}}, + {Script: `{"b": "b", "c": "c"}`, RunOutput: map[interface{}]interface{}{"b": "b", "c": "c"}}, + {Script: `{"b": "b", "c": "c",}`, RunOutput: map[interface{}]interface{}{"b": "b", "c": "c"}}, + {Script: `{"b": "b", "c": "c" +}`, RunOutput: map[interface{}]interface{}{"b": "b", "c": "c"}}, + {Script: `{"b": "b", "c": "c", +}`, RunOutput: map[interface{}]interface{}{"b": "b", "c": "c"}}, + {Script: `{"b": "b", +"c": "c"}`, RunOutput: map[interface{}]interface{}{"b": "b", "c": "c"}}, + {Script: `{"b": "b", +"c": "c",}`, RunOutput: map[interface{}]interface{}{"b": "b", "c": "c"}}, + {Script: `{"b": "b", +"c": "c" +}`, RunOutput: map[interface{}]interface{}{"b": "b", "c": "c"}}, + {Script: `{"b": "b", +"c": "c", +}`, RunOutput: map[interface{}]interface{}{"b": "b", "c": "c"}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestExistenceOfKeyInMaps(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a = {"b":"b"}; v, ok = a[1++]`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a = {"b":"b"}; b.c, ok = a["b"]`, RunError: fmt.Errorf("undefined symbol 'b'")}, + {Script: `a = {"b":"b"}; v, b.c = a["b"]`, RunError: fmt.Errorf("undefined symbol 'b'")}, + + {Script: `a = {"b":"b"}; v, ok = a["a"]`, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b"}, "v": nil, "ok": false}}, + {Script: `a = {"b":"b"}; v, ok = a["b"]`, RunOutput: "b", Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b"}, "v": "b", "ok": true}}, + {Script: `a = {"b":"b", "c":"c"}; v, ok = a["a"]`, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b", "c": "c"}, "v": nil, "ok": false}}, + {Script: `a = {"b":"b", "c":"c"}; v, ok = a["b"]`, RunOutput: "b", Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b", "c": "c"}, "v": "b", "ok": true}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestDeleteMaps(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `delete(1++, "b")`, RunError: fmt.Errorf("invalid operation")}, + {Script: `delete({}, 1++)`, RunError: fmt.Errorf("invalid operation")}, + {Script: `delete(nil, "b")`, RunError: fmt.Errorf("first argument to delete cannot be type interface")}, + {Script: `delete(1, "b")`, RunError: fmt.Errorf("first argument to delete cannot be type int64")}, + + {Script: `delete(a, "")`, Input: map[string]interface{}{"a": testMapEmpty}, Output: map[string]interface{}{"a": testMapEmpty}}, + {Script: `delete(a, "")`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}}, + {Script: `delete(a, "a")`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}}, + {Script: `delete(a, "b")`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b"}}, Output: map[string]interface{}{"a": map[string]interface{}{}}}, + {Script: `delete(a, "a")`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b", "c": "c"}}, Output: map[string]interface{}{"a": map[string]interface{}{"b": "b", "c": "c"}}}, + {Script: `delete(a, "b")`, Input: map[string]interface{}{"a": map[string]interface{}{"b": "b", "c": "c"}}, Output: map[string]interface{}{"a": map[string]interface{}{"c": "c"}}}, + + {Script: `delete(a, 0)`, Input: map[string]interface{}{"a": map[int64]interface{}{1: 1}}, Output: map[string]interface{}{"a": map[int64]interface{}{1: 1}}}, + {Script: `delete(a, 1)`, Input: map[string]interface{}{"a": map[int64]interface{}{1: 1}}, Output: map[string]interface{}{"a": map[int64]interface{}{}}}, + {Script: `delete(a, 0)`, Input: map[string]interface{}{"a": map[int64]interface{}{1: 1, 2: 2}}, Output: map[string]interface{}{"a": map[int64]interface{}{1: 1, 2: 2}}}, + {Script: `delete(a, 1)`, Input: map[string]interface{}{"a": map[int64]interface{}{1: 1, 2: 2}}, Output: map[string]interface{}{"a": map[int64]interface{}{2: 2}}}, + + {Script: `delete({}, "")`}, + {Script: `delete({}, 1)`}, + {Script: `delete({}, "a")`}, + {Script: `delete({"b":"b"}, "")`}, + {Script: `delete({"b":"b"}, 1)`}, + {Script: `delete({"b":"b"}, "a")`}, + {Script: `delete({"b":"b"}, "b")`}, + + {Script: `a = {"b": "b"}; delete(a, "a")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b"}}}, + {Script: `a = {"b": "b"}; delete(a, "b")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = {"b": "b", "c":"c"}; delete(a, "a")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": "b", "c": "c"}}}, + {Script: `a = {"b": "b", "c":"c"}; delete(a, "b")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"c": "c"}}}, + + {Script: `a = {"b": ["b"]}; delete(a, "a")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{"b"}}}}, + {Script: `a = {"b": ["b"]}; delete(a, "b")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = {"b": ["b"], "c": ["c"]}; delete(a, "a")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{"b"}, "c": []interface{}{"c"}}}}, + {Script: `a = {"b": ["b"], "c": ["c"]}; delete(a, "b")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"c": []interface{}{"c"}}}}, + + {Script: `a = {"b": ["b"]}; b = &a; delete(*b, "a")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{"b"}}}}, + {Script: `a = {"b": ["b"]}; b = &a; delete(*b, "b")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = {"b": ["b"], "c": ["c"]}; b = &a; delete(*b, "a")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{"b"}, "c": []interface{}{"c"}}}}, + {Script: `a = {"b": ["b"], "c": ["c"]}; b = &a; delete(*b, "b")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"c": []interface{}{"c"}}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestMakeMaps(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `map[[]string]string {"a":"a"}`, RunError: fmt.Errorf("reflect.MapOf: invalid key type []string")}, + } + runTests(t, tests, nil, &Options{Debug: false}) + + tests = []Test{ + {Script: `make(mapStringBool)`, Types: map[string]interface{}{"mapStringBool": map[string]bool{}}, RunOutput: map[string]bool{}}, + {Script: `make(mapStringInt32)`, Types: map[string]interface{}{"mapStringInt32": map[string]int32{}}, RunOutput: map[string]int32{}}, + {Script: `make(mapStringInt64)`, Types: map[string]interface{}{"mapStringInt64": map[string]int64{}}, RunOutput: map[string]int64{}}, + {Script: `make(mapStringFloat32)`, Types: map[string]interface{}{"mapStringFloat32": map[string]float32{}}, RunOutput: map[string]float32{}}, + {Script: `make(mapStringFloat64)`, Types: map[string]interface{}{"mapStringFloat64": map[string]float64{}}, RunOutput: map[string]float64{}}, + {Script: `make(mapStringString)`, Types: map[string]interface{}{"mapStringString": map[string]string{}}, RunOutput: map[string]string{}}, + + {Script: `a = make(mapStringBool)`, Types: map[string]interface{}{"mapStringBool": map[string]bool{}}, RunOutput: map[string]bool{}, Output: map[string]interface{}{"a": map[string]bool{}}}, + {Script: `a = make(mapStringInt32)`, Types: map[string]interface{}{"mapStringInt32": map[string]int32{}}, RunOutput: map[string]int32{}, Output: map[string]interface{}{"a": map[string]int32{}}}, + {Script: `a = make(mapStringInt64)`, Types: map[string]interface{}{"mapStringInt64": map[string]int64{}}, RunOutput: map[string]int64{}, Output: map[string]interface{}{"a": map[string]int64{}}}, + {Script: `a = make(mapStringFloat32)`, Types: map[string]interface{}{"mapStringFloat32": map[string]float32{}}, RunOutput: map[string]float32{}, Output: map[string]interface{}{"a": map[string]float32{}}}, + {Script: `a = make(mapStringFloat64)`, Types: map[string]interface{}{"mapStringFloat64": map[string]float64{}}, RunOutput: map[string]float64{}, Output: map[string]interface{}{"a": map[string]float64{}}}, + {Script: `a = make(mapStringString)`, Types: map[string]interface{}{"mapStringString": map[string]string{}}, RunOutput: map[string]string{}, Output: map[string]interface{}{"a": map[string]string{}}}, + + {Script: `a = make(mapStringBool); a["b"] = true`, Types: map[string]interface{}{"mapStringBool": map[string]bool{"b": true}}, RunOutput: true, Output: map[string]interface{}{"a": map[string]bool{"b": true}}}, + {Script: `a = make(mapStringInt32); a["b"] = 1`, Types: map[string]interface{}{"mapStringInt32": map[string]int32{"b": int32(1)}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[string]int32{"b": int32(1)}}}, + {Script: `a = make(mapStringInt64); a["b"] = 1`, Types: map[string]interface{}{"mapStringInt64": map[string]int64{"b": int64(1)}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[string]int64{"b": int64(1)}}}, + {Script: `a = make(mapStringFloat32); a["b"] = 1.1`, Types: map[string]interface{}{"mapStringFloat32": map[string]float32{"b": float32(1.1)}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[string]float32{"b": float32(1.1)}}}, + {Script: `a = make(mapStringFloat64); a["b"] = 1.1`, Types: map[string]interface{}{"mapStringFloat64": map[string]float64{"b": float64(1.1)}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[string]float64{"b": float64(1.1)}}}, + {Script: `a = make(mapStringString); a["b"] = "b"`, Types: map[string]interface{}{"mapStringString": map[string]string{"b": "b"}}, RunOutput: "b", Output: map[string]interface{}{"a": map[string]string{"b": "b"}}}, + + {Script: `a = make(mapStringBool); a.b = true`, Types: map[string]interface{}{"mapStringBool": map[string]bool{"b": true}}, RunOutput: true, Output: map[string]interface{}{"a": map[string]bool{"b": true}}}, + + {Script: `a = make(mapInterfaceBool); a["b"] = true; a["b"]`, Types: map[string]interface{}{"mapInterfaceBool": map[interface{}]bool{}}, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]bool{"b": true}}}, + {Script: `a = make(mapInterfaceInt32); a["b"] = 1; a["b"]`, Types: map[string]interface{}{"mapInterfaceInt32": map[interface{}]int32{}}, RunOutput: int32(1), Output: map[string]interface{}{"a": map[interface{}]int32{"b": int32(1)}}}, + {Script: `a = make(mapInterfaceInt64); a["b"] = 1; a["b"]`, Types: map[string]interface{}{"mapInterfaceInt64": map[interface{}]int64{}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]int64{"b": int64(1)}}}, + {Script: `a = make(mapInterfaceFloat32); a["b"] = 1.1; a["b"]`, Types: map[string]interface{}{"mapInterfaceFloat32": map[interface{}]float32{}}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": map[interface{}]float32{"b": float32(1.1)}}}, + {Script: `a = make(mapInterfaceFloat64); a["b"] = 1.1; a["b"]`, Types: map[string]interface{}{"mapInterfaceFloat64": map[interface{}]float64{}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]float64{"b": float64(1.1)}}}, + {Script: `a = make(mapInterfaceString); a["b"] = "b"; a["b"]`, Types: map[string]interface{}{"mapInterfaceString": map[interface{}]string{}}, RunOutput: "b", Output: map[string]interface{}{"a": map[interface{}]string{"b": "b"}}}, + + {Script: `a = make(mapInterfaceBool); a.b = true; a.b`, Types: map[string]interface{}{"mapInterfaceBool": map[interface{}]bool{}}, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]bool{"b": true}}}, + {Script: `a = make(mapInterfaceInt32); a.b = 1; a.b`, Types: map[string]interface{}{"mapInterfaceInt32": map[interface{}]int32{}}, RunOutput: int32(1), Output: map[string]interface{}{"a": map[interface{}]int32{"b": int32(1)}}}, + {Script: `a = make(mapInterfaceInt64); a.b = 1; a.b`, Types: map[string]interface{}{"mapInterfaceInt64": map[interface{}]int64{}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]int64{"b": int64(1)}}}, + {Script: `a = make(mapInterfaceFloat32); a.b = 1.1; a.b`, Types: map[string]interface{}{"mapInterfaceFloat32": map[interface{}]float32{}}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": map[interface{}]float32{"b": float32(1.1)}}}, + {Script: `a = make(mapInterfaceFloat64); a.b = 1.1; a.b`, Types: map[string]interface{}{"mapInterfaceFloat64": map[interface{}]float64{}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]float64{"b": float64(1.1)}}}, + {Script: `a = make(mapInterfaceString); a.b = "b"; a.b`, Types: map[string]interface{}{"mapInterfaceString": map[interface{}]string{}}, RunOutput: "b", Output: map[string]interface{}{"a": map[interface{}]string{"b": "b"}}}, + + // map type errors + {Script: `map[int64]string {"a":"a"}`, RunError: fmt.Errorf("cannot use type string as type int64 as map key")}, + {Script: `map[string]int64 {"a":"a"}`, RunError: fmt.Errorf("cannot use type string as type int64 as map value")}, + {Script: `map[nilT]interface {"a":"a"}`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `map[interface]nilT {"a":"a"}`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `map[int64]int64 {1++:1}`, RunError: fmt.Errorf("invalid operation")}, + {Script: `map[int64]int64 {1:1++}`, RunError: fmt.Errorf("invalid operation")}, + + // map type + {Script: `map[string]interface {"a":nil}`, RunOutput: map[string]interface{}{"a": nil}}, + {Script: `map[string]bool {"a":true}`, RunOutput: map[string]bool{"a": true}}, + {Script: `map[string]int32 {"a":1}`, RunOutput: map[string]int32{"a": 1}}, + {Script: `map[string]int64 {"a":2}`, RunOutput: map[string]int64{"a": 2}}, + {Script: `map[string]float32 {"a":3.5}`, RunOutput: map[string]float32{"a": 3.5}}, + {Script: `map[string]float64 {"a":4.5}`, RunOutput: map[string]float64{"a": 4.5}}, + {Script: `map[string]string {"a":"a"}`, RunOutput: map[string]string{"a": "a"}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestSlicesAndMaps(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a = [{"b": nil}]`, RunOutput: []interface{}{map[interface{}]interface{}{"b": interface{}(nil)}}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": interface{}(nil)}}}}, + {Script: `a = [{"b": true}]`, RunOutput: []interface{}{map[interface{}]interface{}{"b": interface{}(true)}}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": interface{}(true)}}}}, + {Script: `a = [{"b": 1}]`, RunOutput: []interface{}{map[interface{}]interface{}{"b": interface{}(int64(1))}}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": interface{}(int64(1))}}}}, + {Script: `a = [{"b": 1.1}]`, RunOutput: []interface{}{map[interface{}]interface{}{"b": interface{}(float64(1.1))}}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": interface{}(float64(1.1))}}}}, + {Script: `a = [{"b": "b"}]`, RunOutput: []interface{}{map[interface{}]interface{}{"b": interface{}("b")}}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": interface{}("b")}}}}, + + {Script: `a = [{"b": nil}]; a[0]`, RunOutput: map[interface{}]interface{}{"b": interface{}(nil)}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": interface{}(nil)}}}}, + {Script: `a = [{"b": true}]; a[0]`, RunOutput: map[interface{}]interface{}{"b": interface{}(true)}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": interface{}(true)}}}}, + {Script: `a = [{"b": 1}]; a[0]`, RunOutput: map[interface{}]interface{}{"b": interface{}(int64(1))}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": interface{}(int64(1))}}}}, + {Script: `a = [{"b": 1.1}]; a[0]`, RunOutput: map[interface{}]interface{}{"b": interface{}(float64(1.1))}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": interface{}(float64(1.1))}}}}, + {Script: `a = [{"b": "b"}]; a[0]`, RunOutput: map[interface{}]interface{}{"b": interface{}("b")}, Output: map[string]interface{}{"a": []interface{}{map[interface{}]interface{}{"b": interface{}("b")}}}}, + + {Script: `a = {"b": []}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{}}}}, + {Script: `a = {"b": [nil]}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{nil}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{nil}}}}, + {Script: `a = {"b": [true]}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{true}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{true}}}}, + {Script: `a = {"b": [1]}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{int64(1)}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{int64(1)}}}}, + {Script: `a = {"b": [1.1]}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{float64(1.1)}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{float64(1.1)}}}}, + {Script: `a = {"b": ["b"]}`, RunOutput: map[interface{}]interface{}{"b": []interface{}{"b"}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{"b"}}}}, + + {Script: `a = {"b": []}; a.b`, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{}}}}, + {Script: `a = {"b": [nil]}; a.b`, RunOutput: []interface{}{nil}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{nil}}}}, + {Script: `a = {"b": [true]}; a.b`, RunOutput: []interface{}{true}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{true}}}}, + {Script: `a = {"b": [1]}; a.b`, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{int64(1)}}}}, + {Script: `a = {"b": [1.1]}; a.b`, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{float64(1.1)}}}}, + {Script: `a = {"b": ["b"]}; a.b`, RunOutput: []interface{}{"b"}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{"b"}}}}, + + {Script: `a.b = []`, Input: map[string]interface{}{"a": map[string][]interface{}{}}, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": map[string][]interface{}{"b": {}}}}, + {Script: `a.b = [nil]`, Input: map[string]interface{}{"a": map[string][]interface{}{}}, RunOutput: []interface{}{interface{}(nil)}, Output: map[string]interface{}{"a": map[string][]interface{}{"b": {interface{}(nil)}}}}, + {Script: `a.b = [true]`, Input: map[string]interface{}{"a": map[string][]interface{}{}}, RunOutput: []interface{}{true}, Output: map[string]interface{}{"a": map[string][]interface{}{"b": {true}}}}, + {Script: `a.b = [1]`, Input: map[string]interface{}{"a": map[string][]interface{}{}}, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": map[string][]interface{}{"b": {int64(1)}}}}, + {Script: `a.b = [1.1]`, Input: map[string]interface{}{"a": map[string][]interface{}{}}, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": map[string][]interface{}{"b": {float64(1.1)}}}}, + {Script: `a.b = ["b"]`, Input: map[string]interface{}{"a": map[string][]interface{}{}}, RunOutput: []interface{}{"b"}, Output: map[string]interface{}{"a": map[string][]interface{}{"b": {"b"}}}}, + + {Script: `b[0] = [nil]; a.b = b`, Input: map[string]interface{}{"a": map[string][][]interface{}{}, "b": [][]interface{}{}}, RunOutput: [][]interface{}{{interface{}(nil)}}, Output: map[string]interface{}{"a": map[string][][]interface{}{"b": {{interface{}(nil)}}}, "b": [][]interface{}{{interface{}(nil)}}}}, + {Script: `b[0] = [true]; a.b = b`, Input: map[string]interface{}{"a": map[string][][]interface{}{}, "b": [][]interface{}{}}, RunOutput: [][]interface{}{{true}}, Output: map[string]interface{}{"a": map[string][][]interface{}{"b": {{true}}}, "b": [][]interface{}{{true}}}}, + {Script: `b[0] = [1]; a.b = b`, Input: map[string]interface{}{"a": map[string][][]interface{}{}, "b": [][]interface{}{}}, RunOutput: [][]interface{}{{int64(1)}}, Output: map[string]interface{}{"a": map[string][][]interface{}{"b": {{int64(1)}}}, "b": [][]interface{}{{int64(1)}}}}, + {Script: `b[0] = [1.1]; a.b = b`, Input: map[string]interface{}{"a": map[string][][]interface{}{}, "b": [][]interface{}{}}, RunOutput: [][]interface{}{{float64(1.1)}}, Output: map[string]interface{}{"a": map[string][][]interface{}{"b": {{float64(1.1)}}}, "b": [][]interface{}{{float64(1.1)}}}}, + {Script: `b[0] = ["b"]; a.b = b`, Input: map[string]interface{}{"a": map[string][][]interface{}{}, "b": [][]interface{}{}}, RunOutput: [][]interface{}{{"b"}}, Output: map[string]interface{}{"a": map[string][][]interface{}{"b": {{"b"}}}, "b": [][]interface{}{{"b"}}}}, + + {Script: `a`, Input: map[string]interface{}{"a": map[string][][]interface{}{}}, RunOutput: map[string][][]interface{}{}, Output: map[string]interface{}{"a": map[string][][]interface{}{}}}, + {Script: `a.b = 1`, Input: map[string]interface{}{"a": map[string][][]interface{}{}}, RunError: fmt.Errorf("type int64 cannot be assigned to type [][]interface {} for map"), RunOutput: nil, Output: map[string]interface{}{"a": map[string][][]interface{}{}}}, + {Script: `a["b"] = 1`, Input: map[string]interface{}{"a": map[string][][]interface{}{}}, RunError: fmt.Errorf("type int64 cannot be assigned to type [][]interface {} for map"), RunOutput: nil, Output: map[string]interface{}{"a": map[string][][]interface{}{}}}, + + {Script: `a = {}; a.b = []; a.b += 1; a.b[0] = {}; a.b[0].c = []; a.b[0].c += 2; a.b[0].c[0]`, RunOutput: int64(2), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": []interface{}{map[interface{}]interface{}{"c": []interface{}{int64(2)}}}}}}, + + {Script: `a = {}; a.b = b`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: [][]interface{}{}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: [][]interface{}{}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunError: fmt.Errorf("index out of range"), RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{}}, "b": [][]interface{}{}}}, + + {Script: `a = {}; a.b = b; a.b[0] = []`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: []interface{}{}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [nil]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: []interface{}{nil}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{nil}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [nil]; a.b`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: [][]interface{}{{nil}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{nil}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [true]; a.b`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: [][]interface{}{{true}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{true}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [1]; a.b`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: [][]interface{}{{int64(1)}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{int64(1)}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [1.1]; a.b`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: [][]interface{}{{float64(1.1)}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{float64(1.1)}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = ["c"]; a.b`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: [][]interface{}{{"c"}}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{"c"}}}, "b": [][]interface{}{}}}, + + {Script: `a = {}; a.b = b; a.b[0] = [nil]; a.b[0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: []interface{}{nil}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{nil}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [true]; a.b[0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: []interface{}{true}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{true}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [1]; a.b[0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: []interface{}{int64(1)}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{int64(1)}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [1.1]; a.b[0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: []interface{}{float64(1.1)}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{float64(1.1)}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = ["c"]; a.b[0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: []interface{}{"c"}, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{"c"}}}, "b": [][]interface{}{}}}, + + {Script: `a = {}; a.b = b; a.b[0] = [nil]; a.b[0][0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{nil}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [true]; a.b[0][0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{true}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [1]; a.b[0][0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{int64(1)}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [1.1]; a.b[0][0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{float64(1.1)}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = ["c"]; a.b[0][0]`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: "c", Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{"c"}}}, "b": [][]interface{}{}}}, + + {Script: `a = {}; a.b = b; a.b[0] = [nil]; a.b[0][1] = nil`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{nil, nil}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [true]; a.b[0][1] = true`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{true, true}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [1]; a.b[0][1] = 2`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: int64(2), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{int64(1), int64(2)}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = [1.1]; a.b[0][1] = 2.2`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{float64(1.1), float64(2.2)}}}, "b": [][]interface{}{}}}, + {Script: `a = {}; a.b = b; a.b[0] = ["c"]; a.b[0][1] = "d"`, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: "d", Output: map[string]interface{}{"a": map[interface{}]interface{}{"b": [][]interface{}{{"c", "d"}}}, "b": [][]interface{}{}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestMakeSlicesAndMaps(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `make([]aMap)`, Types: map[string]interface{}{"aMap": map[string]interface{}{}}, RunOutput: []map[string]interface{}{}}, + {Script: `make([][]aMap)`, Types: map[string]interface{}{"aMap": map[string]interface{}{}}, RunOutput: [][]map[string]interface{}{}}, + + {Script: `make(mapSlice2x)`, Types: map[string]interface{}{"mapSlice2x": map[string][][]interface{}{}}, RunOutput: map[string][][]interface{}{}}, + {Script: `a = make(mapSlice2x)`, Types: map[string]interface{}{"mapSlice2x": map[string][][]interface{}{}}, RunOutput: map[string][][]interface{}{}, Output: map[string]interface{}{"a": map[string][][]interface{}{}}}, + {Script: `a = make(mapSlice2x); a`, Types: map[string]interface{}{"mapSlice2x": map[string][][]interface{}{}}, RunOutput: map[string][][]interface{}{}, Output: map[string]interface{}{"a": map[string][][]interface{}{}}}, + {Script: `a = make(mapSlice2x); a.b = b`, Types: map[string]interface{}{"mapSlice2x": map[string][][]interface{}{}}, Input: map[string]interface{}{"b": [][]interface{}{}}, RunOutput: [][]interface{}{}, Output: map[string]interface{}{"a": map[string][][]interface{}{"b": {}}, "b": [][]interface{}{}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestMakeSlicesData(t *testing.T) { + t.Parallel() + + stmts, err := parser.ParseSrc("make(slice)") + if err != nil { + t.Errorf("ParseSrc error - received %v - expected: %v", err, nil) + } + + e := env.NewEnv() + err = e.DefineType("slice", []string{}) + if err != nil { + t.Errorf("DefineType error - received %v - expected: %v", err, nil) + } + + value, err := Run(e, nil, stmts) + if err != nil { + t.Errorf("Run error - received %v - expected: %v", err, nil) + } + if !reflect.DeepEqual(value, []string{}) { + t.Errorf("Run value - received %#v - expected: %#v", value, []string{}) + } + + a := value.([]string) + if len(a) != 0 { + t.Errorf("len value - received %#v - expected: %#v", len(a), 0) + } + a = append(a, "a") + if a[0] != "a" { + t.Errorf("Get value - received %#v - expected: %#v", a[0], "a") + } + if len(a) != 1 { + t.Errorf("len value - received %#v - expected: %#v", len(a), 1) + } + + stmts, err = parser.ParseSrc("make([]string)") + if err != nil { + t.Errorf("ParseSrc error - received %v - expected: %v", err, nil) + } + + e = env.NewEnv() + err = e.DefineType("string", "a") + if err != nil { + t.Errorf("DefineType error - received %v - expected: %v", err, nil) + } + + value, err = Run(e, nil, stmts) + if err != nil { + t.Errorf("Run error - received %v - expected: %v", err, nil) + } + if !reflect.DeepEqual(value, []string{}) { + t.Errorf("Run value - received %#v - expected: %#v", value, []string{}) + } + + b := value.([]string) + if len(b) != 0 { + t.Errorf("len value - received %#v - expected: %#v", len(b), 0) + } + b = append(b, "b") + if b[0] != "b" { + t.Errorf("Get value - received %#v - expected: %#v", b[0], "b") + } + if len(b) != 1 { + t.Errorf("len value - received %#v - expected: %#v", len(b), 1) + } +} + +func TestMakeMapsData(t *testing.T) { + t.Parallel() + + stmts, err := parser.ParseSrc("make(aMap)") + if err != nil { + t.Errorf("ParseSrc error - received %v - expected: %v", err, nil) + } + + // test normal map + e := env.NewEnv() + err = e.DefineType("aMap", map[string]string{}) + if err != nil { + t.Errorf("DefineType error - received %v - expected: %v", err, nil) + } + + value, err := Run(e, nil, stmts) + if err != nil { + t.Errorf("Run error - received %v - expected: %v", err, nil) + } + if !reflect.DeepEqual(value, map[string]string{}) { + t.Errorf("Run value - received %#v - expected: %#v", value, map[string]string{}) + } + + a := value.(map[string]string) + a["a"] = "a" + if a["a"] != "a" { + t.Errorf("Get value - received %#v - expected: %#v", a["a"], "a") + } + + // test url Values map + e = env.NewEnv() + err = e.DefineType("aMap", url.Values{}) + if err != nil { + t.Errorf("DefineType error - received %v - expected: %v", err, nil) + } + + value, err = Run(e, nil, stmts) + if err != nil { + t.Errorf("Run error - received %v - expected: %v", err, nil) + } + if !reflect.DeepEqual(value, url.Values{}) { + t.Errorf("Run value - received %#v - expected: %#v", value, url.Values{}) + } + + b := value.(url.Values) + b.Set("b", "b") + if b.Get("b") != "b" { + t.Errorf("Get value - received %#v - expected: %#v", b.Get("b"), "b") + } +} + +func TestStructs(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a["B"]`, Input: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{}}, + RunError: fmt.Errorf("type struct does not support index operation"), + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{}}}, + {Script: `a.C`, Input: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{}}, + RunError: fmt.Errorf("no member named 'C' for struct"), + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{}}}, + + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{}}, + RunOutput: nil, + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: nil, B: nil}}, + RunOutput: nil, + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: nil, B: nil}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: int32(1), B: int32(2)}}, + RunOutput: int32(2), + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: int32(1), B: int32(2)}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: int64(1), B: int64(2)}}, + RunOutput: int64(2), + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: int64(1), B: int64(2)}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: float32(1.1), B: float32(2.2)}}, + RunOutput: float32(2.2), + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: float32(1.1), B: float32(2.2)}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: float64(1.1), B: float64(2.2)}}, + RunOutput: float64(2.2), + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: float64(1.1), B: float64(2.2)}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: "a", B: "b"}}, + RunOutput: "b", + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: "a", B: "b"}}}, + + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A bool + B bool + }{}}, + RunOutput: false, + Output: map[string]interface{}{"a": struct { + A bool + B bool + }{}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A int32 + B int32 + }{}}, + RunOutput: int32(0), + Output: map[string]interface{}{"a": struct { + A int32 + B int32 + }{}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A int64 + B int64 + }{}}, + RunOutput: int64(0), + Output: map[string]interface{}{"a": struct { + A int64 + B int64 + }{}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A float32 + B float32 + }{}}, + RunOutput: float32(0), + Output: map[string]interface{}{"a": struct { + A float32 + B float32 + }{}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A float64 + B float64 + }{}}, + RunOutput: float64(0), + Output: map[string]interface{}{"a": struct { + A float64 + B float64 + }{}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A string + B string + }{}}, + RunOutput: "", + Output: map[string]interface{}{"a": struct { + A string + B string + }{}}}, + + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A bool + B bool + }{A: true, B: true}}, + RunOutput: true, + Output: map[string]interface{}{"a": struct { + A bool + B bool + }{A: true, B: true}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A int32 + B int32 + }{A: int32(1), B: int32(2)}}, + RunOutput: int32(2), + Output: map[string]interface{}{"a": struct { + A int32 + B int32 + }{A: int32(1), B: int32(2)}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A int64 + B int64 + }{A: int64(1), B: int64(2)}}, + RunOutput: int64(2), + Output: map[string]interface{}{"a": struct { + A int64 + B int64 + }{A: int64(1), B: int64(2)}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A float32 + B float32 + }{A: float32(1.1), B: float32(2.2)}}, + RunOutput: float32(2.2), + Output: map[string]interface{}{"a": struct { + A float32 + B float32 + }{A: float32(1.1), B: float32(2.2)}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A float64 + B float64 + }{A: float64(1.1), B: float64(2.2)}}, + RunOutput: float64(2.2), + Output: map[string]interface{}{"a": struct { + A float64 + B float64 + }{A: float64(1.1), B: float64(2.2)}}}, + {Script: `a.B`, Input: map[string]interface{}{"a": struct { + A string + B string + }{A: "a", B: "b"}}, + RunOutput: "b", + Output: map[string]interface{}{"a": struct { + A string + B string + }{A: "a", B: "b"}}}, + + {Script: `a.C = 3`, Input: map[string]interface{}{ + "a": struct { + A interface{} + B interface{} + }{A: int64(1), B: int64(2)}, + }, + RunError: fmt.Errorf("no member named 'C' for struct"), + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: int64(1), B: int64(2)}}}, + + {Script: `a.B = 3`, Input: map[string]interface{}{"a": &struct { + A interface{} + B interface{} + }{A: int64(1), B: int64(2)}}, + RunOutput: int64(3), + Output: map[string]interface{}{"a": &struct { + A interface{} + B interface{} + }{A: int64(1), B: int64(3)}}}, + + {Script: `a.B = 3; a = *a`, Input: map[string]interface{}{"a": &struct { + A interface{} + B interface{} + }{A: int64(1), B: int64(2)}}, + RunOutput: struct { + A interface{} + B interface{} + }{A: int64(1), B: int64(3)}, + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: int64(1), B: int64(3)}}}, + + // nil tests + {Script: `a.A = nil; a.B = nil; a.C = nil;`, Input: map[string]interface{}{"a": &struct { + A *bool + B *int32 + C *int64 + }{A: new(bool), B: new(int32), C: new(int64)}}, + RunOutput: nil, + Output: map[string]interface{}{"a": &struct { + A *bool + B *int32 + C *int64 + }{A: nil, B: nil, C: nil}}}, + {Script: `a.A = nil; a.B = nil; a.C = nil;`, Input: map[string]interface{}{"a": &struct { + A *float32 + B *float64 + C *string + }{A: new(float32), B: new(float64), C: new(string)}}, + RunOutput: nil, + Output: map[string]interface{}{"a": &struct { + A *float32 + B *float64 + C *string + }{A: nil, B: nil, C: nil}}}, + {Script: `a.A = nil; a.B = nil; a.C = nil;`, Input: map[string]interface{}{"a": &struct { + A interface{} + B []interface{} + C [][]interface{} + }{A: "a", B: []interface{}{"b"}, C: [][]interface{}{{"c"}}}}, + RunOutput: nil, + Output: map[string]interface{}{"a": &struct { + A interface{} + B []interface{} + C [][]interface{} + }{A: nil, B: nil, C: nil}}}, + {Script: `a.A = nil; a.B = nil; a.C = nil; a.D = nil;`, Input: map[string]interface{}{"a": &struct { + A map[string]string + B map[string]interface{} + C map[interface{}]string + D map[interface{}]interface{} + }{A: map[string]string{"a": "a"}, B: map[string]interface{}{"b": "b"}, C: map[interface{}]string{"c": "c"}, D: map[interface{}]interface{}{"d": "d"}}}, + RunOutput: nil, + Output: map[string]interface{}{"a": &struct { + A map[string]string + B map[string]interface{} + C map[interface{}]string + D map[interface{}]interface{} + }{A: nil, B: nil, C: nil, D: nil}}}, + {Script: `a.A.AA = nil;`, Input: map[string]interface{}{"a": &struct { + A struct{ AA *int64 } + }{A: struct{ AA *int64 }{AA: new(int64)}}}, + RunOutput: nil, + Output: map[string]interface{}{"a": &struct { + A struct{ AA *int64 } + }{A: struct{ AA *int64 }{AA: nil}}}}, + {Script: `a.A = nil;`, Input: map[string]interface{}{"a": &struct { + A *struct{ AA *int64 } + }{A: &struct{ AA *int64 }{AA: new(int64)}}}, + RunOutput: nil, + Output: map[string]interface{}{"a": &struct { + A *struct{ AA *int64 } + }{A: nil}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestMakeStructs(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a = make(struct1)`, Types: map[string]interface{}{"struct1": &testStruct1{}}, RunOutput: &testStruct1{}, Output: map[string]interface{}{"a": &testStruct1{}}}, + {Script: `a = make(struct2)`, Types: map[string]interface{}{"struct2": &testStruct2{}}, RunOutput: &testStruct2{}, Output: map[string]interface{}{"a": &testStruct2{}}}, + {Script: `make(struct1)`, Types: map[string]interface{}{"struct1": &struct { + A interface{} + B interface{} + }{}}, + RunOutput: &struct { + A interface{} + B interface{} + }{}}, + + {Script: `a = make(struct1)`, Types: map[string]interface{}{"struct1": &struct { + A interface{} + B interface{} + }{}}, + RunOutput: &struct { + A interface{} + B interface{} + }{}, + Output: map[string]interface{}{"a": &struct { + A interface{} + B interface{} + }{}}}, + + {Script: `a = make(struct1); a.A = 3; a.B = 4`, Types: map[string]interface{}{"struct1": &struct { + A interface{} + B interface{} + }{}}, + RunOutput: int64(4), + Output: map[string]interface{}{"a": &struct { + A interface{} + B interface{} + }{A: interface{}(int64(3)), B: interface{}(int64(4))}}}, + + {Script: `a = make(struct1); a = *a; a.A = 3; a.B = 4`, Types: map[string]interface{}{"struct1": &struct { + A interface{} + B interface{} + }{}}, + RunOutput: int64(4), + Output: map[string]interface{}{"a": struct { + A interface{} + B interface{} + }{A: interface{}(int64(3)), B: interface{}(int64(4))}}}, + + {Script: `a = make(struct1); a.A = func () { return 1 }; a.A()`, Types: map[string]interface{}{"struct1": &struct { + A interface{} + B interface{} + }{}}, + RunOutput: int64(1)}, + {Script: `a = make(struct1); a.A = func () { return 1 }; a = *a; a.A()`, Types: map[string]interface{}{"struct1": &struct { + A interface{} + B interface{} + }{}}, + RunOutput: int64(1)}, + + // make struct - new lines + {Script: `make(struct { A int64, B float64 })`, RunOutput: struct { + A int64 + B float64 + }{}}, + {Script: `make(struct { +A int64, B float64 })`, RunOutput: struct { + A int64 + B float64 + }{}}, + {Script: `make(struct { A int64, +B float64 })`, RunOutput: struct { + A int64 + B float64 + }{}}, + {Script: `make(struct { A int64, B float64 +})`, RunOutput: struct { + A int64 + B float64 + }{}}, + {Script: ` +make(struct { + A int64, + B float64 +})`, RunOutput: struct { + A int64 + B float64 + }{}}, + + // make struct - with basic types + {Script: ` +make(struct { + A bool, + B int32, + C int64, + D float32, + E float64, + F string +})`, RunOutput: struct { + A bool + B int32 + C int64 + D float32 + E float64 + F string + }{}}, + + // make struct - with other types + {Script: ` +make(struct { + A *int64, + B []int64, + C map[string]int64 +})`, RunOutput: struct { + A *int64 + B []int64 + C map[string]int64 + }{A: (*int64)(nil), B: []int64{}, C: map[string]int64{}}}, + + // make struct within structs + {Script: ` +make(struct { + A struct { + AA int64, + AB float64 + }, + B struct { + BA []int64, + BB map[string]int64 + } +})`, RunOutput: struct { + A struct { + AA int64 + AB float64 + } + B struct { + BA []int64 + BB map[string]int64 + } + }{A: struct { + AA int64 + AB float64 + }{AA: 0, AB: 0}, B: struct { + BA []int64 + BB map[string]int64 + }{BA: []int64{}, BB: map[string]int64{}}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} diff --git a/src/tool/run/vm/vmConvertToX.go b/src/tool/run/vm/vmConvertToX.go new file mode 100644 index 0000000..38a0032 --- /dev/null +++ b/src/tool/run/vm/vmConvertToX.go @@ -0,0 +1,206 @@ +package vm + +import ( + "context" + "fmt" + "reflect" +) + +// reflectValueSlicetoInterfaceSlice convert from a slice of reflect.Value to a interface slice +// returned in normal reflect.Value form +func reflectValueSlicetoInterfaceSlice(valueSlice []reflect.Value) reflect.Value { + interfaceSlice := make([]interface{}, 0, len(valueSlice)) + for _, value := range valueSlice { + if value.Kind() == reflect.Interface && !value.IsNil() { + value = value.Elem() + } + if value.CanInterface() { + interfaceSlice = append(interfaceSlice, value.Interface()) + } else { + interfaceSlice = append(interfaceSlice, nil) + } + } + return reflect.ValueOf(interfaceSlice) +} + +// convertReflectValueToType trys to covert the reflect.Value to the reflect.Type +// if it can not, it returns the original rv and an error +func convertReflectValueToType(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { + if rt == interfaceType || rv.Type() == rt { + // if reflect.Type is interface or the types match, return the provided reflect.Value + return rv, nil + } + if rv.Type().ConvertibleTo(rt) { + // if reflect can covert, do that conversion and return + return rv.Convert(rt), nil + } + if (rv.Kind() == reflect.Slice || rv.Kind() == reflect.Array) && + (rt.Kind() == reflect.Slice || rt.Kind() == reflect.Array) { + // covert slice or array + return convertSliceOrArray(rv, rt) + } + if rv.Kind() == rt.Kind() { + // kind matches + switch rv.Kind() { + case reflect.Map: + // convert map + return convertMap(rv, rt) + case reflect.Func: + // for runVMFunction conversions, call convertVMFunctionToType + return convertVMFunctionToType(rv, rt) + case reflect.Ptr: + // both rv and rt are pointers, convert what they are pointing to + value, err := convertReflectValueToType(rv.Elem(), rt.Elem()) + if err != nil { + return rv, err + } + // need to make a new value to be able to set it + ptrV, err := makeValue(rt) + if err != nil { + return rv, err + } + // set value and return new pointer + ptrV.Elem().Set(value) + return ptrV, nil + } + } + if rv.Type() == interfaceType { + if rv.IsNil() { + // return nil of correct type + return reflect.Zero(rt), nil + } + // try to convert the element + return convertReflectValueToType(rv.Elem(), rt) + } + + if rv.Type() == stringType { + if rt == byteType { + aString := rv.String() + if len(aString) < 1 { + return reflect.Zero(rt), nil + } + if len(aString) > 1 { + return rv, errInvalidTypeConversion + } + return reflect.ValueOf(aString[0]), nil + } + if rt == runeType { + aString := rv.String() + if len(aString) < 1 { + return reflect.Zero(rt), nil + } + if len(aString) > 1 { + return rv, errInvalidTypeConversion + } + return reflect.ValueOf(rune(aString[0])), nil + } + } + + // TODO: need to handle the case where either rv or rt are a pointer but not both + + return rv, errInvalidTypeConversion +} + +// convertSliceOrArray trys to covert the reflect.Value slice or array to the slice or array reflect.Type +func convertSliceOrArray(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { + rtElemType := rt.Elem() + + // try to covert elements to new slice/array + var value reflect.Value + if rt.Kind() == reflect.Slice { + // make slice + value = reflect.MakeSlice(rt, rv.Len(), rv.Len()) + } else { + // make array + value = reflect.New(rt).Elem() + } + + var err error + var v reflect.Value + for i := 0; i < rv.Len(); i++ { + v, err = convertReflectValueToType(rv.Index(i), rtElemType) + if err != nil { + return rv, err + } + value.Index(i).Set(v) + } + + // return new converted slice or array + return value, nil +} + +// convertVMFunctionToType is for translating a runVMFunction into the correct type +// so it can be passed to a Go function argument with the correct static types +// it creates a translate function runVMConvertFunction +func convertVMFunctionToType(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { + // only translates runVMFunction type + if !checkIfRunVMFunction(rv.Type()) { + return rv, errInvalidTypeConversion + } + + // create runVMConvertFunction to match reflect.Type + // this function is being called by the Go function + runVMConvertFunction := func(in []reflect.Value) []reflect.Value { + // note: this function is being called by another reflect Call + // only way to pass along any errors is by panic + + // make the reflect.Value slice of each of the VM reflect.Value + args := make([]reflect.Value, 0, rt.NumIn()+1) + // for runVMFunction first arg is always context + // TOFIX: use normal context + args = append(args, reflect.ValueOf(context.Background())) + for i := 0; i < rt.NumIn(); i++ { + // have to do the double reflect.ValueOf that runVMFunction expects + args = append(args, reflect.ValueOf(in[i])) + } + + // Call runVMFunction + rvs := rv.Call(args) + + // call processCallReturnValues to process runVMFunction return values + // returns normal VM reflect.Value form + rv, err := processCallReturnValues(rvs, true, false) + if err != nil { + panic(err) + } + + if rt.NumOut() < 1 { + // Go function does not want any return values, so give it none + return []reflect.Value{} + } + if rt.NumOut() < 2 { + // Go function wants one return value + // will try to covert to reflect.Value correct type and return + rv, err = convertReflectValueToType(rv, rt.Out(0)) + if err != nil { + panic("function wants return type " + rt.Out(0).String() + " but received type " + rv.Type().String()) + } + return []reflect.Value{rv} + } + + // Go function wants more than one return value + // make sure we have a slice/array with enought values + + if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array { + panic(fmt.Sprintf("function wants %v return values but received %v", rt.NumOut(), rv.Kind().String())) + } + if rv.Len() < rt.NumOut() { + panic(fmt.Sprintf("function wants %v return values but received %v values", rt.NumOut(), rv.Len())) + } + + // try to covert each value in slice to wanted type and put into a reflect.Value slice + rvs = make([]reflect.Value, rt.NumOut()) + for i := 0; i < rv.Len(); i++ { + rvs[i], err = convertReflectValueToType(rv.Index(i), rt.Out(i)) + if err != nil { + panic("function wants return type " + rt.Out(i).String() + " but received type " + rvs[i].Type().String()) + } + } + + // return created reflect.Value slice + return rvs + } + + // make the reflect.Value function that calls runVMConvertFunction + return reflect.MakeFunc(rt, runVMConvertFunction), nil +} diff --git a/src/tool/run/vm/vmConvertToXGo112.go b/src/tool/run/vm/vmConvertToXGo112.go new file mode 100644 index 0000000..b42d3f5 --- /dev/null +++ b/src/tool/run/vm/vmConvertToXGo112.go @@ -0,0 +1,37 @@ +// +build go1.12 + +package vm + +import ( + "reflect" +) + +// convertMap trys to covert the reflect.Value map to the map reflect.Type +func convertMap(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { + rtKey := rt.Key() + rtElem := rt.Elem() + + // create new map + // note creating slice as work around to create map + // just doing MakeMap can give incorrect type for defined types + newMap := reflect.MakeSlice(reflect.SliceOf(rt), 0, 1) + newMap = reflect.Append(newMap, reflect.MakeMap(reflect.MapOf(rtKey, rtElem))).Index(0) + + // copy keys to new map + // For Go 1.12 and after can use MapRange + mapIter := rv.MapRange() + var value reflect.Value + for mapIter.Next() { + newKey, err := convertReflectValueToType(mapIter.Key(), rtKey) + if err != nil { + return rv, err + } + value, err = convertReflectValueToType(mapIter.Value(), rtElem) + if err != nil { + return rv, err + } + newMap.SetMapIndex(newKey, value) + } + + return newMap, nil +} diff --git a/src/tool/run/vm/vmConvertToXNotGo112.go b/src/tool/run/vm/vmConvertToXNotGo112.go new file mode 100644 index 0000000..afa2248 --- /dev/null +++ b/src/tool/run/vm/vmConvertToXNotGo112.go @@ -0,0 +1,38 @@ +// +build !go1.12 + +package vm + +import ( + "reflect" +) + +// convertMap trys to covert the reflect.Value map to the map reflect.Type +func convertMap(rv reflect.Value, rt reflect.Type) (reflect.Value, error) { + rtKey := rt.Key() + rtElem := rt.Elem() + + // create new map + // note creating slice as work around to create map + // just doing MakeMap can give incorrect type for defined types + newMap := reflect.MakeSlice(reflect.SliceOf(rt), 0, 1) + newMap = reflect.Append(newMap, reflect.MakeMap(reflect.MapOf(rtKey, rtElem))).Index(0) + + // copy keys to new map + // Before Go 1.12 the only way to do this is to get all the keys. + // Note this is costly for large maps. + mapKeys := rv.MapKeys() + for i := 0; i < len(mapKeys); i++ { + newKey, err := convertReflectValueToType(mapKeys[i], rtKey) + if err != nil { + return rv, err + } + value := rv.MapIndex(mapKeys[i]) + value, err = convertReflectValueToType(value, rtElem) + if err != nil { + return rv, err + } + newMap.SetMapIndex(newKey, value) + } + + return newMap, nil +} diff --git a/src/tool/run/vm/vmExpr.go b/src/tool/run/vm/vmExpr.go new file mode 100644 index 0000000..4644626 --- /dev/null +++ b/src/tool/run/vm/vmExpr.go @@ -0,0 +1,761 @@ +package vm + +import ( + "reflect" + + "github.com/surdeus/goblin/src/tool/run/ast" + "github.com/surdeus/goblin/src/tool/run/env" +) + +// invokeExpr evaluates one expression. +func (runInfo *runInfoStruct) invokeExpr() { + switch expr := runInfo.expr.(type) { + + // OpExpr + case *ast.OpExpr: + runInfo.operator = expr.Op + runInfo.invokeOperator() + + // IdentExpr + case *ast.IdentExpr: + runInfo.rv, runInfo.err = runInfo.env.GetValue(expr.Lit) + if runInfo.err != nil { + runInfo.err = newError(expr, runInfo.err) + } + + // LiteralExpr + case *ast.LiteralExpr: + runInfo.rv = expr.Literal + + // ArrayExpr + case *ast.ArrayExpr: + if expr.TypeData == nil { + slice := make([]interface{}, len(expr.Exprs)) + var i int + for i, runInfo.expr = range expr.Exprs { + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + slice[i] = runInfo.rv.Interface() + } + runInfo.rv = reflect.ValueOf(slice) + return + } + + t := makeType(runInfo, expr.TypeData) + if runInfo.err != nil { + runInfo.rv = nilValue + return + } + if t == nil { + runInfo.err = newStringError(expr, "cannot make type nil") + runInfo.rv = nilValue + return + } + + slice := reflect.MakeSlice(t, len(expr.Exprs), len(expr.Exprs)) + var i int + valueType := t.Elem() + for i, runInfo.expr = range expr.Exprs { + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, valueType) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "cannot use type "+runInfo.rv.Type().String()+" as type "+valueType.String()+" as slice value") + runInfo.rv = nilValue + return + } + + slice.Index(i).Set(runInfo.rv) + } + runInfo.rv = slice + + // MapExpr + case *ast.MapExpr: + if expr.TypeData == nil { + var i int + var key reflect.Value + m := make(map[interface{}]interface{}, len(expr.Keys)) + for i, runInfo.expr = range expr.Keys { + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + key = runInfo.rv + + runInfo.expr = expr.Values[i] + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + m[key.Interface()] = runInfo.rv.Interface() + } + runInfo.rv = reflect.ValueOf(m) + return + } + + t := makeType(runInfo, expr.TypeData) + if runInfo.err != nil { + runInfo.rv = nilValue + return + } + if t == nil { + runInfo.err = newStringError(expr, "cannot make type nil") + runInfo.rv = nilValue + return + } + + runInfo.rv, runInfo.err = makeValue(t) + if runInfo.err != nil { + runInfo.rv = nilValue + return + } + + var i int + var key reflect.Value + m := runInfo.rv + keyType := t.Key() + valueType := t.Elem() + for i, runInfo.expr = range expr.Keys { + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + key, runInfo.err = convertReflectValueToType(runInfo.rv, keyType) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "cannot use type "+key.Type().String()+" as type "+keyType.String()+" as map key") + runInfo.rv = nilValue + return + } + + runInfo.expr = expr.Values[i] + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, valueType) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "cannot use type "+runInfo.rv.Type().String()+" as type "+valueType.String()+" as map value") + runInfo.rv = nilValue + return + } + + m.SetMapIndex(key, runInfo.rv) + } + runInfo.rv = m + + // DerefExpr + case *ast.DerefExpr: + runInfo.expr = expr.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + if runInfo.rv.Kind() != reflect.Ptr { + runInfo.err = newStringError(expr.Expr, "cannot deference non-pointer") + runInfo.rv = nilValue + return + } + runInfo.rv = runInfo.rv.Elem() + + // AddrExpr + case *ast.AddrExpr: + runInfo.expr = expr.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + if runInfo.rv.CanAddr() { + runInfo.rv = runInfo.rv.Addr() + } else { + i := runInfo.rv.Interface() + runInfo.rv = reflect.ValueOf(&i) + } + + // UnaryExpr + case *ast.UnaryExpr: + runInfo.expr = expr.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + switch expr.Operator { + case "-": + switch runInfo.rv.Kind() { + case reflect.Int64: + runInfo.rv = reflect.ValueOf(-runInfo.rv.Int()) + case reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int, reflect.Bool: + runInfo.rv = reflect.ValueOf(-toInt64(runInfo.rv)) + case reflect.Float64: + runInfo.rv = reflect.ValueOf(-runInfo.rv.Float()) + default: + runInfo.rv = reflect.ValueOf(-toFloat64(runInfo.rv)) + } + case "^": + runInfo.rv = reflect.ValueOf(^toInt64(runInfo.rv)) + case "!": + if toBool(runInfo.rv) { + runInfo.rv = falseValue + } else { + runInfo.rv = trueValue + } + default: + runInfo.err = newStringError(expr, "unknown operator") + runInfo.rv = nilValue + } + + // ParenExpr + case *ast.ParenExpr: + runInfo.expr = expr.SubExpr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + // MemberExpr + case *ast.MemberExpr: + runInfo.expr = expr.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + + if env, ok := runInfo.rv.Interface().(*env.Env); ok { + runInfo.rv, runInfo.err = env.GetValue(expr.Name) + if runInfo.err != nil { + runInfo.err = newError(expr, runInfo.err) + runInfo.rv = nilValue + } + return + } + + value := runInfo.rv.MethodByName(expr.Name) + if value.IsValid() { + runInfo.rv = value + return + } + + if runInfo.rv.Kind() == reflect.Ptr { + runInfo.rv = runInfo.rv.Elem() + } + + switch runInfo.rv.Kind() { + case reflect.Struct: + field, found := runInfo.rv.Type().FieldByName(expr.Name) + if found { + runInfo.rv = runInfo.rv.FieldByIndex(field.Index) + return + } + if runInfo.rv.CanAddr() { + runInfo.rv = runInfo.rv.Addr() + method, found := runInfo.rv.Type().MethodByName(expr.Name) + if found { + runInfo.rv = runInfo.rv.Method(method.Index) + return + } + } + runInfo.err = newStringError(expr, "no member named '"+expr.Name+"' for struct") + runInfo.rv = nilValue + case reflect.Map: + runInfo.rv = getMapIndex(reflect.ValueOf(expr.Name), runInfo.rv) + default: + runInfo.err = newStringError(expr, "type "+runInfo.rv.Kind().String()+" does not support member operation") + runInfo.rv = nilValue + } + + // ItemExpr + case *ast.ItemExpr: + runInfo.expr = expr.Item + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + item := runInfo.rv + + runInfo.expr = expr.Index + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + if item.Kind() == reflect.Interface && !item.IsNil() { + item = item.Elem() + } + + switch item.Kind() { + case reflect.String, reflect.Slice, reflect.Array: + var index int + index, runInfo.err = tryToInt(runInfo.rv) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "index must be a number") + runInfo.rv = nilValue + return + } + if index < 0 || index >= item.Len() { + runInfo.err = newStringError(expr, "index out of range") + runInfo.rv = nilValue + return + } + if item.Kind() != reflect.String { + runInfo.rv = item.Index(index) + } else { + // String + runInfo.rv = item.Index(index).Convert(stringType) + } + case reflect.Map: + runInfo.rv = getMapIndex(runInfo.rv, item) + default: + runInfo.err = newStringError(expr, "type "+item.Kind().String()+" does not support index operation") + runInfo.rv = nilValue + } + + // SliceExpr + case *ast.SliceExpr: + runInfo.expr = expr.Item + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + item := runInfo.rv + + if item.Kind() == reflect.Interface && !item.IsNil() { + item = item.Elem() + } + + switch item.Kind() { + case reflect.String, reflect.Slice, reflect.Array: + var beginIndex int + endIndex := item.Len() + + if expr.Begin != nil { + runInfo.expr = expr.Begin + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + beginIndex, runInfo.err = tryToInt(runInfo.rv) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "index must be a number") + runInfo.rv = nilValue + return + } + // (0 <= low) <= high <= len(a) + if beginIndex < 0 { + runInfo.err = newStringError(expr, "index out of range") + runInfo.rv = nilValue + return + } + } + + if expr.End != nil { + runInfo.expr = expr.End + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + endIndex, runInfo.err = tryToInt(runInfo.rv) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "index must be a number") + runInfo.rv = nilValue + return + } + // 0 <= low <= (high <= len(a)) + if endIndex > item.Len() { + runInfo.err = newStringError(expr, "index out of range") + runInfo.rv = nilValue + return + } + } + + // 0 <= (low <= high) <= len(a) + if beginIndex > endIndex { + runInfo.err = newStringError(expr, "index out of range") + runInfo.rv = nilValue + return + } + + if item.Kind() == reflect.String { + if expr.Cap != nil { + runInfo.err = newStringError(expr, "type string does not support cap") + runInfo.rv = nilValue + return + } + runInfo.rv = item.Slice(beginIndex, endIndex) + return + } + + sliceCap := item.Cap() + if expr.Cap != nil { + runInfo.expr = expr.Cap + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + sliceCap, runInfo.err = tryToInt(runInfo.rv) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "cap must be a number") + runInfo.rv = nilValue + return + } + // 0 <= low <= (high <= max <= cap(a)) + if sliceCap < endIndex || sliceCap > item.Cap() { + runInfo.err = newStringError(expr, "cap out of range") + runInfo.rv = nilValue + return + } + } + + runInfo.rv = item.Slice3(beginIndex, endIndex, sliceCap) + + default: + runInfo.err = newStringError(expr, "type "+item.Kind().String()+" does not support slice operation") + runInfo.rv = nilValue + } + + // LetsExpr + case *ast.LetsExpr: + var i int + for i, runInfo.expr = range expr.RHSS { + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + if i < len(expr.LHSS) { + runInfo.expr = expr.LHSS[i] + runInfo.invokeLetExpr() + if runInfo.err != nil { + return + } + } + + } + + // TernaryOpExpr + case *ast.TernaryOpExpr: + runInfo.expr = expr.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + if toBool(runInfo.rv) { + runInfo.expr = expr.LHS + } else { + runInfo.expr = expr.RHS + } + runInfo.invokeExpr() + + // NilCoalescingOpExpr + case *ast.NilCoalescingOpExpr: + // if left side has no error and is not nil, returns left side + // otherwise returns right side + runInfo.expr = expr.LHS + runInfo.invokeExpr() + if runInfo.err == nil { + if !isNil(runInfo.rv) { + return + } + } else { + runInfo.err = nil + } + runInfo.expr = expr.RHS + runInfo.invokeExpr() + + // LenExpr + case *ast.LenExpr: + runInfo.expr = expr.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + + switch runInfo.rv.Kind() { + case reflect.Slice, reflect.Array, reflect.Map, reflect.String, reflect.Chan: + runInfo.rv = reflect.ValueOf(int64(runInfo.rv.Len())) + default: + runInfo.err = newStringError(expr, "type "+runInfo.rv.Kind().String()+" does not support len operation") + runInfo.rv = nilValue + } + + // ImportExpr + case *ast.ImportExpr: + runInfo.expr = expr.Name + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, stringType) + if runInfo.err != nil { + runInfo.rv = nilValue + return + } + name := runInfo.rv.String() + runInfo.rv = nilValue + + methods, ok := env.Packages[name] + if !ok { + runInfo.err = newStringError(expr, "package not found: "+name) + return + } + var err error + pack := runInfo.env.NewEnv() + for methodName, methodValue := range methods { + err = pack.DefineValue(methodName, methodValue) + if err != nil { + runInfo.err = newStringError(expr, "import DefineValue error: "+err.Error()) + return + } + } + + types, ok := env.PackageTypes[name] + if ok { + for typeName, typeValue := range types { + err = pack.DefineReflectType(typeName, typeValue) + if err != nil { + runInfo.err = newStringError(expr, "import DefineReflectType error: "+err.Error()) + return + } + } + } + + runInfo.rv = reflect.ValueOf(pack) + + // MakeExpr + case *ast.MakeExpr: + t := makeType(runInfo, expr.TypeData) + if runInfo.err != nil { + runInfo.rv = nilValue + return + } + if t == nil { + runInfo.err = newStringError(expr, "cannot make type nil") + runInfo.rv = nilValue + return + } + + switch expr.TypeData.Kind { + case ast.TypeSlice: + aLen := 0 + if expr.LenExpr != nil { + runInfo.expr = expr.LenExpr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + aLen = toInt(runInfo.rv) + } + cap := aLen + if expr.CapExpr != nil { + runInfo.expr = expr.CapExpr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + cap = toInt(runInfo.rv) + } + if aLen > cap { + runInfo.err = newStringError(expr, "make slice len > cap") + runInfo.rv = nilValue + return + } + runInfo.rv = reflect.MakeSlice(t, aLen, cap) + return + case ast.TypeChan: + aLen := 0 + if expr.LenExpr != nil { + runInfo.expr = expr.LenExpr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + aLen = toInt(runInfo.rv) + } + runInfo.rv = reflect.MakeChan(t, aLen) + return + } + + runInfo.rv, runInfo.err = makeValue(t) + + // MakeTypeExpr + case *ast.MakeTypeExpr: + runInfo.expr = expr.Type + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + // if expr.Name has a dot in it, it should give a syntax error, so no needs to check err + runInfo.env.DefineReflectType(expr.Name, runInfo.rv.Type()) + + runInfo.rv = reflect.ValueOf(runInfo.rv.Type()) + + // ChanExpr + case *ast.ChanExpr: + runInfo.expr = expr.RHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + + var lhs reflect.Value + rhs := runInfo.rv + + if expr.LHS == nil { + // lhs is nil + if rhs.Kind() != reflect.Chan { + // rhs is not channel + runInfo.err = newStringError(expr, "receive from non-chan type "+rhs.Kind().String()) + runInfo.rv = nilValue + return + } + } else { + // lhs is not nil + runInfo.expr = expr.LHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + if runInfo.rv.Kind() != reflect.Chan { + // lhs is not channel + // lhs <- chan rhs or lhs <- rhs + runInfo.err = newStringError(expr, "send to non-chan type "+runInfo.rv.Kind().String()) + runInfo.rv = nilValue + return + } + lhs = runInfo.rv + } + + var chosen int + var ok bool + + if rhs.Kind() == reflect.Chan { + // rhs is channel + // receive from rhs channel + cases := []reflect.SelectCase{{ + Dir: reflect.SelectRecv, + Chan: reflect.ValueOf(runInfo.ctx.Done()), + }, { + Dir: reflect.SelectRecv, + Chan: rhs, + }} + chosen, runInfo.rv, ok = reflect.Select(cases) + if chosen == 0 { + runInfo.err = ErrInterrupt + runInfo.rv = nilValue + return + } + if !ok { + runInfo.rv = nilValue + return + } + rhs = runInfo.rv + } + + if expr.LHS == nil { + // <- chan rhs is receive + return + } + + // chan lhs <- chan rhs is receive & send + // or + // chan lhs <- rhs is send + + runInfo.rv = nilValue + rhs, runInfo.err = convertReflectValueToType(rhs, lhs.Type().Elem()) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "cannot use type "+rhs.Type().String()+" as type "+lhs.Type().Elem().String()+" to send to chan") + return + } + // send rhs to lhs channel + cases := []reflect.SelectCase{{ + Dir: reflect.SelectRecv, + Chan: reflect.ValueOf(runInfo.ctx.Done()), + }, { + Dir: reflect.SelectSend, + Chan: lhs, + Send: rhs, + }} + if !runInfo.options.Debug { + // captures panic + defer recoverFunc(runInfo) + } + chosen, _, _ = reflect.Select(cases) + if chosen == 0 { + runInfo.err = ErrInterrupt + } + + // FuncExpr + case *ast.FuncExpr: + runInfo.expr = expr + runInfo.funcExpr() + + // AnonCallExpr + case *ast.AnonCallExpr: + runInfo.expr = expr + runInfo.anonCallExpr() + + // CallExpr + case *ast.CallExpr: + runInfo.expr = expr + runInfo.callExpr() + + // IncludeExpr + case *ast.IncludeExpr: + runInfo.expr = expr.ItemExpr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + itemExpr := runInfo.rv + + runInfo.expr = expr.ListExpr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + if runInfo.rv.Kind() != reflect.Slice && runInfo.rv.Kind() != reflect.Array { + runInfo.err = newStringError(expr, "second argument must be slice or array; but have "+runInfo.rv.Kind().String()) + runInfo.rv = nilValue + return + } + + for i := 0; i < runInfo.rv.Len(); i++ { + if equal(itemExpr, runInfo.rv.Index(i)) { + runInfo.rv = trueValue + return + } + } + runInfo.rv = falseValue + + default: + runInfo.err = newStringError(expr, "unknown expression") + runInfo.rv = nilValue + } + +} diff --git a/src/tool/run/vm/vmExprFunction.go b/src/tool/run/vm/vmExprFunction.go new file mode 100644 index 0000000..ec06312 --- /dev/null +++ b/src/tool/run/vm/vmExprFunction.go @@ -0,0 +1,478 @@ +package vm + +import ( + "context" + "fmt" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/ast" +) + +// funcExpr creates a function that reflect Call can use. +// When called, it will run runVMFunction, to run the function statements +func (runInfo *runInfoStruct) funcExpr() { + funcExpr := runInfo.expr.(*ast.FuncExpr) + + // create the inTypes needed by reflect.FuncOf + inTypes := make([]reflect.Type, len(funcExpr.Params)+1) + // for runVMFunction first arg is always context + inTypes[0] = contextType + for i := 1; i < len(inTypes); i++ { + inTypes[i] = reflectValueType + } + if funcExpr.VarArg { + inTypes[len(inTypes)-1] = interfaceSliceType + } + // create funcType, output is always slice of reflect.Type with two values + funcType := reflect.FuncOf(inTypes, []reflect.Type{reflectValueType, reflectValueType}, funcExpr.VarArg) + + // for adding env into saved function + envFunc := runInfo.env + + // create a function that can be used by reflect.MakeFunc + // this function is a translator that converts a function call into a vm run + // returns slice of reflect.Type with two values: + // return value of the function and error value of the run + runVMFunction := func(in []reflect.Value) []reflect.Value { + runInfo := runInfoStruct{ctx: in[0].Interface().(context.Context), options: runInfo.options, env: envFunc.NewEnv(), stmt: funcExpr.Stmt, rv: nilValue} + + // add Params to newEnv, except last Params + for i := 0; i < len(funcExpr.Params)-1; i++ { + runInfo.rv = in[i+1].Interface().(reflect.Value) + runInfo.env.DefineValue(funcExpr.Params[i], runInfo.rv) + } + // add last Params to newEnv + if len(funcExpr.Params) > 0 { + if funcExpr.VarArg { + // function is variadic, add last Params to newEnv without convert to Interface and then reflect.Value + runInfo.rv = in[len(funcExpr.Params)] + runInfo.env.DefineValue(funcExpr.Params[len(funcExpr.Params)-1], runInfo.rv) + } else { + // function is not variadic, add last Params to newEnv + runInfo.rv = in[len(funcExpr.Params)].Interface().(reflect.Value) + runInfo.env.DefineValue(funcExpr.Params[len(funcExpr.Params)-1], runInfo.rv) + } + } + + // run function statements + runInfo.runSingleStmt() + if runInfo.err != nil && runInfo.err != ErrReturn { + runInfo.err = newError(funcExpr, runInfo.err) + // return nil value and error + // need to do single reflect.ValueOf because nilValue is already reflect.Value of nil + // need to do double reflect.ValueOf of newError in order to match + return []reflect.Value{reflectValueNilValue, reflect.ValueOf(reflect.ValueOf(newError(funcExpr, runInfo.err)))} + } + + // the reflect.ValueOf of rv is needed to work in the reflect.Value slice + // reflectValueErrorNilValue is already a double reflect.ValueOf + return []reflect.Value{reflect.ValueOf(runInfo.rv), reflectValueErrorNilValue} + } + + // make the reflect.Value function that calls runVMFunction + runInfo.rv = reflect.MakeFunc(funcType, runVMFunction) + + // if function name is not empty, define it in the env + if funcExpr.Name != "" { + runInfo.env.DefineValue(funcExpr.Name, runInfo.rv) + } +} + +// anonCallExpr handles ast.AnonCallExpr which calls a function anonymously +func (runInfo *runInfoStruct) anonCallExpr() { + anonCallExpr := runInfo.expr.(*ast.AnonCallExpr) + + runInfo.expr = anonCallExpr.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + if runInfo.rv.Kind() != reflect.Func { + runInfo.err = newStringError(anonCallExpr, "cannot call type "+runInfo.rv.Kind().String()) + runInfo.rv = nilValue + return + } + + runInfo.expr = &ast.CallExpr{Func: runInfo.rv, SubExprs: anonCallExpr.SubExprs, VarArg: anonCallExpr.VarArg, Go: anonCallExpr.Go} + runInfo.expr.SetPosition(anonCallExpr.Expr.Position()) + runInfo.invokeExpr() +} + +// callExpr handles *ast.CallExpr which calls a function +func (runInfo *runInfoStruct) callExpr() { + // Note that if the function type looks the same as the VM function type, the returned values will probably be wrong + + callExpr := runInfo.expr.(*ast.CallExpr) + + f := callExpr.Func + if !f.IsValid() { + // if function is not valid try to get by function name + f, runInfo.err = runInfo.env.GetValue(callExpr.Name) + if runInfo.err != nil { + runInfo.err = newError(callExpr, runInfo.err) + runInfo.rv = nilValue + return + } + } + + if f.Kind() == reflect.Interface && !f.IsNil() { + f = f.Elem() + } + if f.Kind() != reflect.Func { + runInfo.err = newStringError(callExpr, "cannot call type "+f.Kind().String()) + runInfo.rv = nilValue + return + } + + var rvs []reflect.Value + var args []reflect.Value + var useCallSlice bool + fType := f.Type() + // check if this is a runVMFunction type + isRunVMFunction := checkIfRunVMFunction(fType) + // create/convert the args to the function + args, useCallSlice = runInfo.makeCallArgs(fType, isRunVMFunction, callExpr) + if runInfo.err != nil { + return + } + + if !runInfo.options.Debug { + // captures panic + defer recoverFunc(runInfo) + } + + runInfo.rv = nilValue + + // useCallSlice lets us know to use CallSlice instead of Call because of the format of the args + if useCallSlice { + if callExpr.Go { + go f.CallSlice(args) + return + } + rvs = f.CallSlice(args) + } else { + if callExpr.Go { + go f.Call(args) + return + } + rvs = f.Call(args) + } + + // TOFIX: how VM pointers/addressing work + // Until then, this is a work around to set pointers back to VM variables + // This will probably panic for some functions and/or calls that are variadic + if !isRunVMFunction { + for i, expr := range callExpr.SubExprs { + if addrExpr, ok := expr.(*ast.AddrExpr); ok { + if identExpr, ok := addrExpr.Expr.(*ast.IdentExpr); ok { + runInfo.rv = args[i].Elem() + runInfo.expr = identExpr + runInfo.invokeLetExpr() + } + } + } + } + + // processCallReturnValues to get/convert return values to normal rv form + runInfo.rv, runInfo.err = processCallReturnValues(rvs, isRunVMFunction, true) +} + +// checkIfRunVMFunction checking the number and types of the reflect.Type. +// If it matches the types for a runVMFunction this will return true, otherwise false +func checkIfRunVMFunction(rt reflect.Type) bool { + if rt.NumIn() < 1 || rt.NumOut() != 2 || rt.In(0) != contextType || rt.Out(0) != reflectValueType || rt.Out(1) != reflectValueType { + return false + } + if rt.NumIn() > 1 { + if rt.IsVariadic() { + if rt.In(rt.NumIn()-1) != interfaceSliceType { + return false + } + } else { + if rt.In(rt.NumIn()-1) != reflectValueType { + return false + } + } + for i := 1; i < rt.NumIn()-1; i++ { + if rt.In(i) != reflectValueType { + return false + } + } + } + return true +} + +// makeCallArgs creates the arguments reflect.Value slice for the four different kinds of functions. +// Also returns true if CallSlice should be used on the arguments, or false if Call should be used. +func (runInfo *runInfoStruct) makeCallArgs(rt reflect.Type, isRunVMFunction bool, callExpr *ast.CallExpr) ([]reflect.Value, bool) { + // number of arguments + numInReal := rt.NumIn() + numIn := numInReal + if isRunVMFunction { + // for runVMFunction the first arg is context so does not count against number of SubExprs + numIn-- + } + if numIn < 1 { + // no arguments needed + if isRunVMFunction { + // for runVMFunction first arg is always context + return []reflect.Value{reflect.ValueOf(runInfo.ctx)}, false + } + return []reflect.Value{}, false + } + + // number of expressions + numExprs := len(callExpr.SubExprs) + // checks to short circuit wrong number of arguments + if (!rt.IsVariadic() && !callExpr.VarArg && numIn != numExprs) || + (rt.IsVariadic() && callExpr.VarArg && (numIn < numExprs || numIn > numExprs+1)) || + (rt.IsVariadic() && !callExpr.VarArg && numIn > numExprs+1) || + (!rt.IsVariadic() && callExpr.VarArg && numIn < numExprs) { + runInfo.err = newStringError(callExpr, fmt.Sprintf("function wants %v arguments but received %v", numIn, numExprs)) + runInfo.rv = nilValue + return nil, false + } + if rt.IsVariadic() && rt.In(numInReal-1).Kind() != reflect.Slice && rt.In(numInReal-1).Kind() != reflect.Array { + runInfo.err = newStringError(callExpr, "function is variadic but last parameter is of type "+rt.In(numInReal-1).String()) + runInfo.rv = nilValue + return nil, false + } + + var args []reflect.Value + indexIn := 0 + indexInReal := 0 + indexExpr := 0 + + if numInReal > numExprs { + args = make([]reflect.Value, 0, numInReal) + } else { + args = make([]reflect.Value, 0, numExprs) + } + if isRunVMFunction { + // for runVMFunction first arg is always context + args = append(args, reflect.ValueOf(runInfo.ctx)) + indexInReal++ + } + + // create arguments except the last one + for indexInReal < numInReal-1 && indexExpr < numExprs-1 { + runInfo.expr = callExpr.SubExprs[indexExpr] + runInfo.invokeExpr() + if runInfo.err != nil { + return nil, false + } + if isRunVMFunction { + args = append(args, reflect.ValueOf(runInfo.rv)) + } else { + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, rt.In(indexInReal)) + if runInfo.err != nil { + runInfo.err = newStringError(callExpr.SubExprs[indexExpr], + "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) + runInfo.rv = nilValue + return nil, false + } + args = append(args, runInfo.rv) + } + indexIn++ + indexInReal++ + indexExpr++ + } + + if !rt.IsVariadic() && !callExpr.VarArg { + // function is not variadic and call is not variadic + // add last arguments and return + runInfo.expr = callExpr.SubExprs[indexExpr] + runInfo.invokeExpr() + if runInfo.err != nil { + return nil, false + } + if runInfo.err != nil { + return nil, false + } + if isRunVMFunction { + args = append(args, reflect.ValueOf(runInfo.rv)) + } else { + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, rt.In(indexInReal)) + if runInfo.err != nil { + runInfo.err = newStringError(callExpr.SubExprs[indexExpr], + "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) + runInfo.rv = nilValue + return nil, false + } + args = append(args, runInfo.rv) + } + return args, false + } + + if !rt.IsVariadic() && callExpr.VarArg { + // function is not variadic and call is variadic + runInfo.expr = callExpr.SubExprs[indexExpr] + runInfo.invokeExpr() + if runInfo.err != nil { + return nil, false + } + if runInfo.rv.Kind() != reflect.Slice && runInfo.rv.Kind() != reflect.Array { + runInfo.err = newStringError(callExpr, "call is variadic but last parameter is of type "+runInfo.rv.Type().String()) + runInfo.rv = nilValue + return nil, false + } + if runInfo.rv.Len() < numIn-indexIn { + runInfo.err = newStringError(callExpr, fmt.Sprintf("function wants %v arguments but received %v", numIn, numExprs+runInfo.rv.Len()-1)) + runInfo.rv = nilValue + return nil, false + } + + indexSlice := 0 + for indexInReal < numInReal { + if isRunVMFunction { + args = append(args, reflect.ValueOf(runInfo.rv.Index(indexSlice))) + } else { + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv.Index(indexSlice), rt.In(indexInReal)) + if runInfo.err != nil { + runInfo.err = newStringError(callExpr.SubExprs[indexExpr], + "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) + runInfo.rv = nilValue + return nil, false + } + args = append(args, runInfo.rv) + } + indexIn++ + indexInReal++ + indexSlice++ + } + return args, false + } + + // function is variadic and call may or may not be variadic + + if indexExpr == numExprs { + // no more expressions, return what we have and let reflect Call handle if call is variadic or not + return args, false + } + + if numIn > numExprs { + // there are more arguments after this one, so does not matter if call is variadic or not + // add the last argument then return what we have and let reflect Call handle if call is variadic or not + runInfo.expr = callExpr.SubExprs[indexExpr] + runInfo.invokeExpr() + if runInfo.err != nil { + return nil, false + } + if isRunVMFunction { + args = append(args, reflect.ValueOf(runInfo.rv)) + } else { + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, rt.In(indexInReal)) + if runInfo.err != nil { + runInfo.err = newStringError(callExpr.SubExprs[indexExpr], + "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) + runInfo.rv = nilValue + return nil, false + } + args = append(args, runInfo.rv) + } + return args, false + } + + if rt.IsVariadic() && !callExpr.VarArg { + // function is variadic and call is not variadic + sliceType := rt.In(numInReal - 1).Elem() + for indexExpr < numExprs { + runInfo.expr = callExpr.SubExprs[indexExpr] + runInfo.invokeExpr() + if runInfo.err != nil { + return nil, false + } + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, sliceType) + if runInfo.err != nil { + runInfo.err = newStringError(callExpr.SubExprs[indexExpr], + "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) + runInfo.rv = nilValue + return nil, false + } + args = append(args, runInfo.rv) + indexExpr++ + } + return args, false + + } + + // function is variadic and call is variadic + // the only time we return CallSlice is true + sliceType := rt.In(numInReal - 1) + if sliceType.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + sliceType = sliceType.Elem() + } + runInfo.expr = callExpr.SubExprs[indexExpr] + runInfo.invokeExpr() + if runInfo.err != nil { + return nil, false + } + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, sliceType) + if runInfo.err != nil { + runInfo.err = newStringError(callExpr.SubExprs[indexExpr], + "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) + runInfo.rv = nilValue + return nil, false + } + args = append(args, runInfo.rv) + + return args, true +} + +// processCallReturnValues get/converts the values returned from a function call into our normal reflect.Value, error +func processCallReturnValues(rvs []reflect.Value, isRunVMFunction bool, convertToInterfaceSlice bool) (reflect.Value, error) { + // check if it is not runVMFunction + if !isRunVMFunction { + // the function was a Go function, convert to our normal reflect.Value, error + switch len(rvs) { + case 0: + // no return values so return nil reflect.Value and nil error + return nilValue, nil + case 1: + // one return value but need to add nil error + return rvs[0], nil + } + if convertToInterfaceSlice { + // need to convert from a slice of reflect.Value to slice of interface + return reflectValueSlicetoInterfaceSlice(rvs), nil + } + // need to keep as slice of reflect.Value + return reflect.ValueOf(rvs), nil + } + + // is a runVMFunction, expect return in the runVMFunction format + // convertToInterfaceSlice is ignored + // some of the below checks probably can be removed because they are done in checkIfRunVMFunction + + if len(rvs) != 2 { + return nilValue, fmt.Errorf("VM function did not return 2 values but returned %v values", len(rvs)) + } + if rvs[0].Type() != reflectValueType { + return nilValue, fmt.Errorf("VM function value 1 did not return reflect value type but returned %v type", rvs[0].Type().String()) + } + if rvs[1].Type() != reflectValueType { + return nilValue, fmt.Errorf("VM function value 2 did not return reflect value type but returned %v type", rvs[1].Type().String()) + } + + rvError := rvs[1].Interface().(reflect.Value) + if rvError.Type() != errorType && rvError.Type() != vmErrorType { + return nilValue, fmt.Errorf("VM function error type is %v", rvError.Type()) + } + + if rvError.IsNil() { + // no error, so return the normal VM reflect.Value form + return rvs[0].Interface().(reflect.Value), nil + } + + // VM returns two types of errors, check to see which type + if rvError.Type() == vmErrorType { + // convert to VM *Error + return nilValue, rvError.Interface().(*Error) + } + // convert to error + return nilValue, rvError.Interface().(error) +} diff --git a/src/tool/run/vm/vmFunctions_test.go b/src/tool/run/vm/vmFunctions_test.go new file mode 100644 index 0000000..2e239fc --- /dev/null +++ b/src/tool/run/vm/vmFunctions_test.go @@ -0,0 +1,863 @@ +package vm + +import ( + "bytes" + "fmt" + "reflect" + "sync" + "testing" + "time" + + "github.com/surdeus/goblin/src/tool/run/env" +) + +func TestReturns(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `return 1++`, RunError: fmt.Errorf("invalid operation")}, + {Script: `return 1, 1++`, RunError: fmt.Errorf("invalid operation")}, + {Script: `return 1, 2, 1++`, RunError: fmt.Errorf("invalid operation")}, + + {Script: `return`, RunOutput: nil}, + {Script: `return nil`, RunOutput: nil}, + {Script: `return true`, RunOutput: true}, + {Script: `return 1`, RunOutput: int64(1)}, + {Script: `return 1.1`, RunOutput: float64(1.1)}, + {Script: `return "a"`, RunOutput: "a"}, + + {Script: `b()`, Input: map[string]interface{}{"b": func() {}}, RunOutput: nil}, + {Script: `b()`, Input: map[string]interface{}{"b": func() reflect.Value { return reflect.Value{} }}, RunOutput: reflect.Value{}}, + {Script: `b()`, Input: map[string]interface{}{"b": func() interface{} { return nil }}, RunOutput: nil}, + {Script: `b()`, Input: map[string]interface{}{"b": func() bool { return true }}, RunOutput: true}, + {Script: `b()`, Input: map[string]interface{}{"b": func() int32 { return int32(1) }}, RunOutput: int32(1)}, + {Script: `b()`, Input: map[string]interface{}{"b": func() int64 { return int64(1) }}, RunOutput: int64(1)}, + {Script: `b()`, Input: map[string]interface{}{"b": func() float32 { return float32(1.1) }}, RunOutput: float32(1.1)}, + {Script: `b()`, Input: map[string]interface{}{"b": func() float64 { return float64(1.1) }}, RunOutput: float64(1.1)}, + {Script: `b()`, Input: map[string]interface{}{"b": func() string { return "a" }}, RunOutput: "a"}, + + {Script: `b(a)`, Input: map[string]interface{}{"a": reflect.Value{}, "b": func(c reflect.Value) reflect.Value { return c }}, RunOutput: reflect.Value{}, Output: map[string]interface{}{"a": reflect.Value{}}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": nil, "b": func(c interface{}) interface{} { return c }}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": true, "b": func(c bool) bool { return c }}, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": int32(1), "b": func(c int32) int32 { return c }}, RunOutput: int32(1), Output: map[string]interface{}{"a": int32(1)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": int64(1), "b": func(c int64) int64 { return c }}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": float32(1.1), "b": func(c float32) float32 { return c }}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": float32(1.1)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": float64(1.1), "b": func(c float64) float64 { return c }}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": "a", "b": func(c string) string { return c }}, RunOutput: "a", Output: map[string]interface{}{"a": "a"}}, + + {Script: `b(a)`, Input: map[string]interface{}{"a": "a", "b": func(c bool) bool { return c }}, RunError: fmt.Errorf("function wants argument type bool but received type string"), Output: map[string]interface{}{"a": "a"}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": int64(1), "b": func(c int32) int32 { return c }}, RunOutput: int32(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": int32(1), "b": func(c int64) int64 { return c }}, RunOutput: int64(1), Output: map[string]interface{}{"a": int32(1)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": float64(1.25), "b": func(c float32) float32 { return c }}, RunOutput: float32(1.25), Output: map[string]interface{}{"a": float64(1.25)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": float32(1.25), "b": func(c float64) float64 { return c }}, RunOutput: float64(1.25), Output: map[string]interface{}{"a": float32(1.25)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": true, "b": func(c string) string { return c }}, RunError: fmt.Errorf("function wants argument type string but received type bool"), Output: map[string]interface{}{"a": true}}, + + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueBool, "b": func(c interface{}) interface{} { return c }}, RunOutput: testVarValueBool, Output: map[string]interface{}{"a": testVarValueBool}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueInt32, "b": func(c interface{}) interface{} { return c }}, RunOutput: testVarValueInt32, Output: map[string]interface{}{"a": testVarValueInt32}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueInt64, "b": func(c interface{}) interface{} { return c }}, RunOutput: testVarValueInt64, Output: map[string]interface{}{"a": testVarValueInt64}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueFloat32, "b": func(c interface{}) interface{} { return c }}, RunOutput: testVarValueFloat32, Output: map[string]interface{}{"a": testVarValueFloat32}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueFloat64, "b": func(c interface{}) interface{} { return c }}, RunOutput: testVarValueFloat64, Output: map[string]interface{}{"a": testVarValueFloat64}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueString, "b": func(c interface{}) interface{} { return c }}, RunOutput: testVarValueString, Output: map[string]interface{}{"a": testVarValueString}}, + + {Script: `func aFunc() {}; aFunc()`, RunOutput: nil}, + {Script: `func aFunc() { return }; aFunc()`, RunOutput: nil}, + {Script: `func aFunc() { return }; a = aFunc()`, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `func aFunc() { return 1 }; aFunc()`, RunOutput: int64(1)}, + {Script: `func aFunc() { return 1 }; a = aFunc()`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + + {Script: `func aFunc() {return nil}; aFunc()`, RunOutput: nil}, + {Script: `func aFunc() {return true}; aFunc()`, RunOutput: true}, + {Script: `func aFunc() {return 1}; aFunc()`, RunOutput: int64(1)}, + {Script: `func aFunc() {return 1.1}; aFunc()`, RunOutput: float64(1.1)}, + {Script: `func aFunc() {return "a"}; aFunc()`, RunOutput: "a"}, + + {Script: `func aFunc() {return 1 + 2}; aFunc()`, RunOutput: int64(3)}, + {Script: `func aFunc() {return 1.25 + 2.25}; aFunc()`, RunOutput: float64(3.5)}, + {Script: `func aFunc() {return "a" + "b"}; aFunc()`, RunOutput: "ab"}, + + {Script: `func aFunc() {return 1 + 2, 3 + 4}; aFunc()`, RunOutput: []interface{}{int64(3), int64(7)}}, + {Script: `func aFunc() {return 1.25 + 2.25, 3.25 + 4.25}; aFunc()`, RunOutput: []interface{}{float64(3.5), float64(7.5)}}, + {Script: `func aFunc() {return "a" + "b", "c" + "d"}; aFunc()`, RunOutput: []interface{}{"ab", "cd"}}, + + {Script: `func aFunc() {return nil, nil}; aFunc()`, RunOutput: []interface{}{nil, nil}}, + {Script: `func aFunc() {return true, false}; aFunc()`, RunOutput: []interface{}{true, false}}, + {Script: `func aFunc() {return 1, 2}; aFunc()`, RunOutput: []interface{}{int64(1), int64(2)}}, + {Script: `func aFunc() {return 1.1, 2.2}; aFunc()`, RunOutput: []interface{}{float64(1.1), float64(2.2)}}, + {Script: `func aFunc() {return "a", "b"}; aFunc()`, RunOutput: []interface{}{"a", "b"}}, + + {Script: `func aFunc() {return [nil]}; aFunc()`, RunOutput: []interface{}{nil}}, + {Script: `func aFunc() {return [nil, nil]}; aFunc()`, RunOutput: []interface{}{nil, nil}}, + {Script: `func aFunc() {return [nil, nil, nil]}; aFunc()`, RunOutput: []interface{}{nil, nil, nil}}, + {Script: `func aFunc() {return [nil, nil], [nil, nil]}; aFunc()`, RunOutput: []interface{}{[]interface{}{nil, nil}, []interface{}{nil, nil}}}, + + {Script: `func aFunc() {return [true]}; aFunc()`, RunOutput: []interface{}{true}}, + {Script: `func aFunc() {return [true, false]}; aFunc()`, RunOutput: []interface{}{true, false}}, + {Script: `func aFunc() {return [true, false, true]}; aFunc()`, RunOutput: []interface{}{true, false, true}}, + {Script: `func aFunc() {return [true, false], [false, true]}; aFunc()`, RunOutput: []interface{}{[]interface{}{true, false}, []interface{}{false, true}}}, + + {Script: `func aFunc() {return []}; aFunc()`, RunOutput: []interface{}{}}, + {Script: `func aFunc() {return [1]}; aFunc()`, RunOutput: []interface{}{int64(1)}}, + {Script: `func aFunc() {return [1, 2]}; aFunc()`, RunOutput: []interface{}{int64(1), int64(2)}}, + {Script: `func aFunc() {return [1, 2, 3]}; aFunc()`, RunOutput: []interface{}{int64(1), int64(2), int64(3)}}, + {Script: `func aFunc() {return [1, 2], [3, 4]}; aFunc()`, RunOutput: []interface{}{[]interface{}{int64(1), int64(2)}, []interface{}{int64(3), int64(4)}}}, + + {Script: `func aFunc() {return [1.1]}; aFunc()`, RunOutput: []interface{}{float64(1.1)}}, + {Script: `func aFunc() {return [1.1, 2.2]}; aFunc()`, RunOutput: []interface{}{float64(1.1), float64(2.2)}}, + {Script: `func aFunc() {return [1.1, 2.2, 3.3]}; aFunc()`, RunOutput: []interface{}{float64(1.1), float64(2.2), float64(3.3)}}, + {Script: `func aFunc() {return [1.1, 2.2], [3.3, 4.4]}; aFunc()`, RunOutput: []interface{}{[]interface{}{float64(1.1), float64(2.2)}, []interface{}{float64(3.3), float64(4.4)}}}, + + {Script: `func aFunc() {return ["a"]}; aFunc()`, RunOutput: []interface{}{"a"}}, + {Script: `func aFunc() {return ["a", "b"]}; aFunc()`, RunOutput: []interface{}{"a", "b"}}, + {Script: `func aFunc() {return ["a", "b", "c"]}; aFunc()`, RunOutput: []interface{}{"a", "b", "c"}}, + {Script: `func aFunc() {return ["a", "b"], ["c", "d"]}; aFunc()`, RunOutput: []interface{}{[]interface{}{"a", "b"}, []interface{}{"c", "d"}}}, + + {Script: `func aFunc() {return nil, nil}; aFunc()`, RunOutput: []interface{}{interface{}(nil), interface{}(nil)}}, + {Script: `func aFunc() {return true, false}; aFunc()`, RunOutput: []interface{}{true, false}}, + {Script: `func aFunc() {return 1, 2}; aFunc()`, RunOutput: []interface{}{int64(1), int64(2)}}, + {Script: `func aFunc() {return 1.1, 2.2}; aFunc()`, RunOutput: []interface{}{float64(1.1), float64(2.2)}}, + {Script: `func aFunc() {return "a", "b"}; aFunc()`, RunOutput: []interface{}{"a", "b"}}, + + {Script: `func aFunc() {return a}; aFunc()`, Input: map[string]interface{}{"a": reflect.Value{}}, RunOutput: reflect.Value{}, Output: map[string]interface{}{"a": reflect.Value{}}}, + + {Script: `func aFunc() {return a}; aFunc()`, Input: map[string]interface{}{"a": nil}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `func aFunc() {return a}; aFunc()`, Input: map[string]interface{}{"a": true}, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `func aFunc() {return a}; aFunc()`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `func aFunc() {return a}; aFunc()`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `func aFunc() {return a}; aFunc()`, Input: map[string]interface{}{"a": "a"}, RunOutput: "a", Output: map[string]interface{}{"a": "a"}}, + + {Script: `func aFunc() {return a, a}; aFunc()`, Input: map[string]interface{}{"a": reflect.Value{}}, RunOutput: []interface{}{reflect.Value{}, reflect.Value{}}, Output: map[string]interface{}{"a": reflect.Value{}}}, + {Script: `func aFunc() {return a, a}; aFunc()`, Input: map[string]interface{}{"a": nil}, RunOutput: []interface{}{nil, nil}, Output: map[string]interface{}{"a": nil}}, + {Script: `func aFunc() {return a, a}; aFunc()`, Input: map[string]interface{}{"a": true}, RunOutput: []interface{}{true, true}, Output: map[string]interface{}{"a": true}}, + {Script: `func aFunc() {return a, a}; aFunc()`, Input: map[string]interface{}{"a": int32(1)}, RunOutput: []interface{}{int32(1), int32(1)}, Output: map[string]interface{}{"a": int32(1)}}, + {Script: `func aFunc() {return a, a}; aFunc()`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: []interface{}{int64(1), int64(1)}, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `func aFunc() {return a, a}; aFunc()`, Input: map[string]interface{}{"a": float32(1.1)}, RunOutput: []interface{}{float32(1.1), float32(1.1)}, Output: map[string]interface{}{"a": float32(1.1)}}, + {Script: `func aFunc() {return a, a}; aFunc()`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: []interface{}{float64(1.1), float64(1.1)}, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `func aFunc() {return a, a}; aFunc()`, Input: map[string]interface{}{"a": "a"}, RunOutput: []interface{}{"a", "a"}, Output: map[string]interface{}{"a": "a"}}, + + {Script: `func a(x) { return x}; a(nil)`, RunOutput: nil}, + {Script: `func a(x) { return x}; a(true)`, RunOutput: true}, + {Script: `func a(x) { return x}; a(1)`, RunOutput: int64(1)}, + {Script: `func a(x) { return x}; a(1.1)`, RunOutput: float64(1.1)}, + {Script: `func a(x) { return x}; a("a")`, RunOutput: "a"}, + + {Script: `func aFunc() {return a}; for {aFunc(); break}`, Input: map[string]interface{}{"a": nil}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `func aFunc() {return a}; for {aFunc(); break}`, Input: map[string]interface{}{"a": true}, RunOutput: nil, Output: map[string]interface{}{"a": true}}, + {Script: `func aFunc() {return a}; for {aFunc(); break}`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `func aFunc() {return a}; for {aFunc(); break}`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: nil, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `func aFunc() {return a}; for {aFunc(); break}`, Input: map[string]interface{}{"a": "a"}, RunOutput: nil, Output: map[string]interface{}{"a": "a"}}, + + {Script: `func aFunc() {for {return a}}; aFunc()`, Input: map[string]interface{}{"a": nil}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `func aFunc() {for {return a}}; aFunc()`, Input: map[string]interface{}{"a": true}, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `func aFunc() {for {return a}}; aFunc()`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `func aFunc() {for {return a}}; aFunc()`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `func aFunc() {for {return a}}; aFunc()`, Input: map[string]interface{}{"a": "a"}, RunOutput: "a", Output: map[string]interface{}{"a": "a"}}, + + {Script: `func aFunc() {for {if true {return a}}}; aFunc()`, Input: map[string]interface{}{"a": nil}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `func aFunc() {for {if true {return a}}}; aFunc()`, Input: map[string]interface{}{"a": true}, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `func aFunc() {for {if true {return a}}}; aFunc()`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `func aFunc() {for {if true {return a}}}; aFunc()`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `func aFunc() {for {if true {return a}}}; aFunc()`, Input: map[string]interface{}{"a": "a"}, RunOutput: "a", Output: map[string]interface{}{"a": "a"}}, + + {Script: `func aFunc() {return nil, nil}; a, b = aFunc()`, RunOutput: nil, Output: map[string]interface{}{"a": nil, "b": nil}}, + {Script: `func aFunc() {return true, false}; a, b = aFunc()`, RunOutput: false, Output: map[string]interface{}{"a": true, "b": false}}, + {Script: `func aFunc() {return 1, 2}; a, b = aFunc()`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + {Script: `func aFunc() {return 1.1, 2.2}; a, b = aFunc()`, RunOutput: float64(2.2), Output: map[string]interface{}{"a": float64(1.1), "b": float64(2.2)}}, + {Script: `func aFunc() {return "a", "b"}; a, b = aFunc()`, RunOutput: "b", Output: map[string]interface{}{"a": "a", "b": "b"}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestFunctions(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a()`, Input: map[string]interface{}{"a": reflect.Value{}}, RunError: fmt.Errorf("cannot call type struct")}, + {Script: `a = nil; a()`, RunError: fmt.Errorf("cannot call type interface"), Output: map[string]interface{}{"a": nil}}, + {Script: `a = true; a()`, RunError: fmt.Errorf("cannot call type bool"), Output: map[string]interface{}{"a": true}}, + {Script: `a = nil; b = func c(d) { return d == nil }; c = nil; c(a)`, RunError: fmt.Errorf("cannot call type interface"), Output: map[string]interface{}{"a": nil}}, + {Script: `a = [true]; a()`, RunError: fmt.Errorf("cannot call type slice")}, + {Script: `a = [true]; func b(c) { return c() }; b(a)`, RunError: fmt.Errorf("cannot call type slice")}, + {Script: `a = {}; a.missing()`, RunError: fmt.Errorf("cannot call type interface"), Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = 1; b = func(,a){}; a`, ParseError: fmt.Errorf("syntax error: unexpected ','"), RunOutput: int64(1)}, + + {Script: `func a(b) { }; a()`, RunError: fmt.Errorf("function wants 1 arguments but received 0")}, + {Script: `func a(b) { }; a(true, true)`, RunError: fmt.Errorf("function wants 1 arguments but received 2")}, + {Script: `func a(b, c) { }; a()`, RunError: fmt.Errorf("function wants 2 arguments but received 0")}, + {Script: `func a(b, c) { }; a(true)`, RunError: fmt.Errorf("function wants 2 arguments but received 1")}, + {Script: `func a(b, c) { }; a(true, true, true)`, RunError: fmt.Errorf("function wants 2 arguments but received 3")}, + + {Script: `func a() { return "a" }; a.b()`, RunError: fmt.Errorf("type func does not support member operation")}, + {Script: `a = [func () { return nil}]; func b(c) { return c() }; b(a[1])`, RunError: fmt.Errorf("index out of range")}, + {Script: `func a() { return "a" }; b()`, RunError: fmt.Errorf("undefined symbol 'b'")}, + {Script: ` func a() { return "a" }; 1++()`, RunError: fmt.Errorf("invalid operation")}, + {Script: ` func a(b) { return b }; a(1++)`, RunError: fmt.Errorf("invalid operation")}, + + {Script: `a`, Input: map[string]interface{}{"a": testVarFunc}, RunOutput: testVarFunc, Output: map[string]interface{}{"a": testVarFunc}}, + {Script: `a()`, Input: map[string]interface{}{"a": testVarFunc}, RunOutput: int64(1), Output: map[string]interface{}{"a": testVarFunc}}, + {Script: `a`, Input: map[string]interface{}{"a": testVarFuncP}, RunOutput: testVarFuncP, Output: map[string]interface{}{"a": testVarFuncP}}, + // TOFIX: + // {Script: `a()`, Input: map[string]interface{}{"a": testVarFuncP}, RunOutput: int64(1), Output: map[string]interface{}{"a": testVarFuncP}}, + + {Script: `module a { func b() { return } }; a.b()`, RunOutput: nil}, + {Script: `module a { func b() { return nil} }; a.b()`, RunOutput: nil}, + {Script: `module a { func b() { return true} }; a.b()`, RunOutput: true}, + {Script: `module a { func b() { return 1} }; a.b()`, RunOutput: int64(1)}, + {Script: `module a { func b() { return 1.1} }; a.b()`, RunOutput: float64(1.1)}, + {Script: `module a { func b() { return "a"} }; a.b()`, RunOutput: "a"}, + + {Script: `if true { module a { func b() { return } } }; a.b()`, RunError: fmt.Errorf("undefined symbol 'a'")}, + + {Script: `a = 1; func b() { a = 2 }; b()`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `b(a); a`, Input: map[string]interface{}{"a": int64(1), "b": func(c interface{}) { c = int64(2); _ = c }}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `func b() { }; go b()`, RunOutput: nil}, + + {Script: `b(a)`, Input: map[string]interface{}{"a": nil, "b": func(c interface{}) bool { return c == nil }}, RunOutput: true, Output: map[string]interface{}{"a": nil}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": true, "b": func(c bool) bool { return c == true }}, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": int32(1), "b": func(c int32) bool { return c == 1 }}, RunOutput: true, Output: map[string]interface{}{"a": int32(1)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": int64(1), "b": func(c int64) bool { return c == 1 }}, RunOutput: true, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": float32(1.1), "b": func(c float32) bool { return c == 1.1 }}, RunOutput: true, Output: map[string]interface{}{"a": float32(1.1)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": float64(1.1), "b": func(c float64) bool { return c == 1.1 }}, RunOutput: true, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": "a", "b": func(c string) bool { return c == "a" }}, RunOutput: true, Output: map[string]interface{}{"a": "a"}}, + + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueBool, "b": func(c reflect.Value) bool { return c == testVarValueBool }}, RunOutput: true, Output: map[string]interface{}{"a": testVarValueBool}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueInt32, "b": func(c reflect.Value) bool { return c == testVarValueInt32 }}, RunOutput: true, Output: map[string]interface{}{"a": testVarValueInt32}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueInt64, "b": func(c reflect.Value) bool { return c == testVarValueInt64 }}, RunOutput: true, Output: map[string]interface{}{"a": testVarValueInt64}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueFloat32, "b": func(c reflect.Value) bool { return c == testVarValueFloat32 }}, RunOutput: true, Output: map[string]interface{}{"a": testVarValueFloat32}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueFloat64, "b": func(c reflect.Value) bool { return c == testVarValueFloat64 }}, RunOutput: true, Output: map[string]interface{}{"a": testVarValueFloat64}}, + {Script: `b(a)`, Input: map[string]interface{}{"a": testVarValueString, "b": func(c reflect.Value) bool { return c == testVarValueString }}, RunOutput: true, Output: map[string]interface{}{"a": testVarValueString}}, + + {Script: `x(a, b, c, d, e, f, g)`, Input: map[string]interface{}{"a": nil, "b": true, "c": int32(1), "d": int64(2), "e": float32(1.1), "f": float64(2.2), "g": "g", + "x": func(a interface{}, b bool, c int32, d int64, e float32, f float64, g string) bool { + return a == nil && b == true && c == 1 && d == 2 && e == 1.1 && f == 2.2 && g == "g" + }}, RunOutput: true, Output: map[string]interface{}{"a": nil, "b": true, "c": int32(1), "d": int64(2), "e": float32(1.1), "f": float64(2.2), "g": "g"}}, + {Script: `x(a, b, c, d, e, f, g)`, Input: map[string]interface{}{"a": nil, "b": true, "c": int32(1), "d": int64(2), "e": float32(1.1), "f": float64(2.2), "g": "g", + "x": func(a interface{}, b bool, c int32, d int64, e float32, f float64, g string) (interface{}, bool, int32, int64, float32, float64, string) { + return a, b, c, d, e, f, g + }}, RunOutput: []interface{}{nil, true, int32(1), int64(2), float32(1.1), float64(2.2), "g"}, Output: map[string]interface{}{"a": nil, "b": true, "c": int32(1), "d": int64(2), "e": float32(1.1), "f": float64(2.2), "g": "g"}}, + + {Script: `b = a()`, Input: map[string]interface{}{"a": func() (bool, int32, int64, float32, float64, string) { return true, 1, 2, 3.3, 4.4, "5" }}, RunOutput: []interface{}{true, int32(1), int64(2), float32(3.3), float64(4.4), "5"}, Output: map[string]interface{}{"b": []interface{}{true, int32(1), int64(2), float32(3.3), float64(4.4), "5"}}}, + {Script: `b = a(); b`, Input: map[string]interface{}{"a": func() (bool, int32, int64, float32, float64, string) { return true, 1, 2, 3.3, 4.4, "5" }}, RunOutput: []interface{}{true, int32(1), int64(2), float32(3.3), float64(4.4), "5"}, Output: map[string]interface{}{"b": []interface{}{true, int32(1), int64(2), float32(3.3), float64(4.4), "5"}}}, + {Script: `b, c = a(); b`, Input: map[string]interface{}{"a": func() (bool, int32, int64, float32, float64, string) { return true, 1, 2, 3.3, 4.4, "5" }}, RunOutput: true, Output: map[string]interface{}{"b": true, "c": int32(1)}}, + {Script: `b, c, d = a(); b`, Input: map[string]interface{}{"a": func() (bool, int32, int64, float32, float64, string) { return true, 1, 2, 3.3, 4.4, "5" }}, RunOutput: true, Output: map[string]interface{}{"b": true, "c": int32(1), "d": int64(2)}}, + {Script: `b, c, d, e = a(); b`, Input: map[string]interface{}{"a": func() (bool, int32, int64, float32, float64, string) { return true, 1, 2, 3.3, 4.4, "5" }}, RunOutput: true, Output: map[string]interface{}{"b": true, "c": int32(1), "d": int64(2), "e": float32(3.3)}}, + {Script: `b, c, d, e, f = a(); b`, Input: map[string]interface{}{"a": func() (bool, int32, int64, float32, float64, string) { return true, 1, 2, 3.3, 4.4, "5" }}, RunOutput: true, Output: map[string]interface{}{"b": true, "c": int32(1), "d": int64(2), "e": float32(3.3), "f": float64(4.4)}}, + {Script: `b, c, d, e, f, g = a(); b`, Input: map[string]interface{}{"a": func() (bool, int32, int64, float32, float64, string) { return true, 1, 2, 3.3, 4.4, "5" }}, RunOutput: true, Output: map[string]interface{}{"b": true, "c": int32(1), "d": int64(2), "e": float32(3.3), "f": float64(4.4), "g": "5"}}, + + {Script: `a = nil; b(a)`, Input: map[string]interface{}{"b": func(c interface{}) bool { return c == nil }}, RunOutput: true, Output: map[string]interface{}{"a": nil}}, + {Script: `a = true; b(a)`, Input: map[string]interface{}{"b": func(c bool) bool { return c == true }}, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `a = 1; b(a)`, Input: map[string]interface{}{"b": func(c int64) bool { return c == 1 }}, RunOutput: true, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1.1; b(a)`, Input: map[string]interface{}{"b": func(c float64) bool { return c == 1.1 }}, RunOutput: true, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `a = "a"; b(a)`, Input: map[string]interface{}{"b": func(c string) bool { return c == "a" }}, RunOutput: true, Output: map[string]interface{}{"a": "a"}}, + + {Script: `func b(c) { return c == nil }; b(a)`, Input: map[string]interface{}{"a": nil}, RunOutput: true, Output: map[string]interface{}{"a": nil}}, + {Script: `func b(c) { return c == true }; b(a)`, Input: map[string]interface{}{"a": true}, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `func b(c) { return c == 1 }; b(a)`, Input: map[string]interface{}{"a": int32(1)}, RunOutput: true, Output: map[string]interface{}{"a": int32(1)}}, + {Script: `func b(c) { return c == 1 }; b(a)`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: true, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `func b(c) { return c == 1.1 }; b(a)`, Input: map[string]interface{}{"a": float32(1.1)}, RunOutput: true, Output: map[string]interface{}{"a": float32(1.1)}}, + {Script: `func b(c) { return c == 1.1 }; b(a)`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: true, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `func b(c) { return c == "a" }; b(a)`, Input: map[string]interface{}{"a": "a"}, RunOutput: true, Output: map[string]interface{}{"a": "a"}}, + + {Script: `a = nil; func b(c) { return c == nil }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": nil}}, + {Script: `a = true; func b(c) { return c == true }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `a = 1; func b(c) { return c == 1 }; b(a)`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: true, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1.1; func b(c) { return c == 1.1 }; b(a)`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: true, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `a = "a"; func b(c) { return c == "a" }; b(a)`, Input: map[string]interface{}{"a": "a"}, RunOutput: true, Output: map[string]interface{}{"a": "a"}}, + + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{nil}, "b": func(c interface{}) bool { return c == nil }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{nil}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{true}, "b": func(c interface{}) bool { return c == true }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{true}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{int32(1)}, "b": func(c interface{}) bool { return c == int32(1) }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{int32(1)}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{int64(1)}, "b": func(c interface{}) bool { return c == int64(1) }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{float32(1.1)}, "b": func(c interface{}) bool { return c == float32(1.1) }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{float32(1.1)}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{float64(1.1)}, "b": func(c interface{}) bool { return c == float64(1.1) }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{float64(1.1)}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{"a"}, "b": func(c interface{}) bool { return c == "a" }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{"a"}}}, + + // TOFIX: + // {Script: `b(a)`, + // Input: map[string]interface{}{"a": []bool{true, false, true}, "b": func(c ...bool) bool { return c[len(c)-1] }}, + // RunOutput: true, Output: map[string]interface{}{"a": true}}, + + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{true}, "b": func(c bool) bool { return c == true }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{true}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{int32(1)}, "b": func(c int32) bool { return c == int32(1) }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{int32(1)}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{int64(1)}, "b": func(c int64) bool { return c == int64(1) }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{float32(1.1)}, "b": func(c float32) bool { return c == float32(1.1) }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{float32(1.1)}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{float64(1.1)}, "b": func(c float64) bool { return c == float64(1.1) }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{float64(1.1)}}}, + {Script: `b(a[0])`, Input: map[string]interface{}{"a": []interface{}{"a"}, "b": func(c string) bool { return c == "a" }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{"a"}}}, + + {Script: `a = [nil]; b(a[0])`, Input: map[string]interface{}{"b": func(c interface{}) bool { return c == nil }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{nil}}}, + {Script: `a = [true]; b(a[0])`, Input: map[string]interface{}{"b": func(c bool) bool { return c == true }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{true}}}, + {Script: `a = [1]; b(a[0])`, Input: map[string]interface{}{"b": func(c int64) bool { return c == int64(1) }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `a = [1.1]; b(a[0])`, Input: map[string]interface{}{"b": func(c float64) bool { return c == float64(1.1) }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{float64(1.1)}}}, + {Script: `a = ["a"]; b(a[0])`, Input: map[string]interface{}{"b": func(c string) bool { return c == "a" }}, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{"a"}}}, + + {Script: `a = [nil]; func b(c) { c == nil }; b(a[0])`, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{nil}}}, + {Script: `a = [true]; func b(c) { c == true }; b(a[0])`, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{true}}}, + {Script: `a = [1]; func b(c) { c == 1 }; b(a[0])`, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `a = [1.1]; func b(c) { c == 1.1 }; b(a[0])`, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{float64(1.1)}}}, + {Script: `a = ["a"]; func b(c) { c == "a" }; b(a[0])`, RunOutput: true, Output: map[string]interface{}{"a": []interface{}{"a"}}}, + + {Script: `a = nil; b = func (d) { return d == nil }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": nil}}, + {Script: `a = true; b = func (d) { return d == true }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `a = 1; b = func (d) { return d == 1 }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1.1; b = func (d) { return d == 1.1 }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `a = "a"; b = func (d) { return d == "a" }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": "a"}}, + + {Script: `a = nil; b = func c(d) { return d == nil }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": nil}}, + {Script: `a = true; b = func c(d) { return d == true }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `a = 1; b = func c(d) { return d == 1 }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1.1; b = func c(d) { return d == 1.1 }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `a = "a"; b = func c(d) { return d == "a" }; b(a)`, RunOutput: true, Output: map[string]interface{}{"a": "a"}}, + + {Script: `a = nil; b = func c(d) { return d == nil }; c(a)`, RunOutput: true, Output: map[string]interface{}{"a": nil}}, + {Script: `a = true; b = func c(d) { return d == true }; c(a)`, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `a = 1; b = func c(d) { return d == 1 }; c(a)`, RunOutput: true, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1.1; b = func c(d) { return d == 1.1 }; c(a)`, RunOutput: true, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `a = "a"; b = func c(d) { return d == "a" }; c(a)`, RunOutput: true, Output: map[string]interface{}{"a": "a"}}, + + {Script: `a = nil; func b() { return func c(d) { d == nil } }; e = b(); e(a)`, RunOutput: true, Output: map[string]interface{}{"a": nil}}, + {Script: `a = true; func b() { return func c(d) { d == true } }; e = b(); e(a)`, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `a = 1; func b() { return func c(d) { d == 1 } }; e = b(); e(a)`, RunOutput: true, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1.1; func b() { return func c(d) { d == 1.1 } }; e = b(); e(a)`, RunOutput: true, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `a = "a"; func b() { return func c(d) { d == "a" } }; e = b(); e(a)`, RunOutput: true, Output: map[string]interface{}{"a": "a"}}, + + {Script: `a = func () { return nil }; func b(c) { return c() }; b(a)`, RunOutput: nil}, + {Script: `a = func () { return true }; func b(c) { return c() }; b(a)`, RunOutput: true}, + {Script: `a = func () { return 1 }; func b(c) { return c() }; b(a)`, RunOutput: int64(1)}, + {Script: `a = func () { return 1.1 }; func b(c) { return c() }; b(a)`, RunOutput: float64(1.1)}, + {Script: `a = func () { return "a" }; func b(c) { return c() }; b(a)`, RunOutput: "a"}, + + {Script: `a = [nil]; func c(d) { return d[0] }; c(a)`, RunOutput: nil}, + {Script: `a = [true]; func c(d) { return d[0] }; c(a)`, RunOutput: true}, + {Script: `a = [1]; func c(d) { return d[0] }; c(a)`, RunOutput: int64(1)}, + {Script: `a = [1.1]; func c(d) { return d[0] }; c(a)`, RunOutput: float64(1.1)}, + {Script: `a = ["a"]; func c(d) { return d[0] }; c(a)`, RunOutput: "a"}, + + {Script: `a = {"b": nil}; func c(d) { return d.b }; c(a)`, RunOutput: nil}, + {Script: `a = {"b": true}; func c(d) { return d.b }; c(a)`, RunOutput: true}, + {Script: `a = {"b": 1}; func c(d) { return d.b }; c(a)`, RunOutput: int64(1)}, + {Script: `a = {"b": 1.1}; func c(d) { return d.b }; c(a)`, RunOutput: float64(1.1)}, + {Script: `a = {"b": "a"}; func c(d) { return d.b }; c(a)`, RunOutput: "a"}, + + {Script: `a = func() { return func(c) { return c + "c"} }; a()("a")`, RunOutput: "ac"}, + {Script: `a = func() { return func(c) { return c + "c"} }(); a("a")`, RunOutput: "ac"}, + {Script: `a = func() { return func(c) { return c + "c"} }()("a")`, RunOutput: "ac"}, + {Script: `func() { return func(c) { return c + "c"} }()("a")`, RunOutput: "ac"}, + + {Script: `a = func(b) { return func() { return b + "c"} }; b = a("a"); b()`, RunOutput: "ac"}, + {Script: `a = func(b) { return func() { return b + "c"} }("a"); a()`, RunOutput: "ac"}, + {Script: `a = func(b) { return func() { return b + "c"} }("a")()`, RunOutput: "ac"}, + {Script: `func(b) { return func() { return b + "c"} }("a")()`, RunOutput: "ac"}, + + {Script: `a = func(b) { return func(c) { return b[c] } }; b = a({"x": "x"}); b("x")`, RunOutput: "x"}, + {Script: `a = func(b) { return func(c) { return b[c] } }({"x": "x"}); a("x")`, RunOutput: "x"}, + {Script: `a = func(b) { return func(c) { return b[c] } }({"x": "x"})("x")`, RunOutput: "x"}, + {Script: `func(b) { return func(c) { return b[c] } }({"x": "x"})("x")`, RunOutput: "x"}, + + {Script: `a = func(b) { return func(c) { return b[c] } }; x = {"y": "y"}; b = a(x); x = {"y": "y"}; b("y")`, RunOutput: "y"}, + {Script: `a = func(b) { return func(c) { return b[c] } }; x = {"y": "y"}; b = a(x); x.y = "z"; b("y")`, RunOutput: "z"}, + + {Script: ` func a() { return "a" }; a()`, RunOutput: "a"}, + {Script: `a = func a() { return "a" }; a = func() { return "b" }; a()`, RunOutput: "b"}, + {Script: `a = "a.b"; func a() { return "a" }; a()`, RunOutput: "a"}, + + {Script: `a = func() { b = "b"; return func() { b += "c" } }(); a()`, RunOutput: "bc"}, + {Script: `a = func() { b = "b"; return func() { b += "c"; return b} }(); a()`, RunOutput: "bc"}, + {Script: `a = func(b) { return func(c) { return func(d) { return d + "d" }(c) + "c" }(b) + "b" }("a")`, RunOutput: "adcb"}, + {Script: `a = func(b) { return "b" + func(c) { return "c" + func(d) { return "d" + d }(c) }(b) }("a")`, RunOutput: "bcda"}, + {Script: `a = func(b) { return b + "b" }; a( func(c) { return c + "c" }("a") )`, RunOutput: "acb"}, + + {Script: `a = func(x, y) { return func() { x(y) } }; b = a(func (z) { return z + "z" }, "b"); b()`, RunOutput: "bz"}, + + {Script: `a = make(Time); a.IsZero()`, Types: map[string]interface{}{"Time": time.Time{}}, RunOutput: true}, + + {Script: `a = make(Buffer); n, err = a.WriteString("a"); if err != nil { return err }; n`, Types: map[string]interface{}{"Buffer": bytes.Buffer{}}, RunOutput: 1}, + {Script: `a = make(Buffer); n, err = a.WriteString("a"); if err != nil { return err }; a.String()`, Types: map[string]interface{}{"Buffer": bytes.Buffer{}}, RunOutput: "a"}, + + {Script: `b = {}; c = a(b.c); c`, Input: map[string]interface{}{"a": func(b string) bool { + if b == "" { + return true + } + return false + }}, RunOutput: true}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestPointerFunctions(t *testing.T) { + t.Parallel() + + testFunctionPointer := func(b interface{}) string { + rv := reflect.ValueOf(b) + if !rv.IsValid() { + return "invalid" + } + if rv.Kind() != reflect.Ptr { + return fmt.Sprintf("not ptr: " + rv.Kind().String()) + } + if rv.IsNil() { + return "IsNil" + } + if !rv.Elem().CanInterface() { + return "cannot interface" + } + if rv.Elem().Interface() != int64(1) { + return fmt.Sprintf("not 1: %v", rv.Elem().Interface()) + } + if !rv.Elem().CanSet() { + return "cannot set" + } + slice := reflect.MakeSlice(interfaceSliceType, 0, 1) + value, _ := makeValue(stringType) + value.SetString("b") + slice = reflect.Append(slice, value) + rv.Elem().Set(slice) + return "good" + } + tests := []Test{ + {Script: `b = 1; a(&b)`, Input: map[string]interface{}{"a": testFunctionPointer}, RunOutput: "good", Output: map[string]interface{}{"b": []interface{}{"b"}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestVariadicFunctions(t *testing.T) { + t.Parallel() + + tests := []Test{ + // params Variadic arg !Variadic + {Script: `func a(b...) { return b }; a()`, RunOutput: []interface{}{}}, + {Script: `func a(b...) { return b }; a(true)`, RunOutput: []interface{}{true}}, + {Script: `func a(b...) { return b }; a(true, true)`, RunOutput: []interface{}{true, true}}, + {Script: `func a(b...) { return b }; a([true])`, RunOutput: []interface{}{[]interface{}{true}}}, + {Script: `func a(b...) { return b }; a([true, true])`, RunOutput: []interface{}{[]interface{}{true, true}}}, + {Script: `func a(b...) { return b }; a([true, true], [true, true])`, RunOutput: []interface{}{[]interface{}{true, true}, []interface{}{true, true}}}, + + // params Variadic arg !Variadic + {Script: `func a(b, c...) { return c }; a()`, RunError: fmt.Errorf("function wants 2 arguments but received 0")}, + {Script: `func a(b, c...) { return c }; a(true)`, RunOutput: []interface{}{}}, + {Script: `func a(b, c...) { return c }; a(true, true)`, RunOutput: []interface{}{true}}, + {Script: `func a(b, c...) { return c }; a(true, true, true)`, RunOutput: []interface{}{true, true}}, + {Script: `func a(b, c...) { return c }; a([true])`, RunOutput: []interface{}{}}, + {Script: `func a(b, c...) { return c }; a([true], [true])`, RunOutput: []interface{}{[]interface{}{true}}}, + {Script: `func a(b, c...) { return c }; a([true], [true], [true])`, RunOutput: []interface{}{[]interface{}{true}, []interface{}{true}}}, + {Script: `func a(b, c...) { return c }; a([true], [true, true], [true, true])`, RunOutput: []interface{}{[]interface{}{true, true}, []interface{}{true, true}}}, + + // params Variadic arg Variadic + {Script: `func a(b...) { return b }; a([true]...)`, RunOutput: []interface{}{true}}, + {Script: `func a(b...) { return b }; a([true, true]...)`, RunOutput: []interface{}{true, true}}, + {Script: `func a(b...) { return b }; a(true, [true]...)`, RunError: fmt.Errorf("function wants 1 arguments but received 2")}, + + // params Variadic arg Variadic + {Script: `func a(b, c...) { return c }; a([true]...)`, RunOutput: []interface{}{}}, + {Script: `func a(b, c...) { return c }; a([true, true]...)`, RunOutput: []interface{}{}}, + {Script: `func a(b, c...) { return c }; a(true, [true]...)`, RunOutput: []interface{}{true}}, + {Script: `func a(b, c...) { return c }; a(true, [true, true]...)`, RunOutput: []interface{}{true, true}}, + + // params !Variadic arg Variadic + {Script: `func a() { return "a" }; a([true]...)`, RunOutput: "a"}, + {Script: `func a() { return "a" }; a(true, [true]...)`, RunOutput: "a"}, + {Script: `func a() { return "a" }; a(true, [true, true]...)`, RunOutput: "a"}, + + // params !Variadic arg Variadic + {Script: `func a(b) { return b }; a(true...)`, RunError: fmt.Errorf("call is variadic but last parameter is of type bool")}, + {Script: `func a(b) { return b }; a([true]...)`, RunOutput: true}, + {Script: `func a(b) { return b }; a(true, false...)`, RunError: fmt.Errorf("function wants 1 arguments but received 2")}, + {Script: `func a(b) { return b }; a(true, [1]...)`, RunError: fmt.Errorf("function wants 1 arguments but received 2")}, + {Script: `func a(b) { return b }; a(true, [1, 2]...)`, RunError: fmt.Errorf("function wants 1 arguments but received 2")}, + {Script: `func a(b) { return b }; a([true, 1]...)`, RunOutput: true}, + {Script: `func a(b) { return b }; a([true, 1, 2]...)`, RunOutput: true}, + + // params !Variadic arg Variadi + {Script: `func a(b, c) { return c }; a(false...)`, RunError: fmt.Errorf("call is variadic but last parameter is of type bool")}, + {Script: `func a(b, c) { return c }; a([1]...)`, RunError: fmt.Errorf("function wants 2 arguments but received 1")}, + {Script: `func a(b, c) { return c }; a(1, true...)`, RunError: fmt.Errorf("call is variadic but last parameter is of type bool")}, + {Script: `func a(b, c) { return c }; a(1, [true]...)`, RunOutput: true}, + {Script: `func a(b, c) { return c }; a([1, true]...)`, RunOutput: true}, + {Script: `func a(b, c) { return c }; a(1, true...)`, RunError: fmt.Errorf("call is variadic but last parameter is of type bool")}, + {Script: `func a(b, c) { return c }; a(1, [true]...)`, RunOutput: true}, + {Script: `func a(b, c) { return c }; a(1, true, false...)`, RunError: fmt.Errorf("function wants 2 arguments but received 3")}, + {Script: `func a(b, c) { return c }; a(1, true, [2]...)`, RunError: fmt.Errorf("function wants 2 arguments but received 3")}, + {Script: `func a(b, c) { return c }; a(1, [true, 2]...)`, RunOutput: true}, + {Script: `func a(b, c) { return c }; a([1, true, 2]...)`, RunOutput: true}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestFunctionsInArraysAndMaps(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a = [func () { return nil }]; a[0]()`, RunOutput: nil}, + {Script: `a = [func () { return true }]; a[0]()`, RunOutput: true}, + {Script: `a = [func () { return 1 }]; a[0]()`, RunOutput: int64(1)}, + {Script: `a = [func () { return 1.1 }]; a[0]()`, RunOutput: float64(1.1)}, + {Script: `a = [func () { return "a" }]; a[0]()`, RunOutput: "a"}, + + {Script: `a = [func () { return nil }]; b = a[0]; b()`, RunOutput: nil}, + {Script: `a = [func () { return true }]; b = a[0]; b()`, RunOutput: true}, + {Script: `a = [func () { return 1 }]; b = a[0]; b()`, RunOutput: int64(1)}, + {Script: `a = [func () { return 1.1 }]; b = a[0]; b()`, RunOutput: float64(1.1)}, + {Script: `a = [func () { return "a" }]; b = a[0]; b()`, RunOutput: "a"}, + + {Script: `a = [func () { return nil}]; func b(c) { return c() }; b(a[0])`, RunOutput: nil}, + {Script: `a = [func () { return true}]; func b(c) { return c() }; b(a[0])`, RunOutput: true}, + {Script: `a = [func () { return 1}]; func b(c) { return c() }; b(a[0])`, RunOutput: int64(1)}, + {Script: `a = [func () { return 1.1}]; func b(c) { return c() }; b(a[0])`, RunOutput: float64(1.1)}, + {Script: `a = [func () { return "a"}]; func b(c) { return c() }; b(a[0])`, RunOutput: "a"}, + + {Script: `a = {"b": func () { return nil }}; a["b"]()`, RunOutput: nil}, + {Script: `a = {"b": func () { return true }}; a["b"]()`, RunOutput: true}, + {Script: `a = {"b": func () { return 1 }}; a["b"]()`, RunOutput: int64(1)}, + {Script: `a = {"b": func () { return 1.1 }}; a["b"]()`, RunOutput: float64(1.1)}, + {Script: `a = {"b": func () { return "a" }}; a["b"]()`, RunOutput: "a"}, + + {Script: `a = {"b": func () { return nil }}; a.b()`, RunOutput: nil}, + {Script: `a = {"b": func () { return true }}; a.b()`, RunOutput: true}, + {Script: `a = {"b": func () { return 1 }}; a.b()`, RunOutput: int64(1)}, + {Script: `a = {"b": func () { return 1.1 }}; a.b()`, RunOutput: float64(1.1)}, + {Script: `a = {"b": func () { return "a" }}; a.b()`, RunOutput: "a"}, + + {Script: `a = {"b": func () { return nil }}; func c(d) { return d() }; c(a.b)`, RunOutput: nil}, + {Script: `a = {"b": func () { return true }}; func c(d) { return d() }; c(a.b)`, RunOutput: true}, + {Script: `a = {"b": func () { return 1 }}; func c(d) { return d() }; c(a.b)`, RunOutput: int64(1)}, + {Script: `a = {"b": func () { return 1.1 }}; func c(d) { return d() }; c(a.b)`, RunOutput: float64(1.1)}, + {Script: `a = {"b": func () { return "a" }}; func c(d) { return d() }; c(a.b)`, RunOutput: "a"}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestFunctionConversions(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `b = func(c){ return c }; a("x", b)`, Input: map[string]interface{}{"a": func(b string, c func(string) string) string { return c(b) }}, RunOutput: "x"}, + {Script: `b = make(struct1); b.A = func (c, d) { return c == d }; b.A(2, 2)`, Types: map[string]interface{}{"struct1": &struct { + A func(int, int) bool + }{}}, + RunOutput: true}, + {Script: `b = 1; a(&b)`, Input: map[string]interface{}{"a": func(b *int64) { *b = int64(2) }}, Output: map[string]interface{}{"b": int64(2)}}, + {Script: `b = func(){ return true, 1, 2, 3.3, 4.4, "5" }; c, d, e, f, g, h = a(b); c`, Input: map[string]interface{}{"a": func(b func() (bool, int32, int64, float32, float64, string)) (bool, int32, int64, float32, float64, string) { + return b() + }}, RunOutput: true, Output: map[string]interface{}{"c": true, "d": int32(1), "e": int64(2), "f": float32(3.3), "g": float64(4.4), "h": "5"}}, + + // string to byte + {Script: `b = a("yz"); b`, Input: map[string]interface{}{"a": func(b byte) string { return string(b) }}, RunError: fmt.Errorf("function wants argument type uint8 but received type string")}, + {Script: `b = a("x"); b`, Input: map[string]interface{}{"a": func(b byte) string { return string(b) }}, RunOutput: "x"}, + {Script: `b = a(""); b`, Input: map[string]interface{}{"a": func(b byte) string { return string(b) }}, RunOutput: "\x00"}, + // string to rune + {Script: `b = a("yz"); b`, Input: map[string]interface{}{"a": func(b rune) string { return string(b) }}, RunError: fmt.Errorf("function wants argument type int32 but received type string")}, + {Script: `b = a("x"); b`, Input: map[string]interface{}{"a": func(b rune) string { return string(b) }}, RunOutput: "x"}, + {Script: `b = a(""); b`, Input: map[string]interface{}{"a": func(b rune) string { return string(b) }}, RunOutput: "\x00"}, + + // slice inteface unable to convert to int + {Script: `b = [1, 2.2, "3"]; a(b)`, Input: map[string]interface{}{"a": func(b []int) int { return len(b) }}, RunError: fmt.Errorf("function wants argument type []int but received type []interface {}"), Output: map[string]interface{}{"b": []interface{}{int64(1), float64(2.2), "3"}}}, + // slice no sub convertible conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b []int) int { return len(b) }, "b": []int64{1}}, RunOutput: int(1), Output: map[string]interface{}{"b": []int64{1}}}, + // array no sub convertible conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b [2]int) int { return len(b) }, "b": [2]int64{1, 2}}, RunOutput: int(2), Output: map[string]interface{}{"b": [2]int64{1, 2}}}, + // slice no sub to interface conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b []interface{}) int { return len(b) }, "b": []int64{1}}, RunOutput: int(1), Output: map[string]interface{}{"b": []int64{1}}}, + // array no sub to interface conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b [2]interface{}) int { return len(b) }, "b": [2]int64{1, 2}}, RunOutput: int(2), Output: map[string]interface{}{"b": [2]int64{1, 2}}}, + // slice no sub from interface conversion + {Script: `b = [1]; a(b)`, Input: map[string]interface{}{"a": func(b []int) int { return len(b) }}, RunOutput: int(1), Output: map[string]interface{}{"b": []interface{}{int64(1)}}}, + // array no sub from interface conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b [2]int) int { return len(b) }, "b": [2]interface{}{1, 2}}, RunOutput: int(2), Output: map[string]interface{}{"b": [2]interface{}{1, 2}}}, + + // slice sub mismatch + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b []int) int { return len(b) }, "b": [][]int64{{1, 2}}}, RunError: fmt.Errorf("function wants argument type []int but received type [][]int64"), Output: map[string]interface{}{"b": [][]int64{{1, 2}}}}, + // array sub mismatch + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b [2]int) int { return len(b) }, "b": [1][2]int64{{1, 2}}}, RunError: fmt.Errorf("function wants argument type [2]int but received type [1][2]int64"), Output: map[string]interface{}{"b": [1][2]int64{{1, 2}}}}, + + // slice with sub int64 to int conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b [][]int) int { return len(b) }, "b": [][]int64{{1, 2}, {3, 4}}}, RunOutput: int(2), Output: map[string]interface{}{"b": [][]int64{{1, 2}, {3, 4}}}}, + // array with sub int64 to int conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b [][]int) int { return len(b) }, "b": [2][2]int64{{1, 2}, {3, 4}}}, RunOutput: int(2), Output: map[string]interface{}{"b": [2][2]int64{{1, 2}, {3, 4}}}}, + // slice with sub interface to int conversion + {Script: `b = [[1, 2], [3, 4]]; a(b)`, Input: map[string]interface{}{"a": func(b [][]int) int { return len(b) }}, RunOutput: int(2), Output: map[string]interface{}{"b": []interface{}{[]interface{}{int64(1), int64(2)}, []interface{}{int64(3), int64(4)}}}}, + // slice with sub interface to int conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b [][]int) int { return len(b) }, "b": [][]interface{}{{int64(1), int32(2)}, {float64(3.3), float32(4.4)}}}, RunOutput: int(2), Output: map[string]interface{}{"b": [][]interface{}{{int64(1), int32(2)}, {float64(3.3), float32(4.4)}}}}, + // array with sub interface to int conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b [][]int) int { return len(b) }, "b": [2][2]interface{}{{1, 2}, {3, 4}}}, RunOutput: int(2), Output: map[string]interface{}{"b": [2][2]interface{}{{1, 2}, {3, 4}}}}, + // slice with single interface to double interface + {Script: `b = [[1, 2], [3, 4]]; a(b)`, Input: map[string]interface{}{"a": func(b [][]interface{}) int { return len(b) }}, RunOutput: int(2), Output: map[string]interface{}{"b": []interface{}{[]interface{}{int64(1), int64(2)}, []interface{}{int64(3), int64(4)}}}}, + // slice with sub int64 to double interface conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b [][]interface{}) int { return len(b) }, "b": [][]int64{{1, 2}, {3, 4}}}, RunOutput: int(2), Output: map[string]interface{}{"b": [][]int64{{1, 2}, {3, 4}}}}, + // array with sub int64 to double interface conversion + {Script: `a(b)`, Input: map[string]interface{}{"a": func(b [][]interface{}) int { return len(b) }, "b": [2][2]int64{{1, 2}, {3, 4}}}, RunOutput: int(2), Output: map[string]interface{}{"b": [2][2]int64{{1, 2}, {3, 4}}}}, + + // TOFIX: not able to change pointer value + // {Script: `b = 1; c = &b; a(c); *c`, Input: map[string]interface{}{"a": func(b *int64) { *b = int64(2) }}, RunOutput: int64(2), Output: map[string]interface{}{"b": int64(2)}}, + + // map [interface]interface to [interface]interface + {Script: `b = {nil:nil}; c = nil; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[interface{}]interface{}, c interface{}) interface{} { return b[c] }}, RunOutput: nil, Output: map[string]interface{}{"b": map[interface{}]interface{}{nil: nil}, "c": nil}}, + {Script: `b = {true:true}; c = true; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[interface{}]interface{}, c interface{}) interface{} { return b[c] }}, RunOutput: true, Output: map[string]interface{}{"b": map[interface{}]interface{}{true: true}, "c": true}}, + {Script: `b = {1:2}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[interface{}]interface{}, c interface{}) interface{} { return b[c] }}, RunOutput: int64(2), Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): int64(2)}, "c": int64(1)}}, + {Script: `b = {1.1:2.2}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[interface{}]interface{}, c interface{}) interface{} { return b[c] }}, RunOutput: float64(2.2), Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): float64(2.2)}, "c": float64(1.1)}}, + {Script: `b = {"a":"b"}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[interface{}]interface{}, c interface{}) interface{} { return b[c] }}, RunOutput: "b", Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": "b"}, "c": "a"}}, + + // map [interface]interface to [bool]interface + {Script: `b = {"a":"b"}; c = true; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[bool]interface{}, c bool) interface{} { return b[c] }}, RunError: fmt.Errorf("function wants argument type map[bool]interface {} but received type map[interface {}]interface {}"), Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": "b"}, "c": true}}, + {Script: `b = {"a":"b"}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[bool]interface{}, c bool) interface{} { return b[c] }}, RunError: fmt.Errorf("function wants argument type map[bool]interface {} but received type map[interface {}]interface {}"), Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": "b"}, "c": "a"}}, + {Script: `b = {true:"b"}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[bool]interface{}, c bool) interface{} { return b[c] }}, RunError: fmt.Errorf("function wants argument type bool but received type string"), Output: map[string]interface{}{"b": map[interface{}]interface{}{true: "b"}, "c": "a"}}, + {Script: `b = {true:nil}; c = true; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[bool]interface{}, c bool) interface{} { return b[c] }}, RunOutput: nil, Output: map[string]interface{}{"b": map[interface{}]interface{}{true: nil}, "c": true}}, + {Script: `b = {true:true}; c = true; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[bool]interface{}, c bool) interface{} { return b[c] }}, RunOutput: true, Output: map[string]interface{}{"b": map[interface{}]interface{}{true: true}, "c": true}}, + {Script: `b = {true:2}; c = true; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[bool]interface{}, c bool) interface{} { return b[c] }}, RunOutput: int64(2), Output: map[string]interface{}{"b": map[interface{}]interface{}{true: int64(2)}, "c": true}}, + {Script: `b = {true:2.2}; c = true; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[bool]interface{}, c bool) interface{} { return b[c] }}, RunOutput: float64(2.2), Output: map[string]interface{}{"b": map[interface{}]interface{}{true: float64(2.2)}, "c": true}}, + {Script: `b = {true:"b"}; c = true; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[bool]interface{}, c bool) interface{} { return b[c] }}, RunOutput: "b", Output: map[string]interface{}{"b": map[interface{}]interface{}{true: "b"}, "c": true}}, + + // map [interface]interface to [int32]interface + {Script: `b = {1:nil}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[int32]interface{}, c int32) interface{} { return b[c] }}, RunOutput: nil, Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): nil}, "c": int64(1)}}, + {Script: `b = {1:true}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[int32]interface{}, c int32) interface{} { return b[c] }}, RunOutput: true, Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): true}, "c": int64(1)}}, + {Script: `b = {1:2}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[int32]interface{}, c int32) interface{} { return b[c] }}, RunOutput: int64(2), Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): int64(2)}, "c": int64(1)}}, + {Script: `b = {1:2.2}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[int32]interface{}, c int32) interface{} { return b[c] }}, RunOutput: float64(2.2), Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): float64(2.2)}, "c": int64(1)}}, + {Script: `b = {1:"b"}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[int32]interface{}, c int32) interface{} { return b[c] }}, RunOutput: "b", Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): "b"}, "c": int64(1)}}, + + // map [interface]interface to [int64]interface + {Script: `b = {1:nil}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[int64]interface{}, c int64) interface{} { return b[c] }}, RunOutput: nil, Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): nil}, "c": int64(1)}}, + {Script: `b = {1:true}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[int64]interface{}, c int64) interface{} { return b[c] }}, RunOutput: true, Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): true}, "c": int64(1)}}, + {Script: `b = {1:2}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[int64]interface{}, c int64) interface{} { return b[c] }}, RunOutput: int64(2), Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): int64(2)}, "c": int64(1)}}, + {Script: `b = {1:2.2}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[int64]interface{}, c int64) interface{} { return b[c] }}, RunOutput: float64(2.2), Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): float64(2.2)}, "c": int64(1)}}, + {Script: `b = {1:"b"}; c = 1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[int64]interface{}, c int64) interface{} { return b[c] }}, RunOutput: "b", Output: map[string]interface{}{"b": map[interface{}]interface{}{int64(1): "b"}, "c": int64(1)}}, + + // map [interface]interface to [float32]interface + {Script: `b = {1.1:nil}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[float32]interface{}, c float32) interface{} { return b[c] }}, RunOutput: nil, Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): nil}, "c": float64(1.1)}}, + {Script: `b = {1.1:true}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[float32]interface{}, c float32) interface{} { return b[c] }}, RunOutput: true, Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): true}, "c": float64(1.1)}}, + {Script: `b = {1.1:2}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[float32]interface{}, c float32) interface{} { return b[c] }}, RunOutput: int64(2), Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): int64(2)}, "c": float64(1.1)}}, + {Script: `b = {1.1:2.2}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[float32]interface{}, c float32) interface{} { return b[c] }}, RunOutput: float64(2.2), Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): float64(2.2)}, "c": float64(1.1)}}, + {Script: `b = {1.1:"b"}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[float32]interface{}, c float32) interface{} { return b[c] }}, RunOutput: "b", Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): "b"}, "c": float64(1.1)}}, + + // map [interface]interface to [float64]interface + {Script: `b = {1.1:nil}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[float64]interface{}, c float64) interface{} { return b[c] }}, RunOutput: nil, Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): nil}, "c": float64(1.1)}}, + {Script: `b = {1.1:true}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[float64]interface{}, c float64) interface{} { return b[c] }}, RunOutput: true, Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): true}, "c": float64(1.1)}}, + {Script: `b = {1.1:2}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[float64]interface{}, c float64) interface{} { return b[c] }}, RunOutput: int64(2), Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): int64(2)}, "c": float64(1.1)}}, + {Script: `b = {1.1:2.2}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[float64]interface{}, c float64) interface{} { return b[c] }}, RunOutput: float64(2.2), Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): float64(2.2)}, "c": float64(1.1)}}, + {Script: `b = {1.1:"b"}; c = 1.1; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[float64]interface{}, c float64) interface{} { return b[c] }}, RunOutput: "b", Output: map[string]interface{}{"b": map[interface{}]interface{}{float64(1.1): "b"}, "c": float64(1.1)}}, + + // map [interface]interface to [string]interface + {Script: `b = {"a":nil}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]interface{}, c string) interface{} { return b[c] }}, RunOutput: nil, Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": nil}, "c": "a"}}, + {Script: `b = {"a":true}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]interface{}, c string) interface{} { return b[c] }}, RunOutput: true, Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": true}, "c": "a"}}, + {Script: `b = {"a":2}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]interface{}, c string) interface{} { return b[c] }}, RunOutput: int64(2), Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": int64(2)}, "c": "a"}}, + {Script: `b = {"a":2.2}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]interface{}, c string) interface{} { return b[c] }}, RunOutput: float64(2.2), Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": float64(2.2)}, "c": "a"}}, + {Script: `b = {"a":"b"}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]interface{}, c string) interface{} { return b[c] }}, RunOutput: "b", Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": "b"}, "c": "a"}}, + + // map [interface]interface to [string]X + {Script: `b = {"a":"b"}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]bool, c string) bool { return b[c] }}, RunError: fmt.Errorf("function wants argument type map[string]bool but received type map[interface {}]interface {}"), Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": "b"}, "c": "a"}}, + {Script: `b = {"a":true}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]bool, c string) bool { return b[c] }}, RunOutput: true, Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": true}, "c": "a"}}, + {Script: `b = {"a":1}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]int32, c string) int32 { return b[c] }}, RunOutput: int32(1), Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": int64(1)}, "c": "a"}}, + {Script: `b = {"a":1}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]int64, c string) int64 { return b[c] }}, RunOutput: int64(1), Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": int64(1)}, "c": "a"}}, + {Script: `b = {"a":1.1}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]float32, c string) float32 { return b[c] }}, RunOutput: float32(1.1), Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": float64(1.1)}, "c": "a"}}, + {Script: `b = {"a":1.1}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]float64, c string) float64 { return b[c] }}, RunOutput: float64(1.1), Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": float64(1.1)}, "c": "a"}}, + {Script: `b = {"a":"b"}; c = "a"; d = a(b, c)`, Input: map[string]interface{}{"a": func(b map[string]string, c string) string { return b[c] }}, RunOutput: "b", Output: map[string]interface{}{"b": map[interface{}]interface{}{"a": "b"}, "c": "a"}}, + } + runTests(t, tests, nil, &Options{Debug: true}) + + tests = []Test{ + {Script: `c = a(b)`, + Input: map[string]interface{}{"a": func(b func() bool) bool { + return b() + }, "b": func(c func(bool)) { c(true) }}, RunError: fmt.Errorf("function wants argument type func() bool but received type func(func(bool))")}, + {Script: `b = func(){ return 1++ }; c = a(b)`, + Input: map[string]interface{}{"a": func(b func() bool) bool { + return b() + }}, RunError: fmt.Errorf("invalid operation")}, + {Script: `b = func(){ return true }; c = a(b)`, + Input: map[string]interface{}{"a": func(b func() string) string { + return b() + }}, RunError: fmt.Errorf("function wants return type string but received type bool")}, + {Script: `b = func(){ return true }; c = a(b)`, + Input: map[string]interface{}{"a": func(b func() (bool, string)) (bool, string) { + return b() + }}, RunError: fmt.Errorf("function wants 2 return values but received bool")}, + {Script: `b = func(){ return true, 1 }; c = a(b)`, + Input: map[string]interface{}{"a": func(b func() (bool, int64, string)) (bool, int64, string) { + return b() + }}, RunError: fmt.Errorf("function wants 3 return values but received 2 values")}, + {Script: `b = func(){ return "1", true }; c = a(b)`, + Input: map[string]interface{}{"a": func(b func() (bool, string)) (bool, string) { + return b() + }}, RunError: fmt.Errorf("function wants return type bool but received type string")}, + } + runTests(t, tests, nil, &Options{Debug: false}) +} + +func TestVariadicFunctionConversions(t *testing.T) { + t.Parallel() + + testSumFunc := func(nums ...int64) int64 { + var total int64 + for _, num := range nums { + total += num + } + return total + } + tests := []Test{ + // params Variadic arg !Variadic + {Script: `a(true)`, Input: map[string]interface{}{"a": func(b ...interface{}) []interface{} { return b }}, RunOutput: []interface{}{true}}, + + {Script: `a()`, Input: map[string]interface{}{"a": testSumFunc}, RunOutput: int64(0)}, + {Script: `a(1)`, Input: map[string]interface{}{"a": testSumFunc}, RunOutput: int64(1)}, + {Script: `a(1, 2)`, Input: map[string]interface{}{"a": testSumFunc}, RunOutput: int64(3)}, + {Script: `a(1, 2, 3)`, Input: map[string]interface{}{"a": testSumFunc}, RunOutput: int64(6)}, + + // TODO: add more tests + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestLen(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `len(1++)`, RunError: fmt.Errorf("invalid operation")}, + {Script: `len(true)`, RunError: fmt.Errorf("type bool does not support len operation")}, + + {Script: `a = ""; len(a)`, RunOutput: int64(0)}, + {Script: `a = "test"; len(a)`, RunOutput: int64(4)}, + {Script: `a = []; len(a)`, RunOutput: int64(0)}, + {Script: `a = [nil]; len(a)`, RunOutput: int64(1)}, + {Script: `a = [true]; len(a)`, RunOutput: int64(1)}, + {Script: `a = ["test"]; len(a)`, RunOutput: int64(1)}, + {Script: `a = [1]; len(a)`, RunOutput: int64(1)}, + {Script: `a = [1.1]; len(a)`, RunOutput: int64(1)}, + + {Script: `a = [[]]; len(a)`, RunOutput: int64(1)}, + {Script: `a = [[nil]]; len(a)`, RunOutput: int64(1)}, + {Script: `a = [[true]]; len(a)`, RunOutput: int64(1)}, + {Script: `a = [["test"]]; len(a)`, RunOutput: int64(1)}, + {Script: `a = [[1]]; len(a)`, RunOutput: int64(1)}, + {Script: `a = [[1.1]]; len(a)`, RunOutput: int64(1)}, + + {Script: `a = [[]]; len(a[0])`, RunOutput: int64(0)}, + {Script: `a = [[nil]]; len(a[0])`, RunOutput: int64(1)}, + {Script: `a = [[true]]; len(a[0])`, RunOutput: int64(1)}, + {Script: `a = [["test"]]; len(a[0])`, RunOutput: int64(1)}, + {Script: `a = [[1]]; len(a[0])`, RunOutput: int64(1)}, + {Script: `a = [[1.1]]; len(a[0])`, RunOutput: int64(1)}, + + {Script: `len(a)`, Input: map[string]interface{}{"a": "a"}, RunOutput: int64(1), Output: map[string]interface{}{"a": "a"}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": map[string]interface{}{}}, RunOutput: int64(0), Output: map[string]interface{}{"a": map[string]interface{}{}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": map[string]interface{}{"test": "test"}}, RunOutput: int64(1), Output: map[string]interface{}{"a": map[string]interface{}{"test": "test"}}}, + {Script: `len(a["test"])`, Input: map[string]interface{}{"a": map[string]interface{}{"test": "test"}}, RunOutput: int64(4), Output: map[string]interface{}{"a": map[string]interface{}{"test": "test"}}}, + + {Script: `len(a)`, Input: map[string]interface{}{"a": []interface{}{}}, RunOutput: int64(0), Output: map[string]interface{}{"a": []interface{}{}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": []interface{}{nil}}, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{nil}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": []interface{}{true}}, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{true}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": []interface{}{int32(1)}}, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{int32(1)}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": []interface{}{int64(1)}}, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": []interface{}{float32(1.1)}}, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{float32(1.1)}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": []interface{}{float64(1.1)}}, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{float64(1.1)}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": []interface{}{"a"}}, RunOutput: int64(1), Output: map[string]interface{}{"a": []interface{}{"a"}}}, + + {Script: `len(a[0])`, Input: map[string]interface{}{"a": []interface{}{"test"}}, RunOutput: int64(4), Output: map[string]interface{}{"a": []interface{}{"test"}}}, + + {Script: `len(a)`, Input: map[string]interface{}{"a": [][]interface{}{}}, RunOutput: int64(0), Output: map[string]interface{}{"a": [][]interface{}{}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": [][]interface{}{nil}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{nil}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": [][]interface{}{{nil}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{nil}}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": [][]interface{}{{true}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{true}}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": [][]interface{}{{int32(1)}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{int32(1)}}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": [][]interface{}{{int64(1)}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{int64(1)}}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": [][]interface{}{{float32(1.1)}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{float32(1.1)}}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": [][]interface{}{{float64(1.1)}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{float64(1.1)}}}}, + {Script: `len(a)`, Input: map[string]interface{}{"a": [][]interface{}{{"a"}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{"a"}}}}, + + {Script: `len(a[0])`, Input: map[string]interface{}{"a": [][]interface{}{nil}}, RunOutput: int64(0), Output: map[string]interface{}{"a": [][]interface{}{nil}}}, + {Script: `len(a[0])`, Input: map[string]interface{}{"a": [][]interface{}{{nil}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{nil}}}}, + {Script: `len(a[0])`, Input: map[string]interface{}{"a": [][]interface{}{{true}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{true}}}}, + {Script: `len(a[0])`, Input: map[string]interface{}{"a": [][]interface{}{{int32(1)}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{int32(1)}}}}, + {Script: `len(a[0])`, Input: map[string]interface{}{"a": [][]interface{}{{int64(1)}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{int64(1)}}}}, + {Script: `len(a[0])`, Input: map[string]interface{}{"a": [][]interface{}{{float32(1.1)}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{float32(1.1)}}}}, + {Script: `len(a[0])`, Input: map[string]interface{}{"a": [][]interface{}{{float64(1.1)}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{float64(1.1)}}}}, + {Script: `len(a[0])`, Input: map[string]interface{}{"a": [][]interface{}{{"a"}}}, RunOutput: int64(1), Output: map[string]interface{}{"a": [][]interface{}{{"a"}}}}, + + {Script: `len(a[0][0])`, Input: map[string]interface{}{"a": [][]interface{}{{"test"}}}, RunOutput: int64(4), Output: map[string]interface{}{"a": [][]interface{}{{"test"}}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestCallFunctionWithVararg(t *testing.T) { + t.Parallel() + + e := env.NewEnv() + err := e.Define("X", func(args ...string) []string { + return args + }) + if err != nil { + t.Errorf("Define error: %v", err) + } + want := []string{"foo", "bar", "baz"} + err = e.Define("a", want) + if err != nil { + t.Errorf("Define error: %v", err) + } + got, err := Execute(e, nil, "X(a...)") + if err != nil { + t.Errorf("execute error - received %#v - expected: %#v", err, nil) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("execute error - received %#v - expected: %#v", got, want) + } +} + +func TestGoFunctionConcurrency(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: ` +waitGroup.Add(5); +a = []; b = []; c = []; d = []; e = [] +fa = func() { for i = 0; i < 100; i++ { a += 1 }; waitGroup.Done() } +fb = func() { for i = 0; i < 100; i++ { b += 2 }; waitGroup.Done() } +fc = func() { for i = 0; i < 100; i++ { c += 3 }; waitGroup.Done() } +fd = func() { for i = 0; i < 100; i++ { d += 4 }; waitGroup.Done() } +fe = func() { for i = 0; i < 100; i++ { e += 5 }; waitGroup.Done() } +go fa(); go fb(); go fc(); go fd(); go fe() +waitGroup.Wait()`, + Input: map[string]interface{}{"waitGroup": &sync.WaitGroup{}}, + Output: map[string]interface{}{ + "a": []interface{}{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}, + "b": []interface{}{int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2)}, + "c": []interface{}{int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3)}, + "d": []interface{}{int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4)}, + "e": []interface{}{int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5)}, + }}, + {Script: ` +waitGroup.Add(5); +x = [1, 2, 3, 4, 5] +a = []; b = []; c = []; d = []; e = [] +fa = func() { for i = 0; i < 100; i++ { a += x[0] }; waitGroup.Done() } +fb = func() { for i = 0; i < 100; i++ { b += x[1] }; waitGroup.Done() } +fc = func() { for i = 0; i < 100; i++ { c += x[2] }; waitGroup.Done() } +fd = func() { for i = 0; i < 100; i++ { d += x[3] }; waitGroup.Done() } +fe = func() { for i = 0; i < 100; i++ { e += x[4] }; waitGroup.Done() } +go fa(); go fb(); go fc(); go fd(); go fe() +waitGroup.Wait()`, + Input: map[string]interface{}{"waitGroup": &sync.WaitGroup{}}, + Output: map[string]interface{}{ + "a": []interface{}{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}, + "b": []interface{}{int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2)}, + "c": []interface{}{int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3)}, + "d": []interface{}{int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4)}, + "e": []interface{}{int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5)}, + }}, + {Script: ` +waitGroup.Add(5); +x = func(y) { return y } +a = []; b = []; c = []; d = []; e = [] +fa = func() { for i = 0; i < 100; i++ { a += x(1) }; waitGroup.Done() } +fb = func() { for i = 0; i < 100; i++ { b += x(2) }; waitGroup.Done() } +fc = func() { for i = 0; i < 100; i++ { c += x(3) }; waitGroup.Done() } +fd = func() { for i = 0; i < 100; i++ { d += x(4) }; waitGroup.Done() } +fe = func() { for i = 0; i < 100; i++ { e += x(5) }; waitGroup.Done() } +go fa(); go fb(); go fc(); go fd(); go fe() +waitGroup.Wait()`, + Input: map[string]interface{}{"waitGroup": &sync.WaitGroup{}}, + Output: map[string]interface{}{ + "a": []interface{}{int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1), int64(1)}, + "b": []interface{}{int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2), int64(2)}, + "c": []interface{}{int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3), int64(3)}, + "d": []interface{}{int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4), int64(4)}, + "e": []interface{}{int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5), int64(5)}, + }}, + } + + runTests(t, tests, nil, &Options{Debug: true}) +} diff --git a/src/tool/run/vm/vmLetExpr.go b/src/tool/run/vm/vmLetExpr.go new file mode 100644 index 0000000..865e2ee --- /dev/null +++ b/src/tool/run/vm/vmLetExpr.go @@ -0,0 +1,382 @@ +package vm + +import ( + "reflect" + + "github.com/surdeus/goblin/src/tool/run/ast" + "github.com/surdeus/goblin/src/tool/run/env" +) + +func (runInfo *runInfoStruct) invokeLetExpr() { + switch expr := runInfo.expr.(type) { + + // IdentExpr + case *ast.IdentExpr: + if runInfo.env.SetValue(expr.Lit, runInfo.rv) != nil { + runInfo.err = nil + runInfo.env.DefineValue(expr.Lit, runInfo.rv) + } + + // MemberExpr + case *ast.MemberExpr: + value := runInfo.rv + + runInfo.expr = expr.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + + if env, ok := runInfo.rv.Interface().(*env.Env); ok { + runInfo.err = env.SetValue(expr.Name, value) + if runInfo.err != nil { + runInfo.err = newError(expr, runInfo.err) + runInfo.rv = nilValue + } + return + } + + if runInfo.rv.Kind() == reflect.Ptr { + runInfo.rv = runInfo.rv.Elem() + } + + switch runInfo.rv.Kind() { + + // Struct + case reflect.Struct: + field, found := runInfo.rv.Type().FieldByName(expr.Name) + if !found { + runInfo.err = newStringError(expr, "no member named '"+expr.Name+"' for struct") + runInfo.rv = nilValue + return + } + runInfo.rv = runInfo.rv.FieldByIndex(field.Index) + // From reflect CanSet: + // A Value can be changed only if it is addressable and was not obtained by the use of unexported struct fields. + // Often a struct has to be passed as a pointer to be set + if !runInfo.rv.CanSet() { + runInfo.err = newStringError(expr, "struct member '"+expr.Name+"' cannot be assigned") + runInfo.rv = nilValue + return + } + + value, runInfo.err = convertReflectValueToType(value, runInfo.rv.Type()) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+runInfo.rv.Type().String()+" for struct") + runInfo.rv = nilValue + return + } + + runInfo.rv.Set(value) + return + + // Map + case reflect.Map: + value, runInfo.err = convertReflectValueToType(value, runInfo.rv.Type().Elem()) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+runInfo.rv.Type().Elem().String()+" for map") + runInfo.rv = nilValue + return + } + if runInfo.rv.IsNil() { + // make new map + item := reflect.MakeMap(runInfo.rv.Type()) + item.SetMapIndex(reflect.ValueOf(expr.Name), value) + // assign new map + runInfo.rv = item + runInfo.expr = expr.Expr + runInfo.invokeLetExpr() + runInfo.rv = item.MapIndex(reflect.ValueOf(expr.Name)) + return + } + runInfo.rv.SetMapIndex(reflect.ValueOf(expr.Name), value) + + default: + runInfo.err = newStringError(expr, "type "+runInfo.rv.Kind().String()+" does not support member operation") + runInfo.rv = nilValue + } + + // ItemExpr + case *ast.ItemExpr: + value := runInfo.rv + + runInfo.expr = expr.Item + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + item := runInfo.rv + + runInfo.expr = expr.Index + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + if item.Kind() == reflect.Interface && !item.IsNil() { + item = item.Elem() + } + + switch item.Kind() { + + // Slice && Array + case reflect.Slice, reflect.Array: + var index int + index, runInfo.err = tryToInt(runInfo.rv) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "index must be a number") + runInfo.rv = nilValue + return + } + + if index == item.Len() { + // try to do automatic append + value, runInfo.err = convertReflectValueToType(value, item.Type().Elem()) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+item.Type().Elem().String()+" for slice index") + runInfo.rv = nilValue + return + } + item = reflect.Append(item, value) + runInfo.rv = item + runInfo.expr = expr.Item + runInfo.invokeLetExpr() + runInfo.rv = item.Index(index) + return + } + + if index < 0 || index >= item.Len() { + runInfo.err = newStringError(expr, "index out of range") + runInfo.rv = nilValue + return + } + item = item.Index(index) + if !item.CanSet() { + runInfo.err = newStringError(expr, "index cannot be assigned") + runInfo.rv = nilValue + return + } + + value, runInfo.err = convertReflectValueToType(value, item.Type()) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+item.Type().String()+" for slice index") + runInfo.rv = nilValue + return + } + + item.Set(value) + runInfo.rv = item + + // Map + case reflect.Map: + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, item.Type().Key()) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "index type "+runInfo.rv.Type().String()+" cannot be used for map index type "+item.Type().Key().String()) + runInfo.rv = nilValue + return + } + + value, runInfo.err = convertReflectValueToType(value, item.Type().Elem()) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+item.Type().Elem().String()+" for map") + runInfo.rv = nilValue + return + } + + if item.IsNil() { + // make new map + item = reflect.MakeMap(item.Type()) + item.SetMapIndex(runInfo.rv, value) + mapIndex := runInfo.rv + // assign new map + runInfo.rv = item + runInfo.expr = expr.Item + runInfo.invokeLetExpr() + runInfo.rv = item.MapIndex(mapIndex) + return + } + item.SetMapIndex(runInfo.rv, value) + + // String + case reflect.String: + var index int + index, runInfo.err = tryToInt(runInfo.rv) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "index must be a number") + runInfo.rv = nilValue + return + } + + value, runInfo.err = convertReflectValueToType(value, item.Type()) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "type "+value.Type().String()+" cannot be assigned to type "+item.Type().String()) + runInfo.rv = nilValue + return + } + + if index == item.Len() { + // automatic append + if item.CanSet() { + item.SetString(item.String() + value.String()) + return + } + + runInfo.rv = reflect.ValueOf(item.String() + value.String()) + runInfo.expr = expr.Item + runInfo.invokeLetExpr() + return + } + + if index < 0 || index >= item.Len() { + runInfo.err = newStringError(expr, "index out of range") + runInfo.rv = nilValue + return + } + + if item.CanSet() { + item.SetString(item.Slice(0, index).String() + value.String() + item.Slice(index+1, item.Len()).String()) + runInfo.rv = item + return + } + + runInfo.rv = reflect.ValueOf(item.Slice(0, index).String() + value.String() + item.Slice(index+1, item.Len()).String()) + runInfo.expr = expr.Item + runInfo.invokeLetExpr() + + default: + runInfo.err = newStringError(expr, "type "+item.Kind().String()+" does not support index operation") + runInfo.rv = nilValue + } + + // SliceExpr + case *ast.SliceExpr: + value := runInfo.rv + + runInfo.expr = expr.Item + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + item := runInfo.rv + + if item.Kind() == reflect.Interface && !item.IsNil() { + item = item.Elem() + } + + switch item.Kind() { + + // Slice && Array + case reflect.Slice, reflect.Array: + var beginIndex int + endIndex := item.Len() + + if expr.Begin != nil { + runInfo.expr = expr.Begin + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + beginIndex, runInfo.err = tryToInt(runInfo.rv) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "index must be a number") + runInfo.rv = nilValue + return + } + // (0 <= low) <= high <= len(a) + if beginIndex < 0 { + runInfo.err = newStringError(expr, "index out of range") + runInfo.rv = nilValue + return + } + } + + if expr.End != nil { + runInfo.expr = expr.End + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + endIndex, runInfo.err = tryToInt(runInfo.rv) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "index must be a number") + runInfo.rv = nilValue + return + } + // 0 <= low <= (high <= len(a)) + if endIndex > item.Len() { + runInfo.err = newStringError(expr, "index out of range") + runInfo.rv = nilValue + return + } + } + + // 0 <= (low <= high) <= len(a) + if beginIndex > endIndex { + runInfo.err = newStringError(expr, "index out of range") + runInfo.rv = nilValue + return + } + + sliceCap := item.Cap() + if expr.Cap != nil { + runInfo.expr = expr.Cap + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + sliceCap, runInfo.err = tryToInt(runInfo.rv) + if runInfo.err != nil { + runInfo.err = newStringError(expr, "cap must be a number") + runInfo.rv = nilValue + return + } + // 0 <= low <= (high <= max <= cap(a)) + if sliceCap < endIndex || sliceCap > item.Cap() { + runInfo.err = newStringError(expr, "cap out of range") + runInfo.rv = nilValue + return + } + } + + item = item.Slice3(beginIndex, endIndex, sliceCap) + + if !item.CanSet() { + runInfo.err = newStringError(expr, "slice cannot be assigned") + runInfo.rv = nilValue + return + } + item.Set(value) + + // String + case reflect.String: + runInfo.err = newStringError(expr, "type string does not support slice operation for assignment") + runInfo.rv = nilValue + + default: + runInfo.err = newStringError(expr, "type "+item.Kind().String()+" does not support slice operation") + runInfo.rv = nilValue + } + + // DerefExpr + case *ast.DerefExpr: + value := runInfo.rv + + runInfo.expr = expr.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + runInfo.rv.Elem().Set(value) + runInfo.rv = value + + default: + runInfo.err = newStringError(expr, "invalid operation") + runInfo.rv = nilValue + } + +} diff --git a/src/tool/run/vm/vmOperator.go b/src/tool/run/vm/vmOperator.go new file mode 100644 index 0000000..527252a --- /dev/null +++ b/src/tool/run/vm/vmOperator.go @@ -0,0 +1,228 @@ +package vm + +import ( + "reflect" + "strings" + + "github.com/surdeus/goblin/src/tool/run/ast" +) + +// invokeOperator evaluates one Operator. +func (runInfo *runInfoStruct) invokeOperator() { + switch operator := runInfo.operator.(type) { + + // BinaryOperator + case *ast.BinaryOperator: + runInfo.expr = operator.LHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + + switch operator.Operator { + case "||": + if toBool(runInfo.rv) { + runInfo.rv = trueValue + return + } + case "&&": + if !toBool(runInfo.rv) { + runInfo.rv = falseValue + return + } + default: + runInfo.err = newStringError(operator, "unknown operator") + runInfo.rv = nilValue + return + } + + runInfo.expr = operator.RHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + + if toBool(runInfo.rv) { + runInfo.rv = trueValue + } else { + runInfo.rv = falseValue + } + + // ComparisonOperator + case *ast.ComparisonOperator: + runInfo.expr = operator.LHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + lhsV := runInfo.rv + + runInfo.expr = operator.RHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + + switch operator.Operator { + case "==": + runInfo.rv = reflect.ValueOf(equal(lhsV, runInfo.rv)) + case "!=": + runInfo.rv = reflect.ValueOf(!equal(lhsV, runInfo.rv)) + case "<": + runInfo.rv = reflect.ValueOf(toFloat64(lhsV) < toFloat64(runInfo.rv)) + case "<=": + runInfo.rv = reflect.ValueOf(toFloat64(lhsV) <= toFloat64(runInfo.rv)) + case ">": + runInfo.rv = reflect.ValueOf(toFloat64(lhsV) > toFloat64(runInfo.rv)) + case ">=": + runInfo.rv = reflect.ValueOf(toFloat64(lhsV) >= toFloat64(runInfo.rv)) + default: + runInfo.err = newStringError(operator, "unknown operator") + runInfo.rv = nilValue + } + + // AddOperator + case *ast.AddOperator: + runInfo.expr = operator.LHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + lhsV := runInfo.rv + + runInfo.expr = operator.RHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + + switch operator.Operator { + case "+": + lhsKind := lhsV.Kind() + rhsKind := runInfo.rv.Kind() + + if lhsKind == reflect.Slice || lhsKind == reflect.Array { + if rhsKind == reflect.Slice || rhsKind == reflect.Array { + // append slice to slice + runInfo.rv, runInfo.err = appendSlice(operator, lhsV, runInfo.rv) + return + } + // try to append rhs non-slice to lhs slice + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, lhsV.Type().Elem()) + if runInfo.err != nil { + runInfo.err = newStringError(operator, "invalid type conversion") + runInfo.rv = nilValue + return + } + runInfo.rv = reflect.Append(lhsV, runInfo.rv) + return + } + if rhsKind == reflect.Slice || rhsKind == reflect.Array { + // can not append rhs slice to lhs non-slice + runInfo.err = newStringError(operator, "invalid type conversion") + runInfo.rv = nilValue + return + } + + kind := precedenceOfKinds(lhsKind, rhsKind) + switch kind { + case reflect.String: + runInfo.rv = reflect.ValueOf(toString(lhsV) + toString(runInfo.rv)) + case reflect.Float64, reflect.Float32: + runInfo.rv = reflect.ValueOf(toFloat64(lhsV) + toFloat64(runInfo.rv)) + default: + runInfo.rv = reflect.ValueOf(toInt64(lhsV) + toInt64(runInfo.rv)) + } + + case "-": + switch lhsV.Kind() { + case reflect.Float64, reflect.Float32: + runInfo.rv = reflect.ValueOf(toFloat64(lhsV) - toFloat64(runInfo.rv)) + return + } + switch runInfo.rv.Kind() { + case reflect.Float64, reflect.Float32: + runInfo.rv = reflect.ValueOf(toFloat64(lhsV) - toFloat64(runInfo.rv)) + default: + runInfo.rv = reflect.ValueOf(toInt64(lhsV) - toInt64(runInfo.rv)) + } + + case "|": + runInfo.rv = reflect.ValueOf(toInt64(lhsV) | toInt64(runInfo.rv)) + default: + runInfo.err = newStringError(operator, "unknown operator") + runInfo.rv = nilValue + } + + // MultiplyOperator + case *ast.MultiplyOperator: + runInfo.expr = operator.LHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + lhsV := runInfo.rv + + runInfo.expr = operator.RHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + + switch operator.Operator { + case "*": + if lhsV.Kind() == reflect.String && (runInfo.rv.Kind() == reflect.Int || runInfo.rv.Kind() == reflect.Int32 || runInfo.rv.Kind() == reflect.Int64) { + runInfo.rv = reflect.ValueOf(strings.Repeat(toString(lhsV), int(toInt64(runInfo.rv)))) + return + } + if lhsV.Kind() == reflect.Float64 || runInfo.rv.Kind() == reflect.Float64 { + runInfo.rv = reflect.ValueOf(toFloat64(lhsV) * toFloat64(runInfo.rv)) + return + } + runInfo.rv = reflect.ValueOf(toInt64(lhsV) * toInt64(runInfo.rv)) + case "/": + runInfo.rv = reflect.ValueOf(toFloat64(lhsV) / toFloat64(runInfo.rv)) + case "%": + runInfo.rv = reflect.ValueOf(toInt64(lhsV) % toInt64(runInfo.rv)) + case ">>": + runInfo.rv = reflect.ValueOf(toInt64(lhsV) >> uint64(toInt64(runInfo.rv))) + case "<<": + runInfo.rv = reflect.ValueOf(toInt64(lhsV) << uint64(toInt64(runInfo.rv))) + case "&": + runInfo.rv = reflect.ValueOf(toInt64(lhsV) & toInt64(runInfo.rv)) + + default: + runInfo.err = newStringError(operator, "unknown operator") + runInfo.rv = nilValue + } + + default: + runInfo.err = newStringError(operator, "unknown operator") + runInfo.rv = nilValue + + } +} diff --git a/src/tool/run/vm/vmOperators_test.go b/src/tool/run/vm/vmOperators_test.go new file mode 100644 index 0000000..0d4bdf0 --- /dev/null +++ b/src/tool/run/vm/vmOperators_test.go @@ -0,0 +1,1073 @@ +package vm + +import ( + "fmt" + "reflect" + "testing" +) + +func TestBasicOperators(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `]`, ParseError: fmt.Errorf("syntax error")}, + + {Script: `2 + 1`, RunOutput: int64(3)}, + {Script: `2 - 1`, RunOutput: int64(1)}, + {Script: `2 * 1`, RunOutput: int64(2)}, + {Script: `2 / 1`, RunOutput: float64(2)}, + {Script: `2.1 + 1.1`, RunOutput: float64(3.2)}, + {Script: `2.1 - 1.1`, RunOutput: float64(1)}, + {Script: `2 + 1.1`, RunOutput: float64(3.1)}, + {Script: `2.1 + 1`, RunOutput: float64(3.1)}, + {Script: `3 - 1.5`, RunOutput: float64(1.5)}, + {Script: `2.1 - 1`, RunOutput: float64(1.1)}, + {Script: `2.1 * 2.0`, RunOutput: float64(4.2)}, + {Script: `6.5 / 2.0`, RunOutput: float64(3.25)}, + + {Script: `2-1`, RunOutput: int64(1)}, + {Script: `2 -1`, RunOutput: int64(1)}, + {Script: `2- 1`, RunOutput: int64(1)}, + {Script: `2 - -1`, RunOutput: int64(3)}, + {Script: `2- -1`, RunOutput: int64(3)}, + {Script: `2 - - 1`, RunOutput: int64(3)}, + {Script: `2- - 1`, RunOutput: int64(3)}, + + {Script: `a + b`, Input: map[string]interface{}{"a": int64(2), "b": int64(1)}, RunOutput: int64(3)}, + {Script: `a - b`, Input: map[string]interface{}{"a": int64(2), "b": int64(1)}, RunOutput: int64(1)}, + {Script: `a * b`, Input: map[string]interface{}{"a": int64(2), "b": int64(1)}, RunOutput: int64(2)}, + {Script: `a / b`, Input: map[string]interface{}{"a": int64(2), "b": int64(1)}, RunOutput: float64(2)}, + {Script: `a + b`, Input: map[string]interface{}{"a": float64(2.1), "b": float64(1.1)}, RunOutput: float64(3.2)}, + {Script: `a - b`, Input: map[string]interface{}{"a": float64(2.1), "b": float64(1.1)}, RunOutput: float64(1)}, + {Script: `a * b`, Input: map[string]interface{}{"a": float64(2.1), "b": float64(2)}, RunOutput: float64(4.2)}, + {Script: `a / b`, Input: map[string]interface{}{"a": float64(6.5), "b": float64(2)}, RunOutput: float64(3.25)}, + + {Script: `a + b`, Input: map[string]interface{}{"a": "a", "b": "b"}, RunOutput: "ab"}, + {Script: `a + b`, Input: map[string]interface{}{"a": "a", "b": int64(1)}, RunOutput: "a1"}, + {Script: `a + b`, Input: map[string]interface{}{"a": "a", "b": float64(1.1)}, RunOutput: "a1.1"}, + {Script: `a + b`, Input: map[string]interface{}{"a": int64(2), "b": "b"}, RunOutput: "2b"}, + {Script: `a + b`, Input: map[string]interface{}{"a": float64(2.5), "b": "b"}, RunOutput: "2.5b"}, + + {Script: `a + z`, Input: map[string]interface{}{"a": "a"}, RunError: fmt.Errorf("undefined symbol 'z'"), RunOutput: nil}, + {Script: `z + b`, Input: map[string]interface{}{"a": "a"}, RunError: fmt.Errorf("undefined symbol 'z'"), RunOutput: nil}, + + {Script: `c = a + b`, Input: map[string]interface{}{"a": int64(2), "b": int64(1)}, RunOutput: int64(3), Output: map[string]interface{}{"c": int64(3)}}, + {Script: `c = a - b`, Input: map[string]interface{}{"a": int64(2), "b": int64(1)}, RunOutput: int64(1), Output: map[string]interface{}{"c": int64(1)}}, + {Script: `c = a * b`, Input: map[string]interface{}{"a": int64(2), "b": int64(1)}, RunOutput: int64(2), Output: map[string]interface{}{"c": int64(2)}}, + {Script: `c = a / b`, Input: map[string]interface{}{"a": int64(2), "b": int64(1)}, RunOutput: float64(2), Output: map[string]interface{}{"c": float64(2)}}, + {Script: `c = a + b`, Input: map[string]interface{}{"a": float64(2.1), "b": float64(1.1)}, RunOutput: float64(3.2), Output: map[string]interface{}{"c": float64(3.2)}}, + {Script: `c = a - b`, Input: map[string]interface{}{"a": float64(2.1), "b": float64(1.1)}, RunOutput: float64(1), Output: map[string]interface{}{"c": float64(1)}}, + {Script: `c = a * b`, Input: map[string]interface{}{"a": float64(2.1), "b": float64(2)}, RunOutput: float64(4.2), Output: map[string]interface{}{"c": float64(4.2)}}, + {Script: `c = a / b`, Input: map[string]interface{}{"a": float64(6.5), "b": float64(2)}, RunOutput: float64(3.25), Output: map[string]interface{}{"c": float64(3.25)}}, + + {Script: `a = nil; a++`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = false; a++`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = true; a++`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; a++`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1.5; a++`, RunOutput: float64(2.5), Output: map[string]interface{}{"a": float64(2.5)}}, + {Script: `a = "1"; a++`, RunOutput: "11", Output: map[string]interface{}{"a": "11"}}, + {Script: `a = "a"; a++`, RunOutput: "a1", Output: map[string]interface{}{"a": "a1"}}, + + {Script: `a = nil; a--`, RunOutput: int64(-1), Output: map[string]interface{}{"a": int64(-1)}}, + {Script: `a = false; a--`, RunOutput: int64(-1), Output: map[string]interface{}{"a": int64(-1)}}, + {Script: `a = true; a--`, RunOutput: int64(0), Output: map[string]interface{}{"a": int64(0)}}, + {Script: `a = 2; a--`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2.5; a--`, RunOutput: float64(1.5), Output: map[string]interface{}{"a": float64(1.5)}}, + + {Script: `a++`, Input: map[string]interface{}{"a": nil}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a++`, Input: map[string]interface{}{"a": false}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a++`, Input: map[string]interface{}{"a": true}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a++`, Input: map[string]interface{}{"a": int32(1)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a++`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a++`, Input: map[string]interface{}{"a": float32(3.5)}, RunOutput: float64(4.5), Output: map[string]interface{}{"a": float64(4.5)}}, + {Script: `a++`, Input: map[string]interface{}{"a": float64(4.5)}, RunOutput: float64(5.5), Output: map[string]interface{}{"a": float64(5.5)}}, + {Script: `a++`, Input: map[string]interface{}{"a": "2"}, RunOutput: "21", Output: map[string]interface{}{"a": "21"}}, + {Script: `a++`, Input: map[string]interface{}{"a": "a"}, RunOutput: "a1", Output: map[string]interface{}{"a": "a1"}}, + + {Script: `a--`, Input: map[string]interface{}{"a": nil}, RunOutput: int64(-1), Output: map[string]interface{}{"a": int64(-1)}}, + {Script: `a--`, Input: map[string]interface{}{"a": false}, RunOutput: int64(-1), Output: map[string]interface{}{"a": int64(-1)}}, + {Script: `a--`, Input: map[string]interface{}{"a": true}, RunOutput: int64(0), Output: map[string]interface{}{"a": int64(0)}}, + {Script: `a--`, Input: map[string]interface{}{"a": int32(2)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a--`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a--`, Input: map[string]interface{}{"a": float32(2.5)}, RunOutput: float64(1.5), Output: map[string]interface{}{"a": float64(1.5)}}, + {Script: `a--`, Input: map[string]interface{}{"a": float64(2.5)}, RunOutput: float64(1.5), Output: map[string]interface{}{"a": float64(1.5)}}, + {Script: `a--`, Input: map[string]interface{}{"a": "2"}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a--`, Input: map[string]interface{}{"a": "a"}, RunOutput: int64(-1), Output: map[string]interface{}{"a": int64(-1)}}, + + {Script: `1++`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1--`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `z++`, RunError: fmt.Errorf("undefined symbol 'z'"), RunOutput: nil}, + {Script: `z--`, RunError: fmt.Errorf("undefined symbol 'z'"), RunOutput: nil}, + {Script: `!(1++)`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1 + 1++`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1 - 1++`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1 * 1++`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1 / 1++`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1++ + 1`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1++ - 1`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1++ * 1`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1++ / 1`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + + {Script: `a = 1; b = 2; a + b`, RunOutput: int64(3)}, + {Script: `a = [1]; b = 2; a[0] + b`, RunOutput: int64(3)}, + {Script: `a = 1; b = [2]; a + b[0]`, RunOutput: int64(3)}, + {Script: `a = 2; b = 1; a - b`, RunOutput: int64(1)}, + {Script: `a = [2]; b = 1; a[0] - b`, RunOutput: int64(1)}, + {Script: `a = 2; b = [1]; a - b[0]`, RunOutput: int64(1)}, + {Script: `a = 1; b = 2; a * b`, RunOutput: int64(2)}, + {Script: `a = [1]; b = 2; a[0] * b`, RunOutput: int64(2)}, + {Script: `a = 1; b = [2]; a * b[0]`, RunOutput: int64(2)}, + {Script: `a = 4; b = 2; a / b`, RunOutput: float64(2)}, + {Script: `a = [4]; b = 2; a[0] / b`, RunOutput: float64(2)}, + {Script: `a = 4; b = [2]; a / b[0]`, RunOutput: float64(2)}, + + {Script: `a += 1`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a -= 1`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a *= 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(4), Output: map[string]interface{}{"a": int64(4)}}, + {Script: `a /= 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: float64(1), Output: map[string]interface{}{"a": float64(1)}}, + {Script: `a += 1`, Input: map[string]interface{}{"a": 2.1}, RunOutput: float64(3.1), Output: map[string]interface{}{"a": float64(3.1)}}, + {Script: `a -= 1`, Input: map[string]interface{}{"a": 2.1}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `a *= 2`, Input: map[string]interface{}{"a": 2.1}, RunOutput: float64(4.2), Output: map[string]interface{}{"a": float64(4.2)}}, + {Script: `a /= 2`, Input: map[string]interface{}{"a": 6.5}, RunOutput: float64(3.25), Output: map[string]interface{}{"a": float64(3.25)}}, + + {Script: `a &= 1`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(0), Output: map[string]interface{}{"a": int64(0)}}, + {Script: `a &= 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a &= 1`, Input: map[string]interface{}{"a": float64(2.1)}, RunOutput: int64(0), Output: map[string]interface{}{"a": int64(0)}}, + {Script: `a &= 2`, Input: map[string]interface{}{"a": float64(2.1)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + + {Script: `a |= 1`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a |= 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a |= 1`, Input: map[string]interface{}{"a": float64(2.1)}, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a |= 2`, Input: map[string]interface{}{"a": float64(2.1)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + + {Script: `a << 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(8), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a >> 2`, Input: map[string]interface{}{"a": int64(8)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(8)}}, + {Script: `a << 2`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: int64(8), Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a >> 2`, Input: map[string]interface{}{"a": float64(8)}, RunOutput: int64(2), Output: map[string]interface{}{"a": float64(8)}}, + + {Script: `a % 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(0), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a % 3`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a % 2`, Input: map[string]interface{}{"a": float64(2.1)}, RunOutput: int64(0), Output: map[string]interface{}{"a": float64(2.1)}}, + {Script: `a % 3`, Input: map[string]interface{}{"a": float64(2.1)}, RunOutput: int64(2), Output: map[string]interface{}{"a": float64(2.1)}}, + + {Script: `a * 4`, Input: map[string]interface{}{"a": "a"}, RunOutput: "aaaa", Output: map[string]interface{}{"a": "a"}}, + {Script: `a * 4.0`, Input: map[string]interface{}{"a": "a"}, RunOutput: float64(0), Output: map[string]interface{}{"a": "a"}}, + + {Script: `-a`, Input: map[string]interface{}{"a": nil}, RunOutput: float64(-0), Output: map[string]interface{}{"a": nil}}, + {Script: `-a`, Input: map[string]interface{}{"a": int32(1)}, RunOutput: int64(-1), Output: map[string]interface{}{"a": int32(1)}}, + {Script: `-a`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(-2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `-a`, Input: map[string]interface{}{"a": float32(3.5)}, RunOutput: float64(-3.5), Output: map[string]interface{}{"a": float32(3.5)}}, + {Script: `-a`, Input: map[string]interface{}{"a": float64(4.5)}, RunOutput: float64(-4.5), Output: map[string]interface{}{"a": float64(4.5)}}, + {Script: `-a`, Input: map[string]interface{}{"a": "a"}, RunOutput: float64(-0), Output: map[string]interface{}{"a": "a"}}, + {Script: `-a`, Input: map[string]interface{}{"a": "1"}, RunOutput: float64(-1), Output: map[string]interface{}{"a": "1"}}, + + {Script: `^a`, Input: map[string]interface{}{"a": nil}, RunOutput: int64(-1), Output: map[string]interface{}{"a": nil}}, + {Script: `^a`, Input: map[string]interface{}{"a": "a"}, RunOutput: int64(-1), Output: map[string]interface{}{"a": "a"}}, + {Script: `^a`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(-3), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `^a`, Input: map[string]interface{}{"a": float64(2.1)}, RunOutput: int64(-3), Output: map[string]interface{}{"a": float64(2.1)}}, + + {Script: `!true`, RunOutput: false}, + {Script: `!false`, RunOutput: true}, + {Script: `!1`, RunOutput: false}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestComparisonOperators(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `1++ == 2`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `2 == 1++`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1++ || true`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `false || 1++`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `1++ && true`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + {Script: `true && 1++`, RunError: fmt.Errorf("invalid operation"), RunOutput: nil}, + + {Script: `a == 1`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a == 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a != 1`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a != 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a == 1.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a == 2.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a != 1.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a != 2.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + + {Script: `a == 1`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a == 2`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a != 1`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a != 2`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a == 1.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a == 2.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a != 1.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a != 2.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + + {Script: `a == nil`, Input: map[string]interface{}{"a": nil}, RunOutput: true, Output: map[string]interface{}{"a": nil}}, + {Script: `a == nil`, Input: map[string]interface{}{"a": nil}, RunOutput: true, Output: map[string]interface{}{"a": nil}}, + {Script: `a == nil`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a == nil`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a == 2`, Input: map[string]interface{}{"a": nil}, RunOutput: false, Output: map[string]interface{}{"a": nil}}, + {Script: `a == 2.0`, Input: map[string]interface{}{"a": nil}, RunOutput: false, Output: map[string]interface{}{"a": nil}}, + + {Script: `1 == 1.0`, RunOutput: true}, + {Script: `1 != 1.0`, RunOutput: false}, + {Script: `"a" != "a"`, RunOutput: false}, + + {Script: `a > 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a > 1`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a < 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a < 3`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a > 2.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a > 1.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a < 2.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a < 3.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + + {Script: `a > 2`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a > 1`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a < 2`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a < 3`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a > 2.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a > 1.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a < 2.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a < 3.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + + {Script: `a >= 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a >= 3`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a <= 2`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a <= 3`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a >= 2.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a >= 3.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a <= 2.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a <= 3.0`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2)}}, + + {Script: `a >= 2`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a >= 3`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a <= 2`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a <= 3`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a >= 2.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a >= 3.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a <= 2.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + {Script: `a <= 3.0`, Input: map[string]interface{}{"a": float64(2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2)}}, + + {Script: `a = false; b = false; a && b`, RunOutput: false}, + {Script: `a = false; b = true; a && b`, RunOutput: false}, + {Script: `a = true; b = false; a && b`, RunOutput: false}, + {Script: `a = true; b = true; a && b`, RunOutput: true}, + {Script: `a = false; b = false; a || b`, RunOutput: false}, + {Script: `a = false; b = true; a || b`, RunOutput: true}, + {Script: `a = true; b = false; a || b`, RunOutput: true}, + {Script: `a = true; b = true; a || b`, RunOutput: true}, + + {Script: `a = [false]; b = false; a[0] && b`, RunOutput: false}, + {Script: `a = [false]; b = true; a[0] && b`, RunOutput: false}, + {Script: `a = [true]; b = false; a[0] && b`, RunOutput: false}, + {Script: `a = [true]; b = true; a[0] && b`, RunOutput: true}, + {Script: `a = [false]; b = false; a[0] || b`, RunOutput: false}, + {Script: `a = [false]; b = true; a[0] || b`, RunOutput: true}, + {Script: `a = [true]; b = false; a[0] || b`, RunOutput: true}, + {Script: `a = [true]; b = true; a[0] || b`, RunOutput: true}, + + {Script: `a = false; b = [false]; a && b[0]`, RunOutput: false}, + {Script: `a = false; b = [true]; a && b[0]`, RunOutput: false}, + {Script: `a = true; b = [false]; a && b[0]`, RunOutput: false}, + {Script: `a = true; b = [true]; a && b[0]`, RunOutput: true}, + {Script: `a = false; b = [false]; a || b[0]`, RunOutput: false}, + {Script: `a = false; b = [true]; a || b[0]`, RunOutput: true}, + {Script: `a = true; b = [false]; a || b[0]`, RunOutput: true}, + {Script: `a = true; b = [true]; a || b[0]`, RunOutput: true}, + + {Script: `0 && 0`, RunOutput: false}, + {Script: `0 && 1`, RunOutput: false}, + {Script: `1 && 0`, RunOutput: false}, + {Script: `1 && 1`, RunOutput: true}, + {Script: `0 || 0`, RunOutput: false}, + {Script: `0 || 1`, RunOutput: true}, + {Script: `1 || 0`, RunOutput: true}, + {Script: `1 || 1`, RunOutput: true}, + + {Script: `1 == 1 && 1 == 1`, RunOutput: true}, + {Script: `1 == 1 && 1 == 2`, RunOutput: false}, + {Script: `1 == 2 && 1 == 1`, RunOutput: false}, + {Script: `1 == 2 && 1 == 2`, RunOutput: false}, + {Script: `1 == 1 || 1 == 1`, RunOutput: true}, + {Script: `1 == 1 || 1 == 2`, RunOutput: true}, + {Script: `1 == 2 || 1 == 1`, RunOutput: true}, + {Script: `1 == 2 || 1 == 2`, RunOutput: false}, + + {Script: `true == "1"`, RunOutput: true}, + {Script: `true == "t"`, RunOutput: true}, + {Script: `true == "T"`, RunOutput: true}, + {Script: `true == "true"`, RunOutput: true}, + {Script: `true == "TRUE"`, RunOutput: true}, + {Script: `true == "True"`, RunOutput: true}, + {Script: `true == "false"`, RunOutput: false}, + {Script: `false == "0"`, RunOutput: true}, + {Script: `false == "f"`, RunOutput: true}, + {Script: `false == "F"`, RunOutput: true}, + {Script: `false == "false"`, RunOutput: true}, + {Script: `false == "false"`, RunOutput: true}, + {Script: `false == "FALSE"`, RunOutput: true}, + {Script: `false == "False"`, RunOutput: true}, + {Script: `false == "true"`, RunOutput: false}, + {Script: `false == "foo"`, RunOutput: false}, + {Script: `true == "foo"`, RunOutput: true}, + + {Script: `0 == "0"`, RunOutput: true}, + {Script: `"1.0" == 1`, RunOutput: true}, + {Script: `1 == "1"`, RunOutput: true}, + {Script: `0.0 == "0"`, RunOutput: true}, + {Script: `0.0 == "0.0"`, RunOutput: true}, + {Script: `1.0 == "1.0"`, RunOutput: true}, + {Script: `1.2 == "1.2"`, RunOutput: true}, + {Script: `"7" == 7.2`, RunOutput: false}, + {Script: `1.2 == "1"`, RunOutput: false}, + {Script: `"1.1" == 1`, RunOutput: false}, + {Script: `0 == "1"`, RunOutput: false}, + + {Script: `a == b`, Input: map[string]interface{}{"a": reflect.Value{}, "b": reflect.Value{}}, RunOutput: true, Output: map[string]interface{}{"a": reflect.Value{}, "b": reflect.Value{}}}, + {Script: `a == b`, Input: map[string]interface{}{"a": reflect.Value{}, "b": true}, RunOutput: false, Output: map[string]interface{}{"a": reflect.Value{}, "b": true}}, + {Script: `a == b`, Input: map[string]interface{}{"a": true, "b": reflect.Value{}}, RunOutput: false, Output: map[string]interface{}{"a": true, "b": reflect.Value{}}}, + + {Script: `a == b`, Input: map[string]interface{}{"a": nil, "b": nil}, RunOutput: true, Output: map[string]interface{}{"a": nil, "b": nil}}, + {Script: `a == b`, Input: map[string]interface{}{"a": nil, "b": true}, RunOutput: false, Output: map[string]interface{}{"a": nil, "b": true}}, + {Script: `a == b`, Input: map[string]interface{}{"a": true, "b": nil}, RunOutput: false, Output: map[string]interface{}{"a": true, "b": nil}}, + + {Script: `a == b`, Input: map[string]interface{}{"a": false, "b": false}, RunOutput: true, Output: map[string]interface{}{"a": false, "b": false}}, + {Script: `a == b`, Input: map[string]interface{}{"a": false, "b": true}, RunOutput: false, Output: map[string]interface{}{"a": false, "b": true}}, + {Script: `a == b`, Input: map[string]interface{}{"a": true, "b": false}, RunOutput: false, Output: map[string]interface{}{"a": true, "b": false}}, + {Script: `a == b`, Input: map[string]interface{}{"a": true, "b": true}, RunOutput: true, Output: map[string]interface{}{"a": true, "b": true}}, + + {Script: `a == b`, Input: map[string]interface{}{"a": int32(1), "b": int32(1)}, RunOutput: true, Output: map[string]interface{}{"a": int32(1), "b": int32(1)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": int32(1), "b": int32(2)}, RunOutput: false, Output: map[string]interface{}{"a": int32(1), "b": int32(2)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": int32(2), "b": int32(1)}, RunOutput: false, Output: map[string]interface{}{"a": int32(2), "b": int32(1)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": int32(2), "b": int32(2)}, RunOutput: true, Output: map[string]interface{}{"a": int32(2), "b": int32(2)}}, + + {Script: `a == b`, Input: map[string]interface{}{"a": int64(1), "b": int64(1)}, RunOutput: true, Output: map[string]interface{}{"a": int64(1), "b": int64(1)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": int64(1), "b": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": int64(2), "b": int64(1)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2), "b": int64(1)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": int64(2), "b": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": int64(2), "b": int64(2)}}, + + {Script: `a == b`, Input: map[string]interface{}{"a": float32(1.1), "b": float32(1.1)}, RunOutput: true, Output: map[string]interface{}{"a": float32(1.1), "b": float32(1.1)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": float32(1.1), "b": float32(2.2)}, RunOutput: false, Output: map[string]interface{}{"a": float32(1.1), "b": float32(2.2)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": float32(2.2), "b": float32(1.1)}, RunOutput: false, Output: map[string]interface{}{"a": float32(2.2), "b": float32(1.1)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": float32(2.2), "b": float32(2.2)}, RunOutput: true, Output: map[string]interface{}{"a": float32(2.2), "b": float32(2.2)}}, + + {Script: `a == b`, Input: map[string]interface{}{"a": float64(1.1), "b": float64(1.1)}, RunOutput: true, Output: map[string]interface{}{"a": float64(1.1), "b": float64(1.1)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": float64(1.1), "b": float64(2.2)}, RunOutput: false, Output: map[string]interface{}{"a": float64(1.1), "b": float64(2.2)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": float64(2.2), "b": float64(1.1)}, RunOutput: false, Output: map[string]interface{}{"a": float64(2.2), "b": float64(1.1)}}, + {Script: `a == b`, Input: map[string]interface{}{"a": float64(2.2), "b": float64(2.2)}, RunOutput: true, Output: map[string]interface{}{"a": float64(2.2), "b": float64(2.2)}}, + + {Script: `a == b`, Input: map[string]interface{}{"a": 'a', "b": 'a'}, RunOutput: true, Output: map[string]interface{}{"a": 'a', "b": 'a'}}, + {Script: `a == b`, Input: map[string]interface{}{"a": 'a', "b": 'b'}, RunOutput: false, Output: map[string]interface{}{"a": 'a', "b": 'b'}}, + {Script: `a == b`, Input: map[string]interface{}{"a": 'b', "b": 'a'}, RunOutput: false, Output: map[string]interface{}{"a": 'b', "b": 'a'}}, + {Script: `a == b`, Input: map[string]interface{}{"a": 'b', "b": 'b'}, RunOutput: true, Output: map[string]interface{}{"a": 'b', "b": 'b'}}, + + {Script: `a == b`, Input: map[string]interface{}{"a": "a", "b": "a"}, RunOutput: true, Output: map[string]interface{}{"a": "a", "b": "a"}}, + {Script: `a == b`, Input: map[string]interface{}{"a": "a", "b": "b"}, RunOutput: false, Output: map[string]interface{}{"a": "a", "b": "b"}}, + {Script: `a == b`, Input: map[string]interface{}{"a": "b", "b": "a"}, RunOutput: false, Output: map[string]interface{}{"a": "b", "b": "a"}}, + {Script: `a == b`, Input: map[string]interface{}{"a": "b", "b": "b"}, RunOutput: true, Output: map[string]interface{}{"a": "b", "b": "b"}}, + + {Script: `b = "\"a\""; a == b`, Input: map[string]interface{}{"a": `"a"`}, RunOutput: true, Output: map[string]interface{}{"a": `"a"`, "b": `"a"`}}, + + {Script: `a = "test"; a == "test"`, RunOutput: true}, + {Script: `a = "test"; a[0:1] == "t"`, RunOutput: true}, + {Script: `a = "test"; a[0:2] == "te"`, RunOutput: true}, + {Script: `a = "test"; a[1:3] == "es"`, RunOutput: true}, + {Script: `a = "test"; a[0:4] == "test"`, RunOutput: true}, + + {Script: `a = "a b"; a[1] == ' '`, RunOutput: true}, + {Script: `a = "test"; a[0] == 't'`, RunOutput: true}, + {Script: `a = "test"; a[1] == 'e'`, RunOutput: true}, + {Script: `a = "test"; a[3] == 't'`, RunOutput: true}, + + {Script: `a = "a b"; a[1] != ' '`, RunOutput: false}, + {Script: `a = "test"; a[0] != 't'`, RunOutput: false}, + {Script: `a = "test"; a[1] != 'e'`, RunOutput: false}, + {Script: `a = "test"; a[3] != 't'`, RunOutput: false}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestThrows(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `throw(1++)`, RunError: fmt.Errorf("invalid operation")}, + // {Script: `throw(a)`, Input: map[string]interface{}{"a": reflect.Value{}}, RunError: fmt.Errorf("invalid operation")}, + + {Script: `true && func(){throw('abcde')}()`, RunError: fmt.Errorf("abcde")}, + {Script: `false && func(){throw('abcde')}()`, RunOutput: false}, + {Script: `true || func(){throw('abcde')}()`, RunOutput: true}, + {Script: `false || func(){throw('abcde')}()`, RunError: fmt.Errorf("abcde")}, + {Script: `true && true && func(){throw('abcde')}()`, RunError: fmt.Errorf("abcde")}, + {Script: `true && false && func(){throw('abcde')}()`, RunOutput: false}, + {Script: `true && func(){throw('abcde')}() && true`, RunError: fmt.Errorf("abcde")}, + {Script: `false && func(){throw('abcde')}() && func(){throw('abcde')}() `, RunOutput: false}, + + {Script: `true && func(){throw('abcde')}() || false`, RunError: fmt.Errorf("abcde")}, + {Script: `true && false || func(){throw('abcde')}()`, RunError: fmt.Errorf("abcde")}, + {Script: `true && true || func(){throw('abcde')}()`, RunOutput: true}, + + {Script: `true || func(){throw('abcde')}() || func(){throw('abcde')}()`, RunOutput: true}, + {Script: `false || func(){throw('abcde')}() || true`, RunError: fmt.Errorf("abcde")}, + {Script: `false || true || func(){throw('abcde')}()`, RunOutput: true}, + {Script: `false || false || func(){throw('abcde')}()`, RunError: fmt.Errorf("abcde")}, + + {Script: `false || false && func(){throw('abcde')}()`, RunOutput: false}, + {Script: `false || true && func(){throw('abcde')}()`, RunError: fmt.Errorf("abcde")}, + {Script: `false || func(){throw('abcde')}() || true`, RunError: fmt.Errorf("abcde")}, + + {Script: `1 == 1 && func(){throw('abcde')}()`, RunError: fmt.Errorf("abcde")}, + {Script: `1 == 2 && func(){throw('abcde')}()`, RunOutput: false}, + {Script: `1 == 1 || func(){throw('abcde')}()`, RunOutput: true}, + {Script: `1 == 2 || func(){throw('abcde')}()`, RunError: fmt.Errorf("abcde")}, + + {Script: `(true || func(){throw('abcde')}()) && (true || func(){throw('hello')}())`, RunOutput: true}, + {Script: `(true || func(){throw('abcde')}()) && (true && func(){throw('hello')}())`, RunError: fmt.Errorf("hello")}, + {Script: `(true || func(){throw('abcde')}()) || (true && func(){throw('hello')}())`, RunOutput: true}, + {Script: `(true && func(){throw('abcde')}()) && (true && func(){throw('hello')}())`, RunError: fmt.Errorf("abcde")}, + {Script: `(true || func(){throw('abcde')}()) && (false || func(){throw('hello')}())`, RunError: fmt.Errorf("hello")}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestTernaryOperator(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a = a ? 1 : 2`, RunError: fmt.Errorf("undefined symbol 'a'")}, + {Script: `a = z ? 1 : 2`, RunError: fmt.Errorf("undefined symbol 'z'")}, + {Script: `a = 0; a = a ? 1 : z`, RunError: fmt.Errorf("undefined symbol 'z'")}, + {Script: `a = 1; a = a ? z : 1`, RunError: fmt.Errorf("undefined symbol 'z'")}, + {Script: `a = b[1] ? 2 : 1`, Input: map[string]interface{}{"b": []interface{}{}}, RunError: fmt.Errorf("index out of range")}, + {Script: `a = b[1][2] ? 2 : 1`, Input: map[string]interface{}{"b": []interface{}{}}, RunError: fmt.Errorf("index out of range")}, + {Script: `a = b["test"][1] ? 2 : 1`, Input: map[string]interface{}{"b": map[string]interface{}{"test": 2}}, RunError: fmt.Errorf("type int does not support index operation")}, + + {Script: `a = 1 ? 2 : z`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = -1 ? 2 : 1`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = true ? 2 : 1`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = false ? 2 : 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = "true" ? 2 : 1`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = "false" ? 2 : 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = "-1" ? 2 : 1`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = "0" ? 2 : 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = "0.0" ? 2 : 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = "2" ? 2 : 1`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = b ? 2 : 1`, Input: map[string]interface{}{"b": int64(0)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = b ? 2 : 1`, Input: map[string]interface{}{"b": int64(2)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = b ? 2 : 1`, Input: map[string]interface{}{"b": float64(0.0)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = b ? 2 : 1`, Input: map[string]interface{}{"b": float64(2.0)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = b ? 2 : 1.0`, Input: map[string]interface{}{"b": float64(0.0)}, RunOutput: float64(1.0), Output: map[string]interface{}{"a": float64(1.0)}}, + {Script: `a = b ? 2 : 1.0`, Input: map[string]interface{}{"b": float64(0.1)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = b ? 2 : 1.0`, Input: map[string]interface{}{"b": nil}, RunOutput: float64(1.0), Output: map[string]interface{}{"a": float64(1.0)}}, + {Script: `a = nil ? 2 : 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = b ? 2 : 1`, Input: map[string]interface{}{"b": []interface{}{}}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = b ? 2 : 1`, Input: map[string]interface{}{"b": map[string]interface{}{}}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = [] ? 2 : 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = [2] ? 2 : 1`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = b ? 2 : 1`, Input: map[string]interface{}{"b": map[string]interface{}{"test": int64(2)}}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = b["test"] ? 2 : 1`, Input: map[string]interface{}{"b": map[string]interface{}{"test": int64(2)}}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `b = "test"; a = b ? 2 : "empty"`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `b = "test"; a = b[1:3] ? 2 : "empty"`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `b = "test"; a = b[2:2] ? 2 : "empty"`, RunOutput: "empty", Output: map[string]interface{}{"a": "empty"}}, + {Script: `b = "0.0"; a = false ? 2 : b ? 3 : 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `b = "true"; a = false ? 2 : b ? 3 : 1`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestNilCoalescingOperator(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `nil ?? nil`, RunOutput: nil}, + {Script: `false ?? nil`, RunOutput: false}, + {Script: `true ?? nil`, RunOutput: true}, + {Script: `nil ?? false`, RunOutput: false}, + {Script: `nil ?? true`, RunOutput: true}, + {Script: `1 ?? nil`, RunOutput: int64(1)}, + {Script: `1 ?? 2`, RunOutput: int64(1)}, + {Script: `nil ?? 1`, RunOutput: int64(1)}, + + {Script: `a ?? 1`, RunOutput: int64(1)}, + {Script: `a ?? b`, RunError: fmt.Errorf("undefined symbol 'b'")}, + + {Script: `a ?? 2`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a ?? b`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a ?? b`, Input: map[string]interface{}{"a": int64(1), "b": int64(2)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + {Script: `a ?? b`, Input: map[string]interface{}{"a": nil, "b": int64(2)}, RunOutput: int64(2), Output: map[string]interface{}{"a": nil, "b": int64(2)}}, + + {Script: `[] ?? 1`, RunOutput: []interface{}{}}, + {Script: `{} ?? 1`, RunOutput: map[interface{}]interface{}{}}, + + // test nil array and map + {Script: `a ?? 5`, Input: map[string]interface{}{"a": testSliceEmpty}, RunOutput: int64(5), Output: map[string]interface{}{"a": testSliceEmpty}}, + {Script: `a ?? 6`, Input: map[string]interface{}{"a": testMapEmpty}, RunOutput: int64(6), Output: map[string]interface{}{"a": testMapEmpty}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestIf(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `if 1++ {}`, RunError: fmt.Errorf("invalid operation")}, + {Script: `if false {} else if 1++ {}`, RunError: fmt.Errorf("invalid operation")}, + {Script: `if false {} else if true { 1++ }`, RunError: fmt.Errorf("invalid operation")}, + + {Script: `if true {}`, Input: map[string]interface{}{"a": nil}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `if true {}`, Input: map[string]interface{}{"a": true}, RunOutput: nil, Output: map[string]interface{}{"a": true}}, + {Script: `if true {}`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `if true {}`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: nil, Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `if true {}`, Input: map[string]interface{}{"a": "a"}, RunOutput: nil, Output: map[string]interface{}{"a": "a"}}, + + {Script: `if true {a = nil}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `if true {a = true}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `if true {a = 1}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `if true {a = 1.1}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `if true {a = "a"}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: "a", Output: map[string]interface{}{"a": "a"}}, + + {Script: `if a == 1 {a = 1}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `if a == 2 {a = 1}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `if a == 1 {a = nil}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `if a == 2 {a = nil}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + + {Script: `if a == 1 {a = 1} else {a = 3}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `if a == 2 {a = 1} else {a = 3}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `if a == 1 {a = 1} else if a == 3 {a = 3}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `if a == 1 {a = 1} else if a == 2 {a = 3}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `if a == 1 {a = 1} else if a == 3 {a = 3} else {a = 4}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(4), Output: map[string]interface{}{"a": int64(4)}}, + + {Script: `if a == 1 {a = 1} else {a = nil}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `if a == 2 {a = nil} else {a = 3}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `if a == 1 {a = nil} else if a == 3 {a = nil}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: false, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `if a == 1 {a = 1} else if a == 2 {a = nil}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `if a == 1 {a = 1} else if a == 3 {a = 3} else {a = nil}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + + {Script: `if a == 1 {a = 1} else if a == 3 {a = 3} else if a == 4 {a = 4} else {a = 5}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(5)}}, + {Script: `if a == 1 {a = 1} else if a == 3 {a = 3} else if a == 4 {a = 4} else {a = nil}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `if a == 1 {a = 1} else if a == 3 {a = 3} else if a == 2 {a = 4} else {a = 5}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: int64(4), Output: map[string]interface{}{"a": int64(4)}}, + {Script: `if a == 1 {a = 1} else if a == 3 {a = 3} else if a == 2 {a = nil} else {a = 5}`, Input: map[string]interface{}{"a": int64(2)}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + + // check scope + {Script: `a = 1; if a == 1 { b = 2 }; b`, RunError: fmt.Errorf("undefined symbol 'b'"), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; if a == 2 { b = 3 } else { b = 4 }; b`, RunError: fmt.Errorf("undefined symbol 'b'"), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; if a == 2 { b = 3 } else if a == 1 { b = 4 }; b`, RunError: fmt.Errorf("undefined symbol 'b'"), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; if a == 2 { b = 4 } else if a == 5 { b = 6 } else if a == 1 { c = b }`, RunError: fmt.Errorf("undefined symbol 'b'"), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; if a == 2 { b = 4 } else if a == 5 { b = 6 } else if a == 1 { b = 7 }; b`, RunError: fmt.Errorf("undefined symbol 'b'"), Output: map[string]interface{}{"a": int64(1)}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestSwitch(t *testing.T) { + t.Parallel() + + tests := []Test{ + // test parse errors + {Script: `switch {}`, ParseError: fmt.Errorf("syntax error")}, + {Script: `a = 1; switch a; {}`, ParseError: fmt.Errorf("syntax error")}, + {Script: `a = 1; switch a = 2 {}`, ParseError: fmt.Errorf("syntax error")}, + {Script: `a = 1; switch a {default: return 6; default: return 7}`, ParseError: fmt.Errorf("multiple default statement"), RunOutput: int64(7)}, + {Script: `a = 1; switch a {case 1: return 5; default: return 6; default: return 7}`, ParseError: fmt.Errorf("multiple default statement"), RunOutput: int64(5)}, + + // test run errors + {Script: `a = 1; switch 1++ {}`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a = 1; switch a {case 1++: return 2}`, RunError: fmt.Errorf("invalid operation")}, + + // test no or empty cases + {Script: `a = 1; switch a {}`, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; switch a {case: return 2}`, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; switch a {case: return 2; case: return 3}`, Output: map[string]interface{}{"a": int64(1)}}, + + // test 1 case + {Script: `a = 1; switch a {case 1: return 5}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1: return 5}`, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; switch a {case 1,2: return 5}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1,2: return 5}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 3; switch a {case 1,2: return 5}`, Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 1; switch a {case 1,2,3: return 5}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1,2,3: return 5}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 3; switch a {case 1,2,3: return 5}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 4; switch a {case 1,2,3: return 5}`, Output: map[string]interface{}{"a": int64(4)}}, + {Script: `a = func() { return 1 }; switch a() {case 1: return 5}`, RunOutput: int64(5)}, + {Script: `a = func() { return 2 }; switch a() {case 1: return 5}`}, + {Script: `a = func() { return 5 }; b = 1; switch b {case 1: return a() }`, RunOutput: int64(5), Output: map[string]interface{}{"b": int64(1)}}, + {Script: `a = func() { return 6 }; b = 2; switch b {case 1: return a() }`, Output: map[string]interface{}{"b": int64(2)}}, + + // test 2 cases + {Script: `a = 1; switch a {case 1: return 5; case 2: return 6}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1: return 5; case 2: return 6}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 3; switch a {case 1: return 5; case 2: return 6}`, Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 1; switch a {case 1: return 5; case 2,3: return 6}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1: return 5; case 2,3: return 6}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 3; switch a {case 1: return 5; case 2,3: return 6}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 4; switch a {case 1: return 5; case 2,3: return 6}`, Output: map[string]interface{}{"a": int64(4)}}, + + // test 3 cases + {Script: `a = 1; switch a {case 1,2: return 5; case 3: return 6}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1,2: return 5; case 3: return 6}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 3; switch a {case 1,2: return 5; case 3: return 6}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 4; switch a {case 1,2: return 5; case 3: return 6}`, Output: map[string]interface{}{"a": int64(4)}}, + {Script: `a = 1; switch a {case 1,2: return 5; case 2,3: return 6}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1,2: return 5; case 2,3: return 6}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 3; switch a {case 1,2: return 5; case 2,3: return 6}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 4; switch a {case 1,2: return 5; case 2,3: return 6}`, Output: map[string]interface{}{"a": int64(4)}}, + + // test default + {Script: `a = 1; switch a {default: return 5}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; switch a {case 1: return 5; case 2: return 6; default: return 7}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1: return 5; case 2: return 6; default: return 7}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 3; switch a {case 1: return 5; case 2: return 6; default: return 7}`, RunOutput: int64(7), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 1; switch a {case 1: return 5; case 2,3: return 6; default: return 7}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1: return 5; case 2,3: return 6; default: return 7}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 3; switch a {case 1: return 5; case 2,3: return 6; default: return 7}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 4; switch a {case 1: return 5; case 2,3: return 6; default: return 7}`, RunOutput: int64(7), Output: map[string]interface{}{"a": int64(4)}}, + {Script: `a = 1; switch a {case 1,2: return 5; case 3: return 6; default: return 7}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1,2: return 5; case 3: return 6; default: return 7}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 3; switch a {case 1,2: return 5; case 3: return 6; default: return 7}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 4; switch a {case 1,2: return 5; case 3: return 6; default: return 7}`, RunOutput: int64(7), Output: map[string]interface{}{"a": int64(4)}}, + + // test scope + {Script: `a = 1; switch a {case 1: a = 5}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(5)}}, + {Script: `a = 2; switch a {case 1: a = 5}`, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; b = 5; switch a {case 1: b = 6}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(1), "b": int64(6)}}, + {Script: `a = 2; b = 5; switch a {case 1: b = 6}`, Output: map[string]interface{}{"a": int64(2), "b": int64(5)}}, + {Script: `a = 1; b = 5; switch a {case 1: b = 6; default: b = 7}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(1), "b": int64(6)}}, + {Script: `a = 2; b = 5; switch a {case 1: b = 6; default: b = 7}`, RunOutput: int64(7), Output: map[string]interface{}{"a": int64(2), "b": int64(7)}}, + + // test scope without define b + {Script: `a = 1; switch a {case 1: b = 5}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1: b = 5}`, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; switch a {case 1: b = 5}; b`, RunError: fmt.Errorf("undefined symbol 'b'"), RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1: b = 5}; b`, RunError: fmt.Errorf("undefined symbol 'b'"), RunOutput: nil, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; switch a {case 1: b = 5; default: b = 6}`, RunOutput: int64(5), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1: b = 5; default: b = 6}`, RunOutput: int64(6), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; switch a {case 1: b = 5; default: b = 6}; b`, RunError: fmt.Errorf("undefined symbol 'b'"), RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 2; switch a {case 1: b = 5; default: b = 6}; b`, RunError: fmt.Errorf("undefined symbol 'b'"), RunOutput: nil, Output: map[string]interface{}{"a": int64(2)}}, + + // test new lines + {Script: ` +a = 1; +switch a { + case 1: + return 1 +}`, RunOutput: int64(1)}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestForLoop(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `for in [1] { }`, ParseError: fmt.Errorf("missing identifier")}, + {Script: `for a, b, c in [1] { }`, ParseError: fmt.Errorf("too many identifiers")}, + + {Script: `break`, RunError: fmt.Errorf("unexpected break statement")}, + {Script: `continue`, RunError: fmt.Errorf("unexpected continue statement")}, + {Script: `for 1++ { }`, RunError: fmt.Errorf("invalid operation")}, + {Script: `for { 1++ }`, RunError: fmt.Errorf("invalid operation")}, + {Script: `for a in 1++ { }`, RunError: fmt.Errorf("invalid operation")}, + + {Script: `for { break }`, RunOutput: nil}, + {Script: `for {a = 1; if a == 1 { break } }`, RunOutput: nil}, + {Script: `a = 1; for { if a == 1 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for { if a == 1 { break }; a++ }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for { if a == 3 { break }; a++ }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(3)}}, + + {Script: `a = 1; for { if a == 1 { return }; a++ }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for { if a == 3 { return }; a++ }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 1; for { if a == 1 { return 2 }; a++ }`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for { if a == 3 { return 2 }; a++ }`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(3)}}, + + {Script: `a = 1; for { if a == 3 { return 3 }; a++ }; return 2`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + + {Script: `a = 1; for { a++; if a == 2 { continue } else { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 1; for { a++; if a == 2 { continue }; if a == 3 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(3)}}, + + {Script: `for a in [1] { if a == 1 { break } }`, RunOutput: nil}, + {Script: `for a in [1, 2] { if a == 2 { break } }`, RunOutput: nil}, + {Script: `for a in [1, 2, 3] { if a == 3 { break } }`, RunOutput: nil}, + + {Script: `for a in [1, 2, 3] { if a == 2 { return 2 } }; return 3`, RunOutput: int64(2)}, + + {Script: `a = [1]; for b in a { if b == 1 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1)}}}, + {Script: `a = [1, 2]; for b in a { if b == 2 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2)}}}, + {Script: `a = [1, 2, 3]; for b in a { if b == 3 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}}}, + + {Script: `a = [1]; b = 0; for c in a { b = c }`, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1)}, "b": int64(1)}}, + {Script: `a = [1, 2]; b = 0; for c in a { b = c }`, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2)}, "b": int64(2)}}, + {Script: `a = [1, 2, 3]; b = 0; for c in a { b = c }`, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1), int64(2), int64(3)}, "b": int64(3)}}, + + {Script: `a = 1; for a < 2 { a++ }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; for a < 3 { a++ }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(3)}}, + + {Script: `a = 1; for nil { a++; if a > 2 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for nil { a++; if a > 3 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for true { a++; if a > 2 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 1; for true { a++; if a > 3 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(4)}}, + + {Script: `func x() { return [1] }; for b in x() { if b == 1 { break } }`, RunOutput: nil}, + {Script: `func x() { return [1, 2] }; for b in x() { if b == 2 { break } }`, RunOutput: nil}, + {Script: `func x() { return [1, 2, 3] }; for b in x() { if b == 3 { break } }`, RunOutput: nil}, + + {Script: `func x() { a = 1; for { if a == 1 { return } } }; x()`, RunOutput: nil}, + {Script: `func x() { a = 1; for { if a == 1 { return nil } } }; x()`, RunOutput: nil}, + {Script: `func x() { a = 1; for { if a == 1 { return true } } }; x()`, RunOutput: true}, + {Script: `func x() { a = 1; for { if a == 1 { return 1 } } }; x()`, RunOutput: int64(1)}, + {Script: `func x() { a = 1; for { if a == 1 { return 1.1 } } }; x()`, RunOutput: float64(1.1)}, + {Script: `func x() { a = 1; for { if a == 1 { return "a" } } }; x()`, RunOutput: "a"}, + + {Script: `func x() { for a in [1, 2, 3] { if a == 3 { return } } }; x()`, RunOutput: nil}, + {Script: `func x() { for a in [1, 2, 3] { if a == 3 { return 3 } }; return 2 }; x()`, RunOutput: int64(3)}, + {Script: `func x() { for a in [1, 2, 3] { if a == 1 { continue } } }; x()`, RunOutput: nil}, + {Script: `func x() { for a in [1, 2, 3] { if a == 1 { continue }; if a == 3 { return } } }; x()`, RunOutput: nil}, + + {Script: `func x() { return [1, 2] }; a = 1; for i in x() { a++ }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(3)}}, + {Script: `func x() { return [1, 2, 3] }; a = 1; for i in x() { a++ }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(4)}}, + + {Script: `for a = 1; nil; nil { return }`}, + // TOFIX: + // {Script: `for a, b = 1; nil; nil { return }`}, + // {Script: `for a, b = 1, 2; nil; nil { return }`}, + + {Script: `var a = 1; for ; ; { return a }`, RunOutput: int64(1)}, + {Script: `var a = 1; for ; ; a++ { return a }`, RunOutput: int64(1)}, + {Script: `var a = 1; for ; a > 0 ; { return a }`, RunOutput: int64(1)}, + {Script: `var a = 1; for ; a > 0 ; a++ { return a }`, RunOutput: int64(1)}, + {Script: `for var a = 1 ; ; { return a }`, RunOutput: int64(1)}, + {Script: `for var a = 1 ; ; a++ { return a }`, RunOutput: int64(1)}, + {Script: `for var a = 1 ; a > 0 ; { return a }`, RunOutput: int64(1)}, + {Script: `for var a = 1 ; a > 0 ; a++ { return a }`, RunOutput: int64(1)}, + + {Script: `for var a = 1; nil; nil { return }`}, + {Script: `for var a = 1, 2; nil; nil { return }`}, + {Script: `for var a, b = 1; nil; nil { return }`}, + {Script: `for var a, b = 1, 2; nil; nil { return }`}, + + {Script: `for a.b = 1; nil; nil { return }`, RunError: fmt.Errorf("undefined symbol 'a'")}, + + {Script: `for a = 1; nil; nil { if a == 1 { break } }`, RunOutput: nil}, + {Script: `for a = 1; nil; nil { if a == 2 { break }; a++ }`, RunOutput: nil}, + {Script: `for a = 1; nil; nil { a++; if a == 3 { break } }`, RunOutput: nil}, + + {Script: `for a = 1; a < 1; nil { }`, RunOutput: nil}, + {Script: `for a = 1; a > 1; nil { }`, RunOutput: nil}, + {Script: `for a = 1; a == 1; nil { break }`, RunOutput: nil}, + + {Script: `for a = 1; a == 1; a++ { }`, RunOutput: nil}, + {Script: `for a = 1; a < 2; a++ { }`, RunOutput: nil}, + {Script: `for a = 1; a < 3; a++ { }`, RunOutput: nil}, + + {Script: `for a = 1; a < 5; a++ { if a == 3 { return 3 } }; return 2`, RunOutput: int64(3)}, + + {Script: `a = 1; for b = 1; a < 1; a++ { }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for b = 1; a < 2; a++ { }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; for b = 1; a < 3; a++ { }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(3)}}, + + {Script: `a = 1; for b = 1; a < 1; a++ { if a == 1 { continue } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for b = 1; a < 2; a++ { if a == 1 { continue } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; for b = 1; a < 3; a++ { if a == 1 { continue } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(3)}}, + + {Script: `a = 1; for b = 1; a < 1; a++ { if a == 1 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for b = 1; a < 2; a++ { if a == 1 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for b = 1; a < 3; a++ { if a == 1 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for b = 1; a < 1; a++ { if a == 2 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for b = 1; a < 2; a++ { if a == 2 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; for b = 1; a < 3; a++ { if a == 2 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; for b = 1; a < 1; a++ { if a == 3 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; for b = 1; a < 2; a++ { if a == 3 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; for b = 1; a < 3; a++ { if a == 3 { break } }`, RunOutput: nil, Output: map[string]interface{}{"a": int64(3)}}, + + {Script: `a = ["123", "456", "789"]; b = ""; for i = 0; i < len(a); i++ { b += a[i][len(a[i]) - 2:]; b += a[i][:len(a[i]) - 2] }`, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{"123", "456", "789"}, "b": "231564897"}}, + {Script: `a = [[["123"], ["456"]], [["789"]]]; b = ""; for i = 0; i < len(a); i++ { for j = 0; j < len(a[i]); j++ { for k = 0; k < len(a[i][j]); k++ { for l = 0; l < len(a[i][j][k]); l++ { b += a[i][j][k][l] + "-" } } } }`, + RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{[]interface{}{[]interface{}{"123"}, []interface{}{"456"}}, []interface{}{[]interface{}{"789"}}}, "b": "1-2-3-4-5-6-7-8-9-"}}, + + {Script: `func x() { for a = 1; a < 3; a++ { if a == 1 { return a } } }; x()`, RunOutput: int64(1)}, + {Script: `func x() { for a = 1; a < 3; a++ { if a == 2 { return a } } }; x()`, RunOutput: int64(2)}, + {Script: `func x() { for a = 1; a < 3; a++ { if a == 3 { return a } } }; x()`, RunOutput: nil}, + {Script: `func x() { for a = 1; a < 3; a++ { if a == 4 { return a } } }; x()`, RunOutput: nil}, + + {Script: `func x() { a = 1; for b = 1; a < 3; a++ { if a == 1 { continue } }; return a }; x()`, RunOutput: int64(3)}, + {Script: `func x() { a = 1; for b = 1; a < 3; a++ { if a == 2 { continue } }; return a }; x()`, RunOutput: int64(3)}, + {Script: `func x() { a = 1; for b = 1; a < 3; a++ { if a == 3 { continue } }; return a }; x()`, RunOutput: int64(3)}, + {Script: `func x() { a = 1; for b = 1; a < 3; a++ { if a == 4 { continue } }; return a }; x()`, RunOutput: int64(3)}, + + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{reflect.Value{}}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{reflect.Value{}}, "b": reflect.Value{}}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{nil}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{nil}, "b": nil}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{true}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{true}, "b": true}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{int32(1)}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int32(1)}, "b": int32(1)}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{int64(1)}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{int64(1)}, "b": int64(1)}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{float32(1.1)}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{float32(1.1)}, "b": float32(1.1)}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{float64(1.1)}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{float64(1.1)}, "b": float64(1.1)}}, + + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{interface{}(reflect.Value{})}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{interface{}(reflect.Value{})}, "b": interface{}(reflect.Value{})}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{interface{}(nil)}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{interface{}(nil)}, "b": interface{}(nil)}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{interface{}(true)}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{interface{}(true)}, "b": interface{}(true)}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{interface{}(int32(1))}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{interface{}(int32(1))}, "b": interface{}(int32(1))}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{interface{}(int64(1))}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{interface{}(int64(1))}, "b": interface{}(int64(1))}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{interface{}(float32(1.1))}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{interface{}(float32(1.1))}, "b": interface{}(float32(1.1))}}, + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": []interface{}{interface{}(float64(1.1))}}, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{interface{}(float64(1.1))}, "b": interface{}(float64(1.1))}}, + + {Script: `b = 0; for i in a { b = i }`, Input: map[string]interface{}{"a": interface{}([]interface{}{nil})}, RunOutput: nil, Output: map[string]interface{}{"a": interface{}([]interface{}{nil}), "b": nil}}, + + {Script: `for i in nil { }`, RunError: fmt.Errorf("for cannot loop over type interface")}, + {Script: `for i in true { }`, RunError: fmt.Errorf("for cannot loop over type bool")}, + {Script: `for i in a { }`, Input: map[string]interface{}{"a": reflect.Value{}}, RunError: fmt.Errorf("for cannot loop over type struct"), Output: map[string]interface{}{"a": reflect.Value{}}}, + {Script: `for i in a { }`, Input: map[string]interface{}{"a": interface{}(nil)}, RunError: fmt.Errorf("for cannot loop over type interface"), Output: map[string]interface{}{"a": interface{}(nil)}}, + {Script: `for i in a { }`, Input: map[string]interface{}{"a": interface{}(true)}, RunError: fmt.Errorf("for cannot loop over type bool"), Output: map[string]interface{}{"a": interface{}(true)}}, + {Script: `for i in [1, 2, 3] { b++ }`, RunError: fmt.Errorf("undefined symbol 'b'")}, + {Script: `for a = 1; a < 3; a++ { b++ }`, RunError: fmt.Errorf("undefined symbol 'b'")}, + {Script: `for a = b; a < 3; a++ { }`, RunError: fmt.Errorf("undefined symbol 'b'")}, + {Script: `for a = 1; b < 3; a++ { }`, RunError: fmt.Errorf("undefined symbol 'b'")}, + {Script: `for a = 1; a < 3; b++ { }`, RunError: fmt.Errorf("undefined symbol 'b'")}, + + {Script: `a = 1; b = [{"c": "c"}]; for i in b { a = i }`, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"c": "c"}, "b": []interface{}{map[interface{}]interface{}{"c": "c"}}}}, + {Script: `a = 1; b = {"x": [{"y": "y"}]}; for i in b.x { a = i }`, RunOutput: nil, Output: map[string]interface{}{"a": map[interface{}]interface{}{"y": "y"}, "b": map[interface{}]interface{}{"x": []interface{}{map[interface{}]interface{}{"y": "y"}}}}}, + + {Script: `a = {}; b = 1; for i in a { b = i }; b`, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{}, "b": int64(1)}}, + {Script: `a = {"x": 2}; b = 1; for i in a { b = i }; b`, RunOutput: "x", Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2)}, "b": "x"}}, + {Script: `a = {"x": 2, "y": 3}; b = 0; for i in a { b++ }; b`, RunOutput: int64(2), Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2), "y": int64(3)}, "b": int64(2)}}, + {Script: `a = {"x": 2, "y": 3}; for i in a { b++ }`, RunError: fmt.Errorf("undefined symbol 'b'"), Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2), "y": int64(3)}}}, + + {Script: `a = {"x": 2, "y": 3}; b = 0; for i in a { if i == "x" { continue }; b = i }; b`, RunOutput: "y", Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2), "y": int64(3)}, "b": "y"}}, + {Script: `a = {"x": 2, "y": 3}; b = 0; for i in a { if i == "y" { continue }; b = i }; b`, RunOutput: "x", Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2), "y": int64(3)}, "b": "x"}}, + {Script: `a = {"x": 2, "y": 3}; for i in a { if i == "x" { return 1 } }`, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2), "y": int64(3)}}}, + {Script: `a = {"x": 2, "y": 3}; for i in a { if i == "y" { return 2 } }`, RunOutput: int64(2), Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2), "y": int64(3)}}}, + {Script: `a = {"x": 2, "y": 3}; b = 0; for i in a { if i == "x" { break }; b++ }; if b > 1 { return false } else { return true }`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2), "y": int64(3)}}}, + {Script: `a = {"x": 2, "y": 3}; b = 0; for i in a { if i == "y" { break }; b++ }; if b > 1 { return false } else { return true }`, RunOutput: true, Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2), "y": int64(3)}}}, + {Script: `a = {"x": 2, "y": 3}; b = 1; for i in a { if (i == "x" || i == "y") { break }; b++ }; b`, RunOutput: int64(1), Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2), "y": int64(3)}, "b": int64(1)}}, + + {Script: `a = ["123", "456", "789"]; b = ""; for v in a { b += v[len(v) - 2:]; b += v[:len(v) - 2] }`, RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{"123", "456", "789"}, "b": "231564897"}}, + {Script: `a = [[["123"], ["456"]], [["789"]]]; b = ""; for x in a { for y in x { for z in y { for i = 0; i < len(z); i++ { b += z[i] + "-" } } } }`, + RunOutput: nil, Output: map[string]interface{}{"a": []interface{}{[]interface{}{[]interface{}{"123"}, []interface{}{"456"}}, []interface{}{[]interface{}{"789"}}}, "b": "1-2-3-4-5-6-7-8-9-"}}, + + {Script: `a = {"x": 2}; b = 0; for k, v in a { b = k }; b`, RunOutput: "x", Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2)}, "b": "x"}}, + {Script: `a = {"x": 2}; b = 0; for k, v in a { b = v }; b`, RunOutput: int64(2), Output: map[string]interface{}{"a": map[interface{}]interface{}{"x": int64(2)}, "b": int64(2)}}, + + {Script: `a = make(chan int64, 2); a <- 1; v = 0; for val in a { v = val; break; }; v`, RunOutput: int64(1), Output: map[string]interface{}{"v": int64(1)}}, + {Script: `a = make(chan int64, 4); a <- 1; a <- 2; a <- 3; for i in a { if i == 2 { return 2 } }; return 4`, RunOutput: int64(2)}, + {Script: `a = make(chan int64, 2); a <- 1; for i in a { if i < 4 { a <- i + 1; continue }; return 4 }; return 6`, RunOutput: int64(4)}, + + // test non-buffer and go func + {Script: `a = make(chan int64); go func() { a <- 1; a <- 2; a <- 3 }(); b = []; for i in a { b += i; if i > 2 { break } }`, RunOutput: nil, Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2), int64(3)}}}, + {Script: `a = make(chan int64); go func() { a <- 1; a <- 2; a <- 3; close(a) }(); b = []; for i in a { b += i }`, RunOutput: nil, Output: map[string]interface{}{"b": []interface{}{int64(1), int64(2), int64(3)}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestItemInList(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `"a" in ["a"]`, RunOutput: true}, + {Script: `"a" in ["b"]`, RunOutput: false}, + {Script: `"a" in ["c", "b", "a"]`, RunOutput: true}, + {Script: `"a" in ["a", "b", 1]`, RunOutput: true}, + {Script: `"a" in l`, Input: map[string]interface{}{"l": []interface{}{"a"}}, RunOutput: true}, + {Script: `"a" in l`, Input: map[string]interface{}{"l": []interface{}{"b"}}, RunOutput: false}, + {Script: `"a" in l`, Input: map[string]interface{}{"l": []interface{}{"c", "b", "a"}}, RunOutput: true}, + {Script: `"a" in l`, Input: map[string]interface{}{"l": []interface{}{"a", "b", 1}}, RunOutput: true}, + + {Script: `1 in [1]`, RunOutput: true}, + {Script: `1 in [2]`, RunOutput: false}, + {Script: `1 in [3, 2, 1]`, RunOutput: true}, + {Script: `1 in ["1"]`, RunOutput: true}, + {Script: `1 in l`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `"1" in l`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `1 in l`, Input: map[string]interface{}{"l": []interface{}{2}}, RunOutput: false}, + {Script: `1 in l`, Input: map[string]interface{}{"l": []interface{}{3, 2, 1}}, RunOutput: true}, + {Script: `1 in l`, Input: map[string]interface{}{"l": []interface{}{"1"}}, RunOutput: true}, + + {Script: `0.9 in [1]`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: false}, + {Script: `1.0 in [1]`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `1.1 in [1]`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: false}, + {Script: `1 in [0.9]`, Input: map[string]interface{}{"l": []interface{}{0.9}}, RunOutput: false}, + {Script: `1 in [1.0]`, Input: map[string]interface{}{"l": []interface{}{1.0}}, RunOutput: true}, + {Script: `1 in [1.1]`, Input: map[string]interface{}{"l": []interface{}{1.1}}, RunOutput: false}, + {Script: `0.9 in [1]`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: false}, + {Script: `1.0 in [1]`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `1.1 in [1]`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: false}, + {Script: `1 in [0.9]`, Input: map[string]interface{}{"l": []interface{}{0.9}}, RunOutput: false}, + {Script: `1 in [1.0]`, Input: map[string]interface{}{"l": []interface{}{1.0}}, RunOutput: true}, + {Script: `1 in [1.1]`, Input: map[string]interface{}{"l": []interface{}{1.1}}, RunOutput: false}, + + {Script: `true in ["true"]`, RunOutput: true}, + {Script: `true in [true]`, RunOutput: true}, + {Script: `true in [true, false]`, RunOutput: true}, + {Script: `false in [false, true]`, RunOutput: true}, + {Script: `true in l`, Input: map[string]interface{}{"l": []interface{}{"true"}}, RunOutput: true}, + {Script: `true in l`, Input: map[string]interface{}{"l": []interface{}{true}}, RunOutput: true}, + {Script: `true in l`, Input: map[string]interface{}{"l": []interface{}{true, false}}, RunOutput: true}, + {Script: `false in l`, Input: map[string]interface{}{"l": []interface{}{false, true}}, RunOutput: true}, + + {Script: `"a" in ["b", "a", "c"][1:]`, RunOutput: true}, + {Script: `"a" in ["b", "a", "c"][:1]`, RunOutput: false}, + {Script: `"a" in ["b", "a", "c"][1:2]`, RunOutput: true}, + {Script: `l = ["b", "a", "c"];"a" in l[1:]`, RunOutput: true}, + {Script: `l = ["b", "a", "c"];"a" in l[:1]`, RunOutput: false}, + {Script: `l = ["b", "a", "c"];"a" in l[1:2]`, RunOutput: true}, + {Script: `"a" in l[1:]`, Input: map[string]interface{}{"l": []interface{}{"b", "a", "c"}}, RunOutput: true}, + {Script: `"a" in l[:1]`, Input: map[string]interface{}{"l": []interface{}{"b", "a", "c"}}, RunOutput: false}, + {Script: `"a" in l[1:2]`, Input: map[string]interface{}{"l": []interface{}{"b", "a", "c"}}, RunOutput: true}, + + // for i in list && item in list + {Script: `list_of_list = [["a"]];for l in list_of_list { return "a" in l }`, RunOutput: true}, + {Script: `for l in list_of_list { return "a" in l }`, Input: map[string]interface{}{"list_of_list": []interface{}{[]interface{}{"a"}}}, RunOutput: true}, + + // not slice or array + // todo: support `"a" in "aaa"` ? + {Script: `"a" in "aaa"`, RunError: fmt.Errorf("second argument must be slice or array; but have string")}, + {Script: `1 in 12345`, RunError: fmt.Errorf("second argument must be slice or array; but have int64")}, + + // a in item in list + {Script: `"a" in 5 in [1, 2, 3]`, RunError: fmt.Errorf("second argument must be slice or array; but have bool")}, + + // applying a in b in several part of expresstion/statement + {Script: `switch 1 in [1] {case true: return true;default: return false}`, RunOutput: true}, + {Script: `switch 1 in [2,3] {case true: return true;default: return false}`, RunOutput: false}, + {Script: `switch true {case 1 in [1]: return true;default: return false}`, RunOutput: true}, + {Script: `switch false {case 1 in [1]: return true;default: return false}`, RunOutput: false}, + {Script: `if 1 in [1] {return true} else {return false}`, RunOutput: true}, + {Script: `if 1 in [2,3] {return true} else {return false}`, RunOutput: false}, + {Script: `for i in [1,2,3] { i++ }`}, + {Script: `a=1; a=a in [1]`, RunOutput: true}, + {Script: `a=1; a=a in [2,3]`, RunOutput: false}, + {Script: `1 in [1] && true`, RunOutput: true}, + {Script: `1 in [1] && false`, RunOutput: false}, + {Script: `1 in [1] || true`, RunOutput: true}, + {Script: `1 in [1] || false`, RunOutput: true}, + {Script: `1 in [2,3] && true`, RunOutput: false}, + {Script: `1 in [2,3] && false`, RunOutput: false}, + {Script: `1 in [2,3] || true`, RunOutput: true}, + {Script: `1 in [2,3] || false`, RunOutput: false}, + {Script: `1++ in [1, 2, 3]`, RunError: fmt.Errorf("invalid operation")}, + {Script: `3++ in [1, 2, 3]`, RunError: fmt.Errorf("invalid operation")}, + {Script: `1 in 1++`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a=1;a++ in [1, 2, 3]`, RunOutput: true}, + {Script: `a=3;a++ in [1, 2, 3]`, RunOutput: false}, + {Script: `switch 1 in l {case true: return true;default: return false}`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `switch 1 in l {case true: return true;default: return false}`, Input: map[string]interface{}{"l": []interface{}{2, 3}}, RunOutput: false}, + {Script: `switch true {case 1 in l: return true;default: return false}`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `switch false {case 1 in l: return true;default: return false}`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: false}, + {Script: `if 1 in l {return true} else {return false}`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `if 1 in l {return true} else {return false}`, Input: map[string]interface{}{"l": []interface{}{2, 3}}, RunOutput: false}, + {Script: `for i in l { i++ }`, Input: map[string]interface{}{"l": []interface{}{1, 2, 3}}}, + {Script: `a=1; a=a in l`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `a=1; a=a in l`, Input: map[string]interface{}{"l": []interface{}{2, 3}}, RunOutput: false}, + {Script: `1 in l && true`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `1 in l && false`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: false}, + {Script: `1 in l || true`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `1 in l || false`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `1 in l && true`, Input: map[string]interface{}{"l": []interface{}{2, 3}}, RunOutput: false}, + {Script: `1 in l && false`, Input: map[string]interface{}{"l": []interface{}{2, 3}}, RunOutput: false}, + {Script: `1 in l || true`, Input: map[string]interface{}{"l": []interface{}{2, 3}}, RunOutput: true}, + {Script: `1 in l || false`, Input: map[string]interface{}{"l": []interface{}{2, 3}}, RunOutput: false}, + {Script: `1++ in l`, Input: map[string]interface{}{"l": []interface{}{1, 2, 3}}, RunError: fmt.Errorf("invalid operation")}, + {Script: `3++ in l`, Input: map[string]interface{}{"l": []interface{}{1, 2, 3}}, RunError: fmt.Errorf("invalid operation")}, + {Script: `a=1;a++ in l`, Input: map[string]interface{}{"l": []interface{}{1, 2, 3}}, RunOutput: true}, + {Script: `a=3;a++ in l`, Input: map[string]interface{}{"l": []interface{}{1, 2, 3}}, RunOutput: false}, + + // multidimensional slice + {Script: `1 in [1]`, RunOutput: true}, + {Script: `1 in [[1]]`, RunOutput: false}, + {Script: `1 in [[[1]]]`, RunOutput: false}, + {Script: `1 in [[1],[[1]],1]`, RunOutput: true}, + {Script: `[1] in [1]`, RunOutput: false}, + {Script: `[1] in [[1]]`, RunOutput: true}, + {Script: `[1] in [[[1]]]`, RunOutput: false}, + {Script: `[[1]] in [1]`, RunOutput: false}, + {Script: `[[1]] in [[1]]`, RunOutput: false}, + {Script: `[[1]] in [[[1]]]`, RunOutput: true}, + {Script: `1 in [1]`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: true}, + {Script: `1 in [[1]]`, Input: map[string]interface{}{"l": []interface{}{[]interface{}{1}}}, RunOutput: false}, + {Script: `1 in [[[1]]]`, Input: map[string]interface{}{"l": []interface{}{[]interface{}{[]interface{}{1}}}}, RunOutput: false}, + {Script: `1 in [[1],[[1]],1]`, Input: map[string]interface{}{"l": []interface{}{[]interface{}{1}, []interface{}{[]interface{}{1}}, 1}}, RunOutput: true}, + {Script: `[1] in [1]`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: false}, + {Script: `[1] in [[1]]`, Input: map[string]interface{}{"l": []interface{}{[]interface{}{1}}}, RunOutput: true}, + {Script: `[1] in [[[1]]]`, Input: map[string]interface{}{"l": []interface{}{[]interface{}{[]interface{}{1}}}}, RunOutput: false}, + {Script: `[[1]] in [1]`, Input: map[string]interface{}{"l": []interface{}{1}}, RunOutput: false}, + {Script: `[[1]] in [[1]]`, Input: map[string]interface{}{"l": []interface{}{[]interface{}{1}}}, RunOutput: false}, + {Script: `[[1]] in [[[1]]]`, Input: map[string]interface{}{"l": []interface{}{[]interface{}{[]interface{}{1}}}}, RunOutput: true}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestOperatorPrecedence(t *testing.T) { + t.Parallel() + + tests := []Test{ + // test && > || + {Script: `true || true && false`, RunOutput: true}, + {Script: `(true || true) && false`, RunOutput: false}, + {Script: `false && true || true`, RunOutput: true}, + {Script: `false && (true || true)`, RunOutput: false}, + + // test == > || + {Script: `0 == 1 || 1 == 1`, RunOutput: true}, + {Script: `0 == (1 || 1) == 1`, RunOutput: false}, + + // test + > == + {Script: `1 + 2 == 2 + 1`, RunOutput: true}, + {Script: `1 + (2 == 2) + 1`, RunOutput: int64(3)}, + + // test * > + + {Script: `2 * 3 + 4 * 5`, RunOutput: int64(26)}, + {Script: `2 * (3 + 4) * 5`, RunOutput: int64(70)}, + + // test * > && + {Script: `2 * 0 && 3 * 4`, RunOutput: false}, + {Script: `2 * (0 && 3) * 4`, RunOutput: int64(0)}, + + // test ++ > * + {Script: `a = 1; b = 2; a++ * b++`, RunOutput: int64(6)}, + + // test ++ > * + {Script: `a = 1; b = 2; a++ * b++`, RunOutput: int64(6)}, + + // test unary - > + + {Script: `a = 1; b = 2; -a + b`, RunOutput: int64(1)}, + {Script: `a = 1; b = 2; -(a + b)`, RunOutput: int64(-3)}, + {Script: `a = 1; b = 2; a + -b`, RunOutput: int64(-1)}, + + // test ! > || + {Script: `!true || true`, RunOutput: true}, + {Script: `!(true || true)`, RunOutput: false}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestTry(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `try { 1++ } catch { 1++ }`, RunError: fmt.Errorf("invalid operation")}, + {Script: `try { 1++ } catch a { return a }`, RunOutput: fmt.Errorf("invalid operation")}, + {Script: `try { 1++ } catch a { a = 2 }; return a`, RunError: fmt.Errorf("undefined symbol 'a'")}, + + // test finally + {Script: `try { 1++ } catch { 1++ } finally { return 1 }`, RunError: fmt.Errorf("invalid operation")}, + {Script: `try { } catch { } finally { 1++ }`, RunError: fmt.Errorf("invalid operation")}, + {Script: `try { } catch { 1 } finally { 1++ }`, RunError: fmt.Errorf("invalid operation")}, + {Script: `try { 1++ } catch { } finally { 1++ }`, RunError: fmt.Errorf("invalid operation")}, + {Script: `try { 1++ } catch a { } finally { return a }`, RunOutput: fmt.Errorf("invalid operation")}, + {Script: `try { 1++ } catch a { } finally { a = 2 }; return a`, RunError: fmt.Errorf("undefined symbol 'a'")}, + + {Script: `try { } catch { }`, RunOutput: nil}, + {Script: `try { 1++ } catch { }`, RunOutput: nil}, + {Script: `try { } catch { 1++ }`, RunOutput: nil}, + {Script: `try { return 1 } catch { }`, RunOutput: int64(1)}, + {Script: `try { return 1 } catch { return 2 }`, RunOutput: int64(2)}, + {Script: `try { 1++ } catch { return 1 }`, RunOutput: int64(1)}, + + // test finally + {Script: `try { } catch { } finally { return 1 }`, RunOutput: int64(1)}, + {Script: `try { 1++ } catch { } finally { return 1 }`, RunOutput: int64(1)}, + {Script: `try { 1++ } catch { return 1 } finally { 1++ }`, RunOutput: int64(1)}, + + // test variable scope + {Script: `try { 1++ } catch a { if a.Error() == "invalid operation" { return 1 } else { return 2 } }`, RunOutput: int64(1)}, + {Script: `try { 1++ } catch a { } finally { if a.Error() == "invalid operation" { return 1 } else { return 2 } }`, RunOutput: int64(1)}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} diff --git a/src/tool/run/vm/vmStmt.go b/src/tool/run/vm/vmStmt.go new file mode 100644 index 0000000..a71b782 --- /dev/null +++ b/src/tool/run/vm/vmStmt.go @@ -0,0 +1,803 @@ +package vm + +import ( + "context" + "fmt" + "reflect" + + "github.com/surdeus/goblin/src/tool/run/ast" + "github.com/surdeus/goblin/src/tool/run/env" + "github.com/surdeus/goblin/src/tool/run/parser" +) + +// Execute parses script and executes in the specified environment. +func Execute(env *env.Env, options *Options, script string) (interface{}, error) { + stmt, err := parser.ParseSrc(script) + if err != nil { + return nilValue, err + } + + return RunContext(context.Background(), env, options, stmt) +} + +// ExecuteContext parses script and executes in the specified environment with context. +func ExecuteContext(ctx context.Context, env *env.Env, options *Options, script string) (interface{}, error) { + stmt, err := parser.ParseSrc(script) + if err != nil { + return nilValue, err + } + + return RunContext(ctx, env, options, stmt) +} + +// Run executes statement in the specified environment. +func Run(env *env.Env, options *Options, stmt ast.Stmt) (interface{}, error) { + return RunContext(context.Background(), env, options, stmt) +} + +// RunContext executes statement in the specified environment with context. +func RunContext(ctx context.Context, env *env.Env, options *Options, stmt ast.Stmt) (interface{}, error) { + runInfo := runInfoStruct{ctx: ctx, env: env, options: options, stmt: stmt, rv: nilValue} + if runInfo.options == nil { + runInfo.options = &Options{} + } + runInfo.runSingleStmt() + if runInfo.err == ErrReturn { + runInfo.err = nil + } + return runInfo.rv.Interface(), runInfo.err +} + +// runSingleStmt executes statement in the specified environment with context. +func (runInfo *runInfoStruct) runSingleStmt() { + select { + case <-runInfo.ctx.Done(): + runInfo.rv = nilValue + runInfo.err = ErrInterrupt + return + default: + } + + switch stmt := runInfo.stmt.(type) { + + // nil + case nil: + + // StmtsStmt + case *ast.StmtsStmt: + for _, stmt := range stmt.Stmts { + switch stmt.(type) { + case *ast.BreakStmt: + runInfo.err = ErrBreak + return + case *ast.ContinueStmt: + runInfo.err = ErrContinue + return + case *ast.ReturnStmt: + runInfo.stmt = stmt + runInfo.runSingleStmt() + if runInfo.err != nil { + return + } + runInfo.err = ErrReturn + return + default: + runInfo.stmt = stmt + runInfo.runSingleStmt() + if runInfo.err != nil { + return + } + } + } + + // ExprStmt + case *ast.ExprStmt: + runInfo.expr = stmt.Expr + runInfo.invokeExpr() + + // VarStmt + case *ast.VarStmt: + // get right side expression values + rvs := make([]reflect.Value, len(stmt.Exprs)) + var i int + for i, runInfo.expr = range stmt.Exprs { + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if env, ok := runInfo.rv.Interface().(*env.Env); ok { + rvs[i] = reflect.ValueOf(env.DeepCopy()) + } else { + rvs[i] = runInfo.rv + } + } + + if len(rvs) == 1 && len(stmt.Names) > 1 { + // only one right side value but many left side names + value := rvs[0] + if value.Kind() == reflect.Interface && !value.IsNil() { + value = value.Elem() + } + if (value.Kind() == reflect.Slice || value.Kind() == reflect.Array) && value.Len() > 0 { + // value is slice/array, add each value to left side names + for i := 0; i < value.Len() && i < len(stmt.Names); i++ { + runInfo.env.DefineValue(stmt.Names[i], value.Index(i)) + } + // return last value of slice/array + runInfo.rv = value.Index(value.Len() - 1) + return + } + } + + // define all names with right side values + for i = 0; i < len(rvs) && i < len(stmt.Names); i++ { + runInfo.env.DefineValue(stmt.Names[i], rvs[i]) + } + + // return last right side value + runInfo.rv = rvs[len(rvs)-1] + + // LetsStmt + case *ast.LetsStmt: + // get right side expression values + rvs := make([]reflect.Value, len(stmt.RHSS)) + var i int + for i, runInfo.expr = range stmt.RHSS { + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if env, ok := runInfo.rv.Interface().(*env.Env); ok { + rvs[i] = reflect.ValueOf(env.DeepCopy()) + } else { + rvs[i] = runInfo.rv + } + } + + if len(rvs) == 1 && len(stmt.LHSS) > 1 { + // only one right side value but many left side expressions + value := rvs[0] + if value.Kind() == reflect.Interface && !value.IsNil() { + value = value.Elem() + } + if (value.Kind() == reflect.Slice || value.Kind() == reflect.Array) && value.Len() > 0 { + // value is slice/array, add each value to left side expression + for i := 0; i < value.Len() && i < len(stmt.LHSS); i++ { + runInfo.rv = value.Index(i) + runInfo.expr = stmt.LHSS[i] + runInfo.invokeLetExpr() + if runInfo.err != nil { + return + } + } + // return last value of slice/array + runInfo.rv = value.Index(value.Len() - 1) + return + } + } + + // invoke all left side expressions with right side values + for i = 0; i < len(rvs) && i < len(stmt.LHSS); i++ { + value := rvs[i] + if value.Kind() == reflect.Interface && !value.IsNil() { + value = value.Elem() + } + runInfo.rv = value + runInfo.expr = stmt.LHSS[i] + runInfo.invokeLetExpr() + if runInfo.err != nil { + return + } + } + + // return last right side value + runInfo.rv = rvs[len(rvs)-1] + + // LetMapItemStmt + case *ast.LetMapItemStmt: + runInfo.expr = stmt.RHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + var rvs []reflect.Value + if isNil(runInfo.rv) { + rvs = []reflect.Value{nilValue, falseValue} + } else { + rvs = []reflect.Value{runInfo.rv, trueValue} + } + var i int + for i, runInfo.expr = range stmt.LHSS { + runInfo.rv = rvs[i] + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + runInfo.invokeLetExpr() + if runInfo.err != nil { + return + } + } + runInfo.rv = rvs[0] + + // IfStmt + case *ast.IfStmt: + // if + runInfo.expr = stmt.If + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + + env := runInfo.env + + if toBool(runInfo.rv) { + // then + runInfo.rv = nilValue + runInfo.stmt = stmt.Then + runInfo.env = env.NewEnv() + runInfo.runSingleStmt() + runInfo.env = env + return + } + + for _, statement := range stmt.ElseIf { + elseIf := statement.(*ast.IfStmt) + + // else if - if + runInfo.env = env.NewEnv() + runInfo.expr = elseIf.If + runInfo.invokeExpr() + if runInfo.err != nil { + runInfo.env = env + return + } + + if !toBool(runInfo.rv) { + continue + } + + // else if - then + runInfo.rv = nilValue + runInfo.stmt = elseIf.Then + runInfo.env = env.NewEnv() + runInfo.runSingleStmt() + runInfo.env = env + return + } + + if stmt.Else != nil { + // else + runInfo.rv = nilValue + runInfo.stmt = stmt.Else + runInfo.env = env.NewEnv() + runInfo.runSingleStmt() + } + + runInfo.env = env + + // TryStmt + case *ast.TryStmt: + // only the try statement will ignore any error except ErrInterrupt + // all other parts will return the error + + env := runInfo.env + runInfo.env = env.NewEnv() + + runInfo.stmt = stmt.Try + runInfo.runSingleStmt() + + if runInfo.err != nil { + if runInfo.err == ErrInterrupt { + runInfo.env = env + return + } + + // Catch + runInfo.stmt = stmt.Catch + if stmt.Var != "" { + runInfo.env.DefineValue(stmt.Var, reflect.ValueOf(runInfo.err)) + } + runInfo.err = nil + runInfo.runSingleStmt() + if runInfo.err != nil { + runInfo.env = env + return + } + } + + if stmt.Finally != nil { + // Finally + runInfo.stmt = stmt.Finally + runInfo.runSingleStmt() + } + + runInfo.env = env + + // LoopStmt + case *ast.LoopStmt: + env := runInfo.env + runInfo.env = env.NewEnv() + + for { + select { + case <-runInfo.ctx.Done(): + runInfo.err = ErrInterrupt + runInfo.rv = nilValue + runInfo.env = env + return + default: + } + + if stmt.Expr != nil { + runInfo.expr = stmt.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + break + } + if !toBool(runInfo.rv) { + break + } + } + + runInfo.stmt = stmt.Stmt + runInfo.runSingleStmt() + if runInfo.err != nil { + if runInfo.err == ErrContinue { + runInfo.err = nil + continue + } + if runInfo.err == ErrReturn { + runInfo.env = env + return + } + if runInfo.err == ErrBreak { + runInfo.err = nil + } + break + } + } + + runInfo.rv = nilValue + runInfo.env = env + + // ForStmt + case *ast.ForStmt: + runInfo.expr = stmt.Value + runInfo.invokeExpr() + value := runInfo.rv + if runInfo.err != nil { + return + } + if value.Kind() == reflect.Interface && !value.IsNil() { + value = value.Elem() + } + + env := runInfo.env + runInfo.env = env.NewEnv() + + switch value.Kind() { + case reflect.Slice, reflect.Array: + for i := 0; i < value.Len(); i++ { + select { + case <-runInfo.ctx.Done(): + runInfo.err = ErrInterrupt + runInfo.rv = nilValue + runInfo.env = env + return + default: + } + + iv := value.Index(i) + if iv.Kind() == reflect.Interface && !iv.IsNil() { + iv = iv.Elem() + } + if iv.Kind() == reflect.Ptr { + iv = iv.Elem() + } + runInfo.env.DefineValue(stmt.Vars[0], iv) + + runInfo.stmt = stmt.Stmt + runInfo.runSingleStmt() + if runInfo.err != nil { + if runInfo.err == ErrContinue { + runInfo.err = nil + continue + } + if runInfo.err == ErrReturn { + runInfo.env = env + return + } + if runInfo.err == ErrBreak { + runInfo.err = nil + } + break + } + } + runInfo.rv = nilValue + runInfo.env = env + + case reflect.Map: + keys := value.MapKeys() + for i := 0; i < len(keys); i++ { + select { + case <-runInfo.ctx.Done(): + runInfo.err = ErrInterrupt + runInfo.rv = nilValue + runInfo.env = env + return + default: + } + + runInfo.env.DefineValue(stmt.Vars[0], keys[i]) + + if len(stmt.Vars) > 1 { + runInfo.env.DefineValue(stmt.Vars[1], value.MapIndex(keys[i])) + } + + runInfo.stmt = stmt.Stmt + runInfo.runSingleStmt() + if runInfo.err != nil { + if runInfo.err == ErrContinue { + runInfo.err = nil + continue + } + if runInfo.err == ErrReturn { + runInfo.env = env + return + } + if runInfo.err == ErrBreak { + runInfo.err = nil + } + break + } + } + runInfo.rv = nilValue + runInfo.env = env + + case reflect.Chan: + var chosen int + var ok bool + for { + cases := []reflect.SelectCase{{ + Dir: reflect.SelectRecv, + Chan: reflect.ValueOf(runInfo.ctx.Done()), + }, { + Dir: reflect.SelectRecv, + Chan: value, + }} + chosen, runInfo.rv, ok = reflect.Select(cases) + if chosen == 0 { + runInfo.err = ErrInterrupt + runInfo.rv = nilValue + break + } + if !ok { + break + } + + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + if runInfo.rv.Kind() == reflect.Ptr { + runInfo.rv = runInfo.rv.Elem() + } + + runInfo.env.DefineValue(stmt.Vars[0], runInfo.rv) + + runInfo.stmt = stmt.Stmt + runInfo.runSingleStmt() + if runInfo.err != nil { + if runInfo.err == ErrContinue { + runInfo.err = nil + continue + } + if runInfo.err == ErrReturn { + runInfo.env = env + return + } + if runInfo.err == ErrBreak { + runInfo.err = nil + } + break + } + } + runInfo.rv = nilValue + runInfo.env = env + + default: + runInfo.err = newStringError(stmt, "for cannot loop over type "+value.Kind().String()) + runInfo.rv = nilValue + runInfo.env = env + } + + // CForStmt + case *ast.CForStmt: + env := runInfo.env + runInfo.env = env.NewEnv() + + if stmt.Stmt1 != nil { + runInfo.stmt = stmt.Stmt1 + runInfo.runSingleStmt() + if runInfo.err != nil { + runInfo.env = env + return + } + } + + for { + select { + case <-runInfo.ctx.Done(): + runInfo.err = ErrInterrupt + runInfo.rv = nilValue + runInfo.env = env + return + default: + } + + if stmt.Expr2 != nil { + runInfo.expr = stmt.Expr2 + runInfo.invokeExpr() + if runInfo.err != nil { + break + } + if !toBool(runInfo.rv) { + break + } + } + + runInfo.stmt = stmt.Stmt + runInfo.runSingleStmt() + if runInfo.err == ErrContinue { + runInfo.err = nil + } + if runInfo.err != nil { + if runInfo.err == ErrReturn { + runInfo.env = env + return + } + if runInfo.err == ErrBreak { + runInfo.err = nil + } + break + } + + if stmt.Expr3 != nil { + runInfo.expr = stmt.Expr3 + runInfo.invokeExpr() + if runInfo.err != nil { + break + } + } + } + runInfo.rv = nilValue + runInfo.env = env + + // ReturnStmt + case *ast.ReturnStmt: + switch len(stmt.Exprs) { + case 0: + runInfo.rv = nilValue + return + case 1: + runInfo.expr = stmt.Exprs[0] + runInfo.invokeExpr() + return + } + rvs := make([]interface{}, len(stmt.Exprs)) + var i int + for i, runInfo.expr = range stmt.Exprs { + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + rvs[i] = runInfo.rv.Interface() + } + runInfo.rv = reflect.ValueOf(rvs) + + // ThrowStmt + case *ast.ThrowStmt: + runInfo.expr = stmt.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + runInfo.err = newStringError(stmt, fmt.Sprint(runInfo.rv.Interface())) + + // ModuleStmt + case *ast.ModuleStmt: + e := runInfo.env + runInfo.env, runInfo.err = e.NewModule(stmt.Name) + if runInfo.err != nil { + return + } + runInfo.stmt = stmt.Stmt + runInfo.runSingleStmt() + runInfo.env = e + if runInfo.err != nil { + return + } + runInfo.rv = nilValue + + // SwitchStmt + case *ast.SwitchStmt: + env := runInfo.env + runInfo.env = env.NewEnv() + + runInfo.expr = stmt.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + runInfo.env = env + return + } + value := runInfo.rv + + for _, switchCaseStmt := range stmt.Cases { + caseStmt := switchCaseStmt.(*ast.SwitchCaseStmt) + for _, runInfo.expr = range caseStmt.Exprs { + runInfo.invokeExpr() + if runInfo.err != nil { + runInfo.env = env + return + } + if equal(runInfo.rv, value) { + runInfo.stmt = caseStmt.Stmt + runInfo.runSingleStmt() + runInfo.env = env + return + } + } + } + + if stmt.Default == nil { + runInfo.rv = nilValue + } else { + runInfo.stmt = stmt.Default + runInfo.runSingleStmt() + } + + runInfo.env = env + + // GoroutineStmt + case *ast.GoroutineStmt: + runInfo.expr = stmt.Expr + runInfo.invokeExpr() + + // DeleteStmt + case *ast.DeleteStmt: + runInfo.expr = stmt.Item + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + item := runInfo.rv + + if stmt.Key != nil { + runInfo.expr = stmt.Key + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + } + + if item.Kind() == reflect.Interface && !item.IsNil() { + item = item.Elem() + } + + switch item.Kind() { + case reflect.String: + if stmt.Key != nil && runInfo.rv.Kind() == reflect.Bool && runInfo.rv.Bool() { + runInfo.env.DeleteGlobal(item.String()) + runInfo.rv = nilValue + return + } + runInfo.env.Delete(item.String()) + runInfo.rv = nilValue + + case reflect.Map: + if stmt.Key == nil { + runInfo.err = newStringError(stmt, "second argument to delete cannot be nil for map") + runInfo.rv = nilValue + return + } + if item.IsNil() { + runInfo.rv = nilValue + return + } + runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, item.Type().Key()) + if runInfo.err != nil { + runInfo.err = newStringError(stmt, "cannot use type "+item.Type().Key().String()+" as type "+runInfo.rv.Type().String()+" in delete") + runInfo.rv = nilValue + return + } + item.SetMapIndex(runInfo.rv, reflect.Value{}) + runInfo.rv = nilValue + default: + runInfo.err = newStringError(stmt, "first argument to delete cannot be type "+item.Kind().String()) + runInfo.rv = nilValue + } + + // CloseStmt + case *ast.CloseStmt: + runInfo.expr = stmt.Expr + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Chan { + runInfo.rv.Close() + runInfo.rv = nilValue + return + } + runInfo.err = newStringError(stmt, "type cannot be "+runInfo.rv.Kind().String()+" for close") + runInfo.rv = nilValue + + // ChanStmt + case *ast.ChanStmt: + runInfo.expr = stmt.RHS + runInfo.invokeExpr() + if runInfo.err != nil { + return + } + if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { + runInfo.rv = runInfo.rv.Elem() + } + + if runInfo.rv.Kind() != reflect.Chan { + // rhs is not channel + runInfo.err = newStringError(stmt, "receive from non-chan type "+runInfo.rv.Kind().String()) + runInfo.rv = nilValue + return + } + + // rhs is channel + // receive from rhs channel + rhs := runInfo.rv + cases := []reflect.SelectCase{{ + Dir: reflect.SelectRecv, + Chan: reflect.ValueOf(runInfo.ctx.Done()), + }, { + Dir: reflect.SelectRecv, + Chan: rhs, + }} + var chosen int + var ok bool + chosen, runInfo.rv, ok = reflect.Select(cases) + if chosen == 0 { + runInfo.err = ErrInterrupt + runInfo.rv = nilValue + return + } + + rhs = runInfo.rv // store rv in rhs temporarily + + if stmt.OkExpr != nil { + // set ok to OkExpr + if ok { + runInfo.rv = trueValue + } else { + runInfo.rv = falseValue + } + runInfo.expr = stmt.OkExpr + runInfo.invokeLetExpr() + // TODO: ok to ignore error? + } + + if ok { + // set rv to lhs + runInfo.rv = rhs + runInfo.expr = stmt.LHS + runInfo.invokeLetExpr() + if runInfo.err != nil { + return + } + } else { + runInfo.rv = nilValue + } + + // default + default: + runInfo.err = newStringError(stmt, "unknown statement") + runInfo.rv = nilValue + } + +} diff --git a/src/tool/run/vm/vmToX.go b/src/tool/run/vm/vmToX.go new file mode 100644 index 0000000..0854c91 --- /dev/null +++ b/src/tool/run/vm/vmToX.go @@ -0,0 +1,178 @@ +package vm + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "strings" +) + +// toString converts all reflect.Value-s into string. +func toString(v reflect.Value) string { + if v.Kind() == reflect.Interface && !v.IsNil() { + v = v.Elem() + } + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + if v.Kind() == reflect.String { + return v.String() + } + return fmt.Sprint(v.Interface()) +} + +// toBool converts all reflect.Value-s into bool. +func toBool(v reflect.Value) bool { + b, _ := tryToBool(v) + return b +} + +// tryToBool attempts to convert the value 'v' to a boolean, returning +// an error if it cannot. When converting a string, the function returns +// true if the string nonempty and does not satisfy the condition for false +// with parseBool https://golang.org/pkg/strconv/#ParseBool +// and is not 0.0 +func tryToBool(v reflect.Value) (bool, error) { + if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + v = v.Elem() + } + switch v.Kind() { + case reflect.Float64, reflect.Float32: + return v.Float() != 0, nil + case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: + return v.Int() != 0, nil + case reflect.Bool: + return v.Bool(), nil + case reflect.String: + if v.Len() == 0 { + return false, nil + } + + s := v.String() + if b, err := strconv.ParseBool(s); err == nil && !b { + return false, nil + } + + if f, err := tryToFloat64(v); err == nil && f == 0 { + return false, nil + } + return true, nil + case reflect.Slice, reflect.Map: + if v.Len() > 0 { + return true, nil + } + return false, nil + } + return false, errors.New("unknown type") +} + +// toFloat64 converts all reflect.Value-s into float64. +func toFloat64(v reflect.Value) float64 { + f, _ := tryToFloat64(v) + return f +} + +// tryToFloat64 attempts to convert a value to a float64. +// If it cannot (in the case of a non-numeric string, a struct, etc.) +// it returns 0.0 and an error. +func tryToFloat64(v reflect.Value) (float64, error) { + if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + v = v.Elem() + } + switch v.Kind() { + case reflect.Float64, reflect.Float32: + return v.Float(), nil + case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: + return float64(v.Int()), nil + case reflect.Bool: + if v.Bool() { + return 1, nil + } + return 0, nil + case reflect.String: + f, err := strconv.ParseFloat(v.String(), 64) + if err == nil { + return f, nil + } + } + return 0.0, errors.New("couldn't convert to a float64") +} + +// toInt64 converts all reflect.Value-s into int64. +func toInt64(v reflect.Value) int64 { + i, _ := tryToInt64(v) + return i +} + +// tryToInt64 attempts to convert a value to an int64. +// If it cannot (in the case of a non-numeric string, a struct, etc.) +// it returns 0 and an error. +func tryToInt64(v reflect.Value) (int64, error) { + if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + v = v.Elem() + } + switch v.Kind() { + case reflect.Float64, reflect.Float32: + return int64(v.Float()), nil + case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: + return v.Int(), nil + case reflect.Bool: + if v.Bool() { + return 1, nil + } + return 0, nil + case reflect.String: + s := v.String() + var i int64 + var err error + if strings.HasPrefix(s, "0x") { + i, err = strconv.ParseInt(s, 16, 64) + } else { + i, err = strconv.ParseInt(s, 10, 64) + } + if err == nil { + return i, nil + } + } + return 0, errors.New("couldn't convert to integer") +} + +// toInt converts all reflect.Value-s into int. +func toInt(v reflect.Value) int { + i, _ := tryToInt(v) + return i +} + +// tryToInt attempts to convert a value to an int. +// If it cannot (in the case of a non-numeric string, a struct, etc.) +// it returns 0 and an error. +func tryToInt(v reflect.Value) (int, error) { + if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + v = v.Elem() + } + switch v.Kind() { + case reflect.Float64, reflect.Float32: + return int(v.Float()), nil + case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: + return int(v.Int()), nil + case reflect.Bool: + if v.Bool() { + return 1, nil + } + return 0, nil + case reflect.String: + s := v.String() + var i int64 + var err error + if strings.HasPrefix(s, "0x") { + i, err = strconv.ParseInt(s, 16, 64) + } else { + i, err = strconv.ParseInt(s, 10, 64) + } + if err == nil { + return int(i), nil + } + } + return 0, errors.New("couldn't convert to integer") +} diff --git a/src/tool/run/vm/vm_Go19_test.go b/src/tool/run/vm/vm_Go19_test.go new file mode 100644 index 0000000..5ace198 --- /dev/null +++ b/src/tool/run/vm/vm_Go19_test.go @@ -0,0 +1,17 @@ +// +build go1.9 + +package vm + +import ( + "fmt" + "testing" +) + +func TestMakeGo19(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `make(struct { a int64 })`, RunError: fmt.Errorf("reflect.StructOf: field \"a\" is unexported but missing PkgPath")}, + } + runTests(t, tests, nil, &Options{Debug: false}) +} diff --git a/src/tool/run/vm/vm_NotGo19_test.go b/src/tool/run/vm/vm_NotGo19_test.go new file mode 100644 index 0000000..4c262d8 --- /dev/null +++ b/src/tool/run/vm/vm_NotGo19_test.go @@ -0,0 +1,17 @@ +// +build !go1.9 + +package vm + +import ( + "fmt" + "testing" +) + +func TestMakeNotGo19(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `make(struct { a int64 })`, RunError: fmt.Errorf("reflect.StructOf: field \"a\" is unexported but has no PkgPath")}, + } + runTests(t, tests, nil, &Options{Debug: false}) +} diff --git a/src/tool/run/vm/vm_test.go b/src/tool/run/vm/vm_test.go new file mode 100644 index 0000000..55af9c9 --- /dev/null +++ b/src/tool/run/vm/vm_test.go @@ -0,0 +1,1268 @@ +package vm + +import ( + "context" + "fmt" + "io" + "os" + "reflect" + "sync" + "testing" + "time" + + "github.com/surdeus/goblin/src/tool/run/ast" + "github.com/surdeus/goblin/src/tool/run/env" +) + +func TestNumbers(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: ``}, + {Script: `;`}, + {Script: ` +`}, + {Script: ` +1 +`, RunOutput: int64(1)}, + + {Script: `1..1`, ParseError: fmt.Errorf("invalid number: 1..1")}, + {Script: `1e.1`, ParseError: fmt.Errorf("invalid number: 1e.1")}, + {Script: `1ee1`, ParseError: fmt.Errorf("syntax error")}, + {Script: `1e+e1`, ParseError: fmt.Errorf("syntax error")}, + {Script: `0x1g`, ParseError: fmt.Errorf("syntax error")}, + {Script: `9223372036854775808`, ParseError: fmt.Errorf("invalid number: 9223372036854775808")}, + {Script: `-9223372036854775809`, ParseError: fmt.Errorf("invalid number: -9223372036854775809")}, + + {Script: `1`, RunOutput: int64(1)}, + {Script: `-1`, RunOutput: int64(-1)}, + {Script: `9223372036854775807`, RunOutput: int64(9223372036854775807)}, + {Script: `-9223372036854775808`, RunOutput: int64(-9223372036854775808)}, + {Script: `-9223372036854775807-1`, RunOutput: int64(-9223372036854775808)}, + {Script: `-9223372036854775807 -1`, RunOutput: int64(-9223372036854775808)}, + {Script: `-9223372036854775807 - 1`, RunOutput: int64(-9223372036854775808)}, + {Script: `1.1`, RunOutput: float64(1.1)}, + {Script: `-1.1`, RunOutput: float64(-1.1)}, + + {Script: `1e1`, RunOutput: float64(10)}, + {Script: `1.5e1`, RunOutput: float64(15)}, + {Script: `1e-1`, RunOutput: float64(0.1)}, + + {Script: `-1e1`, RunOutput: float64(-10)}, + {Script: `-1.5e1`, RunOutput: float64(-15)}, + {Script: `-1e-1`, RunOutput: float64(-0.1)}, + + {Script: `0x1`, RunOutput: int64(1)}, + {Script: `0xa`, RunOutput: int64(10)}, + {Script: `0xb`, RunOutput: int64(11)}, + {Script: `0xc`, RunOutput: int64(12)}, + {Script: `0xe`, RunOutput: int64(14)}, + {Script: `0xf`, RunOutput: int64(15)}, + {Script: `0Xf`, RunOutput: int64(15)}, + {Script: `0XF`, RunOutput: int64(15)}, + {Script: `0x7FFFFFFFFFFFFFFF`, RunOutput: int64(9223372036854775807)}, + + {Script: `-0x1`, RunOutput: int64(-1)}, + {Script: `-0xc`, RunOutput: int64(-12)}, + {Script: `-0xe`, RunOutput: int64(-14)}, + {Script: `-0xf`, RunOutput: int64(-15)}, + {Script: `-0Xf`, RunOutput: int64(-15)}, + {Script: `-0x7FFFFFFFFFFFFFFF`, RunOutput: int64(-9223372036854775807)}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestStrings(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `a`, Input: map[string]interface{}{"a": 'a'}, RunOutput: 'a', Output: map[string]interface{}{"a": 'a'}}, + {Script: `a.b`, Input: map[string]interface{}{"a": 'a'}, RunError: fmt.Errorf("type int32 does not support member operation"), Output: map[string]interface{}{"a": 'a'}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": 'a'}, RunError: fmt.Errorf("type int32 does not support index operation"), RunOutput: nil, Output: map[string]interface{}{"a": 'a'}}, + {Script: `a[0:1]`, Input: map[string]interface{}{"a": 'a'}, RunError: fmt.Errorf("type int32 does not support slice operation"), RunOutput: nil, Output: map[string]interface{}{"a": 'a'}}, + + {Script: `a.b = "a"`, Input: map[string]interface{}{"a": 'a'}, RunError: fmt.Errorf("type int32 does not support member operation"), RunOutput: nil, Output: map[string]interface{}{"a": 'a'}}, + {Script: `a[0] = "a"`, Input: map[string]interface{}{"a": 'a'}, RunError: fmt.Errorf("type int32 does not support index operation"), RunOutput: nil, Output: map[string]interface{}{"a": 'a'}}, + {Script: `a[0:1] = "a"`, Input: map[string]interface{}{"a": 'a'}, RunError: fmt.Errorf("type int32 does not support slice operation"), RunOutput: nil, Output: map[string]interface{}{"a": 'a'}}, + + {Script: `a.b = "a"`, Input: map[string]interface{}{"a": "test"}, RunError: fmt.Errorf("type string does not support member operation"), Output: map[string]interface{}{"a": "test"}}, + {Script: `a[0:1] = "a"`, Input: map[string]interface{}{"a": "test"}, RunError: fmt.Errorf("type string does not support slice operation for assignment"), Output: map[string]interface{}{"a": "test"}}, + + {Script: `a`, Input: map[string]interface{}{"a": "test"}, RunOutput: "test", Output: map[string]interface{}{"a": "test"}}, + {Script: `a["a"]`, Input: map[string]interface{}{"a": "test"}, RunError: fmt.Errorf("index must be a number"), Output: map[string]interface{}{"a": "test"}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": ""}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": ""}}, + {Script: `a[-1]`, Input: map[string]interface{}{"a": "test"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test"}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": "test"}, RunOutput: "t", Output: map[string]interface{}{"a": "test"}}, + {Script: `a[1]`, Input: map[string]interface{}{"a": "test"}, RunOutput: "e", Output: map[string]interface{}{"a": "test"}}, + {Script: `a[3]`, Input: map[string]interface{}{"a": "test"}, RunOutput: "t", Output: map[string]interface{}{"a": "test"}}, + {Script: `a[4]`, Input: map[string]interface{}{"a": "test"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test"}}, + + {Script: `a`, Input: map[string]interface{}{"a": `"a"`}, RunOutput: `"a"`, Output: map[string]interface{}{"a": `"a"`}}, + {Script: `a[0]`, Input: map[string]interface{}{"a": `"a"`}, RunOutput: `"`, Output: map[string]interface{}{"a": `"a"`}}, + {Script: `a[1]`, Input: map[string]interface{}{"a": `"a"`}, RunOutput: "a", Output: map[string]interface{}{"a": `"a"`}}, + + {Script: `a = "\"a\""`, RunOutput: `"a"`, Output: map[string]interface{}{"a": `"a"`}}, + {Script: `a = "\"a\""; a`, RunOutput: `"a"`, Output: map[string]interface{}{"a": `"a"`}}, + {Script: `a = "\"a\""; a[0]`, RunOutput: `"`, Output: map[string]interface{}{"a": `"a"`}}, + {Script: `a = "\"a\""; a[1]`, RunOutput: "a", Output: map[string]interface{}{"a": `"a"`}}, + + {Script: `a`, Input: map[string]interface{}{"a": "a\\b"}, RunOutput: "a\\b", Output: map[string]interface{}{"a": "a\\b"}}, + {Script: `a`, Input: map[string]interface{}{"a": "a\\\\b"}, RunOutput: "a\\\\b", Output: map[string]interface{}{"a": "a\\\\b"}}, + {Script: `a = "a\b"`, RunOutput: "a\b", Output: map[string]interface{}{"a": "a\b"}}, + {Script: `a = "a\\b"`, RunOutput: "a\\b", Output: map[string]interface{}{"a": "a\\b"}}, + + {Script: `a[:]`, Input: map[string]interface{}{"a": "test data"}, ParseError: fmt.Errorf("syntax error"), Output: map[string]interface{}{"a": "test data"}}, + + {Script: `a[0:]`, Input: map[string]interface{}{"a": ""}, RunOutput: "", Output: map[string]interface{}{"a": ""}}, + {Script: `a[1:]`, Input: map[string]interface{}{"a": ""}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": ""}}, + {Script: `a[:0]`, Input: map[string]interface{}{"a": ""}, RunOutput: "", Output: map[string]interface{}{"a": ""}}, + {Script: `a[:1]`, Input: map[string]interface{}{"a": ""}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": ""}}, + {Script: `a[0:0]`, Input: map[string]interface{}{"a": ""}, RunOutput: "", Output: map[string]interface{}{"a": ""}}, + + {Script: `a[1:0]`, Input: map[string]interface{}{"a": "test data"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[-1:2]`, Input: map[string]interface{}{"a": "test data"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[1:-2]`, Input: map[string]interface{}{"a": "test data"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[-1:]`, Input: map[string]interface{}{"a": "test data"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[:-2]`, Input: map[string]interface{}{"a": "test data"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test data"}}, + + {Script: `a[0:0]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[0:1]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "t", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[0:2]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "te", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[0:3]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "tes", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[0:7]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "test da", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[0:8]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "test dat", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[0:9]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "test data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[0:10]`, Input: map[string]interface{}{"a": "test data"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test data"}}, + + {Script: `a[1:1]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[1:2]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "e", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[1:3]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "es", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[1:7]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "est da", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[1:8]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "est dat", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[1:9]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "est data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[1:10]`, Input: map[string]interface{}{"a": "test data"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test data"}}, + + {Script: `a[0:9]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "test data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[1:9]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "est data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[2:9]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "st data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[3:9]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "t data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[7:9]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "ta", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[8:9]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "a", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[9:9]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "", Output: map[string]interface{}{"a": "test data"}}, + + {Script: `a[:0]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[:1]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "t", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[:2]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "te", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[:3]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "tes", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[:7]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "test da", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[:8]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "test dat", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[:9]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "test data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[:10]`, Input: map[string]interface{}{"a": "test data"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test data"}}, + + {Script: `a[0:]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "test data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[1:]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "est data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[2:]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "st data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[3:]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "t data", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[7:]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "ta", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[8:]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "a", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[9:]`, Input: map[string]interface{}{"a": "test data"}, RunOutput: "", Output: map[string]interface{}{"a": "test data"}}, + {Script: `a[10:]`, Input: map[string]interface{}{"a": "test data"}, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "test data"}}, + + // index assignment - len 0 + {Script: `a = ""; a[0] = "x"`, RunOutput: "x", Output: map[string]interface{}{"a": "x"}}, + {Script: `a = ""; a[1] = "x"`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": ""}}, + + // index assignment - len 1 + {Script: `a = "a"; a[0] = "x"`, RunOutput: "x", Output: map[string]interface{}{"a": "x"}}, + {Script: `a = "a"; a[1] = "x"`, RunOutput: "x", Output: map[string]interface{}{"a": "ax"}}, + {Script: `a = "a"; a[2] = "x"`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "a"}}, + + // index assignment - len 2 + {Script: `a = "ab"; a[0] = "x"`, RunOutput: "x", Output: map[string]interface{}{"a": "xb"}}, + {Script: `a = "ab"; a[1] = "x"`, RunOutput: "x", Output: map[string]interface{}{"a": "ax"}}, + {Script: `a = "ab"; a[2] = "x"`, RunOutput: "x", Output: map[string]interface{}{"a": "abx"}}, + {Script: `a = "ab"; a[3] = "x"`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "ab"}}, + + // index assignment - len 3 + {Script: `a = "abc"; a[0] = "x"`, RunOutput: "x", Output: map[string]interface{}{"a": "xbc"}}, + {Script: `a = "abc"; a[1] = "x"`, RunOutput: "x", Output: map[string]interface{}{"a": "axc"}}, + {Script: `a = "abc"; a[2] = "x"`, RunOutput: "x", Output: map[string]interface{}{"a": "abx"}}, + {Script: `a = "abc"; a[3] = "x"`, RunOutput: "x", Output: map[string]interface{}{"a": "abcx"}}, + {Script: `a = "abc"; a[4] = "x"`, RunError: fmt.Errorf("index out of range"), Output: map[string]interface{}{"a": "abc"}}, + + // index assignment - vm types + {Script: `a = "abc"; a[1] = nil`, RunOutput: nil, Output: map[string]interface{}{"a": "ac"}}, + {Script: `a = "abc"; a[1] = true`, RunError: fmt.Errorf("type bool cannot be assigned to type string"), Output: map[string]interface{}{"a": "abc"}}, + {Script: `a = "abc"; a[1] = 120`, RunOutput: int64(120), Output: map[string]interface{}{"a": "axc"}}, + {Script: `a = "abc"; a[1] = 2.2`, RunError: fmt.Errorf("type float64 cannot be assigned to type string"), Output: map[string]interface{}{"a": "abc"}}, + {Script: `a = "abc"; a[1] = ["a"]`, RunError: fmt.Errorf("type []interface {} cannot be assigned to type string"), Output: map[string]interface{}{"a": "abc"}}, + + // index assignment - Go types + {Script: `a = "abc"; a[1] = b`, Input: map[string]interface{}{"b": reflect.Value{}}, RunError: fmt.Errorf("type reflect.Value cannot be assigned to type string"), Output: map[string]interface{}{"a": "abc"}}, + {Script: `a = "abc"; a[1] = b`, Input: map[string]interface{}{"b": nil}, RunOutput: nil, Output: map[string]interface{}{"a": "ac"}}, + {Script: `a = "abc"; a[1] = b`, Input: map[string]interface{}{"b": true}, RunError: fmt.Errorf("type bool cannot be assigned to type string"), Output: map[string]interface{}{"a": "abc"}}, + {Script: `a = "abc"; a[1] = b`, Input: map[string]interface{}{"b": int32(120)}, RunOutput: int32(120), Output: map[string]interface{}{"a": "axc"}}, + {Script: `a = "abc"; a[1] = b`, Input: map[string]interface{}{"b": int64(120)}, RunOutput: int64(120), Output: map[string]interface{}{"a": "axc"}}, + {Script: `a = "abc"; a[1] = b`, Input: map[string]interface{}{"b": float32(1.1)}, RunError: fmt.Errorf("type float32 cannot be assigned to type string"), Output: map[string]interface{}{"a": "abc"}}, + {Script: `a = "abc"; a[1] = b`, Input: map[string]interface{}{"b": float64(2.2)}, RunError: fmt.Errorf("type float64 cannot be assigned to type string"), Output: map[string]interface{}{"a": "abc"}}, + {Script: `a = "abc"; a[1] = b`, Input: map[string]interface{}{"b": "x"}, RunOutput: "x", Output: map[string]interface{}{"a": "axc"}}, + {Script: `a = "abc"; a[1] = b`, Input: map[string]interface{}{"b": 'x'}, RunOutput: 'x', Output: map[string]interface{}{"a": "axc"}}, + {Script: `a = "abc"; a[1] = b`, Input: map[string]interface{}{"b": struct{}{}}, RunError: fmt.Errorf("type struct {} cannot be assigned to type string"), Output: map[string]interface{}{"a": "abc"}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestVar(t *testing.T) { + t.Parallel() + + testInput1 := map[string]interface{}{"b": func() {}} + tests := []Test{ + // simple one variable + {Script: `1 = 2`, RunError: fmt.Errorf("invalid operation")}, + {Script: `var 1 = 2`, ParseError: fmt.Errorf("syntax error")}, + {Script: `a = 1++`, RunError: fmt.Errorf("invalid operation")}, + {Script: `var a = 1++`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a := 1`, ParseError: fmt.Errorf("syntax error")}, + {Script: `var a := 1`, ParseError: fmt.Errorf("syntax error")}, + {Script: `y = z`, RunError: fmt.Errorf("undefined symbol 'z'")}, + + {Script: `a = nil`, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `a = true`, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `a = 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1.1`, RunOutput: float64(1.1), Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `a = "a"`, RunOutput: "a", Output: map[string]interface{}{"a": "a"}}, + + {Script: `var a = nil`, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `var a = true`, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `var a = 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `var a = 1.1`, RunOutput: float64(1.1), Output: map[string]interface{}{"a": float64(1.1)}}, + {Script: `var a = "a"`, RunOutput: "a", Output: map[string]interface{}{"a": "a"}}, + + {Script: `a = b`, Input: map[string]interface{}{"b": reflect.Value{}}, RunOutput: reflect.Value{}, Output: map[string]interface{}{"a": reflect.Value{}, "b": reflect.Value{}}}, + {Script: `a = b`, Input: map[string]interface{}{"b": nil}, RunOutput: nil, Output: map[string]interface{}{"a": nil, "b": nil}}, + {Script: `a = b`, Input: map[string]interface{}{"b": true}, RunOutput: true, Output: map[string]interface{}{"a": true, "b": true}}, + {Script: `a = b`, Input: map[string]interface{}{"b": int32(1)}, RunOutput: int32(1), Output: map[string]interface{}{"a": int32(1), "b": int32(1)}}, + {Script: `a = b`, Input: map[string]interface{}{"b": int64(1)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1), "b": int64(1)}}, + {Script: `a = b`, Input: map[string]interface{}{"b": float32(1.1)}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": float32(1.1), "b": float32(1.1)}}, + {Script: `a = b`, Input: map[string]interface{}{"b": float64(1.1)}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": float64(1.1), "b": float64(1.1)}}, + {Script: `a = b`, Input: map[string]interface{}{"b": "a"}, RunOutput: "a", Output: map[string]interface{}{"a": "a", "b": "a"}}, + {Script: `a = b`, Input: map[string]interface{}{"b": 'a'}, RunOutput: 'a', Output: map[string]interface{}{"a": 'a', "b": 'a'}}, + {Script: `a = b`, Input: map[string]interface{}{"b": struct{}{}}, RunOutput: struct{}{}, Output: map[string]interface{}{"a": struct{}{}, "b": struct{}{}}}, + + {Script: `var a = b`, Input: map[string]interface{}{"b": reflect.Value{}}, RunOutput: reflect.Value{}, Output: map[string]interface{}{"a": reflect.Value{}, "b": reflect.Value{}}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": nil}, RunOutput: nil, Output: map[string]interface{}{"a": nil, "b": nil}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": true}, RunOutput: true, Output: map[string]interface{}{"a": true, "b": true}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": int32(1)}, RunOutput: int32(1), Output: map[string]interface{}{"a": int32(1), "b": int32(1)}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": int64(1)}, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1), "b": int64(1)}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": float32(1.1)}, RunOutput: float32(1.1), Output: map[string]interface{}{"a": float32(1.1), "b": float32(1.1)}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": float64(1.1)}, RunOutput: float64(1.1), Output: map[string]interface{}{"a": float64(1.1), "b": float64(1.1)}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": "a"}, RunOutput: "a", Output: map[string]interface{}{"a": "a", "b": "a"}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": 'a'}, RunOutput: 'a', Output: map[string]interface{}{"a": 'a', "b": 'a'}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": struct{}{}}, RunOutput: struct{}{}, Output: map[string]interface{}{"a": struct{}{}, "b": struct{}{}}}, + + // simple one variable overwrite + {Script: `a = true; a = nil`, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `a = nil; a = true`, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `a = 1; a = 2`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1.1; a = 2.2`, RunOutput: float64(2.2), Output: map[string]interface{}{"a": float64(2.2)}}, + {Script: `a = "a"; a = "b"`, RunOutput: "b", Output: map[string]interface{}{"a": "b"}}, + + {Script: `var a = true; var a = nil`, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `var a = nil; var a = true`, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `var a = 1; var a = 2`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `var a = 1.1; var a = 2.2`, RunOutput: float64(2.2), Output: map[string]interface{}{"a": float64(2.2)}}, + {Script: `var a = "a"; var a = "b"`, RunOutput: "b", Output: map[string]interface{}{"a": "b"}}, + + {Script: `a = nil`, Input: map[string]interface{}{"a": true}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `a = true`, Input: map[string]interface{}{"a": nil}, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `a = 2`, Input: map[string]interface{}{"a": int32(1)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 2`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 2.2`, Input: map[string]interface{}{"a": float32(1.1)}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": float64(2.2)}}, + {Script: `a = 2.2`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": float64(2.2)}}, + {Script: `a = "b"`, Input: map[string]interface{}{"a": "a"}, RunOutput: "b", Output: map[string]interface{}{"a": "b"}}, + + {Script: `var a = nil`, Input: map[string]interface{}{"a": true}, RunOutput: nil, Output: map[string]interface{}{"a": nil}}, + {Script: `var a = true`, Input: map[string]interface{}{"a": nil}, RunOutput: true, Output: map[string]interface{}{"a": true}}, + {Script: `var a = 2`, Input: map[string]interface{}{"a": int32(1)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `var a = 2`, Input: map[string]interface{}{"a": int64(1)}, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `var a = 2.2`, Input: map[string]interface{}{"a": float32(1.1)}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": float64(2.2)}}, + {Script: `var a = 2.2`, Input: map[string]interface{}{"a": float64(1.1)}, RunOutput: float64(2.2), Output: map[string]interface{}{"a": float64(2.2)}}, + {Script: `var a = "b"`, Input: map[string]interface{}{"a": "a"}, RunOutput: "b", Output: map[string]interface{}{"a": "b"}}, + + // Go variable copy + {Script: `a = b`, Input: testInput1, RunOutput: testInput1["b"], Output: map[string]interface{}{"a": testInput1["b"], "b": testInput1["b"]}}, + {Script: `var a = b`, Input: testInput1, RunOutput: testInput1["b"], Output: map[string]interface{}{"a": testInput1["b"], "b": testInput1["b"]}}, + + {Script: `a = b`, Input: map[string]interface{}{"b": testVarValue}, RunOutput: testVarValue, Output: map[string]interface{}{"a": testVarValue, "b": testVarValue}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarBoolP}, RunOutput: testVarBoolP, Output: map[string]interface{}{"a": testVarBoolP, "b": testVarBoolP}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarInt32P}, RunOutput: testVarInt32P, Output: map[string]interface{}{"a": testVarInt32P, "b": testVarInt32P}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarInt64P}, RunOutput: testVarInt64P, Output: map[string]interface{}{"a": testVarInt64P, "b": testVarInt64P}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarFloat32P}, RunOutput: testVarFloat32P, Output: map[string]interface{}{"a": testVarFloat32P, "b": testVarFloat32P}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarFloat64P}, RunOutput: testVarFloat64P, Output: map[string]interface{}{"a": testVarFloat64P, "b": testVarFloat64P}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarStringP}, RunOutput: testVarStringP, Output: map[string]interface{}{"a": testVarStringP, "b": testVarStringP}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarFuncP}, RunOutput: testVarFuncP, Output: map[string]interface{}{"a": testVarFuncP, "b": testVarFuncP}}, + + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarValue}, RunOutput: testVarValue, Output: map[string]interface{}{"a": testVarValue, "b": testVarValue}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarBoolP}, RunOutput: testVarBoolP, Output: map[string]interface{}{"a": testVarBoolP, "b": testVarBoolP}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarInt32P}, RunOutput: testVarInt32P, Output: map[string]interface{}{"a": testVarInt32P, "b": testVarInt32P}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarInt64P}, RunOutput: testVarInt64P, Output: map[string]interface{}{"a": testVarInt64P, "b": testVarInt64P}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarFloat32P}, RunOutput: testVarFloat32P, Output: map[string]interface{}{"a": testVarFloat32P, "b": testVarFloat32P}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarFloat64P}, RunOutput: testVarFloat64P, Output: map[string]interface{}{"a": testVarFloat64P, "b": testVarFloat64P}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarStringP}, RunOutput: testVarStringP, Output: map[string]interface{}{"a": testVarStringP, "b": testVarStringP}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarFuncP}, RunOutput: testVarFuncP, Output: map[string]interface{}{"a": testVarFuncP, "b": testVarFuncP}}, + + {Script: `a = b`, Input: map[string]interface{}{"b": testVarValueBool}, RunOutput: testVarValueBool, Output: map[string]interface{}{"a": testVarValueBool, "b": testVarValueBool}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarValueInt32}, RunOutput: testVarValueInt32, Output: map[string]interface{}{"a": testVarValueInt32, "b": testVarValueInt32}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarValueInt64}, RunOutput: testVarValueInt64, Output: map[string]interface{}{"a": testVarValueInt64, "b": testVarValueInt64}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarValueFloat32}, RunOutput: testVarValueFloat32, Output: map[string]interface{}{"a": testVarValueFloat32, "b": testVarValueFloat32}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarValueFloat64}, RunOutput: testVarValueFloat64, Output: map[string]interface{}{"a": testVarValueFloat64, "b": testVarValueFloat64}}, + {Script: `a = b`, Input: map[string]interface{}{"b": testVarValueString}, RunOutput: testVarValueString, Output: map[string]interface{}{"a": testVarValueString, "b": testVarValueString}}, + + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarValueBool}, RunOutput: testVarValueBool, Output: map[string]interface{}{"a": testVarValueBool, "b": testVarValueBool}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarValueInt32}, RunOutput: testVarValueInt32, Output: map[string]interface{}{"a": testVarValueInt32, "b": testVarValueInt32}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarValueInt64}, RunOutput: testVarValueInt64, Output: map[string]interface{}{"a": testVarValueInt64, "b": testVarValueInt64}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarValueFloat32}, RunOutput: testVarValueFloat32, Output: map[string]interface{}{"a": testVarValueFloat32, "b": testVarValueFloat32}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarValueFloat64}, RunOutput: testVarValueFloat64, Output: map[string]interface{}{"a": testVarValueFloat64, "b": testVarValueFloat64}}, + {Script: `var a = b`, Input: map[string]interface{}{"b": testVarValueString}, RunOutput: testVarValueString, Output: map[string]interface{}{"a": testVarValueString, "b": testVarValueString}}, + + // one variable spacing + {Script: ` +a = 1 +`, RunOutput: int64(1)}, + {Script: ` +a = 1; +`, RunOutput: int64(1)}, + + // one variable many values + {Script: `, b = 1, 2`, ParseError: fmt.Errorf("syntax error: unexpected ','"), RunOutput: int64(2), Output: map[string]interface{}{"b": int64(1)}}, + {Script: `var , b = 1, 2`, ParseError: fmt.Errorf("syntax error: unexpected ','"), RunOutput: int64(2), Output: map[string]interface{}{"b": int64(1)}}, + {Script: `a, = 1, 2`, ParseError: fmt.Errorf("syntax error")}, + {Script: `var a, = 1, 2`, ParseError: fmt.Errorf("syntax error")}, + + // TOFIX: should not error? + {Script: `a = 1, 2`, ParseError: fmt.Errorf("syntax error")}, + {Script: `var a = 1, 2`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1)}}, + // TOFIX: should not error? + {Script: `a = 1, 2, 3`, ParseError: fmt.Errorf("syntax error")}, + {Script: `var a = 1, 2, 3`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(1)}}, + + // two variables many values + {Script: `a, b = 1,`, ParseError: fmt.Errorf("syntax error")}, + {Script: `var a, b = 1,`, ParseError: fmt.Errorf("syntax error")}, + {Script: `a, b = ,1`, ParseError: fmt.Errorf("syntax error: unexpected ','"), RunOutput: int64(1)}, + {Script: `var a, b = ,1`, ParseError: fmt.Errorf("syntax error: unexpected ','"), RunOutput: int64(1)}, + {Script: `a, b = 1,,`, ParseError: fmt.Errorf("syntax error")}, + {Script: `var a, b = 1,,`, ParseError: fmt.Errorf("syntax error")}, + {Script: `a, b = ,1,`, ParseError: fmt.Errorf("syntax error")}, + {Script: `var a, b = ,1,`, ParseError: fmt.Errorf("syntax error")}, + {Script: `a, b = ,,1`, ParseError: fmt.Errorf("syntax error")}, + {Script: `var a, b = ,,1`, ParseError: fmt.Errorf("syntax error")}, + + {Script: `a.c, b = 1, 2`, RunError: fmt.Errorf("undefined symbol 'a'")}, + {Script: `a, b.c = 1, 2`, RunError: fmt.Errorf("undefined symbol 'b'")}, + + {Script: `a, b = 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `var a, b = 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a, b = 1, 2`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + {Script: `var a, b = 1, 2`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + {Script: `a, b = 1, 2, 3`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + {Script: `var a, b = 1, 2, 3`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + + // three variables many values + {Script: `a, b, c = 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `var a, b, c = 1`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a, b, c = 1, 2`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + {Script: `var a, b, c = 1, 2`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + {Script: `a, b, c = 1, 2, 3`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(1), "b": int64(2), "c": int64(3)}}, + {Script: `var a, b, c = 1, 2, 3`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(1), "b": int64(2), "c": int64(3)}}, + {Script: `a, b, c = 1, 2, 3, 4`, RunOutput: int64(4), Output: map[string]interface{}{"a": int64(1), "b": int64(2), "c": int64(3)}}, + {Script: `var a, b, c = 1, 2, 3, 4`, RunOutput: int64(4), Output: map[string]interface{}{"a": int64(1), "b": int64(2), "c": int64(3)}}, + + // scope + {Script: `func(){ a = 1 }(); a`, RunError: fmt.Errorf("undefined symbol 'a'")}, + {Script: `func(){ var a = 1 }(); a`, RunError: fmt.Errorf("undefined symbol 'a'")}, + + {Script: `a = 1; func(){ a = 2 }()`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `var a = 1; func(){ a = 2 }()`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + {Script: `a = 1; func(){ var a = 2 }()`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `var a = 1; func(){ var a = 2 }()`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1)}}, + + // function return + {Script: `a, 1++ = func(){ return 1, 2 }()`, RunError: fmt.Errorf("invalid operation"), Output: map[string]interface{}{"a": int64(1)}}, + + {Script: `a = func(){ return 1 }()`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `var a = func(){ return 1 }()`, RunOutput: int64(1), Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a, b = func(){ return 1, 2 }()`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + {Script: `var a, b = func(){ return 1, 2 }()`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(1), "b": int64(2)}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestModule(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `module a.b { }`, ParseError: fmt.Errorf("syntax error")}, + {Script: `module a { 1++ }`, RunError: fmt.Errorf("invalid operation")}, + {Script: `module a { }; a.b`, RunError: fmt.Errorf("undefined symbol 'b'")}, + + {Script: `module a { b = 1 }`, RunOutput: nil}, + + {Script: `module a { b = nil }; a.b`, RunOutput: nil}, + {Script: `module a { b = true }; a.b`, RunOutput: true}, + {Script: `module a { b = 1 }; a.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1.5 }; a.b`, RunOutput: float64(1.5)}, + {Script: `module a { b = "a" }; a.b`, RunOutput: "a"}, + {Script: `module a { func b() { return "b"} }; a.b()`, RunOutput: "b"}, + + {Script: `module a { _b = "b"; func c() { return _b} }`, RunOutput: nil}, + {Script: `module a { _b = "b"; func c() { return _b} }; a.c()`, RunOutput: "b"}, + + {Script: `module a { b = 1 }; var c = a; c.b = 2; c.b`, RunOutput: int64(2)}, + + // test module copy + {Script: `module a { b = 1 }; c = a; d = a; a.b = 2; a.b`, RunOutput: int64(2)}, + {Script: `module a { b = 1 }; c = a; d = a; a.b = 2; c.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; c = a; d = a; a.b = 2; d.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; c = a; d = a; c.b = 2; a.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; c = a; d = a; c.b = 2; c.b`, RunOutput: int64(2)}, + {Script: `module a { b = 1 }; c = a; d = a; c.b = 2; d.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; c = a; d = a; d.b = 2; a.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; c = a; d = a; d.b = 2; c.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; c = a; d = a; d.b = 2; d.b`, RunOutput: int64(2)}, + + {Script: `module a { b = 1 }; var c = a; var d = a; a.b = 2; a.b`, RunOutput: int64(2)}, + {Script: `module a { b = 1 }; var c = a; var d = a; a.b = 2; c.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; var c = a; var d = a; a.b = 2; d.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; var c = a; var d = a; c.b = 2; a.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; var c = a; var d = a; c.b = 2; c.b`, RunOutput: int64(2)}, + {Script: `module a { b = 1 }; var c = a; var d = a; c.b = 2; d.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; var c = a; var d = a; d.b = 2; a.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; var c = a; var d = a; d.b = 2; c.b`, RunOutput: int64(1)}, + {Script: `module a { b = 1 }; var c = a; var d = a; d.b = 2; d.b`, RunOutput: int64(2)}, + + // test type scope + {Script: `module b { make(type Duration, a) }; func c() { d = new(time.Duration); return *d }; c()`, Input: map[string]interface{}{"a": time.Duration(0)}, RunError: fmt.Errorf("no namespace called: time")}, + {Script: `module time { make(type Duration, a) }; func c() { d = new(time.Duration); return *d }; c()`, Input: map[string]interface{}{"a": time.Duration(0)}, RunOutput: time.Duration(0)}, + {Script: `module x { module time { make(type Duration, a) } }; func c() { d = new(x.time.Duration); return *d }; c()`, Input: map[string]interface{}{"a": time.Duration(0)}, RunOutput: time.Duration(0)}, + {Script: `module x { module time { make(type Duration, a) } }; func c() { d = new(y.time.Duration); return *d }; c()`, Input: map[string]interface{}{"a": time.Duration(0)}, RunError: fmt.Errorf("no namespace called: y")}, + {Script: `module x { module time { make(type Duration, a) } }; func c() { d = new(x.y.Duration); return *d }; c()`, Input: map[string]interface{}{"a": time.Duration(0)}, RunError: fmt.Errorf("no namespace called: y")}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestNew(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `new(foo)`, RunError: fmt.Errorf("undefined type 'foo'")}, + {Script: `new(nilT)`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + + // default + {Script: `a = new(bool); *a`, RunOutput: false}, + {Script: `a = new(int32); *a`, RunOutput: int32(0)}, + {Script: `a = new(int64); *a`, RunOutput: int64(0)}, + {Script: `a = new(float32); *a`, RunOutput: float32(0)}, + {Script: `a = new(float64); *a`, RunOutput: float64(0)}, + {Script: `a = new(string); *a`, RunOutput: ""}, + + // ptr + {Script: `a = new(*string); b = *a; *b`, RunOutput: ""}, + {Script: `a = new(*string); **a`, RunOutput: ""}, + + // slice + {Script: `a = new([]int64); *a`, RunOutput: []int64{}}, + + // map + {Script: `a = new(map[string]int64); *a`, RunOutput: map[string]int64{}}, + + // chan + {Script: `a = new(chan int64); go func(){ (*a) <- 1 }(); <- *a`, RunOutput: int64(1)}, + {Script: `a = new(chan int64); go func(){ *a <- 1 }(); <- *a`, RunOutput: int64(1)}, + + // struct + {Script: `a = new(struct{ A int64 }); *a`, RunOutput: struct{ A int64 }{}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestMake(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `make(map[[]string]int64)`, RunError: fmt.Errorf("reflect.MapOf: invalid key type []string")}, + } + runTests(t, tests, nil, &Options{Debug: false}) + + tests = []Test{ + {Script: `make(struct {})`, ParseError: fmt.Errorf("syntax error")}, + {Script: `make(struct { , })`, ParseError: fmt.Errorf("syntax error")}, + {Script: `make(struct { A map })`, ParseError: fmt.Errorf("syntax error")}, + {Script: `make(struct { , A int64})`, ParseError: fmt.Errorf("syntax error")}, + {Script: `make(struct { A int64, })`, ParseError: fmt.Errorf("syntax error")}, + + {Script: `make(foo)`, RunError: fmt.Errorf("undefined type 'foo'")}, + {Script: `make(a.b)`, Types: map[string]interface{}{"a": true}, RunError: fmt.Errorf("no namespace called: a")}, + {Script: `make(a.b)`, Types: map[string]interface{}{"b": true}, RunError: fmt.Errorf("no namespace called: a")}, + {Script: `make([]int64, 1++)`, RunError: fmt.Errorf("invalid operation")}, + {Script: `make([]int64, 1, 1++)`, RunError: fmt.Errorf("invalid operation")}, + {Script: `make([]int64, 2, 1)`, RunError: fmt.Errorf("make slice len > cap")}, + {Script: `make(map[foo]int64)`, RunError: fmt.Errorf("undefined type 'foo'")}, + {Script: `make(map[int64]foo)`, RunError: fmt.Errorf("undefined type 'foo'")}, + {Script: `make(chan foo)`, RunError: fmt.Errorf("undefined type 'foo'")}, + {Script: `make(chan int64, 1++)`, RunError: fmt.Errorf("invalid operation")}, + {Script: `make(struct { A foo })`, RunError: fmt.Errorf("undefined type 'foo'")}, + + // nill type + {Script: `make(nilT)`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `make(*nilT)`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `make([]nilT)`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `make(map[nilT]string)`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `make(map[string]nilT)`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `make(chan nilT)`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + {Script: `make(struct { A nilT })`, Types: map[string]interface{}{"nilT": nil}, RunError: fmt.Errorf("cannot make type nil")}, + + // default + {Script: `make(bool)`, RunOutput: false}, + {Script: `make(int32)`, RunOutput: int32(0)}, + {Script: `make(int64)`, RunOutput: int64(0)}, + {Script: `make(float32)`, RunOutput: float32(0)}, + {Script: `make(float64)`, RunOutput: float64(0)}, + {Script: `make(string)`, RunOutput: ""}, + + // ptr + {Script: `a = make(*int64); *a`, RunOutput: int64(0)}, + {Script: `a = make(**int64); **a`, RunOutput: int64(0)}, + {Script: `a = make(***int64); ***a`, RunOutput: int64(0)}, + {Script: `a = make(*[]int64); *a`, RunOutput: []int64{}}, + {Script: `a = make(*map[string]int64); *a`, RunOutput: map[string]int64{}}, + {Script: `a = make(*chan int64); go func(){ (*a) <- 1 }(); <- *a`, RunOutput: int64(1)}, + {Script: `a = make(*chan int64); go func(){ *a <- 1 }(); <- *a`, RunOutput: int64(1)}, + + // slice + {Script: `make([]int64)`, RunOutput: []int64{}}, + {Script: `a = make([]int64, 1); a[0]`, RunOutput: int64(0)}, + {Script: `a = make([]int64, 1, 2); a[0]`, RunOutput: int64(0)}, + {Script: `make([]*int64)`, RunOutput: []*int64{}}, + {Script: `make([][]int64)`, RunOutput: [][]int64{}}, + {Script: `make([]map[string]int64)`, RunOutput: []map[string]int64{}}, + + // map + {Script: `make(map[string]int64)`, RunOutput: map[string]int64{}}, + {Script: `make(map[string]*int64)`, RunOutput: map[string]*int64{}}, + {Script: `make(map[*string]int64)`, RunOutput: map[*string]int64{}}, + {Script: `make(map[*string]*int64)`, RunOutput: map[*string]*int64{}}, + {Script: `make(map[string][]int64)`, RunOutput: map[string][]int64{}}, + {Script: `make(map[string]chan int64)`, RunOutput: map[string]chan int64{}}, + {Script: `make(map[chan string]int64)`, RunOutput: map[chan string]int64{}}, + + // chan + {Script: `a = make(chan int64); go func(){ a <- 1 }(); <- a`, RunOutput: int64(1)}, + {Script: `a = make(chan int64, 1); a <- 1; <- a`, RunOutput: int64(1)}, + {Script: `a = make(chan *int64, 1); b = 1; a <- &b; c = <- a; *c`, RunOutput: int64(1)}, + {Script: `a = make(chan []int64, 1); a <- [1]; <- a`, RunOutput: []int64{1}}, + {Script: `a = make(chan map[string]int64, 1); b = make(map[string]int64); a <- b; <- a`, RunOutput: map[string]int64{}}, + {Script: `a = make(chan int64, 1); b = &a; *b <- 1; <- *b`, RunOutput: int64(1)}, + + // struct + {Script: `make(struct { A int64 })`, RunOutput: struct{ A int64 }{}}, + {Script: `make(struct { A *int64 })`, RunOutput: struct{ A *int64 }{}}, + {Script: `make(struct { A []int64 })`, RunOutput: struct{ A []int64 }{A: []int64{}}}, + {Script: `make(struct { A map[string]int64 })`, RunOutput: struct{ A map[string]int64 }{A: map[string]int64{}}}, + {Script: `a = make(struct { A chan int64 }); go func(){ a.A <- 1 }(); <- a.A`, RunOutput: int64(1)}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestMakeType(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `make(type a, 1++)`, RunError: fmt.Errorf("invalid operation")}, + + {Script: `make(type a, true)`, RunOutput: reflect.TypeOf(true)}, + {Script: `a = make(type a, true)`, RunOutput: reflect.TypeOf(true), Output: map[string]interface{}{"a": reflect.TypeOf(true)}}, + {Script: `make(type a, true); a = make([]a)`, RunOutput: []bool{}, Output: map[string]interface{}{"a": []bool{}}}, + {Script: `make(type a, make([]bool))`, RunOutput: reflect.TypeOf([]bool{})}, + {Script: `make(type a, make([]bool)); a = make(a)`, RunOutput: []bool{}, Output: map[string]interface{}{"a": []bool{}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestReferencingAndDereference(t *testing.T) { + t.Parallel() + + tests := []Test{ + // TOFIX: + // {Script: `a = 1; b = &a; *b = 2; *b`, RunOutput: int64(2), Output: map[string]interface{}{"a": int64(2)}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestChan(t *testing.T) { + t.Parallel() + + tests := []Test{ + // send on closed channel + {Script: `a = make(chan int64, 2); close(a); a <- 1`, RunError: fmt.Errorf("send on closed channel")}, + } + runTests(t, tests, nil, &Options{Debug: false}) + + tests = []Test{ + {Script: `a = make(chan int64, 2); a <- 1; = <- a`, ParseError: fmt.Errorf("missing expressions on left side of channel operator"), RunError: fmt.Errorf("invalid operation")}, + + {Script: `<- 1++`, RunError: fmt.Errorf("invalid operation")}, + {Script: `1++ <- 1`, RunError: fmt.Errorf("invalid operation")}, + {Script: `1 <- 1++`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a = make(chan int64, 2); a <- 1++`, RunError: fmt.Errorf("invalid operation")}, + {Script: `<- 1`, RunError: fmt.Errorf("receive from non-chan type int64")}, + {Script: `1 <- 1`, RunError: fmt.Errorf("send to non-chan type int64")}, + {Script: `a = make(chan int64, 2); 1 <- a`, RunError: fmt.Errorf("send to non-chan type int64")}, + {Script: `a = make(chan bool, 2); a <- 1`, RunError: fmt.Errorf("cannot use type int64 as type bool to send to chan")}, + {Script: `close(1++)`, RunError: fmt.Errorf("invalid operation")}, + {Script: `close(1)`, RunError: fmt.Errorf("type cannot be int64 for close")}, + + // let channel errors + {Script: `a = <- c`, RunError: fmt.Errorf("undefined symbol 'c'")}, + {Script: `a, b = <- c`, RunError: fmt.Errorf("undefined symbol 'c'")}, + {Script: `a = <- 1++`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a, b = <- 1++`, RunError: fmt.Errorf("invalid operation")}, + {Script: `c = 1; a = <- c`, RunError: fmt.Errorf("receive from non-chan type int64")}, + {Script: `c = 1; a, b = <- c`, RunError: fmt.Errorf("receive from non-chan type int64")}, + {Script: `a = make(chan int64, 2); a <- 1; 1++ = <- a`, RunError: fmt.Errorf("invalid operation")}, + {Script: `a = make(chan int64, 2); a <- 1; 1++, b = <- a`, RunError: fmt.Errorf("invalid operation")}, + + // send to channel + {Script: `a <- nil`, Input: map[string]interface{}{"a": make(chan interface{}, 2)}}, + {Script: `a <- true`, Input: map[string]interface{}{"a": make(chan bool, 2)}}, + {Script: `a <- 1`, Input: map[string]interface{}{"a": make(chan int32, 2)}}, + {Script: `a <- 2`, Input: map[string]interface{}{"a": make(chan int64, 2)}}, + {Script: `a <- 1.5`, Input: map[string]interface{}{"a": make(chan float32, 2)}}, + {Script: `a <- 2.5`, Input: map[string]interface{}{"a": make(chan float64, 2)}}, + {Script: `a <- "b"`, Input: map[string]interface{}{"a": make(chan string, 2)}}, + + {Script: `a = make(chan interface, 2); a <- nil`}, + {Script: `a = make(chan bool, 2); a <- true`}, + {Script: `a = make(chan int32, 2); a <- 1`}, + {Script: `a = make(chan int64, 2); a <- 2`}, + {Script: `a = make(chan float32, 2); a <- 1.5`}, + {Script: `a = make(chan float64, 2); a <- 2.5`}, + {Script: `a = make(chan string, 2); a <- "b"`}, + + // send to channel then receive from channel + {Script: `a <- nil; <- a`, Input: map[string]interface{}{"a": make(chan interface{}, 2)}, RunOutput: nil}, + {Script: `a <- true; <- a`, Input: map[string]interface{}{"a": make(chan bool, 2)}, RunOutput: true}, + {Script: `a <- 1; <- a`, Input: map[string]interface{}{"a": make(chan int32, 2)}, RunOutput: int32(1)}, + {Script: `a <- 2; <- a`, Input: map[string]interface{}{"a": make(chan int64, 2)}, RunOutput: int64(2)}, + {Script: `a <- 1.5; <- a`, Input: map[string]interface{}{"a": make(chan float32, 2)}, RunOutput: float32(1.5)}, + {Script: `a <- 2.5; <- a`, Input: map[string]interface{}{"a": make(chan float64, 2)}, RunOutput: float64(2.5)}, + {Script: `a <- "b"; <- a`, Input: map[string]interface{}{"a": make(chan string, 2)}, RunOutput: "b"}, + + {Script: `a = make(chan interface, 2); a <- nil; <- a`, RunOutput: nil}, + {Script: `a = make(chan bool, 2); a <- true; <- a`, RunOutput: true}, + {Script: `a = make(chan int32, 2); a <- 1; <- a`, RunOutput: int32(1)}, + {Script: `a = make(chan int64, 2); a <- 2; <- a`, RunOutput: int64(2)}, + {Script: `a = make(chan float32, 2); a <- 1.5; <- a`, RunOutput: float32(1.5)}, + {Script: `a = make(chan float64, 2); a <- 2.5; <- a`, RunOutput: float64(2.5)}, + {Script: `a = make(chan string, 2); a <- "b"; <- a`, RunOutput: "b"}, + + // send to channel, receive from channel, then assign to variable + {Script: `a <- nil; b = <- a`, Input: map[string]interface{}{"a": make(chan interface{}, 2)}, RunOutput: nil, Output: map[string]interface{}{"b": nil}}, + {Script: `a <- true; b = <- a`, Input: map[string]interface{}{"a": make(chan bool, 2)}, RunOutput: true, Output: map[string]interface{}{"b": true}}, + {Script: `a <- 1; b = <- a`, Input: map[string]interface{}{"a": make(chan int32, 2)}, RunOutput: int32(1), Output: map[string]interface{}{"b": int32(1)}}, + {Script: `a <- 2; b = <- a`, Input: map[string]interface{}{"a": make(chan int64, 2)}, RunOutput: int64(2), Output: map[string]interface{}{"b": int64(2)}}, + {Script: `a <- 1.5; b = <- a`, Input: map[string]interface{}{"a": make(chan float32, 2)}, RunOutput: float32(1.5), Output: map[string]interface{}{"b": float32(1.5)}}, + {Script: `a <- 2.5; b = <- a`, Input: map[string]interface{}{"a": make(chan float64, 2)}, RunOutput: float64(2.5), Output: map[string]interface{}{"b": float64(2.5)}}, + {Script: `a <- "b"; b = <- a`, Input: map[string]interface{}{"a": make(chan string, 2)}, RunOutput: "b", Output: map[string]interface{}{"b": "b"}}, + + {Script: `a = make(chan interface, 2); a <- nil; b = <- a`, RunOutput: nil, Output: map[string]interface{}{"b": nil}}, + {Script: `a = make(chan bool, 2); a <- true; b = <- a`, RunOutput: true, Output: map[string]interface{}{"b": true}}, + {Script: `a = make(chan int32, 2); a <- 1; b = <- a`, RunOutput: int32(1), Output: map[string]interface{}{"b": int32(1)}}, + {Script: `a = make(chan int64, 2); a <- 2; b = <- a`, RunOutput: int64(2), Output: map[string]interface{}{"b": int64(2)}}, + {Script: `a = make(chan float32, 2); a <- 1.5; b = <- a`, RunOutput: float32(1.5), Output: map[string]interface{}{"b": float32(1.5)}}, + {Script: `a = make(chan float64, 2); a <- 2.5; b = <- a`, RunOutput: float64(2.5), Output: map[string]interface{}{"b": float64(2.5)}}, + {Script: `a = make(chan string, 2); a <- "b"; b = <- a`, RunOutput: "b", Output: map[string]interface{}{"b": "b"}}, + + // receive from closed channel + {Script: `a = make(chan int64, 2); a <- 1; close(a); <- a`, RunOutput: int64(1)}, + {Script: `a = make(chan int64, 2); a <- 1; close(a); <- a; <- a`, RunOutput: nil}, + + // receive & send from same channel + {Script: `a = make(chan int64, 2); a <- 1; a <- <- a`, RunOutput: nil}, + {Script: `a = make(chan int64, 2); a <- 1; a <- <- a; <- a`, RunOutput: int64(1)}, + {Script: `a = make(chan int64, 2); a <- 1; a <- <- a; b = <- a`, RunOutput: int64(1), Output: map[string]interface{}{"b": int64(1)}}, + {Script: `a = make(chan int64, 2); a <- 1; a <- (<- a)`, RunOutput: nil}, + {Script: `a = make(chan int64, 2); a <- 1; a <- (<- a); <- a`, RunOutput: int64(1)}, + {Script: `a = make(chan int64, 2); a <- 1; a <- (<- a); b = <- a`, RunOutput: int64(1), Output: map[string]interface{}{"b": int64(1)}}, + + // 1 then null into a + {Script: `a = make(chan int64, 2); a <- a <- 1`, RunOutput: nil}, + {Script: `a = make(chan int64, 2); a <- a <- 1; <- a`, RunOutput: int64(1)}, + {Script: `a = make(chan int64, 2); a <- a <- 1; <- a; <- a`, RunOutput: int64(0)}, + + // receive & send different channel + {Script: `a = make(chan int64, 2); b = make(chan int64, 2); a <- 1; b <- <- a`, RunOutput: nil}, + {Script: `a = make(chan int64, 2); b = make(chan int64, 2); a <- 1; b <- <- a; <- b`, RunOutput: int64(1)}, + {Script: `a = make(chan int64, 2); b = make(chan int64, 2); a <- 1; b <- <- a; c = <- b`, RunOutput: int64(1), Output: map[string]interface{}{"c": int64(1)}}, + {Script: `a = make(chan int64, 2); b = make(chan int64, 2); a <- 1; b <- (<- a)`, RunOutput: nil}, + {Script: `a = make(chan int64, 2); b = make(chan int64, 2); a <- 1; b <- (<- a); <- b`, RunOutput: int64(1)}, + {Script: `a = make(chan int64, 2); b = make(chan int64, 2); a <- 1; b <- (<- a); c = <- b`, RunOutput: int64(1), Output: map[string]interface{}{"c": int64(1)}}, + + // 1 into a then null into b + {Script: `a = make(chan int64, 2); b = make(chan int64, 2); b <- a <- 1`, RunOutput: nil}, + {Script: `a = make(chan int64, 2); b = make(chan int64, 2); b <- a <- 1; <- a`, RunOutput: int64(1)}, + {Script: `a = make(chan int64, 2); b = make(chan int64, 2); b <- a <- 1; <- a; <- b`, RunOutput: int64(0)}, + + // test ok + {Script: `a = make(chan int64, 2); a <- 1; b, ok = <- a`, RunOutput: int64(1), Output: map[string]interface{}{"b": int64(1), "ok": true}}, + {Script: `a = make(chan int64, 2); a <- 1; b, 1++ = <- a`, RunOutput: int64(1), Output: map[string]interface{}{"b": int64(1)}}, + {Script: `a = make(chan int64, 2); a <- 1; close(a); b, ok = <- a`, RunOutput: int64(1), Output: map[string]interface{}{"b": int64(1), "ok": true}}, + {Script: `a = make(chan int64, 2); a <- 1; close(a); b = <- a; b, ok = <- a`, RunOutput: nil, Output: map[string]interface{}{"b": int64(1), "ok": false}}, + + // test let ++ + {Script: `a = make(chan int64, 2); b = [1, 2, 3, 4]; c = 0; a <- 11; b[c++] = <- a; b[1]`, RunOutput: int64(11)}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestVMDelete(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `delete(1++)`, RunError: fmt.Errorf("invalid operation")}, + {Script: `delete(1)`, RunError: fmt.Errorf("first argument to delete cannot be type int64")}, + {Script: `a = 1; delete("a"); a`, RunError: fmt.Errorf("undefined symbol 'a'")}, + {Script: `a = {"b": "b"}; delete(a)`, RunError: fmt.Errorf("second argument to delete cannot be nil for map")}, + + {Script: `delete("a", 1++)`, RunError: fmt.Errorf("invalid operation")}, + {Script: `b = []; delete(a, b)`, Input: map[string]interface{}{"a": map[int32]interface{}{2: int32(2)}}, RunError: fmt.Errorf("cannot use type int32 as type []interface {} in delete"), Output: map[string]interface{}{"a": map[int32]interface{}{2: int32(2)}}}, + + // test no variable + {Script: `delete("a")`}, + {Script: `delete("a", false)`}, + {Script: `delete("a", true)`}, + {Script: `delete("a", nil)`}, + + // test DeleteGlobal + {Script: `a = 1; func b() { delete("a") }; b()`, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; func b() { delete("a", false) }; b()`, Output: map[string]interface{}{"a": int64(1)}}, + {Script: `a = 1; func b() { delete("a", true) }; b(); a`, RunError: fmt.Errorf("undefined symbol 'a'")}, + {Script: `a = 2; func b() { a = 3; delete("a"); return a }; b()`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 2; func b() { a = 3; delete("a", false); return a }; b()`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 2; func b() { a = 3; delete("a", true); return a }; b()`, RunError: fmt.Errorf("undefined symbol 'a'")}, + {Script: `a = 2; func b() { a = 3; delete("a") }; b(); a`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 2; func b() { a = 3; delete("a", false) }; b(); a`, RunOutput: int64(3), Output: map[string]interface{}{"a": int64(3)}}, + {Script: `a = 2; func b() { a = 3; delete("a", true) }; b(); a`, RunError: fmt.Errorf("undefined symbol 'a'")}, + + // test empty map + {Script: `delete(a, "a")`, Input: map[string]interface{}{"a": testMapEmpty}, Output: map[string]interface{}{"a": testMapEmpty}}, + + // test map + {Script: `a = {"b": "b"}; delete(a, "b")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = {"b": "b"}; delete(a, "b"); a.b`, Output: map[string]interface{}{"a": map[interface{}]interface{}{}}}, + {Script: `a = {"b": "b", "c":"c"}; delete(a, "b")`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"c": "c"}}}, + {Script: `a = {"b": "b", "c":"c"}; delete(a, "b"); a.b`, Output: map[string]interface{}{"a": map[interface{}]interface{}{"c": "c"}}}, + + // test key convert + {Script: `delete(a, 2)`, Input: map[string]interface{}{"a": map[int32]interface{}{2: int32(2)}}, Output: map[string]interface{}{"a": map[int32]interface{}{}}}, + {Script: `delete(a, 2); a[2]`, Input: map[string]interface{}{"a": map[int32]interface{}{2: int32(2)}}, Output: map[string]interface{}{"a": map[int32]interface{}{}}}, + {Script: `delete(a, 2)`, Input: map[string]interface{}{"a": map[int32]interface{}{2: int32(2), 3: int32(3)}}, Output: map[string]interface{}{"a": map[int32]interface{}{3: int32(3)}}}, + {Script: `delete(a, 2); a[2]`, Input: map[string]interface{}{"a": map[int32]interface{}{2: int32(2), 3: int32(3)}}, Output: map[string]interface{}{"a": map[int32]interface{}{3: int32(3)}}}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestComment(t *testing.T) { + t.Parallel() + + tests := []Test{ + {Script: `# 1`}, + {Script: `# 1;`}, + {Script: `# 1 // 2`}, + {Script: `# 1 \n 2`}, + {Script: `# 1 # 2`}, + + {Script: `1# 1`, RunOutput: int64(1)}, + {Script: `1# 1;`, RunOutput: int64(1)}, + {Script: `1# 1 // 2`, RunOutput: int64(1)}, + {Script: `1# 1 \n 2`, RunOutput: int64(1)}, + {Script: `1# 1 # 2`, RunOutput: int64(1)}, + + {Script: `1 +# 1`, RunOutput: int64(1)}, + {Script: `1 +# 1;`, RunOutput: int64(1)}, + {Script: `1 +# 1 // 2`, RunOutput: int64(1)}, + {Script: `1 +# 1 \n 2`, RunOutput: int64(1)}, + {Script: `1 +# 1 # 2`, RunOutput: int64(1)}, + + {Script: `// 1`}, + {Script: `// 1;`}, + {Script: `// 1 // 2`}, + {Script: `// 1 \n 2`}, + {Script: `// 1 # 2`}, + + {Script: `1// 1`, RunOutput: int64(1)}, + {Script: `1// 1;`, RunOutput: int64(1)}, + {Script: `1// 1 // 2`, RunOutput: int64(1)}, + {Script: `1// 1 \n 2`, RunOutput: int64(1)}, + {Script: `1// 1 # 2`, RunOutput: int64(1)}, + + {Script: `1 +// 1`, RunOutput: int64(1)}, + {Script: `1 +// 1;`, RunOutput: int64(1)}, + {Script: `1 +// 1 // 2`, RunOutput: int64(1)}, + {Script: `1 +// 1 \n 2`, RunOutput: int64(1)}, + {Script: `1 +// 1 # 2`, RunOutput: int64(1)}, + + {Script: `/* 1 */`}, + {Script: `/* * 1 */`}, + {Script: `/* 1 * */`}, + {Script: `/** 1 */`}, + {Script: `/*** 1 */`}, + {Script: `/**** 1 */`}, + {Script: `/* 1 **/`}, + {Script: `/* 1 ***/`}, + {Script: `/* 1 ****/`}, + {Script: `/** 1 ****/`}, + {Script: `/*** 1 ****/`}, + {Script: `/**** 1 ****/`}, + + {Script: `1/* 1 */`, RunOutput: int64(1)}, + {Script: `1/* * 1 */`, RunOutput: int64(1)}, + {Script: `1/* 1 * */`, RunOutput: int64(1)}, + {Script: `1/** 1 */`, RunOutput: int64(1)}, + {Script: `1/*** 1 */`, RunOutput: int64(1)}, + {Script: `1/**** 1 */`, RunOutput: int64(1)}, + {Script: `1/* 1 **/`, RunOutput: int64(1)}, + {Script: `1/* 1 ***/`, RunOutput: int64(1)}, + {Script: `1/* 1 ****/`, RunOutput: int64(1)}, + {Script: `1/** 1 ****/`, RunOutput: int64(1)}, + {Script: `1/*** 1 ****/`, RunOutput: int64(1)}, + {Script: `1/**** 1 ****/`, RunOutput: int64(1)}, + + {Script: `/* 1 */1`, RunOutput: int64(1)}, + {Script: `/* * 1 */1`, RunOutput: int64(1)}, + {Script: `/* 1 * */1`, RunOutput: int64(1)}, + {Script: `/** 1 */1`, RunOutput: int64(1)}, + {Script: `/*** 1 */1`, RunOutput: int64(1)}, + {Script: `/**** 1 */1`, RunOutput: int64(1)}, + {Script: `/* 1 **/1`, RunOutput: int64(1)}, + {Script: `/* 1 ***/1`, RunOutput: int64(1)}, + {Script: `/* 1 ****/1`, RunOutput: int64(1)}, + {Script: `/** 1 ****/1`, RunOutput: int64(1)}, + {Script: `/*** 1 ****/1`, RunOutput: int64(1)}, + {Script: `/**** 1 ****/1`, RunOutput: int64(1)}, + + {Script: `1 +/* 1 */`, RunOutput: int64(1)}, + {Script: `1 +/* * 1 */`, RunOutput: int64(1)}, + {Script: `1 +/* 1 * */`, RunOutput: int64(1)}, + {Script: `1 +/** 1 */`, RunOutput: int64(1)}, + {Script: `1 +/*** 1 */`, RunOutput: int64(1)}, + {Script: `1 +/**** 1 */`, RunOutput: int64(1)}, + {Script: `1 +/* 1 **/`, RunOutput: int64(1)}, + {Script: `1 +/* 1 ***/`, RunOutput: int64(1)}, + {Script: `1 +/* 1 ****/`, RunOutput: int64(1)}, + {Script: `1 +/** 1 ****/`, RunOutput: int64(1)}, + {Script: `1 +/*** 1 ****/`, RunOutput: int64(1)}, + {Script: `1 +/**** 1 ****/`, RunOutput: int64(1)}, + } + runTests(t, tests, nil, &Options{Debug: true}) +} + +func TestCancelWithContext(t *testing.T) { + scripts := []string{ + ` +b = 0 +close(waitChan) +for { + b = 1 +} +`, + ` +b = 0 +close(waitChan) +for { + for { + b = 1 + } +} +`, + ` +a = [] +for i = 0; i < 20000; i++ { + a += 1 +} +b = 0 +close(waitChan) +for { + for i in a { + b = i + } +} +`, + ` +a = [] +for i = 0; i < 20000; i++ { + a += 1 +} +b = 0 +close(waitChan) +for i in a { + for j in a { + b = j + } +} +`, + ` +close(waitChan) +b = 0 +for i = 0; true; nil { +} +`, + ` +b = 0 +close(waitChan) +for i = 0; true; nil { + for j = 0; true; nil { + b = 1 + } +} +`, + ` +a = {} +for i = 0; i < 20000; i++ { + a[toString(i)] = 1 +} +b = 0 +close(waitChan) +for { + for i in a { + b = 1 + } +} +`, + ` +a = {} +for i = 0; i < 20000; i++ { + a[toString(i)] = 1 +} +b = 0 +close(waitChan) +for i in a { + for j in a { + b = 1 + } +} +`, + ` +close(waitChan) +<- make(chan string) +`, + ` +a = "" +close(waitChan) +a = <- make(chan string) +`, + ` +for { + a = "" + close(waitChan) + a = <- make(chan string) +} +`, + ` +a = make(chan int) +close(waitChan) +a <- 1 +`, + ` +a = make(chan interface) +close(waitChan) +a <- nil +`, + ` +a = make(chan int64, 1) +close(waitChan) +for v in a { } +`, + ` +close(waitChan) +try { + for { } +} catch { } +`, + } + for _, script := range scripts { + runCancelTestWithContext(t, script) + } +} + +func runCancelTestWithContext(t *testing.T, script string) { + waitChan := make(chan struct{}, 1) + toString := func(value interface{}) string { + return fmt.Sprintf("%v", value) + } + e := env.NewEnv() + err := e.Define("waitChan", waitChan) + if err != nil { + t.Errorf("Define error: %v", err) + } + err = e.Define("toString", toString) + if err != nil { + t.Errorf("Define error: %v", err) + } + + ctx, cancel := context.WithCancel(context.Background()) + go func() { + <-waitChan + time.Sleep(time.Millisecond) + cancel() + }() + + _, err = ExecuteContext(ctx, e, nil, script) + if err == nil || err.Error() != ErrInterrupt.Error() { + t.Errorf("execute error - received %#v - expected: %#v - script: %v", err, ErrInterrupt, script) + } +} + +func TestContextConcurrency(t *testing.T) { + var waitGroup sync.WaitGroup + e := env.NewEnv() + + ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond) + waitGroup.Add(100) + for i := 0; i < 100; i++ { + go func() { + _, err := ExecuteContext(ctx, e, nil, "for { }") + if err == nil || err.Error() != ErrInterrupt.Error() { + t.Errorf("execute error - received %#v - expected: %#v", err, ErrInterrupt) + } + waitGroup.Done() + }() + } + cancel() + waitGroup.Wait() + cancel() + + _, err := ExecuteContext(ctx, e, nil, "for { }") + if err == nil || err.Error() != ErrInterrupt.Error() { + t.Errorf("execute error - received %#v - expected: %#v", err, ErrInterrupt) + } + + ctx, cancel = context.WithCancel(context.Background()) + _, err = ExecuteContext(ctx, e, nil, "for i = 0; i < 1000; i++ {}") + if err != nil { + t.Errorf("execute error - received: %v - expected: %v", err, nil) + } + waitGroup.Add(100) + for i := 0; i < 100; i++ { + go func() { + _, err := ExecuteContext(ctx, e, nil, "for i = 0; i < 1000; i++ { }") + if err != nil { + t.Errorf("execute error - received: %v - expected: %v", err, nil) + } + waitGroup.Done() + }() + } + waitGroup.Wait() + + waitGroup.Add(100) + for i := 0; i < 100; i++ { + go func() { + _, err := ExecuteContext(ctx, e, nil, "for { }") + if err == nil || err.Error() != ErrInterrupt.Error() { + t.Errorf("execute error - received %#v - expected: %#v", err, ErrInterrupt) + } + waitGroup.Done() + }() + } + time.Sleep(time.Millisecond) + cancel() + waitGroup.Wait() + + waitGroup.Add(100) + for i := 0; i < 100; i++ { + go func() { + _, err := Execute(e, nil, "for i = 0; i < 1000; i++ { }") + if err != nil { + t.Errorf("execute error - received: %v - expected: %v", err, nil) + } + waitGroup.Done() + }() + } + waitGroup.Wait() +} + +func TestContextFunction(t *testing.T) { + t.Parallel() + + e := env.NewEnv() + script := ` + func myFunc(myVar) { + myVar = 3 + }` + envModule, err := e.NewModule("a") + if err != nil { + t.Fatal("NewModule error:", err) + } + + ctx, cancel := context.WithCancel(context.Background()) + _, err = ExecuteContext(ctx, envModule, nil, script) + if err != nil { + t.Errorf("execute error - received %#v - expected: %#v", err, nil) + } + cancel() + + script = "a.myFunc(2)" + + ctx, cancel = context.WithCancel(context.Background()) + _, err = ExecuteContext(ctx, e, nil, script) + if err != nil { + t.Errorf("execute error - received %#v - expected: %#v", err, nil) + } + cancel() +} + +func TestAssignToInterface(t *testing.T) { + t.Parallel() + + e := env.NewEnv() + X := new(struct { + Stdout io.Writer + }) + err := e.Define("X", X) + if err != nil { + t.Errorf("Define error: %v", err) + } + err = e.Define("a", new(os.File)) + if err != nil { + t.Errorf("Define error: %v", err) + } + _, err = Execute(e, nil, "X.Stdout = a") + if err != nil { + t.Errorf("execute error - received %#v - expected: %#v", err, ErrInterrupt) + } +} + +// TestValueEqual do some basic ValueEqual tests for coverage +func TestValueEqual(t *testing.T) { + t.Parallel() + + result := valueEqual(true, true) + if result != true { + t.Fatal("ValueEqual") + } + result = valueEqual(true, false) + if result != false { + t.Fatal("ValueEqual") + } + result = valueEqual(false, true) + if result != false { + t.Fatal("ValueEqual") + } +} + +// TestUnknownCases tests switch cases that are the unknown cases +func TestUnknownCases(t *testing.T) { + t.Parallel() + + oneLiteral := &ast.LiteralExpr{Literal: reflect.ValueOf(int64(1))} + type ( + BadStmt struct { + ast.StmtImpl + } + BadExpr struct { + ast.ExprImpl + } + BadOperator struct { + ast.OperatorImpl + } + ) + + stmts := []ast.Stmt{ + &BadStmt{}, + &ast.ExprStmt{Expr: &BadExpr{}}, + &ast.ExprStmt{Expr: &ast.OpExpr{Op: &BadOperator{}}}, + &ast.ExprStmt{Expr: &ast.UnaryExpr{Expr: oneLiteral}}, + &ast.ExprStmt{Expr: &ast.OpExpr{Op: &ast.BinaryOperator{LHS: oneLiteral}}}, + &ast.ExprStmt{Expr: &ast.OpExpr{Op: &ast.ComparisonOperator{LHS: oneLiteral, RHS: oneLiteral}}}, + &ast.ExprStmt{Expr: &ast.OpExpr{Op: &ast.AddOperator{LHS: oneLiteral, RHS: oneLiteral}}}, + &ast.ExprStmt{Expr: &ast.OpExpr{Op: &ast.MultiplyOperator{LHS: oneLiteral, RHS: oneLiteral}}}, + } + + for _, stmt := range stmts { + e := env.NewEnv() + _, err := Run(e, nil, stmt) + if err == nil { + t.Errorf("no error - stmt: %#v", stmt) + } else if len(err.Error()) < 9 || err.Error()[:8] != "unknown " { + t.Errorf("err: %v - stmt: %#v", err, stmt) + } + } +} + +func fib(x int) int { + if x < 2 { + return x + } + return fib(x-1) + fib(x-2) +} + +func BenchmarkFibGo(b *testing.B) { + for i := 0; i < b.N; i++ { + fib(29) + } +} + +func BenchmarkFibVM(b *testing.B) { + b.StopTimer() + + e := env.NewEnv() + a, err := e.NewModule("a") + if err != nil { + b.Fatal("NewModule error:", err) + } + + script := ` +fib = func(x) { + if x < 2 { + return x + } + return fib(x-1) + fib(x-2) +}` + + _, err = Execute(a, nil, script) + if err != nil { + b.Fatal("Execute error:", err) + } + + b.ResetTimer() + b.StartTimer() + + for i := 0; i < b.N; i++ { + _, err = Execute(e, nil, "a.fib(29)") + if err != nil { + b.Fatal("Execute error:", err) + } + } +}