rip-lang 1.1.0 → 1.1.2
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 +63 -91
- package/README.md +190 -47
- package/bin/rip +56 -31
- package/docs/COFFEESCRIPT-COMPARISON.md +2 -2
- package/docs/SOLAR.md +72 -6
- package/docs/WHY-YES-RIP.md +1 -1
- package/docs/dist/rip.browser.js +40 -2
- package/docs/dist/rip.browser.min.js +170 -168
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/docs/examples/sexpr.rip +134 -0
- package/docs/favicon.zip +0 -0
- package/docs/repl.html +4 -131
- package/docs/rip-512b.png +0 -0
- package/package.json +13 -2
- package/src/browser.js +1 -1
- package/src/codegen.js +71 -0
- package/src/compiler.js +3 -0
- package/src/grammar/grammar.rip +25 -25
- package/src/grammar/solar.rip +47 -177
- package/.cursor/rules/rip-agent-onboarding.md +0 -681
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -98
- package/.github/ISSUE_TEMPLATE/coffeescript_compatibility.yml +0 -85
- package/.github/ISSUE_TEMPLATE/config.yml +0 -10
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -82
- package/.github/ISSUE_TEMPLATE/question.yml +0 -54
- package/.github/pull_request_template.md +0 -83
- package/AGENT.md +0 -623
- package/CONTRIBUTING.md +0 -330
- package/SETUP.md +0 -144
- package/bar.coffee +0 -394
- package/bunfig.toml +0 -11
- package/scripts/build-browser.js +0 -76
- package/scripts/serve.js +0 -74
- package/test/rip/assignment.rip +0 -115
- package/test/rip/async.rip +0 -361
- package/test/rip/basic.rip +0 -171
- package/test/rip/classes.rip +0 -167
- package/test/rip/compatibility.rip +0 -338
- package/test/rip/comprehensions.rip +0 -104
- package/test/rip/control.rip +0 -177
- package/test/rip/data.rip +0 -215
- package/test/rip/errors.rip +0 -129
- package/test/rip/functions.rip +0 -443
- package/test/rip/guards.rip +0 -247
- package/test/rip/literals.rip +0 -131
- package/test/rip/loops.rip +0 -117
- package/test/rip/modules.rip +0 -87
- package/test/rip/operators.rip +0 -158
- package/test/rip/optional.rip +0 -184
- package/test/rip/properties.rip +0 -94
- package/test/rip/regex.rip +0 -301
- package/test/rip/stabilization.rip +0 -825
- package/test/rip/strings.rip +0 -483
- package/test/runner.js +0 -329
package/CHANGELOG.md
CHANGED
|
@@ -5,106 +5,78 @@ All notable changes to Rip will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [1.1.
|
|
9
|
-
|
|
10
|
-
### Major Enhancements
|
|
11
|
-
|
|
12
|
-
#### Comprehensions & Loops
|
|
13
|
-
- **Postfix comprehensions with `by` step** - `(x for x in [0...10] by 2)` now works ([#1](https://github.com/shreeve/rip-lang/issues/1))
|
|
14
|
-
- **Range loops without loop variable** - `for [1...N]` for N-time repetition ([#9](https://github.com/shreeve/rip-lang/issues/9))
|
|
15
|
-
- **Nested comprehension optimization** - Eliminated wasteful nested IIFEs, 50%+ output reduction ([#11](https://github.com/shreeve/rip-lang/issues/11))
|
|
16
|
-
- **Unified step handling** - Supports any negative step (`by -2`, `by -3`), 37% code reduction ([#3](https://github.com/shreeve/rip-lang/issues/3))
|
|
8
|
+
## [1.1.1] - 2025-11-01
|
|
17
9
|
|
|
18
|
-
|
|
19
|
-
- **
|
|
20
|
-
-
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Browser REPL launcher (`rip -w`)** - Port fallback now works correctly
|
|
12
|
+
- Fixed `ReferenceError: assignedPort is not defined`
|
|
13
|
+
- Server tries port 3000, falls back to OS-assigned port if busy
|
|
14
|
+
- Browser opens with correct port automatically
|
|
15
|
+
- Works when installed globally via `npm install -g rip-lang` or `bun install -g rip-lang`
|
|
21
16
|
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
17
|
+
### Changed
|
|
18
|
+
- Refactored serve.js to eliminate code duplication
|
|
19
|
+
- Improved port detection by parsing server output
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
- **`rip` executes scripts directly** - `rip script.rip` now runs scripts (no `bun` needed) ([#19](https://github.com/shreeve/rip-lang/issues/19))
|
|
28
|
-
- **`rip -w` launches browser REPL** - One command to start local server and open REPL
|
|
29
|
-
- **Beautiful s-expression formatter** - Canonical format with 80% less vertical space
|
|
30
|
-
- **Friendly error messages** - "File not found: X" instead of stack traces
|
|
21
|
+
## [1.1.0] - 2025-11-01
|
|
31
22
|
|
|
32
|
-
###
|
|
33
|
-
- **
|
|
23
|
+
### Added
|
|
24
|
+
- **Beautiful s-expression formatter** - Canonical format with proper indentation
|
|
25
|
+
- Deployed in CLI (`-s` flag), browser REPL, and as standalone utility
|
|
26
|
+
- 80% more compact than JSON, fully parenthesized
|
|
27
|
+
- Heregex patterns collapsed to single line
|
|
28
|
+
- Meta-circular: Rip code formatting Rip's data structures!
|
|
29
|
+
- **Script execution** - `rip script.rip` now executes directly (no explicit `bun` needed)
|
|
30
|
+
- Auto-detects .rip files and uses Bun loader
|
|
31
|
+
- Passes arguments correctly
|
|
32
|
+
- Shebang support: `#!/usr/bin/env rip`
|
|
33
|
+
- **Browser REPL launcher** - `rip -w` starts local server and opens browser
|
|
34
|
+
- One-command workflow
|
|
35
|
+
- Works offline with local changes
|
|
36
|
+
- Cross-platform (macOS, Windows, Linux)
|
|
37
|
+
- **Resizable REPL panes** - Drag slider between Rip source and JavaScript output
|
|
34
38
|
- **Local time display** - Build timestamp shown in user's timezone
|
|
35
|
-
- **
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
- **
|
|
40
|
-
- **
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
- **
|
|
45
|
-
- **
|
|
46
|
-
- **
|
|
47
|
-
-
|
|
48
|
-
- **
|
|
39
|
+
- **Friendly error messages** - Clear "File not found" instead of stack traces
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- **Postfix `by` step in comprehensions** - `for i in [0..10] by 2` now works
|
|
43
|
+
- **Nested IIFE elimination** - Major code generation optimization (37% smaller)
|
|
44
|
+
- **Throw in expressions** - Properly wrapped in IIFE
|
|
45
|
+
- **Rest parameters in middle position** - Both functions and array destructuring
|
|
46
|
+
- `def fn(first, ...middle, last)` works
|
|
47
|
+
- `[first, ...middle, last] = arr` works
|
|
48
|
+
- **Parser error messages** - Now show line and column numbers
|
|
49
|
+
- **Range loops without variable** - `for [1..10]` optimization
|
|
50
|
+
- **Comprehension context detection** - Smart IIFE vs plain loop decisions
|
|
51
|
+
- **Step handling refactoring** - Unified logic, 37% code reduction
|
|
52
|
+
- **Global installation** - `rip -w` works correctly when installed via npm/bun
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
- Version bumped to 1.1.0
|
|
56
|
+
- Test count: 843 → 864 (+21 tests, all passing)
|
|
57
|
+
- Documentation updated throughout
|
|
58
|
+
- Package.json prepared for NPM publishing
|
|
49
59
|
|
|
50
60
|
### Documentation
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
### Code Quality
|
|
57
|
-
- **Refactored step handling** - Eliminated code duplication, cleaner logic
|
|
58
|
-
- **Consistent formatting** - All s-expressions use canonical parenthesized format
|
|
59
|
-
- **Meta-circular utilities** - S-expression formatter written in Rip itself
|
|
60
|
-
|
|
61
|
-
### Testing
|
|
62
|
-
- **21 new tests added** - Coverage for all new features
|
|
63
|
-
- **Test count: 843 → 864** - All passing (100%)
|
|
64
|
-
- **Comprehensive coverage** - Nested comprehensions, rest in middle, throw expressions
|
|
61
|
+
- Complete GitHub workflow system (issues, PRs, templates)
|
|
62
|
+
- AI agent onboarding guide
|
|
63
|
+
- CONTRIBUTING.md with real examples
|
|
64
|
+
- Updated README, AGENT.md, COFFEESCRIPT-COMPARISON.md
|
|
65
|
+
- All stats current (864 tests)
|
|
65
66
|
|
|
66
|
-
###
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
|
|
70
|
-
### Real-World Validation
|
|
71
|
-
- **bar.coffee migration** - Complex 400-line CoffeeScript file now compiles perfectly
|
|
72
|
-
- **Output quality** - 608 lines (CoffeeScript) → 304 lines (Rip) = 50% smaller
|
|
73
|
-
- **All features working** - Nested switches, comprehensions, rest params, everything!
|
|
74
|
-
|
|
75
|
-
---
|
|
67
|
+
### Infrastructure
|
|
68
|
+
- 10 complete GitHub workflows (issue → branch → test → fix → PR → merge)
|
|
69
|
+
- Comprehensive test coverage (100% passing)
|
|
70
|
+
- Ready for NPM publish
|
|
76
71
|
|
|
77
72
|
## [1.0.0] - 2025-10-31
|
|
78
73
|
|
|
79
74
|
### Initial Release
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
- ✅ Comprehensive documentation
|
|
89
|
-
|
|
90
|
-
**Features:**
|
|
91
|
-
- Dual optional syntax (CoffeeScript soak + ES6 optional chaining)
|
|
92
|
-
- Dammit operator (`!`) for call-and-await
|
|
93
|
-
- Void functions (side-effect only)
|
|
94
|
-
- Heregex (extended regex with comments)
|
|
95
|
-
- Ruby-style regex (`=~` operator, indexing)
|
|
96
|
-
- __DATA__ marker
|
|
97
|
-
- Auto-detection (async/generators)
|
|
98
|
-
- Context-aware comprehensions
|
|
99
|
-
- Smart range optimization
|
|
100
|
-
|
|
101
|
-
**Implementation:**
|
|
102
|
-
- 9,450 LOC (50% smaller than CoffeeScript's 17,760)
|
|
103
|
-
- S-expression IR (simple arrays vs complex AST)
|
|
104
|
-
- SLR(1) parser generator included (solar.rip)
|
|
105
|
-
- Complete ES6 module support
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
[1.1.0]: https://github.com/shreeve/rip-lang/compare/v1.0.0...v1.1.0
|
|
110
|
-
[1.0.0]: https://github.com/shreeve/rip-lang/releases/tag/v1.0.0
|
|
75
|
+
- Complete Rip language compiler
|
|
76
|
+
- CoffeeScript-inspired syntax with modern ES2022 output
|
|
77
|
+
- Zero dependencies (includes SLR(1) parser generator)
|
|
78
|
+
- Self-hosting capability
|
|
79
|
+
- 843/843 tests passing
|
|
80
|
+
- Terminal REPL
|
|
81
|
+
- Browser bundle (43KB brotli-compressed)
|
|
82
|
+
- Complete documentation
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-1.1.
|
|
12
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-1.1.1-blue.svg" alt="Version"></a>
|
|
13
13
|
<a href="#es2022-target"><img src="https://img.shields.io/badge/target-ES2022-blue.svg" alt="Target"></a>
|
|
14
14
|
<a href="#current-status"><img src="https://img.shields.io/badge/tests-864%2F864-brightgreen.svg" alt="Tests"></a>
|
|
15
15
|
<a href="#current-status"><img src="https://img.shields.io/badge/coverage-100%25-brightgreen.svg" alt="Coverage"></a>
|
|
@@ -28,17 +28,16 @@ Rip brings CoffeeScript's elegance to modern JavaScript—but **50% smaller**, c
|
|
|
28
28
|
#### 💎 Elegant syntax with modern features
|
|
29
29
|
|
|
30
30
|
```coffee
|
|
31
|
-
def parseUsers(...inputs)
|
|
32
|
-
users = for input in inputs
|
|
33
|
-
# Ruby-style regex with =~ operator and _ captures
|
|
34
|
-
if input =~ /^(\w+):([^@]+@[\w.]+)$/
|
|
35
|
-
name = _[1] ?? "guest" # Nullish coalescing
|
|
36
|
-
domain = input[/@([\w.]+)/, 1] # Regex extraction syntax
|
|
37
|
-
{ name, domain }
|
|
38
|
-
|
|
39
31
|
# Async with dammit operator! (call and await)
|
|
40
32
|
fetchUser = (id) => fetch! "/api/user/${id}"
|
|
41
33
|
|
|
34
|
+
# Ruby-style regex with =~ operator and _ captures
|
|
35
|
+
def parseUsers(...inputs)
|
|
36
|
+
users = for input in inputs when input =~ /^(\w+):([^@]+@[\w.]+)$/
|
|
37
|
+
name = _[1] ?? "guest" # Nullish coalescing, _ captures
|
|
38
|
+
domain = input[/@([\w.]+)/, 1] # Regex extraction syntax
|
|
39
|
+
{ name, domain }
|
|
40
|
+
|
|
42
41
|
parseUsers "alice:alice@example.com", "bob:bob@test.org"
|
|
43
42
|
```
|
|
44
43
|
|
|
@@ -47,21 +46,20 @@ parseUsers "alice:alice@example.com", "bob:bob@test.org"
|
|
|
47
46
|
```javascript
|
|
48
47
|
let _, fetchUser;
|
|
49
48
|
|
|
49
|
+
fetchUser = async (id) => await fetch(`/api/user/${id}`);
|
|
50
50
|
function parseUsers(...inputs) {
|
|
51
51
|
let domain, name, users;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
} })());
|
|
52
|
+
|
|
53
|
+
users = [];
|
|
54
|
+
for (const input of inputs) {
|
|
55
|
+
if ((_ = toSearchable(input).match(/^(\w+):([^@]+@[\w.]+)$/))) {
|
|
56
|
+
name = (_[1] ?? "guest");
|
|
57
|
+
domain = (_ = toSearchable(input).match(/@([\w.]+)/)) && _[1];
|
|
58
|
+
users.push({name, domain});
|
|
60
59
|
}
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
}
|
|
61
|
+
return users;
|
|
63
62
|
};
|
|
64
|
-
fetchUser = async (id) => await fetch(`/api/user/${id}`);
|
|
65
63
|
parseUsers("alice:alice@example.com", "bob:bob@test.org");
|
|
66
64
|
```
|
|
67
65
|
|
|
@@ -190,7 +188,7 @@ case '+': {
|
|
|
190
188
|
| Component | CoffeeScript | Rip | Notes |
|
|
191
189
|
|-----------|--------------|-----|-------|
|
|
192
190
|
| Lexer+Rewriter | 3,558 LOC | **3,145 LOC** | Expanded syntax |
|
|
193
|
-
| Parser Generator | 2,285 LOC (Jison) | **
|
|
191
|
+
| Parser Generator | 2,285 LOC (Jison) | **928 LOC** (Solar) | Built-in, ~156× faster! |
|
|
194
192
|
| Compiler | 10,346 LOC (AST Nodes) | **4,738 LOC** (S-expressions) | Powerful capabilities |
|
|
195
193
|
| Tools | 1,571 LOC (Repl, Cake) | **520 LOC** (Repl, Browser) | 3 Repl's + Browser |
|
|
196
194
|
| **Total** | **17,760 LOC** | **9,450 LOC** | **~50% smaller** |
|
|
@@ -200,19 +198,131 @@ case '+': {
|
|
|
200
198
|
- ✅ **Self-hosting** - Rip compiles itself
|
|
201
199
|
- ✅ **No external tools** - Just a JavaScript runtime
|
|
202
200
|
|
|
201
|
+
### Real-World Example: The Complete Pipeline
|
|
202
|
+
|
|
203
|
+
Let's see how Rip code flows through the compilation pipeline:
|
|
204
|
+
|
|
205
|
+
**Step 1: Rip Source Code**
|
|
206
|
+
```coffee
|
|
207
|
+
# Rip code - edit me!
|
|
208
|
+
def fibonacci(n)
|
|
209
|
+
if n <= 1
|
|
210
|
+
n
|
|
211
|
+
else
|
|
212
|
+
fibonacci(n - 1) + fibonacci(n - 2)
|
|
213
|
+
|
|
214
|
+
# Try heregex
|
|
215
|
+
pattern = ///
|
|
216
|
+
^ \d+ # digits
|
|
217
|
+
\s* # space
|
|
218
|
+
[a-z]+ # letters
|
|
219
|
+
$
|
|
220
|
+
///i
|
|
221
|
+
|
|
222
|
+
# Try regex features
|
|
223
|
+
email = "user@example.com"
|
|
224
|
+
domain = email[/@(.+)$/, 1]
|
|
225
|
+
|
|
226
|
+
console.log "Fib(10):", fibonacci(10)
|
|
227
|
+
console.log "Domain:", domain
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Step 2: S-Expression Intermediate Representation**
|
|
231
|
+
|
|
232
|
+
The parser converts this to simple arrays (s-expressions):
|
|
233
|
+
|
|
234
|
+
```lisp
|
|
235
|
+
(program
|
|
236
|
+
(def fibonacci (n)
|
|
237
|
+
(block
|
|
238
|
+
(if (<= n 1) (block n)
|
|
239
|
+
(block (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))))
|
|
240
|
+
(= pattern "/^ \\d+\\s*[a-z]+$/i")
|
|
241
|
+
(= email "user@example.com")
|
|
242
|
+
(= domain (regex-index email /@(.+)$/ 1))
|
|
243
|
+
((. console log) "Fib(10):" (fibonacci 10))
|
|
244
|
+
((. console log) "Domain:" domain)
|
|
245
|
+
)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Key insights:**
|
|
249
|
+
- Each operation is just an array: `["+", left, right]`
|
|
250
|
+
- No complex AST node classes - just plain data
|
|
251
|
+
- Easy to inspect, transform, and debug
|
|
252
|
+
- Pattern matching in codegen is straightforward
|
|
253
|
+
|
|
254
|
+
**Step 3: JavaScript Output**
|
|
255
|
+
|
|
256
|
+
The code generator pattern-matches on s-expressions to produce clean JavaScript:
|
|
257
|
+
|
|
258
|
+
```javascript
|
|
259
|
+
let _, domain, email, pattern;
|
|
260
|
+
|
|
261
|
+
function fibonacci(n) {
|
|
262
|
+
return ((n <= 1) ? n : (fibonacci((n - 1)) + fibonacci((n - 2))));
|
|
263
|
+
};
|
|
264
|
+
pattern = /^\d+\s*[a-z]+$/i;
|
|
265
|
+
email = "user@example.com";
|
|
266
|
+
domain = (_ = toSearchable(email).match(/@(.+)$/)) && _[1];
|
|
267
|
+
console.log("Fib(10):", fibonacci(10));
|
|
268
|
+
console.log("Domain:", domain);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**The beauty:** Simple arrays in, clean JavaScript out. No complex AST traversal needed!
|
|
272
|
+
|
|
273
|
+
**Try it yourself:**
|
|
274
|
+
```bash
|
|
275
|
+
# See the s-expressions
|
|
276
|
+
echo 'x = 42' | ./bin/rip -s
|
|
277
|
+
|
|
278
|
+
# See the generated JavaScript
|
|
279
|
+
echo 'x = 42' | ./bin/rip -c
|
|
280
|
+
```
|
|
281
|
+
|
|
203
282
|
---
|
|
204
283
|
|
|
205
284
|
## Quick Start
|
|
206
285
|
|
|
207
286
|
### Installation & Setup
|
|
208
287
|
|
|
288
|
+
**🚀 Fastest Way: Install from Bun Package Registry**
|
|
289
|
+
|
|
290
|
+
First, install Bun if you haven't already:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# Install Bun (macOS, Linux, WSL)
|
|
294
|
+
curl -fsSL https://bun.sh/install | bash
|
|
295
|
+
|
|
296
|
+
# Or on Windows (PowerShell)
|
|
297
|
+
powershell -c "irm bun.sh/install.ps1|iex"
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Then install Rip globally:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# Install Rip globally
|
|
304
|
+
bun add -g rip-lang
|
|
305
|
+
|
|
306
|
+
# Start the REPL immediately!
|
|
307
|
+
rip
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
That's it! You can now:
|
|
311
|
+
- Run `rip` anywhere for an interactive REPL
|
|
312
|
+
- Compile Rip files: `rip yourfile.rip`
|
|
313
|
+
- Execute `.rip` files: `bun yourfile.rip`
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
**Alternative: Install from Source**
|
|
318
|
+
|
|
209
319
|
**Step 1: Clone the repository**
|
|
210
320
|
```bash
|
|
211
321
|
git clone https://github.com/shreeve/rip-lang.git
|
|
212
|
-
cd rip
|
|
322
|
+
cd rip-lang
|
|
213
323
|
```
|
|
214
324
|
|
|
215
|
-
**Step 2: Set up global Bun loader
|
|
325
|
+
**Step 2: Set up global Bun loader**
|
|
216
326
|
```bash
|
|
217
327
|
# Link Rip globally so it's available everywhere
|
|
218
328
|
bun link
|
|
@@ -245,10 +355,12 @@ cat ~/.bunfig.toml
|
|
|
245
355
|
# Should include: preload = ["rip-lang/loader"]
|
|
246
356
|
```
|
|
247
357
|
|
|
358
|
+
---
|
|
359
|
+
|
|
248
360
|
**No npm install needed** - Rip has zero dependencies!
|
|
249
361
|
|
|
250
362
|
**Requirements:**
|
|
251
|
-
- **Bun** (recommended) - For automatic `.rip` loader
|
|
363
|
+
- **Bun** (recommended) - For automatic `.rip` loader and REPL
|
|
252
364
|
- **Or** any ES2022-compatible runtime: Deno, Node.js 12+, modern browsers
|
|
253
365
|
- Note: Deno/Node require compilation first (`./bin/rip -o output.js input.rip`)
|
|
254
366
|
|
|
@@ -274,7 +386,7 @@ bun hello.rip
|
|
|
274
386
|
|
|
275
387
|
**You can also import .rip modules directly:**
|
|
276
388
|
|
|
277
|
-
```
|
|
389
|
+
```coffee
|
|
278
390
|
# utils.rip
|
|
279
391
|
export def add(a, b)
|
|
280
392
|
a + b
|
|
@@ -282,7 +394,7 @@ export def add(a, b)
|
|
|
282
394
|
export multiply = (a, b) => a * b
|
|
283
395
|
```
|
|
284
396
|
|
|
285
|
-
```
|
|
397
|
+
```coffee
|
|
286
398
|
# main.rip
|
|
287
399
|
import { add, multiply } from "./utils.rip"
|
|
288
400
|
|
|
@@ -300,19 +412,50 @@ bun main.rip # Works automatically!
|
|
|
300
412
|
# Interactive REPL
|
|
301
413
|
./bin/rip
|
|
302
414
|
|
|
303
|
-
#
|
|
415
|
+
# Execute a Rip script (default behavior)
|
|
304
416
|
./bin/rip examples/fibonacci.rip
|
|
305
417
|
|
|
306
|
-
#
|
|
418
|
+
# Compile and show JavaScript output
|
|
419
|
+
./bin/rip -c examples/fibonacci.rip
|
|
420
|
+
|
|
421
|
+
# Compile and save to file
|
|
422
|
+
./bin/rip -o output.js examples/fibonacci.rip
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Debug Flags (Mix and Match!)
|
|
426
|
+
|
|
427
|
+
Rip supports flexible debugging with flags that can be combined:
|
|
428
|
+
|
|
429
|
+
```bash
|
|
430
|
+
# Show ONLY s-expressions (no JavaScript)
|
|
307
431
|
./bin/rip -s examples/fibonacci.rip
|
|
308
432
|
|
|
309
|
-
#
|
|
433
|
+
# Show ONLY tokens (no JavaScript)
|
|
310
434
|
./bin/rip -t examples/fibonacci.rip
|
|
311
435
|
|
|
312
|
-
#
|
|
313
|
-
./bin/rip -
|
|
436
|
+
# Show s-expressions AND JavaScript
|
|
437
|
+
./bin/rip -s -c examples/fibonacci.rip
|
|
438
|
+
|
|
439
|
+
# Show tokens AND JavaScript
|
|
440
|
+
./bin/rip -t -c examples/fibonacci.rip
|
|
441
|
+
|
|
442
|
+
# Show EVERYTHING (full debug mode)
|
|
443
|
+
./bin/rip -s -t -c examples/fibonacci.rip
|
|
444
|
+
|
|
445
|
+
# Pipe mode (no headers, just output)
|
|
446
|
+
./bin/rip -q -c examples/fibonacci.rip
|
|
314
447
|
```
|
|
315
448
|
|
|
449
|
+
**How it works:**
|
|
450
|
+
- `rip script.rip` **executes** the script (default behavior)
|
|
451
|
+
- `echo 'code' | rip` **compiles** and shows JavaScript (stdin defaults to compile mode)
|
|
452
|
+
- `-c` flag **compiles** and shows JavaScript output
|
|
453
|
+
- `-o file.js` **compiles** and saves to file
|
|
454
|
+
- `-s` or `-t` alone show **only** that output (no JavaScript)
|
|
455
|
+
- Add `-c` to **also** show the compiled JavaScript
|
|
456
|
+
- Mix and match as needed for debugging
|
|
457
|
+
- Browser REPL always shows JavaScript (checkboxes toggle `-s` and `-t`)
|
|
458
|
+
|
|
316
459
|
### Interactive REPL
|
|
317
460
|
|
|
318
461
|
Rip includes a full-featured REPL for interactive development:
|
|
@@ -423,7 +566,7 @@ bun run serve # Start dev server (REPL at localhost:3000)
|
|
|
423
566
|
|
|
424
567
|
### Core Syntax
|
|
425
568
|
|
|
426
|
-
```
|
|
569
|
+
```coffee
|
|
427
570
|
# Variables (function-scoped, auto-hoisted)
|
|
428
571
|
x = 42
|
|
429
572
|
name = "Alice"
|
|
@@ -469,7 +612,7 @@ greeting = "Hello, ${name}!"
|
|
|
469
612
|
|
|
470
613
|
### Modern Features
|
|
471
614
|
|
|
472
|
-
```
|
|
615
|
+
```coffee
|
|
473
616
|
# Destructuring
|
|
474
617
|
{name, age} = person
|
|
475
618
|
[first, second] = numbers
|
|
@@ -625,7 +768,7 @@ Rip provides **two distinct approaches** to safe property/method access:
|
|
|
625
768
|
|
|
626
769
|
**Compiles to explicit null/undefined checks:**
|
|
627
770
|
|
|
628
|
-
```
|
|
771
|
+
```coffee
|
|
629
772
|
# Existence check
|
|
630
773
|
arr?
|
|
631
774
|
# → (arr != null)
|
|
@@ -657,7 +800,7 @@ a ?= 10
|
|
|
657
800
|
|
|
658
801
|
**Passes through to native JavaScript:**
|
|
659
802
|
|
|
660
|
-
```
|
|
803
|
+
```coffee
|
|
661
804
|
# Optional property
|
|
662
805
|
user?.profile?.name
|
|
663
806
|
# → user?.profile?.name
|
|
@@ -689,7 +832,7 @@ a ??= 10
|
|
|
689
832
|
|
|
690
833
|
**You can combine both styles in the same expression:**
|
|
691
834
|
|
|
692
|
-
```
|
|
835
|
+
```coffee
|
|
693
836
|
# ES6 optional property + CoffeeScript soak index
|
|
694
837
|
obj?.arr?[0]
|
|
695
838
|
# → (obj?.arr != null ? obj?.arr[0] : undefined)
|
|
@@ -728,12 +871,12 @@ Both syntaxes handle `null` and `undefined` - pick the style that fits your proj
|
|
|
728
871
|
### The Pipeline
|
|
729
872
|
|
|
730
873
|
```
|
|
731
|
-
|
|
732
|
-
│
|
|
733
|
-
│
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
874
|
+
┌────────┐ ┌────────────┐ ┌──────────┐ ┌─────────┐
|
|
875
|
+
│ Source │───>│ Lexer │───>│ Parser │───>│ Codegen │
|
|
876
|
+
│ Code │ │ (Coffee) │ │ (Solar) │ │ (Rip) │
|
|
877
|
+
└────────┘ └────────────┘ └──────────┘ └─────────┘
|
|
878
|
+
3,145 LOC 928 LOC 4,738 LOC
|
|
879
|
+
15 yrs tested Generated! S-expr Optimized!
|
|
737
880
|
```
|
|
738
881
|
|
|
739
882
|
### Components
|
|
@@ -748,8 +891,8 @@ Both syntaxes handle `null` and `undefined` - pick the style that fits your proj
|
|
|
748
891
|
- Solar-generated SLR(1) parser
|
|
749
892
|
- Built from grammar specification
|
|
750
893
|
- Generates s-expressions directly
|
|
751
|
-
- Regenerate with `bun run parser` (~
|
|
752
|
-
- **Note:** Solar's
|
|
894
|
+
- Regenerate with `bun run parser` (~80ms, instant feedback!)
|
|
895
|
+
- **Note:** Solar's 156× speed advantage over Jison (80ms vs 12.5s) made rapid grammar iteration possible
|
|
753
896
|
|
|
754
897
|
**3. Code Generator** (`src/codegen.js`)
|
|
755
898
|
- Pattern matches on s-expressions
|
|
@@ -995,7 +1138,7 @@ rip/
|
|
|
995
1138
|
```
|
|
996
1139
|
|
|
997
1140
|
3. **Write tests:**
|
|
998
|
-
```
|
|
1141
|
+
```coffee
|
|
999
1142
|
test "feature name", "code", expectedResult
|
|
1000
1143
|
```
|
|
1001
1144
|
|
|
@@ -1019,7 +1162,7 @@ rip/
|
|
|
1019
1162
|
|
|
1020
1163
|
Rip requires parentheses for ALL arrow function parameters:
|
|
1021
1164
|
|
|
1022
|
-
```
|
|
1165
|
+
```coffee
|
|
1023
1166
|
# ✅ Always use parentheses
|
|
1024
1167
|
() => expr # Zero params
|
|
1025
1168
|
(x) => expr # One param
|
|
@@ -1233,7 +1376,7 @@ MIT
|
|
|
1233
1376
|
**Inspired by:**
|
|
1234
1377
|
- CoffeeScript (syntax and lexer)
|
|
1235
1378
|
- Lisp/Scheme (s-expressions)
|
|
1236
|
-
- Solar (parser generator) - **This project wouldn't have been possible without Solar's incredible speed (
|
|
1379
|
+
- Solar (parser generator) - **This project wouldn't have been possible without Solar's incredible speed (80ms vs Jison's 12.5 seconds for parser generation). Solar's performance enabled rapid iteration on grammar changes with instant feedback, making development a joy.**
|
|
1237
1380
|
- Ruby (regex operators, __DATA__ marker)
|
|
1238
1381
|
|
|
1239
1382
|
**Built by:** Developers who believe simplicity scales
|