IRx is a Python library that lowers
ARXLang ASTx nodes to LLVM IR using
llvmlite. It provides a visitor-based codegen pipeline and a small builder API
that can translate ASTs to LLVM IR text or produce runnable executables
via clang
.
Status: early but functional. Arithmetic, variables, functions, returns, basic control flow, and a few system-level expressions (e.g.
PrintExpr
) are supported.
-
ASTx → LLVM IR via multiple-dispatch visitors (
plum
). -
Back end: IR construction and object emission with llvmlite.
-
Native build: links with
clang
to produce an executable. -
Supported nodes (subset; exact ASTx class names):
- Literals:
LiteralInt16
,LiteralInt32
,LiteralString
- Variables:
Variable
,VariableDeclaration
,InlineVariableDeclaration
- Ops:
UnaryOp
(++
,--
),BinaryOp
(+ - * / < >
) with simple type promotion - Flow:
IfStmt
,ForCountLoopStmt
,ForRangeLoopStmt
- Functions:
FunctionPrototype
,Function
,FunctionReturn
,FunctionCall
- System:
system.PrintExpr
(string printing)
- Literals:
-
Built-ins:
putchar
,putchard
(emitted as IR);puts
declaration when needed.
-
Python 3.9 – 3.13.
-
A recent LLVM/Clang toolchain available on
PATH
. -
A working C standard library (e.g., system libc) for linking calls like
puts
. -
Python deps:
llvmlite
,pytest
, etc. (seepyproject.toml
/requirements.txt
).- Note: llvmlite has specific Python/LLVM compatibility windows; see its docs.
git clone https://github.com/arxlang/irx.git
cd irx
conda env create --file conda/dev.yaml
conda activate irx
poetry install
You can also install it from PyPI: pip install pyirx
.
More details: https://irx.arxlang.org/installation/
import astx
from irx.builders.llvmliteir import LLVMLiteIR
builder = LLVMLiteIR()
module = builder.module()
# int main() { return 0; }
proto = astx.FunctionPrototype("main", astx.Arguments(), astx.Int32())
body = astx.Block()
body.append(astx.FunctionReturn(astx.LiteralInt32(0)))
module.block.append(astx.Function(prototype=proto, body=body))
ir_text = builder.translate(module)
print(ir_text) # LLVM IR text (str)
translate
returns a str
with LLVM IR. It does not produce an object file
or binary; use it for inspection, tests, or feeding another tool.
import astx
from irx.builders.llvmliteir import LLVMLiteIR
from irx.system import PrintExpr
builder = LLVMLiteIR()
module = builder.module()
# int main() { print("Hello, IRx!"); return 0; }
main_proto = astx.FunctionPrototype("main", astx.Arguments(), astx.Int32())
body = astx.Block()
body.append(PrintExpr(astx.LiteralString("Hello, IRx!")))
body.append(astx.FunctionReturn(astx.LiteralInt32(0)))
module.block.append(astx.Function(prototype=main_proto, body=body))
builder.build(module, "hello") # emits object + links with clang
builder.run() # executes ./hello (or hello.exe on Windows)
-
LLVMLiteIR
(public API)translate(ast) -> str
— generate LLVM IR text.build(ast, output_path)
— emit object via llvmlite and link withclang
.run()
— execute the produced binary.
-
LLVMLiteIRVisitor
(codegen)- Uses
@dispatch
to visit each ASTx node type. - Maintains a value stack (
result_stack
) and symbol table (named_values
). - Emits LLVM IR with
llvmlite.ir.IRBuilder
.
- Uses
PrintExpr
is an astx.Expr
holding a LiteralString
. Its lowering:
- Create a global constant for the string (with
\0
). - GEP to an
i8*
pointer. - Declare (or reuse)
i32 @puts(i8*)
. - Call
puts
.
pytest -vv
Example style (simplified):
def test_binary_op_basic():
builder = LLVMLiteIR()
module = builder.module()
decl_a = astx.VariableDeclaration("a", astx.Int32(), astx.LiteralInt32(1))
decl_b = astx.VariableDeclaration("b", astx.Int32(), astx.LiteralInt32(2))
a, b = astx.Variable("a"), astx.Variable("b")
expr = astx.LiteralInt32(1) + b - a * b / a
proto = astx.FunctionPrototype("main", astx.Arguments(), astx.Int32())
block = astx.Block()
block.append(decl_a); block.append(decl_b)
block.append(astx.FunctionReturn(expr))
module.block.append(astx.Function(proto, block))
ir_text = builder.translate(module)
assert "add" in ir_text
-
Ensure Xcode Command Line Tools are installed:
xcode-select --install
. -
Verify
clang --version
works. -
If needed:
export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"
-
CI note: macOS jobs currently run on Python 3.12 only.
- Define
main
to returnInt32
and emitreturn 0
. Falling off the end or returningvoid
can yield an arbitrary exit code.
- A visitor is missing
@dispatch
or is typed against a different class than the one instantiated. Ensure signatures match the exact runtime class (e.g.,visit(self, node: PrintExpr)
).
- Install a recent LLVM/Clang. On Linux, use distro packages.
- On macOS, install Xcode CLT.
- On Windows, ensure LLVM’s
bin
directory is onPATH
.
- Linux & macOS: supported and used in CI.
- Windows: expected to work with a proper LLVM/Clang setup; consider it
experimental.
builder.run()
will executehello.exe
.
- More ASTx coverage (booleans, arrays, structs, varargs/options).
- Richer stdlib bindings (I/O, math).
- Optimization toggles/passes.
- Alternative backends and/or JIT runner.
- Better diagnostics and source locations in IR.
- Integration with Apache Arrow.
Please see the contributing guide. Add tests for new features and keep visitors isolated (avoid special-casing derived nodes inside generic visitors).
- LLVM and llvmlite for the IR infrastructure.
- ASTx / ARXLang for the front-end AST.
- Contributors and users experimenting with IRx.
License: BSD-3-Clause. See LICENSE.