rip-lang 3.13.133 → 3.13.135

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rip-lang",
3
- "version": "3.13.133",
3
+ "version": "3.13.135",
4
4
  "description": "A modern language that compiles to JavaScript",
5
5
  "type": "module",
6
6
  "main": "src/compiler.js",
package/rip-loader.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { plugin } from "bun";
4
4
  import { fileURLToPath } from "url";
5
- import { compileToJS } from "./src/compiler.js";
5
+ import { compileToJS, formatError } from "./src/compiler.js";
6
6
 
7
7
  await plugin({
8
8
  name: "rip-loader",
@@ -32,7 +32,7 @@ await plugin({
32
32
  loader: "js",
33
33
  };
34
34
  } catch (err) {
35
- console.error(`Error compiling ${args.path}:`, err.message);
35
+ console.error(formatError(err, { file: args.path }));
36
36
  throw err;
37
37
  }
38
38
  });
package/src/AGENTS.md CHANGED
@@ -4,6 +4,43 @@ This covers `compiler.js`, `lexer.js`, `components.js`, `browser.js`, `types.js`
4
4
 
5
5
  ---
6
6
 
7
+ ## Architecture Overview
8
+
9
+ The code emitter is `CodeEmitter` in `compiler.js`. It takes s-expression ASTs
10
+ from the parser and produces JavaScript strings. The class was previously called
11
+ `CodeGenerator`; all codegen methods now use `emit*` naming (e.g. `emitIf`,
12
+ `emitSwitch`, `emitClass`). Utility methods that analyze or transform the AST
13
+ without producing output keep descriptive verbs: `collect*`, `extract*`,
14
+ `unwrap*`, `contains*`, `has*`, `find*`, `build*`, `format*`.
15
+
16
+ Key helpers:
17
+ - `asyncIIFE(hasAwait, body)` / `asyncIIFEOpen(hasAwait)` — centralized async
18
+ IIFE wrapping. All 6 expression-context IIFE sites route through these.
19
+ - `_tryPostfixCall(head, rest, context)` — shared postfix-if optimization for
20
+ both simple and complex callee call paths.
21
+ - `_emitArgs(rest)` — shared argument-list emission.
22
+ - `_emitClassMembers(members, parentClass)` — shared class member emission for
23
+ object-style class bodies (handles bound methods, `@param`, `atParamMap`).
24
+
25
+ ### Cleanup Status
26
+
27
+ The compiler has been through a hardening pass. Current state:
28
+
29
+ | Area | Status | Notes |
30
+ | ---- | ------ | ----- |
31
+ | Async IIFE emission | Done | All 6 sites centralized via `asyncIIFE`/`asyncIIFEOpen` |
32
+ | `containsAwait` scope | Done | All enclosed nodes checked (disc, conditions, finally, etc.) |
33
+ | `emitClass` | Done | Deduplicated member loops, fixed 3 latent bugs |
34
+ | `emit()` dispatch | Done | Deduplicated postfix-if and args generation |
35
+ | `emitBodyWithReturns` | Reviewed, not refactored | 143 lines, 12 responsibilities — complex but working, no known bugs |
36
+ | `emitAssignment` | Reviewed, not refactored | 138 lines, 8 patterns — complex but working, no known bugs |
37
+ | `emitForIn` | Reviewed, not refactored | 107 lines — inherent complexity from loop variants |
38
+ | `emitProgram` | Reviewed, not refactored | 136 lines — sequential setup, each section unique |
39
+ | Test runner | Done | Async tests tracked via `pendingTests` + `Promise.all` |
40
+ | Test coverage | Done | 1631 tests, async IIFE + class + nested construct coverage |
41
+
42
+ ---
43
+
7
44
  ## S-Expression Patterns
8
45
 
9
46
  Common patterns:
@@ -26,7 +63,7 @@ Complete node reference:
26
63
  ['program', ...statements]
27
64
 
28
65
  // Variables & Assignment
29
- ['=', target, value] // x = expr or expr :> x (both produce this)
66
+ ['=', target, value] // x = expr
30
67
  ['+=', target, value] // Also: -=, *=, /=, %=, **=
31
68
  ['&&=', target, value] ['||=', target, value]
32
69
  ['?=', target, value] ['??=', target, value]
@@ -66,7 +103,6 @@ Complete node reference:
66
103
  ['!', expr] ['~', expr] ['typeof', expr]
