Compare commits
18 Commits
master
...
v0.0.1-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4ec8a7a49 | ||
|
|
bec52ad5a5 | ||
|
|
5411730a96 | ||
|
|
187f9816ca | ||
|
|
feab8e661c | ||
|
|
96b63a4e83 | ||
|
|
fcddca2226 | ||
|
|
28d78bdb8c | ||
|
|
23c0434ed3 | ||
|
|
e9adc05536 | ||
|
|
b8ee6a1505 | ||
|
|
ac46753546 | ||
|
|
d16521e5e3 | ||
|
|
4955f4bf88 | ||
|
|
c3d2073b2b | ||
|
|
1ddc4d4c36 | ||
|
|
d66a25a525 | ||
|
|
6c05518146 |
48
.github/workflows/main.yml
vendored
Normal file
48
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
name: CI
|
||||
|
||||
# Controls when the action will run. Triggers the workflow on push to master or development
|
||||
# with a tag like v1.0.0 or v1.0.0-dev
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- development
|
||||
tags:
|
||||
- v[0-9]+.[0-9]+.[0-9]+
|
||||
- v[0-9]+.[0-9]+.[0-9]+-[a-zA-Z]+
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.event.base_ref == 'refs/heads/master' || github.event.base_ref == 'refs/heads/development'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v1
|
||||
with:
|
||||
repositories: goff
|
||||
|
||||
- name: Get Version
|
||||
id: get_version
|
||||
uses: battila7/get-version-action@v2.0.0
|
||||
|
||||
- name: Build, tag, and push image to Amazon ECR
|
||||
env:
|
||||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
ECR_REPOSITORY: goff
|
||||
IMAGE_TAG: ${{ steps.get_version.outputs.version-without-v }}
|
||||
run: |
|
||||
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
|
||||
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
|
||||
19
Dockerfile
19
Dockerfile
@ -1,13 +1,20 @@
|
||||
FROM golang:1.14-alpine
|
||||
FROM golang:1.14-alpine as dev
|
||||
|
||||
WORKDIR /go/src/Goff
|
||||
COPY ./go.mod .
|
||||
COPY ./go.sum .
|
||||
|
||||
RUN apk add --no-cache git
|
||||
|
||||
RUN go get -d -v ./...
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
RUN go install -v ./...
|
||||
RUN go install github.com/dustinpianalto/goff
|
||||
|
||||
ENTRYPOINT /go/bin/goff
|
||||
CMD [ "go", "run", "goff.go"]
|
||||
|
||||
from alpine
|
||||
|
||||
WORKDIR /bin
|
||||
|
||||
COPY --from=dev /go/bin/goff ./goff
|
||||
|
||||
CMD [ "goff" ]
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/dustinpianalto/goff/utils"
|
||||
)
|
||||
|
||||
func OnGuildMemberAddLogging(s *discordgo.Session, member *discordgo.GuildMemberAdd) {
|
||||
@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/dustinpianalto/goff/utils"
|
||||
)
|
||||
|
||||
func OnMessageUpdate(session *discordgo.Session, m *discordgo.MessageUpdate) {
|
||||
@ -2,8 +2,11 @@ package exts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"github.com/dustinpianalto/rpnparse"
|
||||
)
|
||||
|
||||
func interleave(ctx disgoman.Context, args []string) {
|
||||
@ -47,3 +50,35 @@ func deinterleave(ctx disgoman.Context, args []string) {
|
||||
ctx.Send(fmt.Sprintf("(%v, %v)", x, y))
|
||||
}
|
||||
}
|
||||
|
||||
func generateRPNCommand(ctx disgoman.Context, args []string) {
|
||||
rpn, err := rpnparse.GenerateRPN(args)
|
||||
if err != nil {
|
||||
ctx.Send(err.Error())
|
||||
return
|
||||
}
|
||||
ctx.Send(rpn)
|
||||
}
|
||||
|
||||
func parseRPNCommand(ctx disgoman.Context, args []string) {
|
||||
res, err := rpnparse.ParseRPN(args)
|
||||
if err != nil {
|
||||
ctx.Send(err.Error())
|
||||
return
|
||||
}
|
||||
ctx.Send(fmt.Sprintf("The result is: %v", res))
|
||||
}
|
||||
|
||||
func solveCommand(ctx disgoman.Context, args []string) {
|
||||
rpn, err := rpnparse.GenerateRPN(args)
|
||||
if err != nil {
|
||||
ctx.Send(err.Error())
|
||||
return
|
||||
}
|
||||
res, err := rpnparse.ParseRPN(strings.Split(rpn, " "))
|
||||
if err != nil {
|
||||
ctx.Send(err.Error())
|
||||
return
|
||||
}
|
||||
ctx.Send(fmt.Sprintf("The result is: %v", res))
|
||||
}
|
||||
@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"github.com/dustinpianalto/goff/utils"
|
||||
)
|
||||
|
||||
// Guild management commands
|
||||
@ -204,4 +204,31 @@ func AddCommandHandlers(h *disgoman.CommandManager) {
|
||||
RequiredPermissions: disgoman.PermissionManageServer,
|
||||
Invoke: getPuzzleChannel,
|
||||
})
|
||||
_ = h.AddCommand(&disgoman.Command{
|
||||
Name: "RPN",
|
||||
Aliases: []string{"rpn"},
|
||||
Description: "Convert infix to rpn",
|
||||
OwnerOnly: false,
|
||||
Hidden: false,
|
||||
RequiredPermissions: 0,
|
||||
Invoke: generateRPNCommand,
|
||||
})
|
||||
_ = h.AddCommand(&disgoman.Command{
|
||||
Name: "ParseRPN",
|
||||
Aliases: []string{"PRPN", "prpn"},
|
||||
Description: "Parse RPN string and return the result",
|
||||
OwnerOnly: false,
|
||||
Hidden: false,
|
||||
RequiredPermissions: 0,
|
||||
Invoke: parseRPNCommand,
|
||||
})
|
||||
_ = h.AddCommand(&disgoman.Command{
|
||||
Name: "solve",
|
||||
Aliases: []string{"math", "infix"},
|
||||
Description: "Solve infix equation and return the result",
|
||||
OwnerOnly: false,
|
||||
Hidden: false,
|
||||
RequiredPermissions: 0,
|
||||
Invoke: solveCommand,
|
||||
})
|
||||
}
|
||||
@ -6,8 +6,8 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"github.com/dustinpianalto/goff/utils"
|
||||
"github.com/kballard/go-shellquote"
|
||||
)
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
package exts
|
||||
|
||||
import (
|
||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"github.com/dustinpianalto/goff/utils"
|
||||
"github.com/olebedev/when"
|
||||
"github.com/olebedev/when/rules/common"
|
||||
"github.com/olebedev/when/rules/en"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func addReminderCommand(ctx disgoman.Context, args []string) {
|
||||
@ -1,13 +1,14 @@
|
||||
package exts
|
||||
|
||||
import (
|
||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"github.com/dustinpianalto/goff/utils"
|
||||
)
|
||||
|
||||
func kickUserCommand(ctx disgoman.Context, args []string) {
|
||||
@ -1,14 +1,15 @@
|
||||
package exts
|
||||
|
||||
import (
|
||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"github.com/dustinpianalto/goff/utils"
|
||||
)
|
||||
|
||||
func pingCommand(ctx disgoman.Context, _ []string) {
|
||||
3
go.mod
3
go.mod
@ -1,10 +1,11 @@
|
||||
module djpianalto.com/goff
|
||||
module github.com/dustinpianalto/goff
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/bwmarrin/discordgo v0.20.3-0.20200525154655-ca64123b05de
|
||||
github.com/dustinpianalto/disgoman v0.0.10
|
||||
github.com/dustinpianalto/rpnparse v1.0.1
|
||||
github.com/emersion/go-imap v1.0.5
|
||||
github.com/emersion/go-message v0.12.0
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
|
||||
@ -4,10 +4,10 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"djpianalto.com/goff/djpianalto.com/goff/events"
|
||||
"djpianalto.com/goff/djpianalto.com/goff/exts"
|
||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"github.com/dustinpianalto/goff/events"
|
||||
"github.com/dustinpianalto/goff/exts"
|
||||
"github.com/dustinpianalto/goff/utils"
|
||||
|
||||
//"github.com/MikeModder/anpan"
|
||||
"os"
|
||||
156
utils/rpn.go
Normal file
156
utils/rpn.go
Normal file
@ -0,0 +1,156 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Operator struct {
|
||||
Token string
|
||||
Precedence int
|
||||
Association string
|
||||
}
|
||||
|
||||
func (o Operator) HasHigherPrecedence(t Operator) bool {
|
||||
return o.Precedence < t.Precedence // lower number is higher precedence
|
||||
}
|
||||
|
||||
func (o Operator) HasEqualPrecedence(t Operator) bool {
|
||||
return o.Precedence == t.Precedence
|
||||
}
|
||||
|
||||
func (o Operator) IsLeftAssociative() bool {
|
||||
return o.Association == "left"
|
||||
}
|
||||
|
||||
var operators = map[string]Operator{
|
||||
"+": Operator{
|
||||
Token: "+",
|
||||
Precedence: 4,
|
||||
Association: "left",
|
||||
},
|
||||
"-": Operator{
|
||||
Token: "-",
|
||||
Precedence: 4,
|
||||
Association: "left",
|
||||
},
|
||||
"*": Operator{
|
||||
Token: "*",
|
||||
Precedence: 3,
|
||||
Association: "left",
|
||||
},
|
||||
"/": Operator{
|
||||
Token: "/",
|
||||
Precedence: 3,
|
||||
Association: "left",
|
||||
},
|
||||
"%": Operator{
|
||||
Token: "%",
|
||||
Precedence: 3,
|
||||
Association: "left",
|
||||
},
|
||||
"(": Operator{
|
||||
Token: "(",
|
||||
Precedence: 1,
|
||||
Association: "left",
|
||||
},
|
||||
")": Operator{
|
||||
Token: ")",
|
||||
Precedence: 1,
|
||||
Association: "left",
|
||||
},
|
||||
}
|
||||
|
||||
type Stack []Operator
|
||||
|
||||
func (s *Stack) IsEmpty() bool {
|
||||
return len(*s) == 0
|
||||
}
|
||||
|
||||
func (s *Stack) Push(op Operator) {
|
||||
*s = append(*s, op)
|
||||
}
|
||||
|
||||
func (s *Stack) Pop() (Operator, bool) {
|
||||
if s.IsEmpty() {
|
||||
return Operator{}, false
|
||||
}
|
||||
index := len(*s) - 1
|
||||
element := (*s)[index]
|
||||
*s = (*s)[:index]
|
||||
return element, true
|
||||
}
|
||||
|
||||
func (s *Stack) Top() Operator {
|
||||
if s.IsEmpty() {
|
||||
return Operator{}
|
||||
}
|
||||
return (*s)[len(*s)-1]
|
||||
}
|
||||
|
||||
func GenerateRPN(tokens []string) (string, error) {
|
||||
output := ""
|
||||
s := Stack{}
|
||||
for _, token := range tokens {
|
||||
err := processToken(token, &s, &output)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
for !s.IsEmpty() {
|
||||
ele, _ := s.Pop()
|
||||
output += " " + ele.Token
|
||||
}
|
||||
|
||||
return strings.TrimSpace(output), nil
|
||||
}
|
||||
|
||||
func processToken(t string, s *Stack, o *string) error {
|
||||
if _, err := strconv.Atoi(t); err == nil {
|
||||
*o += " " + t
|
||||
return nil
|
||||
} else if op, ok := operators[t]; ok {
|
||||
if op.Token == "(" {
|
||||
s.Push(op)
|
||||
} else if op.Token == ")" {
|
||||
if s.IsEmpty() {
|
||||
return fmt.Errorf("mismatched parentheses")
|
||||
}
|
||||
for s.Top().Token != "(" {
|
||||
if ele, ok := s.Pop(); ok {
|
||||
*o += " " + ele.Token
|
||||
} else {
|
||||
return fmt.Errorf("mismatched parentheses")
|
||||
}
|
||||
if s.IsEmpty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
s.Pop() // Pop and discard the (
|
||||
} else if !s.IsEmpty() {
|
||||
for {
|
||||
if (s.Top().HasHigherPrecedence(op) ||
|
||||
(s.Top().HasEqualPrecedence(op) &&
|
||||
op.IsLeftAssociative())) &&
|
||||
s.Top().Token != "(" {
|
||||
if ele, ok := s.Pop(); ok {
|
||||
*o += " " + ele.Token
|
||||
if s.IsEmpty() {
|
||||
break
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
s.Push(op)
|
||||
} else {
|
||||
s.Push(op)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid character %s", t)
|
||||
}
|
||||
95
utils/rpnParser.go
Normal file
95
utils/rpnParser.go
Normal file
@ -0,0 +1,95 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type FStack []float64
|
||||
|
||||
func (s *FStack) IsEmpty() bool {
|
||||
return len(*s) == 0
|
||||
}
|
||||
|
||||
func (s *FStack) Push(op float64) {
|
||||
*s = append(*s, op)
|
||||
}
|
||||
|
||||
func (s *FStack) Pop() (float64, bool) {
|
||||
if s.IsEmpty() {
|
||||
return 0, false
|
||||
}
|
||||
index := len(*s) - 1
|
||||
element := (*s)[index]
|
||||
*s = (*s)[:index]
|
||||
return element, true
|
||||
}
|
||||
|
||||
func (s *FStack) PopTwo() (float64, float64, bool) {
|
||||
if s.IsEmpty() || len(*s) < 2 {
|
||||
return 0, 0, false
|
||||
}
|
||||
index := len(*s) - 1
|
||||
b := (*s)[index]
|
||||
a := (*s)[index-1]
|
||||
*s = (*s)[:index-1]
|
||||
return a, b, true
|
||||
|
||||
}
|
||||
|
||||
func (s *FStack) Top() float64 {
|
||||
if s.IsEmpty() {
|
||||
return 0
|
||||
}
|
||||
return (*s)[len(*s)-1]
|
||||
}
|
||||
|
||||
func ParseRPN(args []string) (float64, error) {
|
||||
s := FStack{}
|
||||
for _, token := range args {
|
||||
switch token {
|
||||
case "+":
|
||||
if a, b, ok := s.PopTwo(); ok {
|
||||
s.Push(a + b)
|
||||
} else {
|
||||
return 0, fmt.Errorf("not enough operands on stack for +: %v", s)
|
||||
}
|
||||
case "-":
|
||||
if a, b, ok := s.PopTwo(); ok {
|
||||
s.Push(a - b)
|
||||
} else {
|
||||
return 0, fmt.Errorf("not enough operands on stack for -: %v", s)
|
||||
}
|
||||
case "*":
|
||||
if a, b, ok := s.PopTwo(); ok {
|
||||
s.Push(a * b)
|
||||
} else {
|
||||
return 0, fmt.Errorf("not enough operands on stack for *: %v", s)
|
||||
}
|
||||
case "/":
|
||||
if a, b, ok := s.PopTwo(); ok {
|
||||
s.Push(a / b)
|
||||
} else {
|
||||
return 0, fmt.Errorf("not enough operands on stack for /: %v", s)
|
||||
}
|
||||
case "%":
|
||||
if a, b, ok := s.PopTwo(); ok {
|
||||
s.Push(math.Mod(a, b))
|
||||
} else {
|
||||
return 0, fmt.Errorf("not enough operands on stack for %: %v", s)
|
||||
}
|
||||
default:
|
||||
f, err := strconv.ParseFloat(token, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
s.Push(f)
|
||||
}
|
||||
}
|
||||
if res, ok := s.Pop(); ok {
|
||||
return res, nil
|
||||
}
|
||||
return 0, errors.New("no result")
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user