github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/lib/stringlib/string_arith.go (about) 1 package stringlib 2 3 import rt "github.com/arnodel/golua/runtime" 4 5 var ( 6 string__add = stringBinOp(rt.Add, "__add") 7 string__sub = stringBinOp(rt.Sub, "__sub") 8 string__mul = stringBinOp(rt.Mul, "__mul") 9 string__div = stringBinOp(rt.Div, "__div") 10 string__idiv = stringBinOpErr(rt.Idiv, "__idiv") 11 string__mod = stringBinOpErr(rt.Mod, "__mod") 12 string__pow = stringBinOp(rt.Pow, "__pow") 13 string__unm = stringUnOp(rt.Unm, "__unm") 14 ) 15 16 func stringBinOp(f func(x, y rt.Value) (rt.Value, bool), op string) func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { 17 return func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { 18 if err := c.CheckNArgs(2); err != nil { 19 return nil, err 20 } 21 x, y := c.Arg(0), c.Arg(1) 22 nx, kx := rt.ToNumberValue(x) 23 ny, ky := rt.ToNumberValue(y) 24 if kx != rt.NaN && ky != rt.NaN { 25 z, _ := f(nx, ny) 26 return c.PushingNext1(t.Runtime, z), nil 27 } 28 if y.Type() != rt.StringType { 29 next := c.Next() 30 err, ok := rt.Metacall(t, y, op, []rt.Value{x, y}, next) 31 if ok { 32 if err != nil { 33 return nil, err 34 } 35 return next, nil 36 } 37 } 38 return nil, rt.BinaryArithmeticError(op[2:], nx, ny) 39 } 40 } 41 42 func stringBinOpErr(f func(x, y rt.Value) (rt.Value, bool, error), op string) func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { 43 return func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { 44 if err := c.CheckNArgs(2); err != nil { 45 return nil, err 46 } 47 x, y := c.Arg(0), c.Arg(1) 48 nx, kx := rt.ToNumberValue(x) 49 ny, ky := rt.ToNumberValue(y) 50 if kx != rt.NaN && ky != rt.NaN { 51 z, _, err := f(nx, ny) 52 if err != nil { 53 return nil, err 54 } 55 return c.PushingNext1(t.Runtime, z), nil 56 } 57 if y.Type() != rt.StringType { 58 next := c.Next() 59 err, ok := rt.Metacall(t, y, op, []rt.Value{x, y}, next) 60 if ok { 61 if err != nil { 62 return nil, err 63 } 64 return next, nil 65 } 66 } 67 return nil, rt.BinaryArithmeticError(op[2:], nx, ny) 68 } 69 } 70 71 func stringUnOp(f func(x rt.Value) (rt.Value, bool), op string) func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { 72 return func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { 73 if err := c.Check1Arg(); err != nil { 74 return nil, err 75 } 76 x := c.Arg(0) 77 nx, _ := rt.ToNumberValue(x) 78 z, ok := f(nx) 79 if ok { 80 return c.PushingNext1(t.Runtime, z), nil 81 } 82 return nil, rt.UnaryArithmeticError(op[2:], nx) 83 } 84 }