Skip to content

UrubuCode/rts

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3,010 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RTS — TypeScript que voa

rts_

TypeScript compilado pra binário nativo. Sem runtime. Sem GC pesado. Sem desculpa.

Um urubu de óculos escuros não tem pressa — ele já chegou.

Cranelift Rust License Single Binary

Bun/Node parity

🌐 Cross-runtime parity

Compatibilidade JS spec validada contra Bun e Node em 609 fixtures TS standalone.

[▰▰▰▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱▱] 34.6%   205/592 fixtures passam
Métrica Valor
Paridade 34.6% (205/592)
✅ RTS = Bun = Node 205
❌ RTS diverge 78
💥 RTS runtime error 309
🛠️ Falta corrigir 387
⚠️ Bun ≠ Node (skip) 17
🚫 Rejeitados (RTS-only) 0
📦 Total fixtures 609

Atualizado: 2026-06-26 — como adicionar fixture


🦅 O que é

RTS é um compilador + runtime que pega seu .ts e cospe um .exe nativo. Não é transpilador, não é bundler, não é wrapper em volta do V8 — é Cranelift gerando código de máquina direto a partir do AST do SWC, com um runtime mínimo em Rust e ABI tipado sem boxing.

Dois caminhos, mesmo codegen:

Modo Comando O que faz
🚀 JIT rts run app.ts Compila pra memória executável e roda. Zero disco.
📦 AOT rts compile -p app.ts out Object file → linker → binário standalone (~3 KB).

⚡ Performance — RTS vs Bun vs Node

Benchmarks executados no Windows 11 (100 runs, 5 warmups, mediana).

Monte Carlo π — 10M iterações

Bun
91.8 ms
baseline
Node.js
113.9 ms
1.24× mais lento que Bun
RTS AOT 🦅
16.9 ms
5.43× mais rápido que Bun
6.74× mais rápido que Node

Monte Carlo π — 10M iterações (8 workers)

Bun Workers
147.6 ms
RTS multi-thread 🦅
30.3 ms
4.87× mais rápido que Bun Workers

HTTP Server — req/s (carga sustentada)

Bun.serve
~14k req/s
RTS http_server 🦅
29k req/s
2.07× mais rápido que Bun.serve
78% do actix puro Rust

Resumo

Bench Bun Node RTS AOT RTS vs Bun RTS vs Node
Monte Carlo 10M (1 thread) 91.8 ms 113.9 ms 16.9 ms 5.43× 6.74×
Monte Carlo 10M (8 threads) 147.6 ms 30.3 ms 4.87×
HTTP throughput ~14k req/s 29k req/s 2.07×

Por que mais rápido? RTS compila TS para binário nativo via Cranelift — sem JIT warmup, sem GC pause, sem dispatch dinâmico nos hot paths. Loops comuns reescrevem automaticamente para parallel.* (rayon) sem o user mencionar threads (silent parallelism). HandleTable shard-aware (32 shards lock-free) escala alocação em paralelo.


🔮 Silent Parallelism — o usuário não pede, o compilador entrega

⚠️ Motor antigo (congelado). Os 3 passes de reescrita silenciosa vivem no rts-codegen-old e NÃO são carregados no motor novo sem rejustificação. Descrito aqui como capacidade histórica; o motor novo prioriza o piso de solidez primeiro.

Você escreve isso:

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let sum = 0;
for (const x of arr) sum = sum + x;

E o codegen vê o padrão de acumulador associativo e reescreve, antes de baixar IR:

sum = parallel.reduce(arr, 0, __par_reduce_0);  // rayon, transparente

Cobre for...of puro, arr.map/.forEach/.reduce, e o padrão clássico s = s + EXPR. 96 funções já marcadas como pure: true (math, string, num, fmt, path, hash, mem) alimentam o reconhecimento. Detalhes em docs/specs/silent-parallelism.md.


🧰 A pilha runtime — std::* inteira, em pure Rust

37 namespaces. Sem dependência de OpenSSL, schannel, libuv ou qualquer runtime externo.

Família Namespaces
I/O & FS io fs path process env os
Compute math num bigfloat fmt hash crypto
Memória gc buffer mem alloc ptr ffi
Concorrência thread atomic sync parallel
Rede net tls http_server (actix-web embutido)
Dados collections string regex json date
Async events (EventEmitter), Promise + Function nativos
Meta runtime test trace hint

