rvn and rvnc
rvnc is the compiler driver used by MSBuild and other build hosts. It keeps to
compiler inputs and outputs: source/project inputs, references, framework
selection, and assembly emission.
rvn is the frontend tool. It owns scaffolding and internal development views,
using the shared compiler workspace setup from Raven.Compiler.Core.
Application builds should use the .NET SDK surface: dotnet build and
dotnet run --project.
Usage
rvnc [compiler-options] <source-files|project-file.rvnproj>
rvn build [project-file.rvnproj] [dotnet-build-options]
rvn run [project-file.rvnproj] [dotnet-run-options] [-- application-args]
rvn clean [project-file.rvnproj] [dotnet-clean-options]
rvn doctor
rvn dev <syntax|dump|macros|binders|bound-tree|symbols|quote> [options] <source-files|project-file.rvnproj>
rvn init [console|classlib] [--name <project-name>] [--framework <tfm>] [--type <console|classlib>] [--force]
rvn --version
rvnc --version
For repository development, load local shell helpers after building:
source scripts/raven-env.sh
The helpers define rvn and rvnc for the current terminal session. Set
RAVEN_CONFIGURATION or RAVEN_FRAMEWORK before sourcing to use a different
build output.
Development Environment Setup
During source development there are several supported ways to run the tools:
Direct
dotnet runinvocations. This requires no shell aliases and always builds the selected project before execution:dotnet run -f net10.0 --project src/Raven -- dev syntax path/to/file.rvn dotnet run -f net10.0 --project src/Raven.Compiler -- path/to/file.rvn -o /tmp/app.dllSession helpers. Build the tool projects once, then source the helper script:
dotnet build src/Raven/Raven.csproj -f net10.0 dotnet build src/Raven.Compiler/Raven.Compiler.csproj -f net10.0 source scripts/raven-env.sh rvn dev bound-tree path/to/file.rvn rvnc path/to/file.rvn -o /tmp/app.dllThe script defines shell functions only for the current terminal session. It does not edit
.zshrc,.bashrc, or global shell profiles.Application builds. Use the .NET SDK surface for project-based apps:
dotnet build path/to/App.rvnproj dotnet run --project path/to/App.rvnprojrvn build,rvn run, andrvn cleanare convenience commands over that same SDK workflow:rvn build path/to/App.rvnproj rvn run path/to/App.rvnproj rvn clean path/to/App.rvnprojIn this repository,
Directory.Build.propswires.rvnprojprojects to the local Raven language targets. External source checkouts can setLanguageTargetsandRavenCompilerHostexplicitly until Raven ships as a packaged SDK/build asset.SDK selection. For
net11.0samples and projects, use a project-localglobal.jsonthat selects an SDK withnet11.0targeting support. The .NET CLI chooses the highest installed SDK by default, which may still be too old for a future target framework.
The distribution shape should make these repo-relative paths unnecessary:
package rvn, rvnc, Raven.LanguageServer, Raven MSBuild assets, and
Raven.Core together so projects can build with ordinary dotnet build and
editors can discover the same SDK root.
rvnc Options
--framework <tfm>– target framework (e.g.net8.0)--refs <path>– additional metadata reference (repeatable)--define <symbols>,-define <symbols>– add conditional-compilation symbols; repeat the option or separate symbols with commas or semicolons-o <path>– output path (.rvn/legacy.ravinputs: assembly file path;.rvnprojinputs: output directory path)--runtime-async– force .NET 11 runtime-async emission for async methods (Asyncmethod impl flag +AsyncHelpers.Awaitcalls when available)--no-runtime-async– disable runtime-async emission and keep classic awaiter pattern/state-machine lowering--global-statements– enable top-level/global statements (default)--no-global-statements– disable top-level/global statements--namespace-members– enable namespace-levelfuncandconstdeclarations (default)--no-namespace-members– disable namespace-levelfuncandconstdeclarations--namespace-member-imports– enable namespace lookup/completion promotion from[TopLevel]containers (default)--no-namespace-member-imports– disable namespace lookup/completion promotion from[TopLevel]containers--returned-value-handling <default|full|none|info|warning|error>– configure the built-in returned-value analyzer (RAV9029); project files control analyzer mode, while.editorconfigcontrols severity--force-returned-value-handling– shorthand for treating returned values that are not handled as errors--no-emit– analyze only; skip assembly emission-h,--help– show help
rvn dev
rvn dev hosts internal debug views outside the compiler binary:
rvn dev syntax [flat|group|json] [--syntax-view authored|expanded] <input>– print the authored or fully macro-expanded syntax tree. JSON mode includes the corresponding complete source text and structured node/token/trivia data for editor tooling.rvn dev dump [plain|pretty] <input>– dump source syntax viewrvn dev macros [original|expanded|both] <input>– dump macro source viewsrvn dev binders <input>– print binder treervn dev bound-tree [original|lowered|both] <input>– print binder and bound treervn dev symbols [list|hierarchy] <input>– inspect symbolsrvn dev quote <input>– print Raven SyntaxFactory-style tree construction code
RavenQuoter emits Raven source by default. API callers can select the legacy
C# rendering with RavenQuoterOptions.OutputLanguage.
rvn build, rvn run, and rvn clean
These are frontend conveniences over the .NET SDK project workflow:
rvn build [project.rvnproj] [dotnet-build-options]runsdotnet buildrvn run [project.rvnproj] [dotnet-run-options] [-- application-args]runsdotnet run --projectrvn clean [project.rvnproj] [dotnet-clean-options]runsdotnet clean
When the project path is omitted, rvn uses the single .rvnproj file in the
current directory. The commands do not invoke rvnc directly; MSBuild owns
restore, NuGet/package resolution, project references, and language target
selection.
Init command
Use init to scaffold a .rvnproj project in the current directory:
rvn init
Generated files:
<CurrentDirectoryName>.rvnprojsrc/main.rvnbin/.gitkeep
Useful init options:
--name <project-name>– override generated project and assembly name--framework <tfm>– setTargetFrameworkin the generated project fileconsole|classlib– select the scaffold type (consoledefault)--type <console|classlib>– compatibility alias for selecting the scaffold type--force– overwrite scaffold files if they already exist
When no framework is specified the compiler defaults to the newest installed framework.
.NET 11 runtime-async
When the project target framework is net11.0 (or newer), Raven auto-enables runtime-async emission.
- Async methods are emitted with the async method-impl flag.
- Await sites are emitted as
System.Runtime.CompilerServices.AsyncHelpers.Await(...)when the compiler host runtime exposes that API. - Async state-machine synthesis is skipped in this mode.
Important: if you run the compiler driver via dotnet run, run it on net11.0 so AsyncHelpers is available:
dotnet run -f net11.0 --project src/Raven.Compiler --property WarningLevel=0 -- path/to/App.rvnproj
If you build or run a net11.0 .rvnproj through MSBuild (dotnet build or
dotnet run --project), the selected .NET SDK must support net11.0. Use a
project-local global.json when the machine has multiple SDK bands installed.
Sample project:
samples/projects/runtime-async-net11/README.md
Classic lowering vs runtime-async
Classic async lowering (runtime-async off):
- Raven synthesizes async state-machine types and rewrites
awaitinto explicit awaiter calls. - Generated IL uses
GetAwaiter/GetResultpatterns from compiler-generated machinery. - Async return types in this mode include
Task,Task<T>,ValueTask, andValueTask<T>.
What this leaves on the compiler side:
- Async correctness depends on Raven maintaining a full custom state-machine rewriter.
- New await shapes require additional compiler-side lowering/emission work.
- Async lowering bugs surface as compiler-emission complexity (for example around nested async constructs).
What runtime-async fills:
- Raven marks async methods with runtime async metadata and emits
AsyncHelpers.Await(...)calls. TaskandTask<int>entry points are bootstrapped withAsyncHelpers.HandleAsyncEntryPoint(...)when targeting a .NET 11 runtime surface that exposes it.- .NET 11 runtime provides the core async suspension/resume machinery, reducing compiler-generated state-machine complexity.
- Await support for core BCL shapes is now direct (
Task,Task<T>,ValueTask,ValueTask<T>, and configured awaitables).
Current limitations:
- To emit
AsyncHelpers.Await(...), the compiler host process must run onnet11.0(for exampledotnet run -f net11.0 ...). - If the host runtime does not expose
AsyncHelpers, Raven falls back to awaiter calls (GetAwaiter/GetResult). - Raven-specific
Result<..., ...>entry-point wrappers still use compiler-emitted bridge logic to map success and error payloads to process results. - Custom task-like return types that rely on
AsyncMethodBuilderAttributeare not supported yet.