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