Fixed tests
Some checks failed
Build / build (push) Failing after 1m49s

This commit is contained in:
Leon Mika 2025-04-10 21:35:12 +10:00
parent 0a7021845e
commit 0ddffcc489
13 changed files with 70 additions and 63 deletions

3
go.mod
View file

@ -1,6 +1,6 @@
module ucl.lmika.dev
go 1.21.1
go 1.24
require (
github.com/alecthomas/participle/v2 v2.1.1
@ -13,7 +13,6 @@ require (
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View file

@ -75,7 +75,7 @@ type astListOrHash struct {
type astBlock struct {
Names []string `parser:"LC NL? (PIPE @Ident+ PIPE NL?)?"`
Statements []*astStatements `parser:"@@ NL? RC"`
Statements []*astStatements `parser:"@@* NL? RC"`
}
type astMaybeSub struct {
@ -139,7 +139,7 @@ var scanner = lexer.MustStateful(lexer.Rules{
{"RC", `\}`, nil},
{"NL", `[;\n][; \n\t]*`, nil},
{"PIPE", `\|`, nil},
{"Ident", `[-]*[a-zA-Z_][\w-]*`, nil},
{"Ident", `[-]*[a-zA-Z_][\w-!?]*`, nil},
},
"String": {
{"Escaped", `\\.`, nil},

View file

@ -196,6 +196,25 @@ func setBuiltin(ctx context.Context, args invocationArgs) (Object, error) {
return newVal, nil
}
func mustSetBuiltin(ctx context.Context, args invocationArgs) (Object, error) {
if err := args.expectArgn(2); err != nil {
return nil, err
}
name, err := args.stringArg(0)
if err != nil {
return nil, err
}
newVal := args.args[1]
if newVal == nil {
return nil, fmt.Errorf("attempt to set '%v' to a nil value", args.args[0])
}
args.ec.setOrDefineVar(name, newVal)
return newVal, nil
}
func eqBuiltin(ctx context.Context, args invocationArgs) (Object, error) {
if err := args.expectArgn(2); err != nil {
return nil, err
@ -878,7 +897,7 @@ func ifBuiltin(ctx context.Context, args macroArgs) (Object, error) {
return nil, errors.New("malformed if-elif-else")
}
func foreachBuiltin(ctx context.Context, args macroArgs) (object, error) {
func foreachBuiltin(ctx context.Context, args macroArgs) (Object, error) {
var (
items Object
blockIdx int

View file

@ -68,6 +68,22 @@ func (h csvHandlers) eachRecord(ctx context.Context, args ucl.CallArgs) (any, er
return nil, nil
}
type stringSlice []string
func (ss stringSlice) String() string {
return strings.Join(ss, ",")
}
func (ss stringSlice) Truthy() bool {
return len(ss) > 0
}
func (ss stringSlice) Len() int {
return len(ss)
}
func (ss stringSlice) Index(i int) ucl.Object {
return ucl.StringObject(ss[i])
}
type headerIndexObject map[string]int
func (hio headerIndexObject) String() string {

View file

@ -5,7 +5,7 @@ type evalCtx struct {
parent *evalCtx
commands map[string]invokable
macros map[string]macroable
vars map[string]object
vars map[string]Object
}
func (ec *evalCtx) forkAndIsolate() *evalCtx {
@ -34,7 +34,7 @@ func (ec *evalCtx) addMacro(name string, inv macroable) {
ec.root.macros[name] = inv
}
func (ec *evalCtx) setVar(name string, val object) bool {
func (ec *evalCtx) setVar(name string, val Object) bool {
if ec == nil || ec.vars == nil {
return false
}
@ -47,20 +47,20 @@ func (ec *evalCtx) setVar(name string, val object) bool {
return ec.parent.setVar(name, val)
}
func (ec *evalCtx) setOrDefineVar(name string, val object) {
func (ec *evalCtx) setOrDefineVar(name string, val Object) {
if ec.setVar(name, val) {
return
}
if ec.vars == nil {
ec.vars = make(map[string]object)
ec.vars = make(map[string]Object)
}
ec.vars[name] = val
}
func (ec *evalCtx) getVar(name string) (object, bool) {
func (ec *evalCtx) getVar(name string) (Object, bool) {
if ec.vars == nil {
return nil, false
return ec.parent.getVar(name)
}
if v, ok := ec.vars[name]; ok {

View file

@ -108,9 +108,9 @@ func (e evaluator) evalCmd(ctx context.Context, ec *evalCtx, currentPipe Object,
func (e evaluator) evalInvokable(ctx context.Context, ec *evalCtx, currentPipe Object, ast *astCmd, cmd invokable) (Object, error) {
var (
pargs listObject
kwargs map[string]*listObject
argsPtr *listObject
pargs ListObject
kwargs map[string]*ListObject
argsPtr *ListObject
)
argsPtr = &pargs
@ -121,10 +121,10 @@ func (e evaluator) evalInvokable(ctx context.Context, ec *evalCtx, currentPipe O
if ident := arg.Arg.Ident; len(arg.DotSuffix) == 0 && ident != nil && ident.String()[0] == '-' {
// Arg switch
if kwargs == nil {
kwargs = make(map[string]*listObject)
kwargs = make(map[string]*ListObject)
}
argsPtr = &listObject{}
argsPtr = &ListObject{}
kwargs[ident.String()[1:]] = argsPtr
} else {
ae, err := e.evalDot(ctx, ec, arg)
@ -203,7 +203,7 @@ func (e evaluator) evalArg(ctx context.Context, ec *evalCtx, n astCmdArg) (Objec
func (e evaluator) evalListOrHash(ctx context.Context, ec *evalCtx, loh *astListOrHash) (Object, error) {
if loh.EmptyList {
return listObject{}, nil
return &ListObject{}, nil
} else if loh.EmptyHash {
return hashObject{}, nil
}
@ -230,7 +230,7 @@ func (e evaluator) evalListOrHash(ctx context.Context, ec *evalCtx, loh *astList
return h, nil
}
l := listObject{}
l := ListObject{}
for _, el := range loh.Elements {
if el.Right != nil {
return nil, errors.New("miss-match of lists and hash")
@ -241,7 +241,7 @@ func (e evaluator) evalListOrHash(ctx context.Context, ec *evalCtx, loh *astList
}
l = append(l, v)
}
return l, nil
return &l, nil
}
func (e evaluator) evalLiteral(ctx context.Context, ec *evalCtx, n *astLiteral) (Object, error) {

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

@ -57,14 +57,19 @@ func New(opts ...InstOption) *Inst {
rootEC.addCmd("echo", invokableFunc(echoBuiltin))
rootEC.addCmd("set", invokableFunc(setBuiltin))
rootEC.addCmd("set!", invokableFunc(mustSetBuiltin))
rootEC.addCmd("len", invokableFunc(lenBuiltin))
rootEC.addCmd("index", invokableFunc(indexBuiltin))
rootEC.addCmd("call", invokableFunc(callBuiltin))
rootEC.addCmd("seq", invokableFunc(seqBuiltin))
rootEC.addCmd("map", invokableFunc(mapBuiltin))
rootEC.addCmd("filter", invokableFunc(filterBuiltin))
rootEC.addCmd("reduce", invokableFunc(reduceBuiltin))
rootEC.addCmd("head", invokableFunc(firstBuiltin))
rootEC.addCmd("keys", invokableFunc(keysBuiltin))
rootEC.addCmd("eq", invokableFunc(eqBuiltin))
rootEC.addCmd("ne", invokableFunc(neBuiltin))
rootEC.addCmd("gt", invokableFunc(gtBuiltin))
@ -75,11 +80,16 @@ func New(opts ...InstOption) *Inst {
rootEC.addCmd("str", invokableFunc(strBuiltin))
rootEC.addCmd("int", invokableFunc(intBuiltin))
rootEC.addCmd("add", invokableFunc(addBuiltin))
rootEC.addCmd("sub", invokableFunc(subBuiltin))
rootEC.addCmd("mup", invokableFunc(mupBuiltin))
rootEC.addCmd("div", invokableFunc(divBuiltin))
rootEC.addCmd("mod", invokableFunc(modBuiltin))
rootEC.addCmd("and", invokableFunc(andBuiltin))
rootEC.addCmd("or", invokableFunc(orBuiltin))
rootEC.addCmd("not", invokableFunc(notBuiltin))
rootEC.addCmd("cat", invokableFunc(concatBuiltin))
rootEC.addCmd("break", invokableFunc(breakBuiltin))
rootEC.addCmd("continue", invokableFunc(continueBuiltin))

View file

@ -3,7 +3,7 @@ package ucl_test
import (
"bytes"
"context"
"github.com/lmika/ucl/ucl"
"ucl.lmika.dev/ucl"
"github.com/stretchr/testify/assert"
"testing"

View file

@ -3,6 +3,7 @@ package ucl
import (
"bytes"
"context"
"errors"
"fmt"
"github.com/stretchr/testify/assert"
"strings"
@ -237,7 +238,6 @@ func TestBuiltins_If(t *testing.T) {
}
}
func TestBuiltins_ForEach(t *testing.T) {
tests := []struct {
desc string
@ -1258,8 +1258,8 @@ func TestBuiltins_EqNe(t *testing.T) {
{desc: "equal bools 1", expr: `eq $true $true`, want: true},
{desc: "equal bools 2", expr: `eq $false $false`, want: true},
{desc: "equal nil 1", expr: `eq () ()`, want: true},
{desc: "equal opaque 1", expr: `eq $hello $hello`, want: true},
{desc: "equal opaque 2", expr: `eq $world $world`, want: true},
{desc: "equal undef 1", expr: `eq $undef $missing`, want: true},
{desc: "equal undef 2", expr: `eq $missing $undef`, want: true},
{desc: "not equal strs 1", expr: `eq "hello" "world"`, want: false},
{desc: "not equal strs 2", expr: `eq "bla" "BLA"`, want: false},
@ -1270,8 +1270,6 @@ func TestBuiltins_EqNe(t *testing.T) {
{desc: "not equal hashes 1", expr: `eq ["this":1 "that":"thing"] ["that":"thing"]`, want: false},
{desc: "not equal hashes 2", expr: `eq ["this":1 "that":"thing"] ["this":1 "that":"thing" "other":"thing"]`, want: false},
{desc: "not equal hashes 3", expr: `eq ["this":1 "that":"thing"] ["this":"1" "that":"other"]`, want: false},
{desc: "not equal opaque 1", expr: `eq $hello $world`, want: false},
{desc: "not equal opaque 2", expr: `eq $hello "hello"`, want: false},
{desc: "not equal types 1", expr: `eq "123" 123`, want: false},
{desc: "not equal types 2", expr: `eq 0 ""`, want: false},
@ -1280,7 +1278,7 @@ func TestBuiltins_EqNe(t *testing.T) {
{desc: "not equal types 5", expr: `eq $true ()`, want: false},
{desc: "not equal types 6", expr: `eq () $false`, want: false},
{desc: "not equal types 7", expr: `eq () "yes"`, want: false},
{desc: "not equal types 8", expr: `eq () $world`, want: false},
{desc: "not equal types 8", expr: `eq () $undef`, want: true},
}
for _, tt := range tests {
@ -1293,7 +1291,6 @@ func TestBuiltins_EqNe(t *testing.T) {
outW := bytes.NewBuffer(nil)
inst := New(WithOut(outW), WithTestBuiltin())
// Removed code I don't have the rights to
inst.SetVar("true", true)
inst.SetVar("false", false)

View file

@ -26,7 +26,7 @@ func (ca *CallArgs) Bind(vars ...interface{}) error {
}
for i, v := range vars {
if err := bindArg(v, ca.args.args[i]); err != nil {
if err := ca.bindArg(v, ca.args.args[i]); err != nil {
return err
}
}

View file

@ -1,6 +1,7 @@
package ucl_test
import (
"bytes"
"context"
"fmt"
"strings"