We are currently working on new rules for what content should and shouldn't be allowed on this website, and are looking for feedback! See Esolang:2026 topicality proposal to view and give feedback on the current draft.

SunnyShell

From Esolang
Jump to navigation Jump to search

SunnyShell is a shell-style programming language designed by PSTF.

Core Philosophy

  • No text-munging by default.
  • Command after arguments.
  • Explicit over implicit.
  • Immutable by default.

Core Features

The Stack & Data Types

You interact with a single, persistent stack. Typing a literal pushes it onto the stack.

These are all valid literals.

114514
3.1415926
"Hello, World!"
true
false
-135
-123.456
[1 2 "Three"]
{ name:"file" size:1024 }
{ size 1024 gt }

Example:

Admin ~/ !> 42 "answer"  
# Stack now: [0] 42, [1] "answer"

The Command Language

Built-in Commands (Words)

Every built-in is a lowercase word that pops required arguments from the stack and pushes the result back.

Category	Words					Effect
Stack		dup, drop, swap, over, rot...		Standard stack manipulation.
Math		add, sub, mul, div, mod, abs...		Pop two, push result.
Logic		gt, lt, eq, ne, and, or, not...		Pop two, push boolean.
Lists/Tables	length, push, pop, get, keys...		Pop list/table, push derived data.
Iteration	map, filter, reduce, each...		Pop a list and a block, push a new list.
Variables	set, @ (fetch)...			Pop value + name to store; @name to push.
I/O		print, println, read...			Print stack top; read stdin into stack.
Filesystem	ls, cd, pwd, mkdir, remove, mv...	Work on paths (strings) and file tables.
OS related	tk, start, help...			Binded with the OS behaviours.

External Commands

To escape into the underlying OS, prefix with $.

Magic behavior
If a string is on top of the stack, SunnyShell feeds it as stdin to the external process.
$ git status          # Runs git, pushes stdout as a single string
"Hello" $ cowsay      # Pipes "Hello" into cowsay's stdin

Variables & Flow Control

Variables

Set a variable by pushing a name and a value, then using set:

"my_files" ls set   # Stores the ls-result into 'my_files'
@my_files length    # Fetches the variable, computes its length

Conditionals (if)

{ @usage 80 > }          # Condition (pushes boolean)
{ "Warning!" println }   # Then
{ "All good" println }   # Else
if                       # Executes conditionally

Loops

each
Pop a list and a block. Execute block for each item.
while
Pop a condition-block and a body-block. Loop until false.
# Print every file name in the current directory
ls { name println } each

Functions (def)

Define a new word using : (colon) and def. The function operates on the stack when called.

: double { 2 mul } def
5 double println   # Prints 10

Working with the Filesystem (STRUCTURED!)

Because ls returns structured tables, filtering is type-safe and readable.

# Find all files > 1MB, sort by size descending, take top 3
ls 
{ size 1048576 gt } filter 
{ size } sort-desc   # 'sort-desc' pops a list and a key-block
3 take 
{ name println } each

No ls -l | grep ... | awk ... in sight.

Robust Error Handling

Errors don't crash the world. Use try and catch with blocks:

try {
  $ rm -rf /important
} catch {
  "Failed to delete: " swap + println   # Catch block receives the error string
}

Examples

Hello, World!

"Hello, World!" println

Zombie-process Cleaning

This program will find any running zombie processes and terminate them. If no zombie processes are found, it returns with error code 0. If it does find any, it terminates them directly and returns with error code 1 after all of them have been terminated.

#!/usr/bin/env sunnyshell
# kill-zombies.s2s
false "%debug-mode" set

"Starting zombie hunt..." println

# 1. Run ps, split stdout into a list of lines
$ ps aux lines -> "raw_lines" set

# 2. Filter lines containing 'Z' (zombie state)
@raw_lines { "Z" contains? } filter -> "zombie_lines" set

# 3. If none, exit early
@zombie_lines length 0 eq {
  "No zombies found. Peace." println
  exit 0
} {
  @zombie_lines length "Zombies found: " swap + println
} if

# 4. Extract PIDs (assumes PID is the 2nd column in `ps aux`)
@zombie_lines 
{ split-whitespace } map   # Convert each line to a list of columns
{ [1] get } map            # Get the 2nd column (PID)
-> "pids" set

# 5. Kill them with extreme prejudice
@pids { 
  dup "Killing PID " swap add println
  tk -regardless -forcibly
  # Pop the top of the stack and parse it as an integer,
  # then terminate the process with that PID. 
  # The two switches indicate whether to ignore if the operation of this process 
  # is already done and to force close.
} each
"Operation completed." println
exit 1

The Interactive Experience

The REPL (Read-Eval-Print Loop) is built for visibility:

  • Prompt: Current_User current/dir !>
  • Stack Viewer: After every command, it shows the top 5 stack items with indices. You can also set "%debug-mode" to false to cancel this feature.
  • Tab Completion: Completes built-in words, variable names (@), and file paths.
  • History: Persistent across sessions.

Interactive debugging:

Admin ~/ !> ls
Stack: [0] [Table(name="docs", size=4096), Table(name="notes.txt", size=120)]
Admin ~/ !> { size 100 > } filter
Stack: [0] [Table(name="docs", size=4096)]

Why This Breaks the Mold

Feature		Bash / Cmd / PowerShell			SunnyShell
Data Model	Strings or heavy .NET objects		Stacked, immutable, lightweight tables/lists
Parsing Output	grep, awk, sed hell			First-class filters (filter, map) on typed data
Syntax		Infix / Prefix (confusing flags)	Postfix (RPN) – deterministic, no operator precedence
Pipes		Byte-streams (|)			No pipes. Data sits on the stack, ready for the next word.
Variables	$var everywhere, quoting chaos		set to store, @ to fetch (unambiguous)
Control Flow	if [ ... ]; then ...			Blocks on the stack ({...} {...} if)
External Calls	$(cmd) spawning subshells		$ cmd with optional stdin push from stack

Conceptual Installation

# Install via Cargo (Rust) or a single static binary
$ curl -sf https://s2.shell.abovesolstice/install | sh
$ sunnyshell
PrySigneToFry ~/ > 

Summary

SunnyShell isn't just a shell—it's a new way of thinking about system interaction. By making data explicit and operations sequential, it eliminates entire classes of bugs (word-splitting, globbing, ambiguous redirects) that have plagued terminal users for decades.

Fun Facts

This is also designed by the author's timeline #284436, and also appears in timeline #811047 and #3018472.

Categories