Skip to content
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
4 changes: 2 additions & 2 deletions .github/workflows/run_tests.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
name: CI
on:
push:
branches: [main, dev]
pull_request:
workflow_dispatch:

Expand Down Expand Up @@ -195,8 +197,6 @@ jobs:
echo "$HOME/.pixi/bin" >> $GITHUB_PATH
- name: pixi install
run: pixi install
- name: Fetch argmojo
run: pixi run fetch
- name: Build CLI binary
run: pixi run buildcli
- name: Run tests
Expand Down
18 changes: 18 additions & 0 deletions pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 24 additions & 19 deletions pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ version = "0.9.0"

[dependencies]
# argmojo = ">=0.4.0" # CLI argument parsing for the Decimo calculator (TODO: waiting for argmojo 0.4.0 compatible with mojo 0.26.2)
argmojo = ">=0.5.0,<0.6.0" # CLI argument parsing for the Decimo calculator
mojo = ">=0.26.2.0,<0.26.3" # Mojo language compiler and runtime
python = ">=3.13" # For Python bindings and tests
python-build = ">=0.2.0" # Build PyPI wheel (`pixi run wheel`)
Expand All @@ -26,17 +27,17 @@ format = """pixi run mojo format ./src \
&&pixi run ruff format ./python"""

# doc
doc = "pixi run mojo doc --diagnose-missing-doc-strings src/decimo"
doc = "pixi run mojo doc --diagnose-missing-doc-strings src/decimo > /dev/null"

# compile the package
p = "clear && pixi run package"
package = """pixi run format \
&& pixi run doc \
&& pixi run package_decimo"""
&&pixi run doc \
&&pixi run package_decimo"""
package_decimo = """pixi run mojo package src/decimo \
&& cp decimo.mojopkg tests/ \
&& cp decimo.mojopkg benches/ \
&& rm decimo.mojopkg"""
&&cp decimo.mojopkg tests/ \
&&cp decimo.mojopkg benches/ \
&&rm decimo.mojopkg"""

# clean the package files in tests folder
c = "clear && pixi run clean"
Expand Down Expand Up @@ -64,26 +65,31 @@ bench = "pixi run package && bash benches/run_bench.sh"

# bench with debug assertions enabled
bdec_debug = """clear && pixi run package && cd benches/bigdecimal \
&& pixi run mojo run -I ../ -D ASSERT=all bench.mojo && cd ../.. \
&& pixi run clean"""
&&pixi run mojo run -I ../ -D ASSERT=all bench.mojo && cd ../.. \
&&pixi run clean"""
bint_debug = """clear && pixi run package && cd benches/bigint \
&& pixi run mojo run -I ../ -D ASSERT=all bench.mojo && cd ../.. \
&& pixi run clean"""
&&pixi run mojo run -I ../ -D ASSERT=all bench.mojo && cd ../.. \
&&pixi run clean"""
buint_debug = """clear && pixi run package && cd benches/biguint \
&& pixi run mojo run -I ../ -D ASSERT=all bench.mojo && cd ../.. \
&& pixi run clean"""
&&pixi run mojo run -I ../ -D ASSERT=all bench.mojo && cd ../.. \
&&pixi run clean"""
dec_debug = """clear && pixi run package && cd benches/decimal128 \
&& pixi run mojo run -I ../ -D ASSERT=all bench.mojo && cd ../.. \
&& pixi run clean"""
&&pixi run mojo run -I ../ -D ASSERT=all bench.mojo && cd ../.. \
&&pixi run clean"""

# Fetch argmojo source code for CLI calculator
fetch = """git clone https://github.com/forfudan/argmojo.git temp/argmojo 2>/dev/null || true \
&& cd temp/argmojo && git checkout 24ca712fa291ec6a82dc9317f6ba5d0484d1fb47 2>/dev/null"""
# Only do this when necessary
# (argmojo is not compatible with the latest mojo version)
# fetch = """git clone https://github.com/forfudan/argmojo.git temp/argmojo 2>/dev/null || true \
# && cd temp/argmojo && git checkout 29b6f54545f850e19d9a9ccfd1185d87f54e92b2 2>/dev/null"""

