---
title: "ƿit Language"
description: "Syntax, types, operators, and built-in functions"
weight: 10
type: "docs"
---

ƿit is a scripting language for actor-based programming. It combines a familiar syntax with a prototype-based object system and strict immutability semantics.

## Basics

### Variables and Constants

Variables are declared with `var`, constants with `def`. All declarations must be initialized and must appear at the function body level — not inside `if`, `while`, `for`, or `do` blocks.

```javascript
var x = 10
var name = "pit"
var empty = null

def PI = 3.14159   // constant, cannot be reassigned

var a = 1, b = 2, c = 3  // multiple declarations
```

### Data Types

ƿit has eight fundamental types:

- **number** — DEC64 decimal floating point (no rounding errors)
- **text** — Unicode strings
- **logical** — `true` or `false`
- **null** — the absence of a value (no `undefined`)
- **array** — ordered, numerically-indexed sequences
- **object** — key-value records with prototype inheritance
- **blob** — binary data (bits, not bytes)
- **function** — first-class callable values

### Literals

```javascript
// Numbers
42
3.14
-5
0
1e3           // scientific notation (1000)

// Text
"hello"
`template ${x}`   // string interpolation
`${1 + 2}`        // expression interpolation

// Logical
true
false

// Null
null

// Arrays
[1, 2, 3]
[]

// Objects
{a: 1, b: "two"}
{}

// Regex
/\d+/
/hello/i          // with flags
```

## Operators

### Arithmetic

```javascript
2 + 3      // 5
5 - 3      // 2
3 * 4      // 12
12 / 4     // 3
10 % 3     // 1
2 ** 3     // 8 (exponentiation)
```

### Comparison

All comparisons are strict — there is no type coercion.

```javascript
5 == 5     // true
5 != 6     // true
3 < 5      // true
5 > 3      // true
3 <= 3     // true
5 >= 5     // true
```

### Logical

```javascript
true && true     // true
true && false    // false
false || true    // true
false || false   // false
!true            // false
!false           // true
```

Logical operators short-circuit:

```javascript
var called = false
var fn = function() { called = true; return true }
var r = false && fn()   // fn() not called
r = true || fn()        // fn() not called
```

### Bitwise

```javascript
5 & 3       // 1   (AND)
5 | 3       // 7   (OR)
5 ^ 3       // 6   (XOR)
~0          // -1  (NOT)
1 << 3      // 8   (left shift)
8 >> 3      // 1   (right shift)
-1 >>> 1    // 2147483647 (unsigned right shift)
```

### Unary

```javascript
+5          // 5
-5          // -5
-(-5)       // 5
```

### Increment and Decrement

```javascript
var x = 5
x++         // returns 5, x becomes 6 (postfix)
++x         // returns 7, x becomes 7 (prefix)
x--         // returns 7, x becomes 6 (postfix)
--x         // returns 5, x becomes 5 (prefix)
```

### Compound Assignment

```javascript
var x = 10
x += 3      // 13
x -= 3      // 10
x *= 2      // 20
x /= 4     // 5
x %= 3      // 2
```

### Ternary

```javascript
var a = true ? 1 : 2       // 1
var b = false ? 1 : 2      // 2
var c = true ? (false ? 1 : 2) : 3  // 2 (nested)
```

### Comma

The comma operator evaluates all expressions and returns the last.

```javascript
var x = (1, 2, 3)  // 3
```

### In

Test whether a key exists in an object.

```javascript
var o = {a: 1}
"a" in o    // true
"b" in o    // false
```

### Delete

Remove a key from an object.

```javascript
var o = {a: 1, b: 2}
delete o.a
"a" in o    // false
o.b         // 2
```

## Property Access

### Dot and Bracket

```javascript
var o = {x: 10}
o.x           // 10 (dot read)
o.x = 20      // dot write
o["x"]        // 20 (bracket read)
var key = "x"
o[key]        // 20 (computed bracket)
o["y"] = 30   // bracket write
```

### Object as Key

Objects can be used as keys in other objects.

