///|
fn is_discard(p : @ast.Pattern) -> Bool {
p is Discard(..)
}
///|
/// The compiler's `pattern_constructor`.
fn Formatter::pattern_constructor(
self : Formatter,
name : String,
arguments : ArrayView[@ast.CallArg[@ast.Pattern]],
module_ : @ast.SpannedString?,
spread : @span.SrcSpan?,
location : @span.SrcSpan,
) -> @pretty.Doc raise FormatError {
let is_breakable = (p : @ast.Pattern) => {
match p {
Tuple(..) | List(..) | BitArray(..) => true
Constructor(arguments~, ..) => !arguments.is_empty()
_ => false
}
}
let name_doc = match module_ {
Some(m) => t(m.name) + t(".") + t(name)
None => t(name)
}
if arguments.is_empty() && spread is Some(_) {
name_doc + t("(..)")
} else if arguments.is_empty() {
name_doc
} else if spread is Some(_) {
let docs = []
for a in arguments {
docs.push(self.pattern_call_arg(a))
}
group(name_doc + self.wrap_arguments_with_spread(docs, location.end))
} else if arguments.length() == 1 && is_breakable(arguments[0].value) {
group(name_doc + t("(") + self.pattern_call_arg(arguments[0]) + t(")"))
} else {
let docs = []
for a in arguments {
docs.push(self.pattern_call_arg(a))
}
group(name_doc + self.wrap_arguments(docs, location.end))
}
}
///|
/// The compiler's `pattern`. One unit of fuel per nesting level.
fn Formatter::pattern(
self : Formatter,
pattern : @ast.Pattern,
) -> @pretty.Doc raise FormatError {
self.nested(op_format, () => {
let comments = self.pop_comments(pattern.location().start)
let doc = match pattern {
Int(value~, ..) => int(value)
Float(value~, ..) => float(value)
String(value~, ..) => string(value)
Variable(name~, ..) => t(name)
BitArraySize(size) => self.bit_array_size(size)
Assign(name~, pattern~, ..) =>
if is_discard(pattern) {
t(name)
} else {
self.pattern(pattern) + t(" as ") + t(name)
}
Discard(name~, ..) => t(name)
List(elements~, tail~, ..) => self.list_pattern(elements, tail)
Constructor(name~, arguments~, module_~, spread~, location~, ..) =>
self.pattern_constructor(name, arguments, module_, spread, location)
Tuple(elements~, location~) => {
let docs = []
for e in elements {
docs.push(self.pattern(e))
}
group(t("#") + self.wrap_arguments(docs, location.end))
}
BitArray(segments~, location~) => {
let docs = []
for s in segments {
docs.push(bit_array_segment(s, p => self.pattern(p)))
}
self.bit_array(docs, FitOnePerLine, location)
}
StringPrefix(
left_side_string~,
right_side_assignment~,
left_side_assignment~,
..
) => {
let left = string(left_side_string)
let right = match right_side_assignment {
Variable(name) | Discard(name) => t(name)
}
match left_side_assignment {
Some(a) => left + t(" as ") + t(a.name) + t(" <> ") + right
None => left + t(" <> ") + right
}
}
}
commented(doc, comments[:])
})
}
///|
/// The compiler's `bit_array_size`.
fn Formatter::bit_array_size(
self : Formatter,
size : @ast.BitArraySize,
) -> @pretty.Doc raise FormatError {
self.nested(op_format, () => {
match size {
Int(value~, ..) => int(value)
Variable(name~, ..) => t(name)
BinaryOperator(left~, right~, operator~, ..) => {
// The left spine in a loop: the parser accepts a chain of any
// length, so no fuel and no stack per link.
let ops = [operator]
let rights = [right]
let mut leaf = left
while leaf is BinaryOperator(operator=o, left=l, right=r, ..) {
ops.push(o)
rights.push(r)
leaf = l
}
let mut doc = self.bit_array_size(leaf)
for k = ops.length() - 1; k >= 0; k = k - 1 {
let op = match ops[k] {
Add => t(" + ")
Subtract => t(" - ")
Multiply => t(" * ")
Divide => t(" / ")
Remainder => t(" % ")
}
doc = doc + op + self.bit_array_size(rights[k])
}
doc
}
Block(inner~, ..) => t("{ ") + self.bit_array_size(inner) + t(" }")
}
})
}
///|
/// The compiler's `list_pattern`.
fn Formatter::list_pattern(
self : Formatter,
elements : ArrayView[@ast.Pattern],
tail : @ast.TailPattern?,
) -> @pretty.Doc raise FormatError {
if elements.is_empty() {
return match tail {
Some(tl) => self.pattern(tl.pattern)
None => t("[]")
}
}
let docs = []
for e in elements {
docs.push(self.pattern(e))
}
let doc = open_square_break + @pretty.join(docs, comma_break)
let doc = match tail {
None => nest(doc) + trailing_comma_break
Some(tl) => {
let comments = self.pop_comments(tl.pattern.location().start)
let tail_doc = if is_discard(tl.pattern) {
t("..")
} else {
t("..") + self.pattern(tl.pattern)
}
let tail_doc = commented(tail_doc, comments[:])
nest(doc + comma_break + tail_doc) + empty_break
}
}
group(doc + t("]"))
}
///|
/// The compiler's `pattern_call_arg`.
fn Formatter::pattern_call_arg(
self : Formatter,
argument : @ast.CallArg[@ast.Pattern],
) -> @pretty.Doc raise FormatError {
self.format_call_arg(argument, p => p.location(), p => self.pattern(p))
}