• Stars
    star
    231
  • Rank 172,899 (Top 4 %)
  • Language
    HTML
  • License
    MIT License
  • Created about 3 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An expressive, simple, dynamic programming language.

Oak 🌳

Build Status

Oak is an expressive, dynamically typed programming language. It takes the best parts of my experience with Ink, and adds what I missed and removes what didn't work to get a language that feels just as small and simple, but much more ergonomic and capable.

Here's an example Oak program.

std := import('std')

fn fizzbuzz(n) if [n % 3, n % 5] {
    [0, 0] -> 'FizzBuzz'
    [0, _] -> 'Fizz'
    [_, 0] -> 'Buzz'
    _ -> string(n)
}

std.range(1, 101) |> std.each(fn(n) {
    std.println(fizzbuzz(n))
})

Oak has good support for asynchronous I/O. Here's how you read a file and print it.

std := import('std')
fs := import('fs')

with fs.readFile('./file.txt') fn(file) if file {
    ? -> std.println('Could not read file!')
    _ -> print(file)
}

Oak also has a pragmatic standard library that comes built into the oak executable. For example, there's a built-in HTTP server and router in the http library.

std := import('std')
fmt := import('fmt')
http := import('http')

server := http.Server()
with server.route('/hello/:name') fn(params) {
    fn(req, end) if req.method {
        'GET' -> end({
            status: 200
            body: fmt.format('Hello, {{ 0 }}!'
                std.default(params.name, 'World'))
        })
        _ -> end(http.MethodNotAllowed)
    }
}
server.start(9999)

Install

On macOS, Oak can be installed through Homebrew.

brew install oak

On other platforms or macOS without Homebrew, check the installation guide on the Oak website to install the Oak CLI or build it from source.

Overview

Oak has 7 primitive and 3 complex types.

?        // null, also "()"
_        // "empty" value, equal to anything
1, 2, 3  // integers
3.14     // floats
true     // booleans
'hello'  // strings
:error   // atoms

[1, :number]    // list
{ a: 'hello' }  // objects
fn(a, b) a + b  // functions

These types mostly behave as you'd expect. Some notable details:

  • There is no implicit type casting between any types, except during arithmetic operations when ints may be cast up to floats.
  • Both ints and floats are full 64-bit.
  • Strings are mutable byte arrays, also used for arbitrary data storage in memory, like in Lua. For immutable strings, use atoms.
  • Lists are backed by a vector data structure -- appending and indexing is cheap, but cloning is not
  • For lists and objects, equality is defined as deep equality. There is no identity equality in Oak.

We define a function in Oak with the fn keyword. A name is optional, and if given, will define that function in that scope. If there are no arguments, the () may be omitted.

fn double(n) 2 * n
fn speak {
    println('Hello!')
}

Besides the normal set of arithmetic operators, Oak has a few strange operators.

  • The assignment operator := binds values on the right side to names on the left, potentially by destructuring an object or list. For example:

    a := 1              // a is 1
    [b, c] := [2, 3]    // b is 2, c is 3
    d := double(a)      // d is 2
  • The nonlocal assignment operator <- binds values on the right side to names on the left, but only when those variables already exist. If the variable doesn't exist in the current scope, the operator ascends up parent scopes until it reaches the global scope to find the last scope where that name was bound.

    n := 10
    m := 20
    {
        n <- 30
        m := 40
    }
    n // 30
    m // 20
  • The push operator << pushes values onto the end of a string or a list, mutating it, and returns the changed string or list.

    str := 'Hello '
    str << 'World!' // 'Hello World!'
    
    list := [1, 2, 3]
    list << 4
    list << 5 << 6 // [1, 2, 3, 4, 5, 6]
  • The pipe operator |> takes a value on the left and makes it the first argument to a function call on the right.

    // print 2n for every prime n in range [0, 10)
    range(10) |> filter(prime?) |>
        each(double) |> each(println)
    
    // adding numbers
    fn add(a, b) a + b
    10 |> add(20) |> add(3) // 33

Oak uses one main construct for control flow -- the if match expression. Unlike a traditional if expression, which can only test for truthy and falsy values, Oak's if acts like a sophisticated switch-case, comparing values until the right match is reached.

fn pluralize(word, count) if count {
    1 -> word
    2 -> 'a pair of ' + word
    _ -> word + 's'
}

This match expression, combined with safe tail recursion, makes Oak Turing-complete.

Lastly, because callback-based asynchronous concurrency is common in Oak, there's special syntax sugar, the with expression, to help. The with syntax sugar de-sugars like this.

with readFile('./path') fn(file) {
    println(file)
}

// desugars to
readFile('./path', fn(file) {
    println(file)
})