67
104
  ['delete', expr] ['instanceof', expr, type]
68
105
  ['?', expr] // Existence check (x?)
69
- ['defined', expr] // Defined check (x!?)
70
106
  ['presence', expr] // Presence check (x?!) — Houdini operator
71
107
  ['++', expr, isPostfix] ['--', expr, isPostfix]
72
108
 
@@ -143,7 +179,7 @@ Tagged template bridge:
143
179
  ## Context-Aware Generation
144
180
 
145
181
  ```javascript
146
- generate(sexpr, context = 'statement')
182
+ emit(sexpr, context = 'statement')
147
183
  ```
148
184
 
149
185
  - Value context: emit an expression result
@@ -151,13 +187,42 @@ generate(sexpr, context = 'statement')
151
187
 
152
188
  Comprehensions are the canonical example — value context becomes an IIFE with array building, statement context becomes a plain loop.
153
189
 
190
+ ### Expression-Context Construct Audit
191
+
192
+ When a construct appears in value context and cannot be a simple JS expression, the
193
+ compiler wraps it in an IIFE. If the enclosed code contains `await`, the IIFE must
194
+ be `async` and the call must be `await`ed. All async IIFE sites use the centralized
195
+ `asyncIIFE()` / `asyncIIFEOpen()` helpers.
196
+
197
+ | Construct | Method | IIFE type | Enclosed nodes |
198
+ | --------- | --------- | --------- | -------------- |
199
+ | `if` (multi-stmt) | `emitIfAsExpression` | async IIFE | condition, thenBranch, elseBranches |
200
+ | `switch` | `emitSwitch` | async IIFE | disc, case labels, case bodies, defaultCase |
201
+ | `switch` (no disc) | `emitSwitchAsIfChain` | async IIFE | when-conditions, when-bodies, defaultCase |
202
+ | `try` | `emitTry` | async IIFE | try body, catch clause, finally block |
203
+ | comprehension | `emitComprehension` | async IIFE | expr, iterators, guards |
204
+ | object comp. | `emitObjectComprehension` | async IIFE | keyExpr, valueExpr, iterators, guards |
205
+ | `or return` etc. | `emitControl` | sync IIFE | expr, ctrl value (return/throw semantics) |
206
+ | `x = e or return` | `emitAssignment` | sync IIFE | expr, target, ctrl value |
207
+ | `throw` | `emitThrow` | sync IIFE | throw expression |
208
+ | `do ->` | `emitDoIIFE` | user fn | user's function (handles own async) |
209
+ | ternary `?:` | `emitTernary` | none | direct JS ternary |
210
+ | block (comma) | `emitBlock` | none | comma expression |
211
+ | calls + postfix if | `emit` | none | conditional rewrite |
212
+ | `->` in value | `emitThinArrow` | none | parenthesized function |
213
+
214
+ **Invariant:** every node listed in the "Enclosed nodes" column must appear in
215
+ that site's `containsAwait` check. The sync IIFE sites use `return`/`throw`
216
+ inside the IIFE, which cannot propagate to the enclosing function, so async
217
+ handling is intentionally omitted.
218
+
154
219
  ## Dispatch Table
155
220
 
156
221
  All node types dispatch through `GENERATORS` for O(1) lookup. To change a feature:
157
222
 
158
223
  1. Inspect the s-expression with `echo 'code' | ./bin/rip -s`
159
224
  2. Search `GENERATORS` in `src/compiler.js`
160
- 3. Edit the matching generator method
225
+ 3. Edit the matching `emit*` method
161
226
  4. Run `bun run test`
162
227
 
163
228
  For grammar work:
