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/interpreter/main.go | 63 ++++++++++++++++++++++++++++++++++ cmd/repl/main.go | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 cmd/interpreter/main.go create mode 100644 cmd/repl/main.go (limited to 'cmd') diff --git a/cmd/interpreter/main.go b/cmd/interpreter/main.go new file mode 100644 index 0000000..822aec8 --- /dev/null +++ b/cmd/interpreter/main.go @@ -0,0 +1,63 @@ +// +// 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 interpreter is a basic ell interpreter. +package main + +import ( + "fmt" + "io/ioutil" + "os" + + "janouch.name/ell/ell" +) + +func main() { + var script []byte + var err error + + if len(os.Args) < 2 { + script, err = ioutil.ReadAll(os.Stdin) + } else { + script, err = ioutil.ReadFile(os.Args[1]) + } + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + L := ell.New() + if !ell.StdInitialize(L) { + fmt.Printf("runtime library initialization failed: %s\n", L.Error) + } + + program, err := ell.NewParser(script).Run() + if err != nil { + fmt.Printf("%s: %s\n", "parse error", err) + os.Exit(1) + } + + var args *ell.V + tail := &args + for i := 2; i < len(os.Args); i++ { + *tail = ell.NewString([]byte(os.Args[i])) + tail = &(*tail).Next + } + + var result *ell.V + if !L.EvalBlock(program, args, &result) { + fmt.Printf("%s: %s\n", "runtime error", L.Error) + } +} 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