[wadler] Cons has a list of documents in it

I think I want to start thinking about "leftmost" and "rightmost" and
it's just easier and faster if cons has an actual list in it instead
of dotted pairs.
This commit is contained in:
John Doty 2024-09-15 08:12:30 -07:00
parent d5ccd5b147
commit 9d55588a35
3 changed files with 38 additions and 28 deletions

View file

@ -558,8 +558,8 @@ class Harness:
self.format_document(lines, doc.resolve(), indent) self.format_document(lines, doc.resolve(), indent)
case wadler.Cons(): case wadler.Cons():
self.format_document(lines, doc.left, indent) for child in doc.docs:
self.format_document(lines, doc.right, indent) self.format_document(lines, child, indent)
case wadler.Marker(): case wadler.Marker():
append("Marker") append("Marker")

View file

@ -13,8 +13,7 @@ from . import runtime
@dataclasses.dataclass(frozen=True) @dataclasses.dataclass(frozen=True)
class Cons: class Cons:
left: "Document" docs: list["Document"]
right: "Document"
@dataclasses.dataclass(frozen=True) @dataclasses.dataclass(frozen=True)
@ -73,14 +72,19 @@ Document = None | Text | Literal | NewLine | ForceBreak | Cons | Indent | Group
def cons(*documents: Document) -> Document: def cons(*documents: Document) -> Document:
result = None if len(documents) == 0:
for doc in documents: return None
if result is None:
result = doc
elif doc is not None:
result = Cons(result, doc)
return result result = []
for document in documents:
if isinstance(document, Cons):
result.extend(document.docs)
elif document is not None:
result.append(document)
if len(result) == 0:
return None
return Cons(result)
def group(document: Document) -> Document: def group(document: Document) -> Document:
@ -174,9 +178,8 @@ def layout_document(doc: Document, width: int, indent: str) -> DocumentLayout:
# line and yes, whatever you were asking about has fit. # line and yes, whatever you were asking about has fit.
return not chunk.flat return not chunk.flat
case Cons(left, right): case Cons(docs):
stack.append(chunk.with_document(right)) stack.extend(chunk.with_document(doc) for doc in reversed(docs))
stack.append(chunk.with_document(left))
case Lazy(): case Lazy():
stack.append(chunk.with_document(chunk.doc.resolve())) stack.append(chunk.with_document(chunk.doc.resolve()))
@ -236,9 +239,8 @@ def layout_document(doc: Document, width: int, indent: str) -> DocumentLayout:
output.append("\n" + (chunk.indent * indent)) output.append("\n" + (chunk.indent * indent))
column = chunk.indent * len(indent) column = chunk.indent * len(indent)
case Cons(left, right): case Cons(docs):
chunks.append(chunk.with_document(right)) chunks.extend(chunk.with_document(doc) for doc in reversed(docs))
chunks.append(chunk.with_document(left))
case Indent(amount, doc): case Indent(amount, doc):
chunks.append(chunk.with_document(doc, and_indent=amount)) chunks.append(chunk.with_document(doc, and_indent=amount))
@ -264,20 +266,25 @@ def layout_document(doc: Document, width: int, indent: str) -> DocumentLayout:
def resolve_document(doc: Document) -> Document: def resolve_document(doc: Document) -> Document:
match doc: match doc:
case Cons(left, right): case Cons(docs):
lr = resolve_document(left) docs = [resolve_document(d) for d in docs]
rr = resolve_document(right) return cons(*docs)
if lr is not left or rr is not right:
return cons(lr, rr)
else:
return doc
case Lazy(_): case Lazy(_):
return resolve_document(doc.resolve()) return resolve_document(doc.resolve())
case _: case Group(doc):
return group(resolve_document(doc))
case Marker(child, meta):
return Marker(resolve_document(child), meta)
case Text() | Literal() | NewLine() | ForceBreak() | Indent() | None:
return doc return doc
case _:
typing.assert_never(doc)
def child_to_name(child: runtime.Tree | runtime.TokenValue) -> str: def child_to_name(child: runtime.Tree | runtime.TokenValue) -> str:
if isinstance(child, runtime.Tree): if isinstance(child, runtime.Tree):

View file

@ -11,8 +11,6 @@ from parser.parser import (
alt, alt,
indent, indent,
seq, seq,
Rule,
Assoc,
sp, sp,
nl, nl,
br, br,
@ -129,9 +127,14 @@ def flatten_document(doc: wadler.Document, src: str) -> list:
case wadler.Lazy(): case wadler.Lazy():
return flatten_document(doc.resolve(), src) return flatten_document(doc.resolve(), src)
case wadler.Cons(): case wadler.Cons():
return flatten_document(doc.left, src) + flatten_document(doc.right, src) result = []
for d in doc.docs:
result += flatten_document(d, src)
return result
case None: case None:
return [] return []
case wadler.Marker():
return [f"<marker {repr(doc.meta)}>", flatten_document(doc.child, src)]
case _: case _:
typing.assert_never(doc) typing.assert_never(doc)