Home

Awesome

<img src="https://github.com/vtereshkov/umka-lang/blob/master/resources/logo.svg" width="320">

CI

Welcome to Umka!

Umka is a statically typed embeddable scripting language. It combines the simplicity and flexibility needed for scripting with a compile-time protection against type errors. Its aim is to follow the Python Zen principle Explicit is better than implicit more consistently than dynamically typed languages generally do.

Features

Performance

400 x 400 matrix multiplication (AMD A4-3300M @ 1.9 GHz, Windows 7)

Getting Started

Examples

Projects in Umka

A Tour of Umka

Hello

fn main() {
    printf("Hello Umka!\n")
}

Declarations

Constants

const a = 3
const b* = 2.38                         // Exported identifier
const (
    c = sin(b) / 5
    d = "Hello" + " World"
)

Types

type IntPtr = ^uint16                   // Pointer
type Arr = [a]real                      // Array
type (
    DynArr = [][5]int                   // Dynamic array
    String = str                        // String
    Button = enum {                     // Enumeration
        left
        middle
        right
    }
    MyMap = map[str]real                // Map
    Quat = struct {                     // Structure
        q: [4]real
        normalized: bool
    }
    Printable = interface {             // Interface
        print(): int
    }
    ErrFn = fn(code: int)               // Function
)

Variables

var e: int
var f: String = d + "!"
var (
    g: Arr = [3]real{2.3, -4.1 / 2, b}
    h: DynArr
    m: MyMap
)
q := Quat{q: [4]real{1, 0, 0, 0}, normalized: true}

Functions

fn tan(x: real): real {return sin(x) / cos(x)}
fn getValue(): (int, bool) {return 42, true}

Methods

fn (a: ^Arr) print(): int {
    printf("Arr: %v\n", a^)
    return 0
}

Statements

Assignment

h = make([][5]int, 3)   // Dynamic arrays and maps are initialized with make()
m = make(MyMap)
m["Hello Umka"] = 3.14

Declaration via assignment (with type inference)

sum := 0.0

Function call

y := tan(30 * std::pi / 180)
h = append(h, [5]int{10, 20, 30, 40, 50})
h = delete(h, 1)

Method call

g.print()

Conditional

if x, ok := getValue(); ok {
    printf("Got %v\n", x)
}

Switch

switch a {
    case 1, 3, 5, 7: std::println(std::itoa(a) + " is odd")
    case 2, 4, 6, 8: std::println(std::itoa(a) + " is even")
    default:         std::println("I don't know")
}

switch v := type(a) {
    case int: printf("int: %d + 5 = %d\n", v, v + 5)
    case str: printf("str: %s + 5 = %s\n", v, v + "5")
    default:  printf("unknown: %v\n", a)
}

Loop

for k := 1; k <= 128; k *= 2 {
    printf("%v\n", k)
}

for i, x in g {
    if fabs(x) > 1e12 {break}
    if x < 0 {continue}
    sum += x
}

Multitasking

a := new(int)
child := make(fiber, |a| {
    for i := 0; i < 5; i++ {
        std::println("Child : i=" + std::itoa(i) + " buf=" + std::itoa(a^))
        a^ = i * 3
        resume()
    }
})
for i := 0; i < 10; i++ {
    std::println("Parent: i=" + std::itoa(i) + " buf=" + std::itoa(a^))
    a^ = i * 7
    if valid(child) {
        resume(child)
    }
} 

Umka vs Go

Purpose

While Go is a compiled systems programming language with a complex runtime library and big output binaries, Umka is a scripting language with a lightweight interpreter that can be easily embedded into any application as a shared library.

Syntax

Umka is very similar to Go syntactically. However, in some aspects it's different. It has shorter keywords: fn for func, str for string, in for range. For better readability, it requires a : between variable names and types in declarations. It doesn't follow the unfortunate C tradition of pointer dereferencing. Instead of *p, it uses the Pascal syntax p^. As the * character is no longer used for pointers, it becomes the export mark, like in Oberon, so that a programmer can freely use upper/lower case letters in identifiers according to his/her own style. Type assertions don't have any special syntax; they look like pointer type casts. Closure definitions require explicit lists of captured variables.

Semantics

Umka allows implicit type casts and supports default parameters in function declarations. It features the ternary conditional operator deliberately omitted from Go. It doesn't have slices as separate data types. Instead, it supports dynamic arrays, which are declared like Go's slices and initialized by calling make(). Method receivers must be pointers. The multithreading model in Umka is inspired by Lua and Wren rather than Go. It offers lightweight threads called fibers instead of goroutines and channels. The garbage collection mechanism is based on reference counting, so Umka needs to support weak pointers. Full Unicode support is under development.