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
14 changes: 4 additions & 10 deletions .github/workflows/run_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ jobs:
- name: Build packages
run: |
pixi run mojo package src/decimo && cp decimo.mojopkg tests/
pixi run mojo package src/tomlmojo && mv tomlmojo.mojopkg tests/
- name: Run tests
run: bash ./tests/test_bigdecimal.sh

Expand All @@ -59,7 +58,6 @@ jobs:
- name: Build packages
run: |
pixi run mojo package src/decimo && cp decimo.mojopkg tests/
pixi run mojo package src/tomlmojo && mv tomlmojo.mojopkg tests/
- name: Run tests
run: bash ./tests/test_bigint.sh

Expand All @@ -83,7 +81,6 @@ jobs:
- name: Build packages
run: |
pixi run mojo package src/decimo && cp decimo.mojopkg tests/
pixi run mojo package src/tomlmojo && mv tomlmojo.mojopkg tests/
- name: Run tests
run: bash ./tests/test_biguint.sh

Expand All @@ -107,7 +104,6 @@ jobs:
- name: Build packages
run: |
pixi run mojo package src/decimo && cp decimo.mojopkg tests/
pixi run mojo package src/tomlmojo && mv tomlmojo.mojopkg tests/
- name: Run tests
run: bash ./tests/test_bigint10.sh

Expand All @@ -131,13 +127,12 @@ jobs:
- name: Build packages
run: |
pixi run mojo package src/decimo && cp decimo.mojopkg tests/
pixi run mojo package src/tomlmojo && mv tomlmojo.mojopkg tests/
- name: Run tests
run: bash ./tests/test_decimal128.sh

# ── Test: TomlMojo ───────────────────────────────────────────────────────────
test-tomlmojo:
name: Test TomlMojo
# ── Test: TOML parser ─────────────────────────────────────────────────────
test-toml:
name: Test TOML parser
runs-on: ubuntu-22.04
timeout-minutes: 15
env:
Expand All @@ -155,9 +150,8 @@ jobs:
- name: Build packages
run: |
pixi run mojo package src/decimo && cp decimo.mojopkg tests/
pixi run mojo package src/tomlmojo && mv tomlmojo.mojopkg tests/
- name: Run tests
run: bash ./tests/test_tomlmojo.sh
run: bash ./tests/test_toml.sh

# ── Test: CLI ────────────────────────────────────────────────────────────────
test-cli:
Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Decimo provides an arbitrary-precision integer and decimal library for Mojo. It

For Pythonistas, `decimo.BInt` to Mojo is like `int` to Python, and `decimo.Decimal` to Mojo is like `decimal.Decimal` to Python.

The core types are:
The core types are[^auxiliary]:

- An arbitrary-precision signed integer type `BInt`[^bigint], which is a Mojo-native equivalent of Python's `int`.
- An arbitrary-precision decimal implementation (`Decimal`) allowing for calculations with unlimited digits and decimal places[^arbitrary], which is a Mojo-native equivalent of Python's `decimal.Decimal`.
Expand All @@ -40,15 +40,13 @@ The core types are:
| `Decimal` | `BDec`, `BigDecimal` | Equivalent to Python's `decimal.Decimal` | Base-10^9 |
| `Dec128` | `Decimal128` | 128-bit fixed-precision decimal type | Triple 32-bit words |

The auxiliary types include a base-10 arbitrary-precision signed integer type (`BigInt10`) and a base-10 arbitrary-precision unsigned integer type (`BigUInt`) supporting unlimited digits[^bigint10]. `BigUInt` is used as the internal representation for `BigInt10` and `Decimal`.

---

**Decimo** combines "**Deci**mal" and "**Mo**jo" - reflecting its purpose and implementation language. "Decimo" is also a Latin word meaning "tenth" and is the root of the word "decimal".

---

This repository includes [TOMLMojo](./docs/readme_tomlmojo.md), a lightweight TOML parser in pure Mojo. It parses configuration files and test data, supporting basic types, arrays, and nested tables. While created for Decimo's testing framework, it offers general-purpose structured data parsing with a clean, simple API.
This repository includes a built-in [TOML parser](./docs/readme_toml.md) (`decimo.toml`), a lightweight pure-Mojo implementation supporting TOML v1.0. It parses configuration files and test data, supporting basic types, arrays, and nested tables. While created for Decimo's testing framework, it offers general-purpose structured data parsing with a clean, simple API.

## Installation

Expand Down Expand Up @@ -343,5 +341,6 @@ This repository and its contributions are licensed under the Apache License v2.0

