use crate::{
formatter::{
shape::{ExprKind, LineStyle},
*,
},
utils::{
map::byte_span::{ByteSpan, LeafSpans},
{CurlyBrace, Parenthesis},
},
};
use std::fmt::Write;
use sway_ast::{
keywords::{ColonToken, DoubleDotToken, Keyword, MutToken, RefToken, Token, UnderscoreToken},
Braces, CommaToken, ExprTupleDescriptor, PathExpr, Pattern, PatternStructField, Punctuated,
};
use sway_types::{ast::Delimiter, Spanned};
impl Format for Pattern {
fn format(
&self,
formatted_code: &mut FormattedCode,
formatter: &mut Formatter,
) -> Result<(), FormatterError> {
match self {
Self::Or {
lhs,
pipe_token: _,
rhs,
} => {
lhs.format(formatted_code, formatter)?;
formatted_code.push_str(" | ");
rhs.format(formatted_code, formatter)?;
}
Self::Wildcard {
underscore_token: _,
} => formatted_code.push_str(UnderscoreToken::AS_STR),
Self::Var {
reference,
mutable,
name,
} => {
if reference.is_some() {
write!(formatted_code, "{} ", RefToken::AS_STR)?;
}
if mutable.is_some() {
write!(formatted_code, "{} ", MutToken::AS_STR)?;
}
name.format(formatted_code, formatter)?;
}
Self::AmbiguousSingleIdent(ident) => {
ident.format(formatted_code, formatter)?;
}
Self::Literal(lit) => lit.format(formatted_code, formatter)?,
Self::Constant(path) => path.format(formatted_code, formatter)?,
Self::Constructor { path, args } => {
formatter.with_shape(
formatter.shape.with_default_code_line(),
|formatter| -> Result<(), FormatterError> {
path.format(formatted_code, formatter)?;
Self::open_parenthesis(formatted_code, formatter)?;
args.get().format(formatted_code, formatter)?;
Self::close_parenthesis(formatted_code, formatter)?;
Ok(())
},
)?;
}
Self::Struct { path, fields } => {
formatter.with_shape(
formatter
.shape
.with_code_line_from(LineStyle::default(), ExprKind::Struct),
|formatter| -> Result<(), FormatterError> {
let mut buf = FormattedCode::new();
let mut temp_formatter = Formatter::default();
temp_formatter
.shape
.code_line
.update_line_style(LineStyle::Inline);
format_pattern_struct(path, fields, &mut buf, &mut temp_formatter)?;
let (field_width, body_width) =
get_field_width(fields.get(), &mut formatter.clone())?;
let expr_width = buf.chars().count();
formatter.shape.code_line.update_width(expr_width);
formatter.shape.get_line_style(
Some(field_width),
Some(body_width),
&formatter.config,
);
format_pattern_struct(path, fields, formatted_code, formatter)?;
Ok(())
},
)?;
}
Self::Tuple(args) => {
formatter.with_shape(
formatter
.shape
.with_code_line_from(LineStyle::default(), ExprKind::Collection),
|formatter| -> Result<(), FormatterError> {
let mut buf = FormattedCode::new();
let mut temp_formatter = Formatter::default();
let tuple_descriptor = args.get();
tuple_descriptor.format(&mut buf, &mut temp_formatter)?;
let body_width = buf.chars().count();
formatter.shape.code_line.update_width(body_width);
formatter
.shape
.get_line_style(None, Some(body_width), &formatter.config);
ExprTupleDescriptor::open_parenthesis(formatted_code, formatter)?;
tuple_descriptor.format(formatted_code, formatter)?;
ExprTupleDescriptor::close_parenthesis(formatted_code, formatter)?;
Ok(())
},
)?;
}
Self::Error(..) => {
return Err(FormatterError::SyntaxError);
}
}
Ok(())
}
}
impl Parenthesis for Pattern {
fn open_parenthesis(
line: &mut FormattedCode,
_formatter: &mut Formatter,
) -> Result<(), FormatterError> {
write!(line, "{}", Delimiter::Parenthesis.as_open_char())?;
Ok(())
}
fn close_parenthesis(
line: &mut FormattedCode,
_formatter: &mut Formatter,
) -> Result<(), FormatterError> {
write!(line, "{}", Delimiter::Parenthesis.as_close_char())?;
Ok(())
}
}
impl CurlyBrace for Pattern {
fn open_curly_brace(
line: &mut String,
formatter: &mut Formatter,
) -> Result<(), FormatterError> {
write!(line, " {}", Delimiter::Brace.as_open_char())?;
formatter.indent();
Ok(())
}
fn close_curly_brace(
line: &mut String,
formatter: &mut Formatter,
) -> Result<(), FormatterError> {
formatter.unindent();
match formatter.shape.code_line.line_style {
LineStyle::Inline => write!(line, "{}", Delimiter::Brace.as_close_char())?,
_ => write!(
line,
"{}{}",
formatter.indent_to_str()?,
Delimiter::Brace.as_close_char()
)?,
}
Ok(())
}
}
impl Format for PatternStructField {
fn format(
&self,
formatted_code: &mut FormattedCode,
formatter: &mut Formatter,
) -> Result<(), FormatterError> {
match self {
Self::Rest { token: _ } => {
write!(formatted_code, "{}", DoubleDotToken::AS_STR)?;
}
Self::Field {
field_name,
pattern_opt,
} => {
write!(formatted_code, "{}", field_name.as_str())?;
if let Some((_colon_token, pattern)) = pattern_opt {
write!(formatted_code, "{} ", ColonToken::AS_STR)?;
pattern.format(formatted_code, formatter)?;
}
}
}
Ok(())
}
}
fn get_field_width(
fields: &Punctuated<PatternStructField, CommaToken>,
formatter: &mut Formatter,
) -> Result<(usize, usize), FormatterError> {
let mut largest_field: usize = 0;
let mut body_width: usize = 3; for (field, _comma_token) in &fields.value_separator_pairs {
let mut field_str = FormattedCode::new();
field.format(&mut field_str, formatter)?;
let mut field_length = field_str.chars().count();
field_length += CommaToken::AS_STR.chars().count();
body_width += &field_length + 1;
if field_length > largest_field {
largest_field = field_length;
}
}
if let Some(final_value) = &fields.final_value_opt {
let mut field_str = FormattedCode::new();
final_value.format(&mut field_str, formatter)?;
let field_length = field_str.chars().count();
body_width += &field_length + 1;
if field_length > largest_field {
largest_field = field_length;
}
}
Ok((largest_field, body_width))
}
fn format_pattern_struct(
path: &PathExpr,
fields: &Braces<Punctuated<PatternStructField, CommaToken>>,
formatted_code: &mut FormattedCode,
formatter: &mut Formatter,
) -> Result<(), FormatterError> {
path.format(formatted_code, formatter)?;
Pattern::open_curly_brace(formatted_code, formatter)?;
let fields = &fields.get();
match formatter.shape.code_line.line_style {
LineStyle::Inline => fields.format(formatted_code, formatter)?,
_ => fields.format(formatted_code, formatter)?,
}
Pattern::close_curly_brace(formatted_code, formatter)?;
Ok(())
}
impl LeafSpans for Pattern {
fn leaf_spans(&self) -> Vec<ByteSpan> {
let mut collected_spans = Vec::new();
match self {
Pattern::Wildcard { underscore_token } => {
collected_spans.push(ByteSpan::from(underscore_token.span()));
}
Pattern::Or {
lhs,
pipe_token,
rhs,
} => {
collected_spans.append(&mut lhs.leaf_spans());
collected_spans.push(ByteSpan::from(pipe_token.span()));
collected_spans.append(&mut rhs.leaf_spans());
}
Pattern::Var {
reference,
mutable,
name,
} => {
if let Some(reference) = reference {
collected_spans.push(ByteSpan::from(reference.span()));
}
if let Some(mutable) = mutable {
collected_spans.push(ByteSpan::from(mutable.span()));
}
collected_spans.push(ByteSpan::from(name.span()));
}
Pattern::AmbiguousSingleIdent(ident) => {
collected_spans.push(ByteSpan::from(ident.span()));
}
Pattern::Literal(literal) => {
collected_spans.append(&mut literal.leaf_spans());
}
Pattern::Constant(constant) => {
collected_spans.append(&mut constant.leaf_spans());
}
Pattern::Constructor { path, args } => {
collected_spans.append(&mut path.leaf_spans());
collected_spans.append(&mut args.leaf_spans());
}
Pattern::Struct { path, fields } => {
collected_spans.append(&mut path.leaf_spans());
collected_spans.append(&mut fields.leaf_spans());
}
Pattern::Tuple(tuple) => {
collected_spans.append(&mut tuple.leaf_spans());
}
Pattern::Error(spans, _) => {
let mut leaf_spans = spans.iter().map(|s| ByteSpan::from(s.clone())).collect();
collected_spans.append(&mut leaf_spans)
}
}
collected_spans
}
}
impl LeafSpans for PatternStructField {
fn leaf_spans(&self) -> Vec<ByteSpan> {
let mut collected_spans = Vec::new();
match self {
PatternStructField::Rest { token } => {
collected_spans.push(ByteSpan::from(token.span()));
}
PatternStructField::Field {
field_name,
pattern_opt,
} => {
collected_spans.push(ByteSpan::from(field_name.span()));
if let Some(pattern) = pattern_opt {
collected_spans.push(ByteSpan::from(pattern.0.span()));
collected_spans.append(&mut pattern.1.leaf_spans());
}
}
}
collected_spans
}
}