forked from lug/matterbridge
		
	Compare commits
	
		
			17 Commits
		
	
	
		
			v1.14.0-rc
			...
			v1.14.1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					858e16d34f | ||
| 
						 | 
					a60e62efb1 | ||
| 
						 | 
					97f9d4be67 | ||
| 
						 | 
					fa4eec41f7 | ||
| 
						 | 
					77516c97db | ||
| 
						 | 
					cba01f0865 | ||
| 
						 | 
					8b754017ca | ||
| 
						 | 
					a27600046e | ||
| 
						 | 
					fb2667631d | ||
| 
						 | 
					b638f7037a | ||
| 
						 | 
					74699a8262 | ||
| 
						 | 
					eabf2a4582 | ||
| 
						 | 
					325d62b41c | ||
| 
						 | 
					e955a056e2 | ||
| 
						 | 
					723f8c5fd5 | ||
| 
						 | 
					a16137f53f | ||
| 
						 | 
					d60b8b97f9 | 
@@ -158,7 +158,6 @@ linters-settings:
 | 
			
		||||
      - regexpMust
 | 
			
		||||
      - singleCaseSwitch
 | 
			
		||||
      - sloppyLen
 | 
			
		||||
      - sloppyReassign
 | 
			
		||||
      - switchTrue
 | 
			
		||||
      - typeSwitchVar
 | 
			
		||||
      - typeUnparen
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -12,6 +12,7 @@ git:
 | 
			
		||||
env:
 | 
			
		||||
  global:
 | 
			
		||||
    - GOOS=linux GOARCH=amd64
 | 
			
		||||
    - GO111MODULE=on
 | 
			
		||||
    - GOLANGCI_VERSION="v1.14.0"
 | 
			
		||||
 | 
			
		||||
matrix:
 | 
			
		||||
@@ -36,10 +37,17 @@ before_script:
 | 
			
		||||
  - ./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
 | 
			
		||||
 | 
			
		||||
@@ -47,6 +55,10 @@ after_script:
 | 
			
		||||
  # Upload test coverage to CodeClimate.
 | 
			
		||||
  - ./cc-test-reporter after-build --exit-code ${TRAVIS_TEST_RESULT}
 | 
			
		||||
 | 
			
		||||
branches:
 | 
			
		||||
  only:
 | 
			
		||||
    - master
 | 
			
		||||
 | 
			
		||||
deploy:
 | 
			
		||||
  on:
 | 
			
		||||
     all_branches: true
 | 
			
		||||
 
 | 
			
		||||
@@ -88,6 +88,7 @@
 | 
			
		||||
