Structural, Embeddable, Minimal Interpreter

Semi is a minimalist programming language designed for embedding within applications.

fn fib(n) {
    if n < 2 {
        return 1
    }
    return fib(n-1) + fib(n-2)
}

before := now()
defer {
    print("elapsed (ms):", now() - before)
}
print(fib(30))
Output will appear here when you run the code.
Built-ins for this demo
  • print(...args): print arguments to output.
  • now(): get the current time in milliseconds.
  • len(value): get the length of a string or collection.
  • max(...args): get the maximum value among the arguments.
  • min(...args): get the minimum value among the arguments.

Semi is Predictable

The syntax is designed to be concise and easy to understand. Variable shadowing is prohibited. Errors must be handled explicitly, not buried in exception blocks.

Semi is Data-Oriented

Semi encourages a data-centric approach with first-class support for algebraic data types and structural typing. By favoring composition over inheritance, it helps you write code that is more flexible and resilient to change.

Semi is Minimal

Semi keeps the builds lean by making the standard library optional. The entire runtime, including the compiler and virtual machine, is under 50KiB when compiled to WebAssembly and gzipped.

Semi is Portable

Semi is C11-compliant and is designed to be compiled and run anywhere

Quick Tour

Literals

# Number
i := 10
f := 42.0

# String
str := "Hello, Semi!"

# Boolean
flag := true

# List Collection
list := List[1, 2, 3, 4, 5]

# Dictionary Collection
dict := Dict[
    "key": "value",
    "number": 123,
]

Definition & Assignment

# Variable definition
x := 10

# Variable assignment
x = 20

# Assignment without definition is not allowed
# y = 30  # Error: 'y' is not defined

# Variable shadowing is prohibited
# x := 40  # Error: 'x' is already defined
#
# if true {
#     x := 50  # Error: 'x' is already defined
# }

Struct & Type

# We are still figuring out the details about
# how types interact with other language features.

# Define a struct planned
struct Point {
    x: Int,
    y: Int,
}

# Struct Initializer planned
point := Point{ x: 10, y: 20 }

Condition

if condition {
    # do something
} elif other_condition {
    # do something else
} else {
    # fallback
}

Iteration

# Range-based
for i in 0..10 step 2 {
    print(i)
}

# Iterator-based planned
for item in collection {
    print(item)
}

# Infinite loop
for {
    # do something
}

Functions

fn add(a, b) {
    return a + b
}

# Defer block
fn example() {
    defer {
        print("This runs at the end of the function")
    }

    print("Function body")
}

Import & Export

# Import a module without aliasing it planned
import "semi/math"

# Import a module with an alias planned
import "semi/io" as io

# Import specific symbols from a module planned
import "semi/io" { print, readFile }

# Export a variable or function definition planned
export pi := 3.14
export fn add(a, b) {
    return a + b
}