Compare commits
No commits in common. "484631782e47ab29c6f89db721acef4c4e0f0b12" and "d501a3af2517e04669731eea646155b3e4ffb531" have entirely different histories.
484631782e
...
d501a3af25
102
ucl/builtins.go
102
ucl/builtins.go
|
@ -102,54 +102,6 @@ func neBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
return boolObject(!objectsEqual(l, r)), nil
|
return boolObject(!objectsEqual(l, r)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ltBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
|
||||||
if err := args.expectArgn(2); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
isLess, err := objectsLessThan(args.args[0], args.args[1])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return boolObject(isLess), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func leBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
|
||||||
if err := args.expectArgn(2); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
isLess, err := objectsLessThan(args.args[0], args.args[1])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return boolObject(isLess || objectsEqual(args.args[0], args.args[1])), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func gtBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
|
||||||
if err := args.expectArgn(2); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
isGreater, err := objectsLessThan(args.args[1], args.args[0])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return boolObject(isGreater), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func geBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
|
||||||
if err := args.expectArgn(2); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
isGreater, err := objectsLessThan(args.args[1], args.args[0])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return boolObject(isGreater || objectsEqual(args.args[0], args.args[1])), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var errObjectsNotEqual = errors.New("objects not equal")
|
var errObjectsNotEqual = errors.New("objects not equal")
|
||||||
|
|
||||||
func objectsEqual(l, r object) bool {
|
func objectsEqual(l, r object) bool {
|
||||||
|
@ -217,60 +169,6 @@ func objectsEqual(l, r object) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func objectsLessThan(l, r object) (bool, error) {
|
|
||||||
switch lv := l.(type) {
|
|
||||||
case strObject:
|
|
||||||
if rv, ok := r.(strObject); ok {
|
|
||||||
return lv < rv, nil
|
|
||||||
}
|
|
||||||
case intObject:
|
|
||||||
if rv, ok := r.(intObject); ok {
|
|
||||||
return lv < rv, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, errors.New("objects are not comparable")
|
|
||||||
}
|
|
||||||
|
|
||||||
func strBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
|
||||||
if err := args.expectArgn(1); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.args[0] == nil {
|
|
||||||
return strObject(""), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return strObject(args.args[0].String()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func intBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
|
||||||
if err := args.expectArgn(1); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.args[0] == nil {
|
|
||||||
return intObject(0), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v := args.args[0].(type) {
|
|
||||||
case intObject:
|
|
||||||
return v, nil
|
|
||||||
case strObject:
|
|
||||||
i, err := strconv.Atoi(string(v))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("cannot convert to int")
|
|
||||||
}
|
|
||||||
return intObject(i), nil
|
|
||||||
case boolObject:
|
|
||||||
if v {
|
|
||||||
return intObject(1), nil
|
|
||||||
}
|
|
||||||
return intObject(0), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("cannot convert to int")
|
|
||||||
}
|
|
||||||
|
|
||||||
func concatBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
func concatBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
|
|
||||||
|
|
|
@ -62,13 +62,6 @@ func New(opts ...InstOption) *Inst {
|
||||||
|
|
||||||
rootEC.addCmd("eq", invokableFunc(eqBuiltin))
|
rootEC.addCmd("eq", invokableFunc(eqBuiltin))
|
||||||
rootEC.addCmd("ne", invokableFunc(neBuiltin))
|
rootEC.addCmd("ne", invokableFunc(neBuiltin))
|
||||||
rootEC.addCmd("gt", invokableFunc(gtBuiltin))
|
|
||||||
rootEC.addCmd("ge", invokableFunc(geBuiltin))
|
|
||||||
rootEC.addCmd("lt", invokableFunc(ltBuiltin))
|
|
||||||
rootEC.addCmd("le", invokableFunc(leBuiltin))
|
|
||||||
|
|
||||||
rootEC.addCmd("str", invokableFunc(strBuiltin))
|
|
||||||
rootEC.addCmd("int", invokableFunc(intBuiltin))
|
|
||||||
|
|
||||||
rootEC.addCmd("add", invokableFunc(addBuiltin))
|
rootEC.addCmd("add", invokableFunc(addBuiltin))
|
||||||
|
|
||||||
|
|
22
ucl/objs.go
22
ucl/objs.go
|
@ -6,7 +6,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/lmika/gopkgs/fp/slices"
|
"github.com/lmika/gopkgs/fp/slices"
|
||||||
)
|
)
|
||||||
|
@ -52,22 +51,7 @@ func (s listObject) Index(i int) object {
|
||||||
type hashObject map[string]object
|
type hashObject map[string]object
|
||||||
|
|
||||||
func (s hashObject) String() string {
|
func (s hashObject) String() string {
|
||||||
if len(s) == 0 {
|
return fmt.Sprintf("%v", map[string]object(s))
|
||||||
return "[:]"
|
|
||||||
}
|
|
||||||
|
|
||||||
sb := strings.Builder{}
|
|
||||||
sb.WriteString("[")
|
|
||||||
for k, v := range s {
|
|
||||||
if sb.Len() != 1 {
|
|
||||||
sb.WriteString(" ")
|
|
||||||
}
|
|
||||||
sb.WriteString(k)
|
|
||||||
sb.WriteString(":")
|
|
||||||
sb.WriteString(v.String())
|
|
||||||
}
|
|
||||||
sb.WriteString("]")
|
|
||||||
return sb.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s hashObject) Truthy() bool {
|
func (s hashObject) Truthy() bool {
|
||||||
|
@ -115,9 +99,9 @@ type boolObject bool
|
||||||
|
|
||||||
func (b boolObject) String() string {
|
func (b boolObject) String() string {
|
||||||
if b {
|
if b {
|
||||||
return "true"
|
return "(true)"
|
||||||
}
|
}
|
||||||
return "false"
|
return "(false))"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b boolObject) Truthy() bool {
|
func (b boolObject) Truthy() bool {
|
||||||
|
|
|
@ -892,66 +892,6 @@ func TestBuiltins_Reduce(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuiltins_LtLeGtLe(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
desc string
|
|
||||||
expr string
|
|
||||||
want bool
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{desc: "str 1 - lt", expr: `lt "hello" "world"`, want: true},
|
|
||||||
{desc: "str 1 - le", expr: `le "hello" "world"`, want: true},
|
|
||||||
{desc: "str 1 - gt", expr: `gt "hello" "world"`, want: false},
|
|
||||||
{desc: "str 1 - ge", expr: `ge "hello" "world"`, want: false},
|
|
||||||
{desc: "str 2 - lt", expr: `lt "zzzzz" "world"`, want: false},
|
|
||||||
{desc: "str 2 - le", expr: `le "zzzzz" "world"`, want: false},
|
|
||||||
{desc: "str 2 - gt", expr: `gt "zzzzz" "world"`, want: true},
|
|
||||||
{desc: "str 2 - ge", expr: `ge "zzzzz" "world"`, want: true},
|
|
||||||
{desc: "str 3 - lt", expr: `lt "hello" "hello"`, want: false},
|
|
||||||
{desc: "str 3 - le", expr: `le "hello" "hello"`, want: true},
|
|
||||||
{desc: "str 3 - gt", expr: `gt "hello" "hello"`, want: false},
|
|
||||||
{desc: "str 3 - ge", expr: `ge "hello" "hello"`, want: true},
|
|
||||||
|
|
||||||
{desc: "int 1 - lt", expr: `lt 5 8`, want: true},
|
|
||||||
{desc: "int 1 - le", expr: `le 5 8`, want: true},
|
|
||||||
{desc: "int 1 - gt", expr: `gt 5 8`, want: false},
|
|
||||||
{desc: "int 1 - ge", expr: `ge 5 8`, want: false},
|
|
||||||
{desc: "int 2 - lt", expr: `lt 5 -8`, want: false},
|
|
||||||
{desc: "int 2 - le", expr: `le 5 -8`, want: false},
|
|
||||||
{desc: "int 2 - gt", expr: `gt 5 -8`, want: true},
|
|
||||||
{desc: "int 2 - ge", expr: `ge 5 -8`, want: true},
|
|
||||||
{desc: "int 3 - lt", expr: `lt 5 5`, want: false},
|
|
||||||
{desc: "int 3 - le", expr: `le 5 5`, want: true},
|
|
||||||
{desc: "int 3 - gt", expr: `gt 5 5`, want: false},
|
|
||||||
{desc: "int 3 - ge", expr: `ge 5 5`, want: true},
|
|
||||||
|
|
||||||
{desc: "not comparable 1", expr: `lt () ()`, wantErr: true},
|
|
||||||
{desc: "not comparable 2", expr: `lt $true $false`, wantErr: true},
|
|
||||||
{desc: "not comparable 3", expr: `lt [1 2 3] [2 3 4]`, wantErr: true},
|
|
||||||
{desc: "not comparable 4", expr: `lt ["1":2] ["2":3]`, wantErr: true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.desc, func(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
outW := bytes.NewBuffer(nil)
|
|
||||||
|
|
||||||
inst := New(WithOut(outW), WithTestBuiltin())
|
|
||||||
inst.SetVar("true", true)
|
|
||||||
inst.SetVar("false", false)
|
|
||||||
|
|
||||||
eqRes, err := inst.Eval(ctx, tt.expr)
|
|
||||||
|
|
||||||
if tt.wantErr {
|
|
||||||
assert.Error(t, err)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.want, eqRes)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBuiltins_EqNe(t *testing.T) {
|
func TestBuiltins_EqNe(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
@ -969,8 +909,8 @@ func TestBuiltins_EqNe(t *testing.T) {
|
||||||
{desc: "equal lists 3", expr: `eq [] []`, want: true},
|
{desc: "equal lists 3", expr: `eq [] []`, want: true},
|
||||||
{desc: "equal hashes 1", expr: `eq ["this":1 "that":"thing"] ["that":"thing" "this":1]`, want: true},
|
{desc: "equal hashes 1", expr: `eq ["this":1 "that":"thing"] ["that":"thing" "this":1]`, want: true},
|
||||||
{desc: "equal hashes 2", expr: `eq ["foo":"bar"] ["foo":"bar"]`, want: true},
|
{desc: "equal hashes 2", expr: `eq ["foo":"bar"] ["foo":"bar"]`, want: true},
|
||||||
{desc: "equal bools 1", expr: `eq $true $true`, want: true},
|
{desc: "equal bools 1", expr: `eq true true`, want: true},
|
||||||
{desc: "equal bools 2", expr: `eq $false $false`, want: true},
|
{desc: "equal bools 2", expr: `eq false false`, want: true},
|
||||||
{desc: "equal nil 1", expr: `eq () ()`, want: true},
|
{desc: "equal nil 1", expr: `eq () ()`, want: true},
|
||||||
{desc: "equal opaque 1", expr: `eq $hello $hello`, want: true},
|
{desc: "equal opaque 1", expr: `eq $hello $hello`, want: true},
|
||||||
{desc: "equal opaque 2", expr: `eq $world $world`, want: true},
|
{desc: "equal opaque 2", expr: `eq $world $world`, want: true},
|
||||||
|
@ -991,8 +931,8 @@ func TestBuiltins_EqNe(t *testing.T) {
|
||||||
{desc: "not equal types 2", expr: `eq 0 ""`, want: false},
|
{desc: "not equal types 2", expr: `eq 0 ""`, want: false},
|
||||||
{desc: "not equal types 3", expr: `eq [] [:]`, want: false},
|
{desc: "not equal types 3", expr: `eq [] [:]`, want: false},
|
||||||
{desc: "not equal types 4", expr: `eq ["23"] "23"`, want: false},
|
{desc: "not equal types 4", expr: `eq ["23"] "23"`, want: false},
|
||||||
{desc: "not equal types 5", expr: `eq $true ()`, want: false},
|
{desc: "not equal types 5", expr: `eq true ()`, want: false},
|
||||||
{desc: "not equal types 6", expr: `eq () $false`, 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 7", expr: `eq () "yes"`, want: false},
|
||||||
{desc: "not equal types 8", expr: `eq () $world`, want: false},
|
{desc: "not equal types 8", expr: `eq () $world`, want: false},
|
||||||
}
|
}
|
||||||
|
@ -1009,8 +949,6 @@ func TestBuiltins_EqNe(t *testing.T) {
|
||||||
inst := New(WithOut(outW), WithTestBuiltin())
|
inst := New(WithOut(outW), WithTestBuiltin())
|
||||||
inst.SetVar("hello", Opaque(testProxyObject{v: "hello"}))
|
inst.SetVar("hello", Opaque(testProxyObject{v: "hello"}))
|
||||||
inst.SetVar("world", Opaque(testProxyObject{v: "world"}))
|
inst.SetVar("world", Opaque(testProxyObject{v: "world"}))
|
||||||
inst.SetVar("true", true)
|
|
||||||
inst.SetVar("false", false)
|
|
||||||
|
|
||||||
eqRes, err := inst.Eval(ctx, tt.expr)
|
eqRes, err := inst.Eval(ctx, tt.expr)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -1022,74 +960,3 @@ func TestBuiltins_EqNe(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuiltins_Str(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
desc string
|
|
||||||
expr string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{desc: "str", expr: `str "hello"`, want: "hello"},
|
|
||||||
{desc: "int", expr: `str 123`, want: "123"},
|
|
||||||
{desc: "bool 1", expr: `str (eq 1 1)`, want: "true"},
|
|
||||||
{desc: "bool 2", expr: `str (eq 1 0)`, want: "false"},
|
|
||||||
{desc: "list 1", expr: `str [1 2 3]`, want: "[1 2 3]"},
|
|
||||||
{desc: "list 2", expr: `str []`, want: "[]"},
|
|
||||||
{desc: "dict 1", expr: `str ["hello":"world"]`, want: `[hello:world]`},
|
|
||||||
{desc: "dict 2", expr: `str [:]`, want: "[:]"},
|
|
||||||
{desc: "nil", expr: `str ()`, want: ""},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.desc, func(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
outW := bytes.NewBuffer(nil)
|
|
||||||
|
|
||||||
inst := New(WithOut(outW), WithTestBuiltin())
|
|
||||||
|
|
||||||
eqRes, err := inst.Eval(ctx, tt.expr)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.want, eqRes)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBuiltins_Int(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
desc string
|
|
||||||
expr string
|
|
||||||
want int
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{desc: "str 1", expr: `int "123"`, want: 123},
|
|
||||||
{desc: "str 2", expr: `int "31452"`, want: 31452},
|
|
||||||
{desc: "str 3", expr: `int "-21"`, want: -21},
|
|
||||||
{desc: "int 1", expr: `int 123`, want: 123},
|
|
||||||
{desc: "int 2", expr: `int -21`, want: -21},
|
|
||||||
{desc: "bool 1", expr: `int (eq 1 1)`, want: 1},
|
|
||||||
{desc: "bool 2", expr: `int (eq 1 0)`, want: 0},
|
|
||||||
{desc: "nil", expr: `int ()`, want: 0},
|
|
||||||
|
|
||||||
{desc: "list 1", expr: `int [1 2 3]`, wantErr: true},
|
|
||||||
{desc: "list 2", expr: `int []`, wantErr: true},
|
|
||||||
{desc: "dict 1", expr: `int ["hello":"world"]`, wantErr: true},
|
|
||||||
{desc: "dict 2", expr: `int [:]`, wantErr: true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.desc, func(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
outW := bytes.NewBuffer(nil)
|
|
||||||
|
|
||||||
inst := New(WithOut(outW), WithTestBuiltin())
|
|
||||||
|
|
||||||
eqRes, err := inst.Eval(ctx, tt.expr)
|
|
||||||
if tt.wantErr {
|
|
||||||
assert.Error(t, err)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.want, eqRes)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue