forked from lug/matterbridge
		
	Compare commits
	
		
			21 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | db012bd9b7 | ||
|   | dd2374158b | ||
|   | 6693157258 | ||
|   | e4d73b29a1 | ||
|   | 8a875f292e | ||
|   | 60a85621ea | ||
|   | 115d20373c | ||
|   | cdf33e5748 | ||
|   | 01d0a9f412 | ||
|   | 8cc2d3b4fe | ||
|   | aba9e4f3be | ||
|   | 4d575ba13a | ||
|   | 7f0e4ad448 | ||
|   | 17cc14a9d2 | ||
|   | 1f8016182c | ||
|   | caf9ef2c4b | ||
|   | 64b57f2da3 | ||
|   | efd2c99862 | ||
|   | cc05ba8907 | ||
|   | 16763b715a | ||
|   | ffaa598796 | 
| @@ -7,7 +7,7 @@ run: | ||||
|   # concurrency: 4 | ||||
|  | ||||
|   # timeout for analysis, e.g. 30s, 5m, default is 1m | ||||
|   deadline: 1m | ||||
|   deadline: 2m | ||||
|  | ||||
|   # exit code when at least one issue was found, default is 1 | ||||
|   issues-exit-code: 1 | ||||
| @@ -105,10 +105,6 @@ linters-settings: | ||||
|     # with golangci-lint call it on a directory with the changed file. | ||||
|     check-exported: false | ||||
|   unparam: | ||||
|     # call graph construction algorithm (cha, rta). In general, use cha for libraries, | ||||
|     # and rta for programs with main packages. Default is cha. | ||||
|     algo: rta | ||||
|  | ||||
|     # Inspect exported functions, default is false. Set to true if no external program/library imports your code. | ||||
|     # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: | ||||
|     # if it's called for subdir of a project it can't find external interfaces. All text editor integrations | ||||
|   | ||||
							
								
								
									
										88
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -1,75 +1,55 @@ | ||||
| language: go | ||||
| go: | ||||
|     - 1.11.x | ||||
| go_import_path: github.com/42wim/matterbridge | ||||
|  | ||||
| # we have everything vendored | ||||
| # We have everything vendored so this helps TravisCI not run `go get ...`. | ||||
| install: true | ||||
|  | ||||
| git: | ||||
|   depth: 200 | ||||
|  | ||||
| env: | ||||
|   global: | ||||
|     - GOOS=linux GOARCH=amd64 | ||||
|     - GO111MODULE=on | ||||
|     - GOLANGCI_VERSION="v1.14.0" | ||||
|  | ||||
| matrix: | ||||
|   # It's ok if our code fails on unstable development versions of Go. | ||||
|   allow_failures: | ||||
|     - go: tip | ||||
|   # Don't wait for tip tests to finish. Mark the test run green if the | ||||
|   # tests pass on the stable versions of Go. | ||||
|   fast_finish: true | ||||
|  | ||||
| notifications: | ||||
|       email: false | ||||
|  | ||||
| before_script: | ||||
|   # Get version info from tags. | ||||
|   - MY_VERSION="$(git describe --tags)" | ||||
|   # Retrieve the golangci-lint linter binary. | ||||
|   - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b ${GOPATH}/bin ${GOLANGCI_VERSION} | ||||
|   # Retrieve and prepare CodeClimate's test coverage reporter. | ||||
|   - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter | ||||
|   - chmod +x ./cc-test-reporter | ||||
|   - ./cc-test-reporter before-build | ||||
|  | ||||
| script: | ||||
|   # Ensure that the module files are being kept correctly and that vendored dependencies are up-to-date. | ||||
|   - go mod tidy | ||||
|   - go mod vendor | ||||
|   - git diff --exit-code --quiet || (echo "Please run 'go mod tidy' to clean up the 'go.mod' and 'go.sum' files."; false) | ||||
|  | ||||
|   # Run the linter. | ||||
|   - golangci-lint run | ||||
|  | ||||
|   # Run all the tests with the race detector and generate coverage. | ||||
|   - go test -v -race -coverprofile c.out ./... | ||||
|  | ||||
|   # Run the build script to generate the necessary binaries and images. | ||||
|   - /bin/bash ci/bintray.sh | ||||
|  | ||||
| after_script: | ||||
|   # Upload test coverage to CodeClimate. | ||||
|   - ./cc-test-reporter after-build --exit-code ${TRAVIS_TEST_RESULT} | ||||
|   email: false | ||||
|  | ||||
| branches: | ||||
|   only: | ||||
|     - master | ||||
|   - master | ||||
|  | ||||
| jobs: | ||||
|   include: | ||||
|   - stage: lint | ||||
|     # Run linting in one Go environment only. | ||||
|     script: ./ci/lint.sh | ||||
|     go: 1.12.x | ||||
|     env: | ||||
|     - GO111MODULE=on | ||||
|     - GOLANGCI_VERSION="v1.16.0" | ||||
|   - stage: test | ||||
|     # Run tests in a combination of Go environments. | ||||
|     script: ./ci/test.sh | ||||
|     go: 1.11.x | ||||
|     env: | ||||
|     - GO111MODULE=off | ||||
|   - script: ./ci/test.sh | ||||
|     go: 1.11.x | ||||
|     env: | ||||
|     - GO111MODULE=on | ||||
|   - script: ./ci/test.sh | ||||
|     go: 1.12.x | ||||
|     env: | ||||
|     - GO111MODULE=on | ||||
|     - REPORT_COVERAGE=1 | ||||
|     - BINDEPLOY=1 | ||||
|  | ||||
| before_deploy: /bin/bash ci/bintray.sh | ||||
|  | ||||
| deploy: | ||||
|   on: | ||||
|      all_branches: true | ||||
|   provider: bintray | ||||
|   on: | ||||
|     all_branches: true | ||||
|     condition: $BINDEPLOY = 1 | ||||
|   provider: bintray | ||||
|   edge: | ||||
|     branch: v1.8.47 | ||||
|   file: ci/deploy.json | ||||
|   user: 42wim | ||||
|   on: | ||||
|      all_branches: true | ||||
|   key: | ||||
|      secure: "CeXXe6JOmt7HYR81MdWLua0ltQHhDdkIeRGBFbgd7hkb1wi8eF9DgpAcQrTso8NIlHNZmSAP46uhFgsRvkuezzX0ygalZ7DCJyAyn3sAMEh+UQSHV1WGThRehTtidqRGjetzsIGSwdrJOWil+XTfbO1Z8DGzfakhSuAZka8CM4BAoe3YeP9rYK8h+84x0GHfczvsLtXZ3mWLvQuwe4pK6+ItBCUg0ae7O7ZUpWHy0xQQkkWztY/6RAzXfaG7DuGjIw+20fhx3WOXRNpHCtZ6Bc3qERCpk0s1HhlQWlrN9wDaFTBWYwlvSnNgvxxMbNXJ6RrRJ0l0bA7FUswYwyroxhzrGLdzWDg8dHaQkypocngdalfhpsnoO9j3ApJhomUFJ3UoEq5nOGRUrKn8MPi+dP0zE4kNQ3e4VNa1ufNrvfpWolMg3xh8OXuhQdD5wIM5zFAbRJLqWSCVAjPq4DDPecmvXBOlIial7oa312lN5qnBnUjvAcxszZ+FUyDHT1Grxzna4tMwxY9obPzZUzm7359AOCCwIQFVB8GLqD2nwIstcXS0zGRz+fhviPipHuBa02q5bGUZwmkvrSNab0s8Jo7pCrel2Rz3nWPKaiCfq2WjbW1CLheSMkOQrjsdUd1hhbqNWFPUjJPInTc77NAKCfm5runv5uyowRLh4NNd0sI=" | ||||
|     secure: "CeXXe6JOmt7HYR81MdWLua0ltQHhDdkIeRGBFbgd7hkb1wi8eF9DgpAcQrTso8NIlHNZmSAP46uhFgsRvkuezzX0ygalZ7DCJyAyn3sAMEh+UQSHV1WGThRehTtidqRGjetzsIGSwdrJOWil+XTfbO1Z8DGzfakhSuAZka8CM4BAoe3YeP9rYK8h+84x0GHfczvsLtXZ3mWLvQuwe4pK6+ItBCUg0ae7O7ZUpWHy0xQQkkWztY/6RAzXfaG7DuGjIw+20fhx3WOXRNpHCtZ6Bc3qERCpk0s1HhlQWlrN9wDaFTBWYwlvSnNgvxxMbNXJ6RrRJ0l0bA7FUswYwyroxhzrGLdzWDg8dHaQkypocngdalfhpsnoO9j3ApJhomUFJ3UoEq5nOGRUrKn8MPi+dP0zE4kNQ3e4VNa1ufNrvfpWolMg3xh8OXuhQdD5wIM5zFAbRJLqWSCVAjPq4DDPecmvXBOlIial7oa312lN5qnBnUjvAcxszZ+FUyDHT1Grxzna4tMwxY9obPzZUzm7359AOCCwIQFVB8GLqD2nwIstcXS0zGRz+fhviPipHuBa02q5bGUZwmkvrSNab0s8Jo7pCrel2Rz3nWPKaiCfq2WjbW1CLheSMkOQrjsdUd1hhbqNWFPUjJPInTc77NAKCfm5runv5uyowRLh4NNd0sI=" | ||||
|   | ||||
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
								
							| @@ -35,6 +35,12 @@ | ||||
