diff --git a/.goreleaser.yml b/.goreleaser.yml index c19e75c..d7f4aef 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -42,7 +42,7 @@ signs: - artifacts: checksum release: gitea: - owner: unflavoredmeson + owner: UnflavoredMeson name: monkey gitea_urls: api: https://gitea.unflavoredmeson.com/api/v1/ \ No newline at end of file diff --git a/Benchmark.md b/Benchmark.md new file mode 100644 index 0000000..0e0aa26 --- /dev/null +++ b/Benchmark.md @@ -0,0 +1,7 @@ +| Command | Mean [ms] | Min [ms] | Max [ms] | Relative | +|:---|---:|---:|---:|---:| +| `c` | 36.7 ± 0.6 | 36.0 | 37.8 | 1.00 | +| `go` | 230.2 ± 14.0 | 206.2 | 252.9 | 6.28 ± 0.40 | +| `python` | 1366.9 ± 30.8 | 1330.9 | 1411.3 | 37.27 ± 1.06 | +| `tengo` | 1704.3 ± 16.0 | 1687.2 | 1739.3 | 46.47 ± 0.91 | +| `monkey` | 3347.6 ± 22.3 | 3314.0 | 3396.0 | 91.27 ± 1.69 | diff --git a/Makefile b/Makefile index 4187880..6e81d74 100644 --- a/Makefile +++ b/Makefile @@ -7,14 +7,14 @@ VERSION ?= $(shell git describe 2>/dev/null || echo "") DESTDIR ?= $(GOBIN) ifeq ($(LOCAL), 1) -IMAGE := r.mills.io/prologic/monkey +IMAGE := r.unflavoredmeson.com/UnflavoredMeson/monkey TAG := dev else ifeq ($(BRANCH), master) -IMAGE := prologic/monkey +IMAGE := UnflavoredMeson/monkey TAG := latest else -IMAGE := prologic/monkey +IMAGE := UnflavoredMeson/monkey TAG := dev endif endif @@ -33,14 +33,14 @@ build: clean cli server ## Build monkey cli: ## Build monkey CLI @go build \ -tags "netgo static_build" -installsuffix netgo \ - -ldflags "-w -X go.mills.io/monkey/v2.MonkeyVersion=$(VERSION)" \ + -ldflags "-w -X go.unflavoredmeson.com/monkey/v2.MonkeyVersion=$(VERSION)" \ ./cmd/monkey/... server: ## Build Monkey server @go build \ -tags "netgo static_build" -installsuffix netgo \ - -ldflags "-w -X go.mills.io/monkey/v2.MonkeyVersion=$(VERSION)" \ - ./cmd/monkey-server/... + -ldflags "-w -X go.unflavoredmeson.com/monkey/v2.MonkeyVersion=$(VERSION)" \ + ./cmd/monkey/... install: cli server ## Install monkey to $DESTDIR @install -D -m 755 monkey $(DESTDIR)/monkey @@ -66,16 +66,14 @@ profile: ## Run tests with profiling enabled @go test -cpuprofile cpu.prof -memprofile mem.prof -v -bench ./... compare: ## Run benchmarks comparing Monkey with other languages - @hyperfine -w 5 -p 'make build; gcc -o examples/fib examples/fib.c' \ - -n c -n go -n tengo -n python -n tauc -n taugo -n monkey \ + @hyperfine -w 3 -p 'make build; gcc -o examples/fib examples/fib.c' \ + -n c -n go -n tengo -n python -n monkey \ --sort mean-time --export-markdown Benchmark.md \ './examples/fib' \ 'go run examples/fib.go' \ 'tengo examples/fib.tengo' \ 'python3 examples/fib.py' \ - 'tauc examples/fib.tau' \ - 'taugo examples/fib.tau' \ - './monkey examples/fib.m' + './monkey examples/fib.monkey' bench: # Run test benchmarks @go test -v -benchmem -bench=. ./... diff --git a/go.sum b/go.sum index 574f0b8..4471a89 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tebeka/atexit v0.3.0 h1:jleL99H7Ywt80oJKR+VWmJNnezcCOG0CuzcN3CIpsdI= github.com/tebeka/atexit v0.3.0/go.mod h1:WJmSUSmMT7WoR7etUOaGBVXk+f5/ZJ+67qwuedq7Fbs= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= diff --git a/internal/builtins/accept.go b/internal/builtins/accept.go index cdfc49f..9ee1c43 100644 --- a/internal/builtins/accept.go +++ b/internal/builtins/accept.go @@ -17,13 +17,13 @@ func Accept(args ...object.Object) object.Object { } var ( - nfd syscall.Handle + nfd int err error ) fd := int(args[0].(*object.Integer).Value) - nfd, _, err = syscall.Accept(syscall.Handle(fd)) + nfd, _, err = syscall.Accept(fd) if err != nil { return newError("SocketError: %s", err) } diff --git a/internal/builtins/bind.go b/internal/builtins/bind.go index 7cc9d5b..4365ad4 100644 --- a/internal/builtins/bind.go +++ b/internal/builtins/bind.go @@ -24,7 +24,7 @@ func Bind(args ...object.Object) object.Object { fd := int(args[0].(*object.Integer).Value) address := args[1].(*object.String).Value - sockaddr, err = syscall.Getsockname(syscall.Handle(fd)) + sockaddr, err = syscall.Getsockname(fd) if err != nil { return newError("ValueError: %s", err) } @@ -45,7 +45,7 @@ func Bind(args ...object.Object) object.Object { return newError("ValueError: Invalid socket type %T for bind '%s'", sockaddr, address) } - err = syscall.Bind(syscall.Handle(fd), sockaddr) + err = syscall.Bind(fd, sockaddr) if err != nil { return newError("SocketError: %s", err) } diff --git a/internal/builtins/close.go b/internal/builtins/close.go index 60f46ed..1cc63bb 100644 --- a/internal/builtins/close.go +++ b/internal/builtins/close.go @@ -18,7 +18,7 @@ func Close(args ...object.Object) object.Object { fd := int(args[0].(*object.Integer).Value) - err := syscall.Close(syscall.Handle(fd)) + err := syscall.Close(fd) if err != nil { return newError("IOError: %s", err) } diff --git a/internal/builtins/connect.go b/internal/builtins/connect.go index 0837202..38161b1 100644 --- a/internal/builtins/connect.go +++ b/internal/builtins/connect.go @@ -21,7 +21,7 @@ func Connect(args ...object.Object) object.Object { fd := int(args[0].(*object.Integer).Value) address := args[1].(*object.String).Value - sockaddr, err := syscall.Getsockname(syscall.Handle(fd)) + sockaddr, err := syscall.Getsockname(fd) if err != nil { return newError("ValueError: %s", err) } @@ -42,7 +42,7 @@ func Connect(args ...object.Object) object.Object { return newError("ValueError: Invalid socket type %T for bind '%s'", sockaddr, address) } - if err = syscall.Connect(syscall.Handle(fd), sa); err != nil { + if err = syscall.Connect(fd, sa); err != nil { return newError("SocketError: %s", err) } diff --git a/internal/builtins/listen.go b/internal/builtins/listen.go index b72894c..6430380 100644 --- a/internal/builtins/listen.go +++ b/internal/builtins/listen.go @@ -19,7 +19,7 @@ func Listen(args ...object.Object) object.Object { fd := int(args[0].(*object.Integer).Value) backlog := int(args[1].(*object.Integer).Value) - if err := syscall.Listen(syscall.Handle(fd), backlog); err != nil { + if err := syscall.Listen(fd, backlog); err != nil { return newError("SocketError: %s", err) } diff --git a/internal/builtins/read.go b/internal/builtins/read.go index 2cb33ea..c119379 100644 --- a/internal/builtins/read.go +++ b/internal/builtins/read.go @@ -31,7 +31,7 @@ func Read(args ...object.Object) object.Object { } buf := make([]byte, n) - n, err := syscall.Read(syscall.Handle(fd), buf) + n, err := syscall.Read(fd, buf) if err != nil { return newError("IOError: %s", err) } diff --git a/internal/builtins/seek.go b/internal/builtins/seek.go index 1725dbb..761a7e9 100644 --- a/internal/builtins/seek.go +++ b/internal/builtins/seek.go @@ -28,7 +28,7 @@ func Seek(args ...object.Object) object.Object { whence = int(args[2].(*object.Integer).Value) } - offset, err := syscall.Seek(syscall.Handle(fd), offset, whence) + offset, err := syscall.Seek(fd, offset, whence) if err != nil { return newError("IOError: %s", err) } diff --git a/internal/builtins/write.go b/internal/builtins/write.go index f6613cc..c5bbe50 100644 --- a/internal/builtins/write.go +++ b/internal/builtins/write.go @@ -19,7 +19,7 @@ func Write(args ...object.Object) object.Object { fd := int(args[0].(*object.Integer).Value) data := []byte(args[1].(*object.String).Value) - n, err := syscall.Write(syscall.Handle(fd), data) + n, err := syscall.Write(fd, data) if err != nil { return newError("IOError: %s", err) } diff --git a/internal/object/errors.go b/internal/object/errors.go index 138181f..4e2978a 100644 --- a/internal/object/errors.go +++ b/internal/object/errors.go @@ -11,7 +11,7 @@ type BinaryOpError struct { } func (e BinaryOpError) Error() string { - return fmt.Sprintf("unsupported types for binary operation: %s %s %s", e.left.Type(), e.op, e.right.Type()) + return fmt.Sprintf("unsupported types for binary operation: %s %s %s %s %s", e.left.Type(), e.left.Inspect(), e.op, e.right.Type(), e.right.Inspect()) } // NewBinaryOpError returns a new BinaryOpError diff --git a/profile.go b/profile.go index 5d28548..d184810 100644 --- a/profile.go +++ b/profile.go @@ -3,14 +3,21 @@ package main import ( - "monkey/internal/compiler" - "monkey/internal/parser" - "monkey/internal/vm" + "flag" + "fmt" + "log" "os" + "runtime" "runtime/pprof" + "strings" + + "git.mills.io/prologic/monkey-lang/internal/compiler" + "git.mills.io/prologic/monkey-lang/internal/object" + "git.mills.io/prologic/monkey-lang/internal/parser" + "git.mills.io/prologic/monkey-lang/internal/vm" ) -const fib = ` +const defaultCode = ` fib := fn(n) { if (n < 2) { return n @@ -18,44 +25,64 @@ fib := fn(n) { return fib(n-1) + fib(n-2) } -print(fib(35))` +print(fib(%d))` -func check(err error) { +func checkErr(err error) { if err != nil { panic(err) } } -func code(path string) string { +func readFile(path string) string { b, err := os.ReadFile(path) - check(err) + checkErr(err) return string(b) } func fileOrDefault() string { - if len(os.Args) > 1 { - return code(os.Args[1]) + if flag.NArg() > 0 { + log.Printf("Using %s as program input...", flag.Arg(0)) + object.Args = flag.Args()[1:] + return readFile(flag.Arg(0)) } - return fib + return defaultCode } func main() { + n := flag.Int("n", 35, "Set n for fib(n) [Default: 35]") + flag.Parse() + cpuf, err := os.Create("cpu.prof") - check(err) + checkErr(err) + + heapf, err := os.Create("heap.prof") + checkErr(err) + + log.Printf("Using %d as n", *n) code := fileOrDefault() + if strings.Count(code, "%d") > 0 { + code = fmt.Sprintf(code, *n) + } + log.Printf("Code:\n%s\n", code) tree, errs := parser.Parse("", code) if len(errs) > 0 { + for _, err := range errs { + log.Println(err) + } panic("parser errors") } c := compiler.New() c.SetFileInfo("", code) - check(c.Compile(tree)) - - check(pprof.StartCPUProfile(cpuf)) + checkErr(c.Compile(tree)) + checkErr(pprof.StartCPUProfile(cpuf)) defer pprof.StopCPUProfile() mvm := vm.New("", c.Bytecode()) - mvm.Run() + checkErr(mvm.Run()) + runtime.GC() + checkErr(pprof.WriteHeapProfile(heapf)) + log.Println("CPU Profile written to cpu.prof") + log.Println("Heap Profile written to heap.prof") } diff --git a/tools/release.sh b/tools/release.sh index fbde7b7..a18742b 100644 --- a/tools/release.sh +++ b/tools/release.sh @@ -1,52 +1,25 @@ -" Vim Syntax File -" Language: monkey -" Creator: James Mills, prologic at shortcircuit dot net dot au -" Last Change: 31st January 2019 +#!/bin/sh -if version < 600 - syntax clear -elseif exists("b:current_syntax") - finish -endif +# Get the highest tag number +VERSION="$(git describe --abbrev=0 --tags)" +VERSION=${VERSION:-'0.0.0'} -syntax case match +# Get number parts +MAJOR="${VERSION%%.*}"; VERSION="${VERSION#*.}" +MINOR="${VERSION%%.*}"; VERSION="${VERSION#*.}" +PATCH="${VERSION%%.*}"; VERSION="${VERSION#*.}" -syntax keyword xType true false null int str bool array hash +# Increase version +PATCH=$((PATCH+1)) -syntax keyword xKeyword fn if else return while +TAG="${1}" -syntax keyword xFunction len input print first last rest push pop exit assert -syntax keyword xFunction bool int str typeof args lower upper join split find -syntax keyword xFunction read write +if [ "${TAG}" = "" ]; then + TAG="${MAJOR}.${MINOR}.${PATCH}" +fi -syntax match xOperator "\v\=\=" -syntax match xOperator "\v!\=" -syntax match xOperator "\v<" -syntax match xOperator "\v>" -syntax match xOperator "\v!" -syntax match xOperator "\v\+" -syntax match xOperator "\v-" -syntax match xOperator "\v\*" -syntax match xOperator "\v/" -syntax match xOperator "\v:\=" -syntax match xOperator "\v\=" -syntax match xOperator "\v&" -syntax match xOperator "\v\|" -syntax match xOperator "\v^" -syntax match xOperator "\v\~" -syntax match xOperator "\v&&" -syntax match xOperator "\v\|\|" +echo "Releasing ${TAG} ..." -syntax region xString start=/"/ skip=/\\./ end=/"/ - -syntax region xComment start='#' end='$' keepend -syntax region xComment start='//' end='$' keepend - -highlight link xType Type -highlight link xKeyword Keyword -highlight link xFunction Function -highlight link xString String -highlight link xComment Comment -highlight link xOperator Operator - -let b:current_syntax = "monkey" \ No newline at end of file +git tag -a -s -m "Release ${TAG}" "${TAG}" +git push --tags +goreleaser release --rm-dist \ No newline at end of file