Azkal Language

A programming language built from scratch in TypeScript, featuring closures, objects, arrays, template strings, pipe operator, destructuring, and more.

New to Azkal? Try the interactive playground to experiment with code in your browser.

Installation

npm install -g azkal-lang

Then run files with azkal myfile.azkal or start the REPL with just azkal.

Hello World

print("Hello, World!")

Save as hello.azkal and run with azkal hello.azkal.

Variables

Declare variables with let. Azkal uses block scoping.

let name = "Azkal"
let age = 1
let active = true
let nothing = null

// Reassign
name = "Azkal v2"

// Block scoping
{
  let x = "inner"
  print(x)  // "inner"
}
// x is not accessible here

Types

Azkal has 7 types: number, string, boolean, null, array, object, function.

type(42)         // "number"
type("hello")    // "string"
type(true)      // "boolean"
type(null)      // "null"
type([1,2])     // "array"
type({a:1})     // "object"
type(fn(){})    // "function"

Functions

Functions are first-class values. Declare with fn.

// Named function
fn add(a, b) {
  return a + b
}

// Anonymous function
let double = fn(x) { return x * 2 }

// Default parameters
fn greet(name = "World") {
  print(`Hello, {name}!`)
}
greet()           // Hello, World!
greet("Azkal")    // Hello, Azkal!

// Closures
fn counter() {
  let n = 0
  return fn() {
    n = n + 1
    return n
  }
}
let c = counter()
print(c())  // 1
print(c())  // 2

Control Flow

If / Else

if x > 0 {
  print("positive")
} else if x == 0 {
  print("zero")
} else {
  print("negative")
}

While Loop

let i = 0
while i < 10 {
  print(i)
  i = i + 1
}

For...In Loop

for item in [1, 2, 3] {
  print(item)
}

for ch in "hello" {
  print(ch)
}

for key in {a: 1, b: 2} {
  print(key)
}

Use break and continue to control loop execution.

Arrays

let nums = [1, 2, 3, 4, 5]
nums[0]        // 1
nums.length    // 5

// Spread
let merged = [...nums, 6, 7]
MethodDescription
.map(f)Transform each element
.filter(f)Keep matching elements
.reduce(f, init)Combine into single value
.find(f)First matching element
.includes(v)Check if value exists
.sort()Sort ascending (returns new array)
.reverse()Reverse order (returns new array)
.flat()Flatten nested arrays
.push(v)Add to end (mutates)
.pop()Remove from end (mutates)
.lengthNumber of elements

Objects

let user = {
  name: "alky",
  level: 99
}
user.name       // "alky"
user["level"]   // 99
user.hp = 100   // add new property

// Shorthand
let x = 10
let y = 20
let point = { x, y }  // { x: 10, y: 20 }
MethodDescription
.keys()Array of keys
.values()Array of values
.has(key)Check if key exists
.remove(key)Delete a key

Strings

let s = "Hello, World!"
s[0]          // "H"
s.length      // 13
MethodDescription
.upper()Uppercase
.lower()Lowercase
.trim()Remove whitespace
.split(sep)Split into array
.contains(s)Check substring
.replace(a, b)Replace all occurrences
.starts_with(s)Check prefix
.ends_with(s)Check suffix
.chars()Array of characters
.lengthString length

Template Strings

Use backticks with {expr} for interpolation.

let name = "world"
print(`Hello, {name}!`)
print(`2 + 2 = {2 + 2}`)

// Nested expressions
print(`{name.upper()} has {name.length} chars`)

Destructuring

Extract values from arrays and objects into variables.

Array Destructuring

let [a, b, c] = [1, 2, 3]
print(a)  // 1
print(b)  // 2
print(c)  // 3

// Extra names get null
let [x, y] = [10]
print(y)  // null

Object Destructuring

let user = { name: "alky", age: 25 }
let { name, age } = user
print(name)  // "alky"
print(age)   // 25

Pipe Operator

The pipe operator |> passes the left value as the first argument to the right function.

42 |> str             // "42"

5 |> fn(x) { return x * 2 }
  |> fn(x) { return x + 1 }
  |> print             // 11

// Great for data pipelines
[1, 2, 3, 4, 5]
  .filter(fn(x) { return x > 2 })
  .map(fn(x) { return x * 10 })

Error Handling

Use try/catch to handle runtime errors gracefully.

try {
  let result = 1 / 0
} catch (e) {
  print(`Caught: {e}`)
}

// Catch undefined variables
try {
  print(unknown_var)
} catch (e) {
  print("Variable not found")
}

The catch variable e contains the error message as a string.

Comments

// Single-line comment

/* Multi-line
   block comment */

let x = 1 /* inline */ + 2

Operators

OperatorDescription
+ - * / %Arithmetic
== !=Equality
< > <= >=Comparison
and or !Logical
|>Pipe
...Spread

String concatenation with + works when either operand is a string.

Standard Library

FunctionDescription
print(...args)Output values (space-separated)
type(val)Get type as string
len(val)Length of array, string, or object
range(n)Array [0, 1, ..., n-1]
range(a, b)Array [a, a+1, ..., b-1]
range(a, b, step)Array with step
num(val)Convert to number (null on failure)
str(val)Convert to string
bool(val)Convert to boolean
join(arr, sep)Join array into string
slice(val, start, end)Slice array or string
append(arr, val)Return new array with val appended
reverse(val)Reverse array or string
keys(obj)Object keys as array
values(obj)Object values as array
clock()Current time in seconds

Math

FunctionDescription
PI3.141592653589793
abs(n)Absolute value
floor(n)Round down
ceil(n)Round up
round(n)Round to nearest
sqrt(n)Square root
pow(a, b)a raised to power b
min(a, b)Smaller of two numbers
max(a, b)Larger of two numbers
random()Random number between 0 and 1
Azkal is open source. View on GitHub · Try the Playground