From 872cd6ab51362d86bce1d7b9dc77991347708eaf Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 9 Feb 2026 11:00:23 -0600 Subject: [PATCH] more correct syntax and AI instructions --- CLAUDE.md | 134 +++- docs/_index.md | 32 +- docs/actors.md | 50 +- docs/c-modules.md | 2 +- docs/functions.md | 104 ++- docs/language.md | 670 +++++++++++++++----- docs/library/_index.md | 8 +- docs/library/array.md | 47 +- docs/library/json.md | 2 +- docs/library/math.md | 10 +- docs/library/number.md | 14 +- docs/library/object.md | 15 +- docs/library/random.md | 17 +- docs/library/text.md | 21 +- docs/library/time.md | 6 +- docs/requestors.md | 20 +- docs/spec/bytecode.md | 118 ---- docs/spec/gc.md | 2 +- docs/spec/objects.md | 9 +- source/cell.c | 26 + website/content/_index.md | 2 +- website/content/start/_index.md | 14 +- website/data/docs_nav.yaml | 22 +- website/data/manual_sections.yaml | 49 +- website/data/spec_sections.yaml | 12 +- website/themes/knr/layouts/manual/list.html | 2 +- website/themes/knr/static/css/main.css | 32 +- website/themes/knr/static/js/toc.js | 11 + 28 files changed, 998 insertions(+), 453 deletions(-) delete mode 100644 docs/spec/bytecode.md diff --git a/CLAUDE.md b/CLAUDE.md index 94ababe6..f2bfe99c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,25 +1,123 @@ -# Code style -All code is done with 2 spaces for indentation. +# ƿit (pit) Language Project -For cell script and its integration files, objects are preferred over classes, and preferrably limited use of prototypes, make objects sendable between actors (.ce files). +## Building -## cell script format -Cell script files end in .ce or .cm. Cell script is similar to Javascript but with some differences. +Recompile after changes: `make` +Bootstrap from scratch (first time): `make bootstrap` +Run `cell --help` to see all CLI flags. -Variables are delcared with 'var'. Var behaves like let. -Constants are declared with 'def'. -!= and == are strict, there is no !== or ===. -There is no undefined, only null. -There are no classes, only objects and prototypes. -Prefer backticks for string interpolation. Otherwise, convering non strings with the text() function is required. -Everything should be lowercase. +## Code Style -There are no arraybuffers, only blobs, which work with bits. They must be stoned like stone(blob) before being read from. +All code uses 2 spaces for indentation. K&R style for C and Javascript. -## c format -For cell script integration files, everything should be declared static that can be. Most don't have headers at all. Files in a package are not shared between packages. +## ƿit Script Quick Reference -There is no undefined, so JS_IsNull and JS_NULL should be used only. +ƿit script files: `.ce` (actors) and `.cm` (modules). The syntax is similar to JavaScript with important differences listed below. -## how module loading is done in cell script -Within a package, a c file, if using the correct macros (CELL_USE_FUNCS etc), will be loaded as a module with its name; so png.c inside ac package is loaded as /png, giving you access to its functions. \ No newline at end of file +### Key Differences from JavaScript + +- `var` (mutable) and `def` (constant) — no `let` or `const` +- `==` and `!=` are strict (no `===` or `!==`) +- No `undefined` — only `null` +- No classes — only objects and prototypes (`meme()`, `proto()`, `isa()`) +- No `for...in`, `for...of`, spread (`...`), rest params, or default params +- No named function declarations — use `var fn = function() {}` or arrow functions +- Variables must be declared at function body level only (not in if/while/for/blocks) +- All variables must be initialized at declaration (`var x` alone is an error; use `var x = null`) +- No `try`/`catch`/`throw` — use `disrupt`/`disruption` +- No arraybuffers — only `blob` (works with bits; must `stone(blob)` before reading) +- Identifiers can contain `?` and `!` (e.g., `nil?`, `set!`, `is?valid`) +- Prefer backticks for string interpolation; otherwise use `text()` to convert non-strings +- Everything should be lowercase + +### Intrinsic Functions (always available, no `use()` needed) + +The creator functions are **polymorphic** — behavior depends on argument types: + +- `array(number)` — create array of size N filled with null +- `array(number, value_or_fn)` — create array with initial values +- `array(array)` — copy array +- `array(array, fn)` — map +- `array(array, array)` — concatenate +- `array(array, from, to)` — slice +- `array(record)` — get keys as array of text +- **`array(text)` — split text into individual characters** (e.g., `array("hello")` → `["h","e","l","l","o"]`) +- `array(text, separator)` — split by separator +- `array(text, length)` — split into chunks of length + +- `text(array, separator)` — join array into text +- `text(number)` or `text(number, radix)` — number to text +- `text(text, from, to)` — substring + +- `number(text)` or `number(text, radix)` — parse text to number +- `number(logical)` — boolean to number + +- `record(record)` — copy +- `record(record, another)` — merge +- `record(array_of_keys)` — create record from keys + +Other key intrinsics: `length()`, `stone()`, `is_stone()`, `print()`, `filter()`, `find()`, `reduce()`, `sort()`, `reverse()`, `some()`, `every()`, `starts_with()`, `ends_with()`, `meme()`, `proto()`, `isa()`, `splat()`, `apply()`, `extract()`, `replace()`, `search()`, `format()`, `lower()`, `upper()`, `trim()` + +Sensory functions: `is_array()`, `is_text()`, `is_number()`, `is_object()`, `is_function()`, `is_null()`, `is_logical()`, `is_integer()`, `is_stone()`, etc. + +### Standard Library (loaded with `use()`) + +- `blob` — binary data (bits, not bytes) +- `time` — time constants and conversions +- `math` — trig, logarithms, roots (`math/radians`, `math/turns`) +- `json` — JSON encoding/decoding +- `random` — random number generation + +### Actor Model + +- `.ce` files are actors (independent execution units, don't return values) +- `.cm` files are modules (return a value, cached and frozen) +- Actors never share memory; communicate via `$send()` message passing +- Actor intrinsics start with `$`: `$me`, `$stop()`, `$send()`, `$start()`, `$delay()`, `$receiver()`, `$clock()`, `$portal()`, `$contact()`, `$couple()`, `$unneeded()`, `$connection()`, `$time_limit()` + +### Requestors (async composition) + +`sequence()`, `parallel()`, `race()`, `fallback()` — compose asynchronous operations. See docs/requestors.md. + +### Error Handling + +```javascript +var fn = function() { + disrupt // bare keyword, no value +} disruption { + // handle error; can re-raise with disrupt +} +``` + +### Push/Pop Syntax + +```javascript +var a = [1, 2] +a[] = 3 // push: [1, 2, 3] +var v = a[] // pop: v is 3, a is [1, 2] +``` + +## C Integration + +- Declare everything `static` that can be +- Most files don't have headers; files in a package are not shared between packages +- No undefined in C API: use `JS_IsNull` and `JS_NULL` only +- A C file with correct macros (`CELL_USE_FUNCS` etc) is loaded as a module by its name (e.g., `png.c` in a package → `use('/png')`) + +## Project Layout + +- `source/` — C source for the cell runtime and CLI +- `docs/` — master documentation (Markdown), reflected on the website +- `website/` — Hugo site; theme at `website/themes/knr/` +- `internal/` — internal ƿit scripts (engine.cm etc.) +- `packages/` — core packages +- `Makefile` — build system (`make` to rebuild, `make bootstrap` for first build) + +## Documentation + +The `docs/` folder is the single source of truth. The website at `website/` mounts it via Hugo. Key files: +- `docs/language.md` — language syntax reference +- `docs/functions.md` — all built-in intrinsic functions +- `docs/actors.md` — actor model and actor intrinsics +- `docs/requestors.md` — async requestor pattern +- `docs/library/*.md` — intrinsic type reference (text, number, array, object) and standard library modules diff --git a/docs/_index.md b/docs/_index.md index dd2c31a5..ea4edd8e 100644 --- a/docs/_index.md +++ b/docs/_index.md @@ -20,7 +20,7 @@ type: "docs" ```javascript // hello.ce - A simple actor -log.console("Hello, ƿit!") +print("Hello, ƿit!") $stop() ``` @@ -30,28 +30,34 @@ pit hello ## Language -- [**ƿit Language**](/docs/language/) — syntax, types, and built-in functions +- [**ƿit Language**](/docs/language/) — syntax, types, and operators - [**Actors and Modules**](/docs/actors/) — the execution model +- [**Requestors**](/docs/requestors/) — asynchronous composition - [**Packages**](/docs/packages/) — code organization and sharing -- [**Command Line**](/docs/cli/) — the `pit` tool -- [**Writing C Modules**](/docs/c-modules/) — native extensions ## Reference - [**Built-in Functions**](/docs/functions/) — intrinsics reference +- [text](/docs/library/text/) — text conversion and manipulation +- [number](/docs/library/number/) — numeric conversion and operations +- [array](/docs/library/array/) — array creation and manipulation +- [object](/docs/library/object/) — object creation, prototypes, and serialization ## Standard Library -- [text](/docs/library/text/) — string manipulation -- [number](/docs/library/number/) — numeric operations (functions are global: `floor()`, `max()`, etc.) -- [array](/docs/library/array/) — array utilities -- [object](/docs/library/object/) — object utilities +Modules loaded with `use()`: + - [blob](/docs/library/blob/) — binary data - [time](/docs/library/time/) — time and dates - [math](/docs/library/math/) — trigonometry and math - [json](/docs/library/json/) — JSON encoding/decoding - [random](/docs/library/random/) — random numbers +## Tools + +- [**Command Line**](/docs/cli/) — the `pit` tool +- [**Writing C Modules**](/docs/c-modules/) — native extensions + ## Architecture ƿit programs are organized into **packages**. Each package contains: @@ -72,3 +78,13 @@ make bootstrap ``` The ƿit shop is stored at `~/.pit/`. + +## Development + +After making changes, recompile with: + +```bash +make +``` + +Run `cell --help` to see all available CLI flags. diff --git a/docs/actors.md b/docs/actors.md index 13949900..e25ff919 100644 --- a/docs/actors.md +++ b/docs/actors.md @@ -26,13 +26,13 @@ A module is a script that **returns a value**. The returned value is cached and // math_utils.cm var math = use('math/radians') -function distance(x1, y1, x2, y2) { +var distance = function(x1, y1, x2, y2) { var dx = x2 - x1 var dy = y2 - y1 return math.sqrt(dx * dx + dy * dy) } -function midpoint(x1, y1, x2, y2) { +var midpoint = function(x1, y1, x2, y2) { return { x: (x1 + x2) / 2, y: (y1 + y2) / 2 @@ -65,10 +65,10 @@ An actor is a script that **does not return a value**. It runs as an independent ```javascript // worker.ce -log.console("Worker started") +print("Worker started") $receiver(function(msg, reply) { - log.console("Received:", msg) + print("Received:", msg) // Process message... }) ``` @@ -88,7 +88,7 @@ Actors have access to special functions prefixed with `$`: Reference to the current actor. ```javascript -log.console($me) // actor reference +print($me) // actor reference ``` ### $stop() @@ -105,7 +105,7 @@ Send a message to another actor. ```javascript $send(other_actor, {type: "ping", data: 42}, function(reply) { - log.console("Got reply:", reply) + print("Got reply:", reply) }) ``` @@ -117,7 +117,7 @@ Start a new actor from a script. ```javascript $start(function(new_actor) { - log.console("Started:", new_actor) + print("Started:", new_actor) }, "worker") ``` @@ -127,7 +127,7 @@ Schedule a callback after a delay. ```javascript $delay(function() { - log.console("5 seconds later") + print("5 seconds later") }, 5) ``` @@ -174,12 +174,40 @@ $contact(function(connection) { ### $time_limit(requestor, seconds) -Wrap a requestor with a timeout. +Wrap a requestor with a timeout. See [Requestors](/docs/requestors/) for details. ```javascript $time_limit(my_requestor, 10) // 10 second timeout ``` +### $couple(actor) + +Couple the current actor to another actor. When the coupled actor dies, the current actor also dies. Coupling is automatic between an actor and its overling (parent). + +```javascript +$couple(other_actor) +``` + +### $unneeded(callback, seconds) + +Schedule the actor for removal after a specified time. + +```javascript +$unneeded(function() { + // cleanup before removal +}, 30) +``` + +### $connection(callback, actor, config) + +Get information about the connection to another actor, such as latency, bandwidth, and activity. + +```javascript +$connection(function(info) { + print(info.latency) +}, other_actor, {}) +``` + ## Module Resolution When you call `use('name')`, ƿit searches: @@ -204,14 +232,14 @@ Files starting with underscore (`_helper.cm`) are private to the package. // main.ce - Entry point var config = use('config') -log.console("Starting application...") +print("Starting application...") $start(function(worker) { $send(worker, {task: "process", data: [1, 2, 3]}) }, "worker") $delay(function() { - log.console("Shutting down") + print("Shutting down") $stop() }, 10) ``` diff --git a/docs/c-modules.md b/docs/c-modules.md index 405cfdff..bf12e81e 100644 --- a/docs/c-modules.md +++ b/docs/c-modules.md @@ -229,7 +229,7 @@ A common pattern is to have a C file provide low-level functions and a `.cm` fil // vector.cm var native = this // C module passed as 'this' -function Vector(x, y) { +var Vector = function(x, y) { return {x: x, y: y} } diff --git a/docs/functions.md b/docs/functions.md index 41b6f2d1..4d4bcf55 100644 --- a/docs/functions.md +++ b/docs/functions.md @@ -33,13 +33,17 @@ An approximation of circumference / diameter: 3.1415926535897932. ## Creator Functions -The creator functions make new objects. Some can take various types. All return null if their inputs are not suitable. +The creator functions are **polymorphic** — they examine the types of their arguments to decide what to do. The first argument's type selects the behavior. All return null if their inputs are not suitable. ### array -`array(number)` — Make an array. All elements are initialized to null. +The `array` function creates arrays from various inputs. Its behavior depends on the type of the first argument: -`array(number, initial_value)` — Make an array. All elements are initialized to initial_value. If initial_value is a function, it is called for each element. If the function has arity >= 1, it is passed the element number. +**From a number** — create an array of that size: + +`array(number)` — All elements are initialized to null. + +`array(number, initial_value)` — All elements are initialized to initial_value. If initial_value is a function, it is called for each element. If the function has arity >= 1, it is passed the element number. ```javascript array(3) // [null, null, null] @@ -47,6 +51,8 @@ array(3, 0) // [0, 0, 0] array(5, i => i * 2) // [0, 2, 4, 6, 8] ``` +**From an array** — copy, map, concat, or slice: + `array(array)` — Copy. Make a mutable copy of the array. `array(array, function, reverse, exit)` — Map. Call the function with each element, collecting return values in a new array. The function is passed each element and its element number. @@ -72,15 +78,28 @@ array([1, 2, 3, 4, 5], 1, 4) // [2, 3, 4] array([1, 2, 3], -2) // [2, 3] ``` +**From a record** — get keys: + `array(record)` — Keys. Make an array containing all text keys in the record. -`array(text)` — Split text into grapheme clusters. +```javascript +array({a: 1, b: 2}) // ["a", "b"] +``` + +**From text** — split into characters or substrings: + +`array(text)` — Split text into an array of individual characters (grapheme clusters). This is the standard way to iterate over characters. ```javascript array("hello") // ["h", "e", "l", "l", "o"] +array("ƿit") // ["ƿ", "i", "t"] ``` -`array(text, separator)` — Split text into an array of subtexts. +`array(text, separator)` — Split text by a separator string into an array of subtexts. + +```javascript +array("a,b,c", ",") // ["a", "b", "c"] +``` `array(text, length)` — Dice text into an array of subtexts of a given length. @@ -100,6 +119,8 @@ All other values return null. ### number +The `number` function converts values to numbers. Its behavior depends on the type of the first argument: + `number(logical)` — Returns 1 or 0. `number(number)` — Returns the number. @@ -131,8 +152,19 @@ number("666", "h") // 1638 ### text +The `text` function converts values to text. Its behavior depends on the type of the first argument: + +**From an array** — join elements into text: + `text(array, separator)` — Convert array to text. Elements are concatenated with the separator (default: empty text). +```javascript +text(["h", "e", "l", "l", "o"]) // "hello" +text(["a", "b", "c"], ", ") // "a, b, c" +``` + +**From a number** — format as text: + `text(number, radix)` — Convert number to text. Radix is 2 thru 37 (default: 10). `text(number, format)` — Format a number as text: @@ -173,6 +205,8 @@ text(data, "h") // "75BCD15" text(12, "4b8") // "0000_1100" ``` +**From text** — extract a substring: + `text(text, from, to)` — Extract a substring. If from/to are negative, add length(text). ```javascript @@ -184,12 +218,18 @@ text(my_text, -3) // "nic" ### record +The `record` function creates and manipulates records (objects). Its behavior depends on the type of the first argument: + +**From a record** — copy, merge, or select: + `record(record)` — Copy. Make a mutable copy. `record(record, another_record)` — Combine. Copy a record, then put all fields of another into the copy. `record(record, array_of_keys)` — Select. New record with only the named fields. +**From an array of keys** — create a new record: + `record(array_of_keys)` — Set. New record using array as keys, each value is true. `record(array_of_keys, value)` — Value Set. Each field value is value. @@ -242,13 +282,31 @@ If text, returns the first character. If a non-negative 32-bit integer, returns Returns the codepoint number of the first character. +### ends_with(text, suffix) + +Returns `true` if the text ends with the given suffix. + +```javascript +ends_with("hello.ce", ".ce") // true +ends_with("hello.cm", ".ce") // false +``` + +### every(array, function) + +Returns `true` if every element satisfies the predicate. + +```javascript +every([2, 4, 6], x => x % 2 == 0) // true +every([2, 3, 6], x => x % 2 == 0) // false +``` + ### extract(text, pattern, from, to) Match text to pattern. Returns a record of saved fields, or null if no match. ### fallback(requestor_array) -Returns a requestor that tries each requestor in order until one succeeds. Returns a cancel function. +Returns a requestor that tries each requestor in order until one succeeds. Returns a cancel function. See [Requestors](/docs/requestors/) for usage. ### filter(array, function) @@ -335,11 +393,21 @@ Returns the opposite logical. Returns null for non-logicals. ### parallel(requestor_array, throttle, need) -Returns a requestor that starts all requestors in the array. Results are collected into an array matching the input order. Optional throttle limits concurrent requestors. Optional need specifies the minimum number of successes required. +Returns a requestor that starts all requestors in the array. Results are collected into an array matching the input order. Optional throttle limits concurrent requestors. Optional need specifies the minimum number of successes required. See [Requestors](/docs/requestors/) for usage. + +### print(value) + +Print a value to standard output. + +```javascript +print("hello") +print(42) +print(`result: ${x}`) +``` ### race(requestor_array, throttle, need) -Like parallel, but returns as soon as the needed number of results are obtained. Default need is 1. Unfinished requestors are cancelled. +Like parallel, but returns as soon as the needed number of results are obtained. Default need is 1. Unfinished requestors are cancelled. See [Requestors](/docs/requestors/) for usage. ### reduce(array, function, initial, reverse) @@ -376,12 +444,21 @@ Search text for target. Returns character position or null. ### sequence(requestor_array) -Returns a requestor that processes each requestor in order. Each result becomes the input to the next. The last result is the final result. +Returns a requestor that processes each requestor in order. Each result becomes the input to the next. The last result is the final result. See [Requestors](/docs/requestors/) for usage. ### sign(number) Returns -1, 0, or 1. +### some(array, function) + +Returns `true` if any element satisfies the predicate. Stops at the first match. + +```javascript +some([1, 2, 3], x => x > 2) // true +some([1, 2, 3], x => x > 5) // false +``` + ### sort(array, select) Returns a new sorted array. Sort keys must be all numbers or all texts. Sort is ascending and stable. @@ -401,6 +478,15 @@ sort([{n: 3}, {n: 1}], "n") // [{n: 1}, {n: 3}] ``` +### starts_with(text, prefix) + +Returns `true` if the text starts with the given prefix. + +```javascript +starts_with("hello world", "hello") // true +starts_with("hello world", "world") // false +``` + ### stone(value) Petrify the value, making it permanently immutable. The operation is deep — all nested objects and arrays are also frozen. Returns the value. diff --git a/docs/language.md b/docs/language.md index e6d136ae..62224d14 100644 --- a/docs/language.md +++ b/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 +``` diff --git a/docs/library/_index.md b/docs/library/_index.md index 321cc9b1..e187bf30 100644 --- a/docs/library/_index.md +++ b/docs/library/_index.md @@ -5,18 +5,14 @@ weight: 90 type: "docs" --- -ƿit includes a standard library of modules loaded with `use()`. +The standard library provides modules loaded with `use()`. | Module | Description | |--------|-------------| -| [text](/docs/library/text/) | String conversion and manipulation | -| [number](/docs/library/number/) | Numeric conversion and operations | -| [array](/docs/library/array/) | Array creation and manipulation | -| [object](/docs/library/object/) | Object creation and manipulation | | [blob](/docs/library/blob/) | Binary data (bits, not bytes) | | [time](/docs/library/time/) | Time constants and conversions | | [math](/docs/library/math/) | Trigonometry, logarithms, roots | | [json](/docs/library/json/) | JSON encoding and decoding | | [random](/docs/library/random/) | Random number generation | -Most numeric functions (`floor`, `max`, `abs`, etc.) are global intrinsics and do not require `use`. See [Built-in Functions](/docs/functions/) for the full list. +The `text`, `number`, `array`, and `object` functions are intrinsics — they are always available without `use`. See [Built-in Functions](/docs/functions/) for the full list, and the individual reference pages for [text](/docs/library/text/), [number](/docs/library/number/), [array](/docs/library/array/), and [object](/docs/library/object/). diff --git a/docs/library/array.md b/docs/library/array.md index 9d51993b..c97a6ae1 100644 --- a/docs/library/array.md +++ b/docs/library/array.md @@ -5,13 +5,15 @@ weight: 30 type: "docs" --- -The `array` function and its methods handle array creation and manipulation. +The `array` function is an intrinsic (always available, no `use()` needed). It is **polymorphic** — its behavior depends on the type of the first argument. -## Creation +## From a Number + +Create an array of a given size. ### array(number) -Create an array of specified size, filled with `null`. +All elements initialized to `null`. ```javascript array(3) // [null, null, null] @@ -19,24 +21,36 @@ array(3) // [null, null, null] ### array(number, initial) -Create an array with initial values. +All elements initialized to a value. If initial is a function, it is called for each element (passed the index if arity >= 1). ```javascript array(3, 0) // [0, 0, 0] array(3, i => i * 2) // [0, 2, 4] ``` +## From an Array + +Copy, map, concat, or slice. + ### array(array) -Copy an array. +Copy an array (mutable). ```javascript var copy = array(original) ``` +### array(array, function) + +Map — call function with each element, collect results. + +```javascript +array([1, 2, 3], x => x * 2) // [2, 4, 6] +``` + ### array(array, from, to) -Slice an array. +Slice — extract a sub-array. Negative indices count from end. ```javascript array([1, 2, 3, 4, 5], 1, 4) // [2, 3, 4] @@ -45,31 +59,36 @@ array([1, 2, 3], -2) // [2, 3] ### array(array, another) -Concatenate arrays. +Concatenate two arrays. ```javascript array([1, 2], [3, 4]) // [1, 2, 3, 4] ``` -### array(object) +## From a Record -Get keys of an object. +### array(record) + +Get the keys of a record as an array of text. ```javascript array({a: 1, b: 2}) // ["a", "b"] ``` +## From Text + ### array(text) -Split text into grapheme clusters. +Split text into individual characters (grapheme clusters). This is the standard way to iterate over characters in a string. ```javascript array("hello") // ["h", "e", "l", "l", "o"] +array("ƿit") // ["ƿ", "i", "t"] ``` ### array(text, separator) -Split text by separator. +Split text by a separator string. ```javascript array("a,b,c", ",") // ["a", "b", "c"] @@ -77,7 +96,7 @@ array("a,b,c", ",") // ["a", "b", "c"] ### array(text, length) -Split text into chunks. +Dice text into chunks of a given length. ```javascript array("abcdef", 2) // ["ab", "cd", "ef"] @@ -91,13 +110,13 @@ Iterate over elements. ```javascript array.for([1, 2, 3], function(el, i) { - log.console(i, el) + print(i, el) }) // With early exit array.for([1, 2, 3, 4], function(el) { if (el > 2) return true - log.console(el) + print(el) }, false, true) // prints 1, 2 ``` diff --git a/docs/library/json.md b/docs/library/json.md index 5541d1e9..45adcc94 100644 --- a/docs/library/json.md +++ b/docs/library/json.md @@ -91,5 +91,5 @@ var config_text = json.encode(config, 2) // Load configuration var loaded = json.decode(config_text) -log.console(loaded.debug) // true +print(loaded.debug) // true ``` diff --git a/docs/library/math.md b/docs/library/math.md index d785378f..2dc33770 100644 --- a/docs/library/math.md +++ b/docs/library/math.md @@ -135,21 +135,21 @@ math.e() // 2.71828... var math = use('math/radians') // Distance between two points -function distance(x1, y1, x2, y2) { +var distance = function(x1, y1, x2, y2) { var dx = x2 - x1 var dy = y2 - y1 return math.sqrt(dx * dx + dy * dy) } // Angle between two points -function angle(x1, y1, x2, y2) { +var angle = function(x1, y1, x2, y2) { return math.arc_tangent(y2 - y1, x2 - x1) } // Rotate a point -function rotate(x, y, angle) { - var c = math.cosine(angle) - var s = math.sine(angle) +var rotate = function(x, y, a) { + var c = math.cosine(a) + var s = math.sine(a) return { x: x * c - y * s, y: x * s + y * c diff --git a/docs/library/number.md b/docs/library/number.md index c1a5a527..13e4d652 100644 --- a/docs/library/number.md +++ b/docs/library/number.md @@ -5,7 +5,7 @@ weight: 20 type: "docs" --- -The `number` function and its methods handle numeric conversion and operations. +The `number` function is an intrinsic (always available, no `use()` needed). It is **polymorphic** — its behavior depends on the type of the first argument. ## Conversion @@ -123,20 +123,20 @@ Get the fractional part. fraction(4.75) // 0.75 ``` -### min(...values) +### min(a, b) -Return the smallest value. +Return the smaller of two numbers. ```javascript -min(3, 1, 4, 1, 5) // 1 +min(3, 5) // 3 ``` -### max(...values) +### max(a, b) -Return the largest value. +Return the larger of two numbers. ```javascript -max(3, 1, 4, 1, 5) // 5 +max(3, 5) // 5 ``` ### remainder(dividend, divisor) diff --git a/docs/library/object.md b/docs/library/object.md index 595b370f..676f0151 100644 --- a/docs/library/object.md +++ b/docs/library/object.md @@ -5,9 +5,9 @@ weight: 40 type: "docs" --- -The `object` function and related utilities handle object creation and manipulation. +The `object` function is an intrinsic (always available, no `use()` needed). It is **polymorphic** — its behavior depends on the types of its arguments. -## Creation +## From a Record ### object(obj) @@ -34,6 +34,8 @@ Select specific keys. object({a: 1, b: 2, c: 3}, ["a", "c"]) // {a: 1, c: 3} ``` +## From an Array of Keys + ### object(keys) Create object from keys (values are `true`). @@ -65,9 +67,9 @@ object(["a", "b", "c"], (k, i) => i) // {a: 0, b: 1, c: 2} Create a new object with the given prototype. ```javascript -var animal = {speak: function() { log.console("...") }} +var animal = {speak: function() { print("...") }} var dog = meme(animal) -dog.speak = function() { log.console("woof") } +dog.speak = function() { print("woof") } ``` ### proto(obj) @@ -109,9 +111,4 @@ var obj = {a: 1, b: 2, c: 3} // Get all keys var keys = array(obj) // ["a", "b", "c"] - -// Iterate -for (var key in obj) { - log.console(key, obj[key]) -} ``` diff --git a/docs/library/random.md b/docs/library/random.md index 3f2aaf3c..f385ea26 100644 --- a/docs/library/random.md +++ b/docs/library/random.md @@ -48,7 +48,7 @@ var random = use('random') var coin_flip = random.random() < 0.5 // Random element from array -function pick(arr) { +var pick = function(arr) { return arr[random.random_whole(length(arr))] } @@ -56,11 +56,14 @@ var colors = ["red", "green", "blue"] var color = pick(colors) // Shuffle array -function shuffle(arr) { +var shuffle = function(arr) { var result = array(arr) // copy - for (var i = length(result) - 1; i > 0; i--) { - var j = random.random_whole(i + 1) - var temp = result[i] + var i = length(result) - 1 + var j = 0 + var temp = null + for (i = length(result) - 1; i > 0; i--) { + j = random.random_whole(i + 1) + temp = result[i] result[i] = result[j] result[j] = temp } @@ -68,8 +71,8 @@ function shuffle(arr) { } // Random in range -function random_range(min, max) { - return min + random.random() * (max - min) +var random_range = function(lo, hi) { + return lo + random.random() * (hi - lo) } var x = random_range(-10, 10) // -10 to 10 diff --git a/docs/library/text.md b/docs/library/text.md index 48c23a8b..5543dc4e 100644 --- a/docs/library/text.md +++ b/docs/library/text.md @@ -5,20 +5,24 @@ weight: 10 type: "docs" --- -The `text` function and its methods handle string conversion and manipulation. +The `text` function is an intrinsic (always available, no `use()` needed). It is **polymorphic** — its behavior depends on the type of the first argument. -## Conversion +To split text into characters, use `array(text)` — see [array](/docs/library/array/). + +## From an Array ### text(array, separator) -Convert an array to text, joining elements with a separator (default: space). +Join array elements into text with a separator (default: empty string). ```javascript -text([1, 2, 3]) // "1 2 3" -text([1, 2, 3], ", ") // "1, 2, 3" -text(["a", "b"], "-") // "a-b" +text(["h", "e", "l", "l", "o"]) // "hello" +text([1, 2, 3], ", ") // "1, 2, 3" +text(["a", "b"], "-") // "a-b" ``` +## From a Number + ### text(number, radix) Convert a number to text. Radix is 2-36 (default: 10). @@ -29,13 +33,16 @@ text(255, 16) // "ff" text(255, 2) // "11111111" ``` +## From Text + ### text(text, from, to) -Extract a substring from index `from` to `to`. +Extract a substring from index `from` to `to`. Negative indices count from end. ```javascript text("hello world", 0, 5) // "hello" text("hello world", 6) // "world" +text("hello", -3) // "llo" ``` ## Methods diff --git a/docs/library/time.md b/docs/library/time.md index bbca640e..7fc6f469 100644 --- a/docs/library/time.md +++ b/docs/library/time.md @@ -101,7 +101,7 @@ var last_week = now - time.week var later = now + (2 * time.hour) // Format future time -log.console(time.text(tomorrow)) +print(time.text(tomorrow)) ``` ## Example @@ -113,9 +113,9 @@ var time = use('time') var start = time.number() // ... do work ... var elapsed = time.number() - start -log.console(`Took ${elapsed} seconds`) +print(`Took ${elapsed} seconds`) // Schedule for tomorrow var tomorrow = time.number() + time.day -log.console(`Tomorrow: ${time.text(tomorrow, "yyyy-MM-dd")}`) +print(`Tomorrow: ${time.text(tomorrow, "yyyy-MM-dd")}`) ``` diff --git a/docs/requestors.md b/docs/requestors.md index dce5d73a..2dc18ab2 100644 --- a/docs/requestors.md +++ b/docs/requestors.md @@ -12,7 +12,7 @@ Requestors are functions that encapsulate asynchronous work. They provide a stru A requestor is a function with this signature: ```javascript -function my_requestor(callback, value) { +var my_requestor = function(callback, value) { // Do async work, then call callback with result // Return a cancel function } @@ -29,13 +29,13 @@ The cancel function, when called, should abort the in-progress work. ## Writing a Requestor ```javascript -function fetch_data(callback, url) { +var fetch_data = function(callback, url) { $contact(function(connection) { $send(connection, {get: url}, function(response) { callback(response) }) }, {host: url, port: 80}) - return function cancel() { + return function() { // clean up if needed } } @@ -44,7 +44,7 @@ function fetch_data(callback, url) { A requestor that always succeeds immediately: ```javascript -function constant(callback, value) { +var constant = function(callback, value) { callback(42) } ``` @@ -52,7 +52,7 @@ function constant(callback, value) { A requestor that always fails: ```javascript -function broken(callback, value) { +var broken = function(callback, value) { callback(null, "something went wrong") } ``` @@ -74,9 +74,9 @@ var pipeline = sequence([ pipeline(function(profile, reason) { if (reason) { - log.error(reason) + print(reason) } else { - log.console(profile.name) + print(profile.name) } }, user_id) ``` @@ -133,7 +133,7 @@ var resilient = fallback([ resilient(function(data, reason) { if (reason) { - log.error("all sources failed") + print("all sources failed") } }, key) ``` @@ -157,7 +157,7 @@ If the requestor does not complete within the time limit, it is cancelled and th Requestors are particularly useful with actor messaging. Since `$send` is callback-based, it fits naturally: ```javascript -function ask_worker(callback, task) { +var ask_worker = function(callback, task) { $send(worker, task, function(reply) { callback(reply) }) @@ -170,7 +170,7 @@ var pipeline = sequence([ ]) pipeline(function(stored) { - log.console("done") + print("done") $stop() }, {type: "compute", data: [1, 2, 3]}) ``` diff --git a/docs/spec/bytecode.md b/docs/spec/bytecode.md deleted file mode 100644 index 52db6c23..00000000 --- a/docs/spec/bytecode.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -title: "Bytecode VM" -description: "Stack-based virtual machine" ---- - -## Overview - -The bytecode VM is a stack-based virtual machine. Instructions operate on an implicit operand stack, pushing and popping values. This is the original execution backend for ƿit. - -## Compilation Pipeline - -``` -Source → Tokenize → Parse (AST) → Bytecode → Link → Execute -``` - -The compiler emits `JSFunctionBytecode` objects containing opcode sequences, constant pools, and debug information. - -## Instruction Categories - -### Value Loading - -| Opcode | Description | -|--------|-------------| -| `push_i32` | Push a 32-bit immediate integer | -| `push_const` | Push a value from the constant pool | -| `null` | Push null | -| `push_false` | Push false | -| `push_true` | Push true | - -### Stack Manipulation - -| Opcode | Description | -|--------|-------------| -| `drop` | Remove top of stack | -| `dup` | Duplicate top of stack | -| `dup1` / `dup2` / `dup3` | Duplicate item at depth | -| `swap` | Swap top two items | -| `rot3l` / `rot3r` | Rotate top three items | -| `insert2` / `insert3` | Insert top item deeper | -| `nip` | Remove second item | - -### Variable Access - -| Opcode | Description | -|--------|-------------| -| `get_var` | Load variable by name (pre-link) | -| `put_var` | Store variable by name (pre-link) | -| `get_loc` / `put_loc` | Access local variable by index | -| `get_arg` / `put_arg` | Access function argument by index | -| `get_env_slot` / `set_env_slot` | Access closure variable (post-link) | -| `get_global_slot` / `set_global_slot` | Access global variable (post-link) | - -Variable access opcodes are patched during linking. `get_var` instructions are rewritten to `get_loc`, `get_env_slot`, or `get_global_slot` depending on where the variable is resolved. - -### Arithmetic - -| Opcode | Description | -|--------|-------------| -| `add` / `sub` / `mul` / `div` | Basic arithmetic | -| `mod` / `pow` | Modulo and power | -| `neg` / `inc` / `dec` | Unary operations | -| `add_loc` / `inc_loc` / `dec_loc` | Optimized local variable update | - -### Comparison and Logic - -| Opcode | Description | -|--------|-------------| -| `strict_eq` / `strict_neq` | Equality (ƿit uses strict only) | -| `lt` / `lte` / `gt` / `gte` | Ordered comparison | -| `not` / `lnot` | Logical / bitwise not | -| `and` / `or` / `xor` | Bitwise operations | - -### Control Flow - -| Opcode | Description | -|--------|-------------| -| `goto` | Unconditional jump | -| `if_true` / `if_false` | Conditional jump | -| `goto8` / `goto16` | Short jumps (size-optimized) | -| `if_true8` / `if_false8` | Short conditional jumps | -| `catch` | Set exception handler | - -### Function Calls - -| Opcode | Description | -|--------|-------------| -| `call` | Call function with N arguments | -| `tail_call` | Tail-call optimization | -| `call_method` | Call method on object | -| `return` | Return value from function | -| `return_undef` | Return null from function | -| `throw` | Throw exception (disrupt) | - -### Property Access - -| Opcode | Description | -|--------|-------------| -| `get_field` | Get named property | -| `put_field` | Set named property | -| `get_array_el` | Get computed property | -| `put_array_el` | Set computed property | -| `define_field` | Define property during object literal | - -### Object Creation - -| Opcode | Description | -|--------|-------------| -| `object` | Create new empty object | -| `array_from` | Create array from stack values | - -## Bytecode Patching - -During the link/integrate phase, symbolic variable references are resolved to concrete access instructions. This is a critical optimization — the interpreter does not perform name lookups at runtime. - -A `get_var "x"` instruction becomes: -- `get_loc 3` — if x is local variable at index 3 -- `get_env_slot 1, 5` — if x is captured from outer scope (depth 1, slot 5) -- `get_global_slot 7` — if x is a global diff --git a/docs/spec/gc.md b/docs/spec/gc.md index fc54e8f0..8094f247 100644 --- a/docs/spec/gc.md +++ b/docs/spec/gc.md @@ -50,7 +50,7 @@ The collector traces from these root sources: - **Class prototypes** — built-in type prototypes - **Exception** — the current exception value - **Value stack** — all values on the operand stack -- **Frame stack** — all stack frames (bytecode and register VM) +- **Frame stack** — all stack frames (register VM and mcode) - **GC reference stack** — manually registered roots (via `JS_PUSH_VALUE` / `JS_POP_VALUE`) - **Parser constant pool** — during compilation, constants being built diff --git a/docs/spec/objects.md b/docs/spec/objects.md index fb9bdf68..836cb652 100644 --- a/docs/spec/objects.md +++ b/docs/spec/objects.md @@ -19,8 +19,8 @@ Every heap-allocated object begins with a 64-bit header word (`objhdr_t`): | 1 | `OBJ_BLOB` | Binary data (bits) | | 2 | `OBJ_TEXT` | Unicode text string | | 3 | `OBJ_RECORD` | Key-value object with prototype chain | -| 4 | `OBJ_FUNCTION` | Function (C, bytecode, register, or mcode) | -| 5 | `OBJ_CODE` | Compiled bytecode | +| 4 | `OBJ_FUNCTION` | Function (C, register, or mcode) | +| 5 | `OBJ_CODE` | Compiled code | | 6 | `OBJ_FRAME` | Stack frame for closures | | 7 | `OBJ_FORWARD` | Forwarding pointer (GC) | @@ -93,17 +93,16 @@ struct JSFunction { objhdr_t header; // type=4 JSValue name; // function name int16_t length; // arity (-1 for variadic) - uint8_t kind; // C, bytecode, register, or mcode + uint8_t kind; // C, register, or mcode union { struct { ... } cfunc; // C function pointer - struct { ... } bytecode; // bytecode + frame struct { ... } regvm; // register VM code struct { ... } mcode; // mcode IR } u; }; ``` -The kind field selects which union variant is active. Functions can be implemented in C (native), bytecode (stack VM), register code (mach VM), or mcode (JSON interpreter). +The kind field selects which union variant is active. Functions can be implemented in C (native), register code (mach VM), or mcode (JSON interpreter). ## Frame diff --git a/source/cell.c b/source/cell.c index 16ad612a..1640d9fe 100644 --- a/source/cell.c +++ b/source/cell.c @@ -387,8 +387,34 @@ static int run_eval(const char *script_or_file, int print_bytecode, int use_boot return result; } +static void print_usage(const char *prog) +{ + printf("Usage: %s [options]