Raven Programming Language
June 12, 2026 · View on GitHub
Raven is a modern general-purpose programming language and compiler inspired by the .NET Roslyn architecture.
✨ Key traits:
- Expression-first Raven syntax — explicit
val/var,match,record class, andResult/Option-centric flow - Targets the .NET runtime — compiles directly to IL and interoperates with .NET libraries
- Compiler-as-a-Service architecture — immutable, service-oriented compiler APIs
Raven is aimed at:
- Building a modern programming language and compiler for .NET
- Providing a clean API for syntax manipulation and analysis
- Documenting language and compiler design clearly
🔰 Language Overview
Raven is expression-oriented and blends functional and imperative styles. It uses () (unit) instead of void, models recoverable failure with Result<T, E> and absence with Option<T>, and uses explicit mutability (val vs var). As a .NET language, Raven interops directly with existing .NET APIs while keeping Raven-native syntax and semantics.
Type members are public by default; add access modifiers only when you intentionally narrow visibility.
Example
import System.*
import System.Console.*
import System.Text.Json.*
import System.Threading.Tasks.*
async func Main() -> Task {
val users: User[] = [
.(1, "Ada", Some("compiler engineer"), .Active),
.(2, "Bo", None, .Suspended("email bounced"))
]
val label = FindUser(users, 1) match {
Ok(val user) => user.Display()
Error(.NotFound(val id)) => "No user with id $id"
}
val options = JsonSerializerOptions with {
WriteIndented = true
PropertyNamingPolicy = .CamelCase
}
await Task.Delay(10)
WriteLine(JsonSerializer.Serialize(label, options))
}
func FindUser(users: User[], id: int) -> Result<User, LookupError> {
for user in users {
if user.Id == id {
return Ok(user)
}
}
return Error(.NotFound(id))
}
record class User(val Id: int, val Name: string, val Role: Option<string>, val Status: UserStatus) {
func Display() -> string {
val role = Role match {
Some(val value) => value
None => "member"
}
val status = Status match {
.Active => "active"
.Suspended(val reason) => "suspended ($reason)"
}
return "$Name is $status as a $role"
}
}
union UserStatus {
case Active
case Suspended(reason: string)
}
union LookupError {
case NotFound(id: int)
}
Highlights:
async/awaitand direct .NET interop- Collection expressions and explicit
val/varmutability - Target-typed member and constructor shorthand such as
.Activeand.(...) - Object initialization with
Type with { ... } Result/Optionfor recoverable flow and absencematchas a first-class expressionrecord class+ promoted constructor parameters- Discriminated unions with typed cases
Read the full Introduction and Getting Started for the complete flow.
🪶 Why the Name "Raven"?
Ravens are remarkable birds, known for their intelligence and adaptability.
In Old Norse mythology, ravens held significant importance as messengers of Odin. His two ravens, Huginn ("thought") and Muninn ("memory/mind"), symbolized intellect and reflection—qualities that align with the goals of this language.
The name reflects both the mythological roots and the clever traits of these birds.
Alternative names considered: Old Norse "Hrafn" or Danish "Ravn."
🎯 Project Goals
- Create a Programming Language — build a language from the ground up, covering design and implementation.
- Focus on Parsing & Semantics — implement parsing, binding, and analysis as the backbone of compilation.
- Serve as a Reference — provide a well-documented example for compiler enthusiasts.
- Pragmatic Scope — aim for a practical subset of Roslyn-like features, not full parity.
✨ Syntax
See the pseudo-specification here.
More samples.
🧩 API
- Compiler API reference: docs/compiler/api
- Example usage: Raven.Compiler project
🛠 Prerequisites
- .NET SDK 9.0
- Optional: DocFX for docs
🚀 Quick Start
# Build essentials
scripts/codex-build.sh
# Run baseline tests (runtime/emission-heavy suites excluded)
scripts/test-baseline.sh
Compile and run a sample case:
dotnet run -f net10.0 --project src/Raven.Compiler --property WarningLevel=0 -- \
samples/cases/quote-summary-linq-result-option.rav -o /tmp/raven-sample.dll
dotnet /tmp/raven-sample.dll
Useful frontend/debug commands:
dotnet run -f net10.0 --project src/Raven --property WarningLevel=0 -- \
dev syntax samples/cases/quote-summary-linq-result-option.rav
dotnet run -f net10.0 --project src/Raven --property WarningLevel=0 -- \
dev bound-tree samples/cases/quote-summary-linq-result-option.rav
Developer environment setup
There are three source-workspace setup modes:
-
Run tools through
dotnet run. This requires no shell setup and is the most explicit form: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.dll -
Build once and source session helpers:
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 syntax path/to/file.rvn rvnc path/to/file.rvn -o /tmp/app.dllSet
RAVEN_CONFIGURATIONorRAVEN_FRAMEWORKbefore sourcing to select a different build output. -
Use normal .NET project commands for applications:
dotnet build path/to/App.rvnproj dotnet run --project path/to/App.rvnprojThe
rvnfrontend also provides convenience commands over the same SDK workflow:rvn build path/to/App.rvnproj rvn run path/to/App.rvnproj rvn clean path/to/App.rvnprojWhen testing
net11.0projects, use a project-localglobal.jsonto pin an SDK that supportsnet11.0; the .NET CLI otherwise selects the highest installed SDK.
Distribution goal: package rvn, rvnc, the language server, Raven build assets, and Raven.Core together so users do not need repo-relative paths. Until then, source checkouts use Directory.Build.props for in-repo .rvnproj builds, and external projects can set LanguageTargets/RavenCompilerHost explicitly.
End-to-end project workflow
Create and run a Raven app project:
mkdir hello-raven
cd hello-raven
# Create a project scaffold (default type: app)
rvn init
# Build and run through rvn's SDK-backed frontend commands
rvn build
rvn run
Create a class library scaffold instead:
rvn init --type classlib --name MyLibrary
Project-system and NuGet details:
Run the compiler manually
Command:
dotnet run --project src/Raven.Compiler -- <path-to-file> -o <output-file-path>
Options:
--framework <tfm>– target framework--refs <path>– additional metadata reference (repeatable)--raven-core <path>– reference a specificRaven.Core.dll--emit-core-types-only– embed Raven core shims instead of usingRaven.Core.dll-o <path>– output assembly path--highlight– display diagnostics with highlighted source snippets and severity-coloured underlines (covers compiler, analyzer, and emit diagnostics)--no-emit– analyze only-h,--help– show help
rvnc references Raven.Core.dll by default. Use --raven-core to point to a different build of Raven.Core, or --emit-core-types-only to embed shimmed core types instead of referencing the DLL.
Creating a .debug/ directory in the current or parent folder causes the
compiler to emit per-file dumps (syntax tree, highlighted syntax, raw source,
bound tree, and binder tree) into that directory.
Use rvn dev for console debug views such as syntax, dump, bound-tree,
symbols, and quote.
Run the editor
dotnet run --project src/Raven.Editor -- <path-to-file>
When a file path is supplied, the editor opens the file and displays its name in the window title.
VS Code F5 (compile + debug)
The Raven VS Code extension now supports F5 compile-and-debug for both single files and project files:
.rvnactive file.ravenprojproject
Repository launch presets are included in .vscode/launch.json:
Raven: Compile and Debug (active file)Raven: Compile and Debug (project)
The debug flow compiles with Raven.Compiler into ${workspaceFolder}/.raven-debug, then launches dotnet <output.dll> under the debugger.
For details and configuration options (raven.sdkPath, raven.compilerProjectPath, raven.languageServerPath, raven.targetFramework), see docs/compiler/raven-vscode-extension.md.
📂 Repository Structure
src/
Raven.CodeAnalysis/ # Compiler core: syntax, binder, semantic model, code gen
Raven.Compiler/ # Command-line compiler
Raven.CodeAnalysis.Testing/ # Diagnostic test helpers
TestDep/ # Auxiliary test project
test/ # Unit tests
samples/ # Example Raven programs and CLI demos
tools/
NodeGenerator/ # Generates syntax node code from Model.xml
Generator/ # Shared Roslyn generator framework
docs/ # Language spec & design docs
🔧 Development Notes
- The
RunNodeGeneratortarget inRaven.CodeAnalysis.csprojruns automatically, but if generated files are missing, run the command manually. - Generated files reside in
Syntax/generated/andSyntax/InternalSyntax/generated/— do not edit by hand. - Always run
dotnet buildanddotnet testbefore committing.
🤝 Contributing
Contributions are welcome! See CONTRIBUTING.md for coding standards, git conventions, and workflow.
📚 Documentation
- Full documentation: docs/
- Unit tests for the language: Raven.CodeAnalysis.Tests
💡 Raven is a playground for exploring compilers and language design — your ideas and contributions can directly shape its evolution!