Execore is an interpreted programming language built in ISO C++23. It combines indentation-based block syntax with explicit static types (int, float, char, str, list), first-class lexical closures, and dynamic method dispatch.
The design goal was simple: get the readable feel of Python while keeping unambiguous static typing and fast, zero-allocation execution paths.
- Clang 19+ or GCC 15+ (ISO C++23 support required)
- CMake 3.28 or newer
- Ninja build system
- Mold or LLD linker (automatically detected)
# Configure and compile with Clang and Ninja
cmake --preset dev-clang
cmake --build --preset dev
# Run an example program
./build/dev-clang/execore examples/algorithms/factorial.exe# Run the complete test matrix (unit, BDD, property, fuzz regression)
ctest --preset test-all
# Run under AddressSanitizer and UndefinedBehaviorSanitizer
cmake --preset asan-ubsan
cmake --build --preset asan-ubsan
ctest --preset test-asanBlocks use 4-space indentation without braces. Variables must be declared with their static type before assignment or use.
def factorial(n)
if n <= 1
return 1
return n * factorial(n - 1)
int number = 6
int result = factorial(number)
print "Factorial of", number, "is:", resultLists store dynamic values with subscripting, negative indices, and slicing.
list items
items.append(10)
items.append(20)
items.append(30)
# Slicing creates a new list with elements from index 1 up to 3
list sub = items[1:3]
print "Sublist:", sub
# Iteration over sequences
for val in items
print "Value:", valStrings support sequence slicing, repetition, and builtins like ord() and chr().
str greeting = "Execore"
print greeting[0:3] # Prints: Exe
print "-" * 15 # Prints: ---------------
char letter = 'A'
int ascii_code = ord(letter)
print "ASCII:", ascii_code, "Next:", chr(ascii_code + 1)| Type | C++ Runtime Representation | Storage Location | Key Behaviors |
|---|---|---|---|
int |
int64_t |
Inline inside std::variant |
64-bit signed arithmetic, bitwise operators, modulo |
float |
double |
Inline inside std::variant |
IEEE 754 double precision floating point |
char |
char |
Inline inside std::variant |
Single-byte character |
str |
std::shared_ptr<StringObject> |
Refcounted heap object | Slicing, repetition with *, concatenation with +, .len() |
list |
std::shared_ptr<ListObject> |
Refcounted heap object | Slicing, .append(), .insert(), .remove(), .len() |
none |
std::monostate |
Inline inside std::variant |
Default return value and null representation |
Primitive types live directly inside a cacheline-friendly tagged variant. They never hit the heap during calculation or comparison.
Source File (.exe)
│
▼
┌───────────────┐
│ SourceManager │ Zero-copy file buffer ownership and line offset indexing
└───────┬───────┘
│
▼
┌───────────────┐
│ Lexer (SoA) │ Off-side rule indentation tracking and synthetic INDENT/DEDENT
└───────┬───────┘
│
▼
┌───────────────┐
│ Parser │ Precedence climbing with C++23 std::expected monadic results
└───────┬───────┘
│
▼
┌───────────────┐
│ AST & Visitor │ Arena bump-pointer allocations and polymorphic AST hierarchy
└───────┬───────┘
│
▼
┌───────────────┐
│ Semantics │ 3-tier symbol table with built-in shadowing and scope checks
└───────┬───────┘
│
▼
┌───────────────┐
│ Interpreter │ Tree-walk execution, cycle-broken lexical closures
└───────────────┘
- Data-Oriented Token Stream (
TokenBufferSoA): Tokens can be stored as parallel contiguous vectors (kinds,spans,lexemes) instead of an array of heavy structs. This gives 100% L1 cache density during token lookahead scans. - Monadic Error Handling: The parser provides
parse_program_monadic()returningResult<std::unique_ptr<Program>, ParseError>. This wraps C++23std::expectedand chains operations with.transform()and.and_then(). - PMR Arena Allocation:
MonotonicArenaResourceinherits fromstd::pmr::memory_resourceso standard library containers and AST nodes allocate from continuous monotonic memory blocks without global malloc contention. - Deterministic Cycle Breaking: Lexical closures hold references to their parent environment. To prevent memory leaks when a function is stored inside its own environment,
Interpretertracks active environments through weak references and clears bindings explicitly on teardown.
We test performance using Google Benchmark across three microbenchmarks in benchmarks/micro/.
# Build and run the entire benchmark suite
./benchmarks/run_benchmarks.sh- Lexer Throughput: >100 MiB/s (~4.8 Million tokens/second).
- Parser Throughput: >32 MiB/s (~870,000 expressions/second).
- Interpreter Loop Latency: ~3.4 Million loop iterations/second.
Execore includes an automated PGO script that compiles an instrumented build, trains it on all sample workloads, merges the profile data using llvm-profdata, and links an optimized binary with ThinLTO:
./tools/scripts/pgo_build.shTesting the PGO release binary shows a 4x reduction in total test execution time compared to debug builds (0.71s vs 3.02s).
Every change to Execore passes five layers of testing:
- Unit Tests (
tests/unit/): Granular component checks for lexer, parser, value variants, and interpreter behavior. - BDD Scenarios (
tests/unit/test_bdd_scenarios.cpp): End-to-end user workflows usingGIVEN/WHEN/THENcovering off-side indentation, operator precedence binding, and recursive closures. - Property-Based Testing (
tests/property/test_properties.cpp): 2,000 randomized property tests verifying arithmetic commutativity, associativity, string slicing round-trips, and boolean truthiness. - Continuous Fuzzing (
tests/fuzz/): LibFuzzer harnesses for lexer and parser inputs, plus a standalone runner that executes 10,000 pseudo-random fuzzing rounds with zero crashes or leaks. - Mutation Testing (
tests/mutation/mutation_check.py): Injects AST and operator mutations across core source files to verify that the test suite kills more than 80% of mutants.
execore [options] <source-file>
Options:
-h, --help Display this help message and exit
-v, --version Display version information and exit
-t, --tab-size <N> Configure indentation tab size (default: 4)
--dump-ast Dump textual AST representation to stdout
--emit-dot <file> Export AST as a Graphviz DOT diagram to <file>
--check-only Perform lexical, syntax, and semantic checks without executing
--no-color Disable colorized diagnostic messages
Exporting an AST visualization to PNG:
./build/dev-clang/execore --emit-dot ast.dot examples/algorithms/factorial.exe
dot -Tpng ast.dot -o ast.png- Architecture Guide: Internal compiler pipeline, memory layout, and runtime design.
- Formal Grammar: EBNF specification for the Execore dialect.
- Architecture Decision Records (ADRs):
- Software Bill of Materials (SBOM): CycloneDX v1.5 JSON manifest.
- Compliance Scorecard: 50/50 Frontier Tier certification.
MIT License. See LICENSE for details.