Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A modern language that compiles to JavaScript

License

NotificationsYou must be signed in to change notification settings

shreeve/rip-lang

Repository files navigation

Rip Logo

Rip

A modern language that compiles to JavaScript

VersionDependenciesTestsLicense


Rip is a modern language inspired by CoffeeScript. It compiles toES2022 (classes,?.,??, modules), adds about adozen new operators, includesbuilt-in reactivity, and sports a self-hosting compiler withzero dependencies — all in about 11,000 lines of code.

No imports. No hooks. No dependency arrays. Just write code.

data= fetchUsers!# Dammit operator (call + await)user=User.newname:"Alice"# Ruby-style constructorsquares= (x* xfor xin [1..10])# List comprehensionstr=~/Hello, (\w+)/# Regex matchlog"Found:#{_[1]}"# Captures in _[1], _[2], etc.get'/users/:id'-># RESTful API endpoint, comma-lessname=read'name','string!'# Required stringage=read'age' , [0,105]# Simple numeric validation

What makes Rip different:

  • Modern output — ES2022 with native classes,?.,??, modules
  • New operators!,!?,//,%%,=~,|>,.new(), and more
  • Reactive operators:=,~=,~> as language syntax
  • Optional types:: annotations,::= aliases,.d.ts emission
  • Zero dependencies — everything included, even the parser generator
  • Self-hostingbun run parser rebuilds the compiler from source

Installation

bun add -g rip-lang# Install globally
rip# Interactive REPLrip file.rip# Run a filerip -c file.rip# Compile to JavaScript

Language

Functions & Classes

defgreet(name)# Named function"Hello,#{name}!"add= (a,b)-> a+ b# Arrow functionhandler= (e)=>@process e# Fat arrow (preserves this)classDogextendsAnimalspeak:->log"#{@name} barks"dog=Dog.new("Buddy")# Ruby-style constructor

String Interpolation

"Hello,#{name}!"# CoffeeScript-style"Hello, ${name}!"# JavaScript-style"#{a} +#{b} =#{a+ b}"# Expressions work in both

Both#{} and${} compile to JavaScript template literals. Use whichever you prefer.

Destructuring & Comprehensions

{name,age}= person[first,...rest]= itemssquares= (x* xfor xin [1..10])# Array comprehensionconsole.log xfor xin items# Loop (no array)

Async & Chaining

defloadUser(id)response=awaitfetch"/api/#{id}"awaitresponse.json()user?.profile?.name# Optional chainingdata= fetchData!# Await shorthand

Iteration

for itemin [1,2,3]# Array iteration (for-in)console.log itemfor key, valueof object# Object iteration (for-of)console.log"#{key}:#{value}"forxas iterable# ES6 for-of on any iterableconsole.log xforxas! asyncIterable# Async iteration shorthandconsole.log x# Equivalent to: for await x as asyncIterableloop# Infinite loop (while true)process!loop5# Repeat N timesconsole.log"hi"

Implicitit

Arrow functions with no params that referenceit auto-inject it as the parameter:

users.filter->it.active# → users.filter(function(it) { ... })names=users.map->it.name# no need to name a throwaway variableorders.filter->it.total>100# works with any expression

Reactivity

State, computed values, and effects as language operators:

OperatorMnemonicExampleWhat it does
="gets value"x = 5Regular assignment
:="gets state"count := 0Reactive state container
~="always equals"twice ~= count * 2Auto-updates on changes
~>"always calls"~> log countRuns on dependency changes
=!"equals, dammit!"MAX =! 100Readonly constant

Types (Optional)

Type annotations are erased at compile time — zero runtime cost:

defgreet(name::string)::string# Typed function"Hello,#{name}!"User::= type# Structural typeid: numbername: stringenum HttpCode# Runtime enumok=200notFound=404

Compiles to.js (types erased) +.d.ts (types preserved) — full IDE support via TypeScript Language Server. Seedocs/RIP-TYPES.md.


Operators

