From b02202767abc646da1a265660fb5688014fc7316 Mon Sep 17 00:00:00 2001 From: Valentin Knabel Date: Sat, 5 Feb 2022 12:53:30 +0100 Subject: [PATCH] Improved CLI (#26) * feat: better cli * fix: imports and declarations in repl were broken --- .goreleaser.yml | 10 +- CHANGELOG.md | 5 + Dockerfile | 2 +- app/lithia/cmd/lsp.go | 50 +++ app/lithia/cmd/repl.go | 55 +++ app/lithia/cmd/root.go | 29 ++ app/lithia/cmd/run.go | 38 +++ app/lithia/main.go | 16 + cmd/lithia/main.go | 70 ---- go.mod | 4 +- go.sum | 748 +++++++++++++++++++++++++++++++++++++++++ runtime/interpreter.go | 12 + 12 files changed, 960 insertions(+), 79 deletions(-) create mode 100644 app/lithia/cmd/lsp.go create mode 100644 app/lithia/cmd/repl.go create mode 100644 app/lithia/cmd/root.go create mode 100644 app/lithia/cmd/run.go create mode 100644 app/lithia/main.go delete mode 100644 cmd/lithia/main.go diff --git a/.goreleaser.yml b/.goreleaser.yml index 7398150..5f98a31 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -8,7 +8,7 @@ before: - go generate ./... builds: - id: lithia-macos - main: ./cmd/lithia + main: ./app/lithia env: - CGO_ENABLED=1 goos: @@ -19,7 +19,7 @@ builds: # brew install FiloSottile/musl-cross/musl-cross --with-aarch64 # brew install mingw-w64 - id: lithia-x-linux-amd64 - main: ./cmd/lithia + main: ./app/lithia env: - CGO_ENABLED=1 - CC=x86_64-linux-musl-gcc @@ -28,7 +28,7 @@ builds: goarch: - amd64 - id: lithia-x-linux-arm64 - main: ./cmd/lithia + main: ./app/lithia env: - CGO_ENABLED=1 - CC=aarch64-linux-musl-gcc @@ -37,7 +37,7 @@ builds: goarch: - arm64 - id: lithia-x-windows-amd64 - main: ./cmd/lithia + main: ./app/lithia env: - CGO_ENABLED=1 - CC=x86_64-w64-mingw32-gcc @@ -88,7 +88,7 @@ dockers: # -> only the second stage extra_files: - ast - - cmd + - app - parser - reporting - runtime diff --git a/CHANGELOG.md b/CHANGELOG.md index 473ca9a..e826f30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## v0.0.12-next + +- cli: new CLI interface, including, help and version +- fix: imports and declarations in repl were broken + ## v0.0.11 - compiler: binaries for macOS, linux, windows diff --git a/Dockerfile b/Dockerfile index 689579d..fb2aff6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ RUN go mod download COPY ./ ./ -RUN go build ./cmd/lithia +RUN go build ./app/lithia ## ## Deploy diff --git a/app/lithia/cmd/lsp.go b/app/lithia/cmd/lsp.go new file mode 100644 index 0000000..dd82c6d --- /dev/null +++ b/app/lithia/cmd/lsp.go @@ -0,0 +1,50 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func init() { + // rootCmd.AddCommand(lspCmd) + lspCmd.AddCommand(lspStdioCmd) + lspCmd.AddCommand(lspSocketCmd) + + lspSocketCmd.Flags().StringVarP( + &lspSocketAddress, + "listen", + "l", + "127.0.0.1:7998", + "Address and port on which to listen for LSP connections", + ) +} + +var lspCmd = &cobra.Command{ + Use: "lsp", + Short: "Language Server", + Long: `Runs the language server for the use inside an editor.`, + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + lspStdioCmd.Run(lspStdioCmd, args) + }, +} + +var lspStdioCmd = &cobra.Command{ + Use: "stdio", + Aliases: []string{"stdin", "-"}, + Short: "stdio mode. Supported by most editors.", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("stdio") + }, +} + +var lspSocketAddress string = "127.0.0.1:7998" +var lspSocketCmd = &cobra.Command{ + Use: "socket", + Short: `opens a socket on the specified address. Make sure the port is free.`, + Args: cobra.RangeArgs(0, 1), + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("socket", lspSocketAddress) + }, +} diff --git a/app/lithia/cmd/repl.go b/app/lithia/cmd/repl.go new file mode 100644 index 0000000..6f8a341 --- /dev/null +++ b/app/lithia/cmd/repl.go @@ -0,0 +1,55 @@ +package cmd + +import ( + "bufio" + "fmt" + "io" + "os" + + "github.com/spf13/cobra" + "github.com/vknabel/go-lithia/reporting" + "github.com/vknabel/go-lithia/runtime" +) + +func init() { + rootCmd.AddCommand(replCmd) +} + +var replCmd = &cobra.Command{ + Use: "repl", + Short: "Runs interactive Lithia REPL.", + Long: ``, + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + runPrompt() + }, +} + +func runPrompt() { + importRoot, err := os.Getwd() + if err != nil { + fmt.Fprint(os.Stderr, err) + os.Exit(1) + } + reader := bufio.NewReader(os.Stdin) + inter := runtime.NewInterpreter(importRoot) + for { + fmt.Print("> ") + line, err := reader.ReadString('\n') + if err == io.EOF { + return + } + if err != nil { + reporting.ReportErrorOrPanic(err) + continue + } + value, err := inter.InterpretEmbed("prompt", line) + if err != nil { + reporting.ReportErrorOrPanic(err) + continue + } + if value != nil { + fmt.Println("- ", value) + } + } +} diff --git a/app/lithia/cmd/root.go b/app/lithia/cmd/root.go new file mode 100644 index 0000000..2d458c9 --- /dev/null +++ b/app/lithia/cmd/root.go @@ -0,0 +1,29 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +func Execute() error { + return rootCmd.Execute() +} + +var rootCmd = &cobra.Command{ + Use: "lithia", + Short: "Lithia programming language", + Long: "Lithia is an experimental functional programming language " + + "with an implicit but strong and dynamic type system.\n" + + "It is designed around a few core concepts in mind " + + "all language features contribute to.\n" + + "\n" + + "Lean more at https://github.com/vknabel/lithia", + Version: "0.0.12-next", + Args: cobra.RangeArgs(0, 1), + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 1 { + runFile(args[0]) + } else { + runPrompt() + } + }, +} diff --git a/app/lithia/cmd/run.go b/app/lithia/cmd/run.go new file mode 100644 index 0000000..bfffb78 --- /dev/null +++ b/app/lithia/cmd/run.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "fmt" + "os" + "path" + + "github.com/spf13/cobra" + "github.com/vknabel/go-lithia/runtime" +) + +func init() { + rootCmd.AddCommand(runCmd) +} + +var runCmd = &cobra.Command{ + Use: "run [script]", + Short: "Runs a Lithia script", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + runFile(args[0]) + }, +} + +func runFile(fileName string) { + scriptData, err := os.ReadFile(fileName) + if err != nil { + fmt.Fprint(os.Stderr, err) + os.Exit(1) + } + inter := runtime.NewInterpreter(path.Dir(fileName)) + script := string(scriptData) + "\n" + _, err = inter.Interpret(fileName, script) + if err != nil { + fmt.Fprint(os.Stderr, err) + os.Exit(1) + } +} diff --git a/app/lithia/main.go b/app/lithia/main.go new file mode 100644 index 0000000..036f5a5 --- /dev/null +++ b/app/lithia/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "os" + + "github.com/vknabel/go-lithia/app/lithia/cmd" +) + +func main() { + err := cmd.Execute() + if err != nil { + fmt.Fprint(os.Stderr, err) + os.Exit(1) + } +} diff --git a/cmd/lithia/main.go b/cmd/lithia/main.go deleted file mode 100644 index bfd8ea1..0000000 --- a/cmd/lithia/main.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "io" - "os" - "path" - - "github.com/vknabel/go-lithia/reporting" - "github.com/vknabel/go-lithia/runtime" -) - -func main() { - args := os.Args[1:] - var err error - if len(args) > 1 { - fmt.Fprint(os.Stderr, "Usage: lithia