Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add hex underscore fmt rule #6417

Merged
merged 3 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion crates/config/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ pub struct FormatterConfig {
pub quote_style: QuoteStyle,
/// Style of underscores in number literals
pub number_underscore: NumberUnderscore,
/// Style of underscores in hex literals
pub hex_underscore: HexUnderscore,
/// Style of single line blocks in statements
pub single_line_statement_blocks: SingleLineBlockStyle,
/// Print space in state variable, function and modifier `override` attribute
Expand All @@ -44,16 +46,70 @@ pub enum IntTypes {
}

/// Style of underscores in number literals
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum NumberUnderscore {
/// Use the underscores defined in the source code
#[default]
Preserve,
/// Remove all underscores
Remove,
/// Add an underscore every thousand, if greater than 9999
/// e.g. 1000 -> 1000 and 10000 -> 10_000
Thousands,
}

impl NumberUnderscore {
/// Returns true if the option is `Preserve`
#[inline]
pub fn is_preserve(self) -> bool {
matches!(self, NumberUnderscore::Preserve)
}

/// Returns true if the option is `Remove`
#[inline]
pub fn is_remove(self) -> bool {
matches!(self, NumberUnderscore::Remove)
}

/// Returns true if the option is `Remove`
#[inline]
pub fn is_thousands(self) -> bool {
matches!(self, NumberUnderscore::Thousands)
}
}

/// Style of underscores in hex literals
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum HexUnderscore {
/// Use the underscores defined in the source code
Preserve,
/// Remove all underscores
#[default]
Remove,
/// Add underscore as separator between byte boundaries
Bytes,
}

impl HexUnderscore {
/// Returns true if the option is `Preserve`
#[inline]
pub fn is_preserve(self) -> bool {
matches!(self, HexUnderscore::Preserve)
}

/// Returns true if the option is `Remove`
#[inline]
pub fn is_remove(self) -> bool {
matches!(self, HexUnderscore::Remove)
}

/// Returns true if the option is `Remove`
#[inline]
pub fn is_bytes(self) -> bool {
matches!(self, HexUnderscore::Bytes)
}
}

/// Style of string quotes
Expand Down Expand Up @@ -114,6 +170,7 @@ impl Default for FormatterConfig {
multiline_func_header: MultilineFuncHeaderStyle::AttributesFirst,
quote_style: QuoteStyle::Double,
number_underscore: NumberUnderscore::Preserve,
hex_underscore: HexUnderscore::Remove,
single_line_statement_blocks: SingleLineBlockStyle::Preserve,
override_spacing: false,
wrap_comments: false,
Expand Down
38 changes: 32 additions & 6 deletions crates/fmt/src/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ use crate::{
solang_ext::{pt::*, *},
string::{QuoteState, QuotedStringExt},
visit::{Visitable, Visitor},
FormatterConfig, InlineConfig, IntTypes, NumberUnderscore,
FormatterConfig, InlineConfig, IntTypes,
};
use alloy_primitives::Address;
use foundry_config::fmt::{MultilineFuncHeaderStyle, SingleLineBlockStyle};
use foundry_config::fmt::{HexUnderscore, MultilineFuncHeaderStyle, SingleLineBlockStyle};
use itertools::{Either, Itertools};
use solang_parser::pt::ImportPath;
use std::{fmt::Write, str::FromStr};
Expand Down Expand Up @@ -1304,7 +1304,7 @@ impl<'a, W: Write> Formatter<'a, W> {
let config = self.config.number_underscore;

// get source if we preserve underscores
let (value, fractional, exponent) = if matches!(config, NumberUnderscore::Preserve) {
let (value, fractional, exponent) = if config.is_preserve() {
let source = &self.source[loc.start()..loc.end()];
// Strip unit
let (source, _) = source.split_once(' ').unwrap_or((source, ""));
Expand Down Expand Up @@ -1336,7 +1336,7 @@ impl<'a, W: Write> Formatter<'a, W> {
exp = exp.trim().trim_start_matches('0');

let add_underscores = |string: &str, reversed: bool| -> String {
if !matches!(config, NumberUnderscore::Thousands) || string.len() < 5 {
if !config.is_thousands() || string.len() < 5 {
return string.to_string()
}
if reversed {
Expand Down Expand Up @@ -1377,6 +1377,32 @@ impl<'a, W: Write> Formatter<'a, W> {
self.write_unit(unit)
}

/// Write and hex literals according to the configuration.
fn write_hex_literal(&mut self, lit: &HexLiteral) -> Result<()> {
let HexLiteral { loc, hex } = lit;
match self.config.hex_underscore {
HexUnderscore::Remove => self.write_quoted_str(*loc, Some("hex"), hex),
HexUnderscore::Preserve => {
let quote = &self.source[loc.start()..loc.end()].trim_start_matches("hex");
// source is always quoted so we remove the quotes first so we can adhere to the
// configured quoting style
let hex = &quote[1..quote.len() - 1];
self.write_quoted_str(*loc, Some("hex"), hex)
}
HexUnderscore::Bytes => {
// split all bytes
let hex = hex
.chars()
.chunks(2)
.into_iter()
.map(|chunk| chunk.collect::<String>())
.collect::<Vec<_>>()
.join("_");
self.write_quoted_str(*loc, Some("hex"), &hex)
}
}
}

/// Write built-in unit.
fn write_unit(&mut self, unit: &mut Option<Identifier>) -> Result<()> {
if let Some(unit) = unit {
Expand Down Expand Up @@ -2061,8 +2087,8 @@ impl<'a, W: Write> Visitor for Formatter<'a, W> {
}
}
Expression::HexLiteral(vals) => {
for HexLiteral { loc, hex } in vals {
self.write_quoted_str(*loc, Some("hex"), hex)?;
for val in vals {
self.write_hex_literal(val)?;
}
}
Expression::AddressLiteral(loc, val) => {
Expand Down
10 changes: 10 additions & 0 deletions crates/fmt/testdata/HexUnderscore/bytes.fmt.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// config: hex_underscore = "bytes"
contract HexLiteral {
function test() external {
hex"01_23_00_00";
hex"01_23_00_00";
hex"01_23_00_00";
hex"";
hex"60_01_60_02_53";
}
}
9 changes: 9 additions & 0 deletions crates/fmt/testdata/HexUnderscore/fmt.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
contract HexLiteral {
function test() external {
hex"01230000";
hex"01230000";
hex"01230000";
hex"";
hex"6001600253";
}
}
9 changes: 9 additions & 0 deletions crates/fmt/testdata/HexUnderscore/original.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
contract HexLiteral {
function test() external {
hex"0123_0000";
hex"01230000";
hex"0123_00_00";
hex"";
hex"6001_6002_53";
}
}
10 changes: 10 additions & 0 deletions crates/fmt/testdata/HexUnderscore/preserve.fmt.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// config: hex_underscore = "preserve"
contract HexLiteral {
function test() external {
hex"0123_0000";
hex"01230000";
hex"0123_00_00";
hex"";
hex"6001_6002_53";
}
}
10 changes: 10 additions & 0 deletions crates/fmt/testdata/HexUnderscore/remove.fmt.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// config: hex_underscore = "remove"
contract HexLiteral {
function test() external {
hex"01230000";
hex"01230000";
hex"01230000";
hex"";
hex"6001600253";
}
}
26 changes: 26 additions & 0 deletions crates/fmt/testdata/NumberLiteralUnderscore/preserve.fmt.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// config: number_underscore = "preserve"
contract NumberLiteral {
function test() external {
1;
123_000;
1_2e345_678;
-1;
2e-10;
0.1;
1.3;
2.5e1;
1.23454;
1.2e34_5_678;
134411.2e34_5_678;
13431.134112e34_135_678;
13431.0134112;
13431.134112e-139_3141340;
134411.2e34_5_6780;
13431.134112e34_135_6780;
0.134112;
1.0;
13431.134112e-139_3141340;
123e456;
1_000;
}
}
1 change: 1 addition & 0 deletions crates/fmt/tests/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ test_directories! {
IntTypes,
InlineDisable,
NumberLiteralUnderscore,
HexUnderscore,
FunctionCall,
TrailingComma,
PragmaDirective,
Expand Down