Show HN: Nimic – Pure Python as a systems language with AOT compilation

Hacker News Top Tools

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.

No content available
Original Article
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:

LayerClassesPurpose
MemoryNtype, NTypeRegistryctypes-backed buffers with value semantics
ScalarsNScalar → NInteger / NFloatFixed-width types (int8..int64, uint8..uint64, float16..float64) with arithmetic promotion
StructsObjectNim “object” — fields via annotations, backed by ctypes.Structure
EnumsNIntEnumNim integer enums with auto-registration
VariantsObject + match kind:Nim “case object” — discriminated unions
Containersseq[T], UncheckedArray[T]Growable sequence and pointer-indexed array
Dispatch@dispatch, DispDict, NMetaClassNim-style multi-dispatch via type annotations
Modifiers@distinct, @converterType distinctness and trivial type conversions
Stringsstringstr 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 — NStrEnum with succ/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 from inliner)

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:

ConventionExamplePurpose
with let/var/const:with let: x = vec3(1,2,3)Variable declaration scope qualifier
mut @ annotationdef 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 <<= -srcValue 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, mod2Re-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: Nibble

Hacker News Top

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.