diff options
| author | Marc Vertes <mvertes@free.fr> | 2023-08-29 18:22:13 +0200 |
|---|---|---|
| committer | Marc Vertes <mvertes@free.fr> | 2023-08-29 18:22:13 +0200 |
| commit | 0f4bfe6e70263fbeb580014b62632f403b29b414 (patch) | |
| tree | de750b60a6c0027b36accf9f0596c3e651309cda /cmd/gint | |
| parent | a3ab9ef5be74cb54a87674aa48abb0c46f9c58f6 (diff) | |
gint: add an interactive REPL
Diffstat (limited to 'cmd/gint')
| -rw-r--r-- | cmd/gint/main.go | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/cmd/gint/main.go b/cmd/gint/main.go index 3ddddc8..5b2b3a2 100644 --- a/cmd/gint/main.go +++ b/cmd/gint/main.go @@ -1,12 +1,16 @@ package main import ( + "bufio" + "errors" "fmt" + "io" "log" "os" "github.com/gnolang/parscan/codegen" "github.com/gnolang/parscan/lang/golang" + "github.com/gnolang/parscan/scanner" "github.com/gnolang/parscan/vm0" ) @@ -16,16 +20,49 @@ type Interpreter interface { func main() { log.SetFlags(log.Lshortfile) - buf, err := os.ReadFile("/dev/stdin") - if err != nil { - log.Fatal(err) - } var interp Interpreter = vm0.New(golang.GoParser) if len(os.Args) > 1 && os.Args[1] == "1" { interp = codegen.NewInterpreter(golang.GoParser) interp.(*codegen.Interpreter).AddSym(fmt.Println, "println", false) } + in := os.Stdin + + if isatty(in) { + // Provide an interactive line oriented Read Eval Print Loop (REPL). + liner := bufio.NewScanner(in) + text, prompt := "", "> " + fmt.Printf(prompt) + for liner.Scan() { + text += liner.Text() + err := interp.Eval(text + "\n") + if err == nil { + text, prompt = "", "> " + } else if errors.Is(err, scanner.ErrBlock) { + prompt = ">> " + } else { + text, prompt = "", "> " + fmt.Println("Error:", err) + } + fmt.Printf(prompt) + } + return + } + + buf, err := io.ReadAll(in) + if err != nil { + log.Fatal(err) + } if err := interp.Eval(string(buf)); err != nil { log.Fatal(err) } } + +// isatty returns true if the input stream is a tty (i.e. a character device). +func isatty(in io.Reader) bool { + s, ok := in.(interface{ Stat() (os.FileInfo, error) }) + if !ok { + return false + } + stat, err := s.Stat() + return err == nil && stat.Mode()&os.ModeCharDevice != 0 +} |
