Architecture
Quartz is designed with simplicity and performance in mind. This document explains the internal architecture for developers who want to understand or contribute to the language.
High-Level Overview
┌─────────────┐ ┌─────────┐ ┌─────────────┐ │ Source Code │────▶│ Lexer │────▶│ Tokens │ │ (.qz) │ │ │ │ │ └─────────────┘ └─────────┘ └──────┬──────┘ │ ▼ ┌─────────────┐ │ Parser │ │ │ └──────┬──────┘ │ ▼ ┌─────────────┐ │ AST │ │ │ └──────┬──────┘ │ ┌──────────────────────┼──────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Interpreter │ │ Bytecode │ │ JIT │ │ (Direct) │ │ Compiler │ │ (Experim.) │ └──────┬──────┘ └──────┬──────┘ └─────────────┘ │ │ │ ▼ │ ┌─────────────┐ │ │ Bytecode │ │ │ (.qzb) │ │ └──────┬──────┘ │ │ │ ▼ │ ┌─────────────┐ │ │ VM │ │ │ │ │ └──────┬──────┘ │ │ ▼ ▼ ┌─────────────────────────────────────┐ │ Runtime │ │ (Memory, Extensions, I/O, etc.) │ └─────────────────────────────────────┘
Core Components
Lexer (Tokenizer)
The lexer transforms source code into a stream of tokens:
let x = 42 + y
Becomes:
LET "let"
IDENTIFIER "x"
ASSIGN "="
NUMBER 42
PLUS "+"
IDENTIFIER "y"
EOF
Implementation: src/core/lexer.cpp
Parser
The parser constructs an Abstract Syntax Tree (AST) from tokens using recursive descent parsing:
BinaryExpr(ASSIGN)
├── Identifier("x")
└── BinaryExpr(PLUS)
├── NumberLiteral(42)
└── Identifier("y")
Implementation: src/core/parser.cpp
Interpreter
Direct AST execution with tree-walking evaluation. Simple but flexible:
Value Runtime::evaluate(const ASTNode* node) {
switch (node->type) {
case NodeType::NumberLiteral:
return Value(node->numberValue);
case NodeType::BinaryExpr:
return evaluateBinary(node);
// ...
}
}
Implementation: src/core/runtime.cpp
Bytecode Compiler
Compiles AST to stack-based bytecode for faster execution:
let x = 1 + 2
Compiles to:
LOAD_CONST 1
LOAD_CONST 2
ADD
STORE_LOCAL 0
Implementation: src/core/bytecode.cpp
Virtual Machine
Stack-based VM that executes bytecode:
void VM::run() {
while (ip < code.size()) {
uint8_t opcode = code[ip++];
switch (opcode) {
case OP_ADD:
push(pop() + pop());
break;
// ...
}
}
}
Implementation: src/core/vm.cpp
Memory Management
Value Representation
Values use tagged union for type safety and efficiency:
struct Value {
enum Type { INT, DOUBLE, STRING, ARRAY, DICT, FUNCTION, CLASS, OBJECT, NULL_T };
Type type;
union {
int64_t intValue;
double doubleValue;
std::string* stringValue;
// ...
};
};
Garbage Collection
Quartz uses reference counting with cycle detection for memory management. Complex objects (arrays, dictionaries, objects) are heap-allocated and reference-counted.
Extension System
Native extensions are dynamically loaded shared libraries:
// Extension entry point
extern "C" void registerExtension(ExtensionRegistry& reg) {
reg.registerFunction("mymodule.myfunction", myFunction);
}
// Function implementation
Value myFunction(const std::vector<Value>& args) {
// Implementation
return Value(result);
}
Extensions are loaded via dlopen (Linux/macOS) or LoadLibrary (Windows).
Standard Library Modules
| Module | Directory | Purpose |
|---|---|---|
| system.io | `extensions/system_io/` | Input/Output |
| system.math | `extensions/system_math/` | Math functions |
| system.string | `extensions/system_string/` | String manipulation |
| system.fs | `extensions/system_fs/` | File system |
| system.net | `extensions/system_net_*/` | Networking |
| system.json | `extensions/system_json/` | JSON parsing |
Execution Modes
Interpreter Mode (Default)
- Direct AST evaluation
- No compilation overhead
- Best for small scripts and REPL
- Easier debugging
quartz script.qz
Bytecode Mode
- Compiles to bytecode first
- ~2-5x faster for compute-heavy code
- Supports ahead-of-time compilation
# Compile and run
quartz -c script.qz
# Compile to .qzb file
quartz -b script.qz
# Run precompiled bytecode
quartz script.qzb
JIT Mode (Experimental)
- Compiles hot paths to native code
- Currently x86_64 only
- Under active development
Source File Structure
src/core/
├── lexer.cpp # Tokenization
├── lexer.h
├── parser.cpp # AST construction
├── parser.h
├── ast.h # AST node definitions
├── runtime.cpp # Interpreter
├── runtime.h
├── bytecode.cpp # Bytecode compiler
├── bytecode.h
├── vm.cpp # Virtual machine
├── vm.h
├── value.cpp # Value type system
├── value.h
├── extension.cpp # Extension loading
└── extension.h
include/
├── quartz.h # Public API
└── core/ # Internal headers
extensions/
├── CMakeLists.txt
├── system_io/
│ ├── io.cpp
│ └── CMakeLists.txt
└── ...
Build System
CMake-based build with options:
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_EXTENSIONS=ON \
-DENABLE_JIT=OFF
cmake --build build
Build Targets
| Target | Output | Description |
|---|---|---|
| `quartz` | `build/quartz` | Main executable |
| `qz-core` | `build/libqz-core.so` | Core library |
| `extensions` | `build/extensions/*.so` | Stdlib modules |
Testing Infrastructure
# Sanity checks - basic functionality
./sanity_check.sh
# Feature checks - language features
./feature_check.sh
# Compile-run checks - test both modes
./compile_run_check.sh
# Benchmarks
cd benchmark && ./run_benchmarks.sh
Debugging Tools
Token Printer
./build/print_tokens script.qz
Bytecode Disassembler
python3 tools/qzb_disasm.py script.qzb
Bytecode Inspector
python3 tools/qzb_inspect.py script.qzb
🔧 Contributing Interested in contributing? Check out the Contributing Guide for how to get started.
Next: Bytecode VM →