rip-lang 3.10.5 → 3.10.7
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 +11 -0
- package/README.md +18 -18
- package/bin/rip +9 -20
- package/docs/RIP-INTERNALS.md +14 -14
- package/docs/RIP-LANG.md +327 -70
- package/docs/dist/rip-ui.min.js +174 -164
- package/docs/dist/rip-ui.min.js.br +0 -0
- package/docs/dist/rip.browser.min.js +194 -184
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/docs/results/images/cover_bg.jpg +0 -0
- package/docs/results/images/crossover.svg +20 -0
- package/docs/results/images/heart.png +0 -0
- package/docs/results/images/human_body.png +0 -0
- package/docs/results/images/pancreas.png +0 -0
- package/docs/results/images/yoga_lady.jpg +0 -0
- package/docs/results/index.html +1117 -0
- package/package.json +1 -1
- package/src/compiler.js +10 -0
- package/src/components.js +151 -53
package/docs/RIP-LANG.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Rip Language Reference
|
|
4
4
|
|
|
5
|
-
Rip is a modern reactive language that compiles to ES2022 JavaScript. It combines CoffeeScript's elegant syntax with built-in reactivity primitives. Zero dependencies, self-hosting, ~
|
|
5
|
+
Rip is a modern reactive language that compiles to ES2022 JavaScript. It combines CoffeeScript's elegant syntax with built-in reactivity primitives. Zero dependencies, self-hosting, ~13,500 LOC.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -17,7 +17,7 @@ Rip is a modern reactive language that compiles to ES2022 JavaScript. It combine
|
|
|
17
17
|
7. [Async Patterns](#7-async-patterns)
|
|
18
18
|
8. [Modules & Imports](#8-modules--imports)
|
|
19
19
|
9. [Regex Features](#9-regex-features)
|
|
20
|
-
10. [
|
|
20
|
+
10. [Packages](#10-packages)
|
|
21
21
|
11. [CLI Tools & Scripts](#11-cli-tools--scripts)
|
|
22
22
|
12. [Types](#12-types)
|
|
23
23
|
13. [JavaScript Interop](#13-javascript-interop)
|
|
@@ -322,6 +322,7 @@ Multiple lines
|
|
|
322
322
|
| `*` | Merge assign | `*obj = {a: 1}` | `Object.assign(obj, {a: 1})` |
|
|
323
323
|
| `not in` | Not in | `x not in arr` | Negated membership test |
|
|
324
324
|
| `not of` | Not of | `k not of obj` | Negated key existence |
|
|
325
|
+
| `<=>` | Two-way bind | `value <=> name` | Bidirectional reactive binding (render blocks) |
|
|
325
326
|
|
|
326
327
|
## Assignment Operators
|
|
327
328
|
|
|
@@ -663,6 +664,19 @@ counter = Counter.new(initial: 5)
|
|
|
663
664
|
# Same as: new Counter({initial: 5})
|
|
664
665
|
```
|
|
665
666
|
|
|
667
|
+
## Implicit Commas
|
|
668
|
+
|
|
669
|
+
When a literal value is followed by an arrow function, Rip inserts a comma automatically:
|
|
670
|
+
|
|
671
|
+
```coffee
|
|
672
|
+
# Clean route handlers
|
|
673
|
+
get '/users' -> User.all!
|
|
674
|
+
get '/users/:id' -> User.find params.id
|
|
675
|
+
post '/users' -> User.create body
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
This enables Sinatra-style routing and other DSLs where functions take a value and a callback.
|
|
679
|
+
|
|
666
680
|
---
|
|
667
681
|
|
|
668
682
|
# 5. Classes
|
|
@@ -902,6 +916,110 @@ declare const count: Signal<number>;
|
|
|
902
916
|
declare const doubled: Computed<number>;
|
|
903
917
|
```
|
|
904
918
|
|
|
919
|
+
## Two-Way Binding (`<=>`)
|
|
920
|
+
|
|
921
|
+
The `<=>` operator creates bidirectional reactive bindings inside render blocks.
|
|
922
|
+
It connects a parent's reactive state to a child element or component — changes
|
|
923
|
+
flow in both directions automatically. This is a Rip original.
|
|
924
|
+
|
|
925
|
+
### With HTML Elements
|
|
926
|
+
|
|
927
|
+
```coffee
|
|
928
|
+
export Form = component
|
|
929
|
+
@name := ''
|
|
930
|
+
@age := 25
|
|
931
|
+
@agree := false
|
|
932
|
+
|
|
933
|
+
render
|
|
934
|
+
input value <=> @name # text input
|
|
935
|
+
input type: "number", value <=> @age # number input
|
|
936
|
+
input type: "checkbox", checked <=> @agree # checkbox
|
|
937
|
+
p "#{@name}, age #{@age}, agreed: #{@agree}"
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
`value <=> @name` compiles to two things:
|
|
941
|
+
1. **State → DOM**: an effect that sets `el.value = name` whenever `name` changes
|
|
942
|
+
2. **DOM → State**: an event listener that sets `name = e.target.value` on input
|
|
943
|
+
|
|
944
|
+
The compiler auto-detects types:
|
|
945
|
+
- Text inputs use the `input` event and `e.target.value`
|
|
946
|
+
- Number/range inputs use `e.target.valueAsNumber`
|
|
947
|
+
- Checkboxes use the `change` event and `e.target.checked`
|
|
948
|
+
|
|
949
|
+
### With Components
|
|
950
|
+
|
|
951
|
+
`<=>` works with custom components using the same syntax:
|
|
952
|
+
|
|
953
|
+
```coffee
|
|
954
|
+
export App = component
|
|
955
|
+
@selected := 'viewer'
|
|
956
|
+
@showDialog := false
|
|
957
|
+
@darkMode := false
|
|
958
|
+
|
|
959
|
+
render
|
|
960
|
+
Select value <=> @selected
|
|
961
|
+
Option value: "viewer", "Viewer"
|
|
962
|
+
Option value: "editor", "Editor"
|
|
963
|
+
Option value: "admin", "Admin"
|
|
964
|
+
Switch checked <=> @darkMode, "Dark mode"
|
|
965
|
+
Dialog open <=> @showDialog
|
|
966
|
+
p "Are you sure?"
|
|
967
|
+
p "Role: #{@selected}"
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
The parent owns the state. The child reads it and writes back to it. No
|
|
971
|
+
callback props, no `onChange` handlers, no `onOpenChange`, no `setValue`.
|
|
972
|
+
|
|
973
|
+
### Why This Matters
|
|
974
|
+
|
|
975
|
+
React requires explicit `value` + `onChange` pairs for every bindable property.
|
|
976
|
+
This is the "controlled component" pattern — the single most tedious aspect of
|
|
977
|
+
React development:
|
|
978
|
+
|
|
979
|
+
```jsx
|
|
980
|
+
// React: 8 lines of wiring for 4 controls
|
|
981
|
+
const [name, setName] = useState('');
|
|
982
|
+
const [role, setRole] = useState('viewer');
|
|
983
|
+
const [notify, setNotify] = useState(true);
|
|
984
|
+
const [show, setShow] = useState(false);
|
|
985
|
+
|
|
986
|
+
<input value={name} onChange={e => setName(e.target.value)} />
|
|
987
|
+
<Select value={role} onValueChange={setRole} />
|
|
988
|
+
<Switch checked={notify} onCheckedChange={setNotify} />
|
|
989
|
+
<Dialog open={show} onOpenChange={setShow} />
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
Rip eliminates all of it:
|
|
993
|
+
|
|
994
|
+
```coffee
|
|
995
|
+
# Rip: 4 state declarations, 4 bindings, zero callbacks
|
|
996
|
+
@name := ''
|
|
997
|
+
@role := 'viewer'
|
|
998
|
+
@notify := true
|
|
999
|
+
@show := false
|
|
1000
|
+
|
|
1001
|
+
input value <=> @name
|
|
1002
|
+
Select value <=> @role
|
|
1003
|
+
Switch checked <=> @notify
|
|
1004
|
+
Dialog open <=> @show
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
Vue has `v-model`. Svelte has `bind:`. But Rip's `<=>` is cleaner — it works
|
|
1008
|
+
uniformly across HTML elements and custom components with the same syntax, the
|
|
1009
|
+
same operator, and the same mental model. No framework-specific directives, no
|
|
1010
|
+
special component protocol. Just a reactive binding that flows both ways.
|
|
1011
|
+
|
|
1012
|
+
### Auto-Detection
|
|
1013
|
+
|
|
1014
|
+
Even without `<=>`, the compiler auto-detects when `value:` or `checked:` is
|
|
1015
|
+
bound to a reactive expression and generates two-way binding automatically:
|
|
1016
|
+
|
|
1017
|
+
```coffee
|
|
1018
|
+
# These are equivalent:
|
|
1019
|
+
input value <=> @name # explicit
|
|
1020
|
+
input value: @name # auto-detected (name is reactive)
|
|
1021
|
+
```
|
|
1022
|
+
|
|
905
1023
|
---
|
|
906
1024
|
|
|
907
1025
|
# 7. Async Patterns
|
|
@@ -1087,98 +1205,218 @@ text =~ /line2/m # Works with /m flag
|
|
|
1087
1205
|
|
|
1088
1206
|
---
|
|
1089
1207
|
|
|
1090
|
-
# 10.
|
|
1208
|
+
# 10. Packages
|
|
1091
1209
|
|
|
1092
|
-
|
|
1210
|
+
Rip includes optional packages for full-stack development. All are written in Rip, have zero dependencies, and run on Bun.
|
|
1211
|
+
|
|
1212
|
+
```bash
|
|
1213
|
+
bun add @rip-lang/api # Web framework
|
|
1214
|
+
bun add @rip-lang/server # Production server
|
|
1215
|
+
bun add @rip-lang/ui # Reactive web UI
|
|
1216
|
+
bun add @rip-lang/db # DuckDB server + client
|
|
1217
|
+
bun add @rip-lang/schema # ORM + validation
|
|
1218
|
+
bun add @rip-lang/swarm # Parallel job runner
|
|
1219
|
+
bun add @rip-lang/csv # CSV parser + writer
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
## @rip-lang/api — Web Framework
|
|
1223
|
+
|
|
1224
|
+
Sinatra-style routing with `@` context magic and built-in validators.
|
|
1093
1225
|
|
|
1094
1226
|
```coffee
|
|
1095
|
-
import {
|
|
1227
|
+
import { get, post, use, read, start, notFound } from '@rip-lang/api'
|
|
1096
1228
|
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
new Response("Not Found", status: 404)
|
|
1229
|
+
# Routes — return data directly
|
|
1230
|
+
get '/' -> { message: 'Hello!' }
|
|
1231
|
+
get '/users/:id' -> User.find!(read 'id', 'id!')
|
|
1232
|
+
|
|
1233
|
+
# Form validation with read()
|
|
1234
|
+
post '/signup' ->
|
|
1235
|
+
email = read 'email', 'email!' # required email
|
|
1236
|
+
age = read 'age', 'int', [18, 120] # integer between 18-120
|
|
1237
|
+
role = read 'role', ['admin', 'user'] # enum
|
|
1238
|
+
{ success: true, email, age, role }
|
|
1108
1239
|
|
|
1109
|
-
|
|
1240
|
+
# File serving
|
|
1241
|
+
get '/css/*' -> @send "public/#{@req.path.slice(5)}"
|
|
1242
|
+
notFound -> @send 'index.html', 'text/html; charset=UTF-8'
|
|
1243
|
+
|
|
1244
|
+
# Middleware
|
|
1245
|
+
import { cors, logger, sessions } from '@rip-lang/api/middleware'
|
|
1246
|
+
|
|
1247
|
+
use logger()
|
|
1248
|
+
use cors origin: '*'
|
|
1249
|
+
use sessions secret: process.env.SECRET
|
|
1250
|
+
|
|
1251
|
+
# Lifecycle hooks
|
|
1252
|
+
before -> @start = Date.now()
|
|
1253
|
+
after -> console.log "#{@req.method} #{@req.path} - #{Date.now() - @start}ms"
|
|
1254
|
+
|
|
1255
|
+
start port: 3000
|
|
1110
1256
|
```
|
|
1111
1257
|
|
|
1112
|
-
|
|
1258
|
+
### read() Validators
|
|
1113
1259
|
|
|
1114
1260
|
```coffee
|
|
1115
|
-
|
|
1261
|
+
id = read 'id', 'id!' # positive integer (required)
|
|
1262
|
+
count = read 'count', 'whole' # non-negative integer
|
|
1263
|
+
price = read 'price', 'money' # cents (multiplies by 100)
|
|
1264
|
+
name = read 'name', 'string' # collapses whitespace
|
|
1265
|
+
email = read 'email', 'email' # valid email format
|
|
1266
|
+
phone = read 'phone', 'phone' # US phone → (555) 123-4567
|
|
1267
|
+
state = read 'state', 'state' # two-letter → uppercase
|
|
1268
|
+
zip = read 'zip', 'zip' # 5-digit zip
|
|
1269
|
+
url = read 'url', 'url' # valid URL
|
|
1270
|
+
uuid = read 'id', 'uuid' # UUID format
|
|
1271
|
+
date = read 'date', 'date' # YYYY-MM-DD
|
|
1272
|
+
time = read 'time', 'time' # HH:MM or HH:MM:SS
|
|
1273
|
+
flag = read 'flag', 'bool' # boolean
|
|
1274
|
+
tags = read 'tags', 'array' # must be array
|
|
1275
|
+
ids = read 'ids', 'ids' # "1,2,3" → [1, 2, 3]
|
|
1276
|
+
slug = read 'slug', 'slug' # URL-safe slug
|
|
1277
|
+
```
|
|
1278
|
+
|
|
1279
|
+
## @rip-lang/server — Production Server
|
|
1280
|
+
|
|
1281
|
+
Multi-worker process manager with hot reload, automatic HTTPS, and mDNS.
|
|
1116
1282
|
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
}
|
|
1283
|
+
```bash
|
|
1284
|
+
rip-server # Start (uses ./index.rip)
|
|
1285
|
+
rip-server -w # With file watching + hot-reload
|
|
1286
|
+
rip-server myapp # Named (accessible at myapp.local)
|
|
1287
|
+
rip-server http:3000 # HTTP on specific port
|
|
1288
|
+
```
|
|
1124
1289
|
|
|
1125
|
-
|
|
1126
|
-
try
|
|
1127
|
-
req.json!
|
|
1128
|
-
catch
|
|
1129
|
-
null
|
|
1290
|
+
## @rip-lang/ui — Reactive Web Framework
|
|
1130
1291
|
|
|
1131
|
-
|
|
1132
|
-
port: 3000
|
|
1133
|
-
fetch: (req) ->
|
|
1134
|
-
{pathname} = new URL(req.url)
|
|
1135
|
-
method = req.method
|
|
1292
|
+
Zero-build reactive framework. Ships the compiler to the browser and compiles `.rip` components on demand. File-based routing, unified reactive stash, and SSE hot reload.
|
|
1136
1293
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1294
|
+
```coffee
|
|
1295
|
+
# Server setup (index.rip)
|
|
1296
|
+
import { get, use, start, notFound } from '@rip-lang/api'
|
|
1297
|
+
import { ripUI } from '@rip-lang/ui/serve'
|
|
1298
|
+
|
|
1299
|
+
dir = import.meta.dir
|
|
1300
|
+
use ripUI dir: dir, components: 'routes', includes: ['ui'], watch: true
|
|
1301
|
+
get '/css/*' -> @send "#{dir}/css/#{@req.path.slice(5)}"
|
|
1302
|
+
notFound -> @send "#{dir}/index.html", 'text/html; charset=UTF-8'
|
|
1303
|
+
start port: 3000
|
|
1304
|
+
```
|
|
1140
1305
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1306
|
+
```coffee
|
|
1307
|
+
# Component (routes/counter.rip)
|
|
1308
|
+
Counter = component
|
|
1309
|
+
@count := 0
|
|
1310
|
+
doubled ~= @count * 2
|
|
1146
1311
|
|
|
1147
|
-
|
|
1148
|
-
body = parseBody!(req)
|
|
1149
|
-
user = {id: db.nextId++, ...body}
|
|
1150
|
-
db.users.push(user)
|
|
1151
|
-
Response.json(user, status: 201)
|
|
1312
|
+
increment: -> @count += 1
|
|
1152
1313
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1314
|
+
render
|
|
1315
|
+
div.counter
|
|
1316
|
+
h1 "Count: #{@count}"
|
|
1317
|
+
p "Doubled: #{doubled}"
|
|
1318
|
+
button @click: @increment, "+"
|
|
1155
1319
|
```
|
|
1156
1320
|
|
|
1157
|
-
##
|
|
1321
|
+
## @rip-lang/db — DuckDB Server + Client
|
|
1322
|
+
|
|
1323
|
+
HTTP server for DuckDB with the official DuckDB UI built in, plus an ActiveRecord-style client library.
|
|
1324
|
+
|
|
1325
|
+
```bash
|
|
1326
|
+
rip-db # In-memory database
|
|
1327
|
+
rip-db mydata.duckdb # File-based database
|
|
1328
|
+
```
|
|
1158
1329
|
|
|
1159
1330
|
```coffee
|
|
1160
|
-
|
|
1331
|
+
# Client library
|
|
1332
|
+
import { connect, query, findAll, Model } from '@rip-lang/db/client'
|
|
1161
1333
|
|
|
1162
|
-
|
|
1334
|
+
connect 'http://localhost:4213'
|
|
1163
1335
|
|
|
1164
|
-
|
|
1165
|
-
port: 3000
|
|
1166
|
-
fetch: (req, server) ->
|
|
1167
|
-
if server.upgrade(req)
|
|
1168
|
-
return
|
|
1169
|
-
new Response("WebSocket server")
|
|
1336
|
+
users = findAll! "SELECT * FROM users WHERE role = $1", ['admin']
|
|
1170
1337
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1338
|
+
User = Model 'users'
|
|
1339
|
+
user = User.find! 42
|
|
1340
|
+
User.where(active: true).order('name').limit(10).all!
|
|
1341
|
+
```
|
|
1342
|
+
|
|
1343
|
+
## @rip-lang/swarm — Parallel Job Runner
|
|
1175
1344
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
client.send(message) unless client is ws
|
|
1345
|
+
```coffee
|
|
1346
|
+
import { swarm, init, retry, todo } from '@rip-lang/swarm'
|
|
1179
1347
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1348
|
+
setup = ->
|
|
1349
|
+
unless retry()
|
|
1350
|
+
init()
|
|
1351
|
+
for i in [1..100] then todo(i)
|
|
1352
|
+
|
|
1353
|
+
perform = (task, ctx) ->
|
|
1354
|
+
await Bun.sleep(Math.random() * 1000)
|
|
1355
|
+
|
|
1356
|
+
swarm { setup, perform }
|
|
1357
|
+
```
|
|
1358
|
+
|
|
1359
|
+
## @rip-lang/csv — CSV Parser + Writer
|
|
1360
|
+
|
|
1361
|
+
```coffee
|
|
1362
|
+
import { CSV } from '@rip-lang/csv'
|
|
1363
|
+
|
|
1364
|
+
# Parse
|
|
1365
|
+
rows = CSV.read "name,age\nAlice,30\nBob,25\n", headers: true
|
|
1366
|
+
# [{name: 'Alice', age: '30'}, {name: 'Bob', age: '25'}]
|
|
1367
|
+
|
|
1368
|
+
# Write
|
|
1369
|
+
CSV.save! 'output.csv', rows
|
|
1370
|
+
```
|
|
1371
|
+
|
|
1372
|
+
## @rip-lang/schema — ORM + Validation
|
|
1373
|
+
|
|
1374
|
+
```coffee
|
|
1375
|
+
import { Model } from '@rip-lang/schema'
|
|
1376
|
+
|
|
1377
|
+
class User extends Model
|
|
1378
|
+
@table = 'users'
|
|
1379
|
+
@schema
|
|
1380
|
+
name: { type: 'string', required: true }
|
|
1381
|
+
email: { type: 'email', unique: true }
|
|
1382
|
+
|
|
1383
|
+
user = User.find!(25)
|
|
1384
|
+
user.name = 'Alice'
|
|
1385
|
+
user.save!()
|
|
1386
|
+
```
|
|
1387
|
+
|
|
1388
|
+
## Full-Stack Example
|
|
1389
|
+
|
|
1390
|
+
A complete API server in Rip:
|
|
1391
|
+
|
|
1392
|
+
```coffee
|
|
1393
|
+
import { get, post, use, read, start, notFound } from '@rip-lang/api'
|
|
1394
|
+
import { cors, logger } from '@rip-lang/api/middleware'
|
|
1395
|
+
|
|
1396
|
+
use logger()
|
|
1397
|
+
use cors origin: '*'
|
|
1398
|
+
|
|
1399
|
+
# In-memory store
|
|
1400
|
+
users = []
|
|
1401
|
+
nextId = 1
|
|
1402
|
+
|
|
1403
|
+
get '/api/users' -> users
|
|
1404
|
+
|
|
1405
|
+
get '/api/users/:id' ->
|
|
1406
|
+
id = read 'id', 'id!'
|
|
1407
|
+
user = users.find (u) -> u.id is id
|
|
1408
|
+
user or throw { status: 404, message: 'Not found' }
|
|
1409
|
+
|
|
1410
|
+
post '/api/users' ->
|
|
1411
|
+
name = read 'name', 'string!'
|
|
1412
|
+
email = read 'email', 'email!'
|
|
1413
|
+
user = { id: nextId++, name, email }
|
|
1414
|
+
users.push user
|
|
1415
|
+
user
|
|
1416
|
+
|
|
1417
|
+
notFound -> { error: 'Not found' }
|
|
1418
|
+
|
|
1419
|
+
start port: 3000
|
|
1182
1420
|
```
|
|
1183
1421
|
|
|
1184
1422
|
---
|
|
@@ -1412,6 +1650,10 @@ a =~ /pat/ # regex match, captures in _
|
|
|
1412
1650
|
a[/pat/, 1] # regex extract
|
|
1413
1651
|
a? # existence check (a != null)
|
|
1414
1652
|
a ?? b # nullish coalescing
|
|
1653
|
+
|
|
1654
|
+
# Two-way binding (render blocks)
|
|
1655
|
+
input value <=> @name # bidirectional reactive binding
|
|
1656
|
+
Dialog open <=> @show # works with components too
|
|
1415
1657
|
```
|
|
1416
1658
|
|
|
1417
1659
|
## File Templates
|
|
@@ -1539,4 +1781,19 @@ Each would need design discussion before building.
|
|
|
1539
1781
|
|
|
1540
1782
|
---
|
|
1541
1783
|
|
|
1542
|
-
|
|
1784
|
+
## Resources
|
|
1785
|
+
|
|
1786
|
+
- [Rip Playground](https://shreeve.github.io/rip-lang/) — Try Rip in the browser
|
|
1787
|
+
- [VS Code Extension](https://marketplace.visualstudio.com/items?itemName=rip-lang.rip) — IDE support
|
|
1788
|
+
- [GitHub](https://github.com/shreeve/rip-lang) — Source code
|
|
1789
|
+
|
|
1790
|
+
| Document | Purpose |
|
|
1791
|
+
|----------|---------|
|
|
1792
|
+
| **[RIP-LANG.md](RIP-LANG.md)** | Full language reference (this file) |
|
|
1793
|
+
| **[RIP-TYPES.md](RIP-TYPES.md)** | Type system specification |
|
|
1794
|
+
| **[RIP-INTERNALS.md](RIP-INTERNALS.md)** | Compiler architecture & design decisions |
|
|
1795
|
+
| **[AGENT.md](../AGENT.md)** | AI agent guide for working on the compiler |
|
|
1796
|
+
|
|
1797
|
+
---
|
|
1798
|
+
|
|
1799
|
+
*Rip 3.10 — 1,243 tests — Zero dependencies — Self-hosting — ~13,500 LOC*
|