Finish annotating test grammar, forced breaks, fixes

Forced breaks force a newline in a spot, which is sometimes what we
want. (Like, this syntax should *never* be on a single line.)
This commit is contained in:
John Doty 2024-09-13 11:57:16 -07:00
parent 938f0e5c69
commit d7a6891519
6 changed files with 273 additions and 92 deletions

View file

@ -5,6 +5,9 @@ import typing
from . import parser
from . import runtime
# TODO: I think I want a *force break*, i.e., a document which forces things
# to not fit on one line.
@dataclasses.dataclass(frozen=True)
class Cons:
@ -24,6 +27,11 @@ class NewLine:
replace: str
@dataclasses.dataclass(frozen=True)
class ForceBreak:
pass
@dataclasses.dataclass(frozen=True)
class Indent:
amount: int
@ -60,7 +68,7 @@ class Lazy:
return Lazy(lambda: printer.convert_tree_to_document(tree))
Document = None | Text | Literal | NewLine | Cons | Indent | Group | Lazy
Document = None | Text | Literal | NewLine | ForceBreak | Cons | Indent | Group | Lazy
class DocumentLayout:
@ -127,6 +135,12 @@ def layout_document(doc: Document, width: int) -> DocumentLayout:
# all fit.
return True
case ForceBreak():
# If we're in a flattened chunk then force it to break by
# returning false here, otherwise we're at the end of the
# line and yes, whatever you were asking about has fit.
return not chunk.flat
case Cons(left, right):
stack.append(chunk.with_document(right))
stack.append(chunk.with_document(left))
@ -180,6 +194,11 @@ def layout_document(doc: Document, width: int) -> DocumentLayout:
output.append("\n" + (chunk.indent * " "))
column = chunk.indent
case ForceBreak():
# TODO: Custom newline expansion, custom indent segments.
output.append("\n" + (chunk.indent * " "))
column = chunk.indent
case Cons(left, right):
chunks.append(chunk.with_document(right))
chunks.append(chunk.with_document(left))
@ -292,12 +311,14 @@ class Matcher:
elif name[0] == "n":
replace = self.newline_replace[name]
print(f"!!!! {name} -> {repr(replace)}")
child = cons(child, NewLine(replace))
elif name[0] == "p":
child = cons(NewLine(""), child)
elif name[0] == "f":
child = cons(child, ForceBreak())
else:
pass # Reducing a transparent rule probably.
@ -375,8 +396,8 @@ class Printer:
visited: set[str] = set()
group_count = 0
indent_amounts: dict[str, int] = {}
done_newline = False
newline_map: dict[str, str] = {}
done_forced_break = False
def compile_nonterminal(name: str, rule: parser.NonTerminal):
if name not in visited:
@ -388,7 +409,7 @@ class Printer:
def compile_production(production: parser.FlattenedWithMetadata) -> list[str]:
nonlocal group_count
nonlocal indent_amounts
nonlocal done_newline
nonlocal done_forced_break
result = []
for item in production:
@ -439,6 +460,13 @@ class Printer:
tx_children.append(newline_rule_name)
if pretty.forced_break:
if not done_forced_break:
generated_grammar.append(("forced_break", []))
done_forced_break = True
tx_children.append("forced_break")
# If it turned out to have formatting meta then we will
# have replaced or augmented the translated children
# appropriately. Otherwise, if it's highlighting meta or