github.com/gotranspile/cxgo@v0.3.8-0.20240118201721-29871598a6a2/literals.go (about)

     1  package cxgo
     2  
     3  import (
     4  	"go/ast"
     5  	"go/token"
     6  	"math"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/gotranspile/cxgo/types"
    11  )
    12  
    13  type Number interface {
    14  	Expr
    15  	IsZero() bool
    16  	IsOne() bool
    17  	IsNegative() bool
    18  	Negate() Number
    19  }
    20  
    21  func parseCIntLit(s string, auto bool) (IntLit, error) {
    22  	s = strings.ToLower(s)
    23  	s = strings.TrimRight(s, "ul")
    24  	base := 10
    25  	if strings.HasPrefix(s, "0x") {
    26  		base = 16
    27  		s = s[2:]
    28  	} else if strings.HasPrefix(s, "0b") {
    29  		base = 2
    30  		s = s[2:]
    31  	} else if len(s) > 1 && strings.HasPrefix(s, "0") {
    32  		base = 8
    33  		s = s[1:]
    34  	}
    35  	uv, err := strconv.ParseUint(s, base, 64)
    36  	if err == nil {
    37  		if auto {
    38  			base = 0
    39  		}
    40  		return cUintLit(uv, base), nil
    41  	}
    42  	iv, err := strconv.ParseInt(s, base, 64)
    43  	if err != nil {
    44  		return IntLit{}, err
    45  	}
    46  	if auto {
    47  		base = 0
    48  	}
    49  	return cIntLit(iv, base), nil
    50  }
    51  
    52  func cIntLit(v int64, base int) IntLit {
    53  	if v >= 0 {
    54  		return cUintLit(uint64(v), base)
    55  	}
    56  	l := IntLit{val: uint64(-v), neg: true, base: base}
    57  	if v >= math.MinInt8 && v <= math.MaxInt8 {
    58  		l.typ = types.IntT(1)
    59  	} else if v >= math.MinInt16 && v <= math.MaxInt16 {
    60  		l.typ = types.IntT(2)
    61  	} else if v >= math.MinInt32 && v <= math.MaxInt32 {
    62  		l.typ = types.IntT(4)
    63  	} else {
    64  		l.typ = types.IntT(8)
    65  	}
    66  	return l
    67  }
    68  
    69  func cUintLit(v uint64, base int) IntLit {
    70  	l := IntLit{val: v, base: base}
    71  	if v <= math.MaxUint8 {
    72  		l.typ = types.AsUntypedIntT(types.UintT(1))
    73  	} else if v <= math.MaxUint16 {
    74  		l.typ = types.AsUntypedIntT(types.UintT(2))
    75  	} else if v <= math.MaxUint32 {
    76  		l.typ = types.AsUntypedIntT(types.UintT(4))
    77  	} else {
    78  		l.typ = types.AsUntypedIntT(types.UintT(8))
    79  	}
    80  	return l
    81  }
    82  
    83  func litCanStore(t types.IntType, v IntLit) bool {
    84  	if v.neg {
    85  		if !t.Signed() {
    86  			return false
    87  		}
    88  		switch t.Sizeof() {
    89  		case 1:
    90  			return v.val <= uint64(-math.MinInt8)
    91  		case 2:
    92  			return v.val <= uint64(-math.MinInt16)
    93  		case 4:
    94  			return v.val <= uint64(-math.MinInt32)
    95  		case 8:
    96  			return v.val <= uint64(-math.MinInt64)
    97  		}
    98  		return true
    99  	}
   100  	if t.Signed() {
   101  		switch t.Sizeof() {
   102  		case 1:
   103  			return v.val <= math.MaxInt8
   104  		case 2:
   105  			return v.val <= math.MaxInt16
   106  		case 4:
   107  			return v.val <= math.MaxInt32
   108  		case 8:
   109  			return v.val <= math.MaxInt64
   110  		}
   111  		return true
   112  	}
   113  	switch t.Sizeof() {
   114  	case 1:
   115  		return v.val <= math.MaxUint8
   116  	case 2:
   117  		return v.val <= math.MaxUint16
   118  	case 4:
   119  		return v.val <= math.MaxUint32
   120  	case 8:
   121  		return v.val <= math.MaxUint64
   122  	}
   123  	return true
   124  }
   125  
   126  var _ Number = IntLit{}
   127  
   128  type IntLit struct {
   129  	typ  types.IntType
   130  	val  uint64
   131  	base int
   132  	neg  bool
   133  }
   134  
   135  func (IntLit) Visit(v Visitor) {}
   136  
   137  func (l IntLit) String() string {
   138  	v := strconv.FormatUint(l.val, 10)
   139  	if l.neg {
   140  		return "-" + v
   141  	}
   142  	return v
   143  }
   144  
   145  func (l IntLit) CType(exp types.Type) types.Type {
   146  	if t, ok := types.Unwrap(exp).(types.IntType); ok {
   147  		if !t.Signed() && !l.neg && l.typ.Sizeof() <= t.Sizeof() {
   148  			return exp
   149  		} else if t.Signed() && l.typ.Sizeof() <= t.Sizeof() && litCanStore(t, l) {
   150  			return exp
   151  		}
   152  	}
   153  	return l.typ
   154  }
   155  
   156  func (IntLit) IsConst() bool {
   157  	return true
   158  }
   159  
   160  func (IntLit) HasSideEffects() bool {
   161  	return false
   162  }
   163  
   164  func (l IntLit) IsZero() bool {
   165  	return l.val == 0
   166  }
   167  
   168  func (l IntLit) IsOne() bool {
   169  	return l.val == 1
   170  }
   171  
   172  func (l IntLit) IsNegative() bool {
   173  	return l.neg
   174  }
   175  
   176  func (l IntLit) Negate() Number {
   177  	return l.NegateLit()
   178  }
   179  
   180  func (l IntLit) NegateLit() IntLit {
   181  	if l.neg {
   182  		return cUintLit(l.val, l.base)
   183  	}
   184  	if l.val > math.MaxInt64 {
   185  		panic("cannot negate")
   186  	}
   187  	return cIntLit(-int64(l.val), l.base)
   188  }
   189  
   190  func (l IntLit) MulLit(v int64) IntLit {
   191  	if v < 0 {
   192  		l.neg = !l.neg
   193  		v = -v
   194  	}
   195  	l.val *= uint64(v)
   196  	return l
   197  }
   198  
   199  func (l IntLit) IsUint() bool {
   200  	return !l.neg || l.val > math.MaxInt64
   201  }
   202  
   203  func (l IntLit) IsNeg() bool {
   204  	return l.neg
   205  }
   206  
   207  func (l IntLit) Int() int64 {
   208  	if l.val > math.MaxInt64 {
   209  		panic("value is too big!")
   210  	}
   211  	v := int64(l.val)
   212  	if l.neg {
   213  		return -v
   214  	}
   215  	return v
   216  }
   217  
   218  func (l IntLit) Uint() uint64 {
   219  	if l.neg {
   220  		panic("value is negative!")
   221  	}
   222  	return l.val
   223  }
   224  
   225  func (l IntLit) OverflowInt(sz int) IntLit {
   226  	switch sz {
   227  	case 8:
   228  		v := int64(l.Uint())
   229  		return cIntLit(v, l.base)
   230  	case 4:
   231  		v := int32(uint32(l.Uint()))
   232  		return cIntLit(int64(v), l.base)
   233  	case 2:
   234  		v := int16(uint16(l.Uint()))
   235  		return cIntLit(int64(v), l.base)
   236  	case 1:
   237  		v := int8(uint8(l.Uint()))
   238  		return cIntLit(int64(v), l.base)
   239  	}
   240  	return l
   241  }
   242  
   243  func (l IntLit) OverflowUint(sz int) IntLit {
   244  	switch sz {
   245  	case 8:
   246  		v := uint64(l.Int())
   247  		return cUintLit(v, l.base)
   248  	case 4:
   249  		v := uint32(int32(l.Int()))
   250  		return cUintLit(uint64(v), l.base)
   251  	case 2:
   252  		v := uint16(int16(l.Int()))
   253  		return cUintLit(uint64(v), l.base)
   254  	case 1:
   255  		v := uint8(int8(l.Int()))
   256  		return cUintLit(uint64(v), l.base)
   257  	}
   258  	return l
   259  }
   260  
   261  func (l IntLit) AsExpr() GoExpr {
   262  	if l.neg {
   263  		val := -int64(l.val)
   264  		switch val {
   265  		case math.MinInt64:
   266  			return ident("math.MinInt64")
   267  		case math.MinInt32:
   268  			return ident("math.MinInt32")
   269  		case math.MinInt16:
   270  			return ident("math.MinInt16")
   271  		case math.MinInt8:
   272  			return ident("math.MinInt8")
   273  		}
   274  		return intLit64(val, l.base)
   275  	}
   276  	switch l.val {
   277  	case math.MaxUint64:
   278  		return ident("math.MaxUint64")
   279  	case math.MaxUint32:
   280  		return ident("math.MaxUint32")
   281  	case math.MaxUint16:
   282  		return ident("math.MaxUint16")
   283  	case math.MaxUint8:
   284  		return ident("math.MaxUint8")
   285  	case math.MaxInt64:
   286  		return ident("math.MaxInt64")
   287  	case math.MaxInt32:
   288  		return ident("math.MaxInt32")
   289  	case math.MaxInt16:
   290  		return ident("math.MaxInt16")
   291  	case math.MaxInt8:
   292  		return ident("math.MaxInt8")
   293  	}
   294  	return uintLit64(l.val, l.base)
   295  }
   296  
   297  func (l IntLit) Uses() []types.Usage {
   298  	return nil
   299  }
   300  
   301  var _ Number = FloatLit{}
   302  
   303  func parseCFloatLit(s string) (FloatLit, error) {
   304  	s = strings.ToLower(s)
   305  	s = strings.TrimSuffix(s, "f")
   306  	v, err := strconv.ParseFloat(s, 64)
   307  	if err != nil {
   308  		return FloatLit{}, err
   309  	}
   310  	return FloatLit{typ: types.AsUntypedFloatT(types.FloatT(8)), val: v}, nil
   311  }
   312  
   313  func cFloatLit(typ types.FloatType, v float64) FloatLit {
   314  	return FloatLit{typ: typ, val: v}
   315  }
   316  
   317  type FloatLit struct {
   318  	typ types.FloatType
   319  	val float64
   320  }
   321  
   322  func (FloatLit) Visit(v Visitor) {}
   323  
   324  func (l FloatLit) CType(exp types.Type) types.Type {
   325  	if t, ok := types.Unwrap(exp).(types.FloatType); ok {
   326  		return t
   327  	}
   328  	return l.typ
   329  }
   330  
   331  func (l FloatLit) AsExpr() GoExpr {
   332  	s := strconv.FormatFloat(l.val, 'g', -1, 64)
   333  	if float64(int(l.val)) == l.val && !strings.ContainsAny(s, ".e") {
   334  		s += ".0"
   335  	}
   336  	return &ast.BasicLit{
   337  		Kind:  token.FLOAT,
   338  		Value: s,
   339  	}
   340  }
   341  
   342  func (l FloatLit) IsZero() bool {
   343  	return l.val == 0.0
   344  }
   345  
   346  func (l FloatLit) IsOne() bool {
   347  	return l.val == 1.0
   348  }
   349  
   350  func (l FloatLit) IsNegative() bool {
   351  	return l.val < 0
   352  }
   353  
   354  func (l FloatLit) Negate() Number {
   355  	return FloatLit{val: -l.val}
   356  }
   357  
   358  func (l FloatLit) IsConst() bool {
   359  	return true
   360  }
   361  
   362  func (l FloatLit) HasSideEffects() bool {
   363  	return false
   364  }
   365  
   366  func (l FloatLit) Uses() []types.Usage {
   367  	return nil
   368  }
   369  
   370  func (g *translator) stringLit(s string) StringLit {
   371  	return StringLit{typ: g.env.Go().String(), val: s}
   372  }
   373  
   374  func (g *translator) parseCStringLit(s string) (StringLit, error) {
   375  	return StringLit{typ: g.env.Go().String(), val: s}, nil
   376  }
   377  
   378  func (g *translator) parseCWStringLit(s string) (StringLit, error) {
   379  	v, err := g.parseCStringLit(s)
   380  	if err == nil {
   381  		v.wide = true
   382  	}
   383  	return v, err
   384  }
   385  
   386  var _ Expr = StringLit{}
   387  
   388  type StringLit struct {
   389  	typ  types.Type
   390  	val  string
   391  	wide bool
   392  }
   393  
   394  func (StringLit) Visit(v Visitor) {}
   395  
   396  func (l StringLit) String() string {
   397  	return strconv.Quote(l.val)
   398  }
   399  
   400  func (l StringLit) Value() string {
   401  	return l.val
   402  }
   403  
   404  func (l StringLit) CType(types.Type) types.Type {
   405  	return l.typ
   406  }
   407  
   408  func (l StringLit) AsExpr() GoExpr {
   409  	return &ast.BasicLit{
   410  		Kind:  token.STRING,
   411  		Value: strconv.Quote(l.val),
   412  	}
   413  }
   414  
   415  func (l StringLit) IsWide() bool {
   416  	return l.wide
   417  }
   418  
   419  func (l StringLit) IsConst() bool {
   420  	return true
   421  }
   422  
   423  func (l StringLit) HasSideEffects() bool {
   424  	return false
   425  }
   426  
   427  func (l StringLit) Uses() []types.Usage {
   428  	return nil
   429  }
   430  
   431  func isASCII(b byte) bool {
   432  	return b <= '~'
   433  }
   434  
   435  type CLitKind int
   436  
   437  const (
   438  	CLitChar = CLitKind(iota)
   439  	CLitWChar
   440  )
   441  
   442  func cLit(value string, kind CLitKind) Expr {
   443  	return &CLiteral{
   444  		Value: value,
   445  		Kind:  kind,
   446  	}
   447  }
   448  
   449  func cLitT(value string, kind CLitKind, typ types.Type) Expr {
   450  	if typ == nil {
   451  		panic("use cLit")
   452  	}
   453  	return cLit(value, kind)
   454  }
   455  
   456  type CLiteral struct {
   457  	Value string
   458  	Kind  CLitKind
   459  	Type  types.Type
   460  }
   461  
   462  func (*CLiteral) Visit(v Visitor) {}
   463  
   464  func (e *CLiteral) CType(types.Type) types.Type {
   465  	if e.Type != nil {
   466  		return e.Type
   467  	}
   468  	switch e.Kind {
   469  	case CLitChar:
   470  		return types.AsUntypedIntT(types.UintT(1))
   471  	case CLitWChar:
   472  		panic("TODO")
   473  	default:
   474  		panic(e.Kind)
   475  	}
   476  }
   477  
   478  func (e *CLiteral) IsConst() bool {
   479  	return true
   480  }
   481  
   482  func (e *CLiteral) HasSideEffects() bool {
   483  	return false
   484  }
   485  
   486  func (e *CLiteral) AsExpr() GoExpr {
   487  	lit := &ast.BasicLit{
   488  		Value: e.Value,
   489  	}
   490  	switch e.Kind {
   491  	case CLitChar, CLitWChar: // FIXME
   492  		r := []rune(lit.Value)
   493  		if len(r) != 1 {
   494  			panic(strconv.Quote(lit.Value))
   495  		}
   496  		lit.Kind = token.CHAR
   497  		if isASCII(byte(r[0])) {
   498  			lit.Value = quoteWith(lit.Value, '\'')
   499  		} else {
   500  			lit.Value = "'\\x" + strconv.FormatUint(uint64(r[0]), 16) + "'"
   501  		}
   502  	default:
   503  		panic(e.Kind)
   504  	}
   505  	return lit
   506  }
   507  
   508  func (e *CLiteral) Uses() []types.Usage {
   509  	return nil
   510  }