Skip to main content

Snail programming language interpreter

Project description

Snail logo

Snail

What do you get when you shove a snake in a shell?

Snail, while I hope it is useful to myself and others, is my attempt at improving my knowledge of AI code developement. Things are probably broken in interesting and horrible ways.


Snail is a programming language that compiles to Python, combining Python's power with Perl/awk-inspired syntax for quick scripts and one-liners. No more whitespace sensitivity—just curly braces and concise expressions.

Installing Snail

Install uv and then run:

uv tool install -p 3.12 snail-lang

That installs the snail CLI for your user; try it with snail "print('hello')" once the install completes.

✨ What Makes Snail Unique

Curly Braces, Not Indentation

Write Python logic without worrying about whitespace:

def process(items) {
    for item in items {
        if item > 0 { print(item) }
        else { continue }
    }
}

Note, since it is jarring to write python with semicolons everywhere, semicolons are optional. You can separate statements with newlines.

Awk Mode

Process files line-by-line with familiar awk semantics:

BEGIN { total = 0 }
/^[0-9]+/ { total = total + int($1) }
END { print("Sum:", total); assert total == 15}

Built-in variables: $l (line), $f (fields), $n (line number), $fn (per-file line number), $p (file path), $m (last match).

Compact Error Handling

The ? operator makes error handling terse yet expressive:

# Swallow exception, return None
err = risky()?

# Swallow exception, return exception object
err = risky():$e?

# Provide a fallback value (exception available as $e)
value = js("malformed json"):{}?
details = fetch_url("foo.com"):"default html"?
exception_info = fetch_url("example.com"):$e.http_response_code?

# Access attributes directly
name = risky("")?.__class__.__name__
args = risky("becomes a list"):[1,2,3]?[0]

Pipeline Operator

The | operator enables data pipelining as syntactic sugar for nested function calls. x | y | z becomes z(y(x)). This lets you stay in a shell mindset.

# Pipe data to subprocess stdin
result = "hello\nworld" | $(grep hello)

# Chain multiple transformations
output = "foo\nbar" | $(grep foo) | $(wc -l)

# Custom pipeline handlers
class Doubler {
    def __call__(self, x) { return x * 2 }
}
doubled = 21 | Doubler()  # yields 42

Arbitrary callables make up pipelines, even if they have multiple parameters. Snail supports this via placeholders.

greeting = "World" | greet("Hello ", _)  # greet("Hello ", "World")
excited = "World" | greet(_, "!")        # greet("World", "!")
formal = "World" | greet("Hello ", suffix=_)  # greet("Hello ", "World")

When a pipeline targets a call expression, the left-hand value is passed to the resulting callable. If the call includes a single _ placeholder, Snail substitutes the piped value at that position (including keyword arguments). Only one placeholder is allowed in a piped call. Outside of pipeline calls, _ remains a normal identifier.

Built-in Subprocess

Shell commands are first-class citizens with capturing and non-capturing forms.

# Capture command output with interpolation
greeting = $(echo hello {name})

# Pipe data through commands
result = "foo\nbar\nbaz" | $(grep bar) | $(cat -n)

# Check command status
@(make build)?  # returns exit code on failure instead of raising

Regex Literals

Snail supports first class patterns. Think of them as an infinte set.

if bad_email in /^[\w.]+@[\w.]+$/ {
    print("Valid email")
}

# Compiled regex for reuse
pattern = /\d{3}-\d{4}/
match = pattern.search(phone)

NOTE: this feature is WIP.

JSON Queries with JMESPath

Parse and query JSON data with the js() function and structured pipeline accessor:

# Parse JSON and query with $[jmespath]

