Movatterモバイル変換
[0]ホーム
{-# LANGUAGE Safe #-}{-# LANGUAGE GADTs #-}------------------------------------------------------------------------------- |-- Module : Text.Printf-- Copyright : (c) Lennart Augustsson and Bart Massey 2013-- License : BSD-style (see the file LICENSE in this distribution)---- Maintainer : Bart Massey <bart@cs.pdx.edu>-- Stability : provisional-- Portability : portable---- A C @printf(3)@-like formatter. This version has been-- extended by Bart Massey as per the recommendations of-- John Meacham and Simon Marlow-- \<<http://comments.gmane.org/gmane.comp.lang.haskell.libraries/4726>\>-- to support extensible formatting for new datatypes. It-- has also been extended to support almost all C-- @printf(3)@ syntax.-----------------------------------------------------------------------------moduleText.Printf(-- * Printing Functionsprintf,hPrintf,-- * Extending To New Types---- | This 'printf' can be extended to format types-- other than those provided for by default. This-- is done by instantiating 'PrintfArg' and providing-- a 'formatArg' for the type. It is possible to-- provide a 'parseFormat' to process type-specific-- modifiers, but the default instance is usually-- the best choice.---- For example:---- > instance PrintfArg () where-- > formatArg x fmt | fmtChar (vFmt 'U' fmt) == 'U' =-- > formatString "()" (fmt { fmtChar = 's', fmtPrecision = Nothing })-- > formatArg _ fmt = errorBadFormat $ fmtChar fmt-- >-- > main :: IO ()-- > main = printf "[%-3.1U]\n" ()---- prints \"@[() ]@\". Note the use of 'formatString' to-- take care of field formatting specifications in a convenient-- way.PrintfArg(..),FieldFormatter,FieldFormat(..),FormatAdjustment(..),FormatSign(..),vFmt,-- ** Handling Type-specific Modifiers---- | In the unlikely case that modifier characters of-- some kind are desirable for a user-provided type,-- a 'ModifierParser' can be provided to process these-- characters. The resulting modifiers will appear in-- the 'FieldFormat' for use by the type-specific formatter.ModifierParser,FormatParse(..),-- ** Standard Formatters---- | These formatters for standard types are provided for-- convenience in writting new type-specific formatters:-- a common pattern is to throw to 'formatString' or-- 'formatInteger' to do most of the format handling for-- a new type.formatString,formatChar,formatInt,formatInteger,formatRealFloat,-- ** Raising Errors---- | These functions are used internally to raise various-- errors, and are exported for use by new type-specific-- formatters.errorBadFormat,errorShortFormat,errorMissingArgument,errorBadArgument,perror,-- * Implementation Internals-- | These types are needed for implementing processing-- variable numbers of arguments to 'printf' and 'hPrintf'.-- Their implementation is intentionally not visible from-- this module. If you attempt to pass an argument of a type-- which is not an instance of the appropriate class to-- 'printf' or 'hPrintf', then the compiler will report it-- as a missing instance of 'PrintfArg'. (All 'PrintfArg'-- instances are 'PrintfType' instances.)PrintfType,HPrintfType,-- | This class is needed as a Haskell98 compatibility-- workaround for the lack of FlexibleInstances.IsChar(..))whereimportData.CharimportData.IntimportData.ListimportData.WordimportNumericimportNumeric.NaturalimportSystem.IO--------------------- | Format a variable number of arguments with the C-style formatting string.---- >>> printf "%s, %d, %.4f" "hello" 123 pi-- hello, 123, 3.1416---- The return value is either 'String' or @('IO' a)@ (which-- should be @('IO' '()')@, but Haskell's type system-- makes this hard).---- The format string consists of ordinary characters and-- /conversion specifications/, which specify how to format-- one of the arguments to 'printf' in the output string. A-- format specification is introduced by the @%@ character;-- this character can be self-escaped into the format string-- using @%%@. A format specification ends with a /format-- character/ that provides the primary information about-- how to format the value. The rest of the conversion-- specification is optional. In order, one may have flag-- characters, a width specifier, a precision specifier, and-- type-specific modifier characters.---- Unlike C @printf(3)@, the formatting of this 'printf'-- is driven by the argument type; formatting is type specific. The-- types formatted by 'printf' \"out of the box\" are:---- * 'Integral' types, including 'Char'---- * 'String'---- * 'RealFloat' types---- 'printf' is also extensible to support other types: see below.---- A conversion specification begins with the-- character @%@, followed by zero or more of the following flags:---- > - left adjust (default is right adjust)-- > + always use a sign (+ or -) for signed conversions-- > space leading space for positive numbers in signed conversions-- > 0 pad with zeros rather than spaces-- > # use an \"alternate form\": see below---- When both flags are given, @-@ overrides @0@ and @+@ overrides space.-- A negative width specifier in a @*@ conversion is treated as-- positive but implies the left adjust flag.---- The \"alternate form\" for unsigned radix conversions is-- as in C @printf(3)@:---- > %o prefix with a leading 0 if needed-- > %x prefix with a leading 0x if nonzero-- > %X prefix with a leading 0X if nonzero-- > %b prefix with a leading 0b if nonzero-- > %[eEfFgG] ensure that the number contains a decimal point---- Any flags are followed optionally by a field width:---- > num field width-- > * as num, but taken from argument list---- The field width is a minimum, not a maximum: it will be-- expanded as needed to avoid mutilating a value.---- Any field width is followed optionally by a precision:---- > .num precision-- > . same as .0-- > .* as num, but taken from argument list---- Negative precision is taken as 0. The meaning of the-- precision depends on the conversion type.---- > Integral minimum number of digits to show-- > RealFloat number of digits after the decimal point-- > String maximum number of characters---- The precision for Integral types is accomplished by zero-padding.-- If both precision and zero-pad are given for an Integral field,-- the zero-pad is ignored.---- Any precision is followed optionally for Integral types-- by a width modifier; the only use of this modifier being-- to set the implicit size of the operand for conversion of-- a negative operand to unsigned:---- > hh Int8-- > h Int16-- > l Int32-- > ll Int64-- > L Int64---- The specification ends with a format character:---- > c character Integral-- > d decimal Integral-- > o octal Integral-- > x hexadecimal Integral-- > X hexadecimal Integral-- > b binary Integral-- > u unsigned decimal Integral-- > f floating point RealFloat-- > F floating point RealFloat-- > g general format float RealFloat-- > G general format float RealFloat-- > e exponent format float RealFloat-- > E exponent format float RealFloat-- > s string String-- > v default format any type---- The \"%v\" specifier is provided for all built-in types,-- and should be provided for user-defined type formatters-- as well. It picks a \"best\" representation for the given-- type. For the built-in types the \"%v\" specifier is-- converted as follows:---- > c Char-- > u other unsigned Integral-- > d other signed Integral-- > g RealFloat-- > s String---- Mismatch between the argument types and the format-- string, as well as any other syntactic or semantic errors-- in the format string, will cause an exception to be-- thrown at runtime.---- Note that the formatting for 'RealFloat' types is-- currently a bit different from that of C @printf(3)@,-- conforming instead to 'Numeric.showEFloat',-- 'Numeric.showFFloat' and 'Numeric.showGFloat' (and their-- alternate versions 'Numeric.showFFloatAlt' and-- 'Numeric.showGFloatAlt'). This is hard to fix: the fixed-- versions would format in a backward-incompatible way.-- In any case the Haskell behavior is generally more-- sensible than the C behavior. A brief summary of some-- key differences:---- * Haskell 'printf' never uses the default \"6-digit\" precision-- used by C printf.---- * Haskell 'printf' treats the \"precision\" specifier as-- indicating the number of digits after the decimal point.---- * Haskell 'printf' prints the exponent of e-format-- numbers without a gratuitous plus sign, and with the-- minimum possible number of digits.---- * Haskell 'printf' will place a zero after a decimal point when-- possible.printf::(PrintfTyper)=>String->rprintffmts=sprfmts[]-- | Similar to 'printf', except that output is via the specified-- 'Handle'. The return type is restricted to @('IO' a)@.hPrintf::(HPrintfTyper)=>Handle->String->rhPrintfhdlfmts=hsprhdlfmts[]-- |The 'PrintfType' class provides the variable argument magic for-- 'printf'. Its implementation is intentionally not visible from-- this module. If you attempt to pass an argument of a type which-- is not an instance of this class to 'printf' or 'hPrintf', then-- the compiler will report it as a missing instance of 'PrintfArg'.classPrintfTypetwherespr::String->[UPrintf]->t-- | The 'HPrintfType' class provides the variable argument magic for-- 'hPrintf'. Its implementation is intentionally not visible from-- this module.classHPrintfTypetwherehspr::Handle->String->[UPrintf]->t{- not allowed in Haskell 2010instance PrintfType String where spr fmt args = uprintf fmt (reverse args)-}-- | @since 2.01instance(IsCharc)=>PrintfType[c]wheresprfmtsargs=mapfromChar(uprintffmts(reverseargs))-- Note that this should really be (IO ()), but GHC's-- type system won't readily let us say that without-- bringing the GADTs. So we go conditional for these defs.-- | @since 4.7.0.0instance(a~())=>PrintfType(IOa)wheresprfmtsargs=putStr$mapfromChar$uprintffmts$reverseargs-- | @since 4.7.0.0instance(a~())=>HPrintfType(IOa)wherehsprhdlfmtsargs=dohPutStrhdl(uprintffmts(reverseargs))-- | @since 2.01instance(PrintfArga,PrintfTyper)=>PrintfType(a->r)wheresprfmtsargs=\a->sprfmts((parseFormata,formatArga):args)-- | @since 2.01instance(PrintfArga,HPrintfTyper)=>HPrintfType(a->r)wherehsprhdlfmtsargs=\a->hsprhdlfmts((parseFormata,formatArga):args)-- | Typeclass of 'printf'-formattable values. The 'formatArg' method-- takes a value and a field format descriptor and either fails due-- to a bad descriptor or produces a 'ShowS' as the result. The-- default 'parseFormat' expects no modifiers: this is the normal-- case. Minimal instance: 'formatArg'.classPrintfArgawhere-- | @since 4.7.0.0formatArg::a->FieldFormatter-- | @since 4.7.0.0parseFormat::a->ModifierParserparseFormat_(c:cs)=FormatParse""ccsparseFormat_""=errorShortFormat-- | @since 2.01instancePrintfArgCharwhereformatArg=formatCharparseFormat_cf=parseIntFormat(undefined::Int)cf-- | @since 2.01instance(IsCharc)=>PrintfArg[c]whereformatArg=formatString-- | @since 2.01instancePrintfArgIntwhereformatArg=formatIntparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgInt8whereformatArg=formatIntparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgInt16whereformatArg=formatIntparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgInt32whereformatArg=formatIntparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgInt64whereformatArg=formatIntparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgWordwhereformatArg=formatIntparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgWord8whereformatArg=formatIntparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgWord16whereformatArg=formatIntparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgWord32whereformatArg=formatIntparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgWord64whereformatArg=formatIntparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgIntegerwhereformatArg=formatIntegerparseFormat=parseIntFormat-- | @since 4.8.0.0instancePrintfArgNaturalwhereformatArg=formatInteger.toIntegerparseFormat=parseIntFormat-- | @since 2.01instancePrintfArgFloatwhereformatArg=formatRealFloat-- | @since 2.01instancePrintfArgDoublewhereformatArg=formatRealFloat-- | This class, with only the one instance, is used as-- a workaround for the fact that 'String', as a concrete-- type, is not allowable as a typeclass instance. 'IsChar'-- is exported for backward-compatibility.classIsCharcwhere-- | @since 4.7.0.0toChar::c->Char-- | @since 4.7.0.0fromChar::Char->c-- | @since 2.01instanceIsCharCharwheretoCharc=cfromCharc=c--------------------- | Whether to left-adjust or zero-pad a field. These are-- mutually exclusive, with 'LeftAdjust' taking precedence.---- @since 4.7.0.0dataFormatAdjustment=LeftAdjust|ZeroPad-- | How to handle the sign of a numeric field. These are-- mutually exclusive, with 'SignPlus' taking precedence.---- @since 4.7.0.0dataFormatSign=SignPlus|SignSpace-- | Description of field formatting for 'formatArg'. See UNIX `printf`(3)-- for a description of how field formatting works.---- @since 4.7.0.0dataFieldFormat=FieldFormat{fmtWidth::MaybeInt,-- ^ Total width of the field.fmtPrecision::MaybeInt,-- ^ Secondary field width specifier.fmtAdjust::MaybeFormatAdjustment,-- ^ Kind of filling or padding-- to be done.fmtSign::MaybeFormatSign,-- ^ Whether to insist on a-- plus sign for positive-- numbers.fmtAlternate::Bool,-- ^ Indicates an "alternate-- format". See printf(3)-- for the details, which-- vary by argument spec.fmtModifiers::String,-- ^ Characters that appeared-- immediately to the left of-- 'fmtChar' in the format-- and were accepted by the-- type's 'parseFormat'.-- Normally the empty string.fmtChar::Char-- ^ The format character-- 'printf' was invoked-- with. 'formatArg' should-- fail unless this character-- matches the type. It is-- normal to handle many-- different format-- characters for a single-- type.}-- | The \"format parser\" walks over argument-type-specific-- modifier characters to find the primary format character.-- This is the type of its result.---- @since 4.7.0.0dataFormatParse=FormatParse{fpModifiers::String,-- ^ Any modifiers found.fpChar::Char,-- ^ Primary format character.fpRest::String-- ^ Rest of the format string.}-- Contains the "modifier letters" that can precede an-- integer type.intModifierMap::[(String,Integer)]intModifierMap=[("hh",toInteger(minBound::Int8)),("h",toInteger(minBound::Int16)),("l",toInteger(minBound::Int32)),("ll",toInteger(minBound::Int64)),("L",toInteger(minBound::Int64))]parseIntFormat::a->String->FormatParseparseIntFormat_s=casefoldrmatchPrefixNothingintModifierMapofJustm->mNothing->casesofc:cs->FormatParse""ccs""->errorShortFormatwherematchPrefix(p,_)m@(Just(FormatParsep0__))|lengthp0>=lengthp=m|otherwise=casegetFormatpofNothing->mJustfp->JustfpmatchPrefix(p,_)Nothing=getFormatpgetFormatp=stripPrefixps>>=fpwherefp(c:cs)=Just$FormatParsepccsfp""=errorShortFormat-- | This is the type of a field formatter reified over its-- argument.---- @since 4.7.0.0typeFieldFormatter=FieldFormat->ShowS-- | Type of a function that will parse modifier characters-- from the format string.---- @since 4.7.0.0typeModifierParser=String->FormatParse-- | Substitute a \'v\' format character with the given-- default format character in the 'FieldFormat'. A-- convenience for user-implemented types, which should-- support \"%v\".---- @since 4.7.0.0vFmt::Char->FieldFormat->FieldFormatvFmtcufmt@(FieldFormat{fmtChar='v'})=ufmt{fmtChar=c}vFmt_ufmt=ufmt-- | Formatter for 'Char' values.---- @since 4.7.0.0formatChar::Char->FieldFormatterformatCharxufmt=formatIntegral(Just0)(toInteger$ordx)$vFmt'c'ufmt-- | Formatter for 'String' values.---- @since 4.7.0.0formatString::IsChara=>[a]->FieldFormatterformatStringxufmt=casefmtChar$vFmt's'ufmtof's'->maptoChar.(adjustufmt("",ts)++)wherets=maptoChar$trunc$fmtPrecisionufmtwheretruncNothing=xtrunc(Justn)=takenxc->errorBadFormatc-- Possibly apply the int modifiers to get a new-- int width for conversion.fixupMods::FieldFormat->MaybeInteger->MaybeIntegerfixupModsufmtm=letmods=fmtModifiersufmtincasemodsof""->m_->caselookupmodsintModifierMapofJustm0->Justm0Nothing->perror"unknown format modifier"-- | Formatter for 'Int' values.---- @since 4.7.0.0formatInt::(Integrala,Boundeda)=>a->FieldFormatterformatIntxufmt=letlb=toInteger$minBound`asTypeOf`xm=fixupModsufmt(Justlb)ufmt'=caselbof0->vFmt'u'ufmt_->ufmtinformatIntegralm(toIntegerx)ufmt'-- | Formatter for 'Integer' values.---- @since 4.7.0.0formatInteger::Integer->FieldFormatterformatIntegerxufmt=letm=fixupModsufmtNothinginformatIntegralmxufmt-- All formatting for integral types is handled-- consistently. The only difference is between Integer and-- bounded types; this difference is handled by the 'm'-- argument containing the lower bound.formatIntegral::MaybeInteger->Integer->FieldFormatterformatIntegralmxufmt0=letprec=fmtPrecisionufmt0incasefmtCharufmtof'd'->(adjustSignedufmt(fmtiprecx)++)'i'->(adjustSignedufmt(fmtiprecx)++)'x'->(adjustufmt(fmtu16(alt"0x"x)precmx)++)'X'->(adjustufmt(upcase$fmtu16(alt"0X"x)precmx)++)'b'->(adjustufmt(fmtu2(alt"0b"x)precmx)++)'o'->(adjustufmt(fmtu8(alt"0"x)precmx)++)'u'->(adjustufmt(fmtu10Nothingprecmx)++)'c'|x>=fromIntegral(ord(minBound::Char))&&x<=fromIntegral(ord(maxBound::Char))&&fmtPrecisionufmt==Nothing&&fmtModifiersufmt==""->formatString[chr$fromIntegralx](ufmt{fmtChar='s'})'c'->perror"illegal char conversion"c->errorBadFormatcwhereufmt=vFmt'd'$caseufmt0ofFieldFormat{fmtPrecision=Just_,fmtAdjust=JustZeroPad}->ufmt0{fmtAdjust=Nothing}_->ufmt0alt_0=Nothingaltp_=casefmtAlternateufmtofTrue->JustpFalse->Nothingupcase(s1,s2)=(s1,maptoUppers2)-- | Formatter for 'RealFloat' values.---- @since 4.7.0.0formatRealFloat::RealFloata=>a->FieldFormatterformatRealFloatxufmt=letc=fmtChar$vFmt'g'ufmtprec=fmtPrecisionufmtalt=fmtAlternateufmtincasecof'e'->(adjustSignedufmt(dfmtcprecaltx)++)'E'->(adjustSignedufmt(dfmtcprecaltx)++)'f'->(adjustSignedufmt(dfmtcprecaltx)++)'F'->(adjustSignedufmt(dfmtcprecaltx)++)'g'->(adjustSignedufmt(dfmtcprecaltx)++)'G'->(adjustSignedufmt(dfmtcprecaltx)++)_->errorBadFormatc-- This is the type carried around for arguments in-- the varargs code.typeUPrintf=(ModifierParser,FieldFormatter)-- Given a format string and a list of formatting functions-- (the actual argument value having already been baked into-- each of these functions before delivery), return the-- actual formatted text string.uprintf::String->[UPrintf]->Stringuprintfsus=uprintfssus""-- This function does the actual work, producing a ShowS-- instead of a string, for future expansion and for-- misguided efficiency.uprintfs::String->[UPrintf]->ShowSuprintfs""[]=iduprintfs""(_:_)=errorShortFormatuprintfs('%':'%':cs)us=('%':).uprintfscsusuprintfs('%':_)[]=errorMissingArgumentuprintfs('%':cs)us@(_:_)=fmtcsusuprintfs(c:cs)us=(c:).uprintfscsus-- Given a suffix of the format string starting just after-- the percent sign, and the list of remaining unprocessed-- arguments in the form described above, format the portion-- of the output described by this field description, and-- then continue with 'uprintfs'.fmt::String->[UPrintf]->ShowSfmtcs0us0=casegetSpecsFalseFalseNothingFalsecs0us0of(_,_,[])->errorMissingArgument(ufmt,cs,(_,u):us)->uufmt.uprintfscsus-- Given field formatting information, and a tuple-- consisting of a prefix (for example, a minus sign) that-- is supposed to go before the argument value and a string-- representing the value, return the properly padded and-- formatted result.adjust::FieldFormat->(String,String)->Stringadjustufmt(pre,str)=letnaturalWidth=lengthpre+lengthstrzero=casefmtAdjustufmtofJustZeroPad->True_->Falseleft=casefmtAdjustufmtofJustLeftAdjust->True_->Falsefill=casefmtWidthufmtofJustwidth|naturalWidth<width->letfillchar=ifzerothen'0'else' 'inreplicate(width-naturalWidth)fillchar_->""inifleftthenpre++str++fillelseifzerothenpre++fill++strelsefill++pre++str-- For positive numbers with an explicit sign field ("+" or-- " "), adjust accordingly.adjustSigned::FieldFormat->(String,String)->StringadjustSignedufmt@(FieldFormat{fmtSign=JustSignPlus})("",str)=adjustufmt("+",str)adjustSignedufmt@(FieldFormat{fmtSign=JustSignSpace})("",str)=adjustufmt(" ",str)adjustSignedufmtps=adjustufmtps-- Format a signed integer in the "default" fashion.-- This will be subjected to adjust subsequently.fmti::MaybeInt->Integer->(String,String)fmtipreci|i<0=("-",integral_precprec(show(-i)))|otherwise=("",integral_precprec(showi))-- Format an unsigned integer in the "default" fashion.-- This will be subjected to adjust subsequently. The 'b'-- argument is the base, the 'pre' argument is the prefix,-- and the '(Just m)' argument is the implicit lower-bound-- size of the operand for conversion from signed to-- unsigned. Thus, this function will refuse to convert an-- unbounded negative integer to an unsigned string.fmtu::Integer->MaybeString->MaybeInt->MaybeInteger->Integer->(String,String)fmtub(Justpre)precmi=let("",s)=fmtubNothingprecmiincasepreof"0"->casesof'0':_->("",s)_->(pre,s)_->(pre,s)fmtubNothingprec0m0i0=casefmtu'prec0m0i0ofJusts->("",s)Nothing->errorBadArgumentwherefmtu'::MaybeInt->MaybeInteger->Integer->MaybeStringfmtu'prec(Justm)i|i<0=fmtu'precNothing(-2*m+i)fmtu'(Justprec)_i|i>=0=fmap(integral_prec(Justprec))$fmtu'NothingNothingifmtu'Nothing_i|i>=0=Just$showIntAtBasebintToDigiti""fmtu'___=Nothing-- This is used by 'fmtu' and 'fmti' to zero-pad an-- int-string to a required precision.integral_prec::MaybeInt->String->Stringintegral_precNothingintegral=integralintegral_prec(Just0)"0"=""integral_prec(Justprec)integral=replicate(prec-lengthintegral)'0'++integralstoi::String->(Int,String)stoics=let(as,cs')=spanisDigitcsincaseasof""->(0,cs')_->(readas,cs')-- Figure out the FormatAdjustment, given:-- width, precision, left-adjust, zero-filladjustment::MaybeInt->Maybea->Bool->Bool->MaybeFormatAdjustmentadjustmentwplz=casewofJustn|n<0->adjlpTruez_->adjlplzwhereadjl_True_=JustLeftAdjustadjl_FalseTrue=JustZeroPadadjl___=Nothing-- Parse the various format controls to get a format specification.getSpecs::Bool->Bool->MaybeFormatSign->Bool->String->[UPrintf]->(FieldFormat,String,[UPrintf])getSpecs_zsa('-':cs0)us=getSpecsTruezsacs0usgetSpecslz_a('+':cs0)us=getSpecslz(JustSignPlus)acs0usgetSpecslzsa(' ':cs0)us=getSpecslzssacs0uswheress=casesofJustSignPlus->JustSignPlus_->JustSignSpacegetSpecsl_sa('0':cs0)us=getSpecslTruesacs0usgetSpecslzs_('#':cs0)us=getSpecslzsTruecs0usgetSpecslzsa('*':cs0)us=let(us',n)=getStarus((p,cs''),us'')=casecs0of'.':'*':r->let(us''',p')=getStarus'in((Justp',r),us''')'.':r->let(p',r')=stoirin((Justp',r'),us')_->((Nothing,cs0),us')FormatParsemsccs=caseus''of(ufmt,_):_->ufmtcs''[]->errorMissingArgumentin(FieldFormat{fmtWidth=Just(absn),fmtPrecision=p,fmtAdjust=adjustment(Justn)plz,fmtSign=s,fmtAlternate=a,fmtModifiers=ms,fmtChar=c},cs,us'')getSpecslzsa('.':cs0)us=let((p,cs'),us')=casecs0of'*':cs''->let(us'',p')=getStarusin((p',cs''),us'')_->(stoics0,us)FormatParsemsccs=caseus'of(ufmt,_):_->ufmtcs'[]->errorMissingArgumentin(FieldFormat{fmtWidth=Nothing,fmtPrecision=Justp,fmtAdjust=adjustmentNothing(Justp)lz,fmtSign=s,fmtAlternate=a,fmtModifiers=ms,fmtChar=c},cs,us')getSpecslzsacs0@(c0:_)us|isDigitc0=let(n,cs')=stoics0((p,cs''),us')=casecs'of'.':'*':r->let(us'',p')=getStarusin((Justp',r),us'')'.':r->let(p',r')=stoirin((Justp',r'),us)_->((Nothing,cs'),us)FormatParsemsccs=caseus'of(ufmt,_):_->ufmtcs''[]->errorMissingArgumentin(FieldFormat{fmtWidth=Just(absn),fmtPrecision=p,fmtAdjust=adjustment(Justn)plz,fmtSign=s,fmtAlternate=a,fmtModifiers=ms,fmtChar=c},cs,us')getSpecslzsacs0@(_:_)us=letFormatParsemsccs=caseusof(ufmt,_):_->ufmtcs0[]->errorMissingArgumentin(FieldFormat{fmtWidth=Nothing,fmtPrecision=Nothing,fmtAdjust=adjustmentNothingNothinglz,fmtSign=s,fmtAlternate=a,fmtModifiers=ms,fmtChar=c},cs,us)getSpecs____""_=errorShortFormat-- Process a star argument in a format specification.getStar::[UPrintf]->([UPrintf],Int)getStarus=letufmt=FieldFormat{fmtWidth=Nothing,fmtPrecision=Nothing,fmtAdjust=Nothing,fmtSign=Nothing,fmtAlternate=False,fmtModifiers="",fmtChar='d'}incaseusof[]->errorMissingArgument(_,nu):us'->(us',read(nuufmt""))-- Format a RealFloat value.dfmt::(RealFloata)=>Char->MaybeInt->Bool->a->(String,String)dfmtcpad=letcaseConvert=ifisUppercthenmaptoUpperelseidshowFunction=casetoLowercof'e'->showEFloat'f'->ifathenshowFFloatAltelseshowFFloat'g'->ifathenshowGFloatAltelseshowGFloat_->perror"internal error: impossible dfmt"result=caseConvert$showFunctionpd""incaseresultof'-':cs->("-",cs)cs->("",cs)-- | Raises an 'error' with a printf-specific prefix on the-- message string.---- @since 4.7.0.0perror::String->aperrors=errorWithoutStackTrace$"printf: "++s-- | Calls 'perror' to indicate an unknown format letter for-- a given type.---- @since 4.7.0.0errorBadFormat::Char->aerrorBadFormatc=perror$"bad formatting char "++showcerrorShortFormat,errorMissingArgument,errorBadArgument::a-- | Calls 'perror' to indicate that the format string ended-- early.---- @since 4.7.0.0errorShortFormat=perror"formatting string ended prematurely"-- | Calls 'perror' to indicate that there is a missing-- argument in the argument list.---- @since 4.7.0.0errorMissingArgument=perror"argument list ended prematurely"-- | Calls 'perror' to indicate that there is a type-- error or similar in the given argument.---- @since 4.7.0.0errorBadArgument=perror"bad argument"
[8]ページ先頭