Shortcake is a modern, statically compiled programming language that emits MLIR IR for efficient native execution. It combines functional programming concepts with practical features like seamless C interoperability, a flexible module system, and comprehensive error handling.
- Language Specification - Complete formal specification with grammar, type system, and examples
- Safety: Strong static typing with type inference
- Expressiveness: Algebraic data types, pattern matching, and effects
- Pragmatism: Seamless C interoperability and straightforward syntax
- Modularity: Clear module system with explicit imports
- Performance: Static compilation to MLIR IR for efficient native execution
- Flexible multiline strings with customizable delimiters (
[[ ]],[=[ ]=], etc.) - Flexible multiline comments (
## ##,#=# #=#, etc.) - String interpolation with
#{expression}syntax - Optional parentheses for function definitions with no parameters
- Significant newlines for clean, readable code structure
- Algebraic Data Types (ADTs) with sum types and pattern matching
- Effects and Handlers for structured effectful programming
- Pattern matching with the
~operator and match expressions - Guard clauses for elegant error handling
- Struct system with methods and operator overloading
- Type unions (e.g.,
i33 | f64) for flexible typing - Anonymous functions and higher-order functions
- Range operators (
..inclusive,...exclusive) - Strong static typing with type inference
- Static compilation to MLIR IR for efficient native execution
- Zero-cost abstractions with monomorphized generics
- Native code generation via LLVM backend integration
- Direct C interoperability without FFI overhead
- Zig 0.11+ (systems programming language)
- LLVM 15+ (for MLIR and code generation)
- ANTLR 4.13+ (for parser generation)
git clone https://github.com/igorgue/shortcake.git
cd shortcake
zig build # debug build for development
zig build -Doptimize=ReleaseFast # optimized release build
zig build test # run testsnix-shell# Run with debug build (development)
zig build run -- test/examples/demo.sho
# Build and run optimized version
zig build -Doptimize=ReleaseFast run -- test/examples/demo.sho
# Build executable and run
zig build -Doptimize=ReleaseFast
./zig-out/bin/shortcake test/examples/demo.shoZig provides fast incremental compilation, making development iterations quick:
# Quick development testing
zig build run -- test/examples/demo.sho
# Run tests during development
zig build test
# Watch mode (if you have a file watcher set up)
# Automatically rebuild and test on file changesUse release builds for:
- Performance testing: Measuring optimized execution speed
- Final validation: Ensuring everything works in production mode
- Distribution: Creating optimized standalone executables
# Build optimized version
zig build -Doptimize=ReleaseFast
# Test with optimized build
./zig-out/bin/shortcake test/examples/test.sho# Run all tests
zig build test
# Run specific test files (if supported by test runner)
# zig build test -- test/examples/arithmetic_test.sho
# Integration testing
./zig-out/bin/shortcake test/examples/integration_test.sho# Integers
i8, i16, i32, i64, i128 # Signed integers
u8, u16, u32, u64, u128 # Unsigned integers
# Floats
f32, f64 # Single and double precision
# Boolean and String
bool # true or false
str # String values
# Lists (space-separated elements)
[] # Empty list
[1 2 3] # List of integers
["a" "b" "c"] # List of strings
[1 "mixed" true] # Heterogeneous list
# Dictionaries (space-separated key-value pairs)
{} # Empty dict
{key = "value" count = 42} # String keys
{1 = "one" 2 = "two"} # Integer keys
# Type Unions
i32 | str # Either integer or string
Option | Result # Union of custom types
# Generic Types
List<i32> # List of integers
Dict<str, i32> # Dictionary with string keys, integer values
42 # Integer
0b1010 # Binary
0xFF # Hexadecimal
3.14 # Float
1.5e10 # Scientific notation
"hello" # String
"Interpolated: #{value}" # String interpolation
true, false # Boolean
null # Null value
-x # Negation
+x # Positive (no-op)
not x # Logical NOT
&x # Address of (C interop)
*x # Dereference (C interop)
# Arithmetic (precedence: high to low)
a ** b # Power
a * b, a / b, a % b # Multiplication, division, modulo
a + b, a - b # Addition, subtraction
# Comparison
a == b, a != b # Equality, inequality
a < b, a > b # Less than, greater than
a <= b, a >= b # Less/greater or equal
# Logical
a and b # Logical AND
a or b # Logical OR
# Bitwise
a & b # Bitwise AND
a | b # Bitwise OR
a ^ b # Bitwise XOR
a << b, a >> b # Bit shifts
# Membership and Ranges
a in list # Membership test
a..b # Inclusive range
a...b # Exclusive range
a..b by step # Range with step
func() # No arguments
func(1, 2, 3) # Multiple arguments
obj.method(arg) # Method call
list.length() # Built-in method
x = 42 # Simple assignment
x: i32 = 42 # Typed assignment
x += 1 # Compound assignment
# Block form
if condition do
# then block
else if other_condition do
# else if block
else do
# else block
end
# One-liner
if condition = expression
# Single statement
if condition statement
# Unless statement
unless condition do
# block
end
# While loop
while condition do
# loop body
end
# For loop
for i in 1..10 do
# loop body
end
for i in 1..10 by 2 do
# loop body
end
# Infinite loop
loop do
break when condition
end
return value # Return from function
break # Exit loop
continue # Next iteration
guard condition else do
# error handling
error("Guard failed")
end
# Block form
fn add(a: i32, b: i32) do
a + b
end
# Assignment form (sugar)
fn add(a: i32, b: i32) = a + b
# No parameters
fn greet do
"Hello, World!"
end
# Method on struct
fn Point.distance(other: Point) do
((self.x - other.x)^2 + (self.y - other.y)^2)^0.5
end
fn(x) = x * 2 # Assignment form
fn(x) do x * 2 end # Block form
fn do 42 end # No parameters
multiplier = 2
fn multiply(x) = x * multiplier # Captures multiplier
# Block form
struct Point do
x: i64
y: i64
end
# Assignment form (sugar)
struct Point = x: i64, y: i64
# With inheritance/mixins
struct ColoredPoint do
base Point
color: str
end
# Default constructor
default Point = Point(0, 0)
# Custom constructor
new Point x: i64, y: i64 do
# validation logic
self.x = x
self.y = y
end
# Method
fn Point.distance(other: Point) do
((self.x - other.x)^2 + (self.y - other.y)^2)^0.5
end
# Usage
p = Point(10, 20)
dist = p.distance(other_point)
# Block form
op Point + Point do
Point(left.x + right.x, left.y + right.y)
end
# Assignment form
op Point + Point = Point(left.x + right.x, left.y + right.y)
# Custom named operator
op Rectangle scaled_by factor do
Rectangle(left.width * factor, left.height * factor)
end
# Usage
sum = point1 + point2
type Option = Some(value: i32) | None
type Result = Ok(value: i32) | Error(message: str)
type Color = Red | Green | Blue
some_value = Some(42)
no_value = None
success = Ok(200)
error = Error("Something went wrong")
color = Red
value ~ do
Some(x) do
# handle Some
x
end
None do
# handle None
0
end
end
# Match assignment
result ~ Some(x) = some_option
effect State do
fn get() : i32
fn set(value: i32)
end
effect Async do
fn await() : i32
fn complete(value: i32)
end
handler State(initial: i32) do
handle get() do
current
end
handle set(value) do
current = value
end
end
# Call effect operation
State.get()
State.set(42)
# Handle with handler
handle State(0) do
# code using State effects
State.set(100)
result = State.get()
end
$include <stdio.h>
$include "myheader.h"
$load "libm.so"
# Direct call
$printf("Hello, %s!\n", "World")
# Function pointers
$malloc = $load "libc.so.6"
ptr = $malloc(1024)
$free(ptr)
# Basic C types
$int, $char, $float, $double, $void
# Pointers
$int*, $char**
# Arrays
$int[10], $char[]
# Function pointers
$int (*$func)($int, $int)
$typedef struct {
$int x;
$int y;
} $Point;
# Usage
point = $Point(x: 10, y: 20)
# Module is defined by file path
# utils/math.sho defines module utils.math
# Export symbols (all declarations are exported by default)
fn add(a: i32, b: i32) = a + b
fn multiply(a: i32, b: i32) = a * b
# Private symbols (prefix with underscore)
fn _helper() = "internal"
# Import entire module
import utils.math
# Import with alias
import utils.math as math
# Import specific symbols
from utils.math import add, multiply
# Import all symbols
from utils.math import *
# Dollar prefix for C imports
$include <math.h>
$from <math.h> $import $sin, $cos
# Current directory
import .local_module
# Parent directory
import ..parent_module
# Sibling directory
import ..sibling.module
print(value1, value2, ...) # Print values
format(pattern, ...) # Format string
list.length() # Get length
list.append(item) # Append item
list.concat(other_list) # Concatenate lists
dict.keys() # Get keys
dict.values() # Get values
dict.get(key, default) # Get with default
string.length() # Get length
string.contains(substring) # Check containment
string.split(delimiter) # Split string
type(value) # Get type
value is type # Type check
print("Hello, World!")
x = 5
y = 10
sum = x + y
print("Sum: #{sum}") # String interpolation
fn add_one(x: i32) = x + 1
fn sum(a: i32, b: i32) do
a + b
end
fn divide(a: i32, b:i32) do
guard b != 0 else error "Division by zero"
a / b
end
if x > 0 do
print("positive")
else if x < 0 do
print("negative")
else do
print("zero")
end
for i in 1..10 do
print("i = #{i}")
end
numbers = [1 2 3 4 5]
words = ["hello" "world"]
combined = numbers + [6 7 8]
person = {
name = "Alice"
age = 30
city = "New York"
}
print("Name: #{person.name}")
struct Rectangle do
width: i32
height: i32
end
fn Rectangle.default = Rectangle(0, 0)
fn Rectangle.new(width: i64, height: i64) do
self.width = width
self.height = height
end
fn Rectangle.area do
self.width * self.height
end
r = Rectangle(10, 20)
print("Area: #{r.area}")
type Option = Some(value: i32) | None
fn get_value(opt: Option) do
opt ~ do
Some(x) do x end
None do 0 end
end
end
result = Some(42)
value = get_value(result)
print("Value: #{value}")
# Import standard library
import utils.math
# Define a custom type
type Result = Ok(value: i32) | Error(message: str)
# Define a struct
struct Calculator do
memory: i64
end
# Default constructor
default Calculator = Calculator(0)
# Method
fn Calculator.add(value: i64) do
self.memory = self.memory + value
self.memory
end
# Main function
fn main() do
calc = Calculator()
result = calc.add(42)
print("Result: #{result}")
# Pattern matching
match_result = Ok(result)
match_result ~ do
Ok(value) do
print("Success: #{value}")
end
Error(msg) do
print("Error: #{msg}")
end
end
end
# Run main
main()
Shortcake is built as a systems programming language with a focus on performance and reliability:
- Grammar Definition: ANTLR 4 grammar (
Shortcake.g4) for parsing reference - Type System: Bidirectional type inference and static checking
- MLIR Code Generation: Compiles to MLIR intermediate representation
- LLVM Backend: Native code generation through LLVM integration
- Runtime System: Minimal runtime for compiled executables written in Zig
- Written in Zig for systems programming performance
- ANTLR4 grammar for formal language specification
- MLIR IR generation for efficient compilation
- Static compilation to native executables
- LLVM backend integration through MLIR
.sho- Shortcake source files
- Zig Build System for compilation and dependency management
- ANTLR 4 for parser generation from grammar
- MLIR/LLVM for intermediate representation and code generation
- NixOS shell for reproducible development environment
See LICENSE for details.