Skip to main content

pyjoy-lang

A Python implementation of Manfred von Thun's Joy programming language with dual-mode architecture.

PyPI package: pyjoy-lang | Command: pyjoy

The primary aim of this project is to implement the Joy language in Python 3. This means the implementation should run Joy programs without issue. A secondary aim is to have the Python implementation generate C code which can then be compiled into machine code. This is consistent with the late Manfred von Thun's wish:

Several other people have published other more or less complete Joy interpreters, written in ML and in Scheme, in the "concatenative" mailing group. At this point in time I have no plans to write a full compiler. A first version of such a compiler would presumably use C as an intermediate language and leave the generation of machine code to the C compiler. I would very much welcome if somebody were to take up the task." A Conversation with Manfred von Thun

The implementation provides a dual-mode architecture: strict mode (strict=True) for Joy compliance, and pythonic mode (strict=False) for Python interoperability.

Installation

From PyPI

pip install pyjoy-lang

From Source

Requires Python 3.13+ and uv.

# Clone the repository
git clone https://github.com/shakfu/pyjoy-lang.git
cd pyjoy-lang

# Install dependencies
uv sync

# Run Python tests
uv run pytest

# Run Joy test suite
uv run pyjoy test tests/joy

# Run Joy tests with C compilation
uv run pyjoy test tests/joy --compile

For C compilation, you'll also need gcc or clang.

Usage

Interactive REPL

# Start the Joy REPL
uv run pyjoy

Example session:

Joy> 2 3 + .
5
Joy> [1 2 3] [dup *] map .
[1 4 9]
Joy> DEFINE square == dup *.
Joy> 5 square .
25
Joy> quit

Execute Joy files

# Run a Joy source file
uv run pyjoy examples/factorial.joy

# Or using the run subcommand
uv run pyjoy run examples/factorial.joy

# Evaluate an expression
uv run pyjoy -e "5 [1] [*] primrec ."
120

Compile to C

# Compile Joy source to executable
uv run pyjoy compile program.joy -o build -n myprogram

# Run the compiled program
./build/myprogram

# Or compile and run in one step
uv run pyjoy compile program.joy --run

# Generate C code only (no compilation)
uv run pyjoy compile program.joy --no-compile

Run Test Suite

# Run all Joy tests
uv run pyjoy test tests/joy

# Run with verbose output
uv run pyjoy test tests/joy -v

# Run specific pattern
uv run pyjoy test tests/joy --pattern "fact*.joy"

# Also test C compilation
uv run pyjoy test tests/joy --compile

Status

Test Results

Backend Passing Total Coverage
Python Interpreter 194 215 90.2%
C Backend 199 215 92.6%
pytest (unit tests) 712 712 100%

Primitives

  • 200+ primitives implemented in both Python and C backends
  • Full support for Joy's core operations, combinators, and I/O
  • Mode-aware primitives work with both strict (JoyValue) and pythonic (raw Python) values
  • Some interpreter-specific primitives (get, include) have limited C support

See TODO.md for detailed status and remaining work.

Features

Core Language

  • Stack operations: dup, pop, swap, rollup, rolldown, rotate, etc.
  • Arithmetic: +, -, *, /, rem, div, abs, neg, sign, etc.
  • Comparison: <, >, <=, >=, =, !=, equal, compare
  • Logic: and, or, not, xor
  • Aggregates: lists [...], sets {...}, strings "..."
  • Quotations and combinators

Combinators

  • Basic: i, x, dip, dipd, dipdd
  • Conditionals: ifte, cond, branch, iflist, ifinteger, etc.
  • Recursion: linrec, binrec, genrec, primrec, tailrec
  • Tree recursion: treerec, treegenrec, treestep
  • Conditional recursion: condlinrec, condnestrec
  • Application: app1, app2, app3, app4, map, filter, fold, step
  • Arity: nullary, unary, binary, ternary, unary2, unary3, unary4
  • Control: cleave, construct, some, all, split

I/O and System

  • Console: put, putch, putchars, . (print with newline)
  • File I/O: fopen, fclose, fread, fwrite, fgets, fput, etc.
  • System: system, getenv, argc, argv
  • Time: time, localtime, gmtime, mktime, strftime

Python Interop (Pythonic Mode)

When running with strict=False, Joy gains Python interoperability:

from pyjoy import Evaluator

ev = Evaluator(strict=False)  # Enable pythonic mode