For a more detailed description of the language, see the work-in-progress language spec.

Builds and deployment

While the Oak interpreter can run programs and modules directly from source code on the file system, Oak also offers a build tool, oak build, which can bundle an Oak program distributed across many files into a single "bundle" source file. oak build can also cross-compile Oak bundles into JavaScript bundles, to run in the browser or in JavaScript environments like Node.js and Deno. This allows Oak programs to be deployed and distributed as single-file programs, both on the server and in the browser.

To build a new bundle, we can simply pass an "entrypoint" to the program.

oak build --entry src/main.oak --output dist/bundle.oak

Compiling to JavaScript works similarly, but with the --web flag, which turns on JavaScript cross-compilation.

oak build --entry src/app.js.oak --output dist/bundle.js --web

The bundler and compiler are built on top of my past work with the September toolchain for Ink, but slightly re-architected to support bundling and multiple compilation targets. In the future, the goal of oak build is to become a lightly optimizing compiler and potentially help yield an oak compile command that could package the interpreter and an Oak bundle into a single executable binary. For more information on oak build, see oak help build.

Performance

As of September 2021, Oak is about 5-6x slower than Python 3.9 on pure function call and number-crunching overhead (assessed by a basic fib(30) benchmark). These figures are worst-case estimates -- because Oak's data structures are far simpler than Python's, the ratios start to go down on more realistic complex programs. But nonetheless, this gives a good estimate of the kind of performance (or, currently, the lack thereof) you can expect from Oak programs. It's not fast, though anecdotally it's fast enough for me to have few complaints for most of my use cases.

Runtime performance is not currently my primary concern; my primary concern is implementing a correct and pleasant interpreter that's fast enough for me to write real apps with. Only when speed becomes a problem for software I built with Oak will I really invest much more in speed. I think being as fast as Python and Ruby is a good goal, long-term. Those languages run in production and receive continuous investments into performance tuning, but are far more complex. Oak is much simpler, but it's also just me. I think it evens out the difference.

There are several immediately actionable things we can do to speed up Oak programs' runtime performance, though none are under works today. In order of increasing implementation complexity:

  1. Basic compiler optimization techniques applied to the abstract syntax tree, like constant folding and propagation.
  2. A thorough audit of the interpreter's memory allocation profile and a memory optimization pass (and the same for L1/L2 cache misses).
  3. A bytecode VM that executes Oak compiled down to more compact and efficient bytecode rather than a syntax tree-walking interpreter.

Development

Oak (ab)uses GNU Make to run development workflows and tasks.

  • make run compiles and runs the Oak binary, which opens an interactive REPL
  • make fmt or make f runs the oak fmt code formatter over any files with unstaged changes in the git repository. This is equivalent to running oak fmt --changes --fix.
  • make tests or make t runs the Go test suite for the Oak language and interpreter
  • make test-oak or make tk runs the Oak test suite, which tests the standard libraries
  • make test-bundle runs the Oak test suite, bundled using oak build
  • make test-js runs the Oak test suite on the system's Node.js, compiled using oak build --web
  • make build generates release builds of Oak for various operating systems; make build-<OS> builds for a specific OS
  • make install installs the Oak interpreter on your $GOPATH as oak, and re-installs Oak's vim syntax file
  • make site builds an Oak bundle for the oaklang.org website, amd make site-w does it on every file save
  • make site-gen rebuilds the statically generated parts of the Oak website, like the standard library documentation

To try Oak by building from source, clone the repository and run make install (or simply go build .).

Unit and generative tests

The Oak repository so far as two kinds of tests: unit tests and generative/fuzz tests. Unit tests are just what they sound like -- tests validated with assertions -- and are built on the libtest Oak library with the exception of Go tests in eval_test.go. Generative tests include fuzz tests, and are tests that run some pre-defined behavior of functions through a much larger body of procedurally generated set of inputs, for validating behavior that's difficult to validate manually like correctness of parsers and libdatetime's date/time conversion algorithms.

Both sets of tests are written and run entirely in the "userland" of Oak, without invoking the interpreter separately. Unit tests live in ./test and are run with ./test/main.oak; generative tests are in test/generative, and can be run manually.

More Repositories

1

monocle

Universal personal search engine, powered by a full text search algorithm written in pure Ink, indexing Linus's blogs and private note archives, contacts, tweets, and over a decade of journals.
JavaScript
1,472
star
2

ink

Ink is a minimal programming language inspired by modern JavaScript and Go, with functional style.
Go
557
star
3

blocks.css

Add some dimension to your page with blocks πŸš€
HTML
466
star
4

tabloid

A minimal programming language inspired by clickbait headlines
JavaScript
457
star
5

