From f751975cfd967c717473fea400d926a4c9f8beb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Tue, 9 Oct 2018 10:37:56 +0200 Subject: Add a port to Go --- cmd/repl/main.go | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 cmd/repl/main.go (limited to 'cmd/repl') diff --git a/cmd/repl/main.go b/cmd/repl/main.go new file mode 100644 index 0000000..e7f35fb --- /dev/null +++ b/cmd/repl/main.go @@ -0,0 +1,91 @@ +// +// Copyright (c) 2018, Přemysl Janouch +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +// Program repl is an interactive ell interpreter. +package main + +import ( + "fmt" + "io" + "os" + "strings" + + // This library is rather simplistic but it's going to serve us fine. + "github.com/peterh/liner" + + "janouch.name/ell/ell" +) + +func run(L *ell.Ell, program *ell.V) { + var result *ell.V + if !L.EvalBlock(program, nil, &result) { + fmt.Printf("\x1b[31m%s: %s\x1b[0m\n", "runtime error", L.Error) + L.Error = "" + } else { + ell.PrintSeq(os.Stdout, result) + os.Stdout.WriteString("\n") + } +} + +func complete(L *ell.Ell, line string) (res []string) { + // This never actually completes anything, just shows the options, + // we'd have to figure out the longest common prefix. + res = append(res, line) + + line = strings.ToLower(line) + for v := L.Globals; v != nil; v = v.Next { + name := string(v.Head.String) + if strings.HasPrefix(strings.ToLower(name), line) { + res = append(res, name) + } + } + for name := range L.Native { + if strings.HasPrefix(strings.ToLower(name), line) { + res = append(res, name) + } + } + return +} + +func main() { + L := ell.New() + if !ell.StdInitialize(L) { + fmt.Printf("runtime library initialization failed: %s\n", L.Error) + } + + line := liner.NewLiner() + line.SetCompleter(func(line string) []string { return complete(L, line) }) + line.SetMultiLineMode(true) + line.SetTabCompletionStyle(liner.TabPrints) + + for { + script, err := line.Prompt("> ") + if err == nil { + line.AppendHistory(script) + + p := ell.NewParser([]byte(script)) + if program, err := p.Run(); err != nil { + fmt.Printf("\x1b[31m%s: %s\x1b[0m\n", "parse error", err) + } else { + run(L, program) + } + } else if err == liner.ErrPromptAborted || err == io.EOF { + break + } else { + fmt.Printf("\x1b[31m%s: %s\x1b[0m\n", "error", err) + } + } + os.Stdout.WriteString("\n") +} -- cgit v1.2.3