diff options
Diffstat (limited to 'vendor/github.com/d5/tengo')
-rw-r--r-- | vendor/github.com/d5/tengo/v2/Makefile | 1 | ||||
-rw-r--r-- | vendor/github.com/d5/tengo/v2/README.md | 35 | ||||
-rw-r--r-- | vendor/github.com/d5/tengo/v2/bytecode.go | 12 | ||||
-rw-r--r-- | vendor/github.com/d5/tengo/v2/compiler.go | 42 | ||||
-rw-r--r-- | vendor/github.com/d5/tengo/v2/script.go | 13 | ||||
-rw-r--r-- | vendor/github.com/d5/tengo/v2/stdlib/json/encode.go | 195 |
6 files changed, 264 insertions, 34 deletions
diff --git a/vendor/github.com/d5/tengo/v2/Makefile b/vendor/github.com/d5/tengo/v2/Makefile index 793bc129..d461b661 100644 --- a/vendor/github.com/d5/tengo/v2/Makefile +++ b/vendor/github.com/d5/tengo/v2/Makefile @@ -6,6 +6,7 @@ lint: test: generate lint go test -race -cover ./... + go run ./cmd/tengo -resolve ./testdata/cli/test.tengo fmt: go fmt ./... diff --git a/vendor/github.com/d5/tengo/v2/README.md b/vendor/github.com/d5/tengo/v2/README.md index f170be24..bee19599 100644 --- a/vendor/github.com/d5/tengo/v2/README.md +++ b/vendor/github.com/d5/tengo/v2/README.md @@ -5,8 +5,8 @@ # The Tengo Language [![GoDoc](https://godoc.org/github.com/d5/tengo?status.svg)](https://godoc.org/github.com/d5/tengo) +![test](https://github.com/d5/tengo/workflows/test/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/d5/tengo)](https://goreportcard.com/report/github.com/d5/tengo) -[![CircleCI](https://circleci.com/gh/d5/tengo.svg?style=svg)](https://circleci.com/gh/d5/tengo) **Tengo is a small, dynamic, fast, secure script language for Go.** @@ -51,19 +51,21 @@ fmt.println(sum("", [1, 2, 3])) // "123" ## Benchmark -| | fib(35) | fibt(35) | Type | +| | fib(35) | fibt(35) | Language (Type) | | :--- | ---: | ---: | :---: | -| Go | `48ms` | `3ms` | Go (native) | -| [**Tengo**](https://github.com/d5/tengo) | `2,349ms` | `5ms` | VM on Go | -| Lua | `1,416ms` | `3ms` | Lua (native) | -| [go-lua](https://github.com/Shopify/go-lua) | `4,402ms` | `5ms` | Lua VM on Go | -| [GopherLua](https://github.com/yuin/gopher-lua) | `4,023ms` | `5ms` | Lua VM on Go | -| Python | `2,588ms` | `26ms` | Python (native) | -| [starlark-go](https://github.com/google/starlark-go) | `11,126ms` | `6ms` | Python-like Interpreter on Go | -| [gpython](https://github.com/go-python/gpython) | `15,035ms` | `4ms` | Python Interpreter on Go | -| [goja](https://github.com/dop251/goja) | `5,089ms` | `5ms` | JS VM on Go | -| [otto](https://github.com/robertkrimen/otto) | `68,377ms` | `11ms` | JS Interpreter on Go | -| [Anko](https://github.com/mattn/anko) | `92,579ms` | `18ms` | Interpreter on Go | +| [**Tengo**](https://github.com/d5/tengo) | `2,931ms` | `4ms` | Tengo (VM) | +| [go-lua](https://github.com/Shopify/go-lua) | `4,824ms` | `4ms` | Lua (VM) | +| [GopherLua](https://github.com/yuin/gopher-lua) | `5,365ms` | `4ms` | Lua (VM) | +| [goja](https://github.com/dop251/goja) | `5,533ms` | `5ms` | JavaScript (VM) | +| [starlark-go](https://github.com/google/starlark-go) | `11,495ms` | `5ms` | Starlark (Interpreter) | +| [Yaegi](https://github.com/containous/yaegi) | `15,645ms` | `12ms` | Yaegi (Interpreter) | +| [gpython](https://github.com/go-python/gpython) | `16,322ms` | `5ms` | Python (Interpreter) | +| [otto](https://github.com/robertkrimen/otto) | `73,093ms` | `10ms` | JavaScript (Interpreter) | +| [Anko](https://github.com/mattn/anko) | `79,809ms` | `8ms` | Anko (Interpreter) | +| - | - | - | - | +| Go | `53ms` | `3ms` | Go (Native) | +| Lua | `1,612ms` | `3ms` | Lua (Native) | +| Python | `2,632ms` | `23ms` | Python 2 (Native) | _* [fib(35)](https://github.com/d5/tengobench/blob/master/code/fib.tengo): Fibonacci(35)_ @@ -136,3 +138,10 @@ each([a, b, c, d], func(x) { - [Interoperability](https://github.com/d5/tengo/blob/master/docs/interoperability.md) - [Tengo CLI](https://github.com/d5/tengo/blob/master/docs/tengo-cli.md) - [Standard Library](https://github.com/d5/tengo/blob/master/docs/stdlib.md) +- Syntax Highlighters: [VSCode](https://github.com/lissein/vscode-tengo), [Atom](https://github.com/d5/tengo-atom) +- **Why the name Tengo?** It's from [1Q84](https://en.wikipedia.org/wiki/1Q84). + +## + +:hearts: Like writing Go code? Come work at Skool. [We're hiring!](https://jobs.lever.co/skool) + diff --git a/vendor/github.com/d5/tengo/v2/bytecode.go b/vendor/github.com/d5/tengo/v2/bytecode.go index cfd0d0b5..f3049cee 100644 --- a/vendor/github.com/d5/tengo/v2/bytecode.go +++ b/vendor/github.com/d5/tengo/v2/bytecode.go @@ -97,6 +97,7 @@ func (b *Bytecode) RemoveDuplicates() { var deduped []Object indexMap := make(map[int]int) // mapping from old constant index to new index + fns := make(map[*CompiledFunction]int) ints := make(map[int64]int) strings := make(map[string]int) floats := make(map[float64]int) @@ -106,9 +107,14 @@ func (b *Bytecode) RemoveDuplicates() { for curIdx, c := range b.Constants { switch c := c.(type) { case *CompiledFunction: - // add to deduped list - indexMap[curIdx] = len(deduped) - deduped = append(deduped, c) + if newIdx, ok := fns[c]; ok { + indexMap[curIdx] = newIdx + } else { + newIdx = len(deduped) + fns[c] = newIdx + indexMap[curIdx] = newIdx + deduped = append(deduped, c) + } case *ImmutableMap: modName := inferModuleName(c) newIdx, ok := immutableMaps[modName] diff --git a/vendor/github.com/d5/tengo/v2/compiler.go b/vendor/github.com/d5/tengo/v2/compiler.go index eb686ed6..cb1c8f30 100644 --- a/vendor/github.com/d5/tengo/v2/compiler.go +++ b/vendor/github.com/d5/tengo/v2/compiler.go @@ -44,6 +44,7 @@ type Compiler struct { file *parser.SourceFile parent *Compiler modulePath string + importDir string constants []Object symbolTable *SymbolTable scopes []compilationScope @@ -520,7 +521,7 @@ func (c *Compiler) Compile(node parser.Node) error { switch v := v.(type) { case []byte: // module written in Tengo compiled, err := c.compileModule(node, - node.ModuleName, node.ModuleName, v) + node.ModuleName, v, false) if err != nil { return err } @@ -537,24 +538,20 @@ func (c *Compiler) Compile(node parser.Node) error { moduleName += ".tengo" } - modulePath, err := filepath.Abs(moduleName) + modulePath, err := filepath.Abs( + filepath.Join(c.importDir, moduleName)) if err != nil { return c.errorf(node, "module file path error: %s", err.Error()) } - if err := c.checkCyclicImports(node, modulePath); err != nil { - return err - } - - moduleSrc, err := ioutil.ReadFile(moduleName) + moduleSrc, err := ioutil.ReadFile(modulePath) if err != nil { return c.errorf(node, "module file read error: %s", err.Error()) } - compiled, err := c.compileModule(node, - moduleName, modulePath, moduleSrc) + compiled, err := c.compileModule(node, modulePath, moduleSrc, true) if err != nil { return err } @@ -634,6 +631,11 @@ func (c *Compiler) EnableFileImport(enable bool) { c.allowFileImport = enable } +// SetImportDir sets the initial import directory path for file imports. +func (c *Compiler) SetImportDir(dir string) { + c.importDir = dir +} + func (c *Compiler) compileAssign( node parser.Node, lhs, rhs []parser.Expr, @@ -847,8 +849,8 @@ func (c *Compiler) compileForInStmt(stmt *parser.ForInStmt) error { // ... body ... // } // - // ":it" is a local variable but will be conflict with other user variables - // because character ":" is not allowed. + // ":it" is a local variable but it will not conflict with other user variables + // because character ":" is not allowed in the variable names. // init // :it = iterator(iterable) @@ -893,6 +895,7 @@ func (c *Compiler) compileForInStmt(stmt *parser.ForInStmt) error { if keySymbol.Scope == ScopeGlobal { c.emit(stmt, parser.OpSetGlobal, keySymbol.Index) } else { + keySymbol.LocalAssigned = true c.emit(stmt, parser.OpDefineLocal, keySymbol.Index) } } @@ -909,6 +912,7 @@ func (c *Compiler) compileForInStmt(stmt *parser.ForInStmt) error { if valueSymbol.Scope == ScopeGlobal { c.emit(stmt, parser.OpSetGlobal, valueSymbol.Index) } else { + valueSymbol.LocalAssigned = true c.emit(stmt, parser.OpDefineLocal, valueSymbol.Index) } } @@ -955,8 +959,9 @@ func (c *Compiler) checkCyclicImports( func (c *Compiler) compileModule( node parser.Node, - moduleName, modulePath string, + modulePath string, src []byte, + isFile bool, ) (*CompiledFunction, error) { if err := c.checkCyclicImports(node, modulePath); err != nil { return nil, err @@ -967,7 +972,7 @@ func (c *Compiler) compileModule( return compiledModule, nil } - modFile := c.file.Set().AddFile(moduleName, -1, len(src)) + modFile := c.file.Set().AddFile(modulePath, -1, len(src)) p := parser.NewParser(modFile, src, nil) file, err := p.ParseFile() if err != nil { @@ -984,7 +989,7 @@ func (c *Compiler) compileModule( symbolTable = symbolTable.Fork(false) // compile module - moduleCompiler := c.fork(modFile, modulePath, symbolTable) + moduleCompiler := c.fork(modFile, modulePath, symbolTable, isFile) if err := moduleCompiler.Compile(file); err != nil { return nil, err } @@ -1082,10 +1087,16 @@ func (c *Compiler) fork( file *parser.SourceFile, modulePath string, symbolTable *SymbolTable, + isFile bool, ) *Compiler { child := NewCompiler(file, symbolTable, nil, c.modules, c.trace) child.modulePath = modulePath // module file path child.parent = c // parent to set to current compiler + child.allowFileImport = c.allowFileImport + child.importDir = c.importDir + if isFile && c.importDir != "" { + child.importDir = filepath.Dir(modulePath) + } return child } @@ -1192,6 +1203,7 @@ func (c *Compiler) optimizeFunc(node parser.Node) { var lastOp parser.Opcode var appendReturn bool endPos := len(c.scopes[c.scopeIndex].Instructions) + newEndPost := len(newInsts) iterateInstructions(newInsts, func(pos int, opcode parser.Opcode, operands []int) bool { switch opcode { @@ -1204,6 +1216,8 @@ func (c *Compiler) optimizeFunc(node parser.Node) { } else if endPos == operands[0] { // there's a jump instruction that jumps to the end of // function compiler should append "return". + copy(newInsts[pos:], + MakeInstruction(opcode, newEndPost)) appendReturn = true } else { panic(fmt.Errorf("invalid jump position: %d", newDst)) diff --git a/vendor/github.com/d5/tengo/v2/script.go b/vendor/github.com/d5/tengo/v2/script.go index 906771d9..4f9608c1 100644 --- a/vendor/github.com/d5/tengo/v2/script.go +++ b/vendor/github.com/d5/tengo/v2/script.go @@ -3,6 +3,7 @@ package tengo import ( "context" "fmt" + "path/filepath" "sync" "github.com/d5/tengo/v2/parser" @@ -16,6 +17,7 @@ type Script struct { maxAllocs int64 maxConstObjects int enableFileImport bool + importDir string } // NewScript creates a Script instance with an input script. @@ -56,6 +58,16 @@ func (s *Script) SetImports(modules *ModuleMap) { s.modules = modules } +// SetImportDir sets the initial import directory for script files. +func (s *Script) SetImportDir(dir string) error { + dir, err := filepath.Abs(dir) + if err != nil { + return err + } + s.importDir = dir + return nil +} + // SetMaxAllocs sets the maximum number of objects allocations during the run // time. Compiled script will return ErrObjectAllocLimit error if it // exceeds this limit. @@ -93,6 +105,7 @@ func (s *Script) Compile() (*Compiled, error) { c := NewCompiler(srcFile, symbolTable, nil, s.modules, nil) c.EnableFileImport(s.enableFileImport) + c.SetImportDir(s.importDir) if err := c.Compile(file); err != nil { return nil, err } diff --git a/vendor/github.com/d5/tengo/v2/stdlib/json/encode.go b/vendor/github.com/d5/tengo/v2/stdlib/json/encode.go index ab7ca6ff..10805b01 100644 --- a/vendor/github.com/d5/tengo/v2/stdlib/json/encode.go +++ b/vendor/github.com/d5/tengo/v2/stdlib/json/encode.go @@ -1,20 +1,129 @@ // A modified version of Go's JSON implementation. -// Copyright 2010 The Go Authors. All rights reserved. +// Copyright 2010, 2020 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. package json import ( + "bytes" "encoding/base64" "errors" "math" "strconv" + "unicode/utf8" "github.com/d5/tengo/v2" ) +// safeSet holds the value true if the ASCII character with the given array +// position can be represented inside a JSON string without any further +// escaping. +// +// All values are true except for the ASCII control characters (0-31), the +// double quote ("), and the backslash character ("\"). +var safeSet = [utf8.RuneSelf]bool{ + ' ': true, + '!': true, + '"': false, + '#': true, + '$': true, + '%': true, + '&': true, + '\'': true, + '(': true, + ')': true, + '*': true, + '+': true, + ',': true, + '-': true, + '.': true, + '/': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + ':': true, + ';': true, + '<': true, + '=': true, + '>': true, + '?': true, + '@': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'V': true, + 'W': true, + 'X': true, + 'Y': true, + 'Z': true, + '[': true, + '\\': false, + ']': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '{': true, + '|': true, + '}': true, + '~': true, + '\u007f': true, +} + +var hex = "0123456789abcdef" + // Encode returns the JSON encoding of the object. func Encode(o tengo.Object) ([]byte, error) { var b []byte @@ -53,7 +162,7 @@ func Encode(o tengo.Object) ([]byte, error) { len1 := len(o.Value) - 1 idx := 0 for key, value := range o.Value { - b = strconv.AppendQuote(b, key) + b = encodeString(b, key) b = append(b, ':') eb, err := Encode(value) if err != nil { @@ -71,7 +180,7 @@ func Encode(o tengo.Object) ([]byte, error) { len1 := len(o.Value) - 1 idx := 0 for key, value := range o.Value { - b = strconv.AppendQuote(b, key) + b = encodeString(b, key) b = append(b, ':') eb, err := Encode(value) if err != nil { @@ -130,7 +239,9 @@ func Encode(o tengo.Object) ([]byte, error) { case *tengo.Int: b = strconv.AppendInt(b, o.Value, 10) case *tengo.String: - b = strconv.AppendQuote(b, o.Value) + // string encoding bug is fixed with newly introduced function + // encodeString(). See: https://github.com/d5/tengo/issues/268 + b = encodeString(b, o.Value) case *tengo.Time: y, err := o.Value.MarshalJSON() if err != nil { @@ -144,3 +255,79 @@ func Encode(o tengo.Object) ([]byte, error) { } return b, nil } + +// encodeString encodes given string as JSON string according to +// https://www.json.org/img/string.png +// Implementation is inspired by https://github.com/json-iterator/go +// See encodeStringSlowPath() for more information. +func encodeString(b []byte, val string) []byte { + valLen := len(val) + buf := bytes.NewBuffer(b) + buf.WriteByte('"') + + // write string, the fast path, without utf8 and escape support + i := 0 + for ; i < valLen; i++ { + c := val[i] + if c > 31 && c != '"' && c != '\\' { + buf.WriteByte(c) + } else { + break + } + } + if i == valLen { + buf.WriteByte('"') + return buf.Bytes() + } + encodeStringSlowPath(buf, i, val, valLen) + buf.WriteByte('"') + return buf.Bytes() +} + +// encodeStringSlowPath is ported from Go 1.14.2 encoding/json package. +// U+2028 U+2029 JSONP security holes can be fixed with addition call to +// json.html_escape() thus it is removed from the implementation below. +// Note: Invalid runes are not checked as they are checked in original +// implementation. +func encodeStringSlowPath(buf *bytes.Buffer, i int, val string, valLen int) { + start := i + for i < valLen { + if b := val[i]; b < utf8.RuneSelf { + if safeSet[b] { + i++ + continue + } + if start < i { + buf.WriteString(val[start:i]) + } + buf.WriteByte('\\') + switch b { + case '\\', '"': + buf.WriteByte(b) + case '\n': + buf.WriteByte('n') + case '\r': + buf.WriteByte('r') + case '\t': + buf.WriteByte('t') + default: + // This encodes bytes < 0x20 except for \t, \n and \r. + // If escapeHTML is set, it also escapes <, >, and & + // because they can lead to security holes when + // user-controlled strings are rendered into JSON + // and served to some browsers. + buf.WriteString(`u00`) + buf.WriteByte(hex[b>>4]) + buf.WriteByte(hex[b&0xF]) + } + i++ + start = i + continue + } + i++ + continue + } + if start < valLen { + buf.WriteString(val[start:]) + } +} |