Skip to content

Commit

Permalink
feat: add hex underscore fmt rule
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse committed Nov 24, 2023
1 parent 55dd5de commit 4c1b333
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 7 deletions.
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
#[default]
Preserve,
/// Remove all underscores
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::Preserve,
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"0123_0000";
hex"01230000";
hex"0123_00_00";
hex"";
hex"6001_6002_53";
}
}
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

0 comments on commit 4c1b333

Please sign in to comment.