1111
1212from std.sys import exit
1313
14- from argmojo import Arg , Command
14+ from argmojo import Parsable, Option, Flag, Positional , Command
1515from decimo.rounding_mode import RoundingMode
1616from calculator.tokenizer import tokenize
1717from calculator.parser import parse_to_rpn
1818from calculator.evaluator import evaluate_rpn, final_round
1919from calculator.display import print_error
2020
2121
22+ struct DecimoArgs (Parsable ):
23+ var expr : Positional[
24+ String,
25+ help =" Math expression to evaluate (e.g. 'sqrt(abs(1.1*-12-23/17))')" ,
26+ required=True ,
27+ ]
28+ var precision : Option[
29+ Int,
30+ long =" precision" ,
31+ short=" p" ,
32+ help =" Number of significant digits" ,
33+ default=" 50" ,
34+ ]
35+ var scientific : Flag[
36+ long =" scientific" ,
37+ short=" s" ,
38+ help =" Output in scientific notation (e.g. 1.23E+10)" ,
39+ ]
40+ var engineering : Flag[
41+ long =" engineering" ,
42+ short=" e" ,
43+ help =" Output in engineering notation (exponent multiple of 3)" ,
44+ ]
45+ var pad : Flag[
46+ long =" pad" ,
47+ short=" P" ,
48+ help =" Pad trailing zeros to the specified precision" ,
49+ ]
50+ var delimiter : Option[
51+ String,
52+ long =" delimiter" ,
53+ short=" d" ,
54+ help =" Digit-group separator inserted every 3 digits (e.g. '_' gives 1_234.567_89)" ,
55+ default=" " ,
56+ ]
57+ var rounding_mode : Option[
58+ String,
59+ long =" rounding-mode" ,
60+ short=" r" ,
61+ help =" Rounding mode for the final result" ,
62+ default=" half-even" ,
63+ choices=" half-even,half-up,half-down,up,down,ceiling,floor" ,
64+ ]
65+
66+ @ staticmethod
67+ def description () -> String:
68+ return " Arbitrary-precision CLI calculator powered by Decimo."
69+
70+ @ staticmethod
71+ def version () -> String:
72+ return " 0.1.0"
73+
74+ @ staticmethod
75+ def name () -> String:
76+ return " decimo"
77+
78+
2279def main ():
2380 try :
2481 _run()
@@ -31,106 +88,21 @@ def main():
3188
3289
3390def _run () raises :
34- var cmd = Command(
35- " decimo" ,
36- (
37- " Arbitrary-precision CLI calculator powered by Decimo.\n "
38- " \n "
39- " Note: if your expression contains *, ( or ), your shell may\n "
40- " intercept them before decimo runs. Use quotes or noglob:\n "
41- ' decimo "2 * (3 + 4)" # with quotes\n '
42- " noglob decimo 2*(3+4) # with noglob\n "
43- " alias decimo='noglob decimo' # add to ~/.zshrc"
44- ),
45- version = " 0.1.0" ,
46- )
47-
48- # Positional: the math expression
49- cmd.add_argument(
50- Arg(
51- " expr" ,
52- help = (
53- " Math expression to evaluate (e.g. 'sqrt(abs(1.1*-12-23/17))')"
54- ),
55- )
56- .positional()
57- .required()
58- )
59-
60- # Named option: number of significant digits
61- cmd.add_argument(
62- Arg(" precision" , help = " Number of significant digits (default: 50)" )
63- .long[" precision" ]()
64- .short[" p" ]()
65- .default[" 50" ]()
66- )
67-
68- # Output formatting flags
69- # Mutually exclusive: scientific, engineering
70- cmd.add_argument(
71- Arg(" scientific" , help = " Output in scientific notation (e.g. 1.23E+10)" )
72- .long[" scientific" ]()
73- .short[" s" ]()
74- .flag()
75- )
76- cmd.add_argument(
77- Arg(
78- " engineering" ,
79- help = " Output in engineering notation (exponent multiple of 3)" ,
80- )
81- .long[" engineering" ]()
82- .short[" e" ]()
83- .flag()
84- )
91+ var cmd = DecimoArgs.to_command()
8592 cmd.mutually_exclusive([" scientific" , " engineering" ])
86- cmd.add_argument(
87- Arg(
88- " pad" ,
89- help = " Pad trailing zeros to the specified precision" ,
90- )
91- .long[" pad" ]()
92- .short[" P" ]()
93- .flag()
94- )
95- cmd.add_argument(
96- Arg(
97- " delimiter" ,
98- help = (
99- " Digit-group separator inserted every 3 digits"
100- " (e.g. '_' gives 1_234.567_89)"
101- ),
102- )
103- .long[" delimiter" ]()
104- .short[" d" ]()
105- .default[" " ]()
93+ cmd.add_tip(
94+ ' If your expression contains *, ( or ), quote it: decimo "2 * (3 + 4)"'
10695 )
107-
108- # Rounding mode for the final result
109- cmd.add_argument(
110- Arg(
111- " rounding-mode" ,
112- help = " Rounding mode for the final result (default: half-even)" ,
113- )
114- .long[" rounding-mode" ]()
115- .short[" r" ]()
116- .choice[" half-even" ]()
117- .choice[" half-up" ]()
118- .choice[" half-down" ]()
119- .choice[" up" ]()
120- .choice[" down" ]()
121- .choice[" ceiling" ]()
122- .choice[" floor" ]()
123- .default[" half-even" ]()
124- )
125-
126- var result = cmd.parse()
127- var expr = result.get_string(" expr" )
128- var precision = result.get_int(" precision" )
129- var scientific = result.get_flag(" scientific" )
130- var engineering = result.get_flag(" engineering" )
131- var pad = result.get_flag(" pad" )
132- var delimiter = result.get_string(" delimiter" )
133- var rounding_mode = _parse_rounding_mode(result.get_string(" rounding-mode" ))
96+ cmd.add_tip(" Or use noglob: alias decimo='noglob decimo' (add to ~/.zshrc)" )
97+ var args = DecimoArgs.parse_from_command(cmd^ )
98+
99+ var expr = args.expr.value
100+ var precision = args.precision.value
101+ var scientific = args.scientific.value
102+ var engineering = args.engineering.value
103+ var pad = args.pad.value
104+ var delimiter = args.delimiter.value
105+ var rounding_mode = _parse_rounding_mode(args.rounding_mode.value)
134106
135107 # ── Phase 1: Tokenize & parse ──────────────────────────────────────────
136108 try :
0 commit comments