diff --git a/crates/fmt/src/state/common.rs b/crates/fmt/src/state/common.rs index 085916e60a98e..8ea7e6d914be2 100644 --- a/crates/fmt/src/state/common.rs +++ b/crates/fmt/src/state/common.rs @@ -588,7 +588,7 @@ impl<'ast> State<'_, 'ast> { self.s.offset(offset); } } else if style.is_isolated() { - self.print_sep_unhandled(Separator::Space); + self.print_sep_unhandled(Separator::Hardbreak); self.s.offset(offset); } } diff --git a/crates/fmt/src/state/mod.rs b/crates/fmt/src/state/mod.rs index 878a19d882e99..15959173ad674 100644 --- a/crates/fmt/src/state/mod.rs +++ b/crates/fmt/src/state/mod.rs @@ -250,11 +250,17 @@ impl<'sess> State<'sess, '_> { self.has_crlf && self.char_at(self.cursor.pos) == Some('\r') } + /// Computes the space left, bounded by the max space left. fn space_left(&self) -> usize { - std::cmp::min( - self.s.space_left(), - self.config.line_length.saturating_sub(self.block_depth * self.config.tab_width), - ) + std::cmp::min(self.s.space_left(), self.max_space_left(0)) + } + + /// Computes the maximum space left given the context information available: + /// `block_depth`, `tab_width`, and a user-defined unavailable size `prefix_len`. + fn max_space_left(&self, prefix_len: usize) -> usize { + self.config + .line_length + .saturating_sub(self.block_depth * self.config.tab_width + prefix_len) } fn break_offset_if_not_bol(&mut self, n: usize, off: isize, search: bool) { diff --git a/crates/fmt/src/state/sol.rs b/crates/fmt/src/state/sol.rs index 7303d6fb7d3d3..2728a3c85bdd3 100644 --- a/crates/fmt/src/state/sol.rs +++ b/crates/fmt/src/state/sol.rs @@ -1854,7 +1854,7 @@ impl<'ast> State<'_, 'ast> { _ = self.handle_span(self.cursor.span(span.lo()), false); if !self.handle_span(span.until(block.span), false) { self.cursor.advance_to(span.lo(), true); - self.print_word("assembly "); + self.print_word("assembly "); // 9 chars if let Some(dialect) = dialect { self.print_ast_str_lit(dialect); self.print_sep(Separator::Nbsp); @@ -1871,7 +1871,7 @@ impl<'ast> State<'_, 'ast> { self.print_sep(Separator::Nbsp); } } - self.print_yul_block(block, block.span, false); + self.print_yul_block(block, block.span, false, 9); } /// Prints a multiple-variable declaration with a single initializer expression, diff --git a/crates/fmt/src/state/yul.rs b/crates/fmt/src/state/yul.rs index 120d98312e0b2..0f973624bf9ec 100644 --- a/crates/fmt/src/state/yul.rs +++ b/crates/fmt/src/state/yul.rs @@ -26,11 +26,12 @@ impl<'ast> State<'_, 'ast> { } match kind { - yul::StmtKind::Block(stmts) => self.print_yul_block(stmts, span, false), + yul::StmtKind::Block(stmts) => self.print_yul_block(stmts, span, false, 0), yul::StmtKind::AssignSingle(path, expr) => { self.print_path(path, false); self.word(" := "); self.neverbreak(); + self.cursor.advance_to(expr.span.lo(), self.cursor.enabled); self.print_yul_expr(expr); } yul::StmtKind::AssignMulti(paths, expr_call) => { @@ -53,30 +54,30 @@ impl<'ast> State<'_, 'ast> { } yul::StmtKind::Expr(expr_call) => self.print_yul_expr(expr_call), yul::StmtKind::If(expr, stmts) => { - self.word("if "); + self.print_word("if "); // 3 chars self.print_yul_expr(expr); - self.nbsp(); - self.print_yul_block(stmts, span, false); + self.nbsp(); // 1 char + self.print_yul_block(stmts, span, false, 4 + self.estimate_size(expr.span)); } yul::StmtKind::For(yul::StmtFor { init, cond, step, body }) => { self.ibox(0); - self.word("for "); - self.print_yul_block(init, init.span, false); + self.print_word("for "); // 4 chars + self.print_yul_block(init, init.span, false, 4); self.space(); self.print_yul_expr(cond); self.space(); - self.print_yul_block(step, step.span, false); + self.print_yul_block(step, step.span, false, 0); self.space(); - self.print_yul_block(body, body.span, false); + self.print_yul_block(body, body.span, false, 0); self.end(); } yul::StmtKind::Switch(yul::StmtSwitch { selector, cases }) => { - self.word("switch "); + self.print_word("switch "); self.print_yul_expr(selector); self.print_trailing_comment(selector.span.hi(), None); @@ -88,7 +89,7 @@ impl<'ast> State<'_, 'ast> { constant.span.lo(), CommentConfig::default().mixed_prev_space(), ); - self.word("case "); + self.print_word("case "); self.print_lit_yul(constant); self.nbsp(); } else { @@ -96,16 +97,16 @@ impl<'ast> State<'_, 'ast> { body.span.lo(), CommentConfig::default().mixed_prev_space(), ); - self.word("default "); + self.print_word("default "); } - self.print_yul_block(body, *span, false); + self.print_yul_block(body, *span, false, 0); self.print_trailing_comment(selector.span.hi(), None); } } - yul::StmtKind::Leave => self.word("leave"), - yul::StmtKind::Break => self.word("break"), - yul::StmtKind::Continue => self.word("continue"), + yul::StmtKind::Leave => self.print_word("leave"), + yul::StmtKind::Break => self.print_word("break"), + yul::StmtKind::Continue => self.print_word("continue"), yul::StmtKind::FunctionDef(func) => { let yul::Function { name, parameters, returns, body } = func; let params_hi = parameters @@ -116,7 +117,7 @@ impl<'ast> State<'_, 'ast> { self.cbox(0); self.s.ibox(0); - self.word("function "); + self.print_word("function "); self.print_ident(name); self.print_tuple( parameters, @@ -143,12 +144,12 @@ impl<'ast> State<'_, 'ast> { ); } self.end(); - self.print_yul_block(body, span, skip_opening_brace); + self.print_yul_block(body, span, skip_opening_brace, 0); self.end(); } yul::StmtKind::VarDecl(idents, expr) => { self.s.ibox(self.ind); - self.word("let "); + self.print_word("let "); self.commasep( idents, stmt.span.lo(), @@ -158,7 +159,7 @@ impl<'ast> State<'_, 'ast> { ListFormat::consistent(), ); if let Some(expr) = expr { - self.word(" :="); + self.print_word(" :="); self.space(); self.print_yul_expr(expr); } @@ -201,6 +202,7 @@ impl<'ast> State<'_, 'ast> { block: &'ast yul::Block<'ast>, span: Span, skip_opening_brace: bool, + prefix_len: usize, ) { if self.handle_span(span, false) { return; @@ -210,9 +212,15 @@ impl<'ast> State<'_, 'ast> { self.print_word("{"); } - let can_inline_block = block.len() <= 1 - && !self.is_multiline_yul_block(block) - && self.estimate_size(block.span) <= self.space_left(); + let can_inline_block = if block.len() <= 1 && !self.is_multiline_yul_block(block) { + if self.max_space_left(prefix_len) == 0 { + self.estimate_size(block.span) + self.config.tab_width < self.space_left() + } else { + self.estimate_size(block.span) + prefix_len < self.space_left() + } + } else { + false + }; if can_inline_block { self.neverbreak(); self.print_block_inner( diff --git a/crates/fmt/testdata/Yul/fmt.sol b/crates/fmt/testdata/Yul/fmt.sol index 3db955e48ea69..26ae8f2eb884d 100644 --- a/crates/fmt/testdata/Yul/fmt.sol +++ b/crates/fmt/testdata/Yul/fmt.sol @@ -228,7 +228,28 @@ contract Yul { result, p := parseValue(input, 0, p, e) mstore8(e, c) // Restore the original char at the end. } - if or(lt(p, e), iszero(result)) { fail() } + } + } + + assembly { + function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut { + _pOut := pIn_ + if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'. + if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'. + let c_ := chr(_pOut) + _pOut := add(_pOut, 1) + if iszero(eq(c_, 48)) { + _pOut := skip0To9s(_pOut, end_, 0) + } // Not '0'. + if eq(chr(_pOut), 46) { + _pOut := skip0To9s(add(_pOut, 1), end_, 1) + } // '.'. + let t_ := mload(_pOut) + if eq(or(0x20, byte(0, t_)), 101) { + // forgefmt: disable-next-item + _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'. + add(_pOut, 1)), end_, 1) + } } } } diff --git a/crates/fmt/testdata/Yul/original.sol b/crates/fmt/testdata/Yul/original.sol index 11347d492e911..1fba402759726 100644 --- a/crates/fmt/testdata/Yul/original.sol +++ b/crates/fmt/testdata/Yul/original.sol @@ -171,7 +171,24 @@ contract Yul { result, p := parseValue(input, 0, p, e) mstore8(e, c) // Restore the original char at the end. } - if or(lt(p, e), iszero(result)) { fail() } + } + } + + assembly { + function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut { + _pOut := pIn_ + if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'. + if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'. + let c_ := chr(_pOut) + _pOut := add(_pOut, 1) + if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'. + if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'. + let t_ := mload(_pOut) + if eq(or(0x20, byte(0, t_)), 101) { + // forgefmt: disable-next-item + _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'. + add(_pOut, 1)), end_, 1) + } } } }