{"id":32657770,"url":"https://github.com/shreeve/rip-lang","last_synced_at":"2026-03-02T09:07:26.182Z","repository":{"id":337411680,"uuid":"1152184903","full_name":"shreeve/rip-lang","owner":"shreeve","description":"A modern language that compiles to JavaScript","archived":false,"fork":false,"pushed_at":"2026-03-01T16:58:36.000Z","size":19802,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-01T19:09:41.546Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://shreeve.github.io/rip-lang/","language":"CoffeeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shreeve.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-07T13:50:06.000Z","updated_at":"2026-03-01T16:58:39.000Z","dependencies_parsed_at":"2026-02-18T08:02:40.870Z","dependency_job_id":null,"html_url":"https://github.com/shreeve/rip-lang","commit_stats":null,"previous_names":["shreeve/rip-lang"],"tags_count":30,"template":false,"template_full_name":null,"purl":"pkg:github/shreeve/rip-lang","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shreeve%2Frip-lang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shreeve%2Frip-lang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shreeve%2Frip-lang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shreeve%2Frip-lang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shreeve","download_url":"https://codeload.github.com/shreeve/rip-lang/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shreeve%2Frip-lang/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29991312,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T01:47:34.672Z","status":"online","status_checked_at":"2026-03-02T02:00:07.342Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","coffeescript","compiler","javascript","parser","parser-generator","rip","s-expression","solar"],"created_at":"2025-10-31T13:00:45.596Z","updated_at":"2026-03-02T09:07:26.138Z","avatar_url":"https://github.com/shreeve.png","language":"CoffeeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/assets/rip-1280w.png\" alt=\"Rip Logo\" width=\"400\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eRip\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eA modern language that compiles to JavaScript\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"CHANGELOG.md\"\u003e\u003cimg src=\"https://img.shields.io/badge/version-3.12.4-blue.svg\" alt=\"Version\"\u003e\u003c/a\u003e\n  \u003ca href=\"#zero-dependencies\"\u003e\u003cimg src=\"https://img.shields.io/badge/dependencies-ZERO-brightgreen.svg\" alt=\"Dependencies\"\u003e\u003c/a\u003e\n  \u003ca href=\"#\"\u003e\u003cimg src=\"https://img.shields.io/badge/tests-1%2C243%2F1%2C243-brightgreen.svg\" alt=\"Tests\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-green.svg\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\nRip 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 11,000 lines of code.\n\n\u003e **No imports. No hooks. No dependency arrays. Just write code.**\n\n```coffee\ndata = fetchUsers!                  # Dammit operator (call + await)\nuser = User.new name: \"Alice\"       # Ruby-style constructor\nsquares = (x * x for x in [1..10])  # List comprehension\n\nstr =~ /Hello, (\\w+)/               # Regex match\nlog \"Found: #{_[1]}\"                # Captures in _[1], _[2], etc.\n\nget '/users/:id' -\u003e                 # RESTful API endpoint, comma-less\n  name = read 'name', 'string!'     # Required string\n  age  = read 'age' , [0, 105]      # Simple numeric validation\n```\n\n---\n\n**What makes Rip different:**\n- **Modern output** — ES2022 with native classes, `?.`, `??`, modules\n- **New operators** — `!`, `!?`, `//`, `%%`, `=~`, `|\u003e`, `.new()`, and more\n- **Reactive operators** — `:=`, `~=`, `~\u003e` as language syntax\n- **Optional types** — `::` annotations, `::=` aliases, `.d.ts` emission\n- **Zero dependencies** — everything included, even the parser generator\n- **Self-hosting** — `bun run parser` rebuilds the compiler from source\n\n---\n\n## Installation\n\n```bash\nbun add -g rip-lang            # Install globally\n```\n\n```bash\nrip                            # Interactive REPL\nrip file.rip                   # Run a file\nrip -c file.rip                # Compile to JavaScript\n```\n\n---\n\n## Language\n\n### Functions \u0026 Classes\n\n```coffee\ndef greet(name)                # Named function\n  \"Hello, #{name}!\"\n\nadd = (a, b) -\u003e a + b          # Arrow function\nhandler = (e) =\u003e @process e    # Fat arrow (preserves this)\n\nclass Dog extends Animal\n  speak: -\u003e log \"#{@name} barks\"\n\ndog = Dog.new(\"Buddy\")         # Ruby-style constructor\n```\n\n### String Interpolation\n\n```coffee\n\"Hello, #{name}!\"              # CoffeeScript-style\n\"Hello, ${name}!\"              # JavaScript-style\n\"#{a} + #{b} = #{a + b}\"       # Expressions work in both\n```\n\nBoth `#{}` and `${}` compile to JavaScript template literals. Use whichever you prefer.\n\n### Destructuring \u0026 Comprehensions\n\n```coffee\n{name, age} = person\n[first, ...rest] = items\n\nsquares = (x * x for x in [1..10])   # Array comprehension\nconsole.log x for x in items         # Loop (no array)\n```\n\n### Async \u0026 Chaining\n\n```coffee\ndef loadUser(id)\n  response = await fetch \"/api/#{id}\"\n  await response.json()\n\nuser?.profile?.name            # Optional chaining\ndata = fetchData!              # Await shorthand\n```\n\n### Iteration\n\n```coffee\nfor item in [1, 2, 3]         # Array iteration (for-in)\n  console.log item\n\nfor key, value of object       # Object iteration (for-of)\n  console.log \"#{key}: #{value}\"\n\nfor x as iterable              # ES6 for-of on any iterable\n  console.log x\n\nfor x as! asyncIterable        # Async iteration shorthand\n  console.log x                # Equivalent to: for await x as asyncIterable\n\nloop                           # Infinite loop (while true)\n  process!\nloop 5                         # Repeat N times\n  console.log \"hi\"\n```\n\n### Implicit `it`\n\nArrow functions with no params that reference `it` auto-inject it as the parameter:\n\n```coffee\nusers.filter -\u003e it.active          # → users.filter(function(it) { ... })\nnames = users.map -\u003e it.name       # no need to name a throwaway variable\norders.filter -\u003e it.total \u003e 100    # works with any expression\n```\n\n### Reactivity\n\nState, computed values, and effects as language operators:\n\n| Operator | Mnemonic | Example | What it does |\n|----------|----------|---------|--------------|\n| `=` | \"gets value\" | `x = 5` | Regular assignment |\n| `:=` | \"gets state\" | `count := 0` | Reactive state container |\n| `~=` | \"always equals\" | `twice ~= count * 2` | Auto-updates on changes |\n| `~\u003e` | \"always calls\" | `~\u003e log count` | Runs on dependency changes |\n| `=!` | \"equals, dammit!\" | `MAX =! 100` | Readonly constant |\n\n---\n\n### Types (Optional)\n\nType annotations are erased at compile time — zero runtime cost:\n\n```coffee\ndef greet(name:: string):: string        # Typed function\n  \"Hello, #{name}!\"\n\nUser ::= type                            # Structural type\n  id: number\n  name: string\n\nenum HttpCode                            # Runtime enum\n  ok = 200\n  notFound = 404\n```\n\nCompiles to `.js` (types erased) + `.d.ts` (types preserved) — full IDE support via TypeScript Language Server. See [docs/RIP-TYPES.md](docs/RIP-TYPES.md).\n\n---\n\n## Operators\n\n| Operator | Example | What it does |\n|----------|---------|--------------|\n| `!` (dammit) | `fetchData!` | Calls AND awaits |\n| `!` (void) | `def process!` | Suppresses implicit return |\n| `!?` (otherwise) | `val !? 5` | Default only if `undefined` |\n| `?` (existence) | `x?` | True if `x != null` |\n| `?:` (ternary) | `x \u003e 0 ? 'yes' : 'no'` | JS-style ternary expression |\n| `if...else` (postfix) | `\"yes\" if cond else \"no\"` | Python-style ternary expression |\n| `?.` `?.[]` `?.()` | `a?.b` `a?.[0]` `a?.()` | Optional chaining (ES6) |\n| `?[]` `?()` | `a?[0]` `a?(x)` | Optional chaining shorthand |\n| `??` | `a ?? b` | Nullish coalescing |\n| `...` (spread) | `[...items, last]` | Prefix spread (ES6) |\n| `//` | `7 // 2` | Floor division |\n| `%%` | `-1 %% 3` | True modulo |\n| `=~` | `str =~ /Hello, (\\w+)/` | Match (captures in `_`) |\n| `[//, n]` | `str[/Hello, (\\w+)/, 1]` | Extract capture n |\n| `.new()` | `Dog.new()` | Ruby-style constructor |\n| `::` (prototype) | `String::trim` | `String.prototype.trim` |\n| `[-n]` (negative index) | `arr[-1]` | Last element via `.at()` |\n| `*` (string repeat) | `\"-\" * 40` | String repeat via `.repeat()` |\n| `\u003c` `\u003c=` (chained) | `1 \u003c x \u003c 10` | Chained comparisons |\n| `\\|\u003e` (pipe) | `x \\|\u003e fn` or `x \\|\u003e fn(y)` | Pipe operator (first-arg insertion) |\n| `not in` | `x not in arr` | Negated membership test |\n| `not of` | `k not of obj` | Negated key existence |\n| `.=` (method assign) | `x .= trim()` | `x = x.trim()` — compound method assignment |\n| `*` (merge assign) | `*obj = {a: 1}` | `Object.assign(obj, {a: 1})` |\n| `or return` | `x = get() or return err` | Guard clause (Ruby-style) |\n| `?? throw` | `x = get() ?? throw err` | Nullish guard |\n\n### Heredoc \u0026 Heregex\n\n**Heredoc** — The closing `'''` or `\"\"\"` position defines the left margin. All content is dedented relative to the column where the closing delimiter sits:\n\n```coffee\nhtml = '''\n    \u003cdiv\u003e\n      \u003cp\u003eHello\u003c/p\u003e\n    \u003c/div\u003e\n    '''\n# Closing ''' at column 4 (same as content) — no leading whitespace\n# Result: \"\u003cdiv\u003e\\n  \u003cp\u003eHello\u003c/p\u003e\\n\u003c/div\u003e\"\n\nhtml = '''\n    \u003cdiv\u003e\n      \u003cp\u003eHello\u003c/p\u003e\n    \u003c/div\u003e\n  '''\n# Closing ''' at column 2 — 2 spaces of leading whitespace preserved\n# Result: \"  \u003cdiv\u003e\\n    \u003cp\u003eHello\u003c/p\u003e\\n  \u003c/div\u003e\"\n```\n\n**Raw heredoc** — Append `\\` to the opening delimiter (`'''\\` or `\"\"\"\\`) to prevent escape processing. Backslash sequences like `\\n`, `\\t`, `\\u` stay literal:\n\n```coffee\nscript = '''\\\n  echo \"hello\\nworld\"\n  sed 's/\\t/  /g' file.txt\n  \\'''\n# \\n and \\t stay as literal characters, not newline/tab\n```\n\n**Heregex** — Extended regex with comments and whitespace:\n\n```coffee\npattern = ///\n  ^(\\d{3})    # area code\n  -(\\d{4})    # number\n///\n```\n\n---\n\n## vs React / Vue / Solid\n\n| Concept | React | Vue | Solid | Rip |\n|---------|-------|-----|-------|-----|\n| State | `useState()` | `ref()` | `createSignal()` | `x := 0` |\n| Computed | `useMemo()` | `computed()` | `createMemo()` | `x ~= y * 2` |\n| Effect | `useEffect()` | `watch()` | `createEffect()` | `~\u003e body` |\n\nRip's reactivity is framework-agnostic — use it with React, Vue, Svelte, or vanilla JS.\n\n---\n\n## Rip UI\n\nLoad `rip-ui.min.js` (~53KB Brotli) — the Rip compiler and pre-compiled UI framework in one file. Components are `.rip` source files, compiled on demand, rendered with fine-grained reactivity. No build step. No bundler.\n\n```html\n\u003cscript type=\"module\" src=\"rip-ui.min.js\"\u003e\u003c/script\u003e\n\n\u003cscript type=\"text/rip\" data-name=\"index\"\u003e\nexport Home = component\n  @count := 0\n  render\n    div.counter\n      h1 \"Count: #{@count}\"\n      button @click: (-\u003e @count++), \"+\"\n      button @click: (-\u003e @count--), \"-\"\n\u003c/script\u003e\n```\n\nThat's it. The runtime auto-detects inline `data-name` components, compiles them, and launches the app with hash routing — no bootstrap script needed. Two keywords (`component` and `render`) are all the language adds. Everything else (`:=` state, `~=` computed, methods, lifecycle) is standard Rip.\n\nThe UI framework is built into rip-lang: file-based router, reactive stash, component store, and renderer. **[Try the demo](https://shreeve.github.io/rip-lang/demo.html)** — a complete app in one HTML file.\n\n---\n\n## vs CoffeeScript\n\n| Feature | CoffeeScript | Rip |\n|---------|--------------|-----|\n| **Output** | ES5 (var, prototypes) | ES2022 (classes, `?.`, `??`) |\n| **Reactivity** | None | Built-in |\n| **Dependencies** | Multiple | Zero |\n| **Self-hosting** | No | Yes |\n| **Lexer** | 3,558 LOC | 2,024 LOC |\n| **Compiler** | 10,346 LOC | 3,293 LOC |\n| **Total** | 17,760 LOC | ~11,300 LOC |\n\nSmaller codebase, modern output, built-in reactivity.\n\n---\n\n## Browser\n\nRun Rip directly in the browser — inline scripts and the console REPL both support `await` via the `!` operator:\n\n```html\n\u003cscript type=\"module\" src=\"rip-ui.min.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/rip\"\u003e\n  res = fetch! 'https://api.example.com/data'\n  data = res.json!\n  console.log data\n\u003c/script\u003e\n```\n\nThe `rip()` function is available in the browser console:\n\n```javascript\nrip(\"42 * 10 + 8\")                                         // → 428\nrip(\"(x * x for x in [1..5])\")                             // → [1, 4, 9, 16, 25]\nawait rip(\"res = fetch! 'https://api.example.com/todos/1'; res.json!\")  // → {id: 1, ...}\n```\n\n**Try it live:** [shreeve.github.io/rip-lang](https://shreeve.github.io/rip-lang/)\n\n---\n\n## Architecture\n\n```\nSource  -\u003e  Lexer  -\u003e  emitTypes  -\u003e  Parser  -\u003e  S-Expressions  -\u003e  Codegen  -\u003e  JavaScript\n           (1,761)    (types.js)     (359)       [\"=\", \"x\", 42]     (3,293)      + source map\n```\n\nSimple arrays (with `.loc`) instead of AST node classes. The compiler is self-hosting — `bun run parser` rebuilds from source.\n\n| Component | File | Lines |\n|-----------|------|-------|\n| Lexer + Rewriter | `src/lexer.js` | 1,761 |\n| Compiler + Codegen | `src/compiler.js` | 3,303 |\n| Type System | `src/types.js` | 1,099 |\n| Component System | `src/components.js` | 1,877 |\n| Source Maps | `src/sourcemaps.js` | 189 |\n| Parser (generated) | `src/parser.js` | 357 |\n| Grammar | `src/grammar/grammar.rip` | 944 |\n| Parser Generator | `src/grammar/solar.rip` | 929 |\n| REPL | `src/repl.js` | 601 |\n| Browser Entry | `src/browser.js` | 167 |\n| Tags | `src/tags.js` | 62 |\n| **Total** | | **~11,289** |\n\n---\n\n## The Rip Stack\n\nRip includes optional packages for full-stack development:\n\n| Package | Version | Purpose |\n|---------|---------|---------|\n| [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.10.10 | Core language compiler |\n| [@rip-lang/api](packages/api/) | 1.1.10 | HTTP framework (Sinatra-style routing, 37 validators) |\n| [@rip-lang/server](packages/server/) | 1.1.19 | Multi-worker app server (hot reload, HTTPS, mDNS) |\n| [@rip-lang/db](packages/db/) | 1.2.0 | DuckDB server with official UI + ActiveRecord-style client |\n| [@rip-lang/grid](packages/grid/) | 0.2.0 | Reactive data grid |\n| [@rip-lang/swarm](packages/swarm/) | 1.1.4 | Parallel job runner with worker pool |\n| [@rip-lang/csv](packages/csv/) | 1.1.4 | CSV parser + writer |\n| [@rip-lang/schema](packages/schema/) | 0.2.1 | Unified schema → TypeScript types, SQL DDL, validation, ORM |\n| [VS Code Extension](packages/vscode/) | 0.5.0 | Syntax highlighting, type intelligence, source maps |\n\n```bash\nbun add -g @rip-lang/db    # Installs everything (rip-lang + api + db)\n```\n\n---\n\n## Implicit Commas\n\nRip rescues what would be invalid syntax and gives it elegant meaning. When a literal value is followed directly by an arrow function, Rip inserts the comma for you:\n\n```coffee\n# Clean route handlers (no comma needed!)\nget '/users' -\u003e User.all!\nget '/users/:id' -\u003e User.find params.id\npost '/users' -\u003e User.create body\n\n# Works with all literal types\nhandle 404 -\u003e { error: 'Not found' }\nmatch /^\\/api/ -\u003e { version: 'v1' }\ncheck true -\u003e enable()\n```\n\nThis works because `'/users' -\u003e` was previously a syntax error — there's no valid interpretation. Rip detects this pattern and transforms it into `'/users', -\u003e`, giving dead syntax a beautiful new life.\n\n**Supported literals:** strings, numbers, regex, booleans, null, undefined, arrays, objects\n\n---\n\n## Quick Reference\n\n```bash\nrip                    # REPL\nrip file.rip           # Run\nrip -c file.rip        # Compile\nrip -t file.rip        # Tokens\nrip -s file.rip        # S-expressions\nbun run test           # 1243 tests\nbun run parser         # Rebuild parser\nbun run browser        # Build browser bundle\n```\n\n---\n\n## Documentation\n\n| Guide | Description |\n|-------|-------------|\n| [docs/RIP-LANG.md](docs/RIP-LANG.md) | Full language reference (syntax, operators, reactivity, types, future ideas) |\n| [docs/RIP-INTERNALS.md](docs/RIP-INTERNALS.md) | Compiler architecture (lexer, parser, codegen, S-expressions) |\n| [docs/RIP-TYPES.md](docs/RIP-TYPES.md) | Type system specification |\n| [AGENT.md](AGENT.md) | AI agents — get up to speed for working on the compiler |\n\n---\n\n## Zero Dependencies\n\n```json\n{ \"dependencies\": {} }\n```\n\nEverything included: compiler, parser generator, REPL, browser bundle, test framework.\n\n---\n\n## Philosophy\n\n\u003e *Simplicity scales.*\n\nSimple IR (S-expressions), clear pipeline (lex -\u003e parse -\u003e generate), minimal code, comprehensive tests.\n\n---\n\n**Inspired by:** CoffeeScript, Lisp, Ruby | **Powered by:** [Bun](https://bun.sh)\n\nMIT License\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003eStart simple. Build incrementally. Ship elegantly.\u003c/strong\u003e\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshreeve%2Frip-lang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshreeve%2Frip-lang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshreeve%2Frip-lang/lists"}