mirror of
https://github.com/42wim/matterbridge.git
synced 2024-11-15 08:29:25 +01:00
parent
cdf33e5748
commit
115d20373c
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/42wim/matterbridge/bridge"
|
"github.com/42wim/matterbridge/bridge"
|
||||||
"github.com/42wim/matterbridge/bridge/config"
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
"github.com/d5/tengo/script"
|
"github.com/d5/tengo/script"
|
||||||
|
"github.com/d5/tengo/stdlib"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
"github.com/peterhellberg/emojilib"
|
"github.com/peterhellberg/emojilib"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -503,6 +504,7 @@ func modifyMessageTengo(filename string, msg *config.Message) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s := script.New(res)
|
s := script.New(res)
|
||||||
|
s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...))
|
||||||
_ = s.Add("msgText", msg.Text)
|
_ = s.Add("msgText", msg.Text)
|
||||||
_ = s.Add("msgUsername", msg.Username)
|
_ = s.Add("msgUsername", msg.Username)
|
||||||
_ = s.Add("msgAccount", msg.Account)
|
_ = s.Add("msgAccount", msg.Account)
|
||||||
|
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ require (
|
|||||||
github.com/Jeffail/gabs v1.1.1 // indirect
|
github.com/Jeffail/gabs v1.1.1 // indirect
|
||||||
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329
|
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329
|
||||||
github.com/bwmarrin/discordgo v0.19.0
|
github.com/bwmarrin/discordgo v0.19.0
|
||||||
github.com/d5/tengo v1.12.1
|
github.com/d5/tengo v1.20.0
|
||||||
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
|
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
|
||||||
github.com/fsnotify/fsnotify v1.4.7
|
github.com/fsnotify/fsnotify v1.4.7
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible
|
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible
|
||||||
|
4
go.sum
4
go.sum
@ -15,8 +15,8 @@ github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVO
|
|||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/d5/tengo v1.12.1 h1:libKkDM95CsZgYs6E5eiEaM9sbcw2EzJRSkr9o5NO4s=
|
github.com/d5/tengo v1.20.0 h1:lFmktzEGR6khlZu2MHUWJ5oDWS4l3jNRV/OhclZgcYc=
|
||||||
github.com/d5/tengo v1.12.1/go.mod h1:gsbjo7lBXzBIWBd6NQp1lRKqqiDDANqBOyhW8rTlFsY=
|
github.com/d5/tengo v1.20.0/go.mod h1:gsbjo7lBXzBIWBd6NQp1lRKqqiDDANqBOyhW8rTlFsY=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
5
vendor/github.com/d5/tengo/Makefile
generated
vendored
5
vendor/github.com/d5/tengo/Makefile
generated
vendored
@ -1,10 +1,13 @@
|
|||||||
vet:
|
vet:
|
||||||
go vet ./...
|
go vet ./...
|
||||||
|
|
||||||
|
generate:
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
golint -set_exit_status ./...
|
golint -set_exit_status ./...
|
||||||
|
|
||||||
test: vet lint
|
test: generate vet lint
|
||||||
go test -race -cover ./...
|
go test -race -cover ./...
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
|
32
vendor/github.com/d5/tengo/README.md
generated
vendored
32
vendor/github.com/d5/tengo/README.md
generated
vendored
@ -7,7 +7,6 @@
|
|||||||
[![GoDoc](https://godoc.org/github.com/d5/tengo?status.svg)](https://godoc.org/github.com/d5/tengo/script)
|
[![GoDoc](https://godoc.org/github.com/d5/tengo?status.svg)](https://godoc.org/github.com/d5/tengo/script)
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/d5/tengo)](https://goreportcard.com/report/github.com/d5/tengo)
|
[![Go Report Card](https://goreportcard.com/badge/github.com/d5/tengo)](https://goreportcard.com/report/github.com/d5/tengo)
|
||||||
[![Build Status](https://travis-ci.org/d5/tengo.svg?branch=master)](https://travis-ci.org/d5/tengo)
|
[![Build Status](https://travis-ci.org/d5/tengo.svg?branch=master)](https://travis-ci.org/d5/tengo)
|
||||||
[![](https://img.shields.io/badge/Support%20Tengo-%241-brightgreen.svg)](https://www.patreon.com/tengolang)
|
|
||||||
|
|
||||||
**Tengo is a small, dynamic, fast, secure script language for Go.**
|
**Tengo is a small, dynamic, fast, secure script language for Go.**
|
||||||
|
|
||||||
@ -16,6 +15,8 @@ Tengo is **[fast](#benchmark)** and secure because it's compiled/executed as byt
|
|||||||
```golang
|
```golang
|
||||||
/* The Tengo Language */
|
/* The Tengo Language */
|
||||||
|
|
||||||
|
fmt := import("fmt")
|
||||||
|
|
||||||
each := func(seq, fn) {
|
each := func(seq, fn) {
|
||||||
for x in seq { fn(x) }
|
for x in seq { fn(x) }
|
||||||
}
|
}
|
||||||
@ -25,11 +26,11 @@ sum := func(init, seq) {
|
|||||||
return init
|
return init
|
||||||
}
|
}
|
||||||
|
|
||||||
n := sum(0, [1, 2, 3]) // == 6
|
fmt.println(sum(0, [1, 2, 3])) // "6"
|
||||||
s := sum("", [1, 2, 3]) // == "123"
|
fmt.println(sum("", [1, 2, 3])) // "123"
|
||||||
```
|
```
|
||||||
|
|
||||||
> Run this code in the [Playground](https://tengolang.com/?s=d01cf9ed81daba939e26618530eb171f7397d9c9)
|
> Run this code in the [Playground](https://tengolang.com/?s=0c8d5d0d88f2795a7093d7f35ae12c3afa17bea3)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@ -41,22 +42,23 @@ s := sum("", [1, 2, 3]) // == "123"
|
|||||||
- [Securely Embeddable](https://github.com/d5/tengo/blob/master/docs/interoperability.md) and [Extensible](https://github.com/d5/tengo/blob/master/docs/objects.md)
|
- [Securely Embeddable](https://github.com/d5/tengo/blob/master/docs/interoperability.md) and [Extensible](https://github.com/d5/tengo/blob/master/docs/objects.md)
|
||||||
- Compiler/runtime written in native Go _(no external deps or cgo)_
|
- Compiler/runtime written in native Go _(no external deps or cgo)_
|
||||||
- Executable as a [standalone](https://github.com/d5/tengo/blob/master/docs/tengo-cli.md) language / REPL
|
- Executable as a [standalone](https://github.com/d5/tengo/blob/master/docs/tengo-cli.md) language / REPL
|
||||||
|
- Use cases: rules engine, [state machine](https://github.com/d5/go-fsm), [gaming](https://github.com/d5/pbr), data pipeline, [transpiler](https://github.com/d5/tengo2lua)
|
||||||
|
|
||||||
## Benchmark
|
## Benchmark
|
||||||
|
|
||||||
| | fib(35) | fibt(35) | Type |
|
| | fib(35) | fibt(35) | Type |
|
||||||
| :--- | ---: | ---: | :---: |
|
| :--- | ---: | ---: | :---: |
|
||||||
| Go | `58ms` | `4ms` | Go (native) |
|
| Go | `48ms` | `3ms` | Go (native) |
|
||||||
| [**Tengo**](https://github.com/d5/tengo) | `4,180ms` | `5ms` | VM on Go |
|
| [**Tengo**](https://github.com/d5/tengo) | `2,349ms` | `5ms` | VM on Go |
|
||||||
| Lua | `1,695ms` | `3ms` | Lua (native) |
|
| Lua | `1,416ms` | `3ms` | Lua (native) |
|
||||||
| [go-lua](https://github.com/Shopify/go-lua) | `5,163ms` | `5ms` | Lua VM on Go |
|
| [go-lua](https://github.com/Shopify/go-lua) | `4,402ms` | `5ms` | Lua VM on Go |
|
||||||
| [GopherLua](https://github.com/yuin/gopher-lua) | `5,525ms` | `5ms` | Lua VM on Go |
|
| [GopherLua](https://github.com/yuin/gopher-lua) | `4,023ms` | `5ms` | Lua VM on Go |
|
||||||
| Python | `3,097ms` | `27ms` | Python (native) |
|
| Python | `2,588ms` | `26ms` | Python (native) |
|
||||||
| [starlark-go](https://github.com/google/starlark-go) | `15,307ms` | `5ms` | Python-like Interpreter on Go |
|
| [starlark-go](https://github.com/google/starlark-go) | `11,126ms` | `6ms` | Python-like Interpreter on Go |
|
||||||
| [gpython](https://github.com/go-python/gpython) | `17,656ms` | `5ms` | Python Interpreter on Go |
|
| [gpython](https://github.com/go-python/gpython) | `15,035ms` | `4ms` | Python Interpreter on Go |
|
||||||
| [goja](https://github.com/dop251/goja) | `6,876ms` | `5ms` | JS VM on Go |
|
| [goja](https://github.com/dop251/goja) | `5,089ms` | `5ms` | JS VM on Go |
|
||||||
| [otto](https://github.com/robertkrimen/otto) | `81,886ms` | `12ms` | JS Interpreter on Go |
|
| [otto](https://github.com/robertkrimen/otto) | `68,377ms` | `11ms` | JS Interpreter on Go |
|
||||||
| [Anko](https://github.com/mattn/anko) | `97,517ms` | `14ms` | Interpreter on Go |
|
| [Anko](https://github.com/mattn/anko) | `92,579ms` | `18ms` | Interpreter on Go |
|
||||||
|
|
||||||
_* [fib(35)](https://github.com/d5/tengobench/blob/master/code/fib.tengo): Fibonacci(35)_
|
_* [fib(35)](https://github.com/d5/tengobench/blob/master/code/fib.tengo): Fibonacci(35)_
|
||||||
_* [fibt(35)](https://github.com/d5/tengobench/blob/master/code/fibtc.tengo): [tail-call](https://en.wikipedia.org/wiki/Tail_call) version of Fibonacci(35)_
|
_* [fibt(35)](https://github.com/d5/tengobench/blob/master/code/fibtc.tengo): [tail-call](https://en.wikipedia.org/wiki/Tail_call) version of Fibonacci(35)_
|
||||||
|
66
vendor/github.com/d5/tengo/compiler/bytecode.go
generated
vendored
66
vendor/github.com/d5/tengo/compiler/bytecode.go
generated
vendored
@ -17,32 +17,6 @@ type Bytecode struct {
|
|||||||
Constants []objects.Object
|
Constants []objects.Object
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode reads Bytecode data from the reader.
|
|
||||||
func (b *Bytecode) Decode(r io.Reader) error {
|
|
||||||
dec := gob.NewDecoder(r)
|
|
||||||
|
|
||||||
if err := dec.Decode(&b.FileSet); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// TODO: files in b.FileSet.File does not have their 'set' field properly set to b.FileSet
|
|
||||||
// as it's private field and not serialized by gob encoder/decoder.
|
|
||||||
|
|
||||||
if err := dec.Decode(&b.MainFunction); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := dec.Decode(&b.Constants); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace Bool and Undefined with known value
|
|
||||||
for i, v := range b.Constants {
|
|
||||||
b.Constants[i] = cleanupObjects(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode writes Bytecode data to the writer.
|
// Encode writes Bytecode data to the writer.
|
||||||
func (b *Bytecode) Encode(w io.Writer) error {
|
func (b *Bytecode) Encode(w io.Writer) error {
|
||||||
enc := gob.NewEncoder(w)
|
enc := gob.NewEncoder(w)
|
||||||
@ -59,6 +33,17 @@ func (b *Bytecode) Encode(w io.Writer) error {
|
|||||||
return enc.Encode(b.Constants)
|
return enc.Encode(b.Constants)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountObjects returns the number of objects found in Constants.
|
||||||
|
func (b *Bytecode) CountObjects() int {
|
||||||
|
n := 0
|
||||||
|
|
||||||
|
for _, c := range b.Constants {
|
||||||
|
n += objects.CountObjects(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
// FormatInstructions returns human readable string representations of
|
// FormatInstructions returns human readable string representations of
|
||||||
// compiled instructions.
|
// compiled instructions.
|
||||||
func (b *Bytecode) FormatInstructions() []string {
|
func (b *Bytecode) FormatInstructions() []string {
|
||||||
@ -83,51 +68,22 @@ func (b *Bytecode) FormatConstants() (output []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupObjects(o objects.Object) objects.Object {
|
|
||||||
switch o := o.(type) {
|
|
||||||
case *objects.Bool:
|
|
||||||
if o.IsFalsy() {
|
|
||||||
return objects.FalseValue
|
|
||||||
}
|
|
||||||
return objects.TrueValue
|
|
||||||
case *objects.Undefined:
|
|
||||||
return objects.UndefinedValue
|
|
||||||
case *objects.Array:
|
|
||||||
for i, v := range o.Value {
|
|
||||||
o.Value[i] = cleanupObjects(v)
|
|
||||||
}
|
|
||||||
case *objects.Map:
|
|
||||||
for k, v := range o.Value {
|
|
||||||
o.Value[k] = cleanupObjects(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
gob.Register(&source.FileSet{})
|
gob.Register(&source.FileSet{})
|
||||||
gob.Register(&source.File{})
|
gob.Register(&source.File{})
|
||||||
gob.Register(&objects.Array{})
|
gob.Register(&objects.Array{})
|
||||||
gob.Register(&objects.ArrayIterator{})
|
|
||||||
gob.Register(&objects.Bool{})
|
gob.Register(&objects.Bool{})
|
||||||
gob.Register(&objects.Break{})
|
|
||||||
gob.Register(&objects.BuiltinFunction{})
|
|
||||||
gob.Register(&objects.Bytes{})
|
gob.Register(&objects.Bytes{})
|
||||||
gob.Register(&objects.Char{})
|
gob.Register(&objects.Char{})
|
||||||
gob.Register(&objects.Closure{})
|
gob.Register(&objects.Closure{})
|
||||||
gob.Register(&objects.CompiledFunction{})
|
gob.Register(&objects.CompiledFunction{})
|
||||||
gob.Register(&objects.Continue{})
|
|
||||||
gob.Register(&objects.Error{})
|
gob.Register(&objects.Error{})
|
||||||
gob.Register(&objects.Float{})
|
gob.Register(&objects.Float{})
|
||||||
gob.Register(&objects.ImmutableArray{})
|
gob.Register(&objects.ImmutableArray{})
|
||||||
gob.Register(&objects.ImmutableMap{})
|
gob.Register(&objects.ImmutableMap{})
|
||||||
gob.Register(&objects.Int{})
|
gob.Register(&objects.Int{})
|
||||||
gob.Register(&objects.Map{})
|
gob.Register(&objects.Map{})
|
||||||
gob.Register(&objects.MapIterator{})
|
|
||||||
gob.Register(&objects.ReturnValue{})
|
|
||||||
gob.Register(&objects.String{})
|
gob.Register(&objects.String{})
|
||||||
gob.Register(&objects.StringIterator{})
|
|
||||||
gob.Register(&objects.Time{})
|
gob.Register(&objects.Time{})
|
||||||
gob.Register(&objects.Undefined{})
|
gob.Register(&objects.Undefined{})
|
||||||
gob.Register(&objects.UserFunction{})
|
gob.Register(&objects.UserFunction{})
|
||||||
|
97
vendor/github.com/d5/tengo/compiler/bytecode_decode.go
generated
vendored
Normal file
97
vendor/github.com/d5/tengo/compiler/bytecode_decode.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package compiler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decode reads Bytecode data from the reader.
|
||||||
|
func (b *Bytecode) Decode(r io.Reader, modules *objects.ModuleMap) error {
|
||||||
|
if modules == nil {
|
||||||
|
modules = objects.NewModuleMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
dec := gob.NewDecoder(r)
|
||||||
|
|
||||||
|
if err := dec.Decode(&b.FileSet); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO: files in b.FileSet.File does not have their 'set' field properly set to b.FileSet
|
||||||
|
// as it's private field and not serialized by gob encoder/decoder.
|
||||||
|
|
||||||
|
if err := dec.Decode(&b.MainFunction); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := dec.Decode(&b.Constants); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, v := range b.Constants {
|
||||||
|
fv, err := fixDecoded(v, modules)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.Constants[i] = fv
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fixDecoded(o objects.Object, modules *objects.ModuleMap) (objects.Object, error) {
|
||||||
|
switch o := o.(type) {
|
||||||
|
case *objects.Bool:
|
||||||
|
if o.IsFalsy() {
|
||||||
|
return objects.FalseValue, nil
|
||||||
|
}
|
||||||
|
return objects.TrueValue, nil
|
||||||
|
case *objects.Undefined:
|
||||||
|
return objects.UndefinedValue, nil
|
||||||
|
case *objects.Array:
|
||||||
|
for i, v := range o.Value {
|
||||||
|
fv, err := fixDecoded(v, modules)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
o.Value[i] = fv
|
||||||
|
}
|
||||||
|
case *objects.ImmutableArray:
|
||||||
|
for i, v := range o.Value {
|
||||||
|
fv, err := fixDecoded(v, modules)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
o.Value[i] = fv
|
||||||
|
}
|
||||||
|
case *objects.Map:
|
||||||
|
for k, v := range o.Value {
|
||||||
|
fv, err := fixDecoded(v, modules)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
o.Value[k] = fv
|
||||||
|
}
|
||||||
|
case *objects.ImmutableMap:
|
||||||
|
modName := moduleName(o)
|
||||||
|
if mod := modules.GetBuiltinModule(modName); mod != nil {
|
||||||
|
return mod.AsImmutableMap(modName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range o.Value {
|
||||||
|
// encoding of user function not supported
|
||||||
|
if _, isUserFunction := v.(*objects.UserFunction); isUserFunction {
|
||||||
|
return nil, fmt.Errorf("user function not decodable")
|
||||||
|
}
|
||||||
|
|
||||||
|
fv, err := fixDecoded(v, modules)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
o.Value[k] = fv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return o, nil
|
||||||
|
}
|
129
vendor/github.com/d5/tengo/compiler/bytecode_optimize.go
generated
vendored
Normal file
129
vendor/github.com/d5/tengo/compiler/bytecode_optimize.go
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package compiler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RemoveDuplicates finds and remove the duplicate values in Constants.
|
||||||
|
// Note this function mutates Bytecode.
|
||||||
|
func (b *Bytecode) RemoveDuplicates() {
|
||||||
|
var deduped []objects.Object
|
||||||
|
|
||||||
|
indexMap := make(map[int]int) // mapping from old constant index to new index
|
||||||
|
ints := make(map[int64]int)
|
||||||
|
strings := make(map[string]int)
|
||||||
|
floats := make(map[float64]int)
|
||||||
|
chars := make(map[rune]int)
|
||||||
|
immutableMaps := make(map[string]int) // for modules
|
||||||
|
|
||||||
|
for curIdx, c := range b.Constants {
|
||||||
|
switch c := c.(type) {
|
||||||
|
case *objects.CompiledFunction:
|
||||||
|
// add to deduped list
|
||||||
|
indexMap[curIdx] = len(deduped)
|
||||||
|
deduped = append(deduped, c)
|
||||||
|
case *objects.ImmutableMap:
|
||||||
|
modName := moduleName(c)
|
||||||
|
newIdx, ok := immutableMaps[modName]
|
||||||
|
if modName != "" && ok {
|
||||||
|
indexMap[curIdx] = newIdx
|
||||||
|
} else {
|
||||||
|
newIdx = len(deduped)
|
||||||
|
immutableMaps[modName] = newIdx
|
||||||
|
indexMap[curIdx] = newIdx
|
||||||
|
deduped = append(deduped, c)
|
||||||
|
}
|
||||||
|
case *objects.Int:
|
||||||
|
if newIdx, ok := ints[c.Value]; ok {
|
||||||
|
indexMap[curIdx] = newIdx
|
||||||
|
} else {
|
||||||
|
newIdx = len(deduped)
|
||||||
|
ints[c.Value] = newIdx
|
||||||
|
indexMap[curIdx] = newIdx
|
||||||
|
deduped = append(deduped, c)
|
||||||
|
}
|
||||||
|
case *objects.String:
|
||||||
|
if newIdx, ok := strings[c.Value]; ok {
|
||||||
|
indexMap[curIdx] = newIdx
|
||||||
|
} else {
|
||||||
|
newIdx = len(deduped)
|
||||||
|
strings[c.Value] = newIdx
|
||||||
|
indexMap[curIdx] = newIdx
|
||||||
|
deduped = append(deduped, c)
|
||||||
|
}
|
||||||
|
case *objects.Float:
|
||||||
|
if newIdx, ok := floats[c.Value]; ok {
|
||||||
|
indexMap[curIdx] = newIdx
|
||||||
|
} else {
|
||||||
|
newIdx = len(deduped)
|
||||||
|
floats[c.Value] = newIdx
|
||||||
|
indexMap[curIdx] = newIdx
|
||||||
|
deduped = append(deduped, c)
|
||||||
|
}
|
||||||
|
case *objects.Char:
|
||||||
|
if newIdx, ok := chars[c.Value]; ok {
|
||||||
|
indexMap[curIdx] = newIdx
|
||||||
|
} else {
|
||||||
|
newIdx = len(deduped)
|
||||||
|
chars[c.Value] = newIdx
|
||||||
|
indexMap[curIdx] = newIdx
|
||||||
|
deduped = append(deduped, c)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported top-level constant type: %s", c.TypeName()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace with de-duplicated constants
|
||||||
|
b.Constants = deduped
|
||||||
|
|
||||||
|
// update CONST instructions with new indexes
|
||||||
|
// main function
|
||||||
|
updateConstIndexes(b.MainFunction.Instructions, indexMap)
|
||||||
|
// other compiled functions in constants
|
||||||
|
for _, c := range b.Constants {
|
||||||
|
switch c := c.(type) {
|
||||||
|
case *objects.CompiledFunction:
|
||||||
|
updateConstIndexes(c.Instructions, indexMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateConstIndexes(insts []byte, indexMap map[int]int) {
|
||||||
|
i := 0
|
||||||
|
for i < len(insts) {
|
||||||
|
op := insts[i]
|
||||||
|
numOperands := OpcodeOperands[op]
|
||||||
|
_, read := ReadOperands(numOperands, insts[i+1:])
|
||||||
|
|
||||||
|
switch op {
|
||||||
|
case OpConstant:
|
||||||
|
curIdx := int(insts[i+2]) | int(insts[i+1])<<8
|
||||||
|
newIdx, ok := indexMap[curIdx]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Errorf("constant index not found: %d", curIdx))
|
||||||
|
}
|
||||||
|
copy(insts[i:], MakeInstruction(op, newIdx))
|
||||||
|
case OpClosure:
|
||||||
|
curIdx := int(insts[i+2]) | int(insts[i+1])<<8
|
||||||
|
numFree := int(insts[i+3])
|
||||||
|
newIdx, ok := indexMap[curIdx]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Errorf("constant index not found: %d", curIdx))
|
||||||
|
}
|
||||||
|
copy(insts[i:], MakeInstruction(op, newIdx, numFree))
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1 + read
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func moduleName(mod *objects.ImmutableMap) string {
|
||||||
|
if modName, ok := mod.Value["__module_name__"].(*objects.String); ok {
|
||||||
|
return modName.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
7
vendor/github.com/d5/tengo/compiler/compilation_scope.go
generated
vendored
7
vendor/github.com/d5/tengo/compiler/compilation_scope.go
generated
vendored
@ -5,8 +5,7 @@ import "github.com/d5/tengo/compiler/source"
|
|||||||
// CompilationScope represents a compiled instructions
|
// CompilationScope represents a compiled instructions
|
||||||
// and the last two instructions that were emitted.
|
// and the last two instructions that were emitted.
|
||||||
type CompilationScope struct {
|
type CompilationScope struct {
|
||||||
instructions []byte
|
instructions []byte
|
||||||
lastInstructions [2]EmittedInstruction
|
symbolInit map[string]bool
|
||||||
symbolInit map[string]bool
|
sourceMap map[int]source.Pos
|
||||||
sourceMap map[int]source.Pos
|
|
||||||
}
|
}
|
||||||
|
270
vendor/github.com/d5/tengo/compiler/compiler.go
generated
vendored
270
vendor/github.com/d5/tengo/compiler/compiler.go
generated
vendored
@ -3,7 +3,10 @@ package compiler
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/d5/tengo"
|
"github.com/d5/tengo"
|
||||||
"github.com/d5/tengo/compiler/ast"
|
"github.com/d5/tengo/compiler/ast"
|
||||||
@ -16,14 +19,14 @@ import (
|
|||||||
type Compiler struct {
|
type Compiler struct {
|
||||||
file *source.File
|
file *source.File
|
||||||
parent *Compiler
|
parent *Compiler
|
||||||
moduleName string
|
modulePath string
|
||||||
constants []objects.Object
|
constants []objects.Object
|
||||||
symbolTable *SymbolTable
|
symbolTable *SymbolTable
|
||||||
scopes []CompilationScope
|
scopes []CompilationScope
|
||||||
scopeIndex int
|
scopeIndex int
|
||||||
moduleLoader ModuleLoader
|
modules *objects.ModuleMap
|
||||||
builtinModules map[string]bool
|
|
||||||
compiledModules map[string]*objects.CompiledFunction
|
compiledModules map[string]*objects.CompiledFunction
|
||||||
|
allowFileImport bool
|
||||||
loops []*Loop
|
loops []*Loop
|
||||||
loopIndex int
|
loopIndex int
|
||||||
trace io.Writer
|
trace io.Writer
|
||||||
@ -31,12 +34,7 @@ type Compiler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewCompiler creates a Compiler.
|
// NewCompiler creates a Compiler.
|
||||||
// User can optionally provide the symbol table if one wants to add or remove
|
func NewCompiler(file *source.File, symbolTable *SymbolTable, constants []objects.Object, modules *objects.ModuleMap, trace io.Writer) *Compiler {
|
||||||
// some global- or builtin- scope symbols. If not (nil), Compile will create
|
|
||||||
// a new symbol table and use the default builtin functions. Likewise, standard
|
|
||||||
// modules can be explicitly provided if user wants to add or remove some modules.
|
|
||||||
// By default, Compile will use all the standard modules otherwise.
|
|
||||||
func NewCompiler(file *source.File, symbolTable *SymbolTable, constants []objects.Object, builtinModules map[string]bool, trace io.Writer) *Compiler {
|
|
||||||
mainScope := CompilationScope{
|
mainScope := CompilationScope{
|
||||||
symbolInit: make(map[string]bool),
|
symbolInit: make(map[string]bool),
|
||||||
sourceMap: make(map[int]source.Pos),
|
sourceMap: make(map[int]source.Pos),
|
||||||
@ -45,15 +43,16 @@ func NewCompiler(file *source.File, symbolTable *SymbolTable, constants []object
|
|||||||
// symbol table
|
// symbol table
|
||||||
if symbolTable == nil {
|
if symbolTable == nil {
|
||||||
symbolTable = NewSymbolTable()
|
symbolTable = NewSymbolTable()
|
||||||
|
}
|
||||||
|
|
||||||
for idx, fn := range objects.Builtins {
|
// add builtin functions to the symbol table
|
||||||
symbolTable.DefineBuiltin(idx, fn.Name)
|
for idx, fn := range objects.Builtins {
|
||||||
}
|
symbolTable.DefineBuiltin(idx, fn.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// builtin modules
|
// builtin modules
|
||||||
if builtinModules == nil {
|
if modules == nil {
|
||||||
builtinModules = make(map[string]bool)
|
modules = objects.NewModuleMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Compiler{
|
return &Compiler{
|
||||||
@ -64,7 +63,7 @@ func NewCompiler(file *source.File, symbolTable *SymbolTable, constants []object
|
|||||||
scopeIndex: 0,
|
scopeIndex: 0,
|
||||||
loopIndex: -1,
|
loopIndex: -1,
|
||||||
trace: trace,
|
trace: trace,
|
||||||
builtinModules: builtinModules,
|
modules: modules,
|
||||||
compiledModules: make(map[string]*objects.CompiledFunction),
|
compiledModules: make(map[string]*objects.CompiledFunction),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +119,7 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.emit(node, OpGreaterThan)
|
c.emit(node, OpBinaryOp, int(token.Greater))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
} else if node.Token == token.LessEq {
|
} else if node.Token == token.LessEq {
|
||||||
@ -131,7 +130,7 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.emit(node, OpGreaterThanEqual)
|
c.emit(node, OpBinaryOp, int(token.GreaterEq))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -145,35 +144,35 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
|
|
||||||
switch node.Token {
|
switch node.Token {
|
||||||
case token.Add:
|
case token.Add:
|
||||||
c.emit(node, OpAdd)
|
c.emit(node, OpBinaryOp, int(token.Add))
|
||||||
case token.Sub:
|
case token.Sub:
|
||||||
c.emit(node, OpSub)
|
c.emit(node, OpBinaryOp, int(token.Sub))
|
||||||
case token.Mul:
|
case token.Mul:
|
||||||
c.emit(node, OpMul)
|
c.emit(node, OpBinaryOp, int(token.Mul))
|
||||||
case token.Quo:
|
case token.Quo:
|
||||||
c.emit(node, OpDiv)
|
c.emit(node, OpBinaryOp, int(token.Quo))
|
||||||
case token.Rem:
|
case token.Rem:
|
||||||
c.emit(node, OpRem)
|
c.emit(node, OpBinaryOp, int(token.Rem))
|
||||||
case token.Greater:
|
case token.Greater:
|
||||||
c.emit(node, OpGreaterThan)
|
c.emit(node, OpBinaryOp, int(token.Greater))
|
||||||
case token.GreaterEq:
|
case token.GreaterEq:
|
||||||
c.emit(node, OpGreaterThanEqual)
|
c.emit(node, OpBinaryOp, int(token.GreaterEq))
|
||||||
case token.Equal:
|
case token.Equal:
|
||||||
c.emit(node, OpEqual)
|
c.emit(node, OpEqual)
|
||||||
case token.NotEqual:
|
case token.NotEqual:
|
||||||
c.emit(node, OpNotEqual)
|
c.emit(node, OpNotEqual)
|
||||||
case token.And:
|
case token.And:
|
||||||
c.emit(node, OpBAnd)
|
c.emit(node, OpBinaryOp, int(token.And))
|
||||||
case token.Or:
|
case token.Or:
|
||||||
c.emit(node, OpBOr)
|
c.emit(node, OpBinaryOp, int(token.Or))
|
||||||
case token.Xor:
|
case token.Xor:
|
||||||
c.emit(node, OpBXor)
|
c.emit(node, OpBinaryOp, int(token.Xor))
|
||||||
case token.AndNot:
|
case token.AndNot:
|
||||||
c.emit(node, OpBAndNot)
|
c.emit(node, OpBinaryOp, int(token.AndNot))
|
||||||
case token.Shl:
|
case token.Shl:
|
||||||
c.emit(node, OpBShiftLeft)
|
c.emit(node, OpBinaryOp, int(token.Shl))
|
||||||
case token.Shr:
|
case token.Shr:
|
||||||
c.emit(node, OpBShiftRight)
|
c.emit(node, OpBinaryOp, int(token.Shr))
|
||||||
default:
|
default:
|
||||||
return c.errorf(node, "invalid binary operator: %s", node.Token.String())
|
return c.errorf(node, "invalid binary operator: %s", node.Token.String())
|
||||||
}
|
}
|
||||||
@ -293,6 +292,15 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case *ast.BlockStmt:
|
case *ast.BlockStmt:
|
||||||
|
if len(node.Stmts) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
c.symbolTable = c.symbolTable.Fork(true)
|
||||||
|
defer func() {
|
||||||
|
c.symbolTable = c.symbolTable.Parent(false)
|
||||||
|
}()
|
||||||
|
|
||||||
for _, stmt := range node.Stmts {
|
for _, stmt := range node.Stmts {
|
||||||
if err := c.Compile(stmt); err != nil {
|
if err := c.Compile(stmt); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -405,10 +413,8 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// add OpReturn if function returns nothing
|
// code optimization
|
||||||
if !c.lastInstructionIs(OpReturnValue) && !c.lastInstructionIs(OpReturn) {
|
c.optimizeFunc(node)
|
||||||
c.emit(node, OpReturn)
|
|
||||||
}
|
|
||||||
|
|
||||||
freeSymbols := c.symbolTable.FreeSymbols()
|
freeSymbols := c.symbolTable.FreeSymbols()
|
||||||
numLocals := c.symbolTable.MaxSymbols()
|
numLocals := c.symbolTable.MaxSymbols()
|
||||||
@ -461,9 +467,9 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
s.LocalAssigned = true
|
s.LocalAssigned = true
|
||||||
}
|
}
|
||||||
|
|
||||||
c.emit(node, OpGetLocal, s.Index)
|
c.emit(node, OpGetLocalPtr, s.Index)
|
||||||
case ScopeFree:
|
case ScopeFree:
|
||||||
c.emit(node, OpGetFree, s.Index)
|
c.emit(node, OpGetFreePtr, s.Index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,13 +493,13 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if node.Result == nil {
|
if node.Result == nil {
|
||||||
c.emit(node, OpReturn)
|
c.emit(node, OpReturn, 0)
|
||||||
} else {
|
} else {
|
||||||
if err := c.Compile(node.Result); err != nil {
|
if err := c.Compile(node.Result); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.emit(node, OpReturnValue)
|
c.emit(node, OpReturn, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
@ -510,21 +516,57 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
c.emit(node, OpCall, len(node.Args))
|
c.emit(node, OpCall, len(node.Args))
|
||||||
|
|
||||||
case *ast.ImportExpr:
|
case *ast.ImportExpr:
|
||||||
if c.builtinModules[node.ModuleName] {
|
if node.ModuleName == "" {
|
||||||
if len(node.ModuleName) > tengo.MaxStringLen {
|
return c.errorf(node, "empty module name")
|
||||||
return c.error(node, objects.ErrStringLimit)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
c.emit(node, OpConstant, c.addConstant(&objects.String{Value: node.ModuleName}))
|
if mod := c.modules.Get(node.ModuleName); mod != nil {
|
||||||
c.emit(node, OpGetBuiltinModule)
|
v, err := mod.Import(node.ModuleName)
|
||||||
} else {
|
|
||||||
userMod, err := c.compileModule(node)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.emit(node, OpConstant, c.addConstant(userMod))
|
switch v := v.(type) {
|
||||||
|
case []byte: // module written in Tengo
|
||||||
|
compiled, err := c.compileModule(node, node.ModuleName, node.ModuleName, v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.emit(node, OpConstant, c.addConstant(compiled))
|
||||||
|
c.emit(node, OpCall, 0)
|
||||||
|
case objects.Object: // builtin module
|
||||||
|
c.emit(node, OpConstant, c.addConstant(v))
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("invalid import value type: %T", v))
|
||||||
|
}
|
||||||
|
} else if c.allowFileImport {
|
||||||
|
moduleName := node.ModuleName
|
||||||
|
if !strings.HasSuffix(moduleName, ".tengo") {
|
||||||
|
moduleName += ".tengo"
|
||||||
|
}
|
||||||
|
|
||||||
|
modulePath, err := filepath.Abs(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)
|
||||||
|
if err != nil {
|
||||||
|
return c.errorf(node, "module file read error: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
compiled, err := c.compileModule(node, moduleName, modulePath, moduleSrc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.emit(node, OpConstant, c.addConstant(compiled))
|
||||||
c.emit(node, OpCall, 0)
|
c.emit(node, OpCall, 0)
|
||||||
|
} else {
|
||||||
|
return c.errorf(node, "module '%s' not found", node.ModuleName)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.ExportStmt:
|
case *ast.ExportStmt:
|
||||||
@ -543,7 +585,7 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.emit(node, OpImmutable)
|
c.emit(node, OpImmutable)
|
||||||
c.emit(node, OpReturnValue)
|
c.emit(node, OpReturn, 1)
|
||||||
|
|
||||||
case *ast.ErrorExpr:
|
case *ast.ErrorExpr:
|
||||||
if err := c.Compile(node.Expr); err != nil {
|
if err := c.Compile(node.Expr); err != nil {
|
||||||
@ -602,18 +644,16 @@ func (c *Compiler) Bytecode() *Bytecode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetModuleLoader sets or replaces the current module loader.
|
// EnableFileImport enables or disables module loading from local files.
|
||||||
// Note that the module loader is used for user modules,
|
// Local file modules are disabled by default.
|
||||||
// not for the standard modules.
|
func (c *Compiler) EnableFileImport(enable bool) {
|
||||||
func (c *Compiler) SetModuleLoader(moduleLoader ModuleLoader) {
|
c.allowFileImport = enable
|
||||||
c.moduleLoader = moduleLoader
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) fork(file *source.File, moduleName string, symbolTable *SymbolTable) *Compiler {
|
func (c *Compiler) fork(file *source.File, modulePath string, symbolTable *SymbolTable) *Compiler {
|
||||||
child := NewCompiler(file, symbolTable, nil, c.builtinModules, c.trace)
|
child := NewCompiler(file, symbolTable, nil, c.modules, c.trace)
|
||||||
child.moduleName = moduleName // name of the module to compile
|
child.modulePath = modulePath // module file path
|
||||||
child.parent = c // parent to set to current compiler
|
child.parent = c // parent to set to current compiler
|
||||||
child.moduleLoader = c.moduleLoader // share module loader
|
|
||||||
|
|
||||||
return child
|
return child
|
||||||
}
|
}
|
||||||
@ -657,33 +697,6 @@ func (c *Compiler) addInstruction(b []byte) int {
|
|||||||
return posNewIns
|
return posNewIns
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) setLastInstruction(op Opcode, pos int) {
|
|
||||||
c.scopes[c.scopeIndex].lastInstructions[1] = c.scopes[c.scopeIndex].lastInstructions[0]
|
|
||||||
|
|
||||||
c.scopes[c.scopeIndex].lastInstructions[0].Opcode = op
|
|
||||||
c.scopes[c.scopeIndex].lastInstructions[0].Position = pos
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Compiler) lastInstructionIs(op Opcode) bool {
|
|
||||||
if len(c.currentInstructions()) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.scopes[c.scopeIndex].lastInstructions[0].Opcode == op
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Compiler) removeLastInstruction() {
|
|
||||||
lastPos := c.scopes[c.scopeIndex].lastInstructions[0].Position
|
|
||||||
|
|
||||||
if c.trace != nil {
|
|
||||||
c.printTrace(fmt.Sprintf("DELET %s",
|
|
||||||
FormatInstructions(c.scopes[c.scopeIndex].instructions[lastPos:], lastPos)[0]))
|
|
||||||
}
|
|
||||||
|
|
||||||
c.scopes[c.scopeIndex].instructions = c.currentInstructions()[:lastPos]
|
|
||||||
c.scopes[c.scopeIndex].lastInstructions[0] = c.scopes[c.scopeIndex].lastInstructions[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Compiler) replaceInstruction(pos int, inst []byte) {
|
func (c *Compiler) replaceInstruction(pos int, inst []byte) {
|
||||||
copy(c.currentInstructions()[pos:], inst)
|
copy(c.currentInstructions()[pos:], inst)
|
||||||
|
|
||||||
@ -700,6 +713,92 @@ func (c *Compiler) changeOperand(opPos int, operand ...int) {
|
|||||||
c.replaceInstruction(opPos, inst)
|
c.replaceInstruction(opPos, inst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optimizeFunc performs some code-level optimization for the current function instructions
|
||||||
|
// it removes unreachable (dead code) instructions and adds "returns" instruction if needed.
|
||||||
|
func (c *Compiler) optimizeFunc(node ast.Node) {
|
||||||
|
// any instructions between RETURN and the function end
|
||||||
|
// or instructions between RETURN and jump target position
|
||||||
|
// are considered as unreachable.
|
||||||
|
|
||||||
|
// pass 1. identify all jump destinations
|
||||||
|
dsts := make(map[int]bool)
|
||||||
|
iterateInstructions(c.scopes[c.scopeIndex].instructions, func(pos int, opcode Opcode, operands []int) bool {
|
||||||
|
switch opcode {
|
||||||
|
case OpJump, OpJumpFalsy, OpAndJump, OpOrJump:
|
||||||
|
dsts[operands[0]] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
var newInsts []byte
|
||||||
|
|
||||||
|
// pass 2. eliminate dead code
|
||||||
|
posMap := make(map[int]int) // old position to new position
|
||||||
|
var dstIdx int
|
||||||
|
var deadCode bool
|
||||||
|
iterateInstructions(c.scopes[c.scopeIndex].instructions, func(pos int, opcode Opcode, operands []int) bool {
|
||||||
|
switch {
|
||||||
|
case opcode == OpReturn:
|
||||||
|
if deadCode {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
deadCode = true
|
||||||
|
case dsts[pos]:
|
||||||
|
dstIdx++
|
||||||
|
deadCode = false
|
||||||
|
case deadCode:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
posMap[pos] = len(newInsts)
|
||||||
|
newInsts = append(newInsts, MakeInstruction(opcode, operands...)...)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
// pass 3. update jump positions
|
||||||
|
var lastOp Opcode
|
||||||
|
var appendReturn bool
|
||||||
|
endPos := len(c.scopes[c.scopeIndex].instructions)
|
||||||
|
iterateInstructions(newInsts, func(pos int, opcode Opcode, operands []int) bool {
|
||||||
|
switch opcode {
|
||||||
|
case OpJump, OpJumpFalsy, OpAndJump, OpOrJump:
|
||||||
|
newDst, ok := posMap[operands[0]]
|
||||||
|
if ok {
|
||||||
|
copy(newInsts[pos:], MakeInstruction(opcode, newDst))
|
||||||
|
} else if endPos == operands[0] {
|
||||||
|
// there's a jump instruction that jumps to the end of function
|
||||||
|
// compiler should append "return".
|
||||||
|
appendReturn = true
|
||||||
|
} else {
|
||||||
|
panic(fmt.Errorf("invalid jump position: %d", newDst))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastOp = opcode
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if lastOp != OpReturn {
|
||||||
|
appendReturn = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// pass 4. update source map
|
||||||
|
newSourceMap := make(map[int]source.Pos)
|
||||||
|
for pos, srcPos := range c.scopes[c.scopeIndex].sourceMap {
|
||||||
|
newPos, ok := posMap[pos]
|
||||||
|
if ok {
|
||||||
|
newSourceMap[newPos] = srcPos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.scopes[c.scopeIndex].instructions = newInsts
|
||||||
|
c.scopes[c.scopeIndex].sourceMap = newSourceMap
|
||||||
|
|
||||||
|
// append "return"
|
||||||
|
if appendReturn {
|
||||||
|
c.emit(node, OpReturn, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Compiler) emit(node ast.Node, opcode Opcode, operands ...int) int {
|
func (c *Compiler) emit(node ast.Node, opcode Opcode, operands ...int) int {
|
||||||
filePos := source.NoPos
|
filePos := source.NoPos
|
||||||
if node != nil {
|
if node != nil {
|
||||||
@ -709,7 +808,6 @@ func (c *Compiler) emit(node ast.Node, opcode Opcode, operands ...int) int {
|
|||||||
inst := MakeInstruction(opcode, operands...)
|
inst := MakeInstruction(opcode, operands...)
|
||||||
pos := c.addInstruction(inst)
|
pos := c.addInstruction(inst)
|
||||||
c.scopes[c.scopeIndex].sourceMap[pos] = filePos
|
c.scopes[c.scopeIndex].sourceMap[pos] = filePos
|
||||||
c.setLastInstruction(opcode, pos)
|
|
||||||
|
|
||||||
if c.trace != nil {
|
if c.trace != nil {
|
||||||
c.printTrace(fmt.Sprintf("EMIT %s",
|
c.printTrace(fmt.Sprintf("EMIT %s",
|
||||||
|
22
vendor/github.com/d5/tengo/compiler/compiler_assign.go
generated
vendored
22
vendor/github.com/d5/tengo/compiler/compiler_assign.go
generated
vendored
@ -51,27 +51,27 @@ func (c *Compiler) compileAssign(node ast.Node, lhs, rhs []ast.Expr, op token.To
|
|||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case token.AddAssign:
|
case token.AddAssign:
|
||||||
c.emit(node, OpAdd)
|
c.emit(node, OpBinaryOp, int(token.Add))
|
||||||
case token.SubAssign:
|
case token.SubAssign:
|
||||||
c.emit(node, OpSub)
|
c.emit(node, OpBinaryOp, int(token.Sub))
|
||||||
case token.MulAssign:
|
case token.MulAssign:
|
||||||
c.emit(node, OpMul)
|
c.emit(node, OpBinaryOp, int(token.Mul))
|
||||||
case token.QuoAssign:
|
case token.QuoAssign:
|
||||||
c.emit(node, OpDiv)
|
c.emit(node, OpBinaryOp, int(token.Quo))
|
||||||
case token.RemAssign:
|
case token.RemAssign:
|
||||||
c.emit(node, OpRem)
|
c.emit(node, OpBinaryOp, int(token.Rem))
|
||||||
case token.AndAssign:
|
case token.AndAssign:
|
||||||
c.emit(node, OpBAnd)
|
c.emit(node, OpBinaryOp, int(token.And))
|
||||||
case token.OrAssign:
|
case token.OrAssign:
|
||||||
c.emit(node, OpBOr)
|
c.emit(node, OpBinaryOp, int(token.Or))
|
||||||
case token.AndNotAssign:
|
case token.AndNotAssign:
|
||||||
c.emit(node, OpBAndNot)
|
c.emit(node, OpBinaryOp, int(token.AndNot))
|
||||||
case token.XorAssign:
|
case token.XorAssign:
|
||||||
c.emit(node, OpBXor)
|
c.emit(node, OpBinaryOp, int(token.Xor))
|
||||||
case token.ShlAssign:
|
case token.ShlAssign:
|
||||||
c.emit(node, OpBShiftLeft)
|
c.emit(node, OpBinaryOp, int(token.Shl))
|
||||||
case token.ShrAssign:
|
case token.ShrAssign:
|
||||||
c.emit(node, OpBShiftRight)
|
c.emit(node, OpBinaryOp, int(token.Shr))
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile selector expressions (right to left)
|
// compile selector expressions (right to left)
|
||||||
|
91
vendor/github.com/d5/tengo/compiler/compiler_module.go
generated
vendored
91
vendor/github.com/d5/tengo/compiler/compiler_module.go
generated
vendored
@ -1,72 +1,31 @@
|
|||||||
package compiler
|
package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/d5/tengo/compiler/ast"
|
"github.com/d5/tengo/compiler/ast"
|
||||||
"github.com/d5/tengo/compiler/parser"
|
"github.com/d5/tengo/compiler/parser"
|
||||||
"github.com/d5/tengo/objects"
|
"github.com/d5/tengo/objects"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Compiler) compileModule(expr *ast.ImportExpr) (*objects.CompiledFunction, error) {
|
func (c *Compiler) checkCyclicImports(node ast.Node, modulePath string) error {
|
||||||
compiledModule, exists := c.loadCompiledModule(expr.ModuleName)
|
if c.modulePath == modulePath {
|
||||||
if exists {
|
return c.errorf(node, "cyclic module import: %s", modulePath)
|
||||||
return compiledModule, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
moduleName := expr.ModuleName
|
|
||||||
|
|
||||||
// read module source from loader
|
|
||||||
var moduleSrc []byte
|
|
||||||
if c.moduleLoader == nil {
|
|
||||||
// default loader: read from local file
|
|
||||||
if !strings.HasSuffix(moduleName, ".tengo") {
|
|
||||||
moduleName += ".tengo"
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.checkCyclicImports(expr, moduleName); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
moduleSrc, err = ioutil.ReadFile(moduleName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, c.errorf(expr, "module file read error: %s", err.Error())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := c.checkCyclicImports(expr, moduleName); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
moduleSrc, err = c.moduleLoader(moduleName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compiledModule, err := c.doCompileModule(moduleName, moduleSrc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.storeCompiledModule(moduleName, compiledModule)
|
|
||||||
|
|
||||||
return compiledModule, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Compiler) checkCyclicImports(node ast.Node, moduleName string) error {
|
|
||||||
if c.moduleName == moduleName {
|
|
||||||
return c.errorf(node, "cyclic module import: %s", moduleName)
|
|
||||||
} else if c.parent != nil {
|
} else if c.parent != nil {
|
||||||
return c.parent.checkCyclicImports(node, moduleName)
|
return c.parent.checkCyclicImports(node, modulePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) doCompileModule(moduleName string, src []byte) (*objects.CompiledFunction, error) {
|
func (c *Compiler) compileModule(node ast.Node, moduleName, modulePath string, src []byte) (*objects.CompiledFunction, error) {
|
||||||
|
if err := c.checkCyclicImports(node, modulePath); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
compiledModule, exists := c.loadCompiledModule(modulePath)
|
||||||
|
if exists {
|
||||||
|
return compiledModule, nil
|
||||||
|
}
|
||||||
|
|
||||||
modFile := c.file.Set().AddFile(moduleName, -1, len(src))
|
modFile := c.file.Set().AddFile(moduleName, -1, len(src))
|
||||||
p := parser.NewParser(modFile, src, nil)
|
p := parser.NewParser(modFile, src, nil)
|
||||||
file, err := p.ParseFile()
|
file, err := p.ParseFile()
|
||||||
@ -85,36 +44,36 @@ func (c *Compiler) doCompileModule(moduleName string, src []byte) (*objects.Comp
|
|||||||
symbolTable = symbolTable.Fork(false)
|
symbolTable = symbolTable.Fork(false)
|
||||||
|
|
||||||
// compile module
|
// compile module
|
||||||
moduleCompiler := c.fork(modFile, moduleName, symbolTable)
|
moduleCompiler := c.fork(modFile, modulePath, symbolTable)
|
||||||
if err := moduleCompiler.Compile(file); err != nil {
|
if err := moduleCompiler.Compile(file); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// add OpReturn (== export undefined) if export is missing
|
// code optimization
|
||||||
if !moduleCompiler.lastInstructionIs(OpReturnValue) {
|
moduleCompiler.optimizeFunc(node)
|
||||||
moduleCompiler.emit(nil, OpReturn)
|
|
||||||
}
|
|
||||||
|
|
||||||
compiledFunc := moduleCompiler.Bytecode().MainFunction
|
compiledFunc := moduleCompiler.Bytecode().MainFunction
|
||||||
compiledFunc.NumLocals = symbolTable.MaxSymbols()
|
compiledFunc.NumLocals = symbolTable.MaxSymbols()
|
||||||
|
|
||||||
|
c.storeCompiledModule(modulePath, compiledFunc)
|
||||||
|
|
||||||
return compiledFunc, nil
|
return compiledFunc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) loadCompiledModule(moduleName string) (mod *objects.CompiledFunction, ok bool) {
|
func (c *Compiler) loadCompiledModule(modulePath string) (mod *objects.CompiledFunction, ok bool) {
|
||||||
if c.parent != nil {
|
if c.parent != nil {
|
||||||
return c.parent.loadCompiledModule(moduleName)
|
return c.parent.loadCompiledModule(modulePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
mod, ok = c.compiledModules[moduleName]
|
mod, ok = c.compiledModules[modulePath]
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) storeCompiledModule(moduleName string, module *objects.CompiledFunction) {
|
func (c *Compiler) storeCompiledModule(modulePath string, module *objects.CompiledFunction) {
|
||||||
if c.parent != nil {
|
if c.parent != nil {
|
||||||
c.parent.storeCompiledModule(moduleName, module)
|
c.parent.storeCompiledModule(modulePath, module)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.compiledModules[moduleName] = module
|
c.compiledModules[modulePath] = module
|
||||||
}
|
}
|
||||||
|
13
vendor/github.com/d5/tengo/compiler/instructions.go
generated
vendored
13
vendor/github.com/d5/tengo/compiler/instructions.go
generated
vendored
@ -57,3 +57,16 @@ func FormatInstructions(b []byte, posOffset int) []string {
|
|||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func iterateInstructions(b []byte, fn func(pos int, opcode Opcode, operands []int) bool) {
|
||||||
|
for i := 0; i < len(b); i++ {
|
||||||
|
numOperands := OpcodeOperands[Opcode(b[i])]
|
||||||
|
operands, read := ReadOperands(numOperands, b[i+1:])
|
||||||
|
|
||||||
|
if !fn(i, b[i], operands) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
i += read
|
||||||
|
}
|
||||||
|
}
|
||||||
|
282
vendor/github.com/d5/tengo/compiler/opcodes.go
generated
vendored
282
vendor/github.com/d5/tengo/compiler/opcodes.go
generated
vendored
@ -5,173 +5,137 @@ type Opcode = byte
|
|||||||
|
|
||||||
// List of opcodes
|
// List of opcodes
|
||||||
const (
|
const (
|
||||||
OpConstant Opcode = iota // Load constant
|
OpConstant Opcode = iota // Load constant
|
||||||
OpAdd // Add
|
OpBComplement // bitwise complement
|
||||||
OpSub // Sub
|
OpPop // Pop
|
||||||
OpMul // Multiply
|
OpTrue // Push true
|
||||||
OpDiv // Divide
|
OpFalse // Push false
|
||||||
OpRem // Remainder
|
OpEqual // Equal ==
|
||||||
OpBAnd // bitwise AND
|
OpNotEqual // Not equal !=
|
||||||
OpBOr // bitwise OR
|
OpMinus // Minus -
|
||||||
OpBXor // bitwise XOR
|
OpLNot // Logical not !
|
||||||
OpBShiftLeft // bitwise shift left
|
OpJumpFalsy // Jump if falsy
|
||||||
OpBShiftRight // bitwise shift right
|
OpAndJump // Logical AND jump
|
||||||
OpBAndNot // bitwise AND NOT
|
OpOrJump // Logical OR jump
|
||||||
OpBComplement // bitwise complement
|
OpJump // Jump
|
||||||
OpPop // Pop
|
OpNull // Push null
|
||||||
OpTrue // Push true
|
OpArray // Array object
|
||||||
OpFalse // Push false
|
OpMap // Map object
|
||||||
OpEqual // Equal ==
|
OpError // Error object
|
||||||
OpNotEqual // Not equal !=
|
OpImmutable // Immutable object
|
||||||
OpGreaterThan // Greater than >=
|
OpIndex // Index operation
|
||||||
OpGreaterThanEqual // Greater than or equal to >=
|
OpSliceIndex // Slice operation
|
||||||
OpMinus // Minus -
|
OpCall // Call function
|
||||||
OpLNot // Logical not !
|
OpReturn // Return
|
||||||
OpJumpFalsy // Jump if falsy
|
OpGetGlobal // Get global variable
|
||||||
OpAndJump // Logical AND jump
|
OpSetGlobal // Set global variable
|
||||||
OpOrJump // Logical OR jump
|
OpSetSelGlobal // Set global variable using selectors
|
||||||
OpJump // Jump
|
OpGetLocal // Get local variable
|
||||||
OpNull // Push null
|
OpSetLocal // Set local variable
|
||||||
OpArray // Array object
|
OpDefineLocal // Define local variable
|
||||||
OpMap // Map object
|
OpSetSelLocal // Set local variable using selectors
|
||||||
OpError // Error object
|
OpGetFreePtr // Get free variable pointer object
|
||||||
OpImmutable // Immutable object
|
OpGetFree // Get free variables
|
||||||
OpIndex // Index operation
|
OpSetFree // Set free variables
|
||||||
OpSliceIndex // Slice operation
|
OpGetLocalPtr // Get local variable as a pointer
|
||||||
OpCall // Call function
|
OpSetSelFree // Set free variables using selectors
|
||||||
OpReturn // Return
|
OpGetBuiltin // Get builtin function
|
||||||
OpReturnValue // Return value
|
OpClosure // Push closure
|
||||||
OpGetGlobal // Get global variable
|
OpIteratorInit // Iterator init
|
||||||
OpSetGlobal // Set global variable
|
OpIteratorNext // Iterator next
|
||||||
OpSetSelGlobal // Set global variable using selectors
|
OpIteratorKey // Iterator key
|
||||||
OpGetLocal // Get local variable
|
OpIteratorValue // Iterator value
|
||||||
OpSetLocal // Set local variable
|
OpBinaryOp // Binary Operation
|
||||||
OpDefineLocal // Define local variable
|
|
||||||
OpSetSelLocal // Set local variable using selectors
|
|
||||||
OpGetFree // Get free variables
|
|
||||||
OpSetFree // Set free variables
|
|
||||||
OpSetSelFree // Set free variables using selectors
|
|
||||||
OpGetBuiltin // Get builtin function
|
|
||||||
OpGetBuiltinModule // Get builtin module
|
|
||||||
OpClosure // Push closure
|
|
||||||
OpIteratorInit // Iterator init
|
|
||||||
OpIteratorNext // Iterator next
|
|
||||||
OpIteratorKey // Iterator key
|
|
||||||
OpIteratorValue // Iterator value
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// OpcodeNames is opcode names.
|
// OpcodeNames is opcode names.
|
||||||
var OpcodeNames = [...]string{
|
var OpcodeNames = [...]string{
|
||||||
OpConstant: "CONST",
|
OpConstant: "CONST",
|
||||||
OpPop: "POP",
|
OpPop: "POP",
|
||||||
OpTrue: "TRUE",
|
OpTrue: "TRUE",
|
||||||
OpFalse: "FALSE",
|
OpFalse: "FALSE",
|
||||||
OpAdd: "ADD",
|
OpBComplement: "NEG",
|
||||||
OpSub: "SUB",
|
OpEqual: "EQL",
|
||||||
OpMul: "MUL",
|
OpNotEqual: "NEQ",
|
||||||
OpDiv: "DIV",
|
OpMinus: "NEG",
|
||||||
OpRem: "REM",
|
OpLNot: "NOT",
|
||||||
OpBAnd: "AND",
|
OpJumpFalsy: "JMPF",
|
||||||
OpBOr: "OR",
|
OpAndJump: "ANDJMP",
|
||||||
OpBXor: "XOR",
|
OpOrJump: "ORJMP",
|
||||||
OpBAndNot: "ANDN",
|
OpJump: "JMP",
|
||||||
OpBShiftLeft: "SHL",
|
OpNull: "NULL",
|
||||||
OpBShiftRight: "SHR",
|
OpGetGlobal: "GETG",
|
||||||
OpBComplement: "NEG",
|
OpSetGlobal: "SETG",
|
||||||
OpEqual: "EQL",
|
OpSetSelGlobal: "SETSG",
|
||||||
OpNotEqual: "NEQ",
|
OpArray: "ARR",
|
||||||
OpGreaterThan: "GTR",
|
OpMap: "MAP",
|
||||||
OpGreaterThanEqual: "GEQ",
|
OpError: "ERROR",
|
||||||
OpMinus: "NEG",
|
OpImmutable: "IMMUT",
|
||||||
OpLNot: "NOT",
|
OpIndex: "INDEX",
|
||||||
OpJumpFalsy: "JMPF",
|
OpSliceIndex: "SLICE",
|
||||||
OpAndJump: "ANDJMP",
|
OpCall: "CALL",
|
||||||
OpOrJump: "ORJMP",
|
OpReturn: "RET",
|
||||||
OpJump: "JMP",
|
OpGetLocal: "GETL",
|
||||||
OpNull: "NULL",
|
OpSetLocal: "SETL",
|
||||||
OpGetGlobal: "GETG",
|
OpDefineLocal: "DEFL",
|
||||||
OpSetGlobal: "SETG",
|
OpSetSelLocal: "SETSL",
|
||||||
OpSetSelGlobal: "SETSG",
|
OpGetBuiltin: "BUILTIN",
|
||||||
OpArray: "ARR",
|
OpClosure: "CLOSURE",
|
||||||
OpMap: "MAP",
|
OpGetFreePtr: "GETFP",
|
||||||
OpError: "ERROR",
|
OpGetFree: "GETF",
|
||||||
OpImmutable: "IMMUT",
|
OpSetFree: "SETF",
|
||||||
OpIndex: "INDEX",
|
OpGetLocalPtr: "GETLP",
|
||||||
OpSliceIndex: "SLICE",
|
OpSetSelFree: "SETSF",
|
||||||
OpCall: "CALL",
|
OpIteratorInit: "ITER",
|
||||||
OpReturn: "RET",
|
OpIteratorNext: "ITNXT",
|
||||||
OpReturnValue: "RETVAL",
|
OpIteratorKey: "ITKEY",
|
||||||
OpGetLocal: "GETL",
|
OpIteratorValue: "ITVAL",
|
||||||
OpSetLocal: "SETL",
|
OpBinaryOp: "BINARYOP",
|
||||||
OpDefineLocal: "DEFL",
|
|
||||||
OpSetSelLocal: "SETSL",
|
|
||||||
OpGetBuiltin: "BUILTIN",
|
|
||||||
OpGetBuiltinModule: "BLTMOD",
|
|
||||||
OpClosure: "CLOSURE",
|
|
||||||
OpGetFree: "GETF",
|
|
||||||
OpSetFree: "SETF",
|
|
||||||
OpSetSelFree: "SETSF",
|
|
||||||
OpIteratorInit: "ITER",
|
|
||||||
OpIteratorNext: "ITNXT",
|
|
||||||
OpIteratorKey: "ITKEY",
|
|
||||||
OpIteratorValue: "ITVAL",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpcodeOperands is the number of operands.
|
// OpcodeOperands is the number of operands.
|
||||||
var OpcodeOperands = [...][]int{
|
var OpcodeOperands = [...][]int{
|
||||||
OpConstant: {2},
|
OpConstant: {2},
|
||||||
OpPop: {},
|
OpPop: {},
|
||||||
OpTrue: {},
|
OpTrue: {},
|
||||||
OpFalse: {},
|
OpFalse: {},
|
||||||
OpAdd: {},
|
OpBComplement: {},
|
||||||
OpSub: {},
|
OpEqual: {},
|
||||||
OpMul: {},
|
OpNotEqual: {},
|
||||||
OpDiv: {},
|
OpMinus: {},
|
||||||
OpRem: {},
|
OpLNot: {},
|
||||||
OpBAnd: {},
|
OpJumpFalsy: {2},
|
||||||
OpBOr: {},
|
OpAndJump: {2},
|
||||||
OpBXor: {},
|
OpOrJump: {2},
|
||||||
OpBAndNot: {},
|
OpJump: {2},
|
||||||
OpBShiftLeft: {},
|
OpNull: {},
|
||||||
OpBShiftRight: {},
|
OpGetGlobal: {2},
|
||||||
OpBComplement: {},
|
OpSetGlobal: {2},
|
||||||
OpEqual: {},
|
OpSetSelGlobal: {2, 1},
|
||||||
OpNotEqual: {},
|
OpArray: {2},
|
||||||
OpGreaterThan: {},
|
OpMap: {2},
|
||||||
OpGreaterThanEqual: {},
|
OpError: {},
|
||||||
OpMinus: {},
|
OpImmutable: {},
|
||||||
OpLNot: {},
|
OpIndex: {},
|
||||||
OpJumpFalsy: {2},
|
OpSliceIndex: {},
|
||||||
OpAndJump: {2},
|
OpCall: {1},
|
||||||
OpOrJump: {2},
|
OpReturn: {1},
|
||||||
OpJump: {2},
|
OpGetLocal: {1},
|
||||||
OpNull: {},
|
OpSetLocal: {1},
|
||||||
OpGetGlobal: {2},
|
OpDefineLocal: {1},
|
||||||
OpSetGlobal: {2},
|
OpSetSelLocal: {1, 1},
|
||||||
OpSetSelGlobal: {2, 1},
|
OpGetBuiltin: {1},
|
||||||
OpArray: {2},
|
OpClosure: {2, 1},
|
||||||
OpMap: {2},
|
OpGetFreePtr: {1},
|
||||||
OpError: {},
|
OpGetFree: {1},
|
||||||
OpImmutable: {},
|
OpSetFree: {1},
|
||||||
OpIndex: {},
|
OpGetLocalPtr: {1},
|
||||||
OpSliceIndex: {},
|
OpSetSelFree: {1, 1},
|
||||||
OpCall: {1},
|
OpIteratorInit: {},
|
||||||
OpReturn: {},
|
OpIteratorNext: {},
|
||||||
OpReturnValue: {},
|
OpIteratorKey: {},
|
||||||
OpGetLocal: {1},
|
OpIteratorValue: {},
|
||||||
OpSetLocal: {1},
|
OpBinaryOp: {1},
|
||||||
OpDefineLocal: {1},
|
|
||||||
OpSetSelLocal: {1, 1},
|
|
||||||
OpGetBuiltin: {1},
|
|
||||||
OpGetBuiltinModule: {},
|
|
||||||
OpClosure: {2, 1},
|
|
||||||
OpGetFree: {1},
|
|
||||||
OpSetFree: {1},
|
|
||||||
OpSetSelFree: {1, 1},
|
|
||||||
OpIteratorInit: {},
|
|
||||||
OpIteratorNext: {},
|
|
||||||
OpIteratorKey: {},
|
|
||||||
OpIteratorValue: {},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadOperands reads operands from the bytecode.
|
// ReadOperands reads operands from the bytecode.
|
||||||
|
4
vendor/github.com/d5/tengo/compiler/symbol_table.go
generated
vendored
4
vendor/github.com/d5/tengo/compiler/symbol_table.go
generated
vendored
@ -64,9 +64,7 @@ func (t *SymbolTable) Resolve(name string) (symbol *Symbol, depth int, ok bool)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !t.block {
|
depth++
|
||||||
depth++
|
|
||||||
}
|
|
||||||
|
|
||||||
// if symbol is defined in parent table and if it's not global/builtin
|
// if symbol is defined in parent table and if it's not global/builtin
|
||||||
// then it's free variable.
|
// then it's free variable.
|
||||||
|
37
vendor/github.com/d5/tengo/objects/break.go
generated
vendored
37
vendor/github.com/d5/tengo/objects/break.go
generated
vendored
@ -1,37 +0,0 @@
|
|||||||
package objects
|
|
||||||
|
|
||||||
import "github.com/d5/tengo/compiler/token"
|
|
||||||
|
|
||||||
// Break represents a break statement.
|
|
||||||
type Break struct{}
|
|
||||||
|
|
||||||
// TypeName returns the name of the type.
|
|
||||||
func (o *Break) TypeName() string {
|
|
||||||
return "break"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Break) String() string {
|
|
||||||
return "<break>"
|
|
||||||
}
|
|
||||||
|
|
||||||
// BinaryOp returns another object that is the result of
|
|
||||||
// a given binary operator and a right-hand side object.
|
|
||||||
func (o *Break) BinaryOp(op token.Token, rhs Object) (Object, error) {
|
|
||||||
return nil, ErrInvalidOperator
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy returns a copy of the type.
|
|
||||||
func (o *Break) Copy() Object {
|
|
||||||
return &Break{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsFalsy returns true if the value of the type is falsy.
|
|
||||||
func (o *Break) IsFalsy() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equals returns true if the value of the type
|
|
||||||
// is equal to the value of another object.
|
|
||||||
func (o *Break) Equals(x Object) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
60
vendor/github.com/d5/tengo/objects/builtin_json.go
generated
vendored
60
vendor/github.com/d5/tengo/objects/builtin_json.go
generated
vendored
@ -1,60 +0,0 @@
|
|||||||
package objects
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/d5/tengo"
|
|
||||||
)
|
|
||||||
|
|
||||||
// to_json(v object) => bytes
|
|
||||||
func builtinToJSON(args ...Object) (Object, error) {
|
|
||||||
if len(args) != 1 {
|
|
||||||
return nil, ErrWrongNumArguments
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := json.Marshal(objectToInterface(args[0]))
|
|
||||||
if err != nil {
|
|
||||||
return &Error{Value: &String{Value: err.Error()}}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(res) > tengo.MaxBytesLen {
|
|
||||||
return nil, ErrBytesLimit
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Bytes{Value: res}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// from_json(data string/bytes) => object
|
|
||||||
func builtinFromJSON(args ...Object) (Object, error) {
|
|
||||||
if len(args) != 1 {
|
|
||||||
return nil, ErrWrongNumArguments
|
|
||||||
}
|
|
||||||
|
|
||||||
var target interface{}
|
|
||||||
|
|
||||||
switch o := args[0].(type) {
|
|
||||||
case *Bytes:
|
|
||||||
err := json.Unmarshal(o.Value, &target)
|
|
||||||
if err != nil {
|
|
||||||
return &Error{Value: &String{Value: err.Error()}}, nil
|
|
||||||
}
|
|
||||||
case *String:
|
|
||||||
err := json.Unmarshal([]byte(o.Value), &target)
|
|
||||||
if err != nil {
|
|
||||||
return &Error{Value: &String{Value: err.Error()}}, nil
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, ErrInvalidArgumentType{
|
|
||||||
Name: "first",
|
|
||||||
Expected: "bytes/string",
|
|
||||||
Found: args[0].TypeName(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := FromInterface(target)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
23
vendor/github.com/d5/tengo/objects/builtin_module.go
generated
vendored
Normal file
23
vendor/github.com/d5/tengo/objects/builtin_module.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package objects
|
||||||
|
|
||||||
|
// BuiltinModule is an importable module that's written in Go.
|
||||||
|
type BuiltinModule struct {
|
||||||
|
Attrs map[string]Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import returns an immutable map for the module.
|
||||||
|
func (m *BuiltinModule) Import(moduleName string) (interface{}, error) {
|
||||||
|
return m.AsImmutableMap(moduleName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsImmutableMap converts builtin module into an immutable map.
|
||||||
|
func (m *BuiltinModule) AsImmutableMap(moduleName string) *ImmutableMap {
|
||||||
|
attrs := make(map[string]Object, len(m.Attrs))
|
||||||
|
for k, v := range m.Attrs {
|
||||||
|
attrs[k] = v.Copy()
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs["__module_name__"] = &String{Value: moduleName}
|
||||||
|
|
||||||
|
return &ImmutableMap{Value: attrs}
|
||||||
|
}
|
83
vendor/github.com/d5/tengo/objects/builtin_print.go
generated
vendored
83
vendor/github.com/d5/tengo/objects/builtin_print.go
generated
vendored
@ -1,83 +0,0 @@
|
|||||||
package objects
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/d5/tengo"
|
|
||||||
)
|
|
||||||
|
|
||||||
// print(args...)
|
|
||||||
func builtinPrint(args ...Object) (Object, error) {
|
|
||||||
for _, arg := range args {
|
|
||||||
if str, ok := arg.(*String); ok {
|
|
||||||
fmt.Println(str.Value)
|
|
||||||
} else {
|
|
||||||
fmt.Println(arg.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// printf("format", args...)
|
|
||||||
func builtinPrintf(args ...Object) (Object, error) {
|
|
||||||
numArgs := len(args)
|
|
||||||
if numArgs == 0 {
|
|
||||||
return nil, ErrWrongNumArguments
|
|
||||||
}
|
|
||||||
|
|
||||||
format, ok := args[0].(*String)
|
|
||||||
if !ok {
|
|
||||||
return nil, ErrInvalidArgumentType{
|
|
||||||
Name: "format",
|
|
||||||
Expected: "string",
|
|
||||||
Found: args[0].TypeName(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if numArgs == 1 {
|
|
||||||
fmt.Print(format)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
formatArgs := make([]interface{}, numArgs-1, numArgs-1)
|
|
||||||
for idx, arg := range args[1:] {
|
|
||||||
formatArgs[idx] = objectToInterface(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf(format.Value, formatArgs...)
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// sprintf("format", args...)
|
|
||||||
func builtinSprintf(args ...Object) (Object, error) {
|
|
||||||
numArgs := len(args)
|
|
||||||
if numArgs == 0 {
|
|
||||||
return nil, ErrWrongNumArguments
|
|
||||||
}
|
|
||||||
|
|
||||||
format, ok := args[0].(*String)
|
|
||||||
if !ok {
|
|
||||||
return nil, ErrInvalidArgumentType{
|
|
||||||
Name: "format",
|
|
||||||
Expected: "string",
|
|
||||||
Found: args[0].TypeName(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if numArgs == 1 {
|
|
||||||
return format, nil // okay to return 'format' directly as String is immutable
|
|
||||||
}
|
|
||||||
|
|
||||||
formatArgs := make([]interface{}, numArgs-1, numArgs-1)
|
|
||||||
for idx, arg := range args[1:] {
|
|
||||||
formatArgs[idx] = objectToInterface(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
s := fmt.Sprintf(format.Value, formatArgs...)
|
|
||||||
|
|
||||||
if len(s) > tengo.MaxStringLen {
|
|
||||||
return nil, ErrStringLimit
|
|
||||||
}
|
|
||||||
|
|
||||||
return &String{Value: s}, nil
|
|
||||||
}
|
|
12
vendor/github.com/d5/tengo/objects/builtin_type_checks.go
generated
vendored
12
vendor/github.com/d5/tengo/objects/builtin_type_checks.go
generated
vendored
@ -181,3 +181,15 @@ func builtinIsCallable(args ...Object) (Object, error) {
|
|||||||
|
|
||||||
return FalseValue, nil
|
return FalseValue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func builtinIsIterable(args ...Object) (Object, error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := args[0].(Iterable); ok {
|
||||||
|
return TrueValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return FalseValue, nil
|
||||||
|
}
|
||||||
|
60
vendor/github.com/d5/tengo/objects/builtins.go
generated
vendored
60
vendor/github.com/d5/tengo/objects/builtins.go
generated
vendored
@ -2,19 +2,7 @@ package objects
|
|||||||
|
|
||||||
// Builtins contains all default builtin functions.
|
// Builtins contains all default builtin functions.
|
||||||
// Use GetBuiltinFunctions instead of accessing Builtins directly.
|
// Use GetBuiltinFunctions instead of accessing Builtins directly.
|
||||||
var Builtins = []BuiltinFunction{
|
var Builtins = []*BuiltinFunction{
|
||||||
{
|
|
||||||
Name: "print",
|
|
||||||
Value: builtinPrint,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "printf",
|
|
||||||
Value: builtinPrintf,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "sprintf",
|
|
||||||
Value: builtinSprintf,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "len",
|
Name: "len",
|
||||||
Value: builtinLen,
|
Value: builtinLen,
|
||||||
@ -95,6 +83,10 @@ var Builtins = []BuiltinFunction{
|
|||||||
Name: "is_immutable_map",
|
Name: "is_immutable_map",
|
||||||
Value: builtinIsImmutableMap,
|
Value: builtinIsImmutableMap,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "is_iterable",
|
||||||
|
Value: builtinIsIterable,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "is_time",
|
Name: "is_time",
|
||||||
Value: builtinIsTime,
|
Value: builtinIsTime,
|
||||||
@ -115,50 +107,8 @@ var Builtins = []BuiltinFunction{
|
|||||||
Name: "is_callable",
|
Name: "is_callable",
|
||||||
Value: builtinIsCallable,
|
Value: builtinIsCallable,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "to_json",
|
|
||||||
Value: builtinToJSON,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "from_json",
|
|
||||||
Value: builtinFromJSON,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "type_name",
|
Name: "type_name",
|
||||||
Value: builtinTypeName,
|
Value: builtinTypeName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllBuiltinFunctionNames returns a list of all default builtin function names.
|
|
||||||
func AllBuiltinFunctionNames() []string {
|
|
||||||
var names []string
|
|
||||||
for _, bf := range Builtins {
|
|
||||||
names = append(names, bf.Name)
|
|
||||||
}
|
|
||||||
return names
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBuiltinFunctions returns a slice of builtin function objects.
|
|
||||||
// GetBuiltinFunctions removes the duplicate names, and, the returned builtin functions
|
|
||||||
// are not guaranteed to be in the same order as names.
|
|
||||||
func GetBuiltinFunctions(names ...string) []*BuiltinFunction {
|
|
||||||
include := make(map[string]bool)
|
|
||||||
for _, name := range names {
|
|
||||||
include[name] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
var builtinFuncs []*BuiltinFunction
|
|
||||||
for _, bf := range Builtins {
|
|
||||||
if include[bf.Name] {
|
|
||||||
bf := bf
|
|
||||||
builtinFuncs = append(builtinFuncs, &bf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return builtinFuncs
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllBuiltinFunctions returns all builtin functions.
|
|
||||||
func GetAllBuiltinFunctions() []*BuiltinFunction {
|
|
||||||
return GetBuiltinFunctions(AllBuiltinFunctionNames()...)
|
|
||||||
}
|
|
||||||
|
8
vendor/github.com/d5/tengo/objects/bytes.go
generated
vendored
8
vendor/github.com/d5/tengo/objects/bytes.go
generated
vendored
@ -79,3 +79,11 @@ func (o *Bytes) IndexGet(index Object) (res Object, err error) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate creates a bytes iterator.
|
||||||
|
func (o *Bytes) Iterate() Iterator {
|
||||||
|
return &BytesIterator{
|
||||||
|
v: o.Value,
|
||||||
|
l: len(o.Value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
57
vendor/github.com/d5/tengo/objects/bytes_iterator.go
generated
vendored
Normal file
57
vendor/github.com/d5/tengo/objects/bytes_iterator.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package objects
|
||||||
|
|
||||||
|
import "github.com/d5/tengo/compiler/token"
|
||||||
|
|
||||||
|
// BytesIterator represents an iterator for a string.
|
||||||
|
type BytesIterator struct {
|
||||||
|
v []byte
|
||||||
|
i int
|
||||||
|
l int
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeName returns the name of the type.
|
||||||
|
func (i *BytesIterator) TypeName() string {
|
||||||
|
return "bytes-iterator"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *BytesIterator) String() string {
|
||||||
|
return "<bytes-iterator>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinaryOp returns another object that is the result of
|
||||||
|
// a given binary operator and a right-hand side object.
|
||||||
|
func (i *BytesIterator) BinaryOp(op token.Token, rhs Object) (Object, error) {
|
||||||
|
return nil, ErrInvalidOperator
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFalsy returns true if the value of the type is falsy.
|
||||||
|
func (i *BytesIterator) IsFalsy() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equals returns true if the value of the type
|
||||||
|
// is equal to the value of another object.
|
||||||
|
func (i *BytesIterator) Equals(Object) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy returns a copy of the type.
|
||||||
|
func (i *BytesIterator) Copy() Object {
|
||||||
|
return &BytesIterator{v: i.v, i: i.i, l: i.l}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns true if there are more elements to iterate.
|
||||||
|
func (i *BytesIterator) Next() bool {
|
||||||
|
i.i++
|
||||||
|
return i.i <= i.l
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key returns the key or index value of the current element.
|
||||||
|
func (i *BytesIterator) Key() Object {
|
||||||
|
return &Int{Value: int64(i.i - 1)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the value of the current element.
|
||||||
|
func (i *BytesIterator) Value() Object {
|
||||||
|
return &Int{Value: int64(i.v[i.i-1])}
|
||||||
|
}
|
4
vendor/github.com/d5/tengo/objects/closure.go
generated
vendored
4
vendor/github.com/d5/tengo/objects/closure.go
generated
vendored
@ -7,7 +7,7 @@ import (
|
|||||||
// Closure represents a function closure.
|
// Closure represents a function closure.
|
||||||
type Closure struct {
|
type Closure struct {
|
||||||
Fn *CompiledFunction
|
Fn *CompiledFunction
|
||||||
Free []*Object
|
Free []*ObjectPtr
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeName returns the name of the type.
|
// TypeName returns the name of the type.
|
||||||
@ -29,7 +29,7 @@ func (o *Closure) BinaryOp(op token.Token, rhs Object) (Object, error) {
|
|||||||
func (o *Closure) Copy() Object {
|
func (o *Closure) Copy() Object {
|
||||||
return &Closure{
|
return &Closure{
|
||||||
Fn: o.Fn.Copy().(*CompiledFunction),
|
Fn: o.Fn.Copy().(*CompiledFunction),
|
||||||
Free: append([]*Object{}, o.Free...), // DO NOT Copy() of elements; these are variable pointers
|
Free: append([]*ObjectPtr{}, o.Free...), // DO NOT Copy() of elements; these are variable pointers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
vendor/github.com/d5/tengo/objects/compiled_function.go
generated
vendored
11
vendor/github.com/d5/tengo/objects/compiled_function.go
generated
vendored
@ -47,3 +47,14 @@ func (o *CompiledFunction) IsFalsy() bool {
|
|||||||
func (o *CompiledFunction) Equals(x Object) bool {
|
func (o *CompiledFunction) Equals(x Object) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SourcePos returns the source position of the instruction at ip.
|
||||||
|
func (o *CompiledFunction) SourcePos(ip int) source.Pos {
|
||||||
|
for ip >= 0 {
|
||||||
|
if p, ok := o.SourceMap[ip]; ok {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
ip--
|
||||||
|
}
|
||||||
|
return source.NoPos
|
||||||
|
}
|
||||||
|
38
vendor/github.com/d5/tengo/objects/continue.go
generated
vendored
38
vendor/github.com/d5/tengo/objects/continue.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
package objects
|
|
||||||
|
|
||||||
import "github.com/d5/tengo/compiler/token"
|
|
||||||
|
|
||||||
// Continue represents a continue statement.
|
|
||||||
type Continue struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeName returns the name of the type.
|
|
||||||
func (o *Continue) TypeName() string {
|
|
||||||
return "continue"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Continue) String() string {
|
|
||||||
return "<continue>"
|
|
||||||
}
|
|
||||||
|
|
||||||
// BinaryOp returns another object that is the result of
|
|
||||||
// a given binary operator and a right-hand side object.
|
|
||||||
func (o *Continue) BinaryOp(op token.Token, rhs Object) (Object, error) {
|
|
||||||
return nil, ErrInvalidOperator
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy returns a copy of the type.
|
|
||||||
func (o *Continue) Copy() Object {
|
|
||||||
return &Continue{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsFalsy returns true if the value of the type is falsy.
|
|
||||||
func (o *Continue) IsFalsy() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equals returns true if the value of the type
|
|
||||||
// is equal to the value of another object.
|
|
||||||
func (o *Continue) Equals(x Object) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
25
vendor/github.com/d5/tengo/objects/conversion.go
generated
vendored
25
vendor/github.com/d5/tengo/objects/conversion.go
generated
vendored
@ -1,6 +1,7 @@
|
|||||||
package objects
|
package objects
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -158,8 +159,8 @@ func ToTime(o Object) (v time.Time, ok bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// objectToInterface attempts to convert an object o to an interface{} value
|
// ToInterface attempts to convert an object o to an interface{} value
|
||||||
func objectToInterface(o Object) (res interface{}) {
|
func ToInterface(o Object) (res interface{}) {
|
||||||
switch o := o.(type) {
|
switch o := o.(type) {
|
||||||
case *Int:
|
case *Int:
|
||||||
res = o.Value
|
res = o.Value
|
||||||
@ -176,13 +177,29 @@ func objectToInterface(o Object) (res interface{}) {
|
|||||||
case *Array:
|
case *Array:
|
||||||
res = make([]interface{}, len(o.Value))
|
res = make([]interface{}, len(o.Value))
|
||||||
for i, val := range o.Value {
|
for i, val := range o.Value {
|
||||||
res.([]interface{})[i] = objectToInterface(val)
|
res.([]interface{})[i] = ToInterface(val)
|
||||||
|
}
|
||||||
|
case *ImmutableArray:
|
||||||
|
res = make([]interface{}, len(o.Value))
|
||||||
|
for i, val := range o.Value {
|
||||||
|
res.([]interface{})[i] = ToInterface(val)
|
||||||
}
|
}
|
||||||
case *Map:
|
case *Map:
|
||||||
res = make(map[string]interface{})
|
res = make(map[string]interface{})
|
||||||
for key, v := range o.Value {
|
for key, v := range o.Value {
|
||||||
res.(map[string]interface{})[key] = objectToInterface(v)
|
res.(map[string]interface{})[key] = ToInterface(v)
|
||||||
}
|
}
|
||||||
|
case *ImmutableMap:
|
||||||
|
res = make(map[string]interface{})
|
||||||
|
for key, v := range o.Value {
|
||||||
|
res.(map[string]interface{})[key] = ToInterface(v)
|
||||||
|
}
|
||||||
|
case *Time:
|
||||||
|
res = o.Value
|
||||||
|
case *Error:
|
||||||
|
res = errors.New(o.String())
|
||||||
|
case *Undefined:
|
||||||
|
res = nil
|
||||||
case Object:
|
case Object:
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
31
vendor/github.com/d5/tengo/objects/count_objects.go
generated
vendored
Normal file
31
vendor/github.com/d5/tengo/objects/count_objects.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package objects
|
||||||
|
|
||||||
|
// CountObjects returns the number of objects that a given object o contains.
|
||||||
|
// For scalar value types, it will always be 1. For compound value types,
|
||||||
|
// this will include its elements and all of their elements recursively.
|
||||||
|
func CountObjects(o Object) (c int) {
|
||||||
|
c = 1
|
||||||
|
|
||||||
|
switch o := o.(type) {
|
||||||
|
case *Array:
|
||||||
|
for _, v := range o.Value {
|
||||||
|
c += CountObjects(v)
|
||||||
|
}
|
||||||
|
case *ImmutableArray:
|
||||||
|
for _, v := range o.Value {
|
||||||
|
c += CountObjects(v)
|
||||||
|
}
|
||||||
|
case *Map:
|
||||||
|
for _, v := range o.Value {
|
||||||
|
c += CountObjects(v)
|
||||||
|
}
|
||||||
|
case *ImmutableMap:
|
||||||
|
for _, v := range o.Value {
|
||||||
|
c += CountObjects(v)
|
||||||
|
}
|
||||||
|
case *Error:
|
||||||
|
c += CountObjects(o.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
7
vendor/github.com/d5/tengo/objects/importable.go
generated
vendored
Normal file
7
vendor/github.com/d5/tengo/objects/importable.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package objects
|
||||||
|
|
||||||
|
// Importable interface represents importable module instance.
|
||||||
|
type Importable interface {
|
||||||
|
// Import should return either an Object or module source code ([]byte).
|
||||||
|
Import(moduleName string) (interface{}, error)
|
||||||
|
}
|
77
vendor/github.com/d5/tengo/objects/module_map.go
generated
vendored
Normal file
77
vendor/github.com/d5/tengo/objects/module_map.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package objects
|
||||||
|
|
||||||
|
// ModuleMap represents a set of named modules.
|
||||||
|
// Use NewModuleMap to create a new module map.
|
||||||
|
type ModuleMap struct {
|
||||||
|
m map[string]Importable
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewModuleMap creates a new module map.
|
||||||
|
func NewModuleMap() *ModuleMap {
|
||||||
|
return &ModuleMap{
|
||||||
|
m: make(map[string]Importable),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds an import module.
|
||||||
|
func (m *ModuleMap) Add(name string, module Importable) {
|
||||||
|
m.m[name] = module
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddBuiltinModule adds a builtin module.
|
||||||
|
func (m *ModuleMap) AddBuiltinModule(name string, attrs map[string]Object) {
|
||||||
|
m.m[name] = &BuiltinModule{Attrs: attrs}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSourceModule adds a source module.
|
||||||
|
func (m *ModuleMap) AddSourceModule(name string, src []byte) {
|
||||||
|
m.m[name] = &SourceModule{Src: src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes a named module.
|
||||||
|
func (m *ModuleMap) Remove(name string) {
|
||||||
|
delete(m.m, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns an import module identified by name.
|
||||||
|
// It returns if the name is not found.
|
||||||
|
func (m *ModuleMap) Get(name string) Importable {
|
||||||
|
return m.m[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBuiltinModule returns a builtin module identified by name.
|
||||||
|
// It returns if the name is not found or the module is not a builtin module.
|
||||||
|
func (m *ModuleMap) GetBuiltinModule(name string) *BuiltinModule {
|
||||||
|
mod, _ := m.m[name].(*BuiltinModule)
|
||||||
|
return mod
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSourceModule returns a source module identified by name.
|
||||||
|
// It returns if the name is not found or the module is not a source module.
|
||||||
|
func (m *ModuleMap) GetSourceModule(name string) *SourceModule {
|
||||||
|
mod, _ := m.m[name].(*SourceModule)
|
||||||
|
return mod
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy creates a copy of the module map.
|
||||||
|
func (m *ModuleMap) Copy() *ModuleMap {
|
||||||
|
c := &ModuleMap{
|
||||||
|
m: make(map[string]Importable),
|
||||||
|
}
|
||||||
|
for name, mod := range m.m {
|
||||||
|
c.m[name] = mod
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of named modules.
|
||||||
|
func (m *ModuleMap) Len() int {
|
||||||
|
return len(m.m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddMap adds named modules from another module map.
|
||||||
|
func (m *ModuleMap) AddMap(o *ModuleMap) {
|
||||||
|
for name, mod := range o.m {
|
||||||
|
m.m[name] = mod
|
||||||
|
}
|
||||||
|
}
|
41
vendor/github.com/d5/tengo/objects/object_ptr.go
generated
vendored
Normal file
41
vendor/github.com/d5/tengo/objects/object_ptr.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package objects
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/d5/tengo/compiler/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ObjectPtr represents a free variable.
|
||||||
|
type ObjectPtr struct {
|
||||||
|
Value *Object
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ObjectPtr) String() string {
|
||||||
|
return "free-var"
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeName returns the name of the type.
|
||||||
|
func (o *ObjectPtr) TypeName() string {
|
||||||
|
return "<free-var>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinaryOp returns another object that is the result of
|
||||||
|
// a given binary operator and a right-hand side object.
|
||||||
|
func (o *ObjectPtr) BinaryOp(op token.Token, rhs Object) (Object, error) {
|
||||||
|
return nil, ErrInvalidOperator
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy returns a copy of the type.
|
||||||
|
func (o *ObjectPtr) Copy() Object {
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFalsy returns true if the value of the type is falsy.
|
||||||
|
func (o *ObjectPtr) IsFalsy() bool {
|
||||||
|
return o.Value == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equals returns true if the value of the type
|
||||||
|
// is equal to the value of another object.
|
||||||
|
func (o *ObjectPtr) Equals(x Object) bool {
|
||||||
|
return o == x
|
||||||
|
}
|
39
vendor/github.com/d5/tengo/objects/return_value.go
generated
vendored
39
vendor/github.com/d5/tengo/objects/return_value.go
generated
vendored
@ -1,39 +0,0 @@
|
|||||||
package objects
|
|
||||||
|
|
||||||
import "github.com/d5/tengo/compiler/token"
|
|
||||||
|
|
||||||
// ReturnValue represents a value that is being returned.
|
|
||||||
type ReturnValue struct {
|
|
||||||
Value Object
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeName returns the name of the type.
|
|
||||||
func (o *ReturnValue) TypeName() string {
|
|
||||||
return "return-value"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *ReturnValue) String() string {
|
|
||||||
return "<return-value>"
|
|
||||||
}
|
|
||||||
|
|
||||||
// BinaryOp returns another object that is the result of
|
|
||||||
// a given binary operator and a right-hand side object.
|
|
||||||
func (o *ReturnValue) BinaryOp(op token.Token, rhs Object) (Object, error) {
|
|
||||||
return nil, ErrInvalidOperator
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy returns a copy of the type.
|
|
||||||
func (o *ReturnValue) Copy() Object {
|
|
||||||
return &ReturnValue{Value: o.Copy()}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsFalsy returns true if the value of the type is falsy.
|
|
||||||
func (o *ReturnValue) IsFalsy() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equals returns true if the value of the type
|
|
||||||
// is equal to the value of another object.
|
|
||||||
func (o *ReturnValue) Equals(x Object) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
11
vendor/github.com/d5/tengo/objects/source_module.go
generated
vendored
Normal file
11
vendor/github.com/d5/tengo/objects/source_module.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package objects
|
||||||
|
|
||||||
|
// SourceModule is an importable module that's written in Tengo.
|
||||||
|
type SourceModule struct {
|
||||||
|
Src []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import returns a module source code.
|
||||||
|
func (m *SourceModule) Import(_ string) (interface{}, error) {
|
||||||
|
return m.Src, nil
|
||||||
|
}
|
5
vendor/github.com/d5/tengo/objects/user_function.go
generated
vendored
5
vendor/github.com/d5/tengo/objects/user_function.go
generated
vendored
@ -6,8 +6,9 @@ import (
|
|||||||
|
|
||||||
// UserFunction represents a user function.
|
// UserFunction represents a user function.
|
||||||
type UserFunction struct {
|
type UserFunction struct {
|
||||||
Name string
|
Name string
|
||||||
Value CallableFunc
|
Value CallableFunc
|
||||||
|
EncodingID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeName returns the name of the type.
|
// TypeName returns the name of the type.
|
||||||
|
3
vendor/github.com/d5/tengo/runtime/errors.go
generated
vendored
3
vendor/github.com/d5/tengo/runtime/errors.go
generated
vendored
@ -6,3 +6,6 @@ import (
|
|||||||
|
|
||||||
// ErrStackOverflow is a stack overflow error.
|
// ErrStackOverflow is a stack overflow error.
|
||||||
var ErrStackOverflow = errors.New("stack overflow")
|
var ErrStackOverflow = errors.New("stack overflow")
|
||||||
|
|
||||||
|
// ErrObjectAllocLimit is an objects allocation limit error.
|
||||||
|
var ErrObjectAllocLimit = errors.New("object allocation limit exceeded")
|
||||||
|
2
vendor/github.com/d5/tengo/runtime/frame.go
generated
vendored
2
vendor/github.com/d5/tengo/runtime/frame.go
generated
vendored
@ -7,7 +7,7 @@ import (
|
|||||||
// Frame represents a function call frame.
|
// Frame represents a function call frame.
|
||||||
type Frame struct {
|
type Frame struct {
|
||||||
fn *objects.CompiledFunction
|
fn *objects.CompiledFunction
|
||||||
freeVars []*objects.Object
|
freeVars []*objects.ObjectPtr
|
||||||
ip int
|
ip int
|
||||||
basePointer int
|
basePointer int
|
||||||
}
|
}
|
||||||
|
774
vendor/github.com/d5/tengo/runtime/vm.go
generated
vendored
774
vendor/github.com/d5/tengo/runtime/vm.go
generated
vendored
File diff suppressed because it is too large
Load Diff
102
vendor/github.com/d5/tengo/script/compiled.go
generated
vendored
102
vendor/github.com/d5/tengo/script/compiled.go
generated
vendored
@ -3,6 +3,7 @@ package script
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/d5/tengo/compiler"
|
"github.com/d5/tengo/compiler"
|
||||||
"github.com/d5/tengo/objects"
|
"github.com/d5/tengo/objects"
|
||||||
@ -12,26 +13,39 @@ import (
|
|||||||
// Compiled is a compiled instance of the user script.
|
// Compiled is a compiled instance of the user script.
|
||||||
// Use Script.Compile() to create Compiled object.
|
// Use Script.Compile() to create Compiled object.
|
||||||
type Compiled struct {
|
type Compiled struct {
|
||||||
symbolTable *compiler.SymbolTable
|
globalIndexes map[string]int // global symbol name to index
|
||||||
machine *runtime.VM
|
bytecode *compiler.Bytecode
|
||||||
|
globals []objects.Object
|
||||||
|
maxAllocs int64
|
||||||
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run executes the compiled script in the virtual machine.
|
// Run executes the compiled script in the virtual machine.
|
||||||
func (c *Compiled) Run() error {
|
func (c *Compiled) Run() error {
|
||||||
return c.machine.Run()
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
v := runtime.NewVM(c.bytecode, c.globals, c.maxAllocs)
|
||||||
|
|
||||||
|
return v.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunContext is like Run but includes a context.
|
// RunContext is like Run but includes a context.
|
||||||
func (c *Compiled) RunContext(ctx context.Context) (err error) {
|
func (c *Compiled) RunContext(ctx context.Context) (err error) {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
v := runtime.NewVM(c.bytecode, c.globals, c.maxAllocs)
|
||||||
|
|
||||||
ch := make(chan error, 1)
|
ch := make(chan error, 1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
ch <- c.machine.Run()
|
ch <- v.Run()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
c.machine.Abort()
|
v.Abort()
|
||||||
<-ch
|
<-ch
|
||||||
err = ctx.Err()
|
err = ctx.Err()
|
||||||
case err = <-ch:
|
case err = <-ch:
|
||||||
@ -40,30 +54,58 @@ func (c *Compiled) RunContext(ctx context.Context) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone creates a new copy of Compiled.
|
||||||
|
// Cloned copies are safe for concurrent use by multiple goroutines.
|
||||||
|
func (c *Compiled) Clone() *Compiled {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
clone := &Compiled{
|
||||||
|
globalIndexes: c.globalIndexes,
|
||||||
|
bytecode: c.bytecode,
|
||||||
|
globals: make([]objects.Object, len(c.globals)),
|
||||||
|
maxAllocs: c.maxAllocs,
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy global objects
|
||||||
|
for idx, g := range c.globals {
|
||||||
|
if g != nil {
|
||||||
|
clone.globals[idx] = g
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
// IsDefined returns true if the variable name is defined (has value) before or after the execution.
|
// IsDefined returns true if the variable name is defined (has value) before or after the execution.
|
||||||
func (c *Compiled) IsDefined(name string) bool {
|
func (c *Compiled) IsDefined(name string) bool {
|
||||||
symbol, _, ok := c.symbolTable.Resolve(name)
|
c.lock.RLock()
|
||||||
|
defer c.lock.RUnlock()
|
||||||
|
|
||||||
|
idx, ok := c.globalIndexes[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
v := c.machine.Globals()[symbol.Index]
|
v := c.globals[idx]
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return *v != objects.UndefinedValue
|
return v != objects.UndefinedValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns a variable identified by the name.
|
// Get returns a variable identified by the name.
|
||||||
func (c *Compiled) Get(name string) *Variable {
|
func (c *Compiled) Get(name string) *Variable {
|
||||||
value := &objects.UndefinedValue
|
c.lock.RLock()
|
||||||
|
defer c.lock.RUnlock()
|
||||||
|
|
||||||
symbol, _, ok := c.symbolTable.Resolve(name)
|
value := objects.UndefinedValue
|
||||||
if ok && symbol.Scope == compiler.ScopeGlobal {
|
|
||||||
value = c.machine.Globals()[symbol.Index]
|
if idx, ok := c.globalIndexes[name]; ok {
|
||||||
|
value = c.globals[idx]
|
||||||
if value == nil {
|
if value == nil {
|
||||||
value = &objects.UndefinedValue
|
value = objects.UndefinedValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,20 +117,21 @@ func (c *Compiled) Get(name string) *Variable {
|
|||||||
|
|
||||||
// GetAll returns all the variables that are defined by the compiled script.
|
// GetAll returns all the variables that are defined by the compiled script.
|
||||||
func (c *Compiled) GetAll() []*Variable {
|
func (c *Compiled) GetAll() []*Variable {
|
||||||
var vars []*Variable
|
c.lock.RLock()
|
||||||
for _, name := range c.symbolTable.Names() {
|
defer c.lock.RUnlock()
|
||||||
symbol, _, ok := c.symbolTable.Resolve(name)
|
|
||||||
if ok && symbol.Scope == compiler.ScopeGlobal {
|
|
||||||
value := c.machine.Globals()[symbol.Index]
|
|
||||||
if value == nil {
|
|
||||||
value = &objects.UndefinedValue
|
|
||||||
}
|
|
||||||
|
|
||||||
vars = append(vars, &Variable{
|
var vars []*Variable
|
||||||
name: name,
|
|
||||||
value: value,
|
for name, idx := range c.globalIndexes {
|
||||||
})
|
value := c.globals[idx]
|
||||||
|
if value == nil {
|
||||||
|
value = objects.UndefinedValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vars = append(vars, &Variable{
|
||||||
|
name: name,
|
||||||
|
value: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return vars
|
return vars
|
||||||
@ -97,17 +140,20 @@ func (c *Compiled) GetAll() []*Variable {
|
|||||||
// Set replaces the value of a global variable identified by the name.
|
// Set replaces the value of a global variable identified by the name.
|
||||||
// An error will be returned if the name was not defined during compilation.
|
// An error will be returned if the name was not defined during compilation.
|
||||||
func (c *Compiled) Set(name string, value interface{}) error {
|
func (c *Compiled) Set(name string, value interface{}) error {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
obj, err := objects.FromInterface(value)
|
obj, err := objects.FromInterface(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol, _, ok := c.symbolTable.Resolve(name)
|
idx, ok := c.globalIndexes[name]
|
||||||
if !ok || symbol.Scope != compiler.ScopeGlobal {
|
if !ok {
|
||||||
return fmt.Errorf("'%s' is not defined", name)
|
return fmt.Errorf("'%s' is not defined", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.machine.Globals()[symbol.Index] = &obj
|
c.globals[idx] = obj
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
33
vendor/github.com/d5/tengo/script/conversion.go
generated
vendored
33
vendor/github.com/d5/tengo/script/conversion.go
generated
vendored
@ -1,33 +0,0 @@
|
|||||||
package script
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/d5/tengo/objects"
|
|
||||||
)
|
|
||||||
|
|
||||||
func objectToInterface(o objects.Object) interface{} {
|
|
||||||
switch val := o.(type) {
|
|
||||||
case *objects.Array:
|
|
||||||
return val.Value
|
|
||||||
case *objects.Map:
|
|
||||||
return val.Value
|
|
||||||
case *objects.Int:
|
|
||||||
return val.Value
|
|
||||||
case *objects.Float:
|
|
||||||
return val.Value
|
|
||||||
case *objects.Bool:
|
|
||||||
if val == objects.TrueValue {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
case *objects.Char:
|
|
||||||
return val.Value
|
|
||||||
case *objects.String:
|
|
||||||
return val.Value
|
|
||||||
case *objects.Bytes:
|
|
||||||
return val.Value
|
|
||||||
case *objects.Undefined:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return o
|
|
||||||
}
|
|
127
vendor/github.com/d5/tengo/script/script.go
generated
vendored
127
vendor/github.com/d5/tengo/script/script.go
generated
vendored
@ -14,17 +14,20 @@ import (
|
|||||||
// Script can simplify compilation and execution of embedded scripts.
|
// Script can simplify compilation and execution of embedded scripts.
|
||||||
type Script struct {
|
type Script struct {
|
||||||
variables map[string]*Variable
|
variables map[string]*Variable
|
||||||
builtinFuncs []objects.Object
|
modules *objects.ModuleMap
|
||||||
builtinModules map[string]*objects.Object
|
|
||||||
userModuleLoader compiler.ModuleLoader
|
|
||||||
input []byte
|
input []byte
|
||||||
|
maxAllocs int64
|
||||||
|
maxConstObjects int
|
||||||
|
enableFileImport bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a Script instance with an input script.
|
// New creates a Script instance with an input script.
|
||||||
func New(input []byte) *Script {
|
func New(input []byte) *Script {
|
||||||
return &Script{
|
return &Script{
|
||||||
variables: make(map[string]*Variable),
|
variables: make(map[string]*Variable),
|
||||||
input: input,
|
input: input,
|
||||||
|
maxAllocs: -1,
|
||||||
|
maxConstObjects: -1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +40,7 @@ func (s *Script) Add(name string, value interface{}) error {
|
|||||||
|
|
||||||
s.variables[name] = &Variable{
|
s.variables[name] = &Variable{
|
||||||
name: name,
|
name: name,
|
||||||
value: &obj,
|
value: obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -55,38 +58,31 @@ func (s *Script) Remove(name string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetBuiltinFunctions allows to define builtin functions.
|
// SetImports sets import modules.
|
||||||
func (s *Script) SetBuiltinFunctions(funcs []*objects.BuiltinFunction) {
|
func (s *Script) SetImports(modules *objects.ModuleMap) {
|
||||||
if funcs != nil {
|
s.modules = modules
|
||||||
s.builtinFuncs = make([]objects.Object, len(funcs))
|
|
||||||
for idx, fn := range funcs {
|
|
||||||
s.builtinFuncs[idx] = fn
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s.builtinFuncs = []objects.Object{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetBuiltinModules allows to define builtin modules.
|
// SetMaxAllocs sets the maximum number of objects allocations during the run time.
|
||||||
func (s *Script) SetBuiltinModules(modules map[string]*objects.ImmutableMap) {
|
// Compiled script will return runtime.ErrObjectAllocLimit error if it exceeds this limit.
|
||||||
if modules != nil {
|
func (s *Script) SetMaxAllocs(n int64) {
|
||||||
s.builtinModules = make(map[string]*objects.Object, len(modules))
|
s.maxAllocs = n
|
||||||
for k, mod := range modules {
|
|
||||||
s.builtinModules[k] = objectPtr(mod)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s.builtinModules = map[string]*objects.Object{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUserModuleLoader sets the user module loader for the compiler.
|
// SetMaxConstObjects sets the maximum number of objects in the compiled constants.
|
||||||
func (s *Script) SetUserModuleLoader(loader compiler.ModuleLoader) {
|
func (s *Script) SetMaxConstObjects(n int) {
|
||||||
s.userModuleLoader = loader
|
s.maxConstObjects = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableFileImport enables or disables module loading from local files.
|
||||||
|
// Local file modules are disabled by default.
|
||||||
|
func (s *Script) EnableFileImport(enable bool) {
|
||||||
|
s.enableFileImport = enable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile compiles the script with all the defined variables, and, returns Compiled object.
|
// Compile compiles the script with all the defined variables, and, returns Compiled object.
|
||||||
func (s *Script) Compile() (*Compiled, error) {
|
func (s *Script) Compile() (*Compiled, error) {
|
||||||
symbolTable, builtinModules, globals, err := s.prepCompile()
|
symbolTable, globals, err := s.prepCompile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -100,19 +96,41 @@ func (s *Script) Compile() (*Compiled, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c := compiler.NewCompiler(srcFile, symbolTable, nil, builtinModules, nil)
|
c := compiler.NewCompiler(srcFile, symbolTable, nil, s.modules, nil)
|
||||||
|
c.EnableFileImport(s.enableFileImport)
|
||||||
if s.userModuleLoader != nil {
|
|
||||||
c.SetModuleLoader(s.userModuleLoader)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.Compile(file); err != nil {
|
if err := c.Compile(file); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reduce globals size
|
||||||
|
globals = globals[:symbolTable.MaxSymbols()+1]
|
||||||
|
|
||||||
|
// global symbol names to indexes
|
||||||
|
globalIndexes := make(map[string]int, len(globals))
|
||||||
|
for _, name := range symbolTable.Names() {
|
||||||
|
symbol, _, _ := symbolTable.Resolve(name)
|
||||||
|
if symbol.Scope == compiler.ScopeGlobal {
|
||||||
|
globalIndexes[name] = symbol.Index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove duplicates from constants
|
||||||
|
bytecode := c.Bytecode()
|
||||||
|
bytecode.RemoveDuplicates()
|
||||||
|
|
||||||
|
// check the constant objects limit
|
||||||
|
if s.maxConstObjects >= 0 {
|
||||||
|
cnt := bytecode.CountObjects()
|
||||||
|
if cnt > s.maxConstObjects {
|
||||||
|
return nil, fmt.Errorf("exceeding constant objects limit: %d", cnt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &Compiled{
|
return &Compiled{
|
||||||
symbolTable: symbolTable,
|
globalIndexes: globalIndexes,
|
||||||
machine: runtime.NewVM(c.Bytecode(), globals, s.builtinFuncs, s.builtinModules),
|
bytecode: bytecode,
|
||||||
|
globals: globals,
|
||||||
|
maxAllocs: s.maxAllocs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,39 +159,18 @@ func (s *Script) RunContext(ctx context.Context) (compiled *Compiled, err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Script) prepCompile() (symbolTable *compiler.SymbolTable, builtinModules map[string]bool, globals []*objects.Object, err error) {
|
func (s *Script) prepCompile() (symbolTable *compiler.SymbolTable, globals []objects.Object, err error) {
|
||||||
var names []string
|
var names []string
|
||||||
for name := range s.variables {
|
for name := range s.variables {
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
symbolTable = compiler.NewSymbolTable()
|
symbolTable = compiler.NewSymbolTable()
|
||||||
|
for idx, fn := range objects.Builtins {
|
||||||
if s.builtinFuncs == nil {
|
symbolTable.DefineBuiltin(idx, fn.Name)
|
||||||
s.builtinFuncs = make([]objects.Object, len(objects.Builtins))
|
|
||||||
for idx, fn := range objects.Builtins {
|
|
||||||
s.builtinFuncs[idx] = &objects.BuiltinFunction{
|
|
||||||
Name: fn.Name,
|
|
||||||
Value: fn.Value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.builtinModules == nil {
|
globals = make([]objects.Object, runtime.GlobalsSize)
|
||||||
s.builtinModules = make(map[string]*objects.Object)
|
|
||||||
}
|
|
||||||
|
|
||||||
for idx, fn := range s.builtinFuncs {
|
|
||||||
f := fn.(*objects.BuiltinFunction)
|
|
||||||
symbolTable.DefineBuiltin(idx, f.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
builtinModules = make(map[string]bool)
|
|
||||||
for name := range s.builtinModules {
|
|
||||||
builtinModules[name] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
globals = make([]*objects.Object, runtime.GlobalsSize, runtime.GlobalsSize)
|
|
||||||
|
|
||||||
for idx, name := range names {
|
for idx, name := range names {
|
||||||
symbol := symbolTable.Define(name)
|
symbol := symbolTable.Define(name)
|
||||||
@ -195,7 +192,3 @@ func (s *Script) copyVariables() map[string]*Variable {
|
|||||||
|
|
||||||
return vars
|
return vars
|
||||||
}
|
}
|
||||||
|
|
||||||
func objectPtr(o objects.Object) *objects.Object {
|
|
||||||
return &o
|
|
||||||
}
|
|
||||||
|
36
vendor/github.com/d5/tengo/script/variable.go
generated
vendored
36
vendor/github.com/d5/tengo/script/variable.go
generated
vendored
@ -9,7 +9,7 @@ import (
|
|||||||
// Variable is a user-defined variable for the script.
|
// Variable is a user-defined variable for the script.
|
||||||
type Variable struct {
|
type Variable struct {
|
||||||
name string
|
name string
|
||||||
value *objects.Object
|
value objects.Object
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVariable creates a Variable.
|
// NewVariable creates a Variable.
|
||||||
@ -21,7 +21,7 @@ func NewVariable(name string, value interface{}) (*Variable, error) {
|
|||||||
|
|
||||||
return &Variable{
|
return &Variable{
|
||||||
name: name,
|
name: name,
|
||||||
value: &obj,
|
value: obj,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,18 +32,18 @@ func (v *Variable) Name() string {
|
|||||||
|
|
||||||
// Value returns an empty interface of the variable value.
|
// Value returns an empty interface of the variable value.
|
||||||
func (v *Variable) Value() interface{} {
|
func (v *Variable) Value() interface{} {
|
||||||
return objectToInterface(*v.value)
|
return objects.ToInterface(v.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValueType returns the name of the value type.
|
// ValueType returns the name of the value type.
|
||||||
func (v *Variable) ValueType() string {
|
func (v *Variable) ValueType() string {
|
||||||
return (*v.value).TypeName()
|
return v.value.TypeName()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int returns int value of the variable value.
|
// Int returns int value of the variable value.
|
||||||
// It returns 0 if the value is not convertible to int.
|
// It returns 0 if the value is not convertible to int.
|
||||||
func (v *Variable) Int() int {
|
func (v *Variable) Int() int {
|
||||||
c, _ := objects.ToInt(*v.value)
|
c, _ := objects.ToInt(v.value)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ func (v *Variable) Int() int {
|
|||||||
// Int64 returns int64 value of the variable value.
|
// Int64 returns int64 value of the variable value.
|
||||||
// It returns 0 if the value is not convertible to int64.
|
// It returns 0 if the value is not convertible to int64.
|
||||||
func (v *Variable) Int64() int64 {
|
func (v *Variable) Int64() int64 {
|
||||||
c, _ := objects.ToInt64(*v.value)
|
c, _ := objects.ToInt64(v.value)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ func (v *Variable) Int64() int64 {
|
|||||||
// Float returns float64 value of the variable value.
|
// Float returns float64 value of the variable value.
|
||||||
// It returns 0.0 if the value is not convertible to float64.
|
// It returns 0.0 if the value is not convertible to float64.
|
||||||
func (v *Variable) Float() float64 {
|
func (v *Variable) Float() float64 {
|
||||||
c, _ := objects.ToFloat64(*v.value)
|
c, _ := objects.ToFloat64(v.value)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ func (v *Variable) Float() float64 {
|
|||||||
// Char returns rune value of the variable value.
|
// Char returns rune value of the variable value.
|
||||||
// It returns 0 if the value is not convertible to rune.
|
// It returns 0 if the value is not convertible to rune.
|
||||||
func (v *Variable) Char() rune {
|
func (v *Variable) Char() rune {
|
||||||
c, _ := objects.ToRune(*v.value)
|
c, _ := objects.ToRune(v.value)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ func (v *Variable) Char() rune {
|
|||||||
// Bool returns bool value of the variable value.
|
// Bool returns bool value of the variable value.
|
||||||
// It returns 0 if the value is not convertible to bool.
|
// It returns 0 if the value is not convertible to bool.
|
||||||
func (v *Variable) Bool() bool {
|
func (v *Variable) Bool() bool {
|
||||||
c, _ := objects.ToBool(*v.value)
|
c, _ := objects.ToBool(v.value)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -83,11 +83,11 @@ func (v *Variable) Bool() bool {
|
|||||||
// Array returns []interface value of the variable value.
|
// Array returns []interface value of the variable value.
|
||||||
// It returns 0 if the value is not convertible to []interface.
|
// It returns 0 if the value is not convertible to []interface.
|
||||||
func (v *Variable) Array() []interface{} {
|
func (v *Variable) Array() []interface{} {
|
||||||
switch val := (*v.value).(type) {
|
switch val := v.value.(type) {
|
||||||
case *objects.Array:
|
case *objects.Array:
|
||||||
var arr []interface{}
|
var arr []interface{}
|
||||||
for _, e := range val.Value {
|
for _, e := range val.Value {
|
||||||
arr = append(arr, objectToInterface(e))
|
arr = append(arr, objects.ToInterface(e))
|
||||||
}
|
}
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
@ -98,11 +98,11 @@ func (v *Variable) Array() []interface{} {
|
|||||||
// Map returns map[string]interface{} value of the variable value.
|
// Map returns map[string]interface{} value of the variable value.
|
||||||
// It returns 0 if the value is not convertible to map[string]interface{}.
|
// It returns 0 if the value is not convertible to map[string]interface{}.
|
||||||
func (v *Variable) Map() map[string]interface{} {
|
func (v *Variable) Map() map[string]interface{} {
|
||||||
switch val := (*v.value).(type) {
|
switch val := v.value.(type) {
|
||||||
case *objects.Map:
|
case *objects.Map:
|
||||||
kv := make(map[string]interface{})
|
kv := make(map[string]interface{})
|
||||||
for mk, mv := range val.Value {
|
for mk, mv := range val.Value {
|
||||||
kv[mk] = objectToInterface(mv)
|
kv[mk] = objects.ToInterface(mv)
|
||||||
}
|
}
|
||||||
return kv
|
return kv
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ func (v *Variable) Map() map[string]interface{} {
|
|||||||
// String returns string value of the variable value.
|
// String returns string value of the variable value.
|
||||||
// It returns 0 if the value is not convertible to string.
|
// It returns 0 if the value is not convertible to string.
|
||||||
func (v *Variable) String() string {
|
func (v *Variable) String() string {
|
||||||
c, _ := objects.ToString(*v.value)
|
c, _ := objects.ToString(v.value)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ func (v *Variable) String() string {
|
|||||||
// Bytes returns a byte slice of the variable value.
|
// Bytes returns a byte slice of the variable value.
|
||||||
// It returns nil if the value is not convertible to byte slice.
|
// It returns nil if the value is not convertible to byte slice.
|
||||||
func (v *Variable) Bytes() []byte {
|
func (v *Variable) Bytes() []byte {
|
||||||
c, _ := objects.ToByteSlice(*v.value)
|
c, _ := objects.ToByteSlice(v.value)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -129,7 +129,7 @@ func (v *Variable) Bytes() []byte {
|
|||||||
// Error returns an error if the underlying value is error object.
|
// Error returns an error if the underlying value is error object.
|
||||||
// If not, this returns nil.
|
// If not, this returns nil.
|
||||||
func (v *Variable) Error() error {
|
func (v *Variable) Error() error {
|
||||||
err, ok := (*v.value).(*objects.Error)
|
err, ok := v.value.(*objects.Error)
|
||||||
if ok {
|
if ok {
|
||||||
return errors.New(err.String())
|
return errors.New(err.String())
|
||||||
}
|
}
|
||||||
@ -140,10 +140,10 @@ func (v *Variable) Error() error {
|
|||||||
// Object returns an underlying Object of the variable value.
|
// Object returns an underlying Object of the variable value.
|
||||||
// Note that returned Object is a copy of an actual Object used in the script.
|
// Note that returned Object is a copy of an actual Object used in the script.
|
||||||
func (v *Variable) Object() objects.Object {
|
func (v *Variable) Object() objects.Object {
|
||||||
return *v.value
|
return v.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsUndefined returns true if the underlying value is undefined.
|
// IsUndefined returns true if the underlying value is undefined.
|
||||||
func (v *Variable) IsUndefined() bool {
|
func (v *Variable) IsUndefined() bool {
|
||||||
return *v.value == objects.UndefinedValue
|
return v.value == objects.UndefinedValue
|
||||||
}
|
}
|
||||||
|
14
vendor/github.com/d5/tengo/stdlib/builtin_modules.go
generated
vendored
Normal file
14
vendor/github.com/d5/tengo/stdlib/builtin_modules.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import "github.com/d5/tengo/objects"
|
||||||
|
|
||||||
|
// BuiltinModules are builtin type standard library modules.
|
||||||
|
var BuiltinModules = map[string]map[string]objects.Object{
|
||||||
|
"math": mathModule,
|
||||||
|
"os": osModule,
|
||||||
|
"text": textModule,
|
||||||
|
"times": timesModule,
|
||||||
|
"rand": randModule,
|
||||||
|
"fmt": fmtModule,
|
||||||
|
"json": jsonModule,
|
||||||
|
}
|
11
vendor/github.com/d5/tengo/stdlib/errors.go
generated
vendored
Normal file
11
vendor/github.com/d5/tengo/stdlib/errors.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import "github.com/d5/tengo/objects"
|
||||||
|
|
||||||
|
func wrapError(err error) objects.Object {
|
||||||
|
if err == nil {
|
||||||
|
return objects.TrueValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.Error{Value: &objects.String{Value: err.Error()}}
|
||||||
|
}
|
116
vendor/github.com/d5/tengo/stdlib/fmt.go
generated
vendored
Normal file
116
vendor/github.com/d5/tengo/stdlib/fmt.go
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
var fmtModule = map[string]objects.Object{
|
||||||
|
"print": &objects.UserFunction{Name: "print", Value: fmtPrint},
|
||||||
|
"printf": &objects.UserFunction{Name: "printf", Value: fmtPrintf},
|
||||||
|
"println": &objects.UserFunction{Name: "println", Value: fmtPrintln},
|
||||||
|
"sprintf": &objects.UserFunction{Name: "sprintf", Value: fmtSprintf},
|
||||||
|
}
|
||||||
|
|
||||||
|
func fmtPrint(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
printArgs, err := getPrintArgs(args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _ = fmt.Print(printArgs...)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fmtPrintf(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
numArgs := len(args)
|
||||||
|
if numArgs == 0 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
format, ok := args[0].(*objects.String)
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "format",
|
||||||
|
Expected: "string",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if numArgs == 1 {
|
||||||
|
fmt.Print(format)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
formatArgs := make([]interface{}, numArgs-1, numArgs-1)
|
||||||
|
for idx, arg := range args[1:] {
|
||||||
|
formatArgs[idx] = objects.ToInterface(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(format.Value, formatArgs...)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fmtPrintln(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
printArgs, err := getPrintArgs(args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
printArgs = append(printArgs, "\n")
|
||||||
|
_, _ = fmt.Print(printArgs...)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fmtSprintf(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
numArgs := len(args)
|
||||||
|
if numArgs == 0 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
format, ok := args[0].(*objects.String)
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "format",
|
||||||
|
Expected: "string",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if numArgs == 1 {
|
||||||
|
return format, nil // okay to return 'format' directly as String is immutable
|
||||||
|
}
|
||||||
|
|
||||||
|
formatArgs := make([]interface{}, numArgs-1, numArgs-1)
|
||||||
|
for idx, arg := range args[1:] {
|
||||||
|
formatArgs[idx] = objects.ToInterface(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
s := fmt.Sprintf(format.Value, formatArgs...)
|
||||||
|
|
||||||
|
if len(s) > tengo.MaxStringLen {
|
||||||
|
return nil, objects.ErrStringLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.String{Value: s}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPrintArgs(args ...objects.Object) ([]interface{}, error) {
|
||||||
|
var printArgs []interface{}
|
||||||
|
l := 0
|
||||||
|
for _, arg := range args {
|
||||||
|
s, _ := objects.ToString(arg)
|
||||||
|
slen := len(s)
|
||||||
|
if l+slen > tengo.MaxStringLen { // make sure length does not exceed the limit
|
||||||
|
return nil, objects.ErrStringLimit
|
||||||
|
}
|
||||||
|
l += slen
|
||||||
|
|
||||||
|
printArgs = append(printArgs, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return printArgs, nil
|
||||||
|
}
|
1125
vendor/github.com/d5/tengo/stdlib/func_typedefs.go
generated
vendored
Normal file
1125
vendor/github.com/d5/tengo/stdlib/func_typedefs.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
53
vendor/github.com/d5/tengo/stdlib/gensrcmods.go
generated
vendored
Normal file
53
vendor/github.com/d5/tengo/stdlib/gensrcmods.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var tengoModFileRE = regexp.MustCompile(`^srcmod_(\w+).tengo$`)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
modules := make(map[string]string)
|
||||||
|
|
||||||
|
// enumerate all Tengo module files
|
||||||
|
files, err := ioutil.ReadDir(".")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, file := range files {
|
||||||
|
m := tengoModFileRE.FindStringSubmatch(file.Name())
|
||||||
|
if m != nil {
|
||||||
|
modName := m[1]
|
||||||
|
|
||||||
|
src, err := ioutil.ReadFile(file.Name())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("file '%s' read error: %s", file.Name(), err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
modules[modName] = string(src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var out bytes.Buffer
|
||||||
|
out.WriteString(`// Code generated using gensrcmods.go; DO NOT EDIT.
|
||||||
|
|
||||||
|
package stdlib
|
||||||
|
|
||||||
|
// SourceModules are source type standard library modules.
|
||||||
|
var SourceModules = map[string]string{` + "\n")
|
||||||
|
for modName, modSrc := range modules {
|
||||||
|
out.WriteString("\t\"" + modName + "\": " + strconv.Quote(modSrc) + ",\n")
|
||||||
|
}
|
||||||
|
out.WriteString("}\n")
|
||||||
|
|
||||||
|
const target = "source_modules.go"
|
||||||
|
if err := ioutil.WriteFile(target, out.Bytes(), 0644); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
126
vendor/github.com/d5/tengo/stdlib/json.go
generated
vendored
Normal file
126
vendor/github.com/d5/tengo/stdlib/json.go
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
gojson "encoding/json"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
"github.com/d5/tengo/stdlib/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
var jsonModule = map[string]objects.Object{
|
||||||
|
"decode": &objects.UserFunction{Name: "decode", Value: jsonDecode},
|
||||||
|
"encode": &objects.UserFunction{Name: "encode", Value: jsonEncode},
|
||||||
|
"indent": &objects.UserFunction{Name: "encode", Value: jsonIndent},
|
||||||
|
"html_escape": &objects.UserFunction{Name: "html_escape", Value: jsonHTMLEscape},
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonDecode(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
switch o := args[0].(type) {
|
||||||
|
case *objects.Bytes:
|
||||||
|
v, err := json.Decode(o.Value)
|
||||||
|
if err != nil {
|
||||||
|
return &objects.Error{Value: &objects.String{Value: err.Error()}}, nil
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
case *objects.String:
|
||||||
|
v, err := json.Decode([]byte(o.Value))
|
||||||
|
if err != nil {
|
||||||
|
return &objects.Error{Value: &objects.String{Value: err.Error()}}, nil
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
default:
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "bytes/string",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonEncode(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Encode(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return &objects.Error{Value: &objects.String{Value: err.Error()}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.Bytes{Value: b}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonIndent(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 3 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "prefix",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indent, ok := objects.ToString(args[2])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "indent",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch o := args[0].(type) {
|
||||||
|
case *objects.Bytes:
|
||||||
|
var dst bytes.Buffer
|
||||||
|
err := gojson.Indent(&dst, o.Value, prefix, indent)
|
||||||
|
if err != nil {
|
||||||
|
return &objects.Error{Value: &objects.String{Value: err.Error()}}, nil
|
||||||
|
}
|
||||||
|
return &objects.Bytes{Value: dst.Bytes()}, nil
|
||||||
|
case *objects.String:
|
||||||
|
var dst bytes.Buffer
|
||||||
|
err := gojson.Indent(&dst, []byte(o.Value), prefix, indent)
|
||||||
|
if err != nil {
|
||||||
|
return &objects.Error{Value: &objects.String{Value: err.Error()}}, nil
|
||||||
|
}
|
||||||
|
return &objects.Bytes{Value: dst.Bytes()}, nil
|
||||||
|
default:
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "bytes/string",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonHTMLEscape(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
switch o := args[0].(type) {
|
||||||
|
case *objects.Bytes:
|
||||||
|
var dst bytes.Buffer
|
||||||
|
gojson.HTMLEscape(&dst, o.Value)
|
||||||
|
return &objects.Bytes{Value: dst.Bytes()}, nil
|
||||||
|
case *objects.String:
|
||||||
|
var dst bytes.Buffer
|
||||||
|
gojson.HTMLEscape(&dst, []byte(o.Value))
|
||||||
|
return &objects.Bytes{Value: dst.Bytes()}, nil
|
||||||
|
default:
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "bytes/string",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
374
vendor/github.com/d5/tengo/stdlib/json/decode.go
generated
vendored
Normal file
374
vendor/github.com/d5/tengo/stdlib/json/decode.go
generated
vendored
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
// A modified version of Go's JSON implementation.
|
||||||
|
|
||||||
|
// Copyright 2010 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 (
|
||||||
|
"strconv"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decode parses the JSON-encoded data and returns the result object.
|
||||||
|
func Decode(data []byte) (objects.Object, error) {
|
||||||
|
var d decodeState
|
||||||
|
err := checkValid(data, &d.scan)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.init(data)
|
||||||
|
d.scan.reset()
|
||||||
|
d.scanWhile(scanSkipSpace)
|
||||||
|
|
||||||
|
return d.value()
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeState represents the state while decoding a JSON value.
|
||||||
|
type decodeState struct {
|
||||||
|
data []byte
|
||||||
|
off int // next read offset in data
|
||||||
|
opcode int // last read result
|
||||||
|
scan scanner
|
||||||
|
}
|
||||||
|
|
||||||
|
// readIndex returns the position of the last byte read.
|
||||||
|
func (d *decodeState) readIndex() int {
|
||||||
|
return d.off - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?"
|
||||||
|
|
||||||
|
func (d *decodeState) init(data []byte) *decodeState {
|
||||||
|
d.data = data
|
||||||
|
d.off = 0
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanNext processes the byte at d.data[d.off].
|
||||||
|
func (d *decodeState) scanNext() {
|
||||||
|
if d.off < len(d.data) {
|
||||||
|
d.opcode = d.scan.step(&d.scan, d.data[d.off])
|
||||||
|
d.off++
|
||||||
|
} else {
|
||||||
|
d.opcode = d.scan.eof()
|
||||||
|
d.off = len(d.data) + 1 // mark processed EOF with len+1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanWhile processes bytes in d.data[d.off:] until it
|
||||||
|
// receives a scan code not equal to op.
|
||||||
|
func (d *decodeState) scanWhile(op int) {
|
||||||
|
s, data, i := &d.scan, d.data, d.off
|
||||||
|
for i < len(data) {
|
||||||
|
newOp := s.step(s, data[i])
|
||||||
|
i++
|
||||||
|
if newOp != op {
|
||||||
|
d.opcode = newOp
|
||||||
|
d.off = i
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.off = len(data) + 1 // mark processed EOF with len+1
|
||||||
|
d.opcode = d.scan.eof()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decodeState) value() (objects.Object, error) {
|
||||||
|
switch d.opcode {
|
||||||
|
default:
|
||||||
|
panic(phasePanicMsg)
|
||||||
|
|
||||||
|
case scanBeginArray:
|
||||||
|
o, err := d.array()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.scanNext()
|
||||||
|
|
||||||
|
return o, nil
|
||||||
|
|
||||||
|
case scanBeginObject:
|
||||||
|
o, err := d.object()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.scanNext()
|
||||||
|
|
||||||
|
return o, nil
|
||||||
|
|
||||||
|
case scanBeginLiteral:
|
||||||
|
return d.literal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decodeState) array() (objects.Object, error) {
|
||||||
|
var arr []objects.Object
|
||||||
|
for {
|
||||||
|
// Look ahead for ] - can only happen on first iteration.
|
||||||
|
d.scanWhile(scanSkipSpace)
|
||||||
|
if d.opcode == scanEndArray {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
o, err := d.value()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
arr = append(arr, o)
|
||||||
|
|
||||||
|
// Next token must be , or ].
|
||||||
|
if d.opcode == scanSkipSpace {
|
||||||
|
d.scanWhile(scanSkipSpace)
|
||||||
|
}
|
||||||
|
if d.opcode == scanEndArray {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if d.opcode != scanArrayValue {
|
||||||
|
panic(phasePanicMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.Array{Value: arr}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decodeState) object() (objects.Object, error) {
|
||||||
|
m := make(map[string]objects.Object)
|
||||||
|
for {
|
||||||
|
// Read opening " of string key or closing }.
|
||||||
|
d.scanWhile(scanSkipSpace)
|
||||||
|
if d.opcode == scanEndObject {
|
||||||
|
// closing } - can only happen on first iteration.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if d.opcode != scanBeginLiteral {
|
||||||
|
panic(phasePanicMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read string key.
|
||||||
|
start := d.readIndex()
|
||||||
|
d.scanWhile(scanContinue)
|
||||||
|
item := d.data[start:d.readIndex()]
|
||||||
|
key, ok := unquote(item)
|
||||||
|
if !ok {
|
||||||
|
panic(phasePanicMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read : before value.
|
||||||
|
if d.opcode == scanSkipSpace {
|
||||||
|
d.scanWhile(scanSkipSpace)
|
||||||
|
}
|
||||||
|
if d.opcode != scanObjectKey {
|
||||||
|
panic(phasePanicMsg)
|
||||||
|
}
|
||||||
|
d.scanWhile(scanSkipSpace)
|
||||||
|
|
||||||
|
// Read value.
|
||||||
|
o, err := d.value()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m[key] = o
|
||||||
|
|
||||||
|
// Next token must be , or }.
|
||||||
|
if d.opcode == scanSkipSpace {
|
||||||
|
d.scanWhile(scanSkipSpace)
|
||||||
|
}
|
||||||
|
if d.opcode == scanEndObject {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if d.opcode != scanObjectValue {
|
||||||
|
panic(phasePanicMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.Map{Value: m}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decodeState) literal() (objects.Object, error) {
|
||||||
|
// All bytes inside literal return scanContinue op code.
|
||||||
|
start := d.readIndex()
|
||||||
|
d.scanWhile(scanContinue)
|
||||||
|
|
||||||
|
item := d.data[start:d.readIndex()]
|
||||||
|
|
||||||
|
switch c := item[0]; c {
|
||||||
|
case 'n': // null
|
||||||
|
return objects.UndefinedValue, nil
|
||||||
|
|
||||||
|
case 't', 'f': // true, false
|
||||||
|
if c == 't' {
|
||||||
|
return objects.TrueValue, nil
|
||||||
|
}
|
||||||
|
return objects.FalseValue, nil
|
||||||
|
|
||||||
|
case '"': // string
|
||||||
|
s, ok := unquote(item)
|
||||||
|
if !ok {
|
||||||
|
panic(phasePanicMsg)
|
||||||
|
}
|
||||||
|
return &objects.String{Value: s}, nil
|
||||||
|
|
||||||
|
default: // number
|
||||||
|
if c != '-' && (c < '0' || c > '9') {
|
||||||
|
panic(phasePanicMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
n, _ := strconv.ParseFloat(string(item), 10)
|
||||||
|
return &objects.Float{Value: n}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
|
||||||
|
// or it returns -1.
|
||||||
|
func getu4(s []byte) rune {
|
||||||
|
if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
var r rune
|
||||||
|
for _, c := range s[2:6] {
|
||||||
|
switch {
|
||||||
|
case '0' <= c && c <= '9':
|
||||||
|
c = c - '0'
|
||||||
|
case 'a' <= c && c <= 'f':
|
||||||
|
c = c - 'a' + 10
|
||||||
|
case 'A' <= c && c <= 'F':
|
||||||
|
c = c - 'A' + 10
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
r = r*16 + rune(c)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// unquote converts a quoted JSON string literal s into an actual string t.
|
||||||
|
// The rules are different than for Go, so cannot use strconv.Unquote.
|
||||||
|
func unquote(s []byte) (t string, ok bool) {
|
||||||
|
s, ok = unquoteBytes(s)
|
||||||
|
t = string(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func unquoteBytes(s []byte) (t []byte, ok bool) {
|
||||||
|
if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s = s[1 : len(s)-1]
|
||||||
|
|
||||||
|
// Check for unusual characters. If there are none,
|
||||||
|
// then no unquoting is needed, so return a slice of the
|
||||||
|
// original bytes.
|
||||||
|
r := 0
|
||||||
|
for r < len(s) {
|
||||||
|
c := s[r]
|
||||||
|
if c == '\\' || c == '"' || c < ' ' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if c < utf8.RuneSelf {
|
||||||
|
r++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rr, size := utf8.DecodeRune(s[r:])
|
||||||
|
if rr == utf8.RuneError && size == 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
r += size
|
||||||
|
}
|
||||||
|
if r == len(s) {
|
||||||
|
return s, true
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]byte, len(s)+2*utf8.UTFMax)
|
||||||
|
w := copy(b, s[0:r])
|
||||||
|
for r < len(s) {
|
||||||
|
// Out of room? Can only happen if s is full of
|
||||||
|
// malformed UTF-8 and we're replacing each
|
||||||
|
// byte with RuneError.
|
||||||
|
if w >= len(b)-2*utf8.UTFMax {
|
||||||
|
nb := make([]byte, (len(b)+utf8.UTFMax)*2)
|
||||||
|
copy(nb, b[0:w])
|
||||||
|
b = nb
|
||||||
|
}
|
||||||
|
switch c := s[r]; {
|
||||||
|
case c == '\\':
|
||||||
|
r++
|
||||||
|
if r >= len(s) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch s[r] {
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
case '"', '\\', '/', '\'':
|
||||||
|
b[w] = s[r]
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 'b':
|
||||||
|
b[w] = '\b'
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 'f':
|
||||||
|
b[w] = '\f'
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 'n':
|
||||||
|
b[w] = '\n'
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 'r':
|
||||||
|
b[w] = '\r'
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 't':
|
||||||
|
b[w] = '\t'
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
case 'u':
|
||||||
|
r--
|
||||||
|
rr := getu4(s[r:])
|
||||||
|
if rr < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r += 6
|
||||||
|
if utf16.IsSurrogate(rr) {
|
||||||
|
rr1 := getu4(s[r:])
|
||||||
|
if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
|
||||||
|
// A valid pair; consume.
|
||||||
|
r += 6
|
||||||
|
w += utf8.EncodeRune(b[w:], dec)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Invalid surrogate; fall back to replacement rune.
|
||||||
|
rr = unicode.ReplacementChar
|
||||||
|
}
|
||||||
|
w += utf8.EncodeRune(b[w:], rr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quote, control characters are invalid.
|
||||||
|
case c == '"', c < ' ':
|
||||||
|
return
|
||||||
|
|
||||||
|
// ASCII
|
||||||
|
case c < utf8.RuneSelf:
|
||||||
|
b[w] = c
|
||||||
|
r++
|
||||||
|
w++
|
||||||
|
|
||||||
|
// Coerce to well-formed UTF-8.
|
||||||
|
default:
|
||||||
|
rr, size := utf8.DecodeRune(s[r:])
|
||||||
|
r += size
|
||||||
|
w += utf8.EncodeRune(b[w:], rr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b[0:w], true
|
||||||
|
}
|
147
vendor/github.com/d5/tengo/stdlib/json/encode.go
generated
vendored
Normal file
147
vendor/github.com/d5/tengo/stdlib/json/encode.go
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
// A modified version of Go's JSON implementation.
|
||||||
|
|
||||||
|
// Copyright 2010 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 (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Encode returns the JSON encoding of the object.
|
||||||
|
func Encode(o objects.Object) ([]byte, error) {
|
||||||
|
var b []byte
|
||||||
|
|
||||||
|
switch o := o.(type) {
|
||||||
|
case *objects.Array:
|
||||||
|
b = append(b, '[')
|
||||||
|
len1 := len(o.Value) - 1
|
||||||
|
for idx, elem := range o.Value {
|
||||||
|
eb, err := Encode(elem)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b = append(b, eb...)
|
||||||
|
if idx < len1 {
|
||||||
|
b = append(b, ',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b = append(b, ']')
|
||||||
|
case *objects.ImmutableArray:
|
||||||
|
b = append(b, '[')
|
||||||
|
len1 := len(o.Value) - 1
|
||||||
|
for idx, elem := range o.Value {
|
||||||
|
eb, err := Encode(elem)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b = append(b, eb...)
|
||||||
|
if idx < len1 {
|
||||||
|
b = append(b, ',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b = append(b, ']')
|
||||||
|
case *objects.Map:
|
||||||
|
b = append(b, '{')
|
||||||
|
len1 := len(o.Value) - 1
|
||||||
|
idx := 0
|
||||||
|
for key, value := range o.Value {
|
||||||
|
b = strconv.AppendQuote(b, key)
|
||||||
|
b = append(b, ':')
|
||||||
|
eb, err := Encode(value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b = append(b, eb...)
|
||||||
|
if idx < len1 {
|
||||||
|
b = append(b, ',')
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
b = append(b, '}')
|
||||||
|
case *objects.ImmutableMap:
|
||||||
|
b = append(b, '{')
|
||||||
|
len1 := len(o.Value) - 1
|
||||||
|
idx := 0
|
||||||
|
for key, value := range o.Value {
|
||||||
|
b = strconv.AppendQuote(b, key)
|
||||||
|
b = append(b, ':')
|
||||||
|
eb, err := Encode(value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b = append(b, eb...)
|
||||||
|
if idx < len1 {
|
||||||
|
b = append(b, ',')
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
b = append(b, '}')
|
||||||
|
case *objects.Bool:
|
||||||
|
if o.IsFalsy() {
|
||||||
|
b = strconv.AppendBool(b, false)
|
||||||
|
} else {
|
||||||
|
b = strconv.AppendBool(b, true)
|
||||||
|
}
|
||||||
|
case *objects.Bytes:
|
||||||
|
b = append(b, '"')
|
||||||
|
encodedLen := base64.StdEncoding.EncodedLen(len(o.Value))
|
||||||
|
dst := make([]byte, encodedLen)
|
||||||
|
base64.StdEncoding.Encode(dst, o.Value)
|
||||||
|
b = append(b, dst...)
|
||||||
|
b = append(b, '"')
|
||||||
|
case *objects.Char:
|
||||||
|
b = strconv.AppendInt(b, int64(o.Value), 10)
|
||||||
|
case *objects.Float:
|
||||||
|
var y []byte
|
||||||
|
|
||||||
|
f := o.Value
|
||||||
|
if math.IsInf(f, 0) || math.IsNaN(f) {
|
||||||
|
return nil, errors.New("unsupported float value")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert as if by ES6 number to string conversion.
|
||||||
|
// This matches most other JSON generators.
|
||||||
|
abs := math.Abs(f)
|
||||||
|
fmt := byte('f')
|
||||||
|
if abs != 0 {
|
||||||
|
if abs < 1e-6 || abs >= 1e21 {
|
||||||
|
fmt = 'e'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y = strconv.AppendFloat(y, f, fmt, -1, 64)
|
||||||
|
if fmt == 'e' {
|
||||||
|
// clean up e-09 to e-9
|
||||||
|
n := len(y)
|
||||||
|
if n >= 4 && y[n-4] == 'e' && y[n-3] == '-' && y[n-2] == '0' {
|
||||||
|
y[n-2] = y[n-1]
|
||||||
|
y = y[:n-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b = append(b, y...)
|
||||||
|
case *objects.Int:
|
||||||
|
b = strconv.AppendInt(b, o.Value, 10)
|
||||||
|
case *objects.String:
|
||||||
|
b = strconv.AppendQuote(b, o.Value)
|
||||||
|
case *objects.Time:
|
||||||
|
y, err := o.Value.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b = append(b, y...)
|
||||||
|
case *objects.Undefined:
|
||||||
|
b = append(b, "null"...)
|
||||||
|
default:
|
||||||
|
// unknown type: ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return b, nil
|
||||||
|
}
|
559
vendor/github.com/d5/tengo/stdlib/json/scanner.go
generated
vendored
Normal file
559
vendor/github.com/d5/tengo/stdlib/json/scanner.go
generated
vendored
Normal file
@ -0,0 +1,559 @@
|
|||||||
|
// A modified version of Go's JSON implementation.
|
||||||
|
|
||||||
|
// Copyright 2010 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 "strconv"
|
||||||
|
|
||||||
|
func checkValid(data []byte, scan *scanner) error {
|
||||||
|
scan.reset()
|
||||||
|
for _, c := range data {
|
||||||
|
scan.bytes++
|
||||||
|
if scan.step(scan, c) == scanError {
|
||||||
|
return scan.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if scan.eof() == scanError {
|
||||||
|
return scan.err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A SyntaxError is a description of a JSON syntax error.
|
||||||
|
type SyntaxError struct {
|
||||||
|
msg string // description of error
|
||||||
|
Offset int64 // error occurred after reading Offset bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SyntaxError) Error() string { return e.msg }
|
||||||
|
|
||||||
|
// A scanner is a JSON scanning state machine.
|
||||||
|
// Callers call scan.reset() and then pass bytes in one at a time
|
||||||
|
// by calling scan.step(&scan, c) for each byte.
|
||||||
|
// The return value, referred to as an opcode, tells the
|
||||||
|
// caller about significant parsing events like beginning
|
||||||
|
// and ending literals, objects, and arrays, so that the
|
||||||
|
// caller can follow along if it wishes.
|
||||||
|
// The return value scanEnd indicates that a single top-level
|
||||||
|
// JSON value has been completed, *before* the byte that
|
||||||
|
// just got passed in. (The indication must be delayed in order
|
||||||
|
// to recognize the end of numbers: is 123 a whole value or
|
||||||
|
// the beginning of 12345e+6?).
|
||||||
|
type scanner struct {
|
||||||
|
// The step is a func to be called to execute the next transition.
|
||||||
|
// Also tried using an integer constant and a single func
|
||||||
|
// with a switch, but using the func directly was 10% faster
|
||||||
|
// on a 64-bit Mac Mini, and it's nicer to read.
|
||||||
|
step func(*scanner, byte) int
|
||||||
|
|
||||||
|
// Reached end of top-level value.
|
||||||
|
endTop bool
|
||||||
|
|
||||||
|
// Stack of what we're in the middle of - array values, object keys, object values.
|
||||||
|
parseState []int
|
||||||
|
|
||||||
|
// Error that happened, if any.
|
||||||
|
err error
|
||||||
|
|
||||||
|
// total bytes consumed, updated by decoder.Decode
|
||||||
|
bytes int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// These values are returned by the state transition functions
|
||||||
|
// assigned to scanner.state and the method scanner.eof.
|
||||||
|
// They give details about the current state of the scan that
|
||||||
|
// callers might be interested to know about.
|
||||||
|
// It is okay to ignore the return value of any particular
|
||||||
|
// call to scanner.state: if one call returns scanError,
|
||||||
|
// every subsequent call will return scanError too.
|
||||||
|
const (
|
||||||
|
// Continue.
|
||||||
|
scanContinue = iota // uninteresting byte
|
||||||
|
scanBeginLiteral // end implied by next result != scanContinue
|
||||||
|
scanBeginObject // begin object
|
||||||
|
scanObjectKey // just finished object key (string)
|
||||||
|
scanObjectValue // just finished non-last object value
|
||||||
|
scanEndObject // end object (implies scanObjectValue if possible)
|
||||||
|
scanBeginArray // begin array
|
||||||
|
scanArrayValue // just finished array value
|
||||||
|
scanEndArray // end array (implies scanArrayValue if possible)
|
||||||
|
scanSkipSpace // space byte; can skip; known to be last "continue" result
|
||||||
|
|
||||||
|
// Stop.
|
||||||
|
scanEnd // top-level value ended *before* this byte; known to be first "stop" result
|
||||||
|
scanError // hit an error, scanner.err.
|
||||||
|
)
|
||||||
|
|
||||||
|
// These values are stored in the parseState stack.
|
||||||
|
// They give the current state of a composite value
|
||||||
|
// being scanned. If the parser is inside a nested value
|
||||||
|
// the parseState describes the nested state, outermost at entry 0.
|
||||||
|
const (
|
||||||
|
parseObjectKey = iota // parsing object key (before colon)
|
||||||
|
parseObjectValue // parsing object value (after colon)
|
||||||
|
parseArrayValue // parsing array value
|
||||||
|
)
|
||||||
|
|
||||||
|
// reset prepares the scanner for use.
|
||||||
|
// It must be called before calling s.step.
|
||||||
|
func (s *scanner) reset() {
|
||||||
|
s.step = stateBeginValue
|
||||||
|
s.parseState = s.parseState[0:0]
|
||||||
|
s.err = nil
|
||||||
|
s.endTop = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// eof tells the scanner that the end of input has been reached.
|
||||||
|
// It returns a scan status just as s.step does.
|
||||||
|
func (s *scanner) eof() int {
|
||||||
|
if s.err != nil {
|
||||||
|
return scanError
|
||||||
|
}
|
||||||
|
if s.endTop {
|
||||||
|
return scanEnd
|
||||||
|
}
|
||||||
|
s.step(s, ' ')
|
||||||
|
if s.endTop {
|
||||||
|
return scanEnd
|
||||||
|
}
|
||||||
|
if s.err == nil {
|
||||||
|
s.err = &SyntaxError{"unexpected end of JSON input", s.bytes}
|
||||||
|
}
|
||||||
|
return scanError
|
||||||
|
}
|
||||||
|
|
||||||
|
// pushParseState pushes a new parse state p onto the parse stack.
|
||||||
|
func (s *scanner) pushParseState(p int) {
|
||||||
|
s.parseState = append(s.parseState, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// popParseState pops a parse state (already obtained) off the stack
|
||||||
|
// and updates s.step accordingly.
|
||||||
|
func (s *scanner) popParseState() {
|
||||||
|
n := len(s.parseState) - 1
|
||||||
|
s.parseState = s.parseState[0:n]
|
||||||
|
if n == 0 {
|
||||||
|
s.step = stateEndTop
|
||||||
|
s.endTop = true
|
||||||
|
} else {
|
||||||
|
s.step = stateEndValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSpace(c byte) bool {
|
||||||
|
return c == ' ' || c == '\t' || c == '\r' || c == '\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateBeginValueOrEmpty is the state after reading `[`.
|
||||||
|
func stateBeginValueOrEmpty(s *scanner, c byte) int {
|
||||||
|
if c <= ' ' && isSpace(c) {
|
||||||
|
return scanSkipSpace
|
||||||
|
}
|
||||||
|
if c == ']' {
|
||||||
|
return stateEndValue(s, c)
|
||||||
|
}
|
||||||
|
return stateBeginValue(s, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateBeginValue is the state at the beginning of the input.
|
||||||
|
func stateBeginValue(s *scanner, c byte) int {
|
||||||
|
if c <= ' ' && isSpace(c) {
|
||||||
|
return scanSkipSpace
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case '{':
|
||||||
|
s.step = stateBeginStringOrEmpty
|
||||||
|
s.pushParseState(parseObjectKey)
|
||||||
|
return scanBeginObject
|
||||||
|
case '[':
|
||||||
|
s.step = stateBeginValueOrEmpty
|
||||||
|
s.pushParseState(parseArrayValue)
|
||||||
|
return scanBeginArray
|
||||||
|
case '"':
|
||||||
|
s.step = stateInString
|
||||||
|
return scanBeginLiteral
|
||||||
|
case '-':
|
||||||
|
s.step = stateNeg
|
||||||
|
return scanBeginLiteral
|
||||||
|
case '0': // beginning of 0.123
|
||||||
|
s.step = state0
|
||||||
|
return scanBeginLiteral
|
||||||
|
case 't': // beginning of true
|
||||||
|
s.step = stateT
|
||||||
|
return scanBeginLiteral
|
||||||
|
case 'f': // beginning of false
|
||||||
|
s.step = stateF
|
||||||
|
return scanBeginLiteral
|
||||||
|
case 'n': // beginning of null
|
||||||
|
s.step = stateN
|
||||||
|
return scanBeginLiteral
|
||||||
|
}
|
||||||
|
if '1' <= c && c <= '9' { // beginning of 1234.5
|
||||||
|
s.step = state1
|
||||||
|
return scanBeginLiteral
|
||||||
|
}
|
||||||
|
return s.error(c, "looking for beginning of value")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateBeginStringOrEmpty is the state after reading `{`.
|
||||||
|
func stateBeginStringOrEmpty(s *scanner, c byte) int {
|
||||||
|
if c <= ' ' && isSpace(c) {
|
||||||
|
return scanSkipSpace
|
||||||
|
}
|
||||||
|
if c == '}' {
|
||||||
|
n := len(s.parseState)
|
||||||
|
s.parseState[n-1] = parseObjectValue
|
||||||
|
return stateEndValue(s, c)
|
||||||
|
}
|
||||||
|
return stateBeginString(s, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateBeginString is the state after reading `{"key": value,`.
|
||||||
|
func stateBeginString(s *scanner, c byte) int {
|
||||||
|
if c <= ' ' && isSpace(c) {
|
||||||
|
return scanSkipSpace
|
||||||
|
}
|
||||||
|
if c == '"' {
|
||||||
|
s.step = stateInString
|
||||||
|
return scanBeginLiteral
|
||||||
|
}
|
||||||
|
return s.error(c, "looking for beginning of object key string")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateEndValue is the state after completing a value,
|
||||||
|
// such as after reading `{}` or `true` or `["x"`.
|
||||||
|
func stateEndValue(s *scanner, c byte) int {
|
||||||
|
n := len(s.parseState)
|
||||||
|
if n == 0 {
|
||||||
|
// Completed top-level before the current byte.
|
||||||
|
s.step = stateEndTop
|
||||||
|
s.endTop = true
|
||||||
|
return stateEndTop(s, c)
|
||||||
|
}
|
||||||
|
if c <= ' ' && isSpace(c) {
|
||||||
|
s.step = stateEndValue
|
||||||
|
return scanSkipSpace
|
||||||
|
}
|
||||||
|
ps := s.parseState[n-1]
|
||||||
|
switch ps {
|
||||||
|
case parseObjectKey:
|
||||||
|
if c == ':' {
|
||||||
|
s.parseState[n-1] = parseObjectValue
|
||||||
|
s.step = stateBeginValue
|
||||||
|
return scanObjectKey
|
||||||
|
}
|
||||||
|
return s.error(c, "after object key")
|
||||||
|
case parseObjectValue:
|
||||||
|
if c == ',' {
|
||||||
|
s.parseState[n-1] = parseObjectKey
|
||||||
|
s.step = stateBeginString
|
||||||
|
return scanObjectValue
|
||||||
|
}
|
||||||
|
if c == '}' {
|
||||||
|
s.popParseState()
|
||||||
|
return scanEndObject
|
||||||
|
}
|
||||||
|
return s.error(c, "after object key:value pair")
|
||||||
|
case parseArrayValue:
|
||||||
|
if c == ',' {
|
||||||
|
s.step = stateBeginValue
|
||||||
|
return scanArrayValue
|
||||||
|
}
|
||||||
|
if c == ']' {
|
||||||
|
s.popParseState()
|
||||||
|
return scanEndArray
|
||||||
|
}
|
||||||
|
return s.error(c, "after array element")
|
||||||
|
}
|
||||||
|
return s.error(c, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateEndTop is the state after finishing the top-level value,
|
||||||
|
// such as after reading `{}` or `[1,2,3]`.
|
||||||
|
// Only space characters should be seen now.
|
||||||
|
func stateEndTop(s *scanner, c byte) int {
|
||||||
|
if !isSpace(c) {
|
||||||
|
// Complain about non-space byte on next call.
|
||||||
|
s.error(c, "after top-level value")
|
||||||
|
}
|
||||||
|
return scanEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateInString is the state after reading `"`.
|
||||||
|
func stateInString(s *scanner, c byte) int {
|
||||||
|
if c == '"' {
|
||||||
|
s.step = stateEndValue
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
if c == '\\' {
|
||||||
|
s.step = stateInStringEsc
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
if c < 0x20 {
|
||||||
|
return s.error(c, "in string literal")
|
||||||
|
}
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateInStringEsc is the state after reading `"\` during a quoted string.
|
||||||
|
func stateInStringEsc(s *scanner, c byte) int {
|
||||||
|
switch c {
|
||||||
|
case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
|
||||||
|
s.step = stateInString
|
||||||
|
return scanContinue
|
||||||
|
case 'u':
|
||||||
|
s.step = stateInStringEscU
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in string escape code")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateInStringEscU is the state after reading `"\u` during a quoted string.
|
||||||
|
func stateInStringEscU(s *scanner, c byte) int {
|
||||||
|
if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
|
||||||
|
s.step = stateInStringEscU1
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
// numbers
|
||||||
|
return s.error(c, "in \\u hexadecimal character escape")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateInStringEscU1 is the state after reading `"\u1` during a quoted string.
|
||||||
|
func stateInStringEscU1(s *scanner, c byte) int {
|
||||||
|
if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
|
||||||
|
s.step = stateInStringEscU12
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
// numbers
|
||||||
|
return s.error(c, "in \\u hexadecimal character escape")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateInStringEscU12 is the state after reading `"\u12` during a quoted string.
|
||||||
|
func stateInStringEscU12(s *scanner, c byte) int {
|
||||||
|
if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
|
||||||
|
s.step = stateInStringEscU123
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
// numbers
|
||||||
|
return s.error(c, "in \\u hexadecimal character escape")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateInStringEscU123 is the state after reading `"\u123` during a quoted string.
|
||||||
|
func stateInStringEscU123(s *scanner, c byte) int {
|
||||||
|
if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
|
||||||
|
s.step = stateInString
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
// numbers
|
||||||
|
return s.error(c, "in \\u hexadecimal character escape")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateNeg is the state after reading `-` during a number.
|
||||||
|
func stateNeg(s *scanner, c byte) int {
|
||||||
|
if c == '0' {
|
||||||
|
s.step = state0
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
if '1' <= c && c <= '9' {
|
||||||
|
s.step = state1
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in numeric literal")
|
||||||
|
}
|
||||||
|
|
||||||
|
// state1 is the state after reading a non-zero integer during a number,
|
||||||
|
// such as after reading `1` or `100` but not `0`.
|
||||||
|
func state1(s *scanner, c byte) int {
|
||||||
|
if '0' <= c && c <= '9' {
|
||||||
|
s.step = state1
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return state0(s, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// state0 is the state after reading `0` during a number.
|
||||||
|
func state0(s *scanner, c byte) int {
|
||||||
|
if c == '.' {
|
||||||
|
s.step = stateDot
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
if c == 'e' || c == 'E' {
|
||||||
|
s.step = stateE
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return stateEndValue(s, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateDot is the state after reading the integer and decimal point in a number,
|
||||||
|
// such as after reading `1.`.
|
||||||
|
func stateDot(s *scanner, c byte) int {
|
||||||
|
if '0' <= c && c <= '9' {
|
||||||
|
s.step = stateDot0
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "after decimal point in numeric literal")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateDot0 is the state after reading the integer, decimal point, and subsequent
|
||||||
|
// digits of a number, such as after reading `3.14`.
|
||||||
|
func stateDot0(s *scanner, c byte) int {
|
||||||
|
if '0' <= c && c <= '9' {
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
if c == 'e' || c == 'E' {
|
||||||
|
s.step = stateE
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return stateEndValue(s, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateE is the state after reading the mantissa and e in a number,
|
||||||
|
// such as after reading `314e` or `0.314e`.
|
||||||
|
func stateE(s *scanner, c byte) int {
|
||||||
|
if c == '+' || c == '-' {
|
||||||
|
s.step = stateESign
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return stateESign(s, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateESign is the state after reading the mantissa, e, and sign in a number,
|
||||||
|
// such as after reading `314e-` or `0.314e+`.
|
||||||
|
func stateESign(s *scanner, c byte) int {
|
||||||
|
if '0' <= c && c <= '9' {
|
||||||
|
s.step = stateE0
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in exponent of numeric literal")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateE0 is the state after reading the mantissa, e, optional sign,
|
||||||
|
// and at least one digit of the exponent in a number,
|
||||||
|
// such as after reading `314e-2` or `0.314e+1` or `3.14e0`.
|
||||||
|
func stateE0(s *scanner, c byte) int {
|
||||||
|
if '0' <= c && c <= '9' {
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return stateEndValue(s, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateT is the state after reading `t`.
|
||||||
|
func stateT(s *scanner, c byte) int {
|
||||||
|
if c == 'r' {
|
||||||
|
s.step = stateTr
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in literal true (expecting 'r')")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateTr is the state after reading `tr`.
|
||||||
|
func stateTr(s *scanner, c byte) int {
|
||||||
|
if c == 'u' {
|
||||||
|
s.step = stateTru
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in literal true (expecting 'u')")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateTru is the state after reading `tru`.
|
||||||
|
func stateTru(s *scanner, c byte) int {
|
||||||
|
if c == 'e' {
|
||||||
|
s.step = stateEndValue
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in literal true (expecting 'e')")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateF is the state after reading `f`.
|
||||||
|
func stateF(s *scanner, c byte) int {
|
||||||
|
if c == 'a' {
|
||||||
|
s.step = stateFa
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in literal false (expecting 'a')")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateFa is the state after reading `fa`.
|
||||||
|
func stateFa(s *scanner, c byte) int {
|
||||||
|
if c == 'l' {
|
||||||
|
s.step = stateFal
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in literal false (expecting 'l')")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateFal is the state after reading `fal`.
|
||||||
|
func stateFal(s *scanner, c byte) int {
|
||||||
|
if c == 's' {
|
||||||
|
s.step = stateFals
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in literal false (expecting 's')")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateFals is the state after reading `fals`.
|
||||||
|
func stateFals(s *scanner, c byte) int {
|
||||||
|
if c == 'e' {
|
||||||
|
s.step = stateEndValue
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in literal false (expecting 'e')")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateN is the state after reading `n`.
|
||||||
|
func stateN(s *scanner, c byte) int {
|
||||||
|
if c == 'u' {
|
||||||
|
s.step = stateNu
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in literal null (expecting 'u')")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateNu is the state after reading `nu`.
|
||||||
|
func stateNu(s *scanner, c byte) int {
|
||||||
|
if c == 'l' {
|
||||||
|
s.step = stateNul
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in literal null (expecting 'l')")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateNul is the state after reading `nul`.
|
||||||
|
func stateNul(s *scanner, c byte) int {
|
||||||
|
if c == 'l' {
|
||||||
|
s.step = stateEndValue
|
||||||
|
return scanContinue
|
||||||
|
}
|
||||||
|
return s.error(c, "in literal null (expecting 'l')")
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateError is the state after reaching a syntax error,
|
||||||
|
// such as after reading `[1}` or `5.1.2`.
|
||||||
|
func stateError(s *scanner, c byte) int {
|
||||||
|
return scanError
|
||||||
|
}
|
||||||
|
|
||||||
|
// error records an error and switches to the error state.
|
||||||
|
func (s *scanner) error(c byte, context string) int {
|
||||||
|
s.step = stateError
|
||||||
|
s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes}
|
||||||
|
return scanError
|
||||||
|
}
|
||||||
|
|
||||||
|
// quoteChar formats c as a quoted character literal
|
||||||
|
func quoteChar(c byte) string {
|
||||||
|
// special cases - different from quoted strings
|
||||||
|
if c == '\'' {
|
||||||
|
return `'\''`
|
||||||
|
}
|
||||||
|
if c == '"' {
|
||||||
|
return `'"'`
|
||||||
|
}
|
||||||
|
|
||||||
|
// use quoted string with different quotation marks
|
||||||
|
s := strconv.Quote(string(c))
|
||||||
|
return "'" + s[1:len(s)-1] + "'"
|
||||||
|
}
|
74
vendor/github.com/d5/tengo/stdlib/math.go
generated
vendored
Normal file
74
vendor/github.com/d5/tengo/stdlib/math.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mathModule = map[string]objects.Object{
|
||||||
|
"e": &objects.Float{Value: math.E},
|
||||||
|
"pi": &objects.Float{Value: math.Pi},
|
||||||
|
"phi": &objects.Float{Value: math.Phi},
|
||||||
|
"sqrt2": &objects.Float{Value: math.Sqrt2},
|
||||||
|
"sqrtE": &objects.Float{Value: math.SqrtE},
|
||||||
|
"sqrtPi": &objects.Float{Value: math.SqrtPi},
|
||||||
|
"sqrtPhi": &objects.Float{Value: math.SqrtPhi},
|
||||||
|
"ln2": &objects.Float{Value: math.Ln2},
|
||||||
|
"log2E": &objects.Float{Value: math.Log2E},
|
||||||
|
"ln10": &objects.Float{Value: math.Ln10},
|
||||||
|
"log10E": &objects.Float{Value: math.Log10E},
|
||||||
|
"abs": &objects.UserFunction{Name: "abs", Value: FuncAFRF(math.Abs)},
|
||||||
|
"acos": &objects.UserFunction{Name: "acos", Value: FuncAFRF(math.Acos)},
|
||||||
|
"acosh": &objects.UserFunction{Name: "acosh", Value: FuncAFRF(math.Acosh)},
|
||||||
|
"asin": &objects.UserFunction{Name: "asin", Value: FuncAFRF(math.Asin)},
|
||||||
|
"asinh": &objects.UserFunction{Name: "asinh", Value: FuncAFRF(math.Asinh)},
|
||||||
|
"atan": &objects.UserFunction{Name: "atan", Value: FuncAFRF(math.Atan)},
|
||||||
|
"atan2": &objects.UserFunction{Name: "atan2", Value: FuncAFFRF(math.Atan2)},
|
||||||
|
"atanh": &objects.UserFunction{Name: "atanh", Value: FuncAFRF(math.Atanh)},
|
||||||
|
"cbrt": &objects.UserFunction{Name: "cbrt", Value: FuncAFRF(math.Cbrt)},
|
||||||
|
"ceil": &objects.UserFunction{Name: "ceil", Value: FuncAFRF(math.Ceil)},
|
||||||
|
"copysign": &objects.UserFunction{Name: "copysign", Value: FuncAFFRF(math.Copysign)},
|
||||||
|
"cos": &objects.UserFunction{Name: "cos", Value: FuncAFRF(math.Cos)},
|
||||||
|
"cosh": &objects.UserFunction{Name: "cosh", Value: FuncAFRF(math.Cosh)},
|
||||||
|
"dim": &objects.UserFunction{Name: "dim", Value: FuncAFFRF(math.Dim)},
|
||||||
|
"erf": &objects.UserFunction{Name: "erf", Value: FuncAFRF(math.Erf)},
|
||||||
|
"erfc": &objects.UserFunction{Name: "erfc", Value: FuncAFRF(math.Erfc)},
|
||||||
|
"exp": &objects.UserFunction{Name: "exp", Value: FuncAFRF(math.Exp)},
|
||||||
|
"exp2": &objects.UserFunction{Name: "exp2", Value: FuncAFRF(math.Exp2)},
|
||||||
|
"expm1": &objects.UserFunction{Name: "expm1", Value: FuncAFRF(math.Expm1)},
|
||||||
|
"floor": &objects.UserFunction{Name: "floor", Value: FuncAFRF(math.Floor)},
|
||||||
|
"gamma": &objects.UserFunction{Name: "gamma", Value: FuncAFRF(math.Gamma)},
|
||||||
|
"hypot": &objects.UserFunction{Name: "hypot", Value: FuncAFFRF(math.Hypot)},
|
||||||
|
"ilogb": &objects.UserFunction{Name: "ilogb", Value: FuncAFRI(math.Ilogb)},
|
||||||
|
"inf": &objects.UserFunction{Name: "inf", Value: FuncAIRF(math.Inf)},
|
||||||
|
"is_inf": &objects.UserFunction{Name: "is_inf", Value: FuncAFIRB(math.IsInf)},
|
||||||
|
"is_nan": &objects.UserFunction{Name: "is_nan", Value: FuncAFRB(math.IsNaN)},
|
||||||
|
"j0": &objects.UserFunction{Name: "j0", Value: FuncAFRF(math.J0)},
|
||||||
|
"j1": &objects.UserFunction{Name: "j1", Value: FuncAFRF(math.J1)},
|
||||||
|
"jn": &objects.UserFunction{Name: "jn", Value: FuncAIFRF(math.Jn)},
|
||||||
|
"ldexp": &objects.UserFunction{Name: "ldexp", Value: FuncAFIRF(math.Ldexp)},
|
||||||
|
"log": &objects.UserFunction{Name: "log", Value: FuncAFRF(math.Log)},
|
||||||
|
"log10": &objects.UserFunction{Name: "log10", Value: FuncAFRF(math.Log10)},
|
||||||
|
"log1p": &objects.UserFunction{Name: "log1p", Value: FuncAFRF(math.Log1p)},
|
||||||
|
"log2": &objects.UserFunction{Name: "log2", Value: FuncAFRF(math.Log2)},
|
||||||
|
"logb": &objects.UserFunction{Name: "logb", Value: FuncAFRF(math.Logb)},
|
||||||
|
"max": &objects.UserFunction{Name: "max", Value: FuncAFFRF(math.Max)},
|
||||||
|
"min": &objects.UserFunction{Name: "min", Value: FuncAFFRF(math.Min)},
|
||||||
|
"mod": &objects.UserFunction{Name: "mod", Value: FuncAFFRF(math.Mod)},
|
||||||
|
"nan": &objects.UserFunction{Name: "nan", Value: FuncARF(math.NaN)},
|
||||||
|
"nextafter": &objects.UserFunction{Name: "nextafter", Value: FuncAFFRF(math.Nextafter)},
|
||||||
|
"pow": &objects.UserFunction{Name: "pow", Value: FuncAFFRF(math.Pow)},
|
||||||
|
"pow10": &objects.UserFunction{Name: "pow10", Value: FuncAIRF(math.Pow10)},
|
||||||
|
"remainder": &objects.UserFunction{Name: "remainder", Value: FuncAFFRF(math.Remainder)},
|
||||||
|
"signbit": &objects.UserFunction{Name: "signbit", Value: FuncAFRB(math.Signbit)},
|
||||||
|
"sin": &objects.UserFunction{Name: "sin", Value: FuncAFRF(math.Sin)},
|
||||||
|
"sinh": &objects.UserFunction{Name: "sinh", Value: FuncAFRF(math.Sinh)},
|
||||||
|
"sqrt": &objects.UserFunction{Name: "sqrt", Value: FuncAFRF(math.Sqrt)},
|
||||||
|
"tan": &objects.UserFunction{Name: "tan", Value: FuncAFRF(math.Tan)},
|
||||||
|
"tanh": &objects.UserFunction{Name: "tanh", Value: FuncAFRF(math.Tanh)},
|
||||||
|
"trunc": &objects.UserFunction{Name: "trunc", Value: FuncAFRF(math.Trunc)},
|
||||||
|
"y0": &objects.UserFunction{Name: "y0", Value: FuncAFRF(math.Y0)},
|
||||||
|
"y1": &objects.UserFunction{Name: "y1", Value: FuncAFRF(math.Y1)},
|
||||||
|
"yn": &objects.UserFunction{Name: "yn", Value: FuncAIFRF(math.Yn)},
|
||||||
|
}
|
492
vendor/github.com/d5/tengo/stdlib/os.go
generated
vendored
Normal file
492
vendor/github.com/d5/tengo/stdlib/os.go
generated
vendored
Normal file
@ -0,0 +1,492 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
var osModule = map[string]objects.Object{
|
||||||
|
"o_rdonly": &objects.Int{Value: int64(os.O_RDONLY)},
|
||||||
|
"o_wronly": &objects.Int{Value: int64(os.O_WRONLY)},
|
||||||
|
"o_rdwr": &objects.Int{Value: int64(os.O_RDWR)},
|
||||||
|
"o_append": &objects.Int{Value: int64(os.O_APPEND)},
|
||||||
|
"o_create": &objects.Int{Value: int64(os.O_CREATE)},
|
||||||
|
"o_excl": &objects.Int{Value: int64(os.O_EXCL)},
|
||||||
|
"o_sync": &objects.Int{Value: int64(os.O_SYNC)},
|
||||||
|
"o_trunc": &objects.Int{Value: int64(os.O_TRUNC)},
|
||||||
|
"mode_dir": &objects.Int{Value: int64(os.ModeDir)},
|
||||||
|
"mode_append": &objects.Int{Value: int64(os.ModeAppend)},
|
||||||
|
"mode_exclusive": &objects.Int{Value: int64(os.ModeExclusive)},
|
||||||
|
"mode_temporary": &objects.Int{Value: int64(os.ModeTemporary)},
|
||||||
|
"mode_symlink": &objects.Int{Value: int64(os.ModeSymlink)},
|
||||||
|
"mode_device": &objects.Int{Value: int64(os.ModeDevice)},
|
||||||
|
"mode_named_pipe": &objects.Int{Value: int64(os.ModeNamedPipe)},
|
||||||
|
"mode_socket": &objects.Int{Value: int64(os.ModeSocket)},
|
||||||
|
"mode_setuid": &objects.Int{Value: int64(os.ModeSetuid)},
|
||||||
|
"mode_setgui": &objects.Int{Value: int64(os.ModeSetgid)},
|
||||||
|
"mode_char_device": &objects.Int{Value: int64(os.ModeCharDevice)},
|
||||||
|
"mode_sticky": &objects.Int{Value: int64(os.ModeSticky)},
|
||||||
|
"mode_type": &objects.Int{Value: int64(os.ModeType)},
|
||||||
|
"mode_perm": &objects.Int{Value: int64(os.ModePerm)},
|
||||||
|
"path_separator": &objects.Char{Value: os.PathSeparator},
|
||||||
|
"path_list_separator": &objects.Char{Value: os.PathListSeparator},
|
||||||
|
"dev_null": &objects.String{Value: os.DevNull},
|
||||||
|
"seek_set": &objects.Int{Value: int64(io.SeekStart)},
|
||||||
|
"seek_cur": &objects.Int{Value: int64(io.SeekCurrent)},
|
||||||
|
"seek_end": &objects.Int{Value: int64(io.SeekEnd)},
|
||||||
|
"args": &objects.UserFunction{Name: "args", Value: osArgs}, // args() => array(string)
|
||||||
|
"chdir": &objects.UserFunction{Name: "chdir", Value: FuncASRE(os.Chdir)}, // chdir(dir string) => error
|
||||||
|
"chmod": osFuncASFmRE("chmod", os.Chmod), // chmod(name string, mode int) => error
|
||||||
|
"chown": &objects.UserFunction{Name: "chown", Value: FuncASIIRE(os.Chown)}, // chown(name string, uid int, gid int) => error
|
||||||
|
"clearenv": &objects.UserFunction{Name: "clearenv", Value: FuncAR(os.Clearenv)}, // clearenv()
|
||||||
|
"environ": &objects.UserFunction{Name: "environ", Value: FuncARSs(os.Environ)}, // environ() => array(string)
|
||||||
|
"exit": &objects.UserFunction{Name: "exit", Value: FuncAIR(os.Exit)}, // exit(code int)
|
||||||
|
"expand_env": &objects.UserFunction{Name: "expand_env", Value: osExpandEnv}, // expand_env(s string) => string
|
||||||
|
"getegid": &objects.UserFunction{Name: "getegid", Value: FuncARI(os.Getegid)}, // getegid() => int
|
||||||
|
"getenv": &objects.UserFunction{Name: "getenv", Value: FuncASRS(os.Getenv)}, // getenv(s string) => string
|
||||||
|
"geteuid": &objects.UserFunction{Name: "geteuid", Value: FuncARI(os.Geteuid)}, // geteuid() => int
|
||||||
|
"getgid": &objects.UserFunction{Name: "getgid", Value: FuncARI(os.Getgid)}, // getgid() => int
|
||||||
|
"getgroups": &objects.UserFunction{Name: "getgroups", Value: FuncARIsE(os.Getgroups)}, // getgroups() => array(string)/error
|
||||||
|
"getpagesize": &objects.UserFunction{Name: "getpagesize", Value: FuncARI(os.Getpagesize)}, // getpagesize() => int
|
||||||
|
"getpid": &objects.UserFunction{Name: "getpid", Value: FuncARI(os.Getpid)}, // getpid() => int
|
||||||
|
"getppid": &objects.UserFunction{Name: "getppid", Value: FuncARI(os.Getppid)}, // getppid() => int
|
||||||
|
"getuid": &objects.UserFunction{Name: "getuid", Value: FuncARI(os.Getuid)}, // getuid() => int
|
||||||
|
"getwd": &objects.UserFunction{Name: "getwd", Value: FuncARSE(os.Getwd)}, // getwd() => string/error
|
||||||
|
"hostname": &objects.UserFunction{Name: "hostname", Value: FuncARSE(os.Hostname)}, // hostname() => string/error
|
||||||
|
"lchown": &objects.UserFunction{Name: "lchown", Value: FuncASIIRE(os.Lchown)}, // lchown(name string, uid int, gid int) => error
|
||||||
|
"link": &objects.UserFunction{Name: "link", Value: FuncASSRE(os.Link)}, // link(oldname string, newname string) => error
|
||||||
|
"lookup_env": &objects.UserFunction{Name: "lookup_env", Value: osLookupEnv}, // lookup_env(key string) => string/false
|
||||||
|
"mkdir": osFuncASFmRE("mkdir", os.Mkdir), // mkdir(name string, perm int) => error
|
||||||
|
"mkdir_all": osFuncASFmRE("mkdir_all", os.MkdirAll), // mkdir_all(name string, perm int) => error
|
||||||
|
"readlink": &objects.UserFunction{Name: "readlink", Value: FuncASRSE(os.Readlink)}, // readlink(name string) => string/error
|
||||||
|
"remove": &objects.UserFunction{Name: "remove", Value: FuncASRE(os.Remove)}, // remove(name string) => error
|
||||||
|
"remove_all": &objects.UserFunction{Name: "remove_all", Value: FuncASRE(os.RemoveAll)}, // remove_all(name string) => error
|
||||||
|
"rename": &objects.UserFunction{Name: "rename", Value: FuncASSRE(os.Rename)}, // rename(oldpath string, newpath string) => error
|
||||||
|
"setenv": &objects.UserFunction{Name: "setenv", Value: FuncASSRE(os.Setenv)}, // setenv(key string, value string) => error
|
||||||
|
"symlink": &objects.UserFunction{Name: "symlink", Value: FuncASSRE(os.Symlink)}, // symlink(oldname string newname string) => error
|
||||||
|
"temp_dir": &objects.UserFunction{Name: "temp_dir", Value: FuncARS(os.TempDir)}, // temp_dir() => string
|
||||||
|
"truncate": &objects.UserFunction{Name: "truncate", Value: FuncASI64RE(os.Truncate)}, // truncate(name string, size int) => error
|
||||||
|
"unsetenv": &objects.UserFunction{Name: "unsetenv", Value: FuncASRE(os.Unsetenv)}, // unsetenv(key string) => error
|
||||||
|
"create": &objects.UserFunction{Name: "create", Value: osCreate}, // create(name string) => imap(file)/error
|
||||||
|
"open": &objects.UserFunction{Name: "open", Value: osOpen}, // open(name string) => imap(file)/error
|
||||||
|
"open_file": &objects.UserFunction{Name: "open_file", Value: osOpenFile}, // open_file(name string, flag int, perm int) => imap(file)/error
|
||||||
|
"find_process": &objects.UserFunction{Name: "find_process", Value: osFindProcess}, // find_process(pid int) => imap(process)/error
|
||||||
|
"start_process": &objects.UserFunction{Name: "start_process", Value: osStartProcess}, // start_process(name string, argv array(string), dir string, env array(string)) => imap(process)/error
|
||||||
|
"exec_look_path": &objects.UserFunction{Name: "exec_look_path", Value: FuncASRSE(exec.LookPath)}, // exec_look_path(file) => string/error
|
||||||
|
"exec": &objects.UserFunction{Name: "exec", Value: osExec}, // exec(name, args...) => command
|
||||||
|
"stat": &objects.UserFunction{Name: "stat", Value: osStat}, // stat(name) => imap(fileinfo)/error
|
||||||
|
"read_file": &objects.UserFunction{Name: "read_file", Value: osReadFile}, // readfile(name) => array(byte)/error
|
||||||
|
}
|
||||||
|
|
||||||
|
func osReadFile(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
fname, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := ioutil.ReadFile(fname)
|
||||||
|
if err != nil {
|
||||||
|
return wrapError(err), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(bytes) > tengo.MaxBytesLen {
|
||||||
|
return nil, objects.ErrBytesLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.Bytes{Value: bytes}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func osStat(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
fname, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stat, err := os.Stat(fname)
|
||||||
|
if err != nil {
|
||||||
|
return wrapError(err), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fstat := &objects.ImmutableMap{
|
||||||
|
Value: map[string]objects.Object{
|
||||||
|
"name": &objects.String{Value: stat.Name()},
|
||||||
|
"mtime": &objects.Time{Value: stat.ModTime()},
|
||||||
|
"size": &objects.Int{Value: stat.Size()},
|
||||||
|
"mode": &objects.Int{Value: int64(stat.Mode())},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if stat.IsDir() {
|
||||||
|
fstat.Value["directory"] = objects.TrueValue
|
||||||
|
} else {
|
||||||
|
fstat.Value["directory"] = objects.FalseValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return fstat, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func osCreate(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := os.Create(s1)
|
||||||
|
if err != nil {
|
||||||
|
return wrapError(err), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeOSFile(res), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func osOpen(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := os.Open(s1)
|
||||||
|
if err != nil {
|
||||||
|
return wrapError(err), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeOSFile(res), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func osOpenFile(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) != 3 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i2, ok := objects.ToInt(args[1])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i3, ok := objects.ToInt(args[2])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "third",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := os.OpenFile(s1, i2, os.FileMode(i3))
|
||||||
|
if err != nil {
|
||||||
|
return wrapError(err), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeOSFile(res), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func osArgs(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) != 0 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := &objects.Array{}
|
||||||
|
for _, osArg := range os.Args {
|
||||||
|
if len(osArg) > tengo.MaxStringLen {
|
||||||
|
return nil, objects.ErrStringLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
arr.Value = append(arr.Value, &objects.String{Value: osArg})
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func osFuncASFmRE(name string, fn func(string, os.FileMode) error) *objects.UserFunction {
|
||||||
|
return &objects.UserFunction{
|
||||||
|
Name: name,
|
||||||
|
Value: func(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i2, ok := objects.ToInt64(args[1])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapError(fn(s1, os.FileMode(i2))), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func osLookupEnv(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, ok := os.LookupEnv(s1)
|
||||||
|
if !ok {
|
||||||
|
return objects.FalseValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > tengo.MaxStringLen {
|
||||||
|
return nil, objects.ErrStringLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.String{Value: res}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func osExpandEnv(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlen int
|
||||||
|
var failed bool
|
||||||
|
s := os.Expand(s1, func(k string) string {
|
||||||
|
if failed {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
v := os.Getenv(k)
|
||||||
|
|
||||||
|
// this does not count the other texts that are not being replaced
|
||||||
|
// but the code checks the final length at the end
|
||||||
|
vlen += len(v)
|
||||||
|
if vlen > tengo.MaxStringLen {
|
||||||
|
failed = true
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
})
|
||||||
|
|
||||||
|
if failed || len(s) > tengo.MaxStringLen {
|
||||||
|
return nil, objects.ErrStringLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.String{Value: s}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func osExec(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
name, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var execArgs []string
|
||||||
|
for idx, arg := range args[1:] {
|
||||||
|
execArg, ok := objects.ToString(arg)
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: fmt.Sprintf("args[%d]", idx),
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1+idx].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
execArgs = append(execArgs, execArg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeOSExecCommand(exec.Command(name, execArgs...)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func osFindProcess(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc, err := os.FindProcess(i1)
|
||||||
|
if err != nil {
|
||||||
|
return wrapError(err), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeOSProcess(proc), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func osStartProcess(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) != 4 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
name, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var argv []string
|
||||||
|
var err error
|
||||||
|
switch arg1 := args[1].(type) {
|
||||||
|
case *objects.Array:
|
||||||
|
argv, err = stringArray(arg1.Value, "second")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case *objects.ImmutableArray:
|
||||||
|
argv, err = stringArray(arg1.Value, "second")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "array",
|
||||||
|
Found: arg1.TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, ok := objects.ToString(args[2])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "third",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var env []string
|
||||||
|
switch arg3 := args[3].(type) {
|
||||||
|
case *objects.Array:
|
||||||
|
env, err = stringArray(arg3.Value, "fourth")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case *objects.ImmutableArray:
|
||||||
|
env, err = stringArray(arg3.Value, "fourth")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "fourth",
|
||||||
|
Expected: "array",
|
||||||
|
Found: arg3.TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc, err := os.StartProcess(name, argv, &os.ProcAttr{
|
||||||
|
Dir: dir,
|
||||||
|
Env: env,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return wrapError(err), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeOSProcess(proc), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringArray(arr []objects.Object, argName string) ([]string, error) {
|
||||||
|
var sarr []string
|
||||||
|
for idx, elem := range arr {
|
||||||
|
str, ok := elem.(*objects.String)
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: fmt.Sprintf("%s[%d]", argName, idx),
|
||||||
|
Expected: "string",
|
||||||
|
Found: elem.TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sarr = append(sarr, str.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sarr, nil
|
||||||
|
}
|
113
vendor/github.com/d5/tengo/stdlib/os_exec.go
generated
vendored
Normal file
113
vendor/github.com/d5/tengo/stdlib/os_exec.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeOSExecCommand(cmd *exec.Cmd) *objects.ImmutableMap {
|
||||||
|
return &objects.ImmutableMap{
|
||||||
|
Value: map[string]objects.Object{
|
||||||
|
// combined_output() => bytes/error
|
||||||
|
"combined_output": &objects.UserFunction{Name: "combined_output", Value: FuncARYE(cmd.CombinedOutput)}, //
|
||||||
|
// output() => bytes/error
|
||||||
|
"output": &objects.UserFunction{Name: "output", Value: FuncARYE(cmd.Output)}, //
|
||||||
|
// run() => error
|
||||||
|
"run": &objects.UserFunction{Name: "run", Value: FuncARE(cmd.Run)}, //
|
||||||
|
// start() => error
|
||||||
|
"start": &objects.UserFunction{Name: "start", Value: FuncARE(cmd.Start)}, //
|
||||||
|
// wait() => error
|
||||||
|
"wait": &objects.UserFunction{Name: "wait", Value: FuncARE(cmd.Wait)}, //
|
||||||
|
// set_path(path string)
|
||||||
|
"set_path": &objects.UserFunction{
|
||||||
|
Name: "set_path",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Path = s1
|
||||||
|
|
||||||
|
return objects.UndefinedValue, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// set_dir(dir string)
|
||||||
|
"set_dir": &objects.UserFunction{
|
||||||
|
Name: "set_dir",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Dir = s1
|
||||||
|
|
||||||
|
return objects.UndefinedValue, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// set_env(env array(string))
|
||||||
|
"set_env": &objects.UserFunction{
|
||||||
|
Name: "set_env",
|
||||||
|
Value: func(args ...objects.Object) (objects.Object, error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
var env []string
|
||||||
|
var err error
|
||||||
|
switch arg0 := args[0].(type) {
|
||||||
|
case *objects.Array:
|
||||||
|
env, err = stringArray(arg0.Value, "first")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case *objects.ImmutableArray:
|
||||||
|
env, err = stringArray(arg0.Value, "first")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "array",
|
||||||
|
Found: arg0.TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Env = env
|
||||||
|
|
||||||
|
return objects.UndefinedValue, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// process() => imap(process)
|
||||||
|
"process": &objects.UserFunction{
|
||||||
|
Name: "process",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 0 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeOSProcess(cmd.Process), nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
96
vendor/github.com/d5/tengo/stdlib/os_file.go
generated
vendored
Normal file
96
vendor/github.com/d5/tengo/stdlib/os_file.go
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeOSFile(file *os.File) *objects.ImmutableMap {
|
||||||
|
return &objects.ImmutableMap{
|
||||||
|
Value: map[string]objects.Object{
|
||||||
|
// chdir() => true/error
|
||||||
|
"chdir": &objects.UserFunction{Name: "chdir", Value: FuncARE(file.Chdir)}, //
|
||||||
|
// chown(uid int, gid int) => true/error
|
||||||
|
"chown": &objects.UserFunction{Name: "chown", Value: FuncAIIRE(file.Chown)}, //
|
||||||
|
// close() => error
|
||||||
|
"close": &objects.UserFunction{Name: "close", Value: FuncARE(file.Close)}, //
|
||||||
|
// name() => string
|
||||||
|
"name": &objects.UserFunction{Name: "name", Value: FuncARS(file.Name)}, //
|
||||||
|
// readdirnames(n int) => array(string)/error
|
||||||
|
"readdirnames": &objects.UserFunction{Name: "readdirnames", Value: FuncAIRSsE(file.Readdirnames)}, //
|
||||||
|
// sync() => error
|
||||||
|
"sync": &objects.UserFunction{Name: "sync", Value: FuncARE(file.Sync)}, //
|
||||||
|
// write(bytes) => int/error
|
||||||
|
"write": &objects.UserFunction{Name: "write", Value: FuncAYRIE(file.Write)}, //
|
||||||
|
// write(string) => int/error
|
||||||
|
"write_string": &objects.UserFunction{Name: "write_string", Value: FuncASRIE(file.WriteString)}, //
|
||||||
|
// read(bytes) => int/error
|
||||||
|
"read": &objects.UserFunction{Name: "read", Value: FuncAYRIE(file.Read)}, //
|
||||||
|
// chmod(mode int) => error
|
||||||
|
"chmod": &objects.UserFunction{
|
||||||
|
Name: "chmod",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapError(file.Chmod(os.FileMode(i1))), nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// seek(offset int, whence int) => int/error
|
||||||
|
"seek": &objects.UserFunction{
|
||||||
|
Name: "seek",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i2, ok := objects.ToInt(args[1])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := file.Seek(i1, i2)
|
||||||
|
if err != nil {
|
||||||
|
return wrapError(err), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.Int{Value: res}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// stat() => imap(fileinfo)/error
|
||||||
|
"stat": &objects.UserFunction{
|
||||||
|
Name: "start",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 0 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
return osStat(&objects.String{Value: file.Name()})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
62
vendor/github.com/d5/tengo/stdlib/os_process.go
generated
vendored
Normal file
62
vendor/github.com/d5/tengo/stdlib/os_process.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeOSProcessState(state *os.ProcessState) *objects.ImmutableMap {
|
||||||
|
return &objects.ImmutableMap{
|
||||||
|
Value: map[string]objects.Object{
|
||||||
|
"exited": &objects.UserFunction{Name: "exited", Value: FuncARB(state.Exited)}, //
|
||||||
|
"pid": &objects.UserFunction{Name: "pid", Value: FuncARI(state.Pid)}, //
|
||||||
|
"string": &objects.UserFunction{Name: "string", Value: FuncARS(state.String)}, //
|
||||||
|
"success": &objects.UserFunction{Name: "success", Value: FuncARB(state.Success)}, //
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeOSProcess(proc *os.Process) *objects.ImmutableMap {
|
||||||
|
return &objects.ImmutableMap{
|
||||||
|
Value: map[string]objects.Object{
|
||||||
|
"kill": &objects.UserFunction{Name: "kill", Value: FuncARE(proc.Kill)}, //
|
||||||
|
"release": &objects.UserFunction{Name: "release", Value: FuncARE(proc.Release)}, //
|
||||||
|
"signal": &objects.UserFunction{
|
||||||
|
Name: "signal",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapError(proc.Signal(syscall.Signal(i1))), nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"wait": &objects.UserFunction{
|
||||||
|
Name: "wait",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 0 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err := proc.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return wrapError(err), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeOSProcessState(state), nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
102
vendor/github.com/d5/tengo/stdlib/rand.go
generated
vendored
Normal file
102
vendor/github.com/d5/tengo/stdlib/rand.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
var randModule = map[string]objects.Object{
|
||||||
|
"int": &objects.UserFunction{Name: "int", Value: FuncARI64(rand.Int63)},
|
||||||
|
"float": &objects.UserFunction{Name: "float", Value: FuncARF(rand.Float64)},
|
||||||
|
"intn": &objects.UserFunction{Name: "intn", Value: FuncAI64RI64(rand.Int63n)},
|
||||||
|
"exp_float": &objects.UserFunction{Name: "exp_float", Value: FuncARF(rand.ExpFloat64)},
|
||||||
|
"norm_float": &objects.UserFunction{Name: "norm_float", Value: FuncARF(rand.NormFloat64)},
|
||||||
|
"perm": &objects.UserFunction{Name: "perm", Value: FuncAIRIs(rand.Perm)},
|
||||||
|
"seed": &objects.UserFunction{Name: "seed", Value: FuncAI64R(rand.Seed)},
|
||||||
|
"read": &objects.UserFunction{
|
||||||
|
Name: "read",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
y1, ok := args[0].(*objects.Bytes)
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "bytes",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := rand.Read(y1.Value)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.Int{Value: int64(res)}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"rand": &objects.UserFunction{
|
||||||
|
Name: "rand",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
src := rand.NewSource(i1)
|
||||||
|
|
||||||
|
return randRand(rand.New(src)), nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func randRand(r *rand.Rand) *objects.ImmutableMap {
|
||||||
|
return &objects.ImmutableMap{
|
||||||
|
Value: map[string]objects.Object{
|
||||||
|
"int": &objects.UserFunction{Name: "int", Value: FuncARI64(r.Int63)},
|
||||||
|
"float": &objects.UserFunction{Name: "float", Value: FuncARF(r.Float64)},
|
||||||
|
"intn": &objects.UserFunction{Name: "intn", Value: FuncAI64RI64(r.Int63n)},
|
||||||
|
"exp_float": &objects.UserFunction{Name: "exp_float", Value: FuncARF(r.ExpFloat64)},
|
||||||
|
"norm_float": &objects.UserFunction{Name: "norm_float", Value: FuncARF(r.NormFloat64)},
|
||||||
|
"perm": &objects.UserFunction{Name: "perm", Value: FuncAIRIs(r.Perm)},
|
||||||
|
"seed": &objects.UserFunction{Name: "seed", Value: FuncAI64R(r.Seed)},
|
||||||
|
"read": &objects.UserFunction{
|
||||||
|
Name: "read",
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
y1, ok := args[0].(*objects.Bytes)
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "bytes",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := r.Read(y1.Value)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.Int{Value: int64(res)}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
8
vendor/github.com/d5/tengo/stdlib/source_modules.go
generated
vendored
Normal file
8
vendor/github.com/d5/tengo/stdlib/source_modules.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Code generated using gensrcmods.go; DO NOT EDIT.
|
||||||
|
|
||||||
|
package stdlib
|
||||||
|
|
||||||
|
// SourceModules are source type standard library modules.
|
||||||
|
var SourceModules = map[string]string{
|
||||||
|
"enum": "is_enumerable := func(x) {\n return is_array(x) || is_map(x) || is_immutable_array(x) || is_immutable_map(x)\n}\n\nis_array_like := func(x) {\n return is_array(x) || is_immutable_array(x)\n}\n\nexport {\n // all returns true if the given function `fn` evaluates to a truthy value on\n // all of the items in `x`. It returns undefined if `x` is not enumerable.\n all: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n for k, v in x {\n if !fn(k, v) { return false }\n }\n\n return true\n },\n // any returns true if the given function `fn` evaluates to a truthy value on\n // any of the items in `x`. It returns undefined if `x` is not enumerable.\n any: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n for k, v in x {\n if fn(k, v) { return true }\n }\n\n return false\n },\n // chunk returns an array of elements split into groups the length of size.\n // If `x` can't be split evenly, the final chunk will be the remaining elements.\n // It returns undefined if `x` is not array.\n chunk: func(x, size) {\n if !is_array_like(x) || !size { return undefined }\n\n numElements := len(x)\n if !numElements { return [] }\n\n res := []\n idx := 0\n for idx < numElements {\n res = append(res, x[idx:idx+size])\n idx += size\n }\n\n return res\n },\n // at returns an element at the given index (if `x` is array) or\n // key (if `x` is map). It returns undefined if `x` is not enumerable.\n at: func(x, key) {\n if !is_enumerable(x) { return undefined }\n\n if is_array_like(x) {\n if !is_int(key) { return undefined }\n } else {\n if !is_string(key) { return undefined }\n }\n\n return x[key]\n },\n // each iterates over elements of `x` and invokes `fn` for each element. `fn` is\n // invoked with two arguments: `key` and `value`. `key` is an int index\n // if `x` is array. `key` is a string key if `x` is map. It does not iterate\n // and returns undefined if `x` is not enumerable.\n each: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n for k, v in x {\n fn(k, v)\n }\n },\n // filter iterates over elements of `x`, returning an array of all elements `fn`\n // returns truthy for. `fn` is invoked with two arguments: `key` and `value`.\n // `key` is an int index if `x` is array. `key` is a string key if `x` is map.\n // It returns undefined if `x` is not enumerable.\n filter: func(x, fn) {\n if !is_array_like(x) { return undefined }\n\n dst := []\n for k, v in x {\n if fn(k, v) { dst = append(dst, v) }\n }\n\n return dst\n },\n // find iterates over elements of `x`, returning value of the first element `fn`\n // returns truthy for. `fn` is invoked with two arguments: `key` and `value`.\n // `key` is an int index if `x` is array. `key` is a string key if `x` is map.\n // It returns undefined if `x` is not enumerable.\n find: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n for k, v in x {\n if fn(k, v) { return v }\n }\n },\n // find_key iterates over elements of `x`, returning key or index of the first\n // element `fn` returns truthy for. `fn` is invoked with two arguments: `key`\n // and `value`. `key` is an int index if `x` is array. `key` is a string key if\n // `x` is map. It returns undefined if `x` is not enumerable.\n find_key: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n for k, v in x {\n if fn(k, v) { return k }\n }\n },\n // map creates an array of values by running each element in `x` through `fn`.\n // `fn` is invoked with two arguments: `key` and `value`. `key` is an int index\n // if `x` is array. `key` is a string key if `x` is map. It returns undefined\n // if `x` is not enumerable.\n map: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n dst := []\n for k, v in x {\n dst = append(dst, fn(k, v))\n }\n\n return dst\n },\n // key returns the first argument.\n key: func(k, _) { return k },\n // value returns the second argument.\n value: func(_, v) { return v }\n}\n",
|
||||||
|
}
|
128
vendor/github.com/d5/tengo/stdlib/srcmod_enum.tengo
generated
vendored
Normal file
128
vendor/github.com/d5/tengo/stdlib/srcmod_enum.tengo
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
is_enumerable := func(x) {
|
||||||
|
return is_array(x) || is_map(x) || is_immutable_array(x) || is_immutable_map(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_array_like := func(x) {
|
||||||
|
return is_array(x) || is_immutable_array(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
// all returns true if the given function `fn` evaluates to a truthy value on
|
||||||
|
// all of the items in `x`. It returns undefined if `x` is not enumerable.
|
||||||
|
all: func(x, fn) {
|
||||||
|
if !is_enumerable(x) { return undefined }
|
||||||
|
|
||||||
|
for k, v in x {
|
||||||
|
if !fn(k, v) { return false }
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
// any returns true if the given function `fn` evaluates to a truthy value on
|
||||||
|
// any of the items in `x`. It returns undefined if `x` is not enumerable.
|
||||||
|
any: func(x, fn) {
|
||||||
|
if !is_enumerable(x) { return undefined }
|
||||||
|
|
||||||
|
for k, v in x {
|
||||||
|
if fn(k, v) { return true }
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
// chunk returns an array of elements split into groups the length of size.
|
||||||
|
// If `x` can't be split evenly, the final chunk will be the remaining elements.
|
||||||
|
// It returns undefined if `x` is not array.
|
||||||
|
chunk: func(x, size) {
|
||||||
|
if !is_array_like(x) || !size { return undefined }
|
||||||
|
|
||||||
|
numElements := len(x)
|
||||||
|
if !numElements { return [] }
|
||||||
|
|
||||||
|
res := []
|
||||||
|
idx := 0
|
||||||
|
for idx < numElements {
|
||||||
|
res = append(res, x[idx:idx+size])
|
||||||
|
idx += size
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
// at returns an element at the given index (if `x` is array) or
|
||||||
|
// key (if `x` is map). It returns undefined if `x` is not enumerable.
|
||||||
|
at: func(x, key) {
|
||||||
|
if !is_enumerable(x) { return undefined }
|
||||||
|
|
||||||
|
if is_array_like(x) {
|
||||||
|
if !is_int(key) { return undefined }
|
||||||
|
} else {
|
||||||
|
if !is_string(key) { return undefined }
|
||||||
|
}
|
||||||
|
|
||||||
|
return x[key]
|
||||||
|
},
|
||||||
|
// each iterates over elements of `x` and invokes `fn` for each element. `fn` is
|
||||||
|
// invoked with two arguments: `key` and `value`. `key` is an int index
|
||||||
|
// if `x` is array. `key` is a string key if `x` is map. It does not iterate
|
||||||
|
// and returns undefined if `x` is not enumerable.
|
||||||
|
each: func(x, fn) {
|
||||||
|
if !is_enumerable(x) { return undefined }
|
||||||
|
|
||||||
|
for k, v in x {
|
||||||
|
fn(k, v)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// filter iterates over elements of `x`, returning an array of all elements `fn`
|
||||||
|
// returns truthy for. `fn` is invoked with two arguments: `key` and `value`.
|
||||||
|
// `key` is an int index if `x` is array. `key` is a string key if `x` is map.
|
||||||
|
// It returns undefined if `x` is not enumerable.
|
||||||
|
filter: func(x, fn) {
|
||||||
|
if !is_array_like(x) { return undefined }
|
||||||
|
|
||||||
|
dst := []
|
||||||
|
for k, v in x {
|
||||||
|
if fn(k, v) { dst = append(dst, v) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
|
},
|
||||||
|
// find iterates over elements of `x`, returning value of the first element `fn`
|
||||||
|
// returns truthy for. `fn` is invoked with two arguments: `key` and `value`.
|
||||||
|
// `key` is an int index if `x` is array. `key` is a string key if `x` is map.
|
||||||
|
// It returns undefined if `x` is not enumerable.
|
||||||
|
find: func(x, fn) {
|
||||||
|
if !is_enumerable(x) { return undefined }
|
||||||
|
|
||||||
|
for k, v in x {
|
||||||
|
if fn(k, v) { return v }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// find_key iterates over elements of `x`, returning key or index of the first
|
||||||
|
// element `fn` returns truthy for. `fn` is invoked with two arguments: `key`
|
||||||
|
// and `value`. `key` is an int index if `x` is array. `key` is a string key if
|
||||||
|
// `x` is map. It returns undefined if `x` is not enumerable.
|
||||||
|
find_key: func(x, fn) {
|
||||||
|
if !is_enumerable(x) { return undefined }
|
||||||
|
|
||||||
|
for k, v in x {
|
||||||
|
if fn(k, v) { return k }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// map creates an array of values by running each element in `x` through `fn`.
|
||||||
|
// `fn` is invoked with two arguments: `key` and `value`. `key` is an int index
|
||||||
|
// if `x` is array. `key` is a string key if `x` is map. It returns undefined
|
||||||
|
// if `x` is not enumerable.
|
||||||
|
map: func(x, fn) {
|
||||||
|
if !is_enumerable(x) { return undefined }
|
||||||
|
|
||||||
|
dst := []
|
||||||
|
for k, v in x {
|
||||||
|
dst = append(dst, fn(k, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
|
},
|
||||||
|
// key returns the first argument.
|
||||||
|
key: func(k, _) { return k },
|
||||||
|
// value returns the second argument.
|
||||||
|
value: func(_, v) { return v }
|
||||||
|
}
|
34
vendor/github.com/d5/tengo/stdlib/stdlib.go
generated
vendored
Normal file
34
vendor/github.com/d5/tengo/stdlib/stdlib.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
//go:generate go run gensrcmods.go
|
||||||
|
|
||||||
|
import "github.com/d5/tengo/objects"
|
||||||
|
|
||||||
|
// AllModuleNames returns a list of all default module names.
|
||||||
|
func AllModuleNames() []string {
|
||||||
|
var names []string
|
||||||
|
for name := range BuiltinModules {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
for name := range SourceModules {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetModuleMap returns the module map that includes all modules
|
||||||
|
// for the given module names.
|
||||||
|
func GetModuleMap(names ...string) *objects.ModuleMap {
|
||||||
|
modules := objects.NewModuleMap()
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
if mod := BuiltinModules[name]; mod != nil {
|
||||||
|
modules.AddBuiltinModule(name, mod)
|
||||||
|
}
|
||||||
|
if mod := SourceModules[name]; mod != "" {
|
||||||
|
modules.AddSourceModule(name, []byte(mod))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return modules
|
||||||
|
}
|
737
vendor/github.com/d5/tengo/stdlib/text.go
generated
vendored
Normal file
737
vendor/github.com/d5/tengo/stdlib/text.go
generated
vendored
Normal file
@ -0,0 +1,737 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
var textModule = map[string]objects.Object{
|
||||||
|
"re_match": &objects.UserFunction{Name: "re_match", Value: textREMatch}, // re_match(pattern, text) => bool/error
|
||||||
|
"re_find": &objects.UserFunction{Name: "re_find", Value: textREFind}, // re_find(pattern, text, count) => [[{text:,begin:,end:}]]/undefined
|
||||||
|
"re_replace": &objects.UserFunction{Name: "re_replace", Value: textREReplace}, // re_replace(pattern, text, repl) => string/error
|
||||||
|
"re_split": &objects.UserFunction{Name: "re_split", Value: textRESplit}, // re_split(pattern, text, count) => [string]/error
|
||||||
|
"re_compile": &objects.UserFunction{Name: "re_compile", Value: textRECompile}, // re_compile(pattern) => Regexp/error
|
||||||
|
"compare": &objects.UserFunction{Name: "compare", Value: FuncASSRI(strings.Compare)}, // compare(a, b) => int
|
||||||
|
"contains": &objects.UserFunction{Name: "contains", Value: FuncASSRB(strings.Contains)}, // contains(s, substr) => bool
|
||||||
|
"contains_any": &objects.UserFunction{Name: "contains_any", Value: FuncASSRB(strings.ContainsAny)}, // contains_any(s, chars) => bool
|
||||||
|
"count": &objects.UserFunction{Name: "count", Value: FuncASSRI(strings.Count)}, // count(s, substr) => int
|
||||||
|
"equal_fold": &objects.UserFunction{Name: "equal_fold", Value: FuncASSRB(strings.EqualFold)}, // "equal_fold(s, t) => bool
|
||||||
|
"fields": &objects.UserFunction{Name: "fields", Value: FuncASRSs(strings.Fields)}, // fields(s) => [string]
|
||||||
|
"has_prefix": &objects.UserFunction{Name: "has_prefix", Value: FuncASSRB(strings.HasPrefix)}, // has_prefix(s, prefix) => bool
|
||||||
|
"has_suffix": &objects.UserFunction{Name: "has_suffix", Value: FuncASSRB(strings.HasSuffix)}, // has_suffix(s, suffix) => bool
|
||||||
|
"index": &objects.UserFunction{Name: "index", Value: FuncASSRI(strings.Index)}, // index(s, substr) => int
|
||||||
|
"index_any": &objects.UserFunction{Name: "index_any", Value: FuncASSRI(strings.IndexAny)}, // index_any(s, chars) => int
|
||||||
|
"join": &objects.UserFunction{Name: "join", Value: textJoin}, // join(arr, sep) => string
|
||||||
|
"last_index": &objects.UserFunction{Name: "last_index", Value: FuncASSRI(strings.LastIndex)}, // last_index(s, substr) => int
|
||||||
|
"last_index_any": &objects.UserFunction{Name: "last_index_any", Value: FuncASSRI(strings.LastIndexAny)}, // last_index_any(s, chars) => int
|
||||||
|
"repeat": &objects.UserFunction{Name: "repeat", Value: textRepeat}, // repeat(s, count) => string
|
||||||
|
"replace": &objects.UserFunction{Name: "replace", Value: textReplace}, // replace(s, old, new, n) => string
|
||||||
|
"split": &objects.UserFunction{Name: "split", Value: FuncASSRSs(strings.Split)}, // split(s, sep) => [string]
|
||||||
|
"split_after": &objects.UserFunction{Name: "split_after", Value: FuncASSRSs(strings.SplitAfter)}, // split_after(s, sep) => [string]
|
||||||
|
"split_after_n": &objects.UserFunction{Name: "split_after_n", Value: FuncASSIRSs(strings.SplitAfterN)}, // split_after_n(s, sep, n) => [string]
|
||||||
|
"split_n": &objects.UserFunction{Name: "split_n", Value: FuncASSIRSs(strings.SplitN)}, // split_n(s, sep, n) => [string]
|
||||||
|
"title": &objects.UserFunction{Name: "title", Value: FuncASRS(strings.Title)}, // title(s) => string
|
||||||
|
"to_lower": &objects.UserFunction{Name: "to_lower", Value: FuncASRS(strings.ToLower)}, // to_lower(s) => string
|
||||||
|
"to_title": &objects.UserFunction{Name: "to_title", Value: FuncASRS(strings.ToTitle)}, // to_title(s) => string
|
||||||
|
"to_upper": &objects.UserFunction{Name: "to_upper", Value: FuncASRS(strings.ToUpper)}, // to_upper(s) => string
|
||||||
|
"trim_left": &objects.UserFunction{Name: "trim_left", Value: FuncASSRS(strings.TrimLeft)}, // trim_left(s, cutset) => string
|
||||||
|
"trim_prefix": &objects.UserFunction{Name: "trim_prefix", Value: FuncASSRS(strings.TrimPrefix)}, // trim_prefix(s, prefix) => string
|
||||||
|
"trim_right": &objects.UserFunction{Name: "trim_right", Value: FuncASSRS(strings.TrimRight)}, // trim_right(s, cutset) => string
|
||||||
|
"trim_space": &objects.UserFunction{Name: "trim_space", Value: FuncASRS(strings.TrimSpace)}, // trim_space(s) => string
|
||||||
|
"trim_suffix": &objects.UserFunction{Name: "trim_suffix", Value: FuncASSRS(strings.TrimSuffix)}, // trim_suffix(s, suffix) => string
|
||||||
|
"atoi": &objects.UserFunction{Name: "atoi", Value: FuncASRIE(strconv.Atoi)}, // atoi(str) => int/error
|
||||||
|
"format_bool": &objects.UserFunction{Name: "format_bool", Value: textFormatBool}, // format_bool(b) => string
|
||||||
|
"format_float": &objects.UserFunction{Name: "format_float", Value: textFormatFloat}, // format_float(f, fmt, prec, bits) => string
|
||||||
|
"format_int": &objects.UserFunction{Name: "format_int", Value: textFormatInt}, // format_int(i, base) => string
|
||||||
|
"itoa": &objects.UserFunction{Name: "itoa", Value: FuncAIRS(strconv.Itoa)}, // itoa(i) => string
|
||||||
|
"parse_bool": &objects.UserFunction{Name: "parse_bool", Value: textParseBool}, // parse_bool(str) => bool/error
|
||||||
|
"parse_float": &objects.UserFunction{Name: "parse_float", Value: textParseFloat}, // parse_float(str, bits) => float/error
|
||||||
|
"parse_int": &objects.UserFunction{Name: "parse_int", Value: textParseInt}, // parse_int(str, base, bits) => int/error
|
||||||
|
"quote": &objects.UserFunction{Name: "quote", Value: FuncASRS(strconv.Quote)}, // quote(str) => string
|
||||||
|
"unquote": &objects.UserFunction{Name: "unquote", Value: FuncASRSE(strconv.Unquote)}, // unquote(str) => string/error
|
||||||
|
}
|
||||||
|
|
||||||
|
func textREMatch(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
matched, err := regexp.MatchString(s1, s2)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if matched {
|
||||||
|
ret = objects.TrueValue
|
||||||
|
} else {
|
||||||
|
ret = objects.FalseValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textREFind(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
numArgs := len(args)
|
||||||
|
if numArgs != 2 && numArgs != 3 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
re, err := regexp.Compile(s1)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if numArgs < 3 {
|
||||||
|
m := re.FindStringSubmatchIndex(s2)
|
||||||
|
if m == nil {
|
||||||
|
ret = objects.UndefinedValue
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := &objects.Array{}
|
||||||
|
for i := 0; i < len(m); i += 2 {
|
||||||
|
arr.Value = append(arr.Value, &objects.ImmutableMap{Value: map[string]objects.Object{
|
||||||
|
"text": &objects.String{Value: s2[m[i]:m[i+1]]},
|
||||||
|
"begin": &objects.Int{Value: int64(m[i])},
|
||||||
|
"end": &objects.Int{Value: int64(m[i+1])},
|
||||||
|
}})
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Array{Value: []objects.Object{arr}}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i3, ok := objects.ToInt(args[2])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "third",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m := re.FindAllStringSubmatchIndex(s2, i3)
|
||||||
|
if m == nil {
|
||||||
|
ret = objects.UndefinedValue
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := &objects.Array{}
|
||||||
|
for _, m := range m {
|
||||||
|
subMatch := &objects.Array{}
|
||||||
|
for i := 0; i < len(m); i += 2 {
|
||||||
|
subMatch.Value = append(subMatch.Value, &objects.ImmutableMap{Value: map[string]objects.Object{
|
||||||
|
"text": &objects.String{Value: s2[m[i]:m[i+1]]},
|
||||||
|
"begin": &objects.Int{Value: int64(m[i])},
|
||||||
|
"end": &objects.Int{Value: int64(m[i+1])},
|
||||||
|
}})
|
||||||
|
}
|
||||||
|
|
||||||
|
arr.Value = append(arr.Value, subMatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = arr
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textREReplace(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 3 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s3, ok := objects.ToString(args[2])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "third",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
re, err := regexp.Compile(s1)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
} else {
|
||||||
|
s, ok := doTextRegexpReplace(re, s2, s3)
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrStringLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.String{Value: s}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textRESplit(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
numArgs := len(args)
|
||||||
|
if numArgs != 2 && numArgs != 3 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var i3 = -1
|
||||||
|
if numArgs > 2 {
|
||||||
|
i3, ok = objects.ToInt(args[2])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "third",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
re, err := regexp.Compile(s1)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := &objects.Array{}
|
||||||
|
for _, s := range re.Split(s2, i3) {
|
||||||
|
arr.Value = append(arr.Value, &objects.String{Value: s})
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = arr
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textRECompile(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
re, err := regexp.Compile(s1)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
} else {
|
||||||
|
ret = makeTextRegexp(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textReplace(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 4 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s3, ok := objects.ToString(args[2])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "third",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i4, ok := objects.ToInt(args[3])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "fourth",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[3].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s, ok := doTextReplace(s1, s2, s3, i4)
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrStringLimit
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.String{Value: s}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textRepeat(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i2, ok := objects.ToInt(args[1])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s1)*i2 > tengo.MaxStringLen {
|
||||||
|
return nil, objects.ErrStringLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.String{Value: strings.Repeat(s1, i2)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func textJoin(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
return nil, objects.ErrWrongNumArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
var slen int
|
||||||
|
var ss1 []string
|
||||||
|
switch arg0 := args[0].(type) {
|
||||||
|
case *objects.Array:
|
||||||
|
for idx, a := range arg0.Value {
|
||||||
|
as, ok := objects.ToString(a)
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: fmt.Sprintf("first[%d]", idx),
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: a.TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slen += len(as)
|
||||||
|
ss1 = append(ss1, as)
|
||||||
|
}
|
||||||
|
case *objects.ImmutableArray:
|
||||||
|
for idx, a := range arg0.Value {
|
||||||
|
as, ok := objects.ToString(a)
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: fmt.Sprintf("first[%d]", idx),
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: a.TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slen += len(as)
|
||||||
|
ss1 = append(ss1, as)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "array",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure output length does not exceed the limit
|
||||||
|
if slen+len(s2)*(len(ss1)-1) > tengo.MaxStringLen {
|
||||||
|
return nil, objects.ErrStringLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
return &objects.String{Value: strings.Join(ss1, s2)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func textFormatBool(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b1, ok := args[0].(*objects.Bool)
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "bool",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if b1 == objects.TrueValue {
|
||||||
|
ret = &objects.String{Value: "true"}
|
||||||
|
} else {
|
||||||
|
ret = &objects.String{Value: "false"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textFormatFloat(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 4 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f1, ok := args[0].(*objects.Float)
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "float",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i3, ok := objects.ToInt(args[2])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "third",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i4, ok := objects.ToInt(args[3])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "fourth",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[3].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.String{Value: strconv.FormatFloat(f1.Value, s2[0], i3, i4)}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textFormatInt(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := args[0].(*objects.Int)
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i2, ok := objects.ToInt(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.String{Value: strconv.FormatInt(i1.Value, i2)}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textParseBool(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := args[0].(*objects.String)
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := strconv.ParseBool(s1.Value)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if parsed {
|
||||||
|
ret = objects.TrueValue
|
||||||
|
} else {
|
||||||
|
ret = objects.FalseValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textParseFloat(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := args[0].(*objects.String)
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i2, ok := objects.ToInt(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := strconv.ParseFloat(s1.Value, i2)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Float{Value: parsed}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func textParseInt(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 3 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := args[0].(*objects.String)
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i2, ok := objects.ToInt(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i3, ok := objects.ToInt(args[2])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "third",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := strconv.ParseInt(s1.Value, i2, i3)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: parsed}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modified implementation of strings.Replace
|
||||||
|
// to limit the maximum length of output string.
|
||||||
|
func doTextReplace(s, old, new string, n int) (string, bool) {
|
||||||
|
if old == new || n == 0 {
|
||||||
|
return s, true // avoid allocation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute number of replacements.
|
||||||
|
if m := strings.Count(s, old); m == 0 {
|
||||||
|
return s, true // avoid allocation
|
||||||
|
} else if n < 0 || m < n {
|
||||||
|
n = m
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply replacements to buffer.
|
||||||
|
t := make([]byte, len(s)+n*(len(new)-len(old)))
|
||||||
|
w := 0
|
||||||
|
start := 0
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
j := start
|
||||||
|
if len(old) == 0 {
|
||||||
|
if i > 0 {
|
||||||
|
_, wid := utf8.DecodeRuneInString(s[start:])
|
||||||
|
j += wid
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
j += strings.Index(s[start:], old)
|
||||||
|
}
|
||||||
|
|
||||||
|
ssj := s[start:j]
|
||||||
|
if w+len(ssj)+len(new) > tengo.MaxStringLen {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
w += copy(t[w:], ssj)
|
||||||
|
w += copy(t[w:], new)
|
||||||
|
start = j + len(old)
|
||||||
|
}
|
||||||
|
|
||||||
|
ss := s[start:]
|
||||||
|
if w+len(ss) > tengo.MaxStringLen {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
w += copy(t[w:], ss)
|
||||||
|
|
||||||
|
return string(t[0:w]), true
|
||||||
|
}
|
228
vendor/github.com/d5/tengo/stdlib/text_regexp.go
generated
vendored
Normal file
228
vendor/github.com/d5/tengo/stdlib/text_regexp.go
generated
vendored
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeTextRegexp(re *regexp.Regexp) *objects.ImmutableMap {
|
||||||
|
return &objects.ImmutableMap{
|
||||||
|
Value: map[string]objects.Object{
|
||||||
|
// match(text) => bool
|
||||||
|
"match": &objects.UserFunction{
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if re.MatchString(s1) {
|
||||||
|
ret = objects.TrueValue
|
||||||
|
} else {
|
||||||
|
ret = objects.FalseValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// find(text) => array(array({text:,begin:,end:}))/undefined
|
||||||
|
// find(text, maxCount) => array(array({text:,begin:,end:}))/undefined
|
||||||
|
"find": &objects.UserFunction{
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
numArgs := len(args)
|
||||||
|
if numArgs != 1 && numArgs != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if numArgs == 1 {
|
||||||
|
m := re.FindStringSubmatchIndex(s1)
|
||||||
|
if m == nil {
|
||||||
|
ret = objects.UndefinedValue
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := &objects.Array{}
|
||||||
|
for i := 0; i < len(m); i += 2 {
|
||||||
|
arr.Value = append(arr.Value, &objects.ImmutableMap{Value: map[string]objects.Object{
|
||||||
|
"text": &objects.String{Value: s1[m[i]:m[i+1]]},
|
||||||
|
"begin": &objects.Int{Value: int64(m[i])},
|
||||||
|
"end": &objects.Int{Value: int64(m[i+1])},
|
||||||
|
}})
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Array{Value: []objects.Object{arr}}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i2, ok := objects.ToInt(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m := re.FindAllStringSubmatchIndex(s1, i2)
|
||||||
|
if m == nil {
|
||||||
|
ret = objects.UndefinedValue
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := &objects.Array{}
|
||||||
|
for _, m := range m {
|
||||||
|
subMatch := &objects.Array{}
|
||||||
|
for i := 0; i < len(m); i += 2 {
|
||||||
|
subMatch.Value = append(subMatch.Value, &objects.ImmutableMap{Value: map[string]objects.Object{
|
||||||
|
"text": &objects.String{Value: s1[m[i]:m[i+1]]},
|
||||||
|
"begin": &objects.Int{Value: int64(m[i])},
|
||||||
|
"end": &objects.Int{Value: int64(m[i+1])},
|
||||||
|
}})
|
||||||
|
}
|
||||||
|
|
||||||
|
arr.Value = append(arr.Value, subMatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = arr
|
||||||
|
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// replace(src, repl) => string
|
||||||
|
"replace": &objects.UserFunction{
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s, ok := doTextRegexpReplace(re, s1, s2)
|
||||||
|
if !ok {
|
||||||
|
return nil, objects.ErrStringLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.String{Value: s}
|
||||||
|
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// split(text) => array(string)
|
||||||
|
// split(text, maxCount) => array(string)
|
||||||
|
"split": &objects.UserFunction{
|
||||||
|
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
numArgs := len(args)
|
||||||
|
if numArgs != 1 && numArgs != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var i2 = -1
|
||||||
|
if numArgs > 1 {
|
||||||
|
i2, ok = objects.ToInt(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arr := &objects.Array{}
|
||||||
|
for _, s := range re.Split(s1, i2) {
|
||||||
|
arr.Value = append(arr.Value, &objects.String{Value: s})
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = arr
|
||||||
|
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size-limit checking implementation of regexp.ReplaceAllString.
|
||||||
|
func doTextRegexpReplace(re *regexp.Regexp, src, repl string) (string, bool) {
|
||||||
|
idx := 0
|
||||||
|
out := ""
|
||||||
|
|
||||||
|
for _, m := range re.FindAllStringSubmatchIndex(src, -1) {
|
||||||
|
var exp []byte
|
||||||
|
exp = re.ExpandString(exp, repl, src, m)
|
||||||
|
|
||||||
|
if len(out)+m[0]-idx+len(exp) > tengo.MaxStringLen {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
out += src[idx:m[0]] + string(exp)
|
||||||
|
idx = m[1]
|
||||||
|
}
|
||||||
|
if idx < len(src) {
|
||||||
|
if len(out)+len(src)-idx > tengo.MaxStringLen {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
out += src[idx:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(out), true
|
||||||
|
}
|
989
vendor/github.com/d5/tengo/stdlib/times.go
generated
vendored
Normal file
989
vendor/github.com/d5/tengo/stdlib/times.go
generated
vendored
Normal file
@ -0,0 +1,989 @@
|
|||||||
|
package stdlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
|
"github.com/d5/tengo/objects"
|
||||||
|
)
|
||||||
|
|
||||||
|
var timesModule = map[string]objects.Object{
|
||||||
|
"format_ansic": &objects.String{Value: time.ANSIC},
|
||||||
|
"format_unix_date": &objects.String{Value: time.UnixDate},
|
||||||
|
"format_ruby_date": &objects.String{Value: time.RubyDate},
|
||||||
|
"format_rfc822": &objects.String{Value: time.RFC822},
|
||||||
|
"format_rfc822z": &objects.String{Value: time.RFC822Z},
|
||||||
|
"format_rfc850": &objects.String{Value: time.RFC850},
|
||||||
|
"format_rfc1123": &objects.String{Value: time.RFC1123},
|
||||||
|
"format_rfc1123z": &objects.String{Value: time.RFC1123Z},
|
||||||
|
"format_rfc3339": &objects.String{Value: time.RFC3339},
|
||||||
|
"format_rfc3339_nano": &objects.String{Value: time.RFC3339Nano},
|
||||||
|
"format_kitchen": &objects.String{Value: time.Kitchen},
|
||||||
|
"format_stamp": &objects.String{Value: time.Stamp},
|
||||||
|
"format_stamp_milli": &objects.String{Value: time.StampMilli},
|
||||||
|
"format_stamp_micro": &objects.String{Value: time.StampMicro},
|
||||||
|
"format_stamp_nano": &objects.String{Value: time.StampNano},
|
||||||
|
"nanosecond": &objects.Int{Value: int64(time.Nanosecond)},
|
||||||
|
"microsecond": &objects.Int{Value: int64(time.Microsecond)},
|
||||||
|
"millisecond": &objects.Int{Value: int64(time.Millisecond)},
|
||||||
|
"second": &objects.Int{Value: int64(time.Second)},
|
||||||
|
"minute": &objects.Int{Value: int64(time.Minute)},
|
||||||
|
"hour": &objects.Int{Value: int64(time.Hour)},
|
||||||
|
"january": &objects.Int{Value: int64(time.January)},
|
||||||
|
"february": &objects.Int{Value: int64(time.February)},
|
||||||
|
"march": &objects.Int{Value: int64(time.March)},
|
||||||
|
"april": &objects.Int{Value: int64(time.April)},
|
||||||
|
"may": &objects.Int{Value: int64(time.May)},
|
||||||
|
"june": &objects.Int{Value: int64(time.June)},
|
||||||
|
"july": &objects.Int{Value: int64(time.July)},
|
||||||
|
"august": &objects.Int{Value: int64(time.August)},
|
||||||
|
"september": &objects.Int{Value: int64(time.September)},
|
||||||
|
"october": &objects.Int{Value: int64(time.October)},
|
||||||
|
"november": &objects.Int{Value: int64(time.November)},
|
||||||
|
"december": &objects.Int{Value: int64(time.December)},
|
||||||
|
"sleep": &objects.UserFunction{Name: "sleep", Value: timesSleep}, // sleep(int)
|
||||||
|
"parse_duration": &objects.UserFunction{Name: "parse_duration", Value: timesParseDuration}, // parse_duration(str) => int
|
||||||
|
"since": &objects.UserFunction{Name: "since", Value: timesSince}, // since(time) => int
|
||||||
|
"until": &objects.UserFunction{Name: "until", Value: timesUntil}, // until(time) => int
|
||||||
|
"duration_hours": &objects.UserFunction{Name: "duration_hours", Value: timesDurationHours}, // duration_hours(int) => float
|
||||||
|
"duration_minutes": &objects.UserFunction{Name: "duration_minutes", Value: timesDurationMinutes}, // duration_minutes(int) => float
|
||||||
|
"duration_nanoseconds": &objects.UserFunction{Name: "duration_nanoseconds", Value: timesDurationNanoseconds}, // duration_nanoseconds(int) => int
|
||||||
|
"duration_seconds": &objects.UserFunction{Name: "duration_seconds", Value: timesDurationSeconds}, // duration_seconds(int) => float
|
||||||
|
"duration_string": &objects.UserFunction{Name: "duration_string", Value: timesDurationString}, // duration_string(int) => string
|
||||||
|
"month_string": &objects.UserFunction{Name: "month_string", Value: timesMonthString}, // month_string(int) => string
|
||||||
|
"date": &objects.UserFunction{Name: "date", Value: timesDate}, // date(year, month, day, hour, min, sec, nsec) => time
|
||||||
|
"now": &objects.UserFunction{Name: "now", Value: timesNow}, // now() => time
|
||||||
|
"parse": &objects.UserFunction{Name: "parse", Value: timesParse}, // parse(format, str) => time
|
||||||
|
"unix": &objects.UserFunction{Name: "unix", Value: timesUnix}, // unix(sec, nsec) => time
|
||||||
|
"add": &objects.UserFunction{Name: "add", Value: timesAdd}, // add(time, int) => time
|
||||||
|
"add_date": &objects.UserFunction{Name: "add_date", Value: timesAddDate}, // add_date(time, years, months, days) => time
|
||||||
|
"sub": &objects.UserFunction{Name: "sub", Value: timesSub}, // sub(t time, u time) => int
|
||||||
|
"after": &objects.UserFunction{Name: "after", Value: timesAfter}, // after(t time, u time) => bool
|
||||||
|
"before": &objects.UserFunction{Name: "before", Value: timesBefore}, // before(t time, u time) => bool
|
||||||
|
"time_year": &objects.UserFunction{Name: "time_year", Value: timesTimeYear}, // time_year(time) => int
|
||||||
|
"time_month": &objects.UserFunction{Name: "time_month", Value: timesTimeMonth}, // time_month(time) => int
|
||||||
|
"time_day": &objects.UserFunction{Name: "time_day", Value: timesTimeDay}, // time_day(time) => int
|
||||||
|
"time_weekday": &objects.UserFunction{Name: "time_weekday", Value: timesTimeWeekday}, // time_weekday(time) => int
|
||||||
|
"time_hour": &objects.UserFunction{Name: "time_hour", Value: timesTimeHour}, // time_hour(time) => int
|
||||||
|
"time_minute": &objects.UserFunction{Name: "time_minute", Value: timesTimeMinute}, // time_minute(time) => int
|
||||||
|
"time_second": &objects.UserFunction{Name: "time_second", Value: timesTimeSecond}, // time_second(time) => int
|
||||||
|
"time_nanosecond": &objects.UserFunction{Name: "time_nanosecond", Value: timesTimeNanosecond}, // time_nanosecond(time) => int
|
||||||
|
"time_unix": &objects.UserFunction{Name: "time_unix", Value: timesTimeUnix}, // time_unix(time) => int
|
||||||
|
"time_unix_nano": &objects.UserFunction{Name: "time_unix_nano", Value: timesTimeUnixNano}, // time_unix_nano(time) => int
|
||||||
|
"time_format": &objects.UserFunction{Name: "time_format", Value: timesTimeFormat}, // time_format(time, format) => string
|
||||||
|
"time_location": &objects.UserFunction{Name: "time_location", Value: timesTimeLocation}, // time_location(time) => string
|
||||||
|
"time_string": &objects.UserFunction{Name: "time_string", Value: timesTimeString}, // time_string(time) => string
|
||||||
|
"is_zero": &objects.UserFunction{Name: "is_zero", Value: timesIsZero}, // is_zero(time) => bool
|
||||||
|
"to_local": &objects.UserFunction{Name: "to_local", Value: timesToLocal}, // to_local(time) => time
|
||||||
|
"to_utc": &objects.UserFunction{Name: "to_utc", Value: timesToUTC}, // to_utc(time) => time
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesSleep(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Duration(i1))
|
||||||
|
ret = objects.UndefinedValue
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesParseDuration(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dur, err := time.ParseDuration(s1)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(dur)}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesSince(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(time.Since(t1))}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesUntil(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(time.Until(t1))}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesDurationHours(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Float{Value: time.Duration(i1).Hours()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesDurationMinutes(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Float{Value: time.Duration(i1).Minutes()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesDurationNanoseconds(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: time.Duration(i1).Nanoseconds()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesDurationSeconds(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Float{Value: time.Duration(i1).Seconds()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesDurationString(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.String{Value: time.Duration(i1).String()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesMonthString(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.String{Value: time.Month(i1).String()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesDate(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 7 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i2, ok := objects.ToInt(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i3, ok := objects.ToInt(args[2])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "third",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i4, ok := objects.ToInt(args[3])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "fourth",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[3].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i5, ok := objects.ToInt(args[4])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "fifth",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[4].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i6, ok := objects.ToInt(args[5])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "sixth",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[5].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i7, ok := objects.ToInt(args[6])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "seventh",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[6].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Time{Value: time.Date(i1, time.Month(i2), i3, i4, i5, i6, i7, time.Now().Location())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesNow(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 0 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Time{Value: time.Now()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesParse(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, ok := objects.ToString(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := time.Parse(s1, s2)
|
||||||
|
if err != nil {
|
||||||
|
ret = wrapError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Time{Value: parsed}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesUnix(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i1, ok := objects.ToInt64(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i2, ok := objects.ToInt64(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Time{Value: time.Unix(i1, i2)}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesAdd(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i2, ok := objects.ToInt64(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Time{Value: t1.Add(time.Duration(i2))}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesSub(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t2, ok := objects.ToTime(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.Sub(t2))}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesAddDate(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 4 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i2, ok := objects.ToInt(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i3, ok := objects.ToInt(args[2])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "third",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[2].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
i4, ok := objects.ToInt(args[3])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "fourth",
|
||||||
|
Expected: "int(compatible)",
|
||||||
|
Found: args[3].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Time{Value: t1.AddDate(i2, i3, i4)}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesAfter(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t2, ok := objects.ToTime(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if t1.After(t2) {
|
||||||
|
ret = objects.TrueValue
|
||||||
|
} else {
|
||||||
|
ret = objects.FalseValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesBefore(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t2, ok := objects.ToTime(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if t1.Before(t2) {
|
||||||
|
ret = objects.TrueValue
|
||||||
|
} else {
|
||||||
|
ret = objects.FalseValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeYear(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.Year())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeMonth(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.Month())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeDay(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.Day())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeWeekday(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.Weekday())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeHour(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.Hour())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeMinute(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.Minute())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeSecond(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.Second())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeNanosecond(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.Nanosecond())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeUnix(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.Unix())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeUnixNano(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Int{Value: int64(t1.UnixNano())}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeFormat(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s2, ok := objects.ToString(args[1])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "second",
|
||||||
|
Expected: "string(compatible)",
|
||||||
|
Found: args[1].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s := t1.Format(s2)
|
||||||
|
if len(s) > tengo.MaxStringLen {
|
||||||
|
|
||||||
|
return nil, objects.ErrStringLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.String{Value: s}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesIsZero(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if t1.IsZero() {
|
||||||
|
ret = objects.TrueValue
|
||||||
|
} else {
|
||||||
|
ret = objects.FalseValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesToLocal(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Time{Value: t1.Local()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesToUTC(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.Time{Value: t1.UTC()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeLocation(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.String{Value: t1.Location().String()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func timesTimeString(args ...objects.Object) (ret objects.Object, err error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
err = objects.ErrWrongNumArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, ok := objects.ToTime(args[0])
|
||||||
|
if !ok {
|
||||||
|
err = objects.ErrInvalidArgumentType{
|
||||||
|
Name: "first",
|
||||||
|
Expected: "time(compatible)",
|
||||||
|
Found: args[0].TypeName(),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = &objects.String{Value: t1.String()}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@ -17,14 +17,16 @@ github.com/Philipp15b/go-steam/rwu
|
|||||||
github.com/Philipp15b/go-steam/socialcache
|
github.com/Philipp15b/go-steam/socialcache
|
||||||
# github.com/bwmarrin/discordgo v0.19.0
|
# github.com/bwmarrin/discordgo v0.19.0
|
||||||
github.com/bwmarrin/discordgo
|
github.com/bwmarrin/discordgo
|
||||||
# github.com/d5/tengo v1.12.1
|
# github.com/d5/tengo v1.20.0
|
||||||
github.com/d5/tengo/script
|
github.com/d5/tengo/script
|
||||||
|
github.com/d5/tengo/stdlib
|
||||||
github.com/d5/tengo/compiler
|
github.com/d5/tengo/compiler
|
||||||
github.com/d5/tengo/compiler/parser
|
github.com/d5/tengo/compiler/parser
|
||||||
github.com/d5/tengo/compiler/source
|
github.com/d5/tengo/compiler/source
|
||||||
github.com/d5/tengo/objects
|
github.com/d5/tengo/objects
|
||||||
github.com/d5/tengo/runtime
|
github.com/d5/tengo/runtime
|
||||||
github.com/d5/tengo
|
github.com/d5/tengo
|
||||||
|
github.com/d5/tengo/stdlib/json
|
||||||
github.com/d5/tengo/compiler/ast
|
github.com/d5/tengo/compiler/ast
|
||||||
github.com/d5/tengo/compiler/token
|
github.com/d5/tengo/compiler/token
|
||||||
github.com/d5/tengo/compiler/scanner
|
github.com/d5/tengo/compiler/scanner
|
||||||
|
Loading…
Reference in New Issue
Block a user