Execore is an interpreted programming language compiler frontend and tree-walk runtime engineered in ISO C++23.
Source (.exe) ──> SourceManager ──> Lexer (SoA) ──> Parser (Monadic) ──> AST ──> SemanticAnalyzer ──> Interpreter
│ │
▼ ▼
DiagnosticEngine DotExporter (Graphviz)
-
Buffer Ownership & Slices: Holds raw file buffers in contiguous memory, giving downstream passes string slices (
std::string_view) with zero heap copies. -
Line Indexing: Pre-computes line break byte offsets during registration. Line and column coordinates resolve via binary search in
$O(\log N)$ time for error diagnostics.
- Indentation Tracking (Off-Side Rule): Maintains an indentation depth stack (
std::vector<size_t>). When indentation increases, the lexer synthesizes aTokenKind::Indenttoken. When indentation decreases, it pops matching levels and synthesizes one or moreTokenKind::Dedenttokens. - Configurable Tab Stops: Supports custom tab spacing via
-t / --tab-size <N>(default: 4 spaces). - Data-Oriented Structure of Arrays (
TokenBufferSoA): Tokens can be laid out as parallel contiguous vectors (kinds,spans,lexemes) rather than an array of individual structs. This packs 64 token kinds per standard 64-byte L1 cacheline, speeding up token lookahead and keyword scans. - String Decoding: Escaped sequences (
\n,\t,\r,\0,\\,\",\') decode into owned string buffers without fixed size ceilings.
- Monadic Error Results: Exposes
parse_program_monadic()returningResult<std::unique_ptr<Program>, ParseError>. This wraps C++23std::expectedand chains downstream semantic analysis or AST serialization through.transform()and.and_then(). - Precedence Climbing: Resolves binary and unary expressions through an operator precedence hierarchy:
- Assignment (
=,+=,-=,*=,/=,%=) - Logical OR (
or) - Logical AND (
and) - Equality and Membership (
==,!=,<>,in) - Relational (
<,<=,>,>=) - Additive (
+,-) - Multiplicative (
*,/,%) - Unary prefix (
+,-,!,not) - Postfix (Function calls, Indexing
[], Slicing[:], Method calls.method()) - Primary (Literals, Identifiers, Grouped
())
- Assignment (
- Memory Ownership: AST nodes use
std::unique_ptr, ensuring clear ownership trees and clean teardown.
- Polymorphic Hierarchy: Base classes
ASTNode,Expr, andStmtdefine standard virtual destructors. - Visitor Pattern: Implemented through
ASTVisitor. Concrete visitors implement the tree-walk interpreter, semantic validation, and Graphviz visualization without adding methods to node classes. - Graphviz DOT Exporter (
execore::DotExporter): Generates Graphviz DOT graphs with distinct node shapes and color palettes for visual debugging (--emit-dot).
- 3-Tier Symbol Table: Scopes chain together in a hierarchy:
Placing builtins in an enclosing parent scope allows global variables to shadow builtins without redefinition errors.
builtin_scope_ (chr, ord, type, len) ▲ │ global_scope_ (user global variables and functions) ▲ │ local_scope_ (block / function variables) - Validation Passes:
- Variable declaration enforcement before use.
- Local scope redeclaration checks.
- Function parameter uniqueness and call-site arity checks.
- Control flow verification ensuring
breakandcontinueonly appear inside loops.
- Inline Primitives:
Valueuses a tagged union (std::variant). Primitives (int64_t,double,char,std::monostate) live inline without dynamic heap allocations. - Reference-Counted Objects: Dynamic sequences (
StringObject,ListObject,FunctionObject) usestd::shared_ptr. - Polymorphic Operators: Numeric operations promote integers to floating point when mixed. Strings and lists support repetition with
*and concatenation with+.
MonotonicArenaResourceinherits fromstd::pmr::memory_resource.- Allocates memory in growing chunks (default 64 KB). Individual deallocations are no-ops. All chunk memory reclaims in a single call to
release().
- Scope Frames: Environments chain parent pointers for lexical lookup.
- First-Class Functions:
FunctionObjectcaptures its declaration environment inclosure_. - Cycle Breaking: When a function is stored in its own lexical environment, a mutual reference cycle forms.
Interpreterregisters created environments usingstd::weak_ptrand callsEnvironment::clear()during destruction to break these cycles cleanly under AddressSanitizer and LeakSanitizer. - Cacheline Interference Protection:
ThreadExecutionContextaligns tohardware_destructive_interference_size(64 bytes) to avoid false sharing on multi-threaded runs.
- Return statements, loop breaks, and continue statements propagate through small control signal structures (
ReturnSignal,BreakSignal,ContinueSignal) caught by statement visitor loops.
- Source Coordinates: Reports file, line, and column numbers with severity levels (
error,warning,note). - Underlines and Carets: Fetches line content from
SourceManagerand prints ANSI-colored underlines pointing at the exact token span.