feature/issue-1: built out the core libraries #3
|
@ -264,6 +264,40 @@ func geBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
return boolObject(isGreater || objectsEqual(args.args[0], args.args[1])), nil
|
return boolObject(isGreater || objectsEqual(args.args[0], args.args[1])), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func andBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
|
if err := args.expectArgn(2); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range args.args {
|
||||||
|
if a == nil || !a.Truthy() {
|
||||||
|
return boolObject(false), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args.args[len(args.args)-1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func orBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
|
if err := args.expectArgn(2); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range args.args {
|
||||||
|
if a != nil && a.Truthy() {
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return boolObject(false), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func notBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
|
if err := args.expectArgn(1); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return boolObject(!args.args[0].Truthy()), 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 {
|
||||||
|
|
|
@ -76,6 +76,10 @@ func New(opts ...InstOption) *Inst {
|
||||||
rootEC.addCmd("div", invokableFunc(divBuiltin))
|
rootEC.addCmd("div", invokableFunc(divBuiltin))
|
||||||
rootEC.addCmd("mod", invokableFunc(modBuiltin))
|
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("cat", invokableFunc(concatBuiltin))
|
||||||
rootEC.addCmd("break", invokableFunc(breakBuiltin))
|
rootEC.addCmd("break", invokableFunc(breakBuiltin))
|
||||||
rootEC.addCmd("continue", invokableFunc(continueBuiltin))
|
rootEC.addCmd("continue", invokableFunc(continueBuiltin))
|
||||||
|
|
|
@ -1149,3 +1149,52 @@ func TestBuiltins_AddSubMupDivMod(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuiltins_AndOrNot(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
expr string
|
||||||
|
want any
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{desc: "and 1", expr: `and $true $true`, want: true},
|
||||||
|
{desc: "and 2", expr: `and $false $true`, want: false},
|
||||||
|
{desc: "and 3", expr: `and $false $false`, want: false},
|
||||||
|
{desc: "or 1", expr: `or $true $true`, want: true},
|
||||||
|
{desc: "or 2", expr: `or $false $true`, want: true},
|
||||||
|
{desc: "or 3", expr: `or $false $false`, want: false},
|
||||||
|
{desc: "not 1", expr: `not $true`, want: false},
|
||||||
|
{desc: "not 2", expr: `not $false`, want: true},
|
||||||
|
{desc: "not 3", expr: `not $false $true`, want: true},
|
||||||
|
|
||||||
|
{desc: "short circuit and 1", expr: `and "hello" "world"`, want: "world"},
|
||||||
|
{desc: "short circuit and 2", expr: `and () "world"`, want: false},
|
||||||
|
{desc: "short circuit or 1", expr: `or "hello" "world"`, want: "hello"},
|
||||||
|
{desc: "short circuit or 2", expr: `or () "world"`, want: "world"},
|
||||||
|
|
||||||
|
{desc: "bad and 1", expr: `and "one"`, wantErr: true},
|
||||||
|
{desc: "bad and 2", expr: `and`, wantErr: true},
|
||||||
|
{desc: "bad or 1", expr: `or "one"`, wantErr: true},
|
||||||
|
{desc: "bad or 2", expr: `or`, wantErr: true},
|
||||||
|
{desc: "bad not 2", expr: `not`, 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue