Skip to content

igorgue/shortcake

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

736 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Shortcake 🍰

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.

Documentation

Design Goals

  • 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

Features

🍰 Sweet Syntax

  • 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

πŸš€ Modern Language Features

  • 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

⚑ High Performance

  • 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

Quick Start

Installation

Prerequisites

  • Zig 0.11+ (systems programming language)
  • LLVM 15+ (for MLIR and code generation)
  • ANTLR 4.13+ (for parser generation)

Build from Source

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 tests

Using NixOS

nix-shell

Running Shortcake

# 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.sho

Development Workflow

Fast Development with Debug Builds

Zig 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 changes

When to Use Optimized Builds

Use 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

Testing Strategy

# 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

Language Reference

Types

Primitive Types

# 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

Composite Types

# 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

Expressions

Literals

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

Unary Operations

-x                             # Negation
+x                             # Positive (no-op)
not x                          # Logical NOT
&x                             # Address of (C interop)
*x                             # Dereference (C interop)

Binary Operations

# 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

Function Calls

func()                         # No arguments
func(1, 2, 3)                  # Multiple arguments
obj.method(arg)                # Method call
list.length()                  # Built-in method

Statements

Variable Assignment

x = 42                         # Simple assignment
x: i32 = 42                   # Typed assignment
x += 1                        # Compound assignment

Conditional Statements

# 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

Loops

# 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

Control Flow

return value                   # Return from function
break                          # Exit loop
continue                       # Next iteration

Guard Statements

guard condition else do
  # error handling
  error("Guard failed")
end

Functions

Function Definitions

# 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

Anonymous Functions

fn(x) = x * 2                  # Assignment form
fn(x) do x * 2 end             # Block form
fn do 42 end                   # No parameters

Closures

multiplier = 2
fn multiply(x) = x * multiplier  # Captures multiplier

Structs

Struct Definition

# 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

Constructors and Methods

# 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)

Operator Overloading

# 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

Algebraic Data Types

Sum Types

type Option = Some(value: i32) | None
type Result = Ok(value: i32) | Error(message: str)
type Color = Red | Green | Blue

Construction and Usage

some_value = Some(42)
no_value = None
success = Ok(200)
error = Error("Something went wrong")
color = Red

Pattern Matching

Match Expressions

value ~ do
  Some(x) do
    # handle Some
    x
  end
  None do
    # handle None
    0
  end
end

# Match assignment
result ~ Some(x) = some_option

Effects and Handlers

Effect Declaration

effect State do
  fn get() : i32
  fn set(value: i32)
end

effect Async do
  fn await() : i32
  fn complete(value: i32)
end

Handler Declaration

handler State(initial: i32) do
  handle get() do
    current
  end
  handle set(value) do
    current = value
  end
end

Effect Usage

# 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

C Interoperability

Including Headers and Loading Libraries

$include <stdio.h>
$include "myheader.h"
$load "libm.so"

C Function Calls

# Direct call
$printf("Hello, %s!\n", "World")

# Function pointers
$malloc = $load "libc.so.6"
ptr = $malloc(1024)
$free(ptr)

C Types

# Basic C types
$int, $char, $float, $double, $void

# Pointers
$int*, $char**

# Arrays
$int[10], $char[]

# Function pointers
$int (*$func)($int, $int)

C Structs

$typedef struct {
  $int x;
  $int y;
} $Point;

# Usage
point = $Point(x: 10, y: 20)

Module System

Module Structure

# 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 Syntax

# 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

Relative Imports

# Current directory
import .local_module

# Parent directory
import ..parent_module

# Sibling directory
import ..sibling.module

Built-in Functions

I/O Functions

print(value1, value2, ...)    # Print values
format(pattern, ...)          # Format string

List Operations

list.length()                 # Get length
list.append(item)             # Append item
list.concat(other_list)       # Concatenate lists

Dictionary Operations

dict.keys()                   # Get keys
dict.values()                 # Get values
dict.get(key, default)        # Get with default

String Operations

string.length()               # Get length
string.contains(substring)    # Check containment
string.split(delimiter)       # Split string

Type Operations

type(value)                   # Get type
value is type                 # Type check

Language Examples

Hello World

print("Hello, World!")

Variables and Arithmetic

x = 5
y = 10
sum = x + y
print("Sum: #{sum}")  # String interpolation

Functions

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

Control Flow

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

Lists and Dictionaries

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}")

Structs and Methods

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}")

Pattern Matching

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}")

Complete Program

# 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()

Architecture

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

Implementation Details

  • 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

File Extensions

  • .sho - Shortcake source files

Build System

  • 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

License

See LICENSE for details.

About

🍰 * * A programming language with a sweet syntax! * * statically typed **

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors