rip-lang 3.6.2 → 3.7.3
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.
- package/CHANGELOG.md +37 -1
- package/README.md +42 -17
- package/docs/NOTES.md +93 -0
- package/docs/RIP-GUIDE.md +39 -1
- package/docs/RIP-INTERNALS.md +9 -9
- package/docs/RIP-LANG.md +220 -2
- package/docs/dist/rip.browser.js +449 -307
- package/docs/dist/rip.browser.min.js +206 -206
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/docs/index.html +20 -7
- package/package.json +3 -3
- package/src/compiler.js +201 -126
- package/src/components.js +10 -10
- package/src/grammar/grammar.rip +8 -2
- package/src/lexer.js +91 -5
- package/src/parser.js +123 -120
- package/src/types.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,43 @@ All notable changes to Rip will be documented in this file.
|
|
|
7
7
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
8
8
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
9
9
|
|
|
10
|
-
## [3.
|
|
10
|
+
## [3.7.3] - 2026-02-11
|
|
11
|
+
|
|
12
|
+
### Fixes & Polish
|
|
13
|
+
|
|
14
|
+
- **Interface `::` fix** — `::` type annotations in interface bodies no longer produce double colons in `.d.ts` output.
|
|
15
|
+
- **`.=` dot chain support** — `obj.name .= toUpperCase()` now works (walks back full property chain).
|
|
16
|
+
- **`*` merge auto-init** — `*foo = {...}` auto-creates `foo` if undefined via `??= {}`.
|
|
17
|
+
- **`loop n` uses `it`** — Loop counter is accessible as `it` inside the body.
|
|
18
|
+
- **Syntax highlighting** — `|>` pipe operator added to VS Code, Vim, Playground, and rip-print.
|
|
19
|
+
|
|
20
|
+
## [3.7.0] - 2026-02-11
|
|
21
|
+
|
|
22
|
+
### Pipe Operator (`|>`)
|
|
23
|
+
|
|
24
|
+
- **First-arg insertion pipe** — `x |> fn` compiles to `fn(x)`, and `x |> fn(y)` compiles to `fn(x, y)`. Combines the simplicity of F#-style pipes with multi-arg support like Elixir — no placeholder syntax needed. Left-associative, chains naturally: `5 |> double |> add(1)`.
|
|
25
|
+
- Works with dotted references (`x |> Math.sqrt`, `x |> console.log`) and dotted calls (`x |> obj.method(y)` → `obj.method(x, y)`).
|
|
26
|
+
- Implicit calls close at pipe boundaries — `x |> fn 1 |> bar 2` works correctly without parens.
|
|
27
|
+
|
|
28
|
+
### Method Assignment (`.=`) — A Rip Original
|
|
29
|
+
|
|
30
|
+
- **Compound method assignment** — `x .= trim()` compiles to `x = x.trim()`. The method-call equivalent of `+=`. No other language has this. Combined with implicit `it`, enables concise transformation pipelines: `items .= filter -> it.active` then `items .= map -> it.name`.
|
|
31
|
+
|
|
32
|
+
### Prototype Operator (`::`)
|
|
33
|
+
|
|
34
|
+
- **CoffeeScript-style prototype access restored** — `String::trim` compiles to `String.prototype.trim`. Disambiguated from type annotations by spacing: `::` with no space is prototype, `::` with a space is a type annotation. Both coexist cleanly.
|
|
35
|
+
|
|
36
|
+
### `loop n` — Repeat N Times
|
|
37
|
+
|
|
38
|
+
- **Counted loop** — `loop 5 -> body` compiles to `for (let _i = 0; _i < 5; _i++) { body }`. Works with literals, variables, and expressions.
|
|
39
|
+
|
|
40
|
+
### Implicit `it` Parameter
|
|
41
|
+
|
|
42
|
+
- **Auto-injected parameter** — Arrow functions with no explicit params that reference `it` in the body automatically inject `it` as the parameter. `arr.filter -> it > 5` compiles to `arr.filter(function(it) { return (it > 5); })`. Works with both `->` and `=>`. Stops at nested function boundaries.
|
|
43
|
+
|
|
44
|
+
### Negative Indexing
|
|
45
|
+
|
|
46
|
+
- **Python-style negative indexing** — `arr[-1]` compiles to `arr.at(-1)`, `arr[-2]` to `arr.at(-2)`, etc. Works on arrays and strings. Optional variant: `arr?[-1]` → `arr?.at(-1)`. Only literal negative numbers trigger the transform; variable indexes pass through unchanged.
|
|
11
47
|
|
|
12
48
|
### Browser Runtime — Full Async/Await Support
|
|
13
49
|
|
package/README.md
CHANGED
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.
|
|
12
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.7.3-blue.svg" alt="Version"></a>
|
|
13
13
|
<a href="#zero-dependencies"><img src="https://img.shields.io/badge/dependencies-ZERO-brightgreen.svg" alt="Dependencies"></a>
|
|
14
|
-
<a href="#"><img src="https://img.shields.io/badge/tests-
|
|
14
|
+
<a href="#"><img src="https://img.shields.io/badge/tests-1225%2F1225-brightgreen.svg" alt="Tests"></a>
|
|
15
15
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
Rip is a modern language inspired by CoffeeScript. It compiles to **ES2022** (classes, `?.`, `??`, modules), adds about a **dozen new operators**, includes **built-in reactivity**, and sports a self-hosting compiler with **zero dependencies** — all in about 10,
|
|
20
|
+
Rip is a modern language inspired by CoffeeScript. It compiles to **ES2022** (classes, `?.`, `??`, modules), adds about a **dozen new operators**, includes **built-in reactivity**, and sports a self-hosting compiler with **zero dependencies** — all in about 10,800 lines of code.
|
|
21
21
|
|
|
22
22
|
> **No imports. No hooks. No dependency arrays. Just write code.**
|
|
23
23
|
|
|
@@ -38,7 +38,7 @@ get '/users/:id' -> # RESTful API endpoint, comma-less
|
|
|
38
38
|
|
|
39
39
|
**What makes Rip different:**
|
|
40
40
|
- **Modern output** — ES2022 with native classes, `?.`, `??`, modules
|
|
41
|
-
- **New operators** — `!`, `!?`, `//`, `%%`, `=~`, `.new()`, and more
|
|
41
|
+
- **New operators** — `!`, `!?`, `//`, `%%`, `=~`, `|>`, `.new()`, and more
|
|
42
42
|
- **Reactive operators** — `:=`, `~=`, `~>` as language syntax
|
|
43
43
|
- **Optional types** — `::` annotations, `::=` aliases, `.d.ts` emission
|
|
44
44
|
- **Zero dependencies** — everything included, even the parser generator
|
|
@@ -122,6 +122,21 @@ for x as iterable # ES6 for-of on any iterable
|
|
|
122
122
|
|
|
123
123
|
for x as! asyncIterable # Async iteration shorthand
|
|
124
124
|
console.log x # Equivalent to: for await x as asyncIterable
|
|
125
|
+
|
|
126
|
+
loop # Infinite loop (while true)
|
|
127
|
+
process!
|
|
128
|
+
loop 5 # Repeat N times
|
|
129
|
+
console.log "hi"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Implicit `it`
|
|
133
|
+
|
|
134
|
+
Arrow functions with no params that reference `it` auto-inject it as the parameter:
|
|
135
|
+
|
|
136
|
+
```coffee
|
|
137
|
+
users.filter -> it.active # → users.filter(function(it) { ... })
|
|
138
|
+
names = users.map -> it.name # no need to name a throwaway variable
|
|
139
|
+
orders.filter -> it.total > 100 # works with any expression
|
|
125
140
|
```
|
|
126
141
|
|
|
127
142
|
### Reactivity
|
|
@@ -168,6 +183,7 @@ Compiles to `.js` (types erased) + `.d.ts` (types preserved) — full IDE suppor
|
|
|
168
183
|
| `!?` (otherwise) | `val !? 5` | Default only if `undefined` |
|
|
169
184
|
| `?` (existence) | `x?` | True if `x != null` |
|
|
170
185
|
| `?:` (ternary) | `x > 0 ? 'yes' : 'no'` | JS-style ternary expression |
|
|
186
|
+
| `if...else` (postfix) | `"yes" if cond else "no"` | Python-style ternary expression |
|
|
171
187
|
| `?.` `?.[]` `?.()` | `a?.b` `a?.[0]` `a?.()` | Optional chaining (ES6) |
|
|
172
188
|
| `?[]` `?()` | `a?[0]` `a?(x)` | Optional chaining shorthand |
|
|
173
189
|
| `??` | `a ?? b` | Nullish coalescing |
|
|
@@ -177,6 +193,15 @@ Compiles to `.js` (types erased) + `.d.ts` (types preserved) — full IDE suppor
|
|
|
177
193
|
| `=~` | `str =~ /Hello, (\w+)/` | Match (captures in `_`) |
|
|
178
194
|
| `[//, n]` | `str[/Hello, (\w+)/, 1]` | Extract capture n |
|
|
179
195
|
| `.new()` | `Dog.new()` | Ruby-style constructor |
|
|
196
|
+
| `::` (prototype) | `String::trim` | `String.prototype.trim` |
|
|
197
|
+
| `[-n]` (negative index) | `arr[-1]` | Last element via `.at()` |
|
|
198
|
+
| `*` (string repeat) | `"-" * 40` | String repeat via `.repeat()` |
|
|
199
|
+
| `<` `<=` (chained) | `1 < x < 10` | Chained comparisons |
|
|
200
|
+
| `\|>` (pipe) | `x \|> fn` or `x \|> fn(y)` | Pipe operator (first-arg insertion) |
|
|
201
|
+
| `not in` | `x not in arr` | Negated membership test |
|
|
202
|
+
| `not of` | `k not of obj` | Negated key existence |
|
|
203
|
+
| `.=` (method assign) | `x .= trim()` | `x = x.trim()` — compound method assignment |
|
|
204
|
+
| `*` (merge assign) | `*obj = {a: 1}` | `Object.assign(obj, {a: 1})` |
|
|
180
205
|
| `or return` | `x = get() or return err` | Guard clause (Ruby-style) |
|
|
181
206
|
| `?? throw` | `x = get() ?? throw err` | Nullish guard |
|
|
182
207
|
|
|
@@ -254,9 +279,9 @@ See [@rip-lang/ui](packages/ui/) for the full framework: file-based router, reac
|
|
|
254
279
|
| **Reactivity** | None | Built-in |
|
|
255
280
|
| **Dependencies** | Multiple | Zero |
|
|
256
281
|
| **Self-hosting** | No | Yes |
|
|
257
|
-
| **Lexer** | 3,558 LOC | 1,
|
|
258
|
-
| **Compiler** | 10,346 LOC | 3,
|
|
259
|
-
| **Total** | 17,760 LOC | ~10,
|
|
282
|
+
| **Lexer** | 3,558 LOC | 1,958 LOC |
|
|
283
|
+
| **Compiler** | 10,346 LOC | 3,378 LOC |
|
|
284
|
+
| **Total** | 17,760 LOC | ~10,800 LOC |
|
|
260
285
|
|
|
261
286
|
Smaller codebase, modern output, built-in reactivity.
|
|
262
287
|
|
|
@@ -291,25 +316,25 @@ await rip("res = fetch! 'https://api.example.com/todos/1'; res.json!") // → {
|
|
|
291
316
|
|
|
292
317
|
```
|
|
293
318
|
Source -> Lexer -> emitTypes -> Parser -> S-Expressions -> Codegen -> JavaScript
|
|
294
|
-
(1,
|
|
319
|
+
(1,958) (types.js) (359) ["=", "x", 42] (3,378) + source map
|
|
295
320
|
```
|
|
296
321
|
|
|
297
322
|
Simple arrays (with `.loc`) instead of AST node classes. The compiler is self-hosting — `bun run parser` rebuilds from source.
|
|
298
323
|
|
|
299
324
|
| Component | File | Lines |
|
|
300
325
|
|-----------|------|-------|
|
|
301
|
-
| Lexer + Rewriter | `src/lexer.js` | 1,
|
|
302
|
-
| Compiler + Codegen | `src/compiler.js` | 3,
|
|
303
|
-
| Type System | `src/types.js` |
|
|
326
|
+
| Lexer + Rewriter | `src/lexer.js` | 1,958 |
|
|
327
|
+
| Compiler + Codegen | `src/compiler.js` | 3,378 |
|
|
328
|
+
| Type System | `src/types.js` | 1,099 |
|
|
304
329
|
| Component System | `src/components.js` | 1,240 |
|
|
305
330
|
| Source Maps | `src/sourcemaps.js` | 122 |
|
|
306
|
-
| Parser (generated) | `src/parser.js` |
|
|
307
|
-
| Grammar | `src/grammar/grammar.rip` |
|
|
331
|
+
| Parser (generated) | `src/parser.js` | 359 |
|
|
332
|
+
| Grammar | `src/grammar/grammar.rip` | 945 |
|
|
308
333
|
| Parser Generator | `src/grammar/solar.rip` | 916 |
|
|
309
|
-
| REPL | `src/repl.js` |
|
|
334
|
+
| REPL | `src/repl.js` | 582 |
|
|
310
335
|
| Browser Entry | `src/browser.js` | 119 |
|
|
311
336
|
| Tags | `src/tags.js` | 63 |
|
|
312
|
-
| **Total** | | **~10,
|
|
337
|
+
| **Total** | | **~10,774** |
|
|
313
338
|
|
|
314
339
|
---
|
|
315
340
|
|
|
@@ -319,7 +344,7 @@ Rip includes optional packages for full-stack development:
|
|
|
319
344
|
|
|
320
345
|
| Package | Version | Purpose |
|
|
321
346
|
|---------|---------|---------|
|
|
322
|
-
| [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.
|
|
347
|
+
| [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.7.3 | Core language compiler |
|
|
323
348
|
| [@rip-lang/api](packages/api/) | 1.1.4 | HTTP framework (Sinatra-style routing, 37 validators) |
|
|
324
349
|
| [@rip-lang/server](packages/server/) | 1.1.3 | Multi-worker app server (hot reload, HTTPS, mDNS) |
|
|
325
350
|
| [@rip-lang/db](packages/db/) | 1.1.2 | DuckDB server with official UI (pure Bun FFI) |
|
|
@@ -365,7 +390,7 @@ rip file.rip # Run
|
|
|
365
390
|
rip -c file.rip # Compile
|
|
366
391
|
rip -t file.rip # Tokens
|
|
367
392
|
rip -s file.rip # S-expressions
|
|
368
|
-
bun run test #
|
|
393
|
+
bun run test # 1225 tests
|
|
369
394
|
bun run parser # Rebuild parser
|
|
370
395
|
bun run browser # Build browser bundle
|
|
371
396
|
```
|
package/docs/NOTES.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<img src="https://raw.githubusercontent.com/shreeve/rip-lang/main/docs/rip.png" style="width:50px" /> <br>
|
|
2
|
+
|
|
3
|
+
# Rip — Notes
|
|
4
|
+
|
|
5
|
+
Ideas, future plans, and design thoughts for Rip.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Standard Library (`stdlib`)
|
|
10
|
+
|
|
11
|
+
Rip is a zero-dependency language, but a small standard library of useful
|
|
12
|
+
utilities would save users from writing the same one-liners in every project.
|
|
13
|
+
These are **not** language features — they're plain functions that could ship
|
|
14
|
+
as a prelude or optional import.
|
|
15
|
+
|
|
16
|
+
### Candidates
|
|
17
|
+
|
|
18
|
+
```coffee
|
|
19
|
+
# Printing (Ruby's p)
|
|
20
|
+
p = console.log
|
|
21
|
+
|
|
22
|
+
# Exit with optional code (uses implicit `it`)
|
|
23
|
+
exit = -> process.exit(it)
|
|
24
|
+
|
|
25
|
+
# Tap — call a function for side effects, return the original value
|
|
26
|
+
# Useful in pipe chains: data |> tap(console.log) |> process
|
|
27
|
+
tap = (v, fn) -> fn(v); v
|
|
28
|
+
|
|
29
|
+
# Identity — returns its argument unchanged
|
|
30
|
+
# Useful as a default callback: items.filter(id)
|
|
31
|
+
id = -> it
|
|
32
|
+
|
|
33
|
+
# No-op — does nothing
|
|
34
|
+
# Useful as a default handler: onClick ?= noop
|
|
35
|
+
noop = ->
|
|
36
|
+
|
|
37
|
+
# String method aliases (shorter names for common checks)
|
|
38
|
+
String::starts = String::startsWith
|
|
39
|
+
String::ends = String::endsWith
|
|
40
|
+
String::has = String::includes
|
|
41
|
+
|
|
42
|
+
# Clamp a value to a range
|
|
43
|
+
clamp = (v, lo, hi) -> Math.min(Math.max(v, lo), hi)
|
|
44
|
+
|
|
45
|
+
# Sleep for N milliseconds (returns a Promise)
|
|
46
|
+
sleep = (ms) -> new Promise (resolve) -> setTimeout resolve, ms
|
|
47
|
+
|
|
48
|
+
# Times helper — call a function N times, collect results
|
|
49
|
+
times = (n, fn) -> (fn(i) for i in [0...n])
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Design Questions
|
|
53
|
+
|
|
54
|
+
- **Prelude vs import?** Should these be injected automatically (like Go's
|
|
55
|
+
`fmt` or Rip's reactive runtime), or explicitly imported (`import { p, tap }
|
|
56
|
+
from '@rip-lang/std'`)? Leaning toward explicit — Rip's philosophy is zero
|
|
57
|
+
magic in the output.
|
|
58
|
+
|
|
59
|
+
- **Scope?** Keep it tiny. A stdlib that grows to 500 functions defeats the
|
|
60
|
+
purpose. Each entry should save real keystrokes on something people do
|
|
61
|
+
constantly.
|
|
62
|
+
|
|
63
|
+
- **Node vs Browser?** Some helpers (like `exit`) are Node-only. Others (like
|
|
64
|
+
`p`, `tap`, `sleep`) work everywhere. May want to split into `std` (universal)
|
|
65
|
+
and `std/node` (server-only).
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Future Syntax Ideas
|
|
70
|
+
|
|
71
|
+
Ideas that have been discussed but not yet implemented. Each would need
|
|
72
|
+
design discussion before building.
|
|
73
|
+
|
|
74
|
+
- **`defer`** — Go-style cleanup that runs when the function exits. Compiles
|
|
75
|
+
to try/finally. `defer file.close()`.
|
|
76
|
+
|
|
77
|
+
- **`is a` / `isnt a`** — Readable instanceof. `x is a String` →
|
|
78
|
+
`x instanceof String`.
|
|
79
|
+
|
|
80
|
+
- **`.starts?` / `.ends?` / `.has?`** — Ruby-style question-mark methods.
|
|
81
|
+
`url.starts? "https"` → `url.startsWith("https")`.
|
|
82
|
+
|
|
83
|
+
- **Pattern matching** — `match value` with destructuring arms. Big feature,
|
|
84
|
+
needs careful design.
|
|
85
|
+
|
|
86
|
+
- **Reactive resource operator (`~>?`)** — Language-level `createResource`.
|
|
87
|
+
`user ~>? fetch!("/api/users/#{id}").json!` gives `user.loading`,
|
|
88
|
+
`user.error`, `user.data`. Park until real-world usage shows demand.
|
|
89
|
+
|
|
90
|
+
- **Pipe operator (`|>`) — Hack-style placeholder** — Currently Rip uses
|
|
91
|
+
Elixir-style first-arg insertion. A `%` placeholder for arbitrary position
|
|
92
|
+
(`data |> fn(1, %, 3)`) could be added later if needed. Current design
|
|
93
|
+
covers 95%+ of cases.
|
package/docs/RIP-GUIDE.md
CHANGED
|
@@ -117,6 +117,7 @@ else
|
|
|
117
117
|
|
|
118
118
|
# Ternary
|
|
119
119
|
status = active ? "on" : "off"
|
|
120
|
+
label = "big" if x > 5 else "small"
|
|
120
121
|
|
|
121
122
|
# Postfix
|
|
122
123
|
console.log "hi" if ready
|
|
@@ -147,11 +148,26 @@ for key, value of object
|
|
|
147
148
|
for i in [1..10] # inclusive (1 to 10)
|
|
148
149
|
for i in [1...10] # exclusive (1 to 9)
|
|
149
150
|
|
|
151
|
+
# Loop N times
|
|
152
|
+
loop 5
|
|
153
|
+
console.log "hi"
|
|
154
|
+
|
|
150
155
|
# Comprehensions
|
|
151
156
|
squares = (x * x for x in [1..10])
|
|
152
157
|
evens = (x for x in items when x % 2 is 0)
|
|
153
158
|
```
|
|
154
159
|
|
|
160
|
+
### Implicit `it`
|
|
161
|
+
|
|
162
|
+
Arrow functions with no params that reference `it` auto-inject it as the parameter:
|
|
163
|
+
|
|
164
|
+
```coffee
|
|
165
|
+
users.filter -> it.active # instead of (u) -> u.active
|
|
166
|
+
names = users.map -> it.name # instead of (u) -> u.name
|
|
167
|
+
orders.filter -> it.total > 100 # works with any expression
|
|
168
|
+
items.map => it.toUpperCase() # works with fat arrows too
|
|
169
|
+
```
|
|
170
|
+
|
|
155
171
|
---
|
|
156
172
|
|
|
157
173
|
## Operators
|
|
@@ -174,6 +190,15 @@ Rip extends JavaScript with powerful operators:
|
|
|
174
190
|
| `:=` | State | `count := 0` | Reactive signal |
|
|
175
191
|
| `~=` | Computed | `doubled ~= x * 2` | Reactive computed |
|
|
176
192
|
| `~>` | Effect | `~> console.log x` | Reactive side effect |
|
|
193
|
+
| `::` | Prototype | `String::trim` | `String.prototype.trim` |
|
|
194
|
+
| `[-n]` | Negative index | `arr[-1]` | `arr.at(-1)` |
|
|
195
|
+
| `*` | String repeat | `"-" * 40` | `"-".repeat(40)` |
|
|
196
|
+
| `<` `<=` | Chained | `1 < x < 10` | `(1 < x) && (x < 10)` |
|
|
197
|
+
| `.=` | Method assign | `x .= trim()` | `x = x.trim()` |
|
|
198
|
+
| `*` | Merge assign | `*obj = {a: 1}` | `Object.assign(obj, {a: 1})` |
|
|
199
|
+
| `not in` | Not in | `x not in arr` | Negated membership |
|
|
200
|
+
| `not of` | Not of | `k not of obj` | Negated key existence |
|
|
201
|
+
| `if...else` | Postfix ternary | `"a" if x else "b"` | `x ? "a" : "b"` |
|
|
177
202
|
| `**` | Power | `2 ** 10` | `1024` |
|
|
178
203
|
| `..` | Range | `[1..5]` | Inclusive range |
|
|
179
204
|
| `...` | Spread/rest | `[...a, ...b]` | ES6 spread |
|
|
@@ -211,6 +236,19 @@ if text =~ /Hello, (\w+)/
|
|
|
211
236
|
domain = "user@example.com"[/@(.+)$/, 1] # "example.com"
|
|
212
237
|
```
|
|
213
238
|
|
|
239
|
+
### Pipe Operator (`|>`)
|
|
240
|
+
|
|
241
|
+
Pipes a value into a function as the first argument. Chains left-to-right:
|
|
242
|
+
|
|
243
|
+
```coffee
|
|
244
|
+
5 |> double # → double(5)
|
|
245
|
+
5 |> add(3) # → add(5, 3)
|
|
246
|
+
5 |> double |> add(1) # → add(double(5), 1)
|
|
247
|
+
data |> JSON.stringify(null, 2) # → JSON.stringify(data, null, 2)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
If the right side is a bare reference, it's called with the piped value. If the right side is already a call, the piped value is inserted as the first argument. This is the Elixir-style pipe — cleaner than F# (multi-arg works) and simpler than Hack (no placeholder needed).
|
|
251
|
+
|
|
214
252
|
### Guard Clauses
|
|
215
253
|
|
|
216
254
|
```coffee
|
|
@@ -633,7 +671,7 @@ rip -d file.rip # Generate .d.ts
|
|
|
633
671
|
rip -t file.rip # Show tokens
|
|
634
672
|
rip -s file.rip # Show S-expressions
|
|
635
673
|
rip -q -c file.rip # Quiet (no headers)
|
|
636
|
-
bun run test # Run test suite
|
|
674
|
+
bun run test # Run test suite
|
|
637
675
|
```
|
|
638
676
|
|
|
639
677
|
---
|
package/docs/RIP-INTERNALS.md
CHANGED
|
@@ -45,7 +45,7 @@ class BinaryOp {
|
|
|
45
45
|
["+", left, right] // That's it!
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
**Result:** CoffeeScript's compiler is 17,760 LOC. Rip's is ~10,
|
|
48
|
+
**Result:** CoffeeScript's compiler is 17,760 LOC. Rip's is ~10,800 LOC — smaller, yet includes a complete reactive runtime, type system, component system, and source maps.
|
|
49
49
|
|
|
50
50
|
> **Transform the IR (s-expressions), not the output (strings).**
|
|
51
51
|
|
|
@@ -66,7 +66,7 @@ console.log(code);
|
|
|
66
66
|
| Feature | CoffeeScript | Rip |
|
|
67
67
|
|---------|-------------|------|
|
|
68
68
|
| Optional chaining | 4 soak operators | ES6 `?.` / `?.[]` / `?.()` + shorthand `?[]` / `?()` |
|
|
69
|
-
| Ternary | No | `x ? a : b` |
|
|
69
|
+
| Ternary | No | `x ? a : b` and `a if x else b` |
|
|
70
70
|
| Regex features | Basic | Ruby-style (`=~`, indexing, captures in `_`) |
|
|
71
71
|
| Async shorthand | No | Dammit operator (`!`) |
|
|
72
72
|
| Void functions | No | `def fn!` |
|
|
@@ -77,7 +77,7 @@ console.log(code);
|
|
|
77
77
|
| Dependencies | Multiple | **Zero** |
|
|
78
78
|
| Parser generator | External (Jison) | **Built-in (Solar)** |
|
|
79
79
|
| Self-hosting | No | **Yes** |
|
|
80
|
-
| Total LOC | 17,760 | ~10,
|
|
80
|
+
| Total LOC | 17,760 | ~10,800 |
|
|
81
81
|
|
|
82
82
|
## Design Principles
|
|
83
83
|
|
|
@@ -93,7 +93,7 @@ console.log(code);
|
|
|
93
93
|
|
|
94
94
|
```
|
|
95
95
|
Source Code → Lexer → emitTypes → Parser → S-Expressions → Codegen → JavaScript
|
|
96
|
-
(1,
|
|
96
|
+
(1,958) (types.js) (359) (arrays + .loc) (3,378) + source map
|
|
97
97
|
↓
|
|
98
98
|
file.d.ts (when types: "emit")
|
|
99
99
|
```
|
|
@@ -102,14 +102,14 @@ Source Code → Lexer → emitTypes → Parser → S-Expressions → C
|
|
|
102
102
|
|
|
103
103
|
| File | Purpose | Lines | Modify? |
|
|
104
104
|
|------|---------|-------|---------|
|
|
105
|
-
| `src/lexer.js` | Lexer + Rewriter | 1,
|
|
106
|
-
| `src/compiler.js` | Compiler + Code Generator | 3,
|
|
107
|
-
| `src/types.js` | Type System (lexer sidecar) |
|
|
105
|
+
| `src/lexer.js` | Lexer + Rewriter | 1,958 | Yes |
|
|
106
|
+
| `src/compiler.js` | Compiler + Code Generator | 3,378 | Yes |
|
|
107
|
+
| `src/types.js` | Type System (lexer sidecar) | 1,099 | Yes |
|
|
108
108
|
| `src/components.js` | Component System (compiler sidecar) | 1,240 | Yes |
|
|
109
109
|
| `src/sourcemaps.js` | Source Map V3 Generator | 122 | Yes |
|
|
110
110
|
| `src/tags.js` | HTML Tag Classification | 63 | Yes |
|
|
111
111
|
| `src/parser.js` | Generated parser | 357 | No (auto-gen) |
|
|
112
|
-
| `src/grammar/grammar.rip` | Grammar specification |
|
|
112
|
+
| `src/grammar/grammar.rip` | Grammar specification | 945 | Yes (carefully) |
|
|
113
113
|
| `src/grammar/solar.rip` | Parser generator | 916 | No |
|
|
114
114
|
|
|
115
115
|
## Example Flow
|
|
@@ -579,4 +579,4 @@ rip> .js # Toggle JS display
|
|
|
579
579
|
|
|
580
580
|
---
|
|
581
581
|
|
|
582
|
-
*Rip 3.
|
|
582
|
+
*Rip 3.7 — 1,219 tests passing — Zero dependencies — Self-hosting — ~10,800 LOC*
|