```javascript
var k = {}
var o = {}
o[k] = 42
o[k]          // 42
o[{}]         // null (different object)
k in o        // true
delete o[k]
k in o        // false
```

### Chained Access

```javascript
var d = {a: {b: [1, {c: 99}]}}
d.a.b[1].c    // 99
```

## Arrays

Arrays are **distinct from objects**. They are ordered, numerically-indexed sequences.

```javascript
var arr = [1, 2, 3]
arr[0]              // 1
arr[2] = 10         // [1, 2, 10]
length(arr)         // 3
```

### Push and Pop

```javascript
var a = [1, 2]
a[] = 3             // push: [1, 2, 3]
length(a)           // 3
var v = a[]         // pop: v is 3, a is [1, 2]
length(a)           // 2
```

## Objects

Objects are key-value records with prototype-based inheritance.

```javascript
var point = {x: 10, y: 20}
point.x             // 10
point["y"]          // 20
```

### Prototypes

```javascript
// Create object with prototype
var parent = {x: 10}
var child = meme(parent)
child.x             // 10 (inherited)
proto(child)        // parent

// Override does not mutate parent
child.x = 20
parent.x            // 10
```

### Mixins

```javascript
var p = {a: 1}
var m1 = {b: 2}
var m2 = {c: 3}
var child = meme(p, [m1, m2])
child.a             // 1 (from prototype)
child.b             // 2 (from mixin)
child.c             // 3 (from mixin)
```

## Control Flow

### If / Else

```javascript
var x = 0
if (true) x = 1
if (false) x = 2 else x = 3
if (false) x = 4
else if (true) x = 5
else x = 6
```

### While

```javascript
var i = 0
while (i < 5) i++

// break
i = 0
while (true) {
  if (i >= 3) break
  i++
}

// continue
var sum = 0
i = 0
while (i < 5) {
  i++
  if (i % 2 == 0) continue
  sum += i
}
```

### For

Variables cannot be declared in the for initializer. Declare them at the function body level.

```javascript
var sum = 0
var i = 0
for (i = 0; i < 5; i++) sum += i

// break
sum = 0
i = 0
for (i = 0; i < 10; i++) {
  if (i == 5) break
  sum += i
}

// continue
sum = 0
i = 0
for (i = 0; i < 5; i++) {
  if (i % 2 == 0) continue
  sum += i
}

// nested
sum = 0
var j = 0
for (i = 0; i < 3; i++) {
  for (j = 0; j < 3; j++) {
    sum++
  }
}
```

## Functions

### Function Expressions

```javascript
var add = function(a, b) { return a + b }
add(2, 3)           // 5
```

### Arrow Functions

```javascript
var double = x => x * 2
double(5)           // 10

var sum = (a, b) => a + b
sum(2, 3)           // 5

var block = x => {
  var y = x * 2
  return y + 1
}
block(5)            // 11
```

### Return

A function with no `return` returns `null`. An early `return` exits immediately.

```javascript
var fn = function() { var x = 1 }
fn()                // null

var fn2 = function() { return 1; return 2 }
fn2()               // 1
```

### Arguments

Functions can have at most **4 parameters**. Use a record to pass more values.

Extra arguments are ignored. Missing arguments are `null`.

```javascript
var fn = function(a, b) { return a + b }
fn(1, 2, 3)        // 3 (extra arg ignored)

var fn2 = function(a, b) { return a }
fn2(1)              // 1 (b is null)

// More than 4 parameters — use a record
var draw = function(shape, opts) {
  // opts.x, opts.y, opts.color, ...
}
```

### Immediately Invoked Function Expression

```javascript
var r = (function(x) { return x * 2 })(21)  // 42
```

### Closures

Functions capture variables from their enclosing scope.

```javascript
var make = function(x) {
  return function(y) { return x + y }
}
var add5 = make(5)
add5(3)             // 8
```

Captured variables can be mutated:

```javascript
var counter = function() {
  var n = 0
  return function() { n = n + 1; return n }
}
var c = counter()
c()                 // 1
c()                 // 2
```

### Recursion

```javascript
var fact = function(n) {
  if (n <= 1) return 1
  return n * fact(n - 1)
}
fact(5)             // 120
```

