more correct syntax and AI instructions
This commit is contained in:
670
docs/language.md
670
docs/language.md
@@ -11,14 +11,21 @@ type: "docs"
|
||||
|
||||
### 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 bare `{}` blocks.
|
||||
|
||||
```javascript
|
||||
var x = 10 // mutable variable (block-scoped like let)
|
||||
def PI = 3.14159 // constant (cannot be reassigned)
|
||||
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 six fundamental types:
|
||||
ƿit has eight fundamental types:
|
||||
|
||||
- **number** — DEC64 decimal floating point (no rounding errors)
|
||||
- **text** — Unicode strings
|
||||
@@ -35,12 +42,14 @@ def PI = 3.14159 // constant (cannot be reassigned)
|
||||
// Numbers
|
||||
42
|
||||
3.14
|
||||
1_000_000 // underscores for readability
|
||||
-5
|
||||
0
|
||||
1e3 // scientific notation (1000)
|
||||
|
||||
// Text
|
||||
"hello"
|
||||
'world'
|
||||
`template ${x}` // string interpolation
|
||||
`template ${x}` // string interpolation
|
||||
`${1 + 2}` // expression interpolation
|
||||
|
||||
// Logical
|
||||
true
|
||||
@@ -51,113 +60,196 @@ null
|
||||
|
||||
// Arrays
|
||||
[1, 2, 3]
|
||||
["a", "b", "c"]
|
||||
[]
|
||||
|
||||
// Objects
|
||||
{name: "pit", version: 1}
|
||||
{x: 10, y: 20}
|
||||
{a: 1, b: "two"}
|
||||
{}
|
||||
|
||||
// Regex
|
||||
/\d+/
|
||||
/hello/i // with flags
|
||||
```
|
||||
|
||||
### Operators
|
||||
## Operators
|
||||
|
||||
### Arithmetic
|
||||
|
||||
```javascript
|
||||
// Arithmetic
|
||||
+ - * / %
|
||||
** // exponentiation
|
||||
|
||||
// Comparison (always strict)
|
||||
== // equals (like === in JS)
|
||||
!= // not equals (like !== in JS)
|
||||
< > <= >=
|
||||
|
||||
// Logical
|
||||
&& || !
|
||||
|
||||
// Assignment
|
||||
= += -= *= /=
|
||||
2 + 3 // 5
|
||||
5 - 3 // 2
|
||||
3 * 4 // 12
|
||||
12 / 4 // 3
|
||||
10 % 3 // 1
|
||||
2 ** 3 // 8 (exponentiation)
|
||||
```
|
||||
|
||||
### Control Flow
|
||||
### Comparison
|
||||
|
||||
All comparisons are strict — there is no type coercion.
|
||||
|
||||
```javascript
|
||||
// Conditionals
|
||||
if (x > 0) {
|
||||
log.console("positive")
|
||||
} else if (x < 0) {
|
||||
log.console("negative")
|
||||
} else {
|
||||
log.console("zero")
|
||||
}
|
||||
|
||||
// Ternary
|
||||
var sign = x > 0 ? 1 : -1
|
||||
|
||||
// Loops
|
||||
for (var i = 0; i < 10; i++) {
|
||||
log.console(i)
|
||||
}
|
||||
|
||||
for (var item of items) {
|
||||
log.console(item)
|
||||
}
|
||||
|
||||
for (var key in obj) {
|
||||
log.console(key, obj[key])
|
||||
}
|
||||
|
||||
while (condition) {
|
||||
// body
|
||||
}
|
||||
|
||||
// Control
|
||||
break
|
||||
continue
|
||||
return value
|
||||
disrupt
|
||||
5 == 5 // true
|
||||
5 != 6 // true
|
||||
3 < 5 // true
|
||||
5 > 3 // true
|
||||
3 <= 3 // true
|
||||
5 >= 5 // true
|
||||
```
|
||||
|
||||
### Functions
|
||||
### Logical
|
||||
|
||||
```javascript
|
||||
// Named function
|
||||
function add(a, b) {
|
||||
return a + b
|
||||
}
|
||||
|
||||
// Anonymous function
|
||||
var multiply = function(a, b) {
|
||||
return a * b
|
||||
}
|
||||
|
||||
// Arrow function
|
||||
var square = x => x * x
|
||||
var sum = (a, b) => a + b
|
||||
|
||||
// Rest parameters
|
||||
function log_all(...args) {
|
||||
for (var arg of args) log.console(arg)
|
||||
}
|
||||
|
||||
// Default parameters
|
||||
function greet(name, greeting = "Hello") {
|
||||
return `${greeting}, ${name}!`
|
||||
}
|
||||
true && true // true
|
||||
true && false // false
|
||||
false || true // true
|
||||
false || false // false
|
||||
!true // false
|
||||
!false // true
|
||||
```
|
||||
|
||||
All closures capture `this` (like arrow functions in JavaScript).
|
||||
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. You cannot add arbitrary string keys to an array.
|
||||
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
|
||||
```
|
||||
|
||||
// Array spread
|
||||
var more = [...arr, 4, 5] // [1, 2, 10, 4, 5]
|
||||
### 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
|
||||
@@ -168,26 +260,271 @@ Objects are key-value records with prototype-based inheritance.
|
||||
var point = {x: 10, y: 20}
|
||||
point.x // 10
|
||||
point["y"] // 20
|
||||
|
||||
// Object spread
|
||||
var point3d = {...point, z: 30}
|
||||
|
||||
// Prototype inheritance
|
||||
var colored_point = {__proto__: point, color: "red"}
|
||||
colored_point.x // 10 (inherited)
|
||||
```
|
||||
|
||||
### Prototypes
|
||||
|
||||
```javascript
|
||||
// Create object with prototype
|
||||
var parent = {x: 10}
|
||||
var child = meme(parent)
|
||||
child.x // 10 (inherited)
|
||||
proto(child) // parent
|
||||
|
||||
// Get prototype
|
||||
var p = proto(child)
|
||||
// Override does not mutate parent
|
||||
child.x = 20
|
||||
parent.x // 10
|
||||
```
|
||||
|
||||
// Check prototype chain
|
||||
isa(child, parent) // true
|
||||
### 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
|
||||
|
||||
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)
|
||||
```
|
||||
|
||||
### 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
|
||||
is_array([]) // true
|
||||
is_function(function(){}) // true
|
||||
is_null(null) // true
|
||||
is_object([]) // false (array is not object)
|
||||
is_array({}) // false (object is not array)
|
||||
```
|
||||
|
||||
### 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
|
||||
@@ -195,87 +532,50 @@ isa(child, parent) // true
|
||||
The `stone()` function makes values permanently immutable.
|
||||
|
||||
```javascript
|
||||
var config = stone({
|
||||
debug: true,
|
||||
maxRetries: 3
|
||||
})
|
||||
|
||||
config.debug = false // Error! Stone objects cannot be modified
|
||||
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
|
||||
stone.p(value) // returns true if value is stone
|
||||
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"
|
||||
```
|
||||
|
||||
## Built-in Functions
|
||||
|
||||
### length(value)
|
||||
|
||||
Returns the length of arrays (elements), text (codepoints), blobs (bits), or functions (arity).
|
||||
For non-proxy functions, property access disrupts:
|
||||
|
||||
```javascript
|
||||
length([1, 2, 3]) // 3
|
||||
length("hello") // 5
|
||||
length(function(a,b){}) // 2
|
||||
var fn = function() { return 1 }
|
||||
fn.foo // disrupts
|
||||
fn.foo = 1 // disrupts
|
||||
```
|
||||
|
||||
### use(path)
|
||||
## Regex
|
||||
|
||||
Import a module. Returns the cached, stone value.
|
||||
Regex literals are written with forward slashes, with optional flags.
|
||||
|
||||
```javascript
|
||||
var math = use('math/radians')
|
||||
var json = use('json')
|
||||
```
|
||||
var r = /\d+/
|
||||
var result = extract("abc123", r)
|
||||
result[0] // "123"
|
||||
|
||||
### isa(value, type)
|
||||
|
||||
Check type or prototype chain.
|
||||
|
||||
```javascript
|
||||
is_number(42) // true
|
||||
is_text("hi") // true
|
||||
is_array([1,2]) // true
|
||||
is_object({}) // true
|
||||
isa(child, parent) // true if parent is in prototype chain
|
||||
```
|
||||
|
||||
### reverse(array)
|
||||
|
||||
Returns a new array with elements in reverse order.
|
||||
|
||||
```javascript
|
||||
reverse([1, 2, 3]) // [3, 2, 1]
|
||||
```
|
||||
|
||||
### logical(value)
|
||||
|
||||
Convert to boolean.
|
||||
|
||||
```javascript
|
||||
logical(0) // false
|
||||
logical(1) // true
|
||||
logical("true") // true
|
||||
logical("false") // false
|
||||
logical(null) // false
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
```javascript
|
||||
log.console("message") // standard output
|
||||
log.error("problem") // error output
|
||||
```
|
||||
|
||||
## Pattern Matching
|
||||
|
||||
ƿit supports regex patterns in string functions, but not standalone regex objects.
|
||||
|
||||
```javascript
|
||||
text.search("hello world", /world/)
|
||||
replace("hello", /l/g, "L")
|
||||
var ri = /hello/i
|
||||
var result2 = extract("Hello", ri)
|
||||
result2[0] // "Hello"
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
@@ -287,13 +587,27 @@ var safe_divide = function(a, b) {
|
||||
if (b == 0) disrupt
|
||||
return a / b
|
||||
} disruption {
|
||||
log.error("something went wrong")
|
||||
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.
|
||||
|
||||
To test whether an operation disrupts:
|
||||
### 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) {
|
||||
@@ -309,3 +623,27 @@ var should_disrupt = function(fn) {
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user