Teu progresso
0 / 83 módulos0%
Estágio 01 · 01-13
BloqueadoVocê usa V8, Babel, TypeScript Compiler, esbuild, Webpack, Tailwind CLI, Prisma generator, GraphQL codegen, ESLint, prettier todos os dias. Cada uma dessas ferramentas é um compiler ou interpreter sob algum aspecto, recebe texto, parseia, transforma, emite. Entender as fases (lex → parse → analyze → optimize → emit) é o que permite ler bug em parser de TS, escrever um plugin de Babel, depurar source maps, ou desenhar uma DSL pra um problema do seu domínio.
Este módulo é a base prática de compiladores e interpretadores: o que é tokenizer, o que é AST, como recursive descent parsing funciona, o que é semantic analysis e tipo inferência, o que é IR (intermediate representation), o que é codegen, e como JITs (V8, JVM HotSpot, .NET) escalam. Ao final você consegue escrever um interpreter completo para uma linguagem de brinquedo e entender por que TypeScript demora 30s pra typecheck repo grande.
source text
→ lexer (tokenizer)
→ parser → AST
→ semantic analyzer (resolve names, type-check) → annotated AST
→ IR (intermediate representation)
→ optimizer
→ backend (codegen) → bytecode/asm/JS/binário
Compilers AOT (gcc, rustc, javac) executam tudo antes da execução. Interpreters podem parar em AST (interpretadores tree-walking) ou bytecode (Python, Ruby antigo). JITs combinam: parse → bytecode → execute, e em hot paths recompila pra código nativo.
Pega texto bruto e produz tokens (categoria + lexema): IDENT("foo"), NUMBER(42), KEYWORD("if"), OP("+"). Whitespace e comments geralmente são ignorados (com exceções: Python indent é significant; JS ASI olha newline).
Implementação típica: state machine ou regex tabulado. DFAs vêm de regex via Thompson construction + subset construction. Lex/flex geram tabelas. Hand-written wins em flexibility (TypeScript usa hand-written).
Edge cases comuns: string escapes, comments aninhados, números em multiple bases, identifiers Unicode, JSX em meio de expressão.
Linguagens de programação são tipicamente context-free (CFG) na sintaxe (com pequenas violações resolvidas em semantic). Notação BNF/EBNF.
Classes:
Operator precedence (Pratt parsing): técnica elegante pra parsear expressions com precedence/associativity. V8 e muitos parsers modernos usam.
Estrutura central. Nodes representam constructs (BinaryOp, If, FunctionDecl, Ident). Cada node carrega children + span (file/line/col) pra erros.
Diferente de CST (Concrete Syntax Tree, parse tree completo com tokens). AST descarta details sintáticos. Linters/formatters preferem CST.
Visitors (visitor pattern, ou pattern matching em Rust/OCaml) percorrem AST. Babel plugins manipulam AST.
Após parse, percorra AST construindo scopes (mapas nome → declaration). Cada let, function, import adiciona symbol. Lookup respeita scope chain.
Hoisting em JS: declarations subem pro topo do scope (vars, function declarations). Let/const têm temporal dead zone.
Erros típicos: identifier not declared, redeclared, used before declaration.
Estático: tipo é determinado em compile time, sem rodar. Dinâmico: tipo só conhecido em runtime (Python, JS). Gradual: misto (TypeScript, Mypy).
Algoritmo central: type inference. Hindley-Milner (ML, OCaml, Haskell) infere principal type sem anotação. TypeScript usa flow-based + bidirectional. Subtyping vs structural typing distingue Java de TypeScript (TS é structural).
Variance: covariance (subtipo em posição de saída), contravariance (em entrada), invariance (mutável). Conhecer evita bugs em generics.
Transformação 1:1 com semantics, mas mais regular. Tipos comuns:
t1 = x + y; t2 = t1 * z.LLVM popularizou IR como contrato: front-ends emitem LLVM IR, optimizer trabalha em LLVM IR, back-ends emitem nativo. Rust, Swift, Julia, Zig usam LLVM. V8/JVM têm IRs próprios.
2 + 3 → 5.let x = 5; y = x + 1; → y = 6.Trade-off: tempo de compilação vs qualidade do código. -O0 rápido, -O3 lento. Profile-guided optimization (PGO) usa traces reais.
Backend emite código alvo: máquina, bytecode (JVM, .NET CLR, Python), JS, Wasm.
Para nativo: register allocation (graph coloring, linear scan), instruction selection (cobertura de patterns IR → asm), instruction scheduling (reorder pra pipelining).
ABIs (Application Binary Interface) ditam: como passar args (registros vs stack), calling convention, layout de structs, name mangling. Cross-language interop respeita ABI alvo (extern "C").
Linguagens managed precisam GC. Estratégias:
V8 GC: scavenge (young), mark-compact (old), incremental marking, write barriers.
Interpretador roda; profila hot paths; recompila em código nativo otimizado. Tiered:
Inline caches: lookups de propriedade ficam cached por shape; misses re-lookup. Hidden classes (V8) e shapes (SpiderMonkey) tornam objetos JS rápidos quando shape estabiliza.
Por isso obj.foo = 1; obj.bar = 2 consistente é mais rápido que if cond obj.foo = .... Adicionar property dinamicamente muda shape e invalida caches.
Toolchains modernos (TypeScript, Babel, esbuild, Vite, webpack) emitem source maps: mapeamento posição-no-output → posição-no-source. Permite debugger mostrar source original. Format VLQ (variable-length quantity) pra caber em string.
constexpr em C++, comptime em Zig): código rodando em compile time.Java generics usam erasure: List<String> em runtime é só List. Reflection não vê parameter type. C# generics são reified: type info preservada em runtime. TypeScript: erasure (compila pra JS sem tipos).
Implicação prática: em Java/TS, runtime checks não podem inspecionar generic type. Workaround: passar Class<T> ou t: new () => T.
TypeScript checker é caro porque:
Mitigação: split em projects, usar tsc --build, evitar tipos exóticos sem motivo, skipLibCheck quando seguro.
Internal DSL (chains de método, builders) vs external (parse separado). Casos onde external vence:
Antes de escrever DSL, considere: subset de JSON, YAML com schema, ou config em código host. DSL nova é maintenance burden.
Tese. Em 2026 a indústria JS migrou tooling de JS-on-Node para nativos (Rust, Go, Zig). Razão técnica: AOT compilado, sem GC pause, paralelismo trivial via rayon, single-binary distribution. Ganho típico: 10-100x speedup vs equivalentes JS. Quem ainda roda Babel + ESLint + Prettier + Webpack em projeto novo paga imposto de DX desnecessário.
oxlint), formatter, transformer, minifier. ~50-100x faster que Babel/ESLint. Vite planeja integração; Astro avalia. Fonte: oxc.rs.biome.json). Adoption: Astro, Discord migrando de Prettier. Fonte: biomejs.dev.01-08. Fonte: Microsoft DevBlogs "A 10x Faster TypeScript" Mar 2025.JSC (JIT da Apple, Safari) tem perf comparável a V8 com footprint menor. Bun 1.2+ (2025) é production-ready: package manager (~30x faster que npm install via global cache + symlinks), bundler, transpiler, test runner. Single binary all-in-one. Limitações: compat npm ~95% (módulos nativos como sharp, canvas ainda quebram); ecossistema menor; suporte Windows recente. Em 2026 é hot em CI (cold start fast) e edge runtimes (Cloudflare Workers Bun em beta). Fonte: bun.sh.
| Categoria | Default 2026 | Alternativas |
|---|---|---|
| Linter | oxlint OR Biome | ESLint + plugins (legacy ecosystem) |
| Formatter | Biome | Prettier (ubíquo, legacy) |
| Bundler dev | Vite (Rolldown quando GA) | Turbopack (Next.js dev), Bun |
| Bundler prod | Vite/Rolldown | Webpack 5 (legacy), Rspack (Rust port) |
| Typecheck | tsc → tsgo (GA late 2026 esperado) | — |
| Test runner | Vitest | bun test, node:test (Node 22+), Jest (legacy) |
| Package manager | pnpm (default monorepo) | Bun, npm, yarn 4 |
01-07 §2.12)Pipeline tier-up V8 atual:
Decisão: V8 default; JSC para mobile-iOS-heavy ou ecossistema Bun; Hermes para RN Android perf-critical (cold start); QuickJS para IoT.
03-12.# oxlint vs eslint — repositório médio (~50k LOC)
$ time eslint src/
real 0m18.412s
$ time oxlint src/
real 0m0.234s
# ~78x faster, mesmo conjunto de regras core.
// vite.config.ts — switch Rollup → Rolldown (Vite 7, 2026)
import { defineConfig } from 'vite';
import { rolldown } from 'rolldown/vite'; // experimental flag em Vite 6.x
export default defineConfig({
experimental: { rolldown: true },
build: { target: 'es2022', minify: 'oxc' },
});
# bun install vs npm install — repo Next.js fresh, sem cache
$ time npm install
real 0m42.318s
$ time bun install
real 0m1.487s
# ~28x faster; reusa global cache + hardlinks.
# package.json scripts (recorte) — toolchain moderno 2026
scripts:
lint: "biome lint ."
format: "biome format --write ."
typecheck: "tsgo --noEmit" # fallback: tsc --noEmit
test: "vitest run --coverage"
build: "vite build"
dev: "vite"
tsc full em CI quando isolatedDeclarations + tsgo (quando GA) entregam 10-100x speedup.swc/oxc targetam ES2020+ direto.c8 nativo.npm install em CI sem cache — 5-10x slower que pnpm/Bun com cache global.Monorepo Turborepo + pnpm workspaces. apps/site em Vite + Rolldown (target Vite 7 GA 2026). apps/courier-rn Hermes Android (cold start importa). CI roda Bun para bun install 30x faster em cold start de runner. Biome lint+format unificado substitui ESLint+Prettier. tsgo em avaliação para CI typecheck quando GA.
Cruza com: 01-07 §2.12 (V8 pipeline + ES features), 01-08 (TS toolchain + tsgo), 02-04 (React, JSX transform via swc/oxc), 02-05 (Next.js, Turbopack dev), 03-12 (WebAssembly + AOT).
Fontes: V8 blog "Maglev" Aug 2023; V8 blog "TurboShaft" Mai 2024; Microsoft DevBlogs "A 10x Faster TypeScript" Mar 2025; Vite blog "Rolldown" Out 2024; bun.sh; biomejs.dev; oxc.rs.
Você precisa, sem consultar:
Construir uma linguagem de brinquedo "Mini" com lexer, parser, type-checker e interpreter, escrita em TypeScript.
Mini tem:
int, bool, string, T -> U, [T], { field: T, ... }.+ - * / == < && ||), if/else, let, lambda, function call, list literal, record literal, field access.fn name(args): T = expr), top-level let.Pipeline:
examples/quicksort.mini) com lista, recursion, lambda, records, type-checa e roda.Threshold de Maestria
Acerte todas as 5 pra marcar o módulo como concluído. Sem pressa, sem timer. Tudo fica salvo no teu navegador.
Q1Por que TypeScript optou por parser recursive descent hand-written em vez de gerador LR(1) tipo yacc?
Q2Por que SSA (Static Single Assignment) torna otimizações como dead code elimination triviais?
Q3O que dispara um deopt (bail out) em V8 e por que isso é caro?
Q4Qual a diferença prática entre erasure (Java/TS generics) e reified (C# generics)?
Q5Por que adicionar properties dinamicamente a um objeto JS prejudica performance no V8?
Destrava
01-13 é prereq dos seguintes módulos: