///|
/// The compiler's `statements`.
fn Formatter::statements(
self : Formatter,
statements : ArrayView[@ast.Statement],
) -> @pretty.Doc raise FormatError {
let mut previous_position = 0
let count = statements.length()
let documents = []
for i, statement in statements {
let preceding_newline = self.pop_empty_lines(previous_position + 1)
if i != 0 && preceding_newline {
documents.push(two_lines_doc)
} else if i != 0 {
documents.push(line_doc)
}
previous_position = statement.location().end
documents.push(group(self.statement(statement)))
if statement is Use(_) && i == count - 1 {
documents.push(line_doc)
documents.push(t("todo"))
}
}
if count == 1 && statements[0] is Expression(_) {
@pretty.concat(documents)
} else {
@pretty.force_break(@pretty.concat(documents))
}
}
///|
/// The compiler's `statement`. It spends no fuel of its own: the expression
/// inside it does, so the formatter's depth per nesting level equals the
/// parser's (a block is one level, not two).
fn Formatter::statement(
self : Formatter,
statement : @ast.Statement,
) -> @pretty.Doc raise FormatError {
match statement {
Expression(e) => self.expr(e)
Assignment(a) => self.assignment(a)
Use(u) => self.use_(u)
Assert(a) => self.assert_(a)
}
}
///|
/// The compiler's `assignment`.
fn Formatter::assignment(
self : Formatter,
assignment : @ast.Assignment,
) -> @pretty.Doc raise FormatError {
let comments = self.pop_comments(assignment.location.start)
let _ = self.pop_empty_lines(assignment.pattern.location().end)
let (keyword, message) = match assignment.kind {
Let | Generated => (t("let "), None)
Assert(message~, ..) => (t("let assert "), message)
}
let pattern = self.pattern(assignment.pattern)
let annotation = match assignment.annotation {
Some(ann) => t(": ") + self.type_ast(ann)
None => @pretty.empty()
}
let doc = keyword +
group(pattern + annotation) +
t(" =") +
self.assigned_value(assignment.value)
commented(
self.append_as_message_expression(doc, Expression, message),
comments[:],
)
}
///|
/// The compiler's `case_clause_value`: the value after `->` or `=`.
fn Formatter::case_clause_value(
self : Formatter,
expression : @ast.Expr,
) -> @pretty.Doc raise FormatError {
let doc = match expression {
Fn(..) | List(..) | Tuple(..) | BitArray(..) => {
let expression_comments = self.pop_comments(expression.location().start)
let expression_doc = self.expr(expression)
match printed_comments(expression_comments[:], true) {
Some(c) => nest(line_doc + c + expression_doc)
None => t(" ") + expression_doc
}
}
Case(..) => nest(line_doc + self.expr(expression))
Block(statements~, location~) =>
t(" ") + self.block(location, statements, true)
_ => nest(breakable_space + group(self.expr(expression)))
}
group(@pretty.next_break_fits(doc, Disabled))
}
///|
/// The compiler's `assigned_value`.
fn Formatter::assigned_value(
self : Formatter,
expression : @ast.Expr,
) -> @pretty.Doc raise FormatError {
match expression {
Case(..) => group(t(" ") + self.expr(expression))
_ => self.case_clause_value(expression)
}
}
///|
/// The compiler's `use_`.
fn Formatter::use_(
self : Formatter,
use_ : @ast.Use,
) -> @pretty.Doc raise FormatError {
let comments = self.pop_comments(use_.location.start)
let call = group(
if is_call(use_.call) {
t(" ") + self.expr(use_.call)
} else {
nest(breakable_space + self.expr(use_.call))
},
)
let doc = if use_.assignments.is_empty() {
t("use <-") + call
} else {
let assignments = []
for a in use_.assignments {
let pattern = self.pattern(a.pattern)
let annotation = match a.annotation {
Some(ann) => t(": ") + self.type_ast(ann)
None => @pretty.empty()
}
assignments.push(group(pattern + annotation))
}
let left = group(
nest(t("use") + breakable_space + @pretty.join(assignments, comma_break)) +
breakable_space,
)
group(left + t("<-") + call)
}
commented(doc, comments[:])
}
///|
/// The compiler's `assert`.
fn Formatter::assert_(
self : Formatter,
assert_ : @ast.Assert,
) -> @pretty.Doc raise FormatError {
let comments = self.pop_comments(assert_.location.start)
let expression = if is_binop_expr(assert_.value) || is_pipeline(assert_.value) {
nest(self.expr(assert_.value))
} else {
self.expr(assert_.value)
}
let doc = self.append_as_message_expression(
expression,
Expression,
assert_.message,
)
commented(t("assert ") + doc, comments[:])
}
///|
/// The compiler's `block`.
fn Formatter::block(
self : Formatter,
location : @span.SrcSpan,
statements : ArrayView[@ast.Statement],
force_breaks : Bool,
) -> @pretty.Doc raise FormatError {
let statements_doc = nest(breakable_space + self.statements(statements))
let trailing = printed_comments(self.pop_comments(location.end)[:], false)
let block_doc = match trailing {
Some(c) =>
@pretty.force_break(
t("{") + statements_doc + nest(line_doc) + nest(c) + line_doc + t("}"),
)
None => t("{") + statements_doc + breakable_space + t("}")
}
if force_breaks {
group(@pretty.force_break(block_doc))
} else {
group(block_doc)
}
}