Skip to content

Commit

Permalink
implement built-in function @ to run shell and upgrade golang to 1.19
Browse files Browse the repository at this point in the history
  • Loading branch information
IfanTsai committed Aug 9, 2022
1 parent 645c9f7 commit f894701
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 62 deletions.
22 changes: 11 additions & 11 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
name: Run benchmark tests
on:

on:
schedule:
- cron: '0 0 * * *'
push:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:

jobs:
benchmark:
name: Benchmark Test
runs-on: ubuntu-latest
steps:

steps:
- uses: actions/checkout@v2

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.18
go-version: 1.19

- name: Benchmark
run: go test -run=none -v --cover ./... -benchmem --bench=.
run: go test -run=none -v --cover ./... -benchmem --bench=.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.45.2
version: v1.48.0

unint-test:
name: Unint Test
Expand All @@ -29,7 +29,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.18
go-version: 1.19

- name: Test
run: go test -v -cover ./...
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@ linters:
- ireturn # Do not check the return object is interface
- gocyclo
- cyclop
- exhaustruct
enable-all: true
18 changes: 7 additions & 11 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
module github.com/IfanTsai/jirachi

go 1.18
go 1.19

require (
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/chzyer/readline v1.5.1
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.7.1
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
)

require (
github.com/IfanTsai/go-lib v0.0.0-20220225122438-322a14038807
github.com/chzyer/test v0.0.0-20210722231415-061457976a23 // indirect
)
require github.com/IfanTsai/go-lib v0.0.0-20220723175004-1e4694e968d7

require (
github.com/chzyer/logex v1.1.10 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/exp v0.0.0-20220328175248-053ad81199eb // indirect
golang.org/x/sys v0.0.0-20220403020550-483a9cbc67c0 // indirect
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.0 // indirect
)
33 changes: 17 additions & 16 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
github.com/IfanTsai/go-lib v0.0.0-20220225122438-322a14038807 h1:TFB1keU9wjC1yCIQx07irBPQH0aQIHJUFTbgeKx25Ek=
github.com/IfanTsai/go-lib v0.0.0-20220225122438-322a14038807/go.mod h1:bseMhaFLXs6QUFvZniJLnDwuS4Ktc2pOpcIT0VKMqV4=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20210722231415-061457976a23 h1:dZ0/VyGgQdVGAss6Ju0dt5P0QltE0SFY5Woh6hbIfiQ=
github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/IfanTsai/go-lib v0.0.0-20220723175004-1e4694e968d7 h1:aM/LmlsrslHScURXiAqekPCajoiycKFT3E6bzyFKvsw=
github.com/IfanTsai/go-lib v0.0.0-20220723175004-1e4694e968d7/go.mod h1:Jm1YEsJ/pF3oYAlnkLI+FbQw8ceqIDu69DnbbkZhUH0=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -19,15 +19,16 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/exp v0.0.0-20220328175248-053ad81199eb h1:pC9Okm6BVmxEw76PUu0XUbOTQ92JX11hfvqTjAV3qxM=
golang.org/x/exp v0.0.0-20220328175248-053ad81199eb/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/sys v0.0.0-20220403020550-483a9cbc67c0 h1:PgUUmg0gNMIPY2WafhL/oLyQGw+kdTNPlVWOjltpp3w=
golang.org/x/sys v0.0.0-20220403020550-483a9cbc67c0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
33 changes: 29 additions & 4 deletions interpreter/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package interpreter

import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"os/exec"
"strconv"

"github.com/pkg/errors"
Expand All @@ -28,6 +30,7 @@ var (
IsString = object.NewJBuiltInFunction("is_string", []string{"value"}, ExecuteIsString)
IsList = object.NewJBuiltInFunction("is_list", []string{"value"}, ExecuteIsList)
IsFunction = object.NewJBuiltInFunction("is_function", []string{"value"}, ExecuteIsFunction)
RunShell = object.NewJBuiltInFunction("run_shell", []string{"text"}, ExecuteRunShell)
RunScript = object.NewJBuiltInFunction("run", []string{"filename"}, ExecuteRun)
)

Expand Down Expand Up @@ -110,8 +113,10 @@ func ExecuteInputNumber(function *object.JBuiltInFunction, args []object.JValue)
textBytes, _, _ := bufio.NewReader(os.Stdin).ReadLine()
text := string(textBytes)

var number interface{}
var err error
var (
number interface{}
err error
)

number, err = strconv.Atoi(text)
if err != nil {
Expand Down Expand Up @@ -168,8 +173,7 @@ func ExecuteRun(function *object.JBuiltInFunction, args []object.JValue) (object
}, "failed to call run")
}