### This Binding

When a function is called as a method, `this` refers to the object.

```javascript
var obj = {
  val: 10,
  get: function() { return this.val }
}
obj.get()           // 10
```

### Currying

```javascript
var f = function(a) {
  return function(b) {
    return function(c) { return a + b + c }
  }
}
f(1)(2)(3)          // 6
```

## Identifiers

Identifiers can contain `?` and `!` characters, both as suffixes and mid-name.

```javascript
var nil? = (x) => x == null
nil?(null)          // true
nil?(42)            // false

var set! = (x) => x + 1
set!(5)             // 6

var is?valid = (x) => x > 0
is?valid(3)         // true

var do!stuff = () => 42
do!stuff()          // 42
```

The `?` in an identifier is not confused with the ternary operator:

```javascript
var nil? = (x) => x == null
var a = nil?(null) ? "yes" : "no"   // "yes"
```

## Type Checking

### Type Functions

```javascript
is_number(42)           // true
is_text("hi")           // true
is_logical(true)        // true
is_object({})           // true (records only)
is_array([])            // true
is_function(function(){})  // true
is_null(null)           // true
is_object([])           // false (arrays are not records)
is_object("hello")      // false (text is not a record)
is_array({})            // false (records are not arrays)
```

### Truthiness

Falsy values: `false`, `0`, `""`, `null`. Everything else is truthy.

```javascript
if (0) ...              // not entered
if ("") ...             // not entered
if (null) ...           // not entered
if (1) ...              // entered
if ("hi") ...           // entered
if ({}) ...             // entered
if ([]) ...             // entered
```

## Immutability with Stone

The `stone()` function makes values permanently immutable.

```javascript
var o = {x: 1}
is_stone(o)             // false
stone(o)
is_stone(o)             // true
o.x = 2                 // disrupts!
```

Stone is **deep** — all nested objects and arrays are also frozen. This cannot be reversed.

## Function Proxy

A function with two parameters (`name`, `args`) acts as a proxy when properties are accessed on it. Any method call on the function dispatches through the proxy.

```javascript
var proxy = function(name, args) {
  return `${name}:${length(args)}`
}
proxy.hello()           // "hello:0"
proxy.add(1, 2)         // "add:2"
proxy["method"]()       // "method:0"
var m = "dynamic"
proxy[m]()              // "dynamic:0"
```

For non-proxy functions, property access disrupts:

```javascript
var fn = function() { return 1 }
fn.foo                  // disrupts
fn.foo = 1              // disrupts
```

## Regex

Regex literals are written with forward slashes, with optional flags.

```javascript
var r = /\d+/
var result = extract("abc123", r)
result[0]               // "123"

var ri = /hello/i
var result2 = extract("Hello", ri)
result2[0]              // "Hello"
```

## Error Handling

ƿit uses `disrupt` and `disruption` for error handling. A `disrupt` signals that something went wrong. The `disruption` block attached to a function catches it.

```javascript
var safe_divide = function(a, b) {
  if (b == 0) disrupt
  return a / b
} disruption {
  print("something went wrong")
}
```

`disrupt` is a bare keyword — it does not carry a value. The `disruption` block knows that something went wrong, but not what.

### Re-raising

A `disruption` block can re-raise by calling `disrupt` again:

```javascript
var outer = function() {
  var inner = function() { disrupt } disruption { disrupt }
  inner()
} disruption {
  // caught here after re-raise
}
outer()
```

### Testing for Disruption

```javascript
var should_disrupt = function(fn) {
  var caught = false
  var wrapper = function() {
    fn()
  } disruption {
    caught = true
  }
  wrapper()
  return caught
}
```

If an actor has an unhandled disruption, it crashes.

## Self-Referencing Structures

Objects can reference themselves:

```javascript
var o = {name: "root"}
o.self = o
o.self.self.name        // "root"
```

## Variable Shadowing

Inner functions can shadow outer variables:

```javascript
var x = 10
var fn = function() {
  var x = 20
  return x
}
fn()                    // 20
x                       // 10
```
