Cardinal is a lightweight concurrent scripting language inspired by Wren, with roots in Smalltalk, Lua, and Erlang. It is a C++ rewrite aimed at clarity for education and research while preserving Wren's goals: minimalism, speed, and expressive object-oriented design. Cardinal is intended for embedding and compiles as C++20 with no external dependencies. A single header amalgamation is also available for rapid prototyping.
System.print("Hello, world!")
class Cardinal {
flyTo(city) {
System.print("Flying to %(city)")
}
}
var adjectives = Fiber.new {
["small", "clean", "fast"].each {|word| Fiber.yield(word) }
}
while (!adjectives.isDone) System.print(adjectives.call())-
Small and readable VM and runtime are compact and heavily commented for approachability.
-
Fast and efficient Single-pass compiler to tight bytecode and a compact object representation.
-
Class-based Classes are first-class and form the core abstraction.
-
Concurrency by design Lightweight fibers enable coroutine-style concurrency.
-
Embeddable and portable No external deps, minimal stdlib, clean C++20 build, and a simple C++ API.
-
Header-only option Single-header distribution for experiments. Expect slightly longer compiles and about 15 percent slower foreign method calls compared to the library build.
- Readable C++ codebase for courses on PL, VMs, and concurrency
- Suitable for labs and capstone projects focused on language design
- Clean separation of concerns that maps to standard PL curricula
- Master thesis projects on type systems, effect handlers, memory models, GC strategies, and concurrency paradigms
- Rapid prototyping of runtime and language features due to higher level C++
- Small footprint that supports fast iteration
You can build with either the helper Python script (recommended) or raw CMake. A legacy Premake flow is also provided.
-
C++20 compiler
- Linux: GCC 11+ or Clang 13+
- macOS: Xcode 14+ or Homebrew clang
- Windows: MSVC 19.3x in Visual Studio 2022
-
CMake 3.20 or newer
-
Python 3.8+ to use
utils/build.py -
Optional: Premake5 for the legacy flow
Project layout highlights:
src/ Core implementation
src/include/ Public headers (cardinal.hpp, wren.h, etc.)
src/test-cardinal/ Cardinal test app sources
src/test-wren/ Wren test app sources
utils/build.py Unified builder and runner
utils/scripts/ Benchmarks, tests, codegen tools
utils/build/cmake/ CMake project root
bin/ Built executables (by config suffix)
build/ CMake or Premake build treesDefault configuration is dist which maps to CMAKE_BUILD_TYPE=Dist.
# From the repository root
python3 utils/build.py --buildBuild a specific target:
python3 utils/build.py --build --target cardinal
python3 utils/build.py --build --target cardinal_test
python3 utils/build.py --build --target wren
python3 utils/build.py --build --target wren_testRun a built tool:
# Runs from bin/, passing any arguments after the name
python3 utils/build.py --run cardinal_test
python3 utils/build.py --run cardinal_test -- some_argSelect a configuration:
# debug, release, or dist (default)
python3 utils/build.py --build --config debug
python3 utils/build.py --build --config release
python3 utils/build.py --build --config distClean artifacts:
python3 utils/build.py --cleanRun tests and benchmarks:
python3 utils/build.py --test
python3 utils/build.py --benchmark
python3 utils/build.py --benchmark --html # write an HTML report
python3 utils/build.py --baseline # generate a benchmark baseline
python3 utils/build.py --benchmark --graph # display results as a graphUtilities:
# Convert a .crd standard library file to a C string header
python3 utils/build.py --convert src/cardinal/core/core_source.crd src/cardinal/core/core_source.inc
# Generate a single-header amalgamation
python3 utils/build.py --amalgamation # default output path
python3 utils/build.py --amalgamation out.hpp # choose output path
# Code metrics and TODOs
python3 utils/build.py --cloc
python3 utils/build.py --todoExecutable names and locations:
bin/cardinal_testfor Distbin/cardinal_test-rfor Releasebin/cardinal_test-dfor Debug- Same scheme for
wren_test - On Windows the suffix is the same and an
.exeextension is added
The CMake project root is utils/build/cmake.
# Dist
cmake -S utils/build/cmake -B build/dist -DCMAKE_BUILD_TYPE=Dist
cmake --build build/dist -j
# Release
cmake -S utils/build/cmake -B build/release -DCMAKE_BUILD_TYPE=Release
cmake --build build/release -j
# Debug
cmake -S utils/build/cmake -B build/debug -DCMAKE_BUILD_TYPE=Debug
cmake --build build/debug -jBuild specific targets:
cmake --build build/dist --target cardinal
cmake --build build/dist --target cardinal_testBinaries are configured to be written to bin/ with the config suffix rules shown above.
Premake is optional and provided for platform specific project generation.
# Generate makefiles with gmake2 and build
python3 utils/build.py --use-premake --premake --action gmake2
python3 utils/build.py --use-premake --make all
# Other actions: vs2019, xcode4, codeblocks, codelite, gmake2-cpp20, etc.
python3 utils/build.py --use-premake --premake --action vs2019Targets for the legacy flow:
cardinalandwrenstatic librariescardinal_testandwren_testconsole appsallmeta target
- Create a VM, load modules, and bind foreign classes or methods through the C++ API in
src/include/cardinal.hpp. - The amalgamated single header is handy for teaching and quick experiments. It trades compile time and foreign method call overhead for convenience.
- Fibers provide cooperative concurrency inside the VM.
- Algebraic effect handler with multishot continuations
- Registries and optional typing hooks for effect handling experiments
See LICENSE.
If you use Cardinal in academic work, please cite the repository and mention the C++ rewrite focus on education and research.
