Skip to content

Adjanour/ko-language

Repository files navigation

Kō (kō) — v0.2.0-alpha

A minimal, functional-first programming language that compiles to native binaries via LLVM.

github.com/Adjanour/ko-language

No parens for function calls (add 1 2), indentation-based blocks, uppercase constructors, ADTs, pattern matching, immutable by default, with Hindley-Milner type inference.

Status: Alpha. Expect bugs, missing features, and rough edges. Feedback and contributions welcome.

Quick start

git clone https://github.com/Adjanour/ko-language.git
cd ko-language
./build.sh
echo 'fn main = println "Hello, Kō!"' > hello.ko
./ko-dist/ko hello.ko

New to functional programming? Read the Getting Started Guide — it's written for Python/JS/C programmers.

Installation

Pre-built (recommended)

Build a self-contained folder you can move anywhere — one binary, the full standard library, and example programs. No install, no system-wide dependencies at runtime.

./build.sh

This produces ko-dist/:

ko-dist/
├── bin/
│   ├── ko          # compiler binary
│   └── ko-lsp      # language server
├── std/            # standard library (Bool, Int, Float, String, List, Math)
├── examples/       # example .ko programs
├── editors/
│   ├── vscode/     # VS Code extension
│   └── tree-sitter/ # tree-sitter grammar + queries
└── ko -> bin/ko    # convenience symlink

Drop it anywhere and run:

cp -r ko-dist ~/ko
~/ko/ko hello.ko

No npm install. No brew. No virtualenv. One folder.

Build from source

Requires Zig 0.17 and LLVM 22.

Linux

# Ubuntu/Debian
sudo apt install llvm-22-dev zlib1g-dev

# Arch
sudo pacman -S llvm zlib

git clone https://github.com/Adjanour/ko-language.git
cd ko-language/ko-zig
zig build

macOS

brew install llvm@22
export PATH="/opt/homebrew/opt/llvm@22/bin:$PATH"

git clone https://github.com/Adjanour/ko-language.git
cd ko-language/ko-zig
zig build

Windows

Not yet supported. LLVM-22 has no prebuilt Windows packages and the JIT (MCJIT) doesn't support Windows. AOT-only support is planned for a future release.

AI coding assistants

Kō ships with skills for AI assistants. Install one so your AI can write Kō:

# OpenCode
cp -r ko-zig/skills/ko-language ~/.config/opencode/skills/ko-language

# Claude Code / Copilot — copy to project root
cp ko-zig/skills/ko-language/CLAUDE.md /path/to/your/project/CLAUDE.md

# Cursor — copy to project root
cp ko-zig/skills/ko-language/.cursorrules /path/to/your/project/.cursorrules

See ko-zig/skills/README.md for details.

The compiler binary is at zig-out/bin/ko. Run tests with:

zig build test --summary all

What works

  • Lexer: hex (0xFF), underscores, comments, operators, string literals
  • Parser: ADTs, pattern matching, functions, let bindings, if/then/else, lambdas, tuples, records, modules, imports, pipe operator, named args, type annotations
  • Typechecker: Hindley-Milner type inference, let-polymorphism, ref types, type annotations
  • Codegen: LLVM IR via kassane/llvm-zig bindings; JIT execution and AOT compilation (--emit-obj, --emit-exe)
  • Memory management: Reference counting for heap-allocated objects (tuples, records, constructors, closures)
  • Currying: Multi-param functions support partial application
  • Modules: module Name definitions with pub visibility
  • Stdlib: Bool, Int, Float, String, List, Math — built-in, no import needed
  • LSP: ko-lsp built alongside the compiler, with error locations
  • REPL: ko --repl for interactive evaluation
  • Module imports: import std.Math.{abs, max} — file-based, with selective imports
  • Error propagation: ? operator unwraps Ok or propagates Err
  • 78 of 78 tests passing

CLI

ko <file.ko>                Run program (default)
ko --repl                   Start interactive REPL
ko --dump-ir <file.ko>      Show generated LLVM IR
ko --emit-ir <out> <file>   Write LLVM IR to file
ko --emit-obj <out> <file>  Compile to object file
ko --emit-exe <out> <file>  Compile to executable

No args shows help. Errors include file and location:

error at hello.ko:1:11: undefined name 'x'

Language features

# Functions
fn add x y = x + y
fn apply f x = f x

# Pattern matching
type Maybe a = Just a | Nothing
fn from-just default mx =
  match mx
    Just x => x
    Nothing => default

# Records
type Point = { x: Int, y: Int }
let p = Point { x = 3, y = 4 }

# Tuples
let t = (1, "hello", true)

