chiark / gitweb /
crypto.py: Another missing import.
[chopwood] / format.py
1 ### -*-python-*-
2 ###
3 ### String formatting, with bells, whistles, and gongs
4 ###
5 ### (c) 2013 Mark Wooding
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This file is part of Chopwood: a password-changing service.
11 ###
12 ### Chopwood is free software; you can redistribute it and/or modify
13 ### it under the terms of the GNU Affero General Public License as
14 ### published by the Free Software Foundation; either version 3 of the
15 ### License, or (at your option) any later version.
16 ###
17 ### Chopwood is distributed in the hope that it will be useful,
18 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ### GNU Affero General Public License for more details.
21 ###
22 ### You should have received a copy of the GNU Affero General Public
23 ### License along with Chopwood; if not, see
24 ### <http://www.gnu.org/licenses/>.
25
26 from __future__ import with_statement
27
28 import contextlib as CTX
29 import re as RX
30 from cStringIO import StringIO
31 import sys as SYS
32
33 import util as U
34
35 ###--------------------------------------------------------------------------
36 ### A quick guide to the formatting machinery.
37 ###
38 ### This is basically a re-implementation of Common Lisp's FORMAT function in
39 ### Python.  It differs in a few respects.
40 ###
41 ###   * Most essentially, Python's object and argument-passing models aren't
42 ###     the same as Lisp's.  In fact, for our purposes, they're a bit better:
43 ###     Python's sharp distinction between positional and keyword arguments
44 ###     is often extremely annoying, but here they become a clear benefit.
45 ###     Inspired by Python's own enhanced string-formatting machinery (the
46 ###     new `str.format' method, and `string.Formatting' class, we provide
47 ###     additional syntax to access keyword arguments by name, positional
48 ###     arguments by position (without moving the cursor as manipulated by
49 ###     `~*'), and for selecting individual elements of arguments by indexing
50 ###     or attribute lookup.
51 ###
52 ###   * Unfortunately, Python's I/O subsystem is much less rich than Lisp's.
53 ###     We lack streams which remember their cursor position, and so can't
54 ###     implmenent the `?&' (fresh line) or `~T' (horizontal tab) operators
55 ###     usefully.  Moreover, the Python pretty-printer is rather less well
56 ###     developed than the XP-based Lisp pretty-printer, so the pretty-
57 ###     printing operations are unlikely to be implemented any time soon.
58 ###
59 ###   * This implementation is missing a number of formatting directives just
60 ###     because they're somewhat tedious to write, such as the detailed
61 ###     floating-point printing provided by `~E', `~F' and `~G'.  These might
62 ###     appear in time.
63 ###
64 ### Formatting takes place in two separable stages.  First, a format string
65 ### is compiled into a formatting operation.  Then, the formatting operation
66 ### can be applied to sets of arguments.  State for these two stages is
67 ### maintained in fluid variable sets `COMPILE' and `FORMAT'.
68 ###
69 ### There are a number of protocols involved in making all of this work.
70 ### They're described in detail as we come across them, but here's an
71 ### overview.
72 ###
73 ###   * Output is determined by formatting-operation objects, typically (but
74 ###     not necessarily) subclasses of `BaseFormatOperation'.  A format
75 ###     string is compiled into a single compound formatting operation.
76 ###
77 ###   * Formatting operations determine what to output from their own
78 ###     internal state and from formatting arguments.  The latter are
79 ###     collected from argument-collection objects which are subclasses of
80 ###     `BaseArg'.
81 ###
82 ###   * Formatting operations can be modified using parameters, which are
83 ###     supplied either through the format string or from arguments.  To
84 ###     abstract over this distinction, parameters are collected from
85 ###     parameter-collection objects which are subclasses of `BaseParameter'.
86
87 FORMAT = U.Fluid()
88 ## State for format-time processing.  The base state is established by the
89 ## `format' function, though various formatting operations will rebind
90 ## portions of the state while they perform recursive processing.  The
91 ## variables are as follows.
92 ##
93 ## argmap       The map (typically a dictionary) of keyword arguments to be
94 ##              formatted.  These can be accessed only though `=KEY' or
95 ##              `!KEY' syntax.
96 ##
97 ## argpos       The index of the next positional argument to be collected.
98 ##              The `~*' directive works by setting this variable.
99 ##
100 ## argseq       The sequence (typically a list) of positional arguments to be
101 ##              formatted.  These are collected in order (as modified by the
102 ##              `~*' directive), or may be accessed through `=INDEX' or
103 ##              `!INDEX' syntax.
104 ##
105 ## escape       An escape procedure (i.e., usually created by `Escape()') to
106 ##              be called by `~^'.
107 ##
108 ## last_multi_p A boolean, indicating that there are no more lists of
109 ##              arguments (e.g., from `~:{...~}'), so `~:^' should escape if
110 ##              it is encountered.
111 ##
112 ## multi_escape An escape procedure (i.e., usually created by `Escape()') to
113 ##              be called by `~:^'.
114 ##
115 ## pushback     Some formatting operations, notably `~@[...~]', read
116 ##              arguments without consuming them, so a subsequent operation
117 ##              should collect the same argument.  This works by pushing the
118 ##              arguments onto the `pushback' list.
119 ##
120 ## write        A function which writes its single string argument to the
121 ##              current output.
122
123 COMPILE = U.Fluid()
124 ## State for compile-time processing.  The base state is established by the
125 ## `compile' function, though some formatting operations will rebind portions
126 ## of the state while they perform recursive processing.  The variables are
127 ## as follows.
128 ##
129 ## control      The control string being parsed.
130 ##
131 ## delim        An iterable (usually a string) of delimiter directives.  See
132 ##              the `FormatDelimeter' class and the `collect_subformat'
133 ##              function for details of this.
134 ##
135 ## end          The end of the portion of the control string being parsed.
136 ##              There might be more of the string, but we should pretend that
137 ##              it doesn't exist.
138 ##
139 ## opmaps       A list of operation maps, i.e., dictionaries mapping
140 ##              formatting directive characters to the corresponding
141 ##              formatting operation classes.  The list is searched in order,
142 ##              and the first match is used.  This can be used to provide
143 ##              local extensions to the formatting language.
144 ##
145 ## start        The current position in the control string.  This is advanced
146 ##              as pieces of the string are successfully parsed.
147
148 ###--------------------------------------------------------------------------
149 ### A few random utilities.
150
151 def remaining():
152   """
153   Return the number of positional arguments remaining.
154
155   This will /include/ pushed-back arguments, so this needn't be monotonic
156   even in the absence of `~*' repositioning.
157   """
158   return len(FORMAT.pushback) + len(FORMAT.argseq) - FORMAT.argpos
159
160 @CTX.contextmanager
161 def bind_args(args, **kw):
162   """
163   Context manager: temporarily establish a different collection of arguments.
164
165   If the ARGS have a `keys' attribute, then they're assumed to be a mapping
166   object and are set as the keyword arguments, preserving the positional
167   arguments; otherwise, the positional arguments are set and the keyword
168   arguments are preserved.
169
170   Other keyword arguments to this function are treated as additional `FORMAT'
171   variables to be bound.
172   """
173   if hasattr(args, 'keys'):
174     with FORMAT.bind(argmap = args, **kw): yield
175   else:
176     with FORMAT.bind(argseq = args, argpos = 0, pushback = [], **kw): yield
177
178 ## Some regular expressions for parsing things.
179 R_INT = RX.compile(r'[-+]?[0-9]+')
180 R_WORD = RX.compile(r'[_a-zA-Z][_a-zA-Z0-9]*')
181
182 ###--------------------------------------------------------------------------
183 ### Format string errors.
184
185 class FormatStringError (Exception):
186   """
187   An exception type for reporting errors in format control strings.
188
189   Its most useful feature is that it points out where the error is in a
190   vaguely useful way.  Attributes are as follows.
191
192   control       The offending format control string.
193
194   msg           The error message, as a human-readable string.
195
196   pos           The position at which the error was discovered.  This might
197                 be a little way from the actual problem, but it's usually
198                 good enough.
199   """
200
201   def __init__(me, msg, control, pos):
202     """
203     Construct the exception, given a message MSG, a format CONTROL string,
204     and the position POS at which the error was found.
205     """
206     me.msg = msg
207     me.control = control
208     me.pos = pos
209
210   def __str__(me):
211     """
212     Present a string explaining the problem, including a dump of the
213     offending portion of the string.
214     """
215     s = me.control.rfind('\n', 0, me.pos) + 1
216     e = me.control.find('\n', me.pos)
217     if e < 0: e = len(me.control)
218     return '%s\n        %s\n        %*s^\n' % \
219         (me.msg, me.control[s:e], me.pos - s, '')
220
221 def format_string_error(msg):
222   """Report an error in the current format string."""
223   raise FormatStringError(msg, COMPILE.control, COMPILE.start)
224
225 ###--------------------------------------------------------------------------
226 ### Argument collection protocol.
227
228 ## Argument collectors abstract away the details of collecting formatting
229 ## arguments.  They're used both for collecting arguments to be output, and
230 ## for parameters designated using the `v' or `!ARG' syntaxes.
231 ##
232 ## There are a small number of primitive collectors, and some `compound
233 ## collectors' which read an argument using some other collector, and then
234 ## process it in some way.
235 ##
236 ## An argument collector should implement the following methods.
237 ##
238 ## get()        Return the argument variable.
239 ##
240 ## pair()       Return a pair of arguments.
241 ##
242 ## tostr(FORCEP)
243 ##              Return a string representation of the collector.  If FORCEP,
244 ##              always return a string; otherwise, a `NextArg' collector
245 ##              returns `None' to indicate that no syntax is required to
246 ##              select it.
247
248 class BaseArg (object):
249   """
250   Base class for argument collectors.
251
252   This implements the `pair' method by calling `get' and hoping that the
253   corresponding argument is indeed a sequence of two items.
254   """
255
256   def __init__(me):
257     """Trivial constructor."""
258     pass
259
260   def pair(me):
261     """
262     Return a pair of arguments, by returning an argument which is a pair.
263     """
264     return me.get()
265
266   def __repr__(me):
267     """Print a useful string representation of the collector."""
268     return '#<%s "=%s">' % (type(me).__name__, me.tostr(True))
269
270 class NextArg (BaseArg):
271   """The default argument collector."""
272
273   def get(me):
274     """
275     Return the next argument.
276
277     If there are pushed-back arguments, then return the one most recently
278     pushed back.  Otherwise, return the next argument from `argseq',
279     advancing `argpos'.
280     """
281     if FORMAT.pushback: return FORMAT.pushback.pop()
282     i = FORMAT.argpos
283     a = FORMAT.argseq[i]
284     FORMAT.argpos = i + 1
285     return a
286
287   def pair(me):
288     """Return a pair of arguments, by fetching two separate arguments."""
289     left = me.get()
290     right = me.get()
291     return left, right
292
293   def tostr(me, forcep):
294     """Convert the default collector to a string."""
295     if forcep: return '+'
296     else: return None
297
298 NEXTARG = NextArg()
299 ## Because a `NextArg' collectors are used so commonly, and they're all the
300 ## same, we make a distinguished one and try to use that instead.  Nothing
301 ## goes badly wrong if you don't use this, but you'll use more memory than
302 ## strictly necessary.
303
304 class ThisArg (BaseArg):
305   """Return the current positional argument without consuming it."""
306   def _get(me, i):
307     """Return the positional argument I on from the current position."""
308     n = len(FORMAT.pushback)
309     if n > i: return FORMAT.pushback[n - i - 1]
310     else: return FORMAT.argseq[FORMAT.argpos + i - n]
311   def get(me):
312     """Return the next argument."""
313     return me._get(0)
314   def pair(me):
315     """Return the next two arguments without consuming either."""
316     return me._get(0), me._get(1)
317   def tostr(me, forcep):
318     """Convert the colector to a string."""
319     return '@'
320
321 THISARG = ThisArg()
322
323 class SeqArg (BaseArg):
324   """
325   A primitive collector which picks out the positional argument at a specific
326   index.
327   """
328   def __init__(me, index): me.index = index
329   def get(me): return FORMAT.argseq[me.index]
330   def tostr(me, forcep): return '%d' % me.index
331
332 class MapArg (BaseArg):
333   """
334   A primitive collector which picks out the keyword argument with a specific
335   key.
336   """
337   def __init__(me, key): me.key = key
338   def get(me): return FORMAT.argmap[me.key]
339   def tostr(me, forcep): return '%s' % me.key
340
341 class IndexArg (BaseArg):
342   """
343   A compound collector which indexes an argument.
344   """
345   def __init__(me, base, index):
346     me.base = base
347     me.index = index
348   def get(me):
349     return me.base.get()[me.index]
350   def tostr(me, forcep):
351     return '%s[%s]' % (me.base.tostr(True), me.index)
352
353 class AttrArg (BaseArg):
354   """
355   A compound collector which returns an attribute of an argument.
356   """
357   def __init__(me, base, attr):
358     me.base = base
359     me.attr = attr
360   def get(me):
361     return getattr(me.base.get(), me.attr)
362   def tostr(me, forcep):
363     return '%s.%s' % (me.base.tostr(True), me.attr)
364
365 ## Regular expression matching compound-argument suffixes.
366 R_REF = RX.compile(r'''
367         \[ ( [-+]? [0-9]+ ) \]
368       | \[ ( [^]]* ) \]
369       | \. ( [_a-zA-Z] [_a-zA-Z0-9]* )
370 ''', RX.VERBOSE)
371
372 def parse_arg():
373   """
374   Parse an argument collector from the current format control string.
375
376   The syntax of an argument is as follows.
377
378   ARG ::= COMPOUND-ARG | `{' COMPOUND-ARG `}'
379
380   COMPOUND-ARG ::= SIMPLE-ARG
381         | COMPOUND-ARG `[' INDEX `]'
382         | COMPOUND-ARG `.' WORD
383
384   SIMPLE-ARG ::= INT | WORD | `+' | `@'
385
386   Surrounding braces mean nothing, but may serve to separate the argument
387   from a following alphabetic formatting directive.
388
389   A `+' means `the next pushed-back or positional argument'.  It's useful to
390   be able to say this explicitly so that indexing and attribute references
391   can be attached to it: for example, in `~={thing}@[~={+.attr}A~]'.
392
393   An integer argument selects the positional argument with that index; a
394   negative index counts backwards from the end, as is usual in Python.
395
396   A word argument selects the keyword argument with that key.
397   """
398
399   c = COMPILE.control
400   s, e = COMPILE.start, COMPILE.end
401
402   ## If it's delimited then pick through the delimiter.
403   brace = None
404   if s < e and c[s] == '{':
405     brace = '}'
406     s += 1
407
408   ## Make sure there's something to look at.
409   if s >= e: raise FormatStringError('missing argument specifier', c, s)
410
411   ## Find the start of the breadcrumbs.
412   if c[s] == '+':
413     getarg = NEXTARG
414     s += 1
415   if c[s] == '@':
416     getarg = THISARG
417     s += 1
418   elif c[s].isdigit():
419     m = R_INT.match(c, s, e)
420     getarg = SeqArg(int(m.group()))
421     s = m.end()
422   else:
423     m = R_WORD.match(c, s, e)
424     if not m: raise FormatStringError('unknown argument specifier', c, s)
425     getarg = MapArg(m.group())
426     s = m.end()
427
428   ## Now parse indices and attribute references.
429   while True:
430     m = R_REF.match(c, s, e)
431     if not m: break
432     if m.group(1): getarg = IndexArg(getarg, int(m.group(1)))
433     elif m.group(2): getarg = IndexArg(getarg, m.group(2))
434     elif m.group(3): getarg = AttrArg(getarg, m.group(3))
435     else: raise FormatStringError('internal error (weird ref)', c, s)
436     s = m.end()
437
438   ## Finally, check that we have the close delimiter we want.
439   if brace:
440     if s >= e or c[s] != brace:
441       raise FormatStringError('missing close brace', c, s)
442     s += 1
443
444   ## Done.
445   COMPILE.start = s
446   return getarg
447
448 ###--------------------------------------------------------------------------
449 ### Parameter collectors.
450
451 ## These are pretty similar in shape to argument collectors.  The required
452 ## methods are as follows.
453 ##
454 ## get()        Return the parameter value.
455 ##
456 ## tostr()      Return a string representation of the collector.  (We don't
457 ##              need a FORCEP argument here, because there are no default
458 ##              parameters.)
459
460 class BaseParameter (object):
461   """
462   Base class for parameter collector objects.
463
464   This isn't currently very useful, because all it provides is `__repr__',
465   but the protocol might get more complicated later.
466   """
467   def __init__(me): pass
468   def __repr__(me): return '#<%s "%s">' % (type(me).__name__, me.tostr())
469
470 class LiteralParameter (BaseParameter):
471   """
472   A literal parameter, parsed from the control string.
473   """
474   def __init__(me, lit): me.lit = lit
475   def get(me): return me.lit
476   def tostr(me):
477     if me.lit is None: return ''
478     elif isinstance(me.lit, (int, long)): return str(me.lit)
479     else: return "'%c" % me.lit
480
481 ## Many parameters are omitted, so let's just reuse a distinguished collector
482 ## for them.
483 LITNONE = LiteralParameter(None)
484
485 class RemainingParameter (BaseParameter):
486   """
487   A parameter which collects the number of remaining positional arguments.
488   """
489   def get(me): return remaining()
490   def tostr(me): return '#'
491
492 ## These are all the same, so let's just have one of them.
493 REMAIN = RemainingParameter()
494
495 class VariableParameter (BaseParameter):
496   """
497   A variable parameter, fetched from an argument.
498   """
499   def __init__(me, arg): me.arg = arg
500   def get(me): return me.arg.get()
501   def tostr(me):
502     s = me.arg.tostr(False)
503     if not s: return 'V'
504     else: return '!' + s
505 VARNEXT = VariableParameter(NEXTARG)
506
507 ###--------------------------------------------------------------------------
508 ### Formatting protocol.
509
510 ## The formatting operation protocol is pretty straightforward.  An operation
511 ## must implement a method `format' which takes no arguments, and should
512 ## produce its output (if any) by calling `FORMAT.write'.  In the course of
513 ## its execution, it may collect parameters and arguments.
514 ##
515 ## The `opmaps' table maps formatting directives (which are individual
516 ## characters, in upper-case for letters) to functions returning formatting
517 ## operation objects.  All of the directives are implemented in this way.
518 ## The functions for the base directives are actually the (callable) class
519 ## objects for subclasses of `BaseFormatOperation', though this isn't
520 ## necessary.
521 ##
522 ## The constructor functions are called as follows:
523 ##
524 ## FUNC(ATP, COLONP, GETARG, PARAMS, CHAR)
525 ##      The ATP and COLONP arguments are booleans indicating respectively
526 ##      whether the `@' and `:' modifiers were set in the control string.
527 ##      GETARG is the collector for the operation's argument(s).  The PARAMS
528 ##      are a list of parameter collectors.  Finally, CHAR is the directive
529 ##      character (so directives with siilar behaviour can use the same
530 ##      class).
531
532 class FormatLiteral (object):
533   """
534   A special formatting operation for printing literal text.
535   """
536   def __init__(me, s): me.s = s
537   def __repr__(me): return '#<%s %r>' % (type(me).__name__, me.s)
538   def format(me): FORMAT.write(me.s)
539
540 class FormatSequence (object):
541   """
542   A special formatting operation for applying collection of other operations
543   in sequence.
544   """
545   def __init__(me, seq):
546     me.seq = seq
547   def __repr__(me):
548     return '#<%s [%s]>' % (type(me).__name__,
549                            ', '.join(repr(p) for p in me.seq))
550   def format(me):
551     for p in me.seq: p.format()
552
553 class BaseFormatOperation (object):
554   """
555   The base class for built-in formatting operations (and, probably, most
556   extensions).
557
558   Subclasses should implement a `_format' method.
559
560   _format(ATP, COLONP, [PARAM = DEFAULT, ...])
561                 Called to produce output.  The ATP and COLONP flags are from
562                 the constructor.  The remaining function arguments are the
563                 computed parameter values.  Arguments may be collected using
564                 the `getarg' attribute.
565
566   Subclasses can set class attributes to influence the constructor.
567
568   MINPARAM      The minimal number of parameters acceptable.  If fewer
569                 parameters are supplied then an error is reported at compile
570                 time.  The default is zero.
571
572   MAXPARAM      The maximal number of parameters acceptable.  If more
573                 parameters are supplied then an error is reported at compile
574                 time.  The default is zero; `None' means that there is no
575                 maximum (but this is unusual).
576
577   Instances have a number of useful attributes.
578
579   atp           True if an `@' modifier appeared in the directive.
580
581   char          The directive character from the control string.
582
583   colonp        True if a `:' modifier appeared in the directive.
584
585   getarg        Argument collector; may be called by `_format'.
586
587   params        A list of parameter collector objects.
588   """
589
590   ## Default bounds on parameters.
591   MINPARAM = MAXPARAM = 0
592
593   def __init__(me, atp, colonp, getarg, params, char):
594     """
595     Constructor: store information about the directive, and check the bounds
596     on the parameters.
597
598     A subclass should call this before doing anything fancy such as parsing
599     the control string further.
600     """
601
602     ## Store information.
603     me.atp = atp
604     me.colonp = colonp
605     me.getarg = getarg
606     me.params = params
607     me.char = char
608
609     ## Check the parameters.
610     bad = False
611     if len(params) < me.MINPARAM: bad = True
612     elif me.MAXPARAM is not None and len(params) > me.MAXPARAM: bad = True
613     if bad:
614       format_string_error('bad parameters')
615
616   def format(me):
617     """Produce output: call the subclass's formatting function."""
618     me._format(me.atp, me.colonp, *[p.get() for p in me.params])
619
620   def tostr(me):
621     """Convert the operation to a directive string."""
622     return '~%s%s%s%s%s' % (
623       ','.join(a.tostr() for a in me.params),
624       me.colonp and ':' or '',
625       me.atp and '@' or '',
626       (lambda s: s and '={%s}' % s or '')(me.getarg.tostr(False)),
627       me.char)
628
629   def __repr__(me):
630     """Produce a readable (ahem) version of the directive."""
631     return '#<%s "%s">' % (type(me).__name__, me.tostr())
632
633 class FormatDelimiter (BaseFormatOperation):
634   """
635   A fake formatting operation which exists to impose additional syntactic
636   structure on control strings.
637
638   No `_format' method is actually defined, so `FormatDelimiter' objects
639   should never find their way into the output pipeline.  Instead, they are
640   typically useful in conjunction with the `collect_subformat' function.  To
641   this end, the constructor will fail if its directive character is not in
642   listed as an expected delimiter in `CONTROL.delim'.
643   """
644
645   def __init__(me, *args):
646     """
647     Constructor: make sure this delimiter is expected in the current context.
648     """
649     super(FormatDelimiter, me).__init__(*args)
650     if me.char not in COMPILE.delim:
651       format_string_error("unexpected close delimiter `~%s'" % me.char)
652
653 ###--------------------------------------------------------------------------
654 ### Parsing format strings.
655
656 def parse_operator():
657   """
658   Parse the next portion of the current control string and return a single
659   formatting operator for it.
660
661   If we have reached the end of the control string (as stored in
662   `CONTROL.end') then return `None'.
663   """
664
665   c = COMPILE.control
666   s, e = COMPILE.start, COMPILE.end
667
668   ## If we're at the end then stop.
669   if s >= e: return None
670
671   ## If there's some literal text then collect it.
672   if c[s] != '~':
673     i = c.find('~', s, e)
674     if i < 0: i = e
675     COMPILE.start = i
676     return FormatLiteral(c[s:i])
677
678   ## Otherwise there's a formatting directive to collect.
679   s += 1
680
681   ## First, collect arguments.
682   aa = []
683   while True:
684     if s >= e: break
685     if c[s] == ',':
686       aa.append(LITNONE)
687       s += 1
688       continue
689     elif c[s] == "'":
690       s += 1
691       if s >= e: raise FormatStringError('missing argument character', c, s)
692       aa.append(LiteralParameter(c[s]))
693       s += 1
694     elif c[s].upper() == 'V':
695       s += 1
696       aa.append(VARNEXT)
697     elif c[s] == '!':
698       COMPILE.start = s + 1
699       getarg = parse_arg()
700       s = COMPILE.start
701       aa.append(VariableParameter(getarg))
702     elif c[s] == '#':
703       s += 1
704       aa.append(REMAIN)
705     else:
706       m = R_INT.match(c, s, e)
707       if not m: break
708       aa.append(LiteralParameter(int(m.group())))
709       s = m.end()
710     if s >= e or c[s] != ',': break
711     s += 1
712
713   ## Maybe there's an explicit argument.
714   if s < e and c[s] == '=':
715     COMPILE.start = s + 1
716     getarg = parse_arg()
717     s = COMPILE.start
718   else:
719     getarg = NEXTARG
720
721   ## Next, collect the flags.
722   atp = colonp = False
723   while True:
724     if s >= e:
725       break
726     elif c[s] == '@':
727       if atp: raise FormatStringError('duplicate at flag', c, s)
728       atp = True
729     elif c[s] == ':':
730       if colonp: raise FormatStringError('duplicate colon flag', c, s)
731       colonp = True
732     else:
733       break
734     s += 1
735
736   ## We should now have a directive character.
737   if s >= e: raise FormatStringError('missing directive', c, s)
738   ch = c[s].upper()
739   op = None
740   for map in COMPILE.opmaps:
741     try: op = map[ch]
742     except KeyError: pass
743     else: break
744   else:
745     raise FormatStringError('unknown directive', c, s)
746   s += 1
747
748   ## Done.
749   COMPILE.start = s
750   return op(atp, colonp, getarg, aa, ch)
751
752 def collect_subformat(delim):
753   """
754   Parse formatting operations from the control string until we find one whose
755   directive character is listed in DELIM.
756
757   Where an operation accepts multiple sequences of formatting directives, the
758   first element of DELIM should be the proper closing delimiter.  The
759   traditional separator is `~;'.
760   """
761   pp = []
762   with COMPILE.bind(delim = delim):
763     while True:
764       p = parse_operator()
765       if not p:
766         format_string_error("missing close delimiter `~%s'" % delim[0])
767       if isinstance(p, FormatDelimiter) and p.char in delim: break
768       pp.append(p)
769   return FormatSequence(pp), p
770
771 def compile(control):
772   """
773   Parse the whole CONTROL string, returning the corresponding formatting
774   operator.
775   """
776   pp = []
777   with COMPILE.bind(control = control, start = 0, end = len(control),
778                     delim = ''):
779     while True:
780       p = parse_operator()
781       if not p: break
782       pp.append(p)
783   return FormatSequence(pp)
784
785 ###--------------------------------------------------------------------------
786 ### Formatting text.
787
788 def format(out, control, *args, **kw):
789   """
790   Format the positional args and keywords according to the CONTROL, and write
791   the result to OUT.
792
793   The output is written to OUT, which may be one of the following.
794
795   `True'        Write to standard output.
796
797   `False'       Write to standard error.
798
799   `None'        Return the output as a string.
800
801   Any object with a `write' attribute
802                 Call `write' repeatedly with strings to be output.
803
804   Any callable object
805                 Call the object repeatedly with strings to be output.
806
807   The CONTROL argument may be one of the following.
808
809   A string or unicode object
810                 Compile the string into a formatting operation and use that.
811
812   A formatting operation
813                 Apply the operation to the arguments.
814   """
815
816   ## Turn the output argument into a function which we can use easily.  If
817   ## we're writing to a string, we'll have to extract the result at the end,
818   ## so keep track of anything we have to do later.
819   final = U.constantly(None)
820   if out is True:
821     write = SYS.stdout.write
822   elif out is False:
823     write = SYS.stderr.write
824   elif out is None:
825     strio = StringIO()
826     write = strio.write
827     final = strio.getvalue
828   elif hasattr(out, 'write'):
829     write = out.write
830   elif callable(out):
831     write = out
832   else:
833     raise TypeError, out
834
835   ## Turn the control argument into a formatting operation.
836   if isinstance(control, basestring):
837     op = compile(control)
838   else:
839     op = control
840
841   ## Invoke the formatting operation in the correct environment.
842   with FORMAT.bind(write = write, pushback = [],
843                    argseq = args, argpos = 0,
844                    argmap = kw):
845     op.format()
846
847   ## Done.
848   return final()
849
850 ###--------------------------------------------------------------------------
851 ### Standard formatting directives.
852
853 ## A dictionary, in which we'll build the basic set of formatting operators.
854 ## Callers wishing to implement extensions should include this in their
855 ## `opmaps' lists.
856 BASEOPS = {}
857 COMPILE.opmaps = [BASEOPS]
858
859 ## Some standard delimiter directives.
860 for i in [']', ')', '}', '>', ';']: BASEOPS[i] = FormatDelimiter
861
862 class SimpleFormatOperation (BaseFormatOperation):
863   """
864   Common base class for the `~A' (`str') and `~S' (`repr') directives.
865
866   These take similar parameters, so it's useful to deal with them at the same
867   time.  Subclasses should implement a method `_convert' of one argument,
868   which returns a string to be formatted.
869
870   The parameters are as follows.
871
872   MINCOL        The minimum number of characters to output.  Padding is added
873                 if the output string is shorter than this.
874
875   COLINC        Lengths of padding groups.  The number of padding characters
876                 will be MINPAD more than a multiple of COLINC.
877
878   MINPAD        The smallest number of padding characters to write.
879
880   PADCHAR       The padding character.
881
882   If the `@' modifier is given, then padding is applied on the left;
883   otherwise it is applied on the right.
884   """
885
886   MAXPARAM = 4
887
888   def _format(me, atp, colonp,
889               mincol = 0, colinc = 1, minpad = 0, padchar = ' '):
890     what = me._convert(me.getarg.get())
891     n = len(what)
892     p = mincol - n - minpad + colinc - 1
893     p -= p%colinc
894     if p < 0: p = 0
895     p += minpad
896     if p <= 0: pass
897     elif atp: what = (p * padchar) + what
898     else: what = what + (p * padchar)
899     FORMAT.write(what)
900
901 class FormatString (SimpleFormatOperation):
902   """~A: convert argument to a string."""
903   def _convert(me, arg): return str(arg)
904 BASEOPS['A'] = FormatString
905
906 class FormatRepr (SimpleFormatOperation):
907   """~S: convert argument to readable form."""
908   def _convert(me, arg): return repr(arg)
909 BASEOPS['S'] = FormatRepr
910
911 class IntegerFormat (BaseFormatOperation):
912   """
913   Common base class for the integer formatting directives `~D', `~B', `~O~,
914   `~X', and `~R'.
915
916   These take similar parameters, so it's useful to deal with them at the same
917   time.  There is a `_convert' method which does the main work.  By default,
918   `_format' calls this with the argument and the value of the class attribute
919   `RADIX'; complicated subclasses might want to override this behaviour.
920
921   The parameters are as follows.
922
923   MINCOL        Minimum column width.  If the output is smaller than this
924                 then it will be padded on the left.  The default is 0.
925
926   PADCHAR       Character to use to pad the output, should this be necessary.
927                 The default is space.
928
929   COMMACHAR     If the `:' modifier is present, then use this character to
930                 separate groups of digits.  The default is `,'.
931
932   COMMAINTERVAL If the `:' modifier is present, then separate groups of this
933                 many digits.  The default is 3.
934
935   If `@' is present, then a sign is always written; otherwise only `-' signs
936   are written.
937   """
938
939   MAXPARAM = 4
940
941   def _convert(me, n, radix, atp, colonp,
942                mincol = 0, padchar = ' ',
943                commachar = ',', commainterval = 3):
944     """
945     Convert the integer N into the given RADIX, under the control of the
946     formatting parameters supplied.
947     """
948
949     ## Sort out the sign.  We'll deal with it at the end: for now it's just a
950     ## distraction.
951     if n < 0: sign = '-'; n = -n
952     elif atp: sign = '+'
953     else: sign = None
954
955     ## Build in `dd' a list of the digits, in reverse order.  This will make
956     ## the commafication easier later.  The general radix conversion is
957     ## inefficient but we can make that better later.
958     def revdigits(s):
959       l = list(s)
960       l.reverse()
961       return l
962     if radix == 10: dd = revdigits(str(n))
963     elif radix == 8: dd = revdigits(oct(n))
964     elif radix == 16: dd = revdigits(hex(n).upper())
965     else:
966       dd = []
967       while n:
968         q, r = divmod(n, radix)
969         if r < 10: ch = asc(ord('0') + r)
970         elif r < 36: ch = asc(ord('A') - 10 + r)
971         else: ch = asc(ord('a') - 36 + r)
972         dd.append(ch)
973       if not dd: dd.append('0')
974
975     ## If we must commafy then do that.
976     if colonp:
977       ndd = []
978       i = 0
979       for d in dd:
980         if i >= commainterval: ndd.append(commachar); i = 0
981         ndd.append(d)
982       dd = ndd
983
984     ## Include the sign.
985     if sign: dd.append(sign)
986
987     ## Maybe we must pad the result.
988     s = ''.join(reversed(dd))
989     npad = mincol - len(s)
990     if npad > 0: s = npad*padchar + s
991
992     ## And we're done.
993     FORMAT.write(s)
994
995   def _format(me, atp, colonp, mincol = 0, padchar = ' ',
996               commachar = ',', commainterval = 3):
997     me._convert(me.getarg.get(), me.RADIX, atp, colonp, mincol, padchar,
998                 commachar, commainterval)
999
1000 class FormatDecimal (IntegerFormat):
1001   """~D: Decimal formatting."""
1002   RADIX = 10
1003 BASEOPS['D'] = FormatDecimal
1004
1005 class FormatBinary (IntegerFormat):
1006   """~B: Binary formatting."""
1007   RADIX = 2
1008 BASEOPS['B'] = FormatBinary
1009
1010 class FormatOctal (IntegerFormat):
1011   """~O: Octal formatting."""
1012   RADIX = 8
1013 BASEOPS['O'] = FormatOctal
1014
1015 class FormatHex (IntegerFormat):
1016   """~X: Hexadecimal formatting."""
1017   RADIX = 16
1018 BASEOPS['X'] = FormatHex
1019
1020 class FormatRadix (IntegerFormat):
1021   """~R: General integer formatting."""
1022   MAXPARAM = 5
1023   def _format(me, atp, colonp, radix = None, mincol = 0, padchar = ' ',
1024               commachar = ',', commainterval = 3):
1025     if radix is None:
1026       raise ValueError, 'Not implemented'
1027     me._convert(me.getarg.get(), radix, atp, colonp, mincol, padchar,
1028                 commachar, commainterval)
1029 BASEOPS['R'] = FormatRadix
1030
1031 class FormatSuppressNewline (BaseFormatOperation):
1032   """
1033   ~newline: suppressed newline and/or spaces.
1034
1035   Unless the `@' modifier is present, don't print the newline.  Unless the
1036   `:' modifier is present, don't print the following string of whitespace
1037   characters either.
1038   """
1039   R_SPACE = RX.compile(r'\s*')
1040   def __init__(me, *args):
1041     super(FormatSuppressNewline, me).__init__(*args)
1042     m = me.R_SPACE.match(COMPILE.control, COMPILE.start, COMPILE.end)
1043     me.trail = m.group()
1044     COMPILE.start = m.end()
1045   def _format(me, atp, colonp):
1046     if atp: FORMAT.write('\n')
1047     if colonp: FORMAT.write(me.trail)
1048 BASEOPS['\n'] = FormatSuppressNewline
1049
1050 class LiteralFormat (BaseFormatOperation):
1051   """
1052   A base class for formatting operations which write fixed strings.
1053
1054   Subclasses should have an attribute `CHAR' containing the string (usually a
1055   single character) to be written.
1056
1057   These operations accept a single parameter:
1058
1059   COUNT         The number of copies of the string to be written.
1060   """
1061   MAXPARAM = 1
1062   def _format(me, atp, colonp, count = 1):
1063     FORMAT.write(count * me.CHAR)
1064
1065 class FormatNewline (LiteralFormat):
1066   """~%: Start a new line."""
1067   CHAR = '\n'
1068 BASEOPS['%'] = FormatNewline
1069
1070 class FormatTilde (LiteralFormat):
1071   """~~: Print a literal `@'."""
1072   CHAR = '~'
1073 BASEOPS['~'] = FormatTilde
1074
1075 class FormatCaseConvert (BaseFormatOperation):
1076   """
1077   ~(...~): Case-convert the contained output.
1078
1079   The material output by the contained directives is subject to case
1080   conversion as follows.
1081
1082   no modifiers  Convert to lower-case.
1083   @             Make initial letter upper-case and remainder lower.
1084   :             Make initial letters of words upper-case.
1085   @:            Convert to upper-case.
1086   """
1087   def __init__(me, *args):
1088     super(FormatCaseConvert, me).__init__(*args)
1089     me.sub, _ = collect_subformat(')')
1090   def _format(me, atp, colonp):
1091     strio = StringIO()
1092     try:
1093       with FORMAT.bind(write = strio.write):
1094         me.sub.format()
1095     finally:
1096       inner = strio.getvalue()
1097       if atp:
1098         if colonp: out = inner.upper()
1099         else: out = inner.capitalize()
1100       else:
1101         if colonp: out = inner.title()
1102         else: out = inner.lower()
1103       FORMAT.write(out)
1104 BASEOPS['('] = FormatCaseConvert
1105
1106 class FormatGoto (BaseFormatOperation):
1107   """
1108   ~*: Seek in positional arguments.
1109
1110   There may be a parameter N; the default value depends on which modifiers
1111   are present.  Without `@', skip forwards or backwards by N (default
1112   1) places; with `@', move to argument N (default 0).  With `:', negate N,
1113   so move backwards instead of forwards, or count from the end rather than
1114   the beginning.  (Exception: `~@:0*' leaves no arguments remaining, whereas
1115   `~@-0*' is the same as `~@0*', and starts again from the beginning.
1116
1117   BUG: The list of pushed-back arguments is cleared.
1118   """
1119   MAXPARAM = 1
1120   def _format(me, atp, colonp, n = None):
1121     if atp:
1122       if n is None: n = 0
1123       if colonp:
1124         if n > 0: n = -n
1125         else: n = len(FORMAT.argseq)
1126       if n < 0: n += len(FORMAT.argseq)
1127     else:
1128       if n is None: n = 1
1129       if colonp: n = -n
1130       n += FORMAT.argpos
1131     FORMAT.argpos = n
1132     FORMAT.pushback = []
1133 BASEOPS['*'] = FormatGoto
1134
1135 class FormatConditional (BaseFormatOperation):
1136   """
1137   ~[...[~;...]...[~:;...]~]: Conditional formatting.
1138
1139   There are three variants, which are best dealt with separately.
1140
1141   With no modifiers, apply the Nth enclosed piece, where N is either the
1142   parameter, or the argument if no parameter is provided.  If there is no
1143   such piece (i.e., N is negative or too large) and the final piece is
1144   introduced by `~:;' then use that piece; otherwise produce no output.
1145
1146   With `:', there must be exactly two pieces: apply the first if the argument
1147   is false, otherwise the second.
1148
1149   With `@', there must be exactly one piece: if the argument is not `None'
1150   then push it back and apply the enclosed piece.
1151   """
1152
1153   MAXPARAM = 1
1154
1155   def __init__(me, *args):
1156
1157     ## Store the arguments.
1158     super(FormatConditional, me).__init__(*args)
1159
1160     ## Collect the pieces, and keep track of whether there's a default piece.
1161     pieces = []
1162     default = None
1163     nextdef = False
1164     while True:
1165       piece, delim = collect_subformat('];')
1166       if nextdef: default = piece
1167       else: pieces.append(piece)
1168       if delim.char == ']': break
1169       if delim.colonp:
1170         if default: format_string_error('multiple defaults')
1171         nextdef = True
1172
1173     ## Make sure the syntax matches the modifiers we've been given.
1174     if (me.colonp or me.atp) and default:
1175       format_string_error('default not allowed here')
1176     if (me.colonp and len(pieces) != 2) or \
1177           (me.atp and len(pieces) != 1):
1178       format_string_error('wrong number of pieces')
1179
1180     ## Store stuff.
1181     me.pieces = pieces
1182     me.default = default
1183
1184   def _format(me, atp, colonp, n = None):
1185     if colonp:
1186       arg = me.getarg.get()
1187       if arg: me.pieces[1].format()
1188       else: me.pieces[0].format()
1189     elif atp:
1190       arg = me.getarg.get()
1191       if arg is not None:
1192         FORMAT.pushback.append(arg)
1193         me.pieces[0].format()
1194     else:
1195       if n is None: n = me.getarg.get()
1196       if 0 <= n < len(me.pieces): piece = me.pieces[n]
1197       else: piece = me.default
1198       if piece: piece.format()
1199 BASEOPS['['] = FormatConditional
1200
1201 class FormatIteration (BaseFormatOperation):
1202   """
1203   ~{...~}: Repeated formatting.
1204
1205   Repeatedly apply the enclosed formatting directives to a sequence of
1206   different arguments.  The directives may contain `~^' to escape early.
1207
1208   Without `@', an argument is fetched and is expected to be a sequence; with
1209   `@', the remaining positional arguments are processed.
1210
1211   Without `:', the enclosed directives are simply applied until the sequence
1212   of arguments is exhausted: each iteration may consume any number of
1213   arguments (even zero, though this is likely a bad plan) and any left over
1214   are available to the next iteration.  With `:', each element of the
1215   sequence of arguments is itself treated as a collection of arguments --
1216   either positional or keyword depending on whether it looks like a map --
1217   and exactly one such element is consumed in each iteration.
1218
1219   If a parameter is supplied then perform at most this many iterations.  If
1220   the closing delimeter bears a `:' modifier, and the parameter is not zero,
1221   then the enclosed directives are applied once even if the argument sequence
1222   is empty.
1223
1224   If the formatting directives are empty then a formatting string is fetched
1225   using the argument collector associated with the closing delimiter.
1226   """
1227
1228   MAXPARAM = 1
1229
1230   def __init__(me, *args):
1231     super(FormatIteration, me).__init__(*args)
1232     me.body, me.end = collect_subformat('}')
1233
1234   def _multi(me, body):
1235     """
1236     Treat the positional arguments as a sequence of argument sets to be
1237     processed.
1238     """
1239     args = NEXTARG.get()
1240     with U.Escape() as esc:
1241       with bind_args(args, multi_escape = FORMAT.escape, escape = esc,
1242                      last_multi_p = not remaining()):
1243         body.format()
1244
1245   def _single(me, body):
1246     """
1247     Format arguments from a single argument sequence.
1248     """
1249     body.format()
1250
1251   def _loop(me, each, max):
1252     """
1253     Apply the function EACH repeatedly.  Stop if no positional arguments
1254     remain; if MAX is not `None', then stop after that number of iterations.
1255     The EACH function is passed a formatting operation representing the body
1256     to be applied
1257     """
1258     if me.body.seq: body = me.body
1259     else: body = compile(me.end.getarg.get())
1260     oncep = me.end.colonp
1261     i = 0
1262     while True:
1263       if max is not None and i >= max: break
1264       if (i > 0 or not oncep) and not remaining(): break
1265       each(body)
1266       i += 1
1267
1268   def _format(me, atp, colonp, max = None):
1269     if colonp: each = me._multi
1270     else: each = me._single
1271     with U.Escape() as esc:
1272       with FORMAT.bind(escape = esc):
1273         if atp:
1274           me._loop(each, max)
1275         else:
1276           with bind_args(me.getarg.get()):
1277             me._loop(each, max)
1278 BASEOPS['{'] = FormatIteration
1279
1280 class FormatEscape (BaseFormatOperation):
1281   """
1282   ~^: Escape from iteration.
1283
1284   Conditionally leave an iteration early.
1285
1286   There may be up to three parameters: call then X, Y and Z.  If all three
1287   are present then exit unless Y is between X and Z (inclusive); if two are
1288   present then exit if X = Y; if only one is present, then exit if X is
1289   zero.  Obviously these are more useful if at least one of X, Y and Z is
1290   variable.
1291
1292   With no parameters, exit if there are no positional arguments remaining.
1293   With `:', check the number of argument sets (as read by `~:{...~}') rather
1294   than the number of arguments in the current set, and escape from the entire
1295   iteration rather than from the processing the current set.
1296   """
1297   MAXPARAM = 3
1298   def _format(me, atp, colonp, x = None, y = None, z = None):
1299     if z is not None: cond = x <= y <= z
1300     elif y is not None: cond = x != y
1301     elif x is not None: cond = x != 0
1302     elif colonp: cond = not FORMAT.last_multi_p
1303     else: cond = remaining()
1304     if cond: return
1305     if colonp: FORMAT.multi_escape()
1306     else: FORMAT.escape()
1307 BASEOPS['^'] = FormatEscape
1308
1309 class FormatRecursive (BaseFormatOperation):
1310   """
1311   ~?: Recursive formatting.
1312
1313   Without `@', read a pair of arguments: use the first as a format string,
1314   and apply it to the arguments extracted from the second (which may be a
1315   sequence or a map).
1316
1317   With `@', read a single argument: use it as a format string and apply it to
1318   the remaining arguments.
1319   """
1320   def _format(me, atp, colonp):
1321     with U.Escape() as esc:
1322       if atp:
1323         control = me.getarg.get()
1324         op = compile(control)
1325         with FORMAT.bind(escape = esc): op.format()
1326       else:
1327         control, args = me.getarg.pair()
1328         op = compile(control)
1329         with bind_args(args, escape = esc): op.format()
1330 BASEOPS['?'] = FormatRecursive
1331
1332 ###----- That's all, folks --------------------------------------------------