1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package export
16
17 import (
18 "cuelang.org/go/cue/ast"
19 "cuelang.org/go/internal/core/adt"
20 "github.com/cockroachdb/apd/v3"
21 )
22
23
24
25 type boundSimplifier struct {
26 e *exporter
27
28 isInt bool
29 min *adt.BoundValue
30 minNum *adt.Num
31 max *adt.BoundValue
32 maxNum *adt.Num
33 }
34
35 func (s *boundSimplifier) add(v adt.Value) (used bool) {
36 switch x := v.(type) {
37 case *adt.BasicType:
38 switch x.K & adt.ScalarKinds {
39 case adt.IntKind:
40 s.isInt = true
41 return true
42 }
43
44 case *adt.BoundValue:
45 if adt.IsConcrete(x.Value) && x.Kind() == adt.IntKind {
46 s.isInt = true
47 }
48 switch x.Op {
49 case adt.GreaterThanOp:
50 if n, ok := x.Value.(*adt.Num); ok {
51 if s.min == nil || s.minNum.X.Cmp(&n.X) != 1 {
52 s.min = x
53 s.minNum = n
54 }
55 return true
56 }
57
58 case adt.GreaterEqualOp:
59 if n, ok := x.Value.(*adt.Num); ok {
60 if s.min == nil || s.minNum.X.Cmp(&n.X) == -1 {
61 s.min = x
62 s.minNum = n
63 }
64 return true
65 }
66
67 case adt.LessThanOp:
68 if n, ok := x.Value.(*adt.Num); ok {
69 if s.max == nil || s.maxNum.X.Cmp(&n.X) != -1 {
70 s.max = x
71 s.maxNum = n
72 }
73 return true
74 }
75
76 case adt.LessEqualOp:
77 if n, ok := x.Value.(*adt.Num); ok {
78 if s.max == nil || s.maxNum.X.Cmp(&n.X) == 1 {
79 s.max = x
80 s.maxNum = n
81 }
82 return true
83 }
84 }
85 }
86
87 return false
88 }
89
90 type builtinRange struct {
91 typ string
92 lo *apd.Decimal
93 hi *apd.Decimal
94 }
95
96 func makeDec(s string) *apd.Decimal {
97 d, _, err := apd.NewFromString(s)
98 if err != nil {
99 panic(err)
100 }
101 return d
102 }
103
104 func (s *boundSimplifier) expr(ctx *adt.OpContext) (e ast.Expr) {
105 if s.min == nil || s.max == nil {
106 return nil
107 }
108 switch {
109 case s.isInt:
110 t := s.matchRange(intRanges)
111 if t != "" {
112 e = ast.NewIdent(t)
113 break
114 }
115 if sign := s.minNum.X.Sign(); sign == -1 {
116 e = ast.NewIdent("int")
117
118 } else {
119 e = ast.NewIdent("uint")
120 if sign == 0 && s.min.Op == adt.GreaterEqualOp {
121 s.min = nil
122 break
123 }
124 }
125 fallthrough
126 default:
127 t := s.matchRange(floatRanges)
128 if t != "" {
129 e = wrapBin(e, ast.NewIdent(t), adt.AndOp)
130 }
131 }
132
133 if s.min != nil {
134 e = wrapBin(e, s.e.expr(nil, s.min), adt.AndOp)
135 }
136 if s.max != nil {
137 e = wrapBin(e, s.e.expr(nil, s.max), adt.AndOp)
138 }
139 return e
140 }
141
142 func (s *boundSimplifier) matchRange(ranges []builtinRange) (t string) {
143 for _, r := range ranges {
144 if !s.minNum.X.IsZero() && s.min.Op == adt.GreaterEqualOp && s.minNum.X.Cmp(r.lo) == 0 {
145 switch s.maxNum.X.Cmp(r.hi) {
146 case 0:
147 if s.max.Op == adt.LessEqualOp {
148 s.max = nil
149 }
150 s.min = nil
151 return r.typ
152 case -1:
153 if !s.minNum.X.IsZero() {
154 s.min = nil
155 return r.typ
156 }
157 case 1:
158 }
159 } else if s.max.Op == adt.LessEqualOp && s.maxNum.X.Cmp(r.hi) == 0 {
160 switch s.minNum.X.Cmp(r.lo) {
161 case -1:
162 case 0:
163 if s.min.Op == adt.GreaterEqualOp {
164 s.min = nil
165 }
166 fallthrough
167 case 1:
168 s.max = nil
169 return r.typ
170 }
171 }
172 }
173 return ""
174 }
175
176 var intRanges = []builtinRange{
177 {"int8", makeDec("-128"), makeDec("127")},
178 {"int16", makeDec("-32768"), makeDec("32767")},
179 {"int32", makeDec("-2147483648"), makeDec("2147483647")},
180 {"int64", makeDec("-9223372036854775808"), makeDec("9223372036854775807")},
181 {"int128", makeDec("-170141183460469231731687303715884105728"),
182 makeDec("170141183460469231731687303715884105727")},
183
184 {"uint8", makeDec("0"), makeDec("255")},
185 {"uint16", makeDec("0"), makeDec("65535")},
186 {"uint32", makeDec("0"), makeDec("4294967295")},
187 {"uint64", makeDec("0"), makeDec("18446744073709551615")},
188 {"uint128", makeDec("0"), makeDec("340282366920938463463374607431768211455")},
189
190
191 }
192
193 var floatRanges = []builtinRange{
194
195 {"float32",
196 makeDec("-3.40282346638528859811704183484516925440e+38"),
197 makeDec("3.40282346638528859811704183484516925440e+38")},
198
199
200 {"float64",
201 makeDec("-1.797693134862315708145274237317043567981e+308"),
202 makeDec("1.797693134862315708145274237317043567981e+308")},
203 }
204
205 func wrapBin(a, b ast.Expr, op adt.Op) ast.Expr {
206 if a == nil {
207 return b
208 }
209 if b == nil {
210 return a
211 }
212 return ast.NewBinExpr(op.Token(), a, b)
213 }
214
View as plain text