@@ -204,7 +269,7 @@ if (Array.isArray(body) && body[0] === 'block') {
204
269
 
205
270
  ## Component Internals
206
271
 
207
- The component system is a compiler sidecar. `installComponentSupport(CodeGenerator, Lexer)` adds methods to both prototypes.
272
+ The component system is a compiler sidecar. `installComponentSupport(CodeEmitter, Lexer)` adds methods to both prototypes.
208
273
 
209
274
  ### Render Rewriter
210
275
 
@@ -247,9 +312,9 @@ Key mechanisms:
247
312
  Key entry points:
248
313
 
249
314
  - `buildRender` — initializes counters and create/setup line arrays
250
- - `generateNode` — dispatch for elements, text, conditionals, loops, components
251
- - `generateConditional` — emits conditional block factories
252
- - `generateTemplateLoop` — emits `__reconcile(...)`
315
+ - `emitNode` — dispatch for elements, text, conditionals, loops, components
316
+ - `emitConditional` — emits conditional block factories
317
+ - `emitTemplateLoop` — emits `__reconcile(...)`
253
318
  - `emitBlockFactory` — shared factory emitter used by conditionals and loops
254
319
 
255
320
  ### Factory Mode
@@ -263,7 +328,7 @@ Block factories need locals and `ctx.member` references instead of `this._elN` a
263
328
  - `_pushEffect(body)` — emits `__effect(...)` or `disposers.push(__effect(...))`
264
329
  - `_loopVarStack` — threads loop variables through nested factories
265
330
 
266
- Factory mode is entered in `generateConditionBranch` and `generateTemplateLoop` via save/restore of `[_createLines, _setupLines, _factoryMode, _factoryVars]`.
331
+ Factory mode is entered in `emitConditionBranch` and `emitTemplateLoop` via save/restore of `[_createLines, _setupLines, _factoryMode, _factoryVars]`.
267
332
 
268
333
  ### Auto-Wired Event Handlers
269
334
 
@@ -332,7 +397,7 @@ div ~fade
332
397
  Pipeline:
333
398
 
334
399
  - rewriter converts the tilde form into `__transition__`
335
- - `generateAttributes` emits `this._t = "fade"`
400
+ - `emitAttributes` emits `this._t = "fade"`
336
401
  - conditionals check `_t` for async leave / enter
337
402
  - runtime `__transition(el, name, dir, done)` performs the CSS class dance
338
403
 
@@ -453,7 +518,7 @@ Type emission logic lives in `types.js`. Type-checking integration and diagnosti
453
518
 
454
519
  - `installTypeSupport(Lexer)` adds `rewriteTypes()`
455
520
  - `emitTypes(tokens)` emits `.d.ts`
456
- - `generateEnum()` emits runtime JS for enums
521
+ - `emitEnum()` emits runtime JS for enums
457
522
  - `typecheck.js` drives `rip check` and mediates TypeScript diagnostics
458
523
 
459
524
  Types are processed at the token layer before parsing.
package/src/browser.js CHANGED
@@ -3,8 +3,8 @@
3
3
 
4
4
  export { Lexer } from './lexer.js';
5
5
  export { parser } from './parser.js';
6
- export { CodeGenerator, Compiler, compile, compileToJS, formatSExpr, getStdlibCode, getReactiveRuntime, getComponentRuntime } from './compiler.js';
7
- import { getStdlibCode } from './compiler.js';
6
+ export { CodeEmitter, Compiler, compile, compileToJS, formatSExpr, getStdlibCode, getReactiveRuntime, getComponentRuntime, RipError, formatError, formatErrorHTML } from './compiler.js';
7
+ import { getStdlibCode, formatError as _formatError } from './compiler.js';
8
8
 
9
9
  // Version info (replaced during build)
10
10
  export const VERSION = "0.0.0";
@@ -90,7 +90,7 @@ async function processRipScripts() {
90
90
  let js = '';
91
91
  for (const s of individual) {
92
92
  try { js += compileToJS(s.code, opts) + '\n'; }
93
- catch (e) { console.error(`Rip compile error in ${s.url || 'inline'}:`, e.message); }
93
+ catch (e) { console.error(_formatError(e, { source: s.code, file: s.url || 'inline', color: false })); }
94
94
  }
95
95
  if (js) {
96
96
  try { await (0, eval)(`(async()=>{\n${js}\n})()`); }
@@ -132,7 +132,7 @@ async function processRipScripts() {
132
132
  const js = compileToJS(s.code, opts);
133
133
  compiled.push({ js, url: s.url || 'inline' });
134
134
  } catch (e) {
135
- console.error(`Rip compile error in ${s.url || 'inline'}:`, e.message);
135
+ console.error(_formatError(e, { source: s.code, file: s.url || 'inline', color: false }));
136
136
  }
137
137
  }
138
138
 
@@ -281,7 +281,7 @@ export function rip(code) {
281
281
  if (result !== undefined) globalThis._ = result;
282
282
  return result;
283
283
  } catch (error) {
284
- console.error('Rip compilation error:', error.message);
284
+ console.error(_formatError(error, { source: code, color: false }));
285
285
  return undefined;
286
286
  }
287
287
  }