torus

Torus is an event-driven model-view UI framework for the web, focused on being tiny, efficient, and free of dependencies.
JavaScript
321
star
6

revery

A personal semantic search engine capable of surfacing relevant bookmarks, journal entries, notes, blogs, contacts, and more, built on an efficient document embedding algorithm and Monocle's personal search index.
JavaScript
273
star
7

unim.press

A Reddit front-page reader in the style of The New York Times.
JavaScript
244
star
8

polyx

Productivity suite written from scratch in Ink on the backend and Torus on the web
JavaScript
212
star
9

libsearch

Simple, index-free full-text search for JavaScript
JavaScript
159
star
10

merlot

Web based Markdown writing app built with isomorphic Ink and Torus
JavaScript
150
star
11

h12y

The email service for when just "hey.com" isn't enough.
HTML
147
star
12

modelexicon

This AI Does Not Exist: generate realistic descriptions of made-up machine learning models.
CSS
145
star
13

codeframe

The fastest, easiest way to build and deploy quick static webpages
JavaScript
127
star
14

draw

Real-time collaborative whiteboard on the web
JavaScript
126
star
15

inc

A note-taking tool based on the principles of incremental note-taking, designed for quickly capturing fleeting ideas and growing a knowledge base over time.
Makefile
126
star
16

histools

A collection of tools for generating data visualizations from browser history data
JavaScript
125
star
17

mira

A place for notes, but for the people I keep in touch with
JavaScript
116
star
18

tinyhumans

A little interactive sandbox for tiny people, tiny thoughts, and their tiny stories
HTML
116
star
19

lucerne

A Twitter reader designed for learning from the Twittersphere, built with Ink and Torus
JavaScript
115
star
20

calamity

Self-hosted GPT playground
CSS
110
star
21

stream

A Twitter-like micro-blog for personal project updates and snippets of thought, written in Oak
CSS
83
star
22

burds

Just some burds, jumpin' around in their own little world.
JavaScript
81
star
23

thingboard

A board of things, anywhere you want on the screen
JavaScript
67
star
24

ycvibecheck

Semantic search across every YC company ever. Vibe check your idea?
CSS
57
star
25

lovecroft

Minimal mailing list manager for static sites, with a simple JSON API
Go
57
star
26

frieden

My personal, read-only public availability calendar
JavaScript
55
star
27

paper.css

Lightweight, modern CSS to add some flair to your web-things πŸ“œ
HTML
41
star
28

klisp

A Lisp written in about 200 lines of Ink, featuring an interactive literate programming notebook
JavaScript
38
star
29

superstat

Git status + diff across every repo in a directory
Makefile
35
star
30

typogram

Small, minimalistic graphics for powerful ideas in a few words
JavaScript
34
star
31

plume

Small in-memory real time chat server with Go and WebSockets
Go
33
star
32

september

Ink to JavaScript compiler and toolchain, written in Ink itself
JavaScript
29
star
33

yolo

On the yolo page, anything goes... I'll merge any pull request you make to this website.
HTML
28
star
34

x-oak-notebook

Experimental tool for writing dynamic Markdown docs that embed interactive explorable visualizations
HTML
28
star
35

maverick

Web IDE and REPL for the Ink programming language, written in pure Ink on a self-hosted compiler toolchain
JavaScript
27
star
36

pico

Lightweight notepad for ephemeral memos, todos, meeting notes, and more
JavaScript
26
star
37

zone

A URL shortener / note sharing service.
JavaScript
25
star
38

kin

A refined tool for exploring open-source projects on GitHub with a file tree, rich Markdown and image previews, multi-pane multi-tab layouts and first-class support for Ink syntax highlighting.
JavaScript
24
star
39

august

Assembler from scratch written in Ink, supporting ELF on x86_64 and more.
Assembly
23
star
40

codesynth

Generate music from your source code 🎹
JavaScript
23
star
41

albatross

A simple to-do list app
CSS
23
star
42

spectre

Sparse autoencoders for Contra text embedding models
Jupyter Notebook
23
star
43

cornelia

Guess that Taylor Swift line <3
JavaScript
22
star
44

hfm

Hugging Face Download (Cache) Manager
Makefile
21
star
45

sistine

A simple, flexible, productive static site generator written entirely in Ink
HTML
21
star
46

shelf.page

An online, public β€œblog-shelf” for collecting and sharing interesting reads with your audience. What's on your digital shelf?
JavaScript
21
star
47

clozoom

Close your Zoom meeting tabs automatically
JavaScript
20
star
48

carlisle

A minimal template for a Hugo site
CSS
20
star
49

zerotocode

The best place on the web to learn to make stuff with code
HTML
19
star
50

