Skip to main content

SpaceLang

SpaceLang is an experimental stack-based language toolkit. It currently contains a Python reference VM, an experimental C++ VM, a small Python-subset frontend, and tools for assembling, disassembling, and encoding SpaceLang programs.

Status: Early development. The frontend and VM implement a subset of Python and the project is not yet a drop-in Python runtime. See the source and tests for the behavior currently supported.

Requirements

  • Python 3.10 or newer
  • A C++17 compiler and CMake 3.18 or newer to build the native extension

Install

Install the package from a checkout:

git clone https://github.com/DwwLSM/spacelang.git
cd spacelang
python -m pip install .

For development, install the package with its test dependencies in editable mode:

python -m pip install -e ".[dev]"
python -m pytest

Run Python-subset source

Compile supported Python syntax to a SpaceLang program, then execute it with the reference VM:

from spacelang.pyfront import compile_py
from spacelang.vm_py import VM

source = """
def add(a, b):
    return a + b

i = 0
while i < 3:
    print(add(i, 2))
    i = i + 1
"""

program = compile_py(source)
VM(program).run()

Output:

2
3
4

The current frontend handles basic integer, boolean, and string constants, arithmetic, comparisons, boolean expressions, calls, assignments, supported imports, if/else, while, simple positional functions, and for loops over range(...). Sequence indexing is supported for indexable values.

This is still a Python subset, not full Python; features such as classes, exceptions in source code, generators, nested or filtered comprehensions, keyword arguments to user functions, and general iterator protocols are not implemented. Unsupported syntax raises an error rather than being silently compiled.

Run a .sp program

Write assembly mnemonics to a .spasm file, assemble it into the whitespace-only .sp format, then run it with the reference VM:

example.spasm:

PUSH_INT 2
PUSH_INT 3
OP 1
CALL 0 1
STACK 3
HALT

Run these commands from an installed checkout:

spacelang asm example.spasm example.sp
spacelang disasm example.sp
spacelang run example.sp

The program prints 5. CALL 0 1 calls the print builtin; STACK 3 drops the builtin's return value. To use the source checkout without installing the command, invoke the CLI as python -m spacelang.main run example.sp.

How whitespace becomes instructions

A .sp file is a stream of integer tokens written as spaces and newlines. The number of spaces before each newline is one token's value; the newline ends that token. The parser reads the first token as an opcode, then consumes the number of argument tokens required by that opcode. For example, PUSH_INT 2 is encoded as the tokens 7 (the PUSH_INT opcode) and 4 (zig-zag encoded integer 2). OP 1 is the tokens 5 (OP) and 1 (addition). The VM executes the resulting instructions; spaces are not executed one at a time.

For the example above, the token values are:

Assembly Space-count tokens
PUSH_INT 2 7, 4
PUSH_INT 3 7, 6
OP 1 5, 1
CALL 0 1 1, 0, 1
STACK 3 6, 3
HALT 29

Space instruction table

Every .sp token is the count of spaces before a newline. The first token of each instruction is its opcode ID; the following tokens are its arguments. PUSH_INT uses zig-zag encoding for its integer argument. PUSH_STR is followed by a length and then one code-point token per character. Name IDs refer to the program's name table. The .name, .label, and .enddef forms are assembler directives, not VM opcodes.