# Lambda closures
let x = 10
let f = \y -> x + y
f 5  # 15

# Pipe operator
5 |> add 1 |> add 2  # 8

# Partial application
let add1 = add 1
add1 2  # 3

# References (mutable)
let r = ref 42
r := 100
!r  # 100

# Compile-time evaluation
comptime fn factorial n =
  if n == 0 then 1 else n * factorial (n - 1)

comptime fn sum lst =
  match lst
    | Cons x rest => x + sum rest
    | Nil => 0

let x = comptime factorial 5      # 120, evaluated at compile time
let total = comptime sum xs       # list operations at compile time

# Module imports
import std.Math.{abs, max}
abs (-5)   # 5

# Error propagation
type Result a b = Ok a | Err b
fn divide a b =
  if b == 0 then Err "division by zero"
  else Ok (a / b)

fn compute x y =
  let a = divide x y?    # unwraps Ok, propagates Err
  Ok a

Editor setup

Kō ships with a language server (ko-lsp) and tree-sitter grammar. See the full Editor Setup Guide for detailed instructions.

Quick start:

  • VS Code: code --install-extension vscode-ko/ko-language-0.5.0.vsix
  • Neovim: use nvim-lspconfig with ko-lsp + nvim-treesitter for highlights
  • Helix: add ko-lsp to ~/.config/helix/languages.toml
  • Vim: use vim-lsp or CoC.nvim — see guide

Docs

Design decisions

  • No parens for function calls — add 1 2 not add(1, 2)
  • Minimal indentation — only for function bodies and blocks
  • Uppercase = constructorsJust vs x
  • type for ADTs and recordstype Maybe a = Just a | Nothing
  • Immutability by defaultref for explicit mutation
  • match with => — exhaustive pattern matching
  • ! for deref, not for boolean negation
  • |> pipe operator — left-to-right function application
  • Reference counting — automatic memory management for heap objects
  • comptime expressions — evaluate code at compile time with pattern matching, constructors, and built-in string/list operations

Known Issues (v0.2.0-alpha)

Language

  • Inline comments after let bindings have a scoping bug. The parser no longer crashes, but a comment between a let value and its body silently produces incorrect scoping. Workaround: put comments on their own line.
  • println (fn_call) prints <fn> for function-typed values. This is correct behavior — functions aren't printable. Extract to a let binding first: let n = f x; println n
  • Multi-line match bodies confuse the parser. A multi-line match followed by another expression can cause the next expression to be swallowed. Workaround: extract the match into a helper function.
  • Multi-line closures with captured variables cause codegen errors. Workaround: use single-line lambdas or extract to a let binding.
  • Partial application only works for global fn definitions. Multi-param lambdas (\x y -> ...) do not get partial application.

Modules & Imports

  • Imported module type info doesn't propagate to the main typechecker — shows type variables instead of concrete types. This is an architectural limitation of the current import system.
  • No circular import detection. Recursive imports silently produce incorrect results.
  • No package/module system — just flat file imports with std library support.

Tooling

  • LSP is single-file only. No cross-file go-to-definition or import navigation.
  • LSP document symbols always report line 0. Source location for symbols is not yet implemented.
  • REPL doesn't support multi-line input. Each line is processed independently.
  • REPL can't evaluate top-level let bindings. Use fn definitions instead.

Platform Support

Platform JIT REPL LSP --emit-obj --emit-exe
Linux x86_64 Yes Yes Yes Yes Yes
Linux aarch64 Partial Yes Yes Partial No
macOS (Apple Silicon) Yes Yes Yes Yes Yes
macOS (Intel) Yes Yes Yes Yes Yes
Windows No No No No No

Linux x86_64 is the primary development platform. All features work.

macOS requires brew install llvm@22 and adding LLVM to PATH. JIT, LSP, and AOT all work. See Installation for details.

Linux aarch64 needs: dynamic CPU detection, aarch64 linker paths, and aarch64 data layout.

Windows is not yet supported. LLVM-22 has no prebuilt Windows packages and MCJIT doesn't support Windows. AOT-only support is planned.

Roadmap

  • Lexer, parser, typechecker, codegen
  • Reference counting (heap-allocated objects)
  • Recursive ADTs (binary trees, lists)
  • Stack overflow detection
  • Partial application / currying
  • LSP server with error locations
  • REPL with pretty-printing
  • File-based module imports (import std.Math)
  • ? operator for Result error propagation
  • Result built-in operations
  • Generics (monomorphization)
  • Record type syntax with field access
  • Trait/typeclass system
  • Module system v2 (hierarchical imports, first-class modules)

License

MIT

About

Kō - vibecoded a minimal functional programming language

Resources

License

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors