feat(fstring): add sign-aware alignment
This commit is contained in:
@@ -55,5 +55,12 @@ print(f"{"test":<<9}")
|
||||
print(f"{"test":>>9}")
|
||||
print(f"{"test":^^9}")
|
||||
print()
|
||||
print(f"{d2:8}")
|
||||
print(f"{d2:08}")
|
||||
print(f"{d2:<<8}")
|
||||
print(f"{d2:>>8}")
|
||||
print(f"{d2:^^8}")
|
||||
print(f"{d2:==8}")
|
||||
print()
|
||||
|
||||
print("Complex")
|
||||
@@ -83,6 +83,8 @@ class FormatSpecLexer:
|
||||
self.add_token(TokenType.RIGHT)
|
||||
case "^":
|
||||
self.add_token(TokenType.CENTER)
|
||||
case "=":
|
||||
self.add_token(TokenType.EQUAL)
|
||||
case "+":
|
||||
self.add_token(TokenType.PLUS)
|
||||
case "-":
|
||||
@@ -113,6 +115,8 @@ class FormatSpecLexer:
|
||||
self.add_token(TokenType.T_PCT)
|
||||
case ".":
|
||||
self.add_token(TokenType.DOT)
|
||||
case "0":
|
||||
self.add_token(TokenType.ZERO)
|
||||
case _:
|
||||
if char.isdigit():
|
||||
self.scan_number()
|
||||
|
||||
@@ -23,13 +23,14 @@ class FormatSpecParser:
|
||||
ALIGNMENT: set[TokenType] = {
|
||||
TokenType.LEFT,
|
||||
TokenType.RIGHT,
|
||||
TokenType.CENTER
|
||||
TokenType.CENTER,
|
||||
TokenType.EQUAL,
|
||||
}
|
||||
|
||||
SIGN: set[TokenType] = {
|
||||
TokenType.PLUS,
|
||||
TokenType.MINUS,
|
||||
TokenType.SPACE
|
||||
TokenType.SPACE,
|
||||
}
|
||||
|
||||
def __init__(self, tokens: list[Token]):
|
||||
@@ -93,9 +94,12 @@ class FormatSpecParser:
|
||||
if self.match(*self.SIGN):
|
||||
sign = self.previous()
|
||||
|
||||
zfill: bool = self.match(TokenType.ZERO)
|
||||
|
||||
return FormatSpecOptions(
|
||||
alignment=alignment,
|
||||
sign=sign
|
||||
sign=sign,
|
||||
zfill=zfill
|
||||
)
|
||||
|
||||
def alignment(self) -> Optional[FormatSpecAlignment]:
|
||||
|
||||
@@ -14,6 +14,7 @@ class FormatSpecAlignment:
|
||||
class FormatSpecOptions:
|
||||
alignment: Optional[FormatSpecAlignment]
|
||||
sign: Optional[Token]
|
||||
zfill: bool
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
||||
@@ -69,8 +69,7 @@ class StringFormatter:
|
||||
else:
|
||||
fmt_type, obj = self.guess_type(obj)
|
||||
|
||||
align_side: TokenType = TokenType.LEFT
|
||||
fill_char: str = " "
|
||||
is_num: bool = False
|
||||
match fmt_type:
|
||||
case None:
|
||||
res = self.stringify(obj)
|
||||
@@ -78,18 +77,27 @@ 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)
|
||||
align_side = TokenType.RIGHT
|
||||
is_num = True
|
||||
case TokenType.T_FIX:
|
||||
res = self.format_float_fix(obj, spec, fmt_type)
|
||||
align_side = TokenType.RIGHT
|
||||
is_num = True
|
||||
case TokenType.T_PCT:
|
||||
res = self.format_float_fix(obj * 100, spec, TokenType.T_FIX) + "%"
|
||||
align_side = TokenType.RIGHT
|
||||
is_num = True
|
||||
case TokenType.T_SCI:
|
||||
res = self.format_float_sci(obj, spec, fmt_type)
|
||||
align_side = TokenType.RIGHT
|
||||
is_num = True
|
||||
|
||||
align_spec: Optional[FormatSpecAlignment] = spec.options.alignment
|
||||
align_side: TokenType = TokenType.LEFT
|
||||
fill_char: str = "0" if spec.options.zfill else " "
|
||||
if is_num:
|
||||
align_side = TokenType.EQUAL if spec.options.zfill else TokenType.RIGHT
|
||||
elif align_side == TokenType.EQUAL:
|
||||
# Should always be true at this point
|
||||
if align_spec is not None:
|
||||
raise PebbleRuntimeError(align_spec.align, "Sign-aware alignment is only valid for numbers.")
|
||||
|
||||
if align_spec is not None:
|
||||
align_side = align_spec.align.type
|
||||
if align_spec.fill is not None:
|
||||
@@ -190,11 +198,16 @@ class StringFormatter:
|
||||
case TokenType.LEFT:
|
||||
left = 0
|
||||
right = to_pad
|
||||
case TokenType.RIGHT:
|
||||
case TokenType.RIGHT | TokenType.EQUAL:
|
||||
left = to_pad
|
||||
right = 0
|
||||
case TokenType.CENTER:
|
||||
left = to_pad // 2
|
||||
right = to_pad - left
|
||||
|
||||
return char * left + string + char * right
|
||||
sign: str = ""
|
||||
if side == TokenType.EQUAL:
|
||||
if string.startswith(("+", "-", " ")):
|
||||
sign = string[0]
|
||||
string = string[1:]
|
||||
return sign + char * left + string + char * right
|
||||
|
||||
@@ -10,6 +10,7 @@ class TokenType(Enum):
|
||||
LEFT = auto()
|
||||
RIGHT = auto()
|
||||
CENTER = auto()
|
||||
EQUAL = auto()
|
||||
|
||||
# Sign
|
||||
PLUS = auto()
|
||||
@@ -37,6 +38,7 @@ class TokenType(Enum):
|
||||
T_PCT = auto()
|
||||
|
||||
# Misc
|
||||
ZERO = auto()
|
||||
NUMBER = auto()
|
||||
DOT = auto()
|
||||
EOF = auto()
|
||||
|
||||
Reference in New Issue
Block a user