ID Mnemonic Arguments in .spasm Reference VM effect
0 NOP none Do nothing.
1 CALL func_id, nargs Call a builtin or user function with positional arguments. A builtin's result is pushed.
2 CALL_KW func_id, npos, nkw Call a builtin with positional and keyword arguments; user functions are not supported here.
3 CALL_OBJ nargs Pop a callable and its positional arguments, call it, and push the result.
4 IMPORT module_id Import a supported module and push it.
5 OP operation_id Pop two operands, apply the selected binary operation, and push the result.
6 STACK stack_operation_id Apply a stack manipulation operation.
7 PUSH_INT integer Push an integer; its argument token is zig-zag encoded.
8 PUSH_STR length, codepoint... Push a string from the specified number of code points.
9 LOAD_GLOBAL name_id Push a global value; an undefined name raises an error.
10 STORE_GLOBAL name_id Pop a value and store it as a global.
11 GET_ATTR name_id Pop an object and push the named attribute.
12 CALL_METHOD name_id, nargs Pop a receiver and arguments, call the named method, and push its result.
13 INDEX reserved Pop a key and container, then push container[key]; the argument is currently ignored.
14 BUILD_LIST count Pop count values and push a list in their original order.
15 BUILD_TUPLE count Pop count values and push a tuple in their original order.
16 CONCAT count Pop and concatenate count homogeneous strings, bytes, lists, or tuples.
17 DEF func_id, nargs Mark a function entry; execution skips its body when reached in normal flow.
18 RET none Return the top stack value from the current function.
19 LOAD_ARG index Push a function argument by slot index.
20 LOAD_LOCAL slot Push a local variable by slot index.
21 STORE_LOCAL slot Pop and store a local variable by slot index.
22 JMP target_ip Jump to an instruction index.
23 JZ target_ip Pop a condition; jump if it is false.
24 JNZ target_ip Pop a condition; jump if it is true.
25 RAISE none Pop an exception value and raise it through the active handler, if any.
26 TRY catch_ip, finally_ip Begin a protected region; 0 means that the corresponding handler is absent.
27 END_TRY none Close a try/catch/finally region and continue its control flow.
28 SETUP_WITH none Pop a value onto the VM's with-stack; this alone does not implement Python's full with protocol.
29 HALT none Stop execution; if the stack is non-empty, pop its top as the run result.

OP operation IDs:

ID Operation
1 Addition (left + right)
2 Subtraction (left - right)
3 Multiplication (left * right)
4 True division (left / right)
5 Modulo (left % right)
6 Equal (left == right)
7 Less than (left < right)
8 Greater than (left > right)
9 Not equal (left != right)
10 Less than or equal (left <= right)
11 Greater than or equal (left >= right)

STACK operation IDs (top means the rightmost stack value):

ID Operation Effect
1 DUP Duplicate the top value.
2 SWAP Swap the top two values.
3 DROP Remove the top value.
4 OVER Copy the second value to the top.
5 ROT Rotate the top three values from [a, b, c] to [b, c, a].

IMPORT module IDs are 0=math, 1=random, 2=os, 3=re, and 4=sys. Jump targets and name IDs are zero-based. Function IDs of 10000 or greater identify user-defined functions in the reference VM.

Each individual token is limited to 65,535 spaces. A direct PUSH_INT 100000 would require an argument token of 200,000 spaces because positive integers use zig-zag encoding, so it cannot be encoded as one token. For a Python-subset source constant, use --compress-source; for 100000, the compiler can factor it into smaller constants and multiplication instructions:

large.py:

print(100000)
spacelang compile-py large.py large.sp --compress-source
spacelang run large.sp

This prints 100000. --compress-source makes the integer representable using multiple small tokens; it does not mean that one very long run of spaces is executed. .spz is a separate gzip-compressed container for an already encoded .sp program.

Create a self-copying program

For Python files, quine writes a new file with a small hook that copies that generated file to a .copy.py sibling when run. The input file is left unchanged:

from spacelang.quine import quine

quine("example.py", "example_quine.py")

Then run python example_quine.py. The CLI equivalent is:

python -m spacelang.quine example.py example_quine.py

The CLI also supports --in-place --yes; it creates a .bak backup before replacing the source. The Python API itself rejects in-place operation. SpaceLang .sp/.spz quines produce a companion .names.json file because the instruction stream stores name IDs, not their textual names.

Command-line tools

The command-line interface supports Python compilation, assembly, disassembly, execution with the reference VM, and .sp/.spz compression:

spacelang compile-py example.py example.sp
spacelang run example.sp
spacelang run example.sp --engine cpp
spacelang disasm example.sp
spacelang pack example.sp
spacelang run example.spz

The module form remains available when invoking the source checkout directly:

python -m spacelang.main run example.sp

