Snail programming language interpreter
Project description
What do you get when you shove a snake in a shell?
Snail
Snail is a programming language that compiles to Python, combining Python's familiarity and extensive libraries with Perl/awk-inspired syntax for quick scripts and one-liners.
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: $0 (line), $1, $2 etc (access 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}: {$0}") }'
🏗️ 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_searchand__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
- Language Reference — Complete syntax and semantics
- examples/all_syntax.snail — Every feature in one file
- examples/awk.snail — Awk mode examples
🔌 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
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file snail_lang-0.4.0.tar.gz.
File metadata
- Download URL: snail_lang-0.4.0.tar.gz
- Upload date:
- Size: 57.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98731e226bda2ed9f8c4c0b56b47803d09b4fdd73d053b4f88cd908149374efd
|
|
| MD5 |
7182c08126bd87ecbc23cc47056c7897
|
|
| BLAKE2b-256 |
be1308d438ef0df3f941405cb89e2b8a8c7b2a1ceccfd584fc564f38c50ea29d
|
Provenance
The following attestation bundles were made for snail_lang-0.4.0.tar.gz:
Publisher:
release.yml on sudonym1/snail
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
snail_lang-0.4.0.tar.gz -
Subject digest:
98731e226bda2ed9f8c4c0b56b47803d09b4fdd73d053b4f88cd908149374efd - Sigstore transparency entry: 832667534
- Sigstore integration time:
-
Permalink:
sudonym1/snail@757673f84967bc4e99c1e202deb81a1aca7ee470 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/sudonym1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@757673f84967bc4e99c1e202deb81a1aca7ee470 -
Trigger Event:
push
-
Statement type:
File details
Details for the file snail_lang-0.4.0-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: snail_lang-0.4.0-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 478.8 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a0218b75bb8f4f7848dc9808dfbf197a769a9467458ac50ac02321756eb7586a
|
|
| MD5 |
8411e9d70470951880c91eb4bd2ceca0
|
|
| BLAKE2b-256 |
aee7c5687e72076a892bc1ac240739155f7e5274823473aaf71de7fe97189cab
|
Provenance
The following attestation bundles were made for snail_lang-0.4.0-cp310-abi3-win_amd64.whl:
Publisher:
release.yml on sudonym1/snail
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
snail_lang-0.4.0-cp310-abi3-win_amd64.whl -
Subject digest:
a0218b75bb8f4f7848dc9808dfbf197a769a9467458ac50ac02321756eb7586a - Sigstore transparency entry: 832667539
- Sigstore integration time:
-
Permalink:
sudonym1/snail@757673f84967bc4e99c1e202deb81a1aca7ee470 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/sudonym1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@757673f84967bc4e99c1e202deb81a1aca7ee470 -
Trigger Event:
push
-
Statement type:
File details
Details for the file snail_lang-0.4.0-cp310-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: snail_lang-0.4.0-cp310-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 4.3 MB
- Tags: CPython 3.10+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
461a9b3269c6c8ea099f8ad5cd2b9459824eb49c6f1be6554e1c83800ab28259
|
|
| MD5 |
2643710a6191d7b5201aa2bc07b03df1
|
|
| BLAKE2b-256 |
1de7f0fccd6a816d1fc04db28ec50f75385217dfec458cec9aae5c0dd7bfd42a
|
Provenance
The following attestation bundles were made for snail_lang-0.4.0-cp310-abi3-manylinux_2_34_x86_64.whl:
Publisher:
release.yml on sudonym1/snail
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
snail_lang-0.4.0-cp310-abi3-manylinux_2_34_x86_64.whl -
Subject digest:
461a9b3269c6c8ea099f8ad5cd2b9459824eb49c6f1be6554e1c83800ab28259 - Sigstore transparency entry: 832667536
- Sigstore integration time:
-
Permalink:
sudonym1/snail@757673f84967bc4e99c1e202deb81a1aca7ee470 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/sudonym1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@757673f84967bc4e99c1e202deb81a1aca7ee470 -
Trigger Event:
push
-
Statement type:
File details
Details for the file snail_lang-0.4.0-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: snail_lang-0.4.0-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 518.7 kB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
037654f36737b60182a1f5b7ae7b2e958f9e55adcf3e53db0bb9d91582b9d242
|
|
| MD5 |
84ca5fc0058edbc7345ecd1d7bdf9513
|
|
| BLAKE2b-256 |
110e3b22eeea94cf4138676624a92544ca2aae18d2b3e7a0dbb08e5a39c0b7b1
|
Provenance
The following attestation bundles were made for snail_lang-0.4.0-cp310-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on sudonym1/snail
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
snail_lang-0.4.0-cp310-abi3-macosx_11_0_arm64.whl -
Subject digest:
037654f36737b60182a1f5b7ae7b2e958f9e55adcf3e53db0bb9d91582b9d242 - Sigstore transparency entry: 832667535
- Sigstore integration time:
-
Permalink:
sudonym1/snail@757673f84967bc4e99c1e202deb81a1aca7ee470 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/sudonym1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@757673f84967bc4e99c1e202deb81a1aca7ee470 -
Trigger Event:
push
-
Statement type: