feature/issue-1: built out the core libraries #3

Merged
lmika merged 8 commits from feature/issue-1 into main 2024-09-06 23:38:05 +00:00
3 changed files with 174 additions and 0 deletions
Showing only changes of commit 1169f82f7b - Show all commits

View file

@ -53,6 +53,120 @@ func addBuiltin(ctx context.Context, args invocationArgs) (object, error) {
return intObject(n), nil
}
func subBuiltin(ctx context.Context, args invocationArgs) (object, error) {
if len(args.args) == 0 {
return intObject(0), nil
}
n := 0
for i, a := range args.args {
var p int
switch t := a.(type) {
case intObject:
p = int(t)
case strObject:
v, err := strconv.Atoi(string(t))
if err != nil {
return nil, fmt.Errorf("arg %v of 'sub' not convertable to an int", i)
}
p = v
default:
return nil, fmt.Errorf("arg %v of 'sub' not convertable to an int", i)
}
if i == 0 {
n = p
} else {
n -= p
}
}
return intObject(n), nil
}
func mupBuiltin(ctx context.Context, args invocationArgs) (object, error) {
if len(args.args) == 0 {
return intObject(1), nil
}
n := 1
for i, a := range args.args {
switch t := a.(type) {
case intObject:
n *= int(t)
case strObject:
v, err := strconv.Atoi(string(t))
if err != nil {
return nil, fmt.Errorf("arg %v of 'mup' not convertable to an int", i)
}
n *= v
default:
return nil, fmt.Errorf("arg %v of 'mup' not convertable to an int", i)
}
}
return intObject(n), nil
}
func divBuiltin(ctx context.Context, args invocationArgs) (object, error) {
if len(args.args) == 0 {
return intObject(1), nil
}
n := 1
for i, a := range args.args {
var p int
switch t := a.(type) {
case intObject:
p = int(t)
case strObject:
v, err := strconv.Atoi(string(t))
if err != nil {
return nil, fmt.Errorf("arg %v of 'div' not convertable to an int", i)
}
p = v
default:
return nil, fmt.Errorf("arg %v of 'div' not convertable to an int", i)
}
if i == 0 {
n = p
} else {
n /= p
}
}
return intObject(n), nil
}
func modBuiltin(ctx context.Context, args invocationArgs) (object, error) {
if len(args.args) == 0 {
return intObject(0), nil
}
n := 0
for i, a := range args.args {
var p int
switch t := a.(type) {
case intObject:
p = int(t)
case strObject:
v, err := strconv.Atoi(string(t))
if err != nil {
return nil, fmt.Errorf("arg %v of 'mod' not convertable to an int", i)
}
p = v
default:
return nil, fmt.Errorf("arg %v of 'mod' not convertable to an int", i)
}
if i == 0 {
n = p
} else {
n %= p
}
}
return intObject(n), nil
}
func setBuiltin(ctx context.Context, args invocationArgs) (object, error) {
if err := args.expectArgn(2); err != nil {
return nil, err

View file

@ -71,6 +71,10 @@ func New(opts ...InstOption) *Inst {
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("cat", invokableFunc(concatBuiltin))
rootEC.addCmd("break", invokableFunc(breakBuiltin))

View file

@ -1093,3 +1093,59 @@ func TestBuiltins_Int(t *testing.T) {
})
}
}
func TestBuiltins_AddSubMupDivMod(t *testing.T) {
tests := []struct {
desc string
expr string
want int
wantErr bool
}{
{desc: "add 1", expr: `add 1 2`, want: 3},
{desc: "add 2", expr: `add "3" 5`, want: 8},
{desc: "add 3", expr: `add 1 "2" 8`, want: 11},
{desc: "add 4", expr: `add 1`, want: 1},
{desc: "add 5", expr: `add`, want: 0},
{desc: "sub 1", expr: `sub 9 3`, want: 6},
{desc: "sub 2", expr: `sub 2 "5"`, want: -3},
{desc: "sub 3", expr: `sub 8 1 8`, want: -1},
{desc: "sub 4", expr: `sub 4`, want: 4},
{desc: "sub 5", expr: `sub`, want: 0},
{desc: "mup 1", expr: `mup 2 4`, want: 8},
{desc: "mup 2", expr: `mup 3 "4" 5`, want: 60},
{desc: "mup 3", expr: `mup 7`, want: 7},
{desc: "mup 4", expr: `mup`, want: 1},
{desc: "div 1", expr: `div 8 4`, want: 2},
{desc: "div 2", expr: `div "7" 4`, want: 1},
{desc: "div 3", expr: `div 7`, want: 7},
{desc: "div 4", expr: `div`, want: 1},
{desc: "mod 1", expr: `mod 2 3`, want: 2},
{desc: "mod 2", expr: `mod "7" 4`, want: 3},
{desc: "mod 3", expr: `mod 8 4`, want: 0},
{desc: "mod 4", expr: `mod 3`, want: 3},
{desc: "mod 5", expr: `mod`, want: 0},
{desc: "add err", expr: `add [] [:]`, wantErr: true},
{desc: "sub err", expr: `sub [] [:]`, wantErr: true},
{desc: "mup err", expr: `mup [] [:]`, wantErr: true},
{desc: "div err", expr: `div [] [:]`, wantErr: true},
{desc: "mod err", expr: `mod [] [:]`, 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)
}
})
}
}