litterate

Generate beautiful literate programming-style description of your code from comment annotations
JavaScript
19
star
51

xin

Xin (μ‹ /εΏƒ) is a flexible functional programming language with a tiny core, inspired by Lisp and CSP
Go
19
star
52

animated-value

Imperative animation API for declarative UI renderers, like React, Preact, and Torus.
JavaScript
18
star
53

schrift

A more experimental runtime for Ink, focused on perf and instrumentation
Rust
17
star
54

rush

Rush lets you work on many files at once
Makefile
17
star
55

eliza

A modern port of the ELIZA conversational program to pure Ink to run as a command line and in the browser.
CSS
15
star
56

entr

A searchable repository of my personal notes from readings
JavaScript
15
star
57

sounds

A collection of sounds from places I've been
JavaScript
15
star
58

micropress

An Ink library for automatic text summarization
14
star
59

dotink

dotink (.ink) is the Ink programming language's blog, and my general technical blog
HTML
14
star
60

matisse

Gallery of generative art written with Ink
HTML
12
star
61

socialite

Fast social sharing metadata tag generator
JavaScript
12
star
62

traceur

Experimental pathtracing 3D renderer written in Ink
Makefile
12
star
63

tsqdm

TQDM for TypeScript / Deno
TypeScript
12
star
64

xi

A dynamic, stack-based concatenative toy programming language.
Logos
11
star
65

ink-vscode

Support for the Ink programming language in Visual Studio Code
10
star
66

x-oak-klisp

A Klisp (scheme-like flavor of Lisp) implementation in Oak
Vim Script
9
star
67

wintermute

Generating fake blog posts from my blog with a Markov chain
Go
8
star
68

looking-glass

A simple web screenshot API using Puppeteer
JavaScript
8
star
69

lambda

The untyped lambda calculus, implemented in Ink
8
star
70

etch

Dead simple project scaffolding for my commonly used layouts
CSS
7
star
71

oak-syntax-visualizer

Oak syntax visualizer, made for GopherCon 2021
CSS
7
star
72

vanta

Port of thesephist/klisp to pure Go
Go
6
star
73

dotfiles

Config, scripts, rc files πŸ’»
JavaScript
5
star
74

ky

A modal text editor
Go
5
star
75

rational-arithmetic

A no-dependency, lightweight JS library for arithmetic with rational numbers
JavaScript
5
star
76

inkfmt

Code formatter for the Ink programming language
Shell
4
star
77

markovify

Using Markov chains to naively generate sequences of words from training samples.
JavaScript
4
star
78

nought

Personal people-manager, what some people might call a personal CRM
HTML
3
star
79

dessi

A quick, simple server-side-includes expander
JavaScript
3
star
80

papyrus

Small, static-site for hosting read-optimized content, like stories or e-books
HTML
3
star
81

codeliner

Generate codelines: like silhouette outlines, but for your source code
3
star
82

inker

Web API to run Ink code on any device πŸ’»
JavaScript
3
star
83

state-of-startups-bearx

BearX's State of Startups Report
HTML
3
star
84

web-audio-workshop-2020

Web Audio API Workshop for Hack the Fog and hackswiftly 2020
JavaScript
3
star
85

send-tweet

Small Ink program to send tweets using the Twitter JSON API
2
star
86

korona

Take any JavaScript data and get back a reasonably unique hex or rgb color with an optional alpha channel πŸ–Œ
JavaScript
2
star
87

strat

Minimal framework for futures, options, and cryptocurrency investments built on the Robinhood (private) API
JavaScript
2
star
88

brandish

Visual branding for humans
JavaScript
2
star
89

hurricane

Zero-configuration, read-only JSON API proxy in front of an Airtable base
Go
2
star
90

traceur-web

Web and JavaScript port of thesephist/traceur
JavaScript
2
star
91

ittr

Small library of iterator-related utility functions for JavaScript
JavaScript
2
star
92

ansi.ink

Ink library for printing with ANSI escape sequences
1
star
93

pandora

A small, HTML5 quiz SPA
JavaScript
1
star
94

generator-vanilla-extension

Yeoman generator for simple chrome extensions
JavaScript
1
star
95

thesephist.github.io

Placeholder for personal website
HTML
1
star
96

pyro

Check if any of the routes in a list of critical routes of an app are failing
Go
1
star
97

sigil

My full-time to-do list and task manager πŸ”₯
JavaScript
1
star
98

notepad

Short bash script to pull up $EDITOR
Shell
1
star
99

talaria

Inward-out gesture recognition in a wearable
Python
1
star
100

blocky-logos

Blocky logos, an exploratory creative project about logo and branding 🌁
HTML
1
star