mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
370 lines
8.8 KiB
Swift
370 lines
8.8 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
// OutputStream and Formatting logic
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension Bool : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
alwaysTrap(kind == 'v')
|
|
return Format(layout).printToString(String(this))
|
|
}
|
|
}
|
|
|
|
extension Int8 : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
return Int64(this).format(kind, layout)
|
|
}
|
|
}
|
|
|
|
extension UInt8 : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
return UInt64(this).format(kind, layout)
|
|
}
|
|
}
|
|
|
|
extension Int16 : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
return Int64(this).format(kind, layout)
|
|
}
|
|
}
|
|
|
|
extension UInt16 : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
return UInt64(this).format(kind, layout)
|
|
}
|
|
}
|
|
|
|
extension Int32 : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
return Int64(this).format(kind, layout)
|
|
}
|
|
}
|
|
|
|
extension UInt32 : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
return UInt64(this).format(kind, layout)
|
|
}
|
|
}
|
|
|
|
extension Int64 : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
var radix = 10
|
|
var uppercase = false
|
|
if kind == 'X' { uppercase = true; radix = 16 }
|
|
else if kind == 'x' { radix = 16 }
|
|
else if kind == 'o' { radix = 8 }
|
|
else if kind != 'v' { alwaysTrap() }
|
|
return Format(layout).printToString(
|
|
String(this, radix : radix, uppercase : uppercase))
|
|
}
|
|
}
|
|
|
|
extension UInt64 : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
var radix = 10
|
|
var uppercase = false
|
|
if kind == 'X' { uppercase = true; radix = 16 }
|
|
else if kind == 'x' { radix = 16 }
|
|
else if kind == 'o' { radix = 8 }
|
|
else if kind != 'v' { alwaysTrap() }
|
|
return Format(layout).printToString(
|
|
String(this, radix : radix, uppercase : uppercase))
|
|
}
|
|
}
|
|
|
|
extension Int128 : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
var radix = 10
|
|
var uppercase = false
|
|
if kind == 'X' { uppercase = true; radix = 16 }
|
|
else if kind == 'x' { radix = 16 }
|
|
else if kind == 'o' { radix = 8 }
|
|
else if kind != 'v' { alwaysTrap() }
|
|
return Format(layout).printToString(
|
|
String(this, radix : radix, uppercase : uppercase))
|
|
}
|
|
}
|
|
|
|
extension UInt128 : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
var radix = 10
|
|
var uppercase = false
|
|
if kind == 'X' { uppercase = true; radix = 16 }
|
|
else if kind == 'x' { radix = 16 }
|
|
else if kind == 'o' { radix = 8 }
|
|
else if kind != 'v' { alwaysTrap() }
|
|
return Format(layout).printToString(
|
|
String(this, radix : radix, uppercase : uppercase))
|
|
}
|
|
}
|
|
|
|
extension Float : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
alwaysTrap(kind == 'v')
|
|
return Format(layout).printToString(String(this))
|
|
}
|
|
}
|
|
|
|
extension Double : FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String {
|
|
alwaysTrap(kind == 'v')
|
|
return Format(layout).printToString(String(this))
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Formatted Printing
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
struct Format {
|
|
var width : Int
|
|
var isValid : Bool
|
|
var leftJustify : Bool
|
|
|
|
constructor(layout : String) {
|
|
isValid = true
|
|
leftJustify = false
|
|
width = 0
|
|
|
|
if !layout.isEmpty() {
|
|
if layout[0] == '-' {
|
|
leftJustify = true
|
|
layout = layout.substr(1)
|
|
}
|
|
|
|
if !layout.isEmpty() {
|
|
for c in layout.chars {
|
|
if !c.isDigit() {
|
|
isValid = false
|
|
break
|
|
}
|
|
width = width * 10 + Int(UInt32(c) - UInt32('0'))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func printString(s : String) {
|
|
|
|
/* Causes problems due to <rdar://problem/11529601>
|
|
if !isValid {
|
|
print(s)
|
|
return
|
|
}
|
|
*/
|
|
var padding = max(width - s.size(), 0)
|
|
if !leftJustify {
|
|
for i in 0..padding { print(' ') }
|
|
}
|
|
print(s)
|
|
if leftJustify {
|
|
for i in 0..padding { print(' ') }
|
|
}
|
|
}
|
|
|
|
func printToString(s : String) -> String {
|
|
if !isValid {
|
|
return s
|
|
}
|
|
var r : String
|
|
var padding = max(width - s.size(), 0)
|
|
if !leftJustify {
|
|
r = String(padding, ' ')
|
|
}
|
|
r = r + s
|
|
if leftJustify {
|
|
r = r + String(padding, ' ')
|
|
}
|
|
return r
|
|
}
|
|
|
|
func replPrint() {
|
|
print("valid = \(isValid), leftJustify = \(leftJustify), width=\(width)")
|
|
}
|
|
}
|
|
|
|
// Terminal input & output
|
|
|
|
class Console : Object {
|
|
func write(buf : UInt8[]) -> Int {
|
|
var r = posix_write(1, buf.base.value, buf.length)
|
|
alwaysTrap(r != -1)
|
|
return r
|
|
}
|
|
|
|
func write(buf : String) -> Int {
|
|
var r = posix_write(1, buf.str_value.base.value, buf.length)
|
|
alwaysTrap(r != -1)
|
|
return r
|
|
}
|
|
|
|
func write(c : UInt8) {
|
|
var buf = new UInt8[1]
|
|
buf[0] = c
|
|
var r = write(buf)
|
|
alwaysTrap(r == 1)
|
|
}
|
|
}
|
|
|
|
var con : Console = Console()
|
|
|
|
protocol FormattedPrintable {
|
|
func format(kind : Char, layout : String) -> String
|
|
}
|
|
|
|
func splitFormat(format : String) -> (String, String, Char, String) {
|
|
var (before, afterPercent, foundPercent) = format.splitFirst('%')
|
|
if !foundPercent {
|
|
return (before, "", Char(0), afterPercent)
|
|
}
|
|
|
|
var (layout, kind, after, found) = afterPercent.splitFirstIf({ $0.isAlpha() })
|
|
if !found {
|
|
return (before, "", Char(0), afterPercent)
|
|
}
|
|
|
|
return (before, layout, kind, after)
|
|
}
|
|
|
|
protocol OutputStreamable {
|
|
func write(buf : UInt8[]) -> Int
|
|
// FIXME: Add default implementation when language allows it:
|
|
func write(buf : String) -> Int
|
|
// {return write(buf.asUInt8())}
|
|
}
|
|
|
|
// FIXME: Remove the FormattedPrintable[] overload if/when we can forward
|
|
// variadic arguments.
|
|
// BLOCKED: <rdar://problem/12134482> Can't forward variadic arguments
|
|
func printf(out : OutputStreamable, format : String, args : FormattedPrintable[]) {
|
|
var index = 0
|
|
while !format.isEmpty() {
|
|
var (before, layout, kind, after) = splitFormat(format)
|
|
out.write(before)
|
|
if kind != Char(0) {
|
|
out.write(args[index++].format(kind, layout))
|
|
}
|
|
format = after
|
|
}
|
|
}
|
|
|
|
func printf(out : OutputStreamable, format : String, args : FormattedPrintable...) {
|
|
printf(out, format, args)
|
|
}
|
|
|
|
func printf(format : String, args : FormattedPrintable...) {
|
|
printf(con, format, args)
|
|
}
|
|
|
|
// NOTE: the repl has builtin knowledge of this protocol
|
|
protocol ReplPrintable {
|
|
func replPrint()
|
|
}
|
|
// FIXME: This function shouldn't be necessary!
|
|
func replPrint<E : Enumerable requires E.EnumeratorType.Element: ReplPrintable>(s : E) {
|
|
print('[')
|
|
var first = true
|
|
var total = 0
|
|
for i in s {
|
|
if first {
|
|
first = false
|
|
} else {
|
|
print(", ")
|
|
}
|
|
i.replPrint()
|
|
total = total + 1
|
|
if total > 50 {
|
|
print(" ...]")
|
|
return
|
|
}
|
|
}
|
|
print(']')
|
|
}
|
|
|
|
func print<E : Enumerable requires E.EnumeratorType.Element: ReplPrintable>(s : E) {
|
|
replPrint(s)
|
|
}
|
|
|
|
// Some very basic output functions.
|
|
func [asmname="_TSs5printFT3valSi_T_"] print(val : Int)
|
|
func [asmname="_TSs5printFT3valSu_T_"] print(val : UInt64)
|
|
func [asmname="_TSs5printFT3valSd_T_"] print(val : Double)
|
|
func print(val : String) {
|
|
var len = val.byteLength()
|
|
for var i = 0; i < len; ++i {
|
|
c_putchar(Int32(val.str_value[i]))
|
|
}
|
|
}
|
|
func print(val : Char) {
|
|
var wc = UInt32(val)
|
|
if wc < 0x000080 {
|
|
c_putchar(Int32(wc))
|
|
return
|
|
} else if wc < 0x000800 {
|
|
c_putchar(Int32(0xC0 | (wc >> 6)))
|
|
c_putchar(Int32(0x80 | (wc & 0x03F)))
|
|
return
|
|
} else if wc < 0x010000 {
|
|
if !(0x00D800 <= wc && wc < 0x00E000) {
|
|
c_putchar(Int32(0xE0 | (wc >> 12)))
|
|
c_putchar(Int32(0x80 | ((wc & 0x0FC0) >> 6)))
|
|
c_putchar(Int32(0x80 | (wc & 0x003F)))
|
|
return
|
|
}
|
|
} else if wc < 0x110000 {
|
|
c_putchar(Int32(0xF0 | (wc >> 18)))
|
|
c_putchar(Int32(0x80 | ((wc & 0x03F000) >> 12)))
|
|
c_putchar(Int32(0x80 | ((wc & 0x000FC0) >> 6)))
|
|
c_putchar(Int32(0x80 | (wc & 0x00003F)))
|
|
return
|
|
}
|
|
// print(Char(0xFFFD))
|
|
alwaysTrap()
|
|
}
|
|
|
|
func print(val : Bool) {
|
|
if val {
|
|
print("true")
|
|
} else {
|
|
print("false")
|
|
}
|
|
}
|
|
|
|
// Some derived output functions.
|
|
func println(val : Bool) {
|
|
print(val)
|
|
print('\n')
|
|
}
|
|
func println(val : Int) {
|
|
print(val)
|
|
print('\n')
|
|
}
|
|
func println(val : UInt8) {
|
|
print(UInt64(val))
|
|
print('\n')
|
|
}
|
|
func println(val : UInt16) {
|
|
print(UInt64(val))
|
|
print('\n')
|
|
}
|
|
func println(val : UInt32) {
|
|
print(UInt64(val))
|
|
print('\n')
|
|
}
|
|
func println(val : UInt64) {
|
|
print(val)
|
|
print('\n')
|
|
}
|
|
func println(val : Double) {
|
|
print(val)
|
|
print('\n')
|
|
}
|
|
func println(val : String) {
|
|
print(val)
|
|
print('\n')
|
|
}
|
|
|
|
func println(val : Char) {
|
|
print(val)
|
|
print('\n')
|
|
}
|