[^fixed]: The `Decimal128` type can represent values with up to 29 significant digits and a maximum of 28 digits after the decimal point. When a value exceeds the maximum representable value (`2^96 - 1`), Decimo either raises an error or rounds the value to fit within these constraints. For example, the significant digits of `8.8888888888888888888888888888` (29 eights total with 28 after the decimal point) exceeds the maximum representable value (`2^96 - 1`) and is automatically rounded to `8.888888888888888888888888889` (28 eights total with 27 after the decimal point). Decimo's `Decimal128` type is similar to `System.Decimal` (C#/.NET), `rust_decimal` in Rust, `DECIMAL/NUMERIC` in SQL Server, etc.
[^bigint]: The `BigInt` implementation uses a base-2^32 representation with a little-endian format, where the least significant word is stored at index 0. Each word is a `UInt32`, allowing for efficient storage and arithmetic operations on large integers. This design choice optimizes performance for binary computations while still supporting arbitrary precision.
[^auxiliary]: The auxiliary types include a base-10 arbitrary-precision signed integer type (`BigInt10`) and a base-10 arbitrary-precision unsigned integer type (`BigUInt`) supporting unlimited digits[^bigint10]. `BigUInt` is used as the internal representation for `BigInt10` and `Decimal`.
[^bigint10]: The BigInt10 implementation uses a base-10 representation for users (maintaining decimal semantics), while internally using an optimized base-10^9 storage system for efficient calculations. This approach balances human-readable decimal operations with high-performance computing. It provides both floor division (round toward negative infinity) and truncate division (round toward zero) semantics, enabling precise handling of division operations with correct mathematical behavior regardless of operand signs.
[^arbitrary]: Built on top of our completed BigInt10 implementation, BigDecimal will support arbitrary precision for both the integer and fractional parts, similar to `decimal` and `mpmath` in Python, `java.math.BigDecimal` in Java, etc.
2 changes: 1 addition & 1 deletion benches/decimal128/bench_comparison.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn main() raises:
var pydecimal = Python.import_module("decimal")
pydecimal.getcontext().prec = 28

# --- TOML load via tomlmojo for 'op' field ---
# --- TOML load via decimo.toml for 'op' field ---
var doc = parse_file("bench_data/comparison.toml")
var cases_array = doc.get_array_of_tables("cases")
var iterations = 10000
Expand Down
2 changes: 1 addition & 1 deletion benches/decimal128/bench_quantize.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn main() raises:
var pydecimal = Python.import_module("decimal")
pydecimal.getcontext().prec = 28

# --- TOML load via tomlmojo for 'rounding' field ---
# --- TOML load via decimo.toml for 'rounding' field ---
var doc = parse_file("bench_data/quantize.toml")
var cases_array = doc.get_array_of_tables("cases")
var iterations = 10000
Expand Down
20 changes: 13 additions & 7 deletions docs/plans/mojo4py.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,14 +365,20 @@ jobs:

```txt
python/
├── decimo_module.mojo ← Mojo binding (builds to _decimo.so)
├── _decimo.so ← compiled extension (PyInit__decimo, gitignored)
├── decimo.py ← Python wrapper: Decimal class + BigDecimal alias
├── pyproject.toml ← PyPI package config (hatchling, src layout)
├── README.md ← PyPI landing page
├── decimo_module.mojo ← Mojo binding (builds to src/decimo/_decimo.so)
├── src/
│ └── decimo/
│ ├── __init__.py ← Python wrapper: Decimal class + BigDecimal alias
│ ├── _decimo.pyi ← Type stub for Pylance/mypy
│ ├── _decimo.so ← compiled extension (gitignored)
│ └── py.typed ← PEP 561 marker
└── tests/
└── test_decimo.py ← test script
└── test_decimo.py ← test script
```

4. **Build command:** `pixi run pybuild` (= `mojo build python/decimo_module.mojo --emit shared-lib -I src -o python/_decimo.so`)
4. **Build command:** `pixi run buildpy` (= `mojo build python/decimo_module.mojo --emit shared-lib -I src -o python/src/decimo/_decimo.so`)

5. **`def_py_init` signature:** `fn(out self: T, args: PythonObject, kwargs: PythonObject) raises` — works as a free function, does not need to be a `@staticmethod` on the struct itself. This means **zero modifications to the core BigDecimal struct** are needed for the binding.

Expand Down Expand Up @@ -447,8 +453,8 @@ jobs:
Build and test with two commands:

```bash
pixi run pybuild # Compiles python/decimo_module.mojo → python/_decimo.so
pixi run pytest # Builds, then runs python/tests/test_decimo.py
pixi run buildpy # Compiles python/decimo_module.mojo → python/src/decimo/_decimo.so
pixi run testpy # Builds, then runs python/tests/test_decimo.py
```

From Python:
Expand Down
52 changes: 26 additions & 26 deletions docs/readme_tomlmojo.md → docs/readme_toml.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# TOMLMojo <!-- omit from toc -->
# decimo.toml <!-- omit from toc -->

