verona-conventions
Verona compiler coding conventions, C++ style, trieste patterns, and project structure. Applies when writing or reviewing Verona compiler code.
- License 许可
- MIT
- 所属仓库
- microsoft/verona
- 最近更新
- 2026-11-13
- Stars
- ★ 3.7k
- Forks
- 173
01 前言 Front Matter
- name
- verona-conventions
- description
- Verona compiler coding conventions, C++ style, trieste patterns, and project structure. Applies when writing or reviewing Verona compiler code.
- user-invocable
- false
03 SKILL.md 正文
Verona Compiler Conventions
C++ Style (C++20)
snake_casefor functions, variables, namespaces.PascalCasefor types/classes.- Token definitions use
PascalCase:inline const auto TypeName = TokenDef(...). - Allman braces (opening brace on own line). Exception: single-line lambdas.
- No
goto. Use flags, early returns, or helper functions. #pragma once, not include guards.- Project headers first, then system/library headers separated by a blank line.
- Use
constexpr/consteval, structured bindings,if constexpr,std::span,[[nodiscard]]. - Prefer
static constexprover#definefor constants.
Trieste Patterns
- Node construction:
Node n = SomeTokencreates a node. NOTauto n = SomeToken(copies TokenDef). - Child access:
n / ChildToken(named WF accessor), notn->at(i)(positional). - Append children:
node << child. Set value:node ^ value. Duplicate:clone(). - Clone shared nodes: Always
clone()nodes inserted into multiple AST locations. - Token comparison:
node->type() == OtherToken, NOTnode == other_node(compares pointers). - Error handling:
err(node, "message")wraps inError << ErrorMsg << ErrorAst. - Tree mutation:
traverse()iterators are invalidated byreplace()/erase(). Collect first, mutate after. - WF declarations: Every pass declares output shape.
<<=for children,++for zero-or-more,|for choices. - Symbol table:
lookup()walks up + follows includes.lookdown()searches own symtab only, no includes.look()is immediate, no flags. - Pass structure:
PassDefwith name, WF, direction (dir::topdown/dir::bottomup/dir::once), rewrite rules.pre()/post()hooks.
Build & Test
- Build in
build/directory.ninja installto build. Usedist/vc/vcanddist/vbci/vbci(installed binaries have_builtin). - Rebuild with
ninja installbefore debugging or validating compiler/runtime behavior on the current branch. - Run
vcfrombuild/:dist/vc/vc build ../testsuite/v/hello. Do NOT cd into source dir. - Debug with the binaries under the active build directory's
dist/tree. Do not use non-installed build outputs when validating behavior. ctest --output-on-failure -j$(nproc)for full test suite.-p <passname>stops after a pass.--dump_passes=<dir>dumps intermediate ASTs.- Golden files:
ninja update-dump exit_code.txthas NO trailing newline (printf '0', notecho).- Treat compile-time and runtime test failures as real regressions until they are investigated on the current baseline. Do not assume a failure predates your change without verification.
Test Conventions
- Tests in
testsuite/v/must be self-contained. No external deps, nouse "https://...". - Do NOT write
use "_builtin"— it is always implicitly available. - Bitmask exit code pattern:
var result = 0;thenif cond { result = result + N; }with powers of 2. Exit 0 = all passed. - Compile-error tests:
exit_code.txt: 1incompile/, norun/directory. - Structure:
testsuite/v/<name>/<name>.vwith golden dirs<name>/<name>/compile/and<name>/<name>/run/. - FFI tests must include at least one reachable FFI call from their lib to trigger init function reification.
Verona Source Syntax
- Class definitions:
myclass[T] { ... }(noclasskeyword). - Fields need semicolons:
val: T;. Nolet/varon class fields. - No semicolons after closing braces of
for,if,while. new { field = val }— no class name afternew.use Ximports for unqualified lookup.use "url"for packages._builtinis always implicit.(obj.field)(args)to callapplyon field access result.Type(args)constructor sugar callscreatemethod (e.g.,callback(f)→callback::create(f)).x.methodfor zero-arg methods (no parens).!exprfor boolean negation.- Array literals:
::(expr, ...). - Match:
(match expr { (pattern) -> body; ... }) else (default). - FFI calls:
:::name(args)for direct FFI,ffi::func(args)for_builtin/ffi/wrappers. - FFI data passing: arrays pass as pointers to their data (e.g.,
array[u8]→uint8_t*), objects pass as pointers to their fields (like a C struct). No wrapper types cross the FFI boundary. - Packages:
use "url" "tag"imports from a git repo.use "~/dev/pkg" "main"works for local repos.
Architecture
- Small, composable passes. Many small passes > few large ones.
- Layered dependencies — lower layers never depend on higher ones.
- Frontend (vc, passes 0–9): parse → structure → ident → sugar → functype → dot → application → anf → infer → reify.
- Backend (vbcc library, passes 10–13): assignids → validids → liveness → typecheck.
assert()liberally for invariants.- Errors are AST nodes, not exceptions.
Adding New Ops/Builtins
Adding a new bytecode op requires updates in ~15 places across the codebase. Use this checklist:
- Token def:
include/vbcc.h(token),include/vbci.h(Op enum) - Frontend WFs in
vc/lang.h:wfExprDot,wfPassDot(with<<= Args),wfBodyANF,wfPassANF(with<<= wfDst * wfSrc) - Frontend passes:
dot.cc(builtin reg),anf.cc(lowering),infer.cc(type tracking),reify.cc(IR transform) - Backend WFs in
include/vbcc.h:wfStatement,wfIR Defpattern invbcc/lang.h: manually maintained list — MUST include if op has a dstLocalId- Liveness in
vbcc/passes/liveness.cc: manually categorized ops — add to correct use/def category - Bytecode in
vbcc/bytecode.cc: encoding handler - Type check in
vbcc/passes/typecheck.cc: if needed - Interpreter in
vbci/thread.cc: op handler + op name in name array
Missing items 5 or 6 causes "undefined register" errors in later passes, not at the registration site.
Debugging
- Trace data flow, not just error sites. Root cause is often upstream.
- For tricky compiler/runtime/FFI bugs, do principled analysis first: reproduce, trace, inspect dumps, and localize the fault before changing semantics.
- Before speculative interpreter/runtime changes, explain the evidence and proposed fix and get feedback.
- "Bad type" runtime errors usually mean unrefined default literals in compiler output. Check infer pass dump.
node->type() == other->type()for token comparison, NOTnode == other_node.- Write targeted tests that expose the bug before fixing.
- Runtime failures matter as much as compile-time failures. Investigate both with the current branch's
dist/binaries. - Do not describe runtime behavior as flaky or dismiss it as harness noise without first reproducing and tracing it to a concrete cause.
- Durable Verona-specific workflow rules belong in this skill or the repo
AGENTS.md, not in agent-specific memory stores.
04 同仓库更多 Skills
verona-type-inference
Verona compiler type inference model — bidirectional refinement, per-function inference, lambda/context propagation, algebraic and structural typing, generics, and debugging. Use when changing or debugging `vc/passes/infer.cc` or investigating type inference failures.
verona-conventions
Verona compiler coding conventions, C++ style, trieste patterns, and project structure. Applies when writing or reviewing Verona compiler code.
verona-coding
Patterns, pitfalls, and idioms for writing Verona source code (.v files). Use when writing library code, _builtin types, or user programs.
vbci-memory
Verona interpreter (vbci) memory management model — regions, reference counting, write barriers, dragging, cowns, and finalization. Use when working on or debugging vbci runtime memory management code.
testsuite
Verona compiler test suite infrastructure — running tests, updating golden files, verifying pass completeness, checking error codes. Use when debugging test failures, regenerating golden files, or understanding the test framework.
review
Run a principle-based code review on the current branch. Use when the user asks for a review, or at mandatory review checkpoints (after planning, after implementation before PR).