Step 07 · CLI design & looking ahead to LSP

Unified CLI

minilang <command> <args>
  run <file|->     parse + evaluate
  fmt <file|->     pretty-print
  ast <file|->     dump AST
  repl             interactive read-eval-print loop

Patterns to adopt early:

  • - for stdin everywhere a file is accepted. Pipe-friendly.
  • Exit codes matter: 0 success, 64 usage error, 65 source error, 70 internal error (we follow rough sysexits.h conventions).
  • Subcommand-first so minilang fmt --check and minilang run --debug have separate option spaces — no flag conflicts.
  • One binary, many commands simplifies install + distribution.

What's missing for production

  • minilang check <file> — parse + typecheck, no eval, machine-readable JSON output (--format=json).
  • minilang test <file> — discover and run inline tests.
  • minilang doc — extract docstrings → HTML.
  • minilang lsp — Language Server Protocol stdio mode.

LSP — the natural next step

Every tool we built — span-tracking lexer, error-recovering parser, structured diagnostics, pretty printer — is what an LSP server needs. Sketch:

client → JSON-RPC →  textDocument/didOpen { uri, text }
                  → store in document map, run lex + parse
                  → publishDiagnostics { uri, diagnostics }
client → JSON-RPC →  textDocument/didChange { uri, edits }
                  → incremental re-parse (or full)
                  → publishDiagnostics
client → JSON-RPC →  textDocument/formatting → call format(program)
client → JSON-RPC →  textDocument/hover { position }
                  → look up enclosing AST node, return doc/type

The hardest parts:

  • Incremental parsing to keep latency low on large files (tree-sitter solves this; rust-analyzer rolls its own).
  • Indexing across files for cross-file go-to-definition / find-references.
  • Cancellation — long-running analyses must be interruptable.

All of those build on the foundations we laid here. Diagnostic codes, spans, and AST formatter aren't optional in an LSP world — they're the contract you have with the editor.

Connection to the rest of the curriculum

  • cp-16 (capstone compiler suite) reuses this CLI shell.
  • cp-17 (capstone JIT) layers compile and jit subcommands on top.
  • cp-18 (MLIR framework) adds dump-mlir and lower stages.

The unifying lesson: a great compiler is also a great library, and the CLI / REPL / LSP are just thin shells over that library.