iyi

Standard library, 0.18.0

std/format

Format strings for iyi.

import std/format to use it. Source: src/std/format.iyi at v0.18.0.

Provides sprintf, printf, and String.format / String#% with standard format specifiers:

`%[flags][width][.precision]specifier`

Supported specifiers:

%s - string (Object#to_s)
%p - inspected value (Object#inspect)
%c - character (Char or integer ASCII code)
%d, %i - signed decimal integer
%u - unsigned decimal integer
%x - hexadecimal lowercase
%X - hexadecimal uppercase
%o - octal integer
%b - binary integer
%f - floating point in fixed-point decimal notation
%e - floating point in scientific notation (lowercase e)
%E - floating point in scientific notation (uppercase E)
%g - the shorter of %f and %e, trailing zeros trimmed (C's rule)
%G - the same, with an uppercase E
%% - literal percent sign

Flags:

-  left-align within field (default right-align)
+  always show sign (+ or -)
(space) space before non-negative numbers if no sign
0  pad with zeros instead of spaces (between sign/prefix and digits)
#  alternate format (0x, 0X, 0o, 0b prefixes, trailing dot for float prec 0)

Width: minimum field width; values wider than field are never truncated. Precision:

integers: minimum digits to appear (padded with leading zeros);
          precision 0 on value 0 produces zero digits.
floats: fractional decimal places, exact and rounded half to even.
strings: maximum characters to include (truncated if longer).

Where it lives: Outside the prelude, for the reason socket is: nothing in src/iyi/ calls sprintf, and a program that formats no string should not carry the engine that would. import std/format brings sprintf, printf, String.format and String#% with it, and the reopenings below travel with the import the way std/text's do (SPEC.md III.9).

And against iyi's own prelude only: String#% is a name Crystal has, so import std/format in a --crystal program is refused rather than replacing the library's under the whole program (SPEC.md III.6).

printfdef

The argument list as one array or tuple, as sprintf takes it.

std/formatiyi doc src/std/format.iyi
pub def printf(format_string : String, args : Array) : Nil

printfdef

std/formatiyi doc src/std/format.iyi
pub def printf(format_string : String, args : Tuple) : Nil

printfdef

std/formatiyi doc src/std/format.iyi
pub def printf(format_string : String, *args : *T) : Nil forall T

sprintfdef

The argument list may be one array or tuple, as the other library takes it: "%s, %s, %s, D" % ['A', 'B', 'C'], its own example, panicked "too few arguments for format string" here, and "[%s]" % ["A"] printed [["A"]] where it prints [A]. Two overloads rather than one taking Array | Tuple: a union with Array in it cannot be written into an artifact ("can't use Array(T) in unions yet").

std/formatiyi doc src/std/format.iyi
pub def sprintf(format_string : String, args : Array) : String

sprintfdef

std/formatiyi doc src/std/format.iyi
pub def sprintf(format_string : String, args : Tuple) : String

sprintfdef

std/formatiyi doc src/std/format.iyi
pub def sprintf(format_string : String, *args : *T) : String forall T

IyiBigclass, reopened

std/formatiyi doc src/std/format.iyi
class ::IyiBig
  # self / small for a `small` under 2^32, self reduced to the quotient,
  # the remainder answered. A limb is 32 bits in a 64-bit word, so the
  # running remainder shifted up by a limb still fits the word.
  def div_small(small : UInt64) : UInt64
  # Base ten, most significant digit first, nine digits per division.
  def to_decimal : String
end

IyiFloatTextmodule, reopened

std/formatiyi doc src/std/format.iyi
module ::IyiFloatText
  # Extracts Dragon4 digits for a non-zero, finite double.
  # Returns {digits_pointer, count, k} where value = 0.d1 d2 ... dn * 10^k.
  def self.dragon4(value : Float64) : ::Tuple(Pointer(UInt8), Int32, Int32)
  # Scientific notation with exact places, half to even.
  def self.format_exp(value : Float64, uppercase : Bool, precision : Int32, hash_flag : Bool) : String
  # Fixed-point decimal format with exact places, half to even.
  def self.format_fixed(value : Float64, precision : Int32) : String
  # a * b as its high and low words, from 32-bit halves.
  def self.mul_wide(a : UInt64, b : UInt64) : ::Tuple(UInt64, UInt64)
  # Every digit the double has, not the shortest ones padded with zeros:
  # `round(f * 2^e * 10^places)`, half to even, as decimal digits. This is
  # what a fixed or scientific format prints, and what it did not print:
  # `%.0f` of 1e23 answered 100000000000000000000000 where the double is
  # 99999999999999991611392, `%.20f` of 0.1 answered twenty zeros where
  # the value's digits are 0.10000000000000000555, and `%e` of the
  # smallest denormal answered 5.000000e-324 for 4.940656e-324 - the
  # shortest digits, which round-trip, are not the value, and past them
  # there was nothing but zeros. `places` may be negative, a scale down.
  def self.scaled_digits(f : UInt64, e : Int32, places : Int32) : String
  # `scaled_digits` in two words, when they hold it: f * 10^places is
  # under 2^117 for the places a word of ten's powers reaches, and the
  # quotient by 2^-e and its half-to-even rounding are shifts and one
  # comparison of the remainder with the half. The same integer the
  # bignum's division gives - it is the same arithmetic, exact - where
  # that division made `%.2f` three times what Go's takes. nil when the
  # value, the places or the answer do not fit.
  def self.scaled_quick(f : UInt64, e : Int32, places : Int32) : UInt64 | ::Nil
end

IyiFormatmodule, reopened

std/formatiyi doc src/std/format.iyi
module ::IyiFormat
  # Any integer: an `Int64` or a `UInt64`, whose top half `to_i64` refuses.
  def self.code_point(code) : Char
  # A width or a precision, which an `Int32` holds: read into one, the
  # digits of `%99999999999d` panicked "arithmetic overflow".
  def self.field_number(format_string : String, start : Int32, stop : Int32, what : String) : Int32
  def self.format_arg(val, verb : Char, minus : Bool, plus : Bool, space : Bool, zero : Bool, hash : Bool, width : Int32, precision : Int32) : String
  # A number is a code point, as Crystal's `%c` has it: `%c` of 233 is
  # `é`, where it panicked "233 is out of char range" (`chr` is ASCII).
  # Anything else is its first character, not its first byte, which cut
  # `é` in half.
  def self.format_char_arg(val, minus : Bool, width : Int32) : String
  # Digits as `to_s(base)` writes them, a `-` first when negative, given
  # the verb's sign, prefix, precision and width.
  def self.format_digits(text : String, verb : Char, base : Int32, minus : Bool, plus : Bool, space : Bool, zero : Bool, hash : Bool, width : Int32, precision : Int32) : String
  def self.format_float64(val : Float64, minus : Bool, plus : Bool, space : Bool, zero : Bool, hash : Bool, width : Int32, precision : Int32) : String
  def self.format_float_exp(val : Float64, uppercase : Bool, minus : Bool, plus : Bool, space : Bool, zero : Bool, hash : Bool, width : Int32, precision : Int32) : String
  # `%g`: the shorter of the two notations, C's rule. With P the precision
  # (6 when none is given, 1 when it is 0) and X the exponent `%e` would
  # write at P - 1 places, it is `%e` at P - 1 places when X < -4 or X >= P
  # and `%f` at P - 1 - X places otherwise; either way the trailing zeros
  # of the fraction go, and its point with them, unless `#` keeps them.
  # NaN and the infinities are written as `%e` writes them.
  def self.format_float_general(val : Float64, uppercase : Bool, minus : Bool, plus : Bool, space : Bool, zero : Bool, hash : Bool, width : Int32, precision : Int32) : String
  def self.format_int64(val : Int64, base : Int32, uppercase : Bool, signed : Bool, minus : Bool, plus : Bool, space : Bool, zero : Bool, hash : Bool, width : Int32, precision : Int32) : String
  # Width and precision in characters, because `size` is and because
  # `%-10s` is a column: counted in bytes, a multi-byte string came out
  # short by one space per extra byte, and a precision cut a character in
  # half. The prelude's `ljust`/`rjust` decided the same thing.
  #
  # The characters a precision keeps are written into one buffer, as
  # `each_char` decodes them and `size` counts them: added one at a time
  # onto a string of their own, the text was copied once per character,
  # and `%.800000s` of a megabyte took 12.8 s, four times as long for
  # every doubling.
  def self.format_string_arg(str : String, minus : Bool, width : Int32, precision : Int32) : String
  # A float under an integer verb is truncated, which is what Ruby, Python
  # and the other language answer to it. Past an `Int64` the truncation is
  # the double's own integer, f * 2^e, written whole as Python writes it:
  # `%d` of 1e30 is 1000000000000000019884624838656, where `to_i64`
  # panicked "arithmetic overflow". NaN and the infinities have no
  # integer, and the refusal says that rather than "arithmetic overflow".
  def self.format_truncated(val : Float64, verb : Char, minus : Bool, plus : Bool, space : Bool, zero : Bool, hash : Bool, width : Int32, precision : Int32) : String
  def self.format_uint64(val : UInt64, base : Int32, uppercase : Bool, signed : Bool, minus : Bool, plus : Bool, space : Bool, zero : Bool, hash : Bool, width : Int32, precision : Int32) : String
  # An `Int128` or `UInt128`: an integer verb writes its digits, which may
  # not fit 64 bits; a float verb its nearest double, as `%f` of an
  # `Int64` is.
  def self.format_wide(val, verb : Char, minus : Bool, plus : Bool, space : Bool, zero : Bool, hash : Bool, width : Int32, precision : Int32) : String
  # A numeric verb is a claim about the argument, and an argument that is
  # not a number contradicts it: `%d` of "abc" printed abc, `%f` of a
  # `Char` printed the character, and the caller who had mistyped the
  # argument order saw their strings where their numbers should be and
  # nothing said so.
  def self.not_a_number(val, verb : Char) : NoReturn
  # A decimal's fraction without its trailing zeros, and without its point
  # when nothing is left after it: `%g`'s trim.
  def self.trim_fraction(text : String) : String
end

Stringclass, reopened

std/formatiyi doc src/std/format.iyi
class ::String
  def %(args : Tuple) : String
  def %(arg) : String
  def %(*args : *T) : String forall T
  def self.format(format_string : String, *args : *T) : String forall T
end