🌐 HTTPS sem dor: rustls + webpki-roots (Mozilla CAs embutidos no binário) 🧵 Threading: 4 mecanismos coexistindo — spawn/join, spawn_async, spawn_detached (pool 8 workers, 5M spawn/s), scope auto-join 🔒 HandleTable shard-aware: 32 shards lock-free entre si


🎯 O que a linguagem entende hoje

Controle de fluxoif/else, while, do-while, for, switch (jump table nativa via br_table quando todos os cases são literais inteiros)

Funções — declaração, expression, arrow, tail call optimization (return f(x) vira return_call), ponteiros de função first-class

Classesconstructor, métodos, this, extends, super(...), super.method(...), static, getters/setters, dispatch virtual real, operator overload Rust-style (a + b vira a.add(b) em compile-time)

async / await — pipeline Promise-centric com tokio compartilhado. Promise.create faz spawn_blocking, settle automático via thread-local error slot. Function class completa (call/apply/bind/toString/new Function).

Big decimalbigfloat em i128 fixed-point, ~30 dígitos. π via Machin bate 29 dígitos corretos (f64 entrega 16).

Containers — object/array literals via collections.map_*/vec_*, member access, atribuição, aninhamento livre

try/catch/finally (fase 1) — slot de erro thread-local; unwind real ainda não (#128)

Outrosenum, destructuring nested+rename, spread em literals, regex, default params, exports/imports, JSON, Date, console.*, Map/Set v0, Array/String prototypes essenciais

Não suportado ainda — generators, decorators, generics completos, satisfies, call spread f(...args), closures com captura mutável real (#195 em fase 1)


🏗️ Arquitetura

Redesign em andamento (strangler-fig). O motor de codegen está sendo reescrito do zero atrás do antigo, congelado. O motor novo ativo é crates/rts-codegen-new/ (caminho único HIR→Cranelift, sem MIR; valor PolyValue NaN-boxed; shapes + inline caches de dado; dispatch data-driven). O antigo crates/rts-codegen-old/ (dual HIR→MIR / AST, valor i64 sobrecarregado) está congelado e some no cutover. Plano canônico: docs/specs/rts-codegen-new-design.md.

Workspace Cargo em crates/. O src/ é a fachada do bin rts (re-exporta os crates); paths reais sob crates/<crate>/src/.

crates/
├─ rts-ast/          AST interno
├─ rts-parser/       SWC parse → AST
├─ rts-diagnostics/  erros estruturados
├─ rts-engine/       ⚡ heap GC + contrato ABI (SPECS, AbiType, Intrinsic, símbolos) + Registry
├─ rts-hir/          HIR tipado (I8..I128/F32/F64/Bool/Str/Handle/Array/Function/Class/Object/Any)
├─ rts-mir/          MIR SSA — usado SÓ pelo rts-codegen-old (congelado); some no cutover
├─ rts-codegen-old/  motor CONGELADO (dual MIR/AST, switchboard, add_fn! manual)
├─ rts-codegen-new/  motor ATIVO — value.rs (PolyValue), repr.rs, shape.rs, ic.rs,
│                    dispatch.rs (data-driven), abi_gen.rs (ABI gerada de SPECS), lower/ (single path)
├─ rts-primitives/   classes PRIMORDIAIS (String/Object/Array/Function/Promise/Boolean/Number/Error)
├─ rts-shared/       não-primordial universal (math/num/collections(Map/Set)/json/globals + stdlib/*.ts)
├─ rts-std/          backend (io/net/tokio/console/promise/audio)
├─ rts-runtime/      fachada fina (pub use dos quatro acima) + staticlib AOT
├─ rts-node/         shims node:* (fs, os, path, process, crypto, util)
├─ rts-napi/         N-API (.node addons) via libloading + HandleTable
├─ rts-linker/       link nativo (system linker + fallback object)
└─ rts-cli/          run · compile · apis · init · repl · eval · ir

Pipeline (motor novo — caminho único, sem MIR)

TS → SWC → AST → HIR (rts-hir) → lower/ (HIR → Cranelift IR, UM caminho) → egraph Cranelift → JIT/AOT

Não há tier MIR nem dual AST/MIR no motor novo. O egraph do Cranelift (use_egraphs=true) é o ÚNICO otimizador (const-fold, CSE, DCE, FMA, strength reduction, inline intraprocedural). O front-end só faz o que o Cranelift não pode (semântica JS): coerções ToNumber/ToString/ToBoolean, o + polimórfico, inserção de box/unbox (IR pura que o egraph dobra), emissão de sites de shape/IC, wrap de int estreito, arestas de exceção. AOT/JIT compartilham compile_program (FnCtx.module é &mut dyn Module).

Doutrina PRIMORDIAL-vs-Registry (central ao motor novo): o motor NOMEIA só as classes primordiais; todo o resto resolve via Registry data-driven — nada de nome não-primordial hardcoded no front, nem em "allow-list" (ver CLAUDE.md § anti-hardcode). Os globais não-primordiais (console, Map/Set, JSON, Date) vivem como .ts de prelude (rts-shared/stdlib/*.ts) e chamam pontes privadas engine.*; o front não os nomeia.

ABI sem boxing: cada função de namespace é um símbolo #[no_mangle] extern "C" fn __RTS_FN_NS_<NS>_<NAME>(...). Nada de JsValue, nada de dispatcher central. i64/f64 em bits nativos, strings como (ptr, len) UTF-8, handles u64 opacos para recursos. No motor novo a tabela de símbolos JIT é DERIVADA de SPECS (abi_gen.rs), não add_fn! manual.


🚀 Comece em 30 segundos

# Instalar
git clone https://github.com/UrubuCode/rts && cd rts
cargo build --release

# Rodar
./target/release/rts run examples/console.ts

# Compilar pra binário (~3 KB, sem runtime DLL)
./target/release/rts compile -p examples/console.ts hello
./hello

CLI

rts run file.ts                  # JIT in-memory
rts compile -p file.ts out       # AOT com slicing por uso
rts apis                         # listar APIs registradas em abi::SPECS
rts ir file.ts                   # dump do IR Cranelift (pra debug de codegen)
rts init my-app                  # scaffolding de projeto

🔬 Debug do codegen

Quer ver exatamente o que o Cranelift está gerando?

rts ir file.ts 2>&1 | head -50

Imprime o IR de cada user fn + __RTS_MAIN sem executar. Bom pra caçar loads/stores redundantes em hot loops, calls extern desnecessários, e oportunidades de intrinsic. Ver CLAUDE.md § Debug do codegen.


🎯 Compatibilidade JS/TS

Número honesto: a paridade cross-runtime real do motor novo é a do bloco 🌐 Cross-runtime parity no topo (gerado pelo CI contra Bun+Node). O motor antigo chegou a 100% (372/372) na tag v0.0-202606072107 — um máximo local de uma abordagem hardcoded sobre um modelo de valor insólido; o redesign existe para furar essa parede, não para repetir o número. NÃO cite "1015/1015"/"100%" como estado atual.

O que o motor novo já cobre (em construção, paridade subindo):

  • Sintaxe core: classes (extends/super/static/getters/setters), destructuring, spread em literais, optional chaining, nullish coalescing, arrow/function expressions, template literals
  • Async: Promise + async/await (caminho síncrono sem await; event loop real ainda aberto, #207)
  • JS globals como .ts de prelude (data-driven): Object + statics, Boolean/Number/String prototypes, Error family, console.*, Map/Set, JSON, Date — nenhum nomeado no front
  • Operadores: divisão JS spec (/ SEMPRE f64 — 44100/48000 === 0.91875, inclusive atribuído a const), comparações, ternário, bitwise, shifts
  • try/catch/finally fase 1 (slot de erro thread-local; finally roda e re-propaga o erro corretamente)
  • Diagnóstico: identificador não-resolvido vira erro de compilação, nunca segfault — e nunca um valor errado (o piso de solidez do redesign)

Itens pesados ainda abertos (alguns em fase de redesign): event loop async real (#207), closures com captura mutável (#195), TCO, Proxy (#218), typed arrays/DataView/ArrayBuffer, Symbol/Reflect/BigInt (#216/#219). Tracker mestre de paridade JS/TS: #226.


📚 Documentação


🛡️ Guardrails

  • ✋ Sem xtask — build é cargo puro
  • ✋ Sem download de runtime support em build time
  • ✋ Sem dependência de Rust/Cargo no ambiente final do binário AOT
  • ✋ Single binary distribuído, roda em qualquer Windows/Linux/macOS sem instalar nada

Feito com 🦅 por UrubuCode

Se Bun é foguete, RTS é ave de rapina.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors