From f5f8158ff16916f9395ca11ddcd675b8c5494277 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Sun, 8 Feb 2026 00:35:55 +0100 Subject: [PATCH] feat(fstring): implement scientific and percentage formatting --- examples/basic/23_format_spec.peb | 27 ++++++++++++++++++----- src/core/format_spec/string_formatter.py | 28 ++++++++++++++++++++---- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/examples/basic/23_format_spec.peb b/examples/basic/23_format_spec.peb index d260344..d980035 100644 --- a/examples/basic/23_format_spec.peb +++ b/examples/basic/23_format_spec.peb @@ -1,33 +1,48 @@ -// Basic type +print("Basic type") let a = 42 print(f"int: {a:d}; hex: {a:x}; HEX: {a:X}; oct: {a:o}; bin: {a:b}") +print() -// Grouping +print("Grouping") let b = 1234567890 print(f"{b:,}") print(f"{b:_}") +print() let c = 1234.5678 print(f"{c:,._}") print(f"{c:_.,}") +print() -// Sign +print("Sign") let d1 = 14 let d2 = -26 print(f"{d1} {d2}") print(f"{d1:+} {d2:+}") print(f"{d1:-} {d2:-}") print(f"{d1: } {d2: }") +print() -// Percentage +print("Percentage") let pts = 19 let total = 22 print(f"Correct answers: {pts/total:.2%}") +print() -// Precision +print("Precision") print(f"{c:8}") print(f"{c:8.2}") print(f"{c:.2}") print(f"{c:.8}") +print() -// Complex \ No newline at end of file +print("Scientific") +print(f"{a:e}") +print(f"{b:e}") +print(f"{c:e}") +print(f"{d1:e}") +print(f"{d2:e}") +print(f"{0:e}") +print() + +print("Complex") \ No newline at end of file diff --git a/src/core/format_spec/string_formatter.py b/src/core/format_spec/string_formatter.py index 5d301fd..deac5a9 100644 --- a/src/core/format_spec/string_formatter.py +++ b/src/core/format_spec/string_formatter.py @@ -1,3 +1,4 @@ +from math import log10, floor from typing import Any, Optional from src.core.format_spec.spec import FormatSpec @@ -75,8 +76,12 @@ class StringFormatter: res = obj case TokenType.T_BIN | TokenType.T_DEC | TokenType.T_HEX | TokenType.T_HEX_CAPS | TokenType.T_OCT: res = self.format_int(obj, spec, fmt_type) - case TokenType.T_SCI | TokenType.T_FIX | TokenType.T_PCT: - res = self.format_float(obj, spec, fmt_type) + case TokenType.T_FIX: + res = self.format_float_fix(obj, spec, fmt_type) + case TokenType.T_PCT: + res = self.format_float_fix(obj * 100, spec, TokenType.T_FIX) + "%" + case TokenType.T_SCI: + res = self.format_float_sci(obj, spec, fmt_type) if spec.number.integral.width is not None: res = self.pad(res, spec.number.integral.width) @@ -92,7 +97,7 @@ class StringFormatter: return sign + string - def format_float(self, value: float, spec: FormatSpec, fmt_type: TokenType) -> str: + def format_float_fix(self, value: float, spec: FormatSpec, fmt_type: TokenType) -> str: sign: str = self.make_sign(value, spec) value = abs(value) integer: int = int(value) @@ -100,9 +105,16 @@ class StringFormatter: integer_spec = spec.number.integral decimal_spec = spec.number.decimal + precision: Optional[int] = None + if fmt_type == TokenType.T_SCI: + precision = 6 + if decimal_spec is not None: if decimal_spec.precision is not None: - decimal = round(decimal, decimal_spec.precision) + precision = decimal_spec.precision + + if precision is not None: + decimal = round(decimal, precision) integer_str: str = self.format_int_part(integer, fmt_type, integer_spec.grouping) decimal_str: str = self.format_int_part(int(str(decimal)[2:]), fmt_type, None if decimal_spec is None else decimal_spec.grouping) @@ -111,6 +123,14 @@ class StringFormatter: return f"{sign}{integer_str}{decimal_str}" + def format_float_sci(self, value: float, spec: FormatSpec, fmt_type: TokenType) -> str: + sign: str = self.make_sign(value, spec) + value = abs(value) + mag: int = 0 if value == 0 else floor(log10(value)) + coef: float = value / (10 ** mag) + coef_str: str = self.format_float_fix(coef, spec, fmt_type) + return f"{sign}{coef_str}e{mag:+03d}" + def format_int_part(self, value: int, fmt_type: TokenType, grouping: Optional[Token]): groups: int = 4 string: str = str(value)