# JSON query with JMESPath
data = js($(curl -s https://api.github.com/repos/sudonym1/snail))
counts = data | $[stargazers_count]

# Inline parsing and querying
result = js('{{"foo": 12}}') | $[foo]

# JSONL parsing returns a list
names = js('{{"name": "Ada"}}\n{{"name": "Lin"}}') | $[[*].name]

Full Python Interoperability

Snail compiles to Python AST—import any Python module, use any library, in any environment. Assuming that you are using Python 3.10 or later.

🚀 Quick Start

# One-liner: arithmetic + interpolation
snail 'name="Snail"; print("{name} says: {6 * 7}")'

# JSON query with JMESPath
snail 'js($(curl -s https://api.github.com/repos/sudonym1/snail)) | $[stargazers_count]'

# Compact error handling with fallback
snail 'result = int("oops"):"bad int {$e}"?; print(result)'

# Regex match and capture
snail 'm = "user@example.com" in /^[\\w.]+@([\\w.]+)$/; if m { print(m[1]) }'

# Awk mode: print line numbers for matches
rg -n "TODO" README.md | snail --awk '/TODO/ { print("{$n}: {$l}") }'

🏗️ Architecture

Key Components:

  • Parser: Uses Pest parser generator with PEG grammar defined in src/snail.pest
  • AST: Separate representations for regular Snail (Program) and awk mode (AwkProgram) with source spans for error reporting
  • Lowering: Transforms Snail AST into Python AST, emitting helper calls backed by snail.runtime
    • ? operator → __snail_compact_try
    • $(cmd) subprocess capture → __SnailSubprocessCapture
    • @(cmd) subprocess status → __SnailSubprocessStatus
    • Regex literals → __snail_regex_search and __snail_regex_compile
  • Execution: Compiles Python AST directly for in-process execution
  • CLI: Python wrapper (python/snail/cli.py) that executes via the extension module

📚 Documentation

🔌 Editor Support

Vim/Neovim plugin with syntax highlighting, formatting, and run commands:

Plug 'sudonym1/snail', { 'rtp': 'extras/vim' }

See extras/vim/README.md for details. Tree-sitter grammar available in extras/tree-sitter-snail/.

🛠️ Building from Source

Prerequisites

Python 3.10+ (required at runtime)

Snail runs in-process via a Pyo3 extension module, so it uses the active Python environment.

Installation per platform:

  • Ubuntu/Debian: sudo apt install python3 python3-dev
  • Fedora/RHEL: sudo dnf install python3 python3-devel
  • macOS: brew install python@3.12 (or use the system Python 3)
  • Windows: Download from python.org

No Python packages required: Snail vendors jmespath under snail.vendor.

Build, Test, and Install

# Clone the repository
git clone https://github.com/sudonym1/snail.git
cd snail

make test
make install

Note on Proptests: The snail-proptest crate contains property-based tests that are skipped by default to keep development iteration fast.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

snail_lang-0.3.9.tar.gz (70.6 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

snail_lang-0.3.9-cp310-abi3-win_amd64.whl (494.4 kB view details)

Uploaded CPython 3.10+Windows x86-64

snail_lang-0.3.9-cp310-abi3-manylinux_2_34_x86_64.whl (4.4 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.34+ x86-64

snail_lang-0.3.9-cp310-abi3-macosx_11_0_arm64.whl (536.7 kB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

Details for the file snail_lang-0.3.9.tar.gz.

File metadata

  • Download URL: snail_lang-0.3.9.tar.gz
  • Upload date:
  • Size: 70.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for snail_lang-0.3.9.tar.gz
Algorithm Hash digest
SHA256 9187d42ceff80b18ff9b381e38cdb8b480b64529289ccd18fe112191efb98b1e
MD5 50a213f8c31fbf363b7ed8f1cc5bb2d4
BLAKE2b-256 bd7dd2cda3e7c478de2a8bcde519937b8bf3678db16d35b325c2fb1b83b8e0ba

See more details on using hashes here.

Provenance

The following attestation bundles were made for snail_lang-0.3.9.tar.gz:

Publisher: release.yml on sudonym1/snail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file snail_lang-0.3.9-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: snail_lang-0.3.9-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 494.4 kB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for snail_lang-0.3.9-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 e25d9bf9cdca3d410a207724ba0aa3107a7914a71166afd11ae98c151d204ca2
MD5 e1ded9bbf4d74675809cc76e25fef0fc
BLAKE2b-256 f7dd326b662d5fbb8c2685e7c91a2314757cfcf7d443b2cca4a5e3ab73fbd56b

See more details on using hashes here.

Provenance

The following attestation bundles were made for snail_lang-0.3.9-cp310-abi3-win_amd64.whl:

Publisher: release.yml on sudonym1/snail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file snail_lang-0.3.9-cp310-abi3-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for snail_lang-0.3.9-cp310-abi3-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 10a9344845c72a49709cb92e4a77c077624ecd33db319969aebd856d01d8ae35
MD5 a82b88641d68cf98b69af6c231b796bb
BLAKE2b-256 f54ba6a029812c926254a225e5f482029a246083d531135c2d144671c17c0af2

See more details on using hashes here.

Provenance

The following attestation bundles were made for snail_lang-0.3.9-cp310-abi3-manylinux_2_34_x86_64.whl:

Publisher: release.yml on sudonym1/snail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file snail_lang-0.3.9-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for snail_lang-0.3.9-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 11f37c4fbccee75050cbac4e32cd51b52e2e889850660c2246b36bcf85b873b6
MD5 cbe22ebd2f173658e9e197b038cbf38e
BLAKE2b-256 9679802ff2d85d0784e36181a479b6b5e0252e6ab961bcbe5e80a6416d77faf0

See more details on using hashes here.

Provenance

The following attestation bundles were made for snail_lang-0.3.9-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on sudonym1/snail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page