------------------------------------------------------------------------ -- The Agda standard library -- -- Examples of format strings and printf ------------------------------------------------------------------------ {-# OPTIONS --safe --cubical-compatible #-} module README.Text.Printf where open import Data.Nat.Base open import Data.Char.Base open import Data.List.Base open import Data.String.Base open import Data.Sum.Base open import Relation.Binary.PropositionalEquality ------------------------------------------------------------------------ -- Format strings open import Text.Format -- We can specify a format by writing a string which will get interpreted -- by a lexer into a list of formatting directives. -- The specification types are always started with a '%' character: -- Integers (%d or %i) -- Naturals (%u) -- Floats (%f) -- Chars (%c) -- Strings (%s) -- Anything which is not a type specification is a raw string to be spliced -- in the output of printf. -- For instance the following format alternates types and raw strings _ : lexer "%s: %u + %u ≡ %u" ≡ inj₂ (`String ∷ Raw ": " ∷ `ℕ ∷ Raw " + " ∷ `ℕ ∷ Raw " ≡ " ∷ `ℕ ∷ []) _ = refl -- Lexing can fail. There are two possible errors: -- If we start a specification type with a '%' but the string ends then -- we get an UnexpectedEndOfString error _ : lexer "%s: %u + %u ≡ %" ≡ inj₁ (UnexpectedEndOfString "%s: %u + %u ≡ %") _ = refl -- If we start a specification type with a '%' and the following character -- does not correspond to an existing type, we get an InvalidType error -- together with a focus highlighting the position of the problematic type. _ : lexer "%s: %u + %a ≡ %u" ≡ inj₁ (InvalidType "%s: %u + %" 'a' " ≡ %u") _ = refl ------------------------------------------------------------------------ -- Printf open import Text.Printf -- printf is a function which takes a format string as an argument and -- returns a function expecting a value for each type specification present -- in the format and returns a string splicing in these values into the -- format string. -- For instance `printf "%s: %u + %u ≡ %u"` is a -- `String → ℕ → ℕ → ℕ → String` function. _ : String → ℕ → ℕ → ℕ → String _ = printf "%s: %u + %u ≡ %u" _ : printf "%s: %u + %u ≡ %u" "example" 3 2 5 ≡ "example: 3 + 2 ≡ 5" _ = refl -- If the format string str is invalid then `printf str` will have type -- `Error e` where `e` is the lexing error. _ : Text.Printf.Error (UnexpectedEndOfString "%s: %u + %u ≡ %") _ = printf "%s: %u + %u ≡ %" _ : Text.Printf.Error (InvalidType "%s: %u + %" 'a' " ≡ %u") _ = printf "%s: %u + %a ≡ %u" -- Trying to pass arguments to such an ̀Error` type will lead to a -- unification error which hopefully makes the problem clear e.g. -- `printf "%s: %u + %a ≡ %u" "example" 3 2 5` fails with the error: -- Text.Printf.Error (InvalidType "%s: %u + %" 'a' " ≡ %u") should be -- a function type, but it isn't -- when checking that "example" 3 2 5 are valid arguments to a -- function of type Text.Printf.Printf (lexer "%s: %u + %a ≡ %u")