CIRCT 23.0.0git
Loading...
Searching...
No Matches
indented_writer.py
Go to the documentation of this file.
1# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2# See https://llvm.org/LICENSE.txt for license information.
3# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4"""A tiny indentation-aware writer for emitting source text.
5
6Lets the type/module emitters avoid threading an `indent` string or
7hand-writing trailing newlines and doubled `{{` / `}}` braces. Text is
8streamed straight to the underlying output sink as it is produced --
9nothing is buffered.
10"""
11
12from contextlib import contextmanager
13from typing import Iterator, TextIO
14
15
17 """Stream indented source text to an output sink.
18
19 Wraps a `TextIO`-like `out` and tracks indentation as a stack of two-space
20 levels, so emit code never has to thread an `indent` string or hand-write
21 trailing newlines and doubled `{{` / `}}` braces. Every call writes through
22 to `out` immediately. The primitives are:
23
24 * `line(text)` -- write one line at the current indent (blank if empty).
25 * `block(header)` -- a context manager that writes `header {`, indents its
26 body, then closes with `}` (plus an optional `tail`, e.g. `;`).
27 * `access(label)` -- write an access specifier (`public:` / `private:`)
28 one level out from the members it introduces.
29
30 `write(text)` streams `text` verbatim (no indentation); it mirrors
31 `TextIO.write` so an `IndentedWriter` can itself stand in for a sink.
32 `indented()` opens a bare indent (e.g. a single-statement loop body)
33 without braces.
34 """
35
36 def __init__(self, out: TextIO, level: int = 0) -> None:
37 self._out = out
38 self._level = level
39
40 def line(self, text: str = "") -> None:
41 self._out.write(f"{' ' * self._level}{text}\n" if text else "\n")
42
43 def lines(self, *texts: str) -> None:
44 for text in texts:
45 self.line(text)
46
47 def write(self, text: str) -> None:
48 """Write `text` verbatim (no indentation). Mirrors `TextIO.write` so the
49 writer can be passed to emitters that build pre-indented strings."""
50 self._out.write(text)
51
52 def access(self, label: str) -> None:
53 # Access specifiers conventionally sit one indent level out from the
54 # members they introduce.
55 outer = max(self._level - 1, 0)
56 self._out.write(f"{' ' * outer}{label}\n")
57
58 @contextmanager
59 def indented(self) -> Iterator[None]:
60 self._level += 1
61 try:
62 yield
63 finally:
64 self._level -= 1
65
66 @contextmanager
67 def block(self, header: str, *, tail: str = "") -> Iterator[None]:
68 self.line(f"{header} {{")
69 self._level += 1
70 try:
71 yield
72 finally:
73 self._level -= 1
74 self.line(f"}}{tail}")
None __init__(self, TextIO out, int level=0)
Iterator[None] block(self, str header, *str tail="")