X-Git-Url: https://git.distorted.org.uk/~mdw/chopwood/blobdiff_plain/a2916c0635fec5b45ad742904db9f5769b48f53d..7d41b86a3d323404887ee58eb67a97c66fdf870b:/format.py diff --git a/format.py b/format.py index 231f922..d6eb896 100644 --- a/format.py +++ b/format.py @@ -389,6 +389,8 @@ def parse_arg(): A `+' means `the next pushed-back or positional argument'. It's useful to be able to say this explicitly so that indexing and attribute references can be attached to it: for example, in `~={thing}@[~={+.attr}A~]'. + Similarly, `@' designates the same argument, except that it is not + consumed. An integer argument selects the positional argument with that index; a negative index counts backwards from the end, as is usual in Python. @@ -772,7 +774,45 @@ def compile(control): """ Parse the whole CONTROL string, returning the corresponding formatting operator. + + A format control string consists of formatting directives, introduced by + the `~' character, and literal text. Literal text is simply output as-is. + Formatting directives may read /arguments/ which are provided as additional + inputs to the `format' function, and are typically items to be written to + the output in some form, and /parameters/, which control the formatting of + the arguments, and may be supplied in the control string, or themselves + read from arguments. A directive may also carry up to two flags, `@' and + `:'. + + The effects of the directive are determined by the corresponding formatting + operation, an object found by looking up the directive's identifying + character in `COMPILE.opmaps', which is a list of dictionaries. The + character is converted to upper-case (if it is alphabetic), and then the + dictionaries are examined in order: the first match found wins. See the + description of the `Formatting protocol' for details of how formatting + operations work. + + A formatting directive has the following syntax. + + DIRECTIVE ::= `~' [PARAMS] [`=' ARG] FLAGS CHAR + + PARAMS ::= PARAM [`,' PARAMS] + + PARAM ::= EMPTY | INT | `'' CHAR | `v' | `!' ARG + + FLAGS ::= [[ `@' | `:' ]]* + + (The useful but unusual notation [[ X | Y | ... ]]* denotes a sequence of + items drawn from the listed alternatives, each appearing at most once. See + the function `parse_arg' for the syntax of ARG.) + + An empty PARAM is equivalent to omitting the parameter; `!ARG' reads the + parameter value from the argument; `v' is equivalent to `!+', as a + convenient abbreviation and for Common Lisp compatibility. The `=ARG' + notation indicates which argument(s) should be processed by the operation: + the default is `=+'. """ + if not isinstance(control, basestring): return control pp = [] with COMPILE.bind(control = control, start = 0, end = len(control), delim = ''): @@ -833,10 +873,7 @@ def format(out, control, *args, **kw): raise TypeError, out ## Turn the control argument into a formatting operation. - if isinstance(control, basestring): - op = compile(control) - else: - op = control + op = compile(control) ## Invoke the formatting operation in the correct environment. with FORMAT.bind(write = write, pushback = [], @@ -1221,7 +1258,7 @@ class FormatIteration (BaseFormatOperation): then the enclosed directives are applied once even if the argument sequence is empty. - If the formatting directives are empty then a formatting string is fetched + If the formatting directives are empty then a formatting control is fetched using the argument collector associated with the closing delimiter. """ @@ -1310,7 +1347,7 @@ class FormatRecursive (BaseFormatOperation): """ ~?: Recursive formatting. - Without `@', read a pair of arguments: use the first as a format string, + Without `@', read a pair of arguments: use the first as a format control, and apply it to the arguments extracted from the second (which may be a sequence or a map).