github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/print.go (about) 1 package runtime 2 3 import ( 4 "unsafe" 5 ) 6 7 type stringer interface { 8 String() string 9 } 10 11 //go:nobounds 12 func printstring(s string) { 13 for i := 0; i < len(s); i++ { 14 putchar(s[i]) 15 } 16 } 17 18 func printuint8(n uint8) { 19 if TargetBits >= 32 { 20 printuint32(uint32(n)) 21 } else { 22 prevdigits := n / 10 23 if prevdigits != 0 { 24 printuint8(prevdigits) 25 } 26 putchar(byte((n % 10) + '0')) 27 } 28 } 29 30 func printint8(n int8) { 31 if TargetBits >= 32 { 32 printint32(int32(n)) 33 } else { 34 if n < 0 { 35 putchar('-') 36 n = -n 37 } 38 printuint8(uint8(n)) 39 } 40 } 41 42 func printuintptr(n uintptr) { 43 switch unsafe.Sizeof(n) { 44 case 2: 45 printuint16(uint16(n)) 46 case 4: 47 printuint32(uint32(n)) 48 case 8: 49 printuint64(uint64(n)) 50 } 51 } 52 53 func printuint16(n uint16) { 54 printuint32(uint32(n)) 55 } 56 57 func printint16(n int16) { 58 printint32(int32(n)) 59 } 60 61 func printuint32(n uint32) { 62 printuint64(uint64(n)) 63 } 64 65 func printint32(n int32) { 66 // Print integer in signed big-endian base-10 notation, for humans to 67 // read. 68 if n < 0 { 69 putchar('-') 70 n = -n 71 } 72 printuint32(uint32(n)) 73 } 74 75 //go:nobounds 76 func printuint64(n uint64) { 77 digits := [20]byte{} // enough to hold (2^64)-1 78 // Fill in all 10 digits. 79 firstdigit := 19 // digit index that isn't zero (by default, the last to handle '0' correctly) 80 for i := 19; i >= 0; i-- { 81 digit := byte(n%10 + '0') 82 digits[i] = digit 83 if digit != '0' { 84 firstdigit = i 85 } 86 n /= 10 87 } 88 // Print digits without the leading zeroes. 89 for i := firstdigit; i < 20; i++ { 90 putchar(digits[i]) 91 } 92 } 93 94 func printint64(n int64) { 95 if n < 0 { 96 putchar('-') 97 n = -n 98 } 99 printuint64(uint64(n)) 100 } 101 102 // printfloat32() was copied from the relevant source in the original Go 103 // implementation and modified to work with float32 instead of float64. It is 104 // copyright by the Go authors, licensed under the same BSD 3-clause license. 105 // See https://golang.org/LICENSE for details. 106 // 107 // It is a near-duplicate of printfloat64. This is done so that printing a 108 // float32 value doesn't involve float64 routines, which can be unexpected and a 109 // problem sometimes. It comes with a possible code size reduction if both 110 // printfloat32 and printfloat64 are used, which seems uncommon. 111 // 112 // Source: 113 // https://github.com/golang/go/blob/master/src/runtime/print.go 114 func printfloat32(v float32) { 115 switch { 116 case v != v: 117 printstring("NaN") 118 return 119 case v+v == v && v > 0: 120 printstring("+Inf") 121 return 122 case v+v == v && v < 0: 123 printstring("-Inf") 124 return 125 } 126 127 const n = 7 // digits printed 128 var buf [n + 7]byte 129 buf[0] = '+' 130 e := 0 // exp 131 if v == 0 { 132 if 1/v < 0 { 133 buf[0] = '-' 134 } 135 } else { 136 if v < 0 { 137 v = -v 138 buf[0] = '-' 139 } 140 141 // normalize 142 for v >= 10 { 143 e++ 144 v /= 10 145 } 146 for v < 1 { 147 e-- 148 v *= 10 149 } 150 151 // round 152 h := float32(5.0) 153 for i := 0; i < n; i++ { 154 h /= 10 155 } 156 v += h 157 if v >= 10 { 158 e++ 159 v /= 10 160 } 161 } 162 163 // format +d.dddd+edd 164 for i := 0; i < n; i++ { 165 s := int(v) 166 buf[i+2] = byte(s + '0') 167 v -= float32(s) 168 v *= 10 169 } 170 buf[1] = buf[2] 171 buf[2] = '.' 172 173 buf[n+2] = 'e' 174 buf[n+3] = '+' 175 if e < 0 { 176 e = -e 177 buf[n+3] = '-' 178 } 179 180 buf[n+4] = byte(e/100) + '0' 181 buf[n+5] = byte(e/10)%10 + '0' 182 buf[n+6] = byte(e%10) + '0' 183 for _, c := range buf { 184 putchar(c) 185 } 186 } 187 188 // printfloat64() was copied from the relevant source in the original Go 189 // implementation. It is copyright by the Go authors, licensed under the same 190 // BSD 3-clause license. See https://golang.org/LICENSE for details. 191 // 192 // Source: 193 // https://github.com/golang/go/blob/master/src/runtime/print.go 194 func printfloat64(v float64) { 195 switch { 196 case v != v: 197 printstring("NaN") 198 return 199 case v+v == v && v > 0: 200 printstring("+Inf") 201 return 202 case v+v == v && v < 0: 203 printstring("-Inf") 204 return 205 } 206 207 const n = 7 // digits printed 208 var buf [n + 7]byte 209 buf[0] = '+' 210 e := 0 // exp 211 if v == 0 { 212 if 1/v < 0 { 213 buf[0] = '-' 214 } 215 } else { 216 if v < 0 { 217 v = -v 218 buf[0] = '-' 219 } 220 221 // normalize 222 for v >= 10 { 223 e++ 224 v /= 10 225 } 226 for v < 1 { 227 e-- 228 v *= 10 229 } 230 231 // round 232 h := 5.0 233 for i := 0; i < n; i++ { 234 h /= 10 235 } 236 v += h 237 if v >= 10 { 238 e++ 239 v /= 10 240 } 241 } 242 243 // format +d.dddd+edd 244 for i := 0; i < n; i++ { 245 s := int(v) 246 buf[i+2] = byte(s + '0') 247 v -= float64(s) 248 v *= 10 249 } 250 buf[1] = buf[2] 251 buf[2] = '.' 252 253 buf[n+2] = 'e' 254 buf[n+3] = '+' 255 if e < 0 { 256 e = -e 257 buf[n+3] = '-' 258 } 259 260 buf[n+4] = byte(e/100) + '0' 261 buf[n+5] = byte(e/10)%10 + '0' 262 buf[n+6] = byte(e%10) + '0' 263 for _, c := range buf { 264 putchar(c) 265 } 266 } 267 268 func printcomplex64(c complex64) { 269 putchar('(') 270 printfloat32(real(c)) 271 printfloat32(imag(c)) 272 printstring("i)") 273 } 274 275 func printcomplex128(c complex128) { 276 putchar('(') 277 printfloat64(real(c)) 278 printfloat64(imag(c)) 279 printstring("i)") 280 } 281 282 func printspace() { 283 putchar(' ') 284 } 285 286 func printnl() { 287 if baremetal { 288 putchar('\r') 289 } 290 putchar('\n') 291 } 292 293 func printitf(msg interface{}) { 294 switch msg := msg.(type) { 295 case bool: 296 print(msg) 297 case int: 298 print(msg) 299 case int8: 300 print(msg) 301 case int16: 302 print(msg) 303 case int32: 304 print(msg) 305 case int64: 306 print(msg) 307 case uint: 308 print(msg) 309 case uint8: 310 print(msg) 311 case uint16: 312 print(msg) 313 case uint32: 314 print(msg) 315 case uint64: 316 print(msg) 317 case uintptr: 318 print(msg) 319 case float32: 320 print(msg) 321 case float64: 322 print(msg) 323 case complex64: 324 print(msg) 325 case complex128: 326 print(msg) 327 case string: 328 print(msg) 329 case error: 330 print(msg.Error()) 331 case stringer: 332 print(msg.String()) 333 default: 334 // cast to underlying type 335 itf := *(*_interface)(unsafe.Pointer(&msg)) 336 putchar('(') 337 printuintptr(uintptr(itf.typecode)) 338 putchar(':') 339 print(itf.value) 340 putchar(')') 341 } 342 } 343 344 func printmap(m *hashmap) { 345 print("map[") 346 if m == nil { 347 print("nil") 348 } else { 349 print(uint(m.count)) 350 } 351 putchar(']') 352 } 353 354 func printptr(ptr uintptr) { 355 if ptr == 0 { 356 print("nil") 357 return 358 } 359 putchar('0') 360 putchar('x') 361 for i := 0; i < int(unsafe.Sizeof(ptr))*2; i++ { 362 nibble := byte(ptr >> (unsafe.Sizeof(ptr)*8 - 4)) 363 if nibble < 10 { 364 putchar(nibble + '0') 365 } else { 366 putchar(nibble - 10 + 'a') 367 } 368 ptr <<= 4 369 } 370 } 371 372 func printbool(b bool) { 373 if b { 374 printstring("true") 375 } else { 376 printstring("false") 377 } 378 } 379 380 func printslice(ptr, len_, cap_ uintptr) { 381 putchar('[') 382 printuintptr(len_) 383 putchar('/') 384 printuintptr(cap_) 385 putchar(']') 386 printptr(ptr) 387 }