Renamed project to ucl
This commit is contained in:
parent
c7a4013641
commit
60147d8fdf
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@ clean:
|
||||||
-rm -r build
|
-rm -r build
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test ./cmdlang/...
|
go test ./ucl/...
|
||||||
|
|
||||||
site: clean
|
site: clean
|
||||||
mkdir build
|
mkdir build
|
||||||
|
|
|
@ -3,7 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/chzyer/readline"
|
"github.com/chzyer/readline"
|
||||||
"github.com/lmika/cmdlang-proto/cmdlang"
|
"github.com/lmika/ucl/ucl"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ func main() {
|
||||||
}
|
}
|
||||||
defer rl.Close()
|
defer rl.Close()
|
||||||
|
|
||||||
inst := cmdlang.New()
|
inst := ucl.New()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
@ -23,7 +23,7 @@ func main() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := inst.EvalAndDisplay(ctx, line); err != nil {
|
if err := ucl.EvalAndDisplay(ctx, inst, line); err != nil {
|
||||||
log.Printf("%T: %v", err, err)
|
log.Printf("%T: %v", err, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/alecthomas/participle/v2"
|
"github.com/alecthomas/participle/v2"
|
||||||
"github.com/lmika/cmdlang-proto/cmdlang"
|
"github.com/lmika/ucl/ucl"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall/js"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func invokeUCLCallback(name string, args ...any) {
|
func invokeUCLCallback(name string, args ...any) {
|
||||||
|
@ -21,7 +20,7 @@ func invokeUCLCallback(name string, args ...any) {
|
||||||
func initJS(ctx context.Context) {
|
func initJS(ctx context.Context) {
|
||||||
ucl := make(map[string]any)
|
ucl := make(map[string]any)
|
||||||
|
|
||||||
inst := cmdlang.New(cmdlang.WithOut(&uclOut{
|
inst := ucl.New(ucl.WithOut(&uclOut{
|
||||||
lineBuffer: new(bytes.Buffer),
|
lineBuffer: new(bytes.Buffer),
|
||||||
writeLine: func(line string) {
|
writeLine: func(line string) {
|
||||||
invokeUCLCallback("onOutLine", line)
|
invokeUCLCallback("onOutLine", line)
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
package cmdlang
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
func egLookup(ctx context.Context, args invocationArgs) (object, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
2
go.mod
2
go.mod
|
@ -1,4 +1,4 @@
|
||||||
module github.com/lmika/cmdlang-proto
|
module github.com/lmika/ucl
|
||||||
|
|
||||||
go 1.21.1
|
go 1.21.1
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package cmdlang
|
package ucl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
@ -64,12 +64,13 @@ type astStatements struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type astScript struct {
|
type astScript struct {
|
||||||
Statements *astStatements `parser:"NL* @@ NL*"`
|
Statements *astStatements `parser:"NL* (@@ NL*)?"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var scanner = lexer.MustStateful(lexer.Rules{
|
var scanner = lexer.MustStateful(lexer.Rules{
|
||||||
"Root": {
|
"Root": {
|
||||||
{"Whitespace", `[ \t]+`, nil},
|
{"Whitespace", `[ \t]+`, nil},
|
||||||
|
{"Comment", `[#].*`, nil},
|
||||||
{"String", `"(\\"|[^"])*"`, nil},
|
{"String", `"(\\"|[^"])*"`, nil},
|
||||||
{"Int", `[-]?[0-9][0-9]*`, nil},
|
{"Int", `[-]?[0-9][0-9]*`, nil},
|
||||||
{"DOLLAR", `\$`, nil},
|
{"DOLLAR", `\$`, nil},
|
||||||
|
@ -86,7 +87,7 @@ var scanner = lexer.MustStateful(lexer.Rules{
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
var parser = participle.MustBuild[astScript](participle.Lexer(scanner),
|
var parser = participle.MustBuild[astScript](participle.Lexer(scanner),
|
||||||
participle.Elide("Whitespace"))
|
participle.Elide("Whitespace", "Comment"))
|
||||||
|
|
||||||
func parse(r io.Reader) (*astScript, error) {
|
func parse(r io.Reader) (*astScript, error) {
|
||||||
return parser.Parse("test", r)
|
return parser.Parse("test", r)
|
|
@ -1,4 +1,4 @@
|
||||||
package cmdlang
|
package ucl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -40,8 +40,7 @@ func setBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
|
|
||||||
newVal := args.args[1]
|
newVal := args.args[1]
|
||||||
|
|
||||||
// TODO: if the value is a stream, consume the stream and save it as a list
|
args.ec.setOrDefineVar(name, newVal)
|
||||||
args.ec.setVar(name, newVal)
|
|
||||||
return newVal, nil
|
return newVal, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,9 +382,9 @@ func (b procObject) invoke(ctx context.Context, args invocationArgs) (object, er
|
||||||
|
|
||||||
for i, name := range b.block.Names {
|
for i, name := range b.block.Names {
|
||||||
if i < len(args.args) {
|
if i < len(args.args) {
|
||||||
newEc.setVar(name, args.args[i])
|
newEc.setOrDefineVar(name, args.args[i])
|
||||||
} else {
|
} else {
|
||||||
newEc.setVar(name, nil)
|
newEc.setOrDefineVar(name, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package cmdlang
|
package ucl
|
||||||
|
|
||||||
type evalCtx struct {
|
type evalCtx struct {
|
||||||
root *evalCtx
|
root *evalCtx
|
||||||
|
@ -34,7 +34,24 @@ func (ec *evalCtx) addMacro(name string, inv macroable) {
|
||||||
ec.root.macros[name] = inv
|
ec.root.macros[name] = inv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *evalCtx) setVar(name string, val object) {
|
func (ec *evalCtx) setVar(name string, val object) bool {
|
||||||
|
if ec == nil || ec.vars == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := ec.vars[name]; ok {
|
||||||
|
ec.vars[name] = val
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return ec.parent.setVar(name, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *evalCtx) setOrDefineVar(name string, val object) {
|
||||||
|
if ec.setVar(name, val) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if ec.vars == nil {
|
if ec.vars == nil {
|
||||||
ec.vars = make(map[string]object)
|
ec.vars = make(map[string]object)
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package cmdlang
|
package ucl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -27,6 +27,10 @@ func (e evaluator) evalScript(ctx context.Context, ec *evalCtx, n *astScript) (l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e evaluator) evalStatement(ctx context.Context, ec *evalCtx, n *astStatements) (object, error) {
|
func (e evaluator) evalStatement(ctx context.Context, ec *evalCtx, n *astStatements) (object, error) {
|
||||||
|
if n == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
res, err := e.evalPipeline(ctx, ec, n.First)
|
res, err := e.evalPipeline(ctx, ec, n.First)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
29
ucl/evaldisplay.go
Normal file
29
ucl/evaldisplay.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if _, err = fmt.Fprintln(inst.out, v.String()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
package cmdlang
|
package ucl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -47,7 +46,7 @@ func New(opts ...InstOption) *Inst {
|
||||||
|
|
||||||
//rootEC.addCmd("testTimebomb", invokableStreamFunc(errorTestBuiltin))
|
//rootEC.addCmd("testTimebomb", invokableStreamFunc(errorTestBuiltin))
|
||||||
|
|
||||||
rootEC.setVar("hello", strObject("world"))
|
rootEC.setOrDefineVar("hello", strObject("world"))
|
||||||
|
|
||||||
inst := &Inst{
|
inst := &Inst{
|
||||||
out: os.Stdout,
|
out: os.Stdout,
|
||||||
|
@ -93,26 +92,3 @@ func (inst *Inst) eval(ctx context.Context, expr string) (object, error) {
|
||||||
// TODO: this should be a separate forkAndIsolate() session
|
// TODO: this should be a separate forkAndIsolate() session
|
||||||
return eval.evalScript(ctx, inst.rootEC, ast)
|
return eval.evalScript(ctx, inst.rootEC, ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inst *Inst) EvalAndDisplay(ctx context.Context, expr string) error {
|
|
||||||
res, err := inst.eval(ctx, expr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return inst.display(ctx, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (inst *Inst) display(ctx context.Context, res object) (err error) {
|
|
||||||
switch v := res.(type) {
|
|
||||||
case nil:
|
|
||||||
if _, err = fmt.Fprintln(inst.out, "(nil)"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if _, err = fmt.Fprintln(inst.out, v.String()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,11 +1,11 @@
|
||||||
package cmdlang_test
|
package ucl_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/lmika/ucl/ucl"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/lmika/cmdlang-proto/cmdlang"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ func TestInst_Eval(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
outW := bytes.NewBuffer(nil)
|
outW := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
inst := cmdlang.New(cmdlang.WithOut(outW), cmdlang.WithTestBuiltin())
|
inst := ucl.New(ucl.WithOut(outW), ucl.WithTestBuiltin())
|
||||||
res, err := inst.Eval(ctx, tt.expr)
|
res, err := inst.Eval(ctx, tt.expr)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
|
@ -1,4 +1,4 @@
|
||||||
package cmdlang
|
package ucl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -235,7 +235,7 @@ func (ma macroArgs) evalBlock(ctx context.Context, n int, args []object, pushSco
|
||||||
}
|
}
|
||||||
for i, n := range block.block.Names {
|
for i, n := range block.block.Names {
|
||||||
if i < len(args) {
|
if i < len(args) {
|
||||||
ec.setVar(n, args[i])
|
ec.setOrDefineVar(n, args[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,7 +341,7 @@ func (bo blockObject) invoke(ctx context.Context, args invocationArgs) (object,
|
||||||
ec := args.ec.fork()
|
ec := args.ec.fork()
|
||||||
for i, n := range bo.block.Names {
|
for i, n := range bo.block.Names {
|
||||||
if i < len(args.args) {
|
if i < len(args.args) {
|
||||||
ec.setVar(n, args.args[i])
|
ec.setOrDefineVar(n, args.args[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,8 +370,7 @@ func (p proxyObject) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p proxyObject) Truthy() bool {
|
func (p proxyObject) Truthy() bool {
|
||||||
//TODO implement me
|
return p.p != nil
|
||||||
panic("implement me")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type listableProxyObject struct {
|
type listableProxyObject struct {
|
||||||
|
@ -383,7 +382,7 @@ func (p listableProxyObject) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p listableProxyObject) Truthy() bool {
|
func (p listableProxyObject) Truthy() bool {
|
||||||
panic("implement me")
|
return p.v.Len() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p listableProxyObject) Len() int {
|
func (p listableProxyObject) Len() int {
|
|
@ -1,4 +1,4 @@
|
||||||
package cmdlang
|
package ucl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -53,8 +53,8 @@ func WithTestBuiltin() InstOption {
|
||||||
return strObject(sb.String()), nil
|
return strObject(sb.String()), nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
i.rootEC.setVar("a", strObject("alpha"))
|
i.rootEC.setOrDefineVar("a", strObject("alpha"))
|
||||||
i.rootEC.setVar("bee", strObject("buzz"))
|
i.rootEC.setOrDefineVar("bee", strObject("buzz"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +84,18 @@ func TestBuiltins_Echo(t *testing.T) {
|
||||||
;
|
;
|
||||||
|
|
||||||
echo "world"
|
echo "world"
|
||||||
|
;
|
||||||
|
`, want: "Hello\nworld\n"},
|
||||||
|
{desc: "multi-line 4", expr: `
|
||||||
|
# This is a comment
|
||||||
|
#
|
||||||
|
|
||||||
|
;;;
|
||||||
|
# This is another comment
|
||||||
|
echo "Hello"
|
||||||
|
;
|
||||||
|
|
||||||
|
echo "world" # command after this
|
||||||
;
|
;
|
||||||
`, want: "Hello\nworld\n"},
|
`, want: "Hello\nworld\n"},
|
||||||
}
|
}
|
||||||
|
@ -167,7 +179,7 @@ func TestBuiltins_If(t *testing.T) {
|
||||||
outW := bytes.NewBuffer(nil)
|
outW := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
inst := New(WithOut(outW), WithTestBuiltin())
|
inst := New(WithOut(outW), WithTestBuiltin())
|
||||||
err := inst.EvalAndDisplay(ctx, tt.expr)
|
err := EvalAndDisplay(ctx, inst, tt.expr)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, tt.want, outW.String())
|
assert.Equal(t, tt.want, outW.String())
|
||||||
|
@ -197,7 +209,7 @@ func TestBuiltins_ForEach(t *testing.T) {
|
||||||
outW := bytes.NewBuffer(nil)
|
outW := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
inst := New(WithOut(outW), WithTestBuiltin())
|
inst := New(WithOut(outW), WithTestBuiltin())
|
||||||
err := inst.EvalAndDisplay(ctx, tt.expr)
|
err := EvalAndDisplay(ctx, inst, tt.expr)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, tt.want, outW.String())
|
assert.Equal(t, tt.want, outW.String())
|
||||||
|
@ -257,18 +269,18 @@ func TestBuiltins_Procs(t *testing.T) {
|
||||||
call (makeGreeter "Quick") "call me"
|
call (makeGreeter "Quick") "call me"
|
||||||
|
|
||||||
`, want: "Hello, world\nGoodbye cruel, world\nQuick, call me\n(nil)\n"},
|
`, want: "Hello, world\nGoodbye cruel, world\nQuick, call me\n(nil)\n"},
|
||||||
//{desc: "modifying closed over variables", expr: `
|
{desc: "modifying closed over variables", expr: `
|
||||||
// proc makeSetter {
|
proc makeSetter {
|
||||||
// set bla "X"
|
set bla "X"
|
||||||
// proc appendToBla { |x|
|
proc appendToBla { |x|
|
||||||
// set bla (cat $bla $x)
|
set bla (cat $bla $x)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// set er (makeSetter)
|
set er (makeSetter)
|
||||||
// call $er "xxx"
|
echo (call $er "xxx")
|
||||||
// call $er "yyy"
|
echo (call $er "yyy")
|
||||||
// `, want: "Xxxx\nXxxxyyy(nil)\n"},
|
`, want: "Xxxx\nXxxxyyy\n(nil)\n"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
@ -277,7 +289,7 @@ func TestBuiltins_Procs(t *testing.T) {
|
||||||
outW := bytes.NewBuffer(nil)
|
outW := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
inst := New(WithOut(outW), WithTestBuiltin())
|
inst := New(WithOut(outW), WithTestBuiltin())
|
||||||
err := inst.EvalAndDisplay(ctx, tt.expr)
|
err := EvalAndDisplay(ctx, inst, tt.expr)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, tt.want, outW.String())
|
assert.Equal(t, tt.want, outW.String())
|
||||||
|
@ -309,12 +321,12 @@ func TestBuiltins_Map(t *testing.T) {
|
||||||
{desc: "map list with block", expr: `
|
{desc: "map list with block", expr: `
|
||||||
map ["a" "b" "c"] { |x| toUpper $x }
|
map ["a" "b" "c"] { |x| toUpper $x }
|
||||||
`, want: "[A B C]\n"},
|
`, want: "[A B C]\n"},
|
||||||
//{desc: "map list with stream", expr: `
|
{desc: "map list with stream", expr: `
|
||||||
// set makeUpper (proc { |x| $x | toUpper })
|
set makeUpper (proc { |x| toUpper $x })
|
||||||
//
|
|
||||||
// set l (["a" "b" "c"] | map $makeUpper)
|
set l (["a" "b" "c"] | map $makeUpper)
|
||||||
// echo $l
|
echo $l
|
||||||
// `, want: "[A B C]\n"},
|
`, want: "[A B C]\n(nil)\n"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
@ -323,7 +335,7 @@ func TestBuiltins_Map(t *testing.T) {
|
||||||
outW := bytes.NewBuffer(nil)
|
outW := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
inst := New(WithOut(outW), WithTestBuiltin())
|
inst := New(WithOut(outW), WithTestBuiltin())
|
||||||
err := inst.EvalAndDisplay(ctx, tt.expr)
|
err := EvalAndDisplay(ctx, inst, tt.expr)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, tt.want, outW.String())
|
assert.Equal(t, tt.want, outW.String())
|
||||||
|
@ -379,7 +391,7 @@ func TestBuiltins_Index(t *testing.T) {
|
||||||
Gamma: []int{22, 33},
|
Gamma: []int{22, 33},
|
||||||
}, nil
|
}, nil
|
||||||
})
|
})
|
||||||
err := inst.EvalAndDisplay(ctx, tt.expr)
|
err := EvalAndDisplay(ctx, inst, tt.expr)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, tt.want, outW.String())
|
assert.Equal(t, tt.want, outW.String())
|
||||||
|
@ -438,7 +450,7 @@ func TestBuiltins_Len(t *testing.T) {
|
||||||
missing: "missing",
|
missing: "missing",
|
||||||
}, nil
|
}, nil
|
||||||
})
|
})
|
||||||
err := inst.EvalAndDisplay(ctx, tt.expr)
|
err := EvalAndDisplay(ctx, inst, tt.expr)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, tt.want, outW.String())
|
assert.Equal(t, tt.want, outW.String())
|
|
@ -1,4 +1,4 @@
|
||||||
package cmdlang
|
package ucl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -10,8 +10,8 @@ type CallArgs struct {
|
||||||
args invocationArgs
|
args invocationArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ca CallArgs) Bind(vars ...interface{}) error {
|
func (ca *CallArgs) Bind(vars ...interface{}) error {
|
||||||
if len(ca.args.args) != len(vars) {
|
if len(ca.args.args) < len(vars) {
|
||||||
return errors.New("wrong number of arguments")
|
return errors.New("wrong number of arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ func (ca CallArgs) Bind(vars ...interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ca.args = ca.args.shift(len(vars))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
package cmdlang_test
|
package ucl_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/lmika/ucl/ucl"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/lmika/cmdlang-proto/cmdlang"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInst_SetBuiltin(t *testing.T) {
|
func TestInst_SetBuiltin(t *testing.T) {
|
||||||
t.Run("simple builtin accepting and returning strings", func(t *testing.T) {
|
t.Run("simple builtin accepting and returning strings", func(t *testing.T) {
|
||||||
inst := cmdlang.New()
|
inst := ucl.New()
|
||||||
inst.SetBuiltin("add2", func(ctx context.Context, args cmdlang.CallArgs) (any, error) {
|
inst.SetBuiltin("add2", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
var x, y string
|
var x, y string
|
||||||
|
|
||||||
if err := args.Bind(&x, &y); err != nil {
|
if err := args.Bind(&x, &y); err != nil {
|
||||||
|
@ -28,9 +28,29 @@ func TestInst_SetBuiltin(t *testing.T) {
|
||||||
assert.Equal(t, "Hello, World", res)
|
assert.Equal(t, "Hello, World", res)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("bind shift arguments", func(t *testing.T) {
|
||||||
|
inst := ucl.New()
|
||||||
|
inst.SetBuiltin("add2", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
|
var x, y string
|
||||||
|
|
||||||
|
if err := args.Bind(&x); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := args.Bind(&y); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return x + y, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
res, err := inst.Eval(context.Background(), `add2 "Hello, " "World"`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "Hello, World", res)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("simple builtin with optional switches and strings", func(t *testing.T) {
|
t.Run("simple builtin with optional switches and strings", func(t *testing.T) {
|
||||||
inst := cmdlang.New()
|
inst := ucl.New()
|
||||||
inst.SetBuiltin("add2", func(ctx context.Context, args cmdlang.CallArgs) (any, error) {
|
inst.SetBuiltin("add2", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
var x, y, sep string
|
var x, y, sep string
|
||||||
|
|
||||||
if err := args.BindSwitch("sep", &sep); err != nil {
|
if err := args.BindSwitch("sep", &sep); err != nil {
|
||||||
|
@ -75,8 +95,8 @@ func TestInst_SetBuiltin(t *testing.T) {
|
||||||
x, y string
|
x, y string
|
||||||
}
|
}
|
||||||
|
|
||||||
inst := cmdlang.New()
|
inst := ucl.New()
|
||||||
inst.SetBuiltin("add2", func(ctx context.Context, args cmdlang.CallArgs) (any, error) {
|
inst.SetBuiltin("add2", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
var x, y string
|
var x, y string
|
||||||
|
|
||||||
if err := args.Bind(&x, &y); err != nil {
|
if err := args.Bind(&x, &y); err != nil {
|
||||||
|
@ -107,8 +127,8 @@ func TestInst_SetBuiltin(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.descr, func(t *testing.T) {
|
t.Run(tt.descr, func(t *testing.T) {
|
||||||
inst := cmdlang.New()
|
inst := ucl.New()
|
||||||
inst.SetBuiltin("add2", func(ctx context.Context, args cmdlang.CallArgs) (any, error) {
|
inst.SetBuiltin("add2", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
var x, y string
|
var x, y string
|
||||||
|
|
||||||
if err := args.Bind(&x, &y); err != nil {
|
if err := args.Bind(&x, &y); err != nil {
|
||||||
|
@ -117,7 +137,7 @@ func TestInst_SetBuiltin(t *testing.T) {
|
||||||
|
|
||||||
return pair{x, y}, nil
|
return pair{x, y}, nil
|
||||||
})
|
})
|
||||||
inst.SetBuiltin("join", func(ctx context.Context, args cmdlang.CallArgs) (any, error) {
|
inst.SetBuiltin("join", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
var x pair
|
var x pair
|
||||||
|
|
||||||
if err := args.Bind(&x); err != nil {
|
if err := args.Bind(&x); err != nil {
|
||||||
|
@ -148,9 +168,9 @@ func TestInst_SetBuiltin(t *testing.T) {
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.descr, func(t *testing.T) {
|
t.Run(tt.descr, func(t *testing.T) {
|
||||||
outW := bytes.NewBuffer(nil)
|
outW := bytes.NewBuffer(nil)
|
||||||
inst := cmdlang.New(cmdlang.WithOut(outW))
|
inst := ucl.New(ucl.WithOut(outW))
|
||||||
|
|
||||||
inst.SetBuiltin("countTo3", func(ctx context.Context, args cmdlang.CallArgs) (any, error) {
|
inst.SetBuiltin("countTo3", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
return []string{"1", "2", "3"}, nil
|
return []string{"1", "2", "3"}, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -167,14 +187,14 @@ func TestCallArgs_Bind(t *testing.T) {
|
||||||
t.Run("bind to an interface", func(t *testing.T) {
|
t.Run("bind to an interface", func(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
inst := cmdlang.New()
|
inst := ucl.New()
|
||||||
inst.SetBuiltin("sa", func(ctx context.Context, args cmdlang.CallArgs) (any, error) {
|
inst.SetBuiltin("sa", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
return doStringA{this: "a val"}, nil
|
return doStringA{this: "a val"}, nil
|
||||||
})
|
})
|
||||||
inst.SetBuiltin("sb", func(ctx context.Context, args cmdlang.CallArgs) (any, error) {
|
inst.SetBuiltin("sb", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
return doStringB{left: "foo", right: "bar"}, nil
|
return doStringB{left: "foo", right: "bar"}, nil
|
||||||
})
|
})
|
||||||
inst.SetBuiltin("dostr", func(ctx context.Context, args cmdlang.CallArgs) (any, error) {
|
inst.SetBuiltin("dostr", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
var ds doStringable
|
var ds doStringable
|
||||||
|
|
||||||
if err := args.Bind(&ds); err != nil {
|
if err := args.Bind(&ds); err != nil {
|
Loading…
Reference in a new issue