mirror of
https://github.com/cwinfo/matterbridge.git
synced 2025-06-27 18:09:26 +00:00
Compare commits
14 Commits
v1.14.0-rc
...
v1.14.0
Author | SHA1 | Date | |
---|---|---|---|
fa4eec41f7 | |||
77516c97db | |||
cba01f0865 | |||
8b754017ca | |||
a27600046e | |||
fb2667631d | |||
b638f7037a | |||
74699a8262 | |||
eabf2a4582 | |||
325d62b41c | |||
e955a056e2 | |||
723f8c5fd5 | |||
a16137f53f | |||
d60b8b97f9 |
@ -158,7 +158,6 @@ linters-settings:
|
|||||||
- regexpMust
|
- regexpMust
|
||||||
- singleCaseSwitch
|
- singleCaseSwitch
|
||||||
- sloppyLen
|
- sloppyLen
|
||||||
- sloppyReassign
|
|
||||||
- switchTrue
|
- switchTrue
|
||||||
- typeSwitchVar
|
- typeSwitchVar
|
||||||
- typeUnparen
|
- typeUnparen
|
||||||
|
12
.travis.yml
12
.travis.yml
@ -12,6 +12,7 @@ git:
|
|||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- GOOS=linux GOARCH=amd64
|
- GOOS=linux GOARCH=amd64
|
||||||
|
- GO111MODULE=on
|
||||||
- GOLANGCI_VERSION="v1.14.0"
|
- GOLANGCI_VERSION="v1.14.0"
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
@ -36,10 +37,17 @@ before_script:
|
|||||||
- ./cc-test-reporter before-build
|
- ./cc-test-reporter before-build
|
||||||
|
|
||||||
script:
|
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.
|
# Run the linter.
|
||||||
- golangci-lint run
|
- golangci-lint run
|
||||||
|
|
||||||
# Run all the tests with the race detector and generate coverage.
|
# Run all the tests with the race detector and generate coverage.
|
||||||
- go test -v -race -coverprofile c.out ./...
|
- go test -v -race -coverprofile c.out ./...
|
||||||
|
|
||||||
# Run the build script to generate the necessary binaries and images.
|
# Run the build script to generate the necessary binaries and images.
|
||||||
- /bin/bash ci/bintray.sh
|
- /bin/bash ci/bintray.sh
|
||||||
|
|
||||||
@ -47,6 +55,10 @@ after_script:
|
|||||||
# Upload test coverage to CodeClimate.
|
# Upload test coverage to CodeClimate.
|
||||||
- ./cc-test-reporter after-build --exit-code ${TRAVIS_TEST_RESULT}
|
- ./cc-test-reporter after-build --exit-code ${TRAVIS_TEST_RESULT}
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
on:
|
on:
|
||||||
all_branches: true
|
all_branches: true
|
||||||
|
@ -88,6 +88,7 @@
|
|||||||
* [Minecraft](https://github.com/elytra/MatterLink)
|
* [Minecraft](https://github.com/elytra/MatterLink)
|
||||||
* [Reddit](https://github.com/bonehurtingjuice/mattereddit)
|
* [Reddit](https://github.com/bonehurtingjuice/mattereddit)
|
||||||
* [Facebook messenger](https://github.com/VictorNine/fbridge)
|
* [Facebook messenger](https://github.com/VictorNine/fbridge)
|
||||||
|
* [Discourse](https://github.com/DeclanHoare/matterbabble)
|
||||||
|
|
||||||
### API
|
### API
|
||||||
The API is very basic at the moment.
|
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)
|
* [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot)
|
||||||
* [Mattereddit](https://github.com/bonehurtingjuice/mattereddit) (Reddit chat support)
|
* [Mattereddit](https://github.com/bonehurtingjuice/mattereddit) (Reddit chat support)
|
||||||
* [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support)
|
* [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support)
|
||||||
|
* [matterbabble](https://github.com/DeclanHoare/matterbabble) (Discourse support)
|
||||||
|
|
||||||
## Chat with us
|
## Chat with us
|
||||||
|
|
||||||
@ -121,7 +123,7 @@ See https://github.com/42wim/matterbridge/wiki
|
|||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
### Binaries
|
### Binaries
|
||||||
* Latest stable release [v1.13.1](https://github.com/42wim/matterbridge/releases/latest)
|
* Latest stable release [v1.14.0](https://github.com/42wim/matterbridge/releases/latest)
|
||||||
* Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)
|
* Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)
|
||||||
|
|
||||||
### Packages
|
### 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
|
* [mattermost-plugin](https://github.com/matterbridge/mattermost-plugin) - Run matterbridge as a plugin in mattermost
|
||||||
* [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot)
|
* [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot)
|
||||||
* [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support)
|
* [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
|
## Articles
|
||||||
* [matterbridge on kubernetes](https://medium.freecodecamp.org/using-kubernetes-to-deploy-a-chat-gateway-or-when-technology-works-like-its-supposed-to-a169a8cd69a3)
|
* [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 {
|
func ParseMarkdown(input string) string {
|
||||||
md := markdown.New(markdown.XHTMLOutput(true), markdown.Breaks(true))
|
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)
|
// ConvertWebPToPNG convert input data (which should be WebP format to PNG format)
|
||||||
|
@ -2,6 +2,7 @@ package brocketchat
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/42wim/matterbridge/bridge"
|
"github.com/42wim/matterbridge/bridge"
|
||||||
@ -85,14 +86,14 @@ func (b *Brocketchat) JoinChannel(channel config.ChannelInfo) error {
|
|||||||
if b.c == nil {
|
if b.c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
id, err := b.c.GetChannelId(channel.Name)
|
id, err := b.c.GetChannelId(strings.TrimPrefix(channel.Name, "#"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
b.Lock()
|
b.Lock()
|
||||||
b.channelMap[id] = channel.Name
|
b.channelMap[id] = channel.Name
|
||||||
b.Unlock()
|
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 {
|
if err := b.c.JoinChannel(id); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -103,6 +104,8 @@ func (b *Brocketchat) JoinChannel(channel config.ChannelInfo) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Brocketchat) Send(msg config.Message) (string, 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}
|
channel := &models.Channel{ID: b.getChannelID(msg.Channel), Name: msg.Channel}
|
||||||
|
|
||||||
// Delete message
|
// Delete message
|
||||||
@ -131,6 +134,8 @@ func (b *Brocketchat) Send(msg config.Message) (string, error) {
|
|||||||
// Upload a file if it exists
|
// Upload a file if it exists
|
||||||
if msg.Extra != nil {
|
if msg.Extra != nil {
|
||||||
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
|
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
|
||||||
|
// strip the # if people has set this
|
||||||
|
rmsg.Channel = strings.TrimPrefix(rmsg.Channel, "#")
|
||||||
smsg := &models.Message{
|
smsg := &models.Message{
|
||||||
RoomID: b.getChannelID(rmsg.Channel),
|
RoomID: b.getChannelID(rmsg.Channel),
|
||||||
Msg: rmsg.Username + rmsg.Text,
|
Msg: rmsg.Username + rmsg.Text,
|
||||||
|
@ -34,7 +34,7 @@ func (b *Bslack) handleSlack() {
|
|||||||
message.Text = html.UnescapeString(message.Text)
|
message.Text = html.UnescapeString(message.Text)
|
||||||
|
|
||||||
// Add the avatar
|
// Add the avatar
|
||||||
message.Avatar = b.getAvatar(message.UserID)
|
message.Avatar = b.users.getAvatar(message.UserID)
|
||||||
|
|
||||||
b.Log.Debugf("<= Message is %#v", message)
|
b.Log.Debugf("<= Message is %#v", message)
|
||||||
b.Remote <- *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
|
// 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
|
// well as the information for the channel that we joined as this
|
||||||
// should now tell that we are a member of it.
|
// should now tell that we are a member of it.
|
||||||
b.channelsMutex.Lock()
|
b.channels.registerChannel(ev.Channel)
|
||||||
b.channelsByID[ev.Channel.ID] = &ev.Channel
|
|
||||||
b.channelsByName[ev.Channel.Name] = &ev.Channel
|
|
||||||
b.channelsMutex.Unlock()
|
|
||||||
case *slack.ConnectedEvent:
|
case *slack.ConnectedEvent:
|
||||||
b.si = ev.Info
|
b.si = ev.Info
|
||||||
b.populateChannels(true)
|
b.channels.populateChannels(true)
|
||||||
b.populateUsers(true)
|
b.users.populateUsers(true)
|
||||||
case *slack.InvalidAuthEvent:
|
case *slack.InvalidAuthEvent:
|
||||||
b.Log.Fatalf("Invalid Token %#v", ev)
|
b.Log.Fatalf("Invalid Token %#v", ev)
|
||||||
case *slack.ConnectionErrorEvent:
|
case *slack.ConnectionErrorEvent:
|
||||||
b.Log.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj)
|
b.Log.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj)
|
||||||
case *slack.MemberJoinedChannelEvent:
|
case *slack.MemberJoinedChannelEvent:
|
||||||
b.populateUser(ev.User)
|
b.users.populateUser(ev.User)
|
||||||
case *slack.LatencyReport:
|
case *slack.LatencyReport:
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
@ -210,7 +207,7 @@ func (b *Bslack) handleStatusEvent(ev *slack.MessageEvent, rmsg *config.Message)
|
|||||||
rmsg.Username = sSystemUser
|
rmsg.Username = sSystemUser
|
||||||
rmsg.Event = config.EventJoinLeave
|
rmsg.Event = config.EventJoinLeave
|
||||||
case sChannelTopic, sChannelPurpose:
|
case sChannelTopic, sChannelPurpose:
|
||||||
b.populateChannels(false)
|
b.channels.populateChannels(false)
|
||||||
rmsg.Event = config.EventTopicChange
|
rmsg.Event = config.EventTopicChange
|
||||||
case sMessageChanged:
|
case sMessageChanged:
|
||||||
rmsg.Text = ev.SubMessage.Text
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -316,36 +313,7 @@ func (b *Bslack) handleGetChannelMembers(rmsg *config.Message) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
cMembers := config.ChannelMembers{}
|
cMembers := b.channels.getChannelMembers(b.users)
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
extra := make(map[string][]interface{})
|
extra := make(map[string][]interface{})
|
||||||
extra[config.EventGetChannelMembers] = append(extra[config.EventGetChannelMembers], cMembers)
|
extra[config.EventGetChannelMembers] = append(extra[config.EventGetChannelMembers], cMembers)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package bslack
|
package bslack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@ -9,225 +8,14 @@ import (
|
|||||||
|
|
||||||
"github.com/42wim/matterbridge/bridge/config"
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
"github.com/nlopes/slack"
|
"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
|
// populateReceivedMessage shapes the initial Matterbridge message that we will forward to the
|
||||||
// router before we apply message-dependent modifications.
|
// router before we apply message-dependent modifications.
|
||||||
func (b *Bslack) populateReceivedMessage(ev *slack.MessageEvent) (*config.Message, error) {
|
func (b *Bslack) populateReceivedMessage(ev *slack.MessageEvent) (*config.Message, error) {
|
||||||
// Use our own func because rtm.GetChannelInfo doesn't work for private channels.
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -289,7 +77,7 @@ func (b *Bslack) populateMessageWithUserInfo(ev *slack.MessageEvent, rmsg *confi
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
user := b.getUser(userID)
|
user := b.users.getUser(userID)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return fmt.Errorf("could not find information for user with id %s", ev.User)
|
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
|
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)
|
b.Log.Errorf("Could not retrieve bot information: %#v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -360,7 +148,7 @@ func (b *Bslack) extractTopicOrPurpose(text string) (string, string) {
|
|||||||
func (b *Bslack) replaceMention(text string) string {
|
func (b *Bslack) replaceMention(text string) string {
|
||||||
replaceFunc := func(match string) string {
|
replaceFunc := func(match string) string {
|
||||||
userID := strings.Trim(match, "@<>")
|
userID := strings.Trim(match, "@<>")
|
||||||
if username := b.getUsername(userID); userID != "" {
|
if username := b.users.getUsername(userID); userID != "" {
|
||||||
return "@" + username
|
return "@" + username
|
||||||
}
|
}
|
||||||
return match
|
return match
|
||||||
@ -404,16 +192,6 @@ func (b *Bslack) replaceCodeFence(text string) string {
|
|||||||
return codeFenceRE.ReplaceAllString(text, "```")
|
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
|
// getUsersInConversation returns an array of userIDs that are members of channelID
|
||||||
func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) {
|
func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) {
|
||||||
channelMembers := []string{}
|
channelMembers := []string{}
|
||||||
@ -424,7 +202,7 @@ func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) {
|
|||||||
|
|
||||||
members, nextCursor, err := b.sc.GetUsersInConversation(queryParams)
|
members, nextCursor, err := b.sc.GetUsersInConversation(queryParams)
|
||||||
if err != nil {
|
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)
|
return channelMembers, fmt.Errorf("Could not retrieve users in channels: %#v", err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
@ -439,3 +217,13 @@ func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) {
|
|||||||
}
|
}
|
||||||
return channelMembers, nil
|
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) != "" {
|
if b.GetString(tokenConfig) != "" {
|
||||||
b.Log.Info("Connecting using token (receiving)")
|
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()
|
b.rtm = b.sc.NewRTM()
|
||||||
go b.rtm.ManageConnection()
|
go b.rtm.ManageConnection()
|
||||||
go b.handleSlack()
|
go b.handleSlack()
|
||||||
}
|
}
|
||||||
} else if b.GetString(tokenConfig) != "" {
|
} else if b.GetString(tokenConfig) != "" {
|
||||||
b.Log.Info("Connecting using token (sending and receiving)")
|
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()
|
b.rtm = b.sc.NewRTM()
|
||||||
go b.rtm.ManageConnection()
|
go b.rtm.ManageConnection()
|
||||||
go b.handleSlack()
|
go b.handleSlack()
|
||||||
|
@ -30,20 +30,8 @@ type Bslack struct {
|
|||||||
uuid string
|
uuid string
|
||||||
useChannelID bool
|
useChannelID bool
|
||||||
|
|
||||||
users map[string]*slack.User
|
channels *channels
|
||||||
usersMutex sync.RWMutex
|
users *users
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -97,11 +85,6 @@ func newBridge(cfg *bridge.Config) *Bslack {
|
|||||||
Config: cfg,
|
Config: cfg,
|
||||||
uuid: xid.New().String(),
|
uuid: xid.New().String(),
|
||||||
cache: newCache,
|
cache: newCache,
|
||||||
users: map[string]*slack.User{},
|
|
||||||
channelsByID: map[string]*slack.Channel{},
|
|
||||||
channelsByName: map[string]*slack.Channel{},
|
|
||||||
earliestChannelRefresh: time.Now(),
|
|
||||||
earliestUserRefresh: time.Now(),
|
|
||||||
}
|
}
|
||||||
return b
|
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 we have a token we use the Slack websocket-based RTM for both sending and receiving.
|
||||||
if token := b.GetString(tokenConfig); token != "" {
|
if token := b.GetString(tokenConfig); token != "" {
|
||||||
b.Log.Info("Connecting using token")
|
b.Log.Info("Connecting using token")
|
||||||
|
|
||||||
b.sc = slack.New(token, slack.OptionDebug(b.GetBool("Debug")))
|
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()
|
b.rtm = b.sc.NewRTM()
|
||||||
go b.rtm.ManageConnection()
|
go b.rtm.ManageConnection()
|
||||||
go b.handleSlack()
|
go b.handleSlack()
|
||||||
@ -163,9 +151,9 @@ func (b *Bslack) JoinChannel(channel config.ChannelInfo) error {
|
|||||||
return nil
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("could not join channel: %#v", err)
|
return fmt.Errorf("could not join channel: %#v", err)
|
||||||
}
|
}
|
||||||
@ -275,7 +263,7 @@ func (b *Bslack) sendRTM(msg config.Message) (string, error) {
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
channelInfo, err := b.getChannel(msg.Channel)
|
channelInfo, err := b.channels.getChannel(msg.Channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("could not send message: %v", err)
|
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 {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err = b.handleRateLimit(err); err != nil {
|
if err = handleRateLimit(b.Log, err); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,7 +380,7 @@ func (b *Bslack) deleteMessage(msg *config.Message, channelInfo *slack.Channel)
|
|||||||
return true, nil
|
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)
|
b.Log.Errorf("Failed to delete user message from Slack: %#v", err)
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
@ -411,7 +399,7 @@ func (b *Bslack) editMessage(msg *config.Message, channelInfo *slack.Channel) (b
|
|||||||
return true, nil
|
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)
|
b.Log.Errorf("Failed to edit user message on Slack: %#v", err)
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
@ -424,14 +412,18 @@ func (b *Bslack) postMessage(msg *config.Message, channelInfo *slack.Channel) (s
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
messageOptions := b.prepareMessageOptions(msg)
|
messageOptions := b.prepareMessageOptions(msg)
|
||||||
messageOptions = append(messageOptions, slack.MsgOptionText(msg.Text, false))
|
messageOptions = append(
|
||||||
|
messageOptions,
|
||||||
|
slack.MsgOptionText(msg.Text, false),
|
||||||
|
slack.MsgOptionEnableLinkUnfurl(),
|
||||||
|
)
|
||||||
for {
|
for {
|
||||||
_, id, err := b.rtm.PostMessage(channelInfo.ID, messageOptions...)
|
_, id, err := b.rtm.PostMessage(channelInfo.ID, messageOptions...)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return id, 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)
|
b.Log.Errorf("Failed to sent user message to Slack: %#v", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
336
bridge/slack/users_channels.go
Normal file
336
bridge/slack/users_channels.go
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
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{})
|
||||||
|
b.usersMutex.Unlock()
|
||||||
|
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
|
||||||
|
}
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
## Enhancements
|
## Enhancements
|
||||||
* general: Fail gracefully on incorrect human input. Fixes #739 (#740)
|
* 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
|
## Bugfix
|
||||||
* general: Handle file upload/download only once for each message (#742)
|
* general: Handle file upload/download only once for each message (#742)
|
||||||
@ -27,9 +29,9 @@
|
|||||||
* irc: add support for (older) unrealircd versions. #708
|
* irc: add support for (older) unrealircd versions. #708
|
||||||
* irc: Support quits from irc correctly. Fixes #722 (#724)
|
* irc: Support quits from irc correctly. Fixes #722 (#724)
|
||||||
* matrix: Send username when uploading video/images (matrix). Fixes #715 (#717)
|
* matrix: Send username when uploading video/images (matrix). Fixes #715 (#717)
|
||||||
* matrix: Send notices on join/parts (matrix). Fixes #712 (#716)
|
* matrix: Trim <p> and </p> tags (matrix). Closes #686 (#753)
|
||||||
* matrix: Detect html nicks in RemoteNickFormat (matrix). Fixes #696 (#719)
|
|
||||||
* slack: Hint at thread replies when messages are unthreaded (slack) (#684)
|
* 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)
|
* xmpp: Do not send topic changes on connect (xmpp). Fixes #732 (#733)
|
||||||
* telegram: Fix regression in HTML handling (telegram). Closes #734
|
* telegram: Fix regression in HTML handling (telegram). Closes #734
|
||||||
* discord: Do not relay any bot messages (discord) (#743)
|
* 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/Jeffail/gabs v1.1.1 // indirect
|
||||||
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329
|
github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329
|
||||||
github.com/bwmarrin/discordgo v0.19.0
|
github.com/bwmarrin/discordgo v0.19.0
|
||||||
github.com/d5/tengo v1.9.2
|
github.com/d5/tengo v1.12.1
|
||||||
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
|
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
|
||||||
github.com/fsnotify/fsnotify v1.4.7
|
github.com/fsnotify/fsnotify v1.4.7
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible
|
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible
|
||||||
|
4
go.sum
4
go.sum
@ -15,8 +15,8 @@ github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVO
|
|||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/d5/tengo v1.9.2 h1:UE/X8PYl7bLS4Ww2zGeh91nq5PTnkhe8ncgNeA5PK7k=
|
github.com/d5/tengo v1.12.1 h1:libKkDM95CsZgYs6E5eiEaM9sbcw2EzJRSkr9o5NO4s=
|
||||||
github.com/d5/tengo v1.9.2/go.mod h1:gsbjo7lBXzBIWBd6NQp1lRKqqiDDANqBOyhW8rTlFsY=
|
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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
version = "1.14.0-rc2"
|
version = "1.14.0"
|
||||||
githash string
|
githash string
|
||||||
|
|
||||||
flagConfig = flag.String("conf", "matterbridge.toml", "config file")
|
flagConfig = flag.String("conf", "matterbridge.toml", "config file")
|
||||||
|
@ -1007,9 +1007,10 @@ ShowTopicChange=false
|
|||||||
Server="https://yourrocketchatserver.domain.com:443"
|
Server="https://yourrocketchatserver.domain.com:443"
|
||||||
|
|
||||||
#login/pass of your bot.
|
#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!
|
#Use a dedicated user for this and not your own!
|
||||||
#REQUIRED (when not using webhooks)
|
#REQUIRED (when not using webhooks)
|
||||||
Login="yourlogin"
|
Login="yourlogin@domain.com"
|
||||||
Password="yourpass"
|
Password="yourpass"
|
||||||
|
|
||||||
#### Settings for webhook matterbridge.
|
#### Settings for webhook matterbridge.
|
||||||
|
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"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
"github.com/d5/tengo/compiler/ast"
|
"github.com/d5/tengo/compiler/ast"
|
||||||
"github.com/d5/tengo/compiler/source"
|
"github.com/d5/tengo/compiler/source"
|
||||||
"github.com/d5/tengo/compiler/token"
|
"github.com/d5/tengo/compiler/token"
|
||||||
"github.com/d5/tengo/objects"
|
"github.com/d5/tengo/objects"
|
||||||
"github.com/d5/tengo/stdlib"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Compiler compiles the AST into a bytecode.
|
// Compiler compiles the AST into a bytecode.
|
||||||
@ -54,9 +54,6 @@ func NewCompiler(file *source.File, symbolTable *SymbolTable, constants []object
|
|||||||
// builtin modules
|
// builtin modules
|
||||||
if builtinModules == nil {
|
if builtinModules == nil {
|
||||||
builtinModules = make(map[string]bool)
|
builtinModules = make(map[string]bool)
|
||||||
for name := range stdlib.Modules {
|
|
||||||
builtinModules[name] = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Compiler{
|
return &Compiler{
|
||||||
@ -195,6 +192,10 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case *ast.StringLit:
|
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}))
|
c.emit(node, OpConstant, c.addConstant(&objects.String{Value: node.Value}))
|
||||||
|
|
||||||
case *ast.CharLit:
|
case *ast.CharLit:
|
||||||
@ -332,6 +333,9 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
case *ast.MapLit:
|
case *ast.MapLit:
|
||||||
for _, elt := range node.Elements {
|
for _, elt := range node.Elements {
|
||||||
// key
|
// key
|
||||||
|
if len(elt.Key) > tengo.MaxStringLen {
|
||||||
|
return c.error(node, objects.ErrStringLimit)
|
||||||
|
}
|
||||||
c.emit(node, OpConstant, c.addConstant(&objects.String{Value: elt.Key}))
|
c.emit(node, OpConstant, c.addConstant(&objects.String{Value: elt.Key}))
|
||||||
|
|
||||||
// value
|
// value
|
||||||
@ -507,6 +511,10 @@ func (c *Compiler) Compile(node ast.Node) error {
|
|||||||
|
|
||||||
case *ast.ImportExpr:
|
case *ast.ImportExpr:
|
||||||
if c.builtinModules[node.ModuleName] {
|
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, OpConstant, c.addConstant(&objects.String{Value: node.ModuleName}))
|
||||||
c.emit(node, OpGetBuiltinModule)
|
c.emit(node, OpGetBuiltinModule)
|
||||||
} else {
|
} else {
|
||||||
@ -610,6 +618,14 @@ func (c *Compiler) fork(file *source.File, moduleName string, symbolTable *Symbo
|
|||||||
return child
|
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 {
|
func (c *Compiler) errorf(node ast.Node, format string, args ...interface{}) error {
|
||||||
return &Error{
|
return &Error{
|
||||||
fileSet: c.file.Set(),
|
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()
|
symbolTable := NewSymbolTable()
|
||||||
|
|
||||||
// inherit builtin functions
|
// inherit builtin functions
|
||||||
for idx, fn := range objects.Builtins {
|
for _, sym := range c.symbolTable.BuiltinSymbols() {
|
||||||
s, _, ok := c.symbolTable.Resolve(fn.Name)
|
symbolTable.DefineBuiltin(sym.Index, sym.Name)
|
||||||
if ok && s.Scope == ScopeBuiltin {
|
|
||||||
symbolTable.DefineBuiltin(idx, fn.Name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// no global scope for the module
|
// 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()
|
fileSet := source.NewFileSet()
|
||||||
file := fileSet.AddFile(filename, -1, len(src))
|
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.
|
// 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 {
|
if p.trace {
|
||||||
defer un(trace(p, "File"))
|
defer un(trace(p, "File"))
|
||||||
}
|
}
|
||||||
@ -71,10 +82,12 @@ func (p *Parser) ParseFile() (*ast.File, error) {
|
|||||||
return nil, p.errors.Err()
|
return nil, p.errors.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ast.File{
|
file = &ast.File{
|
||||||
InputFile: p.file,
|
InputFile: p.file,
|
||||||
Stmts: stmts,
|
Stmts: stmts,
|
||||||
}, nil
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) parseExpr() ast.Expr {
|
func (p *Parser) parseExpr() ast.Expr {
|
||||||
@ -1002,16 +1015,26 @@ func (p *Parser) parseMapElementLit() *ast.MapElementLit {
|
|||||||
defer un(trace(p, "MapElementLit"))
|
defer un(trace(p, "MapElementLit"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// key: read identifier token but it's not actually an identifier
|
pos := p.pos
|
||||||
ident := p.parseIdent()
|
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)
|
colonPos := p.expect(token.Colon)
|
||||||
|
|
||||||
valueExpr := p.parseExpr()
|
valueExpr := p.parseExpr()
|
||||||
|
|
||||||
return &ast.MapElementLit{
|
return &ast.MapElementLit{
|
||||||
Key: ident.Name,
|
Key: name,
|
||||||
KeyPos: ident.NamePos,
|
KeyPos: pos,
|
||||||
ColonPos: colonPos,
|
ColonPos: colonPos,
|
||||||
Value: valueExpr,
|
Value: valueExpr,
|
||||||
}
|
}
|
||||||
|
16
vendor/github.com/d5/tengo/compiler/symbol_table.go
generated
vendored
16
vendor/github.com/d5/tengo/compiler/symbol_table.go
generated
vendored
@ -8,6 +8,7 @@ type SymbolTable struct {
|
|||||||
numDefinition int
|
numDefinition int
|
||||||
maxDefinition int
|
maxDefinition int
|
||||||
freeSymbols []*Symbol
|
freeSymbols []*Symbol
|
||||||
|
builtinSymbols []*Symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSymbolTable creates a SymbolTable.
|
// NewSymbolTable creates a SymbolTable.
|
||||||
@ -37,6 +38,10 @@ func (t *SymbolTable) Define(name string) *Symbol {
|
|||||||
|
|
||||||
// DefineBuiltin adds a symbol for builtin function.
|
// DefineBuiltin adds a symbol for builtin function.
|
||||||
func (t *SymbolTable) DefineBuiltin(index int, name string) *Symbol {
|
func (t *SymbolTable) DefineBuiltin(index int, name string) *Symbol {
|
||||||
|
if t.parent != nil {
|
||||||
|
return t.parent.DefineBuiltin(index, name)
|
||||||
|
}
|
||||||
|
|
||||||
symbol := &Symbol{
|
symbol := &Symbol{
|
||||||
Name: name,
|
Name: name,
|
||||||
Index: index,
|
Index: index,
|
||||||
@ -45,6 +50,8 @@ func (t *SymbolTable) DefineBuiltin(index int, name string) *Symbol {
|
|||||||
|
|
||||||
t.store[name] = symbol
|
t.store[name] = symbol
|
||||||
|
|
||||||
|
t.builtinSymbols = append(t.builtinSymbols, symbol)
|
||||||
|
|
||||||
return symbol
|
return symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +108,15 @@ func (t *SymbolTable) FreeSymbols() []*Symbol {
|
|||||||
return t.freeSymbols
|
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.
|
// Names returns the name of all the symbols.
|
||||||
func (t *SymbolTable) Names() []string {
|
func (t *SymbolTable) Names() []string {
|
||||||
var 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
|
package objects
|
||||||
|
|
||||||
|
import "github.com/d5/tengo"
|
||||||
|
|
||||||
func builtinString(args ...Object) (Object, error) {
|
func builtinString(args ...Object) (Object, error) {
|
||||||
argsLen := len(args)
|
argsLen := len(args)
|
||||||
if !(argsLen == 1 || argsLen == 2) {
|
if !(argsLen == 1 || argsLen == 2) {
|
||||||
@ -12,6 +14,10 @@ func builtinString(args ...Object) (Object, error) {
|
|||||||
|
|
||||||
v, ok := ToString(args[0])
|
v, ok := ToString(args[0])
|
||||||
if ok {
|
if ok {
|
||||||
|
if len(v) > tengo.MaxStringLen {
|
||||||
|
return nil, ErrStringLimit
|
||||||
|
}
|
||||||
|
|
||||||
return &String{Value: v}, nil
|
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
|
// bytes(N) => create a new bytes with given size N
|
||||||
if n, ok := args[0].(*Int); ok {
|
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
|
return &Bytes{Value: make([]byte, int(n.Value))}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
v, ok := ToByteSlice(args[0])
|
v, ok := ToByteSlice(args[0])
|
||||||
if ok {
|
if ok {
|
||||||
|
if len(v) > tengo.MaxBytesLen {
|
||||||
|
return nil, ErrBytesLimit
|
||||||
|
}
|
||||||
|
|
||||||
return &Bytes{Value: v}, nil
|
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 (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// to_json(v object) => bytes
|
// to_json(v object) => bytes
|
||||||
@ -15,6 +17,10 @@ func builtinToJSON(args ...Object) (Object, error) {
|
|||||||
return &Error{Value: &String{Value: err.Error()}}, nil
|
return &Error{Value: &String{Value: err.Error()}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(res) > tengo.MaxBytesLen {
|
||||||
|
return nil, ErrBytesLimit
|
||||||
|
}
|
||||||
|
|
||||||
return &Bytes{Value: res}, nil
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// print(args...)
|
// print(args...)
|
||||||
@ -71,5 +73,11 @@ func builtinSprintf(args ...Object) (Object, error) {
|
|||||||
formatArgs[idx] = objectToInterface(arg)
|
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
|
||||||
}
|
}
|
||||||
|
105
vendor/github.com/d5/tengo/objects/builtins.go
generated
vendored
105
vendor/github.com/d5/tengo/objects/builtins.go
generated
vendored
@ -1,135 +1,164 @@
|
|||||||
package objects
|
package objects
|
||||||
|
|
||||||
// NamedBuiltinFunc is a named builtin function.
|
|
||||||
type NamedBuiltinFunc struct {
|
|
||||||
Name string
|
|
||||||
Func CallableFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
// Builtins contains all default builtin functions.
|
// Builtins contains all default builtin functions.
|
||||||
var Builtins = []NamedBuiltinFunc{
|
// Use GetBuiltinFunctions instead of accessing Builtins directly.
|
||||||
|
var Builtins = []BuiltinFunction{
|
||||||
{
|
{
|
||||||
Name: "print",
|
Name: "print",
|
||||||
Func: builtinPrint,
|
Value: builtinPrint,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "printf",
|
Name: "printf",
|
||||||
Func: builtinPrintf,
|
Value: builtinPrintf,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "sprintf",
|
Name: "sprintf",
|
||||||
Func: builtinSprintf,
|
Value: builtinSprintf,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "len",
|
Name: "len",
|
||||||
Func: builtinLen,
|
Value: builtinLen,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "copy",
|
Name: "copy",
|
||||||
Func: builtinCopy,
|
Value: builtinCopy,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "append",
|
Name: "append",
|
||||||
Func: builtinAppend,
|
Value: builtinAppend,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "string",
|
Name: "string",
|
||||||
Func: builtinString,
|
Value: builtinString,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "int",
|
Name: "int",
|
||||||
Func: builtinInt,
|
Value: builtinInt,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "bool",
|
Name: "bool",
|
||||||
Func: builtinBool,
|
Value: builtinBool,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "float",
|
Name: "float",
|
||||||
Func: builtinFloat,
|
Value: builtinFloat,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "char",
|
Name: "char",
|
||||||
Func: builtinChar,
|
Value: builtinChar,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "bytes",
|
Name: "bytes",
|
||||||
Func: builtinBytes,
|
Value: builtinBytes,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "time",
|
Name: "time",
|
||||||
Func: builtinTime,
|
Value: builtinTime,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_int",
|
Name: "is_int",
|
||||||
Func: builtinIsInt,
|
Value: builtinIsInt,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_float",
|
Name: "is_float",
|
||||||
Func: builtinIsFloat,
|
Value: builtinIsFloat,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_string",
|
Name: "is_string",
|
||||||
Func: builtinIsString,
|
Value: builtinIsString,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_bool",
|
Name: "is_bool",
|
||||||
Func: builtinIsBool,
|
Value: builtinIsBool,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_char",
|
Name: "is_char",
|
||||||
Func: builtinIsChar,
|
Value: builtinIsChar,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_bytes",
|
Name: "is_bytes",
|
||||||
Func: builtinIsBytes,
|
Value: builtinIsBytes,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_array",
|
Name: "is_array",
|
||||||
Func: builtinIsArray,
|
Value: builtinIsArray,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_immutable_array",
|
Name: "is_immutable_array",
|
||||||
Func: builtinIsImmutableArray,
|
Value: builtinIsImmutableArray,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_map",
|
Name: "is_map",
|
||||||
Func: builtinIsMap,
|
Value: builtinIsMap,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_immutable_map",
|
Name: "is_immutable_map",
|
||||||
Func: builtinIsImmutableMap,
|
Value: builtinIsImmutableMap,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_time",
|
Name: "is_time",
|
||||||
Func: builtinIsTime,
|
Value: builtinIsTime,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_error",
|
Name: "is_error",
|
||||||
Func: builtinIsError,
|
Value: builtinIsError,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_undefined",
|
Name: "is_undefined",
|
||||||
Func: builtinIsUndefined,
|
Value: builtinIsUndefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_function",
|
Name: "is_function",
|
||||||
Func: builtinIsFunction,
|
Value: builtinIsFunction,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "is_callable",
|
Name: "is_callable",
|
||||||
Func: builtinIsCallable,
|
Value: builtinIsCallable,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "to_json",
|
Name: "to_json",
|
||||||
Func: builtinToJSON,
|
Value: builtinToJSON,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "from_json",
|
Name: "from_json",
|
||||||
Func: builtinFromJSON,
|
Value: builtinFromJSON,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "type_name",
|
Name: "type_name",
|
||||||
Func: builtinTypeName,
|
Value: builtinTypeName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllBuiltinFunctionNames returns a list of all default builtin function names.
|
||||||
|
func AllBuiltinFunctionNames() []string {
|
||||||
|
var names []string
|
||||||
|
for _, bf := range Builtins {
|
||||||
|
names = append(names, bf.Name)
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBuiltinFunctions returns a slice of builtin function objects.
|
||||||
|
// GetBuiltinFunctions removes the duplicate names, and, the returned builtin functions
|
||||||
|
// are not guaranteed to be in the same order as names.
|
||||||
|
func GetBuiltinFunctions(names ...string) []*BuiltinFunction {
|
||||||
|
include := make(map[string]bool)
|
||||||
|
for _, name := range names {
|
||||||
|
include[name] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var builtinFuncs []*BuiltinFunction
|
||||||
|
for _, bf := range Builtins {
|
||||||
|
if include[bf.Name] {
|
||||||
|
bf := bf
|
||||||
|
builtinFuncs = append(builtinFuncs, &bf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builtinFuncs
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllBuiltinFunctions returns all builtin functions.
|
||||||
|
func GetAllBuiltinFunctions() []*BuiltinFunction {
|
||||||
|
return GetBuiltinFunctions(AllBuiltinFunctionNames()...)
|
||||||
|
}
|
||||||
|
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
"github.com/d5/tengo/compiler/token"
|
"github.com/d5/tengo/compiler/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,6 +28,10 @@ func (o *Bytes) BinaryOp(op token.Token, rhs Object) (Object, error) {
|
|||||||
case token.Add:
|
case token.Add:
|
||||||
switch rhs := rhs.(type) {
|
switch rhs := rhs.(type) {
|
||||||
case *Bytes:
|
case *Bytes:
|
||||||
|
if len(o.Value)+len(rhs.Value) > tengo.MaxBytesLen {
|
||||||
|
return nil, ErrBytesLimit
|
||||||
|
}
|
||||||
|
|
||||||
return &Bytes{Value: append(o.Value, rhs.Value...)}, nil
|
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
|
package objects
|
||||||
|
|
||||||
// CallableFunc is a function signature for the callable functions.
|
// 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"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToString will try to convert object o to string value.
|
// ToString will try to convert object o to string value.
|
||||||
@ -194,6 +196,9 @@ func FromInterface(v interface{}) (Object, error) {
|
|||||||
case nil:
|
case nil:
|
||||||
return UndefinedValue, nil
|
return UndefinedValue, nil
|
||||||
case string:
|
case string:
|
||||||
|
if len(v) > tengo.MaxStringLen {
|
||||||
|
return nil, ErrStringLimit
|
||||||
|
}
|
||||||
return &String{Value: v}, nil
|
return &String{Value: v}, nil
|
||||||
case int64:
|
case int64:
|
||||||
return &Int{Value: v}, nil
|
return &Int{Value: v}, nil
|
||||||
@ -211,6 +216,9 @@ func FromInterface(v interface{}) (Object, error) {
|
|||||||
case float64:
|
case float64:
|
||||||
return &Float{Value: v}, nil
|
return &Float{Value: v}, nil
|
||||||
case []byte:
|
case []byte:
|
||||||
|
if len(v) > tengo.MaxBytesLen {
|
||||||
|
return nil, ErrBytesLimit
|
||||||
|
}
|
||||||
return &Bytes{Value: v}, nil
|
return &Bytes{Value: v}, nil
|
||||||
case error:
|
case error:
|
||||||
return &Error{Value: &String{Value: v.Error()}}, nil
|
return &Error{Value: &String{Value: v.Error()}}, nil
|
||||||
@ -243,6 +251,8 @@ func FromInterface(v interface{}) (Object, error) {
|
|||||||
return &Time{Value: v}, nil
|
return &Time{Value: v}, nil
|
||||||
case Object:
|
case Object:
|
||||||
return v, nil
|
return v, nil
|
||||||
|
case CallableFunc:
|
||||||
|
return &UserFunction{Value: v}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("cannot convert to object: %T", v)
|
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.
|
// ErrWrongNumArguments represents a wrong number of arguments error.
|
||||||
var ErrWrongNumArguments = errors.New("wrong number of arguments")
|
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.
|
// ErrInvalidArgumentType represents an invalid argument value type error.
|
||||||
type ErrInvalidArgumentType struct {
|
type ErrInvalidArgumentType struct {
|
||||||
Name string
|
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 (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/d5/tengo"
|
||||||
"github.com/d5/tengo/compiler/token"
|
"github.com/d5/tengo/compiler/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,9 +29,16 @@ func (o *String) BinaryOp(op token.Token, rhs Object) (Object, error) {
|
|||||||
case token.Add:
|
case token.Add:
|
||||||
switch rhs := rhs.(type) {
|
switch rhs := rhs.(type) {
|
||||||
case *String:
|
case *String:
|
||||||
|
if len(o.Value)+len(rhs.Value) > tengo.MaxStringLen {
|
||||||
|
return nil, ErrStringLimit
|
||||||
|
}
|
||||||
return &String{Value: o.Value + rhs.Value}, nil
|
return &String{Value: o.Value + rhs.Value}, nil
|
||||||
default:
|
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
73
vendor/github.com/d5/tengo/script/script.go
generated
vendored
73
vendor/github.com/d5/tengo/script/script.go
generated
vendored
@ -9,14 +9,13 @@ import (
|
|||||||
"github.com/d5/tengo/compiler/source"
|
"github.com/d5/tengo/compiler/source"
|
||||||
"github.com/d5/tengo/objects"
|
"github.com/d5/tengo/objects"
|
||||||
"github.com/d5/tengo/runtime"
|
"github.com/d5/tengo/runtime"
|
||||||
"github.com/d5/tengo/stdlib"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Script can simplify compilation and execution of embedded scripts.
|
// Script can simplify compilation and execution of embedded scripts.
|
||||||
type Script struct {
|
type Script struct {
|
||||||
variables map[string]*Variable
|
variables map[string]*Variable
|
||||||
removedBuiltins map[string]bool
|
builtinFuncs []objects.Object
|
||||||
removedStdModules map[string]bool
|
builtinModules map[string]*objects.Object
|
||||||
userModuleLoader compiler.ModuleLoader
|
userModuleLoader compiler.ModuleLoader
|
||||||
input []byte
|
input []byte
|
||||||
}
|
}
|
||||||
@ -56,22 +55,28 @@ func (s *Script) Remove(name string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisableBuiltinFunction disables a builtin function.
|
// SetBuiltinFunctions allows to define builtin functions.
|
||||||
func (s *Script) DisableBuiltinFunction(name string) {
|
func (s *Script) SetBuiltinFunctions(funcs []*objects.BuiltinFunction) {
|
||||||
if s.removedBuiltins == nil {
|
if funcs != nil {
|
||||||
s.removedBuiltins = make(map[string]bool)
|
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
|
// 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 {
|
||||||
// DisableStdModule disables a standard library module.
|
s.builtinModules = map[string]*objects.Object{}
|
||||||
func (s *Script) DisableStdModule(name string) {
|
|
||||||
if s.removedStdModules == nil {
|
|
||||||
s.removedStdModules = make(map[string]bool)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.removedStdModules[name] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUserModuleLoader sets the user module loader for the compiler.
|
// 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.
|
// Compile compiles the script with all the defined variables, and, returns Compiled object.
|
||||||
func (s *Script) Compile() (*Compiled, error) {
|
func (s *Script) Compile() (*Compiled, error) {
|
||||||
symbolTable, stdModules, globals, err := s.prepCompile()
|
symbolTable, builtinModules, globals, err := s.prepCompile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -92,10 +97,10 @@ func (s *Script) Compile() (*Compiled, error) {
|
|||||||
p := parser.NewParser(srcFile, s.input, nil)
|
p := parser.NewParser(srcFile, s.input, nil)
|
||||||
file, err := p.ParseFile()
|
file, err := p.ParseFile()
|
||||||
if err != nil {
|
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 {
|
if s.userModuleLoader != nil {
|
||||||
c.SetModuleLoader(s.userModuleLoader)
|
c.SetModuleLoader(s.userModuleLoader)
|
||||||
@ -107,7 +112,7 @@ func (s *Script) Compile() (*Compiled, error) {
|
|||||||
|
|
||||||
return &Compiled{
|
return &Compiled{
|
||||||
symbolTable: symbolTable,
|
symbolTable: symbolTable,
|
||||||
machine: runtime.NewVM(c.Bytecode(), globals, nil),
|
machine: runtime.NewVM(c.Bytecode(), globals, s.builtinFuncs, s.builtinModules),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,24 +141,36 @@ func (s *Script) RunContext(ctx context.Context) (compiled *Compiled, err error)
|
|||||||
return
|
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
|
var names []string
|
||||||
for name := range s.variables {
|
for name := range s.variables {
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
symbolTable = compiler.NewSymbolTable()
|
symbolTable = compiler.NewSymbolTable()
|
||||||
|
|
||||||
|
if s.builtinFuncs == nil {
|
||||||
|
s.builtinFuncs = make([]objects.Object, len(objects.Builtins))
|
||||||
for idx, fn := range objects.Builtins {
|
for idx, fn := range objects.Builtins {
|
||||||
if !s.removedBuiltins[fn.Name] {
|
s.builtinFuncs[idx] = &objects.BuiltinFunction{
|
||||||
symbolTable.DefineBuiltin(idx, fn.Name)
|
Name: fn.Name,
|
||||||
|
Value: fn.Value,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stdModules = make(map[string]bool)
|
if s.builtinModules == nil {
|
||||||
for name := range stdlib.Modules {
|
s.builtinModules = make(map[string]*objects.Object)
|
||||||
if !s.removedStdModules[name] {
|
|
||||||
stdModules[name] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for idx, fn := range s.builtinFuncs {
|
||||||
|
f := fn.(*objects.BuiltinFunction)
|
||||||
|
symbolTable.DefineBuiltin(idx, f.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
builtinModules = make(map[string]bool)
|
||||||
|
for name := range s.builtinModules {
|
||||||
|
builtinModules[name] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
globals = make([]*objects.Object, runtime.GlobalsSize, runtime.GlobalsSize)
|
globals = make([]*objects.Object, runtime.GlobalsSize, runtime.GlobalsSize)
|
||||||
@ -178,3 +195,7 @@ func (s *Script) copyVariables() map[string]*Variable {
|
|||||||
|
|
||||||
return vars
|
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/Philipp15b/go-steam/socialcache
|
||||||
# github.com/bwmarrin/discordgo v0.19.0
|
# github.com/bwmarrin/discordgo v0.19.0
|
||||||
github.com/bwmarrin/discordgo
|
github.com/bwmarrin/discordgo
|
||||||
# github.com/d5/tengo v1.9.2
|
# github.com/d5/tengo v1.12.1
|
||||||
github.com/d5/tengo/script
|
github.com/d5/tengo/script
|
||||||
github.com/d5/tengo/compiler
|
github.com/d5/tengo/compiler
|
||||||
github.com/d5/tengo/compiler/parser
|
github.com/d5/tengo/compiler/parser
|
||||||
github.com/d5/tengo/compiler/source
|
github.com/d5/tengo/compiler/source
|
||||||
github.com/d5/tengo/objects
|
github.com/d5/tengo/objects
|
||||||
github.com/d5/tengo/runtime
|
github.com/d5/tengo/runtime
|
||||||
github.com/d5/tengo/stdlib
|
github.com/d5/tengo
|
||||||
github.com/d5/tengo/compiler/ast
|
github.com/d5/tengo/compiler/ast
|
||||||
github.com/d5/tengo/compiler/token
|
github.com/d5/tengo/compiler/token
|
||||||
github.com/d5/tengo/compiler/scanner
|
github.com/d5/tengo/compiler/scanner
|
||||||
|
Reference in New Issue
Block a user