|
45 | 45 |
|
46 | 46 | ## 1. Overview |
47 | 47 |
|
48 | | -The language is a familiar statement-based, imperative language. Programs consist of variable declarations via assignment, expressions, and control-flow constructs such as `IF`, `ELSEIF`, `ELSE`, `WHILE`, and `FOR`. ASM-Lang has five runtime data types: binary integers (`INT`), binary floating-point numbers (`FLT`, IEEE754), strings (`STR`), non-scalar tensors (`TNS`), and first-class user-defined functions (`FUNC`). Identifiers, function parameters, and return values are statically typed; the type of every symbol must be declared when it is first introduced. Computation proceeds by evaluating expressions and executing statements in sequence, with explicit constructs for branching and looping. Input and output are modeled through built-in operators, in particular `INPUT` and `PRINT`. |
| 48 | +The language is a familiar statement-based, imperative language. Programs consist of variable declarations via assignment, expressions, and control-flow constructs such as `IF`, `ELSEIF`, `ELSE`, `WHILE`, and `FOR`. ASM-Lang has seven runtime data types: binary integers (`INT`), binary floating-point numbers (`FLT`, IEEE754), strings (`STR`), non-scalar tensors (`TNS`), first-class user-defined functions (`FUNC`), associative maps (`MAP`), and thread handles (`THR`). Identifiers, function parameters, and return values are statically typed; the type of every symbol must be declared when it is first introduced. Computation proceeds by evaluating expressions and executing statements in sequence, with explicit constructs for branching and looping. Input and output are modeled through built-in operators, in particular `INPUT` and `PRINT`. |
49 | 49 |
|
50 | 50 | The interpreter compiles source code into a single initial configuration (the seed state), which includes the program code, an empty variable environment, and an initial I/O history. It then advances execution by repeatedly applying a single, fixed small-step transition function that is independent of the particular program. A disassembler and log view expose all intermediate states so that every step and every control-flow decision is inspectable and replay-able. |
51 | 51 |
|
|
99 | 99 |
|
100 | 100 | ## 3. Data Model |
101 | 101 |
|
102 | | -ASM-Lang supports five runtime data types: binary integers, binary floating-point numbers, strings, non-scalar tensors, and first-class functions. |
| 102 | +ASM-Lang supports seven runtime data types: binary integers, binary floating-point numbers, strings, non-scalar tensors, first-class functions, associative maps, and thread handles. |
103 | 103 |
|
104 | 104 | Binary integer literal: an unsigned non-empty sequence of `{0,1}` (for example, `0`, `1`, `1011`), or a signed literal formed by a leading `-` (the dash is part of the literal, not an operator) followed by optional spaces, tabs, or carriage returns and then a non-empty sequence of `{0,1}`. A `-` that does not immediately introduce a literal is a syntax error. |
105 | 105 |
|
|
161 | 161 |
|
162 | 162 | Blocks group one or more statements and are enclosed in curly brackets: `{ statement1 ... statementN }`. Curly braces must match (that is, `{` closes with `}`). Blocks serve as the bodies of control-flow constructs and functions. |
163 | 163 |
|
164 | | -ASYNC blocks: The `ASYNC` statement introduces a background task whose body is a regular block: `ASYNC{ ... }`. The statements inside the block execute synchronously with respect to each other but asynchronously relative to the rest of the program: the interpreter begins executing the block in a background task and immediately continues with the next statement in the current thread. The block shares the main program namespace (it executes with the same lexical environment), so assignments and mutations performed inside an `ASYNC` block are visible to the rest of the program immediately. Runtime errors raised inside an `ASYNC` block are reported via the interpreter's error hooks and recorded in the state log; they do not synchronously abort the main thread. Note that language invariants still apply inside the `ASYNC` block (for example, `RETURN` outside a function is a runtime error). |
| 164 | +ASYNC blocks: The `ASYNC` statement introduces a background task whose body is a regular block: `ASYNC{ ... }`. The statements inside the block execute synchronously with respect to each other but asynchronously relative to the rest of the program. The block shares the main program namespace (it executes with the same lexical environment), so assignments and mutations performed inside an `ASYNC` block are visible to the rest of the program immediately. Runtime errors raised inside an `ASYNC` block are reported via the interpreter's error hooks and recorded in the state log; they do not synchronously abort the main thread. When `ASYNC{ ... }` appears as a top-level statement the interpreter begins executing the block immediately in a background task and continues with the next statement. When `ASYNC{ ... }` is evaluated in expression position and is used as an argument to a surrounding call expression, the interpreter returns a `THR` handle but defers starting the worker thread until the immediately-enclosing call expression completes; this allows operators that receive the `THR` (for example `PAUSE` or `STOP`) to act on the thread before it begins execution. Note that language invariants still apply inside the `ASYNC` block (for example, `RETURN` outside a function is a runtime error). |
| 165 | + |
| 166 | +Thread values (`THR`): a `THR` value is a handle to a background task. In Boolean contexts, a finished `THR` (including one that has been stopped) is `0`, otherwise it is `1`. |
| 167 | + |
| 168 | +`THR(symbol){ block }`: the `THR` statement starts executing `block` in a background task and binds the identifier `symbol` (static type `THR`) in the current environment to the newly-created thread handle. The spawned task shares the main program namespace (it executes with the same lexical environment) similarly to `ASYNC`. |
| 169 | + |
| 170 | +`ASYNC{ block }` as an expression: `ASYNC{ ... }` may also appear in expression position, where it evaluates to a `THR` handle. In statement position, `ASYNC{ ... }` remains valid and its resulting `THR` value is ignored. |
165 | 171 |
|
166 | 172 | Assignments have the syntax `TYPE : identifier = expression` on first use, where TYPE is `INT`, `FLT`, `STR`, `TNS`, or `FUNC`. Spaces around the colon and equals sign are optional. Subsequent assignments to an existing identifier may omit the type but must preserve the original type. Variables are deallocated only when `DEL(identifier)` is executed. |
167 | 173 |
|
|
448 | 454 | - `OR(ANY: a1, ..., ANY: aN):INT` ; Boolean OR |
449 | 455 | - `XOR(ANY: a1, ..., ANY: aN):INT` ; Boolean XOR |
450 | 456 | - `NOT(ANY: a):INT` ; Boolean NOT |
451 | | -- `BOOL(ANY: item):INT` ; returns the truthiness of `item` as `INT` (`INT`: non-zero -> `1`, `STR`: non-empty -> `1`, `TNS`: true if any element is true), otherwise `0` |
| 457 | +- `BOOL(ANY: item):INT` ; returns the truthiness of `item` as `INT` (`INT`: non-zero -> `1`, `STR`: non-empty -> `1`, `TNS`: true if any element is true), otherwise `0`, `THR` is true if it is not stopped, `MAP` is true if it has any entries. |
452 | 458 |
|
453 | 459 | ### 12.4 Comparisons |
454 | 460 | - `EQ(ANY: a, ANY: b):INT` ; 1 if a == b else 0 |
|
504 | 510 | ### 12.8 Concurrency |
505 | 511 |
|
506 | 512 | - `PARALLEL(TNS: functions):INT` — Execute each element of `functions` in parallel. Each element must evaluate to a `FUNC` value; the interpreter invokes each function with no arguments (in separate worker threads) and waits for all workers to complete. Returns `INT` 0 on success. If any element is not a `FUNC` or any worker raises an error, `PARALLEL` raises a runtime error (rewrite: `PARALLEL`) and the failing worker's error is propagated. |
507 | | -
|
508 | 513 | - `PARALLEL(FUNC: f1, FUNC: f2, ...):INT` — Variadic form: accept one or more `FUNC` values as direct arguments. Behaviour is equivalent to the tensor form: each supplied function is invoked in parallel with no arguments and the call waits for completion; returns `INT` 0 on success or raises on error. |
| 514 | +- `ASYNC{ block }:THR` — Expression form: start executing `block` asynchronously in a separate thread (while sharing the same namespace) and return a `THR` handle. In statement position, `ASYNC{ block }` is permitted and the returned handle is ignored. |
| 515 | +- `STOP(THR: thread):THR` — Cooperatively stop a running thread and mark it finished. |
| 516 | +- `AWAIT(THR: thread):THR` — Block until the thread is finished. |
| 517 | +- `PAUSE(THR: thread, FLT: seconds=-1):THR` — Pause execution while preserving the current location. If `seconds` is provided and is $\ge 0$, the thread is automatically resumed after that duration. Pausing an already-paused thread is a runtime error. |
| 518 | +- `RESUME(THR: thread):THR` — Resume a paused thread. Resuming a thread that is not paused is a runtime error. |
| 519 | +- `PAUSED(THR: thread):INT` — Returns `INT` 1 if `thread` is paused, otherwise `INT` 0. |
| 520 | +- `RESTART(THR: thread):THR` — Reinitialize and start executing the thread again. |
509 | 521 |
|
510 | 522 | ### 12.9 Logarithms |
511 | 523 | - `LOG(INT: a):INT` ; floor(log2(a)) for a > 0 |
|
586 | 598 | - `CONTINUE()` ; skip remaining statements in the innermost loop iteration and proceed to the next iteration; if used in the last iteration it acts like `BREAK(1)`. Using `CONTINUE()` outside of a loop is a runtime error. |
587 | 599 | - `GOTOPOINT(INT|STR: n)` ; register a gotopoint with identifier `n` at this statement's location (identifier may be `INT` or `STR`) (n evaluated at runtime). Gotopoints are visible across the containing function or top-level scope rather than being restricted to a single lexical block. |
588 | 600 | - `GOTO(INT|STR: n)` ; jump to a previously-registered gotopoint with identifier `n` (`INT` or `STR`) within the same function or top-level scope; runtime error if not registered in that scope |
589 | | -- `ASYNC{ block }` ; execute `block` asynchronously in a separate thread (while sharing the same namespace); the caller continues executing immediately without waiting for the async block to complete. Any uncaught errors in the async block are logged to the interpreter's error log but do not affect the caller. |
| 601 | +- `ASYNC{ block }` ; execute `block` asynchronously in a separate thread (while sharing the same namespace); the caller continues executing immediately without waiting for the async block to complete. Any uncaught errors in the async block are logged to the interpreter's error log but do not affect the caller. When used in expression position, `ASYNC{ block }` evaluates to a `THR` handle. If the expression is used as an argument to a surrounding call expression, the worker thread's start is deferred until that enclosing call completes so that the callee may operate on the `THR` (for example, `PAUSE` or `STOP`) before the worker runs; in statement position the worker starts immediately and the returned handle is ignored. |
| 602 | +- `THR(SYMBOL: symbol){ block }` ; execute `block` asynchronously in a separate thread and bind the identifier `symbol` (static type `THR`) to the thread handle. |
590 | 603 | - `TRY{ block }CATCH{ block }` ; execute `block` in the `TRY` and, if an interpreter-level runtime error occurs during the `TRY` block, stop the `TRY` and execute the directly-following `CATCH` block. If no error occurs, the `CATCH` block is skipped. |
591 | 604 | - `TRY{ block }CATCH(SYMBOL: name){ block }` ; like the previous form but bind a temporary `STR` symbol `name` visible inside the `CATCH` block containing the error message. The temporary symbol shadows any existing binding for `name` and is restored or removed after the `CATCH` block completes. |
592 | 605 |
|
|
0 commit comments