# Backtick expressions - evaluate Python and push result
ev.run("`2 + 3`")           # Pushes 5
ev.run("`math.sqrt(16)`")   # Pushes 4.0 (math is pre-imported)

# Dollar expressions - same as backticks, better for nested parens
ev.run("$(len([1,2,3]))")   # Pushes 3

# Bang statements - execute Python without pushing
ev.run("!x = 42")           # Sets x in Python namespace
ev.run("`x * 2`")           # Pushes 84

# Access stack from Python
ev.run("1 2 3")
ev.run("`sum(stack)`")      # Pushes 6

# Define Python functions
ev.run("!def square(n): return n * n")
ev.run("`square(7)`")       # Pushes 49

Pre-imported modules: math, json, os, sys, re, itertools, functools, collections

Available in namespace: stack (alias S), ctx, evaluator

See docs/pythonic-mode.md for the complete guide.

Extending Joy from Python

Define new Joy words using Python decorators:

from pyjoy.evaluator import joy_word, python_word, ExecutionContext
from pyjoy.types import JoyValue

# Simple functions: use @python_word (auto-pops args, pushes result)
@python_word(name="hypot", doc="X Y -> Z")
def hypot(x, y):
    return (x**2 + y**2) ** 0.5

# Full stack control: use @joy_word
@joy_word(name="rot3", params=3, doc="X Y Z -> Y Z X")
def rot3(ctx: ExecutionContext):
    c, b, a = ctx.stack.pop_n(3)
    ctx.stack.push_value(b)
    ctx.stack.push_value(c)
    ctx.stack.push_value(a)

# Wrap existing Python functions
import math

@python_word(name="deg2rad")
def deg2rad(degrees):
    return math.radians(degrees)

@python_word(name="factorial")
def factorial(n):
    return math.factorial(int(n))

When to use each decorator:

Decorator Use When
@python_word Pure functions, fixed arity, single return value
@joy_word Need stack access, multiple results, control flow, or ExecutionContext

Example: HTTP fetch word

@joy_word(name="http-get", params=1, doc="URL -> RESPONSE")
def http_get(ctx: ExecutionContext):
    import requests
    url = ctx.stack.pop()
    response = requests.get(url.value if hasattr(url, 'value') else url)
    ctx.stack.push(response.text)

C Backend Features

  • Compiles Joy to standalone C executables
  • Compile-time include preprocessing
  • Recursive include with circular dependency detection
  • Full runtime with garbage collection

Project Structure

pyjoy-lang/
  src/pyjoy/
    __init__.py         # Public API
    __main__.py         # CLI entry point
    types.py            # Joy type system
    stack.py            # Stack implementation
    scanner.py          # Lexical analysis
    parser.py           # Parser
    evaluator/          # Execution engine
    backends/c/         # C code generator
    stdlib/             # Joy standard library
  tests/
    joy/                # Joy language tests
    test_*.py           # pytest unit tests
  docs/
    pyjoy.md            # Implementation spec
    pythonic-mode.md    # Python integration guide
    comparison-with-joy.md  # Word comparison tables
    tutorial.md         # Getting started

Documentation

License

MIT License - see LICENSE file for details.

References

Metadata

Release files for pyjoy-lang 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyjoy-lang 0.1.2
File Size Uploaded Provenance
pyjoy_lang-0.1.2.tar.gz 190.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pyjoy-lang 0.1.2
File Interpreter ABI Platform
pyjoy_lang-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 341.3 kB

Release files / pyjoy_lang-0.1.2.tar.gz

Download URL pyjoy_lang-0.1.2.tar.gz
Size 190.5 kB
Tags Source
SHA-256 checksum
How to use checksums
343db87a349bebe264e579aa3c4279ea33fd26351f07766f646abe2fcb9bff6f
BLAKE2b-256 checksum
How to use checksums
1265afaf36ad8db538d0480697eb3d99ed4f98826a3aaded728efacd6151cd1f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / pyjoy_lang-0.1.2-py3-none-any.whl

Download URL pyjoy_lang-0.1.2-py3-none-any.whl
Size 150.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
69514d4c62bce4874b7305bcda7963ed4c8951f17a241ffeed23abee1def0a71
BLAKE2b-256 checksum
How to use checksums
e722c96e106cabbd9f9a7371abfae87f2b3f7ff524950fe1b43e8249029d0ec8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Security for pyjoy-lang 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page