Skip to content

Commit

Permalink
internal/core/compile: add integer division builtins
Browse files Browse the repository at this point in the history
These are to replace the namesake operators,
which will be removed at some point.

Next step is to create a rewriter that rewrites old
uses to the new one.

Change-Id: Ib674559e40f714e24e40e6c9ed71f7eb43231389
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7784
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
  • Loading branch information
mpvl committed Nov 28, 2020
1 parent 0811662 commit 36f2051
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 21 deletions.
171 changes: 171 additions & 0 deletions cue/testdata/builtins/intdiv.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
-- in.cue --
quo1: quo(5, 2) // 2
quo2: quo(5, -2) // -2
quo3: quo(-5, 2) // -2
quo4: quo(-5, -2) // 2

quoDivByZero: quo(2, 0)

quoTypeError1: quo(2.0, 1)
quoTypeError2: quo(2, 1.0)


rem1: rem(5, 2) // 1
rem2: rem(5, -2) // 1
rem3: rem(-5, 2) // -1
rem4: rem(-5, -2) // -1

remDivByZero: rem(2, 0)

remTypeError1: rem(2.0, 1)
remTypeError2: rem(2, 1.0)


div1: div(5, 2) // 2
div2: div(5, -2) // -2
div3: div(-5, 2) // -3
div4: div(-5, -2) // 3

divDivByZero: div(2, 0)

divTypeError1: div(2.0, 1)
divTypeError2: div(2, 1.0)


mod1: mod(5, 2) // 1
mod2: mod(5, -2) // 1
mod3: mod(-5, 2) // 1
mod4: mod(-5, -2) // 1

modDivByZero: mod(2, 0)

modTypeError1: mod(2.0, 1)
modTypeError2: mod(2, 1.0)

-- out/eval --
Errors:
quoDivByZero: division by zero:
./in.cue:6:15
quoTypeError1: cannot use 2.0 (type float) as int in argument 1 to quo:
./in.cue:8:20
quoTypeError2: cannot use 1.0 (type float) as int in argument 2 to quo:
./in.cue:9:23
remDivByZero: division by zero:
./in.cue:17:15
remTypeError1: cannot use 2.0 (type float) as int in argument 1 to rem:
./in.cue:19:20
remTypeError2: cannot use 1.0 (type float) as int in argument 2 to rem:
./in.cue:20:23
divDivByZero: division by zero:
./in.cue:28:15
divTypeError1: cannot use 2.0 (type float) as int in argument 1 to div:
./in.cue:30:20
divTypeError2: cannot use 1.0 (type float) as int in argument 2 to div:
./in.cue:31:23
modDivByZero: division by zero:
./in.cue:39:15
modTypeError1: cannot use 2.0 (type float) as int in argument 1 to mod:
./in.cue:41:20
modTypeError2: cannot use 1.0 (type float) as int in argument 2 to mod:
./in.cue:42:23