OperatorExampleWhat it does
! (dammit)fetchData!Calls AND awaits
! (void)def process!Suppresses implicit return
!? (otherwise)val !? 5Default only ifundefined
? (existence)x?True ifx != null
?: (ternary)x > 0 ? 'yes' : 'no'JS-style ternary expression
if...else (postfix)"yes" if cond else "no"Python-style ternary expression
?.?.[]?.()a?.ba?.[0]a?.()Optional chaining (ES6)
?[]?()a?[0]a?(x)Optional chaining shorthand
??a ?? bNullish coalescing
... (spread)[...items, last]Prefix spread (ES6)
//7 // 2Floor division
%%-1 %% 3True modulo
=~str =~ /Hello, (\w+)/Match (captures in_)
[//, n]str[/Hello, (\w+)/, 1]Extract capture n
.new()Dog.new()Ruby-style constructor
:: (prototype)String::trimString.prototype.trim
[-n] (negative index)arr[-1]Last element via.at()
* (string repeat)"-" * 40String repeat via.repeat()
<<= (chained)1 < x < 10Chained comparisons
|> (pipe)x |> fn orx |> fn(y)Pipe operator (first-arg insertion)
not inx not in arrNegated membership test
not ofk not of objNegated key existence
.= (method assign)x .= trim()x = x.trim() — compound method assignment
* (merge assign)*obj = {a: 1}Object.assign(obj, {a: 1})
or returnx = get() or return errGuard clause (Ruby-style)
?? throwx = get() ?? throw errNullish guard

Heredoc & Heregex

Heredoc — The closing''' or""" position defines the left margin. All content is dedented relative to the column where the closing delimiter sits:

html='''    <div>      <p>Hello</p>    </div>'''# Closing ''' at column 4 (same as content) — no leading whitespace# Result: "<div>\n  <p>Hello</p>\n</div>"html='''    <div>      <p>Hello</p>    </div>'''# Closing ''' at column 2 — 2 spaces of leading whitespace preserved# Result: "  <div>\n    <p>Hello</p>\n  </div>"

Raw heredoc — Append\ to the opening delimiter ('''\ or"""\) to prevent escape processing. Backslash sequences like\n,\t,\u stay literal:

script='''\  echo "hello\nworld"  sed 's/\t/  /g' file.txt\'''#\n and\t stay as literal characters, not newline/tab

Heregex — Extended regex with comments and whitespace:

pattern=///^(\d{3})# area code  -(\d{4})# number///

vs React / Vue / Solid

ConceptReactVueSolidRip
StateuseState()ref()createSignal()x := 0
ComputeduseMemo()computed()createMemo()x ~= y * 2
EffectuseEffect()watch()createEffect()~> body

Rip's reactivity is framework-agnostic — use it with React, Vue, Svelte, or vanilla JS.


Rip UI

Loadrip-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.

<scripttype="module"src="rip-ui.min.js"></script><scripttype="text/rip"data-name="index">exportHome=component  @count :=0renderdiv.counterh1"Count: #{@count}"button @click:(-> @count++), "+"button @click:(-> @count--), "-"</script>

That's it. The runtime auto-detects inlinedata-name components, compiles them, and launches the app with hash routing — no bootstrap script needed. Two keywords (component andrender) are all the language adds. Everything else (:= state,~= computed, methods, lifecycle) is standard Rip.

See@rip-lang/ui for the full framework: file-based router, reactive stash, component store, and renderer.Try the demo — a complete app in one HTML file.


vs CoffeeScript

FeatureCoffeeScriptRip
OutputES5 (var, prototypes)ES2022 (classes,?.,??)
ReactivityNoneBuilt-in
DependenciesMultipleZero
Self-hostingNoYes
Lexer3,558 LOC2,024 LOC
Compiler10,346 LOC3,293 LOC
Total17,760 LOC~11,300 LOC

Smaller codebase, modern output, built-in reactivity.


Browser

Run Rip directly in the browser — inline scripts and the console REPL both supportawait via the! operator:

<scripttype="module"src="rip-ui.min.js"></script><scripttype="text/rip">res=fetch!'https://api.example.com/data'data=res.json!console.logdata</script>

Therip() function is available in the browser console:

rip("42 * 10 + 8")// → 428rip("(x * x for x in [1..5])")// → [1, 4, 9, 16, 25]awaitrip("res = fetch! 'https://api.example.com/todos/1'; res.json!")// → {id: 1, ...}

Try it live:shreeve.github.io/rip-lang


Architecture

Source  ->  Lexer  ->  emitTypes  ->  Parser  ->  S-Expressions  ->  Codegen  ->  JavaScript           (1,761)    (types.js)     (359)       ["=", "x", 42]     (3,293)      + source map

Simple arrays (with.loc) instead of AST node classes. The compiler is self-hosting —bun run parser rebuilds from source.

ComponentFileLines
Lexer + Rewritersrc/lexer.js1,761
Compiler + Codegensrc/compiler.js3,303
Type Systemsrc/types.js1,099
Component Systemsrc/components.js1,877
Source Mapssrc/sourcemaps.js189
Parser (generated)src/parser.js357
Grammarsrc/grammar/grammar.rip944
Parser Generatorsrc/grammar/solar.rip929
REPLsrc/repl.js601
Browser Entrysrc/browser.js167
Tagssrc/tags.js62
Total~11,289

The Rip Stack

Rip includes optional packages for full-stack development:

PackageVersionPurpose
rip-lang3.10.10Core language compiler
@rip-lang/api1.1.10HTTP framework (Sinatra-style routing, 37 validators)
@rip-lang/server1.1.19Multi-worker app server (hot reload, HTTPS, mDNS)
@rip-lang/db1.2.0DuckDB server with official UI + ActiveRecord-style client
@rip-lang/ui0.3.19Zero-build reactive web framework (auto-launch, stash, router)
@rip-lang/swarm1.1.4Parallel job runner with worker pool
@rip-lang/csv1.1.4CSV parser + writer
@rip-lang/schema0.2.1Unified schema → TypeScript types, SQL DDL, validation, ORM
VS Code Extension0.5.0Syntax highlighting, type intelligence, source maps
bun add -g @rip-lang/db# Installs everything (rip-lang + api + db)

Implicit Commas

Rip 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:

# Clean route handlers (no comma needed!)get'/users'->User.all!get'/users/:id'->User.findparams.idpost'/users'->User.create body# Works with all literal typeshandle404-> {error:'Not found' }match/^\/api/-> {version:'v1' }checktrue->enable()

This works because'/users' -> was previously a syntax error — there's no valid interpretation. Rip detects this pattern and transforms it into'/users', ->, giving dead syntax a beautiful new life.

Supported literals: strings, numbers, regex, booleans, null, undefined, arrays, objects


Quick Reference

rip# REPLrip file.rip# Runrip -c file.rip# Compilerip -t file.rip# Tokensrip -s file.rip# S-expressionsbun runtest# 1243 testsbun run parser# Rebuild parserbun run browser# Build browser bundle

Documentation

GuideDescription
docs/RIP-LANG.mdFull language reference (syntax, operators, reactivity, types, future ideas)
docs/RIP-INTERNALS.mdCompiler architecture (lexer, parser, codegen, S-expressions)
docs/RIP-TYPES.mdType system specification
AGENT.mdAI agents — get up to speed for working on the compiler

Zero Dependencies

{"dependencies": {} }

Everything included: compiler, parser generator, REPL, browser bundle, test framework.


Philosophy

Simplicity scales.

Simple IR (S-expressions), clear pipeline (lex -> parse -> generate), minimal code, comprehensive tests.


Inspired by: CoffeeScript, Lisp, Ruby |Powered by:Bun

MIT License

Start simple. Build incrementally. Ship elegantly.

About

A modern language that compiles to JavaScript

Resources

License

Contributing

Stars

Watchers

Forks

Contributors2

  •  
  •  

[8]ページ先頭

©2009-2026 Movatter.jp