Tooling na prática
Objetivo: conhecer o CLI
mkno dia a dia, as ferramentas de runtime (observer/profiler/ debugger), e como o package manager resolve versões.
O compilador é um motor de queries
Seção intitulada “O compilador é um motor de queries”A decisão fundacional: o compilador não é um batch que parseia, checa e morre. É uma biblioteca
incremental de queries (modelo rust-analyzer). Quase toda ferramenta é um consumidor do entendimento
que o compilador tem do código (o LSP pergunta “qual o tipo de X?”, o linter pede a info semântica, o
doc gen as assinaturas). Por isso há um binário único, nada de gopls/zls à parte. A
incrementalidade é por declaração: editou uma função, re-checa aquela declaração e o que depende
dela.
O CLI mk
Seção intitulada “O CLI mk”Tudo num binário (mk é alias de makoto):
mk run app.mko // compila e rodamk build // compila o projeto → bináriomk test // roda os testes (@test) e benchmarks (@bench)mk fmt // formatter zero-config (um formato canônico; sem bikeshedding)mk lint // linter fechado (regras fixas; acaba a format-war)mk get <repo> // adiciona uma depmk tidy // sincroniza deps/lockfilemk doc // gera docs (de /// e dos .mkoui)mk new / mk init // novo projeto / inicializa no diretóriomk update / mk versionDois modos do compilador: portátil (um arquivo no PATH, default) e instalado (mk install host
explode em N estágios versionáveis, pra atualização parcial, como trocar só o parser de TS em vez de
tudo).
Testes e benchmarks
Seção intitulada “Testes e benchmarks”Testes moram junto do código (@test) ou em arquivo_test.mko/tests/. A matriz de execução
@testmode(order, state) cobre (sequential|parallel) × (isolated|shared); o default
(sequential, isolated) é o seguro. Abra a matriz pra caçar uma race:
@testfn parse_aceita_valido() { r := parse("42") test.expect_eq(test.expect_ok(r), 42)}Benchmarks são @bench; o runner é configurável (esforço), mas o comparador é fixo (a estatística
que decide regressão-vs-ruído, anti-p-hacking).
Ferramentas de runtime
Seção intitulada “Ferramentas de runtime”Apoiam-se na observabilidade do runtime (pull, default-off; você não paga pelo que não liga):
- observer: o frontend de
runtime.processes()/trace(), com árvore de supervisão, processos vivos, channels e o|e|das mortes (o:observerdo BEAM). - profiler: sampling/tracing opt-in, com saída textual estruturada (um LLM lê o profile como texto e raciocina sobre ele) além de flamegraph.
- step-debugger: feito pro modelo de atores, com breakpoints
process-only(pausa só aquele) oueverything, e breakpoints linkados (ABC disparam juntos) pra pegar a interação entre processos no momento exato.
ev := runtime.trace(.Named("worker"), [.send, .receive], sink: .channel, sample: 100)loop e in ev { match e { Send(m) => ...; Receive(m) => ... } }Package manager
Seção intitulada “Package manager”Resolução de versão por MVS (Minimal Version Selection) mais lockfile mk.sum (checksums
auto-gerados, build reproduzível). O registry é híbrido: libs oficiais por nome (first-party),
terceiros por URL (estilo Go). O wire-format do registry é a serialização nativa da linguagem.
Codegen tem dois lares: extensões de compilador (§20, in-process, como a UI) para o que toca o
pipeline, e o task runner para ferramentas externas (um protoc, um minificador), declaradas com
suas capabilities no mk.project. Sem REPL (decisão explícita).
Você chegou ao fim do passeio. Daqui, os docs canônicos (language-design.md, language-grammar.md,
official_libraries.md, extensions.md, tooling.md) são a referência completa; este livro foi a
porta de entrada. Bom Makoto.