Started working on a REPL helper

This commit is contained in:
Leon Mika 2024-12-11 20:47:05 +11:00
parent 9b3b8287fa
commit 8c5cb299c2
6 changed files with 110 additions and 37 deletions

View file

@ -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)),
)

6
repl/docs.go Normal file
View file

@ -0,0 +1,6 @@
package repl
type Doc struct {
Brief string
Detailed string
}

37
repl/evaldisplay.go Normal file
View file

@ -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
}

64
repl/repl.go Normal file
View file

@ -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
}

View file

@ -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
}

View file

@ -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))