* [Minecraft](https://github.com/elytra/MatterLink)
 | 
			
		||||
* [Reddit](https://github.com/bonehurtingjuice/mattereddit)
 | 
			
		||||
* [Facebook messenger](https://github.com/VictorNine/fbridge)
 | 
			
		||||
* [Discourse](https://github.com/DeclanHoare/matterbabble)
 | 
			
		||||
 | 
			
		||||
### API
 | 
			
		||||
The API is very basic at the moment.   
 | 
			
		||||
@@ -99,6 +100,7 @@ Used by the projects below. Feel free to make a PR to add your project to this l
 | 
			
		||||
* [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot)
 | 
			
		||||
* [Mattereddit](https://github.com/bonehurtingjuice/mattereddit) (Reddit chat support)
 | 
			
		||||
* [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support)
 | 
			
		||||
* [matterbabble](https://github.com/DeclanHoare/matterbabble) (Discourse support)
 | 
			
		||||
 | 
			
		||||
## Chat with us
 | 
			
		||||
 | 
			
		||||
@@ -121,7 +123,7 @@ See https://github.com/42wim/matterbridge/wiki
 | 
			
		||||
 | 
			
		||||
## Installing
 | 
			
		||||
### Binaries
 | 
			
		||||
* Latest stable release [v1.13.1](https://github.com/42wim/matterbridge/releases/latest)
 | 
			
		||||
* Latest stable release [v1.14.1](https://github.com/42wim/matterbridge/releases/latest)
 | 
			
		||||
* Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)
 | 
			
		||||
 | 
			
		||||
### Packages
 | 
			
		||||
@@ -247,6 +249,8 @@ See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ)
 | 
			
		||||
* [mattermost-plugin](https://github.com/matterbridge/mattermost-plugin) - Run matterbridge as a plugin in mattermost
 | 
			
		||||
* [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot)
 | 
			
		||||
* [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support)
 | 
			
		||||
* [isla](https://github.com/alphachung/isla) (Bot for Discord-Telegram groups used alongside matterbridge)
 | 
			
		||||
* [matterbabble](https://github.com/DeclanHoare/matterbabble) (Connect Discourse threads to Matterbridge)
 | 
			
		||||
 | 
			
		||||
## Articles
 | 
			
		||||
* [matterbridge on kubernetes](https://medium.freecodecamp.org/using-kubernetes-to-deploy-a-chat-gateway-or-when-technology-works-like-its-supposed-to-a169a8cd69a3)
 | 
			
		||||
 
 | 
			
		||||
@@ -178,7 +178,10 @@ func ClipMessage(text string, length int) string {
 | 
			
		||||
 | 
			
		||||
func ParseMarkdown(input string) string {
 | 
			
		||||
	md := markdown.New(markdown.XHTMLOutput(true), markdown.Breaks(true))
 | 
			
		||||
	return (md.RenderToString([]byte(input)))
 | 
			
		||||
	res := md.RenderToString([]byte(input))
 | 
			
		||||
	res = strings.TrimPrefix(res, "<p>")
 | 
			
		||||
	res = strings.TrimSuffix(res, "</p>\n")
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConvertWebPToPNG convert input data (which should be WebP format to PNG format)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package brocketchat
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge"
 | 
			
		||||
@@ -85,14 +86,14 @@ func (b *Brocketchat) JoinChannel(channel config.ChannelInfo) error {
 | 
			
		||||
	if b.c == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	id, err := b.c.GetChannelId(channel.Name)
 | 
			
		||||
	id, err := b.c.GetChannelId(strings.TrimPrefix(channel.Name, "#"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	b.Lock()
 | 
			
		||||
	b.channelMap[id] = channel.Name
 | 
			
		||||
	b.Unlock()
 | 
			
		||||
	mychannel := &models.Channel{ID: id, Name: channel.Name}
 | 
			
		||||
	mychannel := &models.Channel{ID: id, Name: strings.TrimPrefix(channel.Name, "#")}
 | 
			
		||||
	if err := b.c.JoinChannel(id); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -103,6 +104,8 @@ func (b *Brocketchat) JoinChannel(channel config.ChannelInfo) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Brocketchat) Send(msg config.Message) (string, error) {
 | 
			
		||||
	// strip the # if people has set this
 | 
			
		||||
	msg.Channel = strings.TrimPrefix(msg.Channel, "#")
 | 
			
		||||
	channel := &models.Channel{ID: b.getChannelID(msg.Channel), Name: msg.Channel}
 | 
			
		||||
 | 
			
		||||
	// Delete message
 | 
			
		||||
@@ -131,6 +134,8 @@ func (b *Brocketchat) Send(msg config.Message) (string, error) {
 | 
			
		||||
	// Upload a file if it exists
 | 
			
		||||
	if msg.Extra != nil {
 | 
			
		||||
		for _, rmsg := range helper.HandleExtra(&msg, b.General) {
 | 
			
		||||
			// strip the # if people has set this
 | 
			
		||||
			rmsg.Channel = strings.TrimPrefix(rmsg.Channel, "#")
 | 
			
		||||
			smsg := &models.Message{
 | 
			
		||||
				RoomID: b.getChannelID(rmsg.Channel),
 | 
			
		||||
				Msg:    rmsg.Username + rmsg.Text,
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ func (b *Bslack) handleSlack() {
 | 
			
		||||
		message.Text = html.UnescapeString(message.Text)
 | 
			
		||||
 | 
			
		||||
		// Add the avatar
 | 
			
		||||
		message.Avatar = b.getAvatar(message.UserID)
 | 
			
		||||
		message.Avatar = b.users.getAvatar(message.UserID)
 | 
			
		||||
 | 
			
		||||
		b.Log.Debugf("<= Message is %#v", message)
 | 
			
		||||
		b.Remote <- *message
 | 
			
		||||
@@ -75,20 +75,17 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) {
 | 
			
		||||
			// When we join a channel we update the full list of users as
 | 
			
		||||
			// well as the information for the channel that we joined as this
 | 
			
		||||
			// should now tell that we are a member of it.
 | 
			
		||||
			b.channelsMutex.Lock()
 | 
			
		||||
			b.channelsByID[ev.Channel.ID] = &ev.Channel
 | 
			
		||||
			b.channelsByName[ev.Channel.Name] = &ev.Channel
 | 
			
		||||
			b.channelsMutex.Unlock()
 | 
			
		||||
			b.channels.registerChannel(ev.Channel)
 | 
			
		||||
		case *slack.ConnectedEvent:
 | 
			
		||||
			b.si = ev.Info
 | 
			
		||||
			b.populateChannels(true)
 | 
			
		||||
			b.populateUsers(true)
 | 
			
		||||
			b.channels.populateChannels(true)
 | 
			
		||||
			b.users.populateUsers(true)
 | 
			
		||||
		case *slack.InvalidAuthEvent:
 | 
			
		||||
			b.Log.Fatalf("Invalid Token %#v", ev)
 | 
			
		||||
		case *slack.ConnectionErrorEvent:
 | 
			
		||||
			b.Log.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj)
 | 
			
		||||
		case *slack.MemberJoinedChannelEvent:
 | 
			
		||||
			b.populateUser(ev.User)
 | 
			
		||||
			b.users.populateUser(ev.User)
 | 
			
		||||
		case *slack.LatencyReport:
 | 
			
		||||
			continue
 | 
			
		||||
		default:
 | 
			
		||||
@@ -210,7 +207,7 @@ func (b *Bslack) handleStatusEvent(ev *slack.MessageEvent, rmsg *config.Message)
 | 
			
		||||
		rmsg.Username = sSystemUser
 | 
			
		||||
		rmsg.Event = config.EventJoinLeave
 | 
			
		||||
	case sChannelTopic, sChannelPurpose:
 | 
			
		||||
		b.populateChannels(false)
 | 
			
		||||
		b.channels.populateChannels(false)
 | 
			
		||||
		rmsg.Event = config.EventTopicChange
 | 
			
		||||
	case sMessageChanged:
 | 
			
		||||
		rmsg.Text = ev.SubMessage.Text
 | 
			
		||||
@@ -266,7 +263,7 @@ func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) handleTypingEvent(ev *slack.UserTypingEvent) (*config.Message, error) {
 | 
			
		||||
	channelInfo, err := b.getChannelByID(ev.Channel)
 | 
			
		||||
	channelInfo, err := b.channels.getChannelByID(ev.Channel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -316,36 +313,7 @@ func (b *Bslack) handleGetChannelMembers(rmsg *config.Message) bool {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cMembers := config.ChannelMembers{}
 | 
			
		||||
 | 
			
		||||
	b.channelMembersMutex.RLock()
 | 
			
		||||
 | 
			
		||||
	for channelID, members := range b.channelMembers {
 | 
			
		||||
		for _, member := range members {
 | 
			
		||||
			channelName := ""
 | 
			
		||||
			userName := ""
 | 
			
		||||
			userNick := ""
 | 
			
		||||
			user := b.getUser(member)
 | 
			
		||||
			if user != nil {
 | 
			
		||||
				userName = user.Name
 | 
			
		||||
				userNick = user.Profile.DisplayName
 | 
			
		||||
			}
 | 
			
		||||
			channel, _ := b.getChannelByID(channelID)
 | 
			
		||||
			if channel != nil {
 | 
			
		||||
				channelName = channel.Name
 | 
			
		||||
			}
 | 
			
		||||
			cMember := config.ChannelMember{
 | 
			
		||||
				Username:    userName,
 | 
			
		||||
				Nick:        userNick,
 | 
			
		||||
				UserID:      member,
 | 
			
		||||
				ChannelID:   channelID,
 | 
			
		||||
				ChannelName: channelName,
 | 
			
		||||
			}
 | 
			
		||||
			cMembers = append(cMembers, cMember)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.channelMembersMutex.RUnlock()
 | 
			
		||||
	cMembers := b.channels.getChannelMembers(b.users)
 | 
			
		||||
 | 
			
		||||
	extra := make(map[string][]interface{})
 | 
			
		||||
	extra[config.EventGetChannelMembers] = append(extra[config.EventGetChannelMembers], cMembers)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
package bslack
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
@@ -9,225 +8,14 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/nlopes/slack"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) getUser(id string) *slack.User {
 | 
			
		||||
	b.usersMutex.RLock()
 | 
			
		||||
	user, ok := b.users[id]
 | 
			
		||||
	b.usersMutex.RUnlock()
 | 
			
		||||
	if ok {
 | 
			
		||||
		return user
 | 
			
		||||
	}
 | 
			
		||||
	b.populateUser(id)
 | 
			
		||||
	b.usersMutex.RLock()
 | 
			
		||||
	defer b.usersMutex.RUnlock()
 | 
			
		||||
 | 
			
		||||
	return b.users[id]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) getUsername(id string) string {
 | 
			
		||||
	if user := b.getUser(id); user != nil {
 | 
			
		||||
		if user.Profile.DisplayName != "" {
 | 
			
		||||
			return user.Profile.DisplayName
 | 
			
		||||
		}
 | 
			
		||||
		return user.Name
 | 
			
		||||
	}
 | 
			
		||||
	b.Log.Warnf("Could not find user with ID '%s'", id)
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) getAvatar(id string) string {
 | 
			
		||||
	if user := b.getUser(id); user != nil {
 | 
			
		||||
		return user.Profile.Image48
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) getChannel(channel string) (*slack.Channel, error) {
 | 
			
		||||
	if strings.HasPrefix(channel, "ID:") {
 | 
			
		||||
		return b.getChannelByID(strings.TrimPrefix(channel, "ID:"))
 | 
			
		||||
	}
 | 
			
		||||
	return b.getChannelByName(channel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) getChannelByName(name string) (*slack.Channel, error) {
 | 
			
		||||
	return b.getChannelBy(name, b.channelsByName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) getChannelByID(ID string) (*slack.Channel, error) {
 | 
			
		||||
	return b.getChannelBy(ID, b.channelsByID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) getChannelBy(lookupKey string, lookupMap map[string]*slack.Channel) (*slack.Channel, error) {
 | 
			
		||||
	b.channelsMutex.RLock()
 | 
			
		||||
	defer b.channelsMutex.RUnlock()
 | 
			
		||||
 | 
			
		||||
	if channel, ok := lookupMap[lookupKey]; ok {
 | 
			
		||||
		return channel, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, fmt.Errorf("%s: channel %s not found", b.Account, lookupKey)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const minimumRefreshInterval = 10 * time.Second
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) populateUser(userID string) {
 | 
			
		||||
	b.usersMutex.RLock()
 | 
			
		||||
	_, exists := b.users[userID]
 | 
			
		||||
	b.usersMutex.RUnlock()
 | 
			
		||||
	if exists {
 | 
			
		||||
		// already in cache
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user, err := b.sc.GetUserInfo(userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Log.Debugf("GetUserInfo failed for %v: %v", userID, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.usersMutex.Lock()
 | 
			
		||||
	b.users[userID] = user
 | 
			
		||||
	b.usersMutex.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) populateUsers(wait bool) {
 | 
			
		||||
	b.refreshMutex.Lock()
 | 
			
		||||
	if !wait && (time.Now().Before(b.earliestUserRefresh) || b.refreshInProgress) {
 | 
			
		||||
		b.Log.Debugf("Not refreshing user list as it was done less than %v ago.",
 | 
			
		||||
			minimumRefreshInterval)
 | 
			
		||||
		b.refreshMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for b.refreshInProgress {
 | 
			
		||||
		b.refreshMutex.Unlock()
 | 
			
		||||
		time.Sleep(time.Second)
 | 
			
		||||
		b.refreshMutex.Lock()
 | 
			
		||||
	}
 | 
			
		||||
	b.refreshInProgress = true
 | 
			
		||||
	b.refreshMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	newUsers := map[string]*slack.User{}
 | 
			
		||||
	pagination := b.sc.GetUsersPaginated(slack.GetUsersOptionLimit(200))
 | 
			
		||||
	count := 0
 | 
			
		||||
	for {
 | 
			
		||||
		var err error
 | 
			
		||||
		pagination, err = pagination.Next(context.Background())
 | 
			
		||||
		time.Sleep(time.Second)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if pagination.Done(err) {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err = b.handleRateLimit(err); err != nil {
 | 
			
		||||
				b.Log.Errorf("Could not retrieve users: %#v", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for i := range pagination.Users {
 | 
			
		||||
			newUsers[pagination.Users[i].ID] = &pagination.Users[i]
 | 
			
		||||
		}
 | 
			
		||||
		b.Log.Debugf("getting %d users", len(pagination.Users))
 | 
			
		||||
		count++
 | 
			
		||||
		// more > 2000 users, slack will complain and ratelimit. break
 | 
			
		||||
		if count > 10 {
 | 
			
		||||
			b.Log.Info("Large slack detected > 2000 users, skipping loading complete userlist.")
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.usersMutex.Lock()
 | 
			
		||||
	defer b.usersMutex.Unlock()
 | 
			
		||||
	b.users = newUsers
 | 
			
		||||
 | 
			
		||||
	b.refreshMutex.Lock()
 | 
			
		||||
	defer b.refreshMutex.Unlock()
 | 
			
		||||
	b.earliestUserRefresh = time.Now().Add(minimumRefreshInterval)
 | 
			
		||||
	b.refreshInProgress = false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) populateChannels(wait bool) {
 | 
			
		||||
	b.refreshMutex.Lock()
 | 
			
		||||
	if !wait && (time.Now().Before(b.earliestChannelRefresh) || b.refreshInProgress) {
 | 
			
		||||
		b.Log.Debugf("Not refreshing channel list as it was done less than %v seconds ago.",
 | 
			
		||||
			minimumRefreshInterval)
 | 
			
		||||
		b.refreshMutex.Unlock()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for b.refreshInProgress {
 | 
			
		||||
		b.refreshMutex.Unlock()
 | 
			
		||||
		time.Sleep(time.Second)
 | 
			
		||||
		b.refreshMutex.Lock()
 | 
			
		||||
	}
 | 
			
		||||
	b.refreshInProgress = true
 | 
			
		||||
	b.refreshMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	newChannelsByID := map[string]*slack.Channel{}
 | 
			
		||||
	newChannelsByName := map[string]*slack.Channel{}
 | 
			
		||||
	newChannelMembers := make(map[string][]string)
 | 
			
		||||
 | 
			
		||||
	// We only retrieve public and private channels, not IMs
 | 
			
		||||
	// and MPIMs as those do not have a channel name.
 | 
			
		||||
	queryParams := &slack.GetConversationsParameters{
 | 
			
		||||
		ExcludeArchived: "true",
 | 
			
		||||
		Types:           []string{"public_channel,private_channel"},
 | 
			
		||||
	}
 | 
			
		||||
	for {
 | 
			
		||||
		channels, nextCursor, err := b.sc.GetConversations(queryParams)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err = b.handleRateLimit(err); err != nil {
 | 
			
		||||
				b.Log.Errorf("Could not retrieve channels: %#v", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for i := range channels {
 | 
			
		||||
			newChannelsByID[channels[i].ID] = &channels[i]
 | 
			
		||||
			newChannelsByName[channels[i].Name] = &channels[i]
 | 
			
		||||
			// also find all the members in every channel
 | 
			
		||||
			// comment for now, issues on big slacks
 | 
			
		||||
			/*
 | 
			
		||||
				members, err := b.getUsersInConversation(channels[i].ID)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					if err = b.handleRateLimit(err); err != nil {
 | 
			
		||||
						b.Log.Errorf("Could not retrieve channel members: %#v", err)
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				newChannelMembers[channels[i].ID] = members
 | 
			
		||||
			*/
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if nextCursor == "" {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		queryParams.Cursor = nextCursor
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.channelsMutex.Lock()
 | 
			
		||||
	defer b.channelsMutex.Unlock()
 | 
			
		||||
	b.channelsByID = newChannelsByID
 | 
			
		||||
	b.channelsByName = newChannelsByName
 | 
			
		||||
 | 
			
		||||
	b.channelMembersMutex.Lock()
 | 
			
		||||
	defer b.channelMembersMutex.Unlock()
 | 
			
		||||
	b.channelMembers = newChannelMembers
 | 
			
		||||
 | 
			
		||||
	b.refreshMutex.Lock()
 | 
			
		||||
	defer b.refreshMutex.Unlock()
 | 
			
		||||
	b.earliestChannelRefresh = time.Now().Add(minimumRefreshInterval)
 | 
			
		||||
	b.refreshInProgress = false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// populateReceivedMessage shapes the initial Matterbridge message that we will forward to the
 | 
			
		||||
// router before we apply message-dependent modifications.
 | 
			
		||||
func (b *Bslack) populateReceivedMessage(ev *slack.MessageEvent) (*config.Message, error) {
 | 
			
		||||
	// Use our own func because rtm.GetChannelInfo doesn't work for private channels.
 | 
			
		||||
	channel, err := b.getChannelByID(ev.Channel)
 | 
			
		||||
	channel, err := b.channels.getChannelByID(ev.Channel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -289,7 +77,7 @@ func (b *Bslack) populateMessageWithUserInfo(ev *slack.MessageEvent, rmsg *confi
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user := b.getUser(userID)
 | 
			
		||||
	user := b.users.getUser(userID)
 | 
			
		||||
	if user == nil {
 | 
			
		||||
		return fmt.Errorf("could not find information for user with id %s", ev.User)
 | 
			
		||||
	}
 | 
			
		||||
@@ -315,7 +103,7 @@ func (b *Bslack) populateMessageWithBotInfo(ev *slack.MessageEvent, rmsg *config
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = b.handleRateLimit(err); err != nil {
 | 
			
		||||
		if err = handleRateLimit(b.Log, err); err != nil {
 | 
			
		||||
			b.Log.Errorf("Could not retrieve bot information: %#v", err)
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
@@ -360,7 +148,7 @@ func (b *Bslack) extractTopicOrPurpose(text string) (string, string) {
 | 
			
		||||
func (b *Bslack) replaceMention(text string) string {
 | 
			
		||||
	replaceFunc := func(match string) string {
 | 
			
		||||
		userID := strings.Trim(match, "@<>")
 | 
			
		||||
		if username := b.getUsername(userID); userID != "" {
 | 
			
		||||
		if username := b.users.getUsername(userID); userID != "" {
 | 
			
		||||
			return "@" + username
 | 
			
		||||
		}
 | 
			
		||||
		return match
 | 
			
		||||
@@ -404,16 +192,6 @@ func (b *Bslack) replaceCodeFence(text string) string {
 | 
			
		||||
	return codeFenceRE.ReplaceAllString(text, "```")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bslack) handleRateLimit(err error) error {
 | 
			
		||||
	rateLimit, ok := err.(*slack.RateLimitedError)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	b.Log.Infof("Rate-limited by Slack. Sleeping for %v", rateLimit.RetryAfter)
 | 
			
		||||
	time.Sleep(rateLimit.RetryAfter)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getUsersInConversation returns an array of userIDs that are members of channelID
 | 
			
		||||
func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) {
 | 
			
		||||
	channelMembers := []string{}
 | 
			
		||||
@@ -424,7 +202,7 @@ func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) {
 | 
			
		||||
 | 
			
		||||
		members, nextCursor, err := b.sc.GetUsersInConversation(queryParams)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err = b.handleRateLimit(err); err != nil {
 | 
			
		||||
			if err = handleRateLimit(b.Log, err); err != nil {
 | 
			
		||||
				return channelMembers, fmt.Errorf("Could not retrieve users in channels: %#v", err)
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
@@ -439,3 +217,13 @@ func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) {
 | 
			
		||||
	}
 | 
			
		||||
	return channelMembers, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handleRateLimit(log *logrus.Entry, err error) error {
 | 
			
		||||
	rateLimit, ok := err.(*slack.RateLimitedError)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	log.Infof("Rate-limited by Slack. Sleeping for %v", rateLimit.RetryAfter)
 | 
			
		||||
	time.Sleep(rateLimit.RetryAfter)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -55,14 +55,18 @@ func (b *BLegacy) Connect() error {
 | 
			
		||||
		})
 | 
			
		||||
		if b.GetString(tokenConfig) != "" {
 | 
			
		||||
			b.Log.Info("Connecting using token (receiving)")
 | 
			
		||||
			b.sc = slack.New(b.GetString(tokenConfig))
 | 
			
		||||
			b.sc = slack.New(b.GetString(tokenConfig), slack.OptionDebug(b.GetBool("debug")))
 | 
			
		||||
			b.channels = newChannelManager(b.Log, b.sc)
 | 
			
		||||
			b.users = newUserManager(b.Log, b.sc)
 | 
			
		||||
			b.rtm = b.sc.NewRTM()
 | 
			
		||||
			go b.rtm.ManageConnection()
 | 
			
		||||
			go b.handleSlack()
 | 
			
		||||
		}
 | 
			
		||||
	} else if b.GetString(tokenConfig) != "" {
 | 
			
		||||
		b.Log.Info("Connecting using token (sending and receiving)")
 | 
			
		||||
		b.sc = slack.New(b.GetString(tokenConfig))
 | 
			
		||||
		b.sc = slack.New(b.GetString(tokenConfig), slack.OptionDebug(b.GetBool("debug")))
 | 
			
		||||
		b.channels = newChannelManager(b.Log, b.sc)
 | 
			
		||||
		b.users = newUserManager(b.Log, b.sc)
 | 
			
		||||
		b.rtm = b.sc.NewRTM()
 | 
			
		||||
		go b.rtm.ManageConnection()
 | 
			
		||||
		go b.handleSlack()
 | 
			
		||||
 
 | 
			
		||||
@@ -30,20 +30,8 @@ type Bslack struct {
 | 
			
		||||
	uuid         string
 | 
			
		||||
	useChannelID bool
 | 
			
		||||
 | 
			
		||||
	users      map[string]*slack.User
 | 
			
		||||
	usersMutex sync.RWMutex
 | 
			
		||||
 | 
			
		||||
	channelsByID   map[string]*slack.Channel
 | 
			
		||||
	channelsByName map[string]*slack.Channel
 | 
			
		||||
	channelsMutex  sync.RWMutex
 | 
			
		||||
 | 
			
		||||
	channelMembers      map[string][]string
 | 
			
		||||
	channelMembersMutex sync.RWMutex
 | 
			
		||||
 | 
			
		||||
	refreshInProgress      bool
 | 
			
		||||
	earliestChannelRefresh time.Time
 | 
			
		||||
	earliestUserRefresh    time.Time
 | 
			
		||||
	refreshMutex           sync.Mutex
 | 
			
		||||
	channels *channels
 | 
			
		||||
	users    *users
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -94,14 +82,9 @@ func newBridge(cfg *bridge.Config) *Bslack {
 | 
			
		||||
		cfg.Log.Fatalf("Could not create LRU cache for Slack bridge: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	b := &Bslack{
 | 
			
		||||
		Config:                 cfg,
 | 
			
		||||
		uuid:                   xid.New().String(),
 | 
			
		||||
		cache:                  newCache,
 | 
			
		||||
		users:                  map[string]*slack.User{},
 | 
			
		||||
		channelsByID:           map[string]*slack.Channel{},
 | 
			
		||||
		channelsByName:         map[string]*slack.Channel{},
 | 
			
		||||
		earliestChannelRefresh: time.Now(),
 | 
			
		||||
		earliestUserRefresh:    time.Now(),
 | 
			
		||||
		Config: cfg,
 | 
			
		||||
		uuid:   xid.New().String(),
 | 
			
		||||
		cache:  newCache,
 | 
			
		||||
	}
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
@@ -121,7 +104,12 @@ func (b *Bslack) Connect() error {
 | 
			
		||||
	// If we have a token we use the Slack websocket-based RTM for both sending and receiving.
 | 
			
		||||
	if token := b.GetString(tokenConfig); token != "" {
 | 
			
		||||
		b.Log.Info("Connecting using token")
 | 
			
		||||
 | 
			
		||||
		b.sc = slack.New(token, slack.OptionDebug(b.GetBool("Debug")))
 | 
			
		||||
 | 
			
		||||
		b.channels = newChannelManager(b.Log, b.sc)
 | 
			
		||||
		b.users = newUserManager(b.Log, b.sc)
 | 
			
		||||
 | 
			
		||||
		b.rtm = b.sc.NewRTM()
 | 
			
		||||
		go b.rtm.ManageConnection()
 | 
			
		||||
		go b.handleSlack()
 | 
			
		||||
@@ -163,9 +151,9 @@ func (b *Bslack) JoinChannel(channel config.ChannelInfo) error {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.populateChannels(false)
 | 
			
		||||
	b.channels.populateChannels(false)
 | 
			
		||||
 | 
			
		||||
	channelInfo, err := b.getChannel(channel.Name)
 | 
			
		||||
	channelInfo, err := b.channels.getChannel(channel.Name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("could not join channel: %#v", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -275,7 +263,7 @@ func (b *Bslack) sendRTM(msg config.Message) (string, error) {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	channelInfo, err := b.getChannel(msg.Channel)
 | 
			
		||||
	channelInfo, err := b.channels.getChannel(msg.Channel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", fmt.Errorf("could not send message: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -351,7 +339,7 @@ func (b *Bslack) updateTopicOrPurpose(msg *config.Message, channelInfo *slack.Ch
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		if err = b.handleRateLimit(err); err != nil {
 | 
			
		||||
		if err = handleRateLimit(b.Log, err); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -392,7 +380,7 @@ func (b *Bslack) deleteMessage(msg *config.Message, channelInfo *slack.Channel)
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = b.handleRateLimit(err); err != nil {
 | 
			
		||||
		if err = handleRateLimit(b.Log, err); err != nil {
 | 
			
		||||
			b.Log.Errorf("Failed to delete user message from Slack: %#v", err)
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
@@ -411,7 +399,7 @@ func (b *Bslack) editMessage(msg *config.Message, channelInfo *slack.Channel) (b
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = b.handleRateLimit(err); err != nil {
 | 
			
		||||
		if err = handleRateLimit(b.Log, err); err != nil {
 | 
			
		||||
			b.Log.Errorf("Failed to edit user message on Slack: %#v", err)
 | 
			
		||||
			return true, err
 | 
			
		||||
		}
 | 
			
		||||
@@ -424,14 +412,18 @@ func (b *Bslack) postMessage(msg *config.Message, channelInfo *slack.Channel) (s
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
	messageOptions := b.prepareMessageOptions(msg)
 | 
			
		||||
	messageOptions = append(messageOptions, slack.MsgOptionText(msg.Text, false))
 | 
			
		||||
	messageOptions = append(
 | 
			
		||||
		messageOptions,
 | 
			
		||||
		slack.MsgOptionText(msg.Text, false),
 | 
			
		||||
		slack.MsgOptionEnableLinkUnfurl(),
 | 
			
		||||
	)
 | 
			
		||||
	for {
 | 
			
		||||
		_, id, err := b.rtm.PostMessage(channelInfo.ID, messageOptions...)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return id, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = b.handleRateLimit(err); err != nil {
 | 
			
		||||
		if err = handleRateLimit(b.Log, err); err != nil {
 | 
			
		||||
			b.Log.Errorf("Failed to sent user message to Slack: %#v", err)
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										335
									
								
								bridge/slack/users_channels.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								bridge/slack/users_channels.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,335 @@
 | 
			
		||||
package bslack
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/42wim/matterbridge/bridge/config"
 | 
			
		||||
	"github.com/nlopes/slack"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const minimumRefreshInterval = 10 * time.Second
 | 
			
		||||
 | 
			
		||||
type users struct {
 | 
			
		||||
	log *logrus.Entry
 | 
			
		||||
	sc  *slack.Client
 | 
			
		||||
 | 
			
		||||
	users           map[string]*slack.User
 | 
			
		||||
	usersMutex      sync.RWMutex
 | 
			
		||||
	usersSyncPoints map[string]chan struct{}
 | 
			
		||||
 | 
			
		||||
	refreshInProgress bool
 | 
			
		||||
	earliestRefresh   time.Time
 | 
			
		||||
	refreshMutex      sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newUserManager(log *logrus.Entry, sc *slack.Client) *users {
 | 
			
		||||
	return &users{
 | 
			
		||||
		log:             log,
 | 
			
		||||
		sc:              sc,
 | 
			
		||||
		users:           make(map[string]*slack.User),
 | 
			
		||||
		usersSyncPoints: make(map[string]chan struct{}),
 | 
			
		||||
		earliestRefresh: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *users) getUser(id string) *slack.User {
 | 
			
		||||
	b.usersMutex.RLock()
 | 
			
		||||
	user, ok := b.users[id]
 | 
			
		||||
	b.usersMutex.RUnlock()
 | 
			
		||||
	if ok {
 | 
			
		||||
		return user
 | 
			
		||||
	}
 | 
			
		||||
	b.populateUser(id)
 | 
			
		||||
	b.usersMutex.RLock()
 | 
			
		||||
	defer b.usersMutex.RUnlock()
 | 
			
		||||
 | 
			
		||||
	return b.users[id]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *users) getUsername(id string) string {
 | 
			
		||||
	if user := b.getUser(id); user != nil {
 | 
			
		||||
		if user.Profile.DisplayName != "" {
 | 
			
		||||
			return user.Profile.DisplayName
 | 
			
		||||
		}
 | 
			
		||||
		return user.Name
 | 
			
		||||
	}
 | 
			
		||||
	b.log.Warnf("Could not find user with ID '%s'", id)
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *users) getAvatar(id string) string {
 | 
			
		||||
	if user := b.getUser(id); user != nil {
 | 
			
		||||
		return user.Profile.Image48
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *users) populateUser(userID string) {
 | 
			
		||||
	for {
 | 
			
		||||
		b.usersMutex.Lock()
 | 
			
		||||
		_, exists := b.users[userID]
 | 
			
		||||
		if exists {
 | 
			
		||||
			// already in cache
 | 
			
		||||
			b.usersMutex.Unlock()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if syncPoint, ok := b.usersSyncPoints[userID]; ok {
 | 
			
		||||
			// Another goroutine is already populating this user for us so wait on it to finish.
 | 
			
		||||
			b.usersMutex.Unlock()
 | 
			
		||||
			<-syncPoint
 | 
			
		||||
			// We do not return and iterate again to check that the entry does indeed exist
 | 
			
		||||
			// in case the previous query failed for some reason.
 | 
			
		||||
		} else {
 | 
			
		||||
			b.usersSyncPoints[userID] = make(chan struct{})
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Do not hold the lock while fetching information from Slack
 | 
			
		||||
	// as this might take an unbounded amount of time.
 | 
			
		||||
	b.usersMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	user, err := b.sc.GetUserInfo(userID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.log.Debugf("GetUserInfo failed for %v: %v", userID, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.usersMutex.Lock()
 | 
			
		||||
	defer b.usersMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	// Register user information.
 | 
			
		||||
	b.users[userID] = user
 | 
			
		||||
 | 
			
		||||
	// Wake up any waiting goroutines and remove the synchronization point.
 | 
			
		||||
	close(b.usersSyncPoints[userID])
 | 
			
		||||
	delete(b.usersSyncPoints, userID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *users) populateUsers(wait bool) {
 | 
			
		||||
	b.refreshMutex.Lock()
 | 
			
		||||
	if !wait && (time.Now().Before(b.earliestRefresh) || b.refreshInProgress) {
 | 
			
		||||
		b.log.Debugf("Not refreshing user list as it was done less than %v ago.", minimumRefreshInterval)
 | 
			
		||||
		b.refreshMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for b.refreshInProgress {
 | 
			
		||||
		b.refreshMutex.Unlock()
 | 
			
		||||
		time.Sleep(time.Second)
 | 
			
		||||
		b.refreshMutex.Lock()
 | 
			
		||||
	}
 | 
			
		||||
	b.refreshInProgress = true
 | 
			
		||||
	b.refreshMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	newUsers := map[string]*slack.User{}
 | 
			
		||||
	pagination := b.sc.GetUsersPaginated(slack.GetUsersOptionLimit(200))
 | 
			
		||||
	count := 0
 | 
			
		||||
	for {
 | 
			
		||||
		var err error
 | 
			
		||||
		pagination, err = pagination.Next(context.Background())
 | 
			
		||||
		time.Sleep(time.Second)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if pagination.Done(err) {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err = handleRateLimit(b.log, err); err != nil {
 | 
			
		||||
				b.log.Errorf("Could not retrieve users: %#v", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for i := range pagination.Users {
 | 
			
		||||
			newUsers[pagination.Users[i].ID] = &pagination.Users[i]
 | 
			
		||||
		}
 | 
			
		||||
		b.log.Debugf("getting %d users", len(pagination.Users))
 | 
			
		||||
		count++
 | 
			
		||||
		// more > 2000 users, slack will complain and ratelimit. break
 | 
			
		||||
		if count > 10 {
 | 
			
		||||
			b.log.Info("Large slack detected > 2000 users, skipping loading complete userlist.")
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.usersMutex.Lock()
 | 
			
		||||
	defer b.usersMutex.Unlock()
 | 
			
		||||
	b.users = newUsers
 | 
			
		||||
 | 
			
		||||
	b.refreshMutex.Lock()
 | 
			
		||||
	defer b.refreshMutex.Unlock()
 | 
			
		||||
	b.earliestRefresh = time.Now().Add(minimumRefreshInterval)
 | 
			
		||||
	b.refreshInProgress = false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type channels struct {
 | 
			
		||||
	log *logrus.Entry
 | 
			
		||||
	sc  *slack.Client
 | 
			
		||||
 | 
			
		||||
	channelsByID   map[string]*slack.Channel
 | 
			
		||||
	channelsByName map[string]*slack.Channel
 | 
			
		||||
	channelsMutex  sync.RWMutex
 | 
			
		||||
 | 
			
		||||
	channelMembers      map[string][]string
 | 
			
		||||
	channelMembersMutex sync.RWMutex
 | 
			
		||||
 | 
			
		||||
	refreshInProgress bool
 | 
			
		||||
	earliestRefresh   time.Time
 | 
			
		||||
	refreshMutex      sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newChannelManager(log *logrus.Entry, sc *slack.Client) *channels {
 | 
			
		||||
	return &channels{
 | 
			
		||||
		log:             log,
 | 
			
		||||
		sc:              sc,
 | 
			
		||||
		channelsByID:    make(map[string]*slack.Channel),
 | 
			
		||||
		channelsByName:  make(map[string]*slack.Channel),
 | 
			
		||||
		earliestRefresh: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *channels) getChannel(channel string) (*slack.Channel, error) {
 | 
			
		||||
	if strings.HasPrefix(channel, "ID:") {
 | 
			
		||||
		return b.getChannelByID(strings.TrimPrefix(channel, "ID:"))
 | 
			
		||||
	}
 | 
			
		||||
	return b.getChannelByName(channel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *channels) getChannelByName(name string) (*slack.Channel, error) {
 | 
			
		||||
	return b.getChannelBy(name, b.channelsByName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *channels) getChannelByID(id string) (*slack.Channel, error) {
 | 
			
		||||
	return b.getChannelBy(id, b.channelsByID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *channels) getChannelBy(lookupKey string, lookupMap map[string]*slack.Channel) (*slack.Channel, error) {
 | 
			
		||||
	b.channelsMutex.RLock()
 | 
			
		||||
	defer b.channelsMutex.RUnlock()
 | 
			
		||||
 | 
			
		||||
	if channel, ok := lookupMap[lookupKey]; ok {
 | 
			
		||||
		return channel, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, fmt.Errorf("channel %s not found", lookupKey)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *channels) getChannelMembers(users *users) config.ChannelMembers {
 | 
			
		||||
	b.channelMembersMutex.RLock()
 | 
			
		||||
	defer b.channelMembersMutex.RUnlock()
 | 
			
		||||
 | 
			
		||||
	membersInfo := config.ChannelMembers{}
 | 
			
		||||
	for channelID, members := range b.channelMembers {
 | 
			
		||||
		for _, member := range members {
 | 
			
		||||
			channelName := ""
 | 
			
		||||
			userName := ""
 | 
			
		||||
			userNick := ""
 | 
			
		||||
			user := users.getUser(member)
 | 
			
		||||
			if user != nil {
 | 
			
		||||
				userName = user.Name
 | 
			
		||||
				userNick = user.Profile.DisplayName
 | 
			
		||||
			}
 | 
			
		||||
			channel, _ := b.getChannelByID(channelID)
 | 
			
		||||
			if channel != nil {
 | 
			
		||||
				channelName = channel.Name
 | 
			
		||||
			}
 | 
			
		||||
			memberInfo := config.ChannelMember{
 | 
			
		||||
				Username:    userName,
 | 
			
		||||
				Nick:        userNick,
 | 
			
		||||
				UserID:      member,
 | 
			
		||||
				ChannelID:   channelID,
 | 
			
		||||
				ChannelName: channelName,
 | 
			
		||||
			}
 | 
			
		||||
			membersInfo = append(membersInfo, memberInfo)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return membersInfo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *channels) registerChannel(channel slack.Channel) {
 | 
			
		||||
	b.channelsMutex.Lock()
 | 
			
		||||
	defer b.channelsMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	b.channelsByID[channel.ID] = &channel
 | 
			
		||||
	b.channelsByName[channel.Name] = &channel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *channels) populateChannels(wait bool) {
 | 
			
		||||
	b.refreshMutex.Lock()
 | 
			
		||||
	if !wait && (time.Now().Before(b.earliestRefresh) || b.refreshInProgress) {
 | 
			
		||||
		b.log.Debugf("Not refreshing channel list as it was done less than %v seconds ago.", minimumRefreshInterval)
 | 
			
		||||
		b.refreshMutex.Unlock()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	for b.refreshInProgress {
 | 
			
		||||
		b.refreshMutex.Unlock()
 | 
			
		||||
		time.Sleep(time.Second)
 | 
			
		||||
		b.refreshMutex.Lock()
 | 
			
		||||
	}
 | 
			
		||||
	b.refreshInProgress = true
 | 
			
		||||
	b.refreshMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	newChannelsByID := map[string]*slack.Channel{}
 | 
			
		||||
	newChannelsByName := map[string]*slack.Channel{}
 | 
			
		||||
	newChannelMembers := make(map[string][]string)
 | 
			
		||||
 | 
			
		||||
	// We only retrieve public and private channels, not IMs
 | 
			
		||||
	// and MPIMs as those do not have a channel name.
 | 
			
		||||
	queryParams := &slack.GetConversationsParameters{
 | 
			
		||||
		ExcludeArchived: "true",
 | 
			
		||||
		Types:           []string{"public_channel,private_channel"},
 | 
			
		||||
	}
 | 
			
		||||
	for {
 | 
			
		||||
		channels, nextCursor, err := b.sc.GetConversations(queryParams)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err = handleRateLimit(b.log, err); err != nil {
 | 
			
		||||
				b.log.Errorf("Could not retrieve channels: %#v", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for i := range channels {
 | 
			
		||||
			newChannelsByID[channels[i].ID] = &channels[i]
 | 
			
		||||
			newChannelsByName[channels[i].Name] = &channels[i]
 | 
			
		||||
			// also find all the members in every channel
 | 
			
		||||
			// comment for now, issues on big slacks
 | 
			
		||||
			/*
 | 
			
		||||
				members, err := b.getUsersInConversation(channels[i].ID)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					if err = b.handleRateLimit(err); err != nil {
 | 
			
		||||
						b.Log.Errorf("Could not retrieve channel members: %#v", err)
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				newChannelMembers[channels[i].ID] = members
 | 
			
		||||
			*/
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if nextCursor == "" {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		queryParams.Cursor = nextCursor
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.channelsMutex.Lock()
 | 
			
		||||
	defer b.channelsMutex.Unlock()
 | 
			
		||||
	b.channelsByID = newChannelsByID
 | 
			
		||||
	b.channelsByName = newChannelsByName
 | 
			
		||||
 | 
			
		||||
	b.channelMembersMutex.Lock()
 | 
			
		||||
	defer b.channelMembersMutex.Unlock()
 | 
			
		||||
	b.channelMembers = newChannelMembers
 | 
			
		||||
 | 
			
		||||
	b.refreshMutex.Lock()
 | 
			
		||||
	defer b.refreshMutex.Unlock()
 | 
			
		||||
	b.earliestRefresh = time.Now().Add(minimumRefreshInterval)
 | 
			
		||||
	b.refreshInProgress = false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,3 +1,7 @@
 | 
			
		||||
# v1.14.1
 | 
			
		||||
## Bugfix
 | 
			
		||||
* slack: Fix crash double unlock (slack) (#771)
 | 
			
		||||
 | 
			
		||||
# v1.14.0
 | 
			
		||||
 | 
			
		||||
## Breaking
 | 
			
		||||
@@ -19,6 +23,8 @@
 | 
			
		||||
 | 
			
		||||
## Enhancements
 | 
			
		||||
* general: Fail gracefully on incorrect human input. Fixes #739 (#740)
 | 
			
		||||
* matrix: Detect html nicks in RemoteNickFormat (matrix). Fixes #696 (#719)
 | 
			
		||||
* matrix: Send notices on join/parts (matrix). Fixes #712 (#716)
 | 
			
		||||
 | 
			
		||||
## Bugfix
 | 
			
		||||
* general: Handle file upload/download only once for each message (#742)
 | 
			
		||||
@@ -27,9 +33,9 @@
 | 
			
		||||
* irc: add support for (older) unrealircd versions. #708
 | 
			
		||||
* irc: Support quits from irc correctly. Fixes #722 (#724)
 | 
			
		||||
* matrix: Send username when uploading video/images (matrix). Fixes #715 (#717)
 | 
			
		||||
* matrix: Send notices on join/parts (matrix). Fixes #712 (#716)
 | 
			
		||||
* matrix: Detect html nicks in RemoteNickFormat (matrix). Fixes #696 (#719)
 | 
			
		||||
* matrix: Trim <p> and </p> tags (matrix). Closes #686 (#753)
 | 
			
		||||
* slack: Hint at thread replies when messages are unthreaded (slack) (#684)
 | 
			
		||||
* slack: Fix race-condition in populateUser() (#767)
 | 
			
		||||
* xmpp: Do not send topic changes on connect (xmpp). Fixes #732 (#733)
 | 
			
		||||
* telegram: Fix regression in HTML handling (telegram). Closes #734
 | 
			
		||||
* discord: Do not relay any bot messages (discord) (#743)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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.9.2
 | 
			
		||||
	github.com/d5/tengo v1.12.1
 | 
			
		||||
	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.9.2 h1:UE/X8PYl7bLS4Ww2zGeh91nq5PTnkhe8ncgNeA5PK7k=
 | 
			
		||||
github.com/d5/tengo v1.9.2/go.mod h1:gsbjo7lBXzBIWBd6NQp1lRKqqiDDANqBOyhW8rTlFsY=
 | 
			
		||||
github.com/d5/tengo v1.12.1 h1:libKkDM95CsZgYs6E5eiEaM9sbcw2EzJRSkr9o5NO4s=
 | 
			
		||||
github.com/d5/tengo v1.12.1/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.0-rc2"
 | 
			
		||||
	version = "1.14.1"
 | 
			
		||||
	githash string
 | 
			
		||||
 | 
			
		||||
	flagConfig  = flag.String("conf", "matterbridge.toml", "config file")
 | 
			
		||||
 
 | 
			
		||||
@@ -1007,9 +1007,10 @@ ShowTopicChange=false
 | 
			
		||||
Server="https://yourrocketchatserver.domain.com:443"
 | 
			
		||||
 | 
			
		||||
#login/pass of your bot. 
 | 
			
		||||
#login needs to be the login with email address! user@domain.com
 | 
			
		||||
#Use a dedicated user for this and not your own! 
 | 
			
		||||
#REQUIRED (when not using webhooks)
 | 
			
		||||
Login="yourlogin"
 | 
			
		||||
Login="yourlogin@domain.com"
 | 
			
		||||
Password="yourpass"
 | 
			
		||||
 | 
			
		||||
#### Settings for webhook matterbridge.
 | 
			
		||||
@@ -1050,6 +1051,8 @@ SkipTLSVerify=true
 | 
			
		||||
#Useful if username overrides for incoming webhooks isn't enabled on the 
 | 
			
		||||
#rocketchat server. If you set PrefixMessagesWithNick to true, each message 
 | 
			
		||||
#from bridge to rocketchat will by default be prefixed by the RemoteNickFormat setting. i
 | 
			
		||||
#if you're using login/pass you can better enable because of this bug:
 | 
			
		||||
#https://github.com/RocketChat/Rocket.Chat/issues/7549
 | 
			
		||||
#OPTIONAL (default false)
 | 
			
		||||
PrefixMessagesWithNick=false
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/d5/tengo/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/d5/tengo/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
dist/
 | 
			
		||||
							
								
								
									
										23
									
								
								vendor/github.com/d5/tengo/.goreleaser.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/d5/tengo/.goreleaser.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
builds:
 | 
			
		||||
  - env:
 | 
			
		||||
      - CGO_ENABLED=0
 | 
			
		||||
    main: ./cmd/tengo/main.go
 | 
			
		||||
    goos:
 | 
			
		||||
      - darwin
 | 
			
		||||
      - linux
 | 
			
		||||
      - windows
 | 
			
		||||
  - env:
 | 
			
		||||
      - CGO_ENABLED=0
 | 
			
		||||
    main: ./cmd/tengomin/main.go
 | 
			
		||||
    binary: tengomin
 | 
			
		||||
    goos:
 | 
			
		||||
      - darwin
 | 
			
		||||
      - linux
 | 
			
		||||
      - windows
 | 
			
		||||
archive:
 | 
			
		||||
  files:
 | 
			
		||||
    - none*
 | 
			
		||||
checksum:
 | 
			
		||||
  name_template: 'checksums.txt'
 | 
			
		||||
changelog:
 | 
			
		||||
  sort: asc
 | 
			
		||||
							
								
								
									
										17
									
								
								vendor/github.com/d5/tengo/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/d5/tengo/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
language: go
 | 
			
		||||
 | 
			
		||||
go:
 | 
			
		||||
  - 1.9
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
  - go get -u golang.org/x/lint/golint
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - make test
 | 
			
		||||
 | 
			
		||||
deploy:
 | 
			
		||||
  - provider: script
 | 
			
		||||
    skip_cleanup: true
 | 
			
		||||
    script: curl -sL https://git.io/goreleaser | bash
 | 
			
		||||
    on:
 | 
			
		||||
      tags: true
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/github.com/d5/tengo/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/d5/tengo/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
vet:
 | 
			
		||||
	go vet ./...
 | 
			
		||||
 | 
			
		||||
lint:
 | 
			
		||||
	golint -set_exit_status ./...
 | 
			
		||||
 | 
			
		||||
test: vet lint
 | 
			
		||||
	go test -race -cover ./...
 | 
			
		||||
 | 
			
		||||
fmt:
 | 
			
		||||
	go fmt ./...
 | 
			
		||||
							
								
								
									
										74
									
								
								vendor/github.com/d5/tengo/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/d5/tengo/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
<p align="center">
 | 
			
		||||
  <img src="https://raw.githubusercontent.com/d5/tengolang.com/master/logo_400.png" width="200" height="200">
 | 
			
		||||
</p>
 | 
			
		||||
 | 
			
		||||
# The Tengo Language
 | 
			
		||||
 | 
			
		||||
[](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.** 
 | 
			
		||||
 | 
			
		||||
Tengo is **[fast](#benchmark)** and secure because it's compiled/executed as bytecode on stack-based VM that's written in native Go.
 | 
			
		||||
 | 
			
		||||
```golang
 | 
			
		||||
/* The Tengo Language */
 | 
			
		||||
 | 
			
		||||
each := func(seq, fn) {
 | 
			
		||||
    for x in seq { fn(x) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sum := func(init, seq) {
 | 
			
		||||
    each(seq, func(x) { init += x })
 | 
			
		||||
    return init
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
n := sum(0, [1, 2, 3])   // == 6
 | 
			
		||||
s := sum("", [1, 2, 3])  // == "123"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
> Run this code in the [Playground](https://tengolang.com/?s=d01cf9ed81daba939e26618530eb171f7397d9c9)
 | 
			
		||||
 | 
			
		||||
## Features
 | 
			
		||||
 | 
			
		||||
- Simple and highly readable [Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md)
 | 
			
		||||
  - Dynamic typing with type coercion
 | 
			
		||||
  - Higher-order functions and closures
 | 
			
		||||
  - Immutable values
 | 
			
		||||
  - Garbage collection
 | 
			
		||||
- [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
 | 
			
		||||
 | 
			
		||||
## 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 |
 | 
			
		||||
 | 
			
		||||
_* [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)_  
 | 
			
		||||
_* **Go** does not read the source code from file, while all other cases do_  
 | 
			
		||||
_* See [here](https://github.com/d5/tengobench) for commands/codes used_
 | 
			
		||||
 | 
			
		||||
## References
 | 
			
		||||
 | 
			
		||||
- [Language Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md)
 | 
			
		||||
- [Object Types](https://github.com/d5/tengo/blob/master/docs/objects.md)
 | 
			
		||||
- [Runtime Types](https://github.com/d5/tengo/blob/master/docs/runtime-types.md) and [Operators](https://github.com/d5/tengo/blob/master/docs/operators.md)
 | 
			
		||||
- [Builtin Functions](https://github.com/d5/tengo/blob/master/docs/builtins.md)
 | 
			
		||||
- [Interoperability](https://github.com/d5/tengo/blob/master/docs/interoperability.md)
 | 
			
		||||
- [Tengo CLI](https://github.com/d5/tengo/blob/master/docs/tengo-cli.md)
 | 
			
		||||
- [Standard Library](https://github.com/d5/tengo/blob/master/docs/stdlib.md)
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/github.com/d5/tengo/compiler/compiler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/d5/tengo/compiler/compiler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -5,11 +5,11 @@ import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"reflect"
 | 
			
		||||
 | 
			
		||||
	"github.com/d5/tengo"
 | 
			
		||||
	"github.com/d5/tengo/compiler/ast"
 | 
			
		||||
	"github.com/d5/tengo/compiler/source"
 | 
			
		||||
	"github.com/d5/tengo/compiler/token"
 | 
			
		||||
	"github.com/d5/tengo/objects"
 | 
			
		||||
	"github.com/d5/tengo/stdlib"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Compiler compiles the AST into a bytecode.
 | 
			
		||||
@@ -54,9 +54,6 @@ func NewCompiler(file *source.File, symbolTable *SymbolTable, constants []object
 | 
			
		||||
	// builtin modules
 | 
			
		||||
	if builtinModules == nil {
 | 
			
		||||
		builtinModules = make(map[string]bool)
 | 
			
		||||
		for name := range stdlib.Modules {
 | 
			
		||||
			builtinModules[name] = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Compiler{
 | 
			
		||||
@@ -195,6 +192,10 @@ func (c *Compiler) Compile(node ast.Node) error {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case *ast.StringLit:
 | 
			
		||||
		if len(node.Value) > tengo.MaxStringLen {
 | 
			
		||||
			return c.error(node, objects.ErrStringLimit)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c.emit(node, OpConstant, c.addConstant(&objects.String{Value: node.Value}))
 | 
			
		||||
 | 
			
		||||
	case *ast.CharLit:
 | 
			
		||||
@@ -332,6 +333,9 @@ func (c *Compiler) Compile(node ast.Node) error {
 | 
			
		||||
	case *ast.MapLit:
 | 
			
		||||
		for _, elt := range node.Elements {
 | 
			
		||||
			// key
 | 
			
		||||
			if len(elt.Key) > tengo.MaxStringLen {
 | 
			
		||||
				return c.error(node, objects.ErrStringLimit)
 | 
			
		||||
			}
 | 
			
		||||
			c.emit(node, OpConstant, c.addConstant(&objects.String{Value: elt.Key}))
 | 
			
		||||
 | 
			
		||||
			// value
 | 
			
		||||
@@ -507,6 +511,10 @@ func (c *Compiler) Compile(node ast.Node) error {
 | 
			
		||||
 | 
			
		||||
	case *ast.ImportExpr:
 | 
			
		||||
		if c.builtinModules[node.ModuleName] {
 | 
			
		||||
			if len(node.ModuleName) > tengo.MaxStringLen {
 | 
			
		||||
				return c.error(node, objects.ErrStringLimit)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			c.emit(node, OpConstant, c.addConstant(&objects.String{Value: node.ModuleName}))
 | 
			
		||||
			c.emit(node, OpGetBuiltinModule)
 | 
			
		||||
		} else {
 | 
			
		||||
@@ -610,6 +618,14 @@ func (c *Compiler) fork(file *source.File, moduleName string, symbolTable *Symbo
 | 
			
		||||
	return child
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Compiler) error(node ast.Node, err error) error {
 | 
			
		||||
	return &Error{
 | 
			
		||||
		fileSet: c.file.Set(),
 | 
			
		||||
		node:    node,
 | 
			
		||||
		error:   err,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Compiler) errorf(node ast.Node, format string, args ...interface{}) error {
 | 
			
		||||
	return &Error{
 | 
			
		||||
		fileSet: c.file.Set(),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/d5/tengo/compiler/compiler_module.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/d5/tengo/compiler/compiler_module.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -77,11 +77,8 @@ func (c *Compiler) doCompileModule(moduleName string, src []byte) (*objects.Comp
 | 
			
		||||
	symbolTable := NewSymbolTable()
 | 
			
		||||
 | 
			
		||||
	// inherit builtin functions
 | 
			
		||||
	for idx, fn := range objects.Builtins {
 | 
			
		||||
		s, _, ok := c.symbolTable.Resolve(fn.Name)
 | 
			
		||||
		if ok && s.Scope == ScopeBuiltin {
 | 
			
		||||
			symbolTable.DefineBuiltin(idx, fn.Name)
 | 
			
		||||
		}
 | 
			
		||||
	for _, sym := range c.symbolTable.BuiltinSymbols() {
 | 
			
		||||
		symbolTable.DefineBuiltin(sym.Index, sym.Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// no global scope for the module
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/d5/tengo/compiler/parser/parse_file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/d5/tengo/compiler/parser/parse_file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,28 +0,0 @@
 | 
			
		||||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"github.com/d5/tengo/compiler/ast"
 | 
			
		||||
	"github.com/d5/tengo/compiler/source"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ParseFile parses a file with a given src.
 | 
			
		||||
func ParseFile(file *source.File, src []byte, trace io.Writer) (res *ast.File, err error) {
 | 
			
		||||
	p := NewParser(file, src, trace)
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if e := recover(); e != nil {
 | 
			
		||||
			if _, ok := e.(bailout); !ok {
 | 
			
		||||
				panic(e)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		p.errors.Sort()
 | 
			
		||||
		err = p.errors.Err()
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	res, err = p.ParseFile()
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/d5/tengo/compiler/parser/parse_source.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/d5/tengo/compiler/parser/parse_source.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -12,5 +12,6 @@ func ParseSource(filename string, src []byte, trace io.Writer) (res *ast.File, e
 | 
			
		||||
	fileSet := source.NewFileSet()
 | 
			
		||||
	file := fileSet.AddFile(filename, -1, len(src))
 | 
			
		||||
 | 
			
		||||
	return ParseFile(file, src, trace)
 | 
			
		||||
	p := NewParser(file, src, trace)
 | 
			
		||||
	return p.ParseFile()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								vendor/github.com/d5/tengo/compiler/parser/parser.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/d5/tengo/compiler/parser/parser.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -57,7 +57,18 @@ func NewParser(file *source.File, src []byte, trace io.Writer) *Parser {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseFile parses the source and returns an AST file unit.
 | 
			
		||||
func (p *Parser) ParseFile() (*ast.File, error) {
 | 
			
		||||
func (p *Parser) ParseFile() (file *ast.File, err error) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if e := recover(); e != nil {
 | 
			
		||||
			if _, ok := e.(bailout); !ok {
 | 
			
		||||
				panic(e)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		p.errors.Sort()
 | 
			
		||||
		err = p.errors.Err()
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if p.trace {
 | 
			
		||||
		defer un(trace(p, "File"))
 | 
			
		||||
	}
 | 
			
		||||
@@ -71,10 +82,12 @@ func (p *Parser) ParseFile() (*ast.File, error) {
 | 
			
		||||
		return nil, p.errors.Err()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &ast.File{
 | 
			
		||||
	file = &ast.File{
 | 
			
		||||
		InputFile: p.file,
 | 
			
		||||
		Stmts:     stmts,
 | 
			
		||||
	}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) parseExpr() ast.Expr {
 | 
			
		||||
@@ -1002,16 +1015,26 @@ func (p *Parser) parseMapElementLit() *ast.MapElementLit {
 | 
			
		||||
		defer un(trace(p, "MapElementLit"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// key: read identifier token but it's not actually an identifier
 | 
			
		||||
	ident := p.parseIdent()
 | 
			
		||||
	pos := p.pos
 | 
			
		||||
	name := "_"
 | 
			
		||||
 | 
			
		||||
	if p.token == token.Ident {
 | 
			
		||||
		name = p.tokenLit
 | 
			
		||||
	} else if p.token == token.String {
 | 
			
		||||
		v, _ := strconv.Unquote(p.tokenLit)
 | 
			
		||||
		name = v
 | 
			
		||||
	} else {
 | 
			
		||||
		p.errorExpected(pos, "map key")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p.next()
 | 
			
		||||
 | 
			
		||||
	colonPos := p.expect(token.Colon)
 | 
			
		||||
 | 
			
		||||
	valueExpr := p.parseExpr()
 | 
			
		||||
 | 
			
		||||
	return &ast.MapElementLit{
 | 
			
		||||
		Key:      ident.Name,
 | 
			
		||||
		KeyPos:   ident.NamePos,
 | 
			
		||||
		Key:      name,
 | 
			
		||||
		KeyPos:   pos,
 | 
			
		||||
		ColonPos: colonPos,
 | 
			
		||||
		Value:    valueExpr,
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/d5/tengo/compiler/symbol_table.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/d5/tengo/compiler/symbol_table.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,12 +2,13 @@ package compiler
 | 
			
		||||
 | 
			
		||||
// SymbolTable represents a symbol table.
 | 
			
		||||
type SymbolTable struct {
 | 
			
		||||
	parent        *SymbolTable
 | 
			
		||||
	block         bool
 | 
			
		||||
	store         map[string]*Symbol
 | 
			
		||||
	numDefinition int
 | 
			
		||||
	maxDefinition int
 | 
			
		||||
	freeSymbols   []*Symbol
 | 
			
		||||
	parent         *SymbolTable
 | 
			
		||||
	block          bool
 | 
			
		||||
	store          map[string]*Symbol
 | 
			
		||||
	numDefinition  int
 | 
			
		||||
	maxDefinition  int
 | 
			
		||||
	freeSymbols    []*Symbol
 | 
			
		||||
	builtinSymbols []*Symbol
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSymbolTable creates a SymbolTable.
 | 
			
		||||
@@ -37,6 +38,10 @@ func (t *SymbolTable) Define(name string) *Symbol {
 | 
			
		||||
 | 
			
		||||
// DefineBuiltin adds a symbol for builtin function.
 | 
			
		||||
func (t *SymbolTable) DefineBuiltin(index int, name string) *Symbol {
 | 
			
		||||
	if t.parent != nil {
 | 
			
		||||
		return t.parent.DefineBuiltin(index, name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	symbol := &Symbol{
 | 
			
		||||
		Name:  name,
 | 
			
		||||
		Index: index,
 | 
			
		||||
@@ -45,6 +50,8 @@ func (t *SymbolTable) DefineBuiltin(index int, name string) *Symbol {
 | 
			
		||||
 | 
			
		||||
	t.store[name] = symbol
 | 
			
		||||
 | 
			
		||||
	t.builtinSymbols = append(t.builtinSymbols, symbol)
 | 
			
		||||
 | 
			
		||||
	return symbol
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -101,6 +108,15 @@ func (t *SymbolTable) FreeSymbols() []*Symbol {
 | 
			
		||||
	return t.freeSymbols
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BuiltinSymbols returns builtin symbols for the scope.
 | 
			
		||||
func (t *SymbolTable) BuiltinSymbols() []*Symbol {
 | 
			
		||||
	if t.parent != nil {
 | 
			
		||||
		return t.parent.BuiltinSymbols()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return t.builtinSymbols
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Names returns the name of all the symbols.
 | 
			
		||||
func (t *SymbolTable) Names() []string {
 | 
			
		||||
	var names []string
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								vendor/github.com/d5/tengo/objects/builtin_convert.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/d5/tengo/objects/builtin_convert.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,5 +1,7 @@
 | 
			
		||||
package objects
 | 
			
		||||
 | 
			
		||||
import "github.com/d5/tengo"
 | 
			
		||||
 | 
			
		||||
func builtinString(args ...Object) (Object, error) {
 | 
			
		||||
	argsLen := len(args)
 | 
			
		||||
	if !(argsLen == 1 || argsLen == 2) {
 | 
			
		||||
@@ -12,6 +14,10 @@ func builtinString(args ...Object) (Object, error) {
 | 
			
		||||
 | 
			
		||||
	v, ok := ToString(args[0])
 | 
			
		||||
	if ok {
 | 
			
		||||
		if len(v) > tengo.MaxStringLen {
 | 
			
		||||
			return nil, ErrStringLimit
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return &String{Value: v}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -117,11 +123,19 @@ func builtinBytes(args ...Object) (Object, error) {
 | 
			
		||||
 | 
			
		||||
	// bytes(N) => create a new bytes with given size N
 | 
			
		||||
	if n, ok := args[0].(*Int); ok {
 | 
			
		||||
		if n.Value > int64(tengo.MaxBytesLen) {
 | 
			
		||||
			return nil, ErrBytesLimit
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return &Bytes{Value: make([]byte, int(n.Value))}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v, ok := ToByteSlice(args[0])
 | 
			
		||||
	if ok {
 | 
			
		||||
		if len(v) > tengo.MaxBytesLen {
 | 
			
		||||
			return nil, ErrBytesLimit
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return &Bytes{Value: v}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/github.com/d5/tengo/objects/builtin_json.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/d5/tengo/objects/builtin_json.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,6 +2,8 @@ package objects
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
 | 
			
		||||
	"github.com/d5/tengo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// to_json(v object) => bytes
 | 
			
		||||
@@ -15,6 +17,10 @@ func builtinToJSON(args ...Object) (Object, error) {
 | 
			
		||||
		return &Error{Value: &String{Value: err.Error()}}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(res) > tengo.MaxBytesLen {
 | 
			
		||||
		return nil, ErrBytesLimit
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Bytes{Value: res}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								vendor/github.com/d5/tengo/objects/builtin_print.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/d5/tengo/objects/builtin_print.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,6 +2,8 @@ package objects
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/d5/tengo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// print(args...)
 | 
			
		||||
@@ -71,5 +73,11 @@ func builtinSprintf(args ...Object) (Object, error) {
 | 
			
		||||
		formatArgs[idx] = objectToInterface(arg)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &String{Value: fmt.Sprintf(format.Value, formatArgs...)}, nil
 | 
			
		||||
	s := fmt.Sprintf(format.Value, formatArgs...)
 | 
			
		||||
 | 
			
		||||
	if len(s) > tengo.MaxStringLen {
 | 
			
		||||
		return nil, ErrStringLimit
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &String{Value: s}, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										289
									
								
								vendor/github.com/d5/tengo/objects/builtins.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										289
									
								
								vendor/github.com/d5/tengo/objects/builtins.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,135 +1,164 @@
 | 
			
		||||
package objects
 | 
			
		||||
 | 
			
		||||
// NamedBuiltinFunc is a named builtin function.
 | 
			
		||||
type NamedBuiltinFunc struct {
 | 
			
		||||
	Name string
 | 
			
		||||
	Func CallableFunc
 | 
			
		||||
// 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,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "len",
 | 
			
		||||
		Value: builtinLen,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "copy",
 | 
			
		||||
		Value: builtinCopy,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "append",
 | 
			
		||||
		Value: builtinAppend,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "string",
 | 
			
		||||
		Value: builtinString,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "int",
 | 
			
		||||
		Value: builtinInt,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "bool",
 | 
			
		||||
		Value: builtinBool,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "float",
 | 
			
		||||
		Value: builtinFloat,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "char",
 | 
			
		||||
		Value: builtinChar,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "bytes",
 | 
			
		||||
		Value: builtinBytes,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "time",
 | 
			
		||||
		Value: builtinTime,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_int",
 | 
			
		||||
		Value: builtinIsInt,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_float",
 | 
			
		||||
		Value: builtinIsFloat,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_string",
 | 
			
		||||
		Value: builtinIsString,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_bool",
 | 
			
		||||
		Value: builtinIsBool,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_char",
 | 
			
		||||
		Value: builtinIsChar,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_bytes",
 | 
			
		||||
		Value: builtinIsBytes,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_array",
 | 
			
		||||
		Value: builtinIsArray,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_immutable_array",
 | 
			
		||||
		Value: builtinIsImmutableArray,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_map",
 | 
			
		||||
		Value: builtinIsMap,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_immutable_map",
 | 
			
		||||
		Value: builtinIsImmutableMap,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_time",
 | 
			
		||||
		Value: builtinIsTime,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_error",
 | 
			
		||||
		Value: builtinIsError,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_undefined",
 | 
			
		||||
		Value: builtinIsUndefined,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_function",
 | 
			
		||||
		Value: builtinIsFunction,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "is_callable",
 | 
			
		||||
		Value: builtinIsCallable,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "to_json",
 | 
			
		||||
		Value: builtinToJSON,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "from_json",
 | 
			
		||||
		Value: builtinFromJSON,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name:  "type_name",
 | 
			
		||||
		Value: builtinTypeName,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Builtins contains all default builtin functions.
 | 
			
		||||
var Builtins = []NamedBuiltinFunc{
 | 
			
		||||
	{
 | 
			
		||||
		Name: "print",
 | 
			
		||||
		Func: builtinPrint,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "printf",
 | 
			
		||||
		Func: builtinPrintf,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "sprintf",
 | 
			
		||||
		Func: builtinSprintf,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "len",
 | 
			
		||||
		Func: builtinLen,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "copy",
 | 
			
		||||
		Func: builtinCopy,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "append",
 | 
			
		||||
		Func: builtinAppend,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "string",
 | 
			
		||||
		Func: builtinString,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "int",
 | 
			
		||||
		Func: builtinInt,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "bool",
 | 
			
		||||
		Func: builtinBool,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "float",
 | 
			
		||||
		Func: builtinFloat,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "char",
 | 
			
		||||
		Func: builtinChar,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "bytes",
 | 
			
		||||
		Func: builtinBytes,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "time",
 | 
			
		||||
		Func: builtinTime,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_int",
 | 
			
		||||
		Func: builtinIsInt,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_float",
 | 
			
		||||
		Func: builtinIsFloat,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_string",
 | 
			
		||||
		Func: builtinIsString,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_bool",
 | 
			
		||||
		Func: builtinIsBool,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_char",
 | 
			
		||||
		Func: builtinIsChar,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_bytes",
 | 
			
		||||
		Func: builtinIsBytes,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_array",
 | 
			
		||||
		Func: builtinIsArray,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_immutable_array",
 | 
			
		||||
		Func: builtinIsImmutableArray,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_map",
 | 
			
		||||
		Func: builtinIsMap,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_immutable_map",
 | 
			
		||||
		Func: builtinIsImmutableMap,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_time",
 | 
			
		||||
		Func: builtinIsTime,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_error",
 | 
			
		||||
		Func: builtinIsError,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_undefined",
 | 
			
		||||
		Func: builtinIsUndefined,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_function",
 | 
			
		||||
		Func: builtinIsFunction,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "is_callable",
 | 
			
		||||
		Func: builtinIsCallable,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "to_json",
 | 
			
		||||
		Func: builtinToJSON,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "from_json",
 | 
			
		||||
		Func: builtinFromJSON,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		Name: "type_name",
 | 
			
		||||
		Func: 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()...)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/d5/tengo/objects/bytes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/d5/tengo/objects/bytes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -3,6 +3,7 @@ package objects
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
 | 
			
		||||
	"github.com/d5/tengo"
 | 
			
		||||
	"github.com/d5/tengo/compiler/token"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -27,6 +28,10 @@ func (o *Bytes) BinaryOp(op token.Token, rhs Object) (Object, error) {
 | 
			
		||||
	case token.Add:
 | 
			
		||||
		switch rhs := rhs.(type) {
 | 
			
		||||
		case *Bytes:
 | 
			
		||||
			if len(o.Value)+len(rhs.Value) > tengo.MaxBytesLen {
 | 
			
		||||
				return nil, ErrBytesLimit
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return &Bytes{Value: append(o.Value, rhs.Value...)}, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/d5/tengo/objects/callable_func.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/d5/tengo/objects/callable_func.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
package objects
 | 
			
		||||
 | 
			
		||||
// CallableFunc is a function signature for the callable functions.
 | 
			
		||||
type CallableFunc func(args ...Object) (ret Object, err error)
 | 
			
		||||
type CallableFunc = func(args ...Object) (ret Object, err error)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								vendor/github.com/d5/tengo/objects/conversion.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/d5/tengo/objects/conversion.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,6 +4,8 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/d5/tengo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ToString will try to convert object o to string value.
 | 
			
		||||
@@ -194,6 +196,9 @@ func FromInterface(v interface{}) (Object, error) {
 | 
			
		||||
	case nil:
 | 
			
		||||
		return UndefinedValue, nil
 | 
			
		||||
	case string:
 | 
			
		||||
		if len(v) > tengo.MaxStringLen {
 | 
			
		||||
			return nil, ErrStringLimit
 | 
			
		||||
		}
 | 
			
		||||
		return &String{Value: v}, nil
 | 
			
		||||
	case int64:
 | 
			
		||||
		return &Int{Value: v}, nil
 | 
			
		||||
@@ -211,6 +216,9 @@ func FromInterface(v interface{}) (Object, error) {
 | 
			
		||||
	case float64:
 | 
			
		||||
		return &Float{Value: v}, nil
 | 
			
		||||
	case []byte:
 | 
			
		||||
		if len(v) > tengo.MaxBytesLen {
 | 
			
		||||
			return nil, ErrBytesLimit
 | 
			
		||||
		}
 | 
			
		||||
		return &Bytes{Value: v}, nil
 | 
			
		||||
	case error:
 | 
			
		||||
		return &Error{Value: &String{Value: v.Error()}}, nil
 | 
			
		||||
@@ -243,6 +251,8 @@ func FromInterface(v interface{}) (Object, error) {
 | 
			
		||||
		return &Time{Value: v}, nil
 | 
			
		||||
	case Object:
 | 
			
		||||
		return v, nil
 | 
			
		||||
	case CallableFunc:
 | 
			
		||||
		return &UserFunction{Value: v}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, fmt.Errorf("cannot convert to object: %T", v)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/github.com/d5/tengo/objects/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/d5/tengo/objects/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -20,6 +20,12 @@ var ErrInvalidOperator = errors.New("invalid operator")
 | 
			
		||||
// ErrWrongNumArguments represents a wrong number of arguments error.
 | 
			
		||||
var ErrWrongNumArguments = errors.New("wrong number of arguments")
 | 
			
		||||
 | 
			
		||||
// ErrBytesLimit represents an error where the size of bytes value exceeds the limit.
 | 
			
		||||
var ErrBytesLimit = errors.New("exceeding bytes size limit")
 | 
			
		||||
 | 
			
		||||
// ErrStringLimit represents an error where the size of string value exceeds the limit.
 | 
			
		||||
var ErrStringLimit = errors.New("exceeding string size limit")
 | 
			
		||||
 | 
			
		||||
// ErrInvalidArgumentType represents an invalid argument value type error.
 | 
			
		||||
type ErrInvalidArgumentType struct {
 | 
			
		||||
	Name     string
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								vendor/github.com/d5/tengo/objects/string.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/d5/tengo/objects/string.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -3,6 +3,7 @@ package objects
 | 
			
		||||
import (
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/d5/tengo"
 | 
			
		||||
	"github.com/d5/tengo/compiler/token"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -28,9 +29,16 @@ func (o *String) BinaryOp(op token.Token, rhs Object) (Object, error) {
 | 
			
		||||
	case token.Add:
 | 
			
		||||
		switch rhs := rhs.(type) {
 | 
			
		||||
		case *String:
 | 
			
		||||
			if len(o.Value)+len(rhs.Value) > tengo.MaxStringLen {
 | 
			
		||||
				return nil, ErrStringLimit
 | 
			
		||||
			}
 | 
			
		||||
			return &String{Value: o.Value + rhs.Value}, nil
 | 
			
		||||
		default:
 | 
			
		||||
			return &String{Value: o.Value + rhs.String()}, nil
 | 
			
		||||
			rhsStr := rhs.String()
 | 
			
		||||
			if len(o.Value)+len(rhsStr) > tengo.MaxStringLen {
 | 
			
		||||
				return nil, ErrStringLimit
 | 
			
		||||
			}
 | 
			
		||||
			return &String{Value: o.Value + rhsStr}, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										673
									
								
								vendor/github.com/d5/tengo/runtime/vm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										673
									
								
								vendor/github.com/d5/tengo/runtime/vm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										83
									
								
								vendor/github.com/d5/tengo/script/script.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										83
									
								
								vendor/github.com/d5/tengo/script/script.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -9,16 +9,15 @@ import (
 | 
			
		||||
	"github.com/d5/tengo/compiler/source"
 | 
			
		||||
	"github.com/d5/tengo/objects"
 | 
			
		||||
	"github.com/d5/tengo/runtime"
 | 
			
		||||
	"github.com/d5/tengo/stdlib"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Script can simplify compilation and execution of embedded scripts.
 | 
			
		||||
type Script struct {
 | 
			
		||||
	variables         map[string]*Variable
 | 
			
		||||
	removedBuiltins   map[string]bool
 | 
			
		||||
	removedStdModules map[string]bool
 | 
			
		||||
	userModuleLoader  compiler.ModuleLoader
 | 
			
		||||
	input             []byte
 | 
			
		||||
	variables        map[string]*Variable
 | 
			
		||||
	builtinFuncs     []objects.Object
 | 
			
		||||
	builtinModules   map[string]*objects.Object
 | 
			
		||||
	userModuleLoader compiler.ModuleLoader
 | 
			
		||||
	input            []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a Script instance with an input script.
 | 
			
		||||
@@ -56,22 +55,28 @@ func (s *Script) Remove(name string) bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DisableBuiltinFunction disables a builtin function.
 | 
			
		||||
func (s *Script) DisableBuiltinFunction(name string) {
 | 
			
		||||
	if s.removedBuiltins == nil {
 | 
			
		||||
		s.removedBuiltins = make(map[string]bool)
 | 
			
		||||
// 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{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.removedBuiltins[name] = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DisableStdModule disables a standard library module.
 | 
			
		||||
func (s *Script) DisableStdModule(name string) {
 | 
			
		||||
	if s.removedStdModules == nil {
 | 
			
		||||
		s.removedStdModules = make(map[string]bool)
 | 
			
		||||
// 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{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.removedStdModules[name] = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetUserModuleLoader sets the user module loader for the compiler.
 | 
			
		||||
@@ -81,7 +86,7 @@ func (s *Script) SetUserModuleLoader(loader compiler.ModuleLoader) {
 | 
			
		||||
 | 
			
		||||
// Compile compiles the script with all the defined variables, and, returns Compiled object.
 | 
			
		||||
func (s *Script) Compile() (*Compiled, error) {
 | 
			
		||||
	symbolTable, stdModules, globals, err := s.prepCompile()
 | 
			
		||||
	symbolTable, builtinModules, globals, err := s.prepCompile()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -92,10 +97,10 @@ func (s *Script) Compile() (*Compiled, error) {
 | 
			
		||||
	p := parser.NewParser(srcFile, s.input, nil)
 | 
			
		||||
	file, err := p.ParseFile()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("parse error: %s", err.Error())
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c := compiler.NewCompiler(srcFile, symbolTable, nil, stdModules, nil)
 | 
			
		||||
	c := compiler.NewCompiler(srcFile, symbolTable, nil, builtinModules, nil)
 | 
			
		||||
 | 
			
		||||
	if s.userModuleLoader != nil {
 | 
			
		||||
		c.SetModuleLoader(s.userModuleLoader)
 | 
			
		||||
@@ -107,7 +112,7 @@ func (s *Script) Compile() (*Compiled, error) {
 | 
			
		||||
 | 
			
		||||
	return &Compiled{
 | 
			
		||||
		symbolTable: symbolTable,
 | 
			
		||||
		machine:     runtime.NewVM(c.Bytecode(), globals, nil),
 | 
			
		||||
		machine:     runtime.NewVM(c.Bytecode(), globals, s.builtinFuncs, s.builtinModules),
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -136,24 +141,36 @@ func (s *Script) RunContext(ctx context.Context) (compiled *Compiled, err error)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Script) prepCompile() (symbolTable *compiler.SymbolTable, stdModules map[string]bool, globals []*objects.Object, err error) {
 | 
			
		||||
func (s *Script) prepCompile() (symbolTable *compiler.SymbolTable, builtinModules map[string]bool, globals []*objects.Object, err error) {
 | 
			
		||||
	var names []string
 | 
			
		||||
	for name := range s.variables {
 | 
			
		||||
		names = append(names, name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	symbolTable = compiler.NewSymbolTable()
 | 
			
		||||
	for idx, fn := range objects.Builtins {
 | 
			
		||||
		if !s.removedBuiltins[fn.Name] {
 | 
			
		||||
			symbolTable.DefineBuiltin(idx, fn.Name)
 | 
			
		||||
 | 
			
		||||
	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,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stdModules = make(map[string]bool)
 | 
			
		||||
	for name := range stdlib.Modules {
 | 
			
		||||
		if !s.removedStdModules[name] {
 | 
			
		||||
			stdModules[name] = true
 | 
			
		||||
		}
 | 
			
		||||
	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)
 | 
			
		||||
@@ -178,3 +195,7 @@ func (s *Script) copyVariables() map[string]*Variable {
 | 
			
		||||
 | 
			
		||||
	return vars
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func objectPtr(o objects.Object) *objects.Object {
 | 
			
		||||
	return &o
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/github.com/d5/tengo/stdlib/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/d5/tengo/stdlib/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,11 +0,0 @@
 | 
			
		||||
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()}}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1057
									
								
								vendor/github.com/d5/tengo/stdlib/func_typedefs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1057
									
								
								vendor/github.com/d5/tengo/stdlib/func_typedefs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										74
									
								
								vendor/github.com/d5/tengo/stdlib/math.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/d5/tengo/stdlib/math.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,74 +0,0 @@
 | 
			
		||||
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)},
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										437
									
								
								vendor/github.com/d5/tengo/stdlib/os.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										437
									
								
								vendor/github.com/d5/tengo/stdlib/os.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,437 +0,0 @@
 | 
			
		||||
package stdlib
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
 | 
			
		||||
	"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{Value: osArgs},                                           // args() => array(string)
 | 
			
		||||
	"chdir":               &objects.UserFunction{Name: "chdir", Value: FuncASRE(os.Chdir)},                // chdir(dir string) => error
 | 
			
		||||
	"chmod":               osFuncASFmRE(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: FuncASRS(os.ExpandEnv)},       // 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{Value: osLookupEnv},                                      // lookup_env(key string) => string/false
 | 
			
		||||
	"mkdir":               osFuncASFmRE(os.Mkdir),                                                         // mkdir(name string, perm int) => error
 | 
			
		||||
	"mkdir_all":           osFuncASFmRE(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{Value: osCreate},                                         // create(name string) => imap(file)/error
 | 
			
		||||
	"open":                &objects.UserFunction{Value: osOpen},                                           // open(name string) => imap(file)/error
 | 
			
		||||
	"open_file":           &objects.UserFunction{Value: osOpenFile},                                       // open_file(name string, flag int, perm int) => imap(file)/error
 | 
			
		||||
	"find_process":        &objects.UserFunction{Value: osFindProcess},                                    // find_process(pid int) => imap(process)/error
 | 
			
		||||
	"start_process":       &objects.UserFunction{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{Value: osExec},                                           // exec(name, args...) => command
 | 
			
		||||
	"stat":                &objects.UserFunction{Value: osStat},                                           // stat(name) => imap(fileinfo)/error
 | 
			
		||||
	"read_file":           &objects.UserFunction{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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 {
 | 
			
		||||
		arr.Value = append(arr.Value, &objects.String{Value: osArg})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return arr, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func osFuncASFmRE(fn func(string, os.FileMode) error) *objects.UserFunction {
 | 
			
		||||
	return &objects.UserFunction{
 | 
			
		||||
		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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &objects.String{Value: res}, 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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								vendor/github.com/d5/tengo/stdlib/os_exec.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										109
									
								
								vendor/github.com/d5/tengo/stdlib/os_exec.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,109 +0,0 @@
 | 
			
		||||
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{
 | 
			
		||||
				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{
 | 
			
		||||
				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{
 | 
			
		||||
				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{
 | 
			
		||||
				Value: func(args ...objects.Object) (ret objects.Object, err error) {
 | 
			
		||||
					if len(args) != 0 {
 | 
			
		||||
						return nil, objects.ErrWrongNumArguments
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					return makeOSProcess(cmd.Process), nil
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										93
									
								
								vendor/github.com/d5/tengo/stdlib/os_file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										93
									
								
								vendor/github.com/d5/tengo/stdlib/os_file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,93 +0,0 @@
 | 
			
		||||
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{
 | 
			
		||||
				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{
 | 
			
		||||
				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{
 | 
			
		||||
				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()})
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								vendor/github.com/d5/tengo/stdlib/os_process.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/d5/tengo/stdlib/os_process.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,60 +0,0 @@
 | 
			
		||||
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{
 | 
			
		||||
				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{
 | 
			
		||||
				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
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								vendor/github.com/d5/tengo/stdlib/rand.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										99
									
								
								vendor/github.com/d5/tengo/stdlib/rand.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,99 +0,0 @@
 | 
			
		||||
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{
 | 
			
		||||
		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{
 | 
			
		||||
		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{
 | 
			
		||||
				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
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/d5/tengo/stdlib/stdlib.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/d5/tengo/stdlib/stdlib.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,16 +0,0 @@
 | 
			
		||||
package stdlib
 | 
			
		||||
 | 
			
		||||
import "github.com/d5/tengo/objects"
 | 
			
		||||
 | 
			
		||||
// Modules contain the standard modules.
 | 
			
		||||
var Modules = map[string]*objects.Object{
 | 
			
		||||
	"math":  objectPtr(&objects.ImmutableMap{Value: mathModule}),
 | 
			
		||||
	"os":    objectPtr(&objects.ImmutableMap{Value: osModule}),
 | 
			
		||||
	"text":  objectPtr(&objects.ImmutableMap{Value: textModule}),
 | 
			
		||||
	"times": objectPtr(&objects.ImmutableMap{Value: timesModule}),
 | 
			
		||||
	"rand":  objectPtr(&objects.ImmutableMap{Value: randModule}),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func objectPtr(o objects.Object) *objects.Object {
 | 
			
		||||
	return &o
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										585
									
								
								vendor/github.com/d5/tengo/stdlib/text.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										585
									
								
								vendor/github.com/d5/tengo/stdlib/text.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,585 +0,0 @@
 | 
			
		||||
package stdlib
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/d5/tengo/objects"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var textModule = map[string]objects.Object{
 | 
			
		||||
	"re_match":       &objects.UserFunction{Value: textREMatch},                                             // re_match(pattern, text) => bool/error
 | 
			
		||||
	"re_find":        &objects.UserFunction{Value: textREFind},                                              // re_find(pattern, text, count) => [[{text:,begin:,end:}]]/undefined
 | 
			
		||||
	"re_replace":     &objects.UserFunction{Value: textREReplace},                                           // re_replace(pattern, text, repl) => string/error
 | 
			
		||||
	"re_split":       &objects.UserFunction{Value: textRESplit},                                             // re_split(pattern, text, count) => [string]/error
 | 
			
		||||
	"re_compile":     &objects.UserFunction{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: FuncASsSRS(strings.Join)},                  // 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: FuncASIRS(strings.Repeat)},               // repeat(s, count) => string
 | 
			
		||||
	"replace":        &objects.UserFunction{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{Value: textFormatBool},                                          // format_bool(b) => string
 | 
			
		||||
	"format_float":   &objects.UserFunction{Value: textFormatFloat},                                         // format_float(f, fmt, prec, bits) => string
 | 
			
		||||
	"format_int":     &objects.UserFunction{Value: textFormatInt},                                           // format_int(i, base) => string
 | 
			
		||||
	"itoa":           &objects.UserFunction{Name: "itoa", Value: FuncAIRS(strconv.Itoa)},                    // itoa(i) => string
 | 
			
		||||
	"parse_bool":     &objects.UserFunction{Value: textParseBool},                                           // parse_bool(str) => bool/error
 | 
			
		||||
	"parse_float":    &objects.UserFunction{Value: textParseFloat},                                          // parse_float(str, bits) => float/error
 | 
			
		||||
	"parse_int":      &objects.UserFunction{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 {
 | 
			
		||||
		ret = &objects.String{Value: re.ReplaceAllString(s2, s3)}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = &objects.String{Value: strings.Replace(s1, s2, s3, i4)}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										195
									
								
								vendor/github.com/d5/tengo/stdlib/text_regexp.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										195
									
								
								vendor/github.com/d5/tengo/stdlib/text_regexp.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,195 +0,0 @@
 | 
			
		||||
package stdlib
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"regexp"
 | 
			
		||||
 | 
			
		||||
	"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
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					ret = &objects.String{Value: re.ReplaceAllString(s1, s2)}
 | 
			
		||||
 | 
			
		||||
					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
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										982
									
								
								vendor/github.com/d5/tengo/stdlib/times.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										982
									
								
								vendor/github.com/d5/tengo/stdlib/times.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,982 +0,0 @@
 | 
			
		||||
package stdlib
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = &objects.String{Value: t1.Format(s2)}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/github.com/d5/tengo/tengo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/d5/tengo/tengo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
package tengo
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// MaxStringLen is the maximum byte-length for string value.
 | 
			
		||||
	// Note this limit applies to all compiler/VM instances in the process.
 | 
			
		||||
	MaxStringLen = 2147483647
 | 
			
		||||
 | 
			
		||||
	// MaxBytesLen is the maximum length for bytes value.
 | 
			
		||||
	// Note this limit applies to all compiler/VM instances in the process.
 | 
			
		||||
	MaxBytesLen = 2147483647
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@@ -17,14 +17,14 @@ 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.9.2
 | 
			
		||||
# github.com/d5/tengo v1.12.1
 | 
			
		||||
github.com/d5/tengo/script
 | 
			
		||||
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/stdlib
 | 
			
		||||
github.com/d5/tengo
 | 
			
		||||
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