A native TOML v1.0 parser for [Mojo](https://www.modular.com/mojo).
A native TOML v1.0 parser for [Mojo](https://www.modular.com/mojo), included as a subpackage of [Decimo](https://github.com/forfudan/decimo).

**[Repository on GitHub»](https://github.com/forfudan/decimo/tree/main/src/tomlmojo)** | **[Decimo»](https://github.com/forfudan/decimo)**
> Formerly distributed as the standalone package `tomlmojo`. Merged into Decimo as `decimo.toml` starting from v0.9.0.

**[Source on GitHub»](https://github.com/forfudan/decimo/tree/main/src/decimo/toml)** | **[Decimo»](https://github.com/forfudan/decimo)**

- [Overview](#overview)
- [History](#history)
Expand All @@ -24,41 +26,39 @@ A native TOML v1.0 parser for [Mojo](https://www.modular.com/mojo).

## Overview

TOMLMojo is a lightweight, pure-Mojo TOML parser (~1,500 LOC) that implements the core [TOML v1.0 specification](https://toml.io/en/v1.0.0). It parses TOML source text into a `TOMLDocument` — a nested dictionary structure that you can query by key, table name, or array index. It handles all common TOML constructs including nested tables, inline tables, dotted keys, arrays of tables, and all TOML data types.
`decimo.toml` (formerly TOMLMojo) is a lightweight, pure-Mojo TOML parser (~1,500 LOC) that implements the core [TOML v1.0 specification](https://toml.io/en/v1.0.0). It parses TOML source text into a `TOMLDocument` — a nested dictionary structure that you can query by key, table name, or array index. It handles all common TOML constructs including nested tables, inline tables, dotted keys, arrays of tables, and all TOML data types.

## History

TOMLMojo was initially developed in **April 2025** alongside [Decimo](https://github.com/forfudan/decimo) v0.3.0 to support Decimo's TOML-based test data system. At that time, no TOML parser existed in the Mojo ecosystem, so I wrote one from scratch.

Currently, **Decimo heavily depends on TOMLMojo** for its entire testing and benchmarking infrastructure. All test cases and benchmark configurations are stored as TOML files and loaded via TOMLMojo's `parse_file()` API.

While originally built for internal use, TOMLMojo has grown into a general-purpose TOML library suitable for any Mojo project that needs to parse configuration files or structured data.
Decimo heavily depends on this TOML parser for its entire testing and benchmarking infrastructure. All test cases and benchmark configurations are stored as TOML files and loaded via `parse_file()`.

The version number of TOMLMojo is aligned with the latest version of Decimo.
Starting from Decimo v0.9.0, TOMLMojo has been merged into the Decimo package as the `decimo.toml` subpackage to simplify dependency management and packaging. It is no longer distributed as a standalone conda package.

## Installation

TOMLMojo is available in the modular-community `https://repo.prefix.dev/modular-community` package repository. Add it to your `channels` in `pixi.toml`:
`decimo.toml` is included as part of the Decimo package. Install Decimo:

```toml
channels = ["https://conda.modular.com/max", "https://repo.prefix.dev/modular-community", "conda-forge"]
```bash
pixi add decimo
```

Then install:
Then import the TOML parser:

```bash
pixi add tomlmojo
```mojo
from decimo.toml import parse_string, parse_file
```

## Quick start

### Parse a TOML string

```mojo
import tomlmojo
from decimo.toml import parse_string, parse_file

fn main() raises:
var doc = tomlmojo.parse_string("""
var doc = parse_string("""
title = "My App"
version = 42
debug = true
Expand Down Expand Up @@ -86,21 +86,21 @@ fn main() raises:
### Parse a TOML file

```mojo
import tomlmojo
from decimo.toml import parse_string, parse_file

fn main() raises:
var doc = tomlmojo.parse_file("config.toml")
var doc = parse_file("config.toml")
var db = doc.get_table("database")
print(db["name"].as_string()) # mydb
```

### Dotted keys and nested tables

```mojo
import tomlmojo
from decimo.toml import parse_string, parse_file

fn main() raises:
var doc = tomlmojo.parse_string("""
var doc = parse_string("""
fruit.name = "apple"
fruit.color = "red"
fruit.size.width = 10
Expand Down Expand Up @@ -129,10 +129,10 @@ fn main() raises:
### Inline tables

```mojo
import tomlmojo
from decimo.toml import parse_string, parse_file

fn main() raises:
var doc = tomlmojo.parse_string("""
var doc = parse_string("""
point = {x = 1, y = 2}
animal = {type.name = "pug"}
""")
Expand All @@ -150,10 +150,10 @@ fn main() raises:
### Arrays and arrays of tables

```mojo
import tomlmojo
from decimo.toml import parse_string, parse_file

fn main() raises:
var doc = tomlmojo.parse_string("""
var doc = parse_string("""
colors = [
"red",
"green",
Expand Down Expand Up @@ -184,10 +184,10 @@ fn main() raises:
### Integer formats and special floats

```mojo
import tomlmojo
from decimo.toml import parse_string, parse_file

fn main() raises:
var doc = tomlmojo.parse_string("""
var doc = parse_string("""
hex = 0xDEADBEEF
oct = 0o755
bin = 0b11010110
Expand Down
Loading