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)

quartz script.qz

Bytecode Mode

# Compile and run
quartz -c script.qz

# Compile to .qzb file
quartz -b script.qz

# Run precompiled bytecode
quartz script.qzb

JIT Mode (Experimental)

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 →