From 8c5cb299c2ce2a2ac4c7f905e1e68820b65ac596 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Wed, 11 Dec 2024 20:47:05 +1100 Subject: [PATCH] Started working on a REPL helper --- cmd/cmsh/main.go | 3 ++- repl/docs.go | 6 +++++ repl/evaldisplay.go | 37 ++++++++++++++++++++++++++ repl/repl.go | 64 +++++++++++++++++++++++++++++++++++++++++++++ ucl/evaldisplay.go | 35 ------------------------- ucl/inst.go | 2 +- 6 files changed, 110 insertions(+), 37 deletions(-) create mode 100644 repl/docs.go create mode 100644 repl/evaldisplay.go create mode 100644 repl/repl.go delete mode 100644 ucl/evaldisplay.go diff --git a/cmd/cmsh/main.go b/cmd/cmsh/main.go index afd1ba5..1688d2d 100644 --- a/cmd/cmsh/main.go +++ b/cmd/cmsh/main.go @@ -4,6 +4,7 @@ import ( "context" "github.com/chzyer/readline" "log" + "ucl.lmika.dev/repl" "ucl.lmika.dev/ucl" "ucl.lmika.dev/ucl/builtins" ) @@ -15,7 +16,7 @@ func main() { } defer rl.Close() - inst := ucl.New( + instRepl := repl.New( ucl.WithModule(builtins.OS()), ucl.WithModule(builtins.FS(nil)), ) diff --git a/repl/docs.go b/repl/docs.go new file mode 100644 index 0000000..a8ba0e4 --- /dev/null +++ b/repl/docs.go @@ -0,0 +1,6 @@ +package repl + +type Doc struct { + Brief string + Detailed string +} diff --git a/repl/evaldisplay.go b/repl/evaldisplay.go new file mode 100644 index 0000000..c8704ec --- /dev/null +++ b/repl/evaldisplay.go @@ -0,0 +1,37 @@ +package repl + +import ( + "context" + "fmt" + "os" + "ucl.lmika.dev/ucl" +) + +func (r *REPL) EvalAndDisplay(ctx context.Context, expr string) error { + res, err := r.inst.Eval(ctx, expr) + if err != nil { + return err + } + + return displayResult(ctx, r.inst, res) +} + +func displayResult(ctx context.Context, inst *ucl.Inst, res any) (err error) { + switch v := res.(type) { + case nil: + if _, err = fmt.Fprintln(os.Stdout, "(nil)"); err != nil { + return err + } + case listable: + for i := 0; i < v.Len(); i++ { + if err = displayResult(ctx, inst, v.Index(i)); err != nil { + return err + } + } + default: + if _, err = fmt.Fprintln(os.Stdout, v.String()); err != nil { + return err + } + } + return nil +} diff --git a/repl/repl.go b/repl/repl.go new file mode 100644 index 0000000..ec872c1 --- /dev/null +++ b/repl/repl.go @@ -0,0 +1,64 @@ +package repl + +import ( + "context" + "fmt" + "github.com/lmika/gopkgs/fp/maps" + "sort" + "ucl.lmika.dev/ucl" +) + +type CommandOpt interface { + config(cmdName string, r *REPL) +} + +type REPL struct { + inst *ucl.Inst + + commandDocs map[string]Doc +} + +func New(opts ...ucl.InstOption) *REPL { + inst := ucl.New(opts...) + + r := &REPL{ + inst: inst, + commandDocs: make(map[string]Doc), + } + inst.SetBuiltin("help", r.helpBuiltin) + + return r +} + +func (r *REPL) Inst() *ucl.Inst { + return r.inst +} + +func (r *REPL) SetCommand(name string, fn ucl.BuiltinHandler, opts ...CommandOpt) { + r.commandDocs[name] = Doc{} + for _, opt := range opts { + opt.config(name, r) + } + + r.inst.SetBuiltin(name, fn) +} + +func (r *REPL) helpBuiltin(ctx context.Context, args ucl.CallArgs) (any, error) { + switch { + case args.NArgs() == 0: + // TEMP + names := maps.Keys(r.commandDocs) + sort.Strings(names) + + for _, name := range names { + cdoc := r.commandDocs[name] + if cdoc.Brief != "" { + fmt.Println("%v\t%v", name, r.commandDocs[name]) + } else { + fmt.Println("%v", name) + } + } + // END TEMP + } + return nil, nil +} diff --git a/ucl/evaldisplay.go b/ucl/evaldisplay.go deleted file mode 100644 index b73fe87..0000000 --- a/ucl/evaldisplay.go +++ /dev/null @@ -1,35 +0,0 @@ -package ucl - -import ( - "context" - "fmt" -) - -func EvalAndDisplay(ctx context.Context, inst *Inst, expr string) error { - res, err := inst.eval(ctx, expr) - if err != nil { - return err - } - - return displayResult(ctx, inst, res) -} - -func displayResult(ctx context.Context, inst *Inst, res Object) (err error) { - switch v := res.(type) { - case nil: - if _, err = fmt.Fprintln(inst.out, "(nil)"); err != nil { - return err - } - case Listable: - for i := 0; i < v.Len(); i++ { - if err = displayResult(ctx, inst, v.Index(i)); err != nil { - return err - } - } - default: - if _, err = fmt.Fprintln(inst.out, v.String()); err != nil { - return err - } - } - return nil -} diff --git a/ucl/inst.go b/ucl/inst.go index 07b316c..f1c9b19 100644 --- a/ucl/inst.go +++ b/ucl/inst.go @@ -47,7 +47,7 @@ func New(opts ...InstOption) *Inst { rootEC.root = rootEC rootEC.addCmd("echo", invokableFunc(echoBuiltin)) - rootEC.addCmd("set", invokableFunc(setBuiltin)) + rootEC.addCmd("var", invokableFunc(setBuiltin)) rootEC.addCmd("toUpper", invokableFunc(toUpperBuiltin)) rootEC.addCmd("len", invokableFunc(lenBuiltin)) rootEC.addCmd("keys", invokableFunc(keysBuiltin))