rip-lang 2.5.0 → 2.7.1
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 +53 -10
- package/README.md +135 -245
- package/docs/BROWSER.md +8 -11
- package/docs/GUIDE.md +101 -923
- package/docs/INTERNALS.md +2 -2
- package/docs/PHILOSOPHY.md +23 -78
- package/docs/REACTIVITY.md +288 -0
- package/docs/WHY-YES-RIP.md +39 -177
- package/docs/dist/rip.browser.js +603 -2429
- package/docs/dist/rip.browser.min.js +280 -356
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/docs/repl.html +94 -437
- package/package.json +4 -1
- package/scripts/serve.js +2 -0
- package/src/compiler.js +73 -2160
- package/src/grammar/grammar.rip +22 -57
- package/src/lexer.js +11 -298
- package/src/parser.js +220 -223
- package/src/repl.js +202 -128
- package/src/tags.js +0 -62
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,49 @@ 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
|
+
## [2.7.1] - 2026-02-03
|
|
11
|
+
|
|
12
|
+
### Bun-Native REPL with Dynamic Import Support
|
|
13
|
+
|
|
14
|
+
**Full `import()` Support in REPL**: The REPL now uses Bun's native evaluation instead of Node's `vm` module, enabling dynamic imports:
|
|
15
|
+
|
|
16
|
+
```coffee
|
|
17
|
+
rip> { Cash } = await import("./utils.js")
|
|
18
|
+
rip> config = Cash((await import("./config.js")).default)
|
|
19
|
+
rip> config.app.name
|
|
20
|
+
→ 'My App'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Key changes:**
|
|
24
|
+
- Replaced `vm.runInContext` with file-based async evaluation
|
|
25
|
+
- Variables persist across REPL lines via `globalThis.__ripRepl`
|
|
26
|
+
- Temp files cleaned up automatically on exit
|
|
27
|
+
- Reactive runtime injected into global scope for cross-line sharing
|
|
28
|
+
|
|
29
|
+
This enables using the REPL for real development workflows with module imports.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## [2.5.1] - 2026-01-16
|
|
34
|
+
|
|
35
|
+
### Template Enhancement
|
|
36
|
+
|
|
37
|
+
**Hyphenated Attributes Work Directly**:
|
|
38
|
+
```coffee
|
|
39
|
+
render
|
|
40
|
+
# Before: needed quoted keys or spread syntax
|
|
41
|
+
i {"data-lucide": "search"}
|
|
42
|
+
|
|
43
|
+
# Now: just works!
|
|
44
|
+
i data-lucide: "search", aria-hidden: "true"
|
|
45
|
+
div data-testid: "container", aria-label: "Menu"
|
|
46
|
+
span data-foo-bar-baz: "multiple-hyphens-work"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The lexer now automatically converts hyphenated attribute names (like `data-*`, `aria-*`) into quoted strings, making HTML-style data attributes intuitive and clean.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
10
53
|
## [2.5.0] - 2026-01-16
|
|
11
54
|
|
|
12
55
|
### Major Release - Parser Optimization + Complete Framework
|
|
@@ -156,7 +199,7 @@ Counter.new().mount("#app") # Selector string support
|
|
|
156
199
|
|
|
157
200
|
| Category | Score | Notes |
|
|
158
201
|
|----------|-------|-------|
|
|
159
|
-
| **Reactivity** | A+ | Fine-grained,
|
|
202
|
+
| **Reactivity** | A+ | Fine-grained, state, effects |
|
|
160
203
|
| **Templates** | A | S-expressions, Pug shorthand |
|
|
161
204
|
| **Components** | A | Props, lifecycle, context API |
|
|
162
205
|
| **Performance** | A | 250× faster parser gen, 51KB bundle |
|
|
@@ -167,7 +210,7 @@ Counter.new().mount("#app") # Selector string support
|
|
|
167
210
|
|
|
168
211
|
**What's in 51KB?**
|
|
169
212
|
- Complete compiler (lexer, parser, code generator)
|
|
170
|
-
- Reactive runtime (
|
|
213
|
+
- Reactive runtime (state, computed values, effects)
|
|
171
214
|
- Template engine (S-expression syntax, dynamic classes)
|
|
172
215
|
- Component system (props, lifecycle, fine-grained updates)
|
|
173
216
|
- Zero dependencies
|
|
@@ -272,10 +315,10 @@ Each item gets its own effect. Changing `selected` updates ONLY the affected cla
|
|
|
272
315
|
### Added - Reactive UI Framework
|
|
273
316
|
|
|
274
317
|
**Phase 1: Reactivity** (previously released)
|
|
275
|
-
-
|
|
276
|
-
-
|
|
277
|
-
- Effects:
|
|
278
|
-
- Runtime: `
|
|
318
|
+
- State-based reactivity: `count := 0` creates reactive state
|
|
319
|
+
- Computed values: `doubled ~= count * 2` auto-tracks dependencies
|
|
320
|
+
- Effects: `~> console.log count` runs on changes
|
|
321
|
+
- Runtime: `__state()`, `__computed()`, `__effect()`, `__batch()`, `__readonly()`
|
|
279
322
|
|
|
280
323
|
**Phase 2: Templates**
|
|
281
324
|
- Indentation-based template syntax in `render` blocks
|
|
@@ -297,8 +340,8 @@ Each item gets its own effect. Changing `selected` updates ONLY the affected cla
|
|
|
297
340
|
- Optional: `@label?`
|
|
298
341
|
- Default: `@label = "default"`
|
|
299
342
|
- Rest: `@...rest`
|
|
300
|
-
- Reactive state within components (auto-
|
|
301
|
-
-
|
|
343
|
+
- Reactive state within components (auto-state)
|
|
344
|
+
- Computed values within components (auto-computed)
|
|
302
345
|
- Component composition: `Button label: "Click"` inside render
|
|
303
346
|
- Children/slots: `@children` prop for nested content
|
|
304
347
|
- Lifecycle hooks: `mounted:`, `unmounted:`
|
|
@@ -312,8 +355,8 @@ Each item gets its own effect. Changing `selected` updates ONLY the affected cla
|
|
|
312
355
|
### Technical Details
|
|
313
356
|
- Components compile to ES6 classes with constructor, render, mount, unmount
|
|
314
357
|
- Props validated at construction (required props throw if missing)
|
|
315
|
-
- State variables become `
|
|
316
|
-
-
|
|
358
|
+
- State variables become `__state()` calls
|
|
359
|
+
- Computed values become `__computed()` calls
|
|
317
360
|
- `mount()` wraps render in `__effect()` for reactive updates
|
|
318
361
|
- PascalCase names in templates trigger component instantiation
|
|
319
362
|
|
package/README.md
CHANGED
|
@@ -5,27 +5,37 @@
|
|
|
5
5
|
<h1 align="center">Rip</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<strong>
|
|
8
|
+
<strong>A modern language that compiles to JavaScript</strong>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-2.
|
|
12
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-2.7.1-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-979%2F979-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
|
-
|
|
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,000 lines of code.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
> **No imports. No hooks. No dependency arrays. Just write code.**
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
```coffee
|
|
25
|
+
data = fetchUsers! # Dammit operator (call + await)
|
|
26
|
+
user = User.new name: "Alice" # Ruby-style constructor
|
|
27
|
+
squares = (x * x for x in [1..10]) # List comprehension
|
|
28
|
+
|
|
29
|
+
str =~ /Hello, (\w+)/ # Regex match
|
|
30
|
+
log "Found: #{_[1]}" # Captures in _[1], _[2], etc.
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
25
34
|
|
|
26
35
|
**What makes Rip different:**
|
|
27
|
-
- **Reactive primitives** — signals, derived values, and effects built into the language
|
|
28
36
|
- **Modern output** — ES2022 with native classes, `?.`, `??`, modules
|
|
37
|
+
- **New operators** — `!`, `!?`, `//`, `%%`, `=~`, `.new()`, and more
|
|
38
|
+
- **Reactive operators** — `:=`, `~=`, `~>` as language syntax
|
|
29
39
|
- **Zero dependencies** — everything included, even the parser generator
|
|
30
40
|
- **Self-hosting** — `bun run parser` rebuilds the compiler from source
|
|
31
41
|
|
|
@@ -33,229 +43,150 @@ The compiler is completely standalone with zero dependencies, and it's self-host
|
|
|
33
43
|
|
|
34
44
|
## Installation
|
|
35
45
|
|
|
36
|
-
**Option 1: Install from npm**
|
|
37
|
-
```bash
|
|
38
|
-
curl -fsSL https://bun.sh/install | bash # Install Bun (if needed)
|
|
39
|
-
bun add -g rip-lang
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
**Option 2: Clone from source**
|
|
43
46
|
```bash
|
|
44
|
-
|
|
45
|
-
cd rip-lang && bun link
|
|
47
|
+
bun add -g rip-lang # Install globally
|
|
46
48
|
```
|
|
47
49
|
|
|
48
|
-
**Then use it:**
|
|
49
50
|
```bash
|
|
50
|
-
rip
|
|
51
|
-
rip file.rip
|
|
52
|
-
rip -c file.rip
|
|
53
|
-
bun file.rip # Direct execution with Bun loader
|
|
51
|
+
rip # Interactive REPL
|
|
52
|
+
rip file.rip # Run a file
|
|
53
|
+
rip -c file.rip # Compile to JavaScript
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
---
|
|
57
57
|
|
|
58
|
-
## Language
|
|
58
|
+
## Language
|
|
59
59
|
|
|
60
60
|
### Functions & Classes
|
|
61
|
+
|
|
61
62
|
```coffee
|
|
62
|
-
#
|
|
63
|
-
def greet(name) # Named function (hoisted)
|
|
63
|
+
def greet(name) # Named function
|
|
64
64
|
"Hello, #{name}!"
|
|
65
65
|
|
|
66
|
-
add = (a, b) -> a + b
|
|
67
|
-
handler = (e) => @process e
|
|
68
|
-
|
|
69
|
-
# Classes with clean syntax
|
|
70
|
-
class Animal
|
|
71
|
-
constructor: (@name) ->
|
|
72
|
-
speak: -> console.log "#{@name} makes a sound"
|
|
66
|
+
add = (a, b) -> a + b # Arrow function
|
|
67
|
+
handler = (e) => @process e # Fat arrow (preserves this)
|
|
73
68
|
|
|
74
69
|
class Dog extends Animal
|
|
75
|
-
speak: ->
|
|
70
|
+
speak: -> log "#{@name} barks"
|
|
76
71
|
|
|
77
|
-
# Ruby-style
|
|
78
|
-
dog = Dog.new("Buddy") # → new Dog("Buddy")
|
|
79
|
-
dog = new Dog("Buddy") # Traditional JS style
|
|
72
|
+
dog = Dog.new("Buddy") # Ruby-style constructor
|
|
80
73
|
```
|
|
81
74
|
|
|
82
75
|
### Destructuring & Comprehensions
|
|
76
|
+
|
|
83
77
|
```coffee
|
|
84
|
-
# Destructuring
|
|
85
78
|
{name, age} = person
|
|
86
79
|
[first, ...rest] = items
|
|
87
80
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
console.log x for x in items # Just loops (no array created)
|
|
81
|
+
squares = (x * x for x in [1..10]) # Array comprehension
|
|
82
|
+
console.log x for x in items # Loop (no array)
|
|
91
83
|
```
|
|
92
84
|
|
|
93
|
-
### Async &
|
|
85
|
+
### Async & Chaining
|
|
86
|
+
|
|
94
87
|
```coffee
|
|
95
|
-
# Auto-async detection
|
|
96
88
|
def loadUser(id)
|
|
97
|
-
response = await fetch "/api
|
|
89
|
+
response = await fetch "/api/#{id}"
|
|
98
90
|
await response.json()
|
|
99
91
|
|
|
100
|
-
# Optional chaining
|
|
101
|
-
|
|
102
|
-
arr?[0] # CoffeeScript soak
|
|
103
|
-
fn?(arg) # Safe call
|
|
92
|
+
user?.profile?.name # Optional chaining
|
|
93
|
+
data = fetchData! # Await shorthand
|
|
104
94
|
```
|
|
105
95
|
|
|
106
|
-
|
|
96
|
+
### Reactivity
|
|
107
97
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
### New Operators & Syntax
|
|
111
|
-
|
|
112
|
-
| Feature | Example | What it does |
|
|
113
|
-
|---------|---------|--------------|
|
|
114
|
-
| **Ruby `.new()`** | `Counter.new()` | Ruby-style constructor → `new Counter()` |
|
|
115
|
-
| **Dammit `!`** | `fetchData!` | Calls the function AND awaits it |
|
|
116
|
-
| **Void `!`** | `def process!` | Suppresses implicit return (always returns undefined) |
|
|
117
|
-
| **Otherwise `!?`** | `val !? 5` | Defaults only if `undefined` (null/0/false are kept!) |
|
|
118
|
-
| **Floor div `//`** | `7 // 2` | Floor division → `Math.floor(7 / 2)` = 3 |
|
|
119
|
-
| **True mod `%%`** | `-1 %% 3` | True modulo (not remainder) → 2, not -1 |
|
|
120
|
-
| **Equal, dammit! `=!`** | `MAX =! 100` | Forces `const` declaration (can't reassign) |
|
|
121
|
-
| **Ternary `?:`** | `x > 0 ? 'yes' : 'no'` | JS-style ternary (plus CoffeeScript's if/then/else) |
|
|
122
|
-
| **Dual optional** | `a?.b` and `a?[0]` | Both ES6 native and CoffeeScript soak styles |
|
|
123
|
-
|
|
124
|
-
### Regex Enhancements
|
|
125
|
-
|
|
126
|
-
| Feature | Example | What it does |
|
|
127
|
-
|---------|---------|--------------|
|
|
128
|
-
| **Match `=~`** | `str =~ /(\w+)/` | Ruby-style regex, captures in `_[1]` |
|
|
129
|
-
| **Regex index** | `str[/pat/, 1]` | Extract capture group directly |
|
|
130
|
-
| **Heregex** | `///pat # comment///` | Extended regex with comments and whitespace |
|
|
131
|
-
|
|
132
|
-
### Strings & Data
|
|
133
|
-
|
|
134
|
-
| Feature | Example | What it does |
|
|
135
|
-
|---------|---------|--------------|
|
|
136
|
-
| **Heredoc** | `'''` closing column | Smart indentation — closing position sets left margin |
|
|
137
|
-
| **`__DATA__`** | `__DATA__\nconfig...` | Ruby-style inline data section, accessible as `DATA` |
|
|
138
|
-
|
|
139
|
-
### Reactivity (Built-in)
|
|
140
|
-
|
|
141
|
-
| Feature | Example | What it does |
|
|
142
|
-
|---------|---------|--------------|
|
|
143
|
-
| **Signal `:=`** | `count := 0` | Creates reactive state container |
|
|
144
|
-
| **Derived `~=`** | `doubled ~= count * 2` | Auto-updates when dependencies change |
|
|
145
|
-
| **Effect** | `effect -> log x` | Runs whenever referenced signals change |
|
|
146
|
-
|
|
147
|
-
### Components & Templates
|
|
148
|
-
|
|
149
|
-
| Feature | Example | What it does |
|
|
150
|
-
|---------|---------|--------------|
|
|
151
|
-
| **Component** | `component Counter` | Define reactive UI component |
|
|
152
|
-
| **Render** | `render` block | Indentation-based HTML templates |
|
|
153
|
-
| **Props** | `@prop`, `@prop?`, `@prop = default` | Component input from parent |
|
|
154
|
-
| **Rest props** | `@...rest` | Capture remaining props |
|
|
155
|
-
| **Two-way bind** | `input value <=> name` | Bidirectional data binding |
|
|
156
|
-
| **Event handlers** | `@click: handler` | DOM event binding |
|
|
157
|
-
| **Lifecycle** | `mounted:`, `unmounted:` | Component lifecycle hooks |
|
|
158
|
-
| **Context API** | `setContext`, `getContext` | Pass data down component tree |
|
|
159
|
-
| **Fine-grained** | No virtual DOM | Surgical DOM updates via signals |
|
|
160
|
-
|
|
161
|
-
**→ 26 major enhancements over CoffeeScript!**
|
|
98
|
+
State, computed values, and effects as language operators:
|
|
162
99
|
|
|
163
|
-
|
|
100
|
+
| Operator | Mnemonic | Example | What it does |
|
|
101
|
+
|----------|----------|---------|--------------|
|
|
102
|
+
| `=` | "gets value" | `x = 5` | Regular assignment |
|
|
103
|
+
| `:=` | "has state" | `count := 0` | Reactive state container |
|
|
104
|
+
| `~=` | "always equals" | `twice ~= count * 2` | Auto-updates on changes |
|
|
105
|
+
| `~>` | "reacts to" | `~> log count` | Runs on dependency changes |
|
|
106
|
+
| `=!` | "equals, dammit!" | `MAX =! 100` | Readonly constant |
|
|
164
107
|
|
|
165
|
-
|
|
108
|
+
---
|
|
166
109
|
|
|
167
|
-
|
|
110
|
+
## New Operators
|
|
168
111
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
112
|
+
| Operator | Example | What it does |
|
|
113
|
+
|----------|---------|--------------|
|
|
114
|
+
| `!` (dammit) | `fetchData!` | Calls AND awaits |
|
|
115
|
+
| `!` (void) | `def process!` | Suppresses implicit return |
|
|
116
|
+
| `!?` (otherwise) | `val !? 5` | Default only if `undefined` |
|
|
117
|
+
| `?:` (ternary) | `x > 0 ? 'yes' : 'no'` | JS-style ternary expression |
|
|
118
|
+
| `?.` `?[]` | `a?.b` `a?[0]` | Optional chaining (both styles) |
|
|
119
|
+
| `...` (spread) | `[...rest, last]` | Spread at start or end (JS: end only) |
|
|
120
|
+
| `//` | `7 // 2` | Floor division → 3 |
|
|
121
|
+
| `%%` | `-1 %% 3` | True modulo → 2 |
|
|
122
|
+
| `=~` | `str =~ /Hello, (\w+)/` | Match (captures in `_`) |
|
|
123
|
+
| `[//, n]` | `str[/Hello, (\w+)/, 1]` | Extract capture n |
|
|
124
|
+
| `.new()` | `Dog.new()` | Ruby-style constructor |
|
|
173
125
|
|
|
174
|
-
|
|
175
|
-
doubled ~= count * 2
|
|
176
|
-
greeting ~= "Hello, #{name}!"
|
|
126
|
+
**Optional chaining** — Both CoffeeScript and ES6 styles are supported:
|
|
177
127
|
|
|
178
|
-
|
|
179
|
-
|
|
128
|
+
| Syntax | Style | Compiles to |
|
|
129
|
+
|--------|-------|-------------|
|
|
130
|
+
| `obj?[0]` | CoffeeScript | `(obj != null ? obj[0] : undefined)` |
|
|
131
|
+
| `fn?(arg)` | CoffeeScript | `(typeof fn === 'function' ? fn(arg) : undefined)` |
|
|
132
|
+
| `obj?.[0]` | ES6/JS | `obj?.[0]` |
|
|
133
|
+
| `fn?.(arg)` | ES6/JS | `fn?.(arg)` |
|
|
180
134
|
|
|
181
|
-
|
|
182
|
-
count = 5 # Nothing (greeting doesn't depend on count)
|
|
183
|
-
```
|
|
135
|
+
### Heredoc & Heregex
|
|
184
136
|
|
|
185
|
-
|
|
137
|
+
**Heredoc** — The closing `'''` position sets the left margin (smart dedent):
|
|
186
138
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
139
|
+
```coffee
|
|
140
|
+
html = '''
|
|
141
|
+
<div>
|
|
142
|
+
<p>Hello</p>
|
|
143
|
+
</div>
|
|
144
|
+
'''
|
|
145
|
+
# Result: " <div>\n <p>Hello</p>\n </div>" (note the leading 2 spaces)
|
|
146
|
+
```
|
|
190
147
|
|
|
191
|
-
|
|
148
|
+
**Heregex** — Extended regex with comments and whitespace:
|
|
192
149
|
|
|
193
150
|
```coffee
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
dec: -> count -= 1
|
|
199
|
-
|
|
200
|
-
render
|
|
201
|
-
div.counter
|
|
202
|
-
h2 @label
|
|
203
|
-
span.value count
|
|
204
|
-
button @click: @inc, "+"
|
|
205
|
-
button @click: @dec, "−"
|
|
151
|
+
pattern = ///
|
|
152
|
+
^(\d{3}) # area code
|
|
153
|
+
-(\d{4}) # number
|
|
154
|
+
///
|
|
206
155
|
```
|
|
207
156
|
|
|
208
|
-
|
|
209
|
-
```coffee
|
|
210
|
-
# Normal: define methods, reference with @
|
|
211
|
-
inc: -> count += 1
|
|
212
|
-
button @click: @inc, "+"
|
|
157
|
+
---
|
|
213
158
|
|
|
214
|
-
|
|
215
|
-
button (@click: => @count++), "+"
|
|
216
|
-
```
|
|
159
|
+
## vs React / Vue / Solid
|
|
217
160
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
161
|
+
| Concept | React | Vue | Solid | Rip |
|
|
162
|
+
|---------|-------|-----|-------|-----|
|
|
163
|
+
| State | `useState()` | `ref()` | `createSignal()` | `x := 0` |
|
|
164
|
+
| Computed | `useMemo()` | `computed()` | `createMemo()` | `x ~= y * 2` |
|
|
165
|
+
| Effect | `useEffect()` | `watch()` | `createEffect()` | `~> body` |
|
|
223
166
|
|
|
224
|
-
|
|
167
|
+
Rip's reactivity is framework-agnostic — use it with React, Vue, Svelte, or vanilla JS.
|
|
225
168
|
|
|
226
169
|
---
|
|
227
170
|
|
|
228
|
-
##
|
|
171
|
+
## vs CoffeeScript
|
|
229
172
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
ul.items
|
|
240
|
-
for item in items
|
|
241
|
-
li key: item.id, item.name
|
|
242
|
-
```
|
|
173
|
+
| Feature | CoffeeScript | Rip |
|
|
174
|
+
|---------|--------------|-----|
|
|
175
|
+
| **Output** | ES5 (var, prototypes) | ES2022 (classes, `?.`, `??`) |
|
|
176
|
+
| **Reactivity** | None | Built-in |
|
|
177
|
+
| **Dependencies** | Multiple | Zero |
|
|
178
|
+
| **Self-hosting** | No | Yes |
|
|
179
|
+
| **Lexer** | 3,558 LOC | 3,250 LOC |
|
|
180
|
+
| **Compiler** | 10,346 LOC | 5,878 LOC |
|
|
181
|
+
| **Total** | 17,760 LOC | ~10,100 LOC |
|
|
243
182
|
|
|
244
|
-
|
|
245
|
-
- `@click: @handler` — Event handlers (method reference)
|
|
246
|
-
- `(@click: => @count++)` — Inline handlers (fat arrow, parens required)
|
|
247
|
-
- `.("class1", cond && "class2")` — Dynamic classes (Tailwind-friendly)
|
|
248
|
-
- `value <=> var` — Two-way binding
|
|
249
|
-
|
|
250
|
-
[Template guide →](docs/TEMPLATES.md)
|
|
183
|
+
Smaller codebase, modern output, built-in reactivity.
|
|
251
184
|
|
|
252
185
|
---
|
|
253
186
|
|
|
254
|
-
## Browser
|
|
255
|
-
|
|
256
|
-
Run Rip directly in the browser (51KB compressed—complete language + reactive framework).
|
|
187
|
+
## Browser
|
|
257
188
|
|
|
258
|
-
|
|
189
|
+
Run Rip directly in the browser (51KB compressed):
|
|
259
190
|
|
|
260
191
|
```html
|
|
261
192
|
<script src="https://shreeve.github.io/rip-lang/docs/dist/rip.browser.min.js"></script>
|
|
@@ -266,78 +197,50 @@ Run Rip directly in the browser (51KB compressed—complete language + reactive
|
|
|
266
197
|
</script>
|
|
267
198
|
```
|
|
268
199
|
|
|
269
|
-
|
|
270
|
-
bun run browser # Build the bundle
|
|
271
|
-
bun run serve # Start dev server at localhost:3000
|
|
272
|
-
```
|
|
200
|
+
**Try it live:** [shreeve.github.io/rip-lang](https://shreeve.github.io/rip-lang/)
|
|
273
201
|
|
|
274
202
|
---
|
|
275
203
|
|
|
276
|
-
##
|
|
277
|
-
|
|
278
|
-
CoffeeScript showed us beautiful syntax. Rip takes that vision further:
|
|
279
|
-
|
|
280
|
-
| | Rip | CoffeeScript |
|
|
281
|
-
|---|---|---|
|
|
282
|
-
| **Output** | ES2022 (classes, `?.`, `??`) | ES5 (var, prototypes) |
|
|
283
|
-
| **Reactivity** | Built-in (signals, effects, templates) | None |
|
|
284
|
-
| **Dependencies** | Zero | Multiple |
|
|
285
|
-
| **Self-hosting** | Yes (compiles itself) | No |
|
|
286
|
-
| **Codebase** | ~14,000 LOC | 17,760 LOC |
|
|
287
|
-
|
|
288
|
-
---
|
|
289
|
-
|
|
290
|
-
## Why S-Expressions?
|
|
291
|
-
|
|
292
|
-
Traditional compilers use complex AST node classes. Rip uses simple arrays:
|
|
204
|
+
## Architecture
|
|
293
205
|
|
|
294
206
|
```
|
|
295
207
|
Source → Lexer → Parser → S-Expressions → Codegen → JavaScript
|
|
296
208
|
["=", "x", 42]
|
|
297
209
|
```
|
|
298
210
|
|
|
299
|
-
|
|
300
|
-
```javascript
|
|
301
|
-
class BinaryOp {
|
|
302
|
-
constructor(op, left, right) { ... }
|
|
303
|
-
compile() { /* 50 lines */ }
|
|
304
|
-
}
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
**Rip's approach:**
|
|
308
|
-
```javascript
|
|
309
|
-
case '+': return `(${gen(left)} + ${gen(right)})`;
|
|
310
|
-
```
|
|
211
|
+
Simple arrays instead of AST node classes. The compiler is self-hosting — `bun run parser` rebuilds from source.
|
|
311
212
|
|
|
312
|
-
|
|
313
|
-
|-----------|--------------|-----|
|
|
314
|
-
| Lexer | 3,558 LOC | 3,537 LOC |
|
|
315
|
-
| Parser Generator | 2,285 LOC (Jison) | ~1,000 LOC (Solar) |
|
|
316
|
-
| Compiler | 10,346 LOC | 7,965 LOC |
|
|
317
|
-
| **Total** | **17,760 LOC** | **~14,000 LOC** |
|
|
213
|
+
---
|
|
318
214
|
|
|
319
|
-
|
|
215
|
+
## The Rip Stack
|
|
320
216
|
|
|
321
|
-
|
|
217
|
+
Rip includes optional packages for full-stack development:
|
|
322
218
|
|
|
323
|
-
|
|
219
|
+
| Package | Purpose | Lines |
|
|
220
|
+
|---------|---------|-------|
|
|
221
|
+
| [@rip-lang/api](packages/api/) | Web framework (Sinatra-style) | ~595 |
|
|
222
|
+
| [@rip-lang/server](packages/server/) | Multi-worker process manager | ~1,110 |
|
|
223
|
+
| [@rip-lang/db](packages/db/) | DuckDB HTTP server | ~225 |
|
|
224
|
+
| [@rip-lang/schema](packages/schema/) | ORM with reactive models | ~420 |
|
|
324
225
|
|
|
325
|
-
|
|
226
|
+
```bash
|
|
227
|
+
bun add @rip-lang/api @rip-lang/server
|
|
228
|
+
```
|
|
326
229
|
|
|
327
|
-
|
|
230
|
+
[Full stack documentation →](packages/README.md)
|
|
328
231
|
|
|
329
232
|
---
|
|
330
233
|
|
|
331
234
|
## Quick Reference
|
|
332
235
|
|
|
333
236
|
```bash
|
|
334
|
-
rip #
|
|
335
|
-
rip file.rip # Run
|
|
336
|
-
rip -c file.rip # Compile
|
|
337
|
-
rip -
|
|
338
|
-
rip -
|
|
339
|
-
bun run test #
|
|
340
|
-
bun run parser # Rebuild parser
|
|
237
|
+
rip # REPL
|
|
238
|
+
rip file.rip # Run
|
|
239
|
+
rip -c file.rip # Compile
|
|
240
|
+
rip -t file.rip # Tokens
|
|
241
|
+
rip -s file.rip # S-expressions
|
|
242
|
+
bun run test # 979 tests
|
|
243
|
+
bun run parser # Rebuild parser
|
|
341
244
|
bun run browser # Build browser bundle
|
|
342
245
|
```
|
|
343
246
|
|
|
@@ -347,12 +250,11 @@ bun run browser # Build browser bundle
|
|
|
347
250
|
|
|
348
251
|
| Guide | Description |
|
|
349
252
|
|-------|-------------|
|
|
350
|
-
| [
|
|
351
|
-
| [docs/REACTIVITY.md](docs/REACTIVITY.md) |
|
|
352
|
-
| [docs/
|
|
353
|
-
| [
|
|
253
|
+
| [docs/GUIDE.md](docs/GUIDE.md) | Language guide |
|
|
254
|
+
| [docs/REACTIVITY.md](docs/REACTIVITY.md) | Reactivity deep dive |
|
|
255
|
+
| [docs/INTERNALS.md](docs/INTERNALS.md) | Compiler architecture |
|
|
256
|
+
| [packages/](packages/README.md) | Full-stack packages |
|
|
354
257
|
| [CONTRIBUTING.md](CONTRIBUTING.md) | How to contribute |
|
|
355
|
-
| [CHANGELOG.md](CHANGELOG.md) | Version history |
|
|
356
258
|
|
|
357
259
|
---
|
|
358
260
|
|
|
@@ -362,7 +264,7 @@ bun run browser # Build browser bundle
|
|
|
362
264
|
{ "dependencies": {} }
|
|
363
265
|
```
|
|
364
266
|
|
|
365
|
-
Everything included: compiler, parser generator
|
|
267
|
+
Everything included: compiler, parser generator, REPL, browser bundle, test framework.
|
|
366
268
|
|
|
367
269
|
---
|
|
368
270
|
|
|
@@ -370,24 +272,12 @@ Everything included: compiler, parser generator (solar.rip), REPL, browser bundl
|
|
|
370
272
|
|
|
371
273
|
> *Simplicity scales.*
|
|
372
274
|
|
|
373
|
-
|
|
275
|
+
Simple IR (S-expressions), clear pipeline (lex → parse → generate), minimal code, comprehensive tests.
|
|
374
276
|
|
|
375
277
|
---
|
|
376
278
|
|
|
377
|
-
|
|
279
|
+
**Inspired by:** CoffeeScript, Lisp, Ruby | **Powered by:** [Bun](https://bun.sh)
|
|
378
280
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
**Powered by:** [Bun](https://bun.sh) — the fast all-in-one JavaScript runtime.
|
|
382
|
-
|
|
383
|
-
---
|
|
281
|
+
MIT License
|
|
384
282
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
MIT
|
|
388
|
-
|
|
389
|
-
---
|
|
390
|
-
|
|
391
|
-
<p align="center">
|
|
392
|
-
<strong>Start simple. Build incrementally. Ship elegantly.</strong> ✨
|
|
393
|
-
</p>
|
|
283
|
+
<p align="center"><strong>Start simple. Build incrementally. Ship elegantly.</strong></p>
|
package/docs/BROWSER.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# Rip in the Browser
|
|
4
4
|
|
|
5
|
-
**Complete Language + Reactive
|
|
5
|
+
**Complete Language + Reactive Runtime in 51KB**
|
|
6
6
|
|
|
7
|
-
Rip compiles to modern JavaScript and runs beautifully in the browser. With brotli compression, the entire package—compiler
|
|
7
|
+
Rip compiles to modern JavaScript and runs beautifully in the browser. With brotli compression, the entire package—compiler and reactive runtime—fits in just **51KB**. That's a complete language in less space than most utility libraries!
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -18,16 +18,14 @@ rip.browser.min.js.br 51 KB (brotli, 91% smaller!)
|
|
|
18
18
|
|
|
19
19
|
**What's in that 51KB?**
|
|
20
20
|
- Complete compiler (lexer, parser, code generator)
|
|
21
|
-
- Reactive runtime (
|
|
22
|
-
- Template engine (S-expression syntax, dynamic classes)
|
|
23
|
-
- Component system (props, lifecycle, fine-grained updates)
|
|
21
|
+
- Reactive runtime (state, computed values, effects)
|
|
24
22
|
- Zero dependencies
|
|
25
23
|
|
|
26
24
|
**For comparison:**
|
|
27
25
|
- React (min+gzip): ~42KB (just the library, no compiler)
|
|
28
26
|
- Vue (min+gzip): ~34KB (just the library, no compiler)
|
|
29
27
|
- Svelte: ~2KB runtime (but requires build step + compiler)
|
|
30
|
-
- **Rip: 51KB (complete language +
|
|
28
|
+
- **Rip: 51KB (complete language + reactive runtime, runs anywhere!)**
|
|
31
29
|
|
|
32
30
|
---
|
|
33
31
|
|
|
@@ -900,11 +898,10 @@ See the `docs/examples/` directory for working demos:
|
|
|
900
898
|
- More features than most frameworks, smaller than most libraries
|
|
901
899
|
- Fast loading even on mobile
|
|
902
900
|
|
|
903
|
-
**2. Complete
|
|
904
|
-
- Reactive primitives (
|
|
905
|
-
- S-expression templates with fine-grained updates
|
|
906
|
-
- Component system with props and lifecycle
|
|
901
|
+
**2. Complete Language**
|
|
902
|
+
- Reactive primitives (state, computed, effects)
|
|
907
903
|
- Modern ES6+ output
|
|
904
|
+
- Framework-agnostic — use with any UI library
|
|
908
905
|
|
|
909
906
|
**3. Zero Build Step**
|
|
910
907
|
- Write Rip directly in HTML
|
|
@@ -965,7 +962,7 @@ Then serve `node_modules/rip-lang/dist/rip.browser.min.js`
|
|
|
965
962
|
**Rip in the browser gives you:**
|
|
966
963
|
|
|
967
964
|
✅ **51KB** - Complete language + reactive framework (brotli)
|
|
968
|
-
✅ **Reactivity** -
|
|
965
|
+
✅ **Reactivity** - State, computed values, effects
|
|
969
966
|
✅ **Templates** - S-expression syntax, fine-grained DOM updates
|
|
970
967
|
✅ **Components** - Props, lifecycle, zero virtual DOM
|
|
971
968
|
✅ **Triple REPL** - Terminal, Browser, Console
|