Introduction

Sun Programming Language

Sun is a general-purpose systems programming language designed particularly for the needs of robotics and AI. It provides Rust-style memory safety, a familiar syntax, and classic concepts such as classes and interfaces. The design optimizes for performance and intelligibility, for human programmers as well as AI coding agents. Sun additionally aims to improve software distribution, especially in robotics applications, by making it easier to package and distribute portable, systems-level software modules.

Hello World

main.sun
using std;
 
/** Runs the example that prints a greeting. */
function main() void {
  println("Hello, Sun!");
}
 
manifest {
    libraries: ["stdlib.moon"]
}

Run directly with JIT:

sun main.sun
Hello, Sun!

Or compile to a native executable:

sun -c -o main main.sun
./main
Hello, Sun!

This is examples/00-hello/ (opens in a new tab), compiled and run in CI — the source above is read straight from that folder.

Design Goals

  • Fast: Systems-level performance without runtime overhead
  • Memory safe: No undefined behavior via Rust-style borrow checking
  • Readable: Straightforward for humans (and AI agents) to read and understand
  • Unambiguous: Sun minimizes alternative syntaxes and hidden control flow with explicit class hooks for supported arithmetic operators. There are no hidden memory allocations, no implicit copies of compound values, and no macros.
  • Modular: Sun makes it simple to package and distribute pre-compiled modules (called moon libraries). Source files and dependencies are declared in a manifest block, directly in the source code, making the Sun compiler its own build system. Sun can download dependencies directly from your private GitHub and other platforms, making a centralized package manager unnecessary (though one could still be useful for hosting "trusted" packages.)
  • Designed for Robotics: Robotics software typically involves dozens to hundreds of processes that run across one or more compute nodes and communicate over a DDS (opens in a new tab) using some kind of pub-sub middleware (e.g. ROS (opens in a new tab)). The standard message serialization format is protobuf, which Sun provides built-in support for. A custom DDS and middleware are on the roadmap.
  • Designed for AI: NumPy-like N-D matrices and linear algebra are provided in the standard library. Built-in support for hardware accelerators/GPUs using LLVM Offload is on the roadmap.
⚠️

These are goals and not claims about the language's current capabilities.

Installation

Ubuntu (Debian Package)

Download and install the latest development build:

curl -fL https://github.com/namo-robotics/sun/releases/download/dev/sun_0.dev_amd64.deb -o /tmp/sun_0.dev_amd64.deb && chmod 0644 /tmp/sun_0.dev_amd64.deb
sudo apt install /tmp/sun_0.dev_amd64.deb && rm -f /tmp/sun_0.dev_amd64.deb

Using /tmp lets APT's restricted _apt user reach the package even when your home directory is private. Setting mode 0644 also handles restrictive user umasks.

The package installs sun and sun-lsp to /usr/bin and includes bundled libraries installed to /usr/lib/sun. To update, download and install the new package.

macOS (Apple Silicon)

Install with Homebrew:

brew install namo-robotics/sun/sun

That installs sun, sun-lsp, the standard library and the TLS bundle, and pulls in llvm@20 — the compiler's one runtime dependency. Update with brew update && brew upgrade sun.

Uninstalling

To uninstall the Debian package:

sudo apt remove sun
sudo apt autoremove

To uninstall on macOS:

brew uninstall sun

Build from Source

# Clone the repository
git clone https://github.com/namo-robotics/sun.git
cd sun
./build.sh

On Linux this expects clang, LLVM 20 dev packages, Ninja and lld. On a Mac, install the dependencies with Homebrew first — brew install llvm@20 ninja ccache — and ./build.sh picks up Homebrew's LLVM by itself. Protobuf is built into the compiler from a pinned source release (so every platform compiles the same version); building offline instead needs libprotoc-dev and -DSUN_BUNDLED_PROTOBUF=OFF.

Quick Start

The rest of this page works through the main.sun program from Hello World above.

JIT Execution

To compile and run a Sun program in one go, with just-in-time (JIT) compilation, pass the sun compiler a single .sun file containing a manifest block:

sun main.sun
Hello, Sun!

Compile to native executable

sun -c -o main main.sun
Compiling: main.sun -> main
Successfully compiled to: main
./main
Hello, Sun!

Debug Mode

Use --debug to generate artifacts for debugging the compiler itself:

sun --debug main.sun
Hello, Sun!
Debug output folder: main_debug/
  Generated: main_debug/ast.dot
  Generated: main_debug/scope_tree.html
  Generated: main_debug/ir.ll

This creates:

  • ast.dot — GraphViz visualization of the AST
  • ir.ll — the LLVM IR for the program's own code
  • scope_tree.html — HTML visualization of semantic scopes

The IR keeps only what this file compiled to; the stdlib it calls into is filtered out:

main_debug/ir.ll
; LLVM IR (user-defined only)
; Generated in debug mode - library and imported symbols filtered out
 
