About The Language
A small compiled language: Python ish syntax, static types, native binaries via LLVM.
License: MIT · Version: 1.0.4 · Releases
Quick start (Windows)
# 1. Install vpp-1.0.4-setup.exe from GitHub Releases
# 2. Install "v++ Language" in VS Code (publisher: vpp-lang)
vpp run examples\hello.vpp
vpp --version
vpp doctor
Docs: website · hello-world guide
What works
vpp runinterpreter +vpp buildnative codegen- LSP, debugger (F5), tests, fmt, packages (
vpp.toml) - VS Code extension on Marketplace
- Windows installer with bundled LLVM; Unix from source
Build from source
git clone https://github.com/shauryaR790/VPP.git
cd VPP
cargo build --release --features codegen,lsp
cargo test --all-targets
# Verify install: vpp doctor
See CONTRIBUTING.md · SPEC.md
Links
| Releases | https://github.com/shauryaR790/VPP/releases |
| Extension | https://marketplace.visualstudio.com/items?itemName=vpp-lang.vplusplus |
| Issues | https://github.com/shauryaR790/VPP/issues |
| CMake | docs/guides/cmake.md |
V++ Compiler Architecture (v0.2)
Overview
V++ is a statically typed language with a single front end and two backends:
- Interpreter tree walking evaluation for development and teaching
- Native compiler lowers to V++ IR, then LLVM, links the C runtime
Both backends consume the same typed AST produced by the type checker.
.vpp source
│
▼
Lexer (src/lexer)
│
▼
Parser → AST (src/parser, src/ast)
│
▼
Module loader (src/modules) - flat merge, path imports (v0.2)
│
▼
Type checker (src/types/check.rs) → TypedProgram
│
├──────────────────────┐
▼ ▼
Interpreter IR lower (src/ir/lower.rs)
(src/interp) │
│ ▼
│ v++ IR (src/ir)
│ │
│ ▼
│ LLVM emit (src/codegen/emit.rs)
│ │
│ ▼
│ C runtime (runtime/vpp_runtime.c)
│ │
└──────── same semantics ─┴──► native executable
Components
Lexer / Parser
Hand written lexer with significant newlines. Recursive descent parser with Pratt precedence for expressions.
Type checker
Two pass: register types and functions, then check bodies. Uses src/builtins for builtin signatures.
V++ IR
Thin intermediate representation between typed AST and LLVM. Makes memory operations, control flow, and calling conventions explicit. See src/ir/mod.rs.
LLVM backend
Inkwell based. Emits LLVM IR, invokes clang to produce object files, links runtime. Feature gated: --features codegen.
Runtime
C ABI documented in MEMORY_MODEL.md. Heap strings and arrays use ARC reference counting.
Builtins
Single registry in src/builtins/mod.rs consumed by type checker, interpreter, and codegen.
Feature parity (v0.2 target)
See CHANGELOG.md and tests/parity/ for the live matrix. Native codegen must match interpreter output for all supported features.
Version notes
- v0.2 native foundation, IR, ABI, parity tests
- v0.3 module redesign, package manager (not in v0.2)
- v0.4 generics, traits,
mut, compile time match exhaustiveness
V++ Memory Model (v0.2 bootstrap)
Goals
- Predictable behavior for beginners
- Efficient native executables
- Clear C ABI between compiler and runtime
- Extensible toward v1.0 production model
v0.2 does not implement a borrow checker or garbage collector.
Representation
Stack (by value in LLVM)
| Type | Native representation | Notes |
int |
i64 |
Signed 64 bit |
float |
double |
IEEE 64 bit |
bool |
i1 / zero extended |
|
| fixed size struct | LLVM struct | Field layout computed by codegen |
Heap (ARC)
| Type | C type | Header |
string |
VppString* |
{ char* data; int64_t ref_count; } |
array[T] |
VppArray* |
{ void* data; int64_t len; int64_t elem_size; int64_t ref_count; } |
String ABI (v0.2)
1. String literals compiler emits a nul terminated i8* constant, calls vpp_string_new(cstr) → VppString*
2. String locals stored as VppString* (pointer to heap object)
3. print(s) calls vpp_print_str(VppString* s)
4. len(s) calls vpp_strlen(VppString* s)
5. Concatenation vpp_string_concat(VppString* a, VppString* b) → new VppString* (retain inputs during call)
Never pass raw i8* to vpp_print_str.
Array ABI (v0.2)
1. Literals vpp_make_array(len, elem_size) then fill element slots via typed GEP
2. Value type VppArray* everywhere (locals, parameters, returns)
3. Elements inline in buffer; string elements store VppString* (8 bytes); bool uses 1 byte
4. len(a) vpp_array_len(VppArray*)
5. a[i] vpp_array_index_ptr(arr, i) with bounds check (abort on OOB, matches interpreter error)
6. Ownership vpp_array_retain on pass to functions; vpp_array_release at scope exit
7. String elements vpp_string_retain when stored into array literal
ARC rules (v0.2 bootstrap)
vpp_string_new/vpp_make_arrayref_count = 1vpp_*_retainincrementvpp_*_releasedecrement; free at zero- Function arguments: retain on pass (caller keeps ownership)
- Scope exit: release heap locals (v0.2: strings in nested scopes)
Full ARC at scope boundaries is implemented incrementally. Leaks are acceptable in v0.2 for top level only programs; crashes are not.
Interpreter mapping
| Native | Interpreter |
VppString* |
Rc<String> |
VppArray* |
Rc<Vec<Value>> |
Semantics must match observable behavior (print output, len, indexing).
Future (v1.0)
- Move semantics at assignment for heap types
- Struct/enums with explicit layout in spec
- Optional
unsafeblocks - No hidden GC
V++ Language Specification
> v1.0 FROZEN (2026 08 21). Breaking changes require v2.0. See PARITY_PROMISE.md.
This document describes V++ as implemented in v1.0. If code and spec disagree, parity tests and native execution are authoritative.
Types
| Type | Syntax | Notes |
| int | int |
64 bit signed |
| float | float |
64 bit IEEE |
| bool | bool |
true / false |
| string | string |
UTF 8 heap string (ARC native) |
| array | array[T] |
Homogeneous array |
| struct | Name |
User defined product type |
| enum | Name |
User defined sum type |
| Option | Option[T] |
Some(x) / None |
| Result | Result[T, E] |
Ok(x) / Err(e) |
Variables
let x = 10 // immutable int
let mut total = 0 // mutable; required for reassignment
total = total + 1
# ...
# See docs for full examples
Functions
fn add(a: int, b: int) -> int {
return a + b
}
fn id[T](x: T) -> T {
return x
}
fn main() -> int {
let n = id[int](42)
return n
}
Generic calls require explicit type arguments: idint.
When present, fn main() -> int is the program entry point (interpreter and native both invoke it).
Traits
trait Display {
fn to_text(self) -> string
}
impl Display for User {
fn to_text(self) -> string {
return self.name
}
}
// method call (static dispatch)
print(user.to_text())
Control flow
if / else, while, for i in start..end (half open), for item in arr, break, continue, match.
Match arms use blocks:
match status {
Active => {
print("active")
}
Inactive => {
print("inactive")
}
}
User enum variants in expressions use bare names when the expected type is known (e.g. struct field status: Active).
Builtins
| Name | Signature | Behavior |
| printable values | Print line per argument | |
| len | array or string → int | Length |
| assert | bool → void | Fail if false |
| assert_eq | T, T → void | Fail if not equal |
| read_file / write_file / file_exists | fs | File I/O (also via std.fs) |
| json_parse / json_stringify | json | JSON helpers (also via std.json) |
| process_run | process | Run shell command (also via std.process) |
Modules (v0.3)
import std.io
import std.fs
import "legacy/path.vpp" // still supported
# ...
# See docs for full examples
- Canonical paths:
import std.io→std/io.vpp pub fn/pub struct/pub enumfor exports- Namespaced calls:
math.add(1, 2) - Circular imports and duplicate imports are errors
Projects and packages
vpp.toml manifest, vpp.lock, dependencies via path, git, or registry semver (hello-lib = "0.1.0").
Standard library
std/io, std/math, std/string, std/collections, std/fs, std/json, std/process.
Execution
vpp run file.vppinterpreter (callsfn main()when defined)vpp build file.vpp -o out.exenative executable (requires LLVM + codegen).\stress.ps1compare interpreter vs native output forstress.vpp
Interpreter and native must produce identical stdout for supported programs.
Known limitations (v0.4)
- Generics use monomorphization with explicit type arguments at call sites (no inference yet)
- Traits use static dispatch only (no trait objects or bounds)
- Hosted package registry is local (
registry/index.toml); no remote publish yet
Roadmap
v1.0 (shipped)
- [x] Frozen language spec SPEC.md
- [x] Parity Promise PARITY_PROMISE.md
- [x] Compatibility CI all examples on every push
- [x] Debugger (CLI + VS Code F5)
- [x] Test Explorer UI
- [x] Package registry search (
vpp search)
v0.9 (shipped)
- [x] Test Explorer UI
- [x]
vpp test --listfor IDE integration - [x]
vpp searchregistry command - [x] SPEC v1.0 release candidate
v0.8 (shipped)
- [x] Interpreter line debugger (
vpp debug) - [x] VS Code debug launch (DAP)
v0.7 (shipped)
- [x]
vpp watchlive re run on save - [x]
vpp benchinterpreter timing - [x] Cross platform doctor hints
- [x] Extension 0.7 Watch + Benchmark commands
v0.6 (shipped)
- [x]
vpp replinteractive interpreter session - [x] Extension 0.6 format on save, REPL command, snippets, lazy LSP
Post v1.0 (ideas)
- Native debug symbols
- Hosted registry on GitHub Pages
- v2.0 language extensions (only with major version)
Track issues: GitHub Issues
