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 }