@str = private unnamed_addr constant [12 x i8] c"Hello, Sun!\00", align 1
define void @main() {
entry:
  call void @"$5b663db4$_std_println$static_ptr_u8_"(%static_ptr_struct { ptr @str, i64 11 })
  ret void
}

The $5b663db4$ prefix on println marks it as coming from a library bundle; the hash keys the bundle, so two moons can define the same name without colliding.

Visualize the AST:

dot -Tpng main_debug/ast.dot -o ast.png

Manifests

Declare source files and library dependencies in a manifest block:

manifest {
    source_files: ["utils.sun", "math.sun"]
    libraries: [
        "stdlib.moon",
        "$MYLIB/mylib.moon"
    ]
}

Source paths are relative to this file. Libraries are found through configured search paths. Configure downloaded libraries in sun-config.json; manifests reference their verified local .moon paths.

Paths can use variables such as $LIBS/mathlib.moon, defined in sun-config.json or with --path-var LIBS=libs. See Modules and Manifests for more options.

Sun Config

Use sun-config.json to set library search paths, path variables, and the entrypoints to build:

sun-config.json
{
    "root": true,
    "sun_path": ["build"],
    "path_variables": { "LIBS": "libs" },
    "entrypoints": [
        {
            "path": "mylib.sun",
            "type": "library",
            "output_name": "build/mylib"
        },
        {
            "path": "main.sun",
            "type": "binary",
            "output_name": "build/app"
        }
    ]
}

Paths are relative to the config file. Sun looks for configs beside the source and in parent folders; root: true stops that search. Explicit --path-var arguments override configured variables.

Each setting can choose a value independently for each target. An ordinary value is an unconditional default; a wrapper supplies replacements:

{
  "sun_path": {
    "default": ["build"],
    "target": { "aarch64-linux-gnu": ["build/arm64"] }
  },
  "path_variables": {
    "OPENSSL_LIBS": {
      "default": "vendor/openssl",
      "target": { "aarch64-linux-gnu": "vendor/openssl/arm64" }
    }
  },
  "entrypoints": [
    {
      "name": "app",
      "path": "app/main.sun",
      "type": "binary",
      "output_name": {
        "default": "build/app",
        "target": { "aarch64-linux-gnu": "build/arm64/app" }
      }
    },
    {
      "name": "helper",
      "enabled": {
        "default": false,
        "target": { "aarch64-linux-gnu": true }
      },
      "path": "app/helper.sun"
    }
  ]
}

A matching target replaces the default, including entire arrays. Without a match, the default applies; a wrapper with neither is an error when needed. Entrypoints and packages default to enabled. Disabled entries skip resolution of their other settings. Names stay fixed; other entrypoint and package fields can use wrappers, including resource lists. Do not wrap the structural entrypoints, packages, or dependencies collections.

Legacy top-level target blocks remain supported, but cannot overlap wrappers for the same setting. Prefer per-setting values to avoid repeating entrypoints. See dependencies and distributions for config-owned downloads and compressed packages.

Build entrypoints in their listed order, or run their tests:

sun -c sun-config.json
sun test sun-config.json

Unchanged builds skip compilation. Use --target to select another compilation target and --no-test to omit test binaries from a build.

Build a library dependency from its repository's configuration:

{
    "dependencies": {
        "MYLIB": {
            "git": "git@github.com:example/mylib.git",
            "version": "v1.2.3",
            "config": "sun-config.json",
            "entrypoint": "mylib"
        }
    }
}

Import "$MYLIB/mylib.moon" in the consumer's manifest. config defaults to sun-config.json and is relative to the repository. entrypoint selects a named library; omit it when the config declares exactly one library. The library owns its source path and output filename. Sun builds it on demand in an isolated cache without running its tests or building its other entrypoints.

To build a source file with your project's settings instead, replace config and entrypoint with "path": "src/mylib.sun". This form ignores the repository's config and exposes mylib.moon under $MYLIB. The two forms are mutually exclusive.

version is a branch, tag, or commit. HTTPS, ssh:// URLs, and git@host:path SSH addresses are supported, using Git's normal authentication. Sources stay cached until a build uses --refresh-sources. See the Git library example (opens in a new tab) for a complete project building sun_serve from scratch.

Moons

Moons (.moon files) are precompiled library bundles containing compiled code and type information. Create a moon from any .sun file containing a manifest:

mylib.sun
public module mylib {
    public function helper() i32 { return 42; }
}
 
manifest {
    source_files: ["utils.sun", "math.sun"]
}
sun --emit-moon -o mylib.moon mylib.sun

A moon is linked into whatever imports it, so a compiled program carries the moons it uses — nothing to install beside the binary, and nothing to load at run time.

C libraries follow the same preference: sun -c links statically by default, requiring a musl toolchain on Linux, and produces one self-contained executable. Dynamic linkage is still available — --dynamic links against shared objects, which vendor SDKs shipped only as .so files need, and macOS targets are always dynamic because Apple ships no static libSystem. See C FFI for the details.

Quick Links