|  | ||||
| **Note:** Matter<em>most</em> isn't required to run matter<em>bridge</em>.</sup></div> | ||||
|  | ||||
| <p> | ||||
|   <a href="https://www.digitalocean.com/"> | ||||
|     <img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/PoweredByDO/DO_Powered_by_Badge_blue.svg" width="201px"> | ||||
|   </a> | ||||
| </p> | ||||
|  | ||||
| ### Table of Contents | ||||
|  * [Features](https://github.com/42wim/matterbridge/wiki/Features) | ||||
|    * [Natively supported](#natively-supported) | ||||
| @@ -123,7 +129,7 @@ See https://github.com/42wim/matterbridge/wiki | ||||
|  | ||||
| ## Installing | ||||
| ### Binaries | ||||
| * Latest stable release [v1.14.1](https://github.com/42wim/matterbridge/releases/latest) | ||||
| * Latest stable release [v1.14.2](https://github.com/42wim/matterbridge/releases/latest) | ||||
| * Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/) | ||||
|  | ||||
| ### Packages | ||||
| @@ -264,7 +270,13 @@ See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ) | ||||
| * https://daniele.tech/2019/02/how-to-use-matterbridge-to-connect-2-different-slack-workspaces/ | ||||
|  | ||||
| ## Thanks | ||||
| [](https://www.digitalocean.com/) for sponsoring demo/testing droplets. | ||||
|  | ||||
| <p>This project is supported by:</p> | ||||
| <p> | ||||
|   <a href="https://www.digitalocean.com/"> | ||||
|     <img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px"> | ||||
|   </a> | ||||
| </p> | ||||
|  | ||||
| Matterbridge wouldn't exist without these libraries: | ||||
| * discord - https://github.com/bwmarrin/discordgo | ||||
|   | ||||
| @@ -92,10 +92,6 @@ func (b *Birc) handleJoinPart(client *girc.Client, event girc.Event) { | ||||
| 			return | ||||
| 		} | ||||
| 		b.Log.Debugf("<= Sending JOIN_LEAVE event from %s to gateway", b.Account) | ||||
| 		// QUIT isn't channel bound, happens for all channels on the bridge | ||||
| 		if event.Command == "QUIT" { | ||||
| 			channel = "" | ||||
| 		} | ||||
| 		msg := config.Message{Username: "system", Text: event.Source.Name + " " + strings.ToLower(event.Command) + "s", Channel: channel, Account: b.Account, Event: config.EventJoinLeave} | ||||
| 		b.Log.Debugf("<= Message is %#v", msg) | ||||
| 		b.Remote <- msg | ||||
| @@ -160,7 +156,10 @@ func (b *Birc) handleOtherAuth(client *girc.Client, event girc.Event) { | ||||
| 	b.handleNickServ() | ||||
| 	b.handleRunCommands() | ||||
| 	// we are now fully connected | ||||
| 	b.connected <- nil | ||||
| 	// only send on first connection | ||||
| 	if b.FirstConnection { | ||||
| 		b.connected <- nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Birc) handlePrivMsg(client *girc.Client, event girc.Event) { | ||||
|   | ||||
| @@ -137,6 +137,7 @@ func (b *Birc) Send(msg config.Message) (string, error) { | ||||
| 	// we can be in between reconnects #385 | ||||
| 	if !b.i.IsConnected() { | ||||
| 		b.Log.Error("Not connected to server, dropping message") | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	// Execute a command | ||||
| @@ -231,7 +232,7 @@ func (b *Birc) getClient() (*girc.Client, error) { | ||||
| 	// fix strict user handling of girc | ||||
| 	user := b.GetString("Nick") | ||||
| 	for !girc.IsValidUser(user) { | ||||
| 		if len(user) == 1 { | ||||
| 		if len(user) == 1 || len(user) == 0 { | ||||
| 			user = "matterbridge" | ||||
| 			break | ||||
| 		} | ||||
|   | ||||
| @@ -95,7 +95,7 @@ func (b *Brocketchat) getChannelID(name string) string { | ||||
| 	b.RLock() | ||||
| 	defer b.RUnlock() | ||||
| 	for k, v := range b.channelMap { | ||||
| 		if v == name { | ||||
| 		if v == name || v == "#"+name { | ||||
| 			return k | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -130,12 +130,18 @@ func (b *Bslack) skipMessageEvent(ev *slack.MessageEvent) bool { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	// It seems ev.SubMessage.Edited == nil when slack unfurls. | ||||
| 	// Do not forward these messages. See Github issue #266. | ||||
| 	if ev.SubMessage != nil && | ||||
| 		ev.SubMessage.ThreadTimestamp != ev.SubMessage.Timestamp && | ||||
| 		ev.SubMessage.Edited == nil { | ||||
| 		return true | ||||
| 	if ev.SubMessage != nil { | ||||
| 		// It seems ev.SubMessage.Edited == nil when slack unfurls. | ||||
| 		// Do not forward these messages. See Github issue #266. | ||||
| 		if ev.SubMessage.ThreadTimestamp != ev.SubMessage.Timestamp && | ||||
| 			ev.SubMessage.Edited == nil { | ||||
| 			return true | ||||
| 		} | ||||
| 		// see hidden subtypes at https://api.slack.com/events/message | ||||
| 		// these messages are sent when we add a message to a thread #709 | ||||
| 		if ev.SubType == "message_replied" && ev.Hidden { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(ev.Files) > 0 { | ||||
|   | ||||
| @@ -125,6 +125,11 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | ||||
| 		// handle groups | ||||
| 		message = b.handleGroups(&rmsg, message, update) | ||||
|  | ||||
| 		if message == nil { | ||||
| 			b.Log.Error("message is nil, this shouldn't happen.") | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// set the ID's from the channel or group message | ||||
| 		rmsg.ID = strconv.Itoa(message.MessageID) | ||||
| 		rmsg.Channel = strconv.FormatInt(message.Chat.ID, 10) | ||||
|   | ||||
							
								
								
									
										20
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,3 +1,23 @@ | ||||
| # v1.14.3 | ||||
|  | ||||
| ## Bugfix | ||||
| * irc: Fix deadlock on reconnect (irc). Closes #757 | ||||
|  | ||||
| # v1.14.2 | ||||
|  | ||||
| ## Bugfix | ||||
| * general: Update tengo vendor and load the stdlib. Fixes #789 (#792) | ||||
| * rocketchat: Look up #channel too (rocketchat). Fix #773 (#775) | ||||
| * slack: Ignore messagereplied and hidden messages (slack). Fixes #709 (#779) | ||||
| * telegram: Handle nil message (telegram). Fixes #777 | ||||
| * irc: Use default nick if none specified (irc). Fixes #785 | ||||
| * irc: Return when not connected and drop a message (irc). Fixes #786 | ||||
| * irc: Revert fix for #722 (Support quits from irc correctly). Closes #781 | ||||
|  | ||||
| ## Contributors | ||||
| This release couldn't exist without the following contributors: | ||||
| @42wim, @Helcaraxan, @dajohi | ||||
|  | ||||
| # v1.14.1 | ||||
| ## Bugfix | ||||
| * slack: Fix crash double unlock (slack) (#771) | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| #!/bin/bash | ||||
| go version | grep go1.11 || exit | ||||
| #!/usr/bin/env bash | ||||
| set -u -e -x -o pipefail | ||||
|  | ||||
| go version | grep go1.12 || exit | ||||
|  | ||||
| VERSION=$(git describe --tags) | ||||
| mkdir ci/binaries | ||||
| GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-windows-amd64.exe | ||||
|   | ||||
							
								
								
									
										17
									
								
								ci/lint.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								ci/lint.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #!/usr/bin/env bash | ||||
| set -u -e -x -o pipefail | ||||
|  | ||||
| if [[ -n "${GOLANGCI_VERSION-}" ]]; then | ||||
|   # Retrieve the golangci-lint linter binary. | ||||
|   curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b ${GOPATH}/bin ${GOLANGCI_VERSION} | ||||
| fi | ||||
|  | ||||
| # Run the linter. | ||||
| golangci-lint run | ||||
|  | ||||
| if [[ "${GO111MODULE-off}" == "on" ]]; then | ||||
|   # If Go modules are active then check that dependencies are correctly maintained. | ||||
|   go mod tidy | ||||
|   go mod vendor | ||||
|   git diff --exit-code --quiet || (echo "Please run 'go mod tidy' to clean up the 'go.mod' and 'go.sum' files."; false) | ||||
| fi | ||||
							
								
								
									
										17
									
								
								ci/test.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								ci/test.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #!/usr/bin/env bash | ||||
| set -u -e -x -o pipefail | ||||
|  | ||||
| if [[ -n "${REPORT_COVERAGE+cover}" ]]; then | ||||
|   # Retrieve and prepare CodeClimate's test coverage reporter. | ||||
|   curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter | ||||
|   chmod +x ./cc-test-reporter | ||||
|   ./cc-test-reporter before-build | ||||
| fi | ||||
|  | ||||
| # Run all the tests with the race detector and generate coverage. | ||||
| go test -v -race -coverprofile c.out ./... | ||||
|  | ||||
| if [[ -n "${REPORT_COVERAGE+cover}" && "${TRAVIS_SECURE_ENV_VARS}" == "true" ]]; then | ||||
|   # Upload test coverage to CodeClimate. | ||||
|   ./cc-test-reporter after-build | ||||
| fi | ||||
| @@ -10,6 +10,7 @@ import ( | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/d5/tengo/script" | ||||
| 	"github.com/d5/tengo/stdlib" | ||||
| 	lru "github.com/hashicorp/golang-lru" | ||||
| 	"github.com/peterhellberg/emojilib" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| @@ -211,23 +212,6 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con | ||||
| 		return channels | ||||
| 	} | ||||
|  | ||||
| 	// irc quit is for the whole bridge, isn't a per channel quit. | ||||
| 	// channel is empty when we quit | ||||
| 	if msg.Event == config.EventJoinLeave && getProtocol(msg) == "irc" && msg.Channel == "" { | ||||
| 		// if we only have one channel on this irc bridge it's got to be the sending one. | ||||
| 		// don't send it back | ||||
| 		if dest.Account == msg.Account && len(dest.Channels) == 1 && dest.Protocol == "irc" { | ||||
| 			return channels | ||||
| 		} | ||||
| 		for _, channel := range gw.Channels { | ||||
| 			if channel.Account == dest.Account && strings.Contains(channel.Direction, "out") && | ||||
| 				gw.validGatewayDest(msg) { | ||||
| 				channels = append(channels, *channel) | ||||
| 			} | ||||
| 		} | ||||
| 		return channels | ||||
| 	} | ||||
|  | ||||
| 	// if source channel is in only, do nothing | ||||
| 	for _, channel := range gw.Channels { | ||||
| 		// lookup the channel from the message | ||||
| @@ -503,6 +487,7 @@ func modifyMessageTengo(filename string, msg *config.Message) error { | ||||
| 		return err | ||||
| 	} | ||||
| 	s := script.New(res) | ||||
| 	s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...)) | ||||
| 	_ = s.Add("msgText", msg.Text) | ||||
| 	_ = s.Add("msgUsername", msg.Username) | ||||
| 	_ = 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/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329 | ||||
| 	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/fsnotify/fsnotify v1.4.7 | ||||
| 	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/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/d5/tengo v1.12.1 h1:libKkDM95CsZgYs6E5eiEaM9sbcw2EzJRSkr9o5NO4s= | ||||
| github.com/d5/tengo v1.12.1/go.mod h1:gsbjo7lBXzBIWBd6NQp1lRKqqiDDANqBOyhW8rTlFsY= | ||||
| github.com/d5/tengo v1.20.0 h1:lFmktzEGR6khlZu2MHUWJ5oDWS4l3jNRV/OhclZgcYc= | ||||
| 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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
|   | ||||
| @@ -15,7 +15,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	version = "1.14.1" | ||||
| 	version = "1.14.3" | ||||
| 	githash string | ||||
|  | ||||
| 	flagConfig  = flag.String("conf", "matterbridge.toml", "config file") | ||||
|   | ||||
| @@ -27,7 +27,7 @@ UseTLS=false | ||||
| #OPTIONAL (default false) | ||||
| UseSASL=false | ||||
|  | ||||
| #Enable to not verify the certificate on your irc server. i | ||||
| #Enable to not verify the certificate on your irc server. | ||||
| #e.g. when using selfsigned certificates | ||||
| #OPTIONAL (default false) | ||||
| SkipTLSVerify=true | ||||
|   | ||||
| @@ -51,8 +51,9 @@ func (m *MMClient) GetChannelId(name string, teamId string) string { //nolint:go | ||||
| 				if res == name { | ||||
| 					return channel.Id | ||||
| 				} | ||||
| 			} else if channel.Name == name { | ||||
| 				return channel.Id | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
|   | ||||
| @@ -216,9 +216,14 @@ func (m *MMClient) WsReceiver() { | ||||
| 			if msg.Post != nil { | ||||
| 				if msg.Text != "" || len(msg.Post.FileIds) > 0 || msg.Post.Type == "slack_attachment" { | ||||
| 					m.MessageChan <- msg | ||||
| 					continue | ||||
| 				} | ||||
| 			} | ||||
| 			continue | ||||
| 			switch msg.Raw.Event { | ||||
| 			case model.WEBSOCKET_EVENT_USER_ADDED, model.WEBSOCKET_EVENT_USER_REMOVED: | ||||
| 				m.MessageChan <- msg | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		var response model.WebSocketResponse | ||||
|   | ||||
							
								
								
									
										5
									
								
								vendor/github.com/d5/tengo/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/d5/tengo/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,10 +1,13 @@ | ||||
| vet: | ||||
| 	go vet ./... | ||||
|  | ||||
| generate: | ||||
| 	go generate ./... | ||||
|  | ||||
| lint: | ||||
| 	golint -set_exit_status ./... | ||||
|  | ||||
| test: vet lint | ||||
| test: generate vet lint | ||||
| 	go test -race -cover ./... | ||||
|  | ||||
| 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 @@ | ||||
| [](https://godoc.org/github.com/d5/tengo/script) | ||||
| [](https://goreportcard.com/report/github.com/d5/tengo) | ||||
| [](https://travis-ci.org/d5/tengo) | ||||
| [](https://www.patreon.com/tengolang) | ||||
|  | ||||
| **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 | ||||
| /* The Tengo Language */ | ||||
|  | ||||
| fmt := import("fmt") | ||||
|  | ||||
| each := func(seq, fn) { | ||||
|     for x in seq { fn(x) } | ||||
| } | ||||
| @@ -25,11 +26,11 @@ sum := func(init, seq) { | ||||
|     return init | ||||
| } | ||||
|  | ||||
| n := sum(0, [1, 2, 3])   // == 6 | ||||
| s := sum("", [1, 2, 3])  // == "123" | ||||
| fmt.println(sum(0, [1, 2, 3]))   // "6" | ||||
| 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 | ||||
|  | ||||
| @@ -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) | ||||
| - 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 | ||||
| - 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 | ||||
|  | ||||
| | | fib(35) | fibt(35) |  Type  | | ||||
| | :--- |    ---: |     ---: |  :---: | | ||||
| | Go | `58ms` | `4ms` | Go (native) | | ||||
| | [**Tengo**](https://github.com/d5/tengo) | `4,180ms` | `5ms` | VM on Go | | ||||
| | Lua | `1,695ms` | `3ms` | Lua (native) | | ||||
| | [go-lua](https://github.com/Shopify/go-lua) | `5,163ms` | `5ms` | Lua VM on Go | | ||||
| | [GopherLua](https://github.com/yuin/gopher-lua) | `5,525ms` | `5ms` | Lua VM on Go | | ||||
| | Python | `3,097ms` | `27ms` | Python (native) | | ||||
| | [starlark-go](https://github.com/google/starlark-go) | `15,307ms` | `5ms` | Python-like Interpreter on Go | | ||||
| | [gpython](https://github.com/go-python/gpython) | `17,656ms` | `5ms` | Python Interpreter on Go | | ||||
| | [goja](https://github.com/dop251/goja) | `6,876ms` | `5ms` | JS VM on Go | | ||||
| | [otto](https://github.com/robertkrimen/otto) | `81,886ms` | `12ms` | JS Interpreter on Go | | ||||
| | [Anko](https://github.com/mattn/anko) | `97,517ms` | `14ms` | Interpreter on Go | | ||||
| | Go | `48ms` | `3ms` | Go (native) | | ||||
| | [**Tengo**](https://github.com/d5/tengo) | `2,349ms` | `5ms` | VM on Go | | ||||
| | Lua | `1,416ms` | `3ms` | Lua (native) | | ||||
| | [go-lua](https://github.com/Shopify/go-lua) | `4,402ms` | `5ms` | Lua VM on Go | | ||||
| | [GopherLua](https://github.com/yuin/gopher-lua) | `4,023ms` | `5ms` | Lua VM on Go | | ||||
| | Python | `2,588ms` | `26ms` | Python (native) | | ||||
| | [starlark-go](https://github.com/google/starlark-go) | `11,126ms` | `6ms` | Python-like Interpreter on Go | | ||||
| | [gpython](https://github.com/go-python/gpython) | `15,035ms` | `4ms` | Python Interpreter on Go | | ||||
| | [goja](https://github.com/dop251/goja) | `5,089ms` | `5ms` | JS VM on Go | | ||||
| | [otto](https://github.com/robertkrimen/otto) | `68,377ms` | `11ms` | JS Interpreter on Go | | ||||
| | [Anko](https://github.com/mattn/anko) | `92,579ms` | `18ms` | Interpreter on Go | | ||||
|  | ||||
| _* [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)_   | ||||
|   | ||||
							
								
								
									
										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 | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| func (b *Bytecode) Encode(w io.Writer) error { | ||||
| 	enc := gob.NewEncoder(w) | ||||
| @@ -59,6 +33,17 @@ func (b *Bytecode) Encode(w io.Writer) error { | ||||
| 	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 | ||||
| // compiled instructions. | ||||
| func (b *Bytecode) FormatInstructions() []string { | ||||
| @@ -83,51 +68,22 @@ func (b *Bytecode) FormatConstants() (output []string) { | ||||
| 	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() { | ||||
| 	gob.Register(&source.FileSet{}) | ||||
| 	gob.Register(&source.File{}) | ||||
| 	gob.Register(&objects.Array{}) | ||||
| 	gob.Register(&objects.ArrayIterator{}) | ||||
| 	gob.Register(&objects.Bool{}) | ||||
| 	gob.Register(&objects.Break{}) | ||||
| 	gob.Register(&objects.BuiltinFunction{}) | ||||
| 	gob.Register(&objects.Bytes{}) | ||||
| 	gob.Register(&objects.Char{}) | ||||
| 	gob.Register(&objects.Closure{}) | ||||
| 	gob.Register(&objects.CompiledFunction{}) | ||||
| 	gob.Register(&objects.Continue{}) | ||||
| 	gob.Register(&objects.Error{}) | ||||
| 	gob.Register(&objects.Float{}) | ||||
| 	gob.Register(&objects.ImmutableArray{}) | ||||
| 	gob.Register(&objects.ImmutableMap{}) | ||||
| 	gob.Register(&objects.Int{}) | ||||
| 	gob.Register(&objects.Map{}) | ||||
| 	gob.Register(&objects.MapIterator{}) | ||||
| 	gob.Register(&objects.ReturnValue{}) | ||||
| 	gob.Register(&objects.String{}) | ||||
| 	gob.Register(&objects.StringIterator{}) | ||||
| 	gob.Register(&objects.Time{}) | ||||
| 	gob.Register(&objects.Undefined{}) | ||||
| 	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 | ||||
| // and the last two instructions that were emitted. | ||||
| type CompilationScope struct { | ||||
| 	instructions     []byte | ||||
| 	lastInstructions [2]EmittedInstruction | ||||
| 	symbolInit       map[string]bool | ||||
| 	sourceMap        map[int]source.Pos | ||||
| 	instructions []byte | ||||
| 	symbolInit   map[string]bool | ||||
| 	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 ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/d5/tengo" | ||||
| 	"github.com/d5/tengo/compiler/ast" | ||||
| @@ -16,14 +19,14 @@ import ( | ||||
| type Compiler struct { | ||||
| 	file            *source.File | ||||
| 	parent          *Compiler | ||||
| 	moduleName      string | ||||
| 	modulePath      string | ||||
| 	constants       []objects.Object | ||||
| 	symbolTable     *SymbolTable | ||||
| 	scopes          []CompilationScope | ||||
| 	scopeIndex      int | ||||
| 	moduleLoader    ModuleLoader | ||||
| 	builtinModules  map[string]bool | ||||
| 	modules         *objects.ModuleMap | ||||
| 	compiledModules map[string]*objects.CompiledFunction | ||||
| 	allowFileImport bool | ||||
| 	loops           []*Loop | ||||
| 	loopIndex       int | ||||
| 	trace           io.Writer | ||||
| @@ -31,12 +34,7 @@ type Compiler struct { | ||||
| } | ||||
|  | ||||
| // NewCompiler creates a Compiler. | ||||
| // User can optionally provide the symbol table if one wants to add or remove | ||||
| // 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 { | ||||
| func NewCompiler(file *source.File, symbolTable *SymbolTable, constants []objects.Object, modules *objects.ModuleMap, trace io.Writer) *Compiler { | ||||
| 	mainScope := CompilationScope{ | ||||
| 		symbolInit: make(map[string]bool), | ||||
| 		sourceMap:  make(map[int]source.Pos), | ||||
| @@ -45,15 +43,16 @@ func NewCompiler(file *source.File, symbolTable *SymbolTable, constants []object | ||||
| 	// symbol table | ||||
| 	if symbolTable == nil { | ||||
| 		symbolTable = NewSymbolTable() | ||||
| 	} | ||||
|  | ||||
| 		for idx, fn := range objects.Builtins { | ||||
| 			symbolTable.DefineBuiltin(idx, fn.Name) | ||||
| 		} | ||||
| 	// add builtin functions to the symbol table | ||||
| 	for idx, fn := range objects.Builtins { | ||||
| 		symbolTable.DefineBuiltin(idx, fn.Name) | ||||
| 	} | ||||
|  | ||||
| 	// builtin modules | ||||
| 	if builtinModules == nil { | ||||
| 		builtinModules = make(map[string]bool) | ||||
| 	if modules == nil { | ||||
| 		modules = objects.NewModuleMap() | ||||
| 	} | ||||
|  | ||||
| 	return &Compiler{ | ||||
| @@ -64,7 +63,7 @@ func NewCompiler(file *source.File, symbolTable *SymbolTable, constants []object | ||||
| 		scopeIndex:      0, | ||||
| 		loopIndex:       -1, | ||||
| 		trace:           trace, | ||||
| 		builtinModules:  builtinModules, | ||||
| 		modules:         modules, | ||||
| 		compiledModules: make(map[string]*objects.CompiledFunction), | ||||
| 	} | ||||
| } | ||||
| @@ -120,7 +119,7 @@ func (c *Compiler) Compile(node ast.Node) error { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			c.emit(node, OpGreaterThan) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Greater)) | ||||
|  | ||||
| 			return nil | ||||
| 		} else if node.Token == token.LessEq { | ||||
| @@ -131,7 +130,7 @@ func (c *Compiler) Compile(node ast.Node) error { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			c.emit(node, OpGreaterThanEqual) | ||||
| 			c.emit(node, OpBinaryOp, int(token.GreaterEq)) | ||||
|  | ||||
| 			return nil | ||||
| 		} | ||||
| @@ -145,35 +144,35 @@ func (c *Compiler) Compile(node ast.Node) error { | ||||
|  | ||||
| 		switch node.Token { | ||||
| 		case token.Add: | ||||
| 			c.emit(node, OpAdd) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Add)) | ||||
| 		case token.Sub: | ||||
| 			c.emit(node, OpSub) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Sub)) | ||||
| 		case token.Mul: | ||||
| 			c.emit(node, OpMul) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Mul)) | ||||
| 		case token.Quo: | ||||
| 			c.emit(node, OpDiv) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Quo)) | ||||
| 		case token.Rem: | ||||
| 			c.emit(node, OpRem) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Rem)) | ||||
| 		case token.Greater: | ||||
| 			c.emit(node, OpGreaterThan) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Greater)) | ||||
| 		case token.GreaterEq: | ||||
| 			c.emit(node, OpGreaterThanEqual) | ||||
| 			c.emit(node, OpBinaryOp, int(token.GreaterEq)) | ||||
| 		case token.Equal: | ||||
| 			c.emit(node, OpEqual) | ||||
| 		case token.NotEqual: | ||||
| 			c.emit(node, OpNotEqual) | ||||
| 		case token.And: | ||||
| 			c.emit(node, OpBAnd) | ||||
| 			c.emit(node, OpBinaryOp, int(token.And)) | ||||
| 		case token.Or: | ||||
| 			c.emit(node, OpBOr) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Or)) | ||||
| 		case token.Xor: | ||||
| 			c.emit(node, OpBXor) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Xor)) | ||||
| 		case token.AndNot: | ||||
| 			c.emit(node, OpBAndNot) | ||||
| 			c.emit(node, OpBinaryOp, int(token.AndNot)) | ||||
| 		case token.Shl: | ||||
| 			c.emit(node, OpBShiftLeft) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Shl)) | ||||
| 		case token.Shr: | ||||
| 			c.emit(node, OpBShiftRight) | ||||
| 			c.emit(node, OpBinaryOp, int(token.Shr)) | ||||
| 		default: | ||||
| 			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: | ||||
| 		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 { | ||||
| 			if err := c.Compile(stmt); err != nil { | ||||
| 				return err | ||||
| @@ -405,10 +413,8 @@ func (c *Compiler) Compile(node ast.Node) error { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		// add OpReturn if function returns nothing | ||||
| 		if !c.lastInstructionIs(OpReturnValue) && !c.lastInstructionIs(OpReturn) { | ||||
| 			c.emit(node, OpReturn) | ||||
| 		} | ||||
| 		// code optimization | ||||
| 		c.optimizeFunc(node) | ||||
|  | ||||
| 		freeSymbols := c.symbolTable.FreeSymbols() | ||||
| 		numLocals := c.symbolTable.MaxSymbols() | ||||
| @@ -461,9 +467,9 @@ func (c *Compiler) Compile(node ast.Node) error { | ||||
| 					s.LocalAssigned = true | ||||
| 				} | ||||
|  | ||||
| 				c.emit(node, OpGetLocal, s.Index) | ||||
| 				c.emit(node, OpGetLocalPtr, s.Index) | ||||
| 			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 { | ||||
| 			c.emit(node, OpReturn) | ||||
| 			c.emit(node, OpReturn, 0) | ||||
| 		} else { | ||||
| 			if err := c.Compile(node.Result); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			c.emit(node, OpReturnValue) | ||||
| 			c.emit(node, OpReturn, 1) | ||||
| 		} | ||||
|  | ||||
| 	case *ast.CallExpr: | ||||
| @@ -510,21 +516,57 @@ func (c *Compiler) Compile(node ast.Node) error { | ||||
| 		c.emit(node, OpCall, len(node.Args)) | ||||
|  | ||||
| 	case *ast.ImportExpr: | ||||
| 		if c.builtinModules[node.ModuleName] { | ||||
| 			if len(node.ModuleName) > tengo.MaxStringLen { | ||||
| 				return c.error(node, objects.ErrStringLimit) | ||||
| 			} | ||||
| 		if node.ModuleName == "" { | ||||
| 			return c.errorf(node, "empty module name") | ||||
| 		} | ||||
|  | ||||
| 			c.emit(node, OpConstant, c.addConstant(&objects.String{Value: node.ModuleName})) | ||||
| 			c.emit(node, OpGetBuiltinModule) | ||||
| 		} else { | ||||
| 			userMod, err := c.compileModule(node) | ||||
| 		if mod := c.modules.Get(node.ModuleName); mod != nil { | ||||
| 			v, err := mod.Import(node.ModuleName) | ||||
| 			if err != nil { | ||||
| 				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) | ||||
| 		} else { | ||||
| 			return c.errorf(node, "module '%s' not found", node.ModuleName) | ||||
| 		} | ||||
|  | ||||
| 	case *ast.ExportStmt: | ||||
| @@ -543,7 +585,7 @@ func (c *Compiler) Compile(node ast.Node) error { | ||||
| 		} | ||||
|  | ||||
| 		c.emit(node, OpImmutable) | ||||
| 		c.emit(node, OpReturnValue) | ||||
| 		c.emit(node, OpReturn, 1) | ||||
|  | ||||
| 	case *ast.ErrorExpr: | ||||
| 		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. | ||||
| // Note that the module loader is used for user modules, | ||||
| // not for the standard modules. | ||||
| func (c *Compiler) SetModuleLoader(moduleLoader ModuleLoader) { | ||||
| 	c.moduleLoader = moduleLoader | ||||
| // EnableFileImport enables or disables module loading from local files. | ||||
| // Local file modules are disabled by default. | ||||
| func (c *Compiler) EnableFileImport(enable bool) { | ||||
| 	c.allowFileImport = enable | ||||
| } | ||||
|  | ||||
| func (c *Compiler) fork(file *source.File, moduleName string, symbolTable *SymbolTable) *Compiler { | ||||
| 	child := NewCompiler(file, symbolTable, nil, c.builtinModules, c.trace) | ||||
| 	child.moduleName = moduleName       // name of the module to compile | ||||
| 	child.parent = c                    // parent to set to current compiler | ||||
| 	child.moduleLoader = c.moduleLoader // share module loader | ||||
| func (c *Compiler) fork(file *source.File, modulePath string, symbolTable *SymbolTable) *Compiler { | ||||
| 	child := NewCompiler(file, symbolTable, nil, c.modules, c.trace) | ||||
| 	child.modulePath = modulePath // module file path | ||||
| 	child.parent = c              // parent to set to current compiler | ||||
|  | ||||
| 	return child | ||||
| } | ||||
| @@ -657,33 +697,6 @@ func (c *Compiler) addInstruction(b []byte) int { | ||||
| 	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) { | ||||
| 	copy(c.currentInstructions()[pos:], inst) | ||||
|  | ||||
| @@ -700,6 +713,92 @@ func (c *Compiler) changeOperand(opPos int, operand ...int) { | ||||
| 	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 { | ||||
| 	filePos := source.NoPos | ||||
| 	if node != nil { | ||||
| @@ -709,7 +808,6 @@ func (c *Compiler) emit(node ast.Node, opcode Opcode, operands ...int) int { | ||||
| 	inst := MakeInstruction(opcode, operands...) | ||||
| 	pos := c.addInstruction(inst) | ||||
| 	c.scopes[c.scopeIndex].sourceMap[pos] = filePos | ||||
| 	c.setLastInstruction(opcode, pos) | ||||
|  | ||||
| 	if c.trace != nil { | ||||
| 		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 { | ||||
| 	case token.AddAssign: | ||||
| 		c.emit(node, OpAdd) | ||||
| 		c.emit(node, OpBinaryOp, int(token.Add)) | ||||
| 	case token.SubAssign: | ||||
| 		c.emit(node, OpSub) | ||||
| 		c.emit(node, OpBinaryOp, int(token.Sub)) | ||||
| 	case token.MulAssign: | ||||
| 		c.emit(node, OpMul) | ||||
| 		c.emit(node, OpBinaryOp, int(token.Mul)) | ||||
| 	case token.QuoAssign: | ||||
| 		c.emit(node, OpDiv) | ||||
| 		c.emit(node, OpBinaryOp, int(token.Quo)) | ||||
| 	case token.RemAssign: | ||||
| 		c.emit(node, OpRem) | ||||
| 		c.emit(node, OpBinaryOp, int(token.Rem)) | ||||
| 	case token.AndAssign: | ||||
| 		c.emit(node, OpBAnd) | ||||
| 		c.emit(node, OpBinaryOp, int(token.And)) | ||||
| 	case token.OrAssign: | ||||
| 		c.emit(node, OpBOr) | ||||
| 		c.emit(node, OpBinaryOp, int(token.Or)) | ||||
| 	case token.AndNotAssign: | ||||
| 		c.emit(node, OpBAndNot) | ||||
| 		c.emit(node, OpBinaryOp, int(token.AndNot)) | ||||
| 	case token.XorAssign: | ||||
| 		c.emit(node, OpBXor) | ||||
| 		c.emit(node, OpBinaryOp, int(token.Xor)) | ||||
| 	case token.ShlAssign: | ||||
| 		c.emit(node, OpBShiftLeft) | ||||
| 		c.emit(node, OpBinaryOp, int(token.Shl)) | ||||
| 	case token.ShrAssign: | ||||
| 		c.emit(node, OpBShiftRight) | ||||
| 		c.emit(node, OpBinaryOp, int(token.Shr)) | ||||
| 	} | ||||
|  | ||||
| 	// 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 | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/d5/tengo/compiler/ast" | ||||
| 	"github.com/d5/tengo/compiler/parser" | ||||
| 	"github.com/d5/tengo/objects" | ||||
| ) | ||||
|  | ||||
| func (c *Compiler) compileModule(expr *ast.ImportExpr) (*objects.CompiledFunction, error) { | ||||
| 	compiledModule, exists := c.loadCompiledModule(expr.ModuleName) | ||||
| 	if exists { | ||||
| 		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) | ||||
| func (c *Compiler) checkCyclicImports(node ast.Node, modulePath string) error { | ||||
| 	if c.modulePath == modulePath { | ||||
| 		return c.errorf(node, "cyclic module import: %s", modulePath) | ||||
| 	} else if c.parent != nil { | ||||
| 		return c.parent.checkCyclicImports(node, moduleName) | ||||
| 		return c.parent.checkCyclicImports(node, modulePath) | ||||
| 	} | ||||
|  | ||||
| 	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)) | ||||
| 	p := parser.NewParser(modFile, src, nil) | ||||
| 	file, err := p.ParseFile() | ||||
| @@ -85,36 +44,36 @@ func (c *Compiler) doCompileModule(moduleName string, src []byte) (*objects.Comp | ||||
| 	symbolTable = symbolTable.Fork(false) | ||||
|  | ||||
| 	// compile module | ||||
| 	moduleCompiler := c.fork(modFile, moduleName, symbolTable) | ||||
| 	moduleCompiler := c.fork(modFile, modulePath, symbolTable) | ||||
| 	if err := moduleCompiler.Compile(file); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// add OpReturn (== export undefined) if export is missing | ||||
| 	if !moduleCompiler.lastInstructionIs(OpReturnValue) { | ||||
| 		moduleCompiler.emit(nil, OpReturn) | ||||
| 	} | ||||
| 	// code optimization | ||||
| 	moduleCompiler.optimizeFunc(node) | ||||
|  | ||||
| 	compiledFunc := moduleCompiler.Bytecode().MainFunction | ||||
| 	compiledFunc.NumLocals = symbolTable.MaxSymbols() | ||||
|  | ||||
| 	c.storeCompiledModule(modulePath, compiledFunc) | ||||
|  | ||||
| 	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 { | ||||
| 		return c.parent.loadCompiledModule(moduleName) | ||||
| 		return c.parent.loadCompiledModule(modulePath) | ||||
| 	} | ||||
|  | ||||
| 	mod, ok = c.compiledModules[moduleName] | ||||
| 	mod, ok = c.compiledModules[modulePath] | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (c *Compiler) storeCompiledModule(moduleName string, module *objects.CompiledFunction) { | ||||
| func (c *Compiler) storeCompiledModule(modulePath string, module *objects.CompiledFunction) { | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| 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 | ||||
| const ( | ||||
| 	OpConstant         Opcode = iota // Load constant | ||||
| 	OpAdd                            // Add | ||||
| 	OpSub                            // Sub | ||||
| 	OpMul                            // Multiply | ||||
| 	OpDiv                            // Divide | ||||
| 	OpRem                            // Remainder | ||||
| 	OpBAnd                           // bitwise AND | ||||
| 	OpBOr                            // bitwise OR | ||||
| 	OpBXor                           // bitwise XOR | ||||
| 	OpBShiftLeft                     // bitwise shift left | ||||
| 	OpBShiftRight                    // bitwise shift right | ||||
| 	OpBAndNot                        // bitwise AND NOT | ||||
| 	OpBComplement                    // bitwise complement | ||||
| 	OpPop                            // Pop | ||||
| 	OpTrue                           // Push true | ||||
| 	OpFalse                          // Push false | ||||
| 	OpEqual                          // Equal == | ||||
| 	OpNotEqual                       // Not equal != | ||||
| 	OpGreaterThan                    // Greater than >= | ||||
| 	OpGreaterThanEqual               // Greater than or equal to >= | ||||
| 	OpMinus                          // Minus - | ||||
| 	OpLNot                           // Logical not ! | ||||
| 	OpJumpFalsy                      // Jump if falsy | ||||
| 	OpAndJump                        // Logical AND jump | ||||
| 	OpOrJump                         // Logical OR jump | ||||
| 	OpJump                           // Jump | ||||
| 	OpNull                           // Push null | ||||
| 	OpArray                          // Array object | ||||
| 	OpMap                            // Map object | ||||
| 	OpError                          // Error object | ||||
| 	OpImmutable                      // Immutable object | ||||
| 	OpIndex                          // Index operation | ||||
| 	OpSliceIndex                     // Slice operation | ||||
| 	OpCall                           // Call function | ||||
| 	OpReturn                         // Return | ||||
| 	OpReturnValue                    // Return value | ||||
| 	OpGetGlobal                      // Get global variable | ||||
| 	OpSetGlobal                      // Set global variable | ||||
| 	OpSetSelGlobal                   // Set global variable using selectors | ||||
| 	OpGetLocal                       // Get local variable | ||||
| 	OpSetLocal                       // Set local variable | ||||
| 	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 | ||||
| 	OpConstant      Opcode = iota // Load constant | ||||
| 	OpBComplement                 // bitwise complement | ||||
| 	OpPop                         // Pop | ||||
| 	OpTrue                        // Push true | ||||
| 	OpFalse                       // Push false | ||||
| 	OpEqual                       // Equal == | ||||
| 	OpNotEqual                    // Not equal != | ||||
| 	OpMinus                       // Minus - | ||||
| 	OpLNot                        // Logical not ! | ||||
| 	OpJumpFalsy                   // Jump if falsy | ||||
| 	OpAndJump                     // Logical AND jump | ||||
| 	OpOrJump                      // Logical OR jump | ||||
| 	OpJump                        // Jump | ||||
| 	OpNull                        // Push null | ||||
| 	OpArray                       // Array object | ||||
| 	OpMap                         // Map object | ||||
| 	OpError                       // Error object | ||||
| 	OpImmutable                   // Immutable object | ||||
| 	OpIndex                       // Index operation | ||||
| 	OpSliceIndex                  // Slice operation | ||||
| 	OpCall                        // Call function | ||||
| 	OpReturn                      // Return | ||||
| 	OpGetGlobal                   // Get global variable | ||||
| 	OpSetGlobal                   // Set global variable | ||||
| 	OpSetSelGlobal                // Set global variable using selectors | ||||
| 	OpGetLocal                    // Get local variable | ||||
| 	OpSetLocal                    // Set local variable | ||||
| 	OpDefineLocal                 // Define local variable | ||||
| 	OpSetSelLocal                 // Set local variable using selectors | ||||
| 	OpGetFreePtr                  // Get free variable pointer object | ||||
| 	OpGetFree                     // Get free variables | ||||
| 	OpSetFree                     // Set free variables | ||||
| 	OpGetLocalPtr                 // Get local variable as a pointer | ||||
| 	OpSetSelFree                  // Set free variables using selectors | ||||
| 	OpGetBuiltin                  // Get builtin function | ||||
| 	OpClosure                     // Push closure | ||||
| 	OpIteratorInit                // Iterator init | ||||
| 	OpIteratorNext                // Iterator next | ||||
| 	OpIteratorKey                 // Iterator key | ||||
| 	OpIteratorValue               // Iterator value | ||||
| 	OpBinaryOp                    // Binary Operation | ||||
| ) | ||||
|  | ||||
| // OpcodeNames is opcode names. | ||||
| var OpcodeNames = [...]string{ | ||||
| 	OpConstant:         "CONST", | ||||
| 	OpPop:              "POP", | ||||
| 	OpTrue:             "TRUE", | ||||
| 	OpFalse:            "FALSE", | ||||
| 	OpAdd:              "ADD", | ||||
| 	OpSub:              "SUB", | ||||
| 	OpMul:              "MUL", | ||||
| 	OpDiv:              "DIV", | ||||
| 	OpRem:              "REM", | ||||
| 	OpBAnd:             "AND", | ||||
| 	OpBOr:              "OR", | ||||
| 	OpBXor:             "XOR", | ||||
| 	OpBAndNot:          "ANDN", | ||||
| 	OpBShiftLeft:       "SHL", | ||||
| 	OpBShiftRight:      "SHR", | ||||
| 	OpBComplement:      "NEG", | ||||
| 	OpEqual:            "EQL", | ||||
| 	OpNotEqual:         "NEQ", | ||||
| 	OpGreaterThan:      "GTR", | ||||
| 	OpGreaterThanEqual: "GEQ", | ||||
| 	OpMinus:            "NEG", | ||||
| 	OpLNot:             "NOT", | ||||
| 	OpJumpFalsy:        "JMPF", | ||||
| 	OpAndJump:          "ANDJMP", | ||||
| 	OpOrJump:           "ORJMP", | ||||
| 	OpJump:             "JMP", | ||||
| 	OpNull:             "NULL", | ||||
| 	OpGetGlobal:        "GETG", | ||||
| 	OpSetGlobal:        "SETG", | ||||
| 	OpSetSelGlobal:     "SETSG", | ||||
| 	OpArray:            "ARR", | ||||
| 	OpMap:              "MAP", | ||||
| 	OpError:            "ERROR", | ||||
| 	OpImmutable:        "IMMUT", | ||||
| 	OpIndex:            "INDEX", | ||||
| 	OpSliceIndex:       "SLICE", | ||||
| 	OpCall:             "CALL", | ||||
| 	OpReturn:           "RET", | ||||
| 	OpReturnValue:      "RETVAL", | ||||
| 	OpGetLocal:         "GETL", | ||||
| 	OpSetLocal:         "SETL", | ||||
| 	OpDefineLocal:      "DEFL", | ||||
| 	OpSetSelLocal:      "SETSL", | ||||
| 	OpGetBuiltin:       "BUILTIN", | ||||
| 	OpGetBuiltinModule: "BLTMOD", | ||||
| 	OpClosure:          "CLOSURE", | ||||
| 	OpGetFree:          "GETF", | ||||
| 	OpSetFree:          "SETF", | ||||
| 	OpSetSelFree:       "SETSF", | ||||
| 	OpIteratorInit:     "ITER", | ||||
| 	OpIteratorNext:     "ITNXT", | ||||
| 	OpIteratorKey:      "ITKEY", | ||||
| 	OpIteratorValue:    "ITVAL", | ||||
| 	OpConstant:      "CONST", | ||||
| 	OpPop:           "POP", | ||||
| 	OpTrue:          "TRUE", | ||||
| 	OpFalse:         "FALSE", | ||||
| 	OpBComplement:   "NEG", | ||||
| 	OpEqual:         "EQL", | ||||
| 	OpNotEqual:      "NEQ", | ||||
| 	OpMinus:         "NEG", | ||||
| 	OpLNot:          "NOT", | ||||
| 	OpJumpFalsy:     "JMPF", | ||||
| 	OpAndJump:       "ANDJMP", | ||||
| 	OpOrJump:        "ORJMP", | ||||
| 	OpJump:          "JMP", | ||||
| 	OpNull:          "NULL", | ||||
| 	OpGetGlobal:     "GETG", | ||||
| 	OpSetGlobal:     "SETG", | ||||
| 	OpSetSelGlobal:  "SETSG", | ||||
| 	OpArray:         "ARR", | ||||
| 	OpMap:           "MAP", | ||||
| 	OpError:         "ERROR", | ||||
| 	OpImmutable:     "IMMUT", | ||||
| 	OpIndex:         "INDEX", | ||||
| 	OpSliceIndex:    "SLICE", | ||||
| 	OpCall:          "CALL", | ||||
| 	OpReturn:        "RET", | ||||
| 	OpGetLocal:      "GETL", | ||||
| 	OpSetLocal:      "SETL", | ||||
| 	OpDefineLocal:   "DEFL", | ||||
| 	OpSetSelLocal:   "SETSL", | ||||
| 	OpGetBuiltin:    "BUILTIN", | ||||
| 	OpClosure:       "CLOSURE", | ||||
| 	OpGetFreePtr:    "GETFP", | ||||
| 	OpGetFree:       "GETF", | ||||
| 	OpSetFree:       "SETF", | ||||
| 	OpGetLocalPtr:   "GETLP", | ||||
| 	OpSetSelFree:    "SETSF", | ||||
| 	OpIteratorInit:  "ITER", | ||||
| 	OpIteratorNext:  "ITNXT", | ||||
| 	OpIteratorKey:   "ITKEY", | ||||
| 	OpIteratorValue: "ITVAL", | ||||
| 	OpBinaryOp:      "BINARYOP", | ||||
| } | ||||
|  | ||||
| // OpcodeOperands is the number of operands. | ||||
| var OpcodeOperands = [...][]int{ | ||||
| 	OpConstant:         {2}, | ||||
| 	OpPop:              {}, | ||||
| 	OpTrue:             {}, | ||||
| 	OpFalse:            {}, | ||||
| 	OpAdd:              {}, | ||||
| 	OpSub:              {}, | ||||
| 	OpMul:              {}, | ||||
| 	OpDiv:              {}, | ||||
| 	OpRem:              {}, | ||||
| 	OpBAnd:             {}, | ||||
| 	OpBOr:              {}, | ||||
| 	OpBXor:             {}, | ||||
| 	OpBAndNot:          {}, | ||||
| 	OpBShiftLeft:       {}, | ||||
| 	OpBShiftRight:      {}, | ||||
| 	OpBComplement:      {}, | ||||
| 	OpEqual:            {}, | ||||
| 	OpNotEqual:         {}, | ||||
| 	OpGreaterThan:      {}, | ||||
| 	OpGreaterThanEqual: {}, | ||||
| 	OpMinus:            {}, | ||||
| 	OpLNot:             {}, | ||||
| 	OpJumpFalsy:        {2}, | ||||
| 	OpAndJump:          {2}, | ||||
| 	OpOrJump:           {2}, | ||||
| 	OpJump:             {2}, | ||||
| 	OpNull:             {}, | ||||
| 	OpGetGlobal:        {2}, | ||||
| 	OpSetGlobal:        {2}, | ||||
| 	OpSetSelGlobal:     {2, 1}, | ||||
| 	OpArray:            {2}, | ||||
| 	OpMap:              {2}, | ||||
| 	OpError:            {}, | ||||
| 	OpImmutable:        {}, | ||||
| 	OpIndex:            {}, | ||||
| 	OpSliceIndex:       {}, | ||||
| 	OpCall:             {1}, | ||||
| 	OpReturn:           {}, | ||||
| 	OpReturnValue:      {}, | ||||
| 	OpGetLocal:         {1}, | ||||
| 	OpSetLocal:         {1}, | ||||
| 	OpDefineLocal:      {1}, | ||||
| 	OpSetSelLocal:      {1, 1}, | ||||
| 	OpGetBuiltin:       {1}, | ||||
| 	OpGetBuiltinModule: {}, | ||||
| 	OpClosure:          {2, 1}, | ||||
| 	OpGetFree:          {1}, | ||||
| 	OpSetFree:          {1}, | ||||
| 	OpSetSelFree:       {1, 1}, | ||||
| 	OpIteratorInit:     {}, | ||||
| 	OpIteratorNext:     {}, | ||||
| 	OpIteratorKey:      {}, | ||||
| 	OpIteratorValue:    {}, | ||||
| 	OpConstant:      {2}, | ||||
| 	OpPop:           {}, | ||||
| 	OpTrue:          {}, | ||||
| 	OpFalse:         {}, | ||||
| 	OpBComplement:   {}, | ||||
| 	OpEqual:         {}, | ||||
| 	OpNotEqual:      {}, | ||||
| 	OpMinus:         {}, | ||||
| 	OpLNot:          {}, | ||||
| 	OpJumpFalsy:     {2}, | ||||
| 	OpAndJump:       {2}, | ||||
| 	OpOrJump:        {2}, | ||||
| 	OpJump:          {2}, | ||||
| 	OpNull:          {}, | ||||
| 	OpGetGlobal:     {2}, | ||||
| 	OpSetGlobal:     {2}, | ||||
| 	OpSetSelGlobal:  {2, 1}, | ||||
| 	OpArray:         {2}, | ||||
| 	OpMap:           {2}, | ||||
| 	OpError:         {}, | ||||
| 	OpImmutable:     {}, | ||||
| 	OpIndex:         {}, | ||||
| 	OpSliceIndex:    {}, | ||||
| 	OpCall:          {1}, | ||||
| 	OpReturn:        {1}, | ||||
| 	OpGetLocal:      {1}, | ||||
| 	OpSetLocal:      {1}, | ||||
| 	OpDefineLocal:   {1}, | ||||
| 	OpSetSelLocal:   {1, 1}, | ||||
| 	OpGetBuiltin:    {1}, | ||||
| 	OpClosure:       {2, 1}, | ||||
| 	OpGetFreePtr:    {1}, | ||||
| 	OpGetFree:       {1}, | ||||
| 	OpSetFree:       {1}, | ||||
| 	OpGetLocalPtr:   {1}, | ||||
| 	OpSetSelFree:    {1, 1}, | ||||
| 	OpIteratorInit:  {}, | ||||
| 	OpIteratorNext:  {}, | ||||
| 	OpIteratorKey:   {}, | ||||
| 	OpIteratorValue: {}, | ||||
| 	OpBinaryOp:      {1}, | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| 		} | ||||
|  | ||||
| 		if !t.block { | ||||
| 			depth++ | ||||
| 		} | ||||
| 		depth++ | ||||
|  | ||||
| 		// if symbol is defined in parent table and if it's not global/builtin | ||||
| 		// 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 | ||||
| } | ||||
|  | ||||
| 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. | ||||
| // Use GetBuiltinFunctions instead of accessing Builtins directly. | ||||
| var Builtins = []BuiltinFunction{ | ||||
| 	{ | ||||
| 		Name:  "print", | ||||
| 		Value: builtinPrint, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "printf", | ||||
| 		Value: builtinPrintf, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "sprintf", | ||||
| 		Value: builtinSprintf, | ||||
| 	}, | ||||
| var Builtins = []*BuiltinFunction{ | ||||
| 	{ | ||||
| 		Name:  "len", | ||||
| 		Value: builtinLen, | ||||
| @@ -95,6 +83,10 @@ var Builtins = []BuiltinFunction{ | ||||
| 		Name:  "is_immutable_map", | ||||
| 		Value: builtinIsImmutableMap, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_iterable", | ||||
| 		Value: builtinIsIterable, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_time", | ||||
| 		Value: builtinIsTime, | ||||
| @@ -115,50 +107,8 @@ var Builtins = []BuiltinFunction{ | ||||
| 		Name:  "is_callable", | ||||
| 		Value: builtinIsCallable, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "to_json", | ||||
| 		Value: builtinToJSON, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "from_json", | ||||
| 		Value: builtinFromJSON, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "type_name", | ||||
| 		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 | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| type Closure struct { | ||||
| 	Fn   *CompiledFunction | ||||
| 	Free []*Object | ||||
| 	Free []*ObjectPtr | ||||
| } | ||||
|  | ||||
| // 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 { | ||||
| 	return &Closure{ | ||||
| 		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 { | ||||
| 	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 | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| @@ -158,8 +159,8 @@ func ToTime(o Object) (v time.Time, ok bool) { | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // objectToInterface attempts to convert an object o to an interface{} value | ||||
| func objectToInterface(o Object) (res interface{}) { | ||||
| // ToInterface attempts to convert an object o to an interface{} value | ||||
| func ToInterface(o Object) (res interface{}) { | ||||
| 	switch o := o.(type) { | ||||
| 	case *Int: | ||||
| 		res = o.Value | ||||
| @@ -176,13 +177,29 @@ func objectToInterface(o Object) (res interface{}) { | ||||
| 	case *Array: | ||||
| 		res = make([]interface{}, len(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: | ||||
| 		res = make(map[string]interface{}) | ||||
| 		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: | ||||
| 		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. | ||||
| type UserFunction struct { | ||||
| 	Name  string | ||||
| 	Value CallableFunc | ||||
| 	Name       string | ||||
| 	Value      CallableFunc | ||||
| 	EncodingID string | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| 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. | ||||
| type Frame struct { | ||||
| 	fn          *objects.CompiledFunction | ||||
| 	freeVars    []*objects.Object | ||||
| 	freeVars    []*objects.ObjectPtr | ||||
| 	ip          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 ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/d5/tengo/compiler" | ||||
| 	"github.com/d5/tengo/objects" | ||||
| @@ -12,26 +13,39 @@ import ( | ||||
| // Compiled is a compiled instance of the user script. | ||||
| // Use Script.Compile() to create Compiled object. | ||||
| type Compiled struct { | ||||
| 	symbolTable *compiler.SymbolTable | ||||
| 	machine     *runtime.VM | ||||
| 	globalIndexes map[string]int // global symbol name to index | ||||
| 	bytecode      *compiler.Bytecode | ||||
| 	globals       []objects.Object | ||||
| 	maxAllocs     int64 | ||||
| 	lock          sync.RWMutex | ||||
| } | ||||
|  | ||||
| // Run executes the compiled script in the virtual machine. | ||||
| 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. | ||||
| 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) | ||||
|  | ||||
| 	go func() { | ||||
| 		ch <- c.machine.Run() | ||||
| 		ch <- v.Run() | ||||
| 	}() | ||||
|  | ||||
| 	select { | ||||
| 	case <-ctx.Done(): | ||||
| 		c.machine.Abort() | ||||
| 		v.Abort() | ||||
| 		<-ch | ||||
| 		err = ctx.Err() | ||||
| 	case err = <-ch: | ||||
| @@ -40,30 +54,58 @@ func (c *Compiled) RunContext(ctx context.Context) (err error) { | ||||
| 	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. | ||||
| 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 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	v := c.machine.Globals()[symbol.Index] | ||||
| 	v := c.globals[idx] | ||||
| 	if v == nil { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	return *v != objects.UndefinedValue | ||||
| 	return v != objects.UndefinedValue | ||||
| } | ||||
|  | ||||
| // Get returns a variable identified by the name. | ||||
| func (c *Compiled) Get(name string) *Variable { | ||||
| 	value := &objects.UndefinedValue | ||||
| 	c.lock.RLock() | ||||
| 	defer c.lock.RUnlock() | ||||
|  | ||||
| 	symbol, _, ok := c.symbolTable.Resolve(name) | ||||
| 	if ok && symbol.Scope == compiler.ScopeGlobal { | ||||
| 		value = c.machine.Globals()[symbol.Index] | ||||
| 	value := objects.UndefinedValue | ||||
|  | ||||
| 	if idx, ok := c.globalIndexes[name]; ok { | ||||
| 		value = c.globals[idx] | ||||
| 		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. | ||||
| func (c *Compiled) GetAll() []*Variable { | ||||
| 	var vars []*Variable | ||||
| 	for _, name := range c.symbolTable.Names() { | ||||
| 		symbol, _, ok := c.symbolTable.Resolve(name) | ||||
| 		if ok && symbol.Scope == compiler.ScopeGlobal { | ||||
| 			value := c.machine.Globals()[symbol.Index] | ||||
| 			if value == nil { | ||||
| 				value = &objects.UndefinedValue | ||||
| 			} | ||||
| 	c.lock.RLock() | ||||
| 	defer c.lock.RUnlock() | ||||
|  | ||||
| 			vars = append(vars, &Variable{ | ||||
| 				name:  name, | ||||
| 				value: value, | ||||
| 			}) | ||||
| 	var vars []*Variable | ||||
|  | ||||
| 	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 | ||||
| @@ -97,17 +140,20 @@ func (c *Compiled) GetAll() []*Variable { | ||||
| // 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. | ||||
| func (c *Compiled) Set(name string, value interface{}) error { | ||||
| 	c.lock.Lock() | ||||
| 	defer c.lock.Unlock() | ||||
|  | ||||
| 	obj, err := objects.FromInterface(value) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	symbol, _, ok := c.symbolTable.Resolve(name) | ||||
| 	if !ok || symbol.Scope != compiler.ScopeGlobal { | ||||
| 	idx, ok := c.globalIndexes[name] | ||||
| 	if !ok { | ||||
| 		return fmt.Errorf("'%s' is not defined", name) | ||||
| 	} | ||||
|  | ||||
| 	c.machine.Globals()[symbol.Index] = &obj | ||||
| 	c.globals[idx] = obj | ||||
|  | ||||
| 	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. | ||||
| type Script struct { | ||||
| 	variables        map[string]*Variable | ||||
| 	builtinFuncs     []objects.Object | ||||
| 	builtinModules   map[string]*objects.Object | ||||
| 	userModuleLoader compiler.ModuleLoader | ||||
| 	modules          *objects.ModuleMap | ||||
| 	input            []byte | ||||
| 	maxAllocs        int64 | ||||
| 	maxConstObjects  int | ||||
| 	enableFileImport bool | ||||
| } | ||||
|  | ||||
| // New creates a Script instance with an input script. | ||||
| func New(input []byte) *Script { | ||||
| 	return &Script{ | ||||
| 		variables: make(map[string]*Variable), | ||||
| 		input:     input, | ||||
| 		variables:       make(map[string]*Variable), | ||||
| 		input:           input, | ||||
| 		maxAllocs:       -1, | ||||
| 		maxConstObjects: -1, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -37,7 +40,7 @@ func (s *Script) Add(name string, value interface{}) error { | ||||
|  | ||||
| 	s.variables[name] = &Variable{ | ||||
| 		name:  name, | ||||
| 		value: &obj, | ||||
| 		value: obj, | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| @@ -55,38 +58,31 @@ func (s *Script) Remove(name string) bool { | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // SetBuiltinFunctions allows to define builtin functions. | ||||
| func (s *Script) SetBuiltinFunctions(funcs []*objects.BuiltinFunction) { | ||||
| 	if funcs != nil { | ||||
| 		s.builtinFuncs = make([]objects.Object, len(funcs)) | ||||
| 		for idx, fn := range funcs { | ||||
| 			s.builtinFuncs[idx] = fn | ||||
| 		} | ||||
| 	} else { | ||||
| 		s.builtinFuncs = []objects.Object{} | ||||
| 	} | ||||
| // SetImports sets import modules. | ||||
| func (s *Script) SetImports(modules *objects.ModuleMap) { | ||||
| 	s.modules = modules | ||||
| } | ||||
|  | ||||
| // SetBuiltinModules allows to define builtin modules. | ||||
| func (s *Script) SetBuiltinModules(modules map[string]*objects.ImmutableMap) { | ||||
| 	if modules != nil { | ||||
| 		s.builtinModules = make(map[string]*objects.Object, len(modules)) | ||||
| 		for k, mod := range modules { | ||||
| 			s.builtinModules[k] = objectPtr(mod) | ||||
| 		} | ||||
| 	} else { | ||||
| 		s.builtinModules = map[string]*objects.Object{} | ||||
| 	} | ||||
| // SetMaxAllocs sets the maximum number of objects allocations during the run time. | ||||
| // Compiled script will return runtime.ErrObjectAllocLimit error if it exceeds this limit. | ||||
| func (s *Script) SetMaxAllocs(n int64) { | ||||
| 	s.maxAllocs = n | ||||
| } | ||||
|  | ||||
| // SetUserModuleLoader sets the user module loader for the compiler. | ||||
| func (s *Script) SetUserModuleLoader(loader compiler.ModuleLoader) { | ||||
| 	s.userModuleLoader = loader | ||||
| // SetMaxConstObjects sets the maximum number of objects in the compiled constants. | ||||
| func (s *Script) SetMaxConstObjects(n int) { | ||||
| 	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. | ||||
| func (s *Script) Compile() (*Compiled, error) { | ||||
| 	symbolTable, builtinModules, globals, err := s.prepCompile() | ||||
| 	symbolTable, globals, err := s.prepCompile() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -100,19 +96,41 @@ func (s *Script) Compile() (*Compiled, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	c := compiler.NewCompiler(srcFile, symbolTable, nil, builtinModules, nil) | ||||
|  | ||||
| 	if s.userModuleLoader != nil { | ||||
| 		c.SetModuleLoader(s.userModuleLoader) | ||||
| 	} | ||||
|  | ||||
| 	c := compiler.NewCompiler(srcFile, symbolTable, nil, s.modules, nil) | ||||
| 	c.EnableFileImport(s.enableFileImport) | ||||
| 	if err := c.Compile(file); err != nil { | ||||
| 		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{ | ||||
| 		symbolTable: symbolTable, | ||||
| 		machine:     runtime.NewVM(c.Bytecode(), globals, s.builtinFuncs, s.builtinModules), | ||||
| 		globalIndexes: globalIndexes, | ||||
| 		bytecode:      bytecode, | ||||
| 		globals:       globals, | ||||
| 		maxAllocs:     s.maxAllocs, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| @@ -141,39 +159,18 @@ func (s *Script) RunContext(ctx context.Context) (compiled *Compiled, err error) | ||||
| 	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 | ||||
| 	for name := range s.variables { | ||||
| 		names = append(names, name) | ||||
| 	} | ||||
|  | ||||
| 	symbolTable = compiler.NewSymbolTable() | ||||
|  | ||||
| 	if s.builtinFuncs == nil { | ||||
| 		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, | ||||
| 			} | ||||
| 		} | ||||
| 	for idx, fn := range objects.Builtins { | ||||
| 		symbolTable.DefineBuiltin(idx, fn.Name) | ||||
| 	} | ||||
|  | ||||
| 	if s.builtinModules == nil { | ||||
| 		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) | ||||
| 	globals = make([]objects.Object, runtime.GlobalsSize) | ||||
|  | ||||
| 	for idx, name := range names { | ||||
| 		symbol := symbolTable.Define(name) | ||||
| @@ -195,7 +192,3 @@ func (s *Script) copyVariables() map[string]*Variable { | ||||
|  | ||||
| 	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. | ||||
| type Variable struct { | ||||
| 	name  string | ||||
| 	value *objects.Object | ||||
| 	value objects.Object | ||||
| } | ||||
|  | ||||
| // NewVariable creates a Variable. | ||||
| @@ -21,7 +21,7 @@ func NewVariable(name string, value interface{}) (*Variable, error) { | ||||
|  | ||||
| 	return &Variable{ | ||||
| 		name:  name, | ||||
| 		value: &obj, | ||||
| 		value: obj, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| @@ -32,18 +32,18 @@ func (v *Variable) Name() string { | ||||
|  | ||||
| // Value returns an empty interface of the variable value. | ||||
| func (v *Variable) Value() interface{} { | ||||
| 	return objectToInterface(*v.value) | ||||
| 	return objects.ToInterface(v.value) | ||||
| } | ||||
|  | ||||
| // ValueType returns the name of the value type. | ||||
| func (v *Variable) ValueType() string { | ||||
| 	return (*v.value).TypeName() | ||||
| 	return v.value.TypeName() | ||||
| } | ||||
|  | ||||
| // Int returns int value of the variable value. | ||||
| // It returns 0 if the value is not convertible to int. | ||||
| func (v *Variable) Int() int { | ||||
| 	c, _ := objects.ToInt(*v.value) | ||||
| 	c, _ := objects.ToInt(v.value) | ||||
|  | ||||
| 	return c | ||||
| } | ||||
| @@ -51,7 +51,7 @@ func (v *Variable) Int() int { | ||||
| // Int64 returns int64 value of the variable value. | ||||
| // It returns 0 if the value is not convertible to int64. | ||||
| func (v *Variable) Int64() int64 { | ||||
| 	c, _ := objects.ToInt64(*v.value) | ||||
| 	c, _ := objects.ToInt64(v.value) | ||||
|  | ||||
| 	return c | ||||
| } | ||||
| @@ -59,7 +59,7 @@ func (v *Variable) Int64() int64 { | ||||
| // Float returns float64 value of the variable value. | ||||
| // It returns 0.0 if the value is not convertible to float64. | ||||
| func (v *Variable) Float() float64 { | ||||
| 	c, _ := objects.ToFloat64(*v.value) | ||||
| 	c, _ := objects.ToFloat64(v.value) | ||||
|  | ||||
| 	return c | ||||
| } | ||||
| @@ -67,7 +67,7 @@ func (v *Variable) Float() float64 { | ||||
| // Char returns rune value of the variable value. | ||||
| // It returns 0 if the value is not convertible to rune. | ||||
| func (v *Variable) Char() rune { | ||||
| 	c, _ := objects.ToRune(*v.value) | ||||
| 	c, _ := objects.ToRune(v.value) | ||||
|  | ||||
| 	return c | ||||
| } | ||||
| @@ -75,7 +75,7 @@ func (v *Variable) Char() rune { | ||||
| // Bool returns bool value of the variable value. | ||||
| // It returns 0 if the value is not convertible to bool. | ||||
| func (v *Variable) Bool() bool { | ||||
| 	c, _ := objects.ToBool(*v.value) | ||||
| 	c, _ := objects.ToBool(v.value) | ||||
|  | ||||
| 	return c | ||||
| } | ||||
| @@ -83,11 +83,11 @@ func (v *Variable) Bool() bool { | ||||
| // Array returns []interface value of the variable value. | ||||
| // It returns 0 if the value is not convertible to []interface. | ||||
| func (v *Variable) Array() []interface{} { | ||||
| 	switch val := (*v.value).(type) { | ||||
| 	switch val := v.value.(type) { | ||||
| 	case *objects.Array: | ||||
| 		var arr []interface{} | ||||
| 		for _, e := range val.Value { | ||||
| 			arr = append(arr, objectToInterface(e)) | ||||
| 			arr = append(arr, objects.ToInterface(e)) | ||||
| 		} | ||||
| 		return arr | ||||
| 	} | ||||
| @@ -98,11 +98,11 @@ func (v *Variable) Array() []interface{} { | ||||
| // Map returns map[string]interface{} value of the variable value. | ||||
| // It returns 0 if the value is not convertible to map[string]interface{}. | ||||
| func (v *Variable) Map() map[string]interface{} { | ||||
| 	switch val := (*v.value).(type) { | ||||
| 	switch val := v.value.(type) { | ||||
| 	case *objects.Map: | ||||
| 		kv := make(map[string]interface{}) | ||||
| 		for mk, mv := range val.Value { | ||||
| 			kv[mk] = objectToInterface(mv) | ||||
| 			kv[mk] = objects.ToInterface(mv) | ||||
| 		} | ||||
| 		return kv | ||||
| 	} | ||||
| @@ -113,7 +113,7 @@ func (v *Variable) Map() map[string]interface{} { | ||||
| // String returns string value of the variable value. | ||||
| // It returns 0 if the value is not convertible to string. | ||||
| func (v *Variable) String() string { | ||||
| 	c, _ := objects.ToString(*v.value) | ||||
| 	c, _ := objects.ToString(v.value) | ||||
|  | ||||
| 	return c | ||||
| } | ||||
| @@ -121,7 +121,7 @@ func (v *Variable) String() string { | ||||
| // Bytes returns a byte slice of the variable value. | ||||
| // It returns nil if the value is not convertible to byte slice. | ||||
| func (v *Variable) Bytes() []byte { | ||||
| 	c, _ := objects.ToByteSlice(*v.value) | ||||
| 	c, _ := objects.ToByteSlice(v.value) | ||||
|  | ||||
| 	return c | ||||
| } | ||||
| @@ -129,7 +129,7 @@ func (v *Variable) Bytes() []byte { | ||||
| // Error returns an error if the underlying value is error object. | ||||
| // If not, this returns nil. | ||||
| func (v *Variable) Error() error { | ||||
| 	err, ok := (*v.value).(*objects.Error) | ||||
| 	err, ok := v.value.(*objects.Error) | ||||
| 	if ok { | ||||
| 		return errors.New(err.String()) | ||||
| 	} | ||||
| @@ -140,10 +140,10 @@ func (v *Variable) Error() error { | ||||
| // Object returns an underlying Object of the variable value. | ||||
| // Note that returned Object is a copy of an actual Object used in the script. | ||||
| func (v *Variable) Object() objects.Object { | ||||
| 	return *v.value | ||||
| 	return v.value | ||||
| } | ||||
|  | ||||
| // IsUndefined returns true if the underlying value is undefined. | ||||
| 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/bwmarrin/discordgo v0.19.0 | ||||
| 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/stdlib | ||||
| github.com/d5/tengo/compiler | ||||
| github.com/d5/tengo/compiler/parser | ||||
| github.com/d5/tengo/compiler/source | ||||
| github.com/d5/tengo/objects | ||||
| github.com/d5/tengo/runtime | ||||
| github.com/d5/tengo | ||||
| github.com/d5/tengo/stdlib/json | ||||
| github.com/d5/tengo/compiler/ast | ||||
| github.com/d5/tengo/compiler/token | ||||
| github.com/d5/tengo/compiler/scanner | ||||
|   | ||||
		Reference in New Issue
	
	Block a user