Started working on a REPL helper
This commit is contained in:
parent
9b3b8287fa
commit
8c5cb299c2
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/chzyer/readline"
|
"github.com/chzyer/readline"
|
||||||
"log"
|
"log"
|
||||||
|
"ucl.lmika.dev/repl"
|
||||||
"ucl.lmika.dev/ucl"
|
"ucl.lmika.dev/ucl"
|
||||||
"ucl.lmika.dev/ucl/builtins"
|
"ucl.lmika.dev/ucl/builtins"
|
||||||
)
|
)
|
||||||
|
@ -15,7 +16,7 @@ func main() {
|
||||||
}
|
}
|
||||||
defer rl.Close()
|
defer rl.Close()
|
||||||
|
|
||||||
inst := ucl.New(
|
instRepl := repl.New(
|
||||||
ucl.WithModule(builtins.OS()),
|
ucl.WithModule(builtins.OS()),
|
||||||
ucl.WithModule(builtins.FS(nil)),
|
ucl.WithModule(builtins.FS(nil)),
|
||||||
)
|
)
|
||||||
|
|
6
repl/docs.go
Normal file
6
repl/docs.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package repl
|
||||||
|
|
||||||
|
type Doc struct {
|
||||||
|
Brief string
|
||||||
|
Detailed string
|
||||||
|
}
|
37
repl/evaldisplay.go
Normal file
37
repl/evaldisplay.go
Normal 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
64
repl/repl.go
Normal 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
|
||||||
|
}
|
|
@ -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
|
|
||||||
}
|
|
|
@ -47,7 +47,7 @@ func New(opts ...InstOption) *Inst {
|
||||||
rootEC.root = rootEC
|
rootEC.root = rootEC
|
||||||
|
|
||||||
rootEC.addCmd("echo", invokableFunc(echoBuiltin))
|
rootEC.addCmd("echo", invokableFunc(echoBuiltin))
|
||||||
rootEC.addCmd("set", invokableFunc(setBuiltin))
|
rootEC.addCmd("var", invokableFunc(setBuiltin))
|
||||||
rootEC.addCmd("toUpper", invokableFunc(toUpperBuiltin))
|
rootEC.addCmd("toUpper", invokableFunc(toUpperBuiltin))
|
||||||
rootEC.addCmd("len", invokableFunc(lenBuiltin))
|
rootEC.addCmd("len", invokableFunc(lenBuiltin))
|
||||||
rootEC.addCmd("keys", invokableFunc(keysBuiltin))
|
rootEC.addCmd("keys", invokableFunc(keysBuiltin))
|
||||||
|
|
Loading…
Reference in a new issue