_, err = Run(filename, string(bytes))
if err != nil {
if _, err = Run(filename, string(bytes)); err != nil {
return nil, errors.Wrap(&common.JRunTimeError{
JError: &common.JError{
StartPos: function.StartPos,
Expand All @@ -182,3 +186,24 @@ func ExecuteRun(function *object.JBuiltInFunction, args []object.JValue) (object

return nil, nil
}

func ExecuteRunShell(function *object.JBuiltInFunction, args []object.JValue) (object.JValue, error) {
shellStr := args[0].GetValue().(string)
cmd := exec.Command("/bin/sh", "-c", shellStr)

var outBuf, errBuf bytes.Buffer
cmd.Stdout = &outBuf
cmd.Stderr = &errBuf

if err := cmd.Run(); err != nil || errBuf.Len() > 0 {
return nil, errors.Wrap(&common.JRunTimeError{
JError: &common.JError{
StartPos: function.StartPos,
EndPos: function.EndPos,
},
Context: function.GetContext(),
}, errBuf.String())
}

return object.NewJString(outBuf.String()), nil
}
4 changes: 3 additions & 1 deletion interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ func init() {
Set("is_string", IsString).
Set("is_list", IsList).
Set("is_function", IsFunction).
Set("run", RunScript)
Set("run", RunScript).
Set("run_shell", RunShell).
Set("@", RunShell)
}

func Run(filename, text string) (interface{}, error) {
Expand Down
12 changes: 12 additions & 0 deletions interpreter/interpreter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,18 @@ func TestRun(t *testing.T) {

},
},
{
name: "shell",
source: `
@"echo -n hello"
`,
checkResult: func(t *testing.T, resValue interface{}, err error) {
t.Helper()
require.NoError(t, err)
require.IsType(t, object.NewJString(nil), resValue)
require.Equal(t, "hello", resValue.(*object.JString).Value)
},
},
}

for i := range testCases {
Expand Down
16 changes: 11 additions & 5 deletions lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ func NewJLexer(filename, text string) *JLexer {
}

func (l *JLexer) MakeTokens() ([]*token.JToken, error) {
tokens := make([]*token.JToken, 0, len(l.Text))
var (
err error
tok *token.JToken
)

var err error
var tok *token.JToken
tokens := make([]*token.JToken, 0, len(l.Text))

for advanceAble := l.advance(); advanceAble; {
char := l.getCurrentChar()
Expand All @@ -51,7 +53,7 @@ func (l *JLexer) MakeTokens() ([]*token.JToken, error) {
return nil, err
}
tokens = append(tokens, tok)
case isLetters(char):
case isLetters(char), isAt(char):
tok, advanceAble = l.makeIdentifierToken()
tokens = append(tokens, tok)
case char == '"' || char == '\'':
Expand Down Expand Up @@ -187,7 +189,7 @@ func (l *JLexer) makeIdentifierToken() (*token.JToken, bool) {
for {
char := l.getCurrentChar()

if !isLetters(char) && !isDigit(char) {
if !isLetters(char) && !isDigit(char) && !isAt(char) {
break
}

Expand Down Expand Up @@ -363,3 +365,7 @@ func isDigit(char byte) bool {
func isLetters(char byte) bool {
return ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') || char == '_'
}

func isAt(char byte) bool {
return char == '@'
}
34 changes: 34 additions & 0 deletions parser/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,29 @@ func (n *JIfExprNode) Type() JNodeType {
return IfExpr
}

func (n *JIfExprNode) String() string {
strBuilder := strings.Builder{}
strBuilder.WriteString("if ")
for index, caseNode := range n.CaseNodes {
if index != 0 {
strBuilder.WriteString(" else if ")
}

strBuilder.WriteString("(")
strBuilder.WriteString(caseNode[0].String())
strBuilder.WriteString(") {")
strBuilder.WriteString(caseNode[1].String())
strBuilder.WriteString("}")
}

if n.ElseCaseNode != nil {
strBuilder.WriteString(" else ")
strBuilder.WriteString(n.ElseCaseNode.String())
}

return strBuilder.String()
}

// JForExprNode is for expression node structure of AST
type JForExprNode struct {
*JBaseNode // JBaseNode.Token is variable name token
Expand All @@ -268,6 +291,17 @@ func (n *JWhileExprNode) Type() JNodeType {
return WhileExpr
}

func (n *JWhileExprNode) String() string {
strBuilder := strings.Builder{}
strBuilder.WriteString("while (")
strBuilder.WriteString(n.ConditionNode.String())
strBuilder.WriteString(") {")
strBuilder.WriteString(n.BodyNode.String())
strBuilder.WriteString("}")

return strBuilder.String()
}

// JFuncDefNode is function definition node structure of AST
type JFuncDefNode struct {
*JBaseNode // JBaseNode.Token is function name token
Expand Down
Loading

0 comments on commit f894701

Please sign in to comment.