Result:
(_|_){
// [eval]
quo1: (int){ 2 }
quo2: (int){ -2 }
quo3: (int){ -2 }
quo4: (int){ 2 }
quoDivByZero: (_|_){
// [eval] quoDivByZero: division by zero:
// ./in.cue:6:15
}
quoTypeError1: (_|_){
// [eval] quoTypeError1: cannot use 2.0 (type float) as int in argument 1 to quo:
// ./in.cue:8:20
}
quoTypeError2: (_|_){
// [eval] quoTypeError2: cannot use 1.0 (type float) as int in argument 2 to quo:
// ./in.cue:9:23
}
rem1: (int){ 1 }
rem2: (int){ 1 }
rem3: (int){ -1 }
rem4: (int){ -1 }
remDivByZero: (_|_){
// [eval] remDivByZero: division by zero:
// ./in.cue:17:15
}
remTypeError1: (_|_){
// [eval] remTypeError1: cannot use 2.0 (type float) as int in argument 1 to rem:
// ./in.cue:19:20
}
remTypeError2: (_|_){
// [eval] remTypeError2: cannot use 1.0 (type float) as int in argument 2 to rem:
// ./in.cue:20:23
}
div1: (int){ 2 }
div2: (int){ -2 }
div3: (int){ -3 }
div4: (int){ 3 }
divDivByZero: (_|_){
// [eval] divDivByZero: division by zero:
// ./in.cue:28:15
}
divTypeError1: (_|_){
// [eval] divTypeError1: cannot use 2.0 (type float) as int in argument 1 to div:
// ./in.cue:30:20
}
divTypeError2: (_|_){
// [eval] divTypeError2: cannot use 1.0 (type float) as int in argument 2 to div:
// ./in.cue:31:23
}
mod1: (int){ 1 }
mod2: (int){ 1 }
mod3: (int){ 1 }
mod4: (int){ 1 }
modDivByZero: (_|_){
// [eval] modDivByZero: division by zero:
// ./in.cue:39:15
}
modTypeError1: (_|_){
// [eval] modTypeError1: cannot use 2.0 (type float) as int in argument 1 to mod:
// ./in.cue:41:20
}
modTypeError2: (_|_){
// [eval] modTypeError2: cannot use 1.0 (type float) as int in argument 2 to mod:
// ./in.cue:42:23
}
}
-- out/compile --
--- in.cue
{
quo1: quo(5, 2)
quo2: quo(5, -2)
quo3: quo(-5, 2)
quo4: quo(-5, -2)
quoDivByZero: quo(2, 0)
quoTypeError1: quo(2.0, 1)
quoTypeError2: quo(2, 1.0)
rem1: rem(5, 2)
rem2: rem(5, -2)
rem3: rem(-5, 2)
rem4: rem(-5, -2)
remDivByZero: rem(2, 0)
remTypeError1: rem(2.0, 1)
remTypeError2: rem(2, 1.0)
div1: div(5, 2)
div2: div(5, -2)
div3: div(-5, 2)
div4: div(-5, -2)
divDivByZero: div(2, 0)
divTypeError1: div(2.0, 1)
divTypeError2: div(2, 1.0)
mod1: mod(5, 2)
mod2: mod(5, -2)
mod3: mod(-5, 2)
mod4: mod(-5, -2)
modDivByZero: mod(2, 0)
modTypeError1: mod(2.0, 1)
modTypeError2: mod(2, 1.0)
}
30 changes: 15 additions & 15 deletions internal/core/adt/binop.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func BinOp(c *OpContext, op Op, left, right Value) Value {

case leftKind&NumKind != 0 && rightKind&NumKind != 0:
// n := c.newNum()
return cmpTonode(c, op, c.num(left, op).X.Cmp(&c.num(right, op).X))
return cmpTonode(c, op, c.Num(left, op).X.Cmp(&c.Num(right, op).X))

case leftKind == ListKind && rightKind == ListKind:
x := c.Elems(left)
Expand Down Expand Up @@ -114,7 +114,7 @@ func BinOp(c *OpContext, op Op, left, right Value) Value {

case leftKind&NumKind != 0 && rightKind&NumKind != 0:
// n := c.newNum()
return cmpTonode(c, op, c.num(left, op).X.Cmp(&c.num(right, op).X))
return cmpTonode(c, op, c.Num(left, op).X.Cmp(&c.Num(right, op).X))

case leftKind == ListKind && rightKind == ListKind:
x := c.Elems(left)
Expand Down Expand Up @@ -143,7 +143,7 @@ func BinOp(c *OpContext, op Op, left, right Value) Value {

case leftKind&NumKind != 0 && rightKind&NumKind != 0:
// n := c.newNum(left, right)
return cmpTonode(c, op, c.num(left, op).X.Cmp(&c.num(right, op).X))
return cmpTonode(c, op, c.Num(left, op).X.Cmp(&c.Num(right, op).X))
}

case BoolAndOp:
Expand Down Expand Up @@ -284,38 +284,38 @@ func BinOp(c *OpContext, op Op, left, right Value) Value {

case IntDivideOp:
if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
y := c.num(right, op)
y := c.Num(right, op)
if y.X.IsZero() {
return c.NewErrf("division by zero")
}
return intOp(c, (*big.Int).Div, c.num(left, op), y)
return intOp(c, (*big.Int).Div, c.Num(left, op), y)
}

case IntModuloOp:
if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
y := c.num(right, op)
y := c.Num(right, op)
if y.X.IsZero() {
return c.NewErrf("division by zero")
}
return intOp(c, (*big.Int).Mod, c.num(left, op), y)
return intOp(c, (*big.Int).Mod, c.Num(left, op), y)
}

case IntQuotientOp:
if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
y := c.num(right, op)
y := c.Num(right, op)
if y.X.IsZero() {
return c.NewErrf("division by zero")
}
return intOp(c, (*big.Int).Quo, c.num(left, op), y)
return intOp(c, (*big.Int).Quo, c.Num(left, op), y)
}

