From e141f7da4832580aed8c238197e06f6d00737615 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Fri, 8 Sep 2023 11:42:44 +0200 Subject: cli: use flags in command line Also isolate repl in a separate function. Introduce `run` function for executing programs, letting room for other verbs to be done later: test, debug, ... Use file path as argument. Standard input redirect is no more mandatory. --- main.go | 109 +++++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 36 deletions(-) diff --git a/main.go b/main.go index 037614c..4ae57da 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "bufio" "errors" + "flag" "fmt" "io" "log" @@ -20,42 +21,7 @@ type Interpreter interface { func main() { log.SetFlags(log.Lshortfile) - 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") - } - in := os.Stdin - - if isatty(in) { - // Provide an interactive line oriented Read Eval Print Loop (REPL). - liner := bufio.NewScanner(in) - text, prompt := "", "> " - fmt.Print(prompt) - for liner.Scan() { - text += liner.Text() - res, err := interp.Eval(text + "\n") - if err == nil { - if res != nil { - fmt.Println(": ", res) - } - text, prompt = "", "> " - } else if errors.Is(err, scanner.ErrBlock) { - prompt = ">> " - } else { - fmt.Println("Error:", err) - text, prompt = "", "> " - } - fmt.Print(prompt) - } - return - } - - buf, err := io.ReadAll(in) - if err != nil { - log.Fatal(err) - } - if _, err := interp.Eval(string(buf)); err != nil { + if err := run(os.Args[1:]); err != nil { log.Fatal(err) } } @@ -69,3 +35,74 @@ func isatty(in io.Reader) bool { stat, err := s.Stat() return err == nil && stat.Mode()&os.ModeCharDevice != 0 } + +// repl executes an interactive line oriented Read Eval Print Loop (REPL). +func repl(interp Interpreter, in io.Reader) (err error) { + liner := bufio.NewScanner(in) + text, prompt := "", "> " + fmt.Print(prompt) + for liner.Scan() { + text += liner.Text() + res, err := interp.Eval(text + "\n") + if err == nil { + if res != nil { + fmt.Println(": ", res) + } + text, prompt = "", "> " + } else if errors.Is(err, scanner.ErrBlock) { + prompt = ">> " + } else { + fmt.Println("Error:", err) + text, prompt = "", "> " + } + fmt.Print(prompt) + } + return +} + +func run(arg []string) (err error) { + var i int + + rflag := flag.NewFlagSet("run", flag.ContinueOnError) + rflag.IntVar(&i, "i", 1, "set interpreter version for execution, possible values: 0, 1") + rflag.Usage = func() { + fmt.Println("Usage: parscan run [options] [path] [args]") + fmt.Println("Options:") + rflag.PrintDefaults() + } + if err = rflag.Parse(arg); err != nil { + return err + } + args := rflag.Args() + + var interp Interpreter + switch i { + case 0: + interp = vm0.New(golang.GoParser) + case 1: + interp = codegen.NewInterpreter(golang.GoParser) + interp.(*codegen.Interpreter).AddSym(fmt.Println, "println") + default: + return fmt.Errorf("invalid interpreter version: %v", i) + } + + log.Println("args:", args) + in := os.Stdin + if len(args) > 0 { + if in, err = os.Open(arg[0]); err != nil { + return err + } + defer in.Close() + } + + if isatty(in) { + return repl(interp, in) + } + + buf, err := io.ReadAll(in) + if err != nil { + return err + } + _, err = interp.Eval(string(buf)) + return err +} -- cgit v1.2.3