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 }