Show HN: Nimic – Pure Python as a systems language with AOT compilation
Summary
Nimic is a pure Python module that enables writing AOT-compilable code using a Python DSL that transpiles to Nim, achieving C-level performance while remaining valid Python.
View Cached Full Text
Cached at: 06/25/26, 08:09 AM
dima-quant/nimic
Source: https://github.com/dima-quant/nimic
Nimic
Nimic is a pure Python module that facilitates writing AOT compilable code with a subset of Python (domain specific language), aiming to get C-level performance without leaving Python. Based on ctypes built-in module, it includes emulation of native types, pointers and operations on them, implementing dispatch, operator overloading, and templates. Nimic closely follows Nim programming language, to which nimic code transpiles.
Key principle: nimic code is valid Python that runs natively and transpiles to equivalent Nim code.
Module Architecture
nimic/
├── ntypes.py — Public API: re-exports type system + Nim keyword/builtin shims
├── ntypesystem.py — Core type system (Object, NScalar, seq, dispatch, distinct, converter)
├── transpiler.py — AST-based Python → Nim source code transpiler
├── inliner.py — Template function inlining (@template, @template_expand)
├── ncode/ — Nim definitions (pydefs.nim, pystd/)
├── nimpy/ — API for generating Python libraries
├── std/ — Python shims for Nim stdlib (math, options, os, paths, strformat, ...)
└── system/ — Python shims for Nim system modules (ansi_c)
ntypesystem.py — Core Type System
Organized in layers from low-level memory to high-level abstractions:
| Layer | Classes | Purpose |
|---|---|---|
| Memory | Ntype, NTypeRegistry | ctypes-backed buffers with value semantics |
| Scalars | NScalar → NInteger / NFloat | Fixed-width types (int8..int64, uint8..uint64, float16..float64) with arithmetic promotion |
| Structs | Object | Nim “object” — fields via annotations, backed by ctypes.Structure |
| Enums | NIntEnum | Nim integer enums with auto-registration |
| Variants | Object + match kind: | Nim “case object” — discriminated unions |
| Containers | seq[T], UncheckedArray[T] | Growable sequence and pointer-indexed array |
| Dispatch | @dispatch, DispDict, NMetaClass | Nim-style multi-dispatch via type annotations |
| Modifiers | @distinct, @converter | Type distinctness and trivial type conversions |
| Strings | string | str subclass with Nim-compatible &, %, isEmpty |
ntypes.py — Public API & Keywords
Re-exports all of ntypesystem and adds Nim keyword/builtin emulation:
- Compiler hints —
const,let,var,block,export,alias(no-ops in Python, scoping in Nim) - Reference types —
ref,ptr,mut@(@operator returns identity) - Enum utilities —
NStrEnumwithsucc/pred/ord/nrange/low/high - Cast & memory —
cast[T](x),sizeof(x),addr(x),unsafe_addr(x) - Type aliases —
SomeInteger,SomeFloat,untyped,char,u64,i64,f64 - Iteration —
fields(obj),fields(a, b),countdown(a, b) - Compile-time —
comptime(x),defined(varname),static - Templates —
@template,@template_expand(re-exported frominliner)
transpiler.py — Python → Nim Transpiler
A modified CPython ast.py where _Unparser is extended to emit Nim syntax.
Implements 30+ transformation rules for indentation, type definitions, function
signatures, operators, imports, and control flow.
inliner.py — Template Inlining
@template + @template_expand decorators perform AST-level function inlining
for untyped templates, substituting parameter names with call arguments.
DSL Conventions
Nimic uses Python syntax with specific conventions that have dual meaning — runtime behavior in Python and transpilation semantics for Nim:
| Convention | Example | Purpose |
|---|---|---|
with let/var/const: | with let: x = vec3(1,2,3) | Variable declaration scope qualifier |
mut @ annotation | def f(x: mut @ Vec3): | Mutable argument (var in Nim) |
{.pragma.} docstring | """{.inline.}""" | Nim pragma (inline, borrow, noSideEffect) |
@dispatch | @dispatch def f(x: float64): | Multi-dispatch by argument types |
@distinct | @distinct class Color(Vec3): | Distinct type (no implicit conversion) |
@template | @template def toUV(v): | Template (inlined at call site) |
@converter | @converter def toVec3(uv): | Implicit type converter |
<<= | dst <<= -src | Value assignment to mutable variable |
match kind: | match kind: case K.a: ... | Variant type definition (case object) |
comptime(expr) | if comptime(cond): | Compile-time evaluation (when in Nim) |
fields(obj) | for f in fields(obj): | Iterate over object fields |
with export: | with export: mod1, mod2 | Re-export modules |
Projects built with nimic
Quick Example
from __future__ import annotations
from nimic.ntypes import *
# Struct definition (Nim object)
class Vec3(Object):
x: float64
y: float64
z: float64
def __add__(self: Vec3, v: Vec3) -> Vec3:
"""{.inline.}"""
result = Vec3()
result.x = self.x + v.x
result.y = self.y + v.y
result.z = self.z + v.z
return result
# Distinct type
@distinct
class Point3(Vec3):
"""{.borrow: `.`.}"""
# Multi-dispatch
@dispatch
def point3(x: float64, y: float64, z: float64) -> Point3:
result = Point3(Vec3())
result.x = x; result.y = y; result.z = z
return result
# Usage
with let:
a = point3(1.0, 2.0, 3.0)
b = point3(4.0, 5.0, 6.0)
c = Vec3(a) + Vec3(b)
Similar Articles
Show HN: Tiny – An interpeted dynamic langauge with inline Go native functions
Tiny is a new interpreted dynamic programming language written in Go, featuring a bytecode virtual machine, JIT compilation, and inline Go native functions for high performance.
Show HN: Nibble
Nibble is a C-like systems programming language implemented in 3000 lines of C that generates LLVM IR without external dependencies or heap allocations. It supports defer, recursion, various types, structs, pointers, and includes graphical demos.
I built a compiler that rewrites Python into a model-facing representation
Vulpine is a compiler that transforms human-readable Python code into a compressed macro representation optimized for LLMs, reducing token count by 13.8% on average while enabling exact structural reconstruction.
Performance of the Wren programming language
The Wren language site posts micro-benchmarks showing it outruns standard Python/Ruby/Lua interpreters while staying a simple bytecode VM, crediting NaN-tagging and fixed object layout.
Mojo 1.0 Beta
Modular announces the Mojo 1.0 Beta, a high-performance programming language that combines Python's ease of use with the speed of compiled languages for AI and systems programming.