Compilation enables the safe peephole optimizations and integer constant pool by default. Pass --no-optimize to compile-py to preserve the frontend IR, or --compress-source to factorize large integer constants before encoding. The C++ engine is experimental and is not the default. GCC and Clang builds use computed-goto instruction dispatch; other compilers use a portable switch dispatcher. Use the Python engine as the reference for behavior that has not yet been verified for native parity.

To compare both engines on the same recursive workload after installation:

python -m benchmarks.benchmark_vm --n 25 --repeat 3

The benchmark checks that both engines return the same result and reports the median runtime and speedup. Timings depend on the host and are not a performance guarantee.

Assemble and run instructions

The assembler accepts one mnemonic instruction per line. For example:

from spacelang.asm import assemble
from spacelang.vm_py import VM

program = assemble("""
PUSH_INT 2
PUSH_INT 3
OP 1
HALT
""")

print(VM(program).run())

OP 1 adds the two values on top of the stack. This example prints 5.

Inspect and encode programs

from spacelang.asm import assemble
from spacelang.disasm import disassemble
from spacelang.encoder import encode
from spacelang.lexer import tokenize
from spacelang.parser import parse

program = assemble("PUSH_INT 2\nPUSH_INT 3\nOP 1\nHALT\n")

print(disassemble(program))   # Human-readable instructions
encoded = encode(program)     # SpaceLang whitespace encoding
tokens = tokenize(encoded)
decoded_program = parse(tokens)

The package also exports the core Program, Instr, and OP types, along with assemble, disassemble, encode, parse, and tokenize from spacelang.

Development

Run the test suite from the repository root:

python -m pytest

The tests cover the current IR, encoding/parser, assembler/disassembler, VM, Python-subset frontend, and native/reference differential behavior.

Render the introduction animation

The Manim scene source is in scene.py. Install the optional animation dependency (and Manim's required system packages; see the Manim installation guide):

python -m pip install -e ".[animation]"

Render an English version with subtitles:

manim -ql scene.py SpacelangIntroEnglishWithSubtitle

Use SpacelangIntroChineseWithSubtitle, SpacelangIntroEnglishWithoutSubtitle, or SpacelangIntroChineseWithoutSubtitle for the other variants. Manim writes rendered videos and its generated assets under media/; these are ignored by Git and can be recreated from scene.py.

Metadata

Release files for spacelanguage 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 spacelanguage 0.1.2
File Size Uploaded Provenance Actions
spacelanguage-0.1.2.tar.gz 59.9 kB Without provenance Details for spacelanguage-0.1.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for spacelanguage 0.1.2
File Interpreter ABI Platform Actions
spacelanguage-0.1.2-cp313-cp313-macosx_15_0_arm64.whl CPython 3.13 CPython 3.13 macOS 15.0+ ARM64 Details for spacelanguage-0.1.2-cp313-cp313-macosx_15_0_arm64.whl

Total release size: 191.2 kB

Release files / spacelanguage-0.1.2.tar.gz

Download URL spacelanguage-0.1.2.tar.gz
Size 59.9 kB
Tags Source
SHA-256 checksum
How to use checksums
bb09e19f1332a38d96630f3dd2cdab470690eb8b58559c4595721d1377deb2f3
BLAKE2b-256 checksum
How to use checksums
2b89d8956eac40d04c7fc7c1cc89eb95a42f260d1c95fcfacea62db5b174f7a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.3

Release files / spacelanguage-0.1.2-cp313-cp313-macosx_15_0_arm64.whl

Download URL spacelanguage-0.1.2-cp313-cp313-macosx_15_0_arm64.whl
Size 131.3 kB
Tags CPython 3.13 macOS 15.0+ ARM64
SHA-256 checksum
How to use checksums
b769578aff8f243bea48b47c808174c7acda6d46783c467334ab54feefd99cac
BLAKE2b-256 checksum
How to use checksums
76f18e20709920c42eeb270a325c960a8a97510344d14d41543b2d848f0dbad4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.3

Security for spacelanguage 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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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