case IntRemainderOp:
if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
y := c.num(right, op)
y := c.Num(right, op)
if y.X.IsZero() {
return c.NewErrf("division by zero")
}
return intOp(c, (*big.Int).Rem, c.num(left, op), y)
return intOp(c, (*big.Int).Rem, c.Num(left, op), y)
}
}

Expand Down Expand Up @@ -346,8 +346,8 @@ type numFunc func(z, x, y *apd.Decimal) (apd.Condition, error)

func numOp(c *OpContext, fn numFunc, a, b Value, op Op) Value {
var d apd.Decimal
x := c.num(a, op)
y := c.num(b, op)
x := c.Num(a, op)
y := c.Num(b, op)
cond, err := fn(&d, &x.X, &y.X)
if err != nil {
return c.NewErrf("failed arithmetic: %v", err)
Expand All @@ -359,7 +359,7 @@ func numOp(c *OpContext, fn numFunc, a, b Value, op Op) Value {
if k == 0 {
k = FloatKind
}
return c.newNum(&d, k)
return c.NewNum(&d, k)
}

type intFunc func(z, x, y *big.Int) *big.Int
Expand All @@ -381,5 +381,5 @@ func intOp(c *OpContext, fn intFunc, a, b *Num) Value {
d.Coeff.Neg(&d.Coeff)
d.Negative = true
}
return c.newNum(&d, IntKind)
return c.NewNum(&d, IntKind)
}
6 changes: 4 additions & 2 deletions internal/core/adt/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ func (c *OpContext) scalar(v Value) Value {

var zero = &Num{K: NumKind}

func (c *OpContext) num(v Value, as interface{}) *Num {
func (c *OpContext) Num(v Value, as interface{}) *Num {
v = Unwrap(v)
if isError(v) {
return zero
Expand Down Expand Up @@ -930,7 +930,9 @@ func (c *OpContext) regexp(v Value) *regexp.Regexp {
}
}

func (c *OpContext) newNum(d *apd.Decimal, k Kind, sources ...Node) Value {
// NewNum creates a new number of the given kind. It reports an error value
// instead if any error occurred.
func (c *OpContext) NewNum(d *apd.Decimal, k Kind, sources ...Node) Value {
if c.HasErr() {
return c.Err()
}
Expand Down
8 changes: 4 additions & 4 deletions internal/core/adt/simplify.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,23 +133,23 @@ func SimplifyBounds(ctx *OpContext, k Kind, x, y *BoundValue) Value {
case diff == 1:
if k&FloatKind == 0 {
if x.Op == GreaterEqualOp && y.Op == LessThanOp {
return ctx.newNum(&lo, k&NumKind, x, y)
return ctx.NewNum(&lo, k&NumKind, x, y)
}
if x.Op == GreaterThanOp && y.Op == LessEqualOp {
return ctx.newNum(&hi, k&NumKind, x, y)
return ctx.NewNum(&hi, k&NumKind, x, y)
}
}

case diff == 2:
if k&FloatKind == 0 && x.Op == GreaterThanOp && y.Op == LessThanOp {
_, _ = apd.BaseContext.Add(&d, d.SetInt64(1), &lo)
return ctx.newNum(&d, k&NumKind, x, y)
return ctx.NewNum(&d, k&NumKind, x, y)

}

case diff == 0:
if x.Op == GreaterEqualOp && y.Op == LessEqualOp {
return ctx.newNum(&lo, k&NumKind, x, y)
return ctx.NewNum(&lo, k&NumKind, x, y)
}
fallthrough

Expand Down

0 comments on commit 36f2051

Please sign in to comment.