# cli calculator
bcli = "clear && pixi run buildcli"
buildcli = """pixi run mojo package temp/argmojo/src/argmojo -o temp/argmojo.mojopkg \
&& pixi run mojo build -I src -I src/cli -I temp -o decimo src/cli/main.mojo"""
# Uncomment the following lines if we build the CLI package with
# local clone of argmojo
# buildcli = """pixi run mojo package temp/argmojo/src/argmojo -o temp/argmojo.mojopkg \
# && pixi run mojo build -I src -I src/cli -I temp -o decimo src/cli/main.mojo"""
buildcli = """pixi run mojo build -I src -I src/cli -o decimo src/cli/main.mojo"""
tcli = "clear && pixi run testcli"
testcli = "bash tests/test_cli.sh"

Expand All @@ -101,7 +107,6 @@ all = """pixi run format \
&&pixi run package \
&&pixi run doc \
&&pixi run test \
&&pixi run fetch \
&&pixi run buildcli \
&&pixi run testcli \
&&pixi run buildpy \
Expand Down
170 changes: 71 additions & 99 deletions src/cli/main.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,71 @@

from std.sys import exit

from argmojo import Arg, Command
from argmojo import Parsable, Option, Flag, Positional, Command
from decimo.rounding_mode import RoundingMode
from calculator.tokenizer import tokenize
from calculator.parser import parse_to_rpn
from calculator.evaluator import evaluate_rpn, final_round
from calculator.display import print_error


struct DecimoArgs(Parsable):
var expr: Positional[
String,
help="Math expression to evaluate (e.g. 'sqrt(abs(1.1*-12-23/17))')",
required=True,
]
var precision: Option[
Int,
long="precision",
short="p",
help="Number of significant digits",
default="50",
]
var scientific: Flag[
long="scientific",
short="s",
help="Output in scientific notation (e.g. 1.23E+10)",
]
var engineering: Flag[
long="engineering",
short="e",
help="Output in engineering notation (exponent multiple of 3)",
]
var pad: Flag[
long="pad",
short="P",
help="Pad trailing zeros to the specified precision",
]
var delimiter: Option[
String,
long="delimiter",
short="d",
help="Digit-group separator inserted every 3 digits (e.g. '_' gives 1_234.567_89)",
default="",
]
var rounding_mode: Option[
String,
long="rounding-mode",
short="r",
help="Rounding mode for the final result",
default="half-even",
choices="half-even,half-up,half-down,up,down,ceiling,floor",
]

@staticmethod
def description() -> String:
return "Arbitrary-precision CLI calculator powered by Decimo."

@staticmethod
def version() -> String:
return "0.1.0"

@staticmethod
def name() -> String:
return "decimo"


def main():
try:
_run()
Expand All @@ -31,106 +88,21 @@ def main():


def _run() raises:
var cmd = Command(
"decimo",
(
"Arbitrary-precision CLI calculator powered by Decimo.\n"
"\n"
"Note: if your expression contains *, ( or ), your shell may\n"
"intercept them before decimo runs. Use quotes or noglob:\n"
' decimo "2 * (3 + 4)" # with quotes\n'
" noglob decimo 2*(3+4) # with noglob\n"
" alias decimo='noglob decimo' # add to ~/.zshrc"
),
version="0.1.0",
)

# Positional: the math expression
cmd.add_argument(
Arg(
"expr",
help=(
"Math expression to evaluate (e.g. 'sqrt(abs(1.1*-12-23/17))')"
),
)
.positional()
.required()
)

# Named option: number of significant digits
cmd.add_argument(
Arg("precision", help="Number of significant digits (default: 50)")
.long["precision"]()
.short["p"]()
.default["50"]()
)

# Output formatting flags
# Mutually exclusive: scientific, engineering
cmd.add_argument(
Arg("scientific", help="Output in scientific notation (e.g. 1.23E+10)")
.long["scientific"]()
.short["s"]()
.flag()
)
cmd.add_argument(
Arg(
"engineering",
help="Output in engineering notation (exponent multiple of 3)",
)
.long["engineering"]()
.short["e"]()
.flag()
)
var cmd = DecimoArgs.to_command()
cmd.mutually_exclusive(["scientific", "engineering"])
cmd.add_argument(
Arg(
"pad",
help="Pad trailing zeros to the specified precision",
)
.long["pad"]()
.short["P"]()
.flag()
)
cmd.add_argument(
Arg(
"delimiter",
help=(
"Digit-group separator inserted every 3 digits"
" (e.g. '_' gives 1_234.567_89)"
),
)
.long["delimiter"]()
.short["d"]()
.default[""]()
cmd.add_tip(
'If your expression contains *, ( or ), quote it: decimo "2 * (3 + 4)"'
)

# Rounding mode for the final result
cmd.add_argument(
Arg(
"rounding-mode",
help="Rounding mode for the final result (default: half-even)",
)
.long["rounding-mode"]()
.short["r"]()
.choice["half-even"]()
.choice["half-up"]()
.choice["half-down"]()
.choice["up"]()
.choice["down"]()
.choice["ceiling"]()
.choice["floor"]()
.default["half-even"]()
)

var result = cmd.parse()
var expr = result.get_string("expr")
var precision = result.get_int("precision")
var scientific = result.get_flag("scientific")
var engineering = result.get_flag("engineering")
var pad = result.get_flag("pad")
var delimiter = result.get_string("delimiter")
var rounding_mode = _parse_rounding_mode(result.get_string("rounding-mode"))
cmd.add_tip("Or use noglob: alias decimo='noglob decimo' (add to ~/.zshrc)")
var args = DecimoArgs.parse_from_command(cmd^)
Comment thread
forfudan marked this conversation as resolved.

var expr = args.expr.value
var precision = args.precision.value
var scientific = args.scientific.value
var engineering = args.engineering.value
var pad = args.pad.value
var delimiter = args.delimiter.value
var rounding_mode = _parse_rounding_mode(args.rounding_mode.value)

# ── Phase 1: Tokenize & parse ──────────────────────────────────────────
try:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_bigdecimal.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
set -e

for f in tests/bigdecimal/*.mojo; do
pixi run mojo run -I src -D ASSERT=all -debug-level=line-tables "$f"
pixi run mojo run -I src -D ASSERT=all --debug-level=line-tables "$f"
done
2 changes: 1 addition & 1 deletion tests/test_bigfloat.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ trap cleanup EXIT
for f in tests/bigfloat/*.mojo; do
echo "=== $f ==="
TMPBIN=$(mktemp /tmp/decimo_test_bigfloat_XXXXXX)
pixi run mojo build -I src -debug-level=line-tables \
pixi run mojo build -I src --debug-level=line-tables \
-Xlinker -L./"$WRAPPER_DIR" -Xlinker -ldecimo_gmp_wrapper \
-o "$TMPBIN" "$f"
DYLD_LIBRARY_PATH="./$WRAPPER_DIR" LD_LIBRARY_PATH="./$WRAPPER_DIR" "$TMPBIN"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_bigint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
set -e

for f in tests/bigint/*.mojo; do
pixi run mojo run -I src -D ASSERT=all -debug-level=line-tables "$f"
pixi run mojo run -I src -D ASSERT=all --debug-level=line-tables "$f"
done
2 changes: 1 addition & 1 deletion tests/test_bigint10.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
set -e

for f in tests/bigint10/*.mojo; do
pixi run mojo run -I src -D ASSERT=all -debug-level=line-tables "$f"
pixi run mojo run -I src -D ASSERT=all --debug-level=line-tables "$f"
done
2 changes: 1 addition & 1 deletion tests/test_biguint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
set -e

for f in tests/biguint/*.mojo; do
pixi run mojo run -I src -D ASSERT=all -debug-level=line-tables "$f"
pixi run mojo run -I src -D ASSERT=all --debug-level=line-tables "$f"
done
Loading
Loading