...

Source file src/cuelang.org/go/internal/core/export/bounds.go

Documentation: cuelang.org/go/internal/core/export

     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 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  // boundSimplifier simplifies bound values into predeclared identifiers, if
    24  // possible.
    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  	// {"rune", makeDec("0"), makeDec(strconv.Itoa(0x10FFFF))},
   191  }
   192  
   193  var floatRanges = []builtinRange{
   194  	// 2**127 * (2**24 - 1) / 2**23
   195  	{"float32",
   196  		makeDec("-3.40282346638528859811704183484516925440e+38"),
   197  		makeDec("3.40282346638528859811704183484516925440e+38")},
   198  
   199  	// 2**1023 * (2**53 - 1) / 2**52
   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