--- 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 { log.error("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 ```