Skip to content

Commit 8b13752

Browse files
committed
internal/core/adt: move decimal logic into one place
Or at least a start. This prepares for the new numbering system, where 1 and 1.0 can be used interchangeably. Change-Id: Ic311be58d59f75dc533b1bcda2ceb5bda7915056 Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7881 Reviewed-by: CUE cueckoo <[email protected]> Reviewed-by: Marcel van Lohuizen <[email protected]>
1 parent 136e51b commit 8b13752

File tree

6 files changed

+156
-140
lines changed

6 files changed

+156
-140
lines changed

cue/context.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,18 @@ import (
1818
"cuelang.org/go/internal/core/adt"
1919
"cuelang.org/go/internal/core/debug"
2020
"cuelang.org/go/internal/core/eval"
21-
"github.com/cockroachdb/apd/v2"
2221
)
2322

2423
// context manages evaluation state.
2524
type context struct {
2625
opCtx *adt.OpContext
27-
*apd.Context
2826
*index
2927
}
3028

31-
var baseContext apd.Context
32-
33-
func init() {
34-
baseContext = apd.BaseContext
35-
baseContext.Precision = 24
36-
}
37-
3829
// newContext returns a new evaluation context.
3930
func (idx *index) newContext() *context {
4031
c := &context{
41-
Context: &baseContext,
42-
index: idx,
32+
index: idx,
4333
}
4434
if idx != nil {
4535
c.opCtx = eval.NewContext(idx.Runtime, nil)

internal/core/adt/binop.go

Lines changed: 8 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,9 @@ package adt
1616

1717
import (
1818
"bytes"
19-
"math/big"
2019
"strings"
21-
22-
"github.com/cockroachdb/apd/v2"
2320
)
2421

25-
var apdCtx apd.Context
26-
27-
func init() {
28-
apdCtx = apd.BaseContext
29-
apdCtx.Precision = 24
30-
}
31-
3222
// BinOp handles all operations except AndOp and OrOp. This includes processing
3323
// unary comparators such as '<4' and '=~"foo"'.
3424
//
@@ -169,7 +159,7 @@ func BinOp(c *OpContext, op Op, left, right Value) Value {
169159
case AddOp:
170160
switch {
171161
case leftKind&NumKind != 0 && rightKind&NumKind != 0:
172-
return numOp(c, apdCtx.Add, left, right, AddOp)
162+
return c.Add(c.Num(left, op), c.Num(right, op))
173163

174164
case leftKind == StringKind && rightKind == StringKind:
175165
return c.NewString(c.StringValue(left) + c.StringValue(right))
@@ -217,13 +207,13 @@ func BinOp(c *OpContext, op Op, left, right Value) Value {
217207
}
218208

219209
case SubtractOp:
220-
return numOp(c, apdCtx.Sub, left, right, op)
210+
return c.Sub(c.Num(left, op), c.Num(right, op))
221211

222212
case MultiplyOp:
223213
switch {
224214
// float
225215
case leftKind&NumKind != 0 && rightKind&NumKind != 0:
226-
return numOp(c, apdCtx.Mul, left, right, op)
216+
return c.Mul(c.Num(left, op), c.Num(right, op))
227217

228218
case leftKind == StringKind && rightKind == IntKind:
229219
const as = "string multiplication"
@@ -275,47 +265,27 @@ func BinOp(c *OpContext, op Op, left, right Value) Value {
275265

276266
case FloatQuotientOp:
277267
if leftKind&NumKind != 0 && rightKind&NumKind != 0 {
278-
v := numOp(c, apdCtx.Quo, left, right, op)
279-
if n, ok := v.(*Num); ok {
280-
n.K = FloatKind
281-
}
282-
return v
268+
return c.Quo(c.Num(left, op), c.Num(right, op))
283269
}
284270

285271
case IntDivideOp:
286272
if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
287-
y := c.Num(right, op)
288-
if y.X.IsZero() {
289-
return c.NewErrf("division by zero")
290-
}
291-
return intOp(c, (*big.Int).Div, c.Num(left, op), y)
273+
return c.IntDiv(c.Num(left, op), c.Num(right, op))
292274
}
293275

294276
case IntModuloOp:
295277
if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
296-
y := c.Num(right, op)
297-
if y.X.IsZero() {
298-
return c.NewErrf("division by zero")
299-
}
300-
return intOp(c, (*big.Int).Mod, c.Num(left, op), y)
278+
return c.IntMod(c.Num(left, op), c.Num(right, op))
301279
}
302280

303281
case IntQuotientOp:
304282
if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
305-
y := c.Num(right, op)
306-
if y.X.IsZero() {
307-
return c.NewErrf("division by zero")
308-
}
309-
return intOp(c, (*big.Int).Quo, c.Num(left, op), y)
283+
return c.IntQuo(c.Num(left, op), c.Num(right, op))
310284
}
311285

312286
case IntRemainderOp:
313287
if leftKind&IntKind != 0 && rightKind&IntKind != 0 {
314-
y := c.Num(right, op)
315-
if y.X.IsZero() {
316-
return c.NewErrf("division by zero")
317-
}
318-
return intOp(c, (*big.Int).Rem, c.Num(left, op), y)
288+
return c.IntRem(c.Num(left, op), c.Num(right, op))
319289
}
320290
}
321291

@@ -341,45 +311,3 @@ func cmpTonode(c *OpContext, op Op, r int) Value {
341311
}
342312
return c.newBool(result)
343313
}
344-
345-
type numFunc func(z, x, y *apd.Decimal) (apd.Condition, error)
346-
347-
func numOp(c *OpContext, fn numFunc, a, b Value, op Op) Value {
348-
var d apd.Decimal
349-
x := c.Num(a, op)
350-
y := c.Num(b, op)
351-
cond, err := fn(&d, &x.X, &y.X)
352-
if err != nil {
353-
return c.NewErrf("failed arithmetic: %v", err)
354-
}
355-
if cond.DivisionByZero() {
356-
return c.NewErrf("division by zero")
357-
}
358-
k := x.Kind() & y.Kind()
359-
if k == 0 {
360-
k = FloatKind
361-
}
362-
return c.NewNum(&d, k)
363-
}
364-
365-
type intFunc func(z, x, y *big.Int) *big.Int
366-
367-
func intOp(c *OpContext, fn intFunc, a, b *Num) Value {
368-
var d apd.Decimal
369-
370-
var x, y apd.Decimal
371-
_, _ = apdCtx.RoundToIntegralValue(&x, &a.X)
372-
if x.Negative {
373-
x.Coeff.Neg(&x.Coeff)
374-
}
375-
_, _ = apdCtx.RoundToIntegralValue(&y, &b.X)
376-
if y.Negative {
377-
y.Coeff.Neg(&y.Coeff)
378-
}
379-
fn(&d.Coeff, &x.Coeff, &y.Coeff)
380-
if d.Coeff.Sign() < 0 {
381-
d.Coeff.Neg(&d.Coeff)
382-
d.Negative = true
383-
}
384-
return c.NewNum(&d, IntKind)
385-
}

internal/core/adt/context.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -976,9 +976,9 @@ func (c *OpContext) regexp(v Value) *regexp.Regexp {
976976
}
977977
}
978978

