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  }