979-
// NewNum creates a new number of the given kind. It reports an error value
979+
// newNum creates a new number of the given kind. It reports an error value
980980
// instead if any error occurred.
981-
func (c *OpContext) NewNum(d *apd.Decimal, k Kind, sources ...Node) Value {
981+
func (c *OpContext) newNum(d *apd.Decimal, k Kind, sources ...Node) Value {
982982
if c.HasErr() {
983983
return c.Err()
984984
}

internal/core/adt/decimal.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright 2020 CUE Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package adt
16+
17+
import (
18+
"math/big"
19+
20+
"github.com/cockroachdb/apd/v2"
21+
)
22+
23+
var apdCtx apd.Context
24+
25+
func init() {
26+
apdCtx = apd.BaseContext
27+
apdCtx.Precision = 24
28+
}
29+
30+
func (n *Num) Impl() *apd.Decimal {
31+
return &n.X
32+
}
33+
34+
func (n *Num) Negative() bool {
35+
return n.X.Negative
36+
}
37+
38+
func (a *Num) Cmp(b *Num) int {
39+
return a.X.Cmp(&b.X)
40+
}
41+
42+
func (c *OpContext) Add(a, b *Num) Value {
43+
return numOp(c, apdCtx.Add, a, b)
44+
}
45+
46+
func (c *OpContext) Sub(a, b *Num) Value {
47+
return numOp(c, apdCtx.Sub, a, b)
48+
}
49+
50+
func (c *OpContext) Mul(a, b *Num) Value {
51+
return numOp(c, apdCtx.Mul, a, b)
52+
}
53+
54+
func (c *OpContext) Quo(a, b *Num) Value {
55+
v := numOp(c, apdCtx.Quo, a, b)
56+
if n, ok := v.(*Num); ok {
57+
n.K = FloatKind
58+
}
59+
return v
60+
}
61+
62+
func (c *OpContext) Pow(a, b *Num) Value {
63+
return numOp(c, apdCtx.Pow, a, b)
64+
}
65+
66+
type numFunc func(z, x, y *apd.Decimal) (apd.Condition, error)
67+
68+
func numOp(c *OpContext, fn numFunc, x, y *Num) Value {
69+
var d apd.Decimal
70+
71+
cond, err := fn(&d, &x.X, &y.X)
72+
73+
if err != nil {
74+
return c.NewErrf("failed arithmetic: %v", err)
75+
}
76+
77+
if cond.DivisionByZero() {
78+
return c.NewErrf("division by zero")
79+
}
80+
81+
k := x.Kind() & y.Kind()
82+
if k == 0 {
83+
k = FloatKind
84+
}
85+
return c.newNum(&d, k)
86+
}
87+
88+
func (c *OpContext) IntDiv(a, b *Num) Value {
89+
return intDivOp(c, (*big.Int).Div, a, b)
90+
}
91+
92+
func (c *OpContext) IntMod(a, b *Num) Value {
93+
return intDivOp(c, (*big.Int).Mod, a, b)
94+
}
95+
96+
func (c *OpContext) IntQuo(a, b *Num) Value {
97+
return intDivOp(c, (*big.Int).Quo, a, b)
98+
}
99+
100+
func (c *OpContext) IntRem(a, b *Num) Value {
101+
return intDivOp(c, (*big.Int).Rem, a, b)
102+
}
103+
104+
type intFunc func(z, x, y *big.Int) *big.Int
105+
106+
func intDivOp(c *OpContext, fn intFunc, a, b *Num) Value {
107+
if b.X.IsZero() {
108+
return c.NewErrf("division by zero")
109+
}
110+
111+
var x, y apd.Decimal
112+
_, _ = apdCtx.RoundToIntegralValue(&x, &a.X)
113+
if x.Negative {
114+
x.Coeff.Neg(&x.Coeff)
115+
}
116+
_, _ = apdCtx.RoundToIntegralValue(&y, &b.X)
117+
if y.Negative {
118+
y.Coeff.Neg(&y.Coeff)
119+
}
120+
121+
var d apd.Decimal
122+
123+
fn(&d.Coeff, &x.Coeff, &y.Coeff)
124+
125+
if d.Coeff.Sign() < 0 {
126+
d.Coeff.Neg(&d.Coeff)
127+
d.Negative = true
128+
}
129+
130+
return c.newNum(&d, IntKind)
131+
}

internal/core/adt/simplify.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,17 @@ func SimplifyBounds(ctx *OpContext, k Kind, x, y *BoundValue) Value {
8282
// Readjust bounds for integers.
8383
if x.Op == GreaterEqualOp {
8484
// >=3.4 ==> >=4
85-
_, _ = apd.BaseContext.Ceil(&lo, &a.X)
85+
_, _ = apdCtx.Ceil(&lo, &a.X)
8686
} else {
8787
// >3.4 ==> >3
88-
_, _ = apd.BaseContext.Floor(&lo, &a.X)
88+
_, _ = apdCtx.Floor(&lo, &a.X)
8989
}
9090
if y.Op == LessEqualOp {
9191
// <=2.3 ==> <= 2
92-
_, _ = apd.BaseContext.Floor(&hi, &b.X)
92+
_, _ = apdCtx.Floor(&hi, &b.X)
9393
} else {
9494
// <2.3 ==> < 3
95-
_, _ = apd.BaseContext.Ceil(&hi, &b.X)
95+
_, _ = apdCtx.Ceil(&hi, &b.X)
9696
}
9797
}
9898

@@ -133,23 +133,23 @@ func SimplifyBounds(ctx *OpContext, k Kind, x, y *BoundValue) Value {
133133
case diff == 1:
134134
if k&FloatKind == 0 {
135135
if x.Op == GreaterEqualOp && y.Op == LessThanOp {
136-
return ctx.NewNum(&lo, k&NumKind, x, y)
136+
return ctx.newNum(&lo, k&NumKind, x, y)
137137
}
138138
if x.Op == GreaterThanOp && y.Op == LessEqualOp {
139-
return ctx.NewNum(&hi, k&NumKind, x, y)
139+
return ctx.newNum(&hi, k&NumKind, x, y)
140140
}
141141
}
142142

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

148148
}
149149

150150
case diff == 0:
151151
if x.Op == GreaterEqualOp && y.Op == LessEqualOp {
152-
return ctx.NewNum(&lo, k&NumKind, x, y)
152+
return ctx.newNum(&lo, k&NumKind, x, y)
153153
}
154154
fallthrough